Skip to content
Snippets Groups Projects
RunDescriptor.py 60.8 KiB
Newer Older
        if loaded_ws.run().hasProperty("calibrated"):
            return # already calibrated

        ws_calibration = calibration
        if use_ws_calibration:
            try:
                ws_calibration = prop_helpers.get_default_parameter(loaded_ws.getInstrument(),'det_cal_file')
                if ws_calibration is None:
                    ws_calibration = calibration
                if isinstance(ws_calibration,str) and ws_calibration.lower() == 'none':
                    ws_calibration = calibration
                if ws_calibration :
                    test_name = ws_calibration
                    ws_calibration = FileFinder.getFullPath(ws_calibration)
                    if len(ws_calibration) == 0:
                        raise RuntimeError('Can not find defined in run {0} calibration file {1}\n'\
                                           'Define det_cal_file reduction parameter properly'.format(loaded_ws.name(),test_name))
                    RunDescriptor._logger('*** load_data: Calibrating data using workspace defined calibration file: {0}'.format(ws_calibration),'notice')
            except KeyError: # no det_cal_file defined in workspace
                if calibration:
                    ws_calibration = calibration
                else:
                    return

        if type(ws_calibration) == str : # It can be only a file (got it from calibration property)
            RunDescriptor._logger('load_data: Moving detectors to positions specified in cal file {0}'.format(ws_calibration),'debug')
            # Pull in pressures, thicknesses & update from cal file
            LoadDetectorInfo(Workspace=loaded_ws, DataFilename=ws_calibration, RelocateDets=True)
            AddSampleLog(Workspace=loaded_ws,LogName="calibrated",LogText=str(ws_calibration))
        elif isinstance(ws_calibration, api.Workspace):
            RunDescriptor._logger('load_data: Copying detectors positions from workspace {0}: '.format(ws_calibration.name()),'debug')
            CopyInstrumentParameters(InputWorkspace=ws_calibration,OutputWorkspace=loaded_ws)
            AddSampleLog(Workspace=loaded_ws,LogName="calibrated",LogText=str(ws_calibration))
#--------------------------------------------------------------------------------------------------------------------
    @staticmethod
    def copy_spectrum2monitors(data_ws,mon_ws,spectraID):
        this routine copies a spectrum form workspace to monitor workspace and rebins it according to monitor workspace binning

        @param data_ws  -- the  event workspace which detector is considered as monitor or Mantid pointer to this workspace
        @param mon_ws   -- the  histogram workspace with monitors where one needs to place the detector's spectra
        @param spectraID-- the ID of the spectra to copy.

        # ----------------------------
        try:
            ws_index = mon_ws.getIndexFromSpectrumNumber(spectraID)
            # Spectra is already in the monitor workspace
            return mon_ws
        except:
            try:
                ws_index = data_ws.getIndexFromSpectrumNumber(spectraID)
            except: 
                raise RuntimeError('*** Error: Can not retrieve spectra with ID {0} from source workspace: {1}'.\
                                    format(spectraID,data_ws.name()))
        #
        x_param = mon_ws.readX(0)
        homo_binning,dx_min=RunDescriptor._is_binning_homogeneous(x_param)
        bins = [x_param[0],dx_min,x_param[-1]]
        ExtractSingleSpectrum(InputWorkspace=data_ws,OutputWorkspace='tmp_mon',WorkspaceIndex=ws_index)
        Rebin(InputWorkspace='tmp_mon',OutputWorkspace='tmp_mon',Params=bins,PreserveEvents='0')
        mon_ws_name = mon_ws.getName()
        if not homo_binning:
            Rebin(InputWorkspace=mon_ws_name,OutputWorkspace=mon_ws_name,Params=bins,PreserveEvents='0')
        ConjoinWorkspaces(InputWorkspace1=mon_ws_name,InputWorkspace2='tmp_mon')
        mon_ws = mtd[mon_ws_name]

        if 'tmp_mon' in mtd:
            DeleteWorkspace(WorkspaceName='tmp_mon')
        return mon_ws
    #
    @staticmethod
    def _is_binning_homogeneous(x_param):
        """Verify if binning in monitor workspace is homogeneous"""
        dx=x_param[1:]-x_param[0:-1]
        dx_min=min(dx)
        dx_max=max(dx)
        if dx_max-dx_min>1.e-9:
            return False,dx_min
        else:
            return True,dx_min

#--------------------------------------------------------------------------------------------------------------------
        """ method removes monitor workspace form analysis data service if it is there
            (assuming it is not needed any more)
        """
        monWS_name = self._ws_name + '_monitors'
        if monWS_name in mtd:
            DeleteWorkspace(monWS_name)
