Skip to content

Commit ca45367

Browse files
authored
Merge pull request #49 from nfsi-canada/v021
V021
2 parents b043768 + 43692b5 commit ca45367

File tree

6 files changed

+143
-45
lines changed

6 files changed

+143
-45
lines changed

docs/atacr.rst

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -487,7 +487,7 @@ Usage
487487
--debug Plot intermediate steps for debugging. [Default does not
488488
plot figure]
489489
--figAverage Plot daily average figure. [Default does not plot figure]
490-
--figCoh Plot Coherence and Phase figure. [Default does not plot
490+
--figTilt Plot coherence, phase and tilt direction figure. [Default does not plot
491491
figure]
492492
--figCross Plot cross-spectra figure. [Default does not plot figure]
493493
--save-fig Set this option if you wish to save the figure(s). [Default
@@ -1034,7 +1034,7 @@ therefore using all available data) and plot the results, we can type in a termi
10341034

10351035
.. code-block::
10361036
1037-
$ atacr_clean_spectra --figQC --figAverage --figCoh --figCross M08A.pkl
1037+
$ atacr_clean_spectra --figQC --figAverage --figTilt --figCross M08A.pkl
10381038
10391039
###################################################################
10401040
# _ _ #
@@ -1071,8 +1071,13 @@ therefore using all available data) and plot the results, we can type in a termi
10711071
10721072
...
10731073
1074-
And so on until all ``DayNoise`` objects are averaged into a ``StaNoise``
1075-
object, which is saved to a newly created folder called ``AVG_STA/7D.M08A/``.
1074+
* Clean station spectra saved to:
1075+
* AVG_STA/7D.M08A/2011.293-2012.200.avg_sta.pkl
1076+
1077+
* Tilt direction as function of time saved to:
1078+
* AVG_STA/7D.M08A/2011.293-2012.200.tilt.csv
1079+
1080+
The new ``StaNoise`` object and the daily tilt directions are saved to a newly created folder called ``AVG_STA/7D.M08A/``.
10761081

10771082
.. note ::
10781083
@@ -1095,9 +1100,13 @@ Several figures are also produced, including Figures 4, 6-9.
10951100

10961101
Figure 4: The orientation of maximum coherence between the vertical and the two
10971102
horizontal components for M08A during March 2012. (Left) Coherence as a function
1098-
of angle from the H1 component. (Right) Phase as a function of the angle. In this
1099-
example, the coherence is low indicating the absence of dominant, uni-directional tilt
1100-
noise.
1103+
of angle from the H1 component. (Right) Phase as a function of the angle.
1104+
(Bottom) Tilt direction measured from the H1 component as a function of time.
1105+
In this example, the coherence is low indicating low tilt noise.
1106+
1107+
.. note ::
1108+
1109+
In the MATLAB version of ``ATaCR``, the "Angle from H1" (Figure 4 in the manual) corresponds to a counter-clockwise rotation of H1 and H2, and the orientation is chosen at the lowest phase. Here, the angle corresponds to a clockwise rotation and the estimate is chosen to lie between 0 and 180 degrees. There is therefore a 225-degree difference between those two estimates, and the plots are mirrored.
11011110
11021111
.. figure:: ../obstools/examples/figures/Figure_6.png
11031112
:align: center

obstools/atacr/plotting.py

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
import numpy as np
2929
from matplotlib import pyplot as plt
30+
from matplotlib.gridspec import GridSpec
3031
from obstools.atacr import utils
3132
from obspy import Trace
3233

