Source code for seismic.monitor.wfc
'''
:copyright:
The SeisMIC development team (makus@gfz-potsdam.de).
:license:
EUROPEAN UNION PUBLIC LICENCE v. 1.2
(https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12)
:author:
Peter Makus (makus@gfz-potsdam.de)
Created: Friday, 5th November 2021 08:19:58 am
Last Modified: Tuesday, 11th July 2023 04:42:52 pm
'''
import glob
from typing import List
import numpy as np
from matplotlib import pyplot as plt
from seismic.correlate.stats import CorrStats
from seismic.utils import miic_utils as mu
from seismic.plot.plot_wfc import plot_wfc_bulk
[docs]class WFC(dict):
"""
Object to hold the properties of a waveform coherency for a single
frequency and lapse time window.
The waveform coherency can be used as a measure of stability of
a certain correlation. See Steinmann, et. al. (2021) for details.
"""
def __init__(
self, wfc_dict: dict, stats: CorrStats, wfc_processing: dict):
"""
Initialise WFC object.
:param wfc_dict: Dictionary holding the correlation values for
each of the reference traces. The keys follow the syntax
`reftr_%n` where n is the number of the reference trace
(starting with 0).
:type wfc_dict: dict
:param stats: CorrStats object from the original CorrBulk.
Also has to contain the keys holding the information about the
bandpass filter and the used lapse time window.
:type stats: CorrStats
"""
for k, v in wfc_dict.items():
self[k] = v
del wfc_dict
# dict to hold averages
self.av = {}
self.stats = stats
self.mean = np.array([])
self.wfc_processing = wfc_processing
[docs] def compute_average(self):
"""
Computes the average of the waveform coherency over the time axis.
:param average_reftrcs: Average over all reference traces. Defaults to
True.
:type average_reftrcs: bool, optional
"""
for k, v in self.items():
self.av['%s_av' % k] = np.nanmean(v)
self.mean = np.nanmean([v for v in self.av.values()])
[docs] def save(self, path: str):
"""
Saves the object to an npz file.
:param path: Path to save to.
:type path: str
"""
kwargs = mu.save_header_to_np_array(self.stats)
kwargs.update(self.wfc_processing)
np.savez_compressed(path, mean=self.mean, **self.av, **self, **kwargs)
[docs]class WFCBulk(object):
"""
Object to hold the waveform coherency for one station and subsequently plot
it against frequency and lapse time window.
"""
def __init__(self, wfcl: List[WFC]):
# Compute averages if not available
freq = []
lw = []
means = []
for wfc in wfcl:
wfc.mean.size or wfc.compute_average()
# Midpoint of bp-filter (centre frequency)
freq.append(
(wfc.wfc_processing['freq_max']
+ wfc.wfc_processing['freq_min']) / 2)
# midpoint of lapse window
lw.append(
wfc.wfc_processing['tw_start']
+ wfc.wfc_processing['tw_len']/2)
means.append(wfc.mean)
# create grids
lwg, freqg = np.meshgrid(sorted(set(lw)), sorted(set(freq)))
# actual wfc grid
self.wfc = np.full_like(lwg, np.nan)
for f, lwc, v in zip(freq, lw, means):
ii = np.argwhere(((lwg == lwc) & (freqg == f)))[0]
self.wfc[ii[0], ii[1]] = v
del means
# create grids
self.lw = np.array(sorted(set(lw)))
self.lwg = lwg
del lw
self.cfreq = np.array(sorted(set(freq)))
self.cfreqg = freqg
del freq
[docs] def plot(
self, title: str = None, log: bool = False,
cmap: str = 'viridis') -> plt.Axes:
"""
Create a plot of the waveform coherency against frequency and lapse
time window.
:param title: Title of the plot, defaults to None
:type title: str, optional
:param log: plot on logarithmic frequency axis, defaults to False
:type log: bool, optional
"""
return plot_wfc_bulk(
self.lw, self.cfreq, self.wfc, title=title,
log=log, cmap=cmap)
[docs]def read_wfc(path: str) -> WFC:
"""
Read a :class:`~seismic.monitor.wfc.WFC` object saved as *npz*.
Returns a list if wildcards are used
:param path: Path to file
:type path: str
:return: The WFC object.
:rtype: WFC
"""
if '*' in path:
return [read_wfc(f) for f in glob.glob(path, recursive=True)]
loaded = np.load(path)
d = {}
av = {}
stats = {}
for k, v in loaded.items():
if k[-3:] == '_av':
av[k] = v
elif k == 'mean':
mean = v
elif 'reftr' in k:
d[k] = v
else:
stats[k] = v
wfc_processing = {
'tw_start': stats['tw_start'],
'tw_len': stats['tw_len'],
'freq_min': stats['freq_min'],
'freq_max': stats['freq_max']
}
wfc = WFC(
d, stats=CorrStats(mu.load_header_from_np_array(stats)),
wfc_processing=wfc_processing)
wfc.av = av
wfc.mean = mean
return wfc