Alex Buts's avatar
Alex Buts committed
#--------------------------------------------------------------------------------------------------------------------
    def clear_resulting_ws(self):
        """Remove workspace from memory as if it has not been processed
           and clear all operations indicators except cashes and run lists.
           Attempt to get workspace for a file based run should in this case
           load workspace again
Alex Buts's avatar
Alex Buts committed
        """
        ws_name = self._ws_name
        mon_name = ws_name + '_monitors'
        self._ws_name = ''
Alex Buts's avatar
Alex Buts committed
        self._ws_cname = ''
        self._ws_suffix = ''
        if ws_name in mtd:
            ws = mtd[ws_name]
            self._run_number = ws.getRunNumber()
            DeleteWorkspace(ws_name)
        if mon_name in mtd:
            DeleteWorkspace(mon_name)
Alex Buts's avatar
Alex Buts committed
        if self._run_list:
            ind = self._run_list.add_or_replace_run(self._run_number)
            self._run_file_path = self._run_list._file_path[ind]
            self._fext = self._run_list.get_fext(ind)
#--------------------------------------------------------------------------------------------------------------------

    def _build_ws_name(self,sum_runs=None):
        instr_name = self._instr_name()
        if self._run_list:
            if not sum_runs:
                sum_runs = RunDescriptor._holder.sum_runs
            sum_ext = self._run_list.sum_ext(sum_runs)
        else:
            sum_ext = ''
        if self._run_number:
            ws_name = '{0}{1}{2}{3:0>#6d}{4}{5}'.format(self._prop_name,instr_name,self._ws_cname,self._run_number,\
                                                        sum_ext,self._ws_suffix)
            ws_name = '{0}{1}{2}{3}'.format(self._prop_name,self._ws_cname,sum_ext,self._ws_suffix)
        return ws_name
#--------------------------------------------------------------------------------------------------------------------
    @staticmethod
    def rremove(thestr, trailing):
        thelen = len(trailing)
        if thestr[-thelen:] == trailing:
            return thestr[:-thelen]
        return thestr
    def _split_ws_name(self,ws_name):
        """Method to split existing workspace name
           into parts, in such a way that _build_name would restore the same name
        """
        # Remove suffix
        name = self.rremove(ws_name,self._ws_suffix)
        if self._run_list:
            summed = RunDescriptor._holder.sum_runs
            sumExt = self._run_list.sum_ext(summed)
        if len(sumExt) > 0:
            name = self.rremove(ws_name,sumExt)
        name = name.replace(self._prop_name,'',1)
            part_ind = re.search('#(.+?)#', name).group(0)
            name = name.replace(part_ind,'',1)
        except AttributeError:
            part_ind = ''
            instr_name = self._instr_name()
            name = name.replace(instr_name,'',1)
            self._ws_cname = part_ind + filter(lambda c: not c.isdigit(), name)
            self._ws_cname = part_ind + name
        if RunDescriptor._holder:
            instr_name = RunDescriptor._holder.short_inst_name
            instr_name = '_test_instrument'
        return instr_name
        """Interface property used to verify if
           the class got its own values or been shadowed by
           property, this one depends on
        return not self._in_cash

    def notify_sum_runs_changed(self,old_value,new_value):
        """Take actions on changes to sum_runs option
        """
        if self._run_list:
            if old_value != new_value:
                rl = self._run_list
                self._clear_all()
                rl.set_last_ind2sum(-1) # this will reset index to default
                self._run_list = rl
                run_num,file_path,main_fext,ind = self._run_list.get_current_run_info(new_value)
                self._run_list.set_last_ind2sum(ind)
                self._run_number = run_num
                self._run_file_path = file_path
                self._fext = main_fext
                self._ws_name = self._build_ws_name(new_value)
            if new_value is False:
                self._run_list.del_cashed_sum()

    def _load_and_sum_runs(self,inst_name,monitors_with_ws):
        """Load multiple runs and sum them together
           monitors_with_ws -- if true, load monitors with workspace

        RunDescriptor._logger("*** Summing multiple runs            ****")

        runs_to_sum,sum_ws,n_already_summed = self.get_runs_to_sum()
        num_to_sum = len(runs_to_sum)

        if sum_ws:
            RunDescriptor._logger("*** Use cached sum of {0} workspaces and adding {1} remaining".\
                          format(n_already_summed,num_to_sum))
            sum_ws_name = sum_ws.name()
            sum_mon_name = sum_ws_name + '_monitors'
            AddedRunNumbers = sum_ws.getRun().getLogData(RunDescriptor._sum_log_name).value
            load_start = 0
        else:
            RunDescriptor._logger("*** Loading #{0}/{1}, run N: {2} ".\
                   format(1,num_to_sum,runs_to_sum[0]))
            f_guess,index = self._run_list.get_file_guess(inst_name,runs_to_sum[0])
            ws = self.load_file(inst_name,'Sum_ws',False,monitors_with_ws,
                                False,file_hint=f_guess)
            sum_ws_name = ws.name()
            sum_mon_name = sum_ws_name + '_monitors'
            #AddedRunNumbers = [ws.getRunNumber()]
            AddedRunNumbers = str(ws.getRunNumber())
            load_start = 1
        for ind,run_num in enumerate(runs_to_sum[load_start:num_to_sum]):
            RunDescriptor._logger("*** Adding  #{0}/{1}, run N: {2} ".\
                          format(ind + 1 + load_start,num_to_sum,run_num))
            term_name = '{0}_ADDITIVE_#{1}/{2}'.format(inst_name,ind + 1 + load_start,num_to_sum)#
            f_guess,index = self._run_list.get_file_guess(inst_name,run_num)
            wsp = self.load_file(inst_name,term_name,False,
                                monitors_with_ws,False,file_hint=f_guess)

            wsp_name = wsp.name()
            wsp_mon_name = wsp_name + '_monitors'
            Plus(LHSWorkspace=sum_ws_name,RHSWorkspace=wsp_name,
                OutputWorkspace=sum_ws_name,ClearRHSWorkspace=True)
            #  AddedRunNumbers.append(run_num)
            AddedRunNumbers+=',' + str(run_num)
            if not monitors_with_ws:
                Plus(LHSWorkspace=sum_mon_name,RHSWorkspace=wsp_mon_name,
                     OutputWorkspace=sum_mon_name,ClearRHSWorkspace=True)
            if wsp_name in mtd:
                DeleteWorkspace(wsp_name)
            if wsp_mon_name in mtd:
                DeleteWorkspace(wsp_mon_name)
        RunDescriptor._logger("*** Summing multiple runs  completed ****")

        #AddSampleLog(Workspace=sum_ws_name,LogName =
        #RunDescriptor._sum_log_name,
        #             LogText=AddedRunNumbers,LogType='Number Series')
        AddSampleLog(Workspace=sum_ws_name,LogName = RunDescriptor._sum_log_name,
                    LogText=AddedRunNumbers,LogType='String')

        if RunDescriptor._holder.cashe_sum_ws:
            # store workspace in cash for further usage
            self._run_list.set_cashed_sum_ws(mtd[sum_ws_name],self._prop_name + 'Sum_ws')
            ws = self._run_list.get_cashed_sum_clone()
        else:
            ws = mtd[sum_ws_name]
