def _sumForegroundInLambda(self, ws):
     """Sum the foreground region into a single histogram."""
     foreground = self._foregroundIndices(ws)
     sumIndices = [i for i in range(foreground[0], foreground[2] + 1)]
     beamPosIndex = foreground[1]
     foregroundWSName = self._names.withSuffix('foreground_grouped')
     foregroundWS = ExtractSingleSpectrum(InputWorkspace=ws,
                                          OutputWorkspace=foregroundWSName,
                                          WorkspaceIndex=beamPosIndex,
                                          EnableLogging=self._subalgLogging)
     maxIndex = ws.getNumberHistograms() - 1
     foregroundYs = foregroundWS.dataY(0)
     foregroundEs = foregroundWS.dataE(0)
     numpy.square(foregroundEs, out=foregroundEs)
     for i in sumIndices:
         if i == beamPosIndex:
             continue
         if i < 0 or i > maxIndex:
             self.log().warning(
                 'Foreground partially out of the workspace.')
         ys = ws.readY(i)
         foregroundYs += ys
         es = ws.readE(i)
         foregroundEs += es**2
     numpy.sqrt(foregroundEs, out=foregroundEs)
     self._cleanup.cleanup(ws)
     AddSampleLog(Workspace=foregroundWS,
                  LogName=common.SampleLogs.SUM_TYPE,
                  LogText=SumType.IN_LAMBDA,
                  LogType='String',
                  EnableLogging=self._subalgLogging)
     ConvertToDistribution(Workspace=foregroundWS,
                           EnableLogging=self._subalgLogging)
     return foregroundWS
Ejemplo n.º 2
0
def _compute_caad(fit_workspaces):
    indices = _get_caad_indices(fit_workspaces[0])
    normalised_workspaces = [
        _normalise_by_integral(_extract_spectra(workspace, indices))
        for workspace in fit_workspaces
    ]

    number_of_spectrum = normalised_workspaces[0].getNumberHistograms()
    normalised_workspaces = [[
        ExtractSingleSpectrum(InputWorkspace=workspace,
                              OutputWorkspace="__extracted",
                              WorkspaceIndex=index,
                              StoreInADS=False,
                              EnableLogging=True)
        for workspace in normalised_workspaces
    ] for index in range(number_of_spectrum)]
    normalised_workspaces = [
        _append_all(workspaces) for workspaces in normalised_workspaces
    ]

    summed_workspaces = [
        SumSpectra(InputWorkspace=workspace,
                   OutputWorkspace="__summed",
                   StoreInADS=False,
                   EnableLogging=False) for workspace in normalised_workspaces
    ]
    return normalised_workspaces, summed_workspaces, indices
Ejemplo n.º 3
0
 def monitorTransfit(self, files, foilType, divE):
     isFirstFile = True
     isSingleFile = len(files) == 1
     firstFileName = ""
     for file in files:
         discard, fileName = path.split(file)
         fnNoExt = path.splitext(fileName)[0]
         if isFirstFile:
             firstFileName = fnNoExt
         fileName_Raw = fnNoExt + '_raw'
         fileName_3 = fnNoExt + '_3'
         LoadRaw(Filename=file, OutputWorkspace=fileName_Raw)
         CropWorkspace(InputWorkspace=fileName_Raw, OutputWorkspace=fileName_Raw, XMin=100, XMax=19990)
         NormaliseByCurrent(InputWorkspace=fileName_Raw, OutputWorkspace=fileName_Raw)
         ExtractSingleSpectrum(InputWorkspace=fileName_Raw, OutputWorkspace=fileName_3, WorkspaceIndex=3)
         DeleteWorkspace(fileName_Raw)
         ConvertUnits(InputWorkspace=fileName_3, Target='Energy', OutputWorkspace=fileName_3)
         self.TransfitRebin(fileName_3, fileName_3, foilType, divE)
         if not isFirstFile:
             Plus(LHSWorkspace=firstFileName + '_3', RHSWorkspace=fileName_3, OutputWorkspace=firstFileName + '_3')
             DeleteWorkspace(fileName_3)
         else:
             isFirstFile = False
     if isSingleFile:
         RenameWorkspace(InputWorkspace=firstFileName + '_3', OutputWorkspace=firstFileName + '_monitor')
     else:
         noFiles = len(files) ** (-1)
         CreateSingleValuedWorkspace(OutputWorkspace='scale', DataValue=noFiles)
         Multiply(LHSWorkspace=firstFileName + '_3', RHSWorkspace='scale',
                  OutputWorkspace=firstFileName + '_monitor')
         DeleteWorkspace('scale')
         DeleteWorkspace(firstFileName + '_3')
Ejemplo n.º 4
0
def crop_workspaces(workspace_names, spec_min, spec_max, extract_monitors=True, monitor_index=0):
    """
    Crops the workspaces with the specified workspace names, from the specified minimum
    spectra to the specified maximum spectra.

    :param workspace_names:     The names of the workspaces to crop
    :param spec_min:            The minimum spectra of the cropping region
    :param spec_max:            The maximum spectra of the cropping region
    :param extract_monitors:    If True, extracts monitors from the workspaces
    :param monitor_index:       The index of the monitors in the workspaces
    """
    from mantid.simpleapi import ExtractSingleSpectrum, CropWorkspace

    for workspace_name in workspace_names:

        if extract_monitors:
            # Get the monitor spectrum
            monitor_ws_name = workspace_name + '_mon'
            ExtractSingleSpectrum(InputWorkspace=workspace_name,
                                  OutputWorkspace=monitor_ws_name,
                                  WorkspaceIndex=monitor_index)

        # Crop to the detectors required
        workspace = mtd[workspace_name]

        CropWorkspace(InputWorkspace=workspace_name,
                      OutputWorkspace=workspace_name,
                      StartWorkspaceIndex=workspace.getIndexFromSpectrumNumber(int(spec_min)),
                      EndWorkspaceIndex=workspace.getIndexFromSpectrumNumber(int(spec_max)))
