Skip to content

Commit

Permalink
Merge pull request #1457 from obspy/sac_propagate_channel_names
Browse files Browse the repository at this point in the history
SAC output does not use obspy headers
  • Loading branch information
megies committed Jul 19, 2016
2 parents 8ec6ae9 + fcdc60f commit cc6853f
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 20 deletions.
4 changes: 2 additions & 2 deletions obspy/io/sac/tests/test_core.py
Expand Up @@ -33,6 +33,7 @@ def setUp(self):
self.file = os.path.join(self.path, 'data', 'test.sac')
self.filexy = os.path.join(self.path, 'data', 'testxy.sac')
self.filebe = os.path.join(self.path, 'data', 'test.sac.swap')
self.fileseis = os.path.join(self.path, "data", "seism.sac")
self.testdata = np.array(
[-8.74227766e-08, -3.09016973e-01,
-5.87785363e-01, -8.09017122e-01, -9.51056600e-01,
Expand Down Expand Up @@ -276,8 +277,7 @@ def test_reference_time(self):
starttime of the seismogram is calculated by adding the B header
(in seconds) to the SAC reference time.
"""
file = os.path.join(self.path, "data", "seism.sac")
tr = read(file)[0]
tr = read(self.fileseis)[0]
# see that starttime is set correctly (#107)
self.assertAlmostEqual(tr.stats.sac.iztype, 9)
self.assertAlmostEqual(tr.stats.sac.b, 9.4599991)
Expand Down
18 changes: 17 additions & 1 deletion obspy/io/sac/tests/test_sactrace.py
Expand Up @@ -9,7 +9,7 @@

import numpy as np

from obspy import UTCDateTime
from obspy import UTCDateTime, read
from obspy.core.util import NamedTemporaryFile
from obspy.geodetics import gps2dist_azimuth, kilometer2degrees

Expand Down Expand Up @@ -212,6 +212,22 @@ def test_lcalda(self):
sac = SACTrace(lcalda=True, stla=stla)
self.assertRaises(SacHeaderError, sac._set_distances, force=True)

def test_propagate_modified_stats_strings_to_sactrace(self):
"""
If you build a SACTrace from an ObsPy Trace that has certain string
headers mismatched between the Stats header and an existing Stats.sac
header, channel and kcmpnm for example, the resulting SACTrace values
should come from Stats. Addresses GitHub issue #1457.
"""
tr = read(self.fileseis)[0]
# modify the header values by adding a single meaningless character
for sachdr, statshdr in [('kstnm', 'station'), ('knetwk', 'network'),
('kcmpnm', 'channel'), ('khole', 'location')]:
modified_value = tr.stats[statshdr] + '1'
tr.stats[statshdr] = modified_value
sac = SACTrace.from_obspy_trace(tr)
self.assertEqual(getattr(sac, sachdr), modified_value)


def suite():
return unittest.makeSuite(SACTraceTestCase, 'test')
Expand Down
32 changes: 15 additions & 17 deletions obspy/io/sac/util.py
Expand Up @@ -300,10 +300,11 @@ def obspy_to_sac_header(stats, keep_sac_header=True):
and "b" is not set, the reftime will be set from stats.starttime
(with micro/milliseconds precision adjustments) and "b" and "e" are
set accordingly.
* If 'kstnm', 'knetwk', 'kcmpnm', or 'khole' are not set, they are
taken from 'station', 'network', 'channel', and 'location' in stats.
* If 'kstnm', 'knetwk', 'kcmpnm', or 'khole' are not set or differ
from Stats values 'station', 'network', 'channel', or 'location',
they are taken from the Stats values.
If keep_sac_header is False, a new SAC header is constructed from only
information found in the stats dictionary, with some other default
information found in the Stats dictionary, with some other default
values introduced. It will be an iztype 9 ("ib") file, with small
reference time adjustments for micro/milliseconds precision issues.
SAC headers nvhdr, level, lovrok, and iftype are always produced.
Expand All @@ -313,9 +314,6 @@ def obspy_to_sac_header(stats, keep_sac_header=True):
header = {}
oldsac = stats.get('sac', {})

header['npts'] = stats['npts']
header['delta'] = stats['delta']

if keep_sac_header and oldsac:
# start with the old header
header.update(oldsac)
Expand Down Expand Up @@ -371,20 +369,20 @@ def obspy_to_sac_header(stats, keep_sac_header=True):
warnings.warn(msg)

# merge some values from stats if they're missing in the SAC header
# ObsPy issue 1204
if header.get('kstnm') in (None, HD.SNULL):
header['kstnm'] = stats['station'] or HD.SNULL
if header.get('knetwk') in (None, HD.SNULL):
header['knetwk'] = stats['network'] or HD.SNULL
if header.get('kcmpnm') in (None, HD.SNULL):
header['kcmpnm'] = stats['channel'] or HD.SNULL
if header.get('khole') in (None, HD.SNULL):
header['khole'] = stats['location'] or HD.SNULL
# ObsPy issues 1204, 1457
# XXX: If Stats values are empty/"" and SAC header values are real,
# this will replace the real SAC values with SAC null values.
# TODO: make this operation into a private helper function
for sachdr, statshdr in [('kstnm', 'station'), ('knetwk', 'network'),
('kcmpnm', 'channel'), ('khole', 'location')]:
if (header.get(sachdr) in (None, HD.SNULL)) or \
(header.get(sachdr).strip() != stats[statshdr]):
header[sachdr] = stats[statshdr] or HD.SNULL

else:
# SAC header from scratch. Just use stats.
# SAC header from scratch. Just use Stats.

# Here, set headers from stats that would otherwise depend on the old
# Here, set headers from Stats that would otherwise depend on the old
# SAC header
header['iztype'] = 9
starttime = stats['starttime']
Expand Down

0 comments on commit cc6853f

Please sign in to comment.