From d075c038a9408cf67c50855fffe3e6123813f626 Mon Sep 17 00:00:00 2001 From: Ian Bush Date: Wed, 18 Feb 2015 18:16:27 +0000 Subject: [PATCH] Refs #11116 Moved more into MDReductionWrapper class. --- .../Inelastic/Direct/MDReductionWrapper.py | 133 ++++++++++++++---- .../test/MerlinAccumulateMDReduction.py | 87 +----------- 2 files changed, 114 insertions(+), 106 deletions(-) diff --git a/Code/Mantid/scripts/Inelastic/Direct/MDReductionWrapper.py b/Code/Mantid/scripts/Inelastic/Direct/MDReductionWrapper.py index d1a20736cb94..ba59c5313fbd 100644 --- a/Code/Mantid/scripts/Inelastic/Direct/MDReductionWrapper.py +++ b/Code/Mantid/scripts/Inelastic/Direct/MDReductionWrapper.py @@ -1,3 +1,6 @@ +import os +import time + from ReductionWrapper import * class MDReductionWrapper(ReductionWrapper): @@ -7,9 +10,10 @@ class MDReductionWrapper(ReductionWrapper): def __init__(self, instrumentName, web_var = None): super(MDReductionWrapper, self).__init__(instrumentName, web_var = None) - # Create a file with the filename and path, with a '.lock' extension, to indicate file in use, - # unless this already exists, in which case do nothing and return False def lock_obtained(self, fname): + """Create a file with the filename and path, with a '.lock' extension, to indicate + file in use, unless this already exists, in which case do nothing and return False + """ if not os.path.isfile(fname + '.lock'): lock_file = open(fname + '.lock', 'w') lock_file.close() @@ -17,30 +21,34 @@ def lock_obtained(self, fname): else: return False - # Remove lock file, exception will be thrown if this does not exist def release_lock(self, fname): + """Remove lock file, exception will be thrown if this does not exist + """ os.remove(fname + '.lock') - # The table below shows the valid combinations for controlling the run numbers. - # N = number of accumulated MD files to produce (e.g. Run Range Starts is a list of N integers). - # _______________ - # ____________________________|_1_|_2_|_3_|_4_| - # | 'Run Range Starts' | N | N | N | 1 | - # | 'Run Range Ends' | N | - | - | - | - # | 'Number of Runs to Merge' | - | N | 1 | 1 | - # --------------------------------------------- - # - # If file_run_number is between range_starts and range_ends return the range and MD file number (0...N-1), - # as a tuple or return -1, -1, -1 if the run number is not in a range asked for def get_file_number(self, file_run_number, range_starts, range_ends): + """ The table below shows the valid combinations for controlling the run numbers. + N = number of accumulated MD files to produce (e.g. Run Range Starts is a list of N integers). + _______________ + ____________________________|_1_|_2_|_3_|_4_| + | 'Run Range Starts' | N | N | N | 1 | + | 'Run Range Ends' | N | - | - | - | + | 'Number of Runs to Merge' | - | N | 1 | 1 | + --------------------------------------------- + + If file_run_number is between range_starts and range_ends return the range and MD file number (0...N-1), + as a tuple or return -1, -1, -1 if the run number is not in a range asked for + """ + for i in range(0, len(range_starts)): if ((file_run_number >= range_starts[i]) and (file_run_number <= range_ends[i])): return i, range_starts[i], range_ends[i] return -1, -1, -1 - # If number_of_runs_to_merge is given return the run range and MD file number (0...N-1) as a tuple, - # or return -1, -1, -1 if the range is not as asked for def get_file_number_alternative(self, file_run_number, range_starts, number_of_runs_to_merge): + """ If number_of_runs_to_merge is given return the run range and MD file number (0...N-1) as a tuple, + or return -1, -1, -1 if the range is not as asked for + """ if (len(range_starts) == 1 and len(number_of_runs_to_merge) == 1): if (file_run_number < range_starts[0]): return -1, -1, -1 @@ -60,23 +68,25 @@ def get_file_number_alternative(self, file_run_number, range_starts, number_of_r raise Exception("Size of range_starts, ", len(range_starts), " and number_of_runs_to_merge, ", len(number_of_runs_to_merge), " are incompatible") - # If MD:Filenames is set return the appropriate filename, else return a filename such as 123_456_SQW.nxs def get_file_name(self, file_number, start, end): + """ If MD:Filenames is set return the appropriate filename, else return a filename such as 123_456_SQW.nxs + """ file_names = self._wvs.advanced_vars.get('MD:Filenames') if (file_names is None or len(file_names) == 0): return str(start) + '_' + str(end) + '_SQW.nxs' else: return file_names[file_number] - # For psi allowed combinations are shown below - # N = number of accumulated MD files to produce (e.g. Psi Starts is a list of N integers). - # ___________ - # ___________________|_1_|_2_|_3_| - # | 'Psi Starts' | N | N | 1 | - # | 'Psi Increments' | 1 | N | 1 | - # -------------------------------- - # def get_psi(self, file_number, file_run_number, start, end): + """ For psi allowed combinations are shown below + N = number of accumulated MD files to produce (e.g. Psi Starts is a list of N integers). + ___________ + ___________________|_1_|_2_|_3_| + | 'Psi Starts' | N | N | 1 | + | 'Psi Increments' | 1 | N | 1 | + -------------------------------- + """ + psi_starts = self._wvs.advanced_vars.get('MD:Psi Starts') psi_increments = self._wvs.advanced_vars.get('MD:Psi Increments') @@ -90,6 +100,79 @@ def get_psi(self, file_number, file_run_number, start, end): raise Exception("Size of psi_starts, ", len(psi_starts), " and psi_increments, ", len(psi_increments), " are incompatible") + def convert_and_merge(self, input_file, input_dir, file_run_number): + """ Does the conversion process to a filebacked MD file, first working out the file + names required + """ + # Process ranges to merge into something more useful + range_starts = self._wvs.advanced_vars.get('MD:Run Range Starts') + range_ends = self._wvs.advanced_vars.get('MD:Run Range Ends') + number_of_runs_to_merge = self._wvs.advanced_vars.get('MD:Number of Runs to Merge') + + if (len(range_ends) == 0): + file_number, start, end = self.get_file_number_alternative(file_run_number, range_starts, number_of_runs_to_merge) + else: + file_number, start, end = self.get_file_number(file_run_number, range_starts, range_ends) + + merged_filename = input_dir + '/../' + self.get_file_name(file_number, start, end) + + psi = self.get_psi(file_number, file_run_number, start, end) + + ub_matrix = self._wvs.advanced_vars.get('MD:UB Matrix') + + # Convert to an MD workspace and merge into the big file + loaded_ws = Load(Filename = input_file) + + # UB matrix contains lattice and the beam direction + SetUB(Workspace = loaded_ws, a = ub_matrix[0], b = ub_matrix[1], c = ub_matrix[2]) + + # Add crystal rotation logging + # str(float(psi)) psi and can be saved as a number + AddSampleLog(Workspace = loaded_ws, LogName = 'Psi', LogText = str(float(psi)), LogType = 'Number') + + # Set crystal rotation + SetGoniometer(Workspace = loaded_ws, Axis0 = 'Psi, 0, 1, 0, 1') + + # Convert to MD + # If these values need to be changed they can be set in def_advanced_properties + # on the reduction class + pars = dict(); + pars['InputWorkspace']='loaded_ws' + pars['QDimensions']='Q3D' + pars['dEAnalysisMode']='Direct' + pars['Q3DFrames']='HKL' + pars['QConversionScales']='HKL' + pars['PreprocDetectorsWS']='preprDetMantid' + pars['MinValues']=self._wvs.advanced_vars.get('MD:Minimum Extents') + pars['MaxValues']=self._wvs.advanced_vars.get('MD:Maximum Extents') + pars['SplitInto']=50 + pars['MaxRecursionDepth']=1 + pars['MinRecursionDepth']=1 + pars['OutputWorkspace'] = 'merged_ws' + + # Get the lock on the output file. Can obtain this whether or not the file exists yet. + # If lock is not obtained sleep for 10s. TODO: should this timeout? + # In case of problems will need to delete the lock file manually. + while(not self.lock_obtained(merged_filename)): + print "Waiting for lock on ", merged_filename + time.sleep(10) + + # Load the output file if it exists, create it otherwise + if (os.path.exists(merged_filename)): + merged_ws = LoadMD(Filename = merged_filename, FileBackEnd = True) + pars['OverwriteExisting'] = False + else: + pars['OverwriteExisting'] = True + + merged_ws = ConvertToMD(**pars) + + # Save the files + if pars.get('OverwriteExisting'): + SaveMD(merged_ws, Filename = merged_filename, MakeFileBacked = True) + else: + SaveMD(merged_ws, Filename = merged_filename, UpdateFileBackEnd = True) + # Release the file lock now. + self.release_lock(merged_filename) diff --git a/Code/Mantid/scripts/test/MerlinAccumulateMDReduction.py b/Code/Mantid/scripts/test/MerlinAccumulateMDReduction.py index 27d6456e4950..090292d541a8 100644 --- a/Code/Mantid/scripts/test/MerlinAccumulateMDReduction.py +++ b/Code/Mantid/scripts/test/MerlinAccumulateMDReduction.py @@ -1,11 +1,8 @@ """ MERLIN reduction script which also creates Merged MD files """ -import time -import os - ### Only required for running locally ### -import sys -sys.path.insert(0,'/home/whb43145/Mantid/mantid-develop/Code/Mantid/scripts/Inelastic') +#import sys +#sys.path.insert(0,'/home/whb43145/Mantid/mantid-develop/Code/Mantid/scripts/Inelastic') #sys.path.insert(0,'/home/whb43145/autoreduction_test_production') from Direct.MDReductionWrapper import * @@ -67,7 +64,6 @@ def def_advanced_properties(self): def main(self, input_file = None, output_directory = None, output_file = None): # run reduction, write auxiliary script to add something here. outWS = ReductionWrapper.reduce(input_file, output_directory) - #SaveNexus(outWS, Filename = output_file) # When run from web service, instead return additional path for web server to copy data to return outWS @@ -76,85 +72,13 @@ def __init__(self, web_var = None): """ sets properties defaults for the instrument with Name""" super(ReduceMERLIN, self).__init__('MER',web_var) -def convert_and_merge(rd, input_file, input_dir, file_run_number): - - # Process ranges to merge into something more useful - range_starts = web_var.advanced_vars.get('MD:Run Range Starts') - range_ends = web_var.advanced_vars.get('MD:Run Range Ends') - number_of_runs_to_merge = web_var.advanced_vars.get('MD:Number of Runs to Merge') - - if (len(range_ends) == 0): - file_number, start, end = rd.get_file_number_alternative(file_run_number, range_starts, number_of_runs_to_merge) - else: - file_number, start, end = rd.get_file_number(file_run_number, range_starts, range_ends) - - merged_filename = input_dir + '/../' + rd.get_file_name(file_number, start, end) - - psi = rd.get_psi(file_number, file_run_number, start, end) - - ub_matrix = web_var.advanced_vars.get('MD:UB Matrix') - - # Convert to an MD workspace and merge into the big file - loaded_ws = Load(Filename = input_file) - - # UB matrix contains lattice and the beam direction - SetUB(Workspace = loaded_ws, a = ub_matrix[0], b = ub_matrix[1], c = ub_matrix[2]) - - # Add crystal rotation logging - # str(float(psi)) psi and can be saved as a number - AddSampleLog(Workspace = loaded_ws, LogName = 'Psi', LogText = str(float(psi)), LogType = 'Number') - - # Set crystal rotation - SetGoniometer(Workspace = loaded_ws, Axis0 = 'Psi, 0, 1, 0, 1') - - # Convert to MD - # If these values need to be changed they can be set in def_advanced_properties - # on the reduction class - pars = dict(); - pars['InputWorkspace']='loaded_ws' - pars['QDimensions']='Q3D' - pars['dEAnalysisMode']='Direct' - pars['Q3DFrames']='HKL' - pars['QConversionScales']='HKL' - pars['PreprocDetectorsWS']='preprDetMantid' - pars['MinValues']=web_var.advanced_vars.get('MD:Minimum Extents') - pars['MaxValues']=web_var.advanced_vars.get('MD:Maximum Extents') - pars['SplitInto']=50 - pars['MaxRecursionDepth']=1 - pars['MinRecursionDepth']=1 - pars['OutputWorkspace'] = 'merged_ws' - - # Get the lock on the output file. Can obtain this whether or not the file exists yet. - # If lock is not obtained sleep for 10s. TODO: should this timeout? - # In case of problems will need to delete the lock file manually. - while(not rd.lock_obtained(merged_filename)): - print "Waiting for lock on ", merged_filename - time.sleep(10) - - # Load the output file if it exists, create it otherwise - if (os.path.exists(merged_filename)): - merged_ws = LoadMD(Filename = merged_filename, FileBackEnd = True) - pars['OverwriteExisting'] = False - else: - pars['OverwriteExisting'] = True - - merged_ws = ConvertToMD(**pars) - - # Save the files - if pars.get('OverwriteExisting'): - SaveMD(merged_ws, Filename = merged_filename, MakeFileBacked = True) - else: - SaveMD(merged_ws, Filename = merged_filename, UpdateFileBackEnd = True) - - # Release the file lock now. - rd.release_lock(merged_filename) # This is called by the autoreduction script itself def reduce(input_file, output_dir): # Define any extra directories needed for maps files etc. (not needed for running through autoreduction server) ### Only required for running locally ### - maps_dir = '/home/whb43145/Mantid/RAW_to_SPE/MERLIN/masks' + #maps_dir = '/home/whb43145/Mantid/RAW_to_SPE/MERLIN/masks' input_path, input_filename = os.path.split(input_file) @@ -162,7 +86,8 @@ def reduce(input_file, output_dir): file_run_number = int(input_filename.split('MER')[1].split('.')[0]) ### Only required for running locally ### - config.setDataSearchDirs('{0};{1};{2}'.format(input_path,output_dir,maps_dir)) + #config.setDataSearchDirs('{0};{1};{2}'.format(input_path,output_dir,maps_dir)) + config['defaultsave.directory'] = output_dir.encode('ascii','replace') # folder to save resulting spe/nxspe files rd = ReduceMERLIN(web_var) @@ -180,7 +105,7 @@ def reduce(input_file, output_dir): outWS = rd.reduce(input_file, output_dir) if (web_var.advanced_vars.get('MD:Accumulate to MD file')): - convert_and_merge(rd, output_filename, output_dir, file_run_number) + rd.convert_and_merge(output_filename, output_dir, file_run_number) return None # Can make this an additional save directory