HPS-MC
_pattern.py
Go to the documentation of this file.
1 """! pattern that can match one or more Parameters"""
2 
3 from ._parameter import Parameter
4 
5 
6 class Pattern:
7  """! Pattern that can match one or more paramters
8 
9  This is an internal class and should not be used outside of this module
10 
11  A single "pattern" is a str that is one of the unary keywords OR
12  has a binary keyword followed by an "=" character followed by one
13  of that keywords values. All whitespace in a pattern is removed so
14  spaces can be added for easier readability.
15 
16  Syntax
17  ------
18  Each pattern is made up of one or more operations where each operation
19  is separated by an ampersand "&" to reflect that a Pattern takes the
20  logical-and of the operations listed.
21 
22  'op1 & op2 & op3 ...'
23 
24  Each operation can be one of three things.
25 
26  1. An ID number.
27  2. A unary operation.
28  3. A binary operation.
29 
30  ID numbers are the 5-digit millepede ID number for that parameter which encodes all
31  of the location information within it. It specifies a single millepede parameter.
32 
33  Unary operations are special keywords that correspond to different logical grouping
34  of parameters. Some unary operations correspond to functions returning True/False
35  of the Parameter class while others are simple shortenings of common Pattern strings
36  (a.k.a. "aliases").
37 
38  Binary operations are a string formatted like "kw = val" where a *single* equal
39  sign is used. kw is a keyword corresponding to select functions from the Parameter
40  class while val is a keyword corresponding to specific options for each kw.
41  """
42 
43  NUM_MODULES = 7
44 
45  def __validate_id(i):
46  """!Make sure input is a valid ID number, otherwise return NotImplemented
47 
48  A valid ID number is a 5-digit integer matching the Parameter.idn_str_pattern
49  regular expression.
50  """
51  if Parameter.idn_str_pattern.match(i):
52  return int(i)
53  else:
54  return NotImplemented
55 
57  """!Make sure input is a valid module number, otherwise return NotImplemented
58 
59  A valid module number is an index counting from 0 at the front of the detector
60  up to NUM_MODULES-1
61  """
62  try:
63  m = int(m)
64  if m < 0 or m > Pattern.NUM_MODULES-1:
65  return NotImplemented
66  return m
67  except ValueError:
68  return NotImplemented
69 
70  def __validate_layer(layer):
71  """!Make sure input is a valid layer number, otherwise return NotImplemented
72 
73  A valid layer number is an index counting axial/stereo pairs from 1 at
74  the front of the detector up to NUM_MODULES
75  """
76  try:
77  layer = int(layer)
78  if layer < 1 or layer > Pattern.NUM_MODULES:
79  return NotImplemented
80  return layer
81  except ValueError:
82  return NotImplemented
83 
84  # each one of these keywords (both binary and unary) are
85  # the names of functions in the Parameter class which return
86  # that value for the Parameter
87  binary_keywords = {
88  'id': __validate_id,
89  'module': __validate_module,
90  'layer': __validate_layer,
91  'direction': {'u': 1, 'v': 2, 'w': 3}
92  }
93  unary_keywords = [
94  'top',
95  'bottom',
96  'translation',
97  'rotation',
98  'individual',
99  'axial',
100  'stereo',
101  'front',
102  'back',
103  'hole',
104  'slot'
105  ]
106 
107  # aliases are just a shortening of common Pattern strings
108  # that are drop-in replacements
109  aliases = {
110  'bot': 'bottom',
111  'trans': 'translation',
112  'rot': 'rotation',
113  'tu': 'direction=u & translation',
114  'rw': 'direction=w & rotation'
115  }
116 
117  def _add_check(self, c):
118  """! add a check into our list of checks, making sure it is the correct format"""
119  if not isinstance(c, tuple) or len(c) != 2:
120  raise ValueError("Checks have to be 2-tuples")
121 
122  kw = c[0].strip()
123 
124  if kw in Pattern.binary_keywords.keys():
125  # check is a binary check
126  possible_values = Pattern.binary_keywords[kw]
127  val = c[1].strip()
128  if isinstance(possible_values, dict):
129  if val in possible_values.keys():
130  self._checks_checks.append((kw, possible_values[val]))
131  else:
132  raise ValueError(f'Value {val} for {kw} not recognized. Possible values:\n{possible_values.keys()}')
133  else:
134  v = possible_values(val)
135  if v != NotImplemented:
136  self._checks_checks.append((kw, v))
137  else:
138  raise ValueError(f'Value {val} for {kw} is not recognized.')
139  elif kw in Pattern.unary_keywords:
140  self._checks_checks.append((kw, c[1]))
141  elif kw in Pattern.aliases:
142  self.__init____init__(Pattern.aliases[kw], first=False)
143  else:
144  raise ValueError(f'{kw} is not a recognized keyword')
145 
146  def __init__(self, pattern, *, first=True):
147  if first:
148  self._checks_checks = []
149  self._og_str_og_str = str(pattern)
150 
151  if not isinstance(pattern, (int, str)):
152  raise ValueError(f'Pattern {pattern} must be an int or str')
153 
154  # simplest pattern which is just the ID number
155  if isinstance(pattern, int) or pattern.isnumeric():
156  # make sure pattern is casted to str for the regex testing
157  self._add_check_add_check(('id', str(pattern)))
158  else:
159  # now complicated patterns
160  ops = pattern.split('&')
161  for op in ops:
162  if '=' in op:
163  # binary operation
164  split = op.split('=')
165  if len(split) != 2:
166  raise ValueError(f'{op} does not have two sides of the equality')
167  self._add_check_add_check(tuple(split))
168  else:
169  # unary operation
170  value = True
171  if op.startswith('!'):
172  op = op[1:]
173  value = False
174 
175  self._add_check_add_check((op, value))
176 
177  def match(self, p):
178  if not isinstance(p, Parameter):
179  return NotImplemented
180 
181  for kw, val in self._checks_checks:
182  if getattr(p, kw)() != val:
183  return False
184 
185  return True
186 
187  def __eq__(self, p):
188  return self.matchmatch(p)
189 
190  def __repr__(self):
191  return self._og_str_og_str
Pattern that can match one or more paramters.
Definition: _pattern.py:6
def __validate_layer(layer)
Make sure input is a valid layer number, otherwise return NotImplemented.
Definition: _pattern.py:70
def __validate_module(m)
Make sure input is a valid module number, otherwise return NotImplemented.
Definition: _pattern.py:56
def _add_check(self, c)
add a check into our list of checks, making sure it is the correct format
Definition: _pattern.py:117
def __validate_id(i)
Make sure input is a valid ID number, otherwise return NotImplemented.
Definition: _pattern.py:45
def __init__(self, pattern, *first=True)
Definition: _pattern.py:146