Ejemplo n.º 5
0
    def PyExec(self):
        # get parameter values
        wsString = self.getPropertyValue("InputWorkspace").strip()
        #internal values
        wsOutput = "__OutputWorkspace"
        wsTemp = "__Sort_temp"
        #get the workspace list
        wsNames = []
        for wsName in wsString.split(","):
            ws = mtd[wsName.strip()]
            if type(ws) == WorkspaceGroup:
                wsNames.extend(ws.getNames())
            else:
                wsNames.append(wsName)

        if wsOutput in mtd:
            DeleteWorkspace(Workspace=wsOutput)
        sortStat = []
        for wsName in wsNames:
            if "qvectors" in wsName:
                #extract the spectrum
                ws = mtd[wsName.strip()]
                for s in range(0, ws.getNumberHistograms()):
                    y_s = ws.readY(s)
                    tuple = (self.GetXValue(y_s), s)
                    sortStat.append(tuple)
                sortStat.sort()
        if len(sortStat) == 0:
            raise RuntimeError("Cannot find file with qvectors, aborting")
        #sort spectra using norm of q
        for wsName in wsNames:
            ws = mtd[wsName.strip()]
            yUnit = ws.getAxis(1).getUnit().unitID()
            transposed = False
            if ws.getNumberHistograms() < len(sortStat):
                Transpose(InputWorkspace=wsName, OutputWorkspace=wsName)
                transposed = True
            for norm, spec in sortStat:
                ExtractSingleSpectrum(InputWorkspace=wsName, OutputWorkspace=wsTemp, WorkspaceIndex=spec)
                if wsOutput in mtd:
                    ConjoinWorkspaces(InputWorkspace1=wsOutput,InputWorkspace2=wsTemp,CheckOverlapping=False)
                    if wsTemp in mtd:
                        DeleteWorkspace(Workspace=wsTemp)
                else:
                    RenameWorkspace(InputWorkspace=wsTemp, OutputWorkspace=wsOutput)

            #put norm as y value and copy units from input
            loopIndex = 0
            wsOut = mtd[wsOutput]
            for norm, spec in sortStat:
                wsOut.getSpectrum(loopIndex).setSpectrumNo(int(norm*1000))
                loopIndex = loopIndex + 1
            if len(yUnit) > 0:
                wsOut.getAxis(1).setUnit(yUnit)
            if transposed:
                Transpose(InputWorkspace=wsOutput, OutputWorkspace=wsOutput)
            RenameWorkspace(InputWorkspace=wsOutput, OutputWorkspace=wsName)
Ejemplo n.º 6
0
 def _sumForegroundInLambda(self, ws):
     """Sum the foreground region into a single histogram."""
     foreground = self._foregroundIndices(ws)
     sumIndices = [i for i in range(foreground[0], foreground[2] + 1)]
     beamPosIndex = foreground[1]
     foregroundWSName = self._names.withSuffix('foreground_grouped')
     foregroundWS = ExtractSingleSpectrum(
         InputWorkspace=ws,
         OutputWorkspace=foregroundWSName,
         WorkspaceIndex=beamPosIndex,
         EnableLogging=self._subalgLogging)
     maxIndex = ws.getNumberHistograms() - 1
     foregroundYs = foregroundWS.dataY(0)
     foregroundEs = foregroundWS.dataE(0)
     numpy.square(foregroundEs, out=foregroundEs)
     for i in sumIndices:
         if i == beamPosIndex:
             continue
         if i < 0 or i > maxIndex:
             self.log().warning('Foreground partially out of the workspace.')
         addeeWSName = self._names.withSuffix('foreground_addee')
         addeeWS = ExtractSingleSpectrum(
             InputWorkspace=ws,
             OutputWorkspace=addeeWSName,
             WorkspaceIndex=i,
             EnableLogging=self._subalgLogging)
         addeeWS = RebinToWorkspace(
             WorkspaceToRebin=addeeWS,
             WorkspaceToMatch=foregroundWS,
             OutputWorkspace=addeeWSName,
             EnableLogging=self._subalgLogging)
         ys = addeeWS.readY(0)
         foregroundYs += ys
         es = addeeWS.readE(0)
         foregroundEs += es**2
         self._cleanup.cleanup(addeeWS)
     self._cleanup.cleanup(ws)
     numpy.sqrt(foregroundEs, out=foregroundEs)
     return foregroundWS
