All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Classes | Functions | Variables
ICARUSgeometryChecker Namespace Reference

Classes

class  NestedIteration
 
class  SimpleProximityClusterer
 
class  AccumulateExtrema
 
class  StatCollector
 

Functions

def GeoPairToString
 
def BoxToString
 
def boxID
 
def CheckGeoObjOverlaps
 
def checkPlaneAlignment
 
def wireEndBorders
 
def checkWireEndingsInPlane
 
def checkPlaneWireAlignment
 
def checkWireAlignment
 
def groupPlanesByX
 
def performGeometryChecks
 

Variables

string __doc__
 
string __version__ = "%(prog)s 2.1"
 

Function Documentation

def ICARUSgeometryChecker.boxID (   box,
  default 
)

Definition at line 52 of file ICARUSgeometryChecker.py.

52 
53 def boxID(box, default):
54  try: return box.ID()
55  except AttributeError: return default
56 # boxID()
57 
58 
# ------------------------------------------------------------------------------
def ICARUSgeometryChecker.BoxToString (   box)

Definition at line 48 of file ICARUSgeometryChecker.py.

48 
49 def BoxToString(box): return "%s -- %s" % (box.Min(), box.Max())
50 
51 
# ------------------------------------------------------------------------------
def ICARUSgeometryChecker.CheckGeoObjOverlaps (   objs,
  objName = None,
  extractBox = None 
)
Returns a list of pairs of overlapping objects (empty if no overlap).

Definition at line 59 of file ICARUSgeometryChecker.py.

59 
60 def CheckGeoObjOverlaps(objs, objName = None, extractBox = None):
61  """Returns a list of pairs of overlapping objects (empty if no overlap)."""
62  if objName is None: objName = objs.__class__.__name__
63  overlaps = []
64  for (iObj1, obj1), (iObj2, obj2) in itertools.combinations(enumerate(objs), 2):
65  box1 = obj1 if extractBox is None else extractBox(obj1)
66  box2 = obj2 if extractBox is None else extractBox(obj2)
67  if not box2.Overlaps(box1): continue
68  logging.error("%s %s (%s to %s) and %s (%s to %s) overlap!", objName,
69  boxID(box1, iObj1), box1.Min(), box1.Max(),
70  boxID(box2, iObj2), box2.Min(), box2.Max(),
71  )
72  overlaps.append( ( obj1, obj2, ) )
73  # for boxes
74  return overlaps
75 # CheckGeoObjOverlaps()
76 
77 
# ------------------------------------------------------------------------------
auto enumerate(Iterables &&...iterables)
Range-for loop helper tracking the number of iteration.
Definition: enumerate.h:69
def ICARUSgeometryChecker.checkPlaneAlignment (   planes,
  tolerance = 0.1 
)
Check alignment in y and z position of planes on the same x.

Returns triples (distance, first plane, second plane) for each misaligned
pair of planes.

Definition at line 78 of file ICARUSgeometryChecker.py.