@@ -237,7 +238,7 @@ def fig_av_cross(f, field, gooddays, ftype, ncomp, key='',
237238
return plt
238239

239240

240-
def fig_coh_ph(coh, ph, direc):
241+
def fig_coh_ph(coh, ph, direc, tilt, date):
241242
"""
242243
Function to plot the coherence and phase between the rotated H and Z
243244
components, used to characterize the tilt direction.
@@ -250,22 +251,53 @@ def fig_coh_ph(coh, ph, direc):
250251
Phase between rotated H and Z components
251252
direc : :mod:`~numpy.ndarray`
252253
Directions considered in maximizing coherence between H and Z
254+
date : list
255+
List of datetime dates for plotting as function of time
256+
tilt : list
257+
List of tilt azimuths determined for each date
253258
254259
"""
255260

256261
colors = plt.cm.cividis(np.linspace(0, 1, coh.shape[0]))
257262

258263
if coh.ndim > 1:
259-
f, (ax1, ax2) = plt.subplots(1, 2)
260-
for i, (co, p) in enumerate(zip(coh, ph)):
264+
265+
meantilt = np.mean(tilt)
266+
stdetilt = np.std(tilt, ddof=1)/np.sqrt(coh.shape[0])
267+
mediantilt = np.median(tilt)
268+
269+
plt.rcParams['date.converter'] = 'concise'
270+
f = plt.figure(layout='constrained')
271+
gs = GridSpec(4, 2, figure=f)
272+
ax1 = f.add_subplot(gs[0:-2, 0])
273+
ax2 = f.add_subplot(gs[0:-2, 1])
274+
ax3 = f.add_subplot(gs[2, :])
275+
ax4 = f.add_subplot(gs[3, :])
276+
ax3.axhline(
277+
meantilt,
278+
ls='--',
279+
label=r'Mean: {0:.0f} $\pm$ {1:.1f}'.format(meantilt, stdetilt))
280+
ax3.axhline(
281+
mediantilt,
282+
ls=':',
283+
label='Median: {0:.0f}'.format(mediantilt))
284+
for i, (co, p, d, t) in enumerate(zip(coh, ph, date, tilt)):
285+
mcoh = np.max(co)
261286
ax1.plot(direc, co, c=colors[i])
262287
ax2.plot(direc, p*180./np.pi, c=colors[i])
263-
ax1.set_ylabel('Coherence')
288+
ax3.plot(d, t, 'o', c=colors[i])
289+
ax4.plot(d, mcoh, 'o', c=colors[i])
290+
ax1.set_ylabel('Coherence Z-H1')
264291
ax1.set_ylim((0, 1.))
265-
ax2.set_ylabel('Phase')
266-
ax1.set_xlabel('Angle from H1')
267-
ax2.set_xlabel('Angle from H1')
268-
plt.tight_layout()
292+
ax1.set_xlabel('Angle clockwise from H1 (deg)')
293+
ax2.set_ylabel('Phase Z-H1')
294+
ax2.set_xlabel('Angle clockwise from H1 (deg)')
295+
ax3.legend(loc='best', fontsize=8)
296+
ax3.set_xticklabels([])
297+
ax3.set_ylabel('Tilt dir. (deg)')
298+
ax3.set_ylim(-10, 190)
299+
ax4.set_ylabel('Coherence')
300+
ax4.set_ylim(-0.1, 1.1)
269301

270302
else:
271303
plt.figure()

obstools/atacr/utils.py

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ def get_event(eventpath, tstart, tend):
304304
# Find out how many events from Z.SAC files
305305
eventfiles = list(eventpath.glob('*Z.SAC'))
306306
if not eventfiles:
307-
raise(Exception("No event found in folder "+str(eventpath)))
307+
raise Exception("No event found in folder "+str(eventpath))
308308

309309
# Extract events from time stamps
310310
prefix = [file.name.split('.') for file in eventfiles]
@@ -408,9 +408,8 @@ def calculate_tilt(ft1, ft2, ftZ, ftP, f, goodwins, tiltfreqs):
408408
phi = np.arange(0., 360., 10.)
409409
coh = np.zeros(len(phi))
410410
ph = np.zeros(len(phi))
411-
cZZ = np.abs(
412-
np.mean(ftZ[goodwins, :] * \
413-
np.conj(ftZ[goodwins, :]), axis=0))[0:len(f)]
411+
cZZ = np.abs(np.mean(ftZ[goodwins, :] *
412+
np.conj(ftZ[goodwins, :]), axis=0))[0:len(f)]
414413

415414
for i, d in enumerate(phi):
416415

@@ -452,6 +451,8 @@ def calculate_tilt(ft1, ft2, ftZ, ftP, f, goodwins, tiltfreqs):
452451
tilt += 180.
453452
if tilt > 360.:
454453
tilt -= 360.
454+
if tilt > 180.:
455+
tilt -= 180.
455456

456457
# print('Tilt corrected = ', tilt)
457458

@@ -486,6 +487,12 @@ def calculate_tilt(ft1, ft2, ftZ, ftP, f, goodwins, tiltfreqs):
486487
phase_value = rph[ind[0]][0]
487488
coh_value = rcoh[ind[0]][0]
488489
tilt = rphi[ind[0]][0]
490+
if tilt > 360.:
491+
tilt -= 360.
492+
elif tilt < 0:
493+
tilt += 360.
494+
if tilt > 180.:
495+
tilt -= 180.
489496

490497
# Now calculate spectra at tilt direction
491498
ftH = rotate_dir(ft1, ft2, tilt)
@@ -614,16 +621,14 @@ def phase(Gxy):
614621

615622
def rotate_dir(x, y, theta):
616623

617-
d = -theta*np.pi/180.
618-
rot_mat = [[np.cos(d), -np.sin(d)],
619-
[np.sin(d), np.cos(d)]]
624+
d = theta*np.pi/180.
625+
rot_mat = [[np.cos(d), np.sin(d)],
626+
[-np.sin(d), np.cos(d)]]
620627

621628
vxy = [x, y]
622629
vxy_rotated = np.tensordot(rot_mat, vxy, axes=1)
623-
tr_2 = vxy_rotated[0]
624-
tr_1 = vxy_rotated[1]
625630

626-
return tr_1
631+
return vxy_rotated[1]
627632

628633

629634
def ftest(res1, pars1, res2, pars2):
-18.1 KB
Loading

obstools/scripts/atacr_clean_spectra.py

Lines changed: 70 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -162,11 +162,11 @@ def get_cleanspec_arguments(argv=None):
162162
help="Plot daily average figure. " +
163163
"[Default does not plot figure]")
164164
FigureGroup.add_argument(
165-
"--figCoh",
165+
"--figTilt",
166166
action="store_true",
167-
dest="fig_coh_ph",
167+
dest="fig_tilt",
168168
default=False,
169-
help="Plot Coherence and Phase figure. " +
169+
help="Plot coherence, phase and tilt direction figure. " +
170170
"[Default does not plot figure]")
171171
FigureGroup.add_argument(
172172
"--figCross",
@@ -349,6 +349,7 @@ def main(args=None):
349349
dstart = str(tstart.year).zfill(4)+'.'+str(tstart.julday).zfill(3)+'-'
350350
dend = str(tend.year).zfill(4)+'.'+str(tend.julday).zfill(3)+'.'
351351
fileavst = avstpath / (dstart+dend+'avg_sta.pkl')
352+
filetilt = avstpath / (dstart+dend+'tilt.csv')
352353

353354
if fileavst.exists():
354355
if not args.ovr:
@@ -383,14 +384,19 @@ def main(args=None):
383384
# Initialize StaNoise object
384385
stanoise = StaNoise()
385386

387+
# Date + tilt list
388+
date_list = []
389+
tilt_list = []
390+
coh_list = []
391+
386392
# Loop through each day withing time range
387393
while t1 < tend:
388394

389395
year = str(t1.year).zfill(4)
390396
jday = str(t1.julday).zfill(3)
391397

392-
tstamp = year+'.'+jday+'.'
393-
filespec = specpath / (tstamp + 'spectra.pkl')
398+
tstamp = year+'.'+jday
399+
filespec = specpath / (tstamp + '.spectra.pkl')
394400

395401
# Load file if it exists
396402
if filespec.exists():
@@ -401,6 +407,9 @@ def main(args=None):
401407
file = open(filespec, 'rb')
402408
daynoise = pickle.load(file)
403409
file.close()
410+
tilt_list.append(daynoise.rotation.tilt)
411+
date_list.append(t1.date)
412+
coh_list.append(daynoise.rotation.coh_value)
404413
stanoise += daynoise
405414
else:
406415
t1 += 3600.*24.
@@ -526,21 +535,31 @@ def main(args=None):
526535
ad_2Z_all, ad_2P_all, ad_ZP_all)
527536

