Source code for pyatoa.utils.form
"""
Formatting functionality
Pyatoa relies on data structure being ordered and consistent throughout all the
various bits of data required, as well as a few standardized string formatters
to keep everything playing nice. Functions here will aid in reshaping data
into the correct formats.
"""
from pyasdf import ASDFDataSet
from obspy.core.event import Event
from pyatoa import logger
[docs]
def channel_code(dt):
"""
Specfem outputs seismograms with channel band codes set by IRIS. Instrument
codes are always X for synthetics, but band code will vary with the sampling
rate of the data, return the correct code given a sampling rate.
Taken from Appenix B of the Specfem3D cartesian manual (June 15, 2018)
:type dt: float
:param dt: sampling rate of the data in seconds
:rtype: str
:return: band code as specified by Iris
:raises KeyError: when dt is specified incorrectly
"""
if dt >= 1:
return "L" # long period
elif 0.1 < dt < 1:
return "M" # mid period
elif 0.0125 < dt <= 0.1:
return "B" # broad band
elif 0.001 <= dt <= 0.0125:
return "H" # high broad band
elif 0.004 <= dt < 0.001:
return "C"
elif 0.001 <= dt < 0.0002:
return "F"
else:
raise KeyError("Channel code does not exist for this value of 'dt'")
[docs]
def format_iter(iteration):
"""
Format the iteration to be used in internal path naming and labelling.
Standard is to format with a leading 'i' character followed by two digits.
Inputs can be strings or integers. Assumes iterations won't go above 99.
:type iteration: str or int
:param iteration: input model number, e.g. 0, '0', 'i0', 'i00'
:rtype: str
:return: formatted model number, e.g. 'i00', or None if no matching format
"""
if isinstance(iteration, str):
# If e.g. iteration = "0"
if not iteration[0] == "i":
iternum = f"i{iteration:0>2}"
# If e.g. iteration = "m00"
else:
iternum = iteration
# If e.g. iteration = 0
elif isinstance(iteration, int):
iternum = f"i{iteration:0>2}"
else:
iternum = None
return iternum
[docs]
def format_step(count):
"""
Same as for iteration but step count is formatted with a leading 's'
:type count: str or int
:param count: input model number, e.g. 0, '0', 's0', 's00'
:rtype: str
:return: formatted model number, e.g. 's00', or None if no matching format
"""
if isinstance(count, str):
if not count[0] == "s":
stpcnt = f"s{count:0>2}"
else:
stpcnt = count
elif isinstance(count, int):
stpcnt = f"s{count:0>2}"
else:
stpcnt = None
return stpcnt
[docs]
def format_event_name(ds_or_event):
"""
Formalize the definition of Event ID in Pyatoa by parsing it out of the
resource_id attribute of the ObsPy Event object. Different data centers
will tag their resource IDs differently, so this function can parse some
of the more popular ones.
:type ds_or_event: pyasdf.ASDFDataSet or obspy.core.event.Event or str
:param ds_or_event: get dataset event name from the event resource_id
:rtype: str
:return: the event name to be used for naming schema in the workflow
"""
# Extract the resource id dependent on the input file type
if isinstance(ds_or_event, Event):
rid = ds_or_event.resource_id.id
elif isinstance(ds_or_event, str):
rid = ds_or_event
elif isinstance(ds_or_event, ASDFDataSet):
rid = ds_or_event.events[0].resource_id.id
else:
raise TypeError("format_event_name() only accepts pyasdf.ASDFDataSet "
"or obspy.core.event.Event objects")
rid_up = rid.upper()
# GeoNet Client: smi:nz.org.geonet/2018p130600
if "GEONET" in rid_up:
event_name = rid.split("/")[-1]
# IRIS Client: smi:service.iris.edu/fdsnws/event/1/query?eventid=5197722
elif "IRIS" in rid_up:
event_name = rid.split("eventid=")[-1]
# SPUD, GCMT: smi:local/ndk/C202005010101A/event
# or CMTSOLUTION: smi:local/cmtsolution/2013p617227/event
elif ("NDK" in rid_up) or ("CMTSOLUTION" in rid_up):
event_name = rid.split("/")[-2]
# USGS Client: quakeml:earthquake.usgs.gov/fdsnws/event/1/...
# ...query?eventid=ak0198gdhuwa&format=quakeml
elif "USGS" in rid_up:
parts = rid.split("eventid=")[-1]
event_name = parts.split("&")[0]
# USGS ANSS ComCat: quakeml:us.anss.org/event/20005ysu
elif "ANSS" in rid_up:
event_name = rid.split("event/")[-1]
# PySEP reads SPECFEM source files and tags them 'SOURCE'
# smi:local/source/<SOURCE_NAME>/event
elif "SOURCE" in rid_up:
event_name = rid_up.split("/")[2]
else:
logger.warning("unknown resource ID type, tagging event with entire ID")
event_name = rid_up
return event_name