from __future__ import print_function from .lineType import Sl, Nw, Sr, Sg from .nodesi import Instruments from .basesc3 import sc3 import sys debug = 0 class DontFit(Exception): def __init__(self, message): Exception.__init__(self, message) class nslc(object): def __init__(self): self.start = None self.end = None self.code = None def __overlap__(self, another): if self.end: if self.end > another.start: if not another.end or self.start < another.end: return True else: if not another.end or self.start < another.end: return True return False def _span(self): return "%s / %s" % (self.start, self.end) def sc3Att(self): att = {} att['Start'] = self.start if self.end: att['End'] = self.end att['Code'] = self.code for (key,value) in self.att.items(): if not self.sc3ValidKey(key) or key in att: print("[%s] type %s ignoring attribute %s = %s " % (self.code, self.sc3Mode, key,value), file=sys.stderr) continue att[key] = value return att def _cmptime(t1, t2): if t1 is None and t2 is None: return 0 elif t2 is None or (t1 is not None and t1 < t2): return -1 elif t1 is None or (t2 is not None and t1 > t2): return 1 return 0 class StationGroup(nslc,sc3): def __str__(self): return "%s" % (self.code) def __init__(self, sg): if not isinstance(sg,Sg): return False self.stationReferences = [] sc3.__init__(self, 'stationGroup', self.stationReferences) self.code = sg.code self.start = sg.start self.end = sg.end self.att = sg.getStationGroupAttributes() self.srdata = [] def __match__(self, sr): if not isinstance(sr,Sr): return False return (_cmptime(sr.start, self.end) <= 0 and _cmptime(sr.end, self.start) >= 0) def conflict(self, another): if self.code != another.code: return False if self.end: if self.end <= another.start: return False if another.end and another.end <= self.start: return False else: if another.end and another.end <= self.start: return False return True def Sr(self, sr): self.srdata.append((sr.ncode, sr.scode, sr.start, sr.end)) def sc3Resolv(self, inventory): for (ncode, scode, start, end) in self.srdata: for stationID in inventory.resolveStation(ncode, scode, start, end): st = StationReference(self, stationID) self.stationReferences.append(st) class StationReference(sc3): def __str__(self): return "%s" % (self.att["StationID"]) def __init__(self, stationGroup, stationID): self.stationGroup = stationGroup sc3.__init__(self, 'stationReference') self.att = { "StationID": stationID } def sc3Att(self): return self.att class Network(nslc, sc3): def __str__(self): return "%s" % (self.code) def __init__(self, nw): if not isinstance(nw,Nw): return False self.stations = [] sc3.__init__(self, 'network', self.stations) nslc.__init__(self) self.code = nw.code self.start = nw.start self.end = nw.end self.att = nw.getNetworkAttributes() def __match__(self, sl): if not isinstance(sl,Sl): return False if sl.start < self.start: return False if self.end: if not sl.end or sl.end > self.end: return False return True def conflict(self, another): if self.code != another.code: return False if self.end: if self.end <= another.start: return False if another.end and another.end <= self.start: return False else: if another.end and another.end <= self.start: return False return True def Sl(self, sl): if not self.__match__(sl): raise DontFit(" Object doesn't fit this network object.") inserted = False for sta in self.stations: try: where = "%s" % (sta._span()) sta.Sl(sl) if debug: print("[%s] inserted at %s -> %s" % (self, where, sta._span()), file=sys.stderr) inserted = True for other in self.stations: if other is sta: continue if other.conflict(sta): raise Exception("I Station conflict with already existing station (%s/%s/%s)" % (other, other.start, other.end)) break except DontFit: pass if not inserted: st = Station(self, sl) if debug: print("[%s] created new station %s %s" % (self, st, st._span()), file=sys.stderr) for sta in self.stations: if sta.conflict(st): raise Exception("Station conflict with already existing station (%s/%s/%s)" % (sta, sta.start, sta.end)) self.stations.append(st) def check(self, i): error = [] for station in self.stations: error.extend(station.check(i)) return error def use(self, iid): c = False for station in self.stations: c = c or station.use(iid) if c: break return c class Station(nslc, sc3): def __str__(self): return "%s.%s" % (self.network.code, self.code) def __init__(self, network, sl): if not isinstance(sl,Sl): return False self.locations = [] self.network = network sc3.__init__(self, 'station', self.locations) # I load myself as a station nslc.__init__(self) self.code = sl.code self.start = sl.start self.end = sl.end self.att = sl.getStationAttributes() # Further parse to generate my locations self.Sl(sl) def __match__(self, obj): if not isinstance(obj,Sl): return False # Check code if obj.code != self.code: return False # Attributes att = obj.getStationAttributes() for at in att: # Make sure that all attributes in Sl-line are here if at not in self.att: return False # And they match if att[at] != self.att[at]: return False # Make sure that there is no other attribute here that is not on Sl-line for at in self.att: if at not in att: return False return True def __adjustTime__(self, sl): if sl.start < self.start: self.start = sl.start if not self.end: return if sl.end and sl.end < self.end: return self.end = sl.end def conflict(self, another): if not isinstance(another, Station): raise Exception("Cannot compare myself with %s" % type(another)) if self.code != another.code: return False if not self.__overlap__(another): return False return True def use(self, iid): c = False for location in self.locations: c = c or location.use(iid) if c: break return c def check(self, i): error = [] for location in self.locations: error.extend(location.check(i)) return error def Sl(self, sl): if not self.__match__(sl): raise DontFit(" sl doesn't fit this station %s/%s_%s." % (self.code, self.start, self.end)) # Handle Time Adjustments self.__adjustTime__(sl) # Handle Locations inserted = False for loc in self.locations: try: where = loc._span() loc.Sl(sl) if debug: print(" [%s] inserted at %s -> %s" % (self, where, loc._span()), file=sys.stderr) inserted = True for other in self.locations: if other is loc: continue if other.conflict(loc): raise Exception("Location conflict with already existing location") break except DontFit: pass if not inserted: loc = Location(self, sl) if debug: print(" [%s] created new location %s %s" % (self, loc, loc._span()), file=sys.stderr) for lc in self.locations: if lc.conflict(loc): raise Exception("Location conflict with already existing location") self.locations.append(loc) def sc3Att(self): att = nslc.sc3Att(self) ## Make sure that we set the Remark if 'ArchiveNetworkCode' not in att: att['ArchiveNetworkCode'] = self.network.code if 'Remark' not in att: att['Remark'] = "" return att class Location(nslc, sc3): def __str__(self): return "%s.%s.%s" % (self.station.network.code, self.station.code, self.code) def __init__(self, station, sl): if not isinstance(sl, Sl): return False self.channels = [] sc3.__init__(self, 'location', self.channels) nslc.__init__(self) self.station = station self.code = sl.location self.start = sl.start self.end = sl.end self.att = sl.getLocationAttributes() self.Sl(sl) def __adjustTime__(self, sl): if sl.start < self.start: self.start = sl.start if not self.end: return if sl.end and sl.end < self.end: return self.end = sl.end def __match__(self, obj): if not isinstance(obj, Sl): return False if obj.location != self.code: return False # Attributes att = obj.getLocationAttributes() for at in att: # Make sure that all attributes in Sl-line are here if at not in self.att: return False # And they match if att[at] != self.att[at]: return False # Make sure that there is no other attribute here that is not on Sl-line for at in self.att: if at not in att: return False return True def conflict(self, another): if not isinstance(another, Location): raise Exception("Cannot compare myself with %s" % type(another)) if self.code != another.code: return False if not self.__overlap__(another): return False return True def use(self, iid): c = False for channel in self.channels: c = c or channel.use(iid) if c: break return c def check(self, i): error = [] for channel in self.channels: error.extend(channel.check(i)) return error def Sl(self, sl): if not self.__match__(sl): raise DontFit(" This obj doesn't match this Location '%s'" % self.code) # Handle Time Adjustments self.__adjustTime__(sl) # Create Channels for code in sl.channels: channel = (Channel(self, code, sl)) if debug: print(" [%s] created new channel %s/%s" % (self, channel, channel._span()), file=sys.stderr) for echan in self.channels: if echan.conflict(channel): raise Exception("[%s] channel %s conflict with already existing channel" % (self, code)) #print >>sys.stderr," Channel %s appended at '%s'" % (code, self.code) self.channels.append(channel) class Channel(nslc, sc3): def __str__(self): return "%s.%s.%s.%s" % (self.location.station.network.code, self.location.station.code, self.location.code, self.code) def __init__(self, location, code, sl): sc3.__init__(self, 'channel') self.location = location nslc.__init__(self) self.code = code self.start = sl.start self.end = sl.end self.att = sl.getChannelAttributes(self.code) ## Bring the Instrument gains to the channel level self._sensorGain = sl.sensorGain self._dataloggerGain = sl.dataloggerGain def conflict(self, another): if not isinstance(another, Channel): raise Exception("Cannot compare myself with %s" % type(another)) if self.code != another.code: return False if not self.__overlap__(another): return False return True def use(self, iid): if 'Datalogger' in self.att and iid == self.att['Datalogger']: return True if 'Sesor' in self.att and iid == self.att['Sensor']: return True return False def check(self, i): good = [] if not isinstance(i, Instruments): raise Exception("Invalid instrument object") if not self.att['Datalogger'] in i.keys: good.append("no Datalogger") if not self.att['Sensor'] in i.keys: good.append("no Sensor") if good: good = [ " [%s] %s" % (self, "/".join(good)) ] return good def sc3Resolv(self, inventory): if not inventory: print("[%s] Warning, inventory not supplied" % self.code, file=sys.stderr) return try: ssm = self.att['Sensor'] ssg = self._sensorGain sch = self.att['SensorChannel'] ssn = self.att["SensorSerialNumber"] if "SensorSerialNumber" in self.att else None # Sensor publicID ss = inventory.sensorID(ssm, ssg) self.att['Sensor'] = ss # Sensor Calibration inventory.loadSensorCalibrations(ssm, ssn, sch, ssg, self.start, self.end, ss) except Exception as e: print("[%s] Sensor Resolution Error %s" % (self, e), file=sys.stderr) ss = None try: dsm = self.att['Datalogger'] dsg = self._dataloggerGain dch = self.att['DataloggerChannel'] dsn = self.att['DataloggerSerialNumber'] if 'DataloggerSerialNumber' in self.att else None dt = inventory.dataloggerID(dsm, dsg) self.att['Datalogger'] = dt inventory.loadDataloggerCalibrations(dsm, dsn, dch, dsg, self.start, self.end, dt) except Exception as e: print("[%s] Datalogger Resolution Error %s" % (self, e), file=sys.stderr) dt = None try: up = self.att['SampleRateNumerator'] down = self.att['SampleRateDenominator'] self.att.update(inventory.getChannelGainAttribute(dt, ss, dsn, ssn, dch, sch, up, down, self.start)) except Exception as e: print("[%s] Cannot find gain back for the channel: %s" % (self,e), file=sys.stderr)