Ejemplo n.º 7
0
def int3samples(runs, name, masks, binning='0.5, 0.05, 8.0'):
    """
    Finds the polarisation versus wavelength for a set of detector tubes.

    Parameters
    ----------
    runs: list of RunData objects
      The runs whose polarisation we are interested in.

    name: string
      The name of this set of runs

    masks: list of string
      The file names of the masks for the sequential tubes that are being used
      for the SEMSANS measurements.

    binning: string
      The binning values to use for the wavelength bins.  The default value is
      '0.5, 0.025, 10.0'
    """
    for tube, _ in enumerate(masks):
        for i in [1, 2]:
            final_state = "{}_{}_{}".format(name, tube, i)
            if final_state in mtd.getObjectNames():
                DeleteWorkspace(final_state)

    for rnum in runs:
        w1 = Load(BASE.format(rnum.number), LoadMonitors=True)
        w1mon = ExtractSingleSpectrum('w1_monitors', 0)
        w1 = ConvertUnits('w1', 'Wavelength', AlignBins=1)
        w1mon = ConvertUnits(w1mon, 'Wavelength')
        w1 = Rebin(w1, binning, PreserveEvents=False)
        w1mon = Rebin(w1mon, binning)
        w1 = w1 / w1mon
        for tube, mask in enumerate(masks):
            Mask_Tube = LoadMask('LARMOR', mask)
            w1temp = CloneWorkspace(w1)
            MaskDetectors(w1temp, MaskedWorkspace="Mask_Tube")
            Tube_Sum = SumSpectra(w1temp)
            for i in [1, 2]:
                final_state = "{}_{}_{}".format(name, tube, i)
                if final_state in mtd.getObjectNames():
                    mtd[final_state] += mtd["Tube_Sum_{}".format(i)]
                else:
                    mtd[final_state] = mtd["Tube_Sum_{}".format(i)]

    x = mtd["{}_0_1".format(name)].extractX()[0]
    dx = (x[1:] + x[:-1]) / 2
    pols = []

    for run in runs:
        he_stat = he3_stats(run)
        start = (run.start - he_stat.dt).seconds / 3600 / he_stat.t1
        end = (run.end - he_stat.dt).seconds / 3600 / he_stat.t1
        for time in np.linspace(start, end, 10):
            temp = he3pol(he_stat.scale, time)(dx)
            pols.append(temp)
    wpol = CreateWorkspace(
        x,
        np.mean(pols, axis=0),
        # and the blank
        UnitX="Wavelength",
        YUnitLabel="Counts")

    for tube, _ in enumerate(masks):
        up = mtd["{}_{}_2".format(name, tube)]
        dn = mtd["{}_{}_1".format(name, tube)]
        pol = (up - dn) / (up + dn)
        pol /= wpol
        DeleteWorkspaces(
            ["{}_{}_{}".format(name, tube, i) for i in range(1, 3)])
        RenameWorkspace("pol", OutputWorkspace="{}_{}".format(name, tube))
    DeleteWorkspaces(["Tube_Sum_1", "Tube_Sum_2"])

    GroupWorkspaces([
        "{}_{}".format(name, tube) for tube, _ in enumerate(masks)
        for i in range(1, 3)
    ],
                    OutputWorkspace=str(name))
Ejemplo n.º 8
0
        WorkspaceIndex=id_slice,
        StartX=start,
        EndX=end,
        Output="{0}{1}".format(out_root, id_slice),
        CreateOutput=True)
    for key in ("Workspace", "Parameters", "NormalisedCovarianceMatrix"):
        workspaces_to_group.append("{0}{1}_{2}".format(out_root, id_slice,
                                                       key))
    # Update the model string. We take the current optimized model
    # as the initial guess for fitting of the next slice.
    parameters_workspace = mtd["{0}{1}_Parameters".format(out_root, id_slice)]
    model_string = update_model(model_string, parameters_workspace)
    # Calculate the PDF of the residuals, which is the slice without
    # the model background
    fits_workspace = mtd["{0}{1}_Workspace".format(out_root, id_slice)]
    residuals = ExtractSingleSpectrum(fits_workspace, 2)
    sqe = CloneWorkspace(residuals, OutputWorkspace=out_sqe)\
        if not sqe else append_spectrum(residuals, sqe)
    single_gre = PDFFourierTransform(InputWorkspace=residuals,
                                     InputSofQType="S(Q)-1",
                                     Qmin=start,
                                     Qmax=end,
                                     PDFType="G(r)",
                                     DeltaR=gre_options["DeltaR"],
                                     Rmax=gre_options["Rmax"])
    gre = CloneWorkspace(single_gre, OutputWorkspace=out_gre)\
        if not gre else append_spectrum(single_gre, gre)
    id_slice += jump