78 
79 def checkPlaneAlignment(planes, tolerance = 0.1):
80  """Check alignment in y and z position of planes on the same x.
81 
82  Returns triples (distance, first plane, second plane) for each misaligned
83  pair of planes.
84  """
85  assert tolerance >= 0.0
86  PlanesByX = groupPlanesByX(planes, sortBy = 'z')
87  inconsistentPlanes = {}
88  for planesOnX in PlanesByX:
89  if len(planesOnX) < 2: continue
90  planeIter = iter(planesOnX)
91  refPlane = next(planeIter)
92  for nextPlane in planeIter:
93  refBox = refPlane.BoundingBox()
94  nextBox = nextPlane.BoundingBox()
95  #
96  # 1. check plane alignment on z direction
97  #
98  distance = nextBox.MinZ() - refBox.MaxZ()
99  if abs(distance) > tolerance:
100  logging.error(
101  "Planes on x=%s are misaligned along z: ( %g -- %g ) (%s) vs. ( %g -- %g ) (%s)",
102  refPlane.GetCenter().X(), refBox.MinZ(), refBox.MaxZ(), refPlane.ID(),
103  nextBox.MinZ(), nextBox.MaxZ(), nextPlane.ID(),
104  )
105  inconsistentPlanes.setdefault('zalign', []) \
106  .append( ( distance, refPlane, nextPlane, ) )
107  # if misaligned on z
108 
109  #
110  # 2. check plane alignment on y direction
111  #
112  topDistance = nextBox.MaxY() - refBox.MaxY()
113  if abs(topDistance) > tolerance:
114  logging.error(
115  "Planes on x=%s are misaligned along y: ( %g -- %g ) (%s) vs. ( %g -- %g ) (%s)",
116  refPlane.GetCenter().X(), refBox.MinY(), refBox.MaxY(), refPlane.ID(),
117  nextBox.MinY(), nextBox.MaxY(), nextPlane.ID(),
118  )
119  inconsistentPlanes.setdefault('topYalign', []) \
120  .append( ( topDistance, refPlane, nextPlane, ) )
121  # if misaligned on top y
122  bottomDistance = nextBox.MinY() - refBox.MinY()
123  if abs(bottomDistance) > tolerance:
124  inconsistentPlanes.setdefault('bottomYalign', []) \
125  .append( ( bottomDistance, refPlane, nextPlane, ) )
126  # if misaligned on bottom y
127  if 'topYalign' in inconsistentPlanes or 'bottomYalign' in inconsistentPlanes:
128  logging.error(
129  "Planes on x=%s are misaligned along y: ( %g -- %g ) (%s) vs. ( %g -- %g ) (%s)",
130  refPlane.GetCenter().X(), refBox.MinY(), refBox.MaxY(), refPlane.ID(),
131  nextBox.MinY(), nextBox.MaxY(), nextPlane.ID(),
132  )
133  # if misaligned on bottom y
134 
135  #
136  # 3. check wire view
137  #
138  if refPlane.View() != nextPlane.View():
139  logging.error("Plane %s is on view '%s', %s is on view '%s'.",
140  refPlane.ID(), ROOT.geo.PlaneGeo.ViewName(refPlane.View()),
141  nextPlane.ID(), ROOT.geo.PlaneGeo.ViewName(nextPlane.View()),
142  )
143  inconsistentPlanes.setdefault('view', []) \
144  .append( ( refPlane, nextPlane, ) )
145  # if views do not match
146 
147  #
148  # 4. check wire orientation
149  #
150  if 1.0 - refPlane.GetIncreasingWireDirection().Dot(nextPlane.GetIncreasingWireDirection()) > tolerance:
151  logging.error("Plane %s measures direction %s, %s measures %s.",
152  refPlane.ID(), refPlane.GetIncreasingWireDirection(),
153  nextPlane.ID(), nextPlane.GetIncreasingWireDirection(),
154  )
155  inconsistentPlanes.setdefault('direction', []) \
156  .append( ( refPlane, nextPlane, ) )
157  # if views do not match
158 
159  #
160  # 5. check wire extremes alignment along y and z
161  #
162  # This check is different than the previous one in that it uses the actual
163  # coverage of wires rather than the wire plane box boundaries.
164  #
165  refWireMinY = min(
166  min(wire.GetStart().Y(), wire.GetEnd().Y())
167  for wire in refPlane.IterateWires()
168  )
169  refWireMaxY = max(
170  max(wire.GetStart().Y(), wire.GetEnd().Y())
171  for wire in refPlane.IterateWires()
172  )
173  refWireMaxZ = max(
174  max(wire.GetStart().Z(), wire.GetEnd().Z())
175  for wire in refPlane.IterateWires()
176  )
177  nextWireMinY = min(
178  min(wire.GetStart().Y(), wire.GetEnd().Y())
179  for wire in nextPlane.IterateWires()
180  )
181  nextWireMaxY = max(
182  max(wire.GetStart().Y(), wire.GetEnd().Y())
183  for wire in nextPlane.IterateWires()
184  )
185  nextWireMinZ = min(
186  min(wire.GetStart().Z(), wire.GetEnd().Z())
187  for wire in nextPlane.IterateWires()
188  )
189 
190  if abs(nextWireMinZ - refWireMaxZ) > tolerance:
191  logging.error(
192  "Wires of planes on x=%s are misaligned along z: %s ends at %g cm, %s restarts at %g cm",
193  refPlane.GetCenter().X(), refPlane.ID(), refWireMaxZ, nextPlane.ID(), nextWireMinZ,
194  )
195  inconsistentPlanes.setdefault('wireZalign', []) \
196  .append( ( nextWireMinZ - refWireMaxZ, refPlane, nextPlane, ) )
197  # if misaligned on z
198 
199  if abs(nextWireMaxY - refWireMaxY) > tolerance:
200  logging.error(
201  "Wires of planes on x=%s are misaligned along y: %s tops at %g cm, %s at %g cm",
202  refPlane.GetCenter().X(), refPlane.ID(), refWireMaxY, nextPlane.ID(), nextWireMaxY,
203  )
204  inconsistentPlanes.setdefault('wireTopYalign', []) \
205  .append( ( nextWireMaxY - refWireMaxY, refPlane, nextPlane, ) )
206  # if misaligned on top y
207 
208  if abs(nextWireMinY - refWireMinY) > tolerance:
209  logging.error(
210  "Wires of planes on x=%s are misaligned along y: %s floors at %g cm, %s at %g cm",
211  refPlane.GetCenter().X(), refPlane.ID(), refWireMinY, nextPlane.ID(), nextWireMinY,
212  )
213  inconsistentPlanes.setdefault('wireBottomYalign', []) \
214  .append( ( nextWireMinY - refWireMinY, refPlane, nextPlane, ) )
215  # if misaligned on top y
216 
217 
218  refPlane = nextPlane
219  # for all following planes on the same x
220  # for groups of planes along the same x
221  return inconsistentPlanes
222 # checkPlaneAlignment()
223 
224 
# ------------------------------------------------------------------------------
then echo echo For and will not be changed by echo further linking echo echo B echo The symbol is in the uninitialized data multiple common symbols may appear with the echo same name If the symbol is defined the common echo symbols are treated as undefined references For more echo details on common see the discussion of warn common echo in *Note Linker see the discussion of warn common echo in *Note Linker such as a global int variable echo as opposed to a large global array echo echo I echo The symbol is an indirect reference to another symbol This echo is a GNU extension to the a out object file format which is echo rarely used echo echo N echo The symbol is a debugging symbol echo echo R echo The symbol is in a read only data section echo echo S echo The symbol is in an uninitialized data section for small echo objects echo echo T echo The symbol is in the the normal defined echo symbol is used with no error When a weak undefined symbol echo is linked and the symbol is not the value of the echo weak symbol becomes zero with no error echo echo W echo The symbol is a weak symbol that has not been specifically echo tagged as a weak object symbol When a weak defined symbol echo is linked with a normal defined the normal defined echo symbol is used with no error When a weak undefined symbol echo is linked and the symbol is not the value of the echo weak symbol becomes zero with no error echo echo echo The symbol is a stabs symbol in an a out object file In echo this the next values printed are the stabs other echo the stabs desc and the stab type Stabs symbols are echo used to hold debugging information For more echo see *Note or object file format specific echo echo For Mac OS X
T abs(T value)
def ICARUSgeometryChecker.checkPlaneWireAlignment (   planeA,
  planeB,
  tolerance = 0.01 
)
Wires in the plane A are verified to have a continuation in plane B as another
wire. Only wires that reach the side (extreme z coordinate) are tested.

