Compare commits

...

2 Commits

3 changed files with 63 additions and 20 deletions

View File

@ -3,11 +3,11 @@ datapath: "/data/SDS/" # SC3 Datapath
networks: ["1Y", "HA", "MK"] # select networks, list or str networks: ["1Y", "HA", "MK"] # select networks, list or str
stations: "*" # select stations, list or str stations: "*" # select stations, list or str
locations: "*" # select locations, list or str locations: "*" # select locations, list or str
stations_blacklist: ["TEST", "EREA", "DOMV"] # exclude these stations stations_blacklist: ["TEST", "EREA", "DOMV", "LFKM", "GR19", "LAKA"] # exclude these stations
networks_blacklist: [] # exclude these networks networks_blacklist: [] # exclude these networks
interval: 60 # Perform checks every x seconds interval: 60 # Perform checks every x seconds
n_track: 360 # wait n_track * intervals before performing an action (i.e. send mail/end highlight status) n_track: 360 # wait n_track * intervals before performing an action (i.e. send mail/end highlight status)
timespan: 3 # Check data of the recent x days timespan: 7 # Check data of the recent x days
verbosity: 0 # verbosity flag for program console output (not logging) verbosity: 0 # verbosity flag for program console output (not logging)
logging_level: WARN # set logging level (info, warning, debug) logging_level: WARN # set logging level (info, warning, debug)
track_changes: True # tracks all changes since GUI startup by text highlighting (GUI only) track_changes: True # tracks all changes since GUI startup by text highlighting (GUI only)
@ -40,6 +40,7 @@ POWBOX:
THRESHOLDS: THRESHOLDS:
pb_thresh: 0.2 # Threshold for PowBox Voltage check +/- (V) pb_thresh: 0.2 # Threshold for PowBox Voltage check +/- (V)
max_temp: 50 # max temperature for temperature warning max_temp: 50 # max temperature for temperature warning
critical_temp: 65 # max temperature for critical warning (fail)
low_volt: 12 # min voltage for low voltage warning low_volt: 12 # min voltage for low voltage warning
high_volt: 14.8 # max voltage for over voltage warning high_volt: 14.8 # max voltage for over voltage warning
unclassified: 5 # min voltage samples not classified for warning unclassified: 5 # min voltage samples not classified for warning
@ -139,7 +140,7 @@ EMAIL:
mailserver: "localhost" mailserver: "localhost"
addresses: ["marcel.paffrath@rub.de", "kasper.fischer@rub.de"] # list of mail addresses for info mails addresses: ["marcel.paffrath@rub.de", "kasper.fischer@rub.de"] # list of mail addresses for info mails
sender: "webmaster@geophysik.ruhr-uni-bochum.de" # mail sender sender: "webmaster@geophysik.ruhr-uni-bochum.de" # mail sender
stations_blacklist: ['GR33'] # do not send emails for specific stations stations_blacklist: [] # do not send emails for specific stations
networks_blacklist: [] # do not send emails for specific network networks_blacklist: [] # do not send emails for specific network
# specify recipients for single stations in a yaml: key = email-address, val = station list (e.g. [1Y.GR01, 1Y.GR02]) # specify recipients for single stations in a yaml: key = email-address, val = station list (e.g. [1Y.GR01, 1Y.GR02])
external_mail_list: "mailing_list.yaml" external_mail_list: "mailing_list.yaml"

View File

