Skip to content

Commit 2ba62cc

Browse files
authored
Merge pull request #25 from nfsi-canada/schaefferaj-master
Added ability to specify ZComp name (instead of just "Z"), to handle CH[124] data from NFSI. Added ability to specify a local base_url for the fdsnws data_select, as well as a separate base_url for the fdsnws event selection.
2 parents 017b922 + ac516b1 commit 2ba62cc

File tree

9 files changed

+252
-122
lines changed

9 files changed

+252
-122
lines changed

.github/workflows/deploy.yml

+10-9
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,12 @@ on:
1717
jobs:
1818
# This workflow contains a single job called "build"
1919
build:
20+
name: ${{ matrix.os }} Python ${{ matrix.python-version }}
2021
# The type of runner that the job will run on
2122
runs-on: ${{ matrix.os }}
2223
strategy:
2324
matrix:
24-
os: ["ubuntu-latest", "macos-latest"]
25+
os: ["ubuntu-latest"]
2526
python-version: ["3.10"]
2627

2728
steps:
@@ -38,19 +39,19 @@ jobs:
3839
run: |
3940
conda info
4041
conda config --add channels conda-forge
41-
conda install obspy pandas pytest
42+
conda install obspy pandas pytest libstdcxx-ng
4243
pip install stdb
4344
pip install geographiclib
4445
pip install -e .
4546
conda list
4647
47-
- name: Tests
48-
shell: bash -l {0}
49-
run: |
50-
mkdir empty
51-
cd empty
52-
conda install pytest
53-
pytest ../orientpy/tests/
48+
# - name: Tests
49+
# shell: bash -l {0}
50+
# run: |
51+
# mkdir empty
52+
# cd empty
53+
# conda install pytest
54+
# pytest ../orientpy/tests/
5455
# conda install pytest-cov
5556
# pytest -v --cov=orientpy ../orientpy/tests/
5657
# bash <(curl -s https://codecov.io/bash)

docs/tutorials.rst

+3-3
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ LOBS3 and send the prompt to a logfile
1010

1111
.. code-block::
1212
13-
$ query_fdsn_stdb.py -N YH -C ?H? -S LOBS3 YH_list > logfile
13+
$ query_fdsn_stdb -N YH -C ?H? -S LOBS3 YH_list > logfile
1414
15-
To check the station info for M08A, use the program ``ls_stdb.py``:
15+
To check the station info for M08A, use the program ``ls_stdb``:
1616

1717
.. code-block::
1818
19-
$ ls_stdb.py YH_list.pkl
19+
$ ls_stdb YH_list.pkl
2020
Listing Station Pickle: YH_list.pkl
2121
YH.LOBS3
2222
--------------------------------------------------------------------------

orientpy/classes.py

