1 | import numpy |
---|
2 | import sys, os |
---|
3 | import dis, inspect, opcode |
---|
4 | import matplotlib.pyplot as plt |
---|
5 | from mantid.simpleapi import * |
---|
6 | |
---|
7 | ############################################################################################ |
---|
8 | def lineno(): |
---|
9 | """ |
---|
10 | call signature(s):: |
---|
11 | lineno() |
---|
12 | |
---|
13 | Returns the current line number in our program. |
---|
14 | |
---|
15 | No Arguments. |
---|
16 | |
---|
17 | |
---|
18 | Working example |
---|
19 | >>> print "This is the line number ",lineno(),"\n" |
---|
20 | |
---|
21 | """ |
---|
22 | return inspect.currentframe().f_back.f_lineno |
---|
23 | |
---|
24 | def decompile(code_object): |
---|
25 | ''' taken from http://thermalnoise.wordpress.com/2007/12/30/exploring-python-bytecode/ |
---|
26 | |
---|
27 | decompile extracts dissasembly information from the byte code and stores it in a |
---|
28 | list for further use. |
---|
29 | |
---|
30 | call signature(s):: |
---|
31 | instructions=decompile(f.f_code) |
---|
32 | |
---|
33 | Required arguments: |
---|
34 | ========= ===================================================================== |
---|
35 | f.f_code A bytecode object ectracted with inspect.currentframe() |
---|
36 | or anyother mechanism that returns byte code. |
---|
37 | |
---|
38 | Optional keyword arguments: NONE |
---|
39 | |
---|
40 | Outputs: |
---|
41 | ========= ===================================================================== |
---|
42 | instructions a list of offsets, op_codes, names, arguments, argument_type, |
---|
43 | argument_value which can be deconstructed to find out various things |
---|
44 | about a function call. |
---|
45 | |
---|
46 | Examples: |
---|
47 | |
---|
48 | f = inspect.currentframe().f_back.f_back |
---|
49 | i = f.f_lasti # index of the last attempted instruction in byte code |
---|
50 | ins=decompile(f.f_code) |
---|
51 | pretty_print(ins) |
---|
52 | |
---|
53 | |
---|
54 | ''' |
---|
55 | code = code_object.co_code |
---|
56 | variables = code_object.co_cellvars + code_object.co_freevars |
---|
57 | instructions = [] |
---|
58 | n = len(code) |
---|
59 | i = 0 |
---|
60 | e = 0 |
---|
61 | while i < n: |
---|
62 | i_offset = i |
---|
63 | i_opcode = ord(code[i]) |
---|
64 | i = i + 1 |
---|
65 | if i_opcode >= opcode.HAVE_ARGUMENT: |
---|
66 | i_argument = ord(code[i]) + (ord(code[i+1]) << (4*2)) + e |
---|
67 | i = i +2 |
---|
68 | if i_opcode == opcode.EXTENDED_ARG: |
---|
69 | e = iarg << 16 |
---|
70 | else: |
---|
71 | e = 0 |
---|
72 | if i_opcode in opcode.hasconst: |
---|
73 | i_arg_value = repr(code_object.co_consts[i_argument]) |
---|
74 | i_arg_type = 'CONSTANT' |
---|
75 | elif i_opcode in opcode.hasname: |
---|
76 | i_arg_value = code_object.co_names[i_argument] |
---|
77 | i_arg_type = 'GLOBAL VARIABLE' |
---|
78 | elif i_opcode in opcode.hasjrel: |
---|
79 | i_arg_value = repr(i + i_argument) |
---|
80 | i_arg_type = 'RELATIVE JUMP' |
---|
81 | elif i_opcode in opcode.haslocal: |
---|
82 | i_arg_value = code_object.co_varnames[i_argument] |
---|
83 | i_arg_type = 'LOCAL VARIABLE' |
---|
84 | elif i_opcode in opcode.hascompare: |
---|
85 | i_arg_value = opcode.cmp_op[i_argument] |
---|
86 | i_arg_type = 'COMPARE OPERATOR' |
---|
87 | elif i_opcode in opcode.hasfree: |
---|
88 | i_arg_value = variables[i_argument] |
---|
89 | i_arg_type = 'FREE VARIABLE' |
---|
90 | else: |
---|
91 | i_arg_value = i_argument |
---|
92 | i_arg_type = 'OTHER' |
---|
93 | else: |
---|
94 | i_argument = None |
---|
95 | i_arg_value = None |
---|
96 | i_arg_type = None |
---|
97 | instructions.append( (i_offset, i_opcode, opcode.opname[i_opcode], i_argument, i_arg_type, i_arg_value) ) |
---|
98 | return instructions |
---|
99 | |
---|
100 | # Print the byte code in a human readable format |
---|
101 | def pretty_print(instructions): |
---|
102 | print '%5s %-20s %3s %5s %-20s %s' % ('OFFSET', 'INSTRUCTION', 'OPCODE', 'ARG', 'TYPE', 'VALUE') |
---|
103 | for (offset, op, name, argument, argtype, argvalue) in instructions: |
---|
104 | print '%5d %-20s (%3d) ' % (offset, name, op), |
---|
105 | if argument != None: |
---|
106 | print '%5d %-20s (%s)' % (argument, argtype, argvalue), |
---|
107 | print |
---|
108 | |
---|
109 | |
---|
110 | def lhs(output='names'): |
---|
111 | ''' |
---|
112 | call signature(s):: |
---|
113 | NamesofOutPutsExpected = lhs(output='names') # This is the default |
---|
114 | NumberOfOutputsExpected = lhs('number') |
---|
115 | Number, Names = lhs('both') |
---|
116 | |
---|
117 | Return how many values the caller is expecting or the names of the output variables on the left of the = in a list or both. |
---|
118 | |
---|
119 | Required arguments: NONE |
---|
120 | |
---|
121 | Optional keyword arguments: NONE |
---|
122 | |
---|
123 | |
---|
124 | Outputs: |
---|
125 | ========= ===================================================================== |
---|
126 | numReturns Number of return values on expected on the left of the equal sign. |
---|
127 | |
---|
128 | Examples: |
---|
129 | |
---|
130 | This function is not designed for cammand line use. Using in a function can |
---|
131 | follow the form below. |
---|
132 | |
---|
133 | def MyFunction(): |
---|
134 | """Documentation for MyFunction |
---|
135 | """ |
---|
136 | ReturnVarNumber, ReturnVarNames=lhs('both') |
---|
137 | ### Do something useful |
---|
138 | single = 1, double_1 = 1, double_2=2 |
---|
139 | |
---|
140 | if ReturnVarNumber == 0: |
---|
141 | # process like a void return |
---|
142 | return |
---|
143 | elif ReturnVarNumber == 1: |
---|
144 | # return a single output |
---|
145 | return single |
---|
146 | elif ReturnVarNumber == 2: |
---|
147 | # retrun a pair |
---|
148 | return double_1, double_2 |
---|
149 | |
---|
150 | x = MyFunction() # returns x=1 |
---|
151 | x, y = MyFunction() # returns x=1, y=2 |
---|
152 | |
---|
153 | ''' |
---|
154 | f = inspect.currentframe().f_back.f_back |
---|
155 | i = f.f_lasti # index of the last attempted instruction in byte code |
---|
156 | ins=decompile(f.f_code) |
---|
157 | #pretty_print(ins) |
---|
158 | |
---|
159 | CallFunctionLocation={} |
---|
160 | first=False; StartIndex=0; StartOffset=0 |
---|
161 | # we must list all of the operators that behave like a function call in byte-code |
---|
162 | OperatorNames=set(['CALL_FUNCTION','UNARY_POSITIVE','UNARY_NEGATIVE','UNARY_NOT','UNARY_CONVERT','UNARY_INVERT','GET_ITER', 'BINARY_POWER','BINARY_MULTIPLY','BINARY_DIVIDE', 'BINARY_FLOOR_DIVIDE', 'BINARY_TRUE_DIVIDE', 'BINARY_MODULO','BINARY_ADD','BINARY_SUBTRACT','BINARY_SUBSCR','BINARY_LSHIFT','BINARY_RSHIFT','BINARY_AND','BINARY_XOR','BINARY_OR']) |
---|
163 | |
---|
164 | for index in range(len(ins)): |
---|
165 | (offset, op, name, argument, argtype, argvalue) = ins[index] |
---|
166 | if name in OperatorNames: |
---|
167 | if not first: |
---|
168 | CallFunctionLocation[StartOffset] = (StartIndex,index) |
---|
169 | StartIndex=index |
---|
170 | StartOffset = offset |
---|
171 | |
---|
172 | (offset, op, name, argument, argtype, argvalue) = ins[-1] |
---|
173 | CallFunctionLocation[StartOffset]=(StartIndex,len(ins)-1) # append the index of the last entry to form the last boundary |
---|
174 | |
---|
175 | #print CallFunctionLocation |
---|
176 | #pretty_print( ins[CallFunctionLocation[i][0]:CallFunctionLocation[i][1]] ) |
---|
177 | # In our case i should always be the offset of a Call_Function instruction. We can use this to baracket |
---|
178 | # the bit which we are interested in |
---|
179 | |
---|
180 | OutputVariableNames=[] |
---|
181 | (offset, op, name, argument, argtype, argvalue) = ins[CallFunctionLocation[i][0] + 1] |
---|
182 | if name == 'POP_TOP': # no Return Values |
---|
183 | pass |
---|
184 | #return OutputVariableNames |
---|
185 | if name == 'STORE_FAST' or name == 'STORE_NAME': # One Return Value |
---|
186 | OutputVariableNames.append(argvalue) |
---|
187 | if name == 'UNPACK_SEQUENCE': # Many Return Values, One equal sign |
---|
188 | for index in range(argvalue): |
---|
189 | (offset_, op_, name_, argument_, argtype_, argvalue_) = ins[CallFunctionLocation[i][0] + 1 + 1 +index] |
---|
190 | OutputVariableNames.append(argvalue_) |
---|
191 | maxReturns = len(OutputVariableNames) |
---|
192 | if name == 'DUP_TOP': # Many Return Values, Many equal signs |
---|
193 | # The output here should be a multi-dim list which mimics the variable unpacking sequence. |
---|
194 | # For instance a,b=c,d=f() => [ ['a','b'] , ['c','d'] ] |
---|
195 | # a,b=c=d=f() => [ ['a','b'] , 'c','d' ] So on and so forth. |
---|
196 | |
---|
197 | # put this in a loop and stack the results in an array. |
---|
198 | count = 0; maxReturns = 0 # Must count the maxReturns ourselves in this case |
---|
199 | while count < len(ins[CallFunctionLocation[i][0] :CallFunctionLocation[i][1]]): |
---|
200 | (offset_, op_, name_, argument_, argtype_, argvalue_) = ins[CallFunctionLocation[i][0]+count] |
---|
201 | #print 'i= ',i,'count = ', count, 'maxReturns = ',maxReturns |
---|
202 | if name_ == 'UNPACK_SEQUENCE': # Many Return Values, One equal sign |
---|
203 | hold=[] |
---|
204 | #print 'argvalue_ = ', argvalue_, 'count = ',count |
---|
205 | if argvalue_ > maxReturns: |
---|
206 | maxReturns=argvalue_ |
---|
207 | for index in range(argvalue_): |
---|
208 | (_offset_, _op_, _name_, _argument_, _argtype_, _argvalue_) = ins[CallFunctionLocation[i][0] + count+1+index] |
---|
209 | hold.append(_argvalue_) |
---|
210 | count = count + argvalue_ |
---|
211 | OutputVariableNames.append(hold) |
---|
212 | # Need to now skip the entries we just appended with the for loop. |
---|
213 | if name_ == 'STORE_FAST' or name_ == 'STORE_NAME': # One Return Value |
---|
214 | if 1 > maxReturns: |
---|
215 | maxReturns = 1 |
---|
216 | OutputVariableNames.append(argvalue_) |
---|
217 | count = count + 1 |
---|
218 | |
---|
219 | # Now that OutputVariableNames is filled with the right stuff we need to output the correct thing. Either the maximum number of |
---|
220 | # variables to unpack in the case of multiple ='s or just the length of the array or just the naames of the variables. |
---|
221 | |
---|
222 | if output== 'names': |
---|
223 | return OutputVariableNames |
---|
224 | elif output == 'number': |
---|
225 | return maxReturns |
---|
226 | elif output == 'both': |
---|
227 | return (maxReturns,OutputVariableNames) |
---|
228 | |
---|
229 | return 0 # Should never get to here |
---|
230 | |
---|
231 | ############################################################################################ |
---|
232 | def centerbins(xvals): |
---|
233 | ''' for a given numpy array return the bin centers |
---|
234 | ''' |
---|
235 | NewXvals=( xvals + numpy.roll(xvals,-1) )/2 # calculate the bin center |
---|
236 | return numpy.delete(NewXvals,-1) # remove the last element which is junk |
---|
237 | |
---|
238 | |
---|
239 | def CorrectMonitor(TheWorkspaceToCorrect): |
---|
240 | ''' Correct the monitors so that I/Io would return a flat line if the detector was in the direct beam |
---|
241 | ''' |
---|
242 | WorkspaceToCorrect=CloneWorkspace(TheWorkspaceToCorrect) |
---|
243 | CorrectedOutput=0 |
---|
244 | if WorkspaceToCorrect.isMultiPeriod(): |
---|
245 | instrument=WorkspaceToCorrect[0].getInstrument() |
---|
246 | else: |
---|
247 | instrument=WorkspaceToCorrect.getInstrument() |
---|
248 | |
---|
249 | CorrectionType=instrument.getStringParameter('correction')[0] |
---|
250 | if CorrectionType == 'polynomial': |
---|
251 | CorrectedOutput=PolynomialCorrection(InputWorkspace=WorkspaceToCorrect, Coefficients=instrument.getStringParameter('polystring')[0], Operation='Multiply') #Operation='Divide' |
---|
252 | elif CorrectionType == 'exponential': |
---|
253 | CorrectedOutput=ExponentialCorrection(InputWorkspace=WorkspaceToCorrect,C0=instrument.getNumberParameter('C0')[0], C1=instrument.getNumberParameter('C1')[0], Operation='Multiply')#Operation='Divide' |
---|
254 | |
---|
255 | return CorrectedOutput |
---|
256 | |
---|
257 | def CorrectPolarization(TheDataIn): |
---|
258 | ''' |
---|
259 | This function takes a two period data set or four period data set and corrects for polarization efficiencies. |
---|
260 | ''' |
---|
261 | # Make a copy of the data to work on locally |
---|
262 | DataIn=CloneWorkspace(TheDataIn) |
---|
263 | # Check the the workspace is in wavelength |
---|
264 | |
---|
265 | if DataIn.isMultiPeriod(): |
---|
266 | instrument=DataIn[0].getInstrument() |
---|
267 | else: |
---|
268 | instrument=DataIn.getInstrument() |
---|
269 | |
---|
270 | # Calculate the required polynomials |
---|
271 | Ones=DataIn[1] * 0.0 + 1.0 # The polynomial correction function operates on a workspace of ones. |
---|
272 | # In the case of multidetector data we expect the monitors have been stripped away. |
---|
273 | rho = PolynomialCorrection(InputWorkspace=Ones,Coefficients=instrument.getStringParameter('crho')[0]) |
---|
274 | Pp = PolynomialCorrection(InputWorkspace=Ones,Coefficients=instrument.getStringParameter('cPp')[0]) |
---|
275 | if(len(DataIn) == 2):# R+ and R- |
---|
276 | # split out the spin-states and name them according to the journal article |
---|
277 | Ip=DataIn[0]; Ia=DataIn[1] |
---|
278 | #print "Ip,Ia ",Ip, Ia |
---|
279 | D = Pp * ( 1.0 + rho) |
---|
280 | nIp = ( Ip * (rho * Pp + 1.0) + Ia * (Pp - 1.0) ) / D |
---|
281 | nIa = ( Ip * (rho * Pp - 1.0) + Ia * (Pp + 1.0) ) / D |
---|
282 | #print "nIp,nIa ",nIp, nIa |
---|
283 | DataOut=GroupWorkspaces([nIp, nIa]) |
---|
284 | return DataOut |
---|
285 | |
---|
286 | elif(len(DataIn)== 4):# R++ , R+- , R-+ , R-- |
---|
287 | |
---|
288 | alpha = PolynomialCorrection(InputWorkspace=Ones,Coefficients=instrument.getStringParameter('calpha')[0]) |
---|
289 | Ap = PolynomialCorrection(InputWorkspace=Ones,Coefficients=instrument.getStringParameter('cAp')[0]) |
---|
290 | |
---|
291 | # split out the spin-states and name them according to the journal article |
---|
292 | Ipp=DataIn[0]; Iaa=DataIn[1]; Ipa=DataIn[2]; Iap=DataIn[3] |
---|
293 | |
---|
294 | ############## Precalculate parts of the correction equation |
---|
295 | A0 = Iaa * Pp * Ap + Ap * Ipa * rho * Pp + Ap * Iap * Pp * alpha + Ipp * Ap * alpha * rho * Pp |
---|
296 | A1 = Pp * Iaa |
---|
297 | A2 = Pp * Iap |
---|
298 | A3 = Ap * Iaa |
---|
299 | A4 = Ap * Ipa |
---|
300 | A5 = Ap * alpha * Ipp |
---|
301 | A6 = Ap * alpha * Iap |
---|
302 | A7 = Pp * rho * Ipp |
---|
303 | A8 = Pp * rho * Ipa |
---|
304 | |
---|
305 | D = Pp * Ap *( 1.0 + rho + alpha + rho * alpha ) |
---|
306 | |
---|
307 | ############## Build the corrections # Note the mathematical symmetry |
---|
308 | nIpp = (A0 - A1 + A2 - A3 + A4 + A5 - A6 + A7 - A8 + Ipp + Iaa - Ipa - Iap) / D |
---|
309 | nIaa = (A0 + A1 - A2 + A3 - A4 - A5 + A6 - A7 + A8 + Ipp + Iaa - Ipa - Iap) / D |
---|
310 | nIpa = (A0 - A1 + A2 + A3 - A4 - A5 + A6 + A7 - A8 - Ipp - Iaa + Ipa + Iap) / D |
---|
311 | nIap = (A0 + A1 - A2 - A3 + A4 + A5 - A6 - A7 + A8 - Ipp - Iaa + Ipa + Iap) / D |
---|
312 | |
---|
313 | DataOut=GroupWorkspaces([nIpp, nIaa, nIpa, nIap]) |
---|
314 | return DataOut |
---|
315 | else: |
---|
316 | print len(DataIn), ' This function only operates on 2 or 4 period data' |
---|
317 | return DataIn; # Should scream with an error here. We can only correct data which has 2 or 4 spin-states |
---|
318 | |
---|
319 | def ref(RunNumbers='8169+8171+8173+8175+8177+8179+8181', theta=1.0): |
---|
320 | '''Basic shorthand for the default point detector reduction. |
---|
321 | |
---|
322 | Example: |
---|
323 | |
---|
324 | >>> rqz, rLambda , ThetaOut= ref(RunNumbers='8169+8171+8173+8175+8177+8179+8181', theta=1.0) |
---|
325 | ''' |
---|
326 | ReturnVarNumber, ReturnVarNames=lhs('both') |
---|
327 | dd=Load(RunNumbers); |
---|
328 | trans=CreateTransmissionWorkspaceAuto(FirstTransmissionRun=dd,I0MonitorIndex='2',ProcessingInstructions='2') |
---|
329 | #Now correct for the monitor to detector efficiency and optionally correct the monitors to deal with the polarization corrections too |
---|
330 | trans=CorrectMonitor(trans) |
---|
331 | (_,rl,ThetaOut)=ReflectometryReductionOneAuto(InputWorkspace=dd,I0MonitorIndex='2',ProcessingInstructions='3',ThetaIn=theta,FirstTransmissionRun=trans,StrictSpectrumChecking=False) |
---|
332 | |
---|
333 | RcorrectedVsLambda = CorrectPolarization(rl) |
---|
334 | CloneWorkspace(InputWorkspace=RcorrectedVsLambda,OutputWorkspace=ReturnVarNames[1]) |
---|
335 | |
---|
336 | RcorrectedVsQz = RcorrectedVsLambda.convertUnits('MomentumTransfer') |
---|
337 | CloneWorkspace(InputWorkspace=RcorrectedVsQz,OutputWorkspace=ReturnVarNames[0]) |
---|
338 | |
---|
339 | return mtd[ReturnVarNames[0]], mtd[ReturnVarNames[1]] , ThetaOut |
---|
340 | |
---|
341 | def refq(RunNumbers='8169+8171+8173+8175+8177+8179+8181', theta=1.0): |
---|
342 | '''Outputs I/Io vs qz. See ref for more documentation. |
---|
343 | |
---|
344 | Example: |
---|
345 | >>> xx=refq(RunNumbers='8169+8171+8173+8175+8177+8179+8181', theta=1.0) |
---|
346 | ''' |
---|
347 | rq,rl,ThetaOut=ref(RunNumbers, theta) |
---|
348 | # Ensure that the desired output is coppied and named correctly. This is required since Mantid is not completely pass by value. |
---|
349 | ReturnVarNumber, ReturnVarNames=lhs('both') |
---|
350 | CloneWorkspace(InputWorkspace=rq,OutputWorkspace=ReturnVarNames[ReturnVarNumber-1]) |
---|
351 | return mtd[ReturnVarNames[ReturnVarNumber-1]] |
---|
352 | |
---|
353 | def refl(RunNumbers='8169+8171+8173+8175+8177+8179+8181', theta=1.0): |
---|
354 | '''Outputs I/Io vs lambda. See ref for more documentation. |
---|
355 | |
---|
356 | Example: |
---|
357 | >>> xx = refl(RunNumbers='8169+8171+8173+8175+8177+8179+8181') |
---|
358 | ''' |
---|
359 | rq,rl,ThetaOut=ref(RunNumbers, theta) |
---|
360 | # Ensure that the desired output is coppied and named correctly. This is required since Mantid is not completely pass by value. |
---|
361 | ReturnVarNumber, ReturnVarNames=lhs('both') |
---|
362 | CloneWorkspace(InputWorkspace=rq,OutputWorkspace=ReturnVarNames[ReturnVarNumber-1]) |
---|
363 | return mtd[ReturnVarNames[ReturnVarNumber-1]] |
---|
364 | |
---|