@ -69,6 +69,7 @@ def set_logging_level(params: dict) -> None:
logging.warning( logging.warning(
f'Could not set logging level. Parameter logging_level = {logging_level_str} could not be interpreted.') f'Could not set logging level. Parameter logging_level = {logging_level_str} could not be interpreted.')
return return
logging.info(f'Setting logging level to {logging_level_str}')
logging_level = logging_levels.get(logging_level_str.lower()) logging_level = logging_levels.get(logging_level_str.lower())
logging.basicConfig(level=logging_level) logging.basicConfig(level=logging_level)
@ -573,8 +574,6 @@ class StationQC(object):
:param nsl: dictionary containing network, station and location (key: str) :param nsl: dictionary containing network, station and location (key: str)
:param parameters: parameters dictionary from parameters.yaml file :param parameters: parameters dictionary from parameters.yaml file
""" """
if status_track is None:
status_track = {}
self.parent = parent self.parent = parent
self.stream = stream self.stream = stream
self.nsl = nsl self.nsl = nsl
@ -594,6 +593,8 @@ class StationQC(object):
status_track = {} status_track = {}
self.status_track = status_track self.status_track = status_track
self.powbox_active = self.is_pbox_activated_check()
self.start() self.start()
@property @property
@ -645,7 +646,8 @@ class StationQC(object):
send_mail = False send_mail = False
new_error = StatusError(count=count, show_count=self.parameters.get('warn_count')) new_error = StatusError(count=count, show_count=self.parameters.get('warn_count'))
if disc: if disc:
new_error.set_disconnected() msg = disc if type(disc) == str else None
new_error.set_disconnected(msg)
current_status = self.status_dict.get(key) current_status = self.status_dict.get(key)
if current_status.is_error: if current_status.is_error:
current_status.count += count current_status.count += count
@ -1024,9 +1026,12 @@ class StationQC(object):
self.warn(key, detailed_message=detailed_message, count=n_undervolt, self.warn(key, detailed_message=detailed_message, count=n_undervolt,
last_occurrence=self.get_last_occurrence(trace, undervolt)) last_occurrence=self.get_last_occurrence(trace, undervolt))
def pb_temp_analysis(self, channel='EX1'): def pb_temp_analysis(self, channel='EX1', t_max_default=50, t_crit_default=70):
""" Analyse PowBox temperature output. """ """ Analyse PowBox temperature output. """
key = 'temp' key = 'temp'
if not self.powbox_active:
self.set_pbox_inactive_error(key)
return
st = self.stream.select(channel=channel) st = self.stream.select(channel=channel)
trace = self.get_trace(st, key) trace = self.get_trace(st, key)
if not trace: if not trace:
@ -1047,12 +1052,21 @@ class StationQC(object):
logging.info(f'Average temperature at {np.nanmean(temp)}\N{DEGREE SIGN}') logging.info(f'Average temperature at {np.nanmean(temp)}\N{DEGREE SIGN}')
logging.info(f'Peak temperature at {max(temp)}\N{DEGREE SIGN}') logging.info(f'Peak temperature at {max(temp)}\N{DEGREE SIGN}')
logging.info(f'Min temperature at {min(temp)}\N{DEGREE SIGN}') logging.info(f'Min temperature at {min(temp)}\N{DEGREE SIGN}')
max_temp = thresholds.get('max_temp') max_temp = thresholds.get('max_temp', t_max_default)
max_temp_crit = thresholds.get('critical_temp', t_crit_default)
t_check = np.where(temp > max_temp)[0] t_check = np.where(temp > max_temp)[0]
if len(t_check) > 0: t_check_crit = np.where(temp > max_temp_crit)[0]
tcheck_message_template = ('Trace {id}: Temperature over {tmax}' + f'\N{DEGREE SIGN}'
+ '! Current temperature: {temp}' + f'\N{DEGREE SIGN}')
if len(t_check_crit) > 0:
self.error(key=key,
detailed_message=tcheck_message_template.format(id=trace.get_id(), tmax=max_temp, temp=cur_temp)
+ self.get_last_occurrence_timestring(trace, t_check_crit),
last_occurrence=self.get_last_occurrence(trace, t_check_crit))
elif len(t_check) > 0:
self.warn(key=key, self.warn(key=key,
detailed_message=f'Trace {trace.get_id()}: ' detailed_message=tcheck_message_template.format(id=trace.get_id(), tmax=max_temp_crit,
f'Temperature over {max_temp}\N{DEGREE SIGN} at {trace.get_id()}!' temp=cur_temp)
+ self.get_last_occurrence_timestring(trace, t_check), + self.get_last_occurrence_timestring(trace, t_check),
last_occurrence=self.get_last_occurrence(trace, t_check)) last_occurrence=self.get_last_occurrence(trace, t_check))
else: else:
@ -1108,6 +1122,11 @@ class StationQC(object):
def pb_power_analysis(self, channel='EX2', pb_dict_key='pb_SOH2'): def pb_power_analysis(self, channel='EX2', pb_dict_key='pb_SOH2'):
""" Analyse EX2 channel of PowBox """ """ Analyse EX2 channel of PowBox """
keys = ['230V', '12V'] keys = ['230V', '12V']
if not self.powbox_active:
for key in keys:
self.set_pbox_inactive_error(key)
return
st = self.stream.select(channel=channel) st = self.stream.select(channel=channel)
trace = self.get_trace(st, keys) trace = self.get_trace(st, keys)
if not trace: if not trace:
@ -1129,7 +1148,11 @@ class StationQC(object):
def pb_rout_charge_analysis(self, channel='EX3', pb_dict_key='pb_SOH3'): def pb_rout_charge_analysis(self, channel='EX3', pb_dict_key='pb_SOH3'):
""" Analyse EX3 channel of PowBox """ """ Analyse EX3 channel of PowBox """
keys = ['router', 'charger'] keys = ['router', 'charger']
pb_thresh = self.parameters.get('THRESHOLDS').get('pb_1v') if not self.powbox_active:
for key in keys:
self.set_pbox_inactive_error(key)
return
st = self.stream.select(channel=channel) st = self.stream.select(channel=channel)
trace = self.get_trace(st, keys) trace = self.get_trace(st, keys)
if not trace: if not trace:
@ -1243,6 +1266,10 @@ class StationQC(object):
with each voltage value associated to the different steps specified in POWBOX > pb_steps. Also raises with each voltage value associated to the different steps specified in POWBOX > pb_steps. Also raises
self.warn in case there are unassociated voltage values recorded. self.warn in case there are unassociated voltage values recorded.
""" """
if not self.powbox_active:
return
pb_thresh = self.parameters.get('THRESHOLDS').get('pb_thresh') pb_thresh = self.parameters.get('THRESHOLDS').get('pb_thresh')
pb_ok = self.parameters.get('POWBOX').get('pb_ok') pb_ok = self.parameters.get('POWBOX').get('pb_ok')
# possible voltage levels are keys of pb voltage level dict # possible voltage levels are keys of pb voltage level dict
@ -1305,6 +1332,13 @@ class StationQC(object):
""" get UTCDateTime from trace and index""" """ get UTCDateTime from trace and index"""
return trace.stats.starttime + trace.stats.delta * index return trace.stats.starttime + trace.stats.delta * index
def is_pbox_activated_check(self):
return self.station not in self.parameters.get('no_pbox_stations', [])
def set_pbox_inactive_error(self, key):
msg = self.parameters.get('no_pbox_stations')[self.station]
self.error(key, detailed_message=f'PowBox not connected', disc=msg)
class Status(object): class Status(object):
""" Basic Status class. All status classes are derived from this class.""" """ Basic Status class. All status classes are derived from this class."""
@ -1372,8 +1406,10 @@ class StatusError(Status):
self.set_error() self.set_error()
self.default_message = message self.default_message = message
def set_disconnected(self, message='DCN'): def set_disconnected(self, message=None):
self.connection_error = True self.connection_error = True
if not message:
message = 'DCN'
self.message = message self.message = message
def set_connected(self): def set_connected(self):

