diff --git a/Framework/PythonInterface/plugins/algorithms/AlignAndFocusFromFiles.py b/Framework/PythonInterface/plugins/algorithms/AlignAndFocusFromFiles.py deleted file mode 100644 index 2adcf25790178df33681c550b355d2e7e321e639..0000000000000000000000000000000000000000 --- a/Framework/PythonInterface/plugins/algorithms/AlignAndFocusFromFiles.py +++ /dev/null @@ -1,223 +0,0 @@ -from __future__ import (absolute_import, division, print_function) - -from mantid.api import mtd, AlgorithmFactory, DataProcessorAlgorithm, ITableWorkspaceProperty, \ - MatrixWorkspaceProperty, FileAction, FileProperty, MultipleFileProperty, PropertyMode -from mantid.kernel import Direction -from mantid.simpleapi import AlignAndFocusPowder, CompressEvents, ConvertUnits, CreateCacheFilename, \ - DeleteWorkspace, DetermineChunking, Divide, EditInstrumentGeometry, FilterBadPulses, Load, \ - LoadNexusProcessed, PDDetermineCharacterizations, Plus, RenameWorkspace, SaveNexusProcessed -import os - -EXTENSIONS_NXS = ["_event.nxs", ".nxs.h5"] -PROPS_FOR_INSTR = ["PrimaryFlightPath", "SpectrumIDs", "L2", "Polar", "Azimuthal"] -PROPS_FOR_ALIGN = ["CalFileName", "GroupFilename", "GroupingWorkspace", - "CalibrationWorkspace", "OffsetsWorkspace", - "MaskWorkspace", "MaskBinTable", - "Params", "ResampleX", "Dspacing", "DMin", "DMax", - "TMin", "TMax", "PreserveEvents", - "RemovePromptPulseWidth", "CompressTolerance", - "UnwrapRef", "LowResRef", - "CropWavelengthMin", "CropWavelengthMax", - "LowResSpectrumOffset", "ReductionProperties"] -PROPS_FOR_ALIGN.extend(PROPS_FOR_INSTR) - - -def determineChunking(filename, chunkSize): - chunks = DetermineChunking(Filename=filename, MaxChunkSize=chunkSize, OutputWorkspace='chunks') - - strategy = [] - for row in chunks: - strategy.append(row) - - # For table with no rows - if len(strategy) == 0: - strategy.append({}) - - # delete chunks workspace - chunks = str(chunks) - DeleteWorkspace(Workspace='chunks') - - return strategy - - -class AlignAndFocusPowderFromFiles(DataProcessorAlgorithm): - def category(self): - return "Diffraction\\Reduction" - - def name(self): - return "AlignAndFocusPowderFromFiles" - - def summary(self): - """ - summary of the algorithm - :return: - """ - return "The algorithm used for reduction of powder diffraction data" - - def PyInit(self): - self.declareProperty(MultipleFileProperty(name="Filename", - extensions=EXTENSIONS_NXS), - "Files to combine in reduction") - self.declareProperty("MaxChunkSize", 0., - "Specify maximum Gbytes of file to read in one chunk. Default is whole file.") - self.declareProperty("FilterBadPulses", 0., - doc="Filter out events measured while proton charge is more than 5% below average") - - self.declareProperty(MatrixWorkspaceProperty('AbsorptionWorkspace', '', - Direction.Input, PropertyMode.Optional), - doc='Divide data by this Pixel-by-pixel workspace') - - self.declareProperty(FileProperty(name="CacheDirectory",defaultValue="", - action=FileAction.OptionalDirectory)) - - self.declareProperty(MatrixWorkspaceProperty('OutputWorkspace', '', - Direction.Output), - doc='Combined output workspace') - - self.declareProperty(ITableWorkspaceProperty('Characterizations', '', - Direction.Input, PropertyMode.Optional), - 'Characterizations table') - - self.copyProperties("AlignAndFocusPowder", PROPS_FOR_ALIGN) - - def _getLinearizedFilenames(self, propertyName): - runnumbers = self.getProperty(propertyName).value - linearizedRuns = [] - for item in runnumbers: - if type(item) == list: - linearizedRuns.extend(item) - else: - linearizedRuns.append(item) - return linearizedRuns - - def __getAlignAndFocusArgs(self): - args = {} - for name in PROPS_FOR_ALIGN: - prop = self.getProperty(name) - if name == 'PreserveEvents' or not prop.isDefault: - args[name] = prop.value - return args - - def __determineCharacterizations(self, filename, wkspname): - tempname = '__%s_temp' % wkspname - Load(Filename=filename, OutputWorkspace=tempname, - MetaDataOnly=True) - if self.charac is not None: - PDDetermineCharacterizations(InputWorkspace=tempname, - Characterizations=self.charac, - ReductionProperties=self.getProperty('ReductionProperties').valueAsStr) - else: - PDDetermineCharacterizations(InputWorkspace=tempname, - ReductionProperties=self.getProperty('ReductionProperties').valueAsStr) - DeleteWorkspace(Workspace=tempname) - - def __getCacheName(self, wkspname): - propman_properties = ['bank', 'd_min', 'd_max', 'tof_min', 'tof_max', 'wavelength_min', 'wavelength_max'] - alignandfocusargs = [] - for name in PROPS_FOR_ALIGN: - prop = self.getProperty(name) - if name == 'PreserveEvents' or not prop.isDefault: - # TODO need unique identifier for absorption workspace - alignandfocusargs.append('%s=%s' % (name, prop.valueAsStr)) - - return CreateCacheFilename(Prefix=wkspname, - PropertyManager=self.getProperty('ReductionProperties').valueAsStr, - Properties=propman_properties, - OtherProperties=alignandfocusargs, - CacheDir=self.getProperty('CacheDirectory').value).OutputFilename - - def __processFile(self, filename, wkspname, file_prog_start): - chunks = determineChunking(filename, self.chunkSize) - self.log().information('Processing \'%s\' in %d chunks' % (filename, len(chunks))) - prog_per_chunk_step = self.prog_per_file * 1./(6.*float(len(chunks))) # for better progress reporting - 6 steps per chunk - - # inner loop is over chunks - for (j, chunk) in enumerate(chunks): - prog_start = file_prog_start + float(j) * 5. * prog_per_chunk_step - chunkname = "%s_c%d" % (wkspname, j) - Load(Filename=filename, OutputWorkspace=chunkname, - startProgress=prog_start, endProgress=prog_start+prog_per_chunk_step, - **chunk) - prog_start += prog_per_chunk_step - if self.filterBadPulses > 0.: - FilterBadPulses(InputWorkspace=chunkname, OutputWorkspace=chunkname, - LowerCutoff=self.filterBadPulses, - startProgress=prog_start, endProgress=prog_start+prog_per_chunk_step) - prog_start += prog_per_chunk_step - - # absorption correction workspace - if self.absorption is not None and len(str(self.absorption)) > 0: - ConvertUnits(InputWorkspace=chunkname, OutputWorkspace=chunkname, - Target='Wavelength', EMode='Elastic') - Divide(LHSWorkspace=chunkname, RHSWorkspace=self.absorption, OutputWorkspace=chunkname, - startProgress=prog_start, endProgress=prog_start+prog_per_chunk_step) - ConvertUnits(InputWorkspace=chunkname, OutputWorkspace=chunkname, - Target='TOF', EMode='Elastic') - prog_start += prog_per_chunk_step - - AlignAndFocusPowder(InputWorkspace=chunkname, OutputWorkspace=chunkname, - startProgress=prog_start, endProgress=prog_start+2.*prog_per_chunk_step, - **self.kwargs) - prog_start += 2.*prog_per_chunk_step # AlignAndFocusPowder counts for two steps - - if j == 0: - RenameWorkspace(InputWorkspace=chunkname, OutputWorkspace=wkspname) - else: - Plus(LHSWorkspace=wkspname, RHSWorkspace=chunkname, OutputWorkspace=wkspname, - ClearRHSWorkspace=self.kwargs['PreserveEvents'], - startProgress=prog_start, endProgress=prog_start+prog_per_chunk_step) - DeleteWorkspace(Workspace=chunkname) - if self.kwargs['PreserveEvents']: - CompressEvents(InputWorkspace=wkspname, OutputWorkspace=wkspname) - # end of inner loop - - def PyExec(self): - filenames = self._getLinearizedFilenames('Filename') - self.filterBadPulses = self.getProperty('FilterBadPulses').value - self.chunkSize = self.getProperty('MaxChunkSize').value - self.absorption = self.getProperty('AbsorptionWorkspace').value - self.charac = self.getProperty('Characterizations').value - finalname = self.getProperty('OutputWorkspace').valueAsStr - - self.prog_per_file = 1./float(len(filenames)) # for better progress reporting - - # these are also passed into the child-algorithms - self.kwargs = self.__getAlignAndFocusArgs() - - # outer loop creates chunks to load - for (i, filename) in enumerate(filenames): - # default name is based off of filename - wkspname = os.path.split(filename)[-1].split('.')[0] - self.__determineCharacterizations(filename, wkspname) - cachefile = self.__getCacheName(wkspname) - wkspname += '_f%d' % i # add file number to be unique - - if os.path.exists(cachefile): - LoadNexusProcessed(Filename=cachefile, OutputWorkspace=wkspname) - # TODO SaveNexuProcessed/LoadNexusProcessed have a bug - editinstrargs = {} - for name in PROPS_FOR_INSTR: - prop = self.getProperty(name) - if not prop.isDefault: - editinstrargs[name] = prop.value - EditInstrumentGeometry(Workspace=wkspname, **editinstrargs) - else: - self.__processFile(filename, wkspname, self.prog_per_file*float(i)) - SaveNexusProcessed(InputWorkspace=wkspname, Filename=cachefile) - - # accumulate runs - if i == 0: - if wkspname != finalname: - RenameWorkspace(InputWorkspace=wkspname, OutputWorkspace=finalname) - else: - Plus(LHSWorkspace=finalname, RHSWorkspace=wkspname, OutputWorkspace=finalname, - ClearRHSWorkspace=self.kwargs['PreserveEvents']) - DeleteWorkspace(Workspace=wkspname) - if self.kwargs['PreserveEvents']: - CompressEvents(InputWorkspace=finalname, OutputWorkspace=finalname) - - # set the output workspace - self.setProperty('OutputWorkspace', mtd[finalname]) - -# Register algorithm with Mantid. -AlgorithmFactory.subscribe(AlignAndFocusPowderFromFiles) diff --git a/Framework/PythonInterface/plugins/algorithms/AlignAndFocusPowderFromFiles.py b/Framework/PythonInterface/plugins/algorithms/AlignAndFocusPowderFromFiles.py index 3235626de90e5b876d9ac5271fb31ec4ec34c084..618d56cb144180049de10bcaa7faad25510d5aab 100644 --- a/Framework/PythonInterface/plugins/algorithms/AlignAndFocusPowderFromFiles.py +++ b/Framework/PythonInterface/plugins/algorithms/AlignAndFocusPowderFromFiles.py @@ -1,12 +1,15 @@ from __future__ import (absolute_import, division, print_function) -from mantid.api import mtd, AlgorithmFactory, DataProcessorAlgorithm, ITableWorkspaceProperty, MatrixWorkspaceProperty, MultipleFileProperty, PropertyMode +from mantid.api import mtd, AlgorithmFactory, DataProcessorAlgorithm, ITableWorkspaceProperty, \ + MatrixWorkspaceProperty, FileAction, FileProperty, MultipleFileProperty, PropertyMode from mantid.kernel import Direction -from mantid.simpleapi import AlignAndFocusPowder, CompressEvents, ConvertUnits, DeleteWorkspace, DetermineChunking, Divide, FilterBadPulses, Load, PDDetermineCharacterizations, Plus, RenameWorkspace +from mantid.simpleapi import AlignAndFocusPowder, CompressEvents, ConvertUnits, CreateCacheFilename, \ + DeleteWorkspace, DetermineChunking, Divide, EditInstrumentGeometry, FilterBadPulses, Load, \ + LoadNexusProcessed, PDDetermineCharacterizations, Plus, RenameWorkspace, SaveNexusProcessed import os EXTENSIONS_NXS = ["_event.nxs", ".nxs.h5"] - +PROPS_FOR_INSTR = ["PrimaryFlightPath", "SpectrumIDs", "L2", "Polar", "Azimuthal"] PROPS_FOR_ALIGN = ["CalFileName", "GroupFilename", "GroupingWorkspace", "CalibrationWorkspace", "OffsetsWorkspace", "MaskWorkspace", "MaskBinTable", @@ -15,8 +18,9 @@ PROPS_FOR_ALIGN = ["CalFileName", "GroupFilename", "GroupingWorkspace", "RemovePromptPulseWidth", "CompressTolerance", "UnwrapRef", "LowResRef", "CropWavelengthMin", "CropWavelengthMax", - "PrimaryFlightPath", "SpectrumIDs", "L2", "Polar", "Azimuthal", "LowResSpectrumOffset", "ReductionProperties"] +PROPS_FOR_ALIGN.extend(PROPS_FOR_INSTR) + def determineChunking(filename, chunkSize): chunks = DetermineChunking(Filename=filename, MaxChunkSize=chunkSize, OutputWorkspace='chunks') @@ -35,6 +39,7 @@ def determineChunking(filename, chunkSize): return strategy + class AlignAndFocusPowderFromFiles(DataProcessorAlgorithm): def category(self): return "Diffraction\\Reduction" @@ -61,6 +66,10 @@ class AlignAndFocusPowderFromFiles(DataProcessorAlgorithm): self.declareProperty(MatrixWorkspaceProperty('AbsorptionWorkspace', '', Direction.Input, PropertyMode.Optional), doc='Divide data by this Pixel-by-pixel workspace') + + self.declareProperty(FileProperty(name="CacheDirectory",defaultValue="", + action=FileAction.OptionalDirectory)) + self.declareProperty(MatrixWorkspaceProperty('OutputWorkspace', '', Direction.Output), doc='Combined output workspace') @@ -81,7 +90,7 @@ class AlignAndFocusPowderFromFiles(DataProcessorAlgorithm): linearizedRuns.append(item) return linearizedRuns - def getAlignAndFocusArgs(self): + def __getAlignAndFocusArgs(self): args = {} for name in PROPS_FOR_ALIGN: prop = self.getProperty(name) @@ -89,56 +98,114 @@ class AlignAndFocusPowderFromFiles(DataProcessorAlgorithm): args[name] = prop.value return args + def __determineCharacterizations(self, filename, wkspname): + tempname = '__%s_temp' % wkspname + Load(Filename=filename, OutputWorkspace=tempname, + MetaDataOnly=True) + if self.charac is not None: + PDDetermineCharacterizations(InputWorkspace=tempname, + Characterizations=self.charac, + ReductionProperties=self.getProperty('ReductionProperties').valueAsStr) + else: + PDDetermineCharacterizations(InputWorkspace=tempname, + ReductionProperties=self.getProperty('ReductionProperties').valueAsStr) + DeleteWorkspace(Workspace=tempname) + + def __getCacheName(self, wkspname): + propman_properties = ['bank', 'd_min', 'd_max', 'tof_min', 'tof_max', 'wavelength_min', 'wavelength_max'] + alignandfocusargs = [] + for name in PROPS_FOR_ALIGN: + prop = self.getProperty(name) + if name == 'PreserveEvents' or not prop.isDefault: + # TODO need unique identifier for absorption workspace + alignandfocusargs.append('%s=%s' % (name, prop.valueAsStr)) + + return CreateCacheFilename(Prefix=wkspname, + PropertyManager=self.getProperty('ReductionProperties').valueAsStr, + Properties=propman_properties, + OtherProperties=alignandfocusargs, + CacheDir=self.getProperty('CacheDirectory').value).OutputFilename + + def __processFile(self, filename, wkspname, file_prog_start): + chunks = determineChunking(filename, self.chunkSize) + self.log().information('Processing \'%s\' in %d chunks' % (filename, len(chunks))) + prog_per_chunk_step = self.prog_per_file * 1./(6.*float(len(chunks))) # for better progress reporting - 6 steps per chunk + + # inner loop is over chunks + for (j, chunk) in enumerate(chunks): + prog_start = file_prog_start + float(j) * 5. * prog_per_chunk_step + chunkname = "%s_c%d" % (wkspname, j) + Load(Filename=filename, OutputWorkspace=chunkname, + startProgress=prog_start, endProgress=prog_start+prog_per_chunk_step, + **chunk) + prog_start += prog_per_chunk_step + if self.filterBadPulses > 0.: + FilterBadPulses(InputWorkspace=chunkname, OutputWorkspace=chunkname, + LowerCutoff=self.filterBadPulses, + startProgress=prog_start, endProgress=prog_start+prog_per_chunk_step) + prog_start += prog_per_chunk_step + + # absorption correction workspace + if self.absorption is not None and len(str(self.absorption)) > 0: + ConvertUnits(InputWorkspace=chunkname, OutputWorkspace=chunkname, + Target='Wavelength', EMode='Elastic') + Divide(LHSWorkspace=chunkname, RHSWorkspace=self.absorption, OutputWorkspace=chunkname, + startProgress=prog_start, endProgress=prog_start+prog_per_chunk_step) + ConvertUnits(InputWorkspace=chunkname, OutputWorkspace=chunkname, + Target='TOF', EMode='Elastic') + prog_start += prog_per_chunk_step + + AlignAndFocusPowder(InputWorkspace=chunkname, OutputWorkspace=chunkname, + startProgress=prog_start, endProgress=prog_start+2.*prog_per_chunk_step, + **self.kwargs) + prog_start += 2.*prog_per_chunk_step # AlignAndFocusPowder counts for two steps + + if j == 0: + RenameWorkspace(InputWorkspace=chunkname, OutputWorkspace=wkspname) + else: + Plus(LHSWorkspace=wkspname, RHSWorkspace=chunkname, OutputWorkspace=wkspname, + ClearRHSWorkspace=self.kwargs['PreserveEvents'], + startProgress=prog_start, endProgress=prog_start+prog_per_chunk_step) + DeleteWorkspace(Workspace=chunkname) + if self.kwargs['PreserveEvents']: + CompressEvents(InputWorkspace=wkspname, OutputWorkspace=wkspname) + # end of inner loop + def PyExec(self): filenames = self._getLinearizedFilenames('Filename') - filterBadPulses = self.getProperty('FilterBadPulses').value - chunkSize = self.getProperty('MaxChunkSize').value - absorption = self.getProperty('AbsorptionWorkspace').value - charac = self.getProperty('Characterizations').value + self.filterBadPulses = self.getProperty('FilterBadPulses').value + self.chunkSize = self.getProperty('MaxChunkSize').value + self.absorption = self.getProperty('AbsorptionWorkspace').value + self.charac = self.getProperty('Characterizations').value finalname = self.getProperty('OutputWorkspace').valueAsStr + self.prog_per_file = 1./float(len(filenames)) # for better progress reporting + # these are also passed into the child-algorithms - kwargs = self.getAlignAndFocusArgs() + self.kwargs = self.__getAlignAndFocusArgs() # outer loop creates chunks to load for (i, filename) in enumerate(filenames): - wkspname = os.path.split(filename)[-1].split('.')[0] + '_' + str(i) - chunks = determineChunking(filename, chunkSize) - - # inner loop is over chunks - for (j, chunk) in enumerate(chunks): - chunkname = "%s_chunk%d" % (wkspname, j) - Load(Filename=filename, OutputWorkspace=chunkname, **chunk) - if filterBadPulses > 0.: - FilterBadPulses(InputWorkspace=chunkname, OutputWorkspace=chunkname, - LowerCutoff=filterBadPulses) - - # TODO only do once per file - if j == 0 and charac is not None: - PDDetermineCharacterizations(InputWorkspace=chunkname, - Characterizations=charac, - ReductionProperties=self.getProperty('ReductionProperties').valueAsStr) - - # absorption correction workspace - if absorption is not None and len(str(absorption)) > 0: - ConvertUnits(InputWorkspace=chunkname, OutputWorkspace=chunkname, - Target='Wavelength', EMode='Elastic') - Divide(LHSWorkspace=chunkname, RHSWorkspace=absorption, OutputWorkspace=chunkname) - ConvertUnits(InputWorkspace=chunkname, OutputWorkspace=chunkname, - Target='TOF', EMode='Elastic') - - AlignAndFocusPowder(InputWorkspace=chunkname, OutputWorkspace=chunkname, **kwargs) - - - if j == 0: - RenameWorkspace(InputWorkspace=chunkname, OutputWorkspace=wkspname) - else: - Plus(LHSWorkspace=wkspname, RHSWorkspace=chunkname, OutputWorkspace=wkspname, - ClearRHSWorkspace=kwargs['PreserveEvents']) - DeleteWorkspace(Workspace=chunkname) - if kwargs['PreserveEvents']: - CompressEvents(InputWorkspace=wkspname, OutputWorkspace=wkspname) - # end of inner loop + # default name is based off of filename + wkspname = os.path.split(filename)[-1].split('.')[0] + self.__determineCharacterizations(filename, wkspname) + cachefile = self.__getCacheName(wkspname) + wkspname += '_f%d' % i # add file number to be unique + + if os.path.exists(cachefile): + LoadNexusProcessed(Filename=cachefile, OutputWorkspace=wkspname) + # TODO LoadNexusProcessed has a bug. When it finds the + # instrument name without xml it reads in from an IDF + # in the instrument directory. + editinstrargs = {} + for name in PROPS_FOR_INSTR: + prop = self.getProperty(name) + if not prop.isDefault: + editinstrargs[name] = prop.value + EditInstrumentGeometry(Workspace=wkspname, **editinstrargs) + else: + self.__processFile(filename, wkspname, self.prog_per_file*float(i)) + SaveNexusProcessed(InputWorkspace=wkspname, Filename=cachefile) # accumulate runs if i == 0: @@ -146,9 +213,9 @@ class AlignAndFocusPowderFromFiles(DataProcessorAlgorithm): RenameWorkspace(InputWorkspace=wkspname, OutputWorkspace=finalname) else: Plus(LHSWorkspace=finalname, RHSWorkspace=wkspname, OutputWorkspace=finalname, - ClearRHSWorkspace=kwargs['PreserveEvents']) + ClearRHSWorkspace=self.kwargs['PreserveEvents']) DeleteWorkspace(Workspace=wkspname) - if kwargs['PreserveEvents']: + if self.kwargs['PreserveEvents']: CompressEvents(InputWorkspace=finalname, OutputWorkspace=finalname) # set the output workspace