Package gavo :: Package stc :: Module eq
[frames] | no frames]

Source Code for Module gavo.stc.eq

  1  """ 
  2  Determining equivalence for STC systems. 
  3   
  4  Frequenently, one needs to decide if two systems are "close enough" to 
  5  work together, e.g., when building geometries or for ADQL geometry 
  6  predicates.  This code lets you define matching policies. 
  7  """ 
  8   
  9  #c Copyright 2008-2019, the GAVO project 
 10  #c 
 11  #c This program is free software, covered by the GNU GPL.  See the 
 12  #c COPYING file in the source distribution. 
 13   
 14   
 15  import re 
 16   
 17  from gavo import utils 
 18   
 19   
 20  _identifierPat = re.compile("[a-zA-Z_][a-zA-Z_]*$") 
21 22 @utils.memoized 23 -def makeKeyGetter(key):
24 """returns a function getting key from an object. 25 26 key is dot-seperated sequence of python identifiers (this is checked; a 27 ValueError is raised at generation time for malformed keys). 28 29 This function is used to generate functions accessing parts of 30 STC trees. If any attribute within key does not exist, the generated 31 functions return None. 32 """ 33 if (not key.strip() 34 or None in (_identifierPat.match(p) for p in key.split("."))): 35 raise ValueError("'%s' is no valid STC key."%key) 36 getterSrc = "\n".join([ 37 "def get(ob):", 38 " try:", 39 " return ob.%s"%key, 40 " except AttributeError:", 41 " return None"]) 42 ns = {} 43 exec getterSrc in ns 44 return ns["get"]
45
46 47 -class EquivalenceCondition(object):
48 """A base class for EquivalencePolicy elements. 49 50 An EquivalenceCondition has a 51 check(sys1, sys2) -> boolean 52 method. Everything else is up to the individual objects. 53 """
54 - def check(self, sys1, sys2):
55 """returns true when sys1 and sys2 are equivalent as far as this 56 condition is concerned. 57 58 sysN are dm.CoordSys instances. 59 """ 60 return False
61
62 - def _checkWithNone(self, val1, val2):
63 """returns True if val1 or val2 are None of if they are equal. 64 65 This should be the default logic for Equ.Pols. 66 """ 67 if val1 is None or val2 is None: 68 return True 69 return val1==val2
70
71 72 -class KeysEquivalent(EquivalenceCondition):
73 """An equivalence condition specifying a certain key being equal if 74 non-None in both objects. 75 76 key is a dot-seperated sequence of attribute names withing STC system 77 objects. 78 """
79 - def __init__(self, key):
80 self.getKey = makeKeyGetter(key)
81
82 - def check(self, sys1, sys2):
83 return self._checkWithNone( 84 self.getKey(sys1), self.getKey(sys2))
85
86 87 -class RefFramesEquivalent(EquivalenceCondition):
88 """An equivalence condition tailored for reference frames. 89 90 It considers ICRS and FK5 J2000 equivalent. 91 """
92 - def __init__(self):
93 self.getFrame = makeKeyGetter("spaceFrame.refFrame") 94 self.getEquinox = makeKeyGetter("spaceFrame.equinox")
95
96 - def check(self, sys1, sys2):
97 frame1, frame2 = self.getFrame(sys1), self.getFrame(sys2) 98 eq1, eq2 = self.getEquinox(sys1), self.getEquinox(sys2) 99 if (self._checkWithNone(frame1, frame2) 100 and self._checkWithNone(eq1, eq2)): 101 return True 102 # Yikes. If we get more cases like this, we need to think of something 103 if (set([frame1, frame2])==set(["ICRS", "FK5"])): 104 # we should only have one equinox -- get it and check it. 105 eq = [eq for eq in (eq1, eq2) if eq][0] 106 if eq.startswith("J2000"): 107 return True 108 return False
109
110 111 -class EquivalencePolicy(object):
112 """A policy specifying when two STC system objects are considered equivalent. 113 114 checkedKeys is a sequence of EquivalenceConditions or strings. If 115 strings are passed, they are turned into KeysEquivalent conditions 116 for the keys specified in the strings. 117 118 You can also pass entire STC trees to match. 119 """
120 - def __init__(self, checkedKeys):
121 self.conditions = [] 122 for cond in checkedKeys: 123 if isinstance(cond, EquivalenceCondition): 124 self.conditions.append(cond) 125 else: 126 self.conditions.append(KeysEquivalent(cond))
127
128 - def match(self, ast1, ast2):
129 ast1 = getattr(ast1, "astroSystem", ast1) 130 ast2 = getattr(ast2, "astroSystem", ast2) 131 for cond in self.conditions: 132 if not cond.check(ast1, ast2): 133 return False 134 return True
135 136 137 # The default equivalence policy. Currently ignores refFrames on space and 138 # time. 139 defaultPolicy = EquivalencePolicy([ 140 RefFramesEquivalent(), 141 "timeFrame.timeScale", 142 "spaceFrame.flavor", 143 "spaceFrame.nDim", 144 "spectralFrame.refPos.standardOrigin", 145 "redshiftFrame.refPos.standardOrigin", 146 "redshiftFrame.type", 147 "redshiftFrame.dopplerDef",]) 148