Wires are assumed to have to go top to bottom on y direction.

The list of misaligned wires is returned in the 5-uple form:
    
    ( shift, left wire ID, left wire, right wire ID, right wire )
    
if the wire on the left plane was matched to one on the right plane, and
    
    ( None, left wire ID, left wire, None, None )
    
if the wire on the left plane was not matched to any wire on the right plane.

Definition at line 321 of file ICARUSgeometryChecker.py.

322 def checkPlaneWireAlignment(planeA, planeB, tolerance = 0.01):
323  """
324  Wires in the plane A are verified to have a continuation in plane B as another
325  wire. Only wires that reach the side (extreme z coordinate) are tested.
326 
327  Wires are assumed to have to go top to bottom on y direction.
328 
329  The list of misaligned wires is returned in the 5-uple form:
330 
331  ( shift, left wire ID, left wire, right wire ID, right wire )
332 
333  if the wire on the left plane was matched to one on the right plane, and
334 
335  ( None, left wire ID, left wire, None, None )
336 
337  if the wire on the left plane was not matched to any wire on the right plane.
338  """
339  # throughout this code, left refers to lower _z_, right to higher _z_
340 
341  misalignedWires = []
342 
343  # define a left and a right plane
344  if planeA.GetCenter().Z() < planeB.GetCenter().Z():
345  leftPlane, rightPlane = planeA, planeB
346  else:
347  leftPlane, rightPlane = planeB, planeA
348 
349  # wire pitch should be the same for the two planes
350  rightWirePitch = rightPlane.WirePitch()
351  assert abs(rightWirePitch - leftPlane.WirePitch()) < tolerance
352 
353  #
354  # 1. determine the sides
355  #
356  leftMinY = min(
357  min(wire.GetStart().Y(), wire.GetEnd().Y())
358  for wire in leftPlane.IterateWires()
359  )
360  leftMaxY = max(
361  max(wire.GetStart().Y(), wire.GetEnd().Y())
362  for wire in leftPlane.IterateWires()
363  )
364  leftMaxZ = max(
365  max(wire.GetStart().Z(), wire.GetEnd().Z())
366  for wire in leftPlane.IterateWires()
367  )
368  # RminZ = min( min(wire.GetStart().Z(), wire.GetEnd().Z()) for wire in rightPlane.IterateWires() )
369 
370  #
371  # 2. for each wire in left plane ending close to right side, pick and test
372  # the matching wire of the right plane
373  #
374 
375  leftEndPos = lambda wire: \
376  wire.GetStart() if wire.GetStart().Z() > wire.GetEnd().Z() else wire.GetEnd()
377  rightStartPos = lambda wire: \
378  wire.GetStart() if wire.GetStart().Z() < wire.GetEnd().Z() else wire.GetEnd()
379 
380  stats = StatCollector()
381  wireNoDiff = None # offset in wire number only between matching wires
382  for leftWireNo, leftWire in enumerate(leftPlane.IterateWires()):
383 
384  leftEnd = leftEndPos(leftWire)
385 
386  #
387  # 2.1. if the wire does not end on the right edge, move on;
388  # if the wire ends on a corner, also move on
389  #
390  if abs(leftEnd.Z() - leftMaxZ) > 0.01: continue
391  if abs(leftEnd.Y() - leftMaxY) < 0.01 or abs(leftEnd.Y() - leftMinY) < 0.01:
392  continue
393 
394  #
395  # 2.2. find the closest wire on the left
396  #
397  leftWireID = ROOT.geo.WireID(leftPlane.ID(), leftWireNo)
398  try:
399  rightWireID = rightPlane.NearestWireID(leftEnd)
400  #except ( TypeError, ROOT.geo.InvalidWireError ) as e:
401  except TypeError as e:
402  rightWireID = None
403  except ROOT.geo.InvalidWireError as e:
404  # this branch is a placeholder, since Python 3 is not able to catch
405  # ROOT.geo.InvalidWireError (and if one is thrown, a TypeError will raise)
406  logging.error(
407  "No wire on %s is close enough to %s (closest is %s, but would have been %s)",
408  rightPlane.ID(), leftWireID,
409  (e.suggestedWireID() if e.hasSuggestedWire() else "unknown"),
410  (e.badWireID() if e.hasBadWire() else "unknown"),
411  )
412  rightWireID = e.badWireID() if e.hasBadWire() else None
413  rightWireID.markInvalid()
414  misalignedWires.append( ( None, leftWireID, leftWire, None, None, ) )
415  continue
416  # try ... except no wire matched
417  if not rightWireID:
418  msg = ""
419  if rightWireID is None:
420  msg += "No wire on {} is close enough to {}" \
421  .format(rightPlane.ID(), leftWireID)
422  else: # just invalid
423  msg += "No wire on {} is close enough to {} (would have been {})" \
424  .format(rightPlane.ID(), leftWireID, rightWireID)
425  # if ... else
426 
427  wireCoord = rightPlane.WireCoordinate(leftEnd)
428  msg += "; closest would have been {} W: {}" \
429  .format(rightPlane.ID(), wireCoord)
430 
431  nearestWireID = ROOT.geo.WireID(rightPlane.ID(), int(0.5 + wireCoord)) \
432  if 0.5 + wireCoord >= 0.0 else None
433  nearestWire = None
434  if nearestWireID and rightPlane.HasWire(nearestWireID):
435  nearestWire = rightPlane.Wire(nearestWireID)
436  if nearestWire:
437  msg += "; actual {} ends at: {}" \
438  .format(nearestWireID, rightStartPos(nearestWire))
439 
440  logging.error(msg)
441  misalignedWires.append( ( None, leftWireID, leftWire, None, None, ) )
442  continue
443  #
444 
445  rightWire = rightPlane.Wire(rightWireID)
446 
447  #
448  # 2.3. check the projected distance of that wire from this one
449  #
450  shift = leftWire.DistanceFrom(rightWire)
451  stats.add(shift)
452 
453  #
454  # 2.4. compare wire orientation
455  #
456  leftWire.Direction().Dot(rightWire.Direction())
457  if 1.0 - leftWire.Direction().Dot(rightWire.Direction()) > tolerance:
458  logging.error(
459  "Wire %s has direction %s, the matched %s has %s",
460  leftWireID, leftWire.Direction(),
461  rightWireID, rightWire.Direction(),
462  )
463  # if too far
464 
465  #
466  # 2.5. check that wires touch
467  #
468  d = (leftEndPos(leftWire) - rightStartPos(rightWire)).Mag()
469  if d > tolerance:
470  logging.debug(
471  "Distance of wire %s (%s) from the matched wire %s (%s): %g",
472  leftWireID, leftEndPos(leftWire),
473  rightWireID, rightStartPos(rightWire),
474  d
475  )
476  # find which is the wire physically closest to leftWire
477  closestWireID, d_min = rightWireID, d
478  testWireID = rightWireID
479  while testWireID.Wire > 0:
480  testWireID.Wire -= 1
481  testWire = rightPlane.Wire(testWireID)
482  test_d = (leftEndPos(leftWire) - rightStartPos(testWire)).Mag()
483  logging.debug("Distance from %s (%s): %g", testWireID, rightStartPos(testWire), test_d)
484  if test_d >= d_min: break
485  closestWireID, d_min = testWireID, test_d
486  # while
487  testWireID = rightWireID
488  LastWireNo = rightPlane.Nwires() - 1
489  while testWireID.Wire < LastWireNo:
490  testWireID.Wire += 1
491  testWire = rightPlane.Wire(testWireID)
492  test_d = (leftEndPos(leftWire) - rightStartPos(testWire)).Mag()
493  logging.debug("Distance from %s (%s): %g", testWireID, rightStartPos(testWire), test_d)
494  if test_d >= d_min: break
495  closestWireID, d_min = testWireID, test_d
496  # while
497 
498  logging.error(
499  "Wire %s ends at %s, the matched wire %s starts at %s, %g cm away.",
500  leftWireID, leftEndPos(leftWire),
501  rightWireID, rightStartPos(rightWire),
502  d
503  )
504  if closestWireID != rightWireID:
505  logging.error(
506  " => the closest wire is actually %s starting at %s, %g cm away",
507  closestWireID, rightPlane.Wire(closestWireID), d_min
508  )
509  # if
510 
511  misalignedWires.append( ( d_min, leftWireID, leftWire, rightWireID, rightWire ) )
512 
513  # if too far
514 
515  # for wires in the left plane
516 
517  if stats.entries() > 0:
518  logging.debug("Shift for %d wires between %s and %s: %g +/- %g cm",
519  stats.entries(), leftPlane.ID(), rightPlane.ID(),
520  stats.average(), stats.RMS(),
521  )
522  else:
523  logging.debug("No wire shift statistics collected.")
524  return misalignedWires
525 # checkPlaneWireAlignment()
526 
527 
# ------------------------------------------------------------------------------
static std::string format(PyObject *obj, unsigned int pos, unsigned int indent, unsigned int maxlen, unsigned int depth)
Definition: fclmodule.cxx:374
auto enumerate(Iterables &&...iterables)
Range-for loop helper tracking the number of iteration.
Definition: enumerate.h:69
T abs(T value)
def ICARUSgeometryChecker.checkWireAlignment (   planes,
  tolerance = 0.1 
)
Check alignment in z position of planes on the same x.

