forked from episodes-platform/shared-snippets
99 lines
3.2 KiB
Python
99 lines
3.2 KiB
Python
from obspy.io.sac import SACTrace
|
|
|
|
|
|
def to_sac_trace(tr,
|
|
unit_type,
|
|
remove_response,
|
|
inv):
|
|
"""
|
|
Function converting the specified trace to SAC-specific format
|
|
|
|
:type tr: obspy.core.trace.Trace
|
|
:param tr: Trace to be converted
|
|
:type unit_type: str
|
|
:param unit_type: Unit type of the result
|
|
:type remove_response: bool
|
|
:param remove_response: Information whether the response was removed, used to determine scale
|
|
:type inv: obspy.core.inventory.inventory.Inventory
|
|
:param inv: Inventory read either from SEED file or Station XML
|
|
:rtype: obspy.core.trace.Trace
|
|
:return: Converted trace
|
|
|
|
"""
|
|
|
|
# Assure that tr has fields present in SAC-type trace
|
|
sac = SACTrace.from_obspy_trace(tr)
|
|
sac = _prepare_sac_for_writing(sac, remove_response, unit_type, inv, tr.id, tr.stats['starttime'])
|
|
return sac.to_obspy_trace()
|
|
|
|
|
|
def _prepare_sac_for_writing(sac, remove_response, unit_type, inv, tr_id, tr_starttime):
|
|
"""
|
|
Method that adds some additional information to ordinary SACTrace file.
|
|
It adds location info and information about unit type and scale.
|
|
|
|
When the response is removed, it scales down the data to nano units
|
|
nm/s or so.
|
|
|
|
:type sac: obspy.io.sac.SACTrace
|
|
:param sac: SACTrace object, might be converted out of ordinary trace
|
|
:type remove_response: bool
|
|
:param remove_response: Parameter that lets user decide whether the
|
|
response is going to be removed or not
|
|
:type unit_type: str
|
|
:param unit_type: Unit type determined by _get_unit_type
|
|
:type inv: obspy.core.inventory.inventory.Inventory
|
|
:param inv: inventory contents
|
|
:type tr_id: str
|
|
:param tr_id: Trace's id string
|
|
:type tr_starttime: UTCDateTime
|
|
:param tr_starttime: Trace's start time
|
|
:rtype: obspy.io.sac.SACTrace
|
|
:return: SACTrace object with added additional information
|
|
"""
|
|
# Copy details of station's location
|
|
|
|
sac.idep = _get_sac_idep_unit(unit_type)
|
|
if inv:
|
|
try:
|
|
coords = inv.get_coordinates(tr_id, tr_starttime)
|
|
sensitivity = inv.get_response(tr_id, tr_starttime).instrument_sensitivity.value
|
|
sac.stla = coords["latitude"]
|
|
sac.stlo = coords["longitude"]
|
|
sac.stel = coords["elevation"]
|
|
sac.user2 = sensitivity
|
|
|
|
if remove_response:
|
|
# Divide by nano multiplier to get a data with removed response
|
|
# scaled to nano unit (nm/s or so).
|
|
sac.data = sac.data / _get_nano_multiplier()
|
|
sac.scale = -12345
|
|
else:
|
|
sac.scale = (1 / sensitivity / _get_nano_multiplier())
|
|
except Exception as err:
|
|
raise Exception("Cannot read location and sensitivity information: " + str(err))
|
|
else:
|
|
sac.scale = -12345
|
|
return sac
|
|
|
|
|
|
def _get_nano_multiplier():
|
|
"""
|
|
Returns a multiplier to obtain nano value from a full value.
|
|
|
|
:rtype: float
|
|
:return: Multiplier value
|
|
"""
|
|
return 10**(-9)
|
|
|
|
|
|
def _get_sac_idep_unit(unit_abbrev):
|
|
if unit_abbrev == "DISP":
|
|
return "idisp"
|
|
elif unit_abbrev == "VEL":
|
|
return "ivel"
|
|
elif unit_abbrev == "ACC":
|
|
return "iacc"
|
|
else:
|
|
return "iunkn"
|