You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

487 lines
12 KiB
Python

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)