Skip to content

Commit 34457ea

Browse files
committed
Added more robust subset-stacking
1 parent 2c4bdb3 commit 34457ea

File tree

10 files changed

+84
-50
lines changed

10 files changed

+84
-50
lines changed

seismic/ASDFdatabase/cwb2asdf/cwb2asdf.py

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@
2828
from ordered_set import OrderedSet as set
2929
from tqdm import tqdm
3030
from seismic.misc import split_list
31-
from seismic.misc import recursive_glob
3231
from seismic.ASDFdatabase.utils import cleanse_inventory
32+
from seismic.misc import recursive_glob
3333

3434
def make_ASDF_tag(tr, tag):
3535
# def make_ASDF_tag(ri, tag):
@@ -45,7 +45,7 @@ def make_ASDF_tag(tr, tag):
4545
# end func
4646

4747
CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help'])
48-
BUFFER_LENGTH = 1000
48+
BUFFER_LENGTH = 2000
4949

5050
@click.command(context_settings=CONTEXT_SETTINGS)
5151
@click.argument('input-folder', required=True,
@@ -60,7 +60,7 @@ def make_ASDF_tag(tr, tag):
6060
@click.option('--min-length-sec', type=int, default=None, help="Minimum length in seconds")
6161
@click.option('--merge-threshold', type=int, default=None, help="Merge traces if the number of traces fetched for an "
6262
"interval exceeds this threshold")
63-
@click.option('--ntraces-per-file', type=int, default=3600, help="Maximum number of traces per file; if exceeded, the "
63+
@click.option('--ntraces-per-file', type=int, default=600, help="Maximum number of traces per file; if exceeded, the "
6464
"file is ignored.")
6565
@click.option('--dry-run', default=False, is_flag=True, show_default=True,
6666
help="Dry run only reports stations that were not found in the stationXML files, for "
@@ -75,6 +75,7 @@ def process(input_folder, inventory_folder, output_file_name, file_pattern,
7575
OUTPUT_FILE_NAME: Name of output ASDF file \n
7676
"""
7777

78+
inventory_added = defaultdict(bool)
7879
def _read_inventories(inventory_folder):
7980
inv_files = recursive_glob(inventory_folder, '*.xml')
8081

@@ -103,8 +104,11 @@ def _write(ds, ostream, inventory_dict, netsta_set):
103104
# end try
104105

105106
for item in netsta_set:
107+
if(inventory_added[item]): continue
108+
106109
try:
107110
ds.add_stationxml(inventory_dict[item])
111+
inventory_added[item] = True
108112
except Exception as e:
109113
print(e)
110114
print('Failed to append inventory:')
@@ -129,10 +133,7 @@ def _write(ds, ostream, inventory_dict, netsta_set):
129133
inv = _read_inventories(inventory_folder)
130134

131135
# generate a list of files
132-
paths = [i for i in os.listdir(input_folder) if os.path.isfile(os.path.join(input_folder, i))]
133-
expr = re.compile(fnmatch.translate(file_pattern), re.IGNORECASE)
134-
files = [os.path.join(input_folder, j) for j in paths if re.match(expr, j)]
135-
136+
files = recursive_glob(input_folder, file_pattern)
136137
files = np.array(files)
137138
random.Random(nproc).shuffle(files)
138139
#print(files); exit(0)
@@ -143,21 +144,30 @@ def _write(ds, ostream, inventory_dict, netsta_set):
143144
stationlist = []
144145
filtered_files = []
145146
for file in tqdm(files, desc='Reading trace headers: '):
146-
#_, _, net, sta, _ = file.split('.')
147-
#tokens = os.path.basename(file).split('.')
148-
#net, sta = tokens[0], tokens[1]
147+
net = sta = None
149148

150-
st = []
151-
try:
152-
st = read(file, headonly=True)
153-
except Exception as e:
154-
print(e)
155-
continue
156-
# end try
157-
if(len(st) == 0): continue
149+
if(True):
150+
try:
151+
fn = os.path.basename(file)
152+
net, sta = fn.split('.')[:2]
153+
except:
154+
continue
155+
# end try
156+
#tokens = os.path.basename(file).split('.')
157+
#net, sta = tokens[0], tokens[1]
158+
else:
159+
st = []
160+
try:
161+
st = read(file, headonly=True)
162+
except Exception as e:
163+
print(e)
164+
continue
165+
# end try
166+
if(len(st) == 0): continue
158167

159-
net = st[0].meta.network
160-
sta = st[0].meta.station
168+
net = st[0].meta.network
169+
sta = st[0].meta.station
170+
# end if
161171

162172
ustations.add('%s.%s' % (net, sta))
163173
networklist.append(net)

seismic/xcorqc/subset_stacker.py

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ def __init__(self):
6161
self.DIST_MINMAX = [d['DIST_MIN'], d['DIST_MAX']]
6262
self.EMAG_MINMAX = [d['EMAG_MIN'], d['EMAG_MAX']]
6363
self.AZ_TOL = d['AZ_TOL']
64+
self.param_dict = d
6465

6566
self.gc = None
6667
if(self.rank == 0):
@@ -91,6 +92,24 @@ def stack(self, spooled_matrix:SpooledMatrix,
9192
as defined in the manuscript
9293
"""
9394

95+
def circular_select(angles, min_angle, max_angle):
96+
# Normalize angles to [0, 360)
97+
angles = np.mod(angles, 360);
98+
min_angle = np.mod(min_angle, 360);
99+
max_angle = np.mod(max_angle, 360);
100+
101+
result = None
102+
if min_angle <= max_angle:
103+
# Linear range (e.g., 10-20)
104+
result = (angles >= min_angle) & (angles <= max_angle)
105+
else:
106+
# Circular wraparound range (e.g., 350-10)
107+
result = (angles >= min_angle) | (angles <= max_angle)
108+
# end if
109+
110+
return result
111+
# end func
112+
94113
def get_affected_indices(source_eids, pat, swat, swet):
95114
"""
96115
Finds indices of CC windows affected by P and SW energy
@@ -173,9 +192,8 @@ def get_affected_indices(source_eids, pat, swat, swet):
173192
eids2 = (edistdeg2 >= self.DIST_MINMAX[0]) & (edistdeg2 <= self.DIST_MINMAX[1])
174193

175194
# find event indices within azimuth of stations 1 and 2
176-
eids1_inside_az = eids1 & ((eaz1 >= (baz - self.AZ_TOL)) & (eaz1 <= (baz + self.AZ_TOL)))
177-
eids2_inside_az = eids2 & ((eaz2 >= (az - self.AZ_TOL)) & (eaz2 <= (az + self.AZ_TOL)))
178-
195+
eids1_inside_az = eids1 & circular_select(eaz1, (baz - self.AZ_TOL), (baz + self.AZ_TOL))
196+
eids2_inside_az = eids2 & circular_select(eaz2, (az - self.AZ_TOL), (az + self.AZ_TOL))
179197
eids_inside_az = eids1_inside_az | eids2_inside_az
180198

181199
# find event indices outside azimuth of both stations
@@ -242,12 +260,12 @@ def get_affected_indices(source_eids, pat, swat, swet):
242260
mean_XeiUXec /= float(wc_XeiUXec)
243261
mean_Xeo /= float(wc_Xeo)
244262

245-
#"""
263+
"""
246264
np.savez('stack3outputs.npz', xcf=mean,
247265
xcf1=mean_Xei, xcf2=mean_Xec, xcf3=mean_XeiUXec,
248266
xcf4=mean_Xeo, idsXei=idsXei, idsXec=idsXec,
249267
idsXeiUXec=idsXeiUXec, idsXeo=idsXeo)
250-
#"""
268+
"""
251269

252270
return mean, mean_Xei, mean_Xec, mean_XeiUXec, mean_Xeo, \
253271
wc, wc_Xei, wc_Xec, wc_XeiUXec, wc_Xeo

seismic/xcorqc/xcorqc.py

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -809,15 +809,15 @@ def IntervalStackXCorr(refds, tempds,
809809
if(memoryTracker): memoryTracker.update()
810810
# wend (loop over time range)
811811

812-
x = None
812+
times = None
813813
flattenedWindowCounts = None
814814
flattenedIntervalStartTimes = None
815815
flattenedIntervalEndTimes = None
816816
flattenedWindowStartTimes = None
817817
flattenedWindowEndTimes = None
818818
if(spooledXcorr and spooledXcorr.nrows):
819819
dt = 1./sr
820-
x = np.linspace(-window_seconds + dt, window_seconds - dt, spooledXcorr.ncols)
820+
times = np.linspace(-window_seconds + dt, window_seconds - dt, spooledXcorr.ncols)
821821

822822
flattenedWindowCounts = np.concatenate(windowCounts).ravel()
823823
flattenedIntervalStartTimes = np.concatenate(intervalStartTimes).ravel()
@@ -856,11 +856,11 @@ def IntervalStackXCorr(refds, tempds,
856856

857857
# Add data
858858
if ensemble_stack:
859-
nsw = root_grp.createVariable('NumStackedWindows', 'i8')
859+
nsw = root_grp.createVariable('nX', 'i8')
860860
avgnsw = root_grp.createVariable('AvgNumStackedWindowsPerInterval', 'f4')
861861
ist = root_grp.createVariable('IntervalStartTime', 'i8')
862862
iet = root_grp.createVariable('IntervalEndTime', 'i8')
863-
xc = root_grp.createVariable('xcorr', XCORR_FORMAT, ('lag',))
863+
xc = root_grp.createVariable('X', XCORR_FORMAT, ('lag',))
864864

865865
totalIntervalCount = int(np.sum(flattenedWindowCounts > 0))
866866
totalWindowCount = int(np.sum(flattenedWindowCounts))
@@ -897,26 +897,26 @@ def IntervalStackXCorr(refds, tempds,
897897
wet[:] = flattenedWindowEndTimes
898898

899899
if(apply_simple_stacking):
900-
nsw = root_grp.createVariable('NumStackedWindows', 'f4', ('interval',))
901-
xc = root_grp.createVariable('xcorr', XCORR_FORMAT, ('interval', 'lag',),
900+
nsw = root_grp.createVariable('nX', 'f4', ('interval',))
901+
xc = root_grp.createVariable('X', XCORR_FORMAT, ('interval', 'lag',),
902902
chunksizes=(1, spooledXcorr.ncols),
903903
zlib=True)
904904
nsw[:] = flattenedWindowCounts
905905
for irow in np.arange(spooledXcorr.nrows):
906906
xc[irow, :] = spooledXcorr.read_row(irow)
907907
# end for
908908
elif subset_stacker is not None:
909-
xc = root_grp.createVariable('xcorr', XCORR_FORMAT, ('lag',))
910-
xc_Xei = root_grp.createVariable('xcorr_Xei', XCORR_FORMAT, ('lag',))
911-
xc_Xec = root_grp.createVariable('xcorr_Xec', XCORR_FORMAT, ('lag',))
912-
xc_XeiUXec = root_grp.createVariable('xcorr_XeiUXec', XCORR_FORMAT, ('lag',))
913-
xc_Xeo = root_grp.createVariable('xcorr_Xeo', XCORR_FORMAT, ('lag',))
914-
915-
xc_wc = root_grp.createVariable('xcorr_NumStackedWindows', 'i8')
916-
xc_Xei_wc = root_grp.createVariable('xcorr_Xei_NumStackedWindows', 'i8')
917-
xc_Xec_wc = root_grp.createVariable('xcorr_Xec_NumStackedWindows', 'i8')
918-
xc_XeiUXec_wc = root_grp.createVariable('xcorr_XeiUXec_NumStackedWindows', 'i8')
919-
xc_Xeo_wc = root_grp.createVariable('xcorr_Xeo_NumStackedWindows', 'i8')
909+
xc = root_grp.createVariable('X', XCORR_FORMAT, ('lag',))
910+
xc_Xei = root_grp.createVariable('Xei', XCORR_FORMAT, ('lag',))
911+
xc_Xec = root_grp.createVariable('Xec', XCORR_FORMAT, ('lag',))
912+
xc_XeiUXec = root_grp.createVariable('XeiUXec', XCORR_FORMAT, ('lag',))
913+
xc_Xeo = root_grp.createVariable('Xeo', XCORR_FORMAT, ('lag',))
914+
915+
xc_wc = root_grp.createVariable('nX', 'i8')
916+
xc_Xei_wc = root_grp.createVariable('nXei', 'i8')
917+
xc_Xec_wc = root_grp.createVariable('nXec', 'i8')
918+
xc_XeiUXec_wc = root_grp.createVariable('nXeiUXec', 'i8')
919+
xc_Xeo_wc = root_grp.createVariable('nXeo', 'i8')
920920

921921
slon1, slat1 = refds.unique_coordinates[ref_net_sta]
922922
slon2, slat2 = tempds.unique_coordinates[temp_net_sta]
@@ -938,7 +938,7 @@ def IntervalStackXCorr(refds, tempds,
938938
xc_XeiUXec_wc[:] = wc_XeiUXec
939939
xc_Xeo_wc[:] = wc_Xeo
940940
else:
941-
xc = root_grp.createVariable('xcorr', XCORR_FORMAT, ('window', 'lag',),
941+
xc = root_grp.createVariable('X', XCORR_FORMAT, ('window', 'lag',),
942942
chunksizes=(1, spooledXcorr.ncols),
943943
zlib=True)
944944
for irow in np.arange(spooledXcorr.nrows):
@@ -947,7 +947,7 @@ def IntervalStackXCorr(refds, tempds,
947947
# end if
948948
# end if
949949

950-
lag[:] = x
950+
lag[:] = times
951951

952952
# Add and populate a new group for parameters used
953953
pg = root_grp.createGroup('Parameters')
@@ -972,6 +972,12 @@ def IntervalStackXCorr(refds, tempds,
972972
'ensemble_stack': int(ensemble_stack),
973973
'simple_stack': int(apply_simple_stacking),
974974
'subset_stack': int(subset_stacker is not None)}
975+
if(subset_stacker is not None):
976+
for k, v in subset_stacker.param_dict.items():
977+
k = 'subset_stack.{}'.format(k.lower())
978+
params.update({k: v})
979+
# end for
980+
# end if
975981

976982
if whitening:
977983
params['whitening_window_frequency'] = whitening_window_frequency
-5.16 KB
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

tests/test_seismic/xcorqc/test_correlator.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,13 +83,13 @@ def test_correlator():
8383
fn = os.path.join(curr_output_folder, '%s.%s.%s.%s.%s.%s.nc'%(netsta1, loc_code, cha,
8484
netsta2, '', cha))
8585
dc = Dataset(fn)
86-
xcorr_c = dc.variables['xcorr'][:]
86+
xcorr_c = dc.variables['X'][:]
8787

8888
# Read expected
8989
fn = '%s/%s.%s.%s.%s.%s.%s.nc'%(curr_expected_folder, netsta1, loc_code, cha,
9090
netsta2, '', cha)
9191
de = Dataset(fn)
92-
xcorr_e = de.variables['xcorr'][:]
92+
xcorr_e = de.variables['X'][:]
9393

9494
rtol = 1e-5
9595
atol = 1e-5
@@ -116,13 +116,13 @@ def test_correlator():
116116
fn = os.path.join(curr_output_folder, '%s.%s.%s.%s.%s.%s.nc'%(netsta1, loc_code, cha,
117117
netsta2, '', cha))
118118
dc = Dataset(fn)
119-
xcorr_c = dc.variables['xcorr'][:]
119+
xcorr_c = dc.variables['X'][:]
120120

121121
# Read expected
122122
fn = '%s/%s.%s.%s.%s.%s.%s.nc'%(curr_expected_folder, netsta1, loc_code, cha,
123123
netsta2, '', cha)
124124
de = Dataset(fn)
125-
xcorr_e = de.variables['xcorr'][:]
125+
xcorr_e = de.variables['X'][:]
126126

127127
rtol = 1e-5
128128
atol = 1e-5

tests/test_seismic/xcorqc/test_interval_stack_xcorr.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,13 +129,13 @@ def test_interval_stack_xcorr(loccha, inv1, inv2, interval_seconds, window_secon
129129
fn = os.path.join(output_folder, '%s.%s.%s.%s.%s.%s.%s.nc'%(netsta1, loc, cha,
130130
netsta2, loc, cha, tag))
131131
dc = Dataset(fn)
132-
xcorr_c = dc.variables['xcorr'][:]
132+
xcorr_c = dc.variables['X'][:]
133133

134134
# Read expected
135135
fn = '%s/%s.%s.%s.%s.%s.%s.%s.nc'%(expected_folder, netsta1, loc, cha,
136136
netsta2, loc, cha, tag)
137137
de = Dataset(fn)
138-
xcorr_e = de.variables['xcorr'][:]
138+
xcorr_e = de.variables['X'][:]
139139

140140
rtol = 1e-3
141141
atol = 1e-3

0 commit comments

Comments
 (0)