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

Source Code for Module gavo.stc.common

  1  """ 
  2  Definitions and shared code for STC processing. 
  3  """ 
  4   
  5  #c Copyright 2008-2019, the GAVO project 
  6  #c 
  7  #c This program is free software, covered by the GNU GPL.  See the 
  8  #c COPYING file in the source distribution. 
  9   
 10   
 11  import math 
 12  import operator 
 13   
 14  from gavo import utils 
 15  from gavo.utils import ElementTree #noflake:clients expect this name 
 16  from gavo.utils.stanxml import Stub, registerPrefix, schemaURL 
 17   
 18   
19 -class STCError(utils.Error):
20 pass
21
22 -class STCSParseError(STCError):
23 """is raised if an STC-S expression could not be parsed. 24 25 Low-level routines raise a pyparsing ParseException. Only higher 26 level functions raise this error. The offending expression is in 27 the expr attribute, the start position of the offending phrase in pos. 28 """
29 - def __init__(self, msg, expr=None, pos=None):
30 STCError.__init__(self, msg) 31 self.args = [msg, expr, pos] 32 self.pos, self.expr = pos, expr
33 34
35 -class STCLiteralError(STCError):
36 """is raised when a literal is not well-formed. 37 38 There is an attribute literal giving the malformed literal. 39 """
40 - def __init__(self, msg, literal=None):
41 STCError.__init__(self, msg) 42 self.args = [msg, literal] 43 self.literal = literal
44
45 -class STCInternalError(STCError):
46 """is raised when assumptions about the library behaviour are violated. 47 """
48
49 -class STCValueError(STCError):
50 """is raised when some STC specification is inconsistent. 51 """
52
53 -class STCUnitError(STCError):
54 """is raised when some impossible operation on units is requested. 55 """
56
57 -class STCXBadError(STCError):
58 """is raised when something is wrong with STC-X. 59 """
60
61 -class STCNotImplementedError(STCError):
62 """is raised when the current implementation limits are reached. 63 """
64 65 #### Constants 66 67 TWO_PI = 2*math.pi 68 tropicalYear = 365.242198781 # in days 69 secsPerJCy = 36525*86400. 70 71 STCNamespace = "http://www.ivoa.net/xml/STC/stc-v1.30.xsd" 72 XlinkNamespace = "http://www.w3.org/1999/xlink" 73 74 registerPrefix("stc", STCNamespace, 75 schemaURL("stc-v1.30.xsd")) 76 registerPrefix("xlink", XlinkNamespace, 77 schemaURL("xlink.xsd")) 78 79 80 # The following lists have to be updated when the STC standard is 81 # updated. They are used for building the STC-X namespace. 82 83 # known space reference frames 84 stcSpaceRefFrames = set(["ICRS", "FK4", "FK5", "ECLIPTIC", "GALACTIC_I", 85 "GALACTIC_II", "SUPER_GALACTIC", "AZ_EL", "BODY", "GEO_C", "GEO_D", "MAG", 86 "GSE", "GSM", "SM", "HGC", "HGS", "HPC", "HPR", "HEE", "HEEQ", "HGI", 87 "HRTN", "MERCURY_C", "VENUS_C", "LUNA_C", "MARS_C", "JUPITER_C_III", 88 "SATURN_C_III", "UNKNOWNFrame"]) 89 90 # known space reference positions 91 stcRefPositions = set(["TOPOCENTER", "BARYCENTER", "HELIOCENTER", "GEOCENTER", 92 "LSR", "LSRK", "LSRD", "GALACTIC_CENTER", "LOCAL_GROUP_CENTER", "MOON", 93 "EMBARYCENTER", "MERCURY", "VENUS", "MARS", "JUPITER", "SATURN", "URANUS", 94 "NEPTUNE", "PLUTO", "RELOCATABLE", "UNKNOWNRefPos", "CoordRefPos"]) 95 96 # known flavors for coordinates 97 stcCoordFlavors = set(["SPHERICAL", "CARTESIAN", "UNITSPHERE", "POLAR", 98 "CYLINDRICAL", "STRING", "HEALPIX"]) 99 100 # known time scales 101 stcTimeScales = set(["TT", "TDT", "ET", "TAI", "IAT", "UTC", "TEB", "TDB", 102 "TCG", "TCB", "LST", "nil"]) 103 104 105 # Nodes for ASTs 106
107 -def _compareFloat(val1, val2):
108 """returns true if val1==val2 up to a fudge factor. 109 110 This only works for floats. 111 112 >>> _compareFloat(30.0, 29.999999999999996) 113 True 114 """ 115 try: 116 return abs(val1-val2)/val1<1e-12 117 except ZeroDivisionError: # val1 is zero 118 return val2==0
119 120
121 -def _aboutEqual(val1, val2):
122 """compares val1 and val2 inexactly. 123 124 This is for comparing floats or sequences of floats. If you pass in 125 other sequences, bad things will happen. 126 127 It will return true if val1 and val2 are deemed equal. 128 129 >>> _aboutEqual(2.3, 2.2999999999999997) 130 True 131 >>> _aboutEqual(2.3, 2.299999997) 132 False 133 >>> _aboutEqual(None, 2.3) 134 False 135 >>> _aboutEqual((1e-10,1e10), (1.00000000000001e-10,1.00000000000001e10)) 136 True 137 >>> _aboutEqual((1e-10,1e10), (1.0000000001e-10,1.000000001e10)) 138 False 139 """ 140 if val1==val2: 141 return True 142 if isinstance(val1, float) and isinstance(val2, float): 143 return _compareFloat(val1, val2) 144 try: 145 return reduce(operator.and_, (_compareFloat(*p) 146 for p in zip(val1, val2))) 147 except TypeError: # At least one value is not iterable 148 return False
149 150
151 -class ASTNode(utils.AutoNode):
152 """The base class for all nodes in STC ASTs. 153 """ 154 _a_ucd = None 155 _a_id = None 156 157 inexactAttrs = set() 158 159 # we want fast comparison for identitical objects.
160 - def __eq__(self, other):
161 if not isinstance(other, self.__class__): 162 return False 163 if self is other: 164 return True 165 for name, _ in self._nodeAttrs: 166 if name=="id": 167 continue 168 if name in self.inexactAttrs: 169 if not _aboutEqual(getattr(self, name), getattr(other, name)): 170 return False 171 elif getattr(self, name)!=getattr(other, name): 172 return False 173 return True
174
175 - def __ne__(self, other):
176 return not self==other
177
178 - def __hash__(self):
179 return hash(id(self))
180
181 - def ensureId(self):
182 """sets id to some value if still None. 183 """ 184 if self.id is None: 185 self.id = utils.intToFunnyWord(id(self))
186 187
188 -class ColRef(Stub):
189 """A column reference instead of a true value, occurring in an STC-S tree. 190 """ 191 name_ = "_colRef" 192 193 # A ghastly hack: if someone sets this true at some point this 194 # reference will be rendered to a PARAMref rather than a FIELDref 195 # in VOTables. Well, this whole code needs overdoing. 196 toParam = False 197
198 - def __str__(self):
199 return self.dest
200 # only for debugging: '"%s"'%self.dest 201
202 - def __mul__(self, other):
203 raise STCValueError("ColRefs (here, %s) cannot be used in arithmetic" 204 " expressions."%repr(self))
205
206 - def encode(self, encoding): # for ElementTree.dump
207 return self.dest.encode(encoding)
208
209 - def isoformat(self):
210 return self
211
212 - def apply(self, func):
213 return func(self, self.dest, {}, [])
214 215
216 -class GeometryColRef(ColRef):
217 """A ColRef that refers to an in-DB geometry. 218 219 These comprise the entire arguments of a geometry (or all coordinates 220 of a vector). They implement __len__ as soon as they are validated 221 (in stcsast; we don't do col. refs in stc-x); their len is the 222 expected number of elements. 223 """ 224 expectedLength = None 225
226 - def __len__(self):
227 if self.expectedLength is None: 228 raise STCValueError("No length on unvalidated geometry column" 229 " reference") 230 return self.expectedLength
231
232 - def __nonzero__(self):
233 return True
234 235
236 -def clampLong(val):
237 """returns val standardized as a latitude. 238 239 Our latitudes are always in [0, 2*pi]. 240 """ 241 val = math.fmod(val, TWO_PI) 242 if val<0: 243 val += TWO_PI 244 return val
245 246
247 -def clampLat(val):
248 """returns val standardized as a latitude. 249 250 Our latitudes are always in [-pi, pi]. 251 """ 252 val = math.fmod(val, TWO_PI) 253 if val<-math.pi: 254 val += TWO_PI 255 if val>math.pi: 256 val -= TWO_PI 257 return val
258 259
260 -def _test():
261 import doctest, gavo.stc.common 262 doctest.testmod(gavo.stc.common)
263 264 if __name__=="__main__": 265 _test() 266