from __future__ import print_function from .lineType import Dl, Se, Ff, Pz, Cl from .basesc3 import sc3 import sys class prefixable(object): def adjust(self, prefix): if prefix: self.id = "%s:%s" % (prefix, self.id) class Instruments(object): def __init__(self, prefix=""): self.keys = [] self.ses = {} self.dls = {} self.fls = {} self.cls = {} self._sensors = {} self._datalogger = {} self._filters = {} self._Cal = {} self._prefix = prefix def sc3Objs(self): objs = [] for s in list(self._sensors.values()): objs.append(s.sc3Obj(self)) for s in list(self._datalogger.values()): objs.append(s.sc3Obj(self)) for s in list(self._filters.values()): objs.append(s.sc3Obj(self)) return objs def add(self, obj): where = None if isinstance(obj, Se): where = self.ses elif isinstance(obj, Dl): where = self.dls elif isinstance(obj, Cl): where = self.cls elif isinstance(obj, Ff) or isinstance(obj, Pz): where = self.fls else: raise Exception("Object type %s doesn't fir this class" % type(obj)) if obj.id in self.keys: raise Exception("Object id %s already exist." % (obj)) self.keys.append(obj.id) where[obj.id] = obj return def instrumentId(self, iid, gain): if gain is None: if iid in self.dls: gain = self.dls[iid].gain elif iid in self.ses: gain = self.ses[iid].gain else: raise Exception("Instrument iid not found") siid = "%s/g=%s" % (iid, int(float(gain))) return siid def loadDataloggerCalibrations(self, dsm, dsn, dch, dsg, start, end, dd): cls = [] for cl in self.cls.values(): if cl.type != "L": continue if cl.match(dsm, dsn): cls.append(Calibration(cl, dch, start, end)) if len(cls) == 0: if dsn in self.cls: print("[%s] No calibrations found for serial number %s and model %s " % (dsm, dsn, dsm), file=sys.stderr) return diid = self.instrumentId(dsm, dsg) try: datalogger = self._datalogger[diid].sc3Obj(self) if dd != datalogger.publicID(): raise Exception("Public Id doesn't match") except: raise Exception("[%s] Could not retrieve datalogger %s" % (dsm, diid)) for cl in cls: if (dsm, dsn, dch, start, end) in self._Cal: ## print >> sys.stderr,"[%s] Skiping calibration channel %s" % (dsm, cl.channel) continue ## print >> sys.stderr,"[%s] Adding calibration %s (%s)" % (dsm, cl.channel, dd) datalogger.add(cl.sc3Obj(self)) self._Cal[(dsm, dsn, dch, start, end)] = cl def loadSensorCalibrations(self, ssm, ssn, sch, ssg, start, end, ss): cls = [] for cl in self.cls.values(): if cl.type != "S": continue if cl.match(ssm, ssn): cls.append(Calibration(cl, sch, start, end)) if len(cls) == 0: if ssn in self.cls: print("[%s] No calibrations found for serial number %s and model %s " % (ssm,ssn, ssm), file=sys.stderr) return siid = self.instrumentId(ssm, ssg) try: sensor = self._sensors[siid].sc3Obj(self) if ss != sensor.publicID(): raise Exception("Public Id doesn't match") except: raise Exception("[%s] Could not retrieve sensor %s" % (ssm, siid)) for cl in cls: if (ssm, ssn, sch, start, end) in self._Cal: ## print >> sys.stderr,"[%s] Skiping calibration channel %s" % (ssm, cl.channel) continue ## print >> sys.stderr,"[%s] Adding calibration %s channel %s start %s" % (ssm, ssn, cl.channel, start) sensor.add(cl.sc3Obj(self)) self._Cal[(ssm, ssn, sch, start, end)] = cl def check(self, networks): error = [] # Dataloggers check error.append("* Dataloggers:") for dl in self.dls.values(): error.extend(dl.check(self)) error.append("") # Check fir filters error.append("* Filters:") for f in self.fls.values(): c = False for dl in self.dls.values(): c = c or dl.use(f) if c: break if not c: error.append(" [%s] filter is not used" % f.id) error.append("") # Check the calibrations error.append("* Calibrations:") for cl in self.cls.values(): error.extend(cl.check(self)) error.append("") error.append("* Sensors:") for f in self.ses.values(): c = False for network in networks.values(): for station in network.stations: for location in station.locations: for channel in location.channels: c = c or channel.use(f) if c: break if c: break if c: break if c: break if not c: error.append(" [%s] sensor is not used" % f.id) error.append("") error.append("* Dataloggers:") for f in self.dls.values(): c = False for network in networks.values(): c = c or network.use(f) if c: break if not c: error.append(" [%s] datalogger is not used" % f.id) error.append("") return error def filterType(self, iid): if iid not in self.keys: raise Exception("[%s] Filter id not found" % iid) if iid not in self.fls: raise Exception("[%s] Object is not a filter" % iid) obj = self.fls[iid] if isinstance(obj, Ff): fType = 'D' elif isinstance(obj, Pz): fType = obj.type return fType def filterID(self, iid): if iid not in self.keys: raise Exception("[%s] Filter id not found" % iid) if iid not in self.fls: raise Exception("[%s] Object is not a filter" % iid) if iid not in self._filters: obj = self.fls[iid] if isinstance(obj, Pz): ## print >> sys.stderr," Generating new Filter (PZ): %s %s" % (iid,obj.type) newFilter = Paz(obj) elif isinstance(obj, Ff): ## print >> sys.stderr," Generating new Filter (Fir): %s" % (iid) newFilter = Fir(obj) newFilter.adjust(self._prefix) if newFilter.id != self.prefix(iid): raise Exception("Invalid filter created %s" % (iid)) self._filters[iid] = newFilter return self._filters[iid].sc3ID(self) def prefix(self, iid): if self._prefix: iid = "%s:%s" % (self._prefix, iid) return iid def dataloggerID(self, iid, gain = None): if iid not in self.keys: raise Exception("Object not found.") if iid not in self.dls: raise Exception("[%s] Object is not a datalogger" % iid) diid = self.instrumentId(iid, gain) if diid not in self._datalogger: ## print >> sys.stderr,"Generating datalogger %s -> %s" % (iid, diid) newDatalogger = Dataloger(self.dls[iid], gain) newDatalogger.adjust(self._prefix) if newDatalogger.id != self.prefix(diid): raise Exception("Invalid datalogger created %s %s" % (iid, diid)) self._datalogger[diid] = newDatalogger return self._datalogger[diid].sc3ID(self) def sensorID(self, iid, gain = None): if iid not in self.keys: raise Exception("Object not found.") if iid not in self.ses: raise Exception("[%s] Object is not a sensor" % iid) diid = self.instrumentId(iid, gain) if diid not in self._sensors: ## print >> sys.stderr,"Generating Sensor %s -> %s" % (iid, diid) newSensor = Sensor(self.ses[iid], gain) newSensor.adjust(self._prefix) if newSensor.id != self.prefix(diid): raise Exception("Invalid sensor created %s %s" % (iid, diid)) self._sensors[diid] = newSensor return self._sensors[diid].sc3ID(self) def _findObject(self, objID, where): obj = None for ob in where.values(): obj = ob.sc3Obj(self) if obj.publicID() == objID: break; if not obj: raise Exception("Object not found: %s " % objID) return obj def _findCallibration(self, obj, count, serialNumber, channel, start): if serialNumber is None: return None if channel is None: return None for cal in [obj(i) for i in range(0, count)]: if cal.serialNumber() == serialNumber and cal.channel() == channel: return cal.gain() return None def _sensorGain(self, seID, serialNumber, channel, start): sensor = self._findObject(seID, self._sensors) if not sensor: raise Exception("Not found %s" % seID) sensorFilter = self._findObject(sensor.response(), self._filters) if not sensorFilter: raise Exception("Not found %s" % seID) gainFrequency = sensorFilter.gainFrequency() try: gainUnit = sensor.unit() except: print("[%s] No gain unit supplied" % seID, file=sys.stderr) gainUnit = None gain = self._findCallibration(sensor.sensorCalibration, sensor.sensorCalibrationCount(), serialNumber, channel, start) if gain is not None: ## print >> sys.stderr,'[%s] Using sensor gain from calibration %s' % (serialNumber, gain) pass else: gain = sensorFilter.gain() return (gain, gainFrequency, gainUnit) def _dataloggerGain(self, dtID, serialNumber, channel, Numerator, Denominator, start): datalogger = self._findObject(dtID, self._datalogger) gain = self._findCallibration(datalogger.dataloggerCalibration, datalogger.dataloggerCalibrationCount(), serialNumber, channel, start) if gain is not None: ##print >> sys.stderr,'[%s] Using datalogger gain from calibration %s' % (serialNumber, gain) pass else: gain = datalogger.gain() decimation = None for i in range(0,datalogger.decimationCount()): decimation = datalogger.decimation(i) if decimation.sampleRateNumerator() == Numerator and decimation.sampleRateDenominator() == Denominator: break decimation = None if not decimation: raise Exception("Decimation not found %s/%s" % (Numerator, Denominator)) af = decimation.analogueFilterChain().content().split() df = decimation.digitalFilterChain().content().split() for fiID in af: g = self._findObject(fiID, self._filters).gain() #print >> sys.stderr,"Multiplying by %s %s" % (fiID, g) gain = gain * g for fiID in df: g = self._findObject(fiID, self._filters).gain() #print >> sys.stderr,"Multiplying by %s %s" % (fiID, g) gain = gain * g return gain def getChannelGainAttribute(self, dtID, seID, dtSerialNumber, seSerialNumber, dtChannel, seChannel, Numerator, Denominator, channelStart): if not dtID or not seID: raise Exception("Empty instruments ID supplied.") (sensorGain, sensorFrequency,sensorUnit) = self._sensorGain(seID, seSerialNumber, seChannel, channelStart) dataloggerGain = self._dataloggerGain(dtID, dtSerialNumber, dtChannel, Numerator, Denominator, channelStart) att = {} att['Gain'] = sensorGain * dataloggerGain if sensorFrequency is not None: att['GainFrequency'] = sensorFrequency if sensorUnit is not None: att['GainUnit'] = sensorUnit return att class Paz(sc3, prefixable): def __init__(self, pz): sc3.__init__(self, 'paz') self.id = pz.id self.att = pz.getAttributes() def sc3Att(self): att = {} att['Name'] = self.id for (key,value) in self.att.items(): if not self.sc3ValidKey(key) or key in att: print(" [%s] [%s] Ignoring Attribute %s = %s " % (self.sc3Mode, self.id, key,value), file=sys.stderr) continue att[key] = value return att class Sensor(sc3, prefixable): def __init__(self, se, gain = None): sc3.__init__(self, 'sensor') self.baseid = se.id self.att = se.getAttributes() self.pz = se.generatePz(gain) self.id = "%s/g=%s" % (self.baseid, int(float(self.pz.gain))) def sc3Resolv(self, inventory): try: self.att['Response'] = inventory.filterID(self.pz.id) ## print >> sys.stderr,"Re-used a sensor pole-zero" except: inventory.add(self.pz) self.att['Response'] = inventory.filterID(self.pz.id) def sc3Att(self): att = {} att['Name'] = self.id for (key, value) in self.att.items(): if not self.sc3ValidKey(key) or key in att: print(" [%s] [%s] ignoring Attribute %s = %s " % (self.sc3Mode, self.id, key, value), file=sys.stderr) continue att[key] = value ## Forcing needed description on the sensor if 'Description' not in att: att['Description'] = self.id return att class Fir(sc3, prefixable): def __init__(self, ff): sc3.__init__(self, 'fir') self.id = ff.id self.gain = ff.gain self.att = ff.getAttributes() def sc3Att(self): att = {} att['Name'] = self.id for (key,value) in self.att.items(): if not self.sc3ValidKey(key) or key in att : print(" [%s] [%s] Ignoring Attribute %s = %s " % (self.sc3Mode, self.id, key,value), file=sys.stderr) continue att[key] = value return att class Decimation(sc3): def __init__(self, numerator, decimator, dl): sc3.__init__(self, 'decimation') self._numerator = numerator self._denominator = decimator self.chains = dl.chains[(numerator, decimator)] self.att = {} def sc3Resolv(self, inventory): sequence = {} sequence['A'] = [] sequence['D'] = [] for stage in self.chains: sid = inventory.filterID(stage) ADtype = inventory.filterType(stage) sequence[ADtype].append(sid) self.att['AnalogueFilterChain'] = " ".join(sequence['A']) self.att['DigitalFilterChain'] = " ".join(sequence['D']) def sc3Att(self): att = {} att['SampleRateNumerator'] = self._numerator att['SampleRateDenominator'] = self._denominator att.update(self.att) return att class Dataloger(sc3, prefixable): def __init__(self, dl, gain = None): dcs = [] sc3.__init__(self, 'datalogger', dcs) if gain: self.gain = gain else: self.gain = dl.gain self.att = dl.getAttributes() self.id = "%s/g=%s" % (dl.id, int(float(self.gain))) self.maxClockDrift = dl.mcld if dl.chains: for (num, dec) in dl.chains: dcs.append(Decimation(num, dec, dl)) self.dcs = dcs else: print("[%s] Datalogger %s has no stages." % (self.id, dl), file=sys.stderr) def sc3Att(self): att = {} att['Name'] = self.id att['Gain'] = self.gain att['MaxClockDrift'] = self.maxClockDrift for (key,value) in self.att.items(): if not self.sc3ValidKey(key) or key in att: print(" [%s] [%s] ignoring Attribute %s = %s " % (self.sc3Mode, self.id, key, value), file=sys.stderr) continue att[key] = value ## Forcing needed description on the sensor if 'Description' not in att: att['Description'] = self.id return att class Calibration(sc3): def __init__(self, cl, channel, start, end): if cl.type == "S": sc3.__init__(self, "sensorCalibration") else: sc3.__init__(self, "dataloggerCalibration") if channel < 0 or channel >= cl.channelCount: raise Exception("Invalid channel for calibration [%s]" % channel) self.start = start self.end = end self.channel = channel self.id = cl.id self.att = cl.getAttributes(channel) def sc3Att(self): att = {} att['SerialNumber'] = self.id att['Start'] = self.start if self.end: att['End'] = self.end for (key, value) in self.att.items(): if not self.sc3ValidKey(key) or key in att: print(" [%s] [%s] Ignoring Attribute %s = %s " % (self.sc3Mode, self.id, key,value), file=sys.stderr) continue att[key] = value return att