-
Notifications
You must be signed in to change notification settings - Fork 1
/
sac2asdf.py
executable file
·152 lines (120 loc) · 4.45 KB
/
sac2asdf.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#!/usr/bin/env python
import argparse
import collections
import io
import glob
import numpy as np
import obspy
from os.path import exists, join
from asdf_converters.util.sac import read_sac_files, get_event_coords, get_station_coords
from asdf_converters.util.util import dumpjson
from pyasdf import ASDFDataSet
def getargs():
parser = argparse.ArgumentParser()
parser.add_argument('input', type=str,
help='SAC input directory')
parser.add_argument('output', type=str,
help='ASDF output filename')
parser.add_argument('tag', type=str,
help='ASDF tag',
nargs='?',
default='converted_from_sac')
return parser.parse_args()
def get_event_id():
return obspy.core.event.ResourceIdentifier()
def sort_by_station(channels):
"""
Takes a dictionary indexed by channel and reindexes it by station.
In the new dictionary, each key is a station and each value is a list of
channels.
"""
stations = collections.defaultdict(list)
for trace_id, coords in channels.items():
network, station, location, channel = trace_id.split('.')
stations[(network, station)] += [(location, channel,) + coords]
return stations.items()
# SAC2ASDF
if __name__=='__main__':
args = getargs()
if not exists(args.input):
raise Exception("File not found: %s" % args.input)
if exists(args.output):
raise Exception("File exists: %s" % args.output)
wildcard = '*'
files = glob.glob(join(args.input, wildcard))
stream = read_sac_files(files)
ds = ASDFDataSet(args.output, mode='a')
headers = {}
events = {}
channels = {}
starttime = np.inf
endtime = -np.inf
for trace in stream:
print(trace.sac_filename)
# keep track of headers
sac_header = trace.stats.sac
sac_filename = trace.sac_filename
headers[sac_filename] = dict(sac_header)
# keep track of events
coords = get_event_coords(sac_header)
if coords in events:
event_id = events[coords]
else:
event_id = get_event_id()
events[coords] = event_id
# keep track of channels
coords = get_station_coords(sac_header)
name = trace.id
channels[name] = coords
# keep track of recording times
s, e = trace.stats.starttime, trace.stats.endtime
if s.timestamp < starttime:
starttime = s
if e.timestamp > endtime:
endtime = e
ds.add_waveforms(trace, args.tag, event_id, labels=[sac_filename])
# add events
catalog = obspy.core.event.Catalog()
for event_coords, event_id in events.items():
latitude, longitude, depth, origin_time = event_coords
origin = obspy.core.event.Origin(
time=origin_time,
longitude=longitude,
latitude=latitude,
depth=depth)
catalog.append(obspy.core.event.Event(
resource_id=event_id,
origins=[origin]))
ds.add_quakeml(catalog)
# add stations
for group1, group2 in sort_by_station(channels):
network, station = group1
for location, channel, latitude, longitude, depth, elevation in group2:
inventory = obspy.core.inventory.Inventory(
networks=[obspy.core.inventory.Network(
code=network,
stations=[obspy.core.inventory.Station(
code=station,
latitude=group2[0][2],
longitude=group2[0][3],
elevation=group2[0][4],
start_date=starttime,
end_date=endtime,
creation_date=obspy.UTCDateTime(),
site=obspy.core.inventory.Site(name=""),
channels=[obspy.core.inventory.Channel(
code=channel,
location_code=location,
latitude=latitude,
longitude=longitude,
elevation=elevation,
depth=depth,
start_date=starttime,
end_date=endtime)])])],
source="pyasdf sac2asdf converter")
ds.add_stationxml(inventory)
# add sac_headers as auxiliary data
ds.add_auxiliary_data_file(
dumpjson(headers),
path='SacHeaders')
del ds