Source code for pynetdesign.modelling.classes
import numpy as np
# Detection modes for the free surface correction
VALID_FS_MODES = ('auto', 'on', 'off')
[docs]
class DetectionParameters:
r"""
Container for the parameters controlling event detection.
Parameters
----------
min_SNR_p : :obj:`float`
Minimum signal-to-noise ratio required to detect a P wave on one receiver.
min_SNR_s : :obj:`float`
Minimum signal-to-noise ratio required to detect an S wave on one receiver.
min_stations_p : :obj:`int`
Minimum number of receivers on which the event must be detected with P waves.
min_stations_s : :obj:`int`
Minimum number of receivers on which the event must be detected with S waves.
f_p : :obj:`float`, optional
Representative frequency of the P wave (Hz).
If ``None``, the peak frequency is computed from the model.
f_s : :obj:`float`, optional
Representative frequency of the S wave (Hz).
If ``None``, the peak frequency is computed from the model.
f_p_corner : :obj:`float`, optional, default: ``None`` (100 Hz)
Corner frequency of the P wave (Hz), limiting the peak frequency.
f_s_corner : :obj:`float`, optional, default: ``None`` (100 Hz)
Corner frequency of the S wave (Hz), limiting the peak frequency.
fs_mode : :obj:`str`, optional, default: ``None`` (``'auto'``)
Free surface correction mode, one of ``'auto'``, ``'on'`` or ``'off'``.
In ``'auto'`` mode the correction is applied to receivers that are within
``fs_deviation`` of the free surface level, or according to the ``Surface``
column of the geometry when present.
fs_level : :obj:`float`, optional, default: ``None`` (0.0)
Level of the free surface in metres above the reference level.
fs_deviation : :obj:`float`, optional, default: ``None`` (1.0)
Permitted deviation from the free surface level in metres.
free_surface : :obj:`bool`, optional
Deprecated override kept for backward compatibility. ``True`` maps to
``fs_mode='on'`` and ``False`` to ``fs_mode='off'``. If ``None``, ``fs_mode``
is used.
Notes
-----
The free surface correction is applied per receiver, so a geometry combining
surface and downhole receivers is handled correctly. This differs from
PyNetDesign 1.0.x, where ``free_surface=True`` amplified every receiver
irrespective of its depth.
"""
def __init__(self,
min_SNR_p: float,
min_SNR_s: float,
min_stations_p: int,
min_stations_s: int,
f_p: float=None,
f_s: float=None,
f_p_corner: float=None,
f_s_corner: float=None,
fs_mode: str=None,
fs_level: float=None,
fs_deviation: float=None,
free_surface: bool=None):
self.min_SNR_p = min_SNR_p
self.min_SNR_s = min_SNR_s
self.min_stations_p = min_stations_p
self.min_stations_s = min_stations_s
self.f_p = f_p
self.f_s = f_s
self.f_p_corner = f_p_corner
self.f_s_corner = f_s_corner
self.fs_mode = fs_mode
self.fs_level = fs_level
self.fs_deviation = fs_deviation
self.free_surface = free_surface
def validate(self):
if (self.min_SNR_p is None or self.min_SNR_s is None):
raise ValueError("Minimum S/N ratio can not be None")
if (self.min_stations_p is None and self.min_stations_s is None):
raise ValueError("Minimum number of stations can not be None")
if not (self.min_SNR_p > 0 and self.min_SNR_s > 0):
raise ValueError("Minimum S/N ratios must be positive")
if not (self.min_stations_p > 0 and self.min_stations_s > 0):
raise ValueError("Minimum number of stations must be positive")
if self.f_p is not None:
if self.f_p <= 0:
raise ValueError("P-wave frequency must be positive")
if self.f_s is not None:
if self.f_s <= 0:
raise ValueError("S-wave frequency must be positive")
if self.f_p_corner is not None:
if self.f_p_corner <= 0:
raise ValueError("P-wave corner frequency must be positive")
else:
self.f_p_corner = 100
if self.f_s_corner is not None:
if self.f_s_corner <= 0:
raise ValueError("S-wave corner frequency must be positive")
else:
self.f_s_corner = 100
# The deprecated free_surface flag, when given, decides the mode.
# Written back to fs_mode so that repeated validation is idempotent.
if self.free_surface is not None:
mapped = 'on' if self.free_surface else 'off'
if self.fs_mode is not None and self.fs_mode != mapped:
raise ValueError("Provide either free_surface or fs_mode, not both")
self.fs_mode = mapped
if self.fs_mode is None:
self.fs_mode = 'auto'
elif not isinstance(self.fs_mode, str):
raise ValueError("Free surface correction mode must be a string")
elif self.fs_mode not in VALID_FS_MODES:
raise ValueError(
"Free surface correction mode must be one of the following: "
+ ", ".join(VALID_FS_MODES)
)
if self.fs_level is None:
self.fs_level = 0.0
elif np.ndim(self.fs_level) != 0:
raise ValueError("Free surface level must be a scalar")
if self.fs_deviation is None:
self.fs_deviation = 1.0
elif self.fs_deviation < 0:
raise ValueError("Free surface level deviation must be non-negative")