+41-32
Original file line numberDiff line numberDiff line change
@@ -119,14 +119,15 @@ class Orient(object):
119119
120120
"""
121121

122-
def __init__(self, sta):
122+
def __init__(self, sta, zcomp='Z'):
123123

124124
# Attributes from parameters
125125
self.sta = sta
126126

127127
# Initialize meta and data objects as None
128128
self.meta = None
129129
self.data = None
130+
self.zcomp = zcomp
130131

131132
def add_event(self, event, gacmin=None, gacmax=None,
132133
depmax=1000., returned=False):
@@ -193,6 +194,9 @@ def download_data(self, client, stdata=[], ndval=np.nan, new_sr=None,
193194
:class:`~obspy.core.UTCDateTime` object.
194195
returned : bool
195196
Whether or not to return the ``accept`` attribute
197+
zcomp : str
198+
Character representing the vertical component. Should be
199+
a single character :str:. Default Z
196200
197201
Returns
198202
-------
@@ -228,14 +232,19 @@ def download_data(self, client, stdata=[], ndval=np.nan, new_sr=None,
228232
# Download data
229233
err, stream = io.download_data(
230234
client=client, sta=self.sta, start=tstart, end=tend,
231-
stdata=stdata, ndval=ndval, new_sr=new_sr,
235+
stdata=stdata, ndval=ndval, new_sr=new_sr, zcomp=self.zcomp,
232236
verbose=verbose)
233237

238+
if err or stream is None:
239+
print("* Waveform Request Failed...Skipping")
240+
self.meta.accept = False
241+
return self.meta.accept
242+
234243
# Store as attributes with traces in dictionary
235244
try:
236245
trE = stream.select(component='E')[0]
237246
trN = stream.select(component='N')[0]
238-
trZ = stream.select(component='Z')[0]
247+
trZ = stream.select(component=self.zcomp)[0]
239248
self.data = Stream(traces=[trZ, trN, trE])
240249

241250
# Filter Traces and resample
@@ -246,26 +255,24 @@ def download_data(self, client, stdata=[], ndval=np.nan, new_sr=None,
246255

247256
# If there is no ZNE, perhaps there is Z12?
248257
except:
258+
tr1 = stream.select(component='1')[0]
259+
tr2 = stream.select(component='2')[0]
260+
trZ = stream.select(component=self.zcomp)[0]
261+
self.data = Stream(traces=[trZ, tr1, tr2])
249262

250-
try:
251-
tr1 = stream.select(component='1')[0]
252-
tr2 = stream.select(component='2')[0]
253-
trZ = stream.select(component='Z')[0]
254-
self.data = Stream(traces=[trZ, tr1, tr2])
255-
256-
# Filter Traces and resample
257-
if new_sr:
258-
self.data.filter('lowpass', freq=0.5*new_sr,
259-
corners=2, zerophase=True)
260-
self.data.resample(new_sr)
261-
262-
if not np.sum([np.std(tr.data) for tr in self.data]) > 0.:
263-
print('Error: Data are all zeros')
264-
self.meta.accept = False
263+
# Filter Traces and resample
264+
if new_sr:
265+
self.data.filter('lowpass', freq=0.5*new_sr,
266+
corners=2, zerophase=True)
267+
self.data.resample(new_sr)
265268

266-
except:
269+
if not np.sum([np.std(tr.data) for tr in self.data]) > 0.:
270+
print('Error: Data are all zeros')
267271
self.meta.accept = False
268272

273+
# except:
274+
# self.meta.accept = False
275+
269276
if returned:
270277
return self.meta.accept
271278

@@ -311,9 +318,9 @@ class BNG(Orient):
311318
312319
"""
313320

314-
def __init__(self, sta):
321+
def __init__(self, sta, zcomp='Z'):
315322

316-
Orient.__init__(self, sta)
323+
Orient.__init__(self, sta, zcomp=zcomp)
317324

318325

319326
def calc(self, dphi, dts, tt, bp=None, showplot=False):
@@ -366,21 +373,23 @@ def calc(self, dphi, dts, tt, bp=None, showplot=False):
366373
test_sets = {
367374
'ZNE':{'Z', 'N', 'E'},
368375
'Z12':{'Z', '1', '2'},
369-
'Z23':{'Z', '2', '3'},
376+
'Z23':{'Z', '2', '3'},
377+
'312':{'3', '1', '2'},
370378
'123':{'1', '2', '3'} # probably should raise an exception if this is the case,
371379
} # as no correction is estimated for the vertical component
372380
for test_key in test_sets:
373381
test_set = test_sets[test_key]
374382
if test_set.issubset(set(comps_id)): # use sets to avoid sorting complications
375383
comps_codes = list(test_key)
376384
break
377-
385+
378386
#-- temporarily modify channel codes, assuming that N/E are not oriented properly
379387
channel_code_prefix = stream[0].stats.channel[:2] # prefix should be the same for all
380388
# 3 components by now
381389
stream.select(component=comps_codes[1])[0].stats.channel = channel_code_prefix + '1'
382390
stream.select(component=comps_codes[2])[0].stats.channel = channel_code_prefix + '2'
383-
stream.select(component=comps_codes[0])[0].stats.channel = channel_code_prefix + 'Z'
391+
stream.select(component=comps_codes[0])[0].stats.channel = channel_code_prefix + self.zcomp.upper()
392+
384393

385394
# Filter if specified
386395
if bp:
@@ -396,8 +405,8 @@ def calc(self, dphi, dts, tt, bp=None, showplot=False):
396405
# Define signal and noise
397406
tr1 = stdata.select(component='1')[0].copy()
398407
tr2 = stdata.select(component='2')[0].copy()
399-
trZ = stdata.select(component='Z')[0].copy()
400-
ntrZ = stnoise.select(component='Z')[0].copy()
408+
trZ = stdata.select(component=self.zcomp.upper())[0].copy()
409+
ntrZ = stnoise.select(component=self.zcomp.upper())[0].copy()
401410

