| 1 | from mantidsimple import * |
|---|
| 2 | from shutil import copyfile |
|---|
| 3 | |
|---|
| 4 | _NO_INDIVIDUAL_PERIODS = -1 |
|---|
| 5 | |
|---|
| 6 | def add_runs(runs, inst='sans2d', defType='.nxs', rawTypes=('.raw', '.s*', 'add'), lowMem=False, binning='Monitors'): |
|---|
| 7 | #check if there is at least one file in the list |
|---|
| 8 | if len(runs) < 1 : return |
|---|
| 9 | |
|---|
| 10 | if not defType.startswith('.') : defType = '.'+defType |
|---|
| 11 | |
|---|
| 12 | #these input arguments need to be arrays of strings, enforce this |
|---|
| 13 | if type(runs) == str : runs = (runs, ) |
|---|
| 14 | if type(rawTypes) == str : rawTypes = (rawTypes, ) |
|---|
| 15 | |
|---|
| 16 | if lowMem: |
|---|
| 17 | lowMem = _can_load_periods(runs, defType, rawTypes) |
|---|
| 18 | if lowMem: |
|---|
| 19 | period = 1 |
|---|
| 20 | else: |
|---|
| 21 | period = _NO_INDIVIDUAL_PERIODS |
|---|
| 22 | |
|---|
| 23 | userEntry = runs[0] |
|---|
| 24 | |
|---|
| 25 | while(True): |
|---|
| 26 | |
|---|
| 27 | isFirstDataSetEvent = False |
|---|
| 28 | #we need to catch all exceptions to ensure that a dialog box is raised with the error |
|---|
| 29 | try : |
|---|
| 30 | lastPath, lastFile, logFile, num_periods, isFirstDataSetEvent = _loadWS( |
|---|
| 31 | userEntry, defType, inst, 'AddFilesSumTempory', rawTypes, period) |
|---|
| 32 | |
|---|
| 33 | # if event data prevent loop over periods makes no sense |
|---|
| 34 | if isFirstDataSetEvent: |
|---|
| 35 | period = _NO_INDIVIDUAL_PERIODS |
|---|
| 36 | |
|---|
| 37 | if inst.upper() != 'SANS2D' and isFirstDataSetEvent: |
|---|
| 38 | error = 'Adding event data not supported for ' + inst + ' for now' |
|---|
| 39 | print error |
|---|
| 40 | mantid.sendLogMessage(error) |
|---|
| 41 | if mantid.workspaceExists('AddFilesSumTempory') : mantid.deleteWorkspace('AddFilesSumTempory') |
|---|
| 42 | if mantid.workspaceExists('AddFilesSumTempory_monitors') : mantid.deleteWorkspace('AddFilesSumTempory_monitors') |
|---|
| 43 | return "" |
|---|
| 44 | |
|---|
| 45 | for i in range(len(runs)-1): |
|---|
| 46 | userEntry = runs[i+1] |
|---|
| 47 | lastPath, lastFile, logFile, dummy, isDataSetEvent = _loadWS( |
|---|
| 48 | userEntry, defType, inst,'AddFilesNewTempory', rawTypes, period) |
|---|
| 49 | |
|---|
| 50 | if isDataSetEvent != isFirstDataSetEvent: |
|---|
| 51 | error = 'Datasets added must be either ALL histogram data or ALL event data' |
|---|
| 52 | print error |
|---|
| 53 | mantid.sendLogMessage(error) |
|---|
| 54 | if mantid.workspaceExists('AddFilesSumTempory') : mantid.deleteWorkspace('AddFilesSumTempory') |
|---|
| 55 | if mantid.workspaceExists('AddFilesNewTempory') : mantid.deleteWorkspace('AddFilesNewTempory') |
|---|
| 56 | return "" |
|---|
| 57 | |
|---|
| 58 | Plus('AddFilesSumTempory', 'AddFilesNewTempory', 'AddFilesSumTempory') |
|---|
| 59 | if isFirstDataSetEvent: |
|---|
| 60 | Plus('AddFilesSumTempory_monitors', 'AddFilesNewTempory_monitors', 'AddFilesSumTempory_monitors') |
|---|
| 61 | mantid.deleteWorkspace("AddFilesNewTempory") |
|---|
| 62 | if isFirstDataSetEvent: |
|---|
| 63 | mantid.deleteWorkspace("AddFilesNewTempory_monitors") |
|---|
| 64 | |
|---|
| 65 | except ValueError, reason: |
|---|
| 66 | error = 'Error opening file ' + userEntry+': ' + reason.message |
|---|
| 67 | print error |
|---|
| 68 | mantid.sendLogMessage(error) |
|---|
| 69 | if mantid.workspaceExists('AddFilesSumTempory') : mantid.deleteWorkspace('AddFilesSumTempory') |
|---|
| 70 | return "" |
|---|
| 71 | except Exception, reason: |
|---|
| 72 | error = 'Error finding files: ' + reason.message |
|---|
| 73 | print error |
|---|
| 74 | mantid.sendLogMessage(error) |
|---|
| 75 | if mantid.workspaceExists('AddFilesSumTempory') : mantid.deleteWorkspace('AddFilesSumTempory') |
|---|
| 76 | if mantid.workspaceExists('AddFilesNewTempory') : mantid.deleteWorkspace("AddFilesNewTempory") |
|---|
| 77 | return "" |
|---|
| 78 | |
|---|
| 79 | # in case of event file force it into a histogram workspace |
|---|
| 80 | if isFirstDataSetEvent: |
|---|
| 81 | wsInMonitor = mtd['AddFilesSumTempory_monitors'] |
|---|
| 82 | if binning == 'Monitors': |
|---|
| 83 | monX = wsInMonitor.dataX(i) |
|---|
| 84 | binning = str(monX[0]) |
|---|
| 85 | binGap = monX[1] - monX[0] |
|---|
| 86 | binning = binning + "," + str(binGap) |
|---|
| 87 | for j in range(2,len(monX)): |
|---|
| 88 | nextBinGap = monX[j] - monX[j-1] |
|---|
| 89 | if nextBinGap != binGap: |
|---|
| 90 | binGap = nextBinGap |
|---|
| 91 | binning = binning + "," + str(monX[j-1]) + "," + str(binGap) |
|---|
| 92 | binning = binning + "," + str(monX[len(monX)-1]) |
|---|
| 93 | |
|---|
| 94 | mantid.sendLogMessage(binning) |
|---|
| 95 | Rebin('AddFilesSumTempory','AddFilesSumTempory_Rebin', binning, PreserveEvents=False) |
|---|
| 96 | |
|---|
| 97 | filename, ext = _makeFilename(runs[0], defType, inst) |
|---|
| 98 | LoadNexus(filename, OutputWorkspace='AddFilesSumTempory') |
|---|
| 99 | # User may have selected a binning which is different from the default |
|---|
| 100 | Rebin('AddFilesSumTempory','AddFilesSumTempory', binning) |
|---|
| 101 | # For now the monitor binning must be the same as the detector binning |
|---|
| 102 | # since otherwise both cannot exist in the same output histogram file |
|---|
| 103 | Rebin('AddFilesSumTempory_monitors','AddFilesSumTempory_monitors', binning) |
|---|
| 104 | |
|---|
| 105 | wsInMonitor = mtd['AddFilesSumTempory_monitors'] |
|---|
| 106 | wsOut = mtd['AddFilesSumTempory'] |
|---|
| 107 | wsInDetector = mtd['AddFilesSumTempory_Rebin'] |
|---|
| 108 | for i in range(4): |
|---|
| 109 | outY = wsOut.dataY(i) |
|---|
| 110 | outE = wsOut.dataE(i) |
|---|
| 111 | monitorY = wsInMonitor.readY(i) |
|---|
| 112 | monitorE = wsInMonitor.readE(i) |
|---|
| 113 | for j in range(len(outY)): |
|---|
| 114 | outY[j] = monitorY[j] |
|---|
| 115 | outE[j] = monitorE[j] |
|---|
| 116 | |
|---|
| 117 | |
|---|
| 118 | for i in range(4, 73732): |
|---|
| 119 | outY = wsOut.dataY(i+4) |
|---|
| 120 | outE = wsOut.dataE(i+4) |
|---|
| 121 | detectorY = wsInDetector.readY(i) |
|---|
| 122 | detectorE = wsInDetector.readE(i) |
|---|
| 123 | for j in range(len(outY)): |
|---|
| 124 | outY[j] = detectorY[j] |
|---|
| 125 | outE[j] = detectorE[j] |
|---|
| 126 | |
|---|
| 127 | if mantid.workspaceExists('AddFilesSumTempory_Rebin') : mantid.deleteWorkspace('AddFilesSumTempory_Rebin') |
|---|
| 128 | |
|---|
| 129 | lastFile = os.path.splitext(lastFile)[0] |
|---|
| 130 | # now save the added file |
|---|
| 131 | outFile = lastFile+'-add.'+'nxs' |
|---|
| 132 | mantid.sendLogMessage('writing file: '+outFile) |
|---|
| 133 | if period == 1 or period == _NO_INDIVIDUAL_PERIODS: |
|---|
| 134 | #replace the file the first time around |
|---|
| 135 | sav = SaveNexusProcessed("AddFilesSumTempory", outFile, Append=False) |
|---|
| 136 | else: |
|---|
| 137 | #then append |
|---|
| 138 | sav = SaveNexusProcessed("AddFilesSumTempory", outFile, Append=True) |
|---|
| 139 | |
|---|
| 140 | mantid.deleteWorkspace("AddFilesSumTempory") |
|---|
| 141 | if isFirstDataSetEvent: |
|---|
| 142 | mantid.deleteWorkspace("AddFilesSumTempory_monitors") |
|---|
| 143 | |
|---|
| 144 | if period == num_periods: |
|---|
| 145 | break |
|---|
| 146 | |
|---|
| 147 | if period == _NO_INDIVIDUAL_PERIODS: |
|---|
| 148 | break |
|---|
| 149 | else: |
|---|
| 150 | period += 1 |
|---|
| 151 | |
|---|
| 152 | #this adds the path to the filename |
|---|
| 153 | outFile = sav.getPropertyValue('Filename') |
|---|
| 154 | pathout = os.path.split(outFile)[0] |
|---|
| 155 | if logFile: |
|---|
| 156 | _copyLog(lastPath, logFile, pathout) |
|---|
| 157 | |
|---|
| 158 | return 'The following file has been created:\n'+outFile |
|---|
| 159 | |
|---|
| 160 | def _can_load_periods(runs, defType, rawTypes): |
|---|
| 161 | """ |
|---|
| 162 | Searches through the supplied list of run file names and |
|---|
| 163 | returns False if some appear to be raw files else True |
|---|
| 164 | """ |
|---|
| 165 | for i in runs: |
|---|
| 166 | dummy, ext = os.path.splitext(i) |
|---|
| 167 | if ext == '': ext = defType |
|---|
| 168 | if _isType(ext, rawTypes): |
|---|
| 169 | return False |
|---|
| 170 | #no raw files were found, assume we can specify the period number for each |
|---|
| 171 | return True |
|---|
| 172 | |
|---|
| 173 | |
|---|
| 174 | def _makeFilename(entry, ext, inst) : |
|---|
| 175 | """ |
|---|
| 176 | If entry not already a valid filename make it into one |
|---|
| 177 | """ |
|---|
| 178 | try : |
|---|
| 179 | runNum = int(entry) #the user entered something that translates to a run number, convert it to a file |
|---|
| 180 | filename=inst+_padZero(runNum, inst)+ext |
|---|
| 181 | except ValueError : #we don't have a run number, assume it's a valid filename |
|---|
| 182 | filename = entry |
|---|
| 183 | dummy, ext = os.path.splitext(filename) |
|---|
| 184 | |
|---|
| 185 | return filename, ext |
|---|
| 186 | |
|---|
| 187 | def _loadWS(entry, ext, inst, wsName, rawTypes, period=_NO_INDIVIDUAL_PERIODS) : |
|---|
| 188 | |
|---|
| 189 | filename, ext = _makeFilename(entry, ext, inst) |
|---|
| 190 | |
|---|
| 191 | mantid.sendLogMessage('reading file: '+filename) |
|---|
| 192 | |
|---|
| 193 | if period != _NO_INDIVIDUAL_PERIODS: |
|---|
| 194 | #load just a single period |
|---|
| 195 | props = Load(Filename=filename,OutputWorkspace=wsName, EntryNumber=period) |
|---|
| 196 | else: |
|---|
| 197 | props = Load(Filename=filename,OutputWorkspace=wsName) |
|---|
| 198 | |
|---|
| 199 | isDataSetEvent = False |
|---|
| 200 | wsDataSet = mtd[wsName] |
|---|
| 201 | if hasattr(wsDataSet, 'getNumberEvents'): |
|---|
| 202 | isDataSetEvent = True |
|---|
| 203 | |
|---|
| 204 | if isDataSetEvent: |
|---|
| 205 | LoadEventNexus(Filename=filename,OutputWorkspace=wsName, LoadMonitors=True) |
|---|
| 206 | runDetails = mtd[wsName].getRun() |
|---|
| 207 | timeArray = runDetails.getLogData("proton_charge").times |
|---|
| 208 | # There should never be a time increment in the proton charge larger than say "two weeks" |
|---|
| 209 | # SANS2D currently is run at 10 frames per second. This may be increated to 5Hz |
|---|
| 210 | # (step of 0.2 sec). Although time between frames may be larger due to having the SMP veto switched on, |
|---|
| 211 | # but hopefully not longer than two weeks! |
|---|
| 212 | for i in range(len(timeArray)-1): |
|---|
| 213 | # cal time dif in seconds |
|---|
| 214 | timeDif = (timeArray[i+1].total_nanoseconds()-timeArray[i].total_nanoseconds())*1e-9 |
|---|
| 215 | if timeDif > 172800: |
|---|
| 216 | mantid.sendLogMessage('::SANS::WARNING: Time increments in the proton charge log of ' + filename + ' are suspicious large.' + |
|---|
| 217 | ' For example a time difference of ' + str(timeDif) + " seconds has been observed.") |
|---|
| 218 | break |
|---|
| 219 | |
|---|
| 220 | path = props.getPropertyValue('FileName') |
|---|
| 221 | path, fName = os.path.split(path) |
|---|
| 222 | if path.find('/') == -1: |
|---|
| 223 | #looks like we're on a windows system, convert the directory separators |
|---|
| 224 | path = path.replace('\\', '/') |
|---|
| 225 | |
|---|
| 226 | if _isType(ext, rawTypes): |
|---|
| 227 | LoadSampleDetailsFromRaw(wsName, path+'/'+fName) |
|---|
| 228 | |
|---|
| 229 | logFile = None |
|---|
| 230 | #change below when logs in Nexus files work file types of .raw need their log files to be copied too |
|---|
| 231 | if True:#_isType(ext, rawTypes): |
|---|
| 232 | logFile = os.path.splitext(fName)[0]+'.log' |
|---|
| 233 | |
|---|
| 234 | try: |
|---|
| 235 | samp = mtd[wsName].getSampleDetails() |
|---|
| 236 | numPeriods = samp.getLogData('nperiods').value |
|---|
| 237 | except: |
|---|
| 238 | #assume the run file didn't support multi-period data and so there is only one period |
|---|
| 239 | numPeriods = 1 |
|---|
| 240 | |
|---|
| 241 | return path, fName, logFile, numPeriods, isDataSetEvent |
|---|
| 242 | |
|---|
| 243 | def _padZero(runNum, inst='SANS2D'): |
|---|
| 244 | if inst.upper() == 'SANS2D' : numDigits = 8 |
|---|
| 245 | elif inst.upper() == 'LOQ' : numDigits = 5 |
|---|
| 246 | else : raise NotImplementedError('The arguement inst must be set to SANS or LOQ') |
|---|
| 247 | |
|---|
| 248 | run = str(runNum).zfill(numDigits) |
|---|
| 249 | return run |
|---|
| 250 | |
|---|
| 251 | ########################################## |
|---|
| 252 | # returns true if ext is in the tuple allTypes, ext |
|---|
| 253 | # is intended to be a file extension and allTypes a |
|---|
| 254 | # list of allowed extensions. '*' at the end is supported |
|---|
| 255 | def _isType(ext, allTypes): |
|---|
| 256 | for oneType in allTypes: |
|---|
| 257 | oneType = str(oneType) |
|---|
| 258 | if oneType.endswith('*') : |
|---|
| 259 | oneType = oneType[0:len(oneType)-1] |
|---|
| 260 | if ext.startswith(oneType) : |
|---|
| 261 | return True |
|---|
| 262 | else : |
|---|
| 263 | if ext == oneType : |
|---|
| 264 | return True |
|---|
| 265 | return False |
|---|
| 266 | |
|---|
| 267 | def _copyLog(lastPath, logFile, pathout): |
|---|
| 268 | try : |
|---|
| 269 | logFile = lastPath+'/'+logFile |
|---|
| 270 | if os.path.exists(logFile): |
|---|
| 271 | copyfile(logFile, pathout+'/'+os.path.basename(logFile)) |
|---|
| 272 | else: |
|---|
| 273 | mantid.sendLogMessage("Could not find log file %s" % logFile) |
|---|
| 274 | except Exception, reason: |
|---|
| 275 | error = 'Error copying log file ' + logFile + ' to directory ' + pathout+'\n' |
|---|
| 276 | print error |
|---|
| 277 | mantid.sendLogMessage(error) |
|---|
| 278 | |
|---|