Returns triples (distance, first plane, second plane) for each misaligned
pair of planes.

Definition at line 528 of file ICARUSgeometryChecker.py.

529 def checkWireAlignment(planes, tolerance = 0.1):
530  """Check alignment in z position of planes on the same x.
531 
532  Returns triples (distance, first plane, second plane) for each misaligned
533  pair of planes.
534  """
535  assert tolerance >= 0.0
536  PlanesByX = groupPlanesByX(planes, sortBy = 'z')
537  misalignedWires = [] # grouped by extended plane
538  for planesOnX in PlanesByX:
539  if len(planesOnX) < 2: continue
540  misalignedWiresOnPlane = []
541  planeIter = iter(planesOnX)
542  leftPlane = next(planeIter)
543  for rightPlane in planeIter:
544  misalignedWiresOnPair \
545  = checkPlaneWireAlignment(leftPlane, rightPlane, tolerance=tolerance)
546  if misalignedWiresOnPair:
547  misalignedWiresOnPlane.extend(misalignedWiresOnPair)
548  leftPlane = rightPlane
549  # for all following planes on the same x
550  if misalignedWiresOnPlane: misalignedWires.append(misalignedWiresOnPlane)
551  # for groups of planes along the same x
552  return misalignedWires
553 # checkWireAlignment()
554 
555 
# ------------------------------------------------------------------------------
def ICARUSgeometryChecker.checkWireEndingsInPlane (   plane,
  tolerance = 0.01 
)
Wires which do not end on any border of the plane are returned.

