shared-snippets/python/seedconverter/sacutil.py
2024-08-28 17:22:21 +02:00

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"