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
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
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')
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)))
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)
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
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))
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
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
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
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
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)