528537
# Quality control to identify outliers
529-
stanoise.QC_sta_spectra(pd=args.pd, tol=args.tol, alpha=args.alpha,
530-
fig_QC=args.fig_QC, debug=args.debug,
531-
save=plotpath, form=args.form)
538+
stanoise.QC_sta_spectra(
539+
pd=args.pd,
540+
tol=args.tol,
541+
alpha=args.alpha,
542+
fig_QC=args.fig_QC,
543+
debug=args.debug,
544+
save=plotpath,
545+
form=args.form)
532546

533547
# Average spectra for good days
534548
stanoise.average_sta_spectra(
535549
fig_average=args.fig_average,
536-
save=plotpath, form=args.form)
550+
save=plotpath,
551+
form=args.form)
537552

538553
if args.fig_av_cross:
539554
fname = stkey + '.' + 'av_coherence'
540555
plot = plotting.fig_av_cross(
541-
stanoise.f, coh, stanoise.gooddays,
542-
'Coherence', stanoise.ncomp, key=stkey, lw=0.5)
543-
# if plotpath.is_dir():
556+
stanoise.f,
557+
coh, stanoise.gooddays,
558+
'Coherence',
559+
stanoise.ncomp,
560+
key=stkey,
561+
lw=0.5)
562+
544563
if plotpath:
545564
plot.savefig(
546565
str(plotpath / (fname + '.' + args.form)),
@@ -550,8 +569,13 @@ def main(args=None):
550569

551570
fname = stkey + '.' + 'av_admittance'
552571
plot = plotting.fig_av_cross(
553-
stanoise.f, ad, stanoise.gooddays,
554-
'Admittance', stanoise.ncomp, key=stkey, lw=0.5)
572+
stanoise.f,
573+
ad,
574+
stanoise.gooddays,
575+
'Admittance',
576+
stanoise.ncomp,
577+
key=stkey,
578+
lw=0.5)
555579