# Group all the fit workspaces
GroupWorkspaces(InputWorkspaces=",".join(workspaces_to_group),
def load_files(data_files, ipf_filename, spec_min, spec_max, sum_files=False, load_logs=True, load_opts=None):
    """
    Loads a set of files and extracts just the spectra we care about (i.e. detector range and monitor).

    @param data_files List of data file names
    @param ipf_filename File path/name for the instrument parameter file to load
    @param spec_min Minimum spectra ID to load
    @param spec_max Maximum spectra ID to load
    @param sum_files Sum loaded files
    @param load_logs Load log files when loading runs
    @param load_opts Additional options to be passed to load algorithm

    @return List of loaded workspace names and flag indicating chopped data
    """
    from mantid.simpleapi import (Load, LoadVesuvio, LoadParameterFile,
                                  ChopData, ExtractSingleSpectrum,
                                  CropWorkspace)

    if load_opts is None:
        load_opts = {}

    workspace_names = []

    for filename in data_files:
        # The filename without path and extension will be the workspace name
        ws_name = os.path.splitext(os.path.basename(str(filename)))[0]
        logger.debug('Loading file %s as workspace %s' % (filename, ws_name))

        if 'VESUVIO' in ipf_filename:
            # Load all spectra. They are cropped later
            LoadVesuvio(Filename=str(filename),
                        OutputWorkspace=ws_name,
                        SpectrumList='1-198',
                        **load_opts)
        else:
            Load(Filename=filename,
                 OutputWorkspace=ws_name,
                 LoadLogFiles=load_logs,
                 **load_opts)

        # Load the instrument parameters
        LoadParameterFile(Workspace=ws_name,
                          Filename=ipf_filename)

        # Add the workspace to the list of workspaces
        workspace_names.append(ws_name)

        # Get the spectrum number for the monitor
        instrument = mtd[ws_name].getInstrument()
        monitor_index = int(instrument.getNumberParameter('Workflow.Monitor1-SpectrumNumber')[0])
        logger.debug('Workspace %s monitor 1 spectrum number :%d' % (ws_name, monitor_index))

        # Chop data if required
        try:
            chop_threshold = mtd[ws_name].getInstrument().getNumberParameter('Workflow.ChopDataIfGreaterThan')[0]
            x_max = mtd[ws_name].readX(0)[-1]
            chopped_data = x_max > chop_threshold
        except IndexError:
            chopped_data = False
        logger.information('Workspace {0} need data chop: {1}'.format(ws_name, str(chopped_data)))

        workspaces = [ws_name]
        if chopped_data:
            ChopData(InputWorkspace=ws_name,
                     OutputWorkspace=ws_name,
                     MonitorWorkspaceIndex=monitor_index,
                     IntegrationRangeLower=5000.0,
                     IntegrationRangeUpper=10000.0,
                     NChops=5)
            workspaces = mtd[ws_name].getNames()

        for chop_ws_name in workspaces:
            # Get the monitor spectrum
            monitor_ws_name = chop_ws_name + '_mon'
            ExtractSingleSpectrum(InputWorkspace=chop_ws_name,
                                  OutputWorkspace=monitor_ws_name,
                                  WorkspaceIndex=monitor_index)

            # Crop to the detectors required
            chop_ws = mtd[chop_ws_name]
            CropWorkspace(InputWorkspace=chop_ws_name,
                          OutputWorkspace=chop_ws_name,
                          StartWorkspaceIndex=chop_ws.getIndexFromSpectrumNumber(int(spec_min)),
                          EndWorkspaceIndex=chop_ws.getIndexFromSpectrumNumber(int(spec_max)))

    logger.information('Loaded workspace names: %s' % (str(workspace_names)))
    logger.information('Chopped data: %s' % (str(chopped_data)))

    # Sum files if needed
    if sum_files and len(data_files) > 1:
        if chopped_data:
            workspace_names = sum_chopped_runs(workspace_names)
        else:
            workspace_names = sum_regular_runs(workspace_names)

    logger.information('Summed workspace names: %s' % (str(workspace_names)))

    return workspace_names, chopped_data
Ejemplo n.º 10
0
    def _sumForegroundInLambda(self, ws):
        """Sum the foreground region into a single histogram."""
        foreground = self._foregroundIndices(ws)
        sumIndices = [i for i in range(foreground[0], foreground[2] + 1)]
        beamPosIndex = foreground[1]
        foregroundWSName = self._names.withSuffix('grouped')
        foregroundWS = ExtractSingleSpectrum(InputWorkspace=ws,
                                             OutputWorkspace=foregroundWSName,
                                             WorkspaceIndex=beamPosIndex,
                                             EnableLogging=self._subalgLogging)
        maxIndex = ws.getNumberHistograms() - 1
        foregroundYs = foregroundWS.dataY(0)
        foregroundEs = foregroundWS.dataE(0)
        numpy.square(foregroundEs, out=foregroundEs)
        for i in sumIndices:
            if i == beamPosIndex:
                continue
            if i < 0 or i > maxIndex:
                self.log().warning(
                    'Foreground partially out of the workspace.')
            addeeWSName = self._names.withSuffix('addee')
            addeeWS = ExtractSingleSpectrum(InputWorkspace=ws,
                                            OutputWorkspace=addeeWSName,
                                            WorkspaceIndex=i,
                                            EnableLogging=self._subalgLogging)
            addeeWS = RebinToWorkspace(WorkspaceToRebin=addeeWS,
                                       WorkspaceToMatch=foregroundWS,
                                       OutputWorkspace=addeeWSName,
                                       EnableLogging=self._subalgLogging)
            ys = addeeWS.readY(0)
            foregroundYs += ys
            es = addeeWS.readE(0)
            foregroundEs += es**2
            self._cleanup.cleanup(addeeWS)
        self._cleanup.cleanup(ws)
        numpy.sqrt(foregroundEs, out=foregroundEs)
        # Move the detector to the fractional linePosition
        linePosition = ws.run().getProperty(
            common.SampleLogs.LINE_POSITION).value
        instr = common.instrumentName(ws)
        pixelSize = common.pixelSize(instr)
        dist = pixelSize * (linePosition - beamPosIndex)

        if dist != 0.:
            detPoint1 = ws.spectrumInfo().position(0)
            detPoint2 = ws.spectrumInfo().position(20)
            beta = numpy.math.atan2((detPoint2[0] - detPoint1[0]),
                                    (detPoint2[2] - detPoint1[2]))
            xvsy = numpy.math.sin(beta) * dist
            mz = numpy.math.cos(beta) * dist
            if instr == 'D17':
                mx = xvsy
                my = 0.0
                rotationAxis = [0, 1, 0]
            else:
                mx = 0.0
                my = xvsy
                rotationAxis = [-1, 0, 0]
            MoveInstrumentComponent(Workspace=foregroundWS,
                                    ComponentName='detector',
                                    X=mx,
                                    Y=my,
                                    Z=mz,
                                    RelativePosition=True)
            theta = foregroundWS.spectrumInfo().twoTheta(0) / 2.
            RotateInstrumentComponent(Workspace=foregroundWS,
                                      ComponentName='detector',
                                      X=rotationAxis[0],
                                      Y=rotationAxis[1],
                                      Z=rotationAxis[2],
                                      Angle=theta,
                                      RelativeRotation=True)
        return foregroundWS
Ejemplo n.º 11
0
def calculate_ei(input_file):
    # Auto Find Eis by finding maximum data point in m2 (excluding end points)
    # and looking for neighbouring reps according to Fermi speed
    # Doesn't deal with cases where the peaks enter the 2nd frame (i.e 2 meV on MARI)
    print(input_file)
    w1 = Load(input_file)
    mon = LoadNexusMonitors(input_file)
    run = w1.getRun()

    # set up ==================================================
    monitor_spectra_2  = 41475
    monitor_spectra_3  = 41476
    monitor_index_2 = 2
    monitor_index_3 = 3
    log  = 'Fermi_Speed'

    # Get instrument parameters ===============================
    inst = w1.getInstrument()
    source = inst.getSource()
    L_m2 = mon.getDetector(monitor_index_2).getDistance(source)
    L_m3 = mon.getDetector(monitor_index_3).getDistance(source)
    L_Fermi = inst.getComponentByName("chopper-position").getDistance(source)
    freq = run.getLogData(log).value[-1]
    period = L_m2 / L_Fermi * 1.e6 / freq / 2. # include pi-pulses

    # Find maximum value and identify strongest rep ===========
    m2spec = ExtractSingleSpectrum(mon,monitor_index_2)
    m2spec = Rebin(m2spec,"200,2,18000")
    maxm2 = Max(m2spec)
    TOF = maxm2.readX(0)[0]

    # Generate list of possible reps in m2 ====================
    irep = -5
    while True:
        t = TOF + irep*period
        if t > 0:
            ireps = numpy.array(range(irep,irep+20))
            reps = TOF + period * ireps
            break
        else:
            irep += 1

    # exclude all reps that go past the frame in m3 ===========       
    reps_m3 = reps * L_m3 / L_m2
    reps_m3 = [x for x in reps_m3 if x < 19999.]
    reps = reps[0:len(reps_m3)]
    # exclude all reps at short times
    reps = [x for x in reps if x > 200.]

    # try GetEi for the reps ==================================
    Ei = []
    TOF = []
    for t in reps:
        v_i = L_m2 / t                    # m/mus
        Ei_guess = 5.227e6 * v_i**2       # meV
        try:
            (En,TOF2,dummy,tzero) = GetEi(mon, monitor_spectra_2, monitor_spectra_3, Ei_guess)
        except:
            continue
        if abs(t - TOF2) > 20. or abs(tzero) > 100.: continue
        Ei.append(Ei_guess)
        TOF.append(TOF2)

    #=========================================================
    for ii in range(len(Ei)):
        print("%f meV at TOF = %f mus" % (Ei[ii],TOF[ii]))
    return Ei
Ejemplo n.º 12
0
class VesuvioCorrections(VesuvioBase):

    _input_ws = None
    _output_ws = None
    _correction_workspaces = None
    _linear_fit_table = None

#------------------------------------------------------------------------------

    def summary(self):
        return "Apply post fitting steps to vesuvio data"

#------------------------------------------------------------------------------

    def PyInit(self):
        # Inputs
        self.declareProperty(MatrixWorkspaceProperty("InputWorkspace", "", direction=Direction.Input),
                             doc="Input TOF workspace")

        self.declareProperty("WorkspaceIndex", 0,
                             doc="Index of spectrum to calculate corrections for")

        self.declareProperty(ITableWorkspaceProperty("FitParameters", "", direction=Direction.Input,
                                                     optional=PropertyMode.Optional),
                             doc="Table containing the calculated fit parameters for the data in the workspace")

        float_length_validator = FloatArrayLengthValidator()
        float_length_validator.setLengthMin(1)
        self.declareProperty(FloatArrayProperty("Masses", float_length_validator),
                             doc="Mass values for fitting")

        self.declareProperty("MassProfiles", "", StringMandatoryValidator(),
                             doc="Functions used to approximate mass profile. "
                                 "The format is function=Function1Name,param1=val1,param2=val2;function=Function2Name,param3=val3,param4=val4")

        self.declareProperty("IntensityConstraints", "",
                             doc="A semi-colon separated list of intensity constraints defined as lists e.g "
                                 "[0,1,0,-4];[1,0,-2,0]")

        # Container
        self.declareProperty(MatrixWorkspaceProperty("ContainerWorkspace", "", direction=Direction.Input,
                                                     optional=PropertyMode.Optional),
                             doc="Container workspace in TOF")

        self.declareProperty("ContainerScale", 0.0,
                             doc="Scale factor to apply to container, set to 0 for automatic scale based on linear fit")

        # Gamma background
        self.declareProperty("GammaBackground", True, direction=Direction.Input,
                             doc="If true, correct for the gamma background")

        self.declareProperty("GammaBackgroundScale", 0.0,
                             doc="Scale factor to apply to gamma background, set to 0 for automatic scale based on linear fit")

        # Multiple scattering
        self.declareProperty("MultipleScattering", True, direction=Direction.Input,
                             doc="If true, correct for the effects of multiple scattering")

        self.declareProperty("BeamRadius", 2.5,
                             doc="Radius of beam in cm")

        self.declareProperty("SampleHeight", 5.0,
                             doc="Height of sample in cm")

        self.declareProperty("SampleWidth", 5.0,
                             doc="Width of sample in cm")

        self.declareProperty("SampleDepth", 5.0,
                             doc="Depth of sample in cm")

        self.declareProperty("SampleDensity", 1.0,
                             doc="Sample density in g/cm^3")

        self.declareProperty("Seed", 123456789,
                             doc="")

        self.declareProperty("NumScatters", 3,
                             doc="")

        self.declareProperty("NumRuns", 10,
                             doc="")

        self.declareProperty("NumEvents", 50000,
                             doc="Number of neutron events")

        self.declareProperty("SmoothNeighbours", 3,
                             doc="")

        # Outputs
        self.declareProperty(WorkspaceGroupProperty("CorrectionWorkspaces", "",
                                                    direction=Direction.Output,
                                                    optional=PropertyMode.Optional),
                             doc="Workspace group containing correction intensities for each correction")

        self.declareProperty(WorkspaceGroupProperty("CorrectedWorkspaces", "",
                                                    direction=Direction.Output,
                                                    optional=PropertyMode.Optional),
                             doc="Workspace group containing individual corrections applied to raw data")

        self.declareProperty(ITableWorkspaceProperty("LinearFitResult", "",
                                                     direction=Direction.Output,
                                                     optional=PropertyMode.Optional),
                             doc="Table workspace containing the fit parameters used to"
                                 "linearly fit the corrections to the data")

        self.declareProperty(MatrixWorkspaceProperty("OutputWorkspace", "", direction=Direction.Output),
                             doc="The name of the output workspace")

#------------------------------------------------------------------------------

    def validateInputs(self):
        errors = dict()

        if self.getProperty("FitParameters").value is None:
            errors["FitParameters"] = "Corrections require a set of parameters from a fit of the data"

        return errors

#------------------------------------------------------------------------------

    def PyExec(self):
        from mantid.simpleapi import (ExtractSingleSpectrum, GroupWorkspaces,
                                      Scale, Minus, DeleteWorkspace)

        self._input_ws = self.getPropertyValue("InputWorkspace")
        container_ws = self.getPropertyValue("ContainerWorkspace")
        spec_idx = self.getProperty("WorkspaceIndex").value
        self._output_ws = self.getPropertyValue("OutputWorkspace")

        self._correction_wsg = self.getPropertyValue("CorrectionWorkspaces")
        self._corrected_wsg = self.getPropertyValue("CorrectedWorkspaces")
        self._linear_fit_table = self.getPropertyValue("LinearFitResult")

        ExtractSingleSpectrum(InputWorkspace=self._input_ws,
                              OutputWorkspace=self._output_ws,
                              WorkspaceIndex=spec_idx)

        self._correction_workspaces = list()

        self._container_ws = None
        if container_ws != "":
            container_name = str(self._correction_wsg) + "_Container"
            self._container_ws = ExtractSingleSpectrum(InputWorkspace=container_ws,
                                                       OutputWorkspace=container_name,
                                                       WorkspaceIndex=spec_idx)
            self._correction_workspaces.append(self._container_ws.name())

        # Do gamma correction
        if self.getProperty("GammaBackground").value:
            self._correction_workspaces.append(self._gamma_correction())

        # Do multiple scattering correction
        if self.getProperty("MultipleScattering").value:
            self._correction_workspaces.extend(self._ms_correction())

        # Output correction workspaces as a WorkspaceGroup
        if self._correction_wsg != "":
            GroupWorkspaces(InputWorkspaces=self._correction_workspaces,
                            OutputWorkspace=self._correction_wsg)
            self.setProperty("CorrectionWorkspaces", self._correction_wsg)

        # Perform fitting to obtain scale factors for corrections

        # The workspaces to fit for correction scale factors
        fit_corrections = [wks for wks in self._correction_workspaces if 'MultipleScattering' not in wks]

        # Perform fitting of corrections
        fixed_params = {}

        fixed_gamma_factor = self.getProperty("GammaBackgroundScale").value
        if fixed_gamma_factor != 0.0:
            fixed_params['GammaBackground'] = fixed_gamma_factor

        fixed_container_scale = self.getProperty("ContainerScale").value
        if fixed_container_scale != 0.0:
            fixed_params['Container'] = fixed_container_scale

        params_ws = self._fit_corrections(fit_corrections, self._linear_fit_table, **fixed_params)
        self.setProperty("LinearFitResult", params_ws)

        # Scale gamma background
        if self.getProperty("GammaBackground").value:
            gamma_correct_ws = self._get_correction_workspace('GammaBackground')[1]
            gamma_factor = self._get_correction_scale_factor('GammaBackground', fit_corrections, params_ws)
            Scale(InputWorkspace=gamma_correct_ws,
                  OutputWorkspace=gamma_correct_ws,
                  Factor=gamma_factor)

        # Scale multiple scattering
        if self.getProperty("MultipleScattering").value:
            # Use factor of total scattering as this includes single and multiple scattering
            multi_scatter_correct_ws = self._get_correction_workspace('MultipleScattering')[1]
            total_scatter_correct_ws = self._get_correction_workspace('TotalScattering')[1]
            total_scatter_factor = self._get_correction_scale_factor('TotalScattering', fit_corrections, params_ws)
            Scale(InputWorkspace=multi_scatter_correct_ws,
                  OutputWorkspace=multi_scatter_correct_ws,
                  Factor=total_scatter_factor)
            Scale(InputWorkspace=total_scatter_correct_ws,
                  OutputWorkspace=total_scatter_correct_ws,
                  Factor=total_scatter_factor)

        # Scale by container
        if container_ws != "":
            container_correct_ws = self._get_correction_workspace('Container')[1]
            container_factor = self._get_correction_scale_factor('Container', fit_corrections, params_ws)
            Scale(InputWorkspace=container_correct_ws,
                  OutputWorkspace=container_correct_ws,
                  Factor=container_factor)

        # Calculate and output corrected workspaces as a WorkspaceGroup
        if self._corrected_wsg != "":
            corrected_workspaces = [ws_name.replace(self._correction_wsg, self._corrected_wsg) for ws_name in self._correction_workspaces]
            for corrected, correction in zip(corrected_workspaces, self._correction_workspaces):
                Minus(LHSWorkspace=self._output_ws,
                      RHSWorkspace=correction,
                      OutputWorkspace=corrected)
            GroupWorkspaces(InputWorkspaces=corrected_workspaces,
                            OutputWorkspace=self._corrected_wsg)
            self.setProperty("CorrectedWorkspaces", self._corrected_wsg)

        # Apply corrections
        for correction in self. _correction_workspaces:
            if 'TotalScattering' not in correction:
                Minus(LHSWorkspace=self._output_ws,
                      RHSWorkspace=correction,
                      OutputWorkspace=self._output_ws)

        self.setProperty("OutputWorkspace", self._output_ws)

        # Remove correction workspaces if they are no longer required
        if self._correction_wsg == "":
            for wksp in self._correction_workspaces:
                DeleteWorkspace(wksp)

#------------------------------------------------------------------------------

    def _fit_corrections(self, fit_workspaces, param_table_name, **fixed_parameters):
        func_template = Template("name=TabulatedFunction,Workspace=$ws_name,ties=(${scale_tie}Shift=0,XScaling=1),constraints=(Scaling>=0.0)")
        functions = []

        for idx, wsn in enumerate(fit_workspaces):
            tie = ''
            for param, value in fixed_parameters.iteritems():
                if param in wsn:
                    tie = 'Scaling=%f,' % value

            functions.append(func_template.substitute(ws_name=wsn, scale_tie=tie))

            logger.notice('Corrections scale fit index %d is %s' % (idx, wsn))

        fit = AlgorithmManager.create("Fit")
        fit.initialize()
        fit.setChild(True)
        fit.setLogging(True)
        fit.setProperty("Function", ";".join(functions))
        fit.setProperty("InputWorkspace", self._input_ws)
        fit.setProperty("Output", param_table_name)
        fit.setProperty("CreateOutput", True)
        fit.execute()

        return fit.getProperty('OutputParameters').value

#------------------------------------------------------------------------------

    def _get_correction_workspace(self, correction_name, corrections=None):
        if corrections is None:
            corrections = self._correction_workspaces

        for idx, ws_name in enumerate(corrections):
            if correction_name in ws_name:
                return idx, ws_name

        return None, None

#------------------------------------------------------------------------------

    def _get_correction_scale_factor(self, correction_name, corrections, params_ws):
        index = self._get_correction_workspace(correction_name, corrections)[0]
        if index is None:
            raise RuntimeError('No workspace for given correction')

        params_dict = TableWorkspaceDictionaryFacade(params_ws)
        scale_param_name = 'f%d.Scaling' % index

        return params_dict[scale_param_name]

#------------------------------------------------------------------------------

    def _gamma_correction(self):
        from mantid.simpleapi import (CalculateGammaBackground, CloneWorkspace,
                                      DeleteWorkspace)
        correction_background_ws = str(self._correction_wsg) + "_GammaBackground"

        fit_opts = parse_fit_options(mass_values=self.getProperty("Masses").value,
                                     profile_strs=self.getProperty("MassProfiles").value,
                                     constraints_str=self.getProperty("IntensityConstraints").value)
        params_ws_name = self.getPropertyValue("FitParameters")
        params_dict = TableWorkspaceDictionaryFacade(mtd[params_ws_name])
        func_str = fit_opts.create_function_str(params_dict)

        CalculateGammaBackground(InputWorkspace=self._output_ws,
                                 ComptonFunction=func_str,
                                 BackgroundWorkspace=correction_background_ws,
                                 CorrectedWorkspace='__corrected_dummy')
        DeleteWorkspace('__corrected_dummy')

        return correction_background_ws

#------------------------------------------------------------------------------

    def _ms_correction(self):
        """
        Calculates the contributions from multiple scattering
        on the input data from the set of given options
        """
        from mantid.simpleapi import (CalculateMSVesuvio, CreateSampleShape,
                                      DeleteWorkspace, SmoothData, Minus)

        masses = self.getProperty("Masses").value
        params_ws_name = self.getPropertyValue("FitParameters")
        params_dict = TableWorkspaceDictionaryFacade(mtd[params_ws_name])

        atom_props = list()
        for i, mass in enumerate(masses):
            intentisty_prop = 'f%d.Intensity' % i
            c0_prop = 'f%d.C_0' % i

            if intentisty_prop in params_dict:
                intentisy = params_dict[intentisty_prop]
            elif c0_prop in params_dict:
                intentisy = params_dict[c0_prop]
            else:
                continue

            width = params_dict['f%d.Width' % i]

            atom_props.append(mass)
            atom_props.append(intentisy)
            atom_props.append(width)

        # Create the sample shape
        # Input dimensions are expected in CM
        CreateSampleShape(InputWorkspace=self._output_ws,
                          ShapeXML=create_cuboid_xml(self.getProperty("SampleHeight").value/100.,
                                                     self.getProperty("SampleWidth").value/100.,
                                                     self.getProperty("SampleDepth").value/100.))

        # Massage options into how algorithm expects them
        total_scatter_correction = str(self._correction_wsg) + "_TotalScattering"
        multi_scatter_correction = str(self._correction_wsg) + "_MultipleScattering"

        # Calculation
        CalculateMSVesuvio(InputWorkspace=self._output_ws,
                           NoOfMasses=len(atom_props)/3,
                           SampleDensity=self.getProperty("SampleDensity").value,
                           AtomicProperties=atom_props,
                           BeamRadius=self.getProperty("BeamRadius").value,
                           NumEventsPerRun=self.getProperty("NumEvents").value,
                           TotalScatteringWS=total_scatter_correction,
                           MultipleScatteringWS=multi_scatter_correction)

        # Smooth the output
        smooth_neighbours  = self.getProperty("SmoothNeighbours").value
        SmoothData(InputWorkspace=total_scatter_correction,
                   OutputWorkspace=total_scatter_correction,
                   NPoints=smooth_neighbours)
        SmoothData(InputWorkspace=multi_scatter_correction,
                   OutputWorkspace=multi_scatter_correction,
                   NPoints=smooth_neighbours)

        return total_scatter_correction, multi_scatter_correction
Ejemplo n.º 13
0
    def PyExec(self):
        from mantid.simpleapi import (ExtractSingleSpectrum, GroupWorkspaces,
                                      Scale, Minus, DeleteWorkspace)

        self._input_ws = self.getPropertyValue("InputWorkspace")
        container_ws = self.getPropertyValue("ContainerWorkspace")
        spec_idx = self.getProperty("WorkspaceIndex").value
        self._output_ws = self.getPropertyValue("OutputWorkspace")

        self._correction_wsg = self.getPropertyValue("CorrectionWorkspaces")
        self._corrected_wsg = self.getPropertyValue("CorrectedWorkspaces")
        self._linear_fit_table = self.getPropertyValue("LinearFitResult")

        ExtractSingleSpectrum(InputWorkspace=self._input_ws,
                              OutputWorkspace=self._output_ws,
                              WorkspaceIndex=spec_idx)

        self._correction_workspaces = list()

        self._container_ws = None
        if container_ws != "":
            container_name = str(self._correction_wsg) + "_Container"
            self._container_ws = ExtractSingleSpectrum(InputWorkspace=container_ws,
                                                       OutputWorkspace=container_name,
                                                       WorkspaceIndex=spec_idx)
            self._correction_workspaces.append(self._container_ws.name())

        # Do gamma correction
        if self.getProperty("GammaBackground").value:
            self._correction_workspaces.append(self._gamma_correction())

        # Do multiple scattering correction
        if self.getProperty("MultipleScattering").value:
            self._correction_workspaces.extend(self._ms_correction())

        # Output correction workspaces as a WorkspaceGroup
        if self._correction_wsg != "":
            GroupWorkspaces(InputWorkspaces=self._correction_workspaces,
                            OutputWorkspace=self._correction_wsg)
            self.setProperty("CorrectionWorkspaces", self._correction_wsg)

        # Perform fitting to obtain scale factors for corrections

        # The workspaces to fit for correction scale factors
        fit_corrections = [wks for wks in self._correction_workspaces if 'MultipleScattering' not in wks]

        # Perform fitting of corrections
        fixed_params = {}

        fixed_gamma_factor = self.getProperty("GammaBackgroundScale").value
        if fixed_gamma_factor != 0.0:
            fixed_params['GammaBackground'] = fixed_gamma_factor

        fixed_container_scale = self.getProperty("ContainerScale").value
        if fixed_container_scale != 0.0:
            fixed_params['Container'] = fixed_container_scale

        params_ws = self._fit_corrections(fit_corrections, self._linear_fit_table, **fixed_params)
        self.setProperty("LinearFitResult", params_ws)

        # Scale gamma background
        if self.getProperty("GammaBackground").value:
            gamma_correct_ws = self._get_correction_workspace('GammaBackground')[1]
            gamma_factor = self._get_correction_scale_factor('GammaBackground', fit_corrections, params_ws)
            Scale(InputWorkspace=gamma_correct_ws,
                  OutputWorkspace=gamma_correct_ws,
                  Factor=gamma_factor)

        # Scale multiple scattering
        if self.getProperty("MultipleScattering").value:
            # Use factor of total scattering as this includes single and multiple scattering
            multi_scatter_correct_ws = self._get_correction_workspace('MultipleScattering')[1]
            total_scatter_correct_ws = self._get_correction_workspace('TotalScattering')[1]
            total_scatter_factor = self._get_correction_scale_factor('TotalScattering', fit_corrections, params_ws)
            Scale(InputWorkspace=multi_scatter_correct_ws,
                  OutputWorkspace=multi_scatter_correct_ws,
                  Factor=total_scatter_factor)
            Scale(InputWorkspace=total_scatter_correct_ws,
                  OutputWorkspace=total_scatter_correct_ws,
                  Factor=total_scatter_factor)

        # Scale by container
        if container_ws != "":
            container_correct_ws = self._get_correction_workspace('Container')[1]
            container_factor = self._get_correction_scale_factor('Container', fit_corrections, params_ws)
            Scale(InputWorkspace=container_correct_ws,
                  OutputWorkspace=container_correct_ws,
                  Factor=container_factor)

        # Calculate and output corrected workspaces as a WorkspaceGroup
        if self._corrected_wsg != "":
            corrected_workspaces = [ws_name.replace(self._correction_wsg, self._corrected_wsg) for ws_name in self._correction_workspaces]
            for corrected, correction in zip(corrected_workspaces, self._correction_workspaces):
                Minus(LHSWorkspace=self._output_ws,
                      RHSWorkspace=correction,
                      OutputWorkspace=corrected)
            GroupWorkspaces(InputWorkspaces=corrected_workspaces,
                            OutputWorkspace=self._corrected_wsg)
            self.setProperty("CorrectedWorkspaces", self._corrected_wsg)

        # Apply corrections
        for correction in self. _correction_workspaces:
            if 'TotalScattering' not in correction:
                Minus(LHSWorkspace=self._output_ws,
                      RHSWorkspace=correction,
                      OutputWorkspace=self._output_ws)

        self.setProperty("OutputWorkspace", self._output_ws)

        # Remove correction workspaces if they are no longer required
        if self._correction_wsg == "":
            for wksp in self._correction_workspaces:
                DeleteWorkspace(wksp)