1"""! representation of alignment parameters"""
8 Representation of a single alignment parameter
10 This class also contains helpful functions for operating on sets of alignment
11 parameters e.g. parsing the map file or pede res file
16 pede ID number as written in compact.xml, pede steering, and map files
18 human-readable name as written in map file
20 1 is for top and 2 is for bottom
22 1 is for translation and 2 is for rotation
24 1 is for 'u', 2 is for v, and 3 is for w
26 "layer" ID number in millepede (i.e. axial and stereo sensors are separated)
28 value of parameter (if loaded from res file)
30 error of parameter (if loaded from res file)
32 true if parameter is floating, false otherwise
35 idn_str_pattern = re.compile(
'^[12][123][123][0-9][0-9]$')
36 layer_number_pattern = re.compile(
'^.*_L([0-9]).*$')
38 def __init__(self, idn, name, half, trans_rot, direction, mp_layer_id):
51 """!Set whether this parameter is floating/active or not"""
55 """!Get the module number from the millepede layer number
57 We group sensors in pairs to form modules and the layer number
58 for millepede counts up from the furthest upstream sensor. Thus,
59 we do integer-division by two to get the module number.
67 """!Get the human layer number
69 Since, for the 2016 parameter mapping, a typo led to a dis-association between
70 the module number deduced from the ID number and the layer number, we have
71 to extract the layer number from the name of the parameter name as it appears
72 in the mapping. We look for '_L<digit>' and extract <digit> as the layer number.
75 m = Parameter.layer_number_pattern.match(self.
_name)
77 raise ValueError(f
'Unable to deduce layer number from name {self.name}')
79 return int(m.group(1))
88 """!Get whether this Parameter represents a single sensor (True)
89 or a structural component holding two or more sensors (False)
94 """!True if Parameter represents a translation"""
98 """!True if Parameter represents a rotation"""
102 """!Does this parameter represent a component on the top half (True)
105 return (self.
_half == 1)
108 """!True if Parameter is in bottom half, False if in top half"""
109 return (self.
_half == 2)
112 """!Get whether this Parameter represents a single axial sensor (True)
113 or something else (False)
115 We have to check the name to see if 'axial' is in it.
120 """!Get whether this Parameter represents a single stereo sensor (True)
121 or something else (False)
123 We have to check the name to see if 'stereo' is in it.
128 """!True if Parameter is single sensor in front half, False otherwise"""
132 """!True if Parameter is single sensor in back half, False otherwise"""
136 """!True if Parameter is a single sensor in back half on the hole side, Flase otherwise"""
140 """!True if Parameter is a single sensor in back half on the slot side, Flase otherwise"""
144 """!True if Parameter is active (i.e. floating) and False if not"""
148 """parse a line from the map file
150 we assume that the constructor's arguments are in the same
151 order as a line in the sensor map file
156 """! Deduce the categorical flags from the ID number
158 Each ID number is five digis.
161 [12][12][123][0-9][0-9]
162 | |- last two digis are sensor ID number
163 | |------ direction 1==u, 2==v, 3==w
164 | |---------- transformation 1==translation, 2==rotation
165 |--------------- detector half 1==top, 2==bottom
167 So we just need to break it down by modulo and integer
168 division /OR/ do some str conversion nonsense in python.
173 raise ValueError(f
'Bad ID Number: {idn} is not five digis')
175 if not Parameter.idn_str_pattern.match(idn):
176 raise ValueError(f
'Bad ID Number: {idn} does not match the ID pattern')
181 half = int(digits[0])
182 trans_rot = int(digits[1])
183 direction = int(digits[2])
184 mp_layer_id = int(digits[3]+digits[4])
185 return Parameter(int(idn), idn, half, trans_rot, direction, mp_layer_id)
188 """! load the entire parameter set from a map file
193 map from ID number to a Parameter
196 with open(map_filepath)
as mf:
199 if 'MilleParameter' in line:
201 p = Parameter.from_map_file_line(line)
202 parameters[p.id()] = p
206 """! Assumes line is for the same parameter as stored in self
208 A line in the pede result file has either 3 or 5 columns.
212 3. activity (0.0 if floating, -1.0 if not)
214 5. (if active) error in value
216 We ignore the first column and assume that we are only calling
217 this function if the line has already been deduced to correspond
218 to the parameter we represent.
220 elements = line.split()
224 if len(elements) > 4:
229 """! parse a pede results file
231 Parse the results file into a dictionary. If no destination dictionary
232 is provided, a new dictionary is created with the ID numbers as keys
233 and Parameter instances as values. Since this mapping is created without
234 the sensor mapping, the rest of the Parameter attributes are assigned
240 path to results file we are going to parse
241 destination : dict, optional
242 if provided, load the values from the file into parameters in this dict
243 skip_nonfloat : bool, optional
244 skip non-floating parameters
247 with open(res_file)
as rf:
250 if 'Parameter' in line:
252 idn = int(line.split()[0])
253 if destination
is None:
254 p = Parameter.from_idn(idn)
255 p.__from_res_file_line(line)
256 if p.active()
or not skip_nonfloat:
257 parameters[p.id()] = p
259 if idn
not in destination:
260 raise ValueError(f
'Attempting to load parameter {idn} which is not in parameter map')
261 if destination[idn].
active()
or not skip_nonfloat:
263 return parameters
if destination
is None else None
266 """! Print this parameter as it should appear in the pede steering file"""
267 return f
'{self._id} {self._val} {0.0 if self._active else -1.0} {self._name}'
270 """! Print the value of this parameter as it should be inserted into the compact
272 **including** the operator (either + or -)
274 This is where we handle whether the sign flips (translations) or doesn't (rotations)
277 op =
'+' if self.
_val > 0
else '-'
280 op =
'-' if self.
_val > 0
else '+'
282 return f
'{op} {abs(self._val)}'
285 """! Representation of this parameter"""
286 return f'{self.__class__.__name__}({self._id})'
289 """! Human printing of this paramete
r"""
291 if self._trans_rot == 1:
293 # stored as mm, print as um
294 s += f' {self._val*1000} +- {self._error*1000} um'
297 # stored as rad, print as mrad
298 s += f' {self._val*1000} +- {self._error*1000} mrad'
Representation of a single alignment parameter.
__from_res_file_line(self, line)
Assumes line is for the same parameter as stored in self.
float(self, yes=True)
Set whether this parameter is floating/active or not.
layer(self)
Get the human layer number.
active(self)
True if Parameter is active (i.e.
rotation(self)
True if Parameter represents a rotation.
individual(self)
Get whether this Parameter represents a single sensor (True) or a structural component holding two or...
parse_pede_res(res_file, destination=None, skip_nonfloat=False)
parse a pede results file
top(self)
Does this parameter represent a component on the top half (True) or bottom (False)
slot(self)
True if Parameter is a single sensor in back half on the slot side, Flase otherwise.
__repr__(self)
Representation of this parameter.
from_idn(idn)
Deduce the categorical flags from the ID number.
stereo(self)
Get whether this Parameter represents a single stereo sensor (True) or something else (False)
__init__(self, idn, name, half, trans_rot, direction, mp_layer_id)
pede_format(self)
Print this parameter as it should appear in the pede steering file.
back(self)
True if Parameter is single sensor in back half, False otherwise.
module(self)
Get the module number from the millepede layer number.
hole(self)
True if Parameter is a single sensor in back half on the hole side, Flase otherwise.
axial(self)
Get whether this Parameter represents a single axial sensor (True) or something else (False)
compact_value(self)
Print the value of this parameter as it should be inserted into the compact.
front(self)
True if Parameter is single sensor in front half, False otherwise.
parse_map_file(map_filepath)
load the entire parameter set from a map file
bottom(self)
True if Parameter is in bottom half, False if in top half.
translation(self)
True if Parameter represents a translation.