-
Notifications
You must be signed in to change notification settings - Fork 122
/
ReductionHelpers.py
280 lines (227 loc) · 10.2 KB
/
ReductionHelpers.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
from mantid import config
"""
Set of functions to assist with processing instrument parameters relevant to reduction.
"""
class ComplexProperty(object):
""" Class describes property which depends on other properties and stores/receives values in other properties """
def __init__(self,other_prop_list):
self._other_prop = other_prop_list;
def __get__(self,spec_dict,owner=None):
""" return complex properties list """
#if not isinstance(spec_dict,dict):
# spec_dict = spec_dict.__dict__
rez = list()
for key in self._other_prop:
rez.append(spec_dict[key]);
return rez;
def __set__(self,spec_dict,value):
if len(value) != len(self._other_prop):
raise KeyError("Complex property values can be set equal to the same length values list");
#if not isinstance(spec_dict,dict):
# spec_dict = spec_dict.__dict__
#changed_prop=[];
for key,val in zip(self._other_prop,value):
spec_dict[key] =val;
#changed_prop.append(key);
#return changed_prop;
def dependencies(self):
""" returns the list of properties names, this property depends on"""
return self._other_prop
def len(self):
""" returns the number of properties, this property depends on"""
return len(self._other_prop);
#end ComplexProperty
def get_default_parameter(instrument, name):
""" Function gets the value of a default instrument parameter and
assign proper(the one defined in IPF ) type to this parameter
@param instrument --
"""
if instrument is None:
raise ValueError("Cannot initiate default parameter, instrument has not been properly defined.")
type_name = instrument.getParameterType(name)
if type_name == "double":
val = instrument.getNumberParameter(name)
elif type_name == "bool":
val = instrument.getBoolParameter(name)
elif type_name == "string":
val = instrument.getStringParameter(name)
if val[0] == "None" :
return None
elif type_name == "int" :
val = instrument.getIntParameter(name)
else :
raise KeyError(" Instrument: {0} does not have parameter with name: {1}".format(instrument.getName(),name))
return val[0]
def get_default_idf_param_list(pInstrument,synonims_list=None):
""" Obtain default reduction parameters list from the instrument """
params = pInstrument.getParameterNames();
par_list = {};
for name in params:
par_list[name] = get_default_parameter(pInstrument,name);
return par_list;
def build_properties_dict(param_map,synonims,preffix='') :
""" function builds the properties list from the properties strings obtained from Insturment_Parameters.xml file
The properties, which have simple values are added to dictionary in the form:
properties_dict[prop_name]=(False,value);
The properties, expressed trough the values of other properties
e.g. strings in a form key1 = key2:key3
are added to the dictionary in the form:
in the form properties_dict[key1]=(True,['key2','key3'])
"""
# dictionary used for substituting composite keys.
prelim_dict = dict();
for name in param_map:
if name in synonims:
final_name = preffix+str(synonims[name]);
else:
final_name = preffix+str(name)
prelim_dict[final_name]=None;
param_keys = prelim_dict.keys();
properties_dict = dict();
for name,val in param_map.items() :
if name in synonims:
final_name = preffix+str(synonims[name]);
else:
final_name = preffix+str(name)
if isinstance(val,str):
val = val.strip()
keys_candidates = val.split(":")
n_keys = len(keys_candidates)
#
if n_keys>1 : # this is the property we want to modify
result=list();
for key in keys_candidates :
if key in synonims:
rkey = preffix+str(synonims[key]);
else:
rkey = preffix+str(key);
if rkey in param_keys:
result.append(rkey);
else:
raise KeyError('Substitution key : {0} is not in the list of allowed keys'.format(rkey));
properties_dict['_'+final_name]=ComplexProperty(result)
else:
properties_dict[final_name] =keys_candidates[0];
else:
properties_dict[final_name]=val;
return properties_dict
def extract_non_system_names(names_list,prefix='__'):
""" The function processes the input list and returns
the list with names which do not have the system framing (leading __)
"""
result = list();
ns = len(prefix);
for name in names_list:
pend = min(ns,len(name))
if name[:pend] != prefix:
result.append(name)
return result
def build_subst_dictionary(synonims_list=None) :
"""Function to process "synonims_list" in the instrument parameters string, used to support synonyms in the reduction script
it takes string of synonyms in the form key1=subs1=subst2=subts3;key2=subst4 and returns the dictionary
in the form dict[subs1]=key1 ; dict[subst2] = key1 ... dict[subst4]=key2
e.g. if one wants to use the IDF key word my_detector instead of e.g. norm-mon1-spec, he has to type
norm-mon1-spec=my_detector in the synonyms field of the IDF parameters file.
"""
if not synonims_list : # nothing to do
return dict();
if type(synonims_list) == dict : # all done
return synonims_list
if type(synonims_list) != str :
raise AttributeError("The synonyms field of Reducer object has to be special format string or the dictionary")
# we are in the right place and going to transform string into dictionary
subst_lines = synonims_list.split(";")
rez = dict()
for lin in subst_lines :
lin=lin.strip()
keys = lin.split("=")
if len(keys) < 2 :
raise AttributeError("The pairs in the synonyms fields have to have form key1=key2=key3 with at least two values present")
if len(keys[0]) == 0:
raise AttributeError("The pairs in the synonyms fields have to have form key1=key2=key3 with at least two values present, but the first key is empty")
for i in xrange(1,len(keys)) :
if len(keys[i]) == 0 :
raise AttributeError("The pairs in the synonyms fields have to have form key1=key2=key3 with at least two values present, but the key"+str(i)+" is empty")
kkk = keys[i].strip();
rez[kkk]=keys[0].strip()
return rez;
def gen_getter(keyval_dict,key):
""" function returns value from dictionary with substitution
e.g. if keyval_dict[A] = 10, keyval_dict[B] = 20 and key_val[C] = [A,B]
gen_getter(keyval_dict,A) == 10; gen_getter(keyval_dict,B) == 20;
and gen_getter(keyval_dict,C) == [10,20];
"""
if not(key in keyval_dict):
name = '_'+key
if not(name in keyval_dict):
raise KeyError('Property with name: {0} is not among the class properties '.format(key));
else:
name = key
a_val= keyval_dict[name];
if isinstance(a_val,ComplexProperty):
return a_val.__get__(keyval_dict);
else:
return a_val
#end
#end
def gen_setter(keyval_dict,key,val):
""" function sets value to dictionary with substitution
e.g. if keyval_dict[A] = 10, keyval_dict[B] = 20 and key_val[C] = [A,B]
gen_setter(keyval_dict,A,20) causes keyval_dict[A] == 20
gen_setter(keyval_dict,B,30) causes keyval_dict[B] == 30
and gen_getter(keyval_dict,C,[1,2]) causes keyval_dict[A] == 1 and keyval_dict[B] == 2
"""
if not(key in keyval_dict):
name = '_'+key
if not(name in keyval_dict):
raise KeyError(' Property name: {0} is not defined'.format(key))
else:
name = key
test_val = keyval_dict[name];
if isinstance(test_val,ComplexProperty):
if not isinstance(val,list):
raise KeyError(' You can not assign non-list value to complex property {0}'.format(key))
pass
# Assigning values for composite function to the function components
test_val.__set__(keyval_dict,val)
return None
else:
keyval_dict[key] = val;
return None
def check_instrument_name(old_name,new_name):
""" function checks if new instrument name is acceptable instrument name"""
if new_name is None:
if not(old_name is None):
return (None,None,str(config.getFacility()))
else:
raise KeyError("No instrument name is defined")
if old_name == new_name:
return;
# Instrument name might be a prefix, query Mantid for the full name
short_name=''
full_name=''
try :
instrument = config.getFacility().instrument(new_name)
short_name = instrument.shortName()
full_name = instrument.name()
except RuntimeError:
# it is possible to have wrong facility:
facilities = config.getFacilities()
old_facility = str(config.getFacility())
for facility in facilities:
config.setString('default.facility',facility.name())
try :
instrument = facility.instrument(new_name)
short_name = instrument.shortName()
full_name = instrument.name()
if len(short_name)>0 :
break
except:
pass
if len(short_name)==0 :
config.setString('default.facility',old_facility)
raise KeyError(" Can not find/set-up the instrument: "+new_name+' in any supported facility')
new_name = short_name
facility = str(config.getFacility())
config['default.instrument'] = full_name
return (new_name,full_name,facility);