The border is determined by the wires themselves rather than the plane box,
which could in principle extend further (but not less).

A dictionary is returned with key the ID of the wire not ending on a border,
and a list of end labels ('start', 'end') listing which end did not.

Definition at line 245 of file ICARUSgeometryChecker.py.

246 def checkWireEndingsInPlane(plane, tolerance = 0.01):
247  """Wires which do not end on any border of the plane are returned.
248 
249  The border is determined by the wires themselves rather than the plane box,
250  which could in principle extend further (but not less).
251 
252  A dictionary is returned with key the ID of the wire not ending on a border,
253  and a list of end labels ('start', 'end') listing which end did not.
254  """
255 
256  assert tolerance >= 0.0
257 
258  #
259  # 1. determine the boundaries (brute force, brute programming)
260  #
261  borderCoords = {
262  'bottom': min(
263  min(wire.GetStart().Y(), wire.GetEnd().Y())
264  for wire in plane.IterateWires()
265  ),
266  'top': max(
267  max(wire.GetStart().Y(), wire.GetEnd().Y())
268  for wire in plane.IterateWires()
269  ),
270  'upstream': min(
271  min(wire.GetStart().Z(), wire.GetEnd().Z())
272  for wire in plane.IterateWires()
273  ),
274  'downstream': max(
275  max(wire.GetStart().Z(), wire.GetEnd().Z())
276  for wire in plane.IterateWires()
277  ),
278  } # borderCoords
279 
280  shorterWires = dict()
281  for iWire, wire in enumerate(plane.IterateWires()):
282 
283  wireID = ROOT.geo.WireID(plane.ID(), iWire)
284 
285  #
286  # 1. check the start
287  #
288  start = wire.GetStart()
289  borders = wireEndBorders(start, borderCoords, tolerance)
290 
291  # there should be at least one border touched by each wire end
292  if len(borders) == 0:
293  logging.error(
294  "Wire %s \"start\" at %s cm does not touch any plane border (%s)",
295  wireID, start, ", ".join("%s: %g" % item for item in borderCoords.items()),
296  )
297  shorterWires.setdefault(wireID, []).append('start')
298  # if error
299 
300  #
301  # 2. check the end
302  #
303  end = wire.GetEnd()
304  borders = wireEndBorders(end, borderCoords, tolerance)
305 
306  # there should be at least one border touched by each wire end
307  if len(borders) == 0:
308  logging.error(
309  "Wire %s \"end\" at %s cm does not touch any plane border (%s)",
310  wireID, end, ", ".join("%s: %g" % item for item in borderCoords.items()),
311  )
312  shorterWires.setdefault(wireID, []).append('end')
313  # if error
314 
315  # for
316 
317  return shorterWires
318 # checkWireEndingsInPlane()
319 
320 
# ------------------------------------------------------------------------------
auto enumerate(Iterables &&...iterables)
Range-for loop helper tracking the number of iteration.
Definition: enumerate.h:69
S join(S const &sep, Coll const &s)
Returns a concatenation of strings in s separated by sep.
def ICARUSgeometryChecker.GeoPairToString (   pair)

Definition at line 45 of file ICARUSgeometryChecker.py.

45 
46 def GeoPairToString(pair):
47  return " - ".join(map(lambda obj: str(obj.ID()), pair))
S join(S const &sep, Coll const &s)
Returns a concatenation of strings in s separated by sep.
def ICARUSgeometryChecker.groupPlanesByX (   planes,
  tolerance = 0.1,
  sortBy = None 
)

Definition at line 582 of file ICARUSgeometryChecker.py.

