Source code for obspy.xseed.utils
# -*- coding: utf-8 -*-
"""
Various additional utilities for ObsPy xseed.
:copyright:
The ObsPy Development Team (devs@obspy.org)
:license:
GNU Lesser General Public License, Version 3
(http://www.gnu.org/copyleft/lesser.html)
"""
from obspy import UTCDateTime
import sys
# Ignore Attributes of Blockettes
IGNORE_ATTR = ['blockette_id', 'blockette_name', 'compact', 'debug',
'seed_version', 'strict', 'xseed_version',
'length_of_blockette', 'blockette_type']
[docs]class SEEDParserException(Exception):
pass
[docs]def toTag(name):
"""
Creates a XML tag from a given string.
"""
temp = name.lower().replace(' ', '_')
temp = temp.replace('fir_', 'FIR_')
temp = temp.replace('a0_', 'A0_')
return temp
[docs]def toString(tag):
"""
Creates a pretty string from any given XML tag.
"""
temp = tag.replace('_', ' ').title()
temp = temp.replace('Fir', 'FIR')
return temp
[docs]def DateTime2String(dt, compact=False):
"""
Generates a valid SEED time string from a UTCDateTime object.
"""
if isinstance(dt, UTCDateTime):
return dt.formatSEED(compact)
elif isinstance(dt, basestring):
dt = dt.strip()
if not dt:
return ""
try:
dt = UTCDateTime(dt)
return dt.formatSEED(compact)
except:
raise Exception("Invalid datetime %s: %s" % (type(dt), str(dt)))
[docs]def compareSEED(seed1, seed2):
"""
Compares two SEED files.
Only works with a record length of 4096 bytes.
"""
# Each SEED string should be a multiple of the record length.
if (len(seed1) % 4096) != 0:
msg = "Length of first SEED string should be a multiple of 4096 bytes"
raise Exception(msg)
if (len(seed2) % 4096) != 0:
msg = "Length of second SEED string should be a multiple of 4096 bytes"
raise Exception(msg)
# Loop over each record and remove empty ones. obspy.xseed doesn't write
# empty records. Redundant code to ease coding...
recnums = len(seed1) / 4096
new_seed1 = ''
for _i in xrange(recnums):
cur_record = seed1[_i * 4096 + 8:(_i + 1) * 4096].strip()
if cur_record == '':
continue
new_seed1 += seed1[_i * 4096:(_i + 1) * 4096]
seed1 = new_seed1
recnums = len(seed2) / 4096
new_seed2 = ''
for _i in xrange(recnums):
cur_record = seed2[_i * 4096 + 8:(_i + 1) * 4096].strip()
if cur_record == '':
continue
new_seed2 += seed2[_i * 4096:(_i + 1) * 4096]
seed2 = new_seed2
# length should be the same
if len(seed1) != len(seed2):
msg = "Length of SEED strings differ! (%d != %d)" % (len(seed1),
len(seed2))
raise Exception(msg)
# version string is always ' 2.4' for output
if seed1[15:19] == ' 2.3':
seed1 = seed1.replace(' 2.3', ' 2.4', 1)
if seed1[15:19] == '02.3':
seed1 = seed1.replace('02.3', ' 2.4', 1)
# check for missing '~' in blockette 10 (faulty dataless from BW network)
l = int(seed1[11:15])
temp = seed1[0:(l + 8)]
if temp.count('~') == 4:
# added a '~' and remove a space before the next record
# record length for now 4096
seed1 = seed1[0:11] + '%04i' % (l + 1) + seed1[15:(l + 8)] + '~' + \
seed1[(l + 8):4095] + seed1[4096:]
# check each byte
for i in xrange(0, len(seed1)):
if seed1[i] == seed2[i]:
continue
temp = seed1[i] + seed2[i]
if temp == '0+':
continue
if temp == '0 ':
continue
if temp == ' +':
continue
if temp == '- ':
# -056.996398+0031.0
# -56.996398 +31.0
continue
[docs]def LookupCode(blockettes, blkt_number, field_name, lookup_code,
lookup_code_number):
"""
Loops over a list of blockettes until it finds the blockette with the
right number and lookup code.
"""
# List of all possible names for lookup
for blockette in blockettes:
if blockette.id != blkt_number:
continue
if getattr(blockette, lookup_code) != lookup_code_number:
continue
return getattr(blockette, field_name)
return None
[docs]def Blockette34Lookup(abbr, lookup):
"""
Gets certain values from blockette 34. Needed for RESP output.
"""
try:
l1 = LookupCode(abbr, 34, 'unit_name', 'unit_lookup_code', lookup)
l2 = LookupCode(abbr, 34, 'unit_description', 'unit_lookup_code',
lookup)
return l1 + ' - ' + l2
except:
msg = '\nWarning: Abbreviation reference not found.'
sys.stdout.write(msg)
return 'No Abbreviation Referenced'
[docs]def setXPath(blockette, identifier):
"""
Returns an X-Path String to a blockette with the correct identifier.
"""
try:
identifier = int(identifier)
except:
msg = 'X-Path identifier needs to be an integer.'
raise TypeError(msg)
abbr_path = '/xseed/abbreviation_dictionary_control_header/'
end_of_path = '[text()="%s"]/parent::*'
if blockette == 30:
return abbr_path + \
'data_format_dictionary/data_format_identifier_code' + \
end_of_path % identifier
elif blockette == 31:
return abbr_path + \
'comment_description/comment_code_key' + \
end_of_path % identifier
elif blockette == 33:
return abbr_path + \
'generic_abbreviation/abbreviation_lookup_code' + \
end_of_path % identifier
elif blockette == 34:
return abbr_path + \
'units_abbreviations/unit_lookup_code' + \
end_of_path % identifier
# All dictionary blockettes.
elif blockette == 'dictionary':
return abbr_path + \
'*/response_lookup_key' + \
end_of_path % identifier
msg = 'XPath for blockette %d not implemented yet.' % blockette
raise NotImplementedError(msg)
[docs]def getXPath(xpath):
"""
Returns lookup key of XPath expression on abbreviation dictionary.
"""
return int(xpath.split('"')[-2])
[docs]def uniqueList(seq):
# Not order preserving
keys = {}
for e in seq:
keys[e] = 1
return keys.keys()