| 1 | from mantid.simpleapi import * |
|---|
| 2 | from mantid import config, logger |
|---|
| 3 | import sys, platform, os.path, math, datetime, re |
|---|
| 4 | |
|---|
| 5 | def StartTime(prog): |
|---|
| 6 | logger.notice('----------') |
|---|
| 7 | message = 'Program ' + prog +' started @ ' + str(datetime.datetime.now()) |
|---|
| 8 | logger.notice(message) |
|---|
| 9 | |
|---|
| 10 | def EndTime(prog): |
|---|
| 11 | message = 'Program ' + prog +' ended @ ' + str(datetime.datetime.now()) |
|---|
| 12 | logger.notice(message) |
|---|
| 13 | logger.notice('----------') |
|---|
| 14 | |
|---|
| 15 | def loadInst(instrument): |
|---|
| 16 | ws = '__empty_' + instrument |
|---|
| 17 | if not mtd.doesExist(ws): |
|---|
| 18 | idf_dir = config['instrumentDefinition.directory'] |
|---|
| 19 | idf = idf_dir + instrument + '_Definition.xml' |
|---|
| 20 | LoadEmptyInstrument(Filename=idf, OutputWorkspace=ws) |
|---|
| 21 | |
|---|
| 22 | def loadNexus(filename): |
|---|
| 23 | '''Loads a Nexus file into a workspace with the name based on the |
|---|
| 24 | filename. Convenience function for not having to play around with paths |
|---|
| 25 | in every function.''' |
|---|
| 26 | name = os.path.splitext( os.path.split(filename)[1] )[0] |
|---|
| 27 | LoadNexus(Filename=filename, OutputWorkspace=name) |
|---|
| 28 | return name |
|---|
| 29 | |
|---|
| 30 | def getInstrRun(file): |
|---|
| 31 | mo = re.match('([a-zA-Z]+)([0-9]+)',file) |
|---|
| 32 | instr_and_run = mo.group(0) # instr name + run number |
|---|
| 33 | instr = mo.group(1) # instrument prefix |
|---|
| 34 | run = mo.group(2) # run number as string |
|---|
| 35 | return instr,run |
|---|
| 36 | |
|---|
| 37 | def getWSprefix(wsname,runfile=None): |
|---|
| 38 | '''Returns a string of the form '<ins><run>_<analyser><refl>_' on which |
|---|
| 39 | all of our other naming conventions are built. |
|---|
| 40 | The workspace is used to get the instrument parameters. If the runfile |
|---|
| 41 | string is given it is expected to be a string with instrument prefix |
|---|
| 42 | and run number. If it is empty then the workspace name is assumed to |
|---|
| 43 | contain this information |
|---|
| 44 | ''' |
|---|
| 45 | if wsname == '': |
|---|
| 46 | return '' |
|---|
| 47 | if runfile is None: |
|---|
| 48 | runfile = wsname |
|---|
| 49 | ws = mtd[wsname] |
|---|
| 50 | facility = config['default.facility'] |
|---|
| 51 | ws_run = ws.getRun() |
|---|
| 52 | if 'facility' in ws_run: |
|---|
| 53 | facility = ws_run.getLogData('facility').value |
|---|
| 54 | if facility == 'ILL': |
|---|
| 55 | inst = ws.getInstrument().getName() |
|---|
| 56 | runNo = ws.getRun()['run_number'].value |
|---|
| 57 | run_name = inst + '_'+ runNo |
|---|
| 58 | else: |
|---|
| 59 | (instr, run) = getInstrRun(runfile) |
|---|
| 60 | run_name = instr + run |
|---|
| 61 | try: |
|---|
| 62 | analyser = ws.getInstrument().getStringParameter('analyser')[0] |
|---|
| 63 | reflection = ws.getInstrument().getStringParameter('reflection')[0] |
|---|
| 64 | except IndexError: |
|---|
| 65 | analyser = '' |
|---|
| 66 | reflection = '' |
|---|
| 67 | prefix = run_name + '_' + analyser + reflection + '_' |
|---|
| 68 | return prefix |
|---|
| 69 | |
|---|
| 70 | def getEfixed(workspace, detIndex=0): |
|---|
| 71 | inst = mtd[workspace].getInstrument() |
|---|
| 72 | return inst.getNumberParameter("efixed-val")[0] |
|---|
| 73 | |
|---|
| 74 | def getRunTitle(workspace): |
|---|
| 75 | ws = mtd[workspace] |
|---|
| 76 | title = ws.getRun()['run_title'].value.strip() |
|---|
| 77 | runNo = ws.getRun()['run_number'].value |
|---|
| 78 | inst = ws.getInstrument().getName() |
|---|
| 79 | ins = config.getFacility().instrument(ins).shortName().lower() |
|---|
| 80 | valid = "-_.() %s%s" % (string.ascii_letters, string.digits) |
|---|
| 81 | title = ''.join(ch for ch in title if ch in valid) |
|---|
| 82 | title = ins + runNo + '-' + title |
|---|
| 83 | return title |
|---|
| 84 | |
|---|
| 85 | def createQaxis(inputWS): |
|---|
| 86 | result = [] |
|---|
| 87 | ws = mtd[inputWS] |
|---|
| 88 | nHist = ws.getNumberHistograms() |
|---|
| 89 | if ws.getAxis(1).isSpectra(): |
|---|
| 90 | inst = ws.getInstrument() |
|---|
| 91 | samplePos = inst.getSample().getPos() |
|---|
| 92 | beamPos = samplePos - inst.getSource().getPos() |
|---|
| 93 | for i in range(0,nHist): |
|---|
| 94 | efixed = getEfixed(inputWS, i) |
|---|
| 95 | detector = ws.getDetector(i) |
|---|
| 96 | theta = detector.getTwoTheta(samplePos, beamPos) / 2 |
|---|
| 97 | lamda = math.sqrt(81.787/efixed) |
|---|
| 98 | q = 4 * math.pi * math.sin(theta) / lamda |
|---|
| 99 | result.append(q) |
|---|
| 100 | else: |
|---|
| 101 | axis = ws.getAxis(1) |
|---|
| 102 | msg = 'Creating Axis based on Detector Q value: ' |
|---|
| 103 | if not axis.isNumeric(): |
|---|
| 104 | msg += 'Input workspace must have either spectra or numeric axis.' |
|---|
| 105 | logger.notice(msg) |
|---|
| 106 | sys.exit(msg) |
|---|
| 107 | if ( axis.getUnit().unitID() != 'MomentumTransfer' ): |
|---|
| 108 | msg += 'Input must have axis values of Q' |
|---|
| 109 | logger.notice(msg) |
|---|
| 110 | sys.exit(msg) |
|---|
| 111 | for i in range(0, nHist): |
|---|
| 112 | result.append(float(axis.label(i))) |
|---|
| 113 | return result |
|---|
| 114 | |
|---|
| 115 | def GetWSangles(inWS,verbose=False): |
|---|
| 116 | nhist = mtd[inWS].getNumberHistograms() # get no. of histograms/groups |
|---|
| 117 | sourcePos = mtd[inWS].getInstrument().getSource().getPos() |
|---|
| 118 | samplePos = mtd[inWS].getInstrument().getSample().getPos() |
|---|
| 119 | beamPos = samplePos - sourcePos |
|---|
| 120 | angles = [] # will be list of angles |
|---|
| 121 | for index in range(0, nhist): |
|---|
| 122 | detector = mtd[inWS].getDetector(index) # get index |
|---|
| 123 | twoTheta = detector.getTwoTheta(samplePos, beamPos)*180.0/math.pi # calc angle |
|---|
| 124 | angles.append(twoTheta) # add angle |
|---|
| 125 | return angles |
|---|
| 126 | |
|---|
| 127 | def GetThetaQ(inWS): |
|---|
| 128 | nhist = mtd[inWS].getNumberHistograms() # get no. of histograms/groups |
|---|
| 129 | efixed = getEfixed(inWS) |
|---|
| 130 | wavelas = math.sqrt(81.787/efixed) # elastic wavelength |
|---|
| 131 | k0 = 4.0*math.pi/wavelas |
|---|
| 132 | d2r = math.pi/180.0 |
|---|
| 133 | sourcePos = mtd[inWS].getInstrument().getSource().getPos() |
|---|
| 134 | samplePos = mtd[inWS].getInstrument().getSample().getPos() |
|---|
| 135 | beamPos = samplePos - sourcePos |
|---|
| 136 | theta = [] |
|---|
| 137 | Q = [] |
|---|
| 138 | for index in range(0,nhist): |
|---|
| 139 | detector = mtd[inWS].getDetector(index) # get index |
|---|
| 140 | twoTheta = detector.getTwoTheta(samplePos, beamPos)*180.0/math.pi # calc angle |
|---|
| 141 | theta.append(twoTheta) # add angle |
|---|
| 142 | Q.append(k0*math.sin(0.5*twoTheta*d2r)) |
|---|
| 143 | return theta,Q |
|---|
| 144 | |
|---|
| 145 | def ExtractFloat(a): #extract values from line of ascii |
|---|
| 146 | extracted = [] |
|---|
| 147 | elements = a.split() #split line on spaces |
|---|
| 148 | for n in elements: |
|---|
| 149 | extracted.append(float(n)) |
|---|
| 150 | return extracted #values as list |
|---|
| 151 | |
|---|
| 152 | def ExtractInt(a): #extract values from line of ascii |
|---|
| 153 | extracted = [] |
|---|
| 154 | elements = a.split() #split line on spaces |
|---|
| 155 | for n in elements: |
|---|
| 156 | extracted.append(int(n)) |
|---|
| 157 | return extracted #values as list |
|---|
| 158 | |
|---|
| 159 | def PadArray(inarray,nfixed): #pad a list to specified size |
|---|
| 160 | npt=len(inarray) |
|---|
| 161 | padding = nfixed-npt |
|---|
| 162 | outarray=[] |
|---|
| 163 | outarray.extend(inarray) |
|---|
| 164 | outarray +=[0]*padding |
|---|
| 165 | return outarray |
|---|
| 166 | |
|---|
| 167 | def CheckAnalysers(in1WS,in2WS,Verbose): |
|---|
| 168 | ws1 = mtd[in1WS] |
|---|
| 169 | a1 = ws1.getInstrument().getStringParameter('analyser')[0] |
|---|
| 170 | r1 = ws1.getInstrument().getStringParameter('reflection')[0] |
|---|
| 171 | ws2 = mtd[in2WS] |
|---|
| 172 | a2 = ws2.getInstrument().getStringParameter('analyser')[0] |
|---|
| 173 | r2 = ws2.getInstrument().getStringParameter('reflection')[0] |
|---|
| 174 | if a1 != a2: |
|---|
| 175 | error = 'Workspace '+in1WS+' and '+in2WS+' have different analysers' |
|---|
| 176 | logger.notice('ERROR *** '+error) |
|---|
| 177 | sys.exit(error) |
|---|
| 178 | elif r1 != r2: |
|---|
| 179 | error = 'Workspace '+in1WS+' and '+in2WS+' have different reflections' |
|---|
| 180 | logger.notice('ERROR *** '+error) |
|---|
| 181 | sys.exit(error) |
|---|
| 182 | else: |
|---|
| 183 | if Verbose: |
|---|
| 184 | logger.notice('Analyser is '+a1+r1) |
|---|
| 185 | |
|---|
| 186 | def CheckHistZero(inWS): |
|---|
| 187 | nhist = mtd[inWS].getNumberHistograms() # no. of hist/groups in WS |
|---|
| 188 | if nhist == 0: |
|---|
| 189 | error = 'Workspace '+inWS+' has NO histograms' |
|---|
| 190 | logger.notice('ERROR *** ' + error) |
|---|
| 191 | sys.exit(error) |
|---|
| 192 | Xin = mtd[inWS].readX(0) |
|---|
| 193 | ntc = len(Xin)-1 # no. points from length of x array |
|---|
| 194 | if ntc == 0: |
|---|
| 195 | error = 'Workspace '+inWS+' has NO points' |
|---|
| 196 | logger.notice('ERROR *** ' + error) |
|---|
| 197 | sys.exit(error) |
|---|
| 198 | return nhist,ntc |
|---|
| 199 | |
|---|
| 200 | def CheckHistSame(in1WS,name1,in2WS,name2): |
|---|
| 201 | nhist1 = mtd[in1WS].getNumberHistograms() # no. of hist/groups in WS1 |
|---|
| 202 | X1 = mtd[in1WS].readX(0) |
|---|
| 203 | xlen1 = len(X1) |
|---|
| 204 | nhist2 = mtd[in2WS].getNumberHistograms() # no. of hist/groups in WS2 |
|---|
| 205 | X2 = mtd[in2WS].readX(0) |
|---|
| 206 | xlen2 = len(X2) |
|---|
| 207 | if nhist1 != nhist2: # check that no. groups are the same |
|---|
| 208 | e1 = name1+' ('+in1WS+') histograms (' +str(nhist1) + ')' |
|---|
| 209 | e2 = name2+' ('+in2WS+') histograms (' +str(nhist2) + ')' |
|---|
| 210 | error = e1 + ' not = ' + e2 |
|---|
| 211 | logger.notice('ERROR *** ' + error) |
|---|
| 212 | sys.exit(error) |
|---|
| 213 | elif xlen1 != xlen2: |
|---|
| 214 | e1 = name1+' ('+in1WS+') array length (' +str(xlen1) + ')' |
|---|
| 215 | e2 = name2+' ('+in2WS+') array length (' +str(xlen2) + ')' |
|---|
| 216 | error = e1 + ' not = ' + e2 |
|---|
| 217 | logger.notice('ERROR *** ' + error) |
|---|
| 218 | sys.exit(error) |
|---|
| 219 | |
|---|
| 220 | def CheckXrange(xrange,type): |
|---|
| 221 | if not ( ( len(xrange) == 2 ) or ( len(xrange) == 4 ) ): |
|---|
| 222 | error = type + ' - Range must contain either 2 or 4 numbers' |
|---|
| 223 | logger.notice(error) |
|---|
| 224 | sys.exit(error) |
|---|
| 225 | if math.fabs(xrange[0]) < 1e-5: |
|---|
| 226 | error = type + ' - input minimum ('+str(xrange[0])+') is Zero' |
|---|
| 227 | logger.notice('ERROR *** ' + error) |
|---|
| 228 | sys.exit(error) |
|---|
| 229 | if math.fabs(xrange[1]) < 1e-5: |
|---|
| 230 | error = type + ' - input maximum ('+str(xrange[1])+') is Zero' |
|---|
| 231 | logger.notice('ERROR *** ' + error) |
|---|
| 232 | sys.exit(error) |
|---|
| 233 | if xrange[1] < xrange[0]: |
|---|
| 234 | error = type + ' - input max ('+str(xrange[1])+') < min ('+xrange[0]+')' |
|---|
| 235 | logger.notice('ERROR *** ' + error) |
|---|
| 236 | sys.exit(error) |
|---|
| 237 | if len(xrange) >2: |
|---|
| 238 | if math.fabs(xrange[2]) < 1e-5: |
|---|
| 239 | error = type + '2 - input minimum ('+str(xrange[2])+') is Zero' |
|---|
| 240 | logger.notice('ERROR *** ' + error) |
|---|
| 241 | sys.exit(error) |
|---|
| 242 | if math.fabs(xrange[3]) < 1e-5: |
|---|
| 243 | error = type + '2 - input maximum ('+str(xrange[3])+') is Zero' |
|---|
| 244 | logger.notice('ERROR *** ' + error) |
|---|
| 245 | sys.exit(error) |
|---|
| 246 | if xrange[3] < xrange[2]: |
|---|
| 247 | error = type + '2 - input max ('+str(xrange[3])+') < min ('+xrange[2]+')' |
|---|
| 248 | logger.notice('ERROR *** ' + error) |
|---|
| 249 | sys.exit(error) |
|---|
| 250 | |
|---|
| 251 | def CheckElimits(erange,Xin): |
|---|
| 252 | nx = len(Xin)-1 |
|---|
| 253 | if math.fabs(erange[0]) < 1e-5: |
|---|
| 254 | error = 'Elimits - input emin ( '+str(erange[0])+' ) is Zero' |
|---|
| 255 | logger.notice('ERROR *** ' + error) |
|---|
| 256 | sys.exit(error) |
|---|
| 257 | if erange[0] < Xin[0]: |
|---|
| 258 | error = 'Elimits - input emin ( '+str(erange[0])+' ) < data emin ( '+str(Xin[0])+' )' |
|---|
| 259 | logger.notice('ERROR *** ' + error) |
|---|
| 260 | sys.exit(error) |
|---|
| 261 | if math.fabs(erange[1]) < 1e-5: |
|---|
| 262 | error = 'Elimits - input emax ( '+str(erange[1])+' ) is Zero' |
|---|
| 263 | logger.notice('ERROR *** ' + error) |
|---|
| 264 | sys.exit(error) |
|---|
| 265 | if erange[1] > Xin[nx]: |
|---|
| 266 | error = 'Elimits - input emax ( '+str(erange[1])+' ) > data emax ( '+str(Xin[nx])+' )' |
|---|
| 267 | logger.notice('ERROR *** ' + error) |
|---|
| 268 | sys.exit(error) |
|---|
| 269 | if erange[1] < erange[0]: |
|---|
| 270 | error = 'Elimits - input emax ( '+str(erange[1])+' ) < emin ( '+erange[0]+' )' |
|---|
| 271 | logger.notice('ERROR *** ' + error) |
|---|
| 272 | sys.exit(error) |
|---|
| 273 | |
|---|
| 274 | def CopyLogHeader(inWS,outWS): #copies header data from inWS to outWS |
|---|
| 275 | inGR = mtd[inWS].getRun() |
|---|
| 276 | outGR = mtd[outWS].getRun() |
|---|
| 277 | run_header = inGR.getLogData('run_header').value |
|---|
| 278 | AddSampleLog(Workspace=outWS, LogName='run_header', LogType='String', LogText=str(run_header)) |
|---|
| 279 | run_start = inGR.getLogData('run_start').value |
|---|
| 280 | AddSampleLog(Workspace=outWS, LogName='run_start', LogType='String', LogText=str(run_start)) |
|---|
| 281 | run_title = inGR.getLogData('run_title').value |
|---|
| 282 | AddSampleLog(Workspace=outWS, LogName='run_title', LogType='String', LogText=str(run_title)) |
|---|
| 283 | user_name = inGR.getLogData('user_name').value |
|---|
| 284 | AddSampleLog(Workspace=outWS, LogName='user_name', LogType='String', LogText=str(user_name)) |
|---|