583 def groupPlanesByX(planes, tolerance = 0.1, sortBy = None):
584  xPos = lambda plane: plane.GetCenter().X()
585  cluster = SimpleProximityClusterer(xPos, tolerance) # 1 mm
586  groupedByX = cluster(sorted(planes, key=xPos))
587  if sortBy:
588  if sortBy.lower() == 'x':
589  sortKey = xPos
590  elif sortBy.lower() == 'y':
591  sortKey = lambda plane: plane.GetCenter().Y()
592  elif sortBy.lower() == 'z':
593  sortKey = lambda plane: plane.GetCenter().Z()
594  else:
595  raise RuntimeError("Unsupported sorting requested: '%s'" % sortBy)
596  for planes in groupedByX: planes.sort(key=sortKey)
597  # if sorting
598  return groupedByX
599 # groupPlanesByX()
600 
601 
# ------------------------------------------------------------------------------
Cluster finding and building.
then echo echo For and will not be changed by echo further linking echo echo B echo The symbol is in the uninitialized data multiple common symbols may appear with the echo same name If the symbol is defined the common echo symbols are treated as undefined references For more echo details on common see the discussion of warn common echo in *Note Linker see the discussion of warn common echo in *Note Linker such as a global int variable echo as opposed to a large global array echo echo I echo The symbol is an indirect reference to another symbol This echo is a GNU extension to the a out object file format which is echo rarely used echo echo N echo The symbol is a debugging symbol echo echo R echo The symbol is in a read only data section echo echo S echo The symbol is in an uninitialized data section for small echo objects echo echo T echo The symbol is in the the normal defined echo symbol is used with no error When a weak undefined symbol echo is linked and the symbol is not the value of the echo weak symbol becomes zero with no error echo echo W echo The symbol is a weak symbol that has not been specifically echo tagged as a weak object symbol When a weak defined symbol echo is linked with a normal defined the normal defined echo symbol is used with no error When a weak undefined symbol echo is linked and the symbol is not the value of the echo weak symbol becomes zero with no error echo echo echo The symbol is a stabs symbol in an a out object file In echo this the next values printed are the stabs other echo the stabs desc and the stab type Stabs symbols are echo used to hold debugging information For more echo see *Note or object file format specific echo echo For Mac OS X
def ICARUSgeometryChecker.performGeometryChecks (   argv)

Definition at line 647 of file ICARUSgeometryChecker.py.