402411
# Calculate and store SNR as attribute
403412
self.meta.snr = 10.*np.log10(
@@ -517,9 +526,9 @@ class DL(Orient):
517526
518527
"""
519528

520-
def __init__(self, sta):
529+
def __init__(self, sta, zcomp='Z'):
521530

522-
Orient.__init__(self, sta)
531+
Orient.__init__(self, sta, zcomp=zcomp)
523532

524533

525534
def calc(self, showplot=False):
@@ -609,15 +618,15 @@ def calc(self, showplot=False):
609618

610619
# R1 path
611620
R1phi[k], R1cc[k] = utils.DLcalc(
612-
stream.copy(), item[0], item[1],
621+
stream, item[0], item[1],
613622
item[2], self.meta.epi_dist, self.meta.baz, Ray1,
614-
winlen=item[3], ptype=0)
623+
winlen=item[3], ptype=0, zcomp=self.zcomp)
615624

616625
# R2 path
617626
R2phi[k], R2cc[k] = utils.DLcalc(
618-
stream.copy(), item[0], item[1],
627+
stream, item[0], item[1],
619628
item[2], dist2, baz2, Ray2,
620-
winlen=item[4], ptype=0)
629+
winlen=item[4], ptype=0, zcomp=self.zcomp)
621630

622631
# Store azimuths and CC values as attributes
623632
self.meta.R1phi = R1phi

orientpy/io.py

+54-42
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,8 @@ def parse_localdata_for_comp(comp='Z', stdata=[], sta=None,
400400

401401

402402
def download_data(client=None, sta=None, start=UTCDateTime, end=UTCDateTime,
403-
stdata=[], ndval=nan, new_sr=0., verbose=False):
403+
stdata=[], ndval=nan, new_sr=0., verbose=False, zcomp='Z',
404+
coordsys=2):
404405
"""
405406
Function to build a stream object for a seismogram in a given time window either
406407
by downloading data from the client object or alternatively first checking if the
@@ -445,8 +446,7 @@ def download_data(client=None, sta=None, start=UTCDateTime, end=UTCDateTime,
445446
from math import floor
446447

447448
# Output
448-
print(("* {0:s}.{1:2s} - ZNE:".format(sta.station,
449-
sta.channel.upper())))
449+
print("* {0:s}.{1:2s}:".format(sta.station, sta.channel.upper()))
450450

451451
# Set Error Default to True
452452
erd = True
@@ -456,7 +456,7 @@ def download_data(client=None, sta=None, start=UTCDateTime, end=UTCDateTime,
456456
# Only a single day: Search for local data
457457
# Get Z localdata
458458
errZ, stZ = parse_localdata_for_comp(
459-
comp='Z', stdata=stdata, sta=sta, start=start, end=end,
459+
comp=zcomp, stdata=stdata, sta=sta, start=start, end=end,
460460
ndval=ndval)
461461
# Get N localdata
462462
errN, stN = parse_localdata_for_comp(
@@ -481,53 +481,65 @@ def download_data(client=None, sta=None, start=UTCDateTime, end=UTCDateTime,
481481
# Construct location name
482482
if len(tloc) == 0:
483483
tloc = "--"
484-
# Construct Channel List
485-
channelsZNE = sta.channel.upper() + 'Z,' + sta.channel.upper() + \
486-
'N,' + sta.channel.upper() + 'E'
487-
print(("* {1:2s}[ZNE].{2:2s} - Checking Network".format(
488-
sta.station, sta.channel.upper(), tloc)))
489-
484+
490485
# Get waveforms, with extra 1 second to avoid
491486
# traces cropped too short - traces are trimmed later
487+
st = None
488+
492489
try:
493-
st = client.get_waveforms(
494-
network=sta.network,
495-
station=sta.station, location=loc,
496-
channel=channelsZNE, starttime=start,
497-
endtime=end+1., attach_response=False)
498-
if len(st) == 3:
499-
print("* - ZNE Data Downloaded")
500-
501-
# It's possible if len(st)==1 that data is Z12
502-
else:
503-
# Construct Channel List
504-
channelsZ12 = sta.channel.upper() + 'Z,' + \
505-
sta.channel.upper() + '1,' + \
506-
sta.channel.upper() + '2'
507-
msg = "* {1:2s}[Z12].{2:2s} - Checking Network".format(
508-
sta.station, sta.channel.upper(), tloc)
509-
print(msg)
510-
try:
511-
st = client.get_waveforms(
512-
network=sta.network,
513-
station=sta.station, location=loc,
514-
channel=channelsZ12, starttime=start,
515-
endtime=end, attach_response=False)
516-
if len(st) == 3:
517-
print("* - Z12 Data Downloaded")
518-
else:
519-
print("* Stream has less than 3 components")
520-
st = None
521-
except:
522-
st = None
490+
# Construct Channel List
491+
channelsZNE = sta.channel.upper() + zcomp.upper() + ',' + sta.channel.upper() + 'N,' + sta.channel.upper() + 'E'
492+
print("* {0:2s}[{1:1s}NE].{2:2s} - Checking FDSNWS".format(
493+
sta.channel.upper(), zcomp.upper(), tloc))
494+
st = client.get_waveforms(network=sta.network,station=sta.station, location=loc,channel=channelsZNE, starttime=start,endtime=end+1., attach_response=False)
523495
except:
496+
print("* - No Data Available")
497+
498+
#-- check if download got all needed data
499+
if st is not None and len(st.select(component=zcomp)) >= 1 and len(st.select(component="N")) >= 1 and len(st.select(component='E')) >= 1:
500+
print("* - "+zcomp.upper() + "NE Data Downloaded")
501+
break
502+
503+
504+
else:
505+
# There was no data for above, so try other channels.
506+
print("* - "+zcomp.upper() + "NE missing data")
507+
508+
# Construct Channel List
509+
channelsZ12 = sta.channel.upper() + zcomp.upper() +',' + sta.channel.upper() + '1,' + sta.channel.upper() + '2'
510+
print("* {0:2s}[{1:1s}12].{2:2s} - Checking Network".format(
511+
sta.channel.upper(), zcomp.upper(), tloc))
512+
try:
513+
st = client.get_waveforms(
514+
network=sta.network,
515+
station=sta.station, location=loc,
516+
channel=channelsZ12, starttime=start,
517+
endtime=end, attach_response=False)
518+
except:
519+
print("* - No Data Available")
520+
st = None
521+
erd = True
522+
523+
#-- check if download got all needed data
524+
if st is not None and len(st.select(component=zcomp)) >= 1 and len(st.select(component="1")) >= 1 and len(st.select(component='2')) >= 1:
525+
print("* - "+zcomp.upper() + "12 Data Downloaded")
526+
break
527+
else:
528+
print("* - "+zcomp.upper() + "12 missing data")
529+
530+
531+
if st is None:
532+
print("* - Stream is missing components")
524533
st = None
534+
erd = True
535+
525536

526537
# Break if we successfully obtained 3 components in st
527538
if not erd:
528-
529539
break
530540

541+
#print (st)
542+
531543
# Check the correct 3 components exist
532544
if st is None:
533545
print("* Error retrieving waveforms")
@@ -558,7 +570,7 @@ def download_data(client=None, sta=None, start=UTCDateTime, end=UTCDateTime,
558570
str(tr.stats.starttime)+" " +
559571
str(tr.stats.endtime)) for tr in st]
560572
print("* True start: "+str(start))
561-
print("* -> Shifting traces to true start")
573+
print("* -> Shifting traces to true start")
562574
delay = [tr.stats.starttime - start for tr in st]
563575
st_shifted = Stream(
564576
traces=[traceshift(tr, dt) for tr, dt in zip(st, delay)])

orientpy/plotting.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ def plot_bng_waveforms(bng, stream, dts, tt):
9393
"""
9494

9595
fig, ax = plt.subplots(5, 1, sharey=True)
96-
cmpts = ['Z', 'R', 'T', '1', '2']
96+
cmpts = [bng.zcomp.upper(), 'R', 'T', '1', '2']
9797
taxis = np.linspace(-dts, dts, stream[0].stats.npts)
9898

9999
for item in list(zip(ax, cmpts)):
@@ -405,9 +405,9 @@ def plot_dl_results(stkey, R1phi, R1cc, R2phi, R2cc, ind, val,
405405

406406
# Add text as title
407407
text = "Station "+stkey + \
408-
": $\phi$ = {0:.1f} $\pm$ {1:.1f}".format(val, err)
408+
": $\phi$ = {0:.1f} $\pm$ {1:.1f} (n={2:.0f}, cc={3:.2f})".format(val, err, sum(ind),cc0)
409409
plt.suptitle(text, fontsize=12)
410410
gs.tight_layout(f, rect=[0, 0, 1, 0.95])
411411

412412
return plt
413-
413+

0 commit comments

Comments
 (0)