556580
if plotpath:
557581
plot.savefig(
@@ -562,8 +586,14 @@ def main(args=None):
562586

563587
fname = stkey + '.' + 'av_phase'
564588
plot = plotting.fig_av_cross(
565-
stanoise.f, ph, stanoise.gooddays,
566-
'Phase', stanoise.ncomp, key=stkey, marker=',', lw=0)
589+
stanoise.f,
590+
ph,
591+
stanoise.gooddays,
592+
'Phase',
593+
stanoise.ncomp,
594+
key=stkey,
595+
marker=',',
596+
lw=0)
567597

568598
if plotpath:
569599
plot.savefig(
@@ -572,9 +602,15 @@ def main(args=None):
572602
else:
573603
plot.show()
574604

575-
if args.fig_coh_ph and stanoise.phi is not None:
605+
if args.fig_tilt and stanoise.phi is not None:
576606
fname = stkey + '.' + 'coh_ph'
577-
plot = plotting.fig_coh_ph(coh_all, ph_all, stanoise.phi)
607+
plot = plotting.fig_coh_ph(
608+
coh_all,
609+
ph_all,
610+
stanoise.phi,
611+
tilt_list,
612+
date_list)
613+
578614
if plotpath:
579615
plot.savefig(
580616
str(plotpath / (fname + '.' + args.form)),
@@ -583,8 +619,24 @@ def main(args=None):
583619
plot.show()
584620

585621
# Save to file
622+
print()
623+
print("* Clean station spectra saved to: ")
624+
print("* "+str(fileavst))
586625
stanoise.save(fileavst)
587626

627+
# Write out events
628+
print()
629+
print("* Tilt direction and coherence as function of time saved to: ")
630+
print("* "+str(filetilt))
631+
print()
632+
fid = open(filetilt, 'w')
633+
fid.writelines("Date, Tilt dir. (deg from H1), Max coherehce\n")
634+
for i in range(len(tilt_list)):
635+
line1 = "{0},{1:.0f},{2:.2f}\n".format(
636+
date_list[i], tilt_list[i], coh_list[i])
637+
fid.writelines(line1.replace(" ", ""))
638+
fid.close()
639+
588640

589641
if __name__ == "__main__":
590642

obstools/scripts/atacr_download_data.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,7 @@ def main(args=None):
414414
while t2 <= tend:
415415

416416
# Time stamp
417-
tstamp = str(t1.year).zfill(4)+'.'+str(t1.julday).zfill(3)+'.'
417+
tstamp = str(t1.year).zfill(4)+'.'+str(t1.julday).zfill(3)
418418

419419
print("\n"+"*"*60)
420420
print("* Downloading day-long data for key {0} and day {1}.{2:03d}".format(
@@ -441,7 +441,7 @@ def main(args=None):
441441
t2 += dt
442442
continue
443443

444-
print("* "+tstamp +"*.SAC")
444+
print("* " + tstamp + ".*.SAC")
445445
# Get waveforms from client, one channel at a time
446446
try:
447447
cha = sta.channel.upper() + '1'

0 commit comments

Comments
 (0)