Source code for rt_eqcorrscan.event_trigger.triggers
"""
Standardised trigger functions for use with a Reactor.
"""
import logging
import numpy as np
from typing import Union, List, Optional
from obspy import UTCDateTime
from obspy.core.event import Catalog, Event
from obspy.geodetics import locations2degrees
from eqcorrscan.core.match_filter import Detection
from rt_eqcorrscan.event_trigger.listener import event_time
Logger = logging.getLogger(__name__)
[docs]def get_nearby_events(
event: Event,
catalog: Catalog,
radius: float
) -> Catalog:
"""
Get a catalog of events close to another event.
Parameters
----------
event:
Central event to calculate distance relative to
catalog:
Catalog to extract events from
radius:
Radius around `event` in km
Returns
-------
Catalog of events close to `event`
"""
sub_catalog = Catalog(
[e for e in catalog.events
if inter_event_distance(event, e) <= radius])
return sub_catalog
def _event_magnitude(event):
try:
magnitude = event.preferred_magnitude() or event.magnitudes[-1]
except IndexError:
return -9
return magnitude.mag
[docs]def magnitude_rate_trigger_func(
catalog: Catalog,
magnitude_threshold: float = 5.5,
rate_threshold: float = 10.,
rate_bin: float = .2,
minimum_events_in_bin: int = 5,
) -> Catalog:
"""
Function to turn triggered response on based on magnitude and rate.
Parameters
----------
catalog:
Catalog to look in
magnitude_threshold:
magnitude threshold for triggering a response
rate_threshold:
rate in events per day for triggering a response
rate_bin:
radius in degrees to calculate rate for.
minimum_events_in_bin
Minimum number of events in a bin to calculate a rate for.
Returns
-------
The events that forced the trigger.
"""
trigger_events = Catalog()
# Sort by magnitude
magnitudes = np.array([_event_magnitude(ev) for ev in catalog])
sorted_indices = np.argsort(magnitudes)[::-1]
for event_index in sorted_indices:
event = catalog[event_index]
if magnitudes[event_index] >= magnitude_threshold:
trigger_events.events.append(event)
for event in catalog:
sub_catalog = get_nearby_events(event, catalog, radius=rate_bin)
if len(sub_catalog) >= minimum_events_in_bin:
rate = average_rate(sub_catalog)
else:
rate = 0.
if rate >= rate_threshold:
for _event in sub_catalog:
if _event not in trigger_events:
trigger_events.events.append(_event)
return trigger_events
[docs]def inter_event_distance(
event1: Event,
event2: Event
) -> float:
"""
Calculate the distance (in degrees) between two events
returns
-------
distance in degrees between events
"""
try:
origin_1 = event1.preferred_origin() or event1.origins[0]
origin_2 = event2.preferred_origin() or event2.origins[0]
except IndexError:
return 180.
return locations2degrees(
lat1=origin_1.latitude, long1=origin_1.longitude,
lat2=origin_2.latitude, long2=origin_2.longitude)
[docs]def average_rate(
catalog: Union[List[Detection], Catalog],
starttime: Optional[UTCDateTime] = None,
endtime: Optional[UTCDateTime] = None
) -> float:
"""
Compute mean rate (in events per day) of occurrence of events in catalog.
Parameters
----------
catalog
Catalog of events, or list of detections
starttime
Start-time to calculate rate for, if not set will use the time of the
first event in the catalog
endtime
End-time to calculate rate for, if not set will use the time of the
last event in the catalog
Returns
-------
Average rate over duration of catalog. Units: events / day
"""
if len(catalog) <= 1:
return 0.
assert isinstance(catalog, (Catalog, list))
if isinstance(catalog, Catalog):
event_times = sorted([event_time(e) for e in catalog])
elif isinstance(catalog, list):
assert all([isinstance(d, Detection) for d in catalog])
event_times = sorted([d.detect_time for d in catalog])
starttime = starttime or event_times[0]
endtime = endtime or event_times[-1]
duration = (endtime - starttime) / 86400.
return len(event_times) / duration
if __name__ == "__main__":
import doctest
doctest.testmod()