648 def performGeometryChecks(argv):
649 
650  import argparse
651 
652  Parser = argparse.ArgumentParser(description=__doc__)
653 
654  Parser.set_defaults()
655 
656  Parser.add_argument("config", help="configuration file [FHiCL]")
657 
658  Parser.add_argument("--servicetable", "-T", default='services',
659  help="name of the FHiCL table where all services are configured ['%(default)s']"
660  )
661 
662  Parser.add_argument("--debug", "-d", action="count", default=0,
663  help="be more verbose")
664 
665  Parser.add_argument("--version", "-V", action="version", version=__version__)
666 
667  #argGroup = Parser.add_argument_group(title="Numerical output format")
668  #argGroup.add_argument("--integer", "-d", "-i", action="store_false",
669  #dest="bFloat", help="sets the sum of integral numbers")
670 
671  args = Parser.parse_args(args=argv[1:])
672 
673  # `logging.DEBUG` is the standard debugging level;
674  # `logging.DEBUG + 1` (args.debug = 0) is a bit less verbose, but still well
675  # within `logging.INFO` level
676  logging.basicConfig(level=logging.DEBUG - (args.debug - 1))
677 
678  from ICARUSservices import ServiceManager
679  import cppUtils
680  import ROOT
681  import ROOTutils
682 
683  # this is for a bug present in LArSoft v08_52_00 (and many other versions);
684  # the header where exception geo::InvalidWireError is defined is not included.
685  cppUtils.SourceCode.loadHeaderFromUPS("larcorealg/Geometry/Exceptions.h")
686 
687  global ROOT
688 
689  ServiceManager.setConfiguration(args.config, args.servicetable)
690 
691  geom = ServiceManager('Geometry')
692 
693  FailureSummary = []
694 
695  Cryostats = list(geom.IterateCryostats())
696  TPCs = list(geom.IterateTPCs())
697  Planes = list(geom.IteratePlanes())
698 
699  #
700  # cryostat overlap
701  #
702  overlappingCryostats = CheckGeoObjOverlaps(Cryostats, "cryostat")
703  if overlappingCryostats:
704  msg = "%s cryostat overlaps detected: %s." % (
705  len(overlappingCryostats),
706  ", ".join(map(GeoPairToString, overlappingCryostats)),
707  )
708  logging.error(msg)
709  FailureSummary.append(msg)
710  else: logging.info("No cryostat overlap detected.")
711 
712  #
713  # TPC overlaps
714  #
715  overlappingTPCs = CheckGeoObjOverlaps(TPCs, "TPC")
716  if overlappingTPCs:
717  msg = "%s TPC overlaps detected: %s." % (
718  len(overlappingTPCs), ", ".join(map(GeoPairToString, overlappingTPCs)),
719  )
720  logging.error(msg)
721  FailureSummary.append(msg)
722  else: logging.info("No TPC overlap detected.")
723 
724  #
725  # TPC active volume overlaps
726  #
727  overlappingActiveVolTPCs = CheckGeoObjOverlaps \
728  (TPCs, "active TPC volume", extractBox=ROOT.geo.TPCGeo.ActiveBoundingBox)
729  if overlappingActiveVolTPCs:
730  msg = "%s TPC active volume overlaps detected: %s." % (
731  len(overlappingActiveVolTPCs),
732  ", ".join(map(GeoPairToString, overlappingActiveVolTPCs)),
733  )
734  logging.error(msg)
735  FailureSummary.append(msg)
736  else: logging.info("No TPC active volume overlap detected.")
737 
738  #
739  # plane box overlaps
740  #
741  overlappingPlanes = CheckGeoObjOverlaps \
742  (Planes, "wire planes", extractBox=ROOT.geo.PlaneGeo.BoundingBox)
743  if overlappingPlanes:
744  logging.error("%s wire plane overlaps detected: %s.",
745  len(overlappingPlanes),
746  ", ".join(map(GeoPairToString, overlappingPlanes))
747  )
748  FailureSummary.append \
749  ("%s wire plane overlaps detected." % len(overlappingPlanes))
750  else: logging.info("No wire plane overlap detected.")
751 
752  #
753  # check plane alignment
754  #
755  inconsistentPlanes = checkPlaneAlignment(Planes, tolerance=0.0001) # 1 um (!!)
756 
757  try: planesWithIssues = inconsistentPlanes['zalign']
758  except KeyError:
759  logging.info("All %d planes are correctly aligned along z.", len(Planes))
760  else:
761  logging.error("%s wire planes present misalignment on z: %s",
762  len(planesWithIssues), ", ".join(
763  "%s vs. %s (%g mm)" % (planeA.ID(), planeB.ID(), distance)
764  for distance, planeA, planeB in planesWithIssues
765  ),
766  )
767  FailureSummary.append \
768  ("%s wire planes present misalignment: " % len(misalignedPlanes))
769  # if error
770 
771  try: planesWithIssues = inconsistentPlanes['topYalign']
772  except KeyError:
773  logging.info("Top of all %d planes is correctly aligned.", len(Planes))
774  else:
775  logging.error("%s wire planes present misalignment of top side: %s",
776  len(planesWithIssues), ", ".join(
777  "%s vs. %s (%g mm)" % (planeA.ID(), planeB.ID(), distance)
778  for distance, planeA, planeB in planesWithIssues
779  ),
780  )
781  FailureSummary.append \
782  ("%s wire planes present misalignment on top side" % len(planesWithIssues))
783  # if error
784 
785  try: planesWithIssues = inconsistentPlanes['bottomYalign']
786  except KeyError:
787  logging.info("Bottom of all %d planes is correctly aligned.", len(Planes))
788  else:
789  logging.error("%s wire planes present misalignment of bottom side: %s",
790  len(planesWithIssues), ", ".join(
791  "%s vs. %s (%g mm)" % (planeA.ID(), planeB.ID(), distance)
792  for distance, planeA, planeB in planesWithIssues
793  ),
794  )
795  FailureSummary.append \
796  ("%s wire planes present misalignment on bottom side" % len(planesWithIssues))
797  # if error
798 
799  try: planesWithIssues = inconsistentPlanes['wireZalign']
800  except KeyError:
801  logging.info(
802  "Inter-plane areas covered by wires on all %d planes are correctly aligned.",
803  len(Planes)
804  )
805  else:
806  logging.error("%s planes have wires inconsistently covering the touching side: %s",
807  len(planesWithIssues), ", ".join(
808  "%s vs. %s (%g mm)" % (planeA.ID(), planeB.ID(), distance)
809  for distance, planeA, planeB in planesWithIssues
810  ),
811  )
812  FailureSummary.append(
813  "%s planes present inconsistent wire coverage on touching side"
814  % len(planesWithIssues)
815  )
816  # if error
817 
818  try: planesWithIssues = inconsistentPlanes['wireBottomYalign']
819  except KeyError:
820  logging.info(
821  "Bottom of areas covered by wires on all %d planes is correctly aligned.",
822  len(Planes)
823  )
824  else:
825  logging.error("%s planes have wires inconsistently covering bottom side: %s",
826  len(planesWithIssues), ", ".join(
827  "%s vs. %s (%g mm)" % (planeA.ID(), planeB.ID(), distance)
828  for distance, planeA, planeB in planesWithIssues
829  ),
830  )
831  FailureSummary.append(
832  "%s planes present inconsistent wire coverage on bottom side: "
833  % len(misalignedPlanes)
834  )
835  # if error
836 
837  try: planesWithIssues = inconsistentPlanes['wireTopYalign']
838  except KeyError:
839  logging.info(
840  "Top of areas covered by wires on all %d planes is correctly aligned.",
841  len(Planes)
842  )
843  else:
844  logging.error("%s planes have wires inconsistently covering top side: %s",
845  len(planesWithIssues), ", ".join(
846  "%s vs. %s (%g mm)" % (planeA.ID(), planeB.ID(), distance)
847  for distance, planeA, planeB in planesWithIssues
848  ),
849  )
850  FailureSummary.append(
851  "%s planes present inconsistent wire coverage on top side: "
852  % len(misalignedPlanes)
853  )
854  # if error
855 
856 
857 
858  try: planesWithIssues = inconsistentPlanes['view']
859  except KeyError:
860  logging.info("All %d planes have matching views.", len(Planes))
861  else:
862  logging.error("%s wire planes present direction inconsistencies:",
863  len(planesWithIssues), ", ".join(
864  "%s vs. %s" % (planeA.ID(), planeB.ID())
865  for planeA, planeB in planesWithIssues
866  ),
867  )
868  FailureSummary.append(
869  "%s wire planes present direction inconsistencies." % len(planesWithIssues)
870  )
871  # if error
872 
873  try: planesWithIssues = inconsistentPlanes['direction']
874  except KeyError:
875  logging.info("All %d planes have consistent directions.", len(Planes))
876  else:
877  logging.error("%s wire planes present view inconsistencies:",
878  len(planesWithIssues), ", ".join(
879  "%s vs. %s" % (planeA.ID(), planeB.ID())
880  for planeA, planeB in planesWithIssues
881  ),
882  )
883  FailureSummary.append(
884  "%s wire planes present view inconsistencies." % len(planesWithIssues)
885  )
886  # if error
887 
888  #
889  # check wire alignment
890  #
891  shorterWires = {}
892  for plane in Planes:
893  shorterWires.update(checkWireEndingsInPlane(plane, tolerance=0.01))
894  if shorterWires:
895  logging.error("Wires not ending on plane frame found (%d):",
896  len(shorterWires),
897  )
898  for wireID, ends in shorterWires.items():
899  logging.error(" %s: %s", wireID, ", ".join(ends))
900  FailureSummary.append \
901  ("%d wires do not end on plane frame" % len(shorterWires))
902  # if error
903 
904 
905  misalignedWires = checkWireAlignment(Planes, tolerance=0.0001) # 1 um required
906  if misalignedWires:
907  logging.error("Misaligned wires found on %d extended planes:",
908  len(misalignedWires),
909  )
910  for misalignedWiresOnPlane in misalignedWires:
911  logging.error(" %d on wires on plane around x=%g cm:",
912  len(misalignedWiresOnPlane),
913  misalignedWiresOnPlane[0][2].GetCenter().X()
914  )
915  for shift, wireLid, wireL, wireRid, wireR in misalignedWiresOnPlane:
916  if shift is None:
917  logging.error(" %s did not match any wire", wireLid)
918  else:
919  logging.error(" %s and %s are misaligned by %g um",
920  wireLid, wireRid, shift * 1.0e4,
921  )
922  # for all misaligned wire pairs
923  # for
924  FailureSummary.append \
925  ("misaligned wires found on %d extended planes" % len(misalignedWires))
926  else:
927  logging.info("No misaligned wires detected.")
928 
929  if FailureSummary:
930  logging.info("%d failure categories detected:\n - %s",
931  len(FailureSummary), "\n - ".join(FailureSummary),
932  )
933  # if failures
934  return 1 if FailureSummary else 0
935 # performGeometryChecks()
936 
937 
# ##############################################################################
then echo echo For and will not be changed by echo further linking echo echo B echo The symbol is in the uninitialized data multiple common symbols may appear with the echo same name If the symbol is defined the common echo symbols are treated as undefined references For more echo details on common see the discussion of warn common echo in *Note Linker see the discussion of warn common echo in *Note Linker such as a global int variable echo as opposed to a large global array echo echo I echo The symbol is an indirect reference to another symbol This echo is a GNU extension to the a out object file format which is echo rarely used echo echo N echo The symbol is a debugging symbol echo echo R echo The symbol is in a read only data section echo echo S echo The symbol is in an uninitialized data section for small echo objects echo echo T echo The symbol is in the the normal defined echo symbol is used with no error When a weak undefined symbol echo is linked and the symbol is not the value of the echo weak symbol becomes zero with no error echo echo W echo The symbol is a weak symbol that has not been specifically echo tagged as a weak object symbol When a weak defined symbol echo is linked with a normal defined the normal defined echo symbol is used with no error When a weak undefined symbol echo is linked and the symbol is not the value of the echo weak symbol becomes zero with no error echo echo echo The symbol is a stabs symbol in an a out object file In echo this the next values printed are the stabs other echo the stabs desc and the stab type Stabs symbols are echo used to hold debugging information For more echo see *Note or object file format specific echo echo For Mac OS X
S join(S const &sep, Coll const &s)
Returns a concatenation of strings in s separated by sep.
list
Definition: file_to_url.sh:28
def ICARUSgeometryChecker.wireEndBorders (   end,
  borderCoords,
  tolerance 
)
Returns the borders touched by the specified wire end.

Definition at line 225 of file ICARUSgeometryChecker.py.

226 def wireEndBorders(end, borderCoords, tolerance):
227  """Returns the borders touched by the specified wire end."""
228 
229  # this is overdoing, since the check only cares whether any border is touched
230 
231  borders = set()
232  for side in ( 'top', 'bottom', ):
233  if abs(end.Y() - borderCoords[side]) <= tolerance: borders.add(side)
234  assert ('top' not in borders) or ('bottom' not in borders)
235 
236  for side in ( 'upstream', 'downstream', ):
237  if abs(end.Z() - borderCoords[side]) <= tolerance: borders.add(side)
238  assert ('upstream' not in borders) or ('downstream' not in borders)
239 
240  return borders
241 
242 # wireEndBorders()
243 
244 
T abs(T value)

Variable Documentation

string ICARUSgeometryChecker.__doc__
Initial value:
1 = """
2 Performs simple checks on ICARUS geometry.
3 """

Definition at line 10 of file ICARUSgeometryChecker.py.

string ICARUSgeometryChecker.__version__ = "%(prog)s 2.1"

Definition at line 13 of file ICARUSgeometryChecker.py.