View File

@ -9,6 +9,14 @@ import numpy as np
from obspy import Stream from obspy import Stream
COLORS_DICT = {'FAIL': (195, 29, 14, 255),
'NO DATA': (255, 255, 125, 255),
'WARN': (250, 192, 63, 255),
'OK': (185, 245, 145, 255),
'undefined': (240, 240, 240, 255),
'disc': (126, 127, 131, 255), }
def get_bg_color(check_key, status, dt_thresh=None, hex=False): def get_bg_color(check_key, status, dt_thresh=None, hex=False):
message = status.message message = status.message
if check_key == 'last active': if check_key == 'last active':
@ -43,13 +51,9 @@ def get_color(key):
# 'OK': (173, 255, 133, 255), # 'OK': (173, 255, 133, 255),
# 'undefined': (230, 230, 230, 255), # 'undefined': (230, 230, 230, 255),
# 'disc': (255, 160, 40, 255),} # 'disc': (255, 160, 40, 255),}
colors_dict = {'FAIL': (195, 29, 14, 255), if not key in COLORS_DICT.keys():
'NO DATA': (255, 255, 125, 255), key = 'undefined'
'WARN': (250, 192, 63, 255), return COLORS_DICT.get(key)
'OK': (185, 245, 145, 255),
'undefined': (240, 240, 240, 255),
'disc': (126, 127, 131, 255), }
return colors_dict.get(key)
def get_color_mpl(key): def get_color_mpl(key):
@ -84,6 +88,8 @@ def get_mass_color(message):
def get_temp_color(temp, vmin=-10, vmax=60, cmap='coolwarm'): def get_temp_color(temp, vmin=-10, vmax=60, cmap='coolwarm'):
""" Get an rgba temperature value back from specified cmap, linearly interpolated between vmin and vmax. """ """ Get an rgba temperature value back from specified cmap, linearly interpolated between vmin and vmax. """
if type(temp) in [str]: if type(temp) in [str]:
if temp in COLORS_DICT.keys():
return get_color(temp)
return get_color('undefined') return get_color('undefined')
cmap = matplotlib.cm.get_cmap(cmap) cmap = matplotlib.cm.get_cmap(cmap)
val = (temp - vmin) / (vmax - vmin) val = (temp - vmin) / (vmax - vmin)