| 1 | """ | 
|---|
| 2 |     Enables the SANS commands (listed at http://www.mantidproject.org/SANS) to | 
|---|
| 3 |     be run | 
|---|
| 4 | """ | 
|---|
| 5 | import isis_instrument | 
|---|
| 6 | from reducer_singleton import ReductionSingleton | 
|---|
| 7 | from mantid.kernel import Logger | 
|---|
| 8 | sanslog = Logger("SANS") | 
|---|
| 9 |  | 
|---|
| 10 | import isis_reduction_steps | 
|---|
| 11 | import isis_reducer | 
|---|
| 12 | from centre_finder import CentreFinder as CentreFinder | 
|---|
| 13 | #import SANSReduction | 
|---|
| 14 | from mantid.simpleapi import * | 
|---|
| 15 | from mantid.api import WorkspaceGroup | 
|---|
| 16 | import copy | 
|---|
| 17 | from SANSadd2 import * | 
|---|
| 18 | import SANSUtility as su | 
|---|
| 19 | from SANSUtility import deprecated | 
|---|
| 20 |  | 
|---|
| 21 | # disable plotting if running outside Mantidplot | 
|---|
| 22 | try: | 
|---|
| 23 |     import mantidplot | 
|---|
| 24 | except: | 
|---|
| 25 |     mantidplot = None | 
|---|
| 26 |     #this should happen when this is called from outside Mantidplot and only then, the result is that attempting to plot will raise an exception | 
|---|
| 27 |     pass | 
|---|
| 28 |  | 
|---|
| 29 | try: | 
|---|
| 30 |     from PyQt4.QtGui import qApp | 
|---|
| 31 |     def appwidgets(): | 
|---|
| 32 |         return qApp.allWidgets() | 
|---|
| 33 | except ImportError: | 
|---|
| 34 |     def appwidgets(): | 
|---|
| 35 |         return [] | 
|---|
| 36 |  | 
|---|
| 37 | _VERBOSE_ = False | 
|---|
| 38 | LAST_SAMPLE = None | 
|---|
| 39 | def SetVerboseMode(state): | 
|---|
| 40 | #TODO: this needs to be on the reducer | 
|---|
| 41 |     _VERBOSE_ = state | 
|---|
| 42 |  | 
|---|
| 43 | # Print a message and log it if the | 
|---|
| 44 | def _printMessage(msg, log = True, no_console=False): | 
|---|
| 45 |     if log == True and _VERBOSE_ == True: | 
|---|
| 46 |         sanslog.notice(msg) | 
|---|
| 47 |     if not no_console: | 
|---|
| 48 |         print msg | 
|---|
| 49 |  | 
|---|
| 50 | def issueWarning(msg): | 
|---|
| 51 |     """ | 
|---|
| 52 |         Issues a Mantid message | 
|---|
| 53 |         @param msg: message to be issued | 
|---|
| 54 |     """ | 
|---|
| 55 |     isis_reduction_steps._issueWarning(msg) | 
|---|
| 56 |  | 
|---|
| 57 | def _refresh_singleton(): | 
|---|
| 58 |     ReductionSingleton.clean(isis_reducer.ISISReducer) | 
|---|
| 59 |     ReductionSingleton().remove_settings() | 
|---|
| 60 |  | 
|---|
| 61 | def Clean(): | 
|---|
| 62 |     """ | 
|---|
| 63 |     An exposed command to allow cleaning of the reducer, and any related | 
|---|
| 64 |     settings. | 
|---|
| 65 |     """ | 
|---|
| 66 |     _refresh_singleton() | 
|---|
| 67 |  | 
|---|
| 68 | def SANS2D(idf_path=None): | 
|---|
| 69 |     """ | 
|---|
| 70 |         Initialises the instrument settings for SANS2D | 
|---|
| 71 |         @param idf_path :: optionally specify the path to the SANS2D IDF to use. | 
|---|
| 72 |                            Uses default if none specified. | 
|---|
| 73 |         @return True on success | 
|---|
| 74 |     """ | 
|---|
| 75 |     _printMessage('SANS2D()') | 
|---|
| 76 |     try: | 
|---|
| 77 |         instrument = isis_instrument.SANS2D(idf_path) | 
|---|
| 78 |  | 
|---|
| 79 |         ReductionSingleton().set_instrument(instrument) | 
|---|
| 80 |         config['default.instrument']='SANS2D' | 
|---|
| 81 |     except: | 
|---|
| 82 |         return False | 
|---|
| 83 |     return True | 
|---|
| 84 |  | 
|---|
| 85 | def SANS2DTUBES(): | 
|---|
| 86 |     """ | 
|---|
| 87 |     Quick, temporary workaround for the IDF problem we're fixing in #9367. | 
|---|
| 88 |     Simply pass the correct IDF to SANS2D(). | 
|---|
| 89 |     """ | 
|---|
| 90 |     return SANS2D("SANS2D_Definition_Tubes.xml") | 
|---|
| 91 |  | 
|---|
| 92 | def LOQ(): | 
|---|
| 93 |     """ | 
|---|
| 94 |         Initialises the instrument settings for LOQ | 
|---|
| 95 |         @return True on success | 
|---|
| 96 |     """ | 
|---|
| 97 |     _printMessage('LOQ()') | 
|---|
| 98 |     try: | 
|---|
| 99 |         instrument = isis_instrument.LOQ() | 
|---|
| 100 |  | 
|---|
| 101 |         ReductionSingleton().set_instrument(instrument) | 
|---|
| 102 |         config['default.instrument']='LOQ' | 
|---|
| 103 |     except: | 
|---|
| 104 |         return False | 
|---|
| 105 |     return True | 
|---|
| 106 |  | 
|---|
| 107 | def LARMOR(): | 
|---|
| 108 |     """ | 
|---|
| 109 |     Initialises the instrument settings for LARMOR | 
|---|
| 110 |     @return True on success | 
|---|
| 111 |     """ | 
|---|
| 112 |     _printMessage('LARMOR()') | 
|---|
| 113 |     try: | 
|---|
| 114 |         instrument = isis_instrument.LARMOR() | 
|---|
| 115 |  | 
|---|
| 116 |         ReductionSingleton().set_instrument(instrument) | 
|---|
| 117 |         config['default.instrument']='LARMOR' | 
|---|
| 118 |     except: | 
|---|
| 119 |         return False | 
|---|
| 120 |     return True | 
|---|
| 121 |  | 
|---|
| 122 | def Detector(det_name): | 
|---|
| 123 |     """ | 
|---|
| 124 |         Sets the detector bank to use for the reduction e.g. 'front-detector'. The | 
|---|
| 125 |         main detector is assumed if this line is not given | 
|---|
| 126 |         @param det_name: the detector's name | 
|---|
| 127 |     """ | 
|---|
| 128 |     _printMessage('Detector("' + det_name + '")') | 
|---|
| 129 |     ReductionSingleton().instrument.setDetector(det_name) | 
|---|
| 130 |  | 
|---|
| 131 | def Mask(details): | 
|---|
| 132 |     """ | 
|---|
| 133 |         Specify regions of the detector to mask using the same syntax | 
|---|
| 134 |         as used in the user file | 
|---|
| 135 |         @param details: a string that specifies masking as it would appear in a mask file | 
|---|
| 136 |     """ | 
|---|
| 137 |     _printMessage('Mask("' + details + '")') | 
|---|
| 138 |     ReductionSingleton().mask.parse_instruction(ReductionSingleton().instrument.name(),details) | 
|---|
| 139 |  | 
|---|
| 140 | def MaskFile(file_name): | 
|---|
| 141 |     """ | 
|---|
| 142 |         Loads the settings file. The settings are loaded as soon as this line is encountered | 
|---|
| 143 |         and are overridden by other Python commands | 
|---|
| 144 |         @param file_name: the settings file | 
|---|
| 145 |     """ | 
|---|
| 146 |     _printMessage('#Opening "'+file_name+'"') | 
|---|
| 147 |  | 
|---|
| 148 |     # ensure that no slice string is kept from previous executions. | 
|---|
| 149 |     ReductionSingleton().setSlicesLimits("") | 
|---|
| 150 |  | 
|---|
| 151 |     ReductionSingleton().user_settings = isis_reduction_steps.UserFile( | 
|---|
| 152 |         file_name) | 
|---|
| 153 |     status = ReductionSingleton().user_settings.execute( | 
|---|
| 154 |         ReductionSingleton(), None) | 
|---|
| 155 |     _printMessage('#Success reading "'+file_name+'"'+' is '+str(status)) | 
|---|
| 156 |     return status | 
|---|
| 157 |  | 
|---|
| 158 | def SetMonitorSpectrum(specNum, interp=False): | 
|---|
| 159 |     """ | 
|---|
| 160 |         Specifies the spectrum number of the spectrum that will be used to | 
|---|
| 161 |         for monitor normalisation | 
|---|
| 162 |         @param specNum: a spectrum number (1 or greater) | 
|---|
| 163 |         @param interp: when rebinning the wavelength bins to match the main workspace, if use interpolation default no interpolation | 
|---|
| 164 |     """ | 
|---|
| 165 |     ReductionSingleton().set_monitor_spectrum(specNum, interp) | 
|---|
| 166 |  | 
|---|
| 167 | def SetTransSpectrum(specNum, interp=False): | 
|---|
| 168 |     ReductionSingleton().set_trans_spectrum(specNum, interp) | 
|---|
| 169 |  | 
|---|
| 170 | def SetSampleOffset(value): | 
|---|
| 171 |     ReductionSingleton().instrument.set_sample_offset(value) | 
|---|
| 172 |  | 
|---|
| 173 | def Gravity(flag): | 
|---|
| 174 |     _printMessage('Gravity(' + str(flag) + ')') | 
|---|
| 175 |     ReductionSingleton().to_Q.set_gravity(flag) | 
|---|
| 176 |  | 
|---|
| 177 | def SetFrontDetRescaleShift(scale=1.0, shift=0.0, fitScale=False, fitShift=False, qMin=None, qMax=None): | 
|---|
| 178 |     """ | 
|---|
| 179 |         Stores property about the detector which is used to rescale and shift | 
|---|
| 180 |         data in the bank after data have been reduced | 
|---|
| 181 |         @param scale: Default to 1.0. Value to multiply data with | 
|---|
| 182 |         @param shift: Default to 0.0. Value to add to data | 
|---|
| 183 |         @param fitScale: Default is False. Whether or not to try and fit this param | 
|---|
| 184 |         @param fitShift: Default is False. Whether or not to try and fit this param | 
|---|
| 185 |         @param qMin: When set to None (default) then for fitting use the overlapping q region of front and rear detectors | 
|---|
| 186 |         @param qMax: When set to None (default) then for fitting use the overlapping q region of front and rear detectors | 
|---|
| 187 |     """ | 
|---|
| 188 |     ReductionSingleton().instrument.getDetector('FRONT').rescaleAndShift = ReductionSingleton().instrument.getDetector('FRONT')._RescaleAndShift( | 
|---|
| 189 |         scale, shift, fitScale, fitShift, qMin, qMax) | 
|---|
| 190 |     _printMessage('#Set front detector rescale/shift values') | 
|---|
| 191 |  | 
|---|
| 192 | def TransFit(mode,lambdamin=None,lambdamax=None, selector='BOTH'): | 
|---|
| 193 |     """ | 
|---|
| 194 |         Sets the fit method to calculate the transmission fit and the wavelength range | 
|---|
| 195 |         over which to do the fit. These arguments are passed to the algorithm | 
|---|
| 196 |         CalculateTransmission. If mode is set to 'Off' then the unfitted workspace is | 
|---|
| 197 |         used and lambdamin and max have no effect | 
|---|
| 198 |         @param mode: can be 'Logarithmic' ('YLOG', 'LOG') 'OFF' ('CLEAR') or 'LINEAR' (STRAIGHT', LIN'), 'POLYNOMIAL2', 'POLYNOMIAL3', ... | 
|---|
| 199 |         @param lambdamin: the lowest wavelength to use in any fit | 
|---|
| 200 |         @param lambdamax: the end of the fit range | 
|---|
| 201 |         @param selector: define for which transmission this fit specification is valid (BOTH, SAMPLE, CAN) | 
|---|
| 202 |     """ | 
|---|
| 203 |     mode = str(mode).strip().upper() | 
|---|
| 204 |     message = mode | 
|---|
| 205 |     if lambdamin: message += ', ' + str(lambdamin) | 
|---|
| 206 |     if lambdamax: message += ', ' + str(lambdamax) | 
|---|
| 207 |     message += ', selector=' + selector | 
|---|
| 208 |     _printMessage("TransFit(\"" + message + "\")") | 
|---|
| 209 |  | 
|---|
| 210 |     ReductionSingleton().set_trans_fit(lambdamin, lambdamax, mode, selector) | 
|---|
| 211 |  | 
|---|
| 212 | def TransWorkspace(sample, can = None): | 
|---|
| 213 |     """ | 
|---|
| 214 |         Use a given workpspace that contains pre-calculated transmissions | 
|---|
| 215 |         @param sample the workspace to use for the sample | 
|---|
| 216 |         @param can calculated transmission for the can | 
|---|
| 217 |     """ | 
|---|
| 218 |     ReductionSingleton().transmission_calculator.calculated_samp = sample | 
|---|
| 219 |     ReductionSingleton().transmission_calculator.calculated_can = can | 
|---|
| 220 |  | 
|---|
| 221 | def _return_old_compatibility_assign_methods(ws_name): | 
|---|
| 222 |     """For backward compatibility, AssignCan and AssignSample returns a tuple | 
|---|
| 223 |     with workspace name and the log entry if available. | 
|---|
| 224 |  | 
|---|
| 225 |     In the future, those methods should return just workspace name | 
|---|
| 226 |     """ | 
|---|
| 227 |     logs = "" | 
|---|
| 228 |     if isinstance(ReductionSingleton().instrument, isis_instrument.SANS2D): | 
|---|
| 229 |         try: | 
|---|
| 230 |             logs = ReductionSingleton().instrument.get_detector_log(ws_name) | 
|---|
| 231 |         except: | 
|---|
| 232 |             pass | 
|---|
| 233 |     return ws_name, logs | 
|---|
| 234 |  | 
|---|
| 235 | def AssignCan(can_run, reload = True, period = isis_reduction_steps.LoadRun.UNSET_PERIOD): | 
|---|
| 236 |     """ | 
|---|
| 237 |         The can is a scattering run under the same conditions as the experimental run but the | 
|---|
| 238 |         only the sample container is in the sample position. Hence allowing the effect of the | 
|---|
| 239 |         container to be removed. The run is specified using instrumentrunnumber.extension, | 
|---|
| 240 |         e.g. SANS2D7777.nxs. On calling this function the run is loaded to a workspace and the | 
|---|
| 241 |         detector banks and other components moved as applicable. Currently only reload=true is | 
|---|
| 242 |         supported. | 
|---|
| 243 |         @param can_run: run number to analysis e.g. SANS2D7777.nxs | 
|---|
| 244 |         @param reload: must be set to True | 
|---|
| 245 |         @param period: the period (entry) number to load, default is the first period | 
|---|
| 246 |     """ | 
|---|
| 247 |     mes = 'AssignCan("' + str(can_run) + '"' | 
|---|
| 248 |     if period != isis_reduction_steps.LoadRun.UNSET_PERIOD: | 
|---|
| 249 |         mes += ', ' + str(period) | 
|---|
| 250 |     mes += ')' | 
|---|
| 251 |     _printMessage(mes) | 
|---|
| 252 |  | 
|---|
| 253 |     ReductionSingleton().set_can(can_run, reload, period) | 
|---|
| 254 |     return _return_old_compatibility_assign_methods( | 
|---|
| 255 |         ReductionSingleton().get_can().wksp_name) | 
|---|
| 256 |  | 
|---|
| 257 | def TransmissionSample(sample, direct, reload = True, period_t = -1, period_d = -1): | 
|---|
| 258 |     """ | 
|---|
| 259 |         Specify the transmission and direct runs for the sample | 
|---|
| 260 |         @param sample: the transmission run | 
|---|
| 261 |         @param direct: direct run | 
|---|
| 262 |         @param reload: if to replace the workspace if it is already there | 
|---|
| 263 |         @param period_t: the entry number of the transmission run (default single entry file) | 
|---|
| 264 |         @param period_d: the entry number of the direct run (default single entry file) | 
|---|
| 265 |     """ | 
|---|
| 266 |     _printMessage('TransmissionSample("' + str(sample) + '","' + str(direct) + '")') | 
|---|
| 267 |     ReductionSingleton().set_trans_sample(sample, direct, reload, period_t, period_d) | 
|---|
| 268 |     return ReductionSingleton().samp_trans_load.execute( | 
|---|
| 269 |                                         ReductionSingleton(), None) | 
|---|
| 270 |  | 
|---|
| 271 | def TransmissionCan(can, direct, reload = True, period_t = -1, period_d = -1): | 
|---|
| 272 |     """ | 
|---|
| 273 |         Specify the transmission and direct runs for the can | 
|---|
| 274 |         @param can: the transmission run | 
|---|
| 275 |         @param direct: direct run | 
|---|
| 276 |         @param reload: if to replace the workspace if it is already there | 
|---|
| 277 |         @param period_t: the entry number of the transmission run (default single entry file) | 
|---|
| 278 |         @param period_d: the entry number of the direct run (default single entry file) | 
|---|
| 279 |     """ | 
|---|
| 280 |     _printMessage('TransmissionCan("' + str(can) + '","' + str(direct) + '")') | 
|---|
| 281 |     ReductionSingleton().set_trans_can(can, direct, reload, period_t, period_d) | 
|---|
| 282 |     return ReductionSingleton().can_trans_load.execute( | 
|---|
| 283 |                                             ReductionSingleton(), None) | 
|---|
| 284 |  | 
|---|
| 285 | def AssignSample(sample_run, reload = True, period = isis_reduction_steps.LoadRun.UNSET_PERIOD): | 
|---|
| 286 |     """ | 
|---|
| 287 |         Specifies the run to analyse using the format instrumentrunnumber.extension, | 
|---|
| 288 |         e.g. SANS2D7777.nxs. This is one of the few commands that executes Mantid algorithms | 
|---|
| 289 |         when called. Currently only reload=true is supported. | 
|---|
| 290 |         @param sample_run: run number to analysis e.g. SANS2D7777.nxs | 
|---|
| 291 |         @param reload: must be set to True | 
|---|
| 292 |         @param period: the period (entry) number to load, default is the first period | 
|---|
| 293 |     """ | 
|---|
| 294 |     mes = 'AssignSample("' + str(sample_run) + '"' | 
|---|
| 295 |     if period != isis_reduction_steps.LoadRun.UNSET_PERIOD: | 
|---|
| 296 |         mes += ', ' + str(period) | 
|---|
| 297 |     mes += ')' | 
|---|
| 298 |     _printMessage(mes) | 
|---|
| 299 |  | 
|---|
| 300 |     ReductionSingleton().set_sample(sample_run, reload, period) | 
|---|
| 301 |  | 
|---|
| 302 |     global LAST_SAMPLE | 
|---|
| 303 |     LAST_SAMPLE = ReductionSingleton().get_sample().wksp_name | 
|---|
| 304 |     return _return_old_compatibility_assign_methods(LAST_SAMPLE) | 
|---|
| 305 |  | 
|---|
| 306 | def SetCentre(xcoord, ycoord, bank = 'rear'): | 
|---|
| 307 |     """ | 
|---|
| 308 |     Configure the Beam Center position. It support the configuration of the centre for | 
|---|
| 309 |     the both detectors bank (low-angle bank and high-angle bank detectors) | 
|---|
| 310 |  | 
|---|
| 311 |     It allows defining the position for both detector banks. | 
|---|
| 312 |     :param xcoord: X position of beam center in the user coordinate system. | 
|---|
| 313 |     :param ycoord: Y position of beam center in the user coordinate system. | 
|---|
| 314 |     :param bank: The selected bank ('rear' - low angle or 'front' - high angle) | 
|---|
| 315 |     Introduced #5942 | 
|---|
| 316 |     """ | 
|---|
| 317 |     _printMessage('SetCentre(' + str(xcoord) + ', ' + str(ycoord) + ')') | 
|---|
| 318 |  | 
|---|
| 319 |     ReductionSingleton().set_beam_finder(isis_reduction_steps.BaseBeamFinder( | 
|---|
| 320 |                                 float(xcoord)/1000.0, float(ycoord)/1000.0), bank) | 
|---|
| 321 |  | 
|---|
| 322 | def GetMismatchedDetList(): | 
|---|
| 323 |     """ | 
|---|
| 324 |         Return the list of mismatched detector names | 
|---|
| 325 |     """ | 
|---|
| 326 |     return ReductionSingleton().instrument.get_marked_dets() | 
|---|
| 327 |  | 
|---|
| 328 | def WavRangeReduction(wav_start=None, wav_end=None, full_trans_wav=None, name_suffix=None, combineDet=None, resetSetup=True, out_fit_settings = dict()): | 
|---|
| 329 |     """ | 
|---|
| 330 |         Run reduction from loading the raw data to calculating Q. Its optional arguments allows specifics | 
|---|
| 331 |         details to be adjusted, and optionally the old setup is reset at the end. Note if FIT of RESCALE or SHIFT | 
|---|
| 332 |         is selected then both REAR and FRONT detectors are both reduced EXCEPT if only the REAR detector is selected | 
|---|
| 333 |         to be reduced | 
|---|
| 334 |  | 
|---|
| 335 |         @param wav_start: the first wavelength to be in the output data | 
|---|
| 336 |         @param wav_end: the last wavelength in the output data | 
|---|
| 337 |         @param full_trans_wav: if to use a wide wavelength range, the instrument's default wavelength range, for the transmission correction, false by default | 
|---|
| 338 |         @param name_suffix: append the created output workspace with this | 
|---|
| 339 |         @param combineDet: combineDet can be one of the following: | 
|---|
| 340 |                            'rear'                (run one reduction for the 'rear' detector data) | 
|---|
| 341 |                            'front'               (run one reduction for the 'front' detector data, and rescale+shift 'front' data) | 
|---|
| 342 |                            'both'                (run both the above two reductions) | 
|---|
| 343 |                            'merged'              (run the same reductions as 'both' and additionally create a merged data workspace) | 
|---|
| 344 |                             None                 (run one reduction for whatever detector has been set as the current detector | 
|---|
| 345 |                                                   before running this method. If front apply rescale+shift) | 
|---|
| 346 |         @param resetSetup: if true reset setup at the end | 
|---|
| 347 |         @param out_fit_settings: An output parameter. It is used, specially when resetSetup is True, in order to remember the 'scale and fit' of the fitting algorithm. | 
|---|
| 348 |         @return Name of one of the workspaces created | 
|---|
| 349 |     """ | 
|---|
| 350 |     _printMessage('WavRangeReduction(' + str(wav_start) + ', ' + str(wav_end) + ', '+str(full_trans_wav)+')') | 
|---|
| 351 |     # these flags indicate if it is necessary to reduce the front bank, the rear bank and if it is supposed to merge them | 
|---|
| 352 |     reduce_rear_flag = False | 
|---|
| 353 |     reduce_front_flag = False | 
|---|
| 354 |     merge_flag = False | 
|---|
| 355 |  | 
|---|
| 356 |     retWSname_rear, retWSname_front, retWSname_merged = ["", "", ""] | 
|---|
| 357 |  | 
|---|
| 358 |     # combineDet from None to 'rear' or 'front' | 
|---|
| 359 |     if combineDet is None: | 
|---|
| 360 |         if ReductionSingleton().instrument.cur_detector().isAlias('FRONT'): | 
|---|
| 361 |             combineDet = 'front' | 
|---|
| 362 |         else: | 
|---|
| 363 |             combineDet = 'rear' | 
|---|
| 364 |  | 
|---|
| 365 |     if not full_trans_wav is None: | 
|---|
| 366 |         ReductionSingleton().full_trans_wav = full_trans_wav | 
|---|
| 367 |  | 
|---|
| 368 |     ReductionSingleton().to_wavelen.set_range(wav_start, wav_end) | 
|---|
| 369 |  | 
|---|
| 370 |     rAnds = ReductionSingleton().instrument.getDetector('FRONT').rescaleAndShift | 
|---|
| 371 |     # check if fit is required. | 
|---|
| 372 |     fitRequired = False | 
|---|
| 373 |     if rAnds.fitScale or rAnds.fitShift: | 
|---|
| 374 |         fitRequired = True | 
|---|
| 375 |  | 
|---|
| 376 |     com_det_option = combineDet.lower() | 
|---|
| 377 |  | 
|---|
| 378 |     # the only special case where reduce rear is not required is | 
|---|
| 379 |     # if the user chose to reduce front and does not require fit | 
|---|
| 380 |     if not (com_det_option == 'front' and not fitRequired): | 
|---|
| 381 |         reduce_rear_flag = True | 
|---|
| 382 |     if (com_det_option != 'rear'): | 
|---|
| 383 |         reduce_front_flag = True | 
|---|
| 384 |     if (com_det_option == 'merged'): | 
|---|
| 385 |         merge_flag = True | 
|---|
| 386 |  | 
|---|
| 387 |     #The shift and scale is always on the front detector. | 
|---|
| 388 |     if not reduce_front_flag: | 
|---|
| 389 |         fitRequired = False | 
|---|
| 390 |  | 
|---|
| 391 |     #To backup value of singleton which are temporarily modified in this method | 
|---|
| 392 |     toRestoreAfterAnalysis = ReductionSingleton().instrument.cur_detector().name() | 
|---|
| 393 |     toRestoreOutputParts = ReductionSingleton().to_Q.outputParts | 
|---|
| 394 |  | 
|---|
| 395 |     # if 'merged' then when cross section is calculated output the two individual parts | 
|---|
| 396 |     # of the cross section. These additional outputs are required to calculate | 
|---|
| 397 |     # the merged workspace | 
|---|
| 398 |     if merge_flag: | 
|---|
| 399 |         ReductionSingleton().to_Q.outputParts = True | 
|---|
| 400 |  | 
|---|
| 401 |     # do reduce rear bank data | 
|---|
| 402 |     if reduce_rear_flag: | 
|---|
| 403 |         ReductionSingleton().instrument.setDetector('rear') | 
|---|
| 404 |         retWSname_rear = _WavRangeReduction(name_suffix) | 
|---|
| 405 |         retWSname = retWSname_rear | 
|---|
| 406 |  | 
|---|
| 407 |     # do reduce front bank | 
|---|
| 408 |     if reduce_front_flag: | 
|---|
| 409 |         # it is necessary to replace the Singleton if a reduction was done before | 
|---|
| 410 |         if (reduce_rear_flag): | 
|---|
| 411 |             # In this case, it is necessary to reload the files, in order to move the components to the | 
|---|
| 412 |             # correct position defined by its get_beam_center. (ticket #5942) | 
|---|
| 413 |  | 
|---|
| 414 |             # first copy the settings | 
|---|
| 415 |             ReductionSingleton.replace(ReductionSingleton().cur_settings()) | 
|---|
| 416 |  | 
|---|
| 417 |             # for the LOQ instrument, if the beam centers are different, we have to reload the data. | 
|---|
| 418 |             if (ReductionSingleton().instrument._NAME == 'LOQ' and | 
|---|
| 419 |                (ReductionSingleton().get_beam_center('rear') != ReductionSingleton().get_beam_center('front'))): | 
|---|
| 420 |  | 
|---|
| 421 |                 # It is necessary to reload sample, transmission and can files. | 
|---|
| 422 |                 #reload sample | 
|---|
| 423 |                 issueWarning('Trying to reload workspaces') | 
|---|
| 424 |                 ReductionSingleton().instrument.setDetector('front') | 
|---|
| 425 |                 ReductionSingleton()._sample_run.reload(ReductionSingleton()) | 
|---|
| 426 |                 #reassign can | 
|---|
| 427 |                 if ReductionSingleton().get_can(): | 
|---|
| 428 |                     ReductionSingleton().get_can().reload(ReductionSingleton()) | 
|---|
| 429 |                 if ReductionSingleton().samp_trans_load: | 
|---|
| 430 |                     #refresh Transmission | 
|---|
| 431 |                     ReductionSingleton().samp_trans_load.execute(ReductionSingleton(), None) | 
|---|
| 432 |                 if ReductionSingleton().can_trans_load: | 
|---|
| 433 |                     ReductionSingleton().can_trans_load.execute(ReductionSingleton(),None) | 
|---|
| 434 |  | 
|---|
| 435 |         ReductionSingleton().instrument.setDetector('front') | 
|---|
| 436 |  | 
|---|
| 437 |         retWSname_front = _WavRangeReduction(name_suffix) | 
|---|
| 438 |         retWSname = retWSname_front | 
|---|
| 439 |  | 
|---|
| 440 |     # do fit and scale if required | 
|---|
| 441 |     if fitRequired: | 
|---|
| 442 |         scale, shift = _fitRescaleAndShift(rAnds, retWSname_front, retWSname_rear) | 
|---|
| 443 |         ReductionSingleton().instrument.getDetector('FRONT').rescaleAndShift.shift = shift | 
|---|
| 444 |         ReductionSingleton().instrument.getDetector('FRONT').rescaleAndShift.scale = scale | 
|---|
| 445 |         if scale < 0: | 
|---|
| 446 |             issueWarning("Fit returned SCALE negative") | 
|---|
| 447 |  | 
|---|
| 448 |     shift = ReductionSingleton().instrument.getDetector('FRONT').rescaleAndShift.shift | 
|---|
| 449 |     scale = ReductionSingleton().instrument.getDetector('FRONT').rescaleAndShift.scale | 
|---|
| 450 |  | 
|---|
| 451 |     # apply the merge algorithm | 
|---|
| 452 |     if merge_flag: | 
|---|
| 453 |         retWSname_merged = retWSname_rear | 
|---|
| 454 |         if retWSname_merged.count('rear') == 1: | 
|---|
| 455 |           retWSname_merged = retWSname_merged.replace('rear', 'merged') | 
|---|
| 456 |         else: | 
|---|
| 457 |           retWSname_merged = retWSname_merged + "_merged" | 
|---|
| 458 |  | 
|---|
| 459 |         Nf = mtd[retWSname_front+"_sumOfNormFactors"] | 
|---|
| 460 |         Nr = mtd[retWSname_rear+"_sumOfNormFactors"] | 
|---|
| 461 |         Cf = mtd[retWSname_front+"_sumOfCounts"] | 
|---|
| 462 |         Cr = mtd[retWSname_rear+"_sumOfCounts"] | 
|---|
| 463 |         consider_can = True | 
|---|
| 464 |         try: | 
|---|
| 465 |             Nf_can = mtd[retWSname_front+"_can_tmp_sumOfNormFactors"] | 
|---|
| 466 |             Nr_can = mtd[retWSname_rear+"_can_tmp_sumOfNormFactors"] | 
|---|
| 467 |             Cf_can = mtd[retWSname_front+"_can_tmp_sumOfCounts"] | 
|---|
| 468 |             Cr_can = mtd[retWSname_rear+"_can_tmp_sumOfCounts"] | 
|---|
| 469 |             if Cr_can is None: | 
|---|
| 470 |                 consider_can = False | 
|---|
| 471 |         except KeyError : | 
|---|
| 472 |             #The CAN was not specified | 
|---|
| 473 |             consider_can = False | 
|---|
| 474 |  | 
|---|
| 475 |  | 
|---|
| 476 |         fisF = mtd[retWSname_front] | 
|---|
| 477 |         fisR = mtd[retWSname_rear] | 
|---|
| 478 |  | 
|---|
| 479 |         minQ = min(min(fisF.dataX(0)), min(fisR.dataX(0))) | 
|---|
| 480 |         maxQ = max(max(fisF.dataX(0)), max(fisR.dataX(0))) | 
|---|
| 481 |  | 
|---|
| 482 |         if maxQ > minQ: | 
|---|
| 483 |             #preparing the sample | 
|---|
| 484 |             Nf = CropWorkspace(InputWorkspace=Nf, OutputWorkspace=Nf, XMin=minQ, XMax=maxQ) | 
|---|
| 485 |             Nr = CropWorkspace(InputWorkspace=Nr, OutputWorkspace=Nr, XMin=minQ, XMax=maxQ) | 
|---|
| 486 |             Cf = CropWorkspace(InputWorkspace=Cf, OutputWorkspace=Cf, XMin=minQ, XMax=maxQ) | 
|---|
| 487 |             Cr = CropWorkspace(InputWorkspace=Cr, OutputWorkspace=Cr, XMin=minQ, XMax=maxQ) | 
|---|
| 488 |             if consider_can: | 
|---|
| 489 |                 #preparing the can | 
|---|
| 490 |                 Nf_can = CropWorkspace(InputWorkspace=Nf_can, OutputWorkspace=Nf_can, XMin=minQ, XMax=maxQ) | 
|---|
| 491 |                 Nr_can = CropWorkspace(InputWorkspace=Nr_can, OutputWorkspace=Nr_can, XMin=minQ, XMax=maxQ) | 
|---|
| 492 |                 Cf_can = CropWorkspace(InputWorkspace=Cf_can, OutputWorkspace=Cf_can, XMin=minQ, XMax=maxQ) | 
|---|
| 493 |                 Cr_can = CropWorkspace(InputWorkspace=Cr_can, OutputWorkspace=Cr_can, XMin=minQ, XMax=maxQ) | 
|---|
| 494 |  | 
|---|
| 495 |             mergedQ = (Cf+shift*Nf+Cr)/(Nf/scale + Nr) | 
|---|
| 496 |             if consider_can: | 
|---|
| 497 |                 mergedQ -= (Cf_can+Cr_can)/(Nf_can/scale + Nr_can) | 
|---|
| 498 |  | 
|---|
| 499 |             RenameWorkspace(InputWorkspace=mergedQ,OutputWorkspace= retWSname_merged) | 
|---|
| 500 |  | 
|---|
| 501 |             # save the properties Transmission and TransmissionCan inside the merged workspace | 
|---|
| 502 |             # get these values from the rear_workspace because they are the same value as the front one. | 
|---|
| 503 |             # ticket #6929 | 
|---|
| 504 |             rear_ws = mtd[retWSname_rear] | 
|---|
| 505 |             for prop in ['Transmission','TransmissionCan']: | 
|---|
| 506 |                 if rear_ws.getRun().hasProperty(prop): | 
|---|
| 507 |                     ws_name = rear_ws.getRun().getLogData(prop).value | 
|---|
| 508 |                     if mtd.doesExist(ws_name): # ensure the workspace has not been deleted | 
|---|
| 509 |                         AddSampleLog(Workspace=retWSname_merged,LogName= prop, LogText=ws_name) | 
|---|
| 510 |         else: | 
|---|
| 511 |             issueWarning('rear and front data has no overlapping q-region. Merged workspace no calculated') | 
|---|
| 512 |  | 
|---|
| 513 |         delete_workspaces(retWSname_rear+"_sumOfCounts") | 
|---|
| 514 |         delete_workspaces(retWSname_rear+"_sumOfNormFactors") | 
|---|
| 515 |         delete_workspaces(retWSname_front+"_sumOfCounts") | 
|---|
| 516 |         delete_workspaces(retWSname_front+"_sumOfNormFactors") | 
|---|
| 517 |         if consider_can: | 
|---|
| 518 |             delete_workspaces(retWSname_front+"_can_tmp_sumOfNormFactors") | 
|---|
| 519 |             delete_workspaces(retWSname_rear+"_can_tmp_sumOfNormFactors") | 
|---|
| 520 |             delete_workspaces(retWSname_front+"_can_tmp_sumOfCounts") | 
|---|
| 521 |             delete_workspaces(retWSname_rear+"_can_tmp_sumOfCounts") | 
|---|
| 522 |  | 
|---|
| 523 |         retWSname = retWSname_merged | 
|---|
| 524 |  | 
|---|
| 525 |     #applying scale and shift on the front detector reduced data | 
|---|
| 526 |     if reduce_front_flag: | 
|---|
| 527 |         frontWS = mtd[retWSname_front] | 
|---|
| 528 |         frontWS = (frontWS+shift)*scale | 
|---|
| 529 |         RenameWorkspace(InputWorkspace=frontWS,OutputWorkspace= retWSname_front) | 
|---|
| 530 |  | 
|---|
| 531 |     # finished calculating cross section so can restore these value | 
|---|
| 532 |     ReductionSingleton().to_Q.outputParts = toRestoreOutputParts | 
|---|
| 533 |     ReductionSingleton().instrument.setDetector(toRestoreAfterAnalysis) | 
|---|
| 534 |  | 
|---|
| 535 |     # update the scale and shift values of out_fit_settings | 
|---|
| 536 |     out_fit_settings['scale'] = ReductionSingleton().instrument.getDetector('FRONT').rescaleAndShift.scale | 
|---|
| 537 |     out_fit_settings['shift'] = ReductionSingleton().instrument.getDetector('FRONT').rescaleAndShift.shift | 
|---|
| 538 |  | 
|---|
| 539 |     if resetSetup: | 
|---|
| 540 |         _refresh_singleton() | 
|---|
| 541 |  | 
|---|
| 542 |     # Relabel the YUnit of the resulting workspaces before we return anything. | 
|---|
| 543 |     # Depending on the given options, we may have rear, front and merged | 
|---|
| 544 |     # workspaces to handle.  These may also be WorkspaceGroups. | 
|---|
| 545 |     for ws_name in [retWSname_rear, retWSname_front, retWSname_merged]: | 
|---|
| 546 |         if not ws_name in mtd: | 
|---|
| 547 |             continue | 
|---|
| 548 |         ws = mtd[ws_name] | 
|---|
| 549 |         if isinstance(ws, WorkspaceGroup): | 
|---|
| 550 |             relabel_ws_list = [mtd[name] for name in ws.getNames()] | 
|---|
| 551 |         else: | 
|---|
| 552 |             relabel_ws_list = [ws] | 
|---|
| 553 |         for relabel_ws in relabel_ws_list: | 
|---|
| 554 |             relabel_ws.setYUnitLabel("I(q) (cm-1)") | 
|---|
| 555 |  | 
|---|
| 556 |     return retWSname | 
|---|
| 557 |  | 
|---|
| 558 | def _fitRescaleAndShift(rAnds, frontData, rearData): | 
|---|
| 559 |     """ | 
|---|
| 560 |         Fit rear data to FRONTnew(Q) = ( FRONT(Q) + SHIFT )xRESCALE, | 
|---|
| 561 |         FRONT(Q) is the frontData argument. Returns scale and shift | 
|---|
| 562 |  | 
|---|
| 563 |         @param rAnds: A DetectorBank -> _RescaleAndShift structure | 
|---|
| 564 |         @param frontData: Reduced front data | 
|---|
| 565 |         @param rearData: Reduced rear data | 
|---|
| 566 |     """ | 
|---|
| 567 |     if rAnds.fitScale==False and rAnds.fitShift==False: | 
|---|
| 568 |         return rAnds.scale, rAnds.shift | 
|---|
| 569 |     #TODO: we should allow the user to add constraints? | 
|---|
| 570 |     if rAnds.fitScale==False: | 
|---|
| 571 |         if rAnds.qRangeUserSelected: | 
|---|
| 572 |             Fit(InputWorkspace=rearData, | 
|---|
| 573 |                 Function='name=TabulatedFunction, Workspace="'+str(frontData)+'"' | 
|---|
| 574 |                 +";name=FlatBackground", Ties='f0.Scaling='+str(rAnds.scale), | 
|---|
| 575 |                 Output="__fitRescaleAndShift", StartX=rAnds.qMin, EndX=rAnds.qMax) | 
|---|
| 576 |         else: | 
|---|
| 577 |             Fit(InputWorkspace=rearData, | 
|---|
| 578 |                 Function='name=TabulatedFunction, Workspace="'+str(frontData)+'"' | 
|---|
| 579 |                 +";name=FlatBackground", Ties='f0.Scaling='+str(rAnds.scale), | 
|---|
| 580 |                 Output="__fitRescaleAndShift") | 
|---|
| 581 |     elif rAnds.fitShift==False: | 
|---|
| 582 |         if rAnds.qRangeUserSelected: | 
|---|
| 583 |             function_input = 'name=TabulatedFunction, Workspace="'+str(frontData)+'"' +";name=FlatBackground" | 
|---|
| 584 |             ties = 'f1.A0='+str(rAnds.shift*rAnds.scale) | 
|---|
| 585 |             logger.warning('function input ' + str(function_input)) | 
|---|
| 586 |  | 
|---|
| 587 |             Fit(InputWorkspace=rearData, | 
|---|
| 588 |                 Function='name=TabulatedFunction, Workspace="'+str(frontData)+'"' | 
|---|
| 589 |                 +";name=FlatBackground", Ties='f1.A0='+str(rAnds.shift*rAnds.scale), | 
|---|
| 590 |                 Output="__fitRescaleAndShift", StartX=rAnds.qMin, EndX=rAnds.qMax) | 
|---|
| 591 |         else: | 
|---|
| 592 |             Fit(InputWorkspace=rearData, | 
|---|
| 593 |                 Function='name=TabulatedFunction, Workspace="'+str(frontData)+'"' | 
|---|
| 594 |                 +";name=FlatBackground", Ties='f1.A0='+str(rAnds.shift*rAnds.scale), | 
|---|
| 595 |                 Output="__fitRescaleAndShift") | 
|---|
| 596 |     else: | 
|---|
| 597 |         if rAnds.qRangeUserSelected: | 
|---|
| 598 |             Fit(InputWorkspace=rearData, | 
|---|
| 599 |                 Function='name=TabulatedFunction, Workspace="'+str(frontData)+'"' | 
|---|
| 600 |                 +";name=FlatBackground", | 
|---|
| 601 |                 Output="__fitRescaleAndShift", StartX=rAnds.qMin, EndX=rAnds.qMax) | 
|---|
| 602 |         else: | 
|---|
| 603 |             Fit(InputWorkspace=rearData, Function='name=TabulatedFunction, Workspace="'+str(frontData)+'"' | 
|---|
| 604 |                 +";name=FlatBackground",Output="__fitRescaleAndShift") | 
|---|
| 605 |  | 
|---|
| 606 |     param = mtd['__fitRescaleAndShift_Parameters'] | 
|---|
| 607 |  | 
|---|
| 608 |     row1 = param.row(0).items() | 
|---|
| 609 |     row2 = param.row(1).items() | 
|---|
| 610 |     row3 = param.row(2).items() | 
|---|
| 611 |     scale = row1[1][1] | 
|---|
| 612 |     chiSquared = row3[1][1] | 
|---|
| 613 |  | 
|---|
| 614 |     fitSuccess = True | 
|---|
| 615 |     if not chiSquared > 0: | 
|---|
| 616 |         issueWarning("Can't fit front detector RESCALE or SHIFT. Use non fitted values") | 
|---|
| 617 |         fitSuccess = False | 
|---|
| 618 |     if scale == 0.0: | 
|---|
| 619 |         issueWarning("front detector RESCALE fitted to zero. Use non fitted values") | 
|---|
| 620 |         fitSuccess = False | 
|---|
| 621 |  | 
|---|
| 622 |     if fitSuccess == False: | 
|---|
| 623 |         return rAnds.scale, rAnds.shift | 
|---|
| 624 |  | 
|---|
| 625 |     shift = row2[1][1] / scale | 
|---|
| 626 |  | 
|---|
| 627 |     delete_workspaces('__fitRescaleAndShift_Parameters') | 
|---|
| 628 |     delete_workspaces('__fitRescaleAndShift_NormalisedCovarianceMatrix') | 
|---|
| 629 |     delete_workspaces('__fitRescaleAndShift_Workspace') | 
|---|
| 630 |  | 
|---|
| 631 |     return scale, shift | 
|---|
| 632 |  | 
|---|
| 633 | def _WavRangeReduction(name_suffix=None): | 
|---|
| 634 |     """ | 
|---|
| 635 |         Run a reduction that has been set up, from loading the raw data to calculating Q | 
|---|
| 636 |     """ | 
|---|
| 637 |     def _setUpPeriod(period): | 
|---|
| 638 |         assert(ReductionSingleton().get_sample().loader.move2ws(period)) | 
|---|
| 639 |         can = ReductionSingleton().get_can() | 
|---|
| 640 |         if can and can.loader.periods_in_file > 1: | 
|---|
| 641 |             can.loader.move2ws(period) | 
|---|
| 642 |  | 
|---|
| 643 |         for trans in [ReductionSingleton().samp_trans_load, ReductionSingleton().can_trans_load]: | 
|---|
| 644 |             if trans and trans.direct.periods_in_file > 1 and trans.trans.periods_in_file > 1: | 
|---|
| 645 |                 trans.direct.move2ws(period) | 
|---|
| 646 |                 trans.trans.move2next(period) | 
|---|
| 647 |         return | 
|---|
| 648 |  | 
|---|
| 649 |     def _applySuffix(result, name_suffix): | 
|---|
| 650 |         if name_suffix: | 
|---|
| 651 |             old = result | 
|---|
| 652 |             result += name_suffix | 
|---|
| 653 |             RenameWorkspace(InputWorkspace=old,OutputWorkspace= result) | 
|---|
| 654 |         return result | 
|---|
| 655 |  | 
|---|
| 656 |     def _common_substring(val1, val2): | 
|---|
| 657 |         l = [] | 
|---|
| 658 |         for i in range(len(val1)): | 
|---|
| 659 |             if val1[i]==val2[i]: l.append(val1[i]) | 
|---|
| 660 |             else: | 
|---|
| 661 |                 return ''.join(l) | 
|---|
| 662 |  | 
|---|
| 663 |     def _group_workspaces(list_of_values, outputname): | 
|---|
| 664 |         allnames = ','.join(list_of_values) | 
|---|
| 665 |         GroupWorkspaces(InputWorkspaces=allnames, OutputWorkspace=outputname) | 
|---|
| 666 |  | 
|---|
| 667 |     def _reduceAllSlices(): | 
|---|
| 668 |         if ReductionSingleton().getNumSlices() > 1: | 
|---|
| 669 |             slices = [] | 
|---|
| 670 |             for index in range(ReductionSingleton().getNumSlices()): | 
|---|
| 671 |                 ReductionSingleton().setSliceIndex(index) | 
|---|
| 672 |                 slices.append(ReductionSingleton()._reduce()) | 
|---|
| 673 |             ReductionSingleton().setSliceIndex(0) | 
|---|
| 674 |             group_name = _common_substring(slices[0], slices[1]) | 
|---|
| 675 |             if group_name[-2] == "_": | 
|---|
| 676 |                 group_name = group_name[:-2] | 
|---|
| 677 |             _group_workspaces(slices, group_name) | 
|---|
| 678 |             return group_name | 
|---|
| 679 |         else: | 
|---|
| 680 |             return ReductionSingleton()._reduce() | 
|---|
| 681 |  | 
|---|
| 682 |  | 
|---|
| 683 |  | 
|---|
| 684 |     result = "" | 
|---|
| 685 |     if ReductionSingleton().get_sample().loader.periods_in_file == 1: | 
|---|
| 686 |         result = _reduceAllSlices() | 
|---|
| 687 |         return _applySuffix(result, name_suffix) | 
|---|
| 688 |  | 
|---|
| 689 |     calculated = [] | 
|---|
| 690 |     try: | 
|---|
| 691 |         for period in ReductionSingleton().get_sample().loader.entries: | 
|---|
| 692 |             _setUpPeriod(period) | 
|---|
| 693 |             calculated.append(_reduceAllSlices()) | 
|---|
| 694 |  | 
|---|
| 695 |     finally: | 
|---|
| 696 |         if len(calculated) > 0: | 
|---|
| 697 |             result = ReductionSingleton().get_out_ws_name(show_period=False) | 
|---|
| 698 |             _group_workspaces(calculated, result) | 
|---|
| 699 |  | 
|---|
| 700 |     return _applySuffix(result, name_suffix) | 
|---|
| 701 |  | 
|---|
| 702 | def delete_workspaces(workspaces): | 
|---|
| 703 |     """ | 
|---|
| 704 |         Delete the list of workspaces if possible but fail siliently if there is | 
|---|
| 705 |         a problem | 
|---|
| 706 |         @param workspaces: the list to delete | 
|---|
| 707 |     """ | 
|---|
| 708 |     if type(workspaces) != type(list()): | 
|---|
| 709 |         if type(workspaces) != type(tuple()): | 
|---|
| 710 |             workspaces = [workspaces] | 
|---|
| 711 |  | 
|---|
| 712 |     for wksp in workspaces: | 
|---|
| 713 |         if wksp and wksp in mtd: | 
|---|
| 714 |             try: | 
|---|
| 715 |                 DeleteWorkspace(Workspace=wksp) | 
|---|
| 716 |             except: | 
|---|
| 717 |                 #we're only deleting to save memory, if the workspace really won't delete leave it | 
|---|
| 718 |                 pass | 
|---|
| 719 |  | 
|---|
| 720 | def CompWavRanges(wavelens, plot=True, combineDet=None, resetSetup=True): | 
|---|
| 721 |     """ | 
|---|
| 722 |         Compares the momentum transfer results calculated from different wavelength ranges. Given | 
|---|
| 723 |         the list of wave ranges [a, b, c] it reduces for wavelengths a-b, b-c and a-c. | 
|---|
| 724 |         @param wavelens: the list of wavelength ranges | 
|---|
| 725 |         @param plot: set this to true to plot the result (must be run in Mantid), default is true | 
|---|
| 726 |         @param combineDet: see description in WavRangeReduction | 
|---|
| 727 |         @param resetSetup: if true reset setup at the end | 
|---|
| 728 |     """ | 
|---|
| 729 |  | 
|---|
| 730 |     _printMessage('CompWavRanges( %s,plot=%s)'%(str(wavelens),plot)) | 
|---|
| 731 |  | 
|---|
| 732 |     #this only makes sense for 1D reductions | 
|---|
| 733 |     if ReductionSingleton().to_Q.output_type == '2D': | 
|---|
| 734 |         issueWarning('This wave ranges check is a 1D analysis, ignoring 2D setting') | 
|---|
| 735 |         _printMessage('Set1D()') | 
|---|
| 736 |         ReductionSingleton().to_Q.output_type = '1D' | 
|---|
| 737 |  | 
|---|
| 738 |     if type(wavelens) != type([]) or len(wavelens) < 2: | 
|---|
| 739 |         if type(wavelens) != type((1,)): | 
|---|
| 740 |             raise RuntimeError('Error CompWavRanges() requires a list of wavelengths between which reductions will be performed.') | 
|---|
| 741 |  | 
|---|
| 742 |  | 
|---|
| 743 |     calculated = [WavRangeReduction(wav_start=wavelens[0], wav_end=wavelens[len(wavelens)-1], combineDet=combineDet,resetSetup=False)] | 
|---|
| 744 |     for i in range(0, len(wavelens)-1): | 
|---|
| 745 |         calculated.append(WavRangeReduction(wav_start=wavelens[i], wav_end=wavelens[i+1], combineDet=combineDet, resetSetup=False)) | 
|---|
| 746 |  | 
|---|
| 747 |     if resetSetup: | 
|---|
| 748 |         _refresh_singleton() | 
|---|
| 749 |  | 
|---|
| 750 |     if plot and mantidplot: | 
|---|
| 751 |         mantidplot.plotSpectrum(calculated, 0) | 
|---|
| 752 |  | 
|---|
| 753 |     #return just the workspace name of the full range | 
|---|
| 754 |     return calculated[0] | 
|---|
| 755 |  | 
|---|
| 756 | def PhiRanges(phis, plot=True): | 
|---|
| 757 |     """ | 
|---|
| 758 |         Given a list of phi ranges [a, b, c, d] it reduces in the phi ranges a-b and c-d | 
|---|
| 759 |         @param phis: the list of phi ranges | 
|---|
| 760 |         @param plot: set this to true to plot the result (must be run in Mantid), default is true | 
|---|
| 761 |     """ | 
|---|
| 762 |  | 
|---|
| 763 |     _printMessage('PhiRanges( %s,plot=%s)'%(str(phis),plot)) | 
|---|
| 764 |  | 
|---|
| 765 |     #todo covert their string into Python array | 
|---|
| 766 |  | 
|---|
| 767 |     if len(phis)/2 != float(len(phis))/2.: | 
|---|
| 768 |         raise RuntimeError('Phi ranges must be given as pairs') | 
|---|
| 769 |  | 
|---|
| 770 |     try: | 
|---|
| 771 |         #run the reductions, calculated will be an array with the names of all the workspaces produced | 
|---|
| 772 |         calculated = [] | 
|---|
| 773 |         for i in range(0, len(phis), 2): | 
|---|
| 774 |             SetPhiLimit(phis[i],phis[i+1]) | 
|---|
| 775 |             #reducedResult = ReductionSingleton()._reduce() | 
|---|
| 776 |             #RenameWorkspace(reducedResult,'bob') | 
|---|
| 777 |             #calculated.append(reducedResult) | 
|---|
| 778 |             calculated.append(ReductionSingleton()._reduce()) | 
|---|
| 779 |             ReductionSingleton.replace(ReductionSingleton().cur_settings()) | 
|---|
| 780 |     finally: | 
|---|
| 781 |         _refresh_singleton() | 
|---|
| 782 |  | 
|---|
| 783 |     if plot and mantidplot: | 
|---|
| 784 |         mantidplot.plotSpectrum(calculated, 0) | 
|---|
| 785 |  | 
|---|
| 786 |     #return just the workspace name of the full range | 
|---|
| 787 |     return calculated[0] | 
|---|
| 788 |  | 
|---|
| 789 | def Reduce(): | 
|---|
| 790 |     try: | 
|---|
| 791 |         result = ReductionSingleton()._reduce() | 
|---|
| 792 |     finally: | 
|---|
| 793 |         _refresh_singleton() | 
|---|
| 794 |  | 
|---|
| 795 |     return result | 
|---|
| 796 |  | 
|---|
| 797 | def _SetWavelengthRange(start, end): | 
|---|
| 798 |     ReductionSingleton().to_wavelen.set_range(start, end) | 
|---|
| 799 |  | 
|---|
| 800 | def Set1D(): | 
|---|
| 801 |     _printMessage('Set1D()') | 
|---|
| 802 |     ReductionSingleton().set_Q_output_type('1D') | 
|---|
| 803 |  | 
|---|
| 804 | def Set2D(): | 
|---|
| 805 |     _printMessage('Set2D()') | 
|---|
| 806 |     ReductionSingleton().set_Q_output_type('2D') | 
|---|
| 807 |  | 
|---|
| 808 | def SetDetectorFloodFile(filename, detector_name="REAR"): | 
|---|
| 809 |     ReductionSingleton().prep_normalize.setPixelCorrFile(filename, detector_name) | 
|---|
| 810 |  | 
|---|
| 811 | def SetPhiLimit(phimin, phimax, use_mirror=True): | 
|---|
| 812 |     """ | 
|---|
| 813 |         Call this function to restrict the analyse segments of the detector. Phimin and | 
|---|
| 814 |         phimax define the limits of the segment where phi=0 is the -x axis and phi = 90 | 
|---|
| 815 |         is the y-axis. Setting use_mirror to true includes a second segment to be included | 
|---|
| 816 |         it is the same as the first but rotated 180 degrees. | 
|---|
| 817 |         @param phimin: the minimum phi angle to include | 
|---|
| 818 |         @param phimax: the upper limit on phi for the segment | 
|---|
| 819 |         @param use_mirror: when True (default) another segment is included, rotated 180 degrees from the first | 
|---|
| 820 |     """ | 
|---|
| 821 |     _printMessage("SetPhiLimit(" + str(phimin) + ', ' + str(phimax) + ',use_mirror='+str(use_mirror)+')') | 
|---|
| 822 |     #a beam centre of [0,0,0] makes sense if the detector has been moved such that beam centre is at [0,0,0] | 
|---|
| 823 |     ReductionSingleton().mask.set_phi_limit(phimin, phimax, use_mirror) | 
|---|
| 824 |  | 
|---|
| 825 | def SetDetectorOffsets(bank, x, y, z, rot, radius, side, xtilt, ytilt ): | 
|---|
| 826 |     # 19/11/14 RKH added more xtilt & ytilt | 
|---|
| 827 |     """ | 
|---|
| 828 |         Adjust detector position away from position defined in IDF. On SANS2D the detector | 
|---|
| 829 |         banks can be moved around. This method allows fine adjustments of detector bank position | 
|---|
| 830 |         in the same way as the DET/CORR userfile command works. Hence please see | 
|---|
| 831 |         http://www.mantidproject.org/SANS_User_File_Commands#DET for details. | 
|---|
| 832 |  | 
|---|
| 833 |         Note, for now, this command will only have an effect on runs loaded | 
|---|
| 834 |         after this command have been executed (because it is when runs are loaded | 
|---|
| 835 |         that components are moved away from the positions set in the IDF) | 
|---|
| 836 |  | 
|---|
| 837 |         @param bank: Must be either 'front' or 'rear' (not case sensitive) | 
|---|
| 838 |         @param x: shift in mm | 
|---|
| 839 |         @param y: shift in mm | 
|---|
| 840 |         @param z: shift in mm | 
|---|
| 841 |         @param rot: shift in degrees | 
|---|
| 842 |         @param radius: shift in mm | 
|---|
| 843 |         @param side: shift in mm | 
|---|
| 844 |         @param side: xtilt in degrees | 
|---|
| 845 |         @param side: ytilt in degrees | 
|---|
| 846 |     """ | 
|---|
| 847 |     _printMessage("SetDetectorOffsets(" + str(bank) + ', ' + str(x) | 
|---|
| 848 |                   + ','+str(y) + ',' + str(z) + ',' + str(rot) | 
|---|
| 849 |                   + ',' + str(radius) + ',' + str(side) + ',' + str(xtilt)+ ',' + str(ytilt) +')') | 
|---|
| 850 |  | 
|---|
| 851 |     detector = ReductionSingleton().instrument.getDetector(bank) | 
|---|
| 852 |     detector.x_corr = x | 
|---|
| 853 |     detector.y_corr = y | 
|---|
| 854 |     detector.z_corr = z | 
|---|
| 855 |     detector.rot_corr = rot | 
|---|
| 856 |     detector.radius_corr = radius | 
|---|
| 857 |     detector.side_corr = side | 
|---|
| 858 |         # 11/11/14 RKH add 2 more | 
|---|
| 859 |     detector.x_tilt = xtilt | 
|---|
| 860 |     detector.y_tilt = ytilt | 
|---|
| 861 |  | 
|---|
| 862 | def SetCorrectionFile(bank, filename): | 
|---|
| 863 |     # 20/11/14 RKH, create a new routine that allows change of "direct beam file" = correction file, for a given  | 
|---|
| 864 |     # detector, this simplify the iterative process used to adjust it. Will still have to keep changing the name of the file | 
|---|
| 865 |     # for each iteratiom to avoid Mantid using a cached version, but can then use only a single user (=mask) file for each set of iterations. | 
|---|
| 866 |     # Modelled this on SetDetectorOffsets above ... | 
|---|
| 867 |     """ | 
|---|
| 868 |         @param bank: Must be either 'front' or 'rear' (not case sensitive) | 
|---|
| 869 |         @param filename: self explanatory | 
|---|
| 870 |     """ | 
|---|
| 871 |     _printMessage("SetCorrectionFile(" + str(bank) + ', ' + filename +')') | 
|---|
| 872 |  | 
|---|
| 873 |     detector = ReductionSingleton().instrument.getDetector(bank) | 
|---|
| 874 |     detector.correction_file = filename | 
|---|
| 875 |      | 
|---|
| 876 | def LimitsR(rmin, rmax, quiet=False, reducer=None): | 
|---|
| 877 |     if reducer == None: | 
|---|
| 878 |         reducer = ReductionSingleton().reference() | 
|---|
| 879 |  | 
|---|
| 880 |     if not quiet: | 
|---|
| 881 |         _printMessage('LimitsR(' + str(rmin) + ', ' +str(rmax) + ')', reducer) | 
|---|
| 882 |  | 
|---|
| 883 |     reducer.mask.set_radi(rmin, rmax) | 
|---|
| 884 |     reducer.CENT_FIND_RMIN = float(rmin)/1000. | 
|---|
| 885 |     reducer.CENT_FIND_RMAX = float(rmax)/1000. | 
|---|
| 886 |  | 
|---|
| 887 | def LimitsWav(lmin, lmax, step, bin_type): | 
|---|
| 888 |     _printMessage('LimitsWav(' + str(lmin) + ', ' + str(lmax) + ', ' + str(step) + ', '  + bin_type + ')') | 
|---|
| 889 |  | 
|---|
| 890 |     if ( bin_type.upper().strip() == 'LINEAR'): bin_type = 'LIN' | 
|---|
| 891 |     if ( bin_type.upper().strip() == 'LOGARITHMIC'): bin_type = 'LOG' | 
|---|
| 892 |     if bin_type == 'LOG': | 
|---|
| 893 |         bin_sym = '-' | 
|---|
| 894 |     else: | 
|---|
| 895 |         bin_sym = '' | 
|---|
| 896 |  | 
|---|
| 897 |     ReductionSingleton().to_wavelen.set_rebin(lmin, bin_sym + str(step), lmax) | 
|---|
| 898 |  | 
|---|
| 899 | def LimitsQXY(qmin, qmax, step, type): | 
|---|
| 900 |     """ | 
|---|
| 901 |         To set the bin parameters for the algorithm Qxy() | 
|---|
| 902 |         @param qmin: the first Q value to include | 
|---|
| 903 |         @param qmaz: the last Q value to include | 
|---|
| 904 |         @param step: bin width | 
|---|
| 905 |         @param type: pass LOG for logarithmic binning | 
|---|
| 906 |     """ | 
|---|
| 907 |     _printMessage('LimitsQXY(' + str(qmin) + ', ' + str(qmax) +', ' + str(step) + ', ' + str(type) + ')') | 
|---|
| 908 |     settings = ReductionSingleton().user_settings | 
|---|
| 909 |     if settings is None: | 
|---|
| 910 |         raise RuntimeError('MaskFile() first') | 
|---|
| 911 |  | 
|---|
| 912 |     settings.readLimitValues('L/QXY ' + str(qmin) + ' ' + str(qmax) + ' ' + str(step) + '/'  + type, ReductionSingleton()) | 
|---|
| 913 |  | 
|---|
| 914 | def SetEventSlices(input_str): | 
|---|
| 915 |     """ | 
|---|
| 916 |     """ | 
|---|
| 917 |     ReductionSingleton().setSlicesLimits(input_str) | 
|---|
| 918 |  | 
|---|
| 919 |  | 
|---|
| 920 | def PlotResult(workspace, canvas=None): | 
|---|
| 921 |     """ | 
|---|
| 922 |         Draws a graph of the passed workspace. If the workspace is 2D (has many spectra | 
|---|
| 923 |         a contour plot is written | 
|---|
| 924 |         @param workspace: a workspace name or handle to plot | 
|---|
| 925 |         @param canvas: optional handle to an existing graph to write the plot to | 
|---|
| 926 |         @return: a handle to the graph that was written to | 
|---|
| 927 |     """ | 
|---|
| 928 |     if not mantidplot: | 
|---|
| 929 |         issueWarning('Plot functions are not available, is this being run from outside Mantidplot?') | 
|---|
| 930 |         return | 
|---|
| 931 |  | 
|---|
| 932 |     #ensure that we are dealing with a workspace handle rather than its name | 
|---|
| 933 |     workspace = mtd[str(workspace)] | 
|---|
| 934 |     if isinstance(workspace, WorkspaceGroup): | 
|---|
| 935 |         numSpecs = workspace[0].getNumberHistograms() | 
|---|
| 936 |     else: | 
|---|
| 937 |         numSpecs = workspace.getNumberHistograms() | 
|---|
| 938 |  | 
|---|
| 939 |     if numSpecs == 1: | 
|---|
| 940 |         graph = mantidplot.plotSpectrum(workspace,0) | 
|---|
| 941 |     else: | 
|---|
| 942 |         graph = mantidplot.importMatrixWorkspace(workspace.getName()).plotGraph2D() | 
|---|
| 943 |  | 
|---|
| 944 |     if not canvas is None: | 
|---|
| 945 |         #we were given a handle to an existing graph, use it | 
|---|
| 946 |         mantidplot.mergePlots(canvas, graph) | 
|---|
| 947 |         graph = canvas | 
|---|
| 948 |  | 
|---|
| 949 |     return graph | 
|---|
| 950 |  | 
|---|
| 951 | ##################### View mask details ##################################################### | 
|---|
| 952 |  | 
|---|
| 953 | def DisplayMask(mask_worksp=None): | 
|---|
| 954 |     """ | 
|---|
| 955 |         Displays masking by applying it to a workspace and displaying | 
|---|
| 956 |         it in instrument view. If no workspace is passed a copy of the | 
|---|
| 957 |         sample workspace is used, unless no sample was loaded and then | 
|---|
| 958 |         an empty instrument will be shown | 
|---|
| 959 |         @param mask_worksp: optional this named workspace will be modified and should be from the currently selected instrument | 
|---|
| 960 |         @return the name of the workspace that was displayed | 
|---|
| 961 |     """ | 
|---|
| 962 |     #this will be copied from a sample work space if one exists | 
|---|
| 963 |     counts_data = None | 
|---|
| 964 |     instrument = ReductionSingleton().instrument | 
|---|
| 965 |  | 
|---|
| 966 |     if not mask_worksp: | 
|---|
| 967 |         mask_worksp = '__CurrentMask' | 
|---|
| 968 |         samp = LAST_SAMPLE | 
|---|
| 969 |  | 
|---|
| 970 |         if samp: | 
|---|
| 971 |             CloneWorkspace(InputWorkspace=samp, OutputWorkspace=mask_worksp) | 
|---|
| 972 |  | 
|---|
| 973 |             if su.isEventWorkspace(samp): | 
|---|
| 974 |                 assert samp + "_monitors" in mtd | 
|---|
| 975 |                 CloneWorkspace(InputWorkspace=samp + "_monitors", | 
|---|
| 976 |                                OutputWorkspace=mask_worksp + "_monitors") | 
|---|
| 977 |                 su.fromEvent2Histogram(mask_worksp, mtd[mask_worksp + "_monitors"]) | 
|---|
| 978 |  | 
|---|
| 979 |             counts_data = '__DisplayMasked_tempory_wksp' | 
|---|
| 980 |             Integration(InputWorkspace=mask_worksp,OutputWorkspace= counts_data) | 
|---|
| 981 |  | 
|---|
| 982 |         else: | 
|---|
| 983 |             instrument.load_empty(mask_worksp) | 
|---|
| 984 |             instrument.set_up_for_run('emptyInstrument') | 
|---|
| 985 |  | 
|---|
| 986 |     ReductionSingleton().mask.display(mask_worksp, ReductionSingleton(), counts_data) | 
|---|
| 987 |     if counts_data: | 
|---|
| 988 |         DeleteWorkspace(counts_data) | 
|---|
| 989 |  | 
|---|
| 990 |     return mask_worksp | 
|---|
| 991 |  | 
|---|
| 992 | # Print a test script for Colette if asked | 
|---|
| 993 | def createColetteScript(inputdata, format, reduced, centreit , plotresults, csvfile = '', savepath = ''): | 
|---|
| 994 |     script = '' | 
|---|
| 995 |     if csvfile != '': | 
|---|
| 996 |         script += '[COLETTE]  @ ' + csvfile + '\n' | 
|---|
| 997 |     file_1 = inputdata['sample_sans'] + format | 
|---|
| 998 |     script += '[COLETTE]  ASSIGN/SAMPLE ' + file_1 + '\n' | 
|---|
| 999 |     file_1 = inputdata['sample_trans'] + format | 
|---|
| 1000 |     file_2 = inputdata['sample_direct_beam'] + format | 
|---|
| 1001 |     if file_1 != format and file_2 != format: | 
|---|
| 1002 |         script += '[COLETTE]  TRANSMISSION/SAMPLE/MEASURED ' + file_1 + ' ' + file_2 + '\n' | 
|---|
| 1003 |     file_1 = inputdata['can_sans'] + format | 
|---|
| 1004 |     if file_1 != format: | 
|---|
| 1005 |         script +='[COLETTE]  ASSIGN/CAN ' + file_1 + '\n' | 
|---|
| 1006 |     file_1 = inputdata['can_trans'] + format | 
|---|
| 1007 |     file_2 = inputdata['can_direct_beam'] + format | 
|---|
| 1008 |     if file_1 != format and file_2 != format: | 
|---|
| 1009 |         script += '[COLETTE]  TRANSMISSION/CAN/MEASURED ' + file_1 + ' ' + file_2 + '\n' | 
|---|
| 1010 |     if centreit: | 
|---|
| 1011 |         script += '[COLETTE]  FIT/MIDDLE' | 
|---|
| 1012 |     # Parameters | 
|---|
| 1013 |     script += '[COLETTE]  LIMIT/RADIUS ' + str(ReductionSingleton().mask.min_radius) | 
|---|
| 1014 |     script += ' ' + str(ReductionSingleton().mask.max_radius) + '\n' | 
|---|
| 1015 |     script += '[COLETTE]  LIMIT/WAVELENGTH ' + ReductionSingleton().to_wavelen.get_range() + '\n' | 
|---|
| 1016 |     if ReductionSingleton().DWAV <  0: | 
|---|
| 1017 |         script += '[COLETTE]  STEP/WAVELENGTH/LOGARITHMIC ' + str(ReductionSingleton().to_wavelen.w_step)[1:] + '\n' | 
|---|
| 1018 |     else: | 
|---|
| 1019 |         script += '[COLETTE]  STEP/WAVELENGTH/LINEAR ' + str(ReductionSingleton().to_wavelen.w_step) + '\n' | 
|---|
| 1020 |     # For the moment treat the rebin string as min/max/step | 
|---|
| 1021 |     qbins = ReductionSingleton().Q_REBEIN.split(",") | 
|---|
| 1022 |     nbins = len(qbins) | 
|---|
| 1023 |     if ReductionSingleton().to_Q.output_type == '1D': | 
|---|
| 1024 |         script += '[COLETTE]  LIMIT/Q ' + str(qbins[0]) + ' ' + str(qbins[nbins-1]) + '\n' | 
|---|
| 1025 |         dq = float(qbins[1]) | 
|---|
| 1026 |         if dq <  0: | 
|---|
| 1027 |             script += '[COLETTE]  STEP/Q/LOGARITHMIC ' + str(dq)[1:] + '\n' | 
|---|
| 1028 |         else: | 
|---|
| 1029 |             script += '[COLETTE]  STEP/Q/LINEAR ' + str(dq) + '\n' | 
|---|
| 1030 |     else: | 
|---|
| 1031 |         script += '[COLETTE]  LIMIT/QXY ' + str(0.0) + ' ' + str(ReductionSingleton().QXY2) + '\n' | 
|---|
| 1032 |         if ReductionSingleton().DQXY <  0: | 
|---|
| 1033 |             script += '[COLETTE]  STEP/QXY/LOGARITHMIC ' + str(ReductionSingleton().DQXY)[1:] + '\n' | 
|---|
| 1034 |         else: | 
|---|
| 1035 |             script += '[COLETTE]  STEP/QXY/LINEAR ' + str(ReductionSingleton().DQXY) + '\n' | 
|---|
| 1036 |  | 
|---|
| 1037 |     # Correct | 
|---|
| 1038 |     script += '[COLETTE] CORRECT\n' | 
|---|
| 1039 |     if plotresults: | 
|---|
| 1040 |         script += '[COLETTE]  DISPLAY/HISTOGRAM ' + reduced + '\n' | 
|---|
| 1041 |     if savepath != '': | 
|---|
| 1042 |         script += '[COLETTE]  WRITE/LOQ ' + reduced + ' ' + savepath + '\n' | 
|---|
| 1043 |  | 
|---|
| 1044 |     return script | 
|---|
| 1045 |  | 
|---|
| 1046 | def FindBeamCentre(rlow, rupp, MaxIter = 10, xstart = None, ystart = None, tolerance=1.251e-4): | 
|---|
| 1047 |     """ | 
|---|
| 1048 |         Estimates the location of the effective beam centre given a good initial estimate. For more | 
|---|
| 1049 |         information go to this page | 
|---|
| 1050 |         mantidproject.org/Using_the_SANS_GUI_Beam_Centre_Finder | 
|---|
| 1051 |         @param rlow: mask around the (estimated) centre to this radius (in millimetres) | 
|---|
| 1052 |         @param rupp: don't include further out than this distance (mm) from the centre point | 
|---|
| 1053 |         @param MaxInter: don't calculate more than this number of iterations (default = 10) | 
|---|
| 1054 |         @param xstart: initial guess for the horizontal distance of the beam centre from the detector centre in meters (default the values in the mask file) | 
|---|
| 1055 |         @param ystart: initial guess for the distance of the beam centre from the detector centre vertically in metres (default the values in the mask file) | 
|---|
| 1056 |     @param tolerance: define the precision of the search. If the step is smaller than the tolerance, it will be considered stop searching the centre (default=1.251e-4 or 1.251um) | 
|---|
| 1057 |         @return: the best guess for the beam centre point | 
|---|
| 1058 |     """ | 
|---|
| 1059 |     XSTEP = ReductionSingleton().inst.cen_find_step | 
|---|
| 1060 |     YSTEP = ReductionSingleton().inst.cen_find_step | 
|---|
| 1061 |  | 
|---|
| 1062 |     original = ReductionSingleton().get_instrument().cur_detector_position(ReductionSingleton().get_sample().get_wksp_name()) | 
|---|
| 1063 |  | 
|---|
| 1064 |     if ReductionSingleton().instrument.lowAngDetSet: | 
|---|
| 1065 |         det_bank = 'rear' | 
|---|
| 1066 |     else: | 
|---|
| 1067 |         det_bank = 'front' | 
|---|
| 1068 |  | 
|---|
| 1069 |     if xstart or ystart: | 
|---|
| 1070 |         ReductionSingleton().set_beam_finder( | 
|---|
| 1071 |             isis_reduction_steps.BaseBeamFinder( | 
|---|
| 1072 |             float(xstart), float(ystart)),det_bank) | 
|---|
| 1073 |  | 
|---|
| 1074 |     beamcoords = ReductionSingleton().get_beam_center() | 
|---|
| 1075 |     XNEW = beamcoords[0] | 
|---|
| 1076 |     YNEW = beamcoords[1] | 
|---|
| 1077 |     xstart = beamcoords[0] | 
|---|
| 1078 |     ystart = beamcoords[1] | 
|---|
| 1079 |  | 
|---|
| 1080 |  | 
|---|
| 1081 |     #remove this if we know running the Reducer() doesn't change i.e. all execute() methods are const | 
|---|
| 1082 |     centre_reduction = copy.deepcopy(ReductionSingleton().reference()) | 
|---|
| 1083 |     LimitsR(str(float(rlow)), str(float(rupp)), quiet=True, reducer=centre_reduction) | 
|---|
| 1084 |  | 
|---|
| 1085 |     centre = CentreFinder(original) | 
|---|
| 1086 |     centre.logger.notice("xstart,ystart="+str(XNEW*1000.)+" "+str(YNEW*1000.)) | 
|---|
| 1087 |     centre.logger.notice("Starting centre finding routine ...") | 
|---|
| 1088 |     #this function moves the detector to the beam center positions defined above and returns an estimate of where the beam center is relative to the new center | 
|---|
| 1089 |     resX_old, resY_old = centre.SeekCentre(centre_reduction, [XNEW, YNEW]) | 
|---|
| 1090 |     centre_reduction = copy.deepcopy(ReductionSingleton().reference()) | 
|---|
| 1091 |     LimitsR(str(float(rlow)), str(float(rupp)), quiet=True, reducer=centre_reduction) | 
|---|
| 1092 |  | 
|---|
| 1093 |     logger.notice(centre.status_str(0, resX_old, resY_old)) | 
|---|
| 1094 |  | 
|---|
| 1095 |     # take first trial step | 
|---|
| 1096 |     XNEW = xstart + XSTEP | 
|---|
| 1097 |     YNEW = ystart + YSTEP | 
|---|
| 1098 |     graph_handle = None | 
|---|
| 1099 |     for i in range(1, MaxIter+1): | 
|---|
| 1100 |         it = i | 
|---|
| 1101 |  | 
|---|
| 1102 |         centre_reduction.set_beam_finder( | 
|---|
| 1103 |             isis_reduction_steps.BaseBeamFinder(XNEW, YNEW), det_bank) | 
|---|
| 1104 |  | 
|---|
| 1105 |         resX, resY = centre.SeekCentre(centre_reduction, [XNEW, YNEW]) | 
|---|
| 1106 |         centre_reduction = copy.deepcopy(ReductionSingleton().reference()) | 
|---|
| 1107 |         LimitsR(str(float(rlow)), str(float(rupp)), quiet=True, reducer=centre_reduction) | 
|---|
| 1108 |  | 
|---|
| 1109 |         centre.logger.notice(centre.status_str(it, resX, resY)) | 
|---|
| 1110 |  | 
|---|
| 1111 |         if mantidplot: | 
|---|
| 1112 |             try : | 
|---|
| 1113 |                 if not graph_handle: | 
|---|
| 1114 |                     #once we have a plot it will be updated automatically when the workspaces are updated | 
|---|
| 1115 |                     graph_handle = mantidplot.plotSpectrum(centre.QUADS, 0) | 
|---|
| 1116 |                 graph_handle.activeLayer().setTitle( | 
|---|
| 1117 |                         centre.status_str(it, resX, resY)) | 
|---|
| 1118 |             except : | 
|---|
| 1119 |                 #if plotting is not available it probably means we are running outside a GUI, in which case do everything but don't plot | 
|---|
| 1120 |                 pass | 
|---|
| 1121 |  | 
|---|
| 1122 |         #have we stepped across the y-axis that goes through the beam center? | 
|---|
| 1123 |         if resX > resX_old: | 
|---|
| 1124 |             # yes with stepped across the middle, reverse direction and half the step size | 
|---|
| 1125 |             XSTEP = -XSTEP/2. | 
|---|
| 1126 |         if resY > resY_old: | 
|---|
| 1127 |             YSTEP = -YSTEP/2. | 
|---|
| 1128 |         if abs(XSTEP) < tolerance and abs(YSTEP) < tolerance : | 
|---|
| 1129 |             # this is the success criteria, we've close enough to the center | 
|---|
| 1130 |             centre.logger.notice("Converged - check if stuck in local minimum!") | 
|---|
| 1131 |             break | 
|---|
| 1132 |  | 
|---|
| 1133 |         resX_old = resX | 
|---|
| 1134 |         resY_old = resY | 
|---|
| 1135 |         XNEW += XSTEP | 
|---|
| 1136 |         YNEW += YSTEP | 
|---|
| 1137 |  | 
|---|
| 1138 |     if it == MaxIter: | 
|---|
| 1139 |         centre.logger.notice("Out of iterations, new coordinates may not be the best!") | 
|---|
| 1140 |         XNEW -= XSTEP | 
|---|
| 1141 |         YNEW -= YSTEP | 
|---|
| 1142 |  | 
|---|
| 1143 |     ReductionSingleton().set_beam_finder( | 
|---|
| 1144 |         isis_reduction_steps.BaseBeamFinder(XNEW, YNEW), det_bank) | 
|---|
| 1145 |     centre.logger.notice("Centre coordinates updated: [" + str(XNEW)+ ", "+ str(YNEW) + ']') | 
|---|
| 1146 |  | 
|---|
| 1147 |     return XNEW, YNEW | 
|---|
| 1148 |  | 
|---|
| 1149 | ############################################################################### | 
|---|
| 1150 | ######################### Start of Deprecated Code ############################ | 
|---|
| 1151 | ############################################################################### | 
|---|
| 1152 |  | 
|---|
| 1153 | @deprecated | 
|---|
| 1154 | def UserPath(path): | 
|---|
| 1155 |     """ | 
|---|
| 1156 |         Sets the directory in which Mantid should look for the mask file if a | 
|---|
| 1157 |         full path was not specified | 
|---|
| 1158 |         @param path: the full path to the directory | 
|---|
| 1159 |     """ | 
|---|
| 1160 |     _printMessage('UserPath("' + path + '") #Will look for mask file here') | 
|---|
| 1161 |     ReductionSingleton().user_file_path = path | 
|---|
| 1162 |  | 
|---|
| 1163 | @deprecated | 
|---|
| 1164 | def DataPath(path): | 
|---|
| 1165 |     """ | 
|---|
| 1166 |         Sets an extra directory for Mantid to look for run files | 
|---|
| 1167 |         @param path: the full path to a directory containing the run files to analyse | 
|---|
| 1168 |     """ | 
|---|
| 1169 |     ReductionSingleton().set_data_path(path) | 
|---|
| 1170 |  | 
|---|
| 1171 | @deprecated | 
|---|
| 1172 | def CropToDetector(inputWSname, outputWSname=None): | 
|---|
| 1173 |     """ | 
|---|
| 1174 |         Crops the workspace so that it only contains the spectra that correspond | 
|---|
| 1175 |         to the detectors used in the reduction | 
|---|
| 1176 |         @param inputWSname: name of the workspace to crop | 
|---|
| 1177 |         @param outputWSname: name the workspace will take (default is the inputWSname) | 
|---|
| 1178 |     """ | 
|---|
| 1179 |     if not outputWSname: | 
|---|
| 1180 |         outputWSname = inputWSname | 
|---|
| 1181 |  | 
|---|
| 1182 |     ReductionSingleton().instrument.cur_detector().crop_to_detector(inputWSname, outputWSname) | 
|---|
| 1183 |  | 
|---|
| 1184 | @deprecated | 
|---|
| 1185 | def SetRearEfficiencyFile(filename): | 
|---|
| 1186 |     rear_det = ReductionSingleton().instrument.getDetector('rear') | 
|---|
| 1187 |     rear_det.correction_file = filename | 
|---|
| 1188 |  | 
|---|
| 1189 | @deprecated | 
|---|
| 1190 | def SetFrontEfficiencyFile(filename): | 
|---|
| 1191 |     front_det = ReductionSingleton().instrument.getDetector('front') | 
|---|
| 1192 |     front_det.correction_file = filename | 
|---|
| 1193 |  | 
|---|
| 1194 | @deprecated | 
|---|
| 1195 | def displayUserFile(): | 
|---|
| 1196 |     print '-- Mask file defaults --' | 
|---|
| 1197 |     print ReductionSingleton().to_wavlen | 
|---|
| 1198 |     print ReductionSingleton().Q_string() | 
|---|
| 1199 | #    print correction_files() | 
|---|
| 1200 |     print '    direct beam file rear:', | 
|---|
| 1201 |     print ReductionSingleton().instrument.detector_file('rear') | 
|---|
| 1202 |     print '    direct beam file front:', | 
|---|
| 1203 |     print ReductionSingleton().instrument.detector_file('front') | 
|---|
| 1204 |     print ReductionSingleton().mask | 
|---|
| 1205 |  | 
|---|
| 1206 | @deprecated | 
|---|
| 1207 | def displayMaskFile(): | 
|---|
| 1208 |     displayUserFile() | 
|---|
| 1209 |  | 
|---|
| 1210 | @deprecated | 
|---|
| 1211 | def displayGeometry(): | 
|---|
| 1212 |     [x, y] = ReductionSingleton().get_beam_center() | 
|---|
| 1213 |     print 'Beam centre: [' + str(x) + ',' + str(y) + ']' | 
|---|
| 1214 |     print ReductionSingleton().get_sample().geometry | 
|---|
| 1215 |  | 
|---|
| 1216 | @deprecated | 
|---|
| 1217 | def LimitsQ(*args): | 
|---|
| 1218 |     settings = ReductionSingleton().user_settings | 
|---|
| 1219 |     if settings is None: | 
|---|
| 1220 |         raise RuntimeError('MaskFile() first') | 
|---|
| 1221 |  | 
|---|
| 1222 |     # If given one argument it must be a rebin string | 
|---|
| 1223 |     if len(args) == 1: | 
|---|
| 1224 |         val = args[0] | 
|---|
| 1225 |         if type(val) == str: | 
|---|
| 1226 |             _printMessage("LimitsQ(" + val + ")") | 
|---|
| 1227 |             settings.readLimitValues("L/Q " + val, ReductionSingleton()) | 
|---|
| 1228 |         else: | 
|---|
| 1229 |             issueWarning("LimitsQ can only be called with a single string or 4 values") | 
|---|
| 1230 |     elif len(args) == 4: | 
|---|
| 1231 |         qmin,qmax,step,step_type = args | 
|---|
| 1232 |         _printMessage('LimitsQ(' + str(qmin) + ', ' + str(qmax) +', ' + str(step) + ','  + str(step_type) + ')') | 
|---|
| 1233 |         settings.readLimitValues('L/Q ' + str(qmin) + ' ' + str(qmax) + ' ' + str(step) + '/'  + step_type, ReductionSingleton()) | 
|---|
| 1234 |     else: | 
|---|
| 1235 |         issueWarning("LimitsQ called with " + str(len(args)) + " arguments, 1 or 4 expected.") | 
|---|
| 1236 |  | 
|---|
| 1237 | @deprecated | 
|---|
| 1238 | def ViewCurrentMask(): | 
|---|
| 1239 |     """ | 
|---|
| 1240 |         In MantidPlot this opens InstrumentView to display the masked | 
|---|
| 1241 |         detectors in the bank in a different colour | 
|---|
| 1242 |     """ | 
|---|
| 1243 |     ReductionSingleton().ViewCurrentMask() | 
|---|
| 1244 |  | 
|---|
| 1245 | ############################################################################### | 
|---|
| 1246 | ########################## End of Deprecated Code ############################# | 
|---|
| 1247 | ############################################################################### | 
|---|
| 1248 |  | 
|---|
| 1249 | #this is like a #define I'd like to get rid of it because it seems meaningless here | 
|---|
| 1250 | DefaultTrans = 'True' | 
|---|
| 1251 | NewTrans = 'False' | 
|---|
| 1252 |  | 
|---|
| 1253 | _refresh_singleton() | 
|---|
| 1254 |  | 
|---|
| 1255 | if __name__ == '__main__': | 
|---|
| 1256 |     SetVerboseMode(True) | 
|---|
| 1257 |     SANS2D() | 
|---|
| 1258 |     MaskFile('MASKSANS2D_123T_4m_Xpress_8mm.txt') | 
|---|
| 1259 |     Set1D() | 
|---|
| 1260 |     AssignSample('SANS2D00002500.nxs') | 
|---|
| 1261 |     Gravity(True) | 
|---|
| 1262 |     wav1 = 2.0 | 
|---|
| 1263 |     wav2 = wav1 + 2.0 | 
|---|
| 1264 |     reduced = WavRangeReduction(wav1, wav2, DefaultTrans) | 
|---|