#-------------------------------------------------------------------------------------------------------------------------------
#-------------------------------------------------------------------------------------------------------------------------------
#-------------------------------------------------------------------------------------------------------------------------------
class RunDescriptorDependent(RunDescriptor):
    """Simple RunDescriptor class dependent on another RunDescriptor,
       providing the host descriptor if current descriptor value is not defined
       or usual descriptor functionality if somebody sets current descriptor up
    def __init__(self,host_run,ws_preffix,DocString=None):
        RunDescriptor.__init__(self,ws_preffix,DocString)
        self._host = host_run
        self._has_own_value = False
    def __get__(self,instance,owner=None):
        """Return dependent run number which is host run number if this one has not been set
          or this run number if it was
        """
        if instance is None: # this class functions and the host functions
            return self

        if self._has_own_value: # this allows to switch between
            return super(RunDescriptorDependent,self).__get__(instance,owner)
        else:
            return self._host.__get__(instance,owner)
    def __set__(self,instance,value):
        if value is None:
            self._has_own_value = False
            return
        self._has_own_value = True
        super(RunDescriptorDependent,self).__set__(instance,value)
        """Interface property used to verify if
           the class got its own values or been shadowed by
           property, this one depends on
        return self._has_own_value
    #--------------------------------------------------------------
    # TODO -- how to automate all these functions below?
    def run_number(self):
        if self._has_own_value:
            return super(RunDescriptorDependent,self).run_number()
            return self._host.run_number()
    #
    def is_monws_separate(self):
        if self._has_own_value:
            return super(RunDescriptorDependent,self).is_monws_separate()
        else:
            return self._host.is_monws_separate()

    def get_run_files_list(self):
        if self._has_own_value:
            return super(RunDescriptorDependent,self).get_run_files_list()
            return self._host.get_run_files_list()

    def get_run_list(self):
        if self._has_own_value:
            return super(RunDescriptorDependent,self).get_run_list()
        else:
            return self._host.get_run_list()

    def set_action_suffix(self,suffix=None):
        if self._has_own_value:
            return super(RunDescriptorDependent,self).set_action_suffix(suffix)
        else:
            return self._host.set_action_suffix(suffix)

    def synchronize_ws(self,workspace=None):
        if self._has_own_value:
            return super(RunDescriptorDependent,self).synchronize_ws(workspace)
        else:
            return self._host.synchronize_ws(workspace)

        if self._has_own_value:
            return super(RunDescriptorDependent,self).get_fext()

    def set_file_ext(self,val):
        if self._has_own_value:
            return super(RunDescriptorDependent,self).set_file_ex(val)
        else:
            return self._host.set_file_ex(val)

    def get_workspace(self):
        if self._has_own_value:
            return super(RunDescriptorDependent,self).get_workspace()
        else:
            return self._host.get_workspace()

    def get_ws_clone(self,clone_name='ws_clone'):
        if self._has_own_value:
            return super(RunDescriptorDependent,self).get_ws_clone()
        else:
            return self._host.get_ws_clone()

    def chop_ws_part(self,origin,tof_range,rebin,chunk_num,n_chunks):
        if self._has_own_value:
            return super(RunDescriptorDependent,self).chop_ws_part(origin,tof_range,rebin,chunk_num,n_chunks)
        else:
            return self._host.chop_ws_part(origin,tof_range,rebin,chunk_num,n_chunks)

    def get_monitors_ws(self,monitor_ID=None):
        if self._has_own_value:
            return super(RunDescriptorDependent,self).get_monitors_ws(monitor_ID)
        else:
            return self._host.get_monitors_ws(monitor_ID)

    def is_existing_ws(self):
        if self._has_own_value:
            return super(RunDescriptorDependent,self).is_existing_ws()
        else:
            return self._host.is_existing_ws()
    def file_hint(self,run_num_str=None,filePath=None,fileExt=None,**kwargs):
        if self._has_own_value:
            return super(RunDescriptorDependent,self).file_hint(run_num_str,filePath,fileExt,**kwargs)
        else:
            return self._host.file_hint(run_num_str,filePath,fileExt,**kwargs)

    def find_file(self,inst_name=None,run_num=None,filePath=None,fileExt=None,**kwargs):
        if self._has_own_value:
            return super(RunDescriptorDependent,self).find_file(inst_name,run_num,filePath,fileExt,**kwargs)
        else:
            return self._host.find_file(inst_name,run_num,filePath,fileExt,**kwargs)

    def load_file(self,inst_name,ws_name,run_number=None,load_mon_with_workspace=False,filePath=None,fileExt=None,**kwargs):
        if self._has_own_value:
            return super(RunDescriptorDependent,self).load_file(inst_name,ws_name,run_number,load_mon_with_workspace,filePath,fileExt,**kwargs)
        else:
            return self._host.load_file(inst_name,ws_name,run_number,load_mon_with_workspace,filePath,fileExt,**kwargs)

    def load_run(self,inst_name, calibration=None, force=False, mon_load_option=False,use_ws_calibration=True,\
                 filePath=None,fileExt=None,**kwargs):
        if self._has_own_value:
            return super(RunDescriptorDependent,self).load_run(inst_name,calibration, force, mon_load_option,use_ws_calibration,\
                 filePath,fileExt,**kwargs)
        else:
            return self._host.load_run(inst_name,calibration, force, mon_load_option,use_ws_calibration,\
                               filePath,fileExt,**kwargs)

    def apply_calibration(self,loaded_ws,calibration=None,use_ws_calibration=True):
        if self._has_own_value:
            return super(RunDescriptorDependent,self).apply_calibration(loaded_ws,calibration,use_ws_calibration)
        else:
            return self._host.apply_calibration(loaded_ws,calibration,use_ws_calibration)

    def clear_monitors(self):
        if self._has_own_value:
            return super(RunDescriptorDependent,self).clear_monitors()
        else:
            return self._host.clear_monitors()
    def get_masking(self,noutputs=None):
        if self._has_own_value:
            return super(RunDescriptorDependent,self).get_masking(noutputs)
            return self._host.get_masking(noutputs)
    def add_masked_ws(self,masked_ws):
        if self._has_own_value:
            return super(RunDescriptorDependent,self).add_masked_ws(masked_ws)
            return self._host.add_masked_ws(masked_ws)
#--------------------------------------------------------------------------------------------------------------------
#--------------------------------------------------------------------------------------------------------------------
def build_run_file_name(run_num,inst,file_path='',fext=''):
    """Build the full name of a runfile from all possible components"""
    if fext is None:
        fext = ''
    #HACK: current ISIS File format consist of 5 digit. It is defined somewhere in Mantid
    # but redefined here. Should pick things up from MANTID
    fname = '{0}{1:0>5}{2}'.format(inst,run_num,fext)
    if not file_path is None:
        if os.path.exists(file_path):
            fname = os.path.join(file_path,fname)
    return fname