diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/PowderILLDetectorScan.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/PowderILLDetectorScan.py index 929586d9c9b3a907fcac21080456df303d590498..7ff56f0de7ab377883be56492fc11534b4a96b40 100644 --- a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/PowderILLDetectorScan.py +++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/PowderILLDetectorScan.py @@ -8,8 +8,7 @@ from __future__ import (absolute_import, division, print_function) from mantid.kernel import CompositeValidator, Direction, FloatArrayLengthValidator, FloatArrayOrderedPairsValidator, \ FloatArrayProperty, StringListValidator, IntBoundedValidator -from mantid.api import DataProcessorAlgorithm, MultipleFileProperty, Progress, WorkspaceGroupProperty, FileProperty, \ - FileAction +from mantid.api import DataProcessorAlgorithm, MultipleFileProperty, Progress, WorkspaceGroupProperty, FileProperty, FileAction from mantid.simpleapi import * @@ -28,7 +27,7 @@ class PowderILLDetectorScan(DataProcessorAlgorithm): return 'Performs powder diffraction data reduction for D2B and D20 (when doing a detector scan).' def seeAlso(self): - return ["PowderILLParameterScan", "PowderILLEfficiency"] + return [ "PowderILLParameterScan", "PowderILLEfficiency" ] def name(self): return "PowderILLDetectorScan" @@ -123,9 +122,9 @@ class PowderILLDetectorScan(DataProcessorAlgorithm): end_bottom = start_bottom + n_pix - 1 start_top = (tube + 1) * n_pixels - n_pix + 1 end_top = start_top + n_pix - 1 - mask += str(start_bottom) + '-' + str(end_bottom) + ',' - mask += str(start_top) + '-' + str(end_top) + ',' - self.log().debug('Preparing to mask with DetectorList=' + mask[:-1]) + mask += str(start_bottom)+'-'+str(end_bottom)+',' + mask += str(start_top)+'-'+str(end_top)+',' + self.log().debug('Preparing to mask with DetectorList='+mask[:-1]) return mask[:-1] def _reduce_1D(self, input_group): @@ -147,8 +146,8 @@ class PowderILLDetectorScan(DataProcessorAlgorithm): OutputWorkspace=output2DtubesName) if self._final_mask != 0: nSpec = mtd[output2DtubesName].getNumberHistograms() - mask_list = '0-{0},{1}-{2}'.format(self._final_mask, nSpec - self._final_mask, nSpec - 1) - MaskDetectors(Workspace=output2DtubesName, WorkspaceIndexList=mask_list) + mask_list = '0-{0},{1}-{2}'.format(self._final_mask,nSpec-self._final_mask,nSpec-1) + MaskDetectors(Workspace=output2DtubesName,WorkspaceIndexList=mask_list) return output2DTubes @@ -159,26 +158,32 @@ class PowderILLDetectorScan(DataProcessorAlgorithm): HeightAxis=self._height_range, MirrorScatteringAngles=self._mirror, CropNegativeScatteringAngles=self._crop_negative, - OutputWorkspace=output2DName) + OutputWorkspace = output2DName) if self._final_mask != 0: nSpec = mtd[output2DName].getNumberHistograms() - mask_list = '0-{0},{1}-{2}'.format(self._final_mask, nSpec - self._final_mask, nSpec - 1) - MaskDetectors(Workspace=output2DName, WorkspaceIndexList=mask_list) + mask_list = '0-{0},{1}-{2}'.format(self._final_mask,nSpec-self._final_mask,nSpec-1) + MaskDetectors(Workspace=output2DName,WorkspaceIndexList=mask_list) return output2D - def _apply_calibration(self, input_group): - calib_file = self.getPropertyValue('CalibrationFile') - if calib_file: - self._progress.report('Applying detector efficiencies') - LoadNexusProcessed(Filename=calib_file, OutputWorkspace='__det_eff') - for ws in input_group: - name = ws.name() - ExtractMonitors(InputWorkspace=name, DetectorWorkspace=name) - ApplyDetectorScanEffCorr(InputWorkspace=name, DetectorEfficiencyWorkspace='__det_eff', - OutputWorkspace=name) + def PyExec(self): # noqa C901 + data_type = 'Raw' + if self.getProperty('UseCalibratedData').value: + data_type = 'Calibrated' + align_tubes = self.getProperty('AlignTubes').value - def _check_instrument(self, instrument): + self._progress = Progress(self, start=0.0, end=1.0, nreports=6) + self._progress.report('Loading data') + # Do not merge the runs yet, since it will break the calibration + # Load and calibrate separately, then SumOverlappingTubes will merge correctly + # Besides + here does not make sense, and it will also slow down D2B a lot + input_workspace = LoadAndMerge(Filename=self.getPropertyValue('Run').replace('+', ','), + LoaderName='LoadILLDiffraction', + LoaderOptions={'DataType': data_type, 'AlignTubes': align_tubes}) + # We might already have a group, but group just in case + input_group = GroupWorkspaces(InputWorkspaces=input_workspace) + + instrument = input_group[0].getInstrument() supported_instruments = ['D2B', 'D20'] if instrument.getName() not in supported_instruments: self.log.warning('Running for unsupported instrument, use with caution. Supported instruments are: ' @@ -189,14 +194,21 @@ class PowderILLDetectorScan(DataProcessorAlgorithm): if self.getProperty('Output2D').value: raise RuntimeError('Output2D is not supported for D20 (1D detector)') - def _component_cropping(self, input_group): - components = self.getPropertyValue('ComponentsToReduce') - if components: + self._progress.report('Normalising to monitor') + if self.getPropertyValue('NormaliseTo') == 'Monitor': + input_group = NormaliseToMonitor(InputWorkspace=input_group, MonitorID=0) + if instrument.getName() == 'D2B': + input_group = Scale(InputWorkspace=input_group, Factor=1e+6) + + calib_file = self.getPropertyValue('CalibrationFile') + if calib_file: + self._progress.report('Applying detector efficiencies') + LoadNexusProcessed(Filename=calib_file, OutputWorkspace='__det_eff') for ws in input_group: - CropToComponent(InputWorkspace=ws.getName(), OutputWorkspace=ws.getName(), - ComponentNames=components) + name = ws.getName() + ExtractMonitors(InputWorkspace=name, DetectorWorkspace=name) + ApplyDetectorScanEffCorr(InputWorkspace=name,DetectorEfficiencyWorkspace='__det_eff',OutputWorkspace=name) - def _do_masking(self, input_group): pixels_to_mask = self.getProperty('InitialMask').value if pixels_to_mask != 0: mask = self._generate_mask(pixels_to_mask, input_group[0].getInstrument()) @@ -207,21 +219,6 @@ class PowderILLDetectorScan(DataProcessorAlgorithm): for ws in input_group: MaskDetectors(Workspace=ws, ComponentList=components_to_mask) - def _do_reduction(self, input_group, output_workspaces): - self._progress.report('Doing Output2DTubes Option') - if self.getProperty('Output2DTubes').value: - output2DTubes = self._reduce_2DTubes(input_group) - output_workspaces.append(output2DTubes) - self._progress.report('Doing Output2D Option') - if self.getProperty('Output2D').value: - output2D = self._reduce_2D(input_group) - output_workspaces.append(output2D) - self._progress.report('Doing Output1D Option') - if self.getProperty('Output1D').value: - output1D = self._reduce_1D(input_group) - output_workspaces.append(output1D) - - def _get_height_range(self): height_range_prop = self.getProperty('HeightRange').value if len(height_range_prop) == 0: run = mtd["input_group"].getItem(0).getRun() @@ -231,40 +228,6 @@ class PowderILLDetectorScan(DataProcessorAlgorithm): self._height_range = str(-maxHeight) + ',' + str(pixelHeight) + ',' + str(maxHeight) elif len(height_range_prop) == 2: self._height_range = str(height_range_prop[0]) + ', ' + str(height_range_prop[1]) - - def _normalise_input(self, input_group, instrument): - self._progress.report('Normalising to monitor') - if self.getPropertyValue('NormaliseTo') == 'Monitor': - input_group = NormaliseToMonitor(InputWorkspace=input_group, MonitorID=0) - if instrument.getName() == 'D2B': - input_group = Scale(InputWorkspace=input_group, Factor=1e+6) - return input_group - - def PyExec(self): - data_type = 'Raw' - if self.getProperty('UseCalibratedData').value: - data_type = 'Calibrated' - align_tubes = self.getProperty('AlignTubes').value - - self._progress = Progress(self, start=0.0, end=1.0, nreports=6) - self._progress.report('Loading data') - # Do not merge the runs yet, since it will break the calibration - # Load and calibrate separately, then SumOverlappingTubes will merge correctly - # Besides + here does not make sense, and it will also slow down D2B a lot - input_workspace = LoadAndMerge(Filename=self.getPropertyValue('Run').replace('+', ','), - LoaderName='LoadILLDiffraction', - LoaderOptions={'DataType': data_type, 'AlignTubes': align_tubes}) - # We might already have a group, but group just in case - input_group = GroupWorkspaces(InputWorkspaces=input_workspace) - - instrument = input_group[0].getInstrument() - self._check_instrument(instrument) - - input_group = self._normalise_input(input_group, instrument) - self._apply_calibration(input_group) - self._do_masking(input_group) - self._get_height_range() - output_workspaces = [] self._out_ws_name = self.getPropertyValue('OutputWorkspace') self._mirror = False @@ -272,15 +235,32 @@ class PowderILLDetectorScan(DataProcessorAlgorithm): if instrument.hasParameter("mirror_scattering_angles"): self._mirror = instrument.getBoolParameter("mirror_scattering_angles")[0] self._final_mask = self.getProperty('FinalMask').value - self._component_cropping(input_group) - self._do_reduction(input_group, output_workspaces) + components = self.getPropertyValue('ComponentsToReduce') + if components: + for ws in input_group: + CropToComponent(InputWorkspace=ws.getName(), OutputWorkspace=ws.getName(), + ComponentNames=components) + + self._progress.report('Doing Output2DTubes Option') + if self.getProperty('Output2DTubes').value: + output2DTubes = self._reduce_2DTubes(input_group) + output_workspaces.append(output2DTubes) + + self._progress.report('Doing Output2D Option') + if self.getProperty('Output2D').value: + output2D = self._reduce_2D(input_group) + output_workspaces.append(output2D) + + self._progress.report('Doing Output1D Option') + if self.getProperty('Output1D').value: + output1D = self._reduce_1D(input_group) + output_workspaces.append(output1D) self._progress.report('Finishing up...') DeleteWorkspace('input_group') GroupWorkspaces(InputWorkspaces=output_workspaces, OutputWorkspace=self._out_ws_name) self.setProperty('OutputWorkspace', self._out_ws_name) - # Register the algorithm with Mantid AlgorithmFactory.subscribe(PowderILLDetectorScan) diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANSILLReduction.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANSILLReduction.py index 551e95ab012988d5cd1448a16bb82a292e9eec42..f0b2ff9239d4c27f4a604a488049f53992a68616 100644 --- a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANSILLReduction.py +++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANSILLReduction.py @@ -7,14 +7,14 @@ from __future__ import (absolute_import, division, print_function) from mantid.api import PythonAlgorithm, MatrixWorkspaceProperty, MultipleFileProperty, PropertyMode, Progress -from mantid.kernel import Direction, EnabledWhenProperty, FloatBoundedValidator, LogicOperator, PropertyCriterion, \ - StringListValidator +from mantid.kernel import Direction, EnabledWhenProperty, FloatBoundedValidator, LogicOperator, PropertyCriterion, StringListValidator from mantid.simpleapi import * from math import fabs import numpy as np class SANSILLReduction(PythonAlgorithm): + _mode = 'Monochromatic' _instrument = None @@ -45,7 +45,7 @@ class SANSILLReduction(PythonAlgorithm): @param ws2 : workspace 2 @return true if the detector distance difference is less than 1 cm """ - tolerance = 0.01 # m + tolerance = 0.01 #m l2_1 = ws1.getRun().getLogData('L2').value l2_2 = ws2.getRun().getLogData('L2').value return fabs(l2_1 - l2_2) < tolerance @@ -100,8 +100,7 @@ class SANSILLReduction(PythonAlgorithm): self.setPropertySettings('BeamFinderMethod', beam) - self.declareProperty('SampleThickness', 0.1, validator=FloatBoundedValidator(lower=0.), - doc='Sample thickness [cm]') + self.declareProperty('SampleThickness', 0.1, validator=FloatBoundedValidator(lower=0.), doc='Sample thickness [cm]') self.setPropertySettings('SampleThickness', EnabledWhenProperty(sample, reference, LogicOperator.Or)) @@ -214,7 +213,7 @@ class SANSILLReduction(PythonAlgorithm): if mtd[ws].getRun().hasProperty('timer'): duration = mtd[ws].getRun().getLogData('timer').value if duration != 0.: - Scale(InputWorkspace=ws, Factor=1. / duration, OutputWorkspace=ws) + Scale(InputWorkspace=ws, Factor=1./duration, OutputWorkspace=ws) self._dead_time_correction(ws) else: raise RuntimeError('Unable to normalise to time; duration found is 0 seconds.') @@ -239,112 +238,6 @@ class SANSILLReduction(PythonAlgorithm): else: self.log().information('No tau available in IPF, skipping dead time correction.') - def _check_absorber_workspace_processing(self, ws): - absorber_ws = self.getProperty('AbsorberInputWorkspace').value - if absorber_ws: - if not self._check_processed_flag(absorber_ws, 'Absorber'): - self.log().warning('Absorber input workspace is not processed as absorber.') - Minus(LHSWorkspace=ws, RHSWorkspace=absorber_ws, OutputWorkspace=ws) - - def _check_beam_workspace_processing(self, ws): - beam_ws = self.getProperty('BeamInputWorkspace').value - if beam_ws: - if not self._check_processed_flag(beam_ws, 'Beam'): - self.log().warning('Beam input workspace is not processed as beam.') - if self._mode != 'TOF': - beam_x = beam_ws.getRun().getLogData('BeamCenterX').value - beam_y = beam_ws.getRun().getLogData('BeamCenterY').value - AddSampleLog(Workspace=ws, LogName='BeamCenterX', LogText=str(beam_x), LogType='Number') - AddSampleLog(Workspace=ws, LogName='BeamCenterY', LogText=str(beam_y), LogType='Number') - MoveInstrumentComponent(Workspace=ws, X=-beam_x, Y=-beam_y, ComponentName='detector') - if not self._check_distances_match(mtd[ws], beam_ws): - self.log().warning('Different detector distances found for empty beam and sample runs!') - return beam_ws - - def _check_container_workspace_processing(self, container_ws, ws): - if container_ws: - if not self._check_processed_flag(container_ws, 'Container'): - self.log().warning('Container input workspace is not processed as container.') - if not self._check_distances_match(mtd[ws], container_ws): - self.log().warning( - 'Different detector distances found for container and sample runs!') - Minus(LHSWorkspace=ws, RHSWorkspace=container_ws, OutputWorkspace=ws) - - def _check_reference_workspace_processing(self, beam_ws, ws): - reference_ws = self.getProperty('ReferenceInputWorkspace').value - coll_ws = None - if reference_ws: - if not self._check_processed_flag(reference_ws, 'Reference'): - self.log().warning('Reference input workspace is not processed as reference.') - Divide(LHSWorkspace=ws, RHSWorkspace=reference_ws, OutputWorkspace=ws) - coll_ws = reference_ws - else: - self._check_sensitivity_workspace_processing(ws) - flux_in = self.getProperty('FluxInputWorkspace').value - if flux_in: - coll_ws = beam_ws - flux_ws = ws + '_flux' - if self._mode == 'TOF': - RebinToWorkspace(WorkspaceToRebin=flux_in, WorkspaceToMatch=ws, OutputWorkspace=flux_ws) - Divide(LHSWorkspace=ws, RHSWorkspace=flux_ws, OutputWorkspace=ws) - DeleteWorkspace(flux_ws) - else: - Divide(LHSWorkspace=ws, RHSWorkspace=flux_in, OutputWorkspace=ws) - return coll_ws - - def _check_sensitivity_workspace_processing(self, ws): - sensitivity_in = self.getProperty('SensitivityInputWorkspace').value - if sensitivity_in: - if not self._check_processed_flag(sensitivity_in, 'Sensitivity'): - self.log().warning('Sensitivity input workspace is not processed as sensitivity.') - Divide(LHSWorkspace=ws, RHSWorkspace=sensitivity_in, OutputWorkspace=ws) - - def _check_transmission_workspace_processing(self, ws): - transmission_ws = self.getProperty('TransmissionInputWorkspace').value - if transmission_ws: - if not self._check_processed_flag(transmission_ws, 'Transmission'): - self.log().warning('Transmission input workspace is not processed as transmission.') - if transmission_ws.blocksize() == 1: - # monochromatic mode, scalar transmission - transmission = transmission_ws.readY(0)[0] - transmission_err = transmission_ws.readE(0)[0] - ApplyTransmissionCorrection(InputWorkspace=ws, TransmissionValue=transmission, - TransmissionError=transmission_err, OutputWorkspace=ws) - else: - # wavelenght dependent transmission, need to rebin - transmission_rebinned = ws + '_tr_rebinned' - RebinToWorkspace(WorkspaceToRebin=transmission_ws, WorkspaceToMatch=ws, - OutputWorkspace=transmission_rebinned) - ApplyTransmissionCorrection(InputWorkspace=ws, TransmissionWorkspace=transmission_rebinned, - OutputWorkspace=ws) - DeleteWorkspace(transmission_rebinned) - - def _create_sensitivity_out(self, ws): - sensitivity_out = self.getPropertyValue('SensitivityOutputWorkspace') - if sensitivity_out: - CalculateEfficiency(InputWorkspace=ws, OutputWorkspace=sensitivity_out) - mtd[sensitivity_out].getRun().addProperty('ProcessedAs', 'Sensitivity', True) - self.setProperty('SensitivityOutputWorkspace', mtd[sensitivity_out]) - - def _do_masking(self, ws): - mask_ws = self.getProperty('MaskedInputWorkspace').value - if mask_ws: - masked_ws = ws + '_mask' - CloneWorkspace(InputWorkspace=mask_ws, OutputWorkspace=masked_ws) - ExtractMonitors(InputWorkspace=masked_ws, DetectorWorkspace=masked_ws) - MaskDetectors(Workspace=ws, MaskedWorkspace=masked_ws) - DeleteWorkspace(masked_ws) - - def _parallax_correction(self, ws): - if self._instrument in ['D22', 'D22lr', 'D33']: - self.log().information('Performing parallax correction') - if self._instrument == 'D33': - components = ['back_detector', 'front_detector_top', 'front_detector_bottom', - 'front_detector_left', 'front_detector_right'] - else: - components = ['detector'] - ParallaxCorrection(InputWorkspace=ws, OutputWorkspace=ws, ComponentNames=components) - def _process_beam(self, ws): """ Calculates the beam center's x,y coordinates, and the beam flux @@ -353,10 +246,9 @@ class SANSILLReduction(PythonAlgorithm): centers = ws + '_centers' method = self.getPropertyValue('BeamFinderMethod') radius = self.getProperty('BeamRadius').value - FindCenterOfMassPosition(InputWorkspace=ws, DirectBeam=(method == 'DirectBeam'), BeamRadius=radius, - Output=centers) - beam_x = mtd[centers].cell(0, 1) - beam_y = mtd[centers].cell(1, 1) + FindCenterOfMassPosition(InputWorkspace=ws, DirectBeam=(method == 'DirectBeam'), BeamRadius=radius, Output=centers) + beam_x = mtd[centers].cell(0,1) + beam_y = mtd[centers].cell(1,1) AddSampleLog(Workspace=ws, LogName='BeamCenterX', LogText=str(beam_x), LogType='Number') AddSampleLog(Workspace=ws, LogName='BeamCenterY', LogText=str(beam_y), LogType='Number') DeleteWorkspace(centers) @@ -369,12 +261,11 @@ class SANSILLReduction(PythonAlgorithm): att_value = run.getLogData('attenuator.attenuation_value').value if float(att_value) < 10. and self._instrument == 'D33': instrument = mtd[ws].getInstrument() - param = 'att' + str(int(att_value)) + param = 'att'+str(int(att_value)) if instrument.hasParameter(param): att_coeff = instrument.getNumberParameter(param)[0] else: - raise RuntimeError( - 'Unable to find the attenuation coefficient for D33 attenuator #' + str(int(att_value))) + raise RuntimeError('Unable to find the attenuation coefficient for D33 attenuator #'+str(int(att_value))) else: att_coeff = att_value else: @@ -395,45 +286,12 @@ class SANSILLReduction(PythonAlgorithm): RenameWorkspace(InputWorkspace=flux, OutputWorkspace=flux_out) self.setProperty('FluxOutputWorkspace', mtd[flux_out]) - def _process_sample(self, beam_ws, ws): - coll_ws = self._check_reference_workspace_processing(beam_ws, ws) - if coll_ws: - if not self._check_distances_match(mtd[ws], coll_ws): - self.log().warning( - 'Different detector distances found for the reference/flux and sample runs!') - sample_coll = mtd[ws].getRun().getLogData('collimation.actual_position').value - ref_coll = coll_ws.getRun().getLogData('collimation.actual_position').value - flux_factor = (sample_coll ** 2) / (ref_coll ** 2) - self.log().notice('Flux factor is: ' + str(flux_factor)) - Scale(InputWorkspace=ws, Factor=flux_factor, OutputWorkspace=ws) - ReplaceSpecialValues(InputWorkspace=ws, OutputWorkspace=ws, - NaNValue=0., NaNError=0., InfinityValue=0., InfinityError=0.) - - def _process_transmission(self, beam_ws, ws): - if not self._check_distances_match(mtd[ws], beam_ws): - self.log().warning('Different detector distances found for empty beam and transmission runs!') - RebinToWorkspace(WorkspaceToRebin=ws, WorkspaceToMatch=beam_ws, OutputWorkspace=ws) - radius = self.getProperty('BeamRadius').value - shapeXML = self._cylinder(radius) - det_list = FindDetectorsInShape(Workspace=ws, ShapeXML=shapeXML) - lambdas = mtd[ws].extractX() - min_lambda = np.min(lambdas) - max_lambda = np.max(lambdas) - width_lambda = lambdas[0][1] - lambdas[0][0] - lambda_binning = [min_lambda, width_lambda, max_lambda] - self.log().information('Rebinning for transmission calculation to: ' + str(lambda_binning)) - Rebin(InputWorkspace=ws, Params=lambda_binning, OutputWorkspace=ws) - beam_rebinned = Rebin(InputWorkspace=beam_ws, Params=lambda_binning, StoreInADS=False) - CalculateTransmission(SampleRunWorkspace=ws, DirectRunWorkspace=beam_rebinned, - TransmissionROI=det_list, OutputWorkspace=ws, RebinParams=lambda_binning) - - def PyExec(self): + def PyExec(self): # noqa: C901 process = self.getPropertyValue('ProcessAs') processes = ['Absorber', 'Beam', 'Transmission', 'Container', 'Reference', 'Sample'] progress = Progress(self, start=0.0, end=1.0, nreports=processes.index(process) + 1) ws = '__' + self.getPropertyValue('OutputWorkspace') - LoadAndMerge(Filename=self.getPropertyValue('Run').replace(',', '+'), LoaderName='LoadILLSANS', - OutputWorkspace=ws) + LoadAndMerge(Filename=self.getPropertyValue('Run').replace(',','+'), LoaderName='LoadILLSANS', OutputWorkspace=ws) self._normalise(ws) ExtractMonitors(InputWorkspace=ws, DetectorWorkspace=ws) self._instrument = mtd[ws].getInstrument().getName() @@ -443,17 +301,62 @@ class SANSILLReduction(PythonAlgorithm): self._mode = 'TOF' progress.report() if process in ['Beam', 'Transmission', 'Container', 'Reference', 'Sample']: - self._check_absorber_workspace_processing(ws) + absorber_ws = self.getProperty('AbsorberInputWorkspace').value + if absorber_ws: + if not self._check_processed_flag(absorber_ws, 'Absorber'): + self.log().warning('Absorber input workspace is not processed as absorber.') + Minus(LHSWorkspace=ws, RHSWorkspace=absorber_ws, OutputWorkspace=ws) if process == 'Beam': progress.report() self._process_beam(ws) else: - beam_ws = self._check_beam_workspace_processing(ws) + beam_ws = self.getProperty('BeamInputWorkspace').value + if beam_ws: + if not self._check_processed_flag(beam_ws, 'Beam'): + self.log().warning('Beam input workspace is not processed as beam.') + if self._mode != 'TOF': + beam_x = beam_ws.getRun().getLogData('BeamCenterX').value + beam_y = beam_ws.getRun().getLogData('BeamCenterY').value + AddSampleLog(Workspace=ws, LogName='BeamCenterX', LogText=str(beam_x), LogType='Number') + AddSampleLog(Workspace=ws, LogName='BeamCenterY', LogText=str(beam_y), LogType='Number') + MoveInstrumentComponent(Workspace=ws, X=-beam_x, Y=-beam_y, ComponentName='detector') + if not self._check_distances_match(mtd[ws], beam_ws): + self.log().warning('Different detector distances found for empty beam and sample runs!') progress.report() if process == 'Transmission': - self._process_transmission(beam_ws, ws) + if not self._check_distances_match(mtd[ws], beam_ws): + self.log().warning('Different detector distances found for empty beam and transmission runs!') + RebinToWorkspace(WorkspaceToRebin=ws, WorkspaceToMatch=beam_ws, OutputWorkspace=ws) + radius = self.getProperty('BeamRadius').value + shapeXML = self._cylinder(radius) + det_list = FindDetectorsInShape(Workspace=ws, ShapeXML=shapeXML) + lambdas = mtd[ws].extractX() + min_lambda = np.min(lambdas) + max_lambda = np.max(lambdas) + width_lambda = lambdas[0][1]-lambdas[0][0] + lambda_binning = [min_lambda, width_lambda, max_lambda] + self.log().information('Rebinning for transmission calculation to: '+str(lambda_binning)) + Rebin(InputWorkspace=ws, Params=lambda_binning, OutputWorkspace=ws) + beam_rebinned = Rebin(InputWorkspace=beam_ws, Params=lambda_binning, StoreInADS=False) + CalculateTransmission(SampleRunWorkspace=ws, DirectRunWorkspace=beam_rebinned, + TransmissionROI=det_list, OutputWorkspace=ws, RebinParams=lambda_binning) else: - self._check_transmission_workspace_processing(ws) + transmission_ws = self.getProperty('TransmissionInputWorkspace').value + if transmission_ws: + if not self._check_processed_flag(transmission_ws, 'Transmission'): + self.log().warning('Transmission input workspace is not processed as transmission.') + if transmission_ws.blocksize() == 1: + # monochromatic mode, scalar transmission + transmission = transmission_ws.readY(0)[0] + transmission_err = transmission_ws.readE(0)[0] + ApplyTransmissionCorrection(InputWorkspace=ws, TransmissionValue=transmission, + TransmissionError=transmission_err, OutputWorkspace=ws) + else: + # wavelenght dependent transmission, need to rebin + transmission_rebinned = ws + '_tr_rebinned' + RebinToWorkspace(WorkspaceToRebin=transmission_ws, WorkspaceToMatch=ws, OutputWorkspace=transmission_rebinned) + ApplyTransmissionCorrection(InputWorkspace=ws, TransmissionWorkspace=transmission_rebinned, OutputWorkspace=ws) + DeleteWorkspace(transmission_rebinned) solid_angle = ws + '_sa' SolidAngle(InputWorkspace=ws, OutputWorkspace=solid_angle) Divide(LHSWorkspace=ws, RHSWorkspace=solid_angle, OutputWorkspace=ws) @@ -461,17 +364,74 @@ class SANSILLReduction(PythonAlgorithm): progress.report() if process in ['Reference', 'Sample']: container_ws = self.getProperty('ContainerInputWorkspace').value - self._check_container_workspace_processing(container_ws, ws) - self._do_masking(ws) + if container_ws: + if not self._check_processed_flag(container_ws, 'Container'): + self.log().warning('Container input workspace is not processed as container.') + if not self._check_distances_match(mtd[ws], container_ws): + self.log().warning( + 'Different detector distances found for container and sample runs!') + Minus(LHSWorkspace=ws, RHSWorkspace=container_ws, OutputWorkspace=ws) + mask_ws = self.getProperty('MaskedInputWorkspace').value + if mask_ws: + masked_ws = ws + '_mask' + CloneWorkspace(InputWorkspace=mask_ws, OutputWorkspace=masked_ws) + ExtractMonitors(InputWorkspace=masked_ws, DetectorWorkspace=masked_ws) + MaskDetectors(Workspace=ws, MaskedWorkspace=masked_ws) + DeleteWorkspace(masked_ws) thickness = self.getProperty('SampleThickness').value NormaliseByThickness(InputWorkspace=ws, OutputWorkspace=ws, SampleThickness=thickness) # parallax (gondola) effect - self._parallax_correction(ws) + if self._instrument in ['D22', 'D22lr', 'D33']: + self.log().information('Performing parallax correction') + if self._instrument == 'D33': + components = ['back_detector', 'front_detector_top', 'front_detector_bottom', + 'front_detector_left', 'front_detector_right'] + else: + components = ['detector'] + ParallaxCorrection(InputWorkspace=ws, OutputWorkspace=ws, ComponentNames=components) progress.report() if process == 'Reference': - self._create_sensitivity_out(ws) + sensitivity_out = self.getPropertyValue('SensitivityOutputWorkspace') + if sensitivity_out: + CalculateEfficiency(InputWorkspace=ws, OutputWorkspace=sensitivity_out) + mtd[sensitivity_out].getRun().addProperty('ProcessedAs', 'Sensitivity', True) + self.setProperty('SensitivityOutputWorkspace', mtd[sensitivity_out]) elif process == 'Sample': - self._process_sample(beam_ws, ws) + reference_ws = self.getProperty('ReferenceInputWorkspace').value + coll_ws = None + if reference_ws: + if not self._check_processed_flag(reference_ws, 'Reference'): + self.log().warning('Reference input workspace is not processed as reference.') + Divide(LHSWorkspace=ws, RHSWorkspace=reference_ws, OutputWorkspace=ws) + coll_ws = reference_ws + else: + sensitivity_in = self.getProperty('SensitivityInputWorkspace').value + if sensitivity_in: + if not self._check_processed_flag(sensitivity_in, 'Sensitivity'): + self.log().warning('Sensitivity input workspace is not processed as sensitivity.') + Divide(LHSWorkspace=ws, RHSWorkspace=sensitivity_in, OutputWorkspace=ws) + flux_in = self.getProperty('FluxInputWorkspace').value + if flux_in: + coll_ws = beam_ws + flux_ws = ws + '_flux' + if self._mode == 'TOF': + RebinToWorkspace(WorkspaceToRebin=flux_in, WorkspaceToMatch=ws, OutputWorkspace=flux_ws) + Divide(LHSWorkspace=ws, RHSWorkspace=flux_ws, OutputWorkspace=ws) + DeleteWorkspace(flux_ws) + else: + Divide(LHSWorkspace=ws, RHSWorkspace=flux_in, OutputWorkspace=ws) + + if coll_ws: + if not self._check_distances_match(mtd[ws], coll_ws): + self.log().warning( + 'Different detector distances found for the reference/flux and sample runs!') + sample_coll = mtd[ws].getRun().getLogData('collimation.actual_position').value + ref_coll = coll_ws.getRun().getLogData('collimation.actual_position').value + flux_factor = (sample_coll ** 2) / (ref_coll ** 2) + self.log().notice('Flux factor is: ' + str(flux_factor)) + Scale(InputWorkspace=ws, Factor=flux_factor, OutputWorkspace=ws) + ReplaceSpecialValues(InputWorkspace=ws, OutputWorkspace=ws, + NaNValue=0., NaNError=0., InfinityValue=0., InfinityError=0.) progress.report() if process != 'Transmission': if self._instrument == 'D33': @@ -482,6 +442,5 @@ class SANSILLReduction(PythonAlgorithm): RenameWorkspace(InputWorkspace=ws, OutputWorkspace=ws[2:]) self.setProperty('OutputWorkspace', mtd[ws[2:]]) - # Register algorithm with Mantid AlgorithmFactory.subscribe(SANSILLReduction) diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/SANSILLReductionTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/SANSILLReductionTest.py index c9116dcb0f9e0aca681e9faa6a7966e05fa0e4fe..a27ce13af21656b4897a746007b87d47d38e94dc 100644 --- a/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/SANSILLReductionTest.py +++ b/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/SANSILLReductionTest.py @@ -7,8 +7,9 @@ from __future__ import (absolute_import, division, print_function) import unittest -from mantid.api import MatrixWorkspace +from mantid.api import MatrixWorkspace, Run from mantid.simpleapi import SANSILLReduction, config, mtd +from mantid.geometry import Instrument class SANSILLReductionTest(unittest.TestCase): @@ -92,13 +93,13 @@ class SANSILLReductionTest(unittest.TestCase): self._check_output(mtd['flux'], False, 30, 256*256) self._check_process_flag(mtd['flux'], 'Beam') - def xtest_transmission_tof(self): + def test_transmission_tof(self): # D33 VTOF SANSILLReduction(Run='093406', ProcessAs='Beam', OutputWorkspace='beam') SANSILLReduction(Run='093407', ProcessAs='Transmission', BeamInputWorkspace='beam', OutputWorkspace='ctr') self._check_output(mtd['ctr'], False, 75, 1) - def test_container_tof(self): + def test_reference_tof(self): # D33 VTOF # this is actually a sample run, not water, but is fine for this test SANSILLReduction(Run='093410', ProcessAs='Reference', OutputWorkspace='ref') @@ -122,8 +123,8 @@ class SANSILLReductionTest(unittest.TestCase): self.assertEqual(ws.getAxis(0).getUnit().unitID(), "Wavelength") self.assertEqual(ws.blocksize(), blocksize) self.assertEqual(ws.getNumberHistograms(), spectra) - self.assertTrue(ws.getInstrument()) - self.assertTrue(ws.getRun()) + self.assertTrue(isinstance(ws.getInstrument(), Instrument)) + self.assertTrue(isinstance(ws.getRun(), Run)) self.assertTrue(ws.getHistory()) if logs: self.assertTrue(ws.getRun().hasProperty('qmin'))