From e720a1d8bd2eebf2c36569d0de05bcd4dba0993a Mon Sep 17 00:00:00 2001 From: iman kahbasi Date: Sun, 29 Dec 2019 22:28:39 +0330 Subject: [PATCH 001/132] add new function mapplot to plotting.py --- eqcorrscan/utils/plotting.py | 124 +++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) diff --git a/eqcorrscan/utils/plotting.py b/eqcorrscan/utils/plotting.py index 29f204e9c..cbba85d34 100644 --- a/eqcorrscan/utils/plotting.py +++ b/eqcorrscan/utils/plotting.py @@ -2186,6 +2186,130 @@ def subspace_fc_plot(detector, stachans, **kwargs): return fig +def mapplot(events, bgcolor='#909090', mode='3bode', cpalette='jet_r', + s=1, lw=1, marker=',', **kwargs): + """ + Plot seismicity in a 2D map with two cross section along latitude and + longitude. + + :type events: list or 'obspy.core.event.catalog.Catalog' + :param events: + list of one tuple per event of (lat, long, depth(optional)) with + down positive or obspy catalog. + :type bgcolor: string + :param bgcolor: all name or RGB code that acceptable in matplotlib. + :type mode: string + :param mode: + make color pallete according to thrid part of area 'depth' or + occouring time 'time' or occouring sequence 'sequence'. + :type cpalette: string + :param cpalette: + color palette for drawing events. acceptable with matplotlib. + :type s: scalar or array_like, shape (n, ), default: None + :param s: + The marker size in points**2. + Default is rcParams['lines.markersize'] ** 2. + :type lw: scalar or array_like, default: None + :param lw: + The linewidth of the marker edges. + If None, defaults to rcParams lines.linewidth. + :type marker: string + :param marker: + The marker style. *marker* can be either an instance of the class + or the text shorthand for a particular marker. + Defaults to '.' + {plotting_kwargs} + + :returns: :class:`matplotlib.figure.Figure` + + .. image:: ../doc/plots/mapplot_depth.png + .. image:: ../doc/plots/mapplot_time.png + .. image:: ../doc/plots/mapplot_sequrnce.png + """ + import matplotlib.pyplot as plt + from matplotlib import gridspec + from mpl_toolkits.axes_grid1 import make_axes_locatable + from obspy import Catalog + # set parameter + if isinstance(events, list): + if len(events[0]) == 4: + lat, lon, dep, time = zip(*events) + dt = [t-time[0] for t in time] + elif len(events[0]) == 3: + lat, lon, dep = zip(*events) + elif isinstance(events, Catalog): + lat, lon, dep, time = [], [], [], [] + for ev in events: + origin = ev.origins[0] + lat.append(origin.latitude) + lon.append(origin.longitude) + dep.append(origin.depth) + time.append(origin.time) + dt = [t-time[0] for t in time] + if mode == 'depth': + c0, c1, c2 = dep, lon, lat + label0, label1, label2 = 'Depth', 'Longitue', 'Latitude' + elif mode == 'time': + c0 = c1 = c2 = dt + label = 'second from first event' + elif mode == 'sequence': + c0 = c1 = c2 = range(len(dep)) + label = 'sequence of occuring' + fig = plt.figure() + gs = gridspec.GridSpec(2, 2, width_ratios=[3, 1], height_ratios=[3, 1], + wspace=0.01, hspace=0.01) + # map view + ax0 = plt.subplot(gs[0]) + ax0.set_facecolor(bgcolor) + ax0.set_ylabel('Latitude') + ax0.set_xticks([]) + map0 = ax0.scatter(lon, lat, marker=marker, c=c0, cmap=cpalette, + lw=lw, s=s) + # cross section paralel to latitude (lat ,depth) + ax1 = fig.add_subplot(gs[1]) + ax1.set_facecolor(bgcolor) + ax1.set_yticks([]) + ax1.set_xlabel('Depth') + ax1.invert_xaxis() + map1 = ax1.scatter(dep, lat, marker=marker, c=c1, cmap=cpalette, + lw=lw, s=s) + # cross section paralel to longitude (lon ,depth) + ax2 = plt.subplot(gs[2]) + ax2.set_facecolor(bgcolor) + ax2.set_ylabel('Depth') + ax2.set_xlabel('Longitude') + map2 = ax2.scatter(lon, dep, marker=marker, c=c2, cmap=cpalette, + lw=lw, s=s) + # location of color bar + if mode == 'depth': + # location of colorbar + divider0 = make_axes_locatable(ax0) + cax0 = divider0.append_axes("top", size="4%", pad="2%") + cbar0 = fig.colorbar(map0, ax=ax0, cax=cax0, orientation="horizontal") + cbar0.set_label(label0, rotation=0, labelpad=-45, y=1.05) + cax0.xaxis.set_ticks_position("top") + # + divider1 = make_axes_locatable(ax1) + cax1 = divider1.append_axes("top", size="4%", pad="2%") + cbar1 = fig.colorbar(map1, ax=ax1, cax=cax1, orientation="horizontal") + cbar1.set_label(label1, rotation=0, labelpad=-45, y=1.03) + cax1.xaxis.set_ticks_position("top") + # + divider2 = make_axes_locatable(ax2) + cax2 = divider2.append_axes("bottom", size="7%", pad="35%") + cbar2 = fig.colorbar(map2, ax=ax2, cax=cax2, orientation="horizontal", + pad=0.7) + cbar2.set_label(label2, rotation=0, labelpad=-8, x=1.02) + ax2.xaxis.set_label_coords(1.02, -0.1) + elif mode == 'time' or mode == 'sequence': + divider1 = make_axes_locatable(ax1) + cax1 = divider1.append_axes("right", size="4%", pad="2%") + cbar1 = fig.colorbar(map1, ax=ax1, cax=cax1, orientation="vertical") + cbar1.set_label(label) + fig = _finalise_figure(fig=fig, **kwargs) # pragma: no cover + return fig + + def _match_filter_plot(stream, cccsum, template_names, rawthresh, plotdir, plot_format, i): # pragma: no cover """ From 9eb2b5682202b3f890b803645ba4e54a1b64a553 Mon Sep 17 00:00:00 2001 From: iman kahbasi Date: Sun, 29 Dec 2019 22:30:29 +0330 Subject: [PATCH 002/132] add 3 samples output of mapplot --- eqcorrscan/doc/plots/mapplot_depth.png | Bin 0 -> 65752 bytes eqcorrscan/doc/plots/mapplot_sequence.png | Bin 0 -> 75286 bytes eqcorrscan/doc/plots/mapplot_time.png | Bin 0 -> 80562 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 eqcorrscan/doc/plots/mapplot_depth.png create mode 100644 eqcorrscan/doc/plots/mapplot_sequence.png create mode 100644 eqcorrscan/doc/plots/mapplot_time.png diff --git a/eqcorrscan/doc/plots/mapplot_depth.png b/eqcorrscan/doc/plots/mapplot_depth.png new file mode 100644 index 0000000000000000000000000000000000000000..9785f3cad993fbc2d412c5c77765586ce42d1f5f GIT binary patch literal 65752 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

2{dfc7DnGN>HM-9OkFp811^!}V82j`gPUdfp z78?&bGBjq^CaN7wEJm*-Mm_Trkchrg->!;8HGwP6DlgmKPAVLvICYxrAUrbX;5iTg zYEsbWd;)S5NLR`+ehk8*rJa6bN4o+5=Cm%`+>evq{cVV`xF=~kubhqFd+Uzo;@oP8 zQ~fEz$t>dNu&ihjOiB*gv~3~&4^Z2)psgqNod|7!tzPwq`Gy4zV`N&AkX z$HA01tt;Se^J{RR+Wt_wuRaCTch&SBptYf3Yi_5|*a6NV8E#y8&JvM+v539~Le)q7 z!l5l?Np0iLzPJuJOW^wg$X8LjmS z%Nsm;;V*p#1@E@+o!i{|8TY(_XM&c(pm<0N-9ZO`&csyMB6iJqK8GGFvHw+KW`<}C zY{X;sZ<`MdnOj08@G(b(UhE&HqOXI6&NImmdHCB{-cbz7aRRZjF4%Pe{sA#R7M3?? z`heV`X0u{Kv;OVuhou~P1+*IS)thdV0LS7FIcdqj@$Q3i@?>5W|I(#^FEyLHc-h^J z5gS)8g6$p14S{u%#%`SG!jyI0FTANH6_nC09$r~+t|&*henC##l7YjumXHE8orr@O zmwDyram}mp9yUKDNPq3D_oh7eyW_!xC@Lvkw*nv-P}M1dYABxwt4t;IrOyM&!%K$| z3Pp|hjf6^%&(j2Z{z!%ocGbdJA*wmq?0<6I)MRjSQ#p9e#_in z#c(O)w|n&A6QJv}zkX;tt}&m4Q%l+~opjq_dpkE1*wv`!w&nVr)6%n5C?DO3eaTSS z;gpfIox#F%u_;)q4Msf(MhVb9Nkz~AGuQ1112N5l;v?Iawo%c~uZ(7DUt%K?p4Vnd zQK<^DNXEM?DRPQ2m2ZVSX>&96izo+VM%cPFAEIrD@TO4ZJe6!^ zmf>Bma_0JjfyT0~B}FGEr?(!U>g&qG9A}lt1Xu8In&M+iuXrTI0Si4@26`RMOWdMp z`pjrA@2r80Gn0dNR&+WZ#Xjy@sjB1PqZ`?sk%LjHnv9h+vL1>3xGJHG4{6jMhcEPb zzmSAoJ(f*JYvj14XC;TrT}X8$Y3=}*Wd{fmM^voykOv|d=UrtK6;jkWLE2ibPD#C_u+(*bmFU@XUxXs$^b4a2yIvepRte1b~ z{5X?aQfy#0ZIoJa-#Q_0pzOzN?DG!V+(`Bl4?Ur3YOnbOZEkY|<V|4sMV=&rEz&zCxx$h{3Zy%^NqP}czS8@V^>WW`*z<@U&=_k74kos5h|nlZk;aQf@6)}fRPc^h zV-~lrK0>v$XWDJX>(~rzU!VsvW&nzyfey~RHJAj_EdiaqR;_r7Ox`=^xAjZ4za*c+ zTj`|s{Ey@q818#YJ(slez+LSwGCa`l+35>?!$Y51Q|A<9{Y*kQFj3MY>U-UAWh40z z@qwy>r^?h^ekc`9=M1Y-!x+2PDVcGn-Qpr&5*x@mS{tfr^=1;!mTl5&C&0JT&yI>ja!tF60J+;JfB_r_Ww_R0(##47-TI+=50^`z-W&u_hE}a? zip+BvNAo7X$m@gqds*~_b?Q`{{M+Ych$D+4EVOhugOJCYZ>En)QAt*cf%wMBEzo4{p_fto?m^cacNRcui1o^Jv9mM(YQ*s+%q2%!Yjue4 zFm}*aX1r*a)I%JeBqi;ef{Nq*W9}3R0r$6iUOw9ZtA}L(jhH&n@>einLq~T9pA(zmKm>Dy^WB~%F4^qo_Z+l>W}jcAbg z)lrnHquDEKN{A?rqJtybnd_2uhd;!l38exR%iE6c81QxVp~&evozy$M4Fm7jWQrzy zD3>bM${6cWTyxnIh@+PD;7y{4w!-!yvOG+-a9lf<#@sJ*-aI%ns)TGo)TFCb*Y75_;?4=g?IQZ^T1o? zl0m&EZUym&Nyr528cDe4Jm26ipyxdVd+;;>IU5gT{aX!JXj(+}k00`Y;(&I|NJ)JI zr8mSyNh0O&efAS(o`Yf%+Sdo@maV#d+308vZ-eu1-|k+5kf92I20-(rcwe5af&R*@ z#~2fD7_HpQLfA8sQ|Z~%W>{`ECx-9DN-M(=KocgW86zlOtS2dO_Evyas`$I2n?bx{ z9&Wq&+mg4#Fn;vH&w7duiwI>ZHwGqpo7fR~tTvT3yzJ#dcpj0^8B4d8kctp-_UV0> zogg7k^`a_gO>WCH!uyDG$L((|*zD_m!qro|_9|~Tk@+4g!6E|J0B`)f(B6D57QfuF zjhpGhK20h=(Y{K0(RP&FMq}N6L})HZ1u4SClo}+xDcda#&*R9}A>Y%fr-}|7S4v8M z=#h1lv3Pj->~&Nxg6}Giqp!`fFH=jv%g>!07wx);Z;DJt_;Mb zQ6;W;xy>zO?%F*IBsv*RW`0QaIwena(4swe{~# z+t1437SRtg$EXI@<17w7udsJ8w7BPGkj_M07l_OpBi5VEr;mPU39D5v$>wShlnA~G z?~Gq=@KARDb=9LT94M}%_*~~%eet?+bwe2T{NXtpr`9jFPJp8t<#yc3k)#x_6BtkTRK} zKL+oSp;=ALPTu^)12v{KT7=$3&Prh?QaCJIEvU(u{cL0gHcOp6w1K9ZYo-9uMUY@0+Ghy0skdyD zR8%ta@@mMJ0ZH0D^B^uhJx}yo?D7<=%8_~OWbrP&%%MPvGIx@@!@BYx9cHH?U7V|~ zuD!=mQ6F~6x7S>#*=Sg;__PL$JIo^r1gJgI4q9(=p(Zx^@T<6kABOCoc~jc@I@y12 zVi_WqLmC36G+4W5{fgpp_!ah{)`1S3NgwP}6+uk}#wpwG+e8p_M0{2UNLQF}&jE zoJaCzOOp0SJtGho0yF>}OZG3o&M=^7R|I=C*ALIp=i7$?LKkoFY2TSTdik6U!olW- z8%~?!DqxF6iDuzhmmWF|fH$1334lQFj$=!2nZR^#P>wd897R(a_fiygiUvp-yc9W8 zJ`s^!nes3~nZ6~b>F6s#rgL1(N)PDgrdbfx3pwQtNV}{aZ0qfLRgZ?xUkG7nu5Y9* z-xVsflOFbNKsal{q?8h+7;tz8qg6C77Zk?(sknZ8h14CP0pq1^-9GHyR-bRf|wso}JOQ$SF7jtVI!(MVazVufmCc&2X z+5#;!O`B+(5=H+^Q?KWlpvGg5FgU0s=xoD|N?J2UcphF$h@i}_7 zN=o6-b^PL5$Lm)W<|B2z=$+{Ksi0*yy*Y;6>L6rA1t+xS8|-a%1$fok#>NK_r8$1u zI66kz_?%B@1Nifz^6F?tc4AuSqFHDMXbSc~8_xz}w)gqO%-)I*dgXUKM-ae`<=lI( z?VskJV z9{irQ{ih%HwJPw(6Wl;Gb#mTtA(5m0!iv`FDTeuhw{XR=oUv&u5>@ zrx`#TP2f);SYZIV?kC_YJ7zAYW|9;S{Dhwhr}ky6P{VSJ>{e#Jsc*B*)?axta0S49 z+0-xB4QD^WuC+MWnKWi0oD~cQqXLZh;MZ`!J&pa|aarJfs_-(MLJRkGJyuu3Ym%d{ z_wLy`Al}MOAIGA`gs%MUUkw}d%3t>UO3D~K4>suSyQq+hd~eAWe^BnyUu+`66N^|N zny<(AA&vbh2Tke24!3M}XEtF%@y2KC)K3?E74Oz7zg1AFWwGgJTU@zzD~H<=>Hpx< zUHLE3B61jad-*Dxwtuk=AMUg^S?!qW^WipT^P%)TPm;UFTC{%o_bx|5FgUQ*wOBftqMP-VUKUN zjQ0_;cts|!V=Hk%;C-{qIP9po-qpcZA&1i627Sj~=%x)N<8R9swHOHZQX-T1rq|71 zE(C`SygtKcxJCqWch0@o*ni&3zVep0J6QG=TWAoeU+(+hUru(8 zT+#<)SR-{$=2!ElWN04#HOQWu;$wL@yNu+x8U=b6`0XCH@_0o_bdPr4GtA^_EDcT- z$cs39WM}>Kz#Z@XojadmF>m7Dj7<=)_DHEfkuuOIfk z#~ZX87jI-_I1tN*?~SGhaKbyx1NMfy9f9D0zw}=yTa2$pN;K zYj@>;zh0KHEltUG$QU9H&Y7*s;SrtRVSJ))R#_xD*V=;qJxG11HH5L+GTA}bL*?+& zV^#fy>P~9|Zo`=>(eZ(*B@AEao1u(VlUYtD&AraOd;geCa`CaW{k%N3sf1lg5y5-~ zf!JY$U~Aui>V~^rVfvY248N;HBepLudAkBd!i%T!-;(3%)E@A-)tvm%Jl1KgmttE$ ztyq4Z%M0Lq@>`F#Y2@9*!(HrGb^DgD`1yYyH(Yt$x_#Ts+}r^C)r*7UV}~xL${%0` z!Iof}kM<`ffnkDYU%_6}>py^6BmUDSc>5fee+R?oqRr>s%kLki>)iNHWTq||iTv?t$!z`cQeO{G^`3S(za~tqdu`!1PCI636;tkLC@Rk{S)r`2o-x$k`o`=E{TX^m54{w%f42t0cBWcKEsL zh?beI9;hfZ?t@)IYQHhBdHL81<+c)2X%L^NWQN!vE6KG2{P}OJ>#H)jid8wTa#VP2 zQf$zc!Z7%EOO^c`Neu~;dR4ofrye5kyv194`-41ddbN_eT%Hez&xA7LO`p~q4`Bti z59hlpZb(u?#>GSVZhcn6OVA`nhi@}HP{(GV^xzs^CP&#d%)Zfqme)CjjOe}nX9XSn z&wla;rNxx+-J&KKiVIL>;=z3Vpe!fA<@drFZslFIUb|Vh=QVeGd(Sz^N$~JgbuTS4 zY1i|=D3q-}&L!>QNV>d0_Dv}%^ z_>1yaF&W(>GdZnau+Q9@UzOQg9nU{<&jsMF`bo(qMHH)F<-yZkbdKrn3Q-xP-Y((x zv;9-PFP|avtKyv6TUjODc75f_g&qp}fr~*Q5yv;Re;5pXx~=MNU+G0A#9@!x7ZVyd$c;R-IW6Bl#aE7PJJ>$U{7VGB{+fFYa8GZf! z)}t$u`+_*%n2!{mQicxwo_E|Bf9+#UZb&kB<6hr`)LTq<{nAs`kbkfQ#5I=#cUha|>quRd~e+Nw(}^$3`I>758$FuqJ^N6q5sUU#&HmlW(@Uw+J06sg0jZvMQ>$ z+4f`QoAKbqld2A;c!clg$W2g3aWhG{ylNqvU$5uG(z&&7{AP#X3C)%c`{_DIq}`?>&%OHkN*}D$I*YS~ACGFznBgGVpA=0fEjS4<|v)ib)5SkMM$oe*(l%k8zKxzidCCZ3y8ZV}LFe_gs=eAuf-Oq@QCy}X>tmbADPo2UJ} zfq(^Dh{~k@6#dzN@b>cxU*k7?^<&#y26Zp#k+U-xq)*lDjrSrQiQr>5xiCjXcAtE> z3gFh&!|i-@-AFvR2J^8G38s^Q3d;h^wLB@S%bp1TH4gYwW1Md*tBsbcTH|7>`OR2g z0&j^SRMzFC#_;e3HeJHS;^3YM(Z$)KlWurts|G1WIN7ZFFpnDf0%^BLw>uP=M^ zElNZ`|1DKv4j}Nh+=Vw-RjHn8*Q>HQ43#Gmi=OtY9_lCfz9#dxE_R-7{&8o_?`?zK zH91l9YY+VAZ_^2B!S7Cf{F-$aGwj*kzVRv1NiKh_EMq#GZQVeHkodDtal@leDIYQT ziZ>b5FCnz!r#OCYYd-@>6TWhqt%6?lYbzPy!E1rAnvc&$RIfm!aMd)nD88b3w`gJk=*=v=? zovS$A`ud~~77PI^%DVQuw^@o0zHb_s+)okVR1YAqYWk|~I5~@0tar3m&q@zysSR!H zoZ+W2=y&<%KyLYfCpL~cIc#+CfaF@xVRxG0c>IOz=E?z|RQ7Xeb|?;k(Cjkw&Xn)Y z@w@jbwuYy+FZ+I1R3HB^e|z$*OmDiY&sUWV{etc5*WdQnaMl~HEi~L>xfel?xcOkk zOgu`*bSErCe!)S0eqDrbjy^@XULWHrhQP0VfvTxXl7vskK_$BI>xu`GJ*4<11`iAE z3{KxXrup^SYl3dl>xfm6(B<%wm=0CE(7Mg`KWI9~z&Mz$4ac^d#?YU*+ zJ+y&nfxfs<9%=*$F_R4N0;CqGlVnz#tF$YRDEN`!MjE9KkVgNnJYaM^EvH zBv9|vq2IGT^~@8sij$#{Vj>V<4&3tFxf2m59cQ`^+48f0id_7@6aN>vFAHhZVb=2* z-hO*bq~kELkS)kBS61m7tHn>s0bifMTUB^XCk!hF?RqFTfNj}|4SsY{lnt%P3P!P& z3`#@YZ8aJ&4$PgFL`jd=gh@w;xGB$7zZ(#1|57rHQO4;_6OCFUFT=`%Ej3HYU7_Aa{yyAp zD1)7^1#7~7LlSy)D~eHoFF#QS($;hJNJ!9pFsIR3g*X8=YmdVC;J8B3K|Jt7@lnR7 z_E?_7CcAAKZ<{ou*X-%FFT&18WoyQwR z{xSX&&sI|Q1X*uo>}~?oo_9rMwG>(gg?Wm0|8y`AbW`_I^ivaq_(@kxt_#IeCCDm| zPCVvk6S0^TexnJw;3wk&($1cUD<7{{=4`7-l)xxtG_&#Sv!yuO-McV0Fc5P0OZoBh z^7mfpc3ltN+{swQDF|ZIAnXc-$FD4$OxOm5i+n!|MmmX!9UQ=XBk3Qk69`LTSCF6N zZ_G-b*>+nDfs2{lQ);v4I9-KT`HMns+hgdAsXs=F^Dh$o55QJGobeG6y)L|WiEA+2 z>AK+q*Qm~xX{sD-g1%EUu}|;QLK_%e4S>BIfyviuADSpI&$?(mfl&1YSDz1b)kb~` zTtp9$TCnHY@3aufHk)PQ({!m+9nt$|lWFLp%}2VL?8F_6{zHA!?s909I|CiU%nzAc z-?_J%B27N5^YXR#U(dc%5BcL3SbF2u5(#mj}iY+^=ei;B z@EVu<%mCuz6iDokBo7Lsagu1wb=r1Mj`Rt(vXOS=KH+p1GZfRGI;b zqB!qJyUEzwnF7Nw_EyS^GkG`t!J=n^biJ;{8iAbMH>?V;TChId-M9LM$XnbcS7bYZe zv8}y!QpRbTxE`~)G|&GmlCcTW=TJ9j4wsA&fwfq^_eQ()(H5q!#k$7*$VfGc9e=T+ zT9gOb`VfEZr5CG*aU7(eaK=cMbEdqHucG<3P_e;C^2$C7Quu&aM6mJss&CDm583`D zubU5jkYYLr*>P)R1C_!YD*ZM3I})6U298n6p@#Mv$q8!=EJKb z58P|%Ljdh1YGxHy<_`4GD_(nb8K%n3bDdp=3kLXZm7Sn8C8}^fcU?bD_kLF%ca8ZH zc%f@9%dR99W2-FuZx^QXGZN`=@*qh3#1IBt<=^8%#V0(Fz~J+6Fe>~IL|-rTUsl>j zKG=(bnca~?{Q17QZlYpcVC>j#Y{Z_u3NAQ3MR3y_anXVQE0=LHt*74c*Yl*iwm!*Lb7;6Kare{quex#{74Qrd7&+`9^&n?Xq+;IW|L+N#YW=;BJjqo31PAw&}OO?MKK(l}x)JO~i`J7GxuZd=U7?zUfi-;&`5 zYAm8XsOS^T;A?75+|(V;$#;f>HB#YwwW<~|x-Od+YhO6y^Sv3^dfK?#J^fu7pnpSc zJ0?4F&?m;co9^VP=S__MhIm_+7VUDb7oRIC}^nez^M)b-{m)yX`^K7sl3caH$)F;z><(8GQJaM>W<= z-%fMzeuV=yTuUhCmrNIuBnquBE6RS??-U=wg({S<1eIUP;W+PA;?M>%Ha|IN?@J5? z-khhr!yCPp?kPm?f9<$rmGCS8gDM8xGjDW1nfXfnt+~mQW#XiqLEr+SY0VAbG{eN} zupcnF7mgOs3!0t>MF@jR^83a1zMKJ2eETHBl5zX1Sec78uXa+$!U~1J@mN+pKOfAF zD&y8dDJD@=ROduBL70@Z|Z!kp?Tu!0Mn+XG>0r7R-!mf%|a|cX;`_nS`a`;{|{iDq$bhD>{!yDH(ABW?=)DW?gM0ShYX|f5@V^=J= zp?j4Ut_d3iQhSa6Xq!%6G<_h}NjvV+Xy4_lQWV^@{->VufF(B>O*is{KHu?cv0PH~ z$2aWQxWSX9U5EfR?qGKHBl47xzTCtrjhxJNfn+~zOOE5K?d3V zv-az(u`uXh;qFNISS7HqnztL+UEpn%RjIGB8`JnqL;U2*IKI=*h&mcuzvc~hqS_?? z%pj_wL;Dl|U;Hj9Rr@$t!dHeEN@_K6)ng?p8e2J->G7`COxycqo_4=UMi&&q@NxB< z=AWkMpF!uw_f-IxK?HCLN099sFOcCVy8}d(k!rtQVuz(Y zKlUJUH@h{cU&ydA-N(pkx%D>$@Ri0zrp;h~&czHH$H?=Fe%q>P@vpr_J16bjZ*i~( z+W@D;GIcB0aD{+JsomtMj1pkzy5qSEYu6myb)*j*_8iHpzwFICyj!0g>}gopxu;(s zSnz*Bp{j9P;lZs|NTlXqVsc@Y15a5l5|YOVWFDf^4tKweedGYEDe;n)^Qq?ai;Y|4 z{4>x5ZprDD=ULPKhiK=PE7>PP(;sCRHd5MkxKGZGJ&?oRF;3UTfns(g+DI2_&Q%BP4D-&z_5(0@;Qc16Af@FOM{Zd!|$W0=inpU*;!!)36m6W|x- zVLDv%lq$tm6jjx7x}Kr`NJ?sAu4z6afEpHmvdVL7I37ItrwTOd(P6(NRB0feg+70{ zCFM;%9N}yVkzfoXjc9597bB6C4B_0Xh*4CO#i00mKi%yU!~iV&N7coH_sjllu$HE` zpMiZ8l-G7k7HylNnA7tVoTE5mlHg&`Jo^(5SZ}67Bj&|=S86w*Dl5K~fdwd9y@-r* zrU37WS!D;ZXY)hBw8wz#r+VCN4UySAh6CrvR7A2a!eNf`n@4$KU<4MWHvj!;{<4zP zfTl~sth~=@iT%+#b?vDR#n2%*XS~*Hr4xhPCSLr3U)X+f5}%JVg@6{ThQeepnNeEl7!RaT!ox?m9-9 zgJDMSLAa%`6?T43=khWLi3pfNkc#+fBM^}Bn@|t_isyS6vVBLeIO_(Mn=QzClD+jm zbCZu{woWO`L&LvTf$N@2@nIstI(4{Hao0a9uKpDrmp=y4#tE71^OlVcnD4aiyXuup ztEakRs1$|~L_vQ>??9=cQt+;r2Js0Lg@Nv3`mTJHbL9vQ_rt#Bv*@=vd+s~mLPql6 zl|!4kEm>3e*FNxO7?0@%UwaAGG_PiOvM-`H)>3ly%`1ydoge^#A~9y48PPU2n>JYY zF|y_jX{c+uax^O*7H{DK^>p<5FdJ*_P%#|rrSE$yLPD$M8fqbj*idzP&tKv@C_(}t z!2lh+(B>KgaKQYewS_*9yMX>Ckiz+P;lc+eFsE#N36UaFXQu&gb+SCb5r>H}Q;%nzM(dgHg_vHI}|mBp}aBxsF0OE2tFA?wAC|J?f;cOHKd;)MwPzPtLA2& zQoJ3p=j%=lPxnn_<|5qUtV;>uN_o`02zYcdIyiKcBt}F0+y0;p$Rhb87?m(roiVY? z!=iiWK-!MLctX02KA4`MEzjV>6jKkXLj!B}Yz(w5*VZoy&8fly}jdfQu zXyuKoaLV``5xKu*d_ixsf9i?6#MNLqOtnd(TlDq-S&QYRjw==7!$1tj9DFPIMcwSj zr%+7pNl*&l8V_bR{l^ukj7cT2=k9>BeV2R;J2O5o5z>C?vAQ8f3_b3<88(ozm7)2nRGvqaTDakao^(8r-kOW zP~#@82JP9H`J(S1;*HiqLg4ahOg`54$@X|X?0f7$C4-FhxAU6P7ffEo&{zRQ2WSB> z`L4K>=mKV*;r|sP(WGJ9XUS$!86CcA0((a^DQ;s82@Mesb&|ZD2-Lrpaw32IxSKdO zKN#^}5xkqTE+%ol8wxrN^muHyB$Wu-xRBtS*Cj_r#QQyJz>q;Ch8>g_b?0)L_}PhdnT>DN9lCkq z_Vn>yZAIdzaZG^_(GN+Vd@AEn?CiIMmCcK=!kNcLh6`U4@Ycr)feUubZO(VWC{NbB zrJ@_#T|J;InS?##-HtWx5A}7)PU}Mc)2KMR97!d$*%XlmqY2wzaH4E6IR`sdY@wnA{yoWxnf=p5r` zAUl8smPf6xMoRoD2xgKG33^pKQ$Fi!+FuY}1a)n-6l68|vU<2&MG(R2oB@f$I-o`(F zz#xzeg}lD`#ox5d+zLeoJ3}N>6D&?FGu(iIiZK29aD2XIcKFUdDk-L;_5mGw z*LnI<<7EDZt3WY0fVl$A>v!Dcv(@vRm4RXq9aNv$I@zhG)4HpJDOp3t=-s{>BBM4Y zgL87N;|i^H6O`>;G=n3^CxQrwNarutWWE9FWMV$<1L2E=cIXi&Dz15lVXE-LS`XNNsTx^Bljr0et8wQ-xRLOKR z+(7pC{0sy?VQ#q_`0*24B2wsx=aZb?ka*%yv{s}Qd8B`~J4>WLfLrNHaa@l6G2zD8tQXo)>^+0D8)=I-ACpd)&fr~HYueFBU+zh`^<1Lf zIEqF12uITuN{q$XpeC9YOPB~QD(>k)4qVsMNSJpQ5vul%s8=LBz2p)n$Mg%?!a~)Rg1W_+k zdNY)w(Z}p!m~=E4AvQKkuAk}`A25^-TrMPgC|wP)PIZkkL%2N)YuQfo7>$5Cw_?G@ zY+WpY7SrP|ABg{2g3l~QC34>G?rF^m5ee6~Z{=WBJS<-g@zCy_?u^NcSPzgE;udwo zjD>{@6IV>wn`@2_US~&9U0LbUKcL_{)>BSYyF$F&TA?nT6(vyFKcWDUH=qN-A}}>Z zr&~P6v%(}nPRb!FIE2hgeC~`$#87J-FXkSzPLohqhPUmHi4$z&SMrg2wyb$gvq=xU zX|Pp^5`PL@Vhu>mUGR9#(58NlA4Wtc!FQpRXwR3&(JqdnB2kkpUcQt^3xt~$z5^pD zP95qNIC-cBs~Wmj1V3+V{$>FXp$3Lg?Ooz@DE?uB9$=lj)(*UsDKmJDOO~}qMa|d+ zIx;+|@_ozbN|#EADJDGOwec$cWB1HYrKm}U3WW;6F z!DKLo{>ow}bMY>7>hEsqY|RA${yzefnpVZ>U@{)fDp_oCdqkVJ{8>mRw>M_X8 zV5dV%1Ybbqi3e832}I!4C-ZEQ;YTR5xWMJVMmF!}zSQT+{XNuWHJvJedZ8xsRY$r7 zB!1cJ^s!)gU7jxC+WeT4qG_v-z>up`8rVZyG5DHv6B+I(&5 z;%63TAjjXp-Be?)LE1Mkz{~NBeN}X}ztte82bJV&>YS;3C_ZV-!eYP0IS{!Ao9d~#~fB+ssiqHW|t)cLu5*Tv}UW|RP=V*dTH`} zcIFsE5xq_|Xo6vTCgwAvZ5l`>_?5@IoQ|Rck$i%?L?wipvh#>Otv?|d3;rYrT;rR| zF^LfDdyzYrAF|0Max-2k)Y$RR@+UnkR+?=V@Z#Vb)?FDkcbm0Qu{FqO@Vo!tPk-*D zPHQh;kuPh!IHzWm=)1)i9PX!7Sf~K>PDc0Of7Fr#6y;Egz3h58#=@Bb)89T&h;hCR z`KS@+f@o{6nH>m6{z`8jQZYYxBjkmyPEfm=@_as$ za9^-7rXvC-s2|m>X{IKu?%BB@{N}SCsheLQQM1!&bM(+$WZYo0h%D#w_3x`~Am||m zcdtG=Xcaj+;W>B5TwB*RfPN14tW};S{2R&EfYb^^v4in`V_{ z7|ZU`E8_(UVCm6-!ZLDGnPvHJjy(?lX{IeC22`a|G)n7i5QWnXau z289-#$=1!!YzG62UBrKG`R=r~AY3L(2`~chrTzD5st5V70<}SJTGiBf*_MWVdWQEC zohu3vzLYgy(8eZp>Om4q>QG20)~%kd+HuXJP7U`Ta9FHMZWKeXPW4r?C`NOrv=Lv# z(#^q{AU9e~sSV`1!H6AWq5xu`H#^GJrQaVRH}|vE?95T>4KJ*0lm360h}?Z(z>%IO zn`XOcxb_bg!eW8iCL|46ius62)wM-Cg~aU6!^Cu0U`5H!jh0M>mC&C(6%_Gh6#!d$ zaDW`T2y-i7UO3RChe-qnYAbPsH#FJ`DvJZkx$!=W5##T^PLV=k_j6{uvu zzgdXUJyXzJANgx_7KCZKRlvRe*|@FFh)vH2!?O3O_T5kcLDWXR+!kDA*BF)+!2{*(yIi6+4jR@7>Fv$ zjy;?RNa{e|>8AidbAOyfR-d8T`WtA7k+MF*N#1R7x!UOAZV?MJmAvaPFS|sixJCP= z_6p(WM4v*GK;#~u62s=!;;}DxXOvCKxnjwc{vHL^yD|1weu{4H2B>+jXErfUKFSph zo@IBkpPR;P(B)1B*rip#!-=*b(w*ET31(dF&Is0QBz@2?_-@f*P$z}YH#f?5XQ-{Z z?Zp9i{C%|{+^9cTG>|b_;;%va*Zv=4Mg{CswYKERf5ykw{x?UQ8`~v>t@TrW@48F` zg8YuFb|w$za?Qut)1soiVnmwXAG;6ex)tNbvJ2ZQ%RUC(Jbe}&=v?Z)e23veE zB(`(QUSL>O7&g03hY;z$s&Mza+ZVqg{-FR%_=~Ws<-DKFD5k1-OB&R`1N`DfP#x8D zUKfZR9Gz^JfR$u~glob)_-1@& zH4AKF~Pid)1qRHjNgXd2s z$BdkH$v(2Z>XFjfS4ISJUn;u%&AEYp1o zYCxqwDZh=YU2eqn6((4}av)5m_P@CWVEkwt>g$rUHfjCo1tNu#KHea!K zi^<(ORSQkF9s54s`a;WVL{sXio9d%SRZL=BCm?0kU0$49WmcPaAD zzC=qbo-5`IY8a#G%2y96GUM?LyDZSal?|CS`<)7LYhJAinGK*n5bx{ysFr7 zoAA7h-LbV2A@0AhH-g#2B&BrGtF_FM|6R1tl{m!FQ?zf)Q>(ysmIW1-5huO-&|q~6 zD`%bCn@`_w-Lj(TJ4DxfXcrvl2w2EDUBVR#yg&Rc-uZ-ssw~5ErO6J8+p&e5E+pI` zY6i=iNgFJ@FQD6onL$dZktq}G{rXM{22D1~3El#KO|=ySzzh>W-NeiCm4@B)K?&)b zqJ3DOKTJcvUA}(!V`IT#opJFPq${C4F6j!cNTmcpP+MV$=_#>Kj>bz&jNmIJ z1XBdmU`8q>vb&tYqh!{T)m2BB|LaSg=o*aJyKvq#|FNO_AEPqZP8OvKE zFJ5j^n0NHm{5mI46n?DR_n1C3nw=&f<^*#X+AYEK4>!qg*TQ3u`4!NFG&7><+O;$N zL7ze!`(I+=tHgvsoSJ3a!YA(>wOvOUEUzAuVct{cE4ZY1r|OQ^60K$nL3Al0h1&lh z>y-N~7VXCPqfZYht7hyvRl@wN>6%Yb`RXMHbMNHDGIvp@^_U%JY6{Zsu;@|`&1Wmk z@Tpi({`ua5@xLW_gzSOQI?~1}!TDHAizDwQ1W(|2d2q|G;I3h9$UP$G3d_`VvJb9q ztA-ihGVvegoMo>EjMUl$Pu^bAN4Td>$Aaj9g3odfZKduNmU?)Tcs=8KUe?;Qo;}$x zL34rdF1Q*F%i78!SZMOGf_TG0zofcHPR#`wvg+P<_x|{VJF${sm&M9_(F)Dg zACYgP|2L?+GpI|U8CDYEFH|=}H$=x% zsYUl&`{ltsfqvooZREVt(XS8;FfofH|99k| z=8tKHU=88n4May+5!H1AxBliq8GS@@)KcNP{4XH9rgg3R`U}2yQmysggFIG`1Hh(F0Weme-g20SW25lg!)b9er9;;hi-5Fy~H`#NUl z3GhB<52lJ{s-fKuo+~e)W$;Dt{pn0|99g?yDpLKHQzc$E%G7ZK~(9>C`L325w~N1;CP<&lSbrC{HuPq;BCWEJ_yo&wB!% zutQO@*9rjyjySWuQxLAT&Id;&7kPN}6BkE_N7^}RV-n6B-V=l}V;J@~+U9ap+FMJ$gpaApoaUqYM1PjuQt+tBy{ zCraok7`|E${ERlOQ1IhA(CAoc*?Wy;3NC9JqZy=-MXD)kaWU&}D0t$K*og*KBqre* z^)5L426R8_ZKpO~%doWX%1K6k8Txsd&q^avYmTyX$V-ui6sX@|`e-Z) zOMfi_P@)5la(RjUTTvn1S}C(CM0zH7+EiJfv* zR@{MegS+8Q{0WPks7ydgxn^#H({#)`cPxO^k(^6{YHU|x5Mme}y3myU?yaE%Se z_O4IS2XpY*q$gr?F*dw7fURD%@!fs9e~}Tk;NQU<4b0gCz~`=yz!BErZOZ2@dm{`D z#;hZMtlaBm|5Qf08~DDB`ov1#DYU}@?ykp9Ah?EvL8#x=TdjMzgwB^5+TE|DcGnV@ z_+0id{2F4_kDH_}<|eVzDrYHw-vG1%fDN+95GPmm=-qHiy?xfGu1P2A4kFQ?NL!e2 z7z47JG+$}49ZR~(K{2(LM1k*(Y8}8kXptWM>Q9sVE{h)dqD7`hbds8=2Xp?*S`7GX zhbxn-Y4FDvKXR)pJ_g)Tau{3_Cpb*ncQPX@!j^v%4gb_V#DT8*9INNMcGr030gfly z-WQgsZdIgkpfL_kYd-mH{C5ZLWwB(T6F)7)!~EFIDYkzh(Q}Pa)veH1ci2y7{wj$W z1m4`8j6!KI0@J-LgsQ$zSW;Rlg7R`?9~X(EWbpmxl)t1Uu)WzTY%iDz0_n|gEI?Ti z{y!V1i{T0IO~`rs^c(&)_QQoX7+DNg^;7cHvRmwlWUZklcO5!)ruaOVkBT*KrpWp1 zH&iO)2dBHhizFU*6F}4RyRqz2fek5or6{Aw-|V?dtmu!Xc#Bod#0g{Wsm*b4uq0|q zNwgplS7!eD$uCVZPR|0}{(WQ4Wz8Qwwqo=Pn-}mCCGFGYSFFFWvKa-aHvD)n6vhTp z{|mHk#0UPC<9`zxoE_z;J}qk{4g3I_nppUdj`+I(2xJ$F3%0+WM}GL5QCK-ftIdYs zjp~7aLpUB~75agrihr8#8jP^bm5zJP`oIwM(N(w@0fdypte1%Vl-hdp@D=D&QK%YeI0DZU9A zh}t*{8CzQgi$p`VY9rqzppRVnk=3r$Y?vGQRVVz`UevMHYX>tmrc{Exhj)_CY6~Zi*ehOax~a|qI6rtgNY^7;S3e3$mH+(-Xz}r#D+K~5 zqLuYnfkNw!!XDN4E6OMV(PquZ`EIj282>D35%PpAL2p`5o>+(|V8iPrdR;0XhK#kphmlQAecO{m4x8iJ`F1Cf%$Rn*cH zTtWO!)?c|<+Kw9HS;4SQb>4Ibf-a`@o}~XSbcrn5k6o6I+i!9CudKqke~jdMrqb^^ zX9ic^`YZ1ViX$$Zv-$dKXKuA}Hag;LK3dauglDv^FETjWl6%lyT@$dHBIYl=W{sj>z9Gmy`v5hVlc1 zU;pUm_*?>;(gCnl(Be$N>aBF@JM-nqJ;M9&8RmpbnXNPQ?(H3 z*f3)8GR&ubYqY+1Z+U+ApEnpsUI9{5E(`ZpHfWBs;qB?7;8m*OtT7wymlott#~N&* z`=!mtWhq84$K1aIByC?qU7P=HStI3YHVZ^zb98h%$Q;)uy8UAoNFt6dRMT~ym| zdi^1iD*A_f%N2NF7a0>8vXls>44>SZ{-b9-L0FlrTn^C2N2QOHi z!sorinf|Cf9DH7{eMy>F=W{zX&S%dU{T*th&TayVcO0KYnV^`jHRQKzj09<^0|qK8 z>ak0!lfT{>_|td+&c*tJJlqmwz*v^N$(VvpIbd}74J*)c9H(5cwC^&K<#H+RweSsc z3%bz1Q(ULk7!rt4+yZJkf^E6vzT$lze!dYhwCZah8#b*sjKWC55k5g^$j z0!Wm9g$U^d*9VHyZtk~lzW>Eb6#x1an zGXk%@1cvHopa_Qxko@WVe!u7fR0>6ffp`LHg94^GTjp935cPglEG8K_7@QmULYWJ1 zjW<$Tv2=bAE4O$$o02O%rt4DguOy03*tcT$=%;sr(h#1OW&}K(J!?wF)LFFih)GmL zQf6nr*IQosdPM;MQk$&G6e+bG*FL?D3{P&}U8|-q0O<1#eoA~ySs{~(-oD+m5b&HO zJ!v#X0tI*H!2?Bxqs9s*>kJR;2mLYFgtSKkQm?#|#TiZ@Mp>^xBfc;IV%%EQGJFd(HK4Go|T!Q~zb^!sXDip!lw|dHY$}t&-4* zJhXIG7OmPqx16OJW&425Pmu@W6WmTirawHgqeL{KV<%jtE_GMoi!tWTS}V8GUq<`* zYW6CKiHWuCjgld?Y))ORusXcp$pwa}4vil0yVSbJlFVuwr`Z&PLUUzPo9p`$W*A@D zf?IqQ)5qlts^W#3fXM(!m56@-#N+ozh|D7*Rr^K`y@ALpFn`gcRBzw!7& zuR-%(spb5+F1%S;5&zSi>cLYx_Hxe2a{3$7^Z|e4cO;Jun9Zhk(an_THBg(A$?L`x zEfNAKXk4k&90xo%R^7J`XUqM6AH~~uTn{l+Hv$!OadB}qyL`C?pL&s>fSC0WAVVdC z(}4g8^uRmJ4e&3S)@ic+0)%sG#CK9ARB28UlT?SgtonVtyiQ##`>&zbeIo#QFsJ%7 zg>LDA3ujVZW(F)LD$t_z!G)H7OOr;Io9trQ62ch-!8opSx)*hm45Hr+7G+LEDV=pH9xQH{@XewQOK49x-j5`4eSKKj!!vm6boL7Y z%fLSldaYqAvF7LsI>AM&(E6pad+#^<@G5#;5Z&FUH}b$s=!@~hS&>72&T~N5Hf!0N zi2K1UXFoLl+l?Adz`>i!LeO}xgMpTiNnaiVPf#}dLmlFCr>}%Ghb2cCoXBC93(MU- z9%4kff#_x;`M1AxY#c#DVK%fMZ+leZN{n`jnk9Y~FE*;Q0IXz*;rlSA+ z3Y_(G4iC<~!|8WW=B^;EoM)roO6ru{a^Ym2?(ReKoCd8A0^vLUMTScVE~ogcy+L%$ zigoT`H;#Ft{;LxJ03d)CN18l4gRrQn@uR(sb@Jxro3yv*Pg}#HK8vQ`?BFMR@5=HX zpcdn|LeWWmk#`@8>$RSk(x_38E>SX8_R8^#uYZ^qpAZnx*>7lsqeUgTk;jRr6=vE0 z%4YKN!hQ#2!2YQAJGVJostp0k-T;}krDbK?1b@vTq3#b4m4B4x*#)>Su&#l(QUp2GQF27IR5DIyzMwve!~`ON(RvhONgZTwOmpSmI&&8Fr-F13St?L2XG^_(eb(% zLo~bqw-;Rs0?A<0p@@{<-K3}q+cM~_2*mul8?cJo(^Cyvg88e{uuy0213T`#2)Uj1 z1}x{mZgt<^6P;ZPhKJ%sJaJTqoX%{;-Vzu9>b`m?ZXW*1|Ad$ssaxcOaaY9I2+dzO zTU5}M`jY7E*w-QVFrjY4s3+E0!H4~XW#0&XUq9>@Y1JJ-=7F!E1J-Y};}ENy%dqJ{ z9ih~2O+D5y!{m(cly_6p!5rw*2j>qAPD1pM!#mxdjjDN*+91Fw;15?HaprCMxRf89 z>T8X=U2X%OC=mC5^0wUF(n^!-@x466KCLU6-{I5H7t&iR2AX+&Ptkq_^r!NBzbzk0MBeg3m>$yqv2FqFL5-^2d=u}i$zn#^kp;_ z1Y5jME@2k_-bDaM028){QncRhjQf-Jxu=~{i+nsB@cI_yz!BE%HMdyvq_M~P`dEUm zLo`U+4pA%Q`Gsxw%y)2M0ttLMsd0iItT`{_W`fk@=gzg)K>DdEP_KwB!>w7bDud_O zZaY0Lj;N`1`s_X-lSy)?;cMmXCFzYRPV^b}SBlulhv%PWNHr{1D2^oG1FgD!AgZ8s z73+OK*}(03?722|r?oFh(8$U4;*MFB@lQXjuoO{I6Y^;To}})J%5|?;eJN5b=o(eN zZDjh0cO5WPV@5}m>Z3#T%t9S=P=ee~?t?tV@_X{pV|YEZN^o46Wijoa-EWP2mkuO_ zJqz!&iwJ>!&Fu(GuU@MMubQxTSOr{*LxBeEO$?1hUMN-O0J$;|-ErV`os^EzEL9=j$YTHH3J7_WQ8`Y&dP-^Gq zyIsw=a$F19GVK5K#$Vy(e3RywYT7bVOAz>?%B`+5jI9@GwIf3&_3Vq0B5G!$Pc3Hk zUl?ebJ~~;{s?f9Yg|~R_Hny&#)@Au8PB|wd=$Yd_=L1tfZ}*Pvw=P;VH-QoZJvT_X2{M6aXWlrmgBn}WHD)l2_cME zT?5H28v`to8P_scBEPFi{@yL5o<#+ju3s?309~zv7U(6oLTKO+UMJjs5(J_t zY}+oJjU`q0tk-*yd=DAUVZ1KswLmhvrNqQcHEVqH*RB#C3{|Z&Jv}bTxzYG`jm}x4 zrHW+W!0-c=fR`EBl~-muXJa7*8_;$th(qTwNKn{dA>`h=Iw6`Gmx88XSrzov6myoV zyhSm0MFY%NsBMT4pc+t@|P;f zE+Pc0E7XBY3p;xELd1C4`~KH69W3cxRV->Cwr)Wy{>kjQ4O)**F?is{z_#X`W6SdoGmxg1dlhlMKkmvUPaIjVJx}LKJ9br6lHC6ekcAX z_Q>~T|M&u0OQ#7SR$L@G#v9ubNtr=(d~F4b3^Z&|ssK8JGAkDTSCgyFAi^4CyD` zEFmQlFy5QFcY64jS$sS=qA!^^A1jZ$x;q47 ztCZ>`C4JVICg9=wo<5>v`*B@5HG$O@rs>%5&`ls}W!KW39xdCRjEXn9%F3|K9(LgI z17619iR2Q!K$cbS7N3j;d$9Ci=Zt?9GX=)(fxlyWl>FV{Y+J66HnI}Z#M8S!60hVb z{&@S@u9TF+H`*2m6fAGa(qh!If=CE2Z%E(y6xb1Ncd%Se$aq4s<|}&Sqx-0k1~WPh zf)Mvw*^51mh4{G$Y^qbML@Ynjfn;|`8(X|{n{RI%5$G0(%F!x z;2F(M0!e4{r-9l!+fjj8SuE0~P~!BK2(ykvr3AC>uzxicj2S&lkF-9(ifQXL|x<26gwBV&-Ajn1U2jbcHbTaGejOPmtHUNU!^6_o8HXdC7jhP zv%mK-!~Ag>87|&Wd-sNJz}4{cp?l#=4<{$@>AkO`Cab+P$J{(K7Y}6Qv2%M5uQ;3i zkqx5L+n*@+8~#1JvLU@BH6_{o*-OFW+iNgYLNq-N8_1( z^b$n@=0yT}=HQx%{Gt!o08YBH0>O_AwDlG+-(;o$+$J-nQN!v z)DuF`Fvxy=3fv3eBC|#9jZF}!$fn`m9v%wG`ZM$PHl3SFa($O=ql}cGY$5gPuKTV* z7GB9zI1Tq#)qtRRknl{OrpLGBNQszG?ueE7H16-g)z1{PPjIkZzvln^X$B*gji)%X z_&3`A`;{RUhuiY`WX5x)G{J6u-2PXB zhzlV(PKNj#=OyM8`lL)aM@-Oox%IEYc8lj&=P697#^fI7GsK0qOiQfygpZ9$(jI&S zug|~eA&FWBK6D#L6qk0ig|c@vCzLQs4HzxLlVaB&_eUreaY-6|Bmh7!a-x&J#DqLt z%KrW|fo9%Z*QN@SvC-(q)YDnZw&vnpZ~^G7cvEpWvb&bnG zB>?qZHfk40AO3>}Q-?$CyTk?ebM2S+tzes!v7RSu*Xe25JdJj@{JHCjsvVbo9qogp zCp|jqxssF6GauB%G~t}+IUkdFMAEhx+|f{%=NLRQUVcSM{L`Ur_&DYLP+y9Vo~?(?Ny+gY)mt@}U$(S?%VZ{AB=c~?Qde1IwaJ}1pb+|Cd^N|yghH~SB1ld=Om9N4;do`bx5ovEuiJqov z0C)7aD4+HN^FLeGt$XHOd)BXOBgV(2ii$$jHL%EQBUU@U#blv>3~N=MC<%I6i zuK&g&q~2y+mRJ-Dv$5a68D*AP;at2W4Qt?CXGV%D{P_dH74ul|2NM$n_GmhCLP4{Y z?v?a+r<+z})TemnFaoGu!e=hN`OA)|U3$E+UzhM+|CaGmkb7sBpab8USmFX{=E>Y? ztlzXU(Nz^Wngx>I^bI(;G0}Py4`jxkqoR@l>i}V_{`MPEVN(G1?+{wVM%JTC?q9p? zyQFODRRx+^v*Z=F^^m&Itc;Zv$$C)i>?gvl&WQRX4U?Y@cptFKDQu=qs$f-JR=xfE zmhMFn=0-cYQ}_Yr*8?|{$wwYrQt>#KuQEQzm9Ij1+h(Wsy`H}OGAi{rGHI&uPupwL zdA3G78|hNdBu*bVYH+oj`?bFflc|z?c1Hw}G40{B|MC>}`U{@IzQMQWDmq$mb3D6( zLkHn1R^sfEL%m92+C=51cnACQcrkr0XL5}7^qjaLTtBK=Y1Rt=0`qECy>B;3c3H2w zyCmPG!j~1+;%eK*KOUjeJtv(i`J<;>Flxr?i*`_dOs8FnLh7-6s_gN8yV5(t>ADBk zN4%u(mhu`KX%#K5tP{hmy+M=rWu8)HvKyl73m%OxyDScGJTQYquy*2e=A=0$${-ND z^}?U8;d<#Eo#$Fi_|Itd%^`SMos|+=YCOkPAwPS*=u-tA!1iC4j#0{0Y`uh=inIhhq)1Q+;4p+A#@u@d~h%zlAGxU$+7gQ3BAob9lizcuL_kRXXFM7Gaol_i1D`G zKWZG7Exr8>G9}M4*U(+=%i{F6%_eyedr=r@Y(n+^c7latD<5@UO94Mr9kGQZm!0S% ziUQ+e-)(QY*z_F$((=m^HVa6A?fyzts;D_S5|P2S{VP!2R0EJY=TmX{3*tN`e~>h3 zh#H{nybDDXFGdL>d^iwQ8`B)dDtW{!O?XSsu9(MEBhQ*q^0QqnS+ttPFX{052g%vh z$L8yj%PI&ut3UgKrAAP8{EUVPlBB5Chj$oJPk;FDVmwx`rKdK2_->$M@v|30D=|^9 zKmLX~tcW)}J4@OnwsW6FA#?Hg*x+g7!EZ`2?e^jO1dhRAQP|CVLVEj~VCuEc3TEz@ z8ivV{DJacqyP^k+jlZ^o>j`qHfS+>r|^k!XiCeiE;%Du@h8%;|mf1X?`#9T?^)k*ArBqEumEb0D1O;?6%jJ6`pnPJoYOp4{fyn8@B zl2y|;WderA_iI`e3F!jL)@-Ck=TqZTC!1Cwrv3tMn1EN~13o9U^>Ckgjv|xob7g@~ zw=;-FnT_Tl;u)c#JurXCE@waUZf~I8D!$&D7QM_%#n?q}ASy8F_*~~mVl;h!EA)}5 z-|S4_n2`OY`ge9*pOqhVS2MW1&> z0cdY&_)q6~Va)zWAR_r_c~EkiKGEe+ZrCmN1vfjgYWDxGHxxuSKXgjgnDqH_8|*;z z%Rw%@DVD&)yj%(=b?c;(#IA*o;rxqCMp-K5PvMyjJaJ00T5bimag5nUU82;Dx)GP( z=E{gM5Ip60Kd?XjO3NTQwc#&@8*6Y!S_D$%S8*%8djS(K z2gsr3Bh?`=a1N)=T?xs_5QbBl=OooJjx1WJVunsMwvx>Q`fDQV*Qk)$Be%uXu6bw1 zw>aaU*~0!v6zf9b<`C)GFCBC@mDXpFT0cVoD5Z-Fmg#7V8 zsMn-Eiwtg=!#78ql7nIY?Od22`tgnEBiRtVT$#tCDu6XVY|fueD%H>h6_TsiBzT)7 zXvy3Nw14VpO4FkBD5iK5+K4~IylsOU5}F!cBN-qk_!iu8+Trg7B)!-<#~?u%(^=h0 z;RC1dW(*yQUwO1+4Ogi;7`Yv%)m*rgh27zs$J{UXg*aT&?t`Wuy2yTOUaP^76*ULB z@0HFQ7BfHR#Kf`m812;Zns^bn%zy#E1vxs{E7H z@Q=5$AG7R$aqy6QCLJwjZ@fA{Plw68VM6XM_h!P>nkUJP`i5V3D zWDN6Cy>$7y$fq`u!SRXMm-&e^WimX4_Ny%ae2)D|9pP}a71K)N%+t33v|-Wu?`faA z@wKxDt^>txY&d)a9=NrrT`3(DZ5moY$}7`if$4D|HEA1y>6_MCwoD_j%Z5b5Q9Ike zE$T~1UYvLGI^Y&-CaGdfjB~)9S5Rs=WWg}e4+o=%?jq$Zj4%dVX!?%6=_!zrc<1}iF zIVHl&WUqvQM_gj^2Z1k=gx0-O9DKFKr(`gywbPZCyZ*Y(&JTo_vtVuY__B|>2NBMx z$E3+HZu!VPMJ>YI_x}$UfRJ_WRq`iM7rYpeX*l0eGgV%9xG3z7Sl+|!=bm~`^YIV8 z2ffHsFPX_Cz;-&9giTlC@2U4t2=gYV$YJRI?dU?f`l?AN_tR%2y##d|-KP)!Z?LmH z>3+uw2h4BB%KnX^Sz)5B&bRYwGIylD97Au-L)X9+noOqODZ3gU2VuiVtibH2aaa1p zWzE=O#G2)kJ{Gb@cfz*rQ^CBmVVN*<{sy|fn_$=0jjH0nU8x~@t68D2zB~&~IvkEf zrI|w8Gj`}YudLkomTkFYLoSUE@&M->ADq+-hdR3)RX*91&0sB>)iedzbT!S9nUo4! zZ*}OJpl}`2QSjRj&S@|-h*y@12;w|AFmqekPq|q;qoUhX99c!jviR9AeEHshvLQ{{ z!1(M&!(6~W>bN$aXEYn>U&y_`mTs|ERwd*FGAhRe(n`V4!tt>2Z>`pTmTz}ZP!e1Ak zPkyS0S5`papD>0gwTx`OLH61a!ODz;lD_CC>R!8h9hy-~$!wZYr z%E_&f*x7mcL+o6S;BXZo`o?CaTNnOgb%MSi;XkIZ+5e(=|5 zhB>&G;F*jdkkn>aUlUXIh;Y(d=L3N}(UiYyIJY^&Ag84wZhw6g%ko+Mw>iyVL>gK# zI#YX$4ds`bxh7BOH1qwD3U<}A|6tQV$E8W_Xn69~Q&Az!nsxtizFzJl_A7XA&&8~F z+c5y2(joPq28M=Lc)-Lck;h9vp+ln=oiOg@=|)IB-A`LMg7=2!81caCpt=47Lt~$U z9i}a}_Ky$&nuP+|Bb9AzkdT2rxOVVp|Bhg`Z#yv}Y6km%Hq2keLCXxIOM}p_M0w*) z8xD_=iYlyKdBlK$|MJq1b?d|LfrFM8byEK}=Zy$Z_t|ewg)iIpFqgD*m#4zsF9M5# zK2~61zVfYP47Wc%)l|X1onlFthMcpNlp=?@F%Rh2&~Jm=50w!KYHH5mK^4eN>OZNJZ%n7w{H(QXL`P^|uG`T=%xAZO2F$aEF98;;6gj zL&x+ysq04OFq$y3e87g6BH&5hVNml#1{w}$`U z+)&*S54=$pAqL3|gI?!8VOeqJV>bnOuyWQ8%T@bVGI^ew%mHiOvS36U!V_gTs4ppw zK#l5OsesB2tweUC*A08M5t|IBO*yP0OeTUZY1`=&bnsf&FSE8b@no&r@obP6JM2%r*MqJ1SqdKshBr`&xt#p; zf>1S@43a+w9dEea*dyON_zx}dE)m4M5gYvpjzFj+rq?J`l4>AbI0bAW#wgHsTprBT z0SRjUot&6!AlrMh$=lKk{tvKVq(v@f_a=WC_Qx}m*mq)i9VEx6`-*p0+a#QU`wt# z$RA(S%nbr+(fk1qbicacuzoLdj>UPo=>F3pet)f92~vxCoD?y+g?#;|E!JOARvMrA~Z@wQDeZ59i}1q*G%*#s{C=PTU zT~*jD2ndlWCrr7o1mRCNdGM}vM-G$9=c;;c2`;UGn`0mcV#oQzKnmBjX))bHtwUyP zM-W_?K%d**Yn}hw4%CCqNZ;jH5sgm?TZ;hulu&F5Y4*w;-p z0}h9E86at|bxcGS88VtJ&8goWDB|PO@fLz0{LjIr^Tc-OHUM53&?VZmgxnDcI`2~u zpmCUw(O6hm)NcO>16%~`lEzaMvETO<3&2c!RHR7}#H_6k-Y`$IK&PIHBlX;J`|hH| zXJNw-U)v5gNnum1UzQeN9{IbF9H>RqE`6ZNw5fxzExqq>9 zYk`)D_w7g&#fxLx^&4Ld-fy}Cr{l15(UY5969mzJU)1YV!27L(A$HODQx{YJBUiJ} z#hrlHzw1+tdHfxx3s4Hf)w8@HNq%4vft2Wq{O9xt67PqL`mC@1?3q8bJ_7U*pc;nT zYW{`+1seINLVlD4B>3w-sr<*0hW5P31Gyda;0Odb59(Y)(eweZ`FBVpLi0>;{D1Vd zh8ALqQ!PLUrX)N_$qE!7~cb_goSXq4gVnSJcqZ;b^jkZhSD5=gs{NINK!&|_x4}B;!9TazA ziH)@Xe;(`q`5@KZHNe8F(8j=0M9G{x%0mN5aPy_d?@JH1g|IJ9!_7W|I`&2)2jTkL zK#__VkgXmT(4Z5opZoiFg#B9Aj;_KwMb*=R)7z{P>>a1%gSncut2=u>l7|Hn==Ug@ zV|w2K<`b4QiQo7R$%`ukK(zugjk~+M&!53Pj0LZVWt^E-94#qn{1-;Re;wZu(kpoj zL3sv;LhS`U&O${D$Z(GkhtO5qF8z*%gPvF9()^VLm4g}1t-#9F9c=B{kl@LU=fgY^ z^usLBlV=BHZi*BYqyoNpFTl2gCLIoG7QuhVLwe%f`V%NR- zFDTk|*Hs4B1_$9eSR5RZ+#ffDz{mfY^Nv(dihq%p`Onl}A3jMNvzus;hSat=pL@OAXO#hhr_k)PeG|yjwDWpgg7GIr869l{%h1|mgwl{o)<-s4ULvtTqwuTq1&*GpasatXjNI@ z0(uerGGMlDbz&3ra`dgsV_;|agki_ve!;$=*^1l^~ zW*LUhx>?@OVt9MLgU}5DfhW4xsO{tnHXVoey{oSG%|^4$=69^HKQQ#HHCtpOTl05_ zpSRT(s-Vl?6AvozW7~Lw2(CDHRF)>_qWb=QpgsXYH&BDO11hRB8j2*UV>?_m^A4z6 zsg4*KPxo7}UPE5`Bf%mQI$=;3VydE{(G8XQdIY*)#2Ld=OM`@Xc&xeu$ZcPY+jTWAdzJ#{Kc$R%OupLgOlF zc@%(p^2%|gjsxd4=Z2X^H_oehM@*ZV6u?7Got#u>>VNIJ2!!Vegx#G)tK5%)5Lxq| zwMfw+AQahMYrp2uEgebrYq%}}y>Db{{PPquGjr$KiNDXk$u(;@Zbx+kw(Pq1tH$9e z)xL`mIyZyXK$AY*Z8K@!5tzeFwKXx6?b;oW$&#cHZ0oi62}&O|&G3o`-0k}1lW}EH zoeW1-Vy6n1>M5NTppSMZ>|Ais3PyA7cf;ZCNi~$q)zi9hb?3O&Hyalp58_zQ{K;NP zOZuEm!#BXlg!6-e;zw|q$?#|-{gc%{Q0kpDxff2$Qbq$SCSm{%K0Y=Y;syUz`5WBZ z*}dNx-nTnszZ!JQjgV^=oIlx!l0~YisEis;;REB3YTKa`y+KyWj{!)| zBjHO^0>Lv;#7n>fsG4pc2m)Sd9njjWy_o#ea3S!I-Pv=x(a&9=0Y)_^;Xk}jKtO#4 z2WCB@=R0SCJM@;%bii6tNac$<^1f<#|Ni~@uHV*h24(@7CUi0+gKNN(y?6PSicmS& zA%582!Tk=qX=+FgGNYj?2rNY4?X^G zGM^~jlTm5%6+1rYbl)~GbR_@BxA(mGJjgw@YzOu`NnC}*^3$A&o=#bx+JW8lsVNKp>5F58EoBNT@p;$_6sH7603LDepk`@EXARJm z*MS=0#-hhj?vEe-(a|q|H=fEt(c=lwEdwV=-qRX@d^`xi6w%xLTNoP~YuCq+e|*}{ zdbJ_Vw*TK~kH!f-W2~Bz{=sY&jOR^1#N_I5LFnSI8q|rTI?tMGyRHODW{=K0f(r>l z<@|W8rdt8!*$pHxH~BudbTBq856Po3E)#nr~kNH^OF`YLD1W?jz)~ZJcie=`-HD9=WMrtk6R1GR$2z@ zY89;VO@M^=B5Q=1{^xlmk`xd_I@*A6uA+nlJhgNLI1kg+Fcj$B9kpZ#`rKcigp&&L z)QE!A4R|y_-ORZC7(=VrXB|n%iRin~;BvLx5Cw04b%B~UZVnw3=cC1@rSLauc?vsw zoBym4P5!9)js>hvF5t|;(#q3A(-rJsb6>9lFx+Nt#SZ5DdOvHdN(9{t8V!CH{f6Ev zSYJ3on|6FMxvE|>(C`i7{0>l|-2mCb3Q(>yp0BmvpRdCPSqi|U6B~|z#oYxGJ^s~D zYM8sl#T_ROpfU;r5&|btQLzj2?K@~DNNAec231*1WH)qRfF==uv@9(zj|zs6CQh!* za*72?!Yw!Muf0F*znPtC4j$hzI$iIDwv>=RY)eC@&kE4M>C#>O0fpD0i_jEi`Rt~k zxOg4dKP_1#G?R4%dXF6L=VmYw0=x9U7Zm*ZWxU=K1=>*_J?EnHl_i!SPq!MNF#{_? z@UXVoQ|muZX9=Pf7#>9MM8M_qZN#e80+C~I>du|Y{A<_KUOMEE4sGBR67zb&EGKao zqkxHWJrn>mVv@7X!8H&MUJ-qBxYm2FmGCUpHe3j@^C#2WK zJoCOVMp0~>MLiD!XZVLY;nhn*n!%FB4e3x}v+oB=g9&psJ_^`%GA=g?F`Nl3g9j~m z82@%hfH%vUl2`&yIz7iq`R~_F+tB3>{`QYddMI}v^%v zt|*i@vo!buI+KJWw>kN?K>5#C*u0;6N;_a`Z%`P-hUxmxj35j;L%7}sKaVtbSU=r> z@znnCmSgS=UzDjcd9LHXV61mHW&|G%5w;6bv-i1q&EP zA(2hL<%^DFy@dY13~hZJ`W3)m*Y>)Y0INOzY*;h{`UmZGuv-xaUKGLuO(y`p)7%~( zxdO>vnue}h5b#eV{pG+TgMXv~ea*L}LD8Z_YPffPvj{bD-G@8s&k7m5$^KdjZcgFu0z?3UW__&d~qkXIV!+4<%23tZNp!hSCHb zy8*oFC3Tr^dwN`YYG6(IXAe{yOy}lqTVHV*U5}cspk#cI(j)23Ra?6@=_-t`1GhAo zcGpF0du}|AC`4_&O8Mp`dAwSM`oCL{xjHxBPT@3Ff;7*6*UwRW9V72}ho$_V?jO)! zk_(yqm+^zKY#zO+X~5{~?{{1K#>;nq+yR1?6@=IHU1=&MReI@v zs&A6(nb6VwRAaLNb;LjinG)*K|j*`KW{>RwWYl&4ZEmyG7T9aYcStO2~T0sxO$DE z!&sX^4XSINzh=>$k(kG7c_oD01b7vww{tt&ytuxLdR*aAd>zl4Z*b#)&@!CaIoPU6R1vkgX<9+=2(cvzwN=1a&5R^6_+&I7M z5{s-aPvN1cXna5rJ2}A+N^gl#a4)RE*o&&hz%Mi!g}rL%Sd(?C{|Cb0r89z?8GqOM zKi&B}v0@6JzktCA39z24K3O>OP5{V~{QTnoniP1HUH$k$h1NmOcLh?UqjFw*Fe6am zRiua8F`rp+%KI*|P4!1U7b~50L1D7{aGnOMQ3uQ>vSM1xXRMOH+y19yZa*?5L+h1h z^Dnt*1!j8GE&9j~xgARY{g7O|ypE4ITNRF5N}$9zFqSJX`T%#Q39>Jr>ke{Pkavly zH9#eY!77WNi|k$lXwx&#QjXG6GPI{^<;{mh^U5Tqa2BM@`bLWpL_iqA_x7dD*NOEnN0GMaVuG+}a4CLzl zSuMfsP-ofGI%%54nx<3%%8Qe~b@~Aw2?Po6c6Ox6`SvL2ri9iUe}i&z?M_~bW{nML z3Xk{%<9<)z&ubmtZa1O7_Nm>4{6zAk>0voO7OLr7S(usZ*dIYfb{@rYTiw6tVjf24|KB1eixVf+^GcZGUgU&aT}9RIS4o6C0qd z*Xt&n0Bl9QACqWDadsaR8|hU0D_%Y^2h=-F!&PJYP|vzVMXhGLM1$ehZW*ht{w5(A0#|{*OZIvnUwof$@j|+zZfhn97B*os zJb*}9(3DSIqDQolLnB13&2|i8ngamFb^vUEp>PGwvvr%vmYNOD%zINM zN0U`hhXj_YE9h1P&0}@;?qIf8R}K8zD8PCa2B{S>P=J312WwNmLknz8h{E)cYo0bv zdVOKp785gh*`*X(yfSn>+1iO7>6!?9BY{)MGHfx@JWY4oTzO=P)Ky56x z{uGPqz4q0Dzxd#Yh9h_1iM*qox*}tx`-5ih3#pVZbTO?776z9QklDy@dykRN4oIZ@ z$AXSvMl`(~-W+qjq(!YUfw-u~{R0U-BDXZ>zqIS3K?7tusFws6s^#MeUG7&5bAXZw z*x*x`UFag`l!EN2x}J`uz8R>QaOc34A7atGkWDn9UiiK?(~$^WkK*?X`v zl&UXaj{fx*jHebQ$bmc>CJF%2k_LGNo(%QJB~!Cde>;Ty=MabvzPod1BXR0HNhR zef?6`sKfZ_ilcqHZ3e&i)wM2MGUW>6YTB7{Pt}8MICVfk$MrK`&Zh@!U7O}qm&Pqv zJ8{FQ4$uGL0+^vDG#-l`-kU0=4=*J?|Gu};kLhIzA6DQJcLg}A?yzqq5kn-Y-hB9g z`)}801eEy*9iZqD>{H!uON;KFp2)M*1%i&aeAZ+R3a@wvr4Cb7Hw)dFrB4ftcYCZM zMCYfVxL0?O{@mkWwnJAiW4O(}+cSFM^2o(o;|*r3_4It5E z$T#vb%VG9s#Bu^7R6Onnq&Sk)pvtZUp?D$SZ35^6Ote& zgWOF!UhDKGF%cC#Qkg%R2@5-nOwGH52KprG>h|~}y@?oSipHajSo*cl1o(=btrp)! zo0+#veSIPRoKn)#JSL~4u`!iJr=F{>32f|v*jM@X!^?=7Wt&U;#`hc3Zg)PLhL^P` zuU^$`vp_!4Gomi8l+TfFX{)z1Z|vWm8pGf*C;4=#ypFMsgSloOJ*ZapztD0t2vK^LEZ-Z6Mtlp_iPZZq>^*AK9Z_j)4z zO2dCPS+X}DaFl9qSGxmeHruykI`XMDN7Z_B=;EZ~+-lDqlp5+|3>;MVl=H1LSbDYM za`NIGV{Sgrt8>N=wVC8GT2m=W8p=l?a1UXDCKHjliWuk9Yu>< zEo?fFXRV`e*X;TBaZ;ZTWrrZ=Vcv*3W%&7cISOtZ{^oNM#4xoR!K>(1WZlDHQj3It zSHYk3K9V>W2E9>-tG+xkCFCB~SJhUa{!dTVxZ%6t&D&iDlT?&fT6JgHFGW*yg9%;i z{*E}3cu#CH8xFOFHY{cZ4p}P%i9L8Tc$>P;keH>g$_7HMYABzFxakZOU~C;&gd)4K z9h>+#L*|s)E^n+C^Gk#s8V1=DsEthmZx5>UZ0d4yl8+s9kA%+~b~(AIW50)yb1pHZ z1y<0PjGlEVdJ|*fDa8atP3xFgPjU!V71nxcwb3T0J?ANL>WDqGRkJe?;eLkQEbFNI zXZHO!ty-_E7#MFch!pGsbs%07n1iLf2-j3R=yRpr+rgHg?QRSnnF0Erj2!)NR34 z>8DMOqKI$bUwZWQvhxuk6VEN&k>yp9jB@h{u0EwpumZybSVQK9%B>xDtb_+9))r~? zM%gss_7{bCT*K-cY4}P z=&6TYpI0n(B=+IL;1~_r{!Jav2cx*NxSf}`v*vL9K zqh7l#!hnPO+r`p|pS%^>$z~=-@lo-*ZR?g#3OXKQ#v^R6NwXo{nK)G@oczIRu`%E9 zv2_}bI>z!5BZvErkr_vxzj$tpW3nKxbg6QVoDU-dPmBAD?!&~p6zfbW`K)@Lv~Xmk zk$DzAyy9*o!J}3cVg-kL5!8=j2-4oNen;n!;d)`-OmkQ+bPm-%`*@Q!tmipm3A(uo z#CQ03Eu0y0{<0Z^FX}t;^@4YBk73B+lYFsGZ<{0MjM~jc%MyjOFK#ZEA8qvLronqE z)@Tfiu^~sdHQ{~|ysDKa2H_vR^7krdMqn44%EZ?ZNVi6GSmjgjPIvy*uQn_~pX@g8 z@y~v?^@QqM;bZ4ZmQoTvCzsw;;6#t)L{Gp)K4#_|`zhp)(wmGM6|dX&x#BkC2I}ea zxDgjPlNPQc9B61*wT#J84y_*378My>H_gap6_64NHbUFH_0AzoGS+@t+X}#RYL~D? z&eyO8B&K6#dF|G7q! z<%_1m=KlZ*fkFGr%Ta8p&sNA3f*G;oH=GeTmrNA5oM!$mK3GwhSOgD@QlN}v^!bTJdsm(>VxJhOGex$C}uEGIg+8*O<^`THJejqcf2=9%7RWjwqI z{HB!f=I$6ax*`3ibHimWe!V~?_{f-HS%q!Bp3JfIt|(SkeY3HxaAQswX+<5ru5G=-3cI2$ywcSHR1VCHDfgSt%q>bi)}_b zU{F))D2H_Avms*fa~@K3-zkGmRouQ^G+%f$hOc6D@Wvg*i8|g2N}}d>PR~DoYOFLs z+Vcp{y>C%{!=R8Ppb_!u?bp*Ezu?BiltaE|Xu%RJU#IHZ79$~qxe_2bkHK$zFQ$Om zd2}eIMT)6GlxAnHbr*RiuEw~JoXM1V1H*|n_wl(7GOeGFe_Esb|! zHHv}>t9QmLp;==IV229LE3DVM$vW;$=a=L;Q<%E?7hj>>s45@Kw;pN^;r-7B&>I0k z*eRT^w>2D-+~mFF-5-wqXTC5*mm>?T=p$4iU!Qp?G3&yMMEvoJ<$g;R6m+;DoYPAzR6suld7yzdS`uv^jxW%3YVnKfsZ=Q`WU3M zt0!!9TgY$>VrHd%zQ|}<%~p6$a5s8<=+~|FuQl`6y+ta0gGC_{N66_|-*GIk3hO9; z{Y*}-q=_yh_w4=t^G&+{kv}DjNeH>{%nSSAuZOY?J40l&e;?s*5vPXeeO^s}og^vl zfVsjC*S=GE7(az!d`J5F4^kiTfJ%qBo29(e3YzjVS=9E7MgJ~#D~>Eo5O9)Fi8MRd zTQqgW;rhydBU=lcF9IHA_cfiF6Nax%UA*i9j+*>y8&&%l1;kPK=){q-qLOmA666=Pk+QuafV|U|OcYC{7cS@MKgjpF zXU8*^a$JOBX6sc=G0FLID;rGHoo&b76dONI)tcB1ck>KyGR}v=R;4*HRGvRHaeCyU zZ`o4%Ld25A9bcnO5dC#=qq%|c%s*#@OCTJL{_Lsak8DSwrr*fmDPTnA9DuPApsE!o z5X10TlgMT#>-FY|)?M{xWanFPsLVBt(u>9hjVo2JXCIwJNNvWF_kXt?GN91fW<7fF zXb@@*8F+Tlq!Mb)S3fWuGpJwPV7*H6l5qioYbhG-Z*kF5BB}pG43e@>K~NFDV?kYl z*%26SdwnkH$n?SnL*=PaJg31P^Kv!>&wXvtC<|%4nC2(^k@tM&rN(JS_pvRo$0fLq zJ1z(A1F%7aqP@E~-S16D{ADBBWnkd(=5tnmV7Jj0|8b)IX5moKT8vN|Zaa;;EnTiI zA;y_)*d9Wd@CRigKVX>MN6a(OodFsR@1=dgeN3XBIz)X=&{~6lPg5cF-@>AJ{lD0^RH;fjwN1> z;NL&Mq7p2;I2IdAKyf-o^ZzLPWt|$s%P@~vh8c#(6PYV$kM53aum_0ql58qokh%9hf;Z(lCux~LV z)a0D}*<=phsJ%0m$(P(yz~y=VK5N8|m^lZ@qSr~oa99YPDCdKRin-l<^jiU?v8Kh%!&D?Kho;d57&8dIL)`pWuxmqA_gA8R{A~;M+m)>kH_Wb%%-4;2lM-Cwc$q!N`AR#>QmnN|dPG*_>S^mbDikG{318!3sPkZCxE`M%%4JSWA89 ztj??V4aw8}rIKR-#6($-ML`ewo<+c00<*+ch+9HzExWmf%}u#fc_sXyr1bo&8~Yk- z;0sd4y1_n(Eiq;*X&B0@6YNzuIxym$V3!^KM$kG?T?<2hR7O7VNvQUloMg=Y;)?6cF(zcG~tC6UL6K&pT|KDuQ!a z<~X1E^o^_9Cy&30d&A8)K9Cban~9p(x*(e!<1o^@wd`Am`Dhau(@awWhkaeat$>Si z33HQG&fWUFDlI(cUJ(hGByQa4g#daXdFvlbEw+e)%w~p_2?XS2mX{eDTt@-&U)APJnmvBcUT$zQk~~ z*+q}sic~~|??|s_jB!)Ns0UN@w^9xJLr+F)u}bs;orQa-f6=Dl1pthT7YT2k`YylIl~ z$46qc`~EjDDA8Nk+s}BHPH|w4SiGOr2!6{BKFm7d%D%8WYQN1O`q}XD#7T*g&Mp}S z@scP&RuWx3y5NuEOOa@pw{n??iU@qx19`z*?&e5*d7s;4U@}bJjJJjmq6gVoHQ1=RNpPkj=V9W3LHeuGis^?Inw-|IoZVnR5^V5^Zb0ke z^O-s^n~~p+6UB9Es7oRtZb@n7c%vS|ULVg(W35GHdqg7T>^Hc_8vb8&wlB>U<=kC; zQ&*%X5$PO;{c}BjV2k+vP`Y8NxW{p99p4tB8O0V4ou-+=rm~kAqg&my!fp}(psj1b zP5A!0BA0i?*`%^SHox~%Mrclcoc_+Cq&ZQtYL0Q*k47rY4E2N?dO3Vdqx)t|nb&9R zl~&mINSWaasP0%jzlXv0nx=$=vV|E*rf9Vozc5-iY)^I|jX$zQ6{WCijoOX9zC>15 zwmo~p7m|g}@C2iZ5Fw=>aLes|?gtHe{-d7arXR4*NSdUubLS98KDQR$#-YC?$}nlO zE_Q-4RD{i??j|24v!dj#2{{$mdxp;yR6Ik(u< zEQ%7kEM|%0VCgEHL%Oqp0ItHlQ!9aczCE$pOtOgIN_y1=LXh~yn@BSS_%&z&i zzXw@@zIgt)s;%d@`NmcvI!~D-uJ9tnLSKHIZwF$wZZaB5nRm*hEo_F+h2#HAFPuPn zfhr}B-TX1+TM4g%9!v?mUiAcr!@YwiBBx0PX3MbuTvYF-Ke;}KhwNv8I^!*Q#rUh6 zmJ;e^?oreB7G$%FnmjmWt7f9m#x&f%GN$XgP^#vYmtv#xf@rNg9UC;#iv~sP2Io^Q zm5lx6t1^Rd=#8}UcAo;gy)Z0Mcpz--7b)M&ynC3?dHRKBXO!rg;KDOw5k+v7>KoJA z_P>!?jhn%$Qf7~#HX%nO-ym=6ij9xJ!3sRI1)Z77UQ^%M@vv)Jmg{zu#d-!~%iU68 zsHeXd6_s$4n!5GV*wt-DT)>w;yslNb`Sa6uA08E&3OMP3r*BVYs7M==%LjlMJK`c7~rBY19)#WBps~Ui}$j0me%=3SZ-PbUx_6Yr|UnLe!WsW{} zzPDx@N|z`h2+|!#r9?`kyX4R)B}l3$A*Gx2S+x=W+pQEHErG~jl8DbD347x5*F;WDRvAq8-7~qYD*axL{(K$rn&|>bIdZ+i zrJsXL3xs7?KBt?1TRB8w^=oC}%lTo6)LX>{PefMN$Ve%v*b}B~?~59{%kFY0%8|Es zvIoD(hc^-XG^=>xbaE#-IP>Z20{%j9bFl|k}2}-i}&A|OgL#E4tT{+dfQ@6 zn0V`wsQjvCVBfU<--^1)c|KWkt3G4J4kEuFKxnoHeOLlPl46>k&My@3g(-)_qauZC>ve}=4xHO91tAr9-+?t zdNZ#_wtOXMa^9bGljGvH9+@zs5gAvvr{}kG=}&}com!U1>VjURbJK)Yy64Fz30?6X z4`j{vU)^%?uHv|pjqYiCic zc=G@+@F>mEX&)!+Hos;9L^H?u^<5?y=NpoNSyUgaepS4n!acWUkSJ^16L5W!L#Fl5 z7LG2~RY*NAa3)txt=s-tIXY*5r>$^OhLdY4F~L$>Fr>Oi?Mb?E&&Gr_@9}hla&hhp zfgI?0tBMC&}nv9Gw=)H&HMRS(24e8jo;c9pw--`2{ROkRc<1U9@!K7Q!< zEc>;RA2Wz1a%22SEA=7rtpVtAjRk}`hB-L48Y2tOC-70Q=%Za zN6e`TUi`uiV03x@ZTE9{sn_*#ud)id=1VK9HqV|Yv*URVDLl31QNg8a!u&FleLzV0 zEZ4#cCq+zjhT`7&`#nTW^_tF4&fO1qOy8!2ZMy4^K1^JY;r`*zG9nlnLLVTNlAfAp zr(OM*2UR!Q9NSG+ayM~=>CX3{p$UeRL@%a89IWUpcb_(|`K9FST+0#d#Gw7_DAF7s zi8PveMJkS%y|BG!2_#%w+nsrr1%A4(;nw@>JVYH3Q^q9z{F)c0AKt$}oEGntRIh&c5y8_zIJW&{K^Owf@oG$AJERZG-7Mb#PZcgz2b7qlr#%YHJ-+Lfw zL_Q{N@`b(k2mM_6o1^1dO!AJzq=w@h_R1rkM^tvNKTIe%XfmW;Aw4>?eR2O>2U};r z+ZN9(qY~A2|5Ua6-jj@~MmO(QDWgjKYAj96l3s1O?YA3D5PA2>SNFjKAU=YC>N}m= ztw~af(PE2T(zm`nfKk=7WOIiu^{oq~e`YBWETi-zLtVyZ4BDA35At|Zz0@$PAQjVP zv@eOp%T`Jl-7~yonqa~eY*w;-qsQ8X@b#?UO5LAE0iztX21P5AE{u0gi-YA#Cl=G7 z#{RKzBFz!%$;2X6ncX+@)EH+85A#&3&!I29I|FzxR*MUcX|-?moRE}R3|U#bc{C4m zqAjoRQm~TpM*EnZw11#;IsMTOkR2h8ugGp-%_cH85-&DJz3CK!AQ{8!RhY``TyQZm zaEi`Ch28&@E%g)k=~|SL8*|#yq>$?um5h)zaRwIx*hC8hd7&l z*3&4?XEbRc4-1QCN?QDZazCwfG=Wv^bfdmYwf|Z#KDE>Z%?IRI%{G&xL#Z;`?X_su z>4NnbA(!{~(^c)UaJJZWtrS;!`_vU`M$@@H%%csueH*j>{_|44S7Pw#rhADH6}*W< zJM{~uP|;wz3w638#7BbT6)q9-1ur4t&BF+f;LW-p$}e!83$?rgPNQm{!jcYchv@2e z1Q{|)whlbDOM@IGj;rn!Am<2csw?IO5m8r$R^f)uRoZKTbZ#6_(jyD_&XMn|nOU;6ZOChf-Q zFM;y~2!&4{15RYlavfuU2-LTi`Oc@!lp7)I$TFC{AEAb?<|GJW~6=znB#yGsK#2+(JCp9!cSzZbrTeRYtGUKM^d4(z#ig z0^#QHkAjEc+C=rF161-S6&3Mg<~>e!Jfvl0riU%Eta8#%tN1p%Wy*kwY&o2Vlh)S^ z-(^!eW@W>SlfpBN%??kNJkP3I#{WC%W2a%=MSYNnUmD8whSHu~;C!H4zf}W^xHVMI zedw9SYS{)J)RfT#iENWXdG0juFHE4i{`1$b^#|P7R4wW+>UaKlpg7P06@=s+7{)yH z?3Bz*ba%Y8X;}SmzQs_H&21>}gnFuLm(GR#^Tc86Zvq{b2bW(yRZ{A3)V85{`jP!>93kZL+4X0|?7& zMmhs3y1GDYNlDVI{7ZG;qG3L}fm#Wk_|+(8nEVPwXVicjpM0x1=Nf1;$Crjn49looDXBK_s_XYSN_isxl9p!kx)$;sIZ zLqTZbDRe9j(!hH{e-Uh}V(`@2ad9Z_=q8&NJRioh(m zf_ho3ZQh@*(QKZ7`T;0M;}!fmvaAXvx0O)Etdx?HV!pdJX+BosU~=#mr)zFTUXNlA zAyDJHuVFLDM+`2xLmjj6!S?bfu)yS2>=rs{A3uH^+uYpR`mEN6&~-eo5-_rihC*D9mcP#B zmSZJ6sVtt=Rkgm?XZHnUGRUF@;p=X*u?2~`?Y}^1XHcxk-zS>QLqrkO;F)Mf2PwXcBa^h%b z+@$UU5kl`r*bGqO>0LMumDy0E{0T8#^FC&T+5@DLFyWQ2tXf#=MK5UU>gpyNSl6qt z@qfZS;oW+ue3vyaFo-ic0;8DE?GQ!yNOQpPo=Ob2HUyGRcfO=HyX<`FSt^8O(+2m` z+`O;}i_4~oK9t?OH<@9FiHYgV52!p+Tr9Q!bL}^SW@i30c6DMT7rOO_My=Geh}1H4xJLicesPbUKL4 zZRG+9O*P9S)?#@V%b%3vEmC%UczF0C1jAue{}U>LyL)=39hh;FiU+kF`c%Ns5mr-_ z>tE^5PlchTeW66&#>S@g@6527P6ic?Da}B87>~tZw$VjzJgQi@ITmz+pui>P_5qay zcFRHbo8KrafGjoX3{viX&}d~1xS137f=qYroaz7|{JFPH+Pb>BAr1K>%UFY!yta0B zTH1P{EpYLVt&@2?0znQ##vQqQeXY)gNI8Vt;JItjxj-|@e9=9Srk0f~o(HcdD`GCJ0JFQyWLKqQiCF$wu$wteA+1NS*WbFF)d+kK1@rQKRrqK0s;a{P85AF8bg!wb&R^Y=COIAvfH{ksK z%kdGc&Fi_c#V<7#gr}~{xKzAsMcefn$@R4JKWZCdC&j&!5Zk}!TJc=Pt7Z0=DR+*; zV!vdDLw9#~dvV~yyz_g4Z0(uFbL0qd2UuS^1P%MWk++2FY8xUK{Gwb;!cO$I3 z)bTmkm_{yI&PfMKEupa65a?JoLZRX}f_7_>*hfBElUG~)S8btCZCe}(2?>a(-Ve9|I}FrKF5poP#&W_4cn(%SLqc<7pM|EGIx8g^67AxqwT%OTD!n6wm_<}~=i zwBh05qW<#R`~$l{THR{VJAUd0E*t~)Yrci)GhgV8N%c56ZeD)bP=4%tk5g1POAVZ* zLI4?;q}6bq^fH)<2oM|}_i%4@cpP&bM&Mj$NQQk+;BXh*psKXAGzKUaYU8dO0bxRp znK?t2ig7Kzxjp3T#Zd07Vqg#>Xut4rxX30BD3GzuO-+hm!dC90zVVYTBM3)s3kZKH zM+ZA;Anu|Bjc8Ip*@X=wV7r_b+3%yEr7HwXB1ItksOh=y8TWR8#zo&pTCrYW_w@oN ztq-_wy&yb7#-oW&SCrHP?&g|L_+zH6kmy74t(7sY44qQd< z%FxJ_gcT|VEkNYpIV9?)!3n8AO!rjgD~lqmaAmN(rwXEb@tWC&5_ijEAJ&F)uUax5 z?+;XVXK3+(PR2~1OCX+63PK2oWI!d5sY!v* zd%^P!Fn$oytw&l8!qx*#nR`G@6@B~hhvC>5AXyfYRpbeEh#s(jf({P;tvrL83$O{bJLbPDx+%RO z|L+up)7bMg!GJm+cIo}oT;v_WtvAx$jQ@I#BO5IG@2me?&I4z1|ChN7a_gSG%=<30 zFH6^*%jZkUPqQ1Uw{?cJ0s?!kYGOX`=%n>HIubF|HBANDsUD>x=v*2gBTjE0%iU>Wg7Q z4Rcd8+361*I&T;Bu^t3yF4!DNj*+tP6WCyRm})#<6Y4KnuuANFE*59yV0_^g^H>p! zSlrQKGj46NC(7_---u6beqle~^`z0t>)V!J`t;Ds>hn2=KyAD{{gXM}gECw7(%l&?880Eu&Zu5hU))3&)H& zb-0l9xQ4aR$TT-gE>ED&&Y+ld(-q(z!aVz6OYet$I@epiT>E(6klu(@V?eum0Nvob zD{I&trlGd;ospB)yy%{-RytkGWXV^CC#=%C?Ju>`kHTauHN!S}9V2qb`hRzz3^n@P z=B#-Cq@9TMEcPo_wkwPYiuJ|-=+=`ilJ}$j-u>w1Nz6S^C~?8oZ1Vm+=FK8eQ)g41o3}n5 zcji!EmVM@dqGFv}T{!aHr(y}|w1K9hyF#i|m?#p(`OX~FRFL#@<@rXdHx~{T2uH#e zEl7Q`GbXE8wu~L(-)L_Ve%+;WH5wc0TIV|aMW6?*#lQs(vRi_y^pHYz*5 zcm9fbvGoVS@)i66$sG%E%U-4z0gklN<47P~`z}5F7Ezv>`e9|PR7qJ`TvD=rFEh~e zjPKBUi7AK4Pv3N$=+Gozo$6&6Oh|6ILmGEII3$Ga8();aKklB?t2c0kI-M>FHGDwI z@TI{gCvaw;-e~_%PN{V_P45V!HeY&eYKbgBvOb6=sELl%f$he%+$(;yi@$Djl&(E$ zy~lEmjrN`}=SRPP`#7`TO#e@gZMpVtR@twKYR{UG$UsVgU=Tqdcn!M@!hZS~9j);A z@nsR`%?V)HC+6hj)Xk0qOAv&Jcg_Q;+1OaLN3TvLBwFp z^7~^ZWRov>xeQ6}WrQyZ*Q|?v!HdbCp554UT8Qy3TFPnpshKe|JImp+Z3zfj7jaS# zZS6FM_J5v1H#Fes*cH%Ebz*=4hvTjIdD9L>8g8CF;E@ThvkO|$Z*fqR-<;or=ElVBtL`Yk# z>{Wg5Qm>alKBx`}k{>avA&@CYA(}yiKTLqpk6e*a{OyePtJyCs+C?8>tPpXJn9qg~ zmoJq3e)hfcU~JXtPeP~@M2JJ6`lXuor746FL}W%Vd4S9`q$MVL0htw&s&K;SBjm!4xD}<0veLc&*tm`wj@)SdujaQYn$>*nb)> zwoAhN3#XV;R3Ws@8dKOw*U|bGf;W#&|4BC=A8=M*+O#>iSjwa zZHNh^&X}JZA8{03JbUI#cz7BjJhLX~T@w==9NY_(=IN*7fh*cmL@gjNMDznJsasR! z#??H@R?UN4DPdHlKLwxs7=#!$Ojs%Sv@rH~FC9;J^b3Y&<0P_N%`|&}2v&9UuP=P(!Z) zV>BAFy-T7HQy2A>-!>0$s(Y%T;hShSXbB!Q^T(DUFAxa5aLH^{qeVb3Z|ht37%;e@ zk=j*MKeya5-{o~y>F$9*q!C+Q9yg3g(PC!lDJh=+g?`)-OibNrl*m`5?tU;bZpit) z2xe$nWfm`s$4FIE^Fzz*6sR$w0l095@M#oa##Yd*gP^}*gImzQzoH(*k&GdIc?2uz zr#cJhD!oTRE{JG^=q7beMlhj04yS1VKfKM#8URc9qe_~pLAJW#SCywv&)yHcrxV-n z_@|q`OfCZCg4M(zmh+}|_R+E~e(&$^?-cpayJwhV1ai%=#C(hie(4w@rIYrBQQX_U z;yKR;XX+p+$chx)fU=B%=vEctIt(nNz~Q8voTpc5M78BW=;>AYZ-$nASZd1feZ4>% zsacGFWdgX+H!767_8AOlT={CEK=ffNj^^mjy{%PKO)g!?3V`364AYtn@J||O=AbaM zp?a!jW@hGnsVeKj0eG{r8~_!XgT9G5U@YbkS)XP|1qHll4GKPM<=28XQ{uh*2yQp# zy3uAM5)>HAGfmXAxRnZMOe#>rAF68feXZEY$Lms-ZnMOqhXjd`3LF|)BLAaLPijdvOtW@MkmU2&IN z(t1KKLC+@{$OG^Z|XLGjVq`j zPL?5LzwNpE_59=Ni!{oB>V1%L6DqOuRg;qo;0$jw2XIYs5%AvjWPIUR2OfV7I`|Mk zw0)onMr3#J2K(ZT9~D5pPu_wkUImah$Fu>J2(2;<#7z#MwwVTST^a=Sb#Y<0eihd) zy(iJV#AuW)>QV+GROX=1bDE|C$i$37>9vLPv1xC^UXTo_gtCoIHuJrEc#Q8pN$Z)J zrJU^r2uTHbla*EFaX!l*Xz&?@>5B8#EO*X_Z6K=`wvr^k!Qz4|q7P>n0hCk3geZtA z9_*~DbqH_xgZqC9NS8<{iL%ej*gx&eQ)O4qodxM5ENIw?h-t#c0ewFY{o@1x9J`x3 zez^)}^*fIR@yV9n2~nY-qdkn7U)`^t1~r4ZCJMd#IU9>|nVFyW-dXNTBMCx* zq`;U139?qR)mh-wCDx1_@Nl{Q4(mc}{oJ9ju`JsE0_2JiUh7* zR3zXH0@n>L@&GL4kOPrhLL3h~3E%#_DQ|dFTU&s050Ob$zR`s>z+TxQcLhm_7RSm1 z9o0|Y{86O|t3B%o=rPl!vdNoLzc!(sT>4e7ljog52? zIuYScwM$+U)(B=do01eYg{T#wP|@@Je;1$XeCkk>Zhr=qQ4eqG(Vg>-`JurAk zpJGVUGm$I$wOb*?sfHG%h-O4eax#KiBZ4t7Xyf)PqXOEJHQz*bCp?wa)VLg1v?=i} zLI{Qi+=P<^eb;o^3H-0H@VxO@;Ip5mQ5PsPdYdgA&VzpdgRti2#|6*FskcHxLOeU> zr(vg=gV48ZZ!R1OOcgs8VU^wsMey?%m|iB>1P#BAr>U{Q@r{_YG!6iPh>Fh}5Da?@ zg1w$@2ixm|MnTyS2&~xwM2aX-zM6P*5z%b`WvdwoZ-OwPBKlQW*5zBO=#Hp12;T(k z7YM);&LP%-KrNKIOtiyr)_aN>#P5ZO}h-H;3* zuhVfHtAj%+z=;l594q}ajuH3rJ4AOGPB6hnyFO%nB(PElbG-Zy qN&=~)(Esr$_y04}^4~z5BM)URudgw^Ja4ezPg+7=JoBOc+y4MHKUYZr literal 0 HcmV?d00001 diff --git a/eqcorrscan/doc/plots/mapplot_sequence.png b/eqcorrscan/doc/plots/mapplot_sequence.png new file mode 100644 index 0000000000000000000000000000000000000000..59bf6b8d968355f7f3772d49b4359fd530649bb9 GIT binary patch literal 75286 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≪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%0D?B0`V}cyT0PPN4BTqW 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 z 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 vZ&STd0NADcO;_?s*{820Mn3 Date: Sun, 29 Dec 2019 22:39:55 +0330 Subject: [PATCH 003/132] withe new change --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index b8395ceef..1412a3c13 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,6 @@ * Some problem solved in _match_filter_plot. Now it shows all new detections. * Add plotdir to eqcorrscan.core.lag_calc.lag_calc function to save the images. +* The new function with the name mapplot for plotting seismicity added (#365). ## 0.4.0 * Change resampling to use pyFFTW backend for FFT's. This is an attempt to alleviate issue related to large-prime length transforms. This requires an From 1c86f429180533052625b2d543dcef7612b0b9bf Mon Sep 17 00:00:00 2001 From: iman kahbasi Date: Sun, 29 Dec 2019 22:59:47 +0330 Subject: [PATCH 004/132] the additional_docstring added before mapplot functions --- eqcorrscan/utils/plotting.py | 1 + 1 file changed, 1 insertion(+) diff --git a/eqcorrscan/utils/plotting.py b/eqcorrscan/utils/plotting.py index cbba85d34..a8620f001 100644 --- a/eqcorrscan/utils/plotting.py +++ b/eqcorrscan/utils/plotting.py @@ -2186,6 +2186,7 @@ def subspace_fc_plot(detector, stachans, **kwargs): return fig +@additional_docstring(plotting_kwargs=plotting_kwargs) def mapplot(events, bgcolor='#909090', mode='3bode', cpalette='jet_r', s=1, lw=1, marker=',', **kwargs): """ From c0a89cede026dd7169bbee9069e5f4f723f51d01 Mon Sep 17 00:00:00 2001 From: iman kahbasi Date: Mon, 30 Dec 2019 13:06:04 +0330 Subject: [PATCH 005/132] Test and a catalog added for testing mapplot --- eqcorrscan/tests/plotting_test.py | 69 ++- eqcorrscan/tests/test_data/catalog.txt | 573 +++++++++++++++++++++++++ eqcorrscan/utils/plotting.py | 16 +- 3 files changed, 648 insertions(+), 10 deletions(-) create mode 100644 eqcorrscan/tests/test_data/catalog.txt diff --git a/eqcorrscan/tests/plotting_test.py b/eqcorrscan/tests/plotting_test.py index b41768165..bff1357f7 100644 --- a/eqcorrscan/tests/plotting_test.py +++ b/eqcorrscan/tests/plotting_test.py @@ -10,20 +10,85 @@ from obspy import read, read_events, UTCDateTime, Catalog, Stream, Trace from obspy.io.nordic.core import readwavename -from obspy.signal import filter from eqcorrscan.utils.plotting import ( chunk_data, xcorr_plot, triple_plot, peaks_plot, cumulative_detections, threeD_gridplot, multi_event_singlechan, detection_multiplot, interev_mag, obspy_3d_plot, noise_plot, pretty_template_plot, plot_repicked, svd_plot, plot_synth_real, - freq_mag, spec_trace, subspace_detector_plot, subspace_fc_plot) + freq_mag, spec_trace, subspace_detector_plot, subspace_fc_plot, + mapplot) from eqcorrscan.utils.stacking import align_traces from eqcorrscan.utils import findpeaks from eqcorrscan.core.match_filter import normxcorr2 from eqcorrscan.core import template_gen, subspace +class SeimicityPlottingMethods(unittest.TestCase): + @classmethod + def setUpClass(cls): + sfiles = glob.glob(os.path.join( + os.path.dirname(os.path.abspath(__file__)), + 'test_data/REA/TEST_/*.S??????')) + cls.catalog = Catalog() + for sfile in sfiles: + cls.catalog += read_events(sfile) + cls.nodes = [] + data = np.genfromtxt("./catalog.txt") + lon = data[:, 0] + lat = data[:, 1] + dep = data[:, 2] * -1 + sec = data[:, -1].astype(str) + mint = data[:, -2].astype(int).astype(str) + hour = data[:, -3].astype(int).astype(str) + day = data[:, -4].astype(int).astype(str) + month = data[:, -5].astype(int).astype(str) + year = data[:, -6].astype(int).astype(str) + Date = [] + for ii in range(len(year)): + date = '{}-{}-{}T{}:{}:{}'.format( + year[ii], month[ii], day[ii], hour[ii], mint[ii], sec[ii]) + Date.append(UTCDateTime(date)) + for Lat, Lon, Dep, time in zip(lat, lon, dep, Date): + cls.nodes.append((Lat, Lon, Dep, time)) + + @pytest.mark.mpl_image_compare + def test_mapplot_depth_catalog(self): + fig = mapplot(self.catalog, method='depth', show=False, + return_figure=True) + return fig + + @pytest.mark.mpl_image_compare + def test_mapplot_time_catalog(self): + fig = mapplot(self.catalog, method='time', show=False, + return_figure=True) + return fig + + @pytest.mark.mpl_image_compare + def test_mapplot_sequence_catalog(self): + fig = mapplot(self.catalog, method='sequence', show=False, + return_figure=True) + return fig + + @pytest.mark.mpl_image_compare + def test_mapplot_depth_nodes(self): + fig = mapplot(self.nodes, method='depth', show=False, + return_figure=True) + return fig + + @pytest.mark.mpl_image_compare + def test_mapplot_time_nodes(self): + fig = mapplot(self.nodes, method='time', show=False, + return_figure=True) + return fig + + @pytest.mark.mpl_image_compare + def test_mapplot_sequence_nodes(self): + fig = mapplot(self.nodes, method='sequence', show=False, + return_figure=True) + return fig + + class MultiStreamMethods(unittest.TestCase): @classmethod def setUpClass(cls): diff --git a/eqcorrscan/tests/test_data/catalog.txt b/eqcorrscan/tests/test_data/catalog.txt new file mode 100644 index 000000000..d7d423754 --- /dev/null +++ b/eqcorrscan/tests/test_data/catalog.txt @@ -0,0 +1,573 @@ + 47.708 32.737 9.1 0.0 7 5 3.0 166 0.176 0.6 0.6 2014 09 15 00 31 41.45 + 47.660 32.739 8.6 0.0 10 5 2.0 128 0.205 0.4 0.6 2014 09 15 00 43 46.67 + 47.654 32.734 9.2 0.0 10 5 2.0 106 0.258 0.4 0.6 2014 09 15 00 46 28.18 + 47.625 32.713 7.4 0.0 7 4 5.0 131 0.151 0.4 0.8 2014 09 15 00 48 44.38 + 47.718 32.745 9.2 0.0 9 5 4.0 176 0.200 0.4 0.6 2014 09 15 00 58 33.25 + 47.531 32.722 12.4 0.0 12 6 14.0 103 0.132 0.3 1.0 2014 09 15 01 04 57.58 + 47.711 32.733 9.7 0.0 11 6 3.0 166 0.183 0.4 0.4 2014 09 15 03 01 04.07 + 47.807 32.788 14.4 0.0 6 4 14.0 243 0.524 2.3 3.0 2014 09 15 03 12 35.41 + 47.548 32.760 9.4 0.0 10 6 12.0 92 0.139 0.3 1.1 2014 09 15 05 48 47.28 + 47.561 32.757 10.8 0.0 7 4 11.0 126 0.147 0.8 1.9 2014 09 15 05 50 05.36 + 47.647 32.743 6.4 0.0 10 5 15.0 136 0.072 0.4 2.3 2014 09 15 06 07 35.76 + 47.635 32.775 20.6 0.0 7 4 6.0 149 0.524 0.9 0.9 2014 09 15 07 32 21.20 + 47.539 32.718 10.3 0.0 12 6 13.0 105 0.256 0.3 1.1 2014 09 15 08 32 31.23 + 47.534 32.722 10.8 0.0 11 6 13.0 103 0.219 0.3 1.2 2014 09 15 08 34 48.02 + 47.778 32.688 10.1 0.0 5 4 5.0 186 0.057 1.6 1.4 2014 09 15 09 03 54.87 + 47.419 32.712 13.8 0.0 12 6 14.0 117 0.115 0.3 1.0 2014 09 15 09 43 08.93 + 47.417 32.713 12.4 0.0 10 6 14.0 119 0.175 0.4 1.2 2014 09 15 10 15 18.99 + 47.419 32.708 14.2 0.0 6 6 19.0 194 0.041 0.6 1.3 2014 09 15 10 20 55.80 + 47.421 32.712 10.6 0.0 8 6 14.0 117 0.095 0.4 2.2 2014 09 15 10 21 35.52 + 47.846 32.721 7.9 0.0 9 5 9.0 258 0.437 0.8 1.0 2014 09 15 10 41 27.23 + 47.408 32.714 16.0 0.0 11 6 13.0 122 0.180 0.4 0.9 2014 09 15 11 20 03.66 + 47.420 32.713 10.7 0.0 12 6 14.0 118 0.173 0.4 1.4 2014 09 15 11 28 24.70 + 47.419 32.710 13.5 0.0 11 6 14.0 117 0.131 0.3 1.2 2014 09 15 13 28 12.60 + 47.776 32.700 10.9 0.0 9 5 10.0 281 0.140 0.7 1.1 2014 09 15 17 59 51.23 + 47.785 32.691 9.1 0.0 10 5 5.0 195 0.158 0.7 0.5 2014 09 15 17 59 51.28 + 47.657 32.686 9.9 0.0 10 5 6.0 129 0.095 0.3 0.7 2014 09 15 20 26 53.35 + 47.563 32.756 12.9 0.0 10 6 11.0 94 0.174 0.3 0.9 2014 09 15 20 27 29.49 + 47.773 32.669 10.8 0.0 8 4 4.0 184 0.106 1.7 0.7 2014 09 15 20 45 04.95 + 47.580 32.748 8.8 0.0 7 4 9.0 116 0.423 0.5 1.4 2014 09 15 21 00 07.61 + 47.586 32.796 13.8 0.0 6 5 9.0 110 0.532 0.6 1.2 2014 09 15 21 02 36.91 + 47.814 32.719 8.1 0.0 7 5 8.0 234 0.138 0.6 1.3 2014 09 15 21 44 51.09 + 47.516 32.724 12.6 0.0 10 5 15.0 154 0.151 0.4 1.2 2014 09 15 22 48 52.00 + 47.414 32.706 19.7 0.0 10 6 13.0 116 0.365 0.4 0.9 2014 09 15 23 45 19.09 + 47.362 32.727 21.0 0.0 8 6 9.0 148 0.580 0.7 1.0 2014 09 16 01 42 42.85 + 47.724 32.675 0.0 0.0 5 4 8.0 144 0.217 0.8 1.0 2014 09 16 05 22 27.92 + 47.578 32.784 8.6 0.0 10 6 11.0 102 0.105 0.4 1.1 2014 09 16 09 05 42.74 + 47.580 32.781 12.7 0.0 7 5 11.0 128 0.290 0.7 1.2 2014 09 16 09 05 53.92 + 47.642 32.671 13.3 0.0 11 6 8.0 138 0.199 0.4 0.8 2014 09 16 14 28 11.81 + 47.608 32.664 14.1 0.0 4 6 10.0 193 0.001 1.4 2.4 2014 09 16 15 27 52.24 + 47.777 32.671 10.8 0.0 10 6 3.0 165 0.190 0.5 0.6 2014 09 16 15 29 37.25 + 47.786 32.694 9.1 0.0 7 5 5.0 198 0.169 0.5 0.6 2014 09 16 15 31 00.88 + 47.817 32.661 14.4 0.0 9 5 2.0 263 0.234 0.6 0.6 2014 09 16 15 31 32.80 + 47.819 32.796 1.3 0.0 6 4 15.0 250 0.175 1.1 1.1 2014 09 16 16 07 57.78 + 47.813 32.725 7.5 0.0 10 6 8.0 234 0.294 0.5 0.9 2014 09 16 20 32 23.59 + 47.828 32.738 1.1 0.0 7 5 10.0 245 0.219 1.0 1.5 2014 09 16 20 34 10.57 + 47.850 32.725 14.5 0.0 7 5 9.0 260 0.359 0.8 0.9 2014 09 16 20 35 23.92 + 47.813 32.715 10.4 0.0 9 6 7.0 233 0.157 0.6 0.7 2014 09 16 20 49 00.17 + 47.793 32.698 10.9 0.0 7 5 5.0 209 0.063 0.8 0.8 2014 09 16 20 51 37.85 + 47.825 32.656 8.7 0.0 5 4 2.0 290 0.630 1.4 1.0 2014 09 16 20 57 19.48 + 47.812 32.725 7.5 0.0 10 6 8.0 233 0.281 0.5 0.9 2014 09 16 21 07 34.01 + 47.818 32.713 11.0 0.0 8 5 7.0 237 0.175 0.6 0.8 2014 09 16 21 08 34.24 + 47.808 32.710 9.3 0.0 6 6 7.0 227 0.023 0.6 0.6 2014 09 16 21 17 27.53 + 47.590 32.803 7.9 0.0 9 5 8.0 116 0.149 0.4 1.3 2014 09 16 21 42 37.97 + 47.590 32.802 7.5 0.0 8 5 8.0 115 0.159 0.4 1.5 2014 09 16 21 42 49.42 + 47.806 32.711 10.4 0.0 7 4 7.0 226 0.223 0.8 0.9 2014 09 16 21 59 08.48 + 47.606 32.663 17.1 0.0 10 6 10.0 140 0.149 0.4 1.1 2014 09 16 22 53 11.24 + 47.759 32.656 13.1 0.0 6 5 4.0 177 0.202 1.1 1.1 2014 09 17 02 28 19.22 + 47.781 32.770 14.3 0.0 5 4 11.0 224 0.002 1.7 1.8 2014 09 17 04 48 18.96 + 47.821 32.801 2.1 0.0 6 6 15.0 252 0.065 0.7 99.0 2014 09 17 05 30 27.11 + 47.808 32.709 8.5 0.0 7 4 7.0 228 0.043 0.5 0.9 2014 09 17 10 31 05.11 + 47.821 32.799 2.5 0.0 5 5 15.0 252 0.087 2.5 99.0 2014 09 17 10 34 37.87 + 47.553 32.711 18.0 0.0 10 6 12.0 110 0.421 0.4 0.9 2014 09 17 14 43 49.91 + 47.605 32.771 8.1 0.0 11 6 8.0 116 0.129 0.3 0.9 2014 09 17 16 48 05.93 + 47.604 32.773 8.4 0.0 7 6 8.0 161 0.044 0.5 1.0 2014 09 17 16 51 34.82 + 47.813 32.727 3.7 0.0 5 4 9.0 234 0.141 1.9 6.5 2014 09 17 19 26 25.15 + 47.835 32.734 2.0 0.0 6 4 10.0 250 0.243 0.8 33.3 2014 09 17 19 26 37.35 + 47.767 32.668 12.0 0.0 7 4 4.0 152 0.136 0.6 0.7 2014 09 17 19 58 35.88 + 47.709 32.616 13.5 0.0 9 6 10.0 186 0.096 0.5 0.8 2014 09 17 21 24 35.74 + 47.567 32.755 9.3 0.0 11 6 11.0 95 0.134 0.3 1.0 2014 09 17 21 55 37.79 + 47.582 32.699 10.2 0.0 11 6 10.0 118 0.111 0.3 1.0 2014 09 17 22 13 39.81 + 47.803 32.722 2.3 0.0 7 4 8.0 225 0.210 0.7 13.9 2014 09 17 22 32 17.31 + 47.627 32.721 9.1 0.0 8 6 5.0 110 0.072 0.4 1.2 2014 09 17 22 46 21.49 + 47.709 32.610 14.0 0.0 7 4 10.0 191 0.031 0.6 0.9 2014 09 17 22 57 30.95 + 47.681 32.618 18.7 0.0 6 4 12.0 179 0.399 0.7 0.9 2014 09 17 23 23 36.01 + 47.574 32.702 10.0 0.0 10 6 10.0 116 0.117 0.3 0.8 2014 09 18 01 01 40.46 + 47.577 32.703 9.8 0.0 6 5 10.0 118 0.150 0.4 2.7 2014 09 18 02 11 19.06 + 47.755 32.786 8.7 0.0 10 6 9.0 216 0.413 0.6 1.0 2014 09 18 02 13 50.00 + 47.885 32.655 12.7 0.0 12 6 8.0 300 0.128 0.6 0.5 2014 09 18 02 18 15.73 + 47.895 32.602 17.8 0.0 3 4 10.0 352 0.048 99.0 99.0 2014 09 18 02 18 49.28 + 47.879 32.711 0.0 0.0 5 5 10.0 280 0.181 1.1 1.3 2014 09 18 02 19 01.16 + 47.886 32.654 12.4 0.0 12 6 8.0 300 0.132 0.6 0.5 2014 09 18 02 20 13.10 + 47.823 32.592 15.5 0.0 6 5 7.0 277 0.070 0.9 1.1 2014 09 18 02 21 51.06 + 47.886 32.654 12.7 0.0 11 6 8.0 300 0.108 0.6 0.6 2014 09 18 02 22 06.83 + 47.900 32.649 13.1 0.0 8 5 9.0 302 0.291 0.7 0.6 2014 09 18 02 28 29.77 + 47.870 32.640 12.1 0.0 10 5 6.0 298 0.281 0.6 0.5 2014 09 18 02 34 31.15 + 47.885 32.654 12.5 0.0 12 6 8.0 300 0.107 0.6 0.5 2014 09 18 02 58 17.77 + 47.894 32.651 13.0 0.0 3 6 8.0 340 0.001 99.0 99.0 2014 09 18 02 58 46.26 + 47.881 32.637 14.2 0.0 8 5 7.0 300 0.377 0.7 0.7 2014 09 18 03 00 10.51 + 47.877 32.648 12.0 0.0 6 4 7.0 316 0.085 1.2 0.6 2014 09 18 03 04 43.74 + 47.825 32.624 7.0 0.0 8 5 4.0 290 0.608 0.7 0.6 2014 09 18 03 06 52.19 + 47.933 32.719 2.1 0.0 6 6 14.0 302 0.010 0.8 3.0 2014 09 18 03 11 46.09 + 47.833 32.610 13.9 0.0 8 5 5.0 289 0.063 0.6 0.7 2014 09 18 03 20 38.86 + 47.884 32.655 12.7 0.0 9 5 7.0 300 0.105 0.6 0.6 2014 09 18 03 34 57.42 + 47.801 32.687 9.8 0.0 9 6 4.0 215 0.080 0.6 0.4 2014 09 18 03 37 51.00 + 47.767 32.707 12.8 0.0 8 6 7.0 189 0.383 0.6 0.7 2014 09 18 03 39 48.29 + 47.746 32.671 11.9 0.0 7 5 6.0 161 0.295 1.0 0.7 2014 09 18 03 45 33.55 + 47.734 32.633 11.1 0.0 7 4 7.0 248 0.318 1.8 1.0 2014 09 18 03 49 04.99 + 47.775 32.700 10.5 0.0 9 6 6.0 191 0.250 0.5 0.6 2014 09 18 03 49 06.10 + 47.762 32.647 10.9 0.0 5 4 4.0 232 0.178 2.2 1.0 2014 09 18 03 51 20.03 + 47.771 32.713 10.1 0.0 6 6 8.0 195 0.137 0.7 0.7 2014 09 18 03 52 27.37 + 47.758 32.639 11.6 0.0 6 4 5.0 245 0.141 2.2 0.8 2014 09 18 03 53 27.64 + 47.776 32.703 10.1 0.0 9 6 6.0 193 0.282 0.5 0.6 2014 09 18 03 54 10.13 + 47.759 32.643 11.6 0.0 7 4 4.0 239 0.149 1.9 0.8 2014 09 18 03 58 18.22 + 47.761 32.700 11.3 0.0 8 6 7.0 179 0.288 0.5 0.7 2014 09 18 03 59 17.89 + 47.797 32.694 2.0 0.0 5 4 5.0 213 0.254 1.3 1.1 2014 09 18 04 17 34.42 + 47.807 32.659 10.8 0.0 6 5 1.0 230 0.112 0.7 0.8 2014 09 18 04 30 13.41 + 47.729 32.718 11.8 0.0 4 5 5.0 168 0.001 0.7 0.7 2014 09 18 04 40 04.49 + 47.747 32.628 12.3 0.0 5 4 6.0 256 0.232 2.1 1.1 2014 09 18 04 40 30.70 + 47.797 32.687 11.6 0.0 10 5 4.0 209 0.185 0.5 0.6 2014 09 18 05 52 36.38 + 47.711 32.615 13.8 0.0 9 6 10.0 187 0.092 0.5 0.8 2014 09 18 07 10 06.60 + 47.735 32.648 14.9 0.0 6 6 7.0 161 0.078 1.2 1.5 2014 09 18 07 10 58.46 + 47.704 32.616 14.2 0.0 9 6 10.0 185 0.075 0.6 0.8 2014 09 18 07 17 55.18 + 47.758 32.647 10.4 0.0 5 4 4.0 232 0.153 2.1 1.0 2014 09 18 07 25 33.39 + 47.803 32.788 10.9 0.0 7 5 13.0 241 0.096 1.2 1.0 2014 09 18 08 44 40.27 + 47.724 32.630 13.9 0.0 6 4 8.0 178 0.035 0.7 0.9 2014 09 18 08 57 23.38 + 47.697 32.642 11.2 0.0 6 5 10.0 162 0.299 0.6 1.0 2014 09 18 09 08 19.14 + 47.786 32.617 14.6 0.0 7 5 4.0 231 0.425 0.8 0.8 2014 09 18 09 11 36.52 + 47.572 32.704 10.0 0.0 11 6 10.0 115 0.118 0.3 1.0 2014 09 18 09 51 21.74 + 47.573 32.703 9.8 0.0 11 6 10.0 116 0.102 0.3 1.0 2014 09 18 10 07 09.72 + 47.685 32.571 3.4 0.0 5 4 14.0 281 0.423 1.2 2.6 2014 09 18 10 38 12.49 + 47.799 32.577 18.6 0.0 7 4 8.0 317 0.291 2.5 0.9 2014 09 18 10 52 54.64 + 47.778 32.670 10.9 0.0 9 5 3.0 165 0.088 0.5 0.6 2014 09 18 11 50 57.28 + 47.835 32.699 12.3 0.0 8 4 6.0 254 0.405 0.6 0.6 2014 09 18 11 53 58.65 + 47.467 32.712 15.5 0.0 11 6 19.0 103 0.145 0.3 1.0 2014 09 18 12 42 02.24 + 47.858 32.798 16.1 0.0 6 4 17.0 267 0.401 2.2 2.5 2014 09 18 15 50 47.62 + 47.867 32.644 12.8 0.0 7 5 6.0 298 0.103 0.7 0.7 2014 09 18 15 53 52.22 + 47.804 32.790 9.6 0.0 10 6 13.0 242 0.101 0.6 0.5 2014 09 18 16 52 10.04 + 47.787 32.776 13.4 0.0 8 5 11.0 229 0.020 0.8 0.7 2014 09 18 16 56 27.48 + 47.804 32.790 9.3 0.0 10 6 13.0 242 0.139 0.6 0.5 2014 09 18 17 07 14.21 + 47.804 32.790 9.7 0.0 11 6 13.0 242 0.095 0.6 0.4 2014 09 18 17 07 32.13 + 47.573 32.793 12.1 0.0 3 6 10.0 200 0.001 99.0 99.0 2014 09 18 18 25 02.81 + 47.808 32.814 10.0 0.0 8 5 15.0 251 0.187 0.6 0.5 2014 09 18 20 06 59.41 + 47.883 32.652 12.3 0.0 9 5 7.0 300 0.141 0.7 0.6 2014 09 18 21 19 29.65 + 47.828 32.686 16.3 0.0 7 4 5.0 253 0.361 0.8 0.8 2014 09 18 22 48 05.87 + 47.807 32.792 10.2 0.0 11 6 14.0 244 0.119 0.6 0.8 2014 09 18 22 55 24.15 + 47.811 32.797 11.4 0.0 10 6 14.0 247 0.193 0.6 0.8 2014 09 18 22 57 32.73 + 47.563 32.779 14.4 0.0 11 6 12.0 90 0.412 0.4 1.1 2014 09 18 23 20 45.97 + 47.806 32.790 10.2 0.0 8 5 14.0 243 0.107 0.6 1.2 2014 09 18 23 48 29.52 + 47.791 32.692 13.0 0.0 5 3 5.0 204 0.204 0.8 1.1 2014 09 19 00 46 41.13 + 47.778 32.703 1.2 0.0 3 4 6.0 228 0.004 99.0 99.0 2014 09 19 00 48 38.53 + 47.819 32.699 11.9 0.0 7 4 6.0 239 0.167 0.9 0.7 2014 09 19 01 01 38.24 + 47.800 32.706 8.9 0.0 6 4 6.0 219 0.024 2.0 1.3 2014 09 19 01 02 01.53 + 47.793 32.705 9.2 0.0 8 5 6.0 211 0.142 0.9 0.8 2014 09 19 01 02 10.40 + 47.792 32.701 8.9 0.0 4 3 6.0 209 0.001 2.5 1.7 2014 09 19 01 03 05.30 + 47.800 32.709 8.5 0.0 5 3 6.0 220 0.009 2.1 1.7 2014 09 19 01 04 14.16 + 47.792 32.706 9.0 0.0 8 5 6.0 210 0.135 0.6 1.0 2014 09 19 01 04 20.22 + 47.800 32.708 8.8 0.0 4 3 6.0 219 0.001 2.2 2.8 2014 09 19 01 05 44.14 + 47.804 32.708 8.9 0.0 6 4 6.0 223 0.025 0.7 1.3 2014 09 19 01 05 49.30 + 47.803 32.701 10.8 0.0 7 5 6.0 221 0.107 0.7 1.1 2014 09 19 01 06 47.63 + 47.822 32.697 0.5 0.0 9 6 5.0 242 0.309 2.3 2.2 2014 09 19 01 09 18.41 + 47.792 32.706 9.0 0.0 8 5 6.0 210 0.135 0.6 1.0 2014 09 19 01 09 19.12 + 47.802 32.699 10.9 0.0 7 5 5.0 219 0.128 0.7 1.0 2014 09 19 01 12 05.44 + 47.788 32.705 10.1 0.0 7 5 6.0 206 0.188 0.7 1.1 2014 09 19 01 13 41.12 + 47.812 32.716 9.3 0.0 10 6 7.0 232 0.161 0.5 0.6 2014 09 19 01 15 03.54 + 47.842 32.732 5.8 0.0 5 4 10.0 255 0.119 0.9 2.6 2014 09 19 01 16 09.33 + 47.789 32.699 9.1 0.0 5 4 6.0 205 0.010 1.5 1.3 2014 09 19 01 16 45.49 + 47.779 32.697 10.0 0.0 6 5 6.0 193 0.407 1.0 1.7 2014 09 19 01 16 50.92 + 47.779 32.681 16.3 0.0 4 2 4.0 180 0.413 99.0 99.0 2014 09 19 01 17 14.47 + 47.865 32.707 4.1 0.0 3 4 18.0 331 0.090 30.0 99.0 2014 09 19 01 17 58.86 + 47.799 32.714 1.6 0.0 6 4 7.0 220 0.386 1.4 0.9 2014 09 19 01 22 15.44 + 47.768 32.702 1.5 0.0 4 4 7.0 186 0.087 0.8 1.7 2014 09 19 01 25 44.43 + 47.799 32.699 10.9 0.0 7 5 5.0 216 0.104 0.7 1.1 2014 09 19 01 31 07.24 + 47.838 32.716 4.2 0.0 7 6 8.0 253 0.457 0.6 3.5 2014 09 19 01 32 00.66 + 47.804 32.697 11.2 0.0 7 5 5.0 221 0.137 0.7 1.0 2014 09 19 01 34 48.42 + 47.799 32.699 10.9 0.0 7 5 5.0 216 0.104 0.7 1.1 2014 09 19 01 37 32.64 + 47.820 32.706 13.1 0.0 5 6 6.0 239 0.062 7.9 16.9 2014 09 19 01 39 31.88 + 47.803 32.701 10.8 0.0 7 5 6.0 221 0.107 0.7 1.1 2014 09 19 01 44 51.73 + 47.807 32.682 10.1 0.0 6 4 4.0 224 0.320 0.8 1.2 2014 09 19 01 52 15.36 + 47.582 32.695 11.1 0.0 12 6 10.0 120 0.166 0.3 0.9 2014 09 19 02 00 16.88 + 47.831 32.810 12.3 0.0 8 6 17.0 259 0.345 0.8 1.0 2014 09 19 02 38 11.44 + 47.803 32.793 9.2 0.0 10 6 13.0 242 0.126 0.6 0.5 2014 09 19 03 27 54.35 + 47.622 32.815 12.3 0.0 6 6 10.0 204 0.093 1.0 1.0 2014 09 19 03 55 50.86 + 47.584 32.789 9.0 0.0 10 6 10.0 108 0.197 0.4 0.9 2014 09 19 05 42 26.32 + 47.758 32.611 13.5 0.0 12 6 6.0 211 0.147 0.5 0.7 2014 09 19 06 06 09.90 + 47.548 32.779 6.5 0.0 8 5 12.0 94 0.134 0.3 2.1 2014 09 19 06 26 27.97 + 47.549 32.779 8.4 0.0 10 6 12.0 87 0.136 0.3 1.2 2014 09 19 06 45 39.17 + 47.546 32.782 2.7 0.0 8 6 12.0 89 0.337 0.3 9.9 2014 09 19 06 47 04.01 + 47.738 32.689 10.5 0.0 9 6 7.0 153 0.238 0.5 0.6 2014 09 19 09 55 37.56 + 47.664 32.599 2.2 0.0 6 5 14.0 188 0.178 0.4 99.0 2014 09 19 11 34 40.25 + 47.720 32.615 4.6 0.0 7 4 9.0 261 0.288 1.6 3.7 2014 09 19 11 35 09.16 + 47.710 32.610 13.5 0.0 6 4 10.0 191 0.039 0.6 1.0 2014 09 19 16 38 37.50 + 47.804 32.795 9.2 0.0 12 6 14.0 243 0.158 0.5 0.4 2014 09 19 18 23 46.60 + 47.798 32.787 10.9 0.0 8 6 13.0 238 0.113 0.6 0.8 2014 09 19 18 24 40.58 + 47.743 32.779 9.0 0.0 7 5 8.0 207 0.497 0.5 0.9 2014 09 19 18 24 41.69 + 47.811 32.796 8.0 0.0 6 6 14.0 247 0.066 0.6 1.7 2014 09 19 18 25 03.58 + 47.804 32.786 10.0 0.0 5 6 13.0 241 0.030 4.4 7.9 2014 09 19 18 29 23.04 + 47.788 32.787 7.6 0.0 9 6 12.0 233 0.278 0.6 1.0 2014 09 19 18 30 17.62 + 47.771 32.767 13.7 0.0 8 5 10.0 217 0.061 0.6 0.7 2014 09 19 18 30 23.33 + 47.804 32.796 9.2 0.0 11 6 14.0 243 0.155 0.5 0.5 2014 09 19 18 31 12.08 + 47.802 32.795 9.2 0.0 12 6 14.0 242 0.164 0.5 0.4 2014 09 19 19 14 56.65 + 47.789 32.789 9.0 0.0 11 6 12.0 235 0.348 0.5 0.6 2014 09 19 19 16 39.79 + 47.803 32.792 9.4 0.0 10 6 13.0 242 0.066 0.6 0.5 2014 09 19 19 37 54.63 + 47.802 32.796 8.8 0.0 12 6 14.0 243 0.155 0.5 0.9 2014 09 19 19 41 37.04 + 47.802 32.794 9.2 0.0 12 6 14.0 242 0.170 0.5 0.5 2014 09 19 20 06 23.84 + 47.804 32.795 9.2 0.0 12 6 14.0 243 0.158 0.5 0.4 2014 09 19 20 27 11.70 + 47.802 32.793 10.3 0.0 11 6 13.0 242 0.102 0.5 0.8 2014 09 19 20 28 02.59 + 47.798 32.785 9.7 0.0 10 6 13.0 238 0.102 0.5 0.6 2014 09 19 20 30 15.14 + 47.786 32.779 12.1 0.0 7 4 11.0 230 0.013 1.4 1.7 2014 09 19 21 01 22.24 + 47.826 32.755 18.9 0.0 7 4 12.0 246 0.593 1.9 1.6 2014 09 19 21 26 53.81 + 47.814 32.798 10.2 0.0 9 5 15.0 249 0.170 0.6 1.0 2014 09 19 21 26 55.27 + 47.800 32.788 9.8 0.0 6 5 13.0 239 0.019 0.8 0.6 2014 09 19 22 03 14.80 + 47.685 32.739 9.0 0.0 10 6 1.0 154 0.113 0.3 0.5 2014 09 19 22 56 45.68 + 47.806 32.785 2.2 0.0 5 5 13.0 241 0.114 1.5 99.0 2014 09 19 23 32 02.40 + 47.782 32.771 13.7 0.0 7 4 11.0 224 0.050 1.5 1.6 2014 09 20 00 02 21.93 + 47.794 32.686 11.5 0.0 10 5 4.0 204 0.198 0.5 0.6 2014 09 20 00 51 55.29 + 47.786 32.775 12.7 0.0 8 5 11.0 228 0.030 0.6 0.9 2014 09 20 02 16 23.26 + 47.787 32.637 8.5 0.0 9 6 2.0 205 0.179 0.6 0.7 2014 09 20 03 17 23.05 + 47.789 32.779 11.7 0.0 7 5 12.0 231 0.078 1.0 0.7 2014 09 20 03 25 28.36 + 47.807 32.695 11.6 0.0 9 5 5.0 224 0.064 0.5 0.5 2014 09 20 03 59 43.02 + 47.705 32.803 2.4 0.0 5 3 8.0 198 0.429 2.9 99.0 2014 09 20 04 02 23.57 + 47.825 32.673 12.7 0.0 10 5 3.0 259 0.161 0.6 0.5 2014 09 20 04 04 44.35 + 47.830 32.705 2.0 0.0 5 5 15.0 292 0.222 1.2 33.3 2014 09 20 05 23 06.60 + 47.775 32.683 10.9 0.0 6 4 5.0 177 0.112 2.0 1.0 2014 09 20 05 23 06.74 + 47.769 32.778 14.4 0.0 5 3 10.0 220 0.026 3.1 3.1 2014 09 20 09 09 45.88 + 47.748 32.752 14.1 0.0 11 6 7.0 198 0.313 0.5 0.6 2014 09 20 12 44 53.71 + 47.711 32.751 12.3 0.0 9 5 4.0 194 0.495 0.5 0.6 2014 09 20 12 44 54.39 + 47.810 32.793 0.0 0.0 4 6 14.0 246 0.034 1.2 1.7 2014 09 20 17 20 49.49 + 47.860 32.709 12.3 0.0 6 4 8.0 270 0.484 0.7 0.7 2014 09 20 19 10 59.09 + 47.593 32.773 13.1 0.0 9 6 9.0 108 0.301 0.4 0.9 2014 09 20 21 09 49.27 + 47.418 32.712 14.3 0.0 7 5 14.0 118 0.133 0.5 1.6 2014 09 20 21 17 31.31 + 47.797 32.798 9.2 0.0 9 5 13.0 241 0.140 0.6 0.6 2014 09 21 01 12 58.83 + 47.761 32.770 15.1 0.0 6 4 9.0 212 0.018 1.6 1.5 2014 09 21 01 15 31.00 + 47.792 32.696 9.2 0.0 10 5 5.0 207 0.163 0.7 0.5 2014 09 21 02 12 34.63 + 47.773 32.702 10.7 0.0 8 5 10.0 280 0.148 0.7 1.2 2014 09 21 02 12 34.70 + 47.736 32.691 10.7 0.0 9 6 7.0 154 0.201 0.5 0.6 2014 09 21 02 34 23.00 + 47.768 32.704 5.5 0.0 6 4 7.0 187 0.386 1.6 2.0 2014 09 21 02 50 47.17 + 47.788 32.704 8.9 0.0 7 4 6.0 205 0.075 0.5 0.8 2014 09 21 02 53 58.45 + 47.700 32.591 3.3 0.0 7 5 12.0 202 0.349 0.4 2.4 2014 09 21 05 26 00.97 + 47.814 32.724 7.7 0.0 10 6 8.0 234 0.292 0.5 0.9 2014 09 21 08 34 27.39 + 47.796 32.787 11.4 0.0 8 5 13.0 237 0.065 0.6 1.0 2014 09 21 09 43 28.17 + 47.566 32.783 12.1 0.0 11 6 11.0 93 0.156 0.5 1.2 2014 09 21 12 53 34.95 + 47.761 32.684 11.0 0.0 10 5 6.0 166 0.449 0.6 0.6 2014 09 21 13 45 54.94 + 47.794 32.759 0.0 0.0 6 5 11.0 228 0.103 0.9 1.5 2014 09 21 14 03 27.40 + 47.815 32.710 10.1 0.0 9 5 7.0 234 0.135 0.6 0.6 2014 09 21 18 31 00.42 + 47.643 32.676 15.6 0.0 7 6 7.0 172 0.222 0.6 1.5 2014 09 21 18 43 29.94 + 47.818 32.725 2.1 0.0 5 4 8.0 237 0.061 1.0 99.0 2014 09 21 18 51 09.22 + 47.820 32.715 8.0 0.0 6 4 7.0 238 0.045 1.7 2.2 2014 09 21 23 39 22.71 + 47.532 32.822 11.0 0.0 9 6 9.0 95 0.120 0.6 1.2 2014 09 22 00 58 28.77 + 47.498 32.732 10.0 0.0 11 6 17.0 100 0.150 0.3 1.2 2014 09 22 02 31 20.02 + 47.531 32.770 0.1 0.0 8 5 14.0 140 0.353 0.3 0.7 2014 09 22 06 03 56.10 + 47.533 32.757 13.1 0.0 9 5 14.0 139 0.205 0.4 1.0 2014 09 22 06 29 21.59 + 47.528 32.756 11.1 0.0 8 5 14.0 142 0.202 0.4 1.2 2014 09 22 06 38 56.81 + 47.528 32.754 10.7 0.0 8 5 14.0 142 0.199 0.4 1.2 2014 09 22 07 41 54.19 + 47.590 32.781 14.6 0.0 10 6 10.0 109 0.241 0.4 0.8 2014 09 22 07 49 11.59 + 47.576 32.747 7.6 0.0 5 4 10.0 217 0.143 2.1 1.6 2014 09 22 09 47 14.73 + 47.584 32.691 11.9 0.0 10 6 10.0 122 0.179 0.3 0.9 2014 09 22 10 09 44.97 + 47.848 32.723 0.7 0.0 6 5 9.0 259 0.184 1.6 1.9 2014 09 22 15 49 26.26 + 47.756 32.611 12.0 0.0 9 5 6.0 210 0.081 0.6 0.7 2014 09 22 16 42 38.93 + 47.635 32.722 8.8 0.0 9 6 4.0 110 0.109 0.4 0.7 2014 09 22 17 00 14.35 + 47.754 32.605 11.1 0.0 7 4 7.0 214 0.080 0.6 1.1 2014 09 22 17 16 46.46 + 47.484 32.717 2.0 0.0 7 5 18.0 162 0.136 0.4 33.3 2014 09 22 17 21 30.83 + 47.635 32.724 9.0 0.0 9 6 4.0 109 0.087 0.4 0.7 2014 09 22 17 34 37.52 + 47.489 32.776 8.3 0.0 10 6 13.0 115 0.162 0.3 1.4 2014 09 22 19 00 06.05 + 47.474 32.725 13.9 0.0 11 6 19.0 106 0.098 0.4 1.2 2014 09 22 20 18 46.69 + 47.688 32.734 11.1 0.0 10 5 1.0 154 0.294 0.4 0.6 2014 09 22 22 29 54.75 + 47.813 32.723 7.8 0.0 9 5 8.0 233 0.238 0.5 1.0 2014 09 22 22 31 43.83 + 47.715 32.735 9.8 0.0 10 6 4.0 169 0.109 0.4 0.5 2014 09 22 23 23 46.77 + 47.720 32.731 9.2 0.0 12 6 4.0 170 0.222 0.3 0.5 2014 09 22 23 23 46.91 + 47.646 32.663 15.6 0.0 8 6 8.0 143 0.366 0.4 1.0 2014 09 23 00 13 31.70 + 47.489 32.776 7.5 0.0 8 5 13.0 115 0.139 0.4 1.8 2014 09 23 03 26 36.90 + 47.578 32.705 11.3 0.0 9 5 10.0 149 0.192 0.5 1.2 2014 09 23 10 12 01.93 + 47.251 32.454 19.8 0.0 8 6 17.0 297 0.201 1.0 0.7 2014 09 23 14 35 09.32 + 47.203 32.441 18.7 0.0 7 5 22.0 306 0.393 1.0 0.9 2014 09 23 15 23 09.62 + 47.594 32.773 5.7 0.0 7 4 9.0 129 0.116 0.4 1.4 2014 09 23 20 07 59.90 + 47.194 32.414 10.9 0.0 5 3 24.0 347 0.241 3.7 1.7 2014 09 23 20 15 03.11 + 47.779 32.717 2.7 0.0 4 4 8.0 203 0.125 1.7 10.6 2014 09 23 20 48 09.48 + 47.766 32.710 10.7 0.0 8 5 9.0 305 0.275 0.7 0.6 2014 09 23 20 48 37.14 + 47.142 32.417 14.8 0.0 7 5 28.0 315 0.369 1.0 1.5 2014 09 23 20 48 49.35 + 47.490 32.772 2.1 0.0 7 6 14.0 113 0.173 0.3 99.0 2014 09 24 00 13 47.19 + 47.606 32.820 2.5 0.0 5 4 6.0 136 0.392 1.3 19.2 2014 09 24 01 55 33.23 + 47.193 32.437 17.5 0.0 10 6 23.0 307 0.299 0.8 0.5 2014 09 24 02 36 17.72 + 47.279 32.483 18.9 0.0 7 5 14.0 296 0.170 0.9 0.7 2014 09 24 02 36 18.99 + 47.256 32.460 17.6 0.0 7 4 17.0 305 0.228 0.9 0.5 2014 09 24 02 59 43.66 + 47.496 32.736 11.7 0.0 8 6 17.0 140 0.049 0.4 1.3 2014 09 24 03 10 41.34 + 47.522 32.784 6.4 0.0 7 5 13.0 155 0.147 0.4 2.4 2014 09 24 05 22 53.63 + 47.738 32.714 9.6 0.0 8 5 6.0 187 0.063 0.5 0.5 2014 09 24 10 35 04.04 + 47.849 32.620 13.9 0.0 7 4 5.0 346 0.063 2.4 0.8 2014 09 24 10 48 41.63 + 47.798 32.739 14.7 0.0 7 5 10.0 235 0.592 0.7 0.7 2014 09 24 10 54 47.59 + 47.816 32.624 9.3 0.0 5 3 3.0 333 0.040 2.3 0.9 2014 09 24 11 23 40.20 + 47.776 32.608 2.2 0.0 5 5 5.0 228 0.924 0.6 4.0 2014 09 24 11 24 25.19 + 47.735 32.711 9.4 0.0 9 5 6.0 184 0.095 0.5 0.5 2014 09 24 11 38 26.15 + 47.254 32.459 20.1 0.0 8 6 17.0 296 0.206 1.1 0.7 2014 09 24 13 39 08.80 + 47.290 32.505 19.6 0.0 7 5 12.0 284 0.324 1.3 0.6 2014 09 24 13 56 20.47 + 47.293 32.497 18.9 0.0 6 4 12.0 288 0.080 1.4 0.7 2014 09 24 14 27 31.32 + 47.248 32.483 14.7 0.0 8 5 16.0 298 0.416 0.9 0.7 2014 09 24 14 27 38.96 + 47.261 32.484 11.9 0.0 8 5 15.0 296 0.403 0.8 0.6 2014 09 24 14 35 13.15 + 47.155 32.444 0.0 0.0 5 5 26.0 313 0.206 13.5 15.7 2014 09 24 14 42 55.43 + 47.258 32.477 18.0 0.0 8 5 16.0 299 0.144 0.9 0.6 2014 09 24 14 42 57.33 + 47.251 32.481 14.5 0.0 6 4 16.0 298 0.098 0.9 0.9 2014 09 24 14 50 05.92 + 47.259 32.483 17.6 0.0 7 4 15.0 297 0.136 0.9 0.8 2014 09 24 15 43 31.85 + 47.586 32.774 9.0 0.0 11 6 10.0 103 0.201 0.3 0.9 2014 09 24 17 09 12.98 + 47.854 32.810 10.8 0.0 11 6 18.0 267 0.322 0.6 1.0 2014 09 24 17 11 09.06 + 47.757 32.603 11.6 0.0 8 4 7.0 217 0.074 0.6 0.8 2014 09 24 18 27 01.23 + 47.851 32.807 10.9 0.0 11 6 18.0 265 0.342 0.6 1.0 2014 09 24 19 40 25.77 + 47.842 32.784 14.7 0.0 11 6 15.0 258 0.243 0.6 0.7 2014 09 24 20 04 50.37 + 47.517 32.747 9.9 0.0 12 6 15.0 96 0.177 0.3 1.1 2014 09 24 20 11 19.37 + 47.584 32.781 5.8 0.0 7 5 10.0 105 0.184 0.5 2.6 2014 09 24 22 05 05.87 + 47.258 32.482 18.1 0.0 8 5 15.0 297 0.154 0.9 0.6 2014 09 24 22 19 12.96 + 47.703 32.711 20.0 0.0 8 4 3.0 190 0.491 1.8 0.7 2014 09 24 22 57 27.82 + 47.274 32.467 22.0 0.0 6 4 15.0 302 0.320 1.0 0.8 2014 09 24 23 08 03.32 + 47.663 32.616 13.4 0.0 8 6 13.0 176 0.094 0.5 0.9 2014 09 24 23 17 57.30 + 47.574 32.756 9.1 0.0 9 6 10.0 95 0.348 0.3 1.0 2014 09 25 00 31 34.64 + 47.245 32.489 10.3 0.0 6 4 16.0 296 0.288 0.8 1.4 2014 09 25 00 41 29.59 + 47.617 32.789 0.0 0.0 4 4 8.0 222 0.436 3.0 0.9 2014 09 25 02 30 11.03 + 47.584 32.716 10.7 0.0 12 6 9.0 111 0.177 0.3 0.9 2014 09 25 04 02 53.94 + 47.772 32.669 11.8 0.0 9 5 4.0 156 0.176 0.7 0.8 2014 09 25 05 17 15.18 + 47.588 32.775 9.9 0.0 11 6 10.0 105 0.338 0.3 0.8 2014 09 25 06 21 43.87 + 47.573 32.786 12.4 0.0 8 4 10.0 187 0.068 0.6 1.4 2014 09 25 06 21 43.92 + 47.588 32.772 8.0 0.0 12 6 9.0 104 0.182 0.3 1.0 2014 09 25 06 48 10.47 + 47.575 32.772 4.5 0.0 8 4 12.0 192 0.359 0.5 4.9 2014 09 25 06 48 10.93 + 47.591 32.804 8.1 0.0 9 5 8.0 117 0.153 0.4 1.3 2014 09 25 07 33 50.95 + 47.471 32.753 11.7 0.0 6 4 16.0 172 0.110 0.6 2.5 2014 09 25 07 58 40.23 + 47.474 32.751 11.2 0.0 6 4 16.0 170 0.106 0.5 2.7 2014 09 25 07 59 00.05 + 47.827 32.677 12.4 0.0 10 5 4.0 257 0.154 0.6 0.5 2014 09 25 08 04 54.29 + 47.471 32.753 11.7 0.0 6 4 16.0 172 0.110 0.6 2.5 2014 09 25 08 10 27.23 + 47.754 32.635 13.2 0.0 10 5 5.0 181 0.184 0.5 0.7 2014 09 25 09 09 39.46 + 47.840 32.653 6.9 0.0 9 5 3.0 293 0.364 0.6 0.5 2014 09 25 09 18 46.96 + 47.831 32.691 0.0 0.0 5 4 5.0 254 0.415 1.9 2.2 2014 09 25 09 26 52.60 + 47.790 32.708 7.7 0.0 8 4 7.0 210 0.090 0.5 0.8 2014 09 25 09 41 55.78 + 47.791 32.709 8.1 0.0 8 4 7.0 211 0.095 0.5 0.7 2014 09 25 09 42 30.47 + 47.758 32.674 11.1 0.0 7 4 5.0 152 0.191 0.7 0.7 2014 09 25 09 45 13.80 + 47.736 32.613 11.0 0.0 6 5 8.0 198 0.099 0.8 1.4 2014 09 25 10 10 29.62 + 47.718 32.606 10.1 0.0 4 5 9.0 197 0.029 3.2 8.0 2014 09 25 10 11 09.72 + 47.754 32.636 10.6 0.0 10 5 5.0 181 0.165 0.5 0.7 2014 09 25 10 16 59.17 + 47.587 32.718 9.7 0.0 12 6 9.0 110 0.163 0.3 0.9 2014 09 25 10 56 18.66 + 47.768 32.604 2.7 0.0 6 3 6.0 296 0.270 2.1 11.5 2014 09 25 13 05 56.16 + 47.492 32.718 12.0 0.0 6 4 17.0 255 0.307 1.6 2.3 2014 09 25 16 28 23.73 + 47.426 32.703 6.2 0.0 8 4 22.0 276 0.119 1.4 7.2 2014 09 25 16 34 16.36 + 47.730 32.705 11.2 0.0 10 6 6.0 161 0.441 0.4 0.6 2014 09 25 17 18 24.01 + 47.716 32.697 10.9 0.0 12 6 5.0 148 0.199 0.4 0.6 2014 09 25 17 21 01.70 + 47.756 32.733 10.3 0.0 6 5 7.0 193 0.385 0.7 0.8 2014 09 25 17 21 23.03 + 47.668 32.682 0.0 0.0 5 4 6.0 220 0.326 1.2 0.5 2014 09 25 17 21 55.37 + 47.715 32.697 11.2 0.0 10 6 5.0 147 0.220 0.4 0.6 2014 09 25 17 22 57.26 + 47.701 32.681 10.6 0.0 6 5 6.0 229 0.022 1.8 0.7 2014 09 25 17 24 20.13 + 47.712 32.699 11.8 0.0 8 5 5.0 147 0.177 0.7 0.7 2014 09 25 17 35 38.90 + 47.796 32.647 3.1 0.0 7 4 1.0 188 0.469 0.8 0.9 2014 09 25 17 44 27.88 + 47.853 32.669 5.0 0.0 6 4 5.0 289 0.121 0.8 0.8 2014 09 25 18 08 24.94 + 47.724 32.715 9.4 0.0 9 5 5.0 163 0.537 0.4 0.6 2014 09 25 18 08 57.44 + 47.774 32.577 4.0 0.0 3 4 9.0 313 0.003 99.0 99.0 2014 09 25 20 03 07.54 + 47.692 32.702 9.3 0.0 12 6 4.0 139 0.366 0.3 0.6 2014 09 25 21 24 25.30 + 47.679 32.705 11.9 0.0 9 5 3.0 121 0.279 0.4 0.7 2014 09 25 21 56 25.34 + 47.657 32.683 10.3 0.0 7 5 6.0 131 0.092 0.5 0.8 2014 09 25 21 56 25.35 + 47.742 32.631 12.2 0.0 12 6 6.0 182 0.162 0.5 0.7 2014 09 25 22 02 51.27 + 47.521 32.740 22.3 0.0 8 6 15.0 95 0.483 0.4 1.0 2014 09 25 22 12 43.73 + 47.529 32.721 15.5 0.0 9 6 14.0 103 0.251 0.3 1.0 2014 09 25 22 12 57.51 + 47.715 32.741 9.9 0.0 6 4 4.0 191 0.021 0.7 0.6 2014 09 25 22 29 42.71 + 47.713 32.737 9.8 0.0 7 5 3.0 169 0.063 0.6 0.6 2014 09 25 22 29 42.76 + 47.715 32.737 9.7 0.0 9 6 3.0 170 0.048 0.4 0.5 2014 09 25 22 31 13.28 + 47.712 32.736 9.8 0.0 10 6 3.0 168 0.102 0.4 0.5 2014 09 25 22 31 13.31 + 47.726 32.744 10.0 0.0 9 6 5.0 180 0.181 0.4 0.5 2014 09 25 22 32 05.84 + 47.706 32.758 5.7 0.0 8 4 4.0 195 0.512 0.5 0.6 2014 09 25 22 32 06.71 + 47.730 32.758 6.8 0.0 8 4 6.0 206 0.461 0.5 0.7 2014 09 25 22 32 35.54 + 47.727 32.751 7.1 0.0 10 6 5.0 184 0.410 0.4 0.6 2014 09 25 22 32 35.59 + 47.745 32.741 11.4 0.0 7 5 6.0 190 0.269 0.6 0.8 2014 09 25 22 34 48.71 + 47.723 32.745 7.0 0.0 11 6 4.0 179 0.384 0.4 0.6 2014 09 25 22 35 09.59 + 47.723 32.748 6.8 0.0 9 6 5.0 180 0.435 0.4 0.6 2014 09 25 22 35 09.60 + 47.719 32.736 9.5 0.0 12 6 4.0 172 0.164 0.4 0.4 2014 09 25 22 39 23.30 + 47.712 32.736 9.6 0.0 10 6 3.0 167 0.097 0.4 0.4 2014 09 25 22 39 23.33 + 47.713 32.737 12.8 0.0 7 4 3.0 188 0.326 0.6 0.7 2014 09 25 22 40 51.08 + 47.744 32.759 7.4 0.0 7 5 7.0 198 0.220 0.6 0.9 2014 09 25 22 40 51.77 + 47.542 32.718 9.4 0.0 12 6 13.0 106 0.215 0.2 1.1 2014 09 25 22 50 24.33 + 47.706 32.700 10.3 0.0 9 6 5.0 144 0.228 0.4 0.7 2014 09 25 23 00 48.01 + 47.578 32.678 8.5 0.0 9 6 11.0 128 0.434 0.3 1.8 2014 09 25 23 46 50.46 + 47.581 32.709 17.3 0.0 8 5 19.0 114 0.287 0.3 1.2 2014 09 25 23 47 27.75 + 47.586 32.704 10.4 0.0 11 6 9.0 116 0.328 0.3 0.9 2014 09 25 23 53 36.08 + 47.712 32.736 9.8 0.0 10 6 3.0 168 0.117 0.4 0.5 2014 09 26 00 23 45.17 + 47.718 32.737 9.4 0.0 12 6 4.0 172 0.182 0.3 0.5 2014 09 26 00 23 45.19 + 47.795 32.630 5.0 0.0 8 5 2.0 233 0.374 0.7 0.8 2014 09 26 00 25 06.87 + 47.610 32.661 12.7 0.0 10 5 10.0 141 0.151 0.3 0.9 2014 09 26 01 45 42.63 + 47.824 32.674 12.2 0.0 10 5 3.0 255 0.171 0.6 0.5 2014 09 26 07 26 01.47 + 47.768 32.774 14.9 0.0 5 3 10.0 218 0.002 3.1 2.9 2014 09 26 07 29 49.17 + 47.420 32.771 11.3 0.0 9 5 15.0 148 0.269 0.6 1.4 2014 09 26 09 00 53.54 + 47.755 32.641 12.2 0.0 6 4 5.0 241 0.086 1.9 1.0 2014 09 26 09 24 52.39 + 47.506 32.731 3.6 0.0 11 6 16.0 96 0.425 0.3 1.8 2014 09 26 09 32 19.20 + 47.480 32.758 11.4 0.0 6 4 15.0 167 0.034 0.6 2.0 2014 09 26 09 33 10.30 + 47.498 32.775 12.4 0.0 5 4 13.0 159 0.081 0.7 1.8 2014 09 26 10 54 57.07 + 47.810 32.635 15.7 0.0 9 5 2.0 271 0.343 0.9 0.6 2014 09 26 12 52 12.88 + 47.517 32.728 11.7 0.0 11 6 15.0 98 0.247 0.3 1.2 2014 09 26 13 28 36.92 + 47.586 32.689 11.0 0.0 12 6 10.0 124 0.239 0.3 0.9 2014 09 26 13 46 46.45 + 47.658 32.615 12.9 0.0 9 6 13.0 176 0.070 0.4 1.0 2014 09 26 14 43 22.08 + 47.677 32.641 23.5 0.0 9 6 10.0 161 0.469 0.5 0.8 2014 09 26 14 52 28.89 + 47.511 32.728 0.0 0.0 8 5 16.0 152 0.173 0.3 0.7 2014 09 26 16 20 13.31 + 47.667 32.615 14.1 0.0 9 6 13.0 178 0.182 0.5 0.9 2014 09 26 17 45 45.93 + 47.620 32.698 11.2 0.0 10 5 7.0 122 0.266 0.3 0.8 2014 09 26 17 51 31.94 + 47.740 32.709 8.5 0.0 9 5 6.0 186 0.259 0.5 0.6 2014 09 26 21 14 13.00 + 47.708 32.694 3.2 0.0 6 4 5.0 151 0.329 0.6 1.7 2014 09 26 21 14 29.57 + 47.739 32.712 9.8 0.0 8 5 6.0 187 0.101 0.7 0.5 2014 09 26 21 15 41.77 + 47.792 32.701 8.9 0.0 4 3 6.0 209 0.001 2.5 1.7 2014 09 26 23 24 20.30 + 47.653 32.661 7.2 0.0 8 4 8.0 235 0.181 1.4 1.6 2014 09 26 23 44 32.41 + 47.258 32.483 15.8 0.0 6 4 15.0 297 0.073 0.9 0.9 2014 09 27 00 57 50.63 + 47.525 32.722 1.1 0.0 11 6 14.0 102 0.454 0.2 0.6 2014 09 27 03 09 43.90 + 47.843 32.654 6.8 0.0 9 5 4.0 294 0.367 0.6 0.5 2014 09 27 04 12 28.72 + 47.859 32.663 6.6 0.0 5 4 5.0 296 0.087 0.9 1.0 2014 09 27 04 16 28.40 + 47.827 32.647 8.0 0.0 3 3 2.0 317 0.002 99.0 99.0 2014 09 27 04 16 39.06 + 47.857 32.666 6.6 0.0 6 4 5.0 295 0.331 2.2 1.8 2014 09 27 04 18 18.67 + 47.812 32.673 0.9 0.0 5 3 3.0 235 0.571 99.0 99.0 2014 09 27 04 18 47.12 + 47.812 32.673 0.9 0.0 5 3 3.0 235 0.571 99.0 99.0 2014 09 27 04 53 14.22 + 47.610 32.725 9.0 0.0 8 5 6.0 109 0.128 0.3 1.4 2014 09 27 04 54 45.74 + 47.884 32.647 11.1 0.0 6 4 7.0 300 0.366 0.8 0.7 2014 09 27 04 55 49.07 + 47.805 32.637 5.3 0.0 5 3 2.0 312 0.289 2.3 0.7 2014 09 27 05 43 08.31 + 47.793 32.705 9.2 0.0 8 5 6.0 211 0.142 0.9 0.8 2014 09 27 06 28 58.50 + 47.798 32.704 9.2 0.0 5 3 6.0 216 0.023 2.2 1.5 2014 09 27 06 31 26.21 + 47.800 32.634 5.2 0.0 5 3 2.0 300 0.243 2.3 0.8 2014 09 27 08 42 50.95 + 47.514 32.750 1.2 0.0 9 5 15.0 149 0.406 0.3 0.7 2014 09 27 08 46 47.20 + 47.832 32.645 8.0 0.0 3 3 3.0 321 0.002 99.0 99.0 2014 09 27 09 08 04.81 + 47.816 32.615 6.3 0.0 8 4 4.0 273 0.659 0.6 0.7 2014 09 27 09 11 12.62 + 47.835 32.680 1.4 0.0 3 4 30.0 292 0.001 99.0 99.0 2014 09 27 10 38 45.03 + 47.596 32.808 8.4 0.0 7 6 11.0 177 0.022 0.6 2.0 2014 09 27 11 21 51.27 + 47.927 32.719 3.9 0.0 5 3 14.0 296 0.455 1.6 4.8 2014 09 27 19 32 47.97 + 47.792 32.795 10.3 0.0 7 5 13.0 238 0.141 0.8 1.0 2014 09 29 01 10 29.50 + 47.809 32.788 9.6 0.0 7 4 14.0 244 0.059 1.5 2.6 2014 09 29 01 49 22.48 + 47.750 32.607 13.6 0.0 9 5 7.0 210 0.703 0.5 0.8 2014 09 29 03 13 49.22 + 47.726 32.798 2.0 0.0 4 5 9.0 263 0.151 1.9 33.3 2014 09 29 04 38 56.25 + 47.707 32.616 13.7 0.0 9 6 10.0 186 0.071 0.5 0.8 2014 09 29 06 16 10.47 + 47.709 32.639 12.7 0.0 9 6 9.0 166 0.376 0.5 0.7 2014 09 29 06 25 35.34 + 47.584 32.775 9.3 0.0 10 6 10.0 103 0.227 0.3 0.9 2014 09 29 14 35 15.46 + 47.495 32.739 11.6 0.0 12 6 17.0 103 0.078 0.3 1.1 2014 09 29 19 41 58.02 + 47.763 32.709 9.8 0.0 7 5 8.0 186 0.287 0.7 0.6 2014 09 29 23 57 59.45 + 47.588 32.782 2.3 0.0 6 5 10.0 123 0.193 0.3 20.6 2014 09 30 00 03 21.31 + 47.798 32.684 9.9 0.0 8 6 4.0 211 0.082 0.6 0.5 2014 09 30 00 16 20.32 + 47.784 32.700 11.6 0.0 7 6 6.0 200 0.350 0.6 0.8 2014 09 30 03 13 14.78 + 47.807 32.665 10.1 0.0 7 5 2.0 224 0.106 0.8 0.8 2014 09 30 03 15 02.64 + 47.781 32.668 11.6 0.0 6 4 3.0 176 0.109 3.2 0.8 2014 09 30 03 15 02.67 + 47.471 32.752 10.2 0.0 6 4 16.0 172 0.103 0.5 3.2 2014 09 30 03 18 56.82 + 47.494 32.756 9.1 0.0 12 6 16.0 108 0.236 0.3 1.2 2014 09 30 05 47 03.27 + 47.483 32.755 9.9 0.0 9 6 16.0 112 0.490 0.3 1.2 2014 09 30 05 49 11.43 + 47.796 32.704 6.5 0.0 8 6 6.0 214 0.362 0.4 1.0 2014 09 30 06 58 19.09 + 47.668 32.737 7.9 0.0 8 5 1.0 134 0.072 0.4 0.6 2014 09 30 07 27 37.57 + 47.798 32.678 9.7 0.0 6 5 3.0 207 0.008 0.7 0.7 2014 09 30 09 54 20.18 + 47.639 32.824 9.7 0.0 5 5 6.0 181 0.272 1.6 1.7 2014 09 30 10 01 40.42 + 47.802 32.658 9.9 0.0 5 4 1.0 199 0.009 2.6 0.6 2014 09 30 12 38 53.73 + 47.792 32.682 8.1 0.0 7 5 4.0 199 0.156 0.5 0.9 2014 09 30 12 42 12.35 + 47.821 32.721 0.1 0.0 3 6 13.0 333 0.001 99.0 99.0 2014 09 30 12 43 16.11 + 47.626 32.817 9.1 0.0 7 5 6.0 161 0.412 0.6 1.2 2014 09 30 13 20 23.36 + 47.534 32.742 2.0 0.0 6 4 13.0 162 0.192 0.4 33.3 2014 09 30 13 21 39.15 + 47.573 32.769 11.4 0.0 6 4 11.0 119 0.385 0.8 1.5 2014 09 30 13 21 53.35 + 47.801 32.645 14.5 0.0 7 5 1.0 251 0.413 0.8 0.7 2014 09 30 13 41 58.87 + 47.506 32.826 9.4 0.0 10 6 8.0 113 0.275 0.4 1.0 2014 09 30 14 12 49.05 + 47.732 32.693 10.5 0.0 10 6 7.0 153 0.164 0.4 0.6 2014 09 30 14 48 20.17 + 47.822 32.685 11.6 0.0 11 6 4.0 246 0.168 0.6 0.5 2014 09 30 16 26 01.80 + 47.785 32.697 12.1 0.0 7 5 6.0 200 0.191 0.7 0.7 2014 09 30 17 29 12.71 + 47.618 32.634 3.9 0.0 8 4 12.0 253 0.037 0.8 1.8 2014 09 30 18 46 10.19 + 47.495 32.738 11.4 0.0 12 6 17.0 102 0.073 0.3 1.2 2014 09 30 19 16 19.56 + 47.488 32.728 7.3 0.0 7 5 18.0 112 0.161 0.3 2.6 2014 09 30 19 24 26.53 + 47.650 32.704 9.8 0.0 9 6 4.0 119 0.229 0.3 0.7 2014 09 30 19 33 38.94 + 47.495 32.738 10.6 0.0 10 6 17.0 102 0.070 0.3 1.3 2014 09 30 19 34 36.89 + 47.494 32.739 12.0 0.0 12 6 17.0 103 0.092 0.3 1.1 2014 09 30 20 01 15.37 + 47.819 32.709 8.8 0.0 6 5 7.0 237 0.067 0.6 1.0 2014 09 30 20 11 59.56 + 47.776 32.665 13.2 0.0 6 5 3.0 154 0.236 0.7 1.0 2014 09 30 20 58 54.38 + 47.796 32.687 11.4 0.0 10 5 4.0 207 0.177 0.5 0.6 2014 09 30 21 58 56.02 + 47.807 32.721 6.7 0.0 5 3 8.0 228 0.035 1.8 2.7 2014 09 30 22 02 57.49 + 47.715 32.698 11.0 0.0 12 6 5.0 148 0.212 0.4 0.6 2014 09 30 22 18 11.03 + 47.716 32.702 8.6 0.0 5 6 5.0 189 0.183 1.8 1.1 2014 09 30 22 20 31.01 + 47.759 32.647 11.3 0.0 5 4 4.0 165 0.001 0.9 1.1 2014 09 30 22 46 34.45 + 47.537 32.756 13.3 0.0 9 5 13.0 137 0.210 0.4 1.0 2014 09 30 23 13 28.33 + 47.534 32.754 11.3 0.0 8 5 14.0 139 0.189 0.4 1.2 2014 09 30 23 20 32.85 + 47.691 32.804 22.0 0.0 7 5 8.0 190 0.475 0.9 0.7 2014 09 30 23 46 39.83 + 47.661 32.660 10.2 0.0 10 5 8.0 146 0.270 0.4 0.8 2014 09 30 23 58 34.19 + 47.781 32.684 4.5 0.0 6 6 4.0 186 0.159 1.0 3.1 2014 10 01 00 26 08.36 + 47.501 32.758 13.8 0.0 10 6 15.0 105 0.173 0.3 1.2 2014 10 01 00 49 31.72 + 47.487 32.761 25.0 0.0 6 5 15.0 137 0.250 0.7 1.1 2014 10 01 01 36 14.57 + 47.511 32.754 3.1 0.0 9 5 16.0 151 0.338 0.3 7.1 2014 10 01 01 45 28.28 + 47.808 32.653 14.5 0.0 8 6 0.0 262 0.192 0.7 0.7 2014 10 01 05 00 57.41 + 47.506 32.737 3.1 0.0 8 5 16.0 152 0.082 0.4 9.1 2014 10 01 05 20 47.45 + 47.495 32.740 9.9 0.0 6 6 17.0 107 0.013 0.4 2.0 2014 10 01 05 25 09.68 + 47.770 32.600 3.8 0.0 6 3 6.0 299 0.286 0.9 1.4 2014 10 01 05 27 33.48 + 47.802 32.686 10.2 0.0 7 6 4.0 217 0.085 0.5 0.8 2014 10 01 06 42 27.02 + 47.805 32.694 9.9 0.0 8 6 5.0 222 0.174 0.5 0.5 2014 10 01 08 00 12.66 + 47.804 32.685 9.9 0.0 9 6 4.0 219 0.078 0.5 0.5 2014 10 01 08 23 52.01 + 47.767 32.754 6.6 0.0 7 6 9.0 209 0.298 0.5 1.0 2014 10 01 08 25 04.38 + 47.773 32.711 11.0 0.0 7 6 7.0 195 0.138 0.5 0.7 2014 10 01 08 34 58.35 + 47.834 32.744 4.3 0.0 5 3 11.0 257 0.299 8.5 99.0 2014 10 01 08 36 19.28 + 47.762 32.700 12.7 0.0 7 6 7.0 180 0.328 0.6 0.7 2014 10 01 08 36 20.02 + 47.691 32.665 12.4 0.0 5 4 8.0 225 0.074 1.9 1.0 2014 10 01 08 38 21.10 + 47.770 32.697 11.3 0.0 8 6 6.0 184 0.233 0.6 0.7 2014 10 01 08 38 21.23 + 47.803 32.681 10.8 0.0 8 6 3.0 217 0.103 0.5 0.7 2014 10 01 08 49 18.69 + 47.771 32.668 11.5 0.0 4 5 11.0 342 0.001 3.1 1.2 2014 10 01 09 52 53.11 + 47.797 32.706 6.7 0.0 8 6 6.0 215 0.375 0.4 1.0 2014 10 01 09 57 08.04 + 47.780 32.669 3.6 0.0 9 6 3.0 165 0.490 0.5 0.9 2014 10 01 09 57 29.26 + 47.557 32.755 8.8 0.0 11 6 12.0 94 0.089 0.3 1.1 2014 10 01 11 15 42.91 + 47.640 32.686 10.3 0.0 11 6 6.0 129 0.148 0.3 0.7 2014 10 01 12 45 19.92 + 47.843 32.652 10.4 0.0 6 6 4.0 294 0.142 1.9 1.8 2014 10 01 14 46 43.62 + 47.700 32.726 10.9 0.0 8 5 2.0 156 0.032 0.5 0.6 2014 10 01 15 47 16.57 + 47.722 32.755 4.2 0.0 8 6 5.0 183 0.365 0.5 1.2 2014 10 01 17 28 54.92 + 47.550 32.758 1.1 0.0 7 6 12.0 137 0.132 0.4 0.8 2014 10 01 17 58 04.75 + 47.607 32.714 9.8 0.0 11 6 7.0 113 0.126 0.3 0.8 2014 10 01 19 56 58.58 + 47.531 32.748 15.7 0.0 8 6 14.0 94 0.312 0.4 1.1 2014 10 01 20 43 47.78 + 47.751 32.724 10.8 0.0 7 6 7.0 185 0.267 0.4 0.6 2014 10 01 22 04 51.13 + 47.798 32.681 1.4 0.0 4 5 3.0 208 0.115 99.0 99.0 2014 10 01 22 48 37.43 + 47.805 32.687 10.1 0.0 9 6 4.0 221 0.105 0.5 0.7 2014 10 01 22 50 49.88 + 47.803 32.687 10.1 0.0 8 6 4.0 219 0.125 0.5 0.7 2014 10 01 22 52 25.89 + 47.591 32.782 13.2 0.0 11 6 10.0 111 0.178 0.4 0.8 2014 10 01 23 17 45.38 + 47.810 32.798 11.1 0.0 11 6 14.0 247 0.141 0.5 0.8 2014 10 01 23 25 30.77 + 47.511 32.730 13.8 0.0 8 6 16.0 97 0.202 0.3 1.3 2014 10 02 00 17 51.15 + 47.541 32.757 14.1 0.0 9 5 13.0 135 0.214 0.4 1.0 2014 10 02 00 44 09.13 + 47.608 32.732 23.3 0.0 7 5 7.0 107 0.452 0.6 0.8 2014 10 02 01 01 07.77 + 47.537 32.755 13.1 0.0 9 5 13.0 137 0.222 0.4 1.0 2014 10 02 01 08 34.07 + 47.803 32.682 10.7 0.0 6 5 4.0 217 0.116 0.8 0.9 2014 10 02 01 11 46.91 + 47.535 32.752 9.0 0.0 8 4 13.0 138 0.185 0.4 1.5 2014 10 02 01 23 13.48 + 47.766 32.668 9.7 0.0 11 6 4.0 150 0.118 0.4 0.5 2014 10 02 07 15 28.94 + 47.565 32.755 7.4 0.0 6 5 11.0 109 0.551 0.6 2.1 2014 10 02 09 31 13.29 + 47.554 32.764 4.3 0.0 5 4 12.0 147 0.032 0.5 7.6 2014 10 02 09 48 01.57 + 47.649 32.705 8.6 0.0 6 4 4.0 155 0.096 0.6 0.7 2014 10 02 14 39 13.41 + 47.669 32.712 11.8 0.0 10 6 2.0 114 0.573 0.4 0.6 2014 10 02 14 46 27.82 + 47.563 32.816 2.1 0.0 5 5 14.0 246 0.375 0.9 99.0 2014 10 02 16 57 48.72 + 47.645 32.697 10.7 0.0 10 6 5.0 123 0.203 0.3 0.7 2014 10 02 17 01 52.97 + 47.493 32.740 11.3 0.0 9 6 17.0 103 0.074 0.3 1.2 2014 10 02 17 31 19.52 + 47.803 32.683 10.5 0.0 8 6 4.0 217 0.104 0.5 0.7 2014 10 02 18 40 53.93 + 47.647 32.704 10.3 0.0 10 6 4.0 119 0.300 0.3 0.7 2014 10 02 20 17 44.12 + 47.596 32.806 7.7 0.0 11 6 8.0 117 0.121 0.3 1.0 2014 10 02 21 35 56.00 + 47.594 32.807 7.5 0.0 11 6 8.0 115 0.103 0.3 1.1 2014 10 02 21 37 43.56 + 47.593 32.806 7.0 0.0 11 6 8.0 115 0.121 0.3 1.2 2014 10 02 21 39 27.68 + 47.589 32.806 4.9 0.0 9 6 8.0 112 0.183 0.4 2.3 2014 10 02 21 40 30.89 + 47.804 32.684 10.3 0.0 9 6 4.0 219 0.106 0.5 0.7 2014 10 02 22 30 03.05 + 47.820 32.700 9.7 0.0 8 6 6.0 239 0.238 0.6 0.6 2014 10 02 22 31 39.10 + 47.590 32.801 9.8 0.0 11 6 8.0 112 0.399 0.3 0.9 2014 10 02 23 44 02.78 + 47.599 32.811 5.2 0.0 7 5 7.0 119 0.201 0.7 2.3 2014 10 02 23 44 27.12 + 47.608 32.783 7.8 0.0 6 5 9.0 124 0.267 0.4 1.5 2014 10 02 23 54 21.24 + 47.646 32.672 5.8 0.0 9 5 7.0 137 0.183 0.4 1.2 2014 10 03 04 10 03.22 + 47.620 32.656 3.3 0.0 5 4 10.0 185 0.105 2.2 17.1 2014 10 03 10 34 05.62 + 47.790 32.721 7.5 0.0 8 4 8.0 214 0.253 0.5 0.8 2014 10 03 11 40 54.06 + 47.816 32.664 6.5 0.0 8 5 2.0 254 0.096 0.5 0.9 2014 10 03 14 46 36.04 + 47.817 32.673 16.0 0.0 7 5 3.0 245 0.521 0.7 0.8 2014 10 03 14 50 09.67 + 47.683 32.681 8.6 0.0 9 5 6.0 132 0.148 0.4 0.7 2014 10 03 16 32 40.68 + 47.720 32.739 8.8 0.0 7 4 4.0 174 0.128 0.4 0.6 2014 10 03 19 47 53.32 + 47.572 32.627 3.7 0.0 5 3 15.0 285 0.391 1.0 2.5 2014 10 03 21 05 05.34 + 47.598 32.823 6.7 0.0 5 4 6.0 132 0.661 1.2 3.0 2014 10 04 02 18 29.99 + 47.645 32.694 10.2 0.0 9 5 5.0 125 0.206 0.4 0.8 2014 10 04 07 07 08.13 + 47.524 32.783 6.5 0.0 7 5 13.0 154 0.129 0.4 2.4 2014 10 04 12 02 34.26 + 47.748 32.745 15.4 0.0 9 5 7.0 194 0.301 0.6 0.6 2014 10 04 15 31 25.75 + 47.722 32.715 16.1 0.0 6 4 5.0 163 0.249 0.9 0.7 2014 10 04 15 31 25.79 + 47.719 32.740 9.8 0.0 8 5 4.0 174 0.290 0.4 0.5 2014 10 04 15 44 11.91 + 47.699 32.746 15.8 0.0 6 4 2.0 165 0.256 0.6 0.7 2014 10 04 17 48 40.32 + 47.688 32.705 9.8 0.0 8 4 3.0 138 0.439 0.4 0.6 2014 10 04 21 50 41.31 + 47.664 32.653 10.8 0.0 6 3 9.0 259 0.237 1.7 1.1 2014 10 05 01 56 30.93 + 47.636 32.676 3.8 0.0 7 4 7.0 135 0.202 0.8 3.3 2014 10 05 05 46 42.40 + 47.598 32.778 6.8 0.0 9 5 9.0 117 0.161 0.3 1.1 2014 10 05 07 38 22.23 + 47.628 32.793 15.7 0.0 5 3 8.0 153 0.245 1.2 1.4 2014 10 05 09 40 12.62 + 47.645 32.695 10.6 0.0 9 5 5.0 124 0.204 0.4 0.7 2014 10 05 10 13 07.42 + 47.799 32.697 11.2 0.0 5 4 5.0 216 0.022 1.0 0.9 2014 10 05 17 02 02.42 + 47.828 32.678 11.9 0.0 5 5 4.0 258 0.063 2.3 1.5 2014 10 05 18 06 25.20 + 47.798 32.672 8.2 0.0 6 5 3.0 204 0.322 0.7 0.8 2014 10 05 18 06 56.18 + 47.386 32.760 10.1 0.0 8 5 13.0 185 0.103 0.6 2.6 2014 10 06 00 00 37.87 + 47.378 32.757 12.1 0.0 8 5 12.0 186 0.137 0.7 1.8 2014 10 06 00 19 49.75 + 47.642 32.674 8.2 0.0 6 3 7.0 254 0.027 1.8 1.4 2014 10 06 01 09 18.03 + 47.397 32.760 8.6 0.0 5 4 24.0 241 0.110 0.7 4.5 2014 10 06 01 17 13.74 + 47.391 32.757 9.7 0.0 8 5 13.0 182 0.102 0.5 0.7 2014 10 06 05 38 24.86 + 47.383 32.756 8.9 0.0 8 5 13.0 184 0.193 0.5 1.9 2014 10 06 05 38 24.98 + 47.660 32.658 13.3 0.0 8 5 8.0 147 0.165 0.5 0.8 2014 10 06 15 58 21.98 + 47.516 32.785 10.6 0.0 8 5 14.0 158 0.152 0.4 1.4 2014 10 06 21 54 15.36 + 47.523 32.774 8.3 0.0 5 4 14.0 196 0.009 0.7 3.0 2014 10 06 21 56 55.13 + 47.517 32.784 11.3 0.0 8 5 14.0 157 0.160 0.4 1.4 2014 10 06 22 07 02.66 + 47.704 32.673 5.1 0.0 8 5 7.0 137 0.380 0.4 1.1 2014 10 06 22 21 47.74 + 47.721 32.701 8.9 0.0 7 4 5.0 153 0.195 0.5 0.7 2014 10 06 22 22 56.37 + 47.721 32.676 13.6 0.0 6 4 7.0 162 0.186 1.0 0.9 2014 10 06 22 23 13.91 + 47.717 32.690 10.2 0.0 9 5 6.0 143 0.092 0.4 0.6 2014 10 06 22 23 24.04 + 47.676 32.667 8.6 0.0 8 5 7.0 142 0.263 0.3 0.9 2014 10 06 22 24 23.72 + 47.701 32.679 3.7 0.0 7 4 6.0 133 0.416 0.6 1.6 2014 10 06 22 24 50.75 + 47.704 32.679 12.1 0.0 9 5 6.0 132 0.523 0.4 0.7 2014 10 06 22 25 12.65 + 47.806 32.696 11.7 0.0 9 5 5.0 223 0.074 0.5 0.5 2014 10 07 01 57 38.80 + 47.714 32.630 10.9 0.0 3 4 9.0 204 0.000 99.0 99.0 2014 10 07 10 23 18.38 + 47.621 32.780 12.4 0.0 7 5 7.0 132 0.269 0.4 0.9 2014 10 07 18 25 58.54 + 47.641 32.794 15.3 0.0 7 5 8.0 151 0.507 0.5 0.9 2014 10 08 00 14 26.90 + 47.388 32.757 3.9 0.0 8 5 13.0 183 0.356 1.0 3.4 2014 10 08 00 53 13.54 + 47.392 32.755 2.5 0.0 5 5 13.0 181 0.157 0.6 32.5 2014 10 08 01 45 33.82 + 47.518 32.705 11.8 0.0 8 5 21.0 120 0.113 0.4 1.8 2014 10 08 06 58 22.25 + 47.820 32.704 7.6 0.0 5 4 6.0 239 0.218 0.7 1.2 2014 10 08 13 15 48.28 + 47.739 32.685 10.9 0.0 11 7 7.0 151 0.249 0.5 0.6 2014 10 08 15 34 29.90 + 47.509 32.780 12.6 0.0 11 6 14.0 129 0.168 0.4 1.0 2014 10 08 17 59 47.90 + 47.820 32.703 8.7 0.0 8 4 6.0 239 0.207 0.7 0.5 2014 10 08 20 21 49.91 + 47.729 32.734 2.2 0.0 5 3 5.0 177 0.292 3.3 99.0 2014 10 08 20 49 19.98 + 47.791 32.698 9.6 0.0 6 4 5.0 207 0.026 1.0 1.0 2014 10 08 22 38 09.49 + 47.769 32.684 10.3 0.0 6 4 5.0 172 0.094 0.7 1.3 2014 10 08 22 38 58.13 diff --git a/eqcorrscan/utils/plotting.py b/eqcorrscan/utils/plotting.py index a8620f001..87c182a4a 100644 --- a/eqcorrscan/utils/plotting.py +++ b/eqcorrscan/utils/plotting.py @@ -2187,7 +2187,7 @@ def subspace_fc_plot(detector, stachans, **kwargs): @additional_docstring(plotting_kwargs=plotting_kwargs) -def mapplot(events, bgcolor='#909090', mode='3bode', cpalette='jet_r', +def mapplot(events, bgcolor='#909090', method='depth', cpalette='jet_r', s=1, lw=1, marker=',', **kwargs): """ Plot seismicity in a 2D map with two cross section along latitude and @@ -2199,8 +2199,8 @@ def mapplot(events, bgcolor='#909090', mode='3bode', cpalette='jet_r', down positive or obspy catalog. :type bgcolor: string :param bgcolor: all name or RGB code that acceptable in matplotlib. - :type mode: string - :param mode: + :type method: string + :param method: make color pallete according to thrid part of area 'depth' or occouring time 'time' or occouring sequence 'sequence'. :type cpalette: string @@ -2247,13 +2247,13 @@ def mapplot(events, bgcolor='#909090', mode='3bode', cpalette='jet_r', dep.append(origin.depth) time.append(origin.time) dt = [t-time[0] for t in time] - if mode == 'depth': + if method == 'depth': c0, c1, c2 = dep, lon, lat label0, label1, label2 = 'Depth', 'Longitue', 'Latitude' - elif mode == 'time': + elif method == 'time': c0 = c1 = c2 = dt label = 'second from first event' - elif mode == 'sequence': + elif method == 'sequence': c0 = c1 = c2 = range(len(dep)) label = 'sequence of occuring' fig = plt.figure() @@ -2282,7 +2282,7 @@ def mapplot(events, bgcolor='#909090', mode='3bode', cpalette='jet_r', map2 = ax2.scatter(lon, dep, marker=marker, c=c2, cmap=cpalette, lw=lw, s=s) # location of color bar - if mode == 'depth': + if method == 'depth': # location of colorbar divider0 = make_axes_locatable(ax0) cax0 = divider0.append_axes("top", size="4%", pad="2%") @@ -2302,7 +2302,7 @@ def mapplot(events, bgcolor='#909090', mode='3bode', cpalette='jet_r', pad=0.7) cbar2.set_label(label2, rotation=0, labelpad=-8, x=1.02) ax2.xaxis.set_label_coords(1.02, -0.1) - elif mode == 'time' or mode == 'sequence': + elif method == 'time' or method == 'sequence': divider1 = make_axes_locatable(ax1) cax1 = divider1.append_axes("right", size="4%", pad="2%") cbar1 = fig.colorbar(map1, ax=ax1, cax=cax1, orientation="vertical") From 0be527f8a4faceb75555086285bb18c13d59f5ba Mon Sep 17 00:00:00 2001 From: iman kahbasi Date: Fri, 8 May 2020 21:02:22 +0430 Subject: [PATCH 006/132] convert paramters to kwargs --- eqcorrscan/utils/plotting.py | 37 ++++++++++++------------------------ 1 file changed, 12 insertions(+), 25 deletions(-) diff --git a/eqcorrscan/utils/plotting.py b/eqcorrscan/utils/plotting.py index 87c182a4a..577a22bbc 100644 --- a/eqcorrscan/utils/plotting.py +++ b/eqcorrscan/utils/plotting.py @@ -2187,8 +2187,7 @@ def subspace_fc_plot(detector, stachans, **kwargs): @additional_docstring(plotting_kwargs=plotting_kwargs) -def mapplot(events, bgcolor='#909090', method='depth', cpalette='jet_r', - s=1, lw=1, marker=',', **kwargs): +def mapplot(events, bgcolor='#909090', method='depth', **kwargs): """ Plot seismicity in a 2D map with two cross section along latitude and longitude. @@ -2203,22 +2202,6 @@ def mapplot(events, bgcolor='#909090', method='depth', cpalette='jet_r', :param method: make color pallete according to thrid part of area 'depth' or occouring time 'time' or occouring sequence 'sequence'. - :type cpalette: string - :param cpalette: - color palette for drawing events. acceptable with matplotlib. - :type s: scalar or array_like, shape (n, ), default: None - :param s: - The marker size in points**2. - Default is rcParams['lines.markersize'] ** 2. - :type lw: scalar or array_like, default: None - :param lw: - The linewidth of the marker edges. - If None, defaults to rcParams lines.linewidth. - :type marker: string - :param marker: - The marker style. *marker* can be either an instance of the class - or the text shorthand for a particular marker. - Defaults to '.' {plotting_kwargs} :returns: :class:`matplotlib.figure.Figure` @@ -2231,7 +2214,14 @@ def mapplot(events, bgcolor='#909090', method='depth', cpalette='jet_r', from matplotlib import gridspec from mpl_toolkits.axes_grid1 import make_axes_locatable from obspy import Catalog - # set parameter + # set default parameters of plt.scatter + default_parameters = {'cmap': 'jet_r', 'marker': ',', 's': 1, 'lw': 1} + for key in default_parameters.keys(): + if key not in kwargs.keys(): + kwargs[key] = default_parameters[key] + # set default parameters of _finalise_figure + if "size" not in kwargs.keys(): + kwargs.update({"size": (10, 13)}) if isinstance(events, list): if len(events[0]) == 4: lat, lon, dep, time = zip(*events) @@ -2264,23 +2254,20 @@ def mapplot(events, bgcolor='#909090', method='depth', cpalette='jet_r', ax0.set_facecolor(bgcolor) ax0.set_ylabel('Latitude') ax0.set_xticks([]) - map0 = ax0.scatter(lon, lat, marker=marker, c=c0, cmap=cpalette, - lw=lw, s=s) + map0 = ax0.scatter(lon, lat, c=c0, **kwargs) # cross section paralel to latitude (lat ,depth) ax1 = fig.add_subplot(gs[1]) ax1.set_facecolor(bgcolor) ax1.set_yticks([]) ax1.set_xlabel('Depth') ax1.invert_xaxis() - map1 = ax1.scatter(dep, lat, marker=marker, c=c1, cmap=cpalette, - lw=lw, s=s) + map1 = ax1.scatter(dep, lat, c=c1, **kwargs) # cross section paralel to longitude (lon ,depth) ax2 = plt.subplot(gs[2]) ax2.set_facecolor(bgcolor) ax2.set_ylabel('Depth') ax2.set_xlabel('Longitude') - map2 = ax2.scatter(lon, dep, marker=marker, c=c2, cmap=cpalette, - lw=lw, s=s) + map2 = ax2.scatter(lon, dep, c=c2, **kwargs) # location of color bar if method == 'depth': # location of colorbar From dd1cd044799ef3d0baffb41bd4c2438e6fe4ad70 Mon Sep 17 00:00:00 2001 From: iman kahbasi Date: Fri, 8 May 2020 21:10:35 +0430 Subject: [PATCH 007/132] making corrections to the labels --- eqcorrscan/utils/plotting.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/eqcorrscan/utils/plotting.py b/eqcorrscan/utils/plotting.py index 577a22bbc..139dc3471 100644 --- a/eqcorrscan/utils/plotting.py +++ b/eqcorrscan/utils/plotting.py @@ -2239,13 +2239,13 @@ def mapplot(events, bgcolor='#909090', method='depth', **kwargs): dt = [t-time[0] for t in time] if method == 'depth': c0, c1, c2 = dep, lon, lat - label0, label1, label2 = 'Depth', 'Longitue', 'Latitude' + label0, label1, label2 = 'Depth (km)', 'Longitude', 'Latitude' elif method == 'time': c0 = c1 = c2 = dt - label = 'second from first event' + label = 'Origin-time offset from {time[0]} (s)' elif method == 'sequence': c0 = c1 = c2 = range(len(dep)) - label = 'sequence of occuring' + label = 'Event number' fig = plt.figure() gs = gridspec.GridSpec(2, 2, width_ratios=[3, 1], height_ratios=[3, 1], wspace=0.01, hspace=0.01) From f35bb8541572005d3ee3e49aa9b757cd2fc77ca8 Mon Sep 17 00:00:00 2001 From: iman kahbasi Date: Fri, 8 May 2020 22:59:59 +0430 Subject: [PATCH 008/132] Inputs of the function changed --- eqcorrscan/utils/plotting.py | 52 +++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/eqcorrscan/utils/plotting.py b/eqcorrscan/utils/plotting.py index 139dc3471..ee87ecd2e 100644 --- a/eqcorrscan/utils/plotting.py +++ b/eqcorrscan/utils/plotting.py @@ -2187,15 +2187,18 @@ def subspace_fc_plot(detector, stachans, **kwargs): @additional_docstring(plotting_kwargs=plotting_kwargs) -def mapplot(events, bgcolor='#909090', method='depth', **kwargs): +def mapplot(catalog=None, locations=None, bgcolor='#909090', method='depth', + **kwargs): """ Plot seismicity in a 2D map with two cross section along latitude and longitude. - :type events: list or 'obspy.core.event.catalog.Catalog' - :param events: - list of one tuple per event of (lat, long, depth(optional)) with - down positive or obspy catalog. + :type catalog: obspy.core.event.catalog.Catalog + :param catalog: Obspy catalog class containing event metadata + :type locations: list + :param locations: + list of one tuple per event of (lat, long, depth, time) with + down positive, if location doesn't have time or depth then set to zero. :type bgcolor: string :param bgcolor: all name or RGB code that acceptable in matplotlib. :type method: string @@ -2213,7 +2216,6 @@ def mapplot(events, bgcolor='#909090', method='depth', **kwargs): import matplotlib.pyplot as plt from matplotlib import gridspec from mpl_toolkits.axes_grid1 import make_axes_locatable - from obspy import Catalog # set default parameters of plt.scatter default_parameters = {'cmap': 'jet_r', 'marker': ',', 's': 1, 'lw': 1} for key in default_parameters.keys(): @@ -2222,25 +2224,31 @@ def mapplot(events, bgcolor='#909090', method='depth', **kwargs): # set default parameters of _finalise_figure if "size" not in kwargs.keys(): kwargs.update({"size": (10, 13)}) - if isinstance(events, list): - if len(events[0]) == 4: - lat, lon, dep, time = zip(*events) - dt = [t-time[0] for t in time] - elif len(events[0]) == 3: - lat, lon, dep = zip(*events) - elif isinstance(events, Catalog): - lat, lon, dep, time = [], [], [], [] - for ev in events: - origin = ev.origins[0] - lat.append(origin.latitude) - lon.append(origin.longitude) - dep.append(origin.depth) - time.append(origin.time) - dt = [t-time[0] for t in time] + # making coordinates + assert (catalog and locations) or catalog or locations,\ + "Requires catalog and/or locations" + locations = locations or [] + msg = "An event of the catalog got ignored, because it didn't have origin" + if catalog: + for event in catalog: + try: + origin = event.preferred_origin() or event.origins[0] + except IndexError: # No origin found + Logger.warning(msg) + continue + _lat = origin.latitude + _lon = origin.longitude + _dep = origin.depth / 1000 + _time = origin.time + locations.append((_lat, _lon, _dep, _time)) + if method in ['time', 'sequence']: + locations.sort(key=lambda ind: ind[3]) + lat, lon, dep, time = zip(*locations) if method == 'depth': c0, c1, c2 = dep, lon, lat label0, label1, label2 = 'Depth (km)', 'Longitude', 'Latitude' elif method == 'time': + dt = [t - time[0] for t in time] c0 = c1 = c2 = dt label = 'Origin-time offset from {time[0]} (s)' elif method == 'sequence': @@ -2270,7 +2278,7 @@ def mapplot(events, bgcolor='#909090', method='depth', **kwargs): map2 = ax2.scatter(lon, dep, c=c2, **kwargs) # location of color bar if method == 'depth': - # location of colorbar + # divider0 = make_axes_locatable(ax0) cax0 = divider0.append_axes("top", size="4%", pad="2%") cbar0 = fig.colorbar(map0, ax=ax0, cax=cax0, orientation="horizontal") From abef7b19f43b9a4d0a530a38587259788e11b4ae Mon Sep 17 00:00:00 2001 From: iman kahbasi Date: Fri, 8 May 2020 23:05:58 +0430 Subject: [PATCH 009/132] The function's name changed --- eqcorrscan/utils/plotting.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eqcorrscan/utils/plotting.py b/eqcorrscan/utils/plotting.py index ee87ecd2e..f8bdcd517 100644 --- a/eqcorrscan/utils/plotting.py +++ b/eqcorrscan/utils/plotting.py @@ -2187,8 +2187,8 @@ def subspace_fc_plot(detector, stachans, **kwargs): @additional_docstring(plotting_kwargs=plotting_kwargs) -def mapplot(catalog=None, locations=None, bgcolor='#909090', method='depth', - **kwargs): +def twoD_seismplot(catalog=None, locations=None, bgcolor='#909090', + method='depth', **kwargs): """ Plot seismicity in a 2D map with two cross section along latitude and longitude. From 6692de4cb3f92accb267ef7b19ce39fd0c05b97b Mon Sep 17 00:00:00 2001 From: iman kahbasi Date: Fri, 8 May 2020 23:31:13 +0430 Subject: [PATCH 010/132] Changing tests appropriate to new changes --- eqcorrscan/tests/plotting_test.py | 44 ++++++++++++++++++------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/eqcorrscan/tests/plotting_test.py b/eqcorrscan/tests/plotting_test.py index bff1357f7..8364697fa 100644 --- a/eqcorrscan/tests/plotting_test.py +++ b/eqcorrscan/tests/plotting_test.py @@ -17,7 +17,7 @@ detection_multiplot, interev_mag, obspy_3d_plot, noise_plot, pretty_template_plot, plot_repicked, svd_plot, plot_synth_real, freq_mag, spec_trace, subspace_detector_plot, subspace_fc_plot, - mapplot) + twoD_seismplot) from eqcorrscan.utils.stacking import align_traces from eqcorrscan.utils import findpeaks from eqcorrscan.core.match_filter import normxcorr2 @@ -53,39 +53,45 @@ def setUpClass(cls): cls.nodes.append((Lat, Lon, Dep, time)) @pytest.mark.mpl_image_compare - def test_mapplot_depth_catalog(self): - fig = mapplot(self.catalog, method='depth', show=False, - return_figure=True) + def test_twoD_seismplot_depth_catalog(self): + fig = twoD_seismplot( + catalg=self.catalog, method='depth', + show=False, return_figure=True) return fig @pytest.mark.mpl_image_compare - def test_mapplot_time_catalog(self): - fig = mapplot(self.catalog, method='time', show=False, - return_figure=True) + def test_twoD_seismplot_time_catalog(self): + fig = twoD_seismplot( + catalog=self.catalog, method='time', + show=False, return_figure=True) return fig @pytest.mark.mpl_image_compare - def test_mapplot_sequence_catalog(self): - fig = mapplot(self.catalog, method='sequence', show=False, - return_figure=True) + def test_twoD_seismplot_sequence_catalog(self): + fig = twoD_seismplot( + catalog=self.catalog, method='sequence', + show=False, return_figure=True) return fig @pytest.mark.mpl_image_compare - def test_mapplot_depth_nodes(self): - fig = mapplot(self.nodes, method='depth', show=False, - return_figure=True) + def test_twoD_seismplot_depth_locations(self): + fig = twoD_seismplot( + locations=self.nodes, method='depth', + show=False, return_figure=True) return fig @pytest.mark.mpl_image_compare - def test_mapplot_time_nodes(self): - fig = mapplot(self.nodes, method='time', show=False, - return_figure=True) + def test_twoD_seismplot_time_locations(self): + fig = twoD_seismplot( + locations=self.nodes, method='time', + show=False, return_figure=True) return fig @pytest.mark.mpl_image_compare - def test_mapplot_sequence_nodes(self): - fig = mapplot(self.nodes, method='sequence', show=False, - return_figure=True) + def test_twoD_seismplot_sequence_nodes(self): + fig = twoD_seismplot( + locations=self.nodes, method='sequence', + show=False, return_figure=True) return fig From 7f27447968c7663f29f45e99f7670e2133ee23c3 Mon Sep 17 00:00:00 2001 From: iman kahbasi Date: Fri, 15 May 2020 23:09:32 +0430 Subject: [PATCH 011/132] pass kwargs to scatter functions --- eqcorrscan/utils/plotting.py | 37 ++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/eqcorrscan/utils/plotting.py b/eqcorrscan/utils/plotting.py index f8bdcd517..446062c30 100644 --- a/eqcorrscan/utils/plotting.py +++ b/eqcorrscan/utils/plotting.py @@ -2198,35 +2198,41 @@ def twoD_seismplot(catalog=None, locations=None, bgcolor='#909090', :type locations: list :param locations: list of one tuple per event of (lat, long, depth, time) with - down positive, if location doesn't have time or depth then set to zero. + down positive. :type bgcolor: string - :param bgcolor: all name or RGB code that acceptable in matplotlib. + :param bgcolor: Background's color of map and sections. + all name or RGB code that acceptable in matplotlib. :type method: string :param method: - make color pallete according to thrid part of area 'depth' or - occouring time 'time' or occouring sequence 'sequence'. + making color palette of locations according to 'depth', 'time' or + 'sequence'. {plotting_kwargs} :returns: :class:`matplotlib.figure.Figure` - .. image:: ../doc/plots/mapplot_depth.png - .. image:: ../doc/plots/mapplot_time.png - .. image:: ../doc/plots/mapplot_sequrnce.png + .. note:: + If each location doesn't have time or depth, set them to zero. + .. note:: + kwargs accepts all option that available in + `matplotlib.axes.Axes.scatter`. """ import matplotlib.pyplot as plt from matplotlib import gridspec from mpl_toolkits.axes_grid1 import make_axes_locatable - # set default parameters of plt.scatter + assert (catalog and locations) or catalog or locations,\ + "Requires catalog and/or locations" + # set default parameters of plt.scatter() default_parameters = {'cmap': 'jet_r', 'marker': ',', 's': 1, 'lw': 1} for key in default_parameters.keys(): if key not in kwargs.keys(): kwargs[key] = default_parameters[key] - # set default parameters of _finalise_figure - if "size" not in kwargs.keys(): - kwargs.update({"size": (10, 13)}) + # get parameters of _finalise_figure + _kwargs = {} + for key in ['title', 'show', 'save', 'savefile', 'return_fig', 'size']: + if key in kwargs.keys(): + _kwargs[key] = kwargs[key] + del kwargs[key] # making coordinates - assert (catalog and locations) or catalog or locations,\ - "Requires catalog and/or locations" locations = locations or [] msg = "An event of the catalog got ignored, because it didn't have origin" if catalog: @@ -2241,8 +2247,11 @@ def twoD_seismplot(catalog=None, locations=None, bgcolor='#909090', _dep = origin.depth / 1000 _time = origin.time locations.append((_lat, _lon, _dep, _time)) + # sort location according to method if method in ['time', 'sequence']: locations.sort(key=lambda ind: ind[3]) + elif method == 'depth': + locations.sort(reverse=False, key=lambda ind: ind[2]) lat, lon, dep, time = zip(*locations) if method == 'depth': c0, c1, c2 = dep, lon, lat @@ -2302,7 +2311,7 @@ def twoD_seismplot(catalog=None, locations=None, bgcolor='#909090', cax1 = divider1.append_axes("right", size="4%", pad="2%") cbar1 = fig.colorbar(map1, ax=ax1, cax=cax1, orientation="vertical") cbar1.set_label(label) - fig = _finalise_figure(fig=fig, **kwargs) # pragma: no cover + fig = _finalise_figure(fig=fig, **_kwargs) # pragma: no cover return fig From 34acab7eaada162c36057a911c4bdc7de9106592 Mon Sep 17 00:00:00 2001 From: iman kahbasi Date: Sat, 16 May 2020 09:56:53 +0430 Subject: [PATCH 012/132] One output is enough --- eqcorrscan/doc/plots/mapplot_sequence.png | Bin 75286 -> 0 bytes eqcorrscan/doc/plots/mapplot_time.png | Bin 80562 -> 0 bytes ...pplot_depth.png => twoD_seismplot-depth.png} | Bin 3 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 eqcorrscan/doc/plots/mapplot_sequence.png delete mode 100644 eqcorrscan/doc/plots/mapplot_time.png rename eqcorrscan/doc/plots/{mapplot_depth.png => twoD_seismplot-depth.png} (100%) diff --git a/eqcorrscan/doc/plots/mapplot_sequence.png b/eqcorrscan/doc/plots/mapplot_sequence.png deleted file mode 100644 index 59bf6b8d968355f7f3772d49b4359fd530649bb9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 75286 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≪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%0D?B0`V}cyT0PPN4BTqW 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 z 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 vZ&STd0NADcO;_?s*{820Mn3 Date: Sat, 16 May 2020 10:29:14 +0430 Subject: [PATCH 013/132] down is positive now --- eqcorrscan/utils/plotting.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/eqcorrscan/utils/plotting.py b/eqcorrscan/utils/plotting.py index 446062c30..c94bbc76a 100644 --- a/eqcorrscan/utils/plotting.py +++ b/eqcorrscan/utils/plotting.py @@ -2272,16 +2272,16 @@ def twoD_seismplot(catalog=None, locations=None, bgcolor='#909090', ax0.set_ylabel('Latitude') ax0.set_xticks([]) map0 = ax0.scatter(lon, lat, c=c0, **kwargs) - # cross section paralel to latitude (lat ,depth) + # cross section parallel to latitude (lat ,depth) ax1 = fig.add_subplot(gs[1]) ax1.set_facecolor(bgcolor) ax1.set_yticks([]) ax1.set_xlabel('Depth') - ax1.invert_xaxis() map1 = ax1.scatter(dep, lat, c=c1, **kwargs) - # cross section paralel to longitude (lon ,depth) + # cross section parallel to longitude (lon ,depth) ax2 = plt.subplot(gs[2]) ax2.set_facecolor(bgcolor) + ax2.invert_yaxis() ax2.set_ylabel('Depth') ax2.set_xlabel('Longitude') map2 = ax2.scatter(lon, dep, c=c2, **kwargs) From 38f01a19aedb311edcf35d415a61de2ef48cc8ea Mon Sep 17 00:00:00 2001 From: iman kahbasi Date: Sat, 16 May 2020 10:58:41 +0430 Subject: [PATCH 014/132] test script changed for twoD_seismplot and catalog.txt removed --- eqcorrscan/tests/plotting_test.py | 54 +-- eqcorrscan/tests/test_data/catalog.txt | 573 ------------------------- eqcorrscan/utils/plotting.py | 2 +- 3 files changed, 9 insertions(+), 620 deletions(-) delete mode 100644 eqcorrscan/tests/test_data/catalog.txt diff --git a/eqcorrscan/tests/plotting_test.py b/eqcorrscan/tests/plotting_test.py index 8364697fa..8da5da9d7 100644 --- a/eqcorrscan/tests/plotting_test.py +++ b/eqcorrscan/tests/plotting_test.py @@ -27,35 +27,18 @@ class SeimicityPlottingMethods(unittest.TestCase): @classmethod def setUpClass(cls): - sfiles = glob.glob(os.path.join( - os.path.dirname(os.path.abspath(__file__)), - 'test_data/REA/TEST_/*.S??????')) - cls.catalog = Catalog() - for sfile in sfiles: - cls.catalog += read_events(sfile) - cls.nodes = [] - data = np.genfromtxt("./catalog.txt") - lon = data[:, 0] - lat = data[:, 1] - dep = data[:, 2] * -1 - sec = data[:, -1].astype(str) - mint = data[:, -2].astype(int).astype(str) - hour = data[:, -3].astype(int).astype(str) - day = data[:, -4].astype(int).astype(str) - month = data[:, -5].astype(int).astype(str) - year = data[:, -6].astype(int).astype(str) - Date = [] - for ii in range(len(year)): - date = '{}-{}-{}T{}:{}:{}'.format( - year[ii], month[ii], day[ii], hour[ii], mint[ii], sec[ii]) - Date.append(UTCDateTime(date)) - for Lat, Lon, Dep, time in zip(lat, lon, dep, Date): - cls.nodes.append((Lat, Lon, Dep, time)) + from obspy.clients.fdsn import Client + client = Client("IRIS") + starttime = UTCDateTime("2000-01-01") + endtime = UTCDateTime("2020-05-16") + cls.catalog = client.get_events( + starttime=starttime, endtime=endtime, latitude=32.5, + longitude=47.5, maxradius=0.7) @pytest.mark.mpl_image_compare def test_twoD_seismplot_depth_catalog(self): fig = twoD_seismplot( - catalg=self.catalog, method='depth', + catalog=self.catalog, method='depth', show=False, return_figure=True) return fig @@ -73,27 +56,6 @@ def test_twoD_seismplot_sequence_catalog(self): show=False, return_figure=True) return fig - @pytest.mark.mpl_image_compare - def test_twoD_seismplot_depth_locations(self): - fig = twoD_seismplot( - locations=self.nodes, method='depth', - show=False, return_figure=True) - return fig - - @pytest.mark.mpl_image_compare - def test_twoD_seismplot_time_locations(self): - fig = twoD_seismplot( - locations=self.nodes, method='time', - show=False, return_figure=True) - return fig - - @pytest.mark.mpl_image_compare - def test_twoD_seismplot_sequence_nodes(self): - fig = twoD_seismplot( - locations=self.nodes, method='sequence', - show=False, return_figure=True) - return fig - class MultiStreamMethods(unittest.TestCase): @classmethod diff --git a/eqcorrscan/tests/test_data/catalog.txt b/eqcorrscan/tests/test_data/catalog.txt deleted file mode 100644 index d7d423754..000000000 --- a/eqcorrscan/tests/test_data/catalog.txt +++ /dev/null @@ -1,573 +0,0 @@ - 47.708 32.737 9.1 0.0 7 5 3.0 166 0.176 0.6 0.6 2014 09 15 00 31 41.45 - 47.660 32.739 8.6 0.0 10 5 2.0 128 0.205 0.4 0.6 2014 09 15 00 43 46.67 - 47.654 32.734 9.2 0.0 10 5 2.0 106 0.258 0.4 0.6 2014 09 15 00 46 28.18 - 47.625 32.713 7.4 0.0 7 4 5.0 131 0.151 0.4 0.8 2014 09 15 00 48 44.38 - 47.718 32.745 9.2 0.0 9 5 4.0 176 0.200 0.4 0.6 2014 09 15 00 58 33.25 - 47.531 32.722 12.4 0.0 12 6 14.0 103 0.132 0.3 1.0 2014 09 15 01 04 57.58 - 47.711 32.733 9.7 0.0 11 6 3.0 166 0.183 0.4 0.4 2014 09 15 03 01 04.07 - 47.807 32.788 14.4 0.0 6 4 14.0 243 0.524 2.3 3.0 2014 09 15 03 12 35.41 - 47.548 32.760 9.4 0.0 10 6 12.0 92 0.139 0.3 1.1 2014 09 15 05 48 47.28 - 47.561 32.757 10.8 0.0 7 4 11.0 126 0.147 0.8 1.9 2014 09 15 05 50 05.36 - 47.647 32.743 6.4 0.0 10 5 15.0 136 0.072 0.4 2.3 2014 09 15 06 07 35.76 - 47.635 32.775 20.6 0.0 7 4 6.0 149 0.524 0.9 0.9 2014 09 15 07 32 21.20 - 47.539 32.718 10.3 0.0 12 6 13.0 105 0.256 0.3 1.1 2014 09 15 08 32 31.23 - 47.534 32.722 10.8 0.0 11 6 13.0 103 0.219 0.3 1.2 2014 09 15 08 34 48.02 - 47.778 32.688 10.1 0.0 5 4 5.0 186 0.057 1.6 1.4 2014 09 15 09 03 54.87 - 47.419 32.712 13.8 0.0 12 6 14.0 117 0.115 0.3 1.0 2014 09 15 09 43 08.93 - 47.417 32.713 12.4 0.0 10 6 14.0 119 0.175 0.4 1.2 2014 09 15 10 15 18.99 - 47.419 32.708 14.2 0.0 6 6 19.0 194 0.041 0.6 1.3 2014 09 15 10 20 55.80 - 47.421 32.712 10.6 0.0 8 6 14.0 117 0.095 0.4 2.2 2014 09 15 10 21 35.52 - 47.846 32.721 7.9 0.0 9 5 9.0 258 0.437 0.8 1.0 2014 09 15 10 41 27.23 - 47.408 32.714 16.0 0.0 11 6 13.0 122 0.180 0.4 0.9 2014 09 15 11 20 03.66 - 47.420 32.713 10.7 0.0 12 6 14.0 118 0.173 0.4 1.4 2014 09 15 11 28 24.70 - 47.419 32.710 13.5 0.0 11 6 14.0 117 0.131 0.3 1.2 2014 09 15 13 28 12.60 - 47.776 32.700 10.9 0.0 9 5 10.0 281 0.140 0.7 1.1 2014 09 15 17 59 51.23 - 47.785 32.691 9.1 0.0 10 5 5.0 195 0.158 0.7 0.5 2014 09 15 17 59 51.28 - 47.657 32.686 9.9 0.0 10 5 6.0 129 0.095 0.3 0.7 2014 09 15 20 26 53.35 - 47.563 32.756 12.9 0.0 10 6 11.0 94 0.174 0.3 0.9 2014 09 15 20 27 29.49 - 47.773 32.669 10.8 0.0 8 4 4.0 184 0.106 1.7 0.7 2014 09 15 20 45 04.95 - 47.580 32.748 8.8 0.0 7 4 9.0 116 0.423 0.5 1.4 2014 09 15 21 00 07.61 - 47.586 32.796 13.8 0.0 6 5 9.0 110 0.532 0.6 1.2 2014 09 15 21 02 36.91 - 47.814 32.719 8.1 0.0 7 5 8.0 234 0.138 0.6 1.3 2014 09 15 21 44 51.09 - 47.516 32.724 12.6 0.0 10 5 15.0 154 0.151 0.4 1.2 2014 09 15 22 48 52.00 - 47.414 32.706 19.7 0.0 10 6 13.0 116 0.365 0.4 0.9 2014 09 15 23 45 19.09 - 47.362 32.727 21.0 0.0 8 6 9.0 148 0.580 0.7 1.0 2014 09 16 01 42 42.85 - 47.724 32.675 0.0 0.0 5 4 8.0 144 0.217 0.8 1.0 2014 09 16 05 22 27.92 - 47.578 32.784 8.6 0.0 10 6 11.0 102 0.105 0.4 1.1 2014 09 16 09 05 42.74 - 47.580 32.781 12.7 0.0 7 5 11.0 128 0.290 0.7 1.2 2014 09 16 09 05 53.92 - 47.642 32.671 13.3 0.0 11 6 8.0 138 0.199 0.4 0.8 2014 09 16 14 28 11.81 - 47.608 32.664 14.1 0.0 4 6 10.0 193 0.001 1.4 2.4 2014 09 16 15 27 52.24 - 47.777 32.671 10.8 0.0 10 6 3.0 165 0.190 0.5 0.6 2014 09 16 15 29 37.25 - 47.786 32.694 9.1 0.0 7 5 5.0 198 0.169 0.5 0.6 2014 09 16 15 31 00.88 - 47.817 32.661 14.4 0.0 9 5 2.0 263 0.234 0.6 0.6 2014 09 16 15 31 32.80 - 47.819 32.796 1.3 0.0 6 4 15.0 250 0.175 1.1 1.1 2014 09 16 16 07 57.78 - 47.813 32.725 7.5 0.0 10 6 8.0 234 0.294 0.5 0.9 2014 09 16 20 32 23.59 - 47.828 32.738 1.1 0.0 7 5 10.0 245 0.219 1.0 1.5 2014 09 16 20 34 10.57 - 47.850 32.725 14.5 0.0 7 5 9.0 260 0.359 0.8 0.9 2014 09 16 20 35 23.92 - 47.813 32.715 10.4 0.0 9 6 7.0 233 0.157 0.6 0.7 2014 09 16 20 49 00.17 - 47.793 32.698 10.9 0.0 7 5 5.0 209 0.063 0.8 0.8 2014 09 16 20 51 37.85 - 47.825 32.656 8.7 0.0 5 4 2.0 290 0.630 1.4 1.0 2014 09 16 20 57 19.48 - 47.812 32.725 7.5 0.0 10 6 8.0 233 0.281 0.5 0.9 2014 09 16 21 07 34.01 - 47.818 32.713 11.0 0.0 8 5 7.0 237 0.175 0.6 0.8 2014 09 16 21 08 34.24 - 47.808 32.710 9.3 0.0 6 6 7.0 227 0.023 0.6 0.6 2014 09 16 21 17 27.53 - 47.590 32.803 7.9 0.0 9 5 8.0 116 0.149 0.4 1.3 2014 09 16 21 42 37.97 - 47.590 32.802 7.5 0.0 8 5 8.0 115 0.159 0.4 1.5 2014 09 16 21 42 49.42 - 47.806 32.711 10.4 0.0 7 4 7.0 226 0.223 0.8 0.9 2014 09 16 21 59 08.48 - 47.606 32.663 17.1 0.0 10 6 10.0 140 0.149 0.4 1.1 2014 09 16 22 53 11.24 - 47.759 32.656 13.1 0.0 6 5 4.0 177 0.202 1.1 1.1 2014 09 17 02 28 19.22 - 47.781 32.770 14.3 0.0 5 4 11.0 224 0.002 1.7 1.8 2014 09 17 04 48 18.96 - 47.821 32.801 2.1 0.0 6 6 15.0 252 0.065 0.7 99.0 2014 09 17 05 30 27.11 - 47.808 32.709 8.5 0.0 7 4 7.0 228 0.043 0.5 0.9 2014 09 17 10 31 05.11 - 47.821 32.799 2.5 0.0 5 5 15.0 252 0.087 2.5 99.0 2014 09 17 10 34 37.87 - 47.553 32.711 18.0 0.0 10 6 12.0 110 0.421 0.4 0.9 2014 09 17 14 43 49.91 - 47.605 32.771 8.1 0.0 11 6 8.0 116 0.129 0.3 0.9 2014 09 17 16 48 05.93 - 47.604 32.773 8.4 0.0 7 6 8.0 161 0.044 0.5 1.0 2014 09 17 16 51 34.82 - 47.813 32.727 3.7 0.0 5 4 9.0 234 0.141 1.9 6.5 2014 09 17 19 26 25.15 - 47.835 32.734 2.0 0.0 6 4 10.0 250 0.243 0.8 33.3 2014 09 17 19 26 37.35 - 47.767 32.668 12.0 0.0 7 4 4.0 152 0.136 0.6 0.7 2014 09 17 19 58 35.88 - 47.709 32.616 13.5 0.0 9 6 10.0 186 0.096 0.5 0.8 2014 09 17 21 24 35.74 - 47.567 32.755 9.3 0.0 11 6 11.0 95 0.134 0.3 1.0 2014 09 17 21 55 37.79 - 47.582 32.699 10.2 0.0 11 6 10.0 118 0.111 0.3 1.0 2014 09 17 22 13 39.81 - 47.803 32.722 2.3 0.0 7 4 8.0 225 0.210 0.7 13.9 2014 09 17 22 32 17.31 - 47.627 32.721 9.1 0.0 8 6 5.0 110 0.072 0.4 1.2 2014 09 17 22 46 21.49 - 47.709 32.610 14.0 0.0 7 4 10.0 191 0.031 0.6 0.9 2014 09 17 22 57 30.95 - 47.681 32.618 18.7 0.0 6 4 12.0 179 0.399 0.7 0.9 2014 09 17 23 23 36.01 - 47.574 32.702 10.0 0.0 10 6 10.0 116 0.117 0.3 0.8 2014 09 18 01 01 40.46 - 47.577 32.703 9.8 0.0 6 5 10.0 118 0.150 0.4 2.7 2014 09 18 02 11 19.06 - 47.755 32.786 8.7 0.0 10 6 9.0 216 0.413 0.6 1.0 2014 09 18 02 13 50.00 - 47.885 32.655 12.7 0.0 12 6 8.0 300 0.128 0.6 0.5 2014 09 18 02 18 15.73 - 47.895 32.602 17.8 0.0 3 4 10.0 352 0.048 99.0 99.0 2014 09 18 02 18 49.28 - 47.879 32.711 0.0 0.0 5 5 10.0 280 0.181 1.1 1.3 2014 09 18 02 19 01.16 - 47.886 32.654 12.4 0.0 12 6 8.0 300 0.132 0.6 0.5 2014 09 18 02 20 13.10 - 47.823 32.592 15.5 0.0 6 5 7.0 277 0.070 0.9 1.1 2014 09 18 02 21 51.06 - 47.886 32.654 12.7 0.0 11 6 8.0 300 0.108 0.6 0.6 2014 09 18 02 22 06.83 - 47.900 32.649 13.1 0.0 8 5 9.0 302 0.291 0.7 0.6 2014 09 18 02 28 29.77 - 47.870 32.640 12.1 0.0 10 5 6.0 298 0.281 0.6 0.5 2014 09 18 02 34 31.15 - 47.885 32.654 12.5 0.0 12 6 8.0 300 0.107 0.6 0.5 2014 09 18 02 58 17.77 - 47.894 32.651 13.0 0.0 3 6 8.0 340 0.001 99.0 99.0 2014 09 18 02 58 46.26 - 47.881 32.637 14.2 0.0 8 5 7.0 300 0.377 0.7 0.7 2014 09 18 03 00 10.51 - 47.877 32.648 12.0 0.0 6 4 7.0 316 0.085 1.2 0.6 2014 09 18 03 04 43.74 - 47.825 32.624 7.0 0.0 8 5 4.0 290 0.608 0.7 0.6 2014 09 18 03 06 52.19 - 47.933 32.719 2.1 0.0 6 6 14.0 302 0.010 0.8 3.0 2014 09 18 03 11 46.09 - 47.833 32.610 13.9 0.0 8 5 5.0 289 0.063 0.6 0.7 2014 09 18 03 20 38.86 - 47.884 32.655 12.7 0.0 9 5 7.0 300 0.105 0.6 0.6 2014 09 18 03 34 57.42 - 47.801 32.687 9.8 0.0 9 6 4.0 215 0.080 0.6 0.4 2014 09 18 03 37 51.00 - 47.767 32.707 12.8 0.0 8 6 7.0 189 0.383 0.6 0.7 2014 09 18 03 39 48.29 - 47.746 32.671 11.9 0.0 7 5 6.0 161 0.295 1.0 0.7 2014 09 18 03 45 33.55 - 47.734 32.633 11.1 0.0 7 4 7.0 248 0.318 1.8 1.0 2014 09 18 03 49 04.99 - 47.775 32.700 10.5 0.0 9 6 6.0 191 0.250 0.5 0.6 2014 09 18 03 49 06.10 - 47.762 32.647 10.9 0.0 5 4 4.0 232 0.178 2.2 1.0 2014 09 18 03 51 20.03 - 47.771 32.713 10.1 0.0 6 6 8.0 195 0.137 0.7 0.7 2014 09 18 03 52 27.37 - 47.758 32.639 11.6 0.0 6 4 5.0 245 0.141 2.2 0.8 2014 09 18 03 53 27.64 - 47.776 32.703 10.1 0.0 9 6 6.0 193 0.282 0.5 0.6 2014 09 18 03 54 10.13 - 47.759 32.643 11.6 0.0 7 4 4.0 239 0.149 1.9 0.8 2014 09 18 03 58 18.22 - 47.761 32.700 11.3 0.0 8 6 7.0 179 0.288 0.5 0.7 2014 09 18 03 59 17.89 - 47.797 32.694 2.0 0.0 5 4 5.0 213 0.254 1.3 1.1 2014 09 18 04 17 34.42 - 47.807 32.659 10.8 0.0 6 5 1.0 230 0.112 0.7 0.8 2014 09 18 04 30 13.41 - 47.729 32.718 11.8 0.0 4 5 5.0 168 0.001 0.7 0.7 2014 09 18 04 40 04.49 - 47.747 32.628 12.3 0.0 5 4 6.0 256 0.232 2.1 1.1 2014 09 18 04 40 30.70 - 47.797 32.687 11.6 0.0 10 5 4.0 209 0.185 0.5 0.6 2014 09 18 05 52 36.38 - 47.711 32.615 13.8 0.0 9 6 10.0 187 0.092 0.5 0.8 2014 09 18 07 10 06.60 - 47.735 32.648 14.9 0.0 6 6 7.0 161 0.078 1.2 1.5 2014 09 18 07 10 58.46 - 47.704 32.616 14.2 0.0 9 6 10.0 185 0.075 0.6 0.8 2014 09 18 07 17 55.18 - 47.758 32.647 10.4 0.0 5 4 4.0 232 0.153 2.1 1.0 2014 09 18 07 25 33.39 - 47.803 32.788 10.9 0.0 7 5 13.0 241 0.096 1.2 1.0 2014 09 18 08 44 40.27 - 47.724 32.630 13.9 0.0 6 4 8.0 178 0.035 0.7 0.9 2014 09 18 08 57 23.38 - 47.697 32.642 11.2 0.0 6 5 10.0 162 0.299 0.6 1.0 2014 09 18 09 08 19.14 - 47.786 32.617 14.6 0.0 7 5 4.0 231 0.425 0.8 0.8 2014 09 18 09 11 36.52 - 47.572 32.704 10.0 0.0 11 6 10.0 115 0.118 0.3 1.0 2014 09 18 09 51 21.74 - 47.573 32.703 9.8 0.0 11 6 10.0 116 0.102 0.3 1.0 2014 09 18 10 07 09.72 - 47.685 32.571 3.4 0.0 5 4 14.0 281 0.423 1.2 2.6 2014 09 18 10 38 12.49 - 47.799 32.577 18.6 0.0 7 4 8.0 317 0.291 2.5 0.9 2014 09 18 10 52 54.64 - 47.778 32.670 10.9 0.0 9 5 3.0 165 0.088 0.5 0.6 2014 09 18 11 50 57.28 - 47.835 32.699 12.3 0.0 8 4 6.0 254 0.405 0.6 0.6 2014 09 18 11 53 58.65 - 47.467 32.712 15.5 0.0 11 6 19.0 103 0.145 0.3 1.0 2014 09 18 12 42 02.24 - 47.858 32.798 16.1 0.0 6 4 17.0 267 0.401 2.2 2.5 2014 09 18 15 50 47.62 - 47.867 32.644 12.8 0.0 7 5 6.0 298 0.103 0.7 0.7 2014 09 18 15 53 52.22 - 47.804 32.790 9.6 0.0 10 6 13.0 242 0.101 0.6 0.5 2014 09 18 16 52 10.04 - 47.787 32.776 13.4 0.0 8 5 11.0 229 0.020 0.8 0.7 2014 09 18 16 56 27.48 - 47.804 32.790 9.3 0.0 10 6 13.0 242 0.139 0.6 0.5 2014 09 18 17 07 14.21 - 47.804 32.790 9.7 0.0 11 6 13.0 242 0.095 0.6 0.4 2014 09 18 17 07 32.13 - 47.573 32.793 12.1 0.0 3 6 10.0 200 0.001 99.0 99.0 2014 09 18 18 25 02.81 - 47.808 32.814 10.0 0.0 8 5 15.0 251 0.187 0.6 0.5 2014 09 18 20 06 59.41 - 47.883 32.652 12.3 0.0 9 5 7.0 300 0.141 0.7 0.6 2014 09 18 21 19 29.65 - 47.828 32.686 16.3 0.0 7 4 5.0 253 0.361 0.8 0.8 2014 09 18 22 48 05.87 - 47.807 32.792 10.2 0.0 11 6 14.0 244 0.119 0.6 0.8 2014 09 18 22 55 24.15 - 47.811 32.797 11.4 0.0 10 6 14.0 247 0.193 0.6 0.8 2014 09 18 22 57 32.73 - 47.563 32.779 14.4 0.0 11 6 12.0 90 0.412 0.4 1.1 2014 09 18 23 20 45.97 - 47.806 32.790 10.2 0.0 8 5 14.0 243 0.107 0.6 1.2 2014 09 18 23 48 29.52 - 47.791 32.692 13.0 0.0 5 3 5.0 204 0.204 0.8 1.1 2014 09 19 00 46 41.13 - 47.778 32.703 1.2 0.0 3 4 6.0 228 0.004 99.0 99.0 2014 09 19 00 48 38.53 - 47.819 32.699 11.9 0.0 7 4 6.0 239 0.167 0.9 0.7 2014 09 19 01 01 38.24 - 47.800 32.706 8.9 0.0 6 4 6.0 219 0.024 2.0 1.3 2014 09 19 01 02 01.53 - 47.793 32.705 9.2 0.0 8 5 6.0 211 0.142 0.9 0.8 2014 09 19 01 02 10.40 - 47.792 32.701 8.9 0.0 4 3 6.0 209 0.001 2.5 1.7 2014 09 19 01 03 05.30 - 47.800 32.709 8.5 0.0 5 3 6.0 220 0.009 2.1 1.7 2014 09 19 01 04 14.16 - 47.792 32.706 9.0 0.0 8 5 6.0 210 0.135 0.6 1.0 2014 09 19 01 04 20.22 - 47.800 32.708 8.8 0.0 4 3 6.0 219 0.001 2.2 2.8 2014 09 19 01 05 44.14 - 47.804 32.708 8.9 0.0 6 4 6.0 223 0.025 0.7 1.3 2014 09 19 01 05 49.30 - 47.803 32.701 10.8 0.0 7 5 6.0 221 0.107 0.7 1.1 2014 09 19 01 06 47.63 - 47.822 32.697 0.5 0.0 9 6 5.0 242 0.309 2.3 2.2 2014 09 19 01 09 18.41 - 47.792 32.706 9.0 0.0 8 5 6.0 210 0.135 0.6 1.0 2014 09 19 01 09 19.12 - 47.802 32.699 10.9 0.0 7 5 5.0 219 0.128 0.7 1.0 2014 09 19 01 12 05.44 - 47.788 32.705 10.1 0.0 7 5 6.0 206 0.188 0.7 1.1 2014 09 19 01 13 41.12 - 47.812 32.716 9.3 0.0 10 6 7.0 232 0.161 0.5 0.6 2014 09 19 01 15 03.54 - 47.842 32.732 5.8 0.0 5 4 10.0 255 0.119 0.9 2.6 2014 09 19 01 16 09.33 - 47.789 32.699 9.1 0.0 5 4 6.0 205 0.010 1.5 1.3 2014 09 19 01 16 45.49 - 47.779 32.697 10.0 0.0 6 5 6.0 193 0.407 1.0 1.7 2014 09 19 01 16 50.92 - 47.779 32.681 16.3 0.0 4 2 4.0 180 0.413 99.0 99.0 2014 09 19 01 17 14.47 - 47.865 32.707 4.1 0.0 3 4 18.0 331 0.090 30.0 99.0 2014 09 19 01 17 58.86 - 47.799 32.714 1.6 0.0 6 4 7.0 220 0.386 1.4 0.9 2014 09 19 01 22 15.44 - 47.768 32.702 1.5 0.0 4 4 7.0 186 0.087 0.8 1.7 2014 09 19 01 25 44.43 - 47.799 32.699 10.9 0.0 7 5 5.0 216 0.104 0.7 1.1 2014 09 19 01 31 07.24 - 47.838 32.716 4.2 0.0 7 6 8.0 253 0.457 0.6 3.5 2014 09 19 01 32 00.66 - 47.804 32.697 11.2 0.0 7 5 5.0 221 0.137 0.7 1.0 2014 09 19 01 34 48.42 - 47.799 32.699 10.9 0.0 7 5 5.0 216 0.104 0.7 1.1 2014 09 19 01 37 32.64 - 47.820 32.706 13.1 0.0 5 6 6.0 239 0.062 7.9 16.9 2014 09 19 01 39 31.88 - 47.803 32.701 10.8 0.0 7 5 6.0 221 0.107 0.7 1.1 2014 09 19 01 44 51.73 - 47.807 32.682 10.1 0.0 6 4 4.0 224 0.320 0.8 1.2 2014 09 19 01 52 15.36 - 47.582 32.695 11.1 0.0 12 6 10.0 120 0.166 0.3 0.9 2014 09 19 02 00 16.88 - 47.831 32.810 12.3 0.0 8 6 17.0 259 0.345 0.8 1.0 2014 09 19 02 38 11.44 - 47.803 32.793 9.2 0.0 10 6 13.0 242 0.126 0.6 0.5 2014 09 19 03 27 54.35 - 47.622 32.815 12.3 0.0 6 6 10.0 204 0.093 1.0 1.0 2014 09 19 03 55 50.86 - 47.584 32.789 9.0 0.0 10 6 10.0 108 0.197 0.4 0.9 2014 09 19 05 42 26.32 - 47.758 32.611 13.5 0.0 12 6 6.0 211 0.147 0.5 0.7 2014 09 19 06 06 09.90 - 47.548 32.779 6.5 0.0 8 5 12.0 94 0.134 0.3 2.1 2014 09 19 06 26 27.97 - 47.549 32.779 8.4 0.0 10 6 12.0 87 0.136 0.3 1.2 2014 09 19 06 45 39.17 - 47.546 32.782 2.7 0.0 8 6 12.0 89 0.337 0.3 9.9 2014 09 19 06 47 04.01 - 47.738 32.689 10.5 0.0 9 6 7.0 153 0.238 0.5 0.6 2014 09 19 09 55 37.56 - 47.664 32.599 2.2 0.0 6 5 14.0 188 0.178 0.4 99.0 2014 09 19 11 34 40.25 - 47.720 32.615 4.6 0.0 7 4 9.0 261 0.288 1.6 3.7 2014 09 19 11 35 09.16 - 47.710 32.610 13.5 0.0 6 4 10.0 191 0.039 0.6 1.0 2014 09 19 16 38 37.50 - 47.804 32.795 9.2 0.0 12 6 14.0 243 0.158 0.5 0.4 2014 09 19 18 23 46.60 - 47.798 32.787 10.9 0.0 8 6 13.0 238 0.113 0.6 0.8 2014 09 19 18 24 40.58 - 47.743 32.779 9.0 0.0 7 5 8.0 207 0.497 0.5 0.9 2014 09 19 18 24 41.69 - 47.811 32.796 8.0 0.0 6 6 14.0 247 0.066 0.6 1.7 2014 09 19 18 25 03.58 - 47.804 32.786 10.0 0.0 5 6 13.0 241 0.030 4.4 7.9 2014 09 19 18 29 23.04 - 47.788 32.787 7.6 0.0 9 6 12.0 233 0.278 0.6 1.0 2014 09 19 18 30 17.62 - 47.771 32.767 13.7 0.0 8 5 10.0 217 0.061 0.6 0.7 2014 09 19 18 30 23.33 - 47.804 32.796 9.2 0.0 11 6 14.0 243 0.155 0.5 0.5 2014 09 19 18 31 12.08 - 47.802 32.795 9.2 0.0 12 6 14.0 242 0.164 0.5 0.4 2014 09 19 19 14 56.65 - 47.789 32.789 9.0 0.0 11 6 12.0 235 0.348 0.5 0.6 2014 09 19 19 16 39.79 - 47.803 32.792 9.4 0.0 10 6 13.0 242 0.066 0.6 0.5 2014 09 19 19 37 54.63 - 47.802 32.796 8.8 0.0 12 6 14.0 243 0.155 0.5 0.9 2014 09 19 19 41 37.04 - 47.802 32.794 9.2 0.0 12 6 14.0 242 0.170 0.5 0.5 2014 09 19 20 06 23.84 - 47.804 32.795 9.2 0.0 12 6 14.0 243 0.158 0.5 0.4 2014 09 19 20 27 11.70 - 47.802 32.793 10.3 0.0 11 6 13.0 242 0.102 0.5 0.8 2014 09 19 20 28 02.59 - 47.798 32.785 9.7 0.0 10 6 13.0 238 0.102 0.5 0.6 2014 09 19 20 30 15.14 - 47.786 32.779 12.1 0.0 7 4 11.0 230 0.013 1.4 1.7 2014 09 19 21 01 22.24 - 47.826 32.755 18.9 0.0 7 4 12.0 246 0.593 1.9 1.6 2014 09 19 21 26 53.81 - 47.814 32.798 10.2 0.0 9 5 15.0 249 0.170 0.6 1.0 2014 09 19 21 26 55.27 - 47.800 32.788 9.8 0.0 6 5 13.0 239 0.019 0.8 0.6 2014 09 19 22 03 14.80 - 47.685 32.739 9.0 0.0 10 6 1.0 154 0.113 0.3 0.5 2014 09 19 22 56 45.68 - 47.806 32.785 2.2 0.0 5 5 13.0 241 0.114 1.5 99.0 2014 09 19 23 32 02.40 - 47.782 32.771 13.7 0.0 7 4 11.0 224 0.050 1.5 1.6 2014 09 20 00 02 21.93 - 47.794 32.686 11.5 0.0 10 5 4.0 204 0.198 0.5 0.6 2014 09 20 00 51 55.29 - 47.786 32.775 12.7 0.0 8 5 11.0 228 0.030 0.6 0.9 2014 09 20 02 16 23.26 - 47.787 32.637 8.5 0.0 9 6 2.0 205 0.179 0.6 0.7 2014 09 20 03 17 23.05 - 47.789 32.779 11.7 0.0 7 5 12.0 231 0.078 1.0 0.7 2014 09 20 03 25 28.36 - 47.807 32.695 11.6 0.0 9 5 5.0 224 0.064 0.5 0.5 2014 09 20 03 59 43.02 - 47.705 32.803 2.4 0.0 5 3 8.0 198 0.429 2.9 99.0 2014 09 20 04 02 23.57 - 47.825 32.673 12.7 0.0 10 5 3.0 259 0.161 0.6 0.5 2014 09 20 04 04 44.35 - 47.830 32.705 2.0 0.0 5 5 15.0 292 0.222 1.2 33.3 2014 09 20 05 23 06.60 - 47.775 32.683 10.9 0.0 6 4 5.0 177 0.112 2.0 1.0 2014 09 20 05 23 06.74 - 47.769 32.778 14.4 0.0 5 3 10.0 220 0.026 3.1 3.1 2014 09 20 09 09 45.88 - 47.748 32.752 14.1 0.0 11 6 7.0 198 0.313 0.5 0.6 2014 09 20 12 44 53.71 - 47.711 32.751 12.3 0.0 9 5 4.0 194 0.495 0.5 0.6 2014 09 20 12 44 54.39 - 47.810 32.793 0.0 0.0 4 6 14.0 246 0.034 1.2 1.7 2014 09 20 17 20 49.49 - 47.860 32.709 12.3 0.0 6 4 8.0 270 0.484 0.7 0.7 2014 09 20 19 10 59.09 - 47.593 32.773 13.1 0.0 9 6 9.0 108 0.301 0.4 0.9 2014 09 20 21 09 49.27 - 47.418 32.712 14.3 0.0 7 5 14.0 118 0.133 0.5 1.6 2014 09 20 21 17 31.31 - 47.797 32.798 9.2 0.0 9 5 13.0 241 0.140 0.6 0.6 2014 09 21 01 12 58.83 - 47.761 32.770 15.1 0.0 6 4 9.0 212 0.018 1.6 1.5 2014 09 21 01 15 31.00 - 47.792 32.696 9.2 0.0 10 5 5.0 207 0.163 0.7 0.5 2014 09 21 02 12 34.63 - 47.773 32.702 10.7 0.0 8 5 10.0 280 0.148 0.7 1.2 2014 09 21 02 12 34.70 - 47.736 32.691 10.7 0.0 9 6 7.0 154 0.201 0.5 0.6 2014 09 21 02 34 23.00 - 47.768 32.704 5.5 0.0 6 4 7.0 187 0.386 1.6 2.0 2014 09 21 02 50 47.17 - 47.788 32.704 8.9 0.0 7 4 6.0 205 0.075 0.5 0.8 2014 09 21 02 53 58.45 - 47.700 32.591 3.3 0.0 7 5 12.0 202 0.349 0.4 2.4 2014 09 21 05 26 00.97 - 47.814 32.724 7.7 0.0 10 6 8.0 234 0.292 0.5 0.9 2014 09 21 08 34 27.39 - 47.796 32.787 11.4 0.0 8 5 13.0 237 0.065 0.6 1.0 2014 09 21 09 43 28.17 - 47.566 32.783 12.1 0.0 11 6 11.0 93 0.156 0.5 1.2 2014 09 21 12 53 34.95 - 47.761 32.684 11.0 0.0 10 5 6.0 166 0.449 0.6 0.6 2014 09 21 13 45 54.94 - 47.794 32.759 0.0 0.0 6 5 11.0 228 0.103 0.9 1.5 2014 09 21 14 03 27.40 - 47.815 32.710 10.1 0.0 9 5 7.0 234 0.135 0.6 0.6 2014 09 21 18 31 00.42 - 47.643 32.676 15.6 0.0 7 6 7.0 172 0.222 0.6 1.5 2014 09 21 18 43 29.94 - 47.818 32.725 2.1 0.0 5 4 8.0 237 0.061 1.0 99.0 2014 09 21 18 51 09.22 - 47.820 32.715 8.0 0.0 6 4 7.0 238 0.045 1.7 2.2 2014 09 21 23 39 22.71 - 47.532 32.822 11.0 0.0 9 6 9.0 95 0.120 0.6 1.2 2014 09 22 00 58 28.77 - 47.498 32.732 10.0 0.0 11 6 17.0 100 0.150 0.3 1.2 2014 09 22 02 31 20.02 - 47.531 32.770 0.1 0.0 8 5 14.0 140 0.353 0.3 0.7 2014 09 22 06 03 56.10 - 47.533 32.757 13.1 0.0 9 5 14.0 139 0.205 0.4 1.0 2014 09 22 06 29 21.59 - 47.528 32.756 11.1 0.0 8 5 14.0 142 0.202 0.4 1.2 2014 09 22 06 38 56.81 - 47.528 32.754 10.7 0.0 8 5 14.0 142 0.199 0.4 1.2 2014 09 22 07 41 54.19 - 47.590 32.781 14.6 0.0 10 6 10.0 109 0.241 0.4 0.8 2014 09 22 07 49 11.59 - 47.576 32.747 7.6 0.0 5 4 10.0 217 0.143 2.1 1.6 2014 09 22 09 47 14.73 - 47.584 32.691 11.9 0.0 10 6 10.0 122 0.179 0.3 0.9 2014 09 22 10 09 44.97 - 47.848 32.723 0.7 0.0 6 5 9.0 259 0.184 1.6 1.9 2014 09 22 15 49 26.26 - 47.756 32.611 12.0 0.0 9 5 6.0 210 0.081 0.6 0.7 2014 09 22 16 42 38.93 - 47.635 32.722 8.8 0.0 9 6 4.0 110 0.109 0.4 0.7 2014 09 22 17 00 14.35 - 47.754 32.605 11.1 0.0 7 4 7.0 214 0.080 0.6 1.1 2014 09 22 17 16 46.46 - 47.484 32.717 2.0 0.0 7 5 18.0 162 0.136 0.4 33.3 2014 09 22 17 21 30.83 - 47.635 32.724 9.0 0.0 9 6 4.0 109 0.087 0.4 0.7 2014 09 22 17 34 37.52 - 47.489 32.776 8.3 0.0 10 6 13.0 115 0.162 0.3 1.4 2014 09 22 19 00 06.05 - 47.474 32.725 13.9 0.0 11 6 19.0 106 0.098 0.4 1.2 2014 09 22 20 18 46.69 - 47.688 32.734 11.1 0.0 10 5 1.0 154 0.294 0.4 0.6 2014 09 22 22 29 54.75 - 47.813 32.723 7.8 0.0 9 5 8.0 233 0.238 0.5 1.0 2014 09 22 22 31 43.83 - 47.715 32.735 9.8 0.0 10 6 4.0 169 0.109 0.4 0.5 2014 09 22 23 23 46.77 - 47.720 32.731 9.2 0.0 12 6 4.0 170 0.222 0.3 0.5 2014 09 22 23 23 46.91 - 47.646 32.663 15.6 0.0 8 6 8.0 143 0.366 0.4 1.0 2014 09 23 00 13 31.70 - 47.489 32.776 7.5 0.0 8 5 13.0 115 0.139 0.4 1.8 2014 09 23 03 26 36.90 - 47.578 32.705 11.3 0.0 9 5 10.0 149 0.192 0.5 1.2 2014 09 23 10 12 01.93 - 47.251 32.454 19.8 0.0 8 6 17.0 297 0.201 1.0 0.7 2014 09 23 14 35 09.32 - 47.203 32.441 18.7 0.0 7 5 22.0 306 0.393 1.0 0.9 2014 09 23 15 23 09.62 - 47.594 32.773 5.7 0.0 7 4 9.0 129 0.116 0.4 1.4 2014 09 23 20 07 59.90 - 47.194 32.414 10.9 0.0 5 3 24.0 347 0.241 3.7 1.7 2014 09 23 20 15 03.11 - 47.779 32.717 2.7 0.0 4 4 8.0 203 0.125 1.7 10.6 2014 09 23 20 48 09.48 - 47.766 32.710 10.7 0.0 8 5 9.0 305 0.275 0.7 0.6 2014 09 23 20 48 37.14 - 47.142 32.417 14.8 0.0 7 5 28.0 315 0.369 1.0 1.5 2014 09 23 20 48 49.35 - 47.490 32.772 2.1 0.0 7 6 14.0 113 0.173 0.3 99.0 2014 09 24 00 13 47.19 - 47.606 32.820 2.5 0.0 5 4 6.0 136 0.392 1.3 19.2 2014 09 24 01 55 33.23 - 47.193 32.437 17.5 0.0 10 6 23.0 307 0.299 0.8 0.5 2014 09 24 02 36 17.72 - 47.279 32.483 18.9 0.0 7 5 14.0 296 0.170 0.9 0.7 2014 09 24 02 36 18.99 - 47.256 32.460 17.6 0.0 7 4 17.0 305 0.228 0.9 0.5 2014 09 24 02 59 43.66 - 47.496 32.736 11.7 0.0 8 6 17.0 140 0.049 0.4 1.3 2014 09 24 03 10 41.34 - 47.522 32.784 6.4 0.0 7 5 13.0 155 0.147 0.4 2.4 2014 09 24 05 22 53.63 - 47.738 32.714 9.6 0.0 8 5 6.0 187 0.063 0.5 0.5 2014 09 24 10 35 04.04 - 47.849 32.620 13.9 0.0 7 4 5.0 346 0.063 2.4 0.8 2014 09 24 10 48 41.63 - 47.798 32.739 14.7 0.0 7 5 10.0 235 0.592 0.7 0.7 2014 09 24 10 54 47.59 - 47.816 32.624 9.3 0.0 5 3 3.0 333 0.040 2.3 0.9 2014 09 24 11 23 40.20 - 47.776 32.608 2.2 0.0 5 5 5.0 228 0.924 0.6 4.0 2014 09 24 11 24 25.19 - 47.735 32.711 9.4 0.0 9 5 6.0 184 0.095 0.5 0.5 2014 09 24 11 38 26.15 - 47.254 32.459 20.1 0.0 8 6 17.0 296 0.206 1.1 0.7 2014 09 24 13 39 08.80 - 47.290 32.505 19.6 0.0 7 5 12.0 284 0.324 1.3 0.6 2014 09 24 13 56 20.47 - 47.293 32.497 18.9 0.0 6 4 12.0 288 0.080 1.4 0.7 2014 09 24 14 27 31.32 - 47.248 32.483 14.7 0.0 8 5 16.0 298 0.416 0.9 0.7 2014 09 24 14 27 38.96 - 47.261 32.484 11.9 0.0 8 5 15.0 296 0.403 0.8 0.6 2014 09 24 14 35 13.15 - 47.155 32.444 0.0 0.0 5 5 26.0 313 0.206 13.5 15.7 2014 09 24 14 42 55.43 - 47.258 32.477 18.0 0.0 8 5 16.0 299 0.144 0.9 0.6 2014 09 24 14 42 57.33 - 47.251 32.481 14.5 0.0 6 4 16.0 298 0.098 0.9 0.9 2014 09 24 14 50 05.92 - 47.259 32.483 17.6 0.0 7 4 15.0 297 0.136 0.9 0.8 2014 09 24 15 43 31.85 - 47.586 32.774 9.0 0.0 11 6 10.0 103 0.201 0.3 0.9 2014 09 24 17 09 12.98 - 47.854 32.810 10.8 0.0 11 6 18.0 267 0.322 0.6 1.0 2014 09 24 17 11 09.06 - 47.757 32.603 11.6 0.0 8 4 7.0 217 0.074 0.6 0.8 2014 09 24 18 27 01.23 - 47.851 32.807 10.9 0.0 11 6 18.0 265 0.342 0.6 1.0 2014 09 24 19 40 25.77 - 47.842 32.784 14.7 0.0 11 6 15.0 258 0.243 0.6 0.7 2014 09 24 20 04 50.37 - 47.517 32.747 9.9 0.0 12 6 15.0 96 0.177 0.3 1.1 2014 09 24 20 11 19.37 - 47.584 32.781 5.8 0.0 7 5 10.0 105 0.184 0.5 2.6 2014 09 24 22 05 05.87 - 47.258 32.482 18.1 0.0 8 5 15.0 297 0.154 0.9 0.6 2014 09 24 22 19 12.96 - 47.703 32.711 20.0 0.0 8 4 3.0 190 0.491 1.8 0.7 2014 09 24 22 57 27.82 - 47.274 32.467 22.0 0.0 6 4 15.0 302 0.320 1.0 0.8 2014 09 24 23 08 03.32 - 47.663 32.616 13.4 0.0 8 6 13.0 176 0.094 0.5 0.9 2014 09 24 23 17 57.30 - 47.574 32.756 9.1 0.0 9 6 10.0 95 0.348 0.3 1.0 2014 09 25 00 31 34.64 - 47.245 32.489 10.3 0.0 6 4 16.0 296 0.288 0.8 1.4 2014 09 25 00 41 29.59 - 47.617 32.789 0.0 0.0 4 4 8.0 222 0.436 3.0 0.9 2014 09 25 02 30 11.03 - 47.584 32.716 10.7 0.0 12 6 9.0 111 0.177 0.3 0.9 2014 09 25 04 02 53.94 - 47.772 32.669 11.8 0.0 9 5 4.0 156 0.176 0.7 0.8 2014 09 25 05 17 15.18 - 47.588 32.775 9.9 0.0 11 6 10.0 105 0.338 0.3 0.8 2014 09 25 06 21 43.87 - 47.573 32.786 12.4 0.0 8 4 10.0 187 0.068 0.6 1.4 2014 09 25 06 21 43.92 - 47.588 32.772 8.0 0.0 12 6 9.0 104 0.182 0.3 1.0 2014 09 25 06 48 10.47 - 47.575 32.772 4.5 0.0 8 4 12.0 192 0.359 0.5 4.9 2014 09 25 06 48 10.93 - 47.591 32.804 8.1 0.0 9 5 8.0 117 0.153 0.4 1.3 2014 09 25 07 33 50.95 - 47.471 32.753 11.7 0.0 6 4 16.0 172 0.110 0.6 2.5 2014 09 25 07 58 40.23 - 47.474 32.751 11.2 0.0 6 4 16.0 170 0.106 0.5 2.7 2014 09 25 07 59 00.05 - 47.827 32.677 12.4 0.0 10 5 4.0 257 0.154 0.6 0.5 2014 09 25 08 04 54.29 - 47.471 32.753 11.7 0.0 6 4 16.0 172 0.110 0.6 2.5 2014 09 25 08 10 27.23 - 47.754 32.635 13.2 0.0 10 5 5.0 181 0.184 0.5 0.7 2014 09 25 09 09 39.46 - 47.840 32.653 6.9 0.0 9 5 3.0 293 0.364 0.6 0.5 2014 09 25 09 18 46.96 - 47.831 32.691 0.0 0.0 5 4 5.0 254 0.415 1.9 2.2 2014 09 25 09 26 52.60 - 47.790 32.708 7.7 0.0 8 4 7.0 210 0.090 0.5 0.8 2014 09 25 09 41 55.78 - 47.791 32.709 8.1 0.0 8 4 7.0 211 0.095 0.5 0.7 2014 09 25 09 42 30.47 - 47.758 32.674 11.1 0.0 7 4 5.0 152 0.191 0.7 0.7 2014 09 25 09 45 13.80 - 47.736 32.613 11.0 0.0 6 5 8.0 198 0.099 0.8 1.4 2014 09 25 10 10 29.62 - 47.718 32.606 10.1 0.0 4 5 9.0 197 0.029 3.2 8.0 2014 09 25 10 11 09.72 - 47.754 32.636 10.6 0.0 10 5 5.0 181 0.165 0.5 0.7 2014 09 25 10 16 59.17 - 47.587 32.718 9.7 0.0 12 6 9.0 110 0.163 0.3 0.9 2014 09 25 10 56 18.66 - 47.768 32.604 2.7 0.0 6 3 6.0 296 0.270 2.1 11.5 2014 09 25 13 05 56.16 - 47.492 32.718 12.0 0.0 6 4 17.0 255 0.307 1.6 2.3 2014 09 25 16 28 23.73 - 47.426 32.703 6.2 0.0 8 4 22.0 276 0.119 1.4 7.2 2014 09 25 16 34 16.36 - 47.730 32.705 11.2 0.0 10 6 6.0 161 0.441 0.4 0.6 2014 09 25 17 18 24.01 - 47.716 32.697 10.9 0.0 12 6 5.0 148 0.199 0.4 0.6 2014 09 25 17 21 01.70 - 47.756 32.733 10.3 0.0 6 5 7.0 193 0.385 0.7 0.8 2014 09 25 17 21 23.03 - 47.668 32.682 0.0 0.0 5 4 6.0 220 0.326 1.2 0.5 2014 09 25 17 21 55.37 - 47.715 32.697 11.2 0.0 10 6 5.0 147 0.220 0.4 0.6 2014 09 25 17 22 57.26 - 47.701 32.681 10.6 0.0 6 5 6.0 229 0.022 1.8 0.7 2014 09 25 17 24 20.13 - 47.712 32.699 11.8 0.0 8 5 5.0 147 0.177 0.7 0.7 2014 09 25 17 35 38.90 - 47.796 32.647 3.1 0.0 7 4 1.0 188 0.469 0.8 0.9 2014 09 25 17 44 27.88 - 47.853 32.669 5.0 0.0 6 4 5.0 289 0.121 0.8 0.8 2014 09 25 18 08 24.94 - 47.724 32.715 9.4 0.0 9 5 5.0 163 0.537 0.4 0.6 2014 09 25 18 08 57.44 - 47.774 32.577 4.0 0.0 3 4 9.0 313 0.003 99.0 99.0 2014 09 25 20 03 07.54 - 47.692 32.702 9.3 0.0 12 6 4.0 139 0.366 0.3 0.6 2014 09 25 21 24 25.30 - 47.679 32.705 11.9 0.0 9 5 3.0 121 0.279 0.4 0.7 2014 09 25 21 56 25.34 - 47.657 32.683 10.3 0.0 7 5 6.0 131 0.092 0.5 0.8 2014 09 25 21 56 25.35 - 47.742 32.631 12.2 0.0 12 6 6.0 182 0.162 0.5 0.7 2014 09 25 22 02 51.27 - 47.521 32.740 22.3 0.0 8 6 15.0 95 0.483 0.4 1.0 2014 09 25 22 12 43.73 - 47.529 32.721 15.5 0.0 9 6 14.0 103 0.251 0.3 1.0 2014 09 25 22 12 57.51 - 47.715 32.741 9.9 0.0 6 4 4.0 191 0.021 0.7 0.6 2014 09 25 22 29 42.71 - 47.713 32.737 9.8 0.0 7 5 3.0 169 0.063 0.6 0.6 2014 09 25 22 29 42.76 - 47.715 32.737 9.7 0.0 9 6 3.0 170 0.048 0.4 0.5 2014 09 25 22 31 13.28 - 47.712 32.736 9.8 0.0 10 6 3.0 168 0.102 0.4 0.5 2014 09 25 22 31 13.31 - 47.726 32.744 10.0 0.0 9 6 5.0 180 0.181 0.4 0.5 2014 09 25 22 32 05.84 - 47.706 32.758 5.7 0.0 8 4 4.0 195 0.512 0.5 0.6 2014 09 25 22 32 06.71 - 47.730 32.758 6.8 0.0 8 4 6.0 206 0.461 0.5 0.7 2014 09 25 22 32 35.54 - 47.727 32.751 7.1 0.0 10 6 5.0 184 0.410 0.4 0.6 2014 09 25 22 32 35.59 - 47.745 32.741 11.4 0.0 7 5 6.0 190 0.269 0.6 0.8 2014 09 25 22 34 48.71 - 47.723 32.745 7.0 0.0 11 6 4.0 179 0.384 0.4 0.6 2014 09 25 22 35 09.59 - 47.723 32.748 6.8 0.0 9 6 5.0 180 0.435 0.4 0.6 2014 09 25 22 35 09.60 - 47.719 32.736 9.5 0.0 12 6 4.0 172 0.164 0.4 0.4 2014 09 25 22 39 23.30 - 47.712 32.736 9.6 0.0 10 6 3.0 167 0.097 0.4 0.4 2014 09 25 22 39 23.33 - 47.713 32.737 12.8 0.0 7 4 3.0 188 0.326 0.6 0.7 2014 09 25 22 40 51.08 - 47.744 32.759 7.4 0.0 7 5 7.0 198 0.220 0.6 0.9 2014 09 25 22 40 51.77 - 47.542 32.718 9.4 0.0 12 6 13.0 106 0.215 0.2 1.1 2014 09 25 22 50 24.33 - 47.706 32.700 10.3 0.0 9 6 5.0 144 0.228 0.4 0.7 2014 09 25 23 00 48.01 - 47.578 32.678 8.5 0.0 9 6 11.0 128 0.434 0.3 1.8 2014 09 25 23 46 50.46 - 47.581 32.709 17.3 0.0 8 5 19.0 114 0.287 0.3 1.2 2014 09 25 23 47 27.75 - 47.586 32.704 10.4 0.0 11 6 9.0 116 0.328 0.3 0.9 2014 09 25 23 53 36.08 - 47.712 32.736 9.8 0.0 10 6 3.0 168 0.117 0.4 0.5 2014 09 26 00 23 45.17 - 47.718 32.737 9.4 0.0 12 6 4.0 172 0.182 0.3 0.5 2014 09 26 00 23 45.19 - 47.795 32.630 5.0 0.0 8 5 2.0 233 0.374 0.7 0.8 2014 09 26 00 25 06.87 - 47.610 32.661 12.7 0.0 10 5 10.0 141 0.151 0.3 0.9 2014 09 26 01 45 42.63 - 47.824 32.674 12.2 0.0 10 5 3.0 255 0.171 0.6 0.5 2014 09 26 07 26 01.47 - 47.768 32.774 14.9 0.0 5 3 10.0 218 0.002 3.1 2.9 2014 09 26 07 29 49.17 - 47.420 32.771 11.3 0.0 9 5 15.0 148 0.269 0.6 1.4 2014 09 26 09 00 53.54 - 47.755 32.641 12.2 0.0 6 4 5.0 241 0.086 1.9 1.0 2014 09 26 09 24 52.39 - 47.506 32.731 3.6 0.0 11 6 16.0 96 0.425 0.3 1.8 2014 09 26 09 32 19.20 - 47.480 32.758 11.4 0.0 6 4 15.0 167 0.034 0.6 2.0 2014 09 26 09 33 10.30 - 47.498 32.775 12.4 0.0 5 4 13.0 159 0.081 0.7 1.8 2014 09 26 10 54 57.07 - 47.810 32.635 15.7 0.0 9 5 2.0 271 0.343 0.9 0.6 2014 09 26 12 52 12.88 - 47.517 32.728 11.7 0.0 11 6 15.0 98 0.247 0.3 1.2 2014 09 26 13 28 36.92 - 47.586 32.689 11.0 0.0 12 6 10.0 124 0.239 0.3 0.9 2014 09 26 13 46 46.45 - 47.658 32.615 12.9 0.0 9 6 13.0 176 0.070 0.4 1.0 2014 09 26 14 43 22.08 - 47.677 32.641 23.5 0.0 9 6 10.0 161 0.469 0.5 0.8 2014 09 26 14 52 28.89 - 47.511 32.728 0.0 0.0 8 5 16.0 152 0.173 0.3 0.7 2014 09 26 16 20 13.31 - 47.667 32.615 14.1 0.0 9 6 13.0 178 0.182 0.5 0.9 2014 09 26 17 45 45.93 - 47.620 32.698 11.2 0.0 10 5 7.0 122 0.266 0.3 0.8 2014 09 26 17 51 31.94 - 47.740 32.709 8.5 0.0 9 5 6.0 186 0.259 0.5 0.6 2014 09 26 21 14 13.00 - 47.708 32.694 3.2 0.0 6 4 5.0 151 0.329 0.6 1.7 2014 09 26 21 14 29.57 - 47.739 32.712 9.8 0.0 8 5 6.0 187 0.101 0.7 0.5 2014 09 26 21 15 41.77 - 47.792 32.701 8.9 0.0 4 3 6.0 209 0.001 2.5 1.7 2014 09 26 23 24 20.30 - 47.653 32.661 7.2 0.0 8 4 8.0 235 0.181 1.4 1.6 2014 09 26 23 44 32.41 - 47.258 32.483 15.8 0.0 6 4 15.0 297 0.073 0.9 0.9 2014 09 27 00 57 50.63 - 47.525 32.722 1.1 0.0 11 6 14.0 102 0.454 0.2 0.6 2014 09 27 03 09 43.90 - 47.843 32.654 6.8 0.0 9 5 4.0 294 0.367 0.6 0.5 2014 09 27 04 12 28.72 - 47.859 32.663 6.6 0.0 5 4 5.0 296 0.087 0.9 1.0 2014 09 27 04 16 28.40 - 47.827 32.647 8.0 0.0 3 3 2.0 317 0.002 99.0 99.0 2014 09 27 04 16 39.06 - 47.857 32.666 6.6 0.0 6 4 5.0 295 0.331 2.2 1.8 2014 09 27 04 18 18.67 - 47.812 32.673 0.9 0.0 5 3 3.0 235 0.571 99.0 99.0 2014 09 27 04 18 47.12 - 47.812 32.673 0.9 0.0 5 3 3.0 235 0.571 99.0 99.0 2014 09 27 04 53 14.22 - 47.610 32.725 9.0 0.0 8 5 6.0 109 0.128 0.3 1.4 2014 09 27 04 54 45.74 - 47.884 32.647 11.1 0.0 6 4 7.0 300 0.366 0.8 0.7 2014 09 27 04 55 49.07 - 47.805 32.637 5.3 0.0 5 3 2.0 312 0.289 2.3 0.7 2014 09 27 05 43 08.31 - 47.793 32.705 9.2 0.0 8 5 6.0 211 0.142 0.9 0.8 2014 09 27 06 28 58.50 - 47.798 32.704 9.2 0.0 5 3 6.0 216 0.023 2.2 1.5 2014 09 27 06 31 26.21 - 47.800 32.634 5.2 0.0 5 3 2.0 300 0.243 2.3 0.8 2014 09 27 08 42 50.95 - 47.514 32.750 1.2 0.0 9 5 15.0 149 0.406 0.3 0.7 2014 09 27 08 46 47.20 - 47.832 32.645 8.0 0.0 3 3 3.0 321 0.002 99.0 99.0 2014 09 27 09 08 04.81 - 47.816 32.615 6.3 0.0 8 4 4.0 273 0.659 0.6 0.7 2014 09 27 09 11 12.62 - 47.835 32.680 1.4 0.0 3 4 30.0 292 0.001 99.0 99.0 2014 09 27 10 38 45.03 - 47.596 32.808 8.4 0.0 7 6 11.0 177 0.022 0.6 2.0 2014 09 27 11 21 51.27 - 47.927 32.719 3.9 0.0 5 3 14.0 296 0.455 1.6 4.8 2014 09 27 19 32 47.97 - 47.792 32.795 10.3 0.0 7 5 13.0 238 0.141 0.8 1.0 2014 09 29 01 10 29.50 - 47.809 32.788 9.6 0.0 7 4 14.0 244 0.059 1.5 2.6 2014 09 29 01 49 22.48 - 47.750 32.607 13.6 0.0 9 5 7.0 210 0.703 0.5 0.8 2014 09 29 03 13 49.22 - 47.726 32.798 2.0 0.0 4 5 9.0 263 0.151 1.9 33.3 2014 09 29 04 38 56.25 - 47.707 32.616 13.7 0.0 9 6 10.0 186 0.071 0.5 0.8 2014 09 29 06 16 10.47 - 47.709 32.639 12.7 0.0 9 6 9.0 166 0.376 0.5 0.7 2014 09 29 06 25 35.34 - 47.584 32.775 9.3 0.0 10 6 10.0 103 0.227 0.3 0.9 2014 09 29 14 35 15.46 - 47.495 32.739 11.6 0.0 12 6 17.0 103 0.078 0.3 1.1 2014 09 29 19 41 58.02 - 47.763 32.709 9.8 0.0 7 5 8.0 186 0.287 0.7 0.6 2014 09 29 23 57 59.45 - 47.588 32.782 2.3 0.0 6 5 10.0 123 0.193 0.3 20.6 2014 09 30 00 03 21.31 - 47.798 32.684 9.9 0.0 8 6 4.0 211 0.082 0.6 0.5 2014 09 30 00 16 20.32 - 47.784 32.700 11.6 0.0 7 6 6.0 200 0.350 0.6 0.8 2014 09 30 03 13 14.78 - 47.807 32.665 10.1 0.0 7 5 2.0 224 0.106 0.8 0.8 2014 09 30 03 15 02.64 - 47.781 32.668 11.6 0.0 6 4 3.0 176 0.109 3.2 0.8 2014 09 30 03 15 02.67 - 47.471 32.752 10.2 0.0 6 4 16.0 172 0.103 0.5 3.2 2014 09 30 03 18 56.82 - 47.494 32.756 9.1 0.0 12 6 16.0 108 0.236 0.3 1.2 2014 09 30 05 47 03.27 - 47.483 32.755 9.9 0.0 9 6 16.0 112 0.490 0.3 1.2 2014 09 30 05 49 11.43 - 47.796 32.704 6.5 0.0 8 6 6.0 214 0.362 0.4 1.0 2014 09 30 06 58 19.09 - 47.668 32.737 7.9 0.0 8 5 1.0 134 0.072 0.4 0.6 2014 09 30 07 27 37.57 - 47.798 32.678 9.7 0.0 6 5 3.0 207 0.008 0.7 0.7 2014 09 30 09 54 20.18 - 47.639 32.824 9.7 0.0 5 5 6.0 181 0.272 1.6 1.7 2014 09 30 10 01 40.42 - 47.802 32.658 9.9 0.0 5 4 1.0 199 0.009 2.6 0.6 2014 09 30 12 38 53.73 - 47.792 32.682 8.1 0.0 7 5 4.0 199 0.156 0.5 0.9 2014 09 30 12 42 12.35 - 47.821 32.721 0.1 0.0 3 6 13.0 333 0.001 99.0 99.0 2014 09 30 12 43 16.11 - 47.626 32.817 9.1 0.0 7 5 6.0 161 0.412 0.6 1.2 2014 09 30 13 20 23.36 - 47.534 32.742 2.0 0.0 6 4 13.0 162 0.192 0.4 33.3 2014 09 30 13 21 39.15 - 47.573 32.769 11.4 0.0 6 4 11.0 119 0.385 0.8 1.5 2014 09 30 13 21 53.35 - 47.801 32.645 14.5 0.0 7 5 1.0 251 0.413 0.8 0.7 2014 09 30 13 41 58.87 - 47.506 32.826 9.4 0.0 10 6 8.0 113 0.275 0.4 1.0 2014 09 30 14 12 49.05 - 47.732 32.693 10.5 0.0 10 6 7.0 153 0.164 0.4 0.6 2014 09 30 14 48 20.17 - 47.822 32.685 11.6 0.0 11 6 4.0 246 0.168 0.6 0.5 2014 09 30 16 26 01.80 - 47.785 32.697 12.1 0.0 7 5 6.0 200 0.191 0.7 0.7 2014 09 30 17 29 12.71 - 47.618 32.634 3.9 0.0 8 4 12.0 253 0.037 0.8 1.8 2014 09 30 18 46 10.19 - 47.495 32.738 11.4 0.0 12 6 17.0 102 0.073 0.3 1.2 2014 09 30 19 16 19.56 - 47.488 32.728 7.3 0.0 7 5 18.0 112 0.161 0.3 2.6 2014 09 30 19 24 26.53 - 47.650 32.704 9.8 0.0 9 6 4.0 119 0.229 0.3 0.7 2014 09 30 19 33 38.94 - 47.495 32.738 10.6 0.0 10 6 17.0 102 0.070 0.3 1.3 2014 09 30 19 34 36.89 - 47.494 32.739 12.0 0.0 12 6 17.0 103 0.092 0.3 1.1 2014 09 30 20 01 15.37 - 47.819 32.709 8.8 0.0 6 5 7.0 237 0.067 0.6 1.0 2014 09 30 20 11 59.56 - 47.776 32.665 13.2 0.0 6 5 3.0 154 0.236 0.7 1.0 2014 09 30 20 58 54.38 - 47.796 32.687 11.4 0.0 10 5 4.0 207 0.177 0.5 0.6 2014 09 30 21 58 56.02 - 47.807 32.721 6.7 0.0 5 3 8.0 228 0.035 1.8 2.7 2014 09 30 22 02 57.49 - 47.715 32.698 11.0 0.0 12 6 5.0 148 0.212 0.4 0.6 2014 09 30 22 18 11.03 - 47.716 32.702 8.6 0.0 5 6 5.0 189 0.183 1.8 1.1 2014 09 30 22 20 31.01 - 47.759 32.647 11.3 0.0 5 4 4.0 165 0.001 0.9 1.1 2014 09 30 22 46 34.45 - 47.537 32.756 13.3 0.0 9 5 13.0 137 0.210 0.4 1.0 2014 09 30 23 13 28.33 - 47.534 32.754 11.3 0.0 8 5 14.0 139 0.189 0.4 1.2 2014 09 30 23 20 32.85 - 47.691 32.804 22.0 0.0 7 5 8.0 190 0.475 0.9 0.7 2014 09 30 23 46 39.83 - 47.661 32.660 10.2 0.0 10 5 8.0 146 0.270 0.4 0.8 2014 09 30 23 58 34.19 - 47.781 32.684 4.5 0.0 6 6 4.0 186 0.159 1.0 3.1 2014 10 01 00 26 08.36 - 47.501 32.758 13.8 0.0 10 6 15.0 105 0.173 0.3 1.2 2014 10 01 00 49 31.72 - 47.487 32.761 25.0 0.0 6 5 15.0 137 0.250 0.7 1.1 2014 10 01 01 36 14.57 - 47.511 32.754 3.1 0.0 9 5 16.0 151 0.338 0.3 7.1 2014 10 01 01 45 28.28 - 47.808 32.653 14.5 0.0 8 6 0.0 262 0.192 0.7 0.7 2014 10 01 05 00 57.41 - 47.506 32.737 3.1 0.0 8 5 16.0 152 0.082 0.4 9.1 2014 10 01 05 20 47.45 - 47.495 32.740 9.9 0.0 6 6 17.0 107 0.013 0.4 2.0 2014 10 01 05 25 09.68 - 47.770 32.600 3.8 0.0 6 3 6.0 299 0.286 0.9 1.4 2014 10 01 05 27 33.48 - 47.802 32.686 10.2 0.0 7 6 4.0 217 0.085 0.5 0.8 2014 10 01 06 42 27.02 - 47.805 32.694 9.9 0.0 8 6 5.0 222 0.174 0.5 0.5 2014 10 01 08 00 12.66 - 47.804 32.685 9.9 0.0 9 6 4.0 219 0.078 0.5 0.5 2014 10 01 08 23 52.01 - 47.767 32.754 6.6 0.0 7 6 9.0 209 0.298 0.5 1.0 2014 10 01 08 25 04.38 - 47.773 32.711 11.0 0.0 7 6 7.0 195 0.138 0.5 0.7 2014 10 01 08 34 58.35 - 47.834 32.744 4.3 0.0 5 3 11.0 257 0.299 8.5 99.0 2014 10 01 08 36 19.28 - 47.762 32.700 12.7 0.0 7 6 7.0 180 0.328 0.6 0.7 2014 10 01 08 36 20.02 - 47.691 32.665 12.4 0.0 5 4 8.0 225 0.074 1.9 1.0 2014 10 01 08 38 21.10 - 47.770 32.697 11.3 0.0 8 6 6.0 184 0.233 0.6 0.7 2014 10 01 08 38 21.23 - 47.803 32.681 10.8 0.0 8 6 3.0 217 0.103 0.5 0.7 2014 10 01 08 49 18.69 - 47.771 32.668 11.5 0.0 4 5 11.0 342 0.001 3.1 1.2 2014 10 01 09 52 53.11 - 47.797 32.706 6.7 0.0 8 6 6.0 215 0.375 0.4 1.0 2014 10 01 09 57 08.04 - 47.780 32.669 3.6 0.0 9 6 3.0 165 0.490 0.5 0.9 2014 10 01 09 57 29.26 - 47.557 32.755 8.8 0.0 11 6 12.0 94 0.089 0.3 1.1 2014 10 01 11 15 42.91 - 47.640 32.686 10.3 0.0 11 6 6.0 129 0.148 0.3 0.7 2014 10 01 12 45 19.92 - 47.843 32.652 10.4 0.0 6 6 4.0 294 0.142 1.9 1.8 2014 10 01 14 46 43.62 - 47.700 32.726 10.9 0.0 8 5 2.0 156 0.032 0.5 0.6 2014 10 01 15 47 16.57 - 47.722 32.755 4.2 0.0 8 6 5.0 183 0.365 0.5 1.2 2014 10 01 17 28 54.92 - 47.550 32.758 1.1 0.0 7 6 12.0 137 0.132 0.4 0.8 2014 10 01 17 58 04.75 - 47.607 32.714 9.8 0.0 11 6 7.0 113 0.126 0.3 0.8 2014 10 01 19 56 58.58 - 47.531 32.748 15.7 0.0 8 6 14.0 94 0.312 0.4 1.1 2014 10 01 20 43 47.78 - 47.751 32.724 10.8 0.0 7 6 7.0 185 0.267 0.4 0.6 2014 10 01 22 04 51.13 - 47.798 32.681 1.4 0.0 4 5 3.0 208 0.115 99.0 99.0 2014 10 01 22 48 37.43 - 47.805 32.687 10.1 0.0 9 6 4.0 221 0.105 0.5 0.7 2014 10 01 22 50 49.88 - 47.803 32.687 10.1 0.0 8 6 4.0 219 0.125 0.5 0.7 2014 10 01 22 52 25.89 - 47.591 32.782 13.2 0.0 11 6 10.0 111 0.178 0.4 0.8 2014 10 01 23 17 45.38 - 47.810 32.798 11.1 0.0 11 6 14.0 247 0.141 0.5 0.8 2014 10 01 23 25 30.77 - 47.511 32.730 13.8 0.0 8 6 16.0 97 0.202 0.3 1.3 2014 10 02 00 17 51.15 - 47.541 32.757 14.1 0.0 9 5 13.0 135 0.214 0.4 1.0 2014 10 02 00 44 09.13 - 47.608 32.732 23.3 0.0 7 5 7.0 107 0.452 0.6 0.8 2014 10 02 01 01 07.77 - 47.537 32.755 13.1 0.0 9 5 13.0 137 0.222 0.4 1.0 2014 10 02 01 08 34.07 - 47.803 32.682 10.7 0.0 6 5 4.0 217 0.116 0.8 0.9 2014 10 02 01 11 46.91 - 47.535 32.752 9.0 0.0 8 4 13.0 138 0.185 0.4 1.5 2014 10 02 01 23 13.48 - 47.766 32.668 9.7 0.0 11 6 4.0 150 0.118 0.4 0.5 2014 10 02 07 15 28.94 - 47.565 32.755 7.4 0.0 6 5 11.0 109 0.551 0.6 2.1 2014 10 02 09 31 13.29 - 47.554 32.764 4.3 0.0 5 4 12.0 147 0.032 0.5 7.6 2014 10 02 09 48 01.57 - 47.649 32.705 8.6 0.0 6 4 4.0 155 0.096 0.6 0.7 2014 10 02 14 39 13.41 - 47.669 32.712 11.8 0.0 10 6 2.0 114 0.573 0.4 0.6 2014 10 02 14 46 27.82 - 47.563 32.816 2.1 0.0 5 5 14.0 246 0.375 0.9 99.0 2014 10 02 16 57 48.72 - 47.645 32.697 10.7 0.0 10 6 5.0 123 0.203 0.3 0.7 2014 10 02 17 01 52.97 - 47.493 32.740 11.3 0.0 9 6 17.0 103 0.074 0.3 1.2 2014 10 02 17 31 19.52 - 47.803 32.683 10.5 0.0 8 6 4.0 217 0.104 0.5 0.7 2014 10 02 18 40 53.93 - 47.647 32.704 10.3 0.0 10 6 4.0 119 0.300 0.3 0.7 2014 10 02 20 17 44.12 - 47.596 32.806 7.7 0.0 11 6 8.0 117 0.121 0.3 1.0 2014 10 02 21 35 56.00 - 47.594 32.807 7.5 0.0 11 6 8.0 115 0.103 0.3 1.1 2014 10 02 21 37 43.56 - 47.593 32.806 7.0 0.0 11 6 8.0 115 0.121 0.3 1.2 2014 10 02 21 39 27.68 - 47.589 32.806 4.9 0.0 9 6 8.0 112 0.183 0.4 2.3 2014 10 02 21 40 30.89 - 47.804 32.684 10.3 0.0 9 6 4.0 219 0.106 0.5 0.7 2014 10 02 22 30 03.05 - 47.820 32.700 9.7 0.0 8 6 6.0 239 0.238 0.6 0.6 2014 10 02 22 31 39.10 - 47.590 32.801 9.8 0.0 11 6 8.0 112 0.399 0.3 0.9 2014 10 02 23 44 02.78 - 47.599 32.811 5.2 0.0 7 5 7.0 119 0.201 0.7 2.3 2014 10 02 23 44 27.12 - 47.608 32.783 7.8 0.0 6 5 9.0 124 0.267 0.4 1.5 2014 10 02 23 54 21.24 - 47.646 32.672 5.8 0.0 9 5 7.0 137 0.183 0.4 1.2 2014 10 03 04 10 03.22 - 47.620 32.656 3.3 0.0 5 4 10.0 185 0.105 2.2 17.1 2014 10 03 10 34 05.62 - 47.790 32.721 7.5 0.0 8 4 8.0 214 0.253 0.5 0.8 2014 10 03 11 40 54.06 - 47.816 32.664 6.5 0.0 8 5 2.0 254 0.096 0.5 0.9 2014 10 03 14 46 36.04 - 47.817 32.673 16.0 0.0 7 5 3.0 245 0.521 0.7 0.8 2014 10 03 14 50 09.67 - 47.683 32.681 8.6 0.0 9 5 6.0 132 0.148 0.4 0.7 2014 10 03 16 32 40.68 - 47.720 32.739 8.8 0.0 7 4 4.0 174 0.128 0.4 0.6 2014 10 03 19 47 53.32 - 47.572 32.627 3.7 0.0 5 3 15.0 285 0.391 1.0 2.5 2014 10 03 21 05 05.34 - 47.598 32.823 6.7 0.0 5 4 6.0 132 0.661 1.2 3.0 2014 10 04 02 18 29.99 - 47.645 32.694 10.2 0.0 9 5 5.0 125 0.206 0.4 0.8 2014 10 04 07 07 08.13 - 47.524 32.783 6.5 0.0 7 5 13.0 154 0.129 0.4 2.4 2014 10 04 12 02 34.26 - 47.748 32.745 15.4 0.0 9 5 7.0 194 0.301 0.6 0.6 2014 10 04 15 31 25.75 - 47.722 32.715 16.1 0.0 6 4 5.0 163 0.249 0.9 0.7 2014 10 04 15 31 25.79 - 47.719 32.740 9.8 0.0 8 5 4.0 174 0.290 0.4 0.5 2014 10 04 15 44 11.91 - 47.699 32.746 15.8 0.0 6 4 2.0 165 0.256 0.6 0.7 2014 10 04 17 48 40.32 - 47.688 32.705 9.8 0.0 8 4 3.0 138 0.439 0.4 0.6 2014 10 04 21 50 41.31 - 47.664 32.653 10.8 0.0 6 3 9.0 259 0.237 1.7 1.1 2014 10 05 01 56 30.93 - 47.636 32.676 3.8 0.0 7 4 7.0 135 0.202 0.8 3.3 2014 10 05 05 46 42.40 - 47.598 32.778 6.8 0.0 9 5 9.0 117 0.161 0.3 1.1 2014 10 05 07 38 22.23 - 47.628 32.793 15.7 0.0 5 3 8.0 153 0.245 1.2 1.4 2014 10 05 09 40 12.62 - 47.645 32.695 10.6 0.0 9 5 5.0 124 0.204 0.4 0.7 2014 10 05 10 13 07.42 - 47.799 32.697 11.2 0.0 5 4 5.0 216 0.022 1.0 0.9 2014 10 05 17 02 02.42 - 47.828 32.678 11.9 0.0 5 5 4.0 258 0.063 2.3 1.5 2014 10 05 18 06 25.20 - 47.798 32.672 8.2 0.0 6 5 3.0 204 0.322 0.7 0.8 2014 10 05 18 06 56.18 - 47.386 32.760 10.1 0.0 8 5 13.0 185 0.103 0.6 2.6 2014 10 06 00 00 37.87 - 47.378 32.757 12.1 0.0 8 5 12.0 186 0.137 0.7 1.8 2014 10 06 00 19 49.75 - 47.642 32.674 8.2 0.0 6 3 7.0 254 0.027 1.8 1.4 2014 10 06 01 09 18.03 - 47.397 32.760 8.6 0.0 5 4 24.0 241 0.110 0.7 4.5 2014 10 06 01 17 13.74 - 47.391 32.757 9.7 0.0 8 5 13.0 182 0.102 0.5 0.7 2014 10 06 05 38 24.86 - 47.383 32.756 8.9 0.0 8 5 13.0 184 0.193 0.5 1.9 2014 10 06 05 38 24.98 - 47.660 32.658 13.3 0.0 8 5 8.0 147 0.165 0.5 0.8 2014 10 06 15 58 21.98 - 47.516 32.785 10.6 0.0 8 5 14.0 158 0.152 0.4 1.4 2014 10 06 21 54 15.36 - 47.523 32.774 8.3 0.0 5 4 14.0 196 0.009 0.7 3.0 2014 10 06 21 56 55.13 - 47.517 32.784 11.3 0.0 8 5 14.0 157 0.160 0.4 1.4 2014 10 06 22 07 02.66 - 47.704 32.673 5.1 0.0 8 5 7.0 137 0.380 0.4 1.1 2014 10 06 22 21 47.74 - 47.721 32.701 8.9 0.0 7 4 5.0 153 0.195 0.5 0.7 2014 10 06 22 22 56.37 - 47.721 32.676 13.6 0.0 6 4 7.0 162 0.186 1.0 0.9 2014 10 06 22 23 13.91 - 47.717 32.690 10.2 0.0 9 5 6.0 143 0.092 0.4 0.6 2014 10 06 22 23 24.04 - 47.676 32.667 8.6 0.0 8 5 7.0 142 0.263 0.3 0.9 2014 10 06 22 24 23.72 - 47.701 32.679 3.7 0.0 7 4 6.0 133 0.416 0.6 1.6 2014 10 06 22 24 50.75 - 47.704 32.679 12.1 0.0 9 5 6.0 132 0.523 0.4 0.7 2014 10 06 22 25 12.65 - 47.806 32.696 11.7 0.0 9 5 5.0 223 0.074 0.5 0.5 2014 10 07 01 57 38.80 - 47.714 32.630 10.9 0.0 3 4 9.0 204 0.000 99.0 99.0 2014 10 07 10 23 18.38 - 47.621 32.780 12.4 0.0 7 5 7.0 132 0.269 0.4 0.9 2014 10 07 18 25 58.54 - 47.641 32.794 15.3 0.0 7 5 8.0 151 0.507 0.5 0.9 2014 10 08 00 14 26.90 - 47.388 32.757 3.9 0.0 8 5 13.0 183 0.356 1.0 3.4 2014 10 08 00 53 13.54 - 47.392 32.755 2.5 0.0 5 5 13.0 181 0.157 0.6 32.5 2014 10 08 01 45 33.82 - 47.518 32.705 11.8 0.0 8 5 21.0 120 0.113 0.4 1.8 2014 10 08 06 58 22.25 - 47.820 32.704 7.6 0.0 5 4 6.0 239 0.218 0.7 1.2 2014 10 08 13 15 48.28 - 47.739 32.685 10.9 0.0 11 7 7.0 151 0.249 0.5 0.6 2014 10 08 15 34 29.90 - 47.509 32.780 12.6 0.0 11 6 14.0 129 0.168 0.4 1.0 2014 10 08 17 59 47.90 - 47.820 32.703 8.7 0.0 8 4 6.0 239 0.207 0.7 0.5 2014 10 08 20 21 49.91 - 47.729 32.734 2.2 0.0 5 3 5.0 177 0.292 3.3 99.0 2014 10 08 20 49 19.98 - 47.791 32.698 9.6 0.0 6 4 5.0 207 0.026 1.0 1.0 2014 10 08 22 38 09.49 - 47.769 32.684 10.3 0.0 6 4 5.0 172 0.094 0.7 1.3 2014 10 08 22 38 58.13 diff --git a/eqcorrscan/utils/plotting.py b/eqcorrscan/utils/plotting.py index c94bbc76a..306ad05c1 100644 --- a/eqcorrscan/utils/plotting.py +++ b/eqcorrscan/utils/plotting.py @@ -2259,7 +2259,7 @@ def twoD_seismplot(catalog=None, locations=None, bgcolor='#909090', elif method == 'time': dt = [t - time[0] for t in time] c0 = c1 = c2 = dt - label = 'Origin-time offset from {time[0]} (s)' + label = f'Origin-time offset from {time[0]} (s)' elif method == 'sequence': c0 = c1 = c2 = range(len(dep)) label = 'Event number' From 14d3fb755ebc5ef5faf0e3bdc05e89b4bd9aa6b3 Mon Sep 17 00:00:00 2001 From: flixha Date: Fri, 10 Jul 2020 10:23:37 +0200 Subject: [PATCH 015/132] fix overwrite option --- eqcorrscan/core/match_filter/party.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/eqcorrscan/core/match_filter/party.py b/eqcorrscan/core/match_filter/party.py index 6e2ce681f..3c014a749 100644 --- a/eqcorrscan/core/match_filter/party.py +++ b/eqcorrscan/core/match_filter/party.py @@ -578,7 +578,7 @@ def copy(self): return copy.deepcopy(self) def write(self, filename, format='tar', write_detection_catalog=True, - catalog_format="QUAKEML"): + catalog_format="QUAKEML", overwrite=False): """ Write Family out, select output format. @@ -599,6 +599,10 @@ def write(self, filename, format='tar', write_detection_catalog=True, SC3ML, QUAKEML are supported. Note that not all information is written for all formats (QUAKEML is the most complete, but is slow for IO). + :type overwrite: boolean + :param overwrite: + Specifies whether detection-files are overwritten if they exist + already. By default, no files are overwritten. .. NOTE:: csv format will write out detection objects, all other @@ -629,14 +633,17 @@ def write(self, filename, format='tar', write_detection_catalog=True, if catalog_format not in CAT_EXT_MAP.keys(): raise TypeError("{0} is not supported".format(catalog_format)) if format.lower() == 'csv': - if os.path.isfile(filename): - raise MatchFilterError( - 'Will not overwrite existing file: %s' % filename) + if os.path.isfile(filename) and not overwrite: + raise IOError('Will not overwrite existing file: %s' + % filename) for family in self.families: + if os.path.isfile(filename) and overwrite: + os.remove(filename) write_detections(fname=filename, detections=family.detections, mode="a") elif format.lower() == 'tar': - if os.path.exists(filename): + if (os.path.exists(filename) or os.path.exists(filename + ".tgz"))\ + and not overwrite: raise IOError('Will not overwrite existing file: %s' % filename) # os.makedirs(filename) From a6385f591a788cfd351a0a70e8b509baa1b052df Mon Sep 17 00:00:00 2001 From: flixha Date: Fri, 10 Jul 2020 10:24:43 +0200 Subject: [PATCH 016/132] Add SDS-option for archive-read --- eqcorrscan/utils/archive_read.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/eqcorrscan/utils/archive_read.py b/eqcorrscan/utils/archive_read.py index df322851d..e0f85794d 100644 --- a/eqcorrscan/utils/archive_read.py +++ b/eqcorrscan/utils/archive_read.py @@ -21,6 +21,7 @@ from obspy.clients.fdsn.header import FDSNException from obspy.clients.seishub import Client as SeishubClient from obspy.clients.fdsn import Client as FDSNClient +from obspy.clients.filesystem.sds import Client as SDSClient Logger = logging.getLogger(__name__) @@ -128,6 +129,12 @@ def read_data(archive, arc_type, day, stachans, length=86400): Logger.warning('No data on server despite station being ' + 'available...') continue + elif arc_type.upper() == "SDS": + client = SDSClient(archive) + st += client.get_waveforms( + network='*', station=station_map[0], location='*', + channel=station_map[1], starttime=UTCDateTime(day), + endtime=UTCDateTime(day) + length) elif arc_type.lower() == 'day_vols': wavfiles = _get_station_file(os.path.join( archive, day.strftime('Y%Y' + os.sep + 'R%j.01')), From f2f82facaf2ea842bd405c1c7bf96bdaa81c5e34 Mon Sep 17 00:00:00 2001 From: flixha Date: Fri, 10 Jul 2020 14:31:09 +0200 Subject: [PATCH 017/132] Support station availability-check with wildcard + for SDS-client --- eqcorrscan/utils/archive_read.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/eqcorrscan/utils/archive_read.py b/eqcorrscan/utils/archive_read.py index e0f85794d..771ebc0ab 100644 --- a/eqcorrscan/utils/archive_read.py +++ b/eqcorrscan/utils/archive_read.py @@ -16,6 +16,7 @@ import os import logging import glob +import fnmatch from obspy import read, UTCDateTime, Stream from obspy.clients.fdsn.header import FDSNException @@ -107,7 +108,15 @@ def read_data(archive, arc_type, day, stachans, length=86400): else: station_map = station available_stations_map = available_stations - if station_map not in available_stations_map: + # Allow matching of station-channel-tuples with wildcards + stachan_in_station_map = False + for av_station in available_stations_map: + if fnmatch.fnmatch(av_station[0], station[0])\ + and fnmatch.fnmatch(av_station[1], station[1]): + stachan_in_station_map = True + break + #if station_map not in available_stations_map: + if not stachan_in_station_map: msg = ' '.join([station[0], station_map[1], 'is not available for', day.strftime('%Y/%m/%d')]) Logger.warning(msg) @@ -223,6 +232,11 @@ def _check_available_data(archive, arc_type, day): for channel in station: available_stations.append((station.code, channel.code)) + elif arc_type.lower() == 'sds': + client = SDSClient(archive) + nslc = client.get_all_nslc(sds_type=None, datetime=UTCDateTime(day)) + for item in nslc: + available_stations.append((item[1], item[3])) return available_stations From 00c3fda9c069c77b7b9b6db454f6200937470756 Mon Sep 17 00:00:00 2001 From: flixha Date: Tue, 14 Jul 2020 16:20:33 +0200 Subject: [PATCH 018/132] check filename-ending 'tgz' earlier for checks to work --- eqcorrscan/core/match_filter/party.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/eqcorrscan/core/match_filter/party.py b/eqcorrscan/core/match_filter/party.py index 3c014a749..238c95c8b 100644 --- a/eqcorrscan/core/match_filter/party.py +++ b/eqcorrscan/core/match_filter/party.py @@ -634,16 +634,17 @@ def write(self, filename, format='tar', write_detection_catalog=True, raise TypeError("{0} is not supported".format(catalog_format)) if format.lower() == 'csv': if os.path.isfile(filename) and not overwrite: - raise IOError('Will not overwrite existing file: %s' - % filename) + raise MatchFilterError( + 'Will not overwrite existing file: %s' % filename) for family in self.families: if os.path.isfile(filename) and overwrite: os.remove(filename) write_detections(fname=filename, detections=family.detections, mode="a") elif format.lower() == 'tar': - if (os.path.exists(filename) or os.path.exists(filename + ".tgz"))\ - and not overwrite: + if not filename.endswith('.tgz'): + filename = filename + ".tgz" + if os.path.exists(filename) and not overwrite: raise IOError('Will not overwrite existing file: %s' % filename) # os.makedirs(filename) @@ -665,8 +666,6 @@ def write(self, filename, format='tar', write_detection_catalog=True, name = family.template.name + '_detections.csv' name_to_write = join(temp_dir, name) _write_family(family=family, filename=name_to_write) - if not filename.endswith('.tgz'): - filename = filename + ".tgz" with tarfile.open(filename, "w:gz") as tar: tar.add(temp_dir, arcname=os.path.basename(filename)) else: From 87a01a14d2370822c909c7f6e5237b69bce2b2e4 Mon Sep 17 00:00:00 2001 From: flixha Date: Tue, 14 Jul 2020 17:23:34 +0200 Subject: [PATCH 019/132] remove commented line --- eqcorrscan/utils/archive_read.py | 1 - 1 file changed, 1 deletion(-) diff --git a/eqcorrscan/utils/archive_read.py b/eqcorrscan/utils/archive_read.py index 771ebc0ab..3728189bb 100644 --- a/eqcorrscan/utils/archive_read.py +++ b/eqcorrscan/utils/archive_read.py @@ -115,7 +115,6 @@ def read_data(archive, arc_type, day, stachans, length=86400): and fnmatch.fnmatch(av_station[1], station[1]): stachan_in_station_map = True break - #if station_map not in available_stations_map: if not stachan_in_station_map: msg = ' '.join([station[0], station_map[1], 'is not available for', day.strftime('%Y/%m/%d')]) From e3c5d969040d0c99657ac31547da4cd3bbc10f7b Mon Sep 17 00:00:00 2001 From: Calum Chamberlain Date: Wed, 15 Jul 2020 08:44:54 +1200 Subject: [PATCH 020/132] Apply suggestions from code review Consistency --- eqcorrscan/core/match_filter/party.py | 2 +- eqcorrscan/utils/archive_read.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/eqcorrscan/core/match_filter/party.py b/eqcorrscan/core/match_filter/party.py index fc09871fe..859d9606a 100644 --- a/eqcorrscan/core/match_filter/party.py +++ b/eqcorrscan/core/match_filter/party.py @@ -632,7 +632,7 @@ def write(self, filename, format='tar', write_detection_catalog=True, SC3ML, QUAKEML are supported. Note that not all information is written for all formats (QUAKEML is the most complete, but is slow for IO). - :type overwrite: boolean + :type overwrite: bool :param overwrite: Specifies whether detection-files are overwritten if they exist already. By default, no files are overwritten. diff --git a/eqcorrscan/utils/archive_read.py b/eqcorrscan/utils/archive_read.py index 3728189bb..f04ea4260 100644 --- a/eqcorrscan/utils/archive_read.py +++ b/eqcorrscan/utils/archive_read.py @@ -231,7 +231,7 @@ def _check_available_data(archive, arc_type, day): for channel in station: available_stations.append((station.code, channel.code)) - elif arc_type.lower() == 'sds': + elif arc_type.upper() == "SDS": client = SDSClient(archive) nslc = client.get_all_nslc(sds_type=None, datetime=UTCDateTime(day)) for item in nslc: From efe0e67f9fa344706d6f30cae47bab5e13a3ee25 Mon Sep 17 00:00:00 2001 From: flixha Date: Wed, 15 Jul 2020 10:12:29 +0200 Subject: [PATCH 021/132] Add description of changes --- CHANGES.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 229d51efa..bafe458f9 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,4 +1,16 @@ ## Current +* core.party.write + - BUG-FIX: When `format='tar'` is selected, added a check for .tgz-file + suffix before checking the filename against an existing file. Previously, + when a filename without '.tgz'-suffix was supplied, then the file was + overwritten against the function's intention. + - Add option `overwrite=True` to allow overwriting of existing files. +* utils/archive_read.py + - Add support for wildcard-comparisons in the list of requested stations and + channels. + - New option `arctype='SDS'` to read from a SeisComp Data Structure (SDS). + This option is also available in `utils.clustering.extract_detections` and + in `utils.archive_read._check_available_data`. ## 0.4.2 * Add seed-ids to the _spike_test's message. From 168eba4141078e9b7e8e6917a7a385e0e56ff50e Mon Sep 17 00:00:00 2001 From: Calum Chamberlain Date: Fri, 17 Jul 2020 16:26:54 +1200 Subject: [PATCH 022/132] Cope with no quality --- eqcorrscan/utils/catalog_to_dd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eqcorrscan/utils/catalog_to_dd.py b/eqcorrscan/utils/catalog_to_dd.py index 6c7c18ebc..a635270fb 100644 --- a/eqcorrscan/utils/catalog_to_dd.py +++ b/eqcorrscan/utils/catalog_to_dd.py @@ -638,7 +638,7 @@ def _hypodd_phase_str(event, event_id_mapper): magnitude = 0.0 try: time_error = origin.quality['standard_error'] - except AttributeError: + except (TypeError, AttributeError): Logger.warning('No time residual in header') time_error = 0.0 From cec04dac8e90b17ddac4a074832ea25490a92889 Mon Sep 17 00:00:00 2001 From: calum-chamberlain Date: Thu, 23 Jul 2020 12:18:13 +1200 Subject: [PATCH 023/132] Provide option to export cross-correlation sums. --- CHANGES.md | 4 ++++ eqcorrscan/core/match_filter/matched_filter.py | 10 +++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 229d51efa..364f3a4ba 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,4 +1,8 @@ ## Current +* core.match_filter + - match_filter: + - Provide option of exporting the cross-correlation sums for additional later + analysis. ## 0.4.2 * Add seed-ids to the _spike_test's message. diff --git a/eqcorrscan/core/match_filter/matched_filter.py b/eqcorrscan/core/match_filter/matched_filter.py index b9288acde..e2d05d049 100644 --- a/eqcorrscan/core/match_filter/matched_filter.py +++ b/eqcorrscan/core/match_filter/matched_filter.py @@ -385,7 +385,8 @@ def match_filter(template_names, template_list, st, threshold, xcorr_func=None, concurrency=None, cores=None, plot_format='png', output_cat=False, output_event=True, extract_detections=False, arg_check=True, full_peaks=False, - peak_cores=None, spike_test=True, **kwargs): + peak_cores=None, spike_test=True, export_cccsums=False, + **kwargs): """ Main matched-filter detection function. @@ -468,6 +469,8 @@ def match_filter(template_names, template_list, st, threshold, :type spike_test: bool :param spike_test: If set True, raise error when there is a spike in data. defaults to True. + :type export_cccsums: bool + :param export_cccsums: Whether to save the cross-correlation statistic. .. Note:: When using the "fftw" correlation backend the length of the fft @@ -702,6 +705,11 @@ def match_filter(template_names, template_list, st, threshold, outtoc = default_timer() Logger.info("Finding peaks took {0:.4f}s".format(outtoc - outtic)) for i, cccsum in enumerate(cccsums): + if export_cccsums: + fname = (f"{_template_names[i]}-{stream[0].stats.starttime}-" + f"{stream[0].stats.endtime}_cccsum.npy") + np.save(file=fname, arr=cccsum) + Logger.info(f"Saved correlation statistic to {fname}") if np.abs(np.mean(cccsum)) > 0.05: Logger.warning('Mean is not zero! Check this!') # Set up a trace object for the cccsum as this is easier to plot and From 4887b21991f07f9686f49b37f933d02977df2cec Mon Sep 17 00:00:00 2001 From: calum-chamberlain Date: Thu, 23 Jul 2020 12:28:46 +1200 Subject: [PATCH 024/132] Add docs and return ints --- eqcorrscan/utils/mag_calc.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/eqcorrscan/utils/mag_calc.py b/eqcorrscan/utils/mag_calc.py index 3f3d7d6eb..95fd76bf8 100644 --- a/eqcorrscan/utils/mag_calc.py +++ b/eqcorrscan/utils/mag_calc.py @@ -123,8 +123,15 @@ def calc_b_value(magnitudes, completeness, max_mag=None, plotvar=True): :param plotvar: Turn plotting on or off. :rtype: list - :return: List of tuples of (completeness, b-value, residual,\ - number of magnitudes used) + :return: + List of tuples of (completeness, b-value, residual, number of + magnitudes used) + + .. Note:: + High "residuals" indicate better fit. Residuals are calculated + according to the Wiemer & Wyss 2000, Minimum Magnitude of Completeness + in Earthquake Catalogs: Examples from Alaska, the Western United + States, and Japan, BSSA. .. rubric:: Example @@ -182,7 +189,7 @@ def calc_b_value(magnitudes, completeness, max_mag=None, plotvar=True): r = 100 - ((np.sum([abs(complete_freq[i] - predicted_freqs[i]) for i in range(len(complete_freq))]) * 100) / np.sum(complete_freq)) - b_values.append((m_c, abs(fit[0][0]), r, str(len(complete_mags)))) + b_values.append((m_c, abs(fit[0][0]), r, len(complete_mags))) if plotvar: fig, ax1 = plt.subplots() b_vals = ax1.scatter(list(zip(*b_values))[0], list(zip(*b_values))[1], From 62599f1b016db7c6d9fc7ca286a732afd282a457 Mon Sep 17 00:00:00 2001 From: calum-chamberlain Date: Thu, 23 Jul 2020 12:30:03 +1200 Subject: [PATCH 025/132] changelog --- CHANGES.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 229d51efa..5e0a6000c 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,8 @@ ## Current - +* utils.mag_calc.calc_b_value: + - Added useful information to doc-string regarding method and meaning of + residuals + - Changed the number of magnitudes used to an int (from a string!?) ## 0.4.2 * Add seed-ids to the _spike_test's message. * utils.correlation From c16de11132a05af6156519504b38aa7c40ea72fe Mon Sep 17 00:00:00 2001 From: Calum Chamberlain Date: Mon, 3 Aug 2020 08:07:05 +1200 Subject: [PATCH 026/132] Higher precision times in phase.dat --- eqcorrscan/core/lag_calc.py | 7 ++++++- eqcorrscan/utils/catalog_to_dd.py | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/eqcorrscan/core/lag_calc.py b/eqcorrscan/core/lag_calc.py index f5bd8ede4..274086795 100644 --- a/eqcorrscan/core/lag_calc.py +++ b/eqcorrscan/core/lag_calc.py @@ -165,8 +165,13 @@ def _concatenate_and_correlate(streams, template, cores): cores=cores) # Re-order used_chans chan_order = chan_order[0] - for _used_chans in used_chans: + for i in range(len(used_chans)): + _used_chans = used_chans[i] + # Remove any channels that ended up not being used. + _used_chans = [c for c in _used_chans if c.channel in chan_order] + # Order the channels in the same way that they were correlated _used_chans.sort(key=lambda chan: chan_order.index(chan.channel)) + used_chans[i] = _used_chans # Put back in. # Reshape ccc output ccc_out = np.zeros((len(streams), len(chans), diff --git a/eqcorrscan/utils/catalog_to_dd.py b/eqcorrscan/utils/catalog_to_dd.py index a635270fb..7391c65d2 100644 --- a/eqcorrscan/utils/catalog_to_dd.py +++ b/eqcorrscan/utils/catalog_to_dd.py @@ -618,7 +618,7 @@ def write_correlations(catalog, stream_dict, extract_len, pre_pick, def _hypodd_phase_pick_str(pick, sparse_event): """ Make a hypodd phase.dat style pick string. """ - pick_str = "{station:5s} {tt:7.2f} {weight:5.3f} {phase:1s}".format( + pick_str = "{station:5s} {tt:7.4f} {weight:5.3f} {phase:1s}".format( station=pick.waveform_id.station_code, tt=pick.tt, weight=pick.weight, phase=pick.phase[0].upper()) return pick_str From 880b051fd34bf7cfdeabfb1fd5b64cfcc075e725 Mon Sep 17 00:00:00 2001 From: iman kahbasi Date: Fri, 7 Aug 2020 13:26:27 +0430 Subject: [PATCH 027/132] Added the ability of saving correlation data of the lag_calc. --- CHANGES.md | 1 + eqcorrscan/core/lag_calc.py | 27 +++++++++++++++++++++++--- eqcorrscan/core/match_filter/family.py | 14 ++++++++++--- eqcorrscan/core/match_filter/party.py | 12 ++++++++++-- eqcorrscan/tests/lag_calc_test.py | 10 ++++++---- 5 files changed, 52 insertions(+), 12 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 5e0a6000c..d38510621 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,4 +1,5 @@ ## Current +* Added the ability of saving correlation data of the lag_calc. * utils.mag_calc.calc_b_value: - Added useful information to doc-string regarding method and meaning of residuals diff --git a/eqcorrscan/core/lag_calc.py b/eqcorrscan/core/lag_calc.py index 274086795..33e7061cb 100644 --- a/eqcorrscan/core/lag_calc.py +++ b/eqcorrscan/core/lag_calc.py @@ -190,7 +190,7 @@ def _concatenate_and_correlate(streams, template, cores): def xcorr_pick_family(family, stream, shift_len=0.2, min_cc=0.4, horizontal_chans=['E', 'N', '1', '2'], vertical_chans=['Z'], cores=1, interpolate=False, - plot=False, plotdir=None): + plot=False, plotdir=None, npy=False, npydir=None): """ Compute cross-correlation picks for detections in a family. @@ -227,6 +227,13 @@ def xcorr_pick_family(family, stream, shift_len=0.2, min_cc=0.4, :type plotdir: str :param plotdir: Path to plotting folder, plots will be output here. + :type npy: bool + :param npy: + To generate a binary file in NumPy for every detection or not, + defaults to False + :type npydir: str + :param npydir: + Path to saving folder, NumPy files will be output here. :return: Dictionary of picked events keyed by detection id. """ @@ -250,6 +257,8 @@ def xcorr_pick_family(family, stream, shift_len=0.2, min_cc=0.4, for i, detection_id in enumerate(detection_ids): detection = [d for d in family.detections if d.id == detection_id][0] correlations = ccc[i] + if npy: + np.save(os.path.join(npydir, detection_id+'.npy'), correlations) picked_chans = chans[i] detect_stream = detect_streams_dict[detection_id] checksum, cccsum, used_chans = 0.0, 0.0, 0 @@ -393,7 +402,7 @@ def _prepare_data(family, detect_data, shift_len): def lag_calc(detections, detect_data, template_names, templates, shift_len=0.2, min_cc=0.4, horizontal_chans=['E', 'N', '1', '2'], vertical_chans=['Z'], cores=1, interpolate=False, - plot=False, plotdir=None): + plot=False, plotdir=None, npy=False, npydir=None): """ Cross-correlation derived picking of seismic events. @@ -443,6 +452,13 @@ def lag_calc(detections, detect_data, template_names, templates, To generate a plot for every detection or not, defaults to False :param plotdir: Path to plotting folder, plots will be output here. + :type npy: bool + :param npy: + To generate a binary file in NumPy for every detection or not, + defaults to False + :type npydir: str + :param npydir: + Path to saving folder, NumPy files will be output here. :returns: Catalog of events with picks. No origin information is included. @@ -494,6 +510,10 @@ def lag_calc(detections, detect_data, template_names, templates, detections[n].id == output[m].resource_id if the output[m] is for the same event as detections[n]. + + .. note:: + The correlation data that is saved to the binary files can be usefull + for exploration on selecting proper threshold according to your data. """ # First check that sample rates are equal for everything for tr in detect_data: @@ -522,7 +542,8 @@ def lag_calc(detections, detect_data, template_names, templates, family=family, stream=detect_data, min_cc=min_cc, horizontal_chans=horizontal_chans, vertical_chans=vertical_chans, interpolate=interpolate, - cores=cores, shift_len=shift_len, plot=plot, plotdir=plotdir) + cores=cores, shift_len=shift_len, plot=plot, plotdir=plotdir, + npy=npy, npydir=npydir) initial_cat.update(template_dict) # Order the catalogue to match the input output_cat = Catalog() diff --git a/eqcorrscan/core/match_filter/family.py b/eqcorrscan/core/match_filter/family.py index 0f5e6d242..6d81bf123 100644 --- a/eqcorrscan/core/match_filter/family.py +++ b/eqcorrscan/core/match_filter/family.py @@ -503,8 +503,8 @@ def write(self, filename, format='tar'): def lag_calc(self, stream, pre_processed, shift_len=0.2, min_cc=0.4, horizontal_chans=['E', 'N', '1', '2'], vertical_chans=['Z'], cores=1, interpolate=False, plot=False, plotdir=None, - parallel=True, process_cores=None, ignore_length=False, - ignore_bad_data=False, **kwargs): + npy=False, npydir=None, parallel=True, process_cores=None, + ignore_length=False, ignore_bad_data=False, **kwargs): """ Compute picks based on cross-correlation alignment. @@ -547,6 +547,13 @@ def lag_calc(self, stream, pre_processed, shift_len=0.2, min_cc=0.4, :param plotdir: The path to save plots to. If `plotdir=None` (default) then the figure will be shown on screen. + :type npy: bool + :param npy: + To generate a binary file in NumPy for every detection or not, + defaults to False + :type npydir: str + :param npydir: + Path to saving folder, NumPy files will be output here. :type parallel: bool :param parallel: Turn parallel processing on or off. :type process_cores: int @@ -596,7 +603,8 @@ def lag_calc(self, stream, pre_processed, shift_len=0.2, min_cc=0.4, family=self, stream=processed_stream, shift_len=shift_len, min_cc=min_cc, horizontal_chans=horizontal_chans, vertical_chans=vertical_chans, cores=cores, - interpolate=interpolate, plot=plot, plotdir=plotdir) + interpolate=interpolate, plot=plot, plotdir=plotdir, + npy=npy, npydir=npydir) catalog_out = Catalog([ev for ev in picked_dict.values()]) for detection_id, event in picked_dict.items(): for pick in event.picks: diff --git a/eqcorrscan/core/match_filter/party.py b/eqcorrscan/core/match_filter/party.py index 9b437c572..d59b51373 100644 --- a/eqcorrscan/core/match_filter/party.py +++ b/eqcorrscan/core/match_filter/party.py @@ -782,8 +782,8 @@ def read(self, filename=None, read_detection_catalog=True, def lag_calc(self, stream, pre_processed, shift_len=0.2, min_cc=0.4, horizontal_chans=['E', 'N', '1', '2'], vertical_chans=['Z'], cores=1, interpolate=False, plot=False, plotdir=None, - parallel=True, process_cores=None, ignore_length=False, - ignore_bad_data=False, **kwargs): + npy=False, npydir=None, parallel=True, process_cores=None, + ignore_length=False, ignore_bad_data=False, **kwargs): """ Compute picks based on cross-correlation alignment. @@ -826,6 +826,13 @@ def lag_calc(self, stream, pre_processed, shift_len=0.2, min_cc=0.4, :param plotdir: The path to save plots to. If `plotdir=None` (default) then the figure will be shown on screen. + :type npy: bool + :param npy: + To generate a binary file in NumPy for every detection or not, + defaults to False + :type npydir: str + :param npydir: + Path to saving folder, NumPy files will be output here. :type parallel: bool :param parallel: Turn parallel processing on or off. :type process_cores: int @@ -898,6 +905,7 @@ def lag_calc(self, stream, pre_processed, shift_len=0.2, min_cc=0.4, horizontal_chans=horizontal_chans, vertical_chans=vertical_chans, cores=cores, interpolate=interpolate, plot=plot, plotdir=plotdir, + npy=npy, npydir=npydir, parallel=parallel, process_cores=process_cores, ignore_bad_data=ignore_bad_data, ignore_length=ignore_length, **kwargs) diff --git a/eqcorrscan/tests/lag_calc_test.py b/eqcorrscan/tests/lag_calc_test.py index 5fbc581bd..93c45fd4b 100644 --- a/eqcorrscan/tests/lag_calc_test.py +++ b/eqcorrscan/tests/lag_calc_test.py @@ -112,7 +112,8 @@ def test_prepare_data_masked(self): def test_family_picking(self): catalog_dict = xcorr_pick_family( - family=self.party[0], stream=self.data, shift_len=0.2, plot=False) + family=self.party[0], stream=self.data, shift_len=0.2, plot=False, + npy=False) for event in catalog_dict.values(): self.assertEqual(len(event.picks), len(self.data)) for pick in event.picks: @@ -134,7 +135,8 @@ def test_family_picking_missing_data(self): gappy_data[0].data = np.ma.masked_array( data=gappy_data[0].data, mask=mask) catalog_dict = xcorr_pick_family( - family=self.party[0], stream=gappy_data, shift_len=0.2, plot=False) + family=self.party[0], stream=gappy_data, shift_len=0.2, plot=False, + npy=False) gap = gappy_data.split().get_gaps() for event in catalog_dict.values(): if len(event.picks) != len(self.data): @@ -153,7 +155,7 @@ def test_family_picking_missing_data(self): def test_family_picking_with_interpolation(self): catalog_dict = xcorr_pick_family( family=self.party[0], stream=self.data, shift_len=0.2, plot=False, - interpolate=True) + interpolate=True, npy=False) for event in catalog_dict.values(): for pick in event.picks: self.assertTrue("cc_max=" in pick.comments[0].text) @@ -168,7 +170,7 @@ def test_lag_calc_api(self): detections, self.data, template_names, templates, shift_len=0.2, min_cc=0.4, horizontal_chans=['E', 'N', '1', '2'], vertical_chans=['Z'], cores=1, interpolate=False, - plot=False) + plot=False, npy=False) self.assertEqual(len(output_cat), len(detections)) for event in output_cat: self.assertEqual(len(event.picks), len(self.data)) From 3e386aa38a7f54255318cec7d54f236c496394ee Mon Sep 17 00:00:00 2001 From: iman kahbasi Date: Fri, 7 Aug 2020 13:40:05 +0430 Subject: [PATCH 028/132] Writing correction in note of lag_calc --- eqcorrscan/core/lag_calc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eqcorrscan/core/lag_calc.py b/eqcorrscan/core/lag_calc.py index 33e7061cb..5d5e4fc5e 100644 --- a/eqcorrscan/core/lag_calc.py +++ b/eqcorrscan/core/lag_calc.py @@ -512,7 +512,7 @@ def lag_calc(detections, detect_data, template_names, templates, if the output[m] is for the same event as detections[n]. .. note:: - The correlation data that is saved to the binary files can be usefull + The correlation data that is saved to the binary files can be useful for exploration on selecting proper threshold according to your data. """ # First check that sample rates are equal for everything From bc8d3e679f77c897b342f934e0040fec55f81437 Mon Sep 17 00:00:00 2001 From: iman kahbasi Date: Fri, 7 Aug 2020 13:48:35 +0430 Subject: [PATCH 029/132] Make npydir --- eqcorrscan/core/lag_calc.py | 1 + 1 file changed, 1 insertion(+) diff --git a/eqcorrscan/core/lag_calc.py b/eqcorrscan/core/lag_calc.py index 5d5e4fc5e..f987aad2c 100644 --- a/eqcorrscan/core/lag_calc.py +++ b/eqcorrscan/core/lag_calc.py @@ -258,6 +258,7 @@ def xcorr_pick_family(family, stream, shift_len=0.2, min_cc=0.4, detection = [d for d in family.detections if d.id == detection_id][0] correlations = ccc[i] if npy: + os.makedirs(npydir, exist_ok=True) np.save(os.path.join(npydir, detection_id+'.npy'), correlations) picked_chans = chans[i] detect_stream = detect_streams_dict[detection_id] From 6331377df76aa38d99405afd98fdb122c0e348fd Mon Sep 17 00:00:00 2001 From: iman kahbasi Date: Tue, 11 Aug 2020 00:11:11 +0430 Subject: [PATCH 030/132] change variables name same as #420 --- eqcorrscan/core/lag_calc.py | 32 +++++++++++++------------- eqcorrscan/core/match_filter/family.py | 21 +++++++++-------- eqcorrscan/core/match_filter/party.py | 15 ++++++------ eqcorrscan/tests/lag_calc_test.py | 8 +++---- 4 files changed, 39 insertions(+), 37 deletions(-) diff --git a/eqcorrscan/core/lag_calc.py b/eqcorrscan/core/lag_calc.py index f987aad2c..ab3b508bc 100644 --- a/eqcorrscan/core/lag_calc.py +++ b/eqcorrscan/core/lag_calc.py @@ -190,7 +190,7 @@ def _concatenate_and_correlate(streams, template, cores): def xcorr_pick_family(family, stream, shift_len=0.2, min_cc=0.4, horizontal_chans=['E', 'N', '1', '2'], vertical_chans=['Z'], cores=1, interpolate=False, - plot=False, plotdir=None, npy=False, npydir=None): + plot=False, plotdir=None, export_cc=False, cc_dir=None): """ Compute cross-correlation picks for detections in a family. @@ -227,12 +227,12 @@ def xcorr_pick_family(family, stream, shift_len=0.2, min_cc=0.4, :type plotdir: str :param plotdir: Path to plotting folder, plots will be output here. - :type npy: bool - :param npy: + :type export_cc: bool + :param export_cc: To generate a binary file in NumPy for every detection or not, defaults to False - :type npydir: str - :param npydir: + :type cc_dir: str + :param cc_dir: Path to saving folder, NumPy files will be output here. :return: Dictionary of picked events keyed by detection id. @@ -257,9 +257,9 @@ def xcorr_pick_family(family, stream, shift_len=0.2, min_cc=0.4, for i, detection_id in enumerate(detection_ids): detection = [d for d in family.detections if d.id == detection_id][0] correlations = ccc[i] - if npy: - os.makedirs(npydir, exist_ok=True) - np.save(os.path.join(npydir, detection_id+'.npy'), correlations) + if export_cc: + os.makedirs(cc_dir, exist_ok=True) + np.save(os.path.join(cc_dir, f'{detection_id}.npy'), correlations) picked_chans = chans[i] detect_stream = detect_streams_dict[detection_id] checksum, cccsum, used_chans = 0.0, 0.0, 0 @@ -403,7 +403,7 @@ def _prepare_data(family, detect_data, shift_len): def lag_calc(detections, detect_data, template_names, templates, shift_len=0.2, min_cc=0.4, horizontal_chans=['E', 'N', '1', '2'], vertical_chans=['Z'], cores=1, interpolate=False, - plot=False, plotdir=None, npy=False, npydir=None): + plot=False, plotdir=None, export_cc=False, cc_dir=None): """ Cross-correlation derived picking of seismic events. @@ -453,12 +453,12 @@ def lag_calc(detections, detect_data, template_names, templates, To generate a plot for every detection or not, defaults to False :param plotdir: Path to plotting folder, plots will be output here. - :type npy: bool - :param npy: + :type export_cc: bool + :param export_cc: To generate a binary file in NumPy for every detection or not, defaults to False - :type npydir: str - :param npydir: + :type cc_dir: str + :param cc_dir: Path to saving folder, NumPy files will be output here. :returns: @@ -513,8 +513,8 @@ def lag_calc(detections, detect_data, template_names, templates, if the output[m] is for the same event as detections[n]. .. note:: - The correlation data that is saved to the binary files can be useful - for exploration on selecting proper threshold according to your data. + The correlation data that are saved to the binary files can be useful + to select an appropriate threshold for your data. """ # First check that sample rates are equal for everything for tr in detect_data: @@ -544,7 +544,7 @@ def lag_calc(detections, detect_data, template_names, templates, min_cc=min_cc, horizontal_chans=horizontal_chans, vertical_chans=vertical_chans, interpolate=interpolate, cores=cores, shift_len=shift_len, plot=plot, plotdir=plotdir, - npy=npy, npydir=npydir) + export_cc=export_cc, cc_dir=cc_dir) initial_cat.update(template_dict) # Order the catalogue to match the input output_cat = Catalog() diff --git a/eqcorrscan/core/match_filter/family.py b/eqcorrscan/core/match_filter/family.py index 6d81bf123..e997f011c 100644 --- a/eqcorrscan/core/match_filter/family.py +++ b/eqcorrscan/core/match_filter/family.py @@ -503,8 +503,9 @@ def write(self, filename, format='tar'): def lag_calc(self, stream, pre_processed, shift_len=0.2, min_cc=0.4, horizontal_chans=['E', 'N', '1', '2'], vertical_chans=['Z'], cores=1, interpolate=False, plot=False, plotdir=None, - npy=False, npydir=None, parallel=True, process_cores=None, - ignore_length=False, ignore_bad_data=False, **kwargs): + parallel=True, process_cores=None, ignore_length=False, + ignore_bad_data=False, export_cc=False, cc_dir=None, + **kwargs): """ Compute picks based on cross-correlation alignment. @@ -547,13 +548,6 @@ def lag_calc(self, stream, pre_processed, shift_len=0.2, min_cc=0.4, :param plotdir: The path to save plots to. If `plotdir=None` (default) then the figure will be shown on screen. - :type npy: bool - :param npy: - To generate a binary file in NumPy for every detection or not, - defaults to False - :type npydir: str - :param npydir: - Path to saving folder, NumPy files will be output here. :type parallel: bool :param parallel: Turn parallel processing on or off. :type process_cores: int @@ -571,6 +565,13 @@ def lag_calc(self, stream, pre_processed, shift_len=0.2, min_cc=0.4, If False (default), errors will be raised if data are excessively gappy or are mostly zeros. If True then no error will be raised, but an empty trace will be returned (and not used in detection). + :type export_cc: bool + :param export_cc: + To generate a binary file in NumPy for every detection or not, + defaults to False + :type cc_dir: str + :param cc_dir: + Path to saving folder, NumPy files will be output here. :returns: Catalog of events with picks. No origin information is included. @@ -604,7 +605,7 @@ def lag_calc(self, stream, pre_processed, shift_len=0.2, min_cc=0.4, min_cc=min_cc, horizontal_chans=horizontal_chans, vertical_chans=vertical_chans, cores=cores, interpolate=interpolate, plot=plot, plotdir=plotdir, - npy=npy, npydir=npydir) + export_cc=export_cc, cc_dir=cc_dir) catalog_out = Catalog([ev for ev in picked_dict.values()]) for detection_id, event in picked_dict.items(): for pick in event.picks: diff --git a/eqcorrscan/core/match_filter/party.py b/eqcorrscan/core/match_filter/party.py index d59b51373..c6a0f86d4 100644 --- a/eqcorrscan/core/match_filter/party.py +++ b/eqcorrscan/core/match_filter/party.py @@ -782,8 +782,9 @@ def read(self, filename=None, read_detection_catalog=True, def lag_calc(self, stream, pre_processed, shift_len=0.2, min_cc=0.4, horizontal_chans=['E', 'N', '1', '2'], vertical_chans=['Z'], cores=1, interpolate=False, plot=False, plotdir=None, - npy=False, npydir=None, parallel=True, process_cores=None, - ignore_length=False, ignore_bad_data=False, **kwargs): + parallel=True, process_cores=None, ignore_length=False, + ignore_bad_data=False, export_cc=False, cc_dir=None, + **kwargs): """ Compute picks based on cross-correlation alignment. @@ -826,12 +827,12 @@ def lag_calc(self, stream, pre_processed, shift_len=0.2, min_cc=0.4, :param plotdir: The path to save plots to. If `plotdir=None` (default) then the figure will be shown on screen. - :type npy: bool - :param npy: + :type export_cc: bool + :param export_cc: To generate a binary file in NumPy for every detection or not, defaults to False - :type npydir: str - :param npydir: + :type cc_dir: str + :param cc_dir: Path to saving folder, NumPy files will be output here. :type parallel: bool :param parallel: Turn parallel processing on or off. @@ -905,7 +906,7 @@ def lag_calc(self, stream, pre_processed, shift_len=0.2, min_cc=0.4, horizontal_chans=horizontal_chans, vertical_chans=vertical_chans, cores=cores, interpolate=interpolate, plot=plot, plotdir=plotdir, - npy=npy, npydir=npydir, + export_cc=export_cc, cc_dir=cc_dir, parallel=parallel, process_cores=process_cores, ignore_bad_data=ignore_bad_data, ignore_length=ignore_length, **kwargs) diff --git a/eqcorrscan/tests/lag_calc_test.py b/eqcorrscan/tests/lag_calc_test.py index 93c45fd4b..cfd4f8688 100644 --- a/eqcorrscan/tests/lag_calc_test.py +++ b/eqcorrscan/tests/lag_calc_test.py @@ -113,7 +113,7 @@ def test_prepare_data_masked(self): def test_family_picking(self): catalog_dict = xcorr_pick_family( family=self.party[0], stream=self.data, shift_len=0.2, plot=False, - npy=False) + export_cc=False) for event in catalog_dict.values(): self.assertEqual(len(event.picks), len(self.data)) for pick in event.picks: @@ -136,7 +136,7 @@ def test_family_picking_missing_data(self): data=gappy_data[0].data, mask=mask) catalog_dict = xcorr_pick_family( family=self.party[0], stream=gappy_data, shift_len=0.2, plot=False, - npy=False) + export_cc=False) gap = gappy_data.split().get_gaps() for event in catalog_dict.values(): if len(event.picks) != len(self.data): @@ -155,7 +155,7 @@ def test_family_picking_missing_data(self): def test_family_picking_with_interpolation(self): catalog_dict = xcorr_pick_family( family=self.party[0], stream=self.data, shift_len=0.2, plot=False, - interpolate=True, npy=False) + interpolate=True, export_cc=False) for event in catalog_dict.values(): for pick in event.picks: self.assertTrue("cc_max=" in pick.comments[0].text) @@ -170,7 +170,7 @@ def test_lag_calc_api(self): detections, self.data, template_names, templates, shift_len=0.2, min_cc=0.4, horizontal_chans=['E', 'N', '1', '2'], vertical_chans=['Z'], cores=1, interpolate=False, - plot=False, npy=False) + plot=False, export_cc=False) self.assertEqual(len(output_cat), len(detections)) for event in output_cat: self.assertEqual(len(event.picks), len(self.data)) From 492be8c560f770cbc3967164dc76df631c244bb9 Mon Sep 17 00:00:00 2001 From: iman kahbasi Date: Tue, 11 Aug 2020 00:23:49 +0430 Subject: [PATCH 031/132] Added logger to export_cc --- eqcorrscan/core/lag_calc.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/eqcorrscan/core/lag_calc.py b/eqcorrscan/core/lag_calc.py index ab3b508bc..372bf8357 100644 --- a/eqcorrscan/core/lag_calc.py +++ b/eqcorrscan/core/lag_calc.py @@ -259,7 +259,9 @@ def xcorr_pick_family(family, stream, shift_len=0.2, min_cc=0.4, correlations = ccc[i] if export_cc: os.makedirs(cc_dir, exist_ok=True) - np.save(os.path.join(cc_dir, f'{detection_id}.npy'), correlations) + fname = f"{detection_id}-cc.npy" + np.save(os.path.join(cc_dir, f'{fname}'), correlations) + Logger.info(f"Saved correlation statistic to {fname} (phase-picking)") picked_chans = chans[i] detect_stream = detect_streams_dict[detection_id] checksum, cccsum, used_chans = 0.0, 0.0, 0 From 3c6fe04020c0c9914e21a2eff1b9eef04e67c1eb Mon Sep 17 00:00:00 2001 From: iman kahbasi Date: Tue, 11 Aug 2020 01:00:50 +0430 Subject: [PATCH 032/132] Added test for export_cc in xcorr_pick_family --- eqcorrscan/tests/lag_calc_test.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/eqcorrscan/tests/lag_calc_test.py b/eqcorrscan/tests/lag_calc_test.py index cfd4f8688..358ea964e 100644 --- a/eqcorrscan/tests/lag_calc_test.py +++ b/eqcorrscan/tests/lag_calc_test.py @@ -1,6 +1,8 @@ """ A series of test functions for the core functions in EQcorrscan. """ +import glob +import os import unittest import numpy as np import logging @@ -175,6 +177,15 @@ def test_lag_calc_api(self): for event in output_cat: self.assertEqual(len(event.picks), len(self.data)) + def test_xcorr_pick_family_export_cc(self): + cc_dir = 'cc_exported' + xcorr_pick_family( + family=self.party[0], stream=self.data, shift_len=0.2, plot=False, + interpolate=False, export_cc=True, cc_dir=cc_dir) + cc_files = glob.glob(os.path.join(cc_dir, '*.npy')) + for fcc in cc_files: + np.load(fcc) + class SimpleRealDataTests(unittest.TestCase): @classmethod From a9824cbb5abd526e09291f2e3264b59636ec7df2 Mon Sep 17 00:00:00 2001 From: iman kahbasi Date: Tue, 11 Aug 2020 01:03:29 +0430 Subject: [PATCH 033/132] make line <79 characters --- eqcorrscan/core/lag_calc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eqcorrscan/core/lag_calc.py b/eqcorrscan/core/lag_calc.py index 372bf8357..67e945cc7 100644 --- a/eqcorrscan/core/lag_calc.py +++ b/eqcorrscan/core/lag_calc.py @@ -261,7 +261,7 @@ def xcorr_pick_family(family, stream, shift_len=0.2, min_cc=0.4, os.makedirs(cc_dir, exist_ok=True) fname = f"{detection_id}-cc.npy" np.save(os.path.join(cc_dir, f'{fname}'), correlations) - Logger.info(f"Saved correlation statistic to {fname} (phase-picking)") + Logger.info(f"Saved correlation statistic to {fname} (lag_calc)") picked_chans = chans[i] detect_stream = detect_streams_dict[detection_id] checksum, cccsum, used_chans = 0.0, 0.0, 0 From 285ab76e7940ce9a944ca694fc06f2c3b7352dda Mon Sep 17 00:00:00 2001 From: Calum Chamberlain Date: Tue, 11 Aug 2020 10:03:45 +1200 Subject: [PATCH 034/132] Round to 1dp across all systems --- eqcorrscan/utils/mag_calc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eqcorrscan/utils/mag_calc.py b/eqcorrscan/utils/mag_calc.py index 95fd76bf8..10e1444ae 100644 --- a/eqcorrscan/utils/mag_calc.py +++ b/eqcorrscan/utils/mag_calc.py @@ -150,7 +150,7 @@ def calc_b_value(magnitudes, completeness, max_mag=None, plotvar=True): >>> # We can set a maximum magnitude: >>> b_values = calc_b_value(magnitudes, completeness=np.arange(3, 7, 0.2), ... plotvar=False, max_mag=5) - >>> round(b_values[4][1]) + >>> round(b_values[4][1], 1) 1.0 """ b_values = [] From e799826eef19dac1921c236444315b918c27473d Mon Sep 17 00:00:00 2001 From: Calum Chamberlain Date: Tue, 11 Aug 2020 10:14:10 +1200 Subject: [PATCH 035/132] Round to 1 dp across all systems --- eqcorrscan/utils/mag_calc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eqcorrscan/utils/mag_calc.py b/eqcorrscan/utils/mag_calc.py index 10e1444ae..46751850b 100644 --- a/eqcorrscan/utils/mag_calc.py +++ b/eqcorrscan/utils/mag_calc.py @@ -145,7 +145,7 @@ def calc_b_value(magnitudes, completeness, max_mag=None, plotvar=True): >>> magnitudes = [event.magnitudes[0].mag for event in catalog] >>> b_values = calc_b_value(magnitudes, completeness=np.arange(3, 7, 0.2), ... plotvar=False) - >>> round(b_values[4][1]) + >>> round(b_values[4][1], 1) 1.0 >>> # We can set a maximum magnitude: >>> b_values = calc_b_value(magnitudes, completeness=np.arange(3, 7, 0.2), From 1857124c0bfbbc588a1d6cd05cc7f008121591ce Mon Sep 17 00:00:00 2001 From: flixha Date: Thu, 13 Aug 2020 13:52:57 +0200 Subject: [PATCH 036/132] Bugfix for overwrite: remove file before writing --- eqcorrscan/core/match_filter/party.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eqcorrscan/core/match_filter/party.py b/eqcorrscan/core/match_filter/party.py index 859d9606a..b9c5b0e86 100644 --- a/eqcorrscan/core/match_filter/party.py +++ b/eqcorrscan/core/match_filter/party.py @@ -669,9 +669,9 @@ def write(self, filename, format='tar', write_detection_catalog=True, if os.path.isfile(filename) and not overwrite: raise MatchFilterError( 'Will not overwrite existing file: %s' % filename) + if os.path.isfile(filename) and overwrite: + os.remove(filename) for family in self.families: - if os.path.isfile(filename) and overwrite: - os.remove(filename) write_detections(fname=filename, detections=family.detections, mode="a") elif format.lower() == 'tar': From 4060795568d2b34548432700a315214a09532046 Mon Sep 17 00:00:00 2001 From: Calum Chamberlain Date: Fri, 14 Aug 2020 11:04:54 +1200 Subject: [PATCH 037/132] Patches for catalog-to-dd 1. Check only the first char of the phase hint 2. Warn about different lengths being found, which occurs due to insufficient data passed 3. Skip correlations when no matching data are found. --- eqcorrscan/utils/catalog_to_dd.py | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/eqcorrscan/utils/catalog_to_dd.py b/eqcorrscan/utils/catalog_to_dd.py index 7391c65d2..eb06a98f3 100644 --- a/eqcorrscan/utils/catalog_to_dd.py +++ b/eqcorrscan/utils/catalog_to_dd.py @@ -262,12 +262,19 @@ def _compute_dt_correlations(catalog, master, min_link, event_id_mapper, master.resource_id.id, phase_hint)) continue # Check lengths - master_length = Counter( - (tr.stats.npts for tr in _master_stream)).most_common(1)[0][0] + master_length = [tr.stats.npts for tr in _master_stream] + if len(set(master_length)) > 1: + Logger.warning("Multiple lengths found - check that you " + "are providing sufficient data") + master_length = Counter(master_length).most_common(1)[0][0] _master_stream = _master_stream.select(npts=master_length) - matched_length = Counter( - (tr.stats.npts for st in _matched_streams.values() - for tr in st)).most_common(1)[0][0] + + matched_length = [tr.stats.npts for st in _matched_streams.values() for tr in st] + if len(set(matched_length)) > 1: + Logger.warning( + "Multiple lengths found in matched data - check that you " + "are providing sufficient data") + matched_length = Counter(matched_length).most_common(1)[0][0] # Remove empty streams and generate an ordered list of event_ids used_event_ids, used_matched_streams = [], [] for event_id, _matched_stream in _matched_streams.items(): @@ -275,6 +282,15 @@ def _compute_dt_correlations(catalog, master, min_link, event_id_mapper, if len(_matched_stream) > 0: used_event_ids.append(event_id) used_matched_streams.append(_matched_stream) + # Check that there are matching seed ids. + master_seed_ids = set(tr.id for tr in _master_stream) + matched_seed_ids = set(tr.id for st in used_matched_streams for tr in st) + if master_seed_ids not in matched_seed_ids: + Logger.warning( + "After checking length there are no matched traces: " + f"master: {master_seed_ids}, matched: {matched_seed_ids}") + continue + # Do the correlations ccc_out, used_chans = _concatenate_and_correlate( template=_master_stream, streams=used_matched_streams, cores=max_workers) @@ -293,7 +309,7 @@ def _compute_dt_correlations(catalog, master, min_link, event_id_mapper, continue shift -= shift_len pick = [p for p in event_dict[used_event_id].picks - if p.phase_hint == phase_hint + if p.phase_hint[0] == phase_hint and p.waveform_id.station_code == chan.channel[0] and p.waveform_id.channel_code == chan.channel[1]] pick = sorted(pick, key=lambda p: p.time)[0] @@ -311,7 +327,7 @@ def _compute_dt_correlations(catalog, master, min_link, event_id_mapper, _DTObs(station=chan.channel[0], tt1=master_tts["{0}_{1}".format( chan.channel[0], phase_hint)], - tt2=tt2, weight=cc_max ** 2, phase=phase_hint)) + tt2=tt2, weight=cc_max ** 2, phase=phase_hint[0])) differential_times_dict.update({used_event_id: diff_time}) # Threshold on min_link differential_times = [dt for dt in differential_times_dict.values() From 26d95bb1fae5fb536da90ad51a2ba1bd7bf0f7cc Mon Sep 17 00:00:00 2001 From: Calum Chamberlain Date: Sat, 15 Aug 2020 09:31:51 +1200 Subject: [PATCH 038/132] Apply suggestions from code review Minor changes to axis labels and color-palette --- eqcorrscan/utils/plotting.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/eqcorrscan/utils/plotting.py b/eqcorrscan/utils/plotting.py index f449f5b29..ef99d65db 100644 --- a/eqcorrscan/utils/plotting.py +++ b/eqcorrscan/utils/plotting.py @@ -2243,7 +2243,7 @@ def twoD_seismplot(catalog=None, locations=None, bgcolor='#909090', assert (catalog and locations) or catalog or locations,\ "Requires catalog and/or locations" # set default parameters of plt.scatter() - default_parameters = {'cmap': 'jet_r', 'marker': ',', 's': 1, 'lw': 1} + default_parameters = {'cmap': 'viridis_r', 'marker': ',', 's': 1, 'lw': 1} for key in default_parameters.keys(): if key not in kwargs.keys(): kwargs[key] = default_parameters[key] @@ -2297,13 +2297,13 @@ def twoD_seismplot(catalog=None, locations=None, bgcolor='#909090', ax1 = fig.add_subplot(gs[1]) ax1.set_facecolor(bgcolor) ax1.set_yticks([]) - ax1.set_xlabel('Depth') + ax1.set_xlabel('Depth (km)') map1 = ax1.scatter(dep, lat, c=c1, **kwargs) # cross section parallel to longitude (lon ,depth) ax2 = plt.subplot(gs[2]) ax2.set_facecolor(bgcolor) ax2.invert_yaxis() - ax2.set_ylabel('Depth') + ax2.set_ylabel('Depth (km)') ax2.set_xlabel('Longitude') map2 = ax2.scatter(lon, dep, c=c2, **kwargs) # location of color bar From a18d9fe4ff0f9f6548ce44c4b27836ef67de250d Mon Sep 17 00:00:00 2001 From: Calum Chamberlain Date: Sat, 15 Aug 2020 09:32:53 +1200 Subject: [PATCH 039/132] Move changelog to correct place My bad for being so slow! --- CHANGES.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 892c56de0..e6c379288 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -3,6 +3,9 @@ - Added useful information to doc-string regarding method and meaning of residuals - Changed the number of magnitudes used to an int (from a string!?) +* utils.plotting + - Function added (twoD_seismplot) for plotting seismicity (#365). + ## 0.4.2 * Add seed-ids to the _spike_test's message. * utils.correlation @@ -15,8 +18,6 @@ within regions where correlations should not be computed (spikes, step artifacts due to incorrectly padding data gaps). - USERS SHOULD BE CAREFUL TO CHECK THEIR DATA IF THEY SEE THESE WARNINGS -* utils.plotting - - Function added (twoD_seismplot) for plotting seismicity (#365). * utils.mag_calc.amp_pick_event - Added option to output IASPEI standard amplitudes, with static amplification of 1 (rather than 2080 as per Wood Anderson specs). From 87b68f72552f7636ff001bf420a4776253505ca0 Mon Sep 17 00:00:00 2001 From: Calum Chamberlain Date: Sun, 16 Aug 2020 08:30:32 +1200 Subject: [PATCH 040/132] Ensure `return_figure` isn't sent as a kwarg to plotting func. --- eqcorrscan/utils/plotting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eqcorrscan/utils/plotting.py b/eqcorrscan/utils/plotting.py index ef99d65db..a47921c50 100644 --- a/eqcorrscan/utils/plotting.py +++ b/eqcorrscan/utils/plotting.py @@ -2249,7 +2249,7 @@ def twoD_seismplot(catalog=None, locations=None, bgcolor='#909090', kwargs[key] = default_parameters[key] # get parameters of _finalise_figure _kwargs = {} - for key in ['title', 'show', 'save', 'savefile', 'return_fig', 'size']: + for key in ['title', 'show', 'save', 'savefile', 'return_figure', 'size']: if key in kwargs.keys(): _kwargs[key] = kwargs[key] del kwargs[key] From 65d0bd84478019702c8cb866a4e45a4196db17d6 Mon Sep 17 00:00:00 2001 From: Calum Chamberlain Date: Sun, 16 Aug 2020 08:35:12 +1200 Subject: [PATCH 041/132] Check that the numpy files are actually written. --- eqcorrscan/tests/lag_calc_test.py | 1 + 1 file changed, 1 insertion(+) diff --git a/eqcorrscan/tests/lag_calc_test.py b/eqcorrscan/tests/lag_calc_test.py index 358ea964e..7b25aeccc 100644 --- a/eqcorrscan/tests/lag_calc_test.py +++ b/eqcorrscan/tests/lag_calc_test.py @@ -183,6 +183,7 @@ def test_xcorr_pick_family_export_cc(self): family=self.party[0], stream=self.data, shift_len=0.2, plot=False, interpolate=False, export_cc=True, cc_dir=cc_dir) cc_files = glob.glob(os.path.join(cc_dir, '*.npy')) + assert len(cc_files) == len(self.party[0]) for fcc in cc_files: np.load(fcc) From 70ac50d32b3074afc725862bf7a72033cca54b63 Mon Sep 17 00:00:00 2001 From: Calum Chamberlain Date: Sun, 16 Aug 2020 08:43:14 +1200 Subject: [PATCH 042/132] Stickler --- eqcorrscan/utils/catalog_to_dd.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/eqcorrscan/utils/catalog_to_dd.py b/eqcorrscan/utils/catalog_to_dd.py index eb06a98f3..12ee38fb0 100644 --- a/eqcorrscan/utils/catalog_to_dd.py +++ b/eqcorrscan/utils/catalog_to_dd.py @@ -269,7 +269,9 @@ def _compute_dt_correlations(catalog, master, min_link, event_id_mapper, master_length = Counter(master_length).most_common(1)[0][0] _master_stream = _master_stream.select(npts=master_length) - matched_length = [tr.stats.npts for st in _matched_streams.values() for tr in st] + matched_length = [ + tr.stats.npts for st in _matched_streams.values() + for tr in st] if len(set(matched_length)) > 1: Logger.warning( "Multiple lengths found in matched data - check that you " @@ -284,7 +286,8 @@ def _compute_dt_correlations(catalog, master, min_link, event_id_mapper, used_matched_streams.append(_matched_stream) # Check that there are matching seed ids. master_seed_ids = set(tr.id for tr in _master_stream) - matched_seed_ids = set(tr.id for st in used_matched_streams for tr in st) + matched_seed_ids = set( + tr.id for st in used_matched_streams for tr in st) if master_seed_ids not in matched_seed_ids: Logger.warning( "After checking length there are no matched traces: " @@ -327,7 +330,8 @@ def _compute_dt_correlations(catalog, master, min_link, event_id_mapper, _DTObs(station=chan.channel[0], tt1=master_tts["{0}_{1}".format( chan.channel[0], phase_hint)], - tt2=tt2, weight=cc_max ** 2, phase=phase_hint[0])) + tt2=tt2, weight=cc_max ** 2, + phase=phase_hint[0])) differential_times_dict.update({used_event_id: diff_time}) # Threshold on min_link differential_times = [dt for dt in differential_times_dict.values() From 383e3c6ee8858693a9a9af6bf0f247ca3386485e Mon Sep 17 00:00:00 2001 From: Calum Chamberlain Date: Sun, 16 Aug 2020 08:44:20 +1200 Subject: [PATCH 043/132] Stickler --- eqcorrscan/utils/catalog_to_dd.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eqcorrscan/utils/catalog_to_dd.py b/eqcorrscan/utils/catalog_to_dd.py index 12ee38fb0..1ed8d83b2 100644 --- a/eqcorrscan/utils/catalog_to_dd.py +++ b/eqcorrscan/utils/catalog_to_dd.py @@ -270,7 +270,7 @@ def _compute_dt_correlations(catalog, master, min_link, event_id_mapper, _master_stream = _master_stream.select(npts=master_length) matched_length = [ - tr.stats.npts for st in _matched_streams.values() + tr.stats.npts for st in _matched_streams.values() for tr in st] if len(set(matched_length)) > 1: Logger.warning( @@ -330,7 +330,7 @@ def _compute_dt_correlations(catalog, master, min_link, event_id_mapper, _DTObs(station=chan.channel[0], tt1=master_tts["{0}_{1}".format( chan.channel[0], phase_hint)], - tt2=tt2, weight=cc_max ** 2, + tt2=tt2, weight=cc_max ** 2, phase=phase_hint[0])) differential_times_dict.update({used_event_id: diff_time}) # Threshold on min_link From 38cf07e7bceebf0e12217ad61f41f34b01d7ed7c Mon Sep 17 00:00:00 2001 From: Calum Chamberlain Date: Sun, 16 Aug 2020 08:47:04 +1200 Subject: [PATCH 044/132] Only use phase type hint in SparseEvent --- eqcorrscan/utils/catalog_to_dd.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eqcorrscan/utils/catalog_to_dd.py b/eqcorrscan/utils/catalog_to_dd.py index 1ed8d83b2..7a5993b52 100644 --- a/eqcorrscan/utils/catalog_to_dd.py +++ b/eqcorrscan/utils/catalog_to_dd.py @@ -156,7 +156,7 @@ def _make_sparse_event(event): picks=[SparsePick( tt=pick.time - origin_time, seed_id=pick.waveform_id.get_seed_string(), - phase=pick.phase_hint, + phase=pick.phase_hint[0], # Only use P or S hints. time_weight=time_weight_dict.get(pick.resource_id, 1.0)) for pick in event.picks]) return sparse_event @@ -357,7 +357,7 @@ def _make_event_pair(sparse_event, master, event_id_mapper, min_link): event_id_1=event_id_mapper[master.resource_id], event_id_2=event_id_mapper[sparse_event.resource_id]) for master_pick in master.picks: - if master_pick.phase and master_pick.phase not in "PS": # pragma: no cover + if master_pick.phase and master_pick.phase not in "PS": # pragma: no cover continue matched_picks = [p for p in sparse_event.picks if p.station == master_pick.station From 516af580aaec065afcbfb40e6e6c5c1d9bf04978 Mon Sep 17 00:00:00 2001 From: Chet Hopp Date: Mon, 17 Aug 2020 16:30:28 -0400 Subject: [PATCH 045/132] properly check seed subsets; add elevations to write_station --- eqcorrscan/utils/catalog_to_dd.py | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/eqcorrscan/utils/catalog_to_dd.py b/eqcorrscan/utils/catalog_to_dd.py index 7a5993b52..ae7717f6e 100644 --- a/eqcorrscan/utils/catalog_to_dd.py +++ b/eqcorrscan/utils/catalog_to_dd.py @@ -288,7 +288,7 @@ def _compute_dt_correlations(catalog, master, min_link, event_id_mapper, master_seed_ids = set(tr.id for tr in _master_stream) matched_seed_ids = set( tr.id for st in used_matched_streams for tr in st) - if master_seed_ids not in matched_seed_ids: + if not matched_seed_ids.issubset(master_seed_ids): Logger.warning( "After checking length there are no matched traces: " f"master: {master_seed_ids}, matched: {matched_seed_ids}") @@ -872,15 +872,24 @@ def write_event(catalog, event_id_mapper=None): # Station.dat functions -def write_station(inventory): +def write_station(inventory, use_elevation=False): station_strings = [] for network in inventory: for station in network: - station_strings.append( - "{station:<7s} {latitude:6.3f} {longitude:6.3f}".format( - station=station.code, - latitude=station.latitude, - longitude=station.longitude)) + if use_elevation: + station_strings.append( + """{station:<7s} {latitude:6.3f} {longitude:6.3f} + {elevation:5.0f}""".format( + station=station.code, + latitude=station.latitude, + longitude=station.longitude, + elevation=station.elevation - station[0].depth)) + else: + station_strings.append( + "{station:<7s} {latitude:6.3f} {longitude:6.3f}".format( + station=station.code, + latitude=station.latitude, + longitude=station.longitude)) with open("station.dat", "w") as f: f.write("\n".join(station_strings)) From 0538657a59de1deefa50e80db7f406394ffe99d3 Mon Sep 17 00:00:00 2001 From: flixha Date: Sat, 12 Dec 2020 10:58:14 +0100 Subject: [PATCH 046/132] add min_chan and thresh_exc-metric to decluster --- eqcorrscan/core/match_filter/party.py | 43 ++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/eqcorrscan/core/match_filter/party.py b/eqcorrscan/core/match_filter/party.py index b9c5b0e86..8d747ee2b 100644 --- a/eqcorrscan/core/match_filter/party.py +++ b/eqcorrscan/core/match_filter/party.py @@ -472,7 +472,8 @@ def rethreshold(self, new_threshold, new_threshold_type='MAD'): return self def decluster(self, trig_int, timing='detect', metric='avg_cor', - hypocentral_separation=None): + hypocentral_separation=None, min_chans=0, + absolute_values=False): """ De-cluster a Party of detections by enforcing a detection separation. @@ -487,8 +488,10 @@ def decluster(self, trig_int, timing='detect', metric='avg_cor', :param trig_int: Minimum detection separation in seconds. :type metric: str :param metric: What metric to sort peaks by. Either 'avg_cor' which - takes the single station average correlation or 'cor_sum' which - takes the total correlation sum across all channels. + takes the single station average correlation, 'cor_sum' which + takes the total correlation sum across all channels, or + 'thresh_exc' which takes the factor by how much the detection + exceeded the input threshold. :type timing: str :param timing: Either 'detect' or 'origin' to decluster based on either the @@ -498,6 +501,15 @@ def decluster(self, trig_int, timing='detect', metric='avg_cor', Maximum inter-event separation in km to decluster events within. If an event happens within this distance of another event, and within the trig_int defined time, then they will be declustered. + :type min_chans: int + :param min_chans: + Minimum number of channels for a detection to be retained. If a + detection was made on very few channels, then the MAD detection + statistics become much less robust. + :type absolute_values: bool + :param absolute_values: + Use the absolute value of the metric to choose the preferred + detection. .. Warning:: Works in place on object, if you need to keep the original safe @@ -540,24 +552,41 @@ def decluster(self, trig_int, timing='detect', metric='avg_cor', "hypocentral separation") catalog = None - assert metric in ('avg_cor', 'cor_sum'), \ - 'metric is not cor_sum or avg_cor' + if min_chans > 0: + for d in all_detections.copy(): + if d.no_chans < min_chans: + all_detections.remove(d) + if len(all_detections) == 0: + return Party() + + assert metric in ('avg_cor', 'cor_sum', 'thresh_exc'), \ + 'metric is not cor_sum, avg_cor or thresh_exc' assert timing in ('detect', 'origin'), 'timing is not detect or origin' if timing == 'detect': if metric == 'avg_cor': detect_info = [(d.detect_time, d.detect_val / d.no_chans) for d in all_detections] - else: + elif metric == 'cor_sum': detect_info = [(d.detect_time, d.detect_val) for d in all_detections] + elif metric == 'thresh_exc': + detect_info = [(d.detect_time, d.detect_val / d.threshold) + for d in all_detections] else: if metric == 'avg_cor': detect_info = [(_get_origin(d.event).time, d.detect_val / d.no_chans) for d in all_detections] - else: + elif metric == 'cor_sum': detect_info = [(_get_origin(d.event).time, d.detect_val) for d in all_detections] + elif metric == 'thresh_exc': + detect_info = [(_get_origin(d.event).time, + d.detect_val / d.threshold) + for d in all_detections] + if absolute_values: + for j, tup in enumerate(detect_info): + detect_info[j] = (tup[0], abs(tup[1])) min_det = sorted([d[0] for d in detect_info])[0] detect_vals = np.array([d[1] for d in detect_info], dtype=np.float32) detect_times = np.array([ From 96fd69d38a05359c8e826f70a9f0ead05ec711f1 Mon Sep 17 00:00:00 2001 From: flixha Date: Sat, 12 Dec 2020 11:00:32 +0100 Subject: [PATCH 047/132] fix bug where pad_list becomes 0 when samples are misaligned by more than half a sample --- eqcorrscan/utils/correlate.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/eqcorrscan/utils/correlate.py b/eqcorrscan/utils/correlate.py index db3d8455d..5c8da8fed 100644 --- a/eqcorrscan/utils/correlate.py +++ b/eqcorrscan/utils/correlate.py @@ -27,6 +27,7 @@ from multiprocessing.pool import ThreadPool import numpy as np +import math from future.utils import native_str from eqcorrscan.utils.libnames import _load_cdll @@ -929,8 +930,11 @@ def _get_array_dicts(templates, stream, stack, copy_streams=True): np.abs(stream_channel.data)) / 1e5) stream_dict.update( {seed_id: stream_data.astype(np.float32)}) + # PROBLEM - DEBUG: if two traces start just before / just after a + # "full-sample-time", then stream_offset can become 1, while a value in + # pad_list can become 0. 0-1 = -1; which is problematic. stream_offset = int( - round(stream_channel.stats.sampling_rate * + math.floor(stream_channel.stats.sampling_rate * (stream_channel.stats.starttime - stream_start))) if stack: pad_list = [ From 906d6e6acf96934b0386c814a095ed22b2ae73da Mon Sep 17 00:00:00 2001 From: flixha Date: Mon, 15 Feb 2021 11:33:21 +0100 Subject: [PATCH 048/132] add option to compare absolute values of detect_val in rethresholding --- eqcorrscan/core/match_filter/party.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/eqcorrscan/core/match_filter/party.py b/eqcorrscan/core/match_filter/party.py index 8d747ee2b..58497c51a 100644 --- a/eqcorrscan/core/match_filter/party.py +++ b/eqcorrscan/core/match_filter/party.py @@ -405,7 +405,8 @@ def plot(self, plot_grouped=False, dates=None, min_dets=1, rate=False, rate=rate, **kwargs) return fig - def rethreshold(self, new_threshold, new_threshold_type='MAD'): + def rethreshold(self, new_threshold, new_threshold_type='MAD', + abs_values=False): """ Remove detections from the Party that are below a new threshold. @@ -418,6 +419,9 @@ def rethreshold(self, new_threshold, new_threshold_type='MAD'): :param new_threshold: New threshold level :type new_threshold_type: str :param new_threshold_type: Either 'MAD', 'absolute' or 'av_chan_corr' + :type abs_values: bool + :param abs_values: + Whether to compare the absolute value of the detection-value. .. rubric:: Examples @@ -463,7 +467,14 @@ def rethreshold(self, new_threshold, new_threshold_type='MAD'): raise MatchFilterError( 'new_threshold_type %s is not recognised' % str(new_threshold_type)) - if float(d.detect_val) >= new_thresh: + rethresh = False + if abs_values: + if abs(float(d.detect_val)) >= new_thresh: + rethresh = True + else: + if float(d.detect_val) >= new_thresh: + rethresh = True + if rethresh: d.threshold = new_thresh d.threshold_input = new_threshold d.threshold_type = new_threshold_type From 21e995c615813001cf647a8596f42eac99e5d874 Mon Sep 17 00:00:00 2001 From: flixha Date: Mon, 15 Feb 2021 11:41:42 +0100 Subject: [PATCH 049/132] add test to check for bug where detection time depends on content of a tribe when continuous data are missing --- eqcorrscan/tests/match_filter_test.py | 31 +++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/eqcorrscan/tests/match_filter_test.py b/eqcorrscan/tests/match_filter_test.py index df88428fe..4b6eee72a 100644 --- a/eqcorrscan/tests/match_filter_test.py +++ b/eqcorrscan/tests/match_filter_test.py @@ -694,6 +694,37 @@ def test_tribe_detect(self): compare_families( party=party, party_in=self.party, float_tol=0.05, check_event=True) + + def test_tribe_detect_with_empty_streams(self): + """ + Compare the detect method for a tribe of one vs two templates and check + that the detection has the same detect time, in a case where the + continuous data is incomplete. This test should fail in v0.4.2 due to + a bug. + """ + # remove trace for station PHA (PHOB, PSR, PCA, PAG remain) + st = self.unproc_st.copy().remove( + self.unproc_st.copy().select(station='PHA')[0]) + tribe1 = Tribe([t.copy() for t in self.tribe + if (t.name=='2004_09_28t17_19_08' or + t.name=='2004_09_28t17_19_25')]) + # run detection with 2 templates in tribe + party1 = tribe1.detect( + stream=st, threshold=8.0, threshold_type='MAD', + trig_int=6.0, daylong=False, plotvar=False, parallel_process=False) + self.assertEqual(len(party1), 2) + party1 = Party([f for f in party1 + if f.template.name=='2004_09_28t17_19_25']) + # run detection with only 1 template in tribe + tribe2 = Tribe([t.copy() for t in self.tribe + if t.name=='2004_09_28t17_19_25']) + party2 = tribe2.detect( + stream=st, threshold=8.0, threshold_type='MAD', + trig_int=6.0, daylong=False, plotvar=False, parallel_process=False) + self.assertEqual(len(party2), 1) + # This should fail in v0.4.2 + compare_families( + party=party1, party_in=party2, float_tol=0.05, check_event=True) def test_tribe_detect_short_data(self): """Test the detect method on Tribe objects""" From 179965976e0be451509e799579b73beaea1c9f73 Mon Sep 17 00:00:00 2001 From: flixha Date: Mon, 15 Feb 2021 11:41:42 +0100 Subject: [PATCH 050/132] add test to check for bug where detection time depends on content of a tribe when continuous data are missing --- eqcorrscan/tests/match_filter_test.py | 31 +++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/eqcorrscan/tests/match_filter_test.py b/eqcorrscan/tests/match_filter_test.py index df88428fe..4b6eee72a 100644 --- a/eqcorrscan/tests/match_filter_test.py +++ b/eqcorrscan/tests/match_filter_test.py @@ -694,6 +694,37 @@ def test_tribe_detect(self): compare_families( party=party, party_in=self.party, float_tol=0.05, check_event=True) + + def test_tribe_detect_with_empty_streams(self): + """ + Compare the detect method for a tribe of one vs two templates and check + that the detection has the same detect time, in a case where the + continuous data is incomplete. This test should fail in v0.4.2 due to + a bug. + """ + # remove trace for station PHA (PHOB, PSR, PCA, PAG remain) + st = self.unproc_st.copy().remove( + self.unproc_st.copy().select(station='PHA')[0]) + tribe1 = Tribe([t.copy() for t in self.tribe + if (t.name=='2004_09_28t17_19_08' or + t.name=='2004_09_28t17_19_25')]) + # run detection with 2 templates in tribe + party1 = tribe1.detect( + stream=st, threshold=8.0, threshold_type='MAD', + trig_int=6.0, daylong=False, plotvar=False, parallel_process=False) + self.assertEqual(len(party1), 2) + party1 = Party([f for f in party1 + if f.template.name=='2004_09_28t17_19_25']) + # run detection with only 1 template in tribe + tribe2 = Tribe([t.copy() for t in self.tribe + if t.name=='2004_09_28t17_19_25']) + party2 = tribe2.detect( + stream=st, threshold=8.0, threshold_type='MAD', + trig_int=6.0, daylong=False, plotvar=False, parallel_process=False) + self.assertEqual(len(party2), 1) + # This should fail in v0.4.2 + compare_families( + party=party1, party_in=party2, float_tol=0.05, check_event=True) def test_tribe_detect_short_data(self): """Test the detect method on Tribe objects""" From dbb3ec2490d871a23b0237e0f4acc9534472185f Mon Sep 17 00:00:00 2001 From: flixha Date: Mon, 15 Feb 2021 12:10:15 +0100 Subject: [PATCH 051/132] fix pep8 --- eqcorrscan/tests/match_filter_test.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/eqcorrscan/tests/match_filter_test.py b/eqcorrscan/tests/match_filter_test.py index 4b6eee72a..e9bf08501 100644 --- a/eqcorrscan/tests/match_filter_test.py +++ b/eqcorrscan/tests/match_filter_test.py @@ -694,11 +694,11 @@ def test_tribe_detect(self): compare_families( party=party, party_in=self.party, float_tol=0.05, check_event=True) - + def test_tribe_detect_with_empty_streams(self): """ Compare the detect method for a tribe of one vs two templates and check - that the detection has the same detect time, in a case where the + that the detection has the same detect time, in a case where the continuous data is incomplete. This test should fail in v0.4.2 due to a bug. """ @@ -706,18 +706,18 @@ def test_tribe_detect_with_empty_streams(self): st = self.unproc_st.copy().remove( self.unproc_st.copy().select(station='PHA')[0]) tribe1 = Tribe([t.copy() for t in self.tribe - if (t.name=='2004_09_28t17_19_08' or - t.name=='2004_09_28t17_19_25')]) + if (t.name == '2004_09_28t17_19_08' or + t.name == '2004_09_28t17_19_25')]) # run detection with 2 templates in tribe party1 = tribe1.detect( stream=st, threshold=8.0, threshold_type='MAD', trig_int=6.0, daylong=False, plotvar=False, parallel_process=False) self.assertEqual(len(party1), 2) party1 = Party([f for f in party1 - if f.template.name=='2004_09_28t17_19_25']) + if f.template.name == '2004_09_28t17_19_25']) # run detection with only 1 template in tribe tribe2 = Tribe([t.copy() for t in self.tribe - if t.name=='2004_09_28t17_19_25']) + if t.name == '2004_09_28t17_19_25']) party2 = tribe2.detect( stream=st, threshold=8.0, threshold_type='MAD', trig_int=6.0, daylong=False, plotvar=False, parallel_process=False) From 6445d6225215d7c882d9d503dc2559937a67d78a Mon Sep 17 00:00:00 2001 From: flixha Date: Tue, 16 Feb 2021 16:35:29 +0100 Subject: [PATCH 052/132] add check that adds NaN-traces if the earliest trace of any template is not in continuous data --- eqcorrscan/utils/pre_processing.py | 31 ++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/eqcorrscan/utils/pre_processing.py b/eqcorrscan/utils/pre_processing.py index 4d4b4f039..3e06a882e 100644 --- a/eqcorrscan/utils/pre_processing.py +++ b/eqcorrscan/utils/pre_processing.py @@ -846,10 +846,37 @@ def _prep_data_for_correlation(stream, templates, template_names=None, # Remove templates with no matching channels filt = np.ones(len(template_names)).astype(bool) for i, template in enumerate(templates): - template_ids = {tr.id for tr in template} - if len(template_ids.intersection(stream_ids)) == 0: + trace_ids = {tr.id for tr in template} + if len(trace_ids.intersection(stream_ids)) == 0: filt[i] = 0 + # Ensure that the templates' earliest traces are kept, even if there is no + # continuous data for them. If this happens, we need to add a NaN-stream to + # the continuous data to avoid inconsistent detection times. + n_template_traces = np.array([len(temp) for temp in templates]) + n_stream_traces = sum([n+1 for s, n in seed_ids]) + # These checks are not necessary if all templates will get NaN-traces, + # because the NaN-traces will save the right starttime for the template. + if any(n_template_traces > n_stream_traces): + earliest_templ_trace_ids = list(set( + [template.sort(['starttime'])[0].id for template in templates])) + for earliest_templ_trace_id in earliest_templ_trace_ids: + if earliest_templ_trace_id not in template_ids: + net, sta, loc, chan = earliest_templ_trace_id.split('.') + nan_template += Trace(header=Stats({ + 'network': net, 'station': sta, 'location': loc, + 'channel': chan, 'starttime': UTCDateTime(), + 'npts': template_length, 'sampling_rate': samp_rate})) + stream_nan_data = np.full( + stream_length, np.nan, dtype=np.float32) + out_stream += Trace( + data=np.ma.masked_array(stream_nan_data, stream_nan_data), + header=Stats({ + 'network': net, 'station': sta, 'location': loc, + 'channel': chan, 'starttime': stream_start, + 'npts': stream_length, 'sampling_rate': samp_rate})) + seed_ids.append((earliest_templ_trace_id, 0)) + _out = dict(zip( [_tn for _tn, _filt in zip(template_names, filt) if _filt], [_t for _t, _filt in zip(templates, filt) if _filt])) From 382fd28d9d4fdf9c643cb647cf54ba544d5dfc93 Mon Sep 17 00:00:00 2001 From: flixha Date: Tue, 16 Feb 2021 16:51:22 +0100 Subject: [PATCH 053/132] replace template-traces for which the continuous data is all NaN with NaN-traces so that the channel list of a detection lists the right channels --- eqcorrscan/utils/pre_processing.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/eqcorrscan/utils/pre_processing.py b/eqcorrscan/utils/pre_processing.py index 3e06a882e..c381fd0d1 100644 --- a/eqcorrscan/utils/pre_processing.py +++ b/eqcorrscan/utils/pre_processing.py @@ -857,11 +857,13 @@ def _prep_data_for_correlation(stream, templates, template_names=None, n_stream_traces = sum([n+1 for s, n in seed_ids]) # These checks are not necessary if all templates will get NaN-traces, # because the NaN-traces will save the right starttime for the template. + nan_stream_ids = list() if any(n_template_traces > n_stream_traces): earliest_templ_trace_ids = list(set( [template.sort(['starttime'])[0].id for template in templates])) for earliest_templ_trace_id in earliest_templ_trace_ids: if earliest_templ_trace_id not in template_ids: + nan_stream_ids.append(earliest_templ_trace_id) net, sta, loc, chan = earliest_templ_trace_id.split('.') nan_template += Trace(header=Stats({ 'network': net, 'station': sta, 'location': loc, @@ -902,6 +904,13 @@ def _prep_data_for_correlation(stream, templates, template_names=None, template_starttime else: out_template[channel_number] = template_channel[channel_index] + # If a template-trace matches a NaN-trace in the stream , then set + # template-trace to NaN so that this trace does not appear in channel- + # list of detections. + if len(nan_stream_ids) > 0: + for tr in out_template: + if tr.id in nan_stream_ids: + tr.data = nan_channel _out.update({template_name: out_template}) out_templates = list(_out.values()) From 470c6efe5d677797ba73d39e7567344b90b8795a Mon Sep 17 00:00:00 2001 From: flixha Date: Tue, 16 Feb 2021 17:01:54 +0100 Subject: [PATCH 054/132] event-check would always fail for this test --- eqcorrscan/tests/match_filter_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eqcorrscan/tests/match_filter_test.py b/eqcorrscan/tests/match_filter_test.py index e9bf08501..4566e4be2 100644 --- a/eqcorrscan/tests/match_filter_test.py +++ b/eqcorrscan/tests/match_filter_test.py @@ -724,7 +724,7 @@ def test_tribe_detect_with_empty_streams(self): self.assertEqual(len(party2), 1) # This should fail in v0.4.2 compare_families( - party=party1, party_in=party2, float_tol=0.05, check_event=True) + party=party1, party_in=party2, float_tol=0.05, check_event=False) def test_tribe_detect_short_data(self): """Test the detect method on Tribe objects""" From 148d390557d2e3b9a617b23710cbd36d49c58c32 Mon Sep 17 00:00:00 2001 From: Calum Chamberlain Date: Tue, 16 Feb 2021 16:47:56 +1300 Subject: [PATCH 055/132] Update github actions workflow Tests were failed due to old versions of conda setup. --- .github/workflows/runtest.yml | 26 +++++--------------------- 1 file changed, 5 insertions(+), 21 deletions(-) diff --git a/.github/workflows/runtest.yml b/.github/workflows/runtest.yml index 220c65fc5..3fe7cfb87 100644 --- a/.github/workflows/runtest.yml +++ b/.github/workflows/runtest.yml @@ -11,24 +11,16 @@ jobs: fail-fast: false steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v2 - name: Setup conda - uses: actions/cache@v1 - env: - # Increase this value to reset cache if etc/example-environment.yml has not changed - CACHE_NUMBER: 0 - with: - path: ~/conda_pkgs_dir - key: ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-${{ hashFiles('.github/test_conda_env_macOS.yml') }} - - uses: goanpeca/setup-miniconda@v1 + - uses: conda-incubator/setup-miniconda@v2 with: miniconda-version: 'latest' python-version: ${{ matrix.python-version }} activate-environment: eqcorrscan-test environment-file: .github/test_conda_env_macOS.yml condarc-file: .github/test_condarc.yml - use-only-tar-bz2: true # IMPORTANT: This needs to be set for caching to work properly! - name: install eqcorrscan shell: bash -l {0} @@ -74,24 +66,16 @@ jobs: fail-fast: false steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v2 - name: Setup conda - uses: actions/cache@v1 - env: - # Increase this value to reset cache if etc/example-environment.yml has not changed - CACHE_NUMBER: 0 - with: - path: ~/conda_pkgs_dir - key: ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-${{ hashFiles('.github/test_conda_env.yml') }} - - uses: goanpeca/setup-miniconda@v1 + - uses: conda-incubator/setup-miniconda@v2 with: miniconda-version: 'latest' python-version: ${{ matrix.python-version }} activate-environment: eqcorrscan-test environment-file: .github/test_conda_env.yml condarc-file: .github/test_condarc.yml - use-only-tar-bz2: true # IMPORTANT: This needs to be set for caching to work properly! - name: install eqcorrscan shell: bash -l {0} @@ -137,4 +121,4 @@ jobs: # $ some-command-that-can-fail || : # #- name: Setup tmate session -# uses: mxschmitt/action-tmate@v1 \ No newline at end of file +# uses: mxschmitt/action-tmate@v1 From 09460eec9d5868d18e7ef3a1b575309224f0b4a3 Mon Sep 17 00:00:00 2001 From: Calum Chamberlain Date: Tue, 9 Mar 2021 16:57:05 +1300 Subject: [PATCH 056/132] Add option to not copy data --- .../core/match_filter/matched_filter.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/eqcorrscan/core/match_filter/matched_filter.py b/eqcorrscan/core/match_filter/matched_filter.py index b9288acde..910ccf986 100644 --- a/eqcorrscan/core/match_filter/matched_filter.py +++ b/eqcorrscan/core/match_filter/matched_filter.py @@ -385,7 +385,7 @@ def match_filter(template_names, template_list, st, threshold, xcorr_func=None, concurrency=None, cores=None, plot_format='png', output_cat=False, output_event=True, extract_detections=False, arg_check=True, full_peaks=False, - peak_cores=None, spike_test=True, **kwargs): + peak_cores=None, spike_test=True, copy_data=True, **kwargs): """ Main matched-filter detection function. @@ -468,6 +468,10 @@ def match_filter(template_names, template_list, st, threshold, :type spike_test: bool :param spike_test: If set True, raise error when there is a spike in data. defaults to True. + :type copy_data: bool + :param copy_data: + Whether to copy data to keep it safe, otherwise will edit your + templates and stream in place. .. Note:: When using the "fftw" correlation backend the length of the fft @@ -653,11 +657,14 @@ def match_filter(template_names, template_list, st, threshold, parallel = False if peak_cores is None: peak_cores = cores - # Copy the stream here because we will muck about with it - Logger.info("Copying data to keep your input safe") - stream = st.copy() - templates = [t.copy() for t in template_list] - _template_names = template_names.copy() # This can just be a shallow copy + if copy_data: + # Copy the stream here because we will muck about with it + Logger.info("Copying data to keep your input safe") + stream = st.copy() + templates = [t.copy() for t in template_list] + _template_names = template_names.copy() # This can just be a shallow copy + else: + stream, templates, _template_names = st, template_list, template_names Logger.info("Reshaping templates") stream, templates, _template_names = _prep_data_for_correlation( From 2e964b8417edb1e8a03afb2b3a21ba2682904cd1 Mon Sep 17 00:00:00 2001 From: Calum Chamberlain Date: Tue, 9 Mar 2021 17:00:55 +1300 Subject: [PATCH 057/132] Add iteration to Party --- eqcorrscan/core/match_filter/party.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/eqcorrscan/core/match_filter/party.py b/eqcorrscan/core/match_filter/party.py index 9b437c572..3d4440fb5 100644 --- a/eqcorrscan/core/match_filter/party.py +++ b/eqcorrscan/core/match_filter/party.py @@ -269,6 +269,12 @@ def __getitem__(self, index): Logger.warning('Family: %s not in party' % index) return [] + def __iter__(self): + return self.families.__iter__() + + def __next__(self): + return self.families.__next__() + def __len__(self): """ Get total number of detections in Party. From 7478d1b13ab407a6bf566e633866055042292cd5 Mon Sep 17 00:00:00 2001 From: Calum Chamberlain Date: Wed, 10 Mar 2021 00:52:23 +0000 Subject: [PATCH 058/132] Cope with missing parts of seed ids --- eqcorrscan/core/template_gen.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/eqcorrscan/core/template_gen.py b/eqcorrscan/core/template_gen.py index f99b96395..bf159d200 100644 --- a/eqcorrscan/core/template_gen.py +++ b/eqcorrscan/core/template_gen.py @@ -517,9 +517,13 @@ def _download_from_client(client, client_type, catalog, data_pad, process_len, channel_code = pick.waveform_id.channel_code[0:2] + "?" else: channel_code = pick.waveform_id.channel_code + if pick.waveform_id.station_code is None: + Logger.error("No station code for pick, skipping") + continue all_waveform_info.append(( - pick.waveform_id.network_code, pick.waveform_id.station_code, - channel_code, pick.waveform_id.location_code)) + pick.waveform_id.network_code or "*", + pick.waveform_id.station_code, + channel_code, pick.waveform_id.location_code or "*")) starttime = UTCDateTime( catalog[0].origins[0].time - data_pad) endtime = starttime + process_len From a0dc766e479bc454698cc539ee7a4354bae56809 Mon Sep 17 00:00:00 2001 From: flixha Date: Tue, 23 Mar 2021 11:11:42 +0100 Subject: [PATCH 059/132] add option to set minimum-cc-threshold for picks variable based on average detection CC --- eqcorrscan/core/lag_calc.py | 15 ++++++++++++++- eqcorrscan/core/match_filter/family.py | 8 ++++++++ eqcorrscan/core/match_filter/party.py | 8 ++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/eqcorrscan/core/lag_calc.py b/eqcorrscan/core/lag_calc.py index 67e945cc7..f77772251 100644 --- a/eqcorrscan/core/lag_calc.py +++ b/eqcorrscan/core/lag_calc.py @@ -188,6 +188,7 @@ def _concatenate_and_correlate(streams, template, cores): def xcorr_pick_family(family, stream, shift_len=0.2, min_cc=0.4, + min_cc_from_mean_cc_factor=None, horizontal_chans=['E', 'N', '1', '2'], vertical_chans=['Z'], cores=1, interpolate=False, plot=False, plotdir=None, export_cc=False, cc_dir=None): @@ -207,6 +208,11 @@ def xcorr_pick_family(family, stream, shift_len=0.2, min_cc=0.4, :type min_cc: float :param min_cc: Minimum cross-correlation value to be considered a pick, default=0.4. + :type min_cc_from_mean_cc_factor: float + :param min_cc_from_mean_cc_factor: + If set to a value other than None, then the minimum cross-correlation + value for a trace is set individually for each detection based on: + min(detect_val / n_chans * min_cc_from_mean_cc_factor, min_cc). :type horizontal_chans: list :param horizontal_chans: List of channel endings for horizontal-channels, on which S-picks will @@ -266,6 +272,13 @@ def xcorr_pick_family(family, stream, shift_len=0.2, min_cc=0.4, detect_stream = detect_streams_dict[detection_id] checksum, cccsum, used_chans = 0.0, 0.0, 0 event = Event() + if min_cc_from_mean_cc_factor is not None: + cc_thresh = min(detection.detect_val / detection.no_chans + * min_cc_from_mean_cc_factor, min_cc) + Logger.info('Setting minimum cc-threshold for detection %s to %s', + detection.id, str(cc_thresh)) + else: + cc_thresh = min_cc for correlation, stachan in zip(correlations, picked_chans): if not stachan.used: continue @@ -283,7 +296,7 @@ def xcorr_pick_family(family, stream, shift_len=0.2, min_cc=0.4, picktime = tr.stats.starttime + shift checksum += cc_max used_chans += 1 - if cc_max < min_cc: + if cc_max < cc_thresh: Logger.debug('Correlation of {0} is below threshold, not ' 'using'.format(cc_max)) continue diff --git a/eqcorrscan/core/match_filter/family.py b/eqcorrscan/core/match_filter/family.py index e997f011c..011a2b1d5 100644 --- a/eqcorrscan/core/match_filter/family.py +++ b/eqcorrscan/core/match_filter/family.py @@ -501,6 +501,7 @@ def write(self, filename, format='tar'): return def lag_calc(self, stream, pre_processed, shift_len=0.2, min_cc=0.4, + min_cc_from_mean_cc_factor=None, horizontal_chans=['E', 'N', '1', '2'], vertical_chans=['Z'], cores=1, interpolate=False, plot=False, plotdir=None, parallel=True, process_cores=None, ignore_length=False, @@ -526,6 +527,12 @@ def lag_calc(self, stream, pre_processed, shift_len=0.2, min_cc=0.4, :param min_cc: Minimum cross-correlation value to be considered a pick, default=0.4. + :type min_cc_from_mean_cc_factor: float + :param min_cc_from_mean_cc_factor: + If set to a value other than None, then the minimum cross- + correlation value for a trace is set individually for each + detection based on: + min(detect_val / n_chans * min_cc_from_mean_cc_factor, min_cc). :type horizontal_chans: list :param horizontal_chans: List of channel endings for horizontal-channels, on which @@ -603,6 +610,7 @@ def lag_calc(self, stream, pre_processed, shift_len=0.2, min_cc=0.4, picked_dict = xcorr_pick_family( family=self, stream=processed_stream, shift_len=shift_len, min_cc=min_cc, horizontal_chans=horizontal_chans, + min_cc_from_mean_cc_factor=min_cc_from_mean_cc_factor, vertical_chans=vertical_chans, cores=cores, interpolate=interpolate, plot=plot, plotdir=plotdir, export_cc=export_cc, cc_dir=cc_dir) diff --git a/eqcorrscan/core/match_filter/party.py b/eqcorrscan/core/match_filter/party.py index c6a0f86d4..75ea5d540 100644 --- a/eqcorrscan/core/match_filter/party.py +++ b/eqcorrscan/core/match_filter/party.py @@ -780,6 +780,7 @@ def read(self, filename=None, read_detection_catalog=True, return self def lag_calc(self, stream, pre_processed, shift_len=0.2, min_cc=0.4, + min_cc_from_mean_cc_factor=None, horizontal_chans=['E', 'N', '1', '2'], vertical_chans=['Z'], cores=1, interpolate=False, plot=False, plotdir=None, parallel=True, process_cores=None, ignore_length=False, @@ -805,6 +806,12 @@ def lag_calc(self, stream, pre_processed, shift_len=0.2, min_cc=0.4, :param min_cc: Minimum cross-correlation value to be considered a pick, default=0.4. + :type min_cc_from_mean_cc_factor: float + :param min_cc_from_mean_cc_factor: + If set to a value other than None, then the minimum cross- + correlation value for a trace is set individually for each + detection based on: + min(detect_val / n_chans * min_cc_from_mean_cc_factor, min_cc). :type horizontal_chans: list :param horizontal_chans: List of channel endings for horizontal-channels, on which S-picks @@ -903,6 +910,7 @@ def lag_calc(self, stream, pre_processed, shift_len=0.2, min_cc=0.4, catalog += family.lag_calc( stream=processed_stream, pre_processed=True, shift_len=shift_len, min_cc=min_cc, + min_cc_from_mean_cc_factor=min_cc_from_mean_cc_factor, horizontal_chans=horizontal_chans, vertical_chans=vertical_chans, cores=cores, interpolate=interpolate, plot=plot, plotdir=plotdir, From 7285977af72cdc72f35361279d7fc49f37dd9651 Mon Sep 17 00:00:00 2001 From: flixha Date: Mon, 15 Feb 2021 11:33:21 +0100 Subject: [PATCH 060/132] add option to compare absolute values of detect_val in rethresholding --- eqcorrscan/core/match_filter/party.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/eqcorrscan/core/match_filter/party.py b/eqcorrscan/core/match_filter/party.py index 75ea5d540..0f8d4c060 100644 --- a/eqcorrscan/core/match_filter/party.py +++ b/eqcorrscan/core/match_filter/party.py @@ -405,7 +405,8 @@ def plot(self, plot_grouped=False, dates=None, min_dets=1, rate=False, rate=rate, **kwargs) return fig - def rethreshold(self, new_threshold, new_threshold_type='MAD'): + def rethreshold(self, new_threshold, new_threshold_type='MAD', + abs_values=False): """ Remove detections from the Party that are below a new threshold. @@ -418,6 +419,9 @@ def rethreshold(self, new_threshold, new_threshold_type='MAD'): :param new_threshold: New threshold level :type new_threshold_type: str :param new_threshold_type: Either 'MAD', 'absolute' or 'av_chan_corr' + :type abs_values: bool + :param abs_values: + Whether to compare the absolute value of the detection-value. .. rubric:: Examples @@ -463,7 +467,14 @@ def rethreshold(self, new_threshold, new_threshold_type='MAD'): raise MatchFilterError( 'new_threshold_type %s is not recognised' % str(new_threshold_type)) - if float(d.detect_val) >= new_thresh: + rethresh = False + if abs_values: + if abs(float(d.detect_val)) >= new_thresh: + rethresh = True + else: + if float(d.detect_val) >= new_thresh: + rethresh = True + if rethresh: d.threshold = new_thresh d.threshold_input = new_threshold d.threshold_type = new_threshold_type From f40ea5800641466aa69702d272e01c127499e3be Mon Sep 17 00:00:00 2001 From: flixha Date: Tue, 23 Mar 2021 11:45:49 +0100 Subject: [PATCH 061/132] add updates to CHANGES.md --- CHANGES.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 7100fb63a..b36923c48 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,11 @@ ## Current * Added the ability of saving correlation data of the lag_calc. +* lag_calc: + - Added option to set minimum CC threshold individually for detections based + on: min(detect_val / n_chans * min_cc_from_mean_cc_factor, min_cc). +* party.rethreshold: + - added option to rethreshold based on absolute values to keep relevant + detections with large negative detect_val. * utils.mag_calc.calc_b_value: - Added useful information to doc-string regarding method and meaning of residuals From 11d5fc9f2a95fa60064ff2f7c63fa4f724a2e0f0 Mon Sep 17 00:00:00 2001 From: flixha Date: Tue, 23 Mar 2021 11:53:27 +0100 Subject: [PATCH 062/132] add test for variable min-CC --- eqcorrscan/core/lag_calc.py | 13 ++++++++++--- eqcorrscan/tests/lag_calc_test.py | 3 ++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/eqcorrscan/core/lag_calc.py b/eqcorrscan/core/lag_calc.py index f77772251..632f9f8eb 100644 --- a/eqcorrscan/core/lag_calc.py +++ b/eqcorrscan/core/lag_calc.py @@ -416,7 +416,8 @@ def _prepare_data(family, detect_data, shift_len): def lag_calc(detections, detect_data, template_names, templates, - shift_len=0.2, min_cc=0.4, horizontal_chans=['E', 'N', '1', '2'], + shift_len=0.2, min_cc=0.4, min_cc_from_mean_cc_factor=None, + horizontal_chans=['E', 'N', '1', '2'], vertical_chans=['Z'], cores=1, interpolate=False, plot=False, plotdir=None, export_cc=False, cc_dir=None): """ @@ -449,6 +450,11 @@ def lag_calc(detections, detect_data, template_names, templates, :type min_cc: float :param min_cc: Minimum cross-correlation value to be considered a pick, default=0.4. + :type min_cc_from_mean_cc_factor: float + :param min_cc_from_mean_cc_factor: + If set to a value other than None, then the minimum cross-correlation + value for a trace is set individually for each detection based on: + min(detect_val / n_chans * min_cc_from_mean_cc_factor, min_cc). :type horizontal_chans: list :param horizontal_chans: List of channel endings for horizontal-channels, on which S-picks will @@ -555,8 +561,9 @@ def lag_calc(detections, detect_data, template_names, templates, # Make a sparse template if len(template_detections) > 0: template_dict = xcorr_pick_family( - family=family, stream=detect_data, - min_cc=min_cc, horizontal_chans=horizontal_chans, + family=family, stream=detect_data, min_cc=min_cc, + min_cc_from_mean_cc_factor=min_cc_from_mean_cc_factor, + horizontal_chans=horizontal_chans, vertical_chans=vertical_chans, interpolate=interpolate, cores=cores, shift_len=shift_len, plot=plot, plotdir=plotdir, export_cc=export_cc, cc_dir=cc_dir) diff --git a/eqcorrscan/tests/lag_calc_test.py b/eqcorrscan/tests/lag_calc_test.py index 7b25aeccc..cc0dc8501 100644 --- a/eqcorrscan/tests/lag_calc_test.py +++ b/eqcorrscan/tests/lag_calc_test.py @@ -170,7 +170,8 @@ def test_lag_calc_api(self): template_names = [f.template.name for f in self.party] output_cat = lag_calc( detections, self.data, template_names, templates, - shift_len=0.2, min_cc=0.4, horizontal_chans=['E', 'N', '1', '2'], + shift_len=0.2, min_cc=0.4, min_cc_from_mean_cc_factor=1, + horizontal_chans=['E', 'N', '1', '2'], vertical_chans=['Z'], cores=1, interpolate=False, plot=False, export_cc=False) self.assertEqual(len(output_cat), len(detections)) From 93c92e170ae8b75d99e403577f386a9e6d272d66 Mon Sep 17 00:00:00 2001 From: flixha Date: Tue, 23 Mar 2021 12:16:22 +0100 Subject: [PATCH 063/132] add test for rethresholding with absolute values --- eqcorrscan/tests/match_filter_test.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/eqcorrscan/tests/match_filter_test.py b/eqcorrscan/tests/match_filter_test.py index df88428fe..49ff55d35 100644 --- a/eqcorrscan/tests/match_filter_test.py +++ b/eqcorrscan/tests/match_filter_test.py @@ -1208,11 +1208,16 @@ def test_party_rethreshold(self): det.id = str(i) party[0].detections.append(det) self.assertEqual(len(party), 204) - party.rethreshold(new_threshold=9) - for family in party: + party1 = party.copy().rethreshold(new_threshold=9) + for family in party1: for d in family: self.assertEqual(d.threshold_input, 9.0) self.assertGreaterEqual(d.detect_val, d.threshold) + party2 = party.copy().rethreshold(new_threshold=9, abs_values=True) + for family in party2: + for d in family: + self.assertEqual(d.threshold_input, 9.0) + self.assertGreaterEqual(abs(d.detect_val), d.threshold) def test_family_init(self): """Test generating a family with various things.""" From ec9cb3da0876d959b86c4a961506bf98e2784be5 Mon Sep 17 00:00:00 2001 From: flixha Date: Fri, 19 Mar 2021 17:26:48 +0100 Subject: [PATCH 064/132] migrate to function correlate() after depreciation of xcorr() --- eqcorrscan/utils/picker.py | 5 +++-- eqcorrscan/utils/plotting.py | 6 ++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/eqcorrscan/utils/picker.py b/eqcorrscan/utils/picker.py index cd2753132..7d99238f1 100644 --- a/eqcorrscan/utils/picker.py +++ b/eqcorrscan/utils/picker.py @@ -15,7 +15,7 @@ import numpy as np from obspy import UTCDateTime -from obspy.signal.cross_correlation import xcorr +from obspy.signal.cross_correlation import correlate, xcorr_max from obspy.signal.filter import envelope from obspy.core.event import Event, Pick, WaveformStreamID from obspy.core.event import CreationInfo, Comment, Origin @@ -86,7 +86,8 @@ def cross_net(stream, env=False, master=False): Logger.debug('Comparing {0} with the master'.format(tr.id)) shift_len = int(0.3 * len(tr)) Logger.debug('Shift length is set to ' + str(shift_len) + ' samples') - index, cc = xcorr(master, tr, shift_len) + corr_fun = correlate(master, tr, shift_len) + index, cc = xcorr_max(corr_fun) wav_id = WaveformStreamID(station_code=tr.stats.station, channel_code=tr.stats.channel, network_code=tr.stats.network) diff --git a/eqcorrscan/utils/plotting.py b/eqcorrscan/utils/plotting.py index a47921c50..326755518 100644 --- a/eqcorrscan/utils/plotting.py +++ b/eqcorrscan/utils/plotting.py @@ -21,7 +21,7 @@ from scipy.linalg import diagsvd from scipy import fftpack from obspy import UTCDateTime, Stream, Catalog, Trace -from obspy.signal.cross_correlation import xcorr +from obspy.signal.cross_correlation import correlate, xcorr_max from eqcorrscan.utils.stacking import align_traces, PWS_stack, linstack @@ -1758,7 +1758,9 @@ def plot_synth_real(real_template, synthetic, channels=False, **kwargs): channel=stachan[1])[0] synth_tr = synthetic.select(station=stachan[0], channel=stachan[1])[0] - shift, corr = xcorr(real_tr, synth_tr, 2) + corr_fun = correlate(real_tr, synth_tr, 2) + shift, corr = xcorr_max(corr_fun) + shift = int(shift) Logger.info('Shifting by: ' + str(shift) + ' samples') if corr < 0: synth_tr.data = synth_tr.data * -1 From e36affcfdd7d99f0f167b3f779166760b65ea646 Mon Sep 17 00:00:00 2001 From: flixha Date: Fri, 19 Mar 2021 17:27:26 +0100 Subject: [PATCH 065/132] work around depreceated/removed casting of hdf5 dataset into numpy --- eqcorrscan/core/subspace.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/eqcorrscan/core/subspace.py b/eqcorrscan/core/subspace.py index d80c5ec93..649f9379d 100644 --- a/eqcorrscan/core/subspace.py +++ b/eqcorrscan/core/subspace.py @@ -386,18 +386,18 @@ def read(self, filename): f = h5py.File(filename, "r") self.data = [] for i in range(f['data'].attrs['length']): - self.data.append(f['data']['data_' + str(i)].value) + self.data.append(f['data']['data_' + str(i)][...]) self.u = [] for i in range(f['u'].attrs['length']): - self.u.append(f['u']['u_' + str(i)].value) + self.u.append(f['u']['u_' + str(i)][...]) self.sigma = [] for i in range(f['sigma'].attrs['length']): - self.sigma.append(f['sigma']['sigma_' + str(i)].value) + self.sigma.append(f['sigma']['sigma_' + str(i)][...]) self.v = [] for i in range(f['v'].attrs['length']): - self.v.append(f['v']['v_' + str(i)].value) + self.v.append(f['v']['v_' + str(i)][...]) self.stachans = [tuple(stachan.decode('ascii').split('.')) - for stachan in f['stachans'].value] + for stachan in f['stachans'][...]] self.dimension = f['data'].attrs['dimension'] self.filt_order = f['data'].attrs['filt_order'] self.highcut = f['data'].attrs['highcut'] From f895c7344cee0291ca75ca4cb4705b528808c742 Mon Sep 17 00:00:00 2001 From: flixha Date: Tue, 23 Mar 2021 13:20:45 +0100 Subject: [PATCH 066/132] merge conflict during git cherry-picking --- eqcorrscan/core/lag_calc.py | 2 +- eqcorrscan/tests/match_filter_test.py | 109 +++++++++++++++++--------- 2 files changed, 71 insertions(+), 40 deletions(-) diff --git a/eqcorrscan/core/lag_calc.py b/eqcorrscan/core/lag_calc.py index 67e945cc7..db7d00e4d 100644 --- a/eqcorrscan/core/lag_calc.py +++ b/eqcorrscan/core/lag_calc.py @@ -80,7 +80,7 @@ def _xcorr_interp(ccc, dt): Logger.debug( "Fewer than 5 samples selected for fit to cross correlation: " "{0}".format(num_samples)) - coeffs, residual = scipy.polyfit( + coeffs, residual = np.polyfit( cc_t[first_sample:last_sample + 1], cc[first_sample:last_sample + 1], deg=2, full=True)[:2] # check results of fit diff --git a/eqcorrscan/tests/match_filter_test.py b/eqcorrscan/tests/match_filter_test.py index df88428fe..68f76d620 100644 --- a/eqcorrscan/tests/match_filter_test.py +++ b/eqcorrscan/tests/match_filter_test.py @@ -9,7 +9,7 @@ import numpy as np from obspy import read, UTCDateTime, read_events, Catalog, Stream, Trace from obspy.clients.fdsn import Client -from obspy.clients.filesystem.sds import Client as SDSClient +from obspy.clients.earthworm import Client as EWClient from obspy.core.event import Pick, Event from obspy.core.util.base import NamedTemporaryFile @@ -28,7 +28,7 @@ class TestHelpers(unittest.TestCase): def test_monkey_patching(self): """ Test that monkey patching a client works. """ - client = SDSClient('.') + client = EWClient('.') self.assertFalse(hasattr(client, "get_waveforms_bulk")) client = get_waveform_client(client) self.assertTrue(hasattr(client, "get_waveforms_bulk")) @@ -146,7 +146,7 @@ def test_onesamp_diff(self): templates[0][1].stats.station = 'B' match_filter(template_names=['1'], template_list=templates, st=stream, threshold=8, threshold_type='MAD', trig_int=1, - plotvar=False) + plot=False) def test_half_samp_diff(self): """ @@ -170,7 +170,7 @@ def test_half_samp_diff(self): templates[0][1].stats.station = 'B' match_filter(template_names=['1'], template_list=templates, st=stream, threshold=8, threshold_type='MAD', trig_int=1, - plotvar=False) + plot=False) @pytest.mark.network @@ -227,7 +227,7 @@ def test_duplicate_channels_in_template(self): detections = match_filter(template_names=self.template_names, template_list=templates, st=self.st, threshold=8.0, threshold_type='MAD', - trig_int=6.0, plotvar=False, plotdir='.', + trig_int=6.0, plot=False, plotdir='.', cores=1) self.assertEqual(len(detections), 1) self.assertEqual(detections[0].no_chans, 6) @@ -241,7 +241,7 @@ def test_duplicate_cont_data(self): with self.assertRaises(NotImplementedError): match_filter(template_names=self.template_names, template_list=self.templates, st=st, threshold=8.0, - threshold_type='MAD', trig_int=6.0, plotvar=False, + threshold_type='MAD', trig_int=6.0, plot=False, plotdir='.', cores=1) def test_missing_cont_channel(self): @@ -252,7 +252,7 @@ def test_missing_cont_channel(self): detections, det_cat = match_filter( template_names=self.template_names, template_list=self.templates, st=st, threshold=8.0, threshold_type='MAD', trig_int=6.0, - plotvar=False, plotdir='.', cores=1, output_cat=True) + plot=False, plotdir='.', cores=1, output_cat=True) self.assertEqual(len(detections), 1) self.assertEqual(detections[0].no_chans, 5) self.assertEqual(len(detections), len(det_cat)) @@ -266,7 +266,7 @@ def test_no_matching_data(self): match_filter( template_names=self.template_names, template_list=self.templates, st=st, threshold=8.0, - threshold_type='MAD', trig_int=6.0, plotvar=False, + threshold_type='MAD', trig_int=6.0, plot=False, plotdir='.', cores=1) @pytest.mark.flaky(reruns=2) @@ -282,7 +282,7 @@ def test_geonet_tribe_detect(self): party = self.tribe.copy().client_detect( client=client, starttime=self.t1, endtime=self.t2, threshold=8.0, threshold_type='MAD', trig_int=6.0, - daylong=False, plotvar=False) + daylong=False, plot=False) self.assertEqual(len(party), 16) @@ -313,7 +313,7 @@ def test_gappy_data(self): party = self.tribe.client_detect( client=self.client, starttime=self.starttime, endtime=self.endtime, threshold=0.6, - threshold_type="absolute", trig_int=2, plotvar=False, + threshold_type="absolute", trig_int=2, plot=False, parallel_process=False, cores=1) for family in party: print(family) @@ -327,7 +327,7 @@ def test_gappy_data_removal(self): party = self.tribe.client_detect( client=self.client, starttime=self.starttime, endtime=self.endtime, threshold=8, - threshold_type="MAD", trig_int=2, plotvar=False, + threshold_type="MAD", trig_int=2, plot=False, parallel_process=False, min_gap=1) self.assertEqual(len(party), 0) @@ -385,7 +385,7 @@ def test_detection_extraction(self): match_filter(template_names=self.template_names, template_list=self.templates, st=self.st, threshold=8.0, threshold_type='MAD', - trig_int=6.0, plotvar=False, plotdir='.', + trig_int=6.0, plot=False, plotdir='.', cores=1, extract_detections=True) self.assertEqual(len(detections), 4) self.assertEqual(len(detection_streams), len(detections)) @@ -408,7 +408,7 @@ def test_catalog_extraction(self): match_filter(template_names=self.template_names, template_list=self.templates, st=self.st, threshold=8.0, threshold_type='MAD', - trig_int=6.0, plotvar=False, plotdir='.', + trig_int=6.0, plot=False, plotdir='.', cores=1, extract_detections=True, output_cat=True) self.assertEqual(len(detections), 4) self.assertEqual(len(detection_streams), len(detections)) @@ -425,7 +425,7 @@ def test_same_detections_individual_and_parallel(self): individual_detections += match_filter( template_names=[template_name], template_list=[template], st=self.st.copy(), threshold=8.0, threshold_type='MAD', - trig_int=6.0, plotvar=False, plotdir='.', cores=1) + trig_int=6.0, plot=False, plotdir='.', cores=1) individual_dict = [] for detection in individual_detections: individual_dict.append({'template_name': detection.template_name, @@ -434,7 +434,7 @@ def test_same_detections_individual_and_parallel(self): detections = match_filter(template_names=self.template_names, template_list=self.templates, st=self.st, threshold=8.0, threshold_type='MAD', - trig_int=6.0, plotvar=False, plotdir='.', + trig_int=6.0, plot=False, plotdir='.', cores=1) self.assertEqual(len(individual_detections), len(detections)) for detection in detections: @@ -450,7 +450,7 @@ def test_read_write_detections(self): detections = match_filter(template_names=self.template_names, template_list=self.templates, st=self.st, threshold=8.0, threshold_type='MAD', - trig_int=6.0, plotvar=False, plotdir='.', + trig_int=6.0, plot=False, plotdir='.', cores=1) detection_dict = [] for detection in detections: @@ -481,7 +481,7 @@ def test_get_catalog(self): detections = match_filter( template_names=self.template_names, template_list=self.templates, st=self.st, threshold=8.0, threshold_type='MAD', trig_int=6.0, - plotvar=False, plotdir='.', cores=1) + plot=False, plotdir='.', cores=1) cat = get_catalog(detections) self.assertEqual(len(cat), len(detections)) for det in detections: @@ -497,7 +497,7 @@ def test_extraction(self): detections = match_filter(template_names=self.template_names, template_list=self.templates, st=self.st, threshold=8.0, threshold_type='MAD', - trig_int=6.0, plotvar=False, plotdir='.', + trig_int=6.0, plot=False, plotdir='.', cores=1) streams = extract_from_stream(stream=self.st.copy(), detections=detections) @@ -513,37 +513,37 @@ def test_incorrect_arguments(self): match_filter(template_names=self.template_names[0], template_list=self.templates, st=self.st, threshold=8.0, threshold_type='MAD', trig_int=6.0, - plotvar=False, plotdir='.', cores=1) + plot=False, plotdir='.', cores=1) with self.assertRaises(MatchFilterError): # templates is not a list match_filter(template_names=self.template_names, template_list=self.templates[0], st=self.st, threshold=8.0, threshold_type='MAD', trig_int=6.0, - plotvar=False, plotdir='.', cores=1) + plot=False, plotdir='.', cores=1) with self.assertRaises(MatchFilterError): # template and template_names length are not equal match_filter(template_names=self.template_names, template_list=[self.templates[0]], st=self.st, threshold=8.0, threshold_type='MAD', trig_int=6.0, - plotvar=False, plotdir='.', cores=1) + plot=False, plotdir='.', cores=1) with self.assertRaises(MatchFilterError): # templates is not a list of streams match_filter(template_names=self.template_names, template_list=['abc'], st=self.st, threshold=8.0, threshold_type='MAD', trig_int=6.0, - plotvar=False, plotdir='.', cores=1) + plot=False, plotdir='.', cores=1) with self.assertRaises(MatchFilterError): # st is not a Stream match_filter(template_names=self.template_names, template_list=self.templates, st=np.random.randn(10), threshold=8.0, threshold_type='MAD', trig_int=6.0, - plotvar=False, plotdir='.', cores=1) + plot=False, plotdir='.', cores=1) with self.assertRaises(MatchFilterError): # threshold_type is wrong match_filter(template_names=self.template_names, template_list=self.templates, st=self.st, threshold=8.0, threshold_type='albert', trig_int=6.0, - plotvar=False, plotdir='.', cores=1) + plot=False, plotdir='.', cores=1) def test_masked_template(self): templates = [self.templates[0].copy()] @@ -555,7 +555,7 @@ def test_masked_template(self): match_filter(template_names=[self.template_names[0]], template_list=templates, st=self.st, threshold=8.0, threshold_type='MAD', trig_int=6.0, - plotvar=False, plotdir='.', cores=1) + plot=False, plotdir='.', cores=1) def test_non_equal_template_lengths(self): templates = [self.templates[0].copy()] @@ -565,7 +565,7 @@ def test_non_equal_template_lengths(self): match_filter(template_names=[self.template_names[0]], template_list=templates, st=self.st, threshold=8.0, threshold_type='MAD', trig_int=6.0, - plotvar=False, plotdir='.', cores=1) + plot=False, plotdir='.', cores=1) class TestMatchCopy(unittest.TestCase): @@ -689,12 +689,43 @@ def test_tribe_detect(self): """Test the detect method on Tribe objects""" party = self.tribe.detect( stream=self.unproc_st, threshold=8.0, threshold_type='MAD', - trig_int=6.0, daylong=False, plotvar=False, parallel_process=False) + trig_int=6.0, daylong=False, plot=False, parallel_process=False) self.assertEqual(len(party), 4) compare_families( party=party, party_in=self.party, float_tol=0.05, check_event=True) + def test_tribe_detect_with_empty_streams(self): + """ + Compare the detect method for a tribe of one vs two templates and check + that the detection has the same detect time, in a case where the + continuous data is incomplete. This test should fail in v0.4.2 due to + a bug. + """ + # remove trace for station PHA (PHOB, PSR, PCA, PAG remain) + st = self.unproc_st.copy().remove( + self.unproc_st.copy().select(station='PHA')[0]) + tribe1 = Tribe([t.copy() for t in self.tribe + if (t.name=='2004_09_28t17_19_08' or + t.name=='2004_09_28t17_19_25')]) + # run detection with 2 templates in tribe + party1 = tribe1.detect( + stream=st, threshold=8.0, threshold_type='MAD', + trig_int=6.0, daylong=False, plot=False, parallel_process=False) + self.assertEqual(len(party1), 2) + party1 = Party([f for f in party1 + if f.template.name=='2004_09_28t17_19_25']) + # run detection with only 1 template in tribe + tribe2 = Tribe([t.copy() for t in self.tribe + if t.name=='2004_09_28t17_19_25']) + party2 = tribe2.detect( + stream=st, threshold=8.0, threshold_type='MAD', + trig_int=6.0, daylong=False, plot=False, parallel_process=False) + self.assertEqual(len(party2), 1) + # This should fail in v0.4.2 + compare_families( + party=party1, party_in=party2, float_tol=0.05, check_event=True) + def test_tribe_detect_short_data(self): """Test the detect method on Tribe objects""" short_st = self.unproc_st.copy() @@ -703,7 +734,7 @@ def test_tribe_detect_short_data(self): template.process_length = 2400 party = tribe.detect( stream=short_st, threshold=8.0, threshold_type='MAD', - trig_int=6.0, daylong=False, plotvar=False, parallel_process=False, + trig_int=6.0, daylong=False, plot=False, parallel_process=False, ignore_bad_data=True) self.assertEqual(len(party), 4) @@ -712,7 +743,7 @@ def test_tribe_detect_parallel_process(self): """Test the detect method on Tribe objects""" party = self.tribe.detect( stream=self.unproc_st, threshold=8.0, threshold_type='MAD', - trig_int=6.0, daylong=False, plotvar=False, parallel_process=True, + trig_int=6.0, daylong=False, plot=False, parallel_process=True, process_cores=2) self.assertEqual(len(party), 4) compare_families( @@ -723,7 +754,7 @@ def test_tribe_detect_save_progress(self): """Test the detect method on Tribe objects""" party = self.tribe.detect( stream=self.unproc_st, threshold=8.0, threshold_type='MAD', - trig_int=6.0, daylong=False, plotvar=False, parallel_process=False, + trig_int=6.0, daylong=False, plot=False, parallel_process=False, save_progress=True) self.assertEqual(len(party), 4) self.assertTrue(os.path.isfile("eqcorrscan_temporary_party.tgz")) @@ -742,7 +773,7 @@ def test_tribe_detect_masked_data(self): stream[0].stats.starttime + 1900, stream[0].stats.endtime)) party = self.tribe.detect( stream=stream, threshold=8.0, threshold_type='MAD', - trig_int=6.0, daylong=False, plotvar=False, parallel_process=False, + trig_int=6.0, daylong=False, plot=False, parallel_process=False, xcorr_func='fftw', concurrency='concurrent') self.assertEqual(len(party), 4) @@ -754,7 +785,7 @@ def test_tribe_detect_no_processing(self): template.highcut = None party = tribe.detect( stream=self.st, threshold=8.0, threshold_type='MAD', - trig_int=6.0, daylong=False, plotvar=False, parallel_process=False) + trig_int=6.0, daylong=False, plot=False, parallel_process=False) self.assertEqual(len(party), 4) compare_families( party=party, party_in=self.party, float_tol=0.05, @@ -768,7 +799,7 @@ def test_client_detect(self): party = self.tribe.copy().client_detect( client=client, starttime=self.t1 + 2.75, endtime=self.t2, threshold=8.0, threshold_type='MAD', trig_int=6.0, - daylong=False, plotvar=False) + daylong=False, plot=False) compare_families( party=party, party_in=self.party, float_tol=0.05, check_event=False) @@ -781,7 +812,7 @@ def test_client_detect_save_progress(self): party = self.tribe.copy().client_detect( client=client, starttime=self.t1 + 2.75, endtime=self.t2, threshold=8.0, threshold_type='MAD', trig_int=6.0, - daylong=False, plotvar=False, save_progress=True) + daylong=False, plot=False, save_progress=True) self.assertTrue(os.path.isfile("eqcorrscan_temporary_party.tgz")) saved_party = Party().read("eqcorrscan_temporary_party.tgz") self.assertEqual(party, saved_party) @@ -796,7 +827,7 @@ def test_party_lag_calc(self): # Test the chained method chained_cat = self.tribe.detect( stream=self.unproc_st, threshold=8.0, threshold_type='MAD', - trig_int=6.0, daylong=False, plotvar=False).lag_calc( + trig_int=6.0, daylong=False, plot=False).lag_calc( stream=self.unproc_st, pre_processed=False) catalog = self.party.copy().lag_calc( stream=self.unproc_st, pre_processed=False) @@ -938,7 +969,7 @@ def test_day_long_methods(self): # MAD! day_party = daylong_tribe.detect( stream=st, threshold=8.0, threshold_type='MAD', trig_int=6.0, - daylong=True, plotvar=False, parallel_process=False) + daylong=True, plot=False, parallel_process=False) self.assertEqual(len(day_party), 4) day_catalog = day_party.lag_calc(stream=st, pre_processed=False, parallel=False) @@ -957,7 +988,7 @@ def test_template_detect(self): test_template = self.family.template.copy() party_t = test_template.detect( stream=self.unproc_st, threshold=8.0, threshold_type='MAD', - trig_int=6.0, daylong=False, plotvar=False, overlap=None) + trig_int=6.0, daylong=False, plot=False, overlap=None) self.assertEqual(len(party_t), 1) def test_template_construct_not_implemented(self): @@ -1465,7 +1496,7 @@ def compare_families(party, party_in, float_tol=0.001, check_event=True): assert det.__dict__[key] == check_det.__dict__[key] -def test_match_filter(plotvar=False, extract_detections=False, +def test_match_filter(plot=False, extract_detections=False, threshold_type='MAD', threshold=10, template_excess=False, stream_excess=False): """ @@ -1511,7 +1542,7 @@ def test_match_filter(plotvar=False, extract_detections=False, detections = match_filter( template_names=template_names, template_list=templates, st=data, threshold=threshold, threshold_type=threshold_type, trig_int=6.0, - plotvar=plotvar, plotdir='.', cores=1, output_cat=False, + plot=plot, plotdir='.', cores=1, output_cat=False, extract_detections=extract_detections) if extract_detections: detection_streams = detections[1] From 649f1a91eb529737c84e675f6c2d4b4d131098f6 Mon Sep 17 00:00:00 2001 From: flixha Date: Tue, 23 Mar 2021 13:21:16 +0100 Subject: [PATCH 067/132] udpate/fix monkey-patching test --- eqcorrscan/tests/match_filter_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eqcorrscan/tests/match_filter_test.py b/eqcorrscan/tests/match_filter_test.py index 68f76d620..45b95ea01 100644 --- a/eqcorrscan/tests/match_filter_test.py +++ b/eqcorrscan/tests/match_filter_test.py @@ -28,7 +28,7 @@ class TestHelpers(unittest.TestCase): def test_monkey_patching(self): """ Test that monkey patching a client works. """ - client = EWClient('.') + client = EWClient("pubavo1.wr.usgs.gov", 16022) self.assertFalse(hasattr(client, "get_waveforms_bulk")) client = get_waveform_client(client) self.assertTrue(hasattr(client, "get_waveforms_bulk")) From 6f98f9cc7f74b0120ffa0c68622dbe7772b94961 Mon Sep 17 00:00:00 2001 From: flixha Date: Tue, 23 Mar 2021 13:32:45 +0100 Subject: [PATCH 068/132] remove incorrectly merge test (is part of PR #439 and shouldn't have been here) --- eqcorrscan/tests/match_filter_test.py | 31 --------------------------- 1 file changed, 31 deletions(-) diff --git a/eqcorrscan/tests/match_filter_test.py b/eqcorrscan/tests/match_filter_test.py index 45b95ea01..d61dcac4d 100644 --- a/eqcorrscan/tests/match_filter_test.py +++ b/eqcorrscan/tests/match_filter_test.py @@ -695,37 +695,6 @@ def test_tribe_detect(self): party=party, party_in=self.party, float_tol=0.05, check_event=True) - def test_tribe_detect_with_empty_streams(self): - """ - Compare the detect method for a tribe of one vs two templates and check - that the detection has the same detect time, in a case where the - continuous data is incomplete. This test should fail in v0.4.2 due to - a bug. - """ - # remove trace for station PHA (PHOB, PSR, PCA, PAG remain) - st = self.unproc_st.copy().remove( - self.unproc_st.copy().select(station='PHA')[0]) - tribe1 = Tribe([t.copy() for t in self.tribe - if (t.name=='2004_09_28t17_19_08' or - t.name=='2004_09_28t17_19_25')]) - # run detection with 2 templates in tribe - party1 = tribe1.detect( - stream=st, threshold=8.0, threshold_type='MAD', - trig_int=6.0, daylong=False, plot=False, parallel_process=False) - self.assertEqual(len(party1), 2) - party1 = Party([f for f in party1 - if f.template.name=='2004_09_28t17_19_25']) - # run detection with only 1 template in tribe - tribe2 = Tribe([t.copy() for t in self.tribe - if t.name=='2004_09_28t17_19_25']) - party2 = tribe2.detect( - stream=st, threshold=8.0, threshold_type='MAD', - trig_int=6.0, daylong=False, plot=False, parallel_process=False) - self.assertEqual(len(party2), 1) - # This should fail in v0.4.2 - compare_families( - party=party1, party_in=party2, float_tol=0.05, check_event=True) - def test_tribe_detect_short_data(self): """Test the detect method on Tribe objects""" short_st = self.unproc_st.copy() From d32c504116b0ee08e9e8202a3a4cf770a04ba001 Mon Sep 17 00:00:00 2001 From: flixha Date: Tue, 23 Mar 2021 13:47:36 +0100 Subject: [PATCH 069/132] #2 remove incorrectly merged test (is part of PR #439 and shouldn't have been here) --- eqcorrscan/tests/match_filter_test.py | 29 --------------------------- 1 file changed, 29 deletions(-) diff --git a/eqcorrscan/tests/match_filter_test.py b/eqcorrscan/tests/match_filter_test.py index d61dcac4d..098f4f0cf 100644 --- a/eqcorrscan/tests/match_filter_test.py +++ b/eqcorrscan/tests/match_filter_test.py @@ -414,35 +414,6 @@ def test_catalog_extraction(self): self.assertEqual(len(detection_streams), len(detections)) self.assertEqual(len(detection_streams), len(det_cat)) - def test_same_detections_individual_and_parallel(self): - """ - Check that the same detections are made regardless of whether templates - are run together or separately. - """ - individual_detections = [] - for template, template_name in zip(self.templates, - self.template_names): - individual_detections += match_filter( - template_names=[template_name], template_list=[template], - st=self.st.copy(), threshold=8.0, threshold_type='MAD', - trig_int=6.0, plot=False, plotdir='.', cores=1) - individual_dict = [] - for detection in individual_detections: - individual_dict.append({'template_name': detection.template_name, - 'time': detection.detect_time, - 'cccsum': detection.detect_val.round(6)}) - detections = match_filter(template_names=self.template_names, - template_list=self.templates, st=self.st, - threshold=8.0, threshold_type='MAD', - trig_int=6.0, plot=False, plotdir='.', - cores=1) - self.assertEqual(len(individual_detections), len(detections)) - for detection in detections: - detection_dict = {'template_name': detection.template_name, - 'time': detection.detect_time, - 'cccsum': detection.detect_val.round(6)} - self.assertTrue(detection_dict in individual_dict) - def test_read_write_detections(self): """Check that we can read and write detections accurately.""" if os.path.isfile("dets_out.txt"): From 0d2536eb269f057592d0618cd73524d53fd27be2 Mon Sep 17 00:00:00 2001 From: Calum Chamberlain Date: Tue, 23 Mar 2021 20:32:38 +0000 Subject: [PATCH 070/132] Simple trial of migrating superslow and windows tests to github actions --- .circleci/config.yml | 69 ---------------------- .github/workflows/runtest.yml | 108 ++++++++++++++++++++++++++++++++++ appveyor.yml | 65 -------------------- 3 files changed, 108 insertions(+), 134 deletions(-) delete mode 100644 .circleci/config.yml delete mode 100644 appveyor.yml diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index b2068c291..000000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,69 +0,0 @@ -# Python CircleCI 2.0 configuration file -# -# Check https://circleci.com/docs/2.0/language-python/ for more details -# -general: - branches: - ignore: - - gh-pages - -version: 2 -jobs: - build: - docker: - # specify the version you desire here - # use `-browsers` prefix for selenium tests, e.g. `3.6.1-browsers` - - image: circleci/python:3.7 - - # Specify service dependencies here if necessary - # CircleCI maintains a library of pre-built images - # documented at https://circleci.com/docs/2.0/circleci-images/ - # - image: circleci/postgres:9.4 - - working_directory: ~/repo - - steps: - - checkout - - restore_cache: - key: deps1-{{ .Branch }}-{{ checksum "requirements.txt" }} - - run: - name: install fftw - command: | - sudo apt-get update - sudo apt-get install libfftw3-dev - - run: - name: install dependencies - command: | - python3 -m venv venv - . venv/bin/activate - pip install numpy>=1.12 - pip install -r requirements.txt - - save_cache: - key: deps1-{{ .Branch }}-{{ checksum "requirements.txt" }} - paths: - - "venv" - - - run: - name: install EQcorrscan - command: | - . venv/bin/activate - python setup.py develop - # run tests! - - run: - name: run tests - command: | - . venv/bin/activate - py.test -m "network" -n 2 - py.test eqcorrscan/doc/tutorials/*.rst eqcorrscan/doc/submodules/*.rst --cov-append - py.test -m "superslow" -s eqcorrscan/tests/tutorials_test.py eqcorrscan/tests/subspace_test.py --cov-append - - - run: - name: Upload to codecov - command: | - . venv/bin/activate - ls -a - codecov - - - store_artifacts: - path: test-reports - destination: test-reports diff --git a/.github/workflows/runtest.yml b/.github/workflows/runtest.yml index c720eadd7..4f5758938 100644 --- a/.github/workflows/runtest.yml +++ b/.github/workflows/runtest.yml @@ -112,6 +112,114 @@ jobs: yml: ./codecov.yml fail_ci_if_error: true + test-code-slow: + runs-on: "ubuntu-latest" + strategy: + matrix: + python-version: [3.8] + fail-fast: false + + steps: + - uses: actions/checkout@v2 + + - name: Setup conda + uses: conda-incubator/setup-miniconda@v2 + with: + miniconda-version: 'latest' + python-version: ${{ matrix.python-version }} + activate-environment: eqcorrscan-test + environment-file: .github/test_conda_env.yml + condarc-file: .github/test_condarc.yml + + - name: install eqcorrscan + shell: bash -l {0} + run: | + pip install -e . + + - name: print package info + shell: bash -l {0} + run: | + conda info -a + conda list + + - name: run network tests + shell: bash -l {0} + run: | + py.test -n 2 -m "network" --cov-report=xml + - name: run tutorials + shell: bash -l {0} + run: | + py.test eqcorrscan/doc/tutorials/*.rst eqcorrscan/doc/submodules/*.rst --cov-report=xml --cov-append + - name: run superslow tests + shell: bash -l {0} + run: | + py.test -m "superslow" -s eqcorrscan/tests/tutorials_test.py eqcorrscan/tests/subspace_test.py --cov-report=xml --cov-append + + - name: upload coverage + uses: codecov/codecov-action@v1 + with: + token: ${{ secrets.CODECOV_TOKEN }} + file: ./coverage.xml + flags: unittests + name: codecov-umbrella + yml: ./codecov.yml + fail_ci_if_error: true + + test-code-windows: + runs-on: "windows-latest" + strategy: + matrix: + python-version: [3.7, 3.8] + fail-fast: false + + steps: + - uses: actions/checkout@v2 + + - name: Setup conda + uses: conda-incubator/setup-miniconda@v2 + with: + miniconda-version: 'latest' + python-version: ${{ matrix.python-version }} + activate-environment: eqcorrscan-test + environment-file: .github/test_conda_env.yml + condarc-file: .github/test_condarc.yml + + - name: install eqcorrscan + shell: bash -l {0} + run: | + pip install -e . + + - name: print package info + shell: bash -l {0} + run: | + conda info -a + conda list + + - name: run main test suite + shell: bash -l {0} + continue-on-error: true + run: | + py.test -n 2 -m "not serial and not network and not superslow" --cov-report=xml + - name: run slow tests + shell: bash -l {0} + run: | + py.test -v -m "slow and not serial and not network" --cov-report=xml --cov-append + - name: run serial test + shell: bash -l {0} + run: | + export OMP_NUM_THREADS=2 + py.test -m "serial and not network" --cov-report=xml --cov-append + + - name: upload coverage + uses: codecov/codecov-action@v1 + with: + token: ${{ secrets.CODECOV_TOKEN }} + file: ./coverage.xml + flags: unittests + name: codecov-umbrella + yml: ./codecov.yml + fail_ci_if_error: true + # This is a very useful step for debugging, it allows you to ssh into the CI # machine (https://github.com/marketplace/actions/debugging-with-tmate). # Make sure to open the log before the job starts else you cant see the tmate diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index c728c4786..000000000 --- a/appveyor.yml +++ /dev/null @@ -1,65 +0,0 @@ - - -# AppVeyor.com is a Continuous Integration service to build and run tests under Windows -environment: - global: - PYTHON: "C:\\conda" - MINICONDA_VERSION: "3.7.0" - CI_URL: "--ci-url https://ci.appveyor.com/project/%APPVEYOR_REPO_NAME%/build/1.0.%APPVEYOR_BUILD_NUMBER%-%APPVEYOR_REPO_BRANCH%" - PR_URL: "--pr-url https://github.com/%APPVEYOR_REPO_NAME%/pull/%APPVEYOR_PULL_REQUEST_NUMBER%" - - matrix: - - PYTHON: "C:\\Miniconda35-x64" - PYTHON_VERSION: "3.7" - PYTHON_ARCH: "64" - -install: - - '.\\misc\\appveyor\\trim_path.bat' - - "ECHO %PATH%" - - "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%" - # Check that we have the expected version and architecture for Python - - "%CMD_IN_ENV% python --version" - # Install fftw - - "choco install curl" - - "choco install 7zip" - - "%CMD_IN_ENV% ./misc/appveyor/setup_fftw_dlls.cmd" - # Install the build and runtime dependencies of the project. - - "conda update -q --yes conda" - - "conda config --add channels conda-forge" - # Create a conda environment using the astropy bonus packages - - "conda create -q --yes -n test python=%PYTHON_VERSION%" - - "activate test" - # Install default dependencies - # - | - # if [[ "${py:0:1}" == "3" ]]; then - # PYFLAKES="pyflakes=1.0.0" - # else - # PYFLAKES="pyflakes=0.9.0" - # fi - # prproj needs to be pinned before obspy 1.2.0 - - "conda install -q --yes pip obspy numpy=1.14 scipy>=0.18 matplotlib mock flake8 pyflakes cython h5py bottleneck pyfftw" - # additional dependecies - - "pip install pyimgur" - - # Install other pip dependancies - - "pip install -U future" - - "pip install pytest pytest-pep8 pytest-cov pytest-xdist pytest-rerunfailures pytest-mpl codecov" - # list package versions - - "conda list" - # Copy the windows fftw header file - - "cp misc/appveyor/fftw3.h eqcorrscan/utils/src/fftw3.h" - -# Not a .NET project -build: false - -test_script: - - "%CMD_IN_ENV% python setup.py develop" -# - "%CMD_IN_ENV% python setup.py install" - - "%CMD_IN_ENV% py.test -n4 -m \"not serial and not network and not superslow\"" - - "%CMD_IN_ENV% py.test -m \"serial and not network and not superslow\" --cov-append" - -after_test: - # - "coverage combine" - # - "powershell copy-item .coverage ..\\.coverage.empty" - # - "coverage combine" - - "codecov" From 301e7b7971c978882b37c292541eddd717bee056 Mon Sep 17 00:00:00 2001 From: Calum Chamberlain Date: Tue, 23 Mar 2021 21:05:03 +0000 Subject: [PATCH 071/132] Try using static linking for FFTW --- .github/workflows/runtest.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/runtest.yml b/.github/workflows/runtest.yml index 4f5758938..fb2e63f2b 100644 --- a/.github/workflows/runtest.yml +++ b/.github/workflows/runtest.yml @@ -169,7 +169,7 @@ jobs: runs-on: "windows-latest" strategy: matrix: - python-version: [3.7, 3.8] + python-version: [3.7] fail-fast: false steps: @@ -184,6 +184,13 @@ jobs: environment-file: .github/test_conda_env.yml condarc-file: .github/test_condarc.yml + - name: setup fftw + shell: bash -l {0} + run: | + export C_INCLUDE_PATH=${PREFIX}/include:${C_INCLUDE_PATH} # required as fftw3.h installed here + export LDFLAGS="${LDFLAGS} -L${PREFIX}/lib" + export STATIC_FFTW_DIR=$PREFIX/lib + - name: install eqcorrscan shell: bash -l {0} run: | From 267d7d1cabf6609152197000afc23c5418783fe0 Mon Sep 17 00:00:00 2001 From: flixha Date: Wed, 24 Mar 2021 08:56:45 +0100 Subject: [PATCH 072/132] Revert "#2 remove incorrectly merged test (is part of PR #439 and shouldn't have been here)" This reverts commit d32c504116b0ee08e9e8202a3a4cf770a04ba001. Reinstate incorrectly removed test. --- eqcorrscan/tests/match_filter_test.py | 29 +++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/eqcorrscan/tests/match_filter_test.py b/eqcorrscan/tests/match_filter_test.py index 098f4f0cf..d61dcac4d 100644 --- a/eqcorrscan/tests/match_filter_test.py +++ b/eqcorrscan/tests/match_filter_test.py @@ -414,6 +414,35 @@ def test_catalog_extraction(self): self.assertEqual(len(detection_streams), len(detections)) self.assertEqual(len(detection_streams), len(det_cat)) + def test_same_detections_individual_and_parallel(self): + """ + Check that the same detections are made regardless of whether templates + are run together or separately. + """ + individual_detections = [] + for template, template_name in zip(self.templates, + self.template_names): + individual_detections += match_filter( + template_names=[template_name], template_list=[template], + st=self.st.copy(), threshold=8.0, threshold_type='MAD', + trig_int=6.0, plot=False, plotdir='.', cores=1) + individual_dict = [] + for detection in individual_detections: + individual_dict.append({'template_name': detection.template_name, + 'time': detection.detect_time, + 'cccsum': detection.detect_val.round(6)}) + detections = match_filter(template_names=self.template_names, + template_list=self.templates, st=self.st, + threshold=8.0, threshold_type='MAD', + trig_int=6.0, plot=False, plotdir='.', + cores=1) + self.assertEqual(len(individual_detections), len(detections)) + for detection in detections: + detection_dict = {'template_name': detection.template_name, + 'time': detection.detect_time, + 'cccsum': detection.detect_val.round(6)} + self.assertTrue(detection_dict in individual_dict) + def test_read_write_detections(self): """Check that we can read and write detections accurately.""" if os.path.isfile("dets_out.txt"): From 779ca49d226cec0e1dde9554bafc943cf9501bfc Mon Sep 17 00:00:00 2001 From: Calum Chamberlain Date: Mon, 29 Mar 2021 15:05:35 +1300 Subject: [PATCH 073/132] Link to the correct places in windows conda --- setup.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index a164915eb..a7ed29553 100644 --- a/setup.py +++ b/setup.py @@ -85,6 +85,10 @@ def get_include_dirs(): numpy.get_include(), os.path.join(sys.prefix, 'include')] + if get_build_platform() in ('win32', 'win-amd64'): + # Add the Library dir + include_dirs.append(os.path.join(sys.prefix, 'Library', 'include')) + if get_build_platform().startswith('freebsd'): include_dirs.append('/usr/local/include') @@ -98,7 +102,8 @@ def get_library_dirs(): if get_build_platform() in ('win32', 'win-amd64'): library_dirs.append(os.path.join(os.getcwd(), 'eqcorrscan', 'utils', 'lib')) - library_dirs.append(os.path.join(sys.prefix, 'bin')) + library_dirs.append(os.path.join(sys.prefix, 'lib')) + library_dirs.append(os.path.join(sys.prefix, 'Library', 'lib')) library_dirs.append(os.path.join(sys.prefix, 'lib')) if get_build_platform().startswith('freebsd'): @@ -171,7 +176,8 @@ def get_libraries(): from pkg_resources import get_build_platform if get_build_platform() in ('win32', 'win-amd64'): - libraries = ['libfftw3-3', 'libfftw3f-3'] + # libraries = ['libfftw3-3', 'libfftw3f-3'] + libraries = ['fftw3', 'fftw3f'] else: libraries = ['fftw3', 'fftw3_threads', 'fftw3f', 'fftw3f_threads'] From 187e8b35e26d2edafe8e480b2eeac005d94ece53 Mon Sep 17 00:00:00 2001 From: Calum Chamberlain Date: Mon, 29 Mar 2021 15:27:00 +1300 Subject: [PATCH 074/132] Try a single matrix --- .github/workflows/runtest.yml | 125 +++------------------------------- 1 file changed, 9 insertions(+), 116 deletions(-) diff --git a/.github/workflows/runtest.yml b/.github/workflows/runtest.yml index fb2e63f2b..94314e064 100644 --- a/.github/workflows/runtest.yml +++ b/.github/workflows/runtest.yml @@ -3,70 +3,23 @@ on: [pull_request] #, push] jobs: # Runs the tests on combinations of the supported python/os matrix. - test-code-macOS: - runs-on: "macos-latest" + test-code: + runs-on: ${{ matrix.os }} strategy: matrix: + os: [ubuntu-latest, macos-latest, windows-latest] python-version: [3.7, 3.8] fail-fast: false steps: - uses: actions/checkout@v2 - - name: Setup conda - uses: conda-incubator/setup-miniconda@v2 - with: - miniconda-version: 'latest' - python-version: ${{ matrix.python-version }} - activate-environment: eqcorrscan-test - environment-file: .github/test_conda_env_macOS.yml - condarc-file: .github/test_condarc.yml - - - name: install eqcorrscan - shell: bash -l {0} - run: | - pip install -e . - - - name: print package info - shell: bash -l {0} - run: | - conda info -a - conda list - - - name: run main test suite - shell: bash -l {0} - continue-on-error: true - run: | - py.test -n 2 -m "not serial and not network and not superslow" --cov-report=xml - - name: run slow tests - shell: bash -l {0} - run: | - py.test -v -m "slow and not serial and not network" --cov-report=xml --cov-append - - name: run serial test + - name: Get conda env file shell: bash -l {0} run: | - export OMP_NUM_THREADS=2 - py.test -m "serial and not network" --cov-report=xml --cov-append - - - name: upload coverage - uses: codecov/codecov-action@v1 - with: - token: ${{ secrets.CODECOV_TOKEN }} - file: ./coverage.xml - flags: unittests - name: codecov-umbrella - yml: ./codecov.yml - fail_ci_if_error: true - - test-code-ubuntu: - runs-on: "ubuntu-latest" - strategy: - matrix: - python-version: [3.7, 3.8] - fail-fast: false - - steps: - - uses: actions/checkout@v2 + if [ "$RUNNER_OS" == "macOS" ]; then + cp .github/test_conda_env_macOS.yml .github/test_conda_env.yml + fi - name: Setup conda uses: conda-incubator/setup-miniconda@v2 @@ -90,6 +43,7 @@ jobs: - name: run main test suite shell: bash -l {0} + continue-on-error: true run: | py.test -n 2 -m "not serial and not network and not superslow" --cov-report=xml - name: run slow tests @@ -112,6 +66,7 @@ jobs: yml: ./codecov.yml fail_ci_if_error: true + test-code-slow: runs-on: "ubuntu-latest" strategy: @@ -165,68 +120,6 @@ jobs: yml: ./codecov.yml fail_ci_if_error: true - test-code-windows: - runs-on: "windows-latest" - strategy: - matrix: - python-version: [3.7] - fail-fast: false - - steps: - - uses: actions/checkout@v2 - - - name: Setup conda - uses: conda-incubator/setup-miniconda@v2 - with: - miniconda-version: 'latest' - python-version: ${{ matrix.python-version }} - activate-environment: eqcorrscan-test - environment-file: .github/test_conda_env.yml - condarc-file: .github/test_condarc.yml - - - name: setup fftw - shell: bash -l {0} - run: | - export C_INCLUDE_PATH=${PREFIX}/include:${C_INCLUDE_PATH} # required as fftw3.h installed here - export LDFLAGS="${LDFLAGS} -L${PREFIX}/lib" - export STATIC_FFTW_DIR=$PREFIX/lib - - - name: install eqcorrscan - shell: bash -l {0} - run: | - pip install -e . - - - name: print package info - shell: bash -l {0} - run: | - conda info -a - conda list - - - name: run main test suite - shell: bash -l {0} - continue-on-error: true - run: | - py.test -n 2 -m "not serial and not network and not superslow" --cov-report=xml - - name: run slow tests - shell: bash -l {0} - run: | - py.test -v -m "slow and not serial and not network" --cov-report=xml --cov-append - - name: run serial test - shell: bash -l {0} - run: | - export OMP_NUM_THREADS=2 - py.test -m "serial and not network" --cov-report=xml --cov-append - - - name: upload coverage - uses: codecov/codecov-action@v1 - with: - token: ${{ secrets.CODECOV_TOKEN }} - file: ./coverage.xml - flags: unittests - name: codecov-umbrella - yml: ./codecov.yml - fail_ci_if_error: true - # This is a very useful step for debugging, it allows you to ssh into the CI # machine (https://github.com/marketplace/actions/debugging-with-tmate). # Make sure to open the log before the job starts else you cant see the tmate From 1252e0becca5581dedc0291944e7cb1d58a15afb Mon Sep 17 00:00:00 2001 From: Calum Chamberlain Date: Mon, 29 Mar 2021 15:40:04 +1300 Subject: [PATCH 075/132] Try caching for speedz --- .github/workflows/runtest.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/.github/workflows/runtest.yml b/.github/workflows/runtest.yml index 94314e064..e514abf35 100644 --- a/.github/workflows/runtest.yml +++ b/.github/workflows/runtest.yml @@ -21,6 +21,17 @@ jobs: cp .github/test_conda_env_macOS.yml .github/test_conda_env.yml fi + - name: Cache conda + uses: actions/cache@v2 + env: + # Increase this value to reset cache if needed by env file has not changed + CACHE_NUMBER: 0 + with: + path: ~/conda_pkgs_dir + key: + ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-${{ + hashFiles('.github/test_conda_env.yml') }} + - name: Setup conda uses: conda-incubator/setup-miniconda@v2 with: @@ -29,6 +40,7 @@ jobs: activate-environment: eqcorrscan-test environment-file: .github/test_conda_env.yml condarc-file: .github/test_condarc.yml + use-only-tar-bz2: true # Must be set for caching to work properly - name: install eqcorrscan shell: bash -l {0} @@ -77,6 +89,17 @@ jobs: steps: - uses: actions/checkout@v2 + - name: Cache conda + uses: actions/cache@v2 + env: + # Increase this value to reset cache if needed by env file has not changed + CACHE_NUMBER: 0 + with: + path: ~/conda_pkgs_dir + key: + ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-${{ + hashFiles('.github/test_conda_env.yml') }} + - name: Setup conda uses: conda-incubator/setup-miniconda@v2 with: @@ -85,6 +108,7 @@ jobs: activate-environment: eqcorrscan-test environment-file: .github/test_conda_env.yml condarc-file: .github/test_condarc.yml + use-only-tar-bz2: true # Must be set for caching to work properly - name: install eqcorrscan shell: bash -l {0} From 51208480d733d2014bfa794e00a13517b37c49a0 Mon Sep 17 00:00:00 2001 From: Calum Chamberlain Date: Mon, 29 Mar 2021 15:57:30 +1300 Subject: [PATCH 076/132] Fail on error --- .github/workflows/runtest.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/runtest.yml b/.github/workflows/runtest.yml index e514abf35..f22f74ba7 100644 --- a/.github/workflows/runtest.yml +++ b/.github/workflows/runtest.yml @@ -55,7 +55,6 @@ jobs: - name: run main test suite shell: bash -l {0} - continue-on-error: true run: | py.test -n 2 -m "not serial and not network and not superslow" --cov-report=xml - name: run slow tests From e5f63bb6d1a19a84d7056da21a91305a1531ea17 Mon Sep 17 00:00:00 2001 From: Calum Chamberlain Date: Mon, 29 Mar 2021 16:11:35 +1300 Subject: [PATCH 077/132] Remove unused badges --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 879afc9c1..9021d6310 100644 --- a/README.md +++ b/README.md @@ -81,10 +81,8 @@ Note that tests for travis and appveyor are run daily on master as cron jobs, an | Service tests | Badge | |---------------|-------| -| MacOS & Linux | ![test](https://github.com/eqcorrscan/EQcorrscan/workflows/test/badge.svg) -| Windows | [![Build status](https://ci.appveyor.com/api/projects/status/6pp6jdop14hj4e63/branch/master?svg=true)](https://ci.appveyor.com/project/EQcorrscan/eqcorrscan/branch/master) +| CI checks | ![test](https://github.com/eqcorrscan/EQcorrscan/workflows/test/badge.svg) | Code coverage | [![codecov](https://codecov.io/gh/eqcorrscan/EQcorrscan/branch/master/graph/badge.svg)](https://codecov.io/gh/eqcorrscan/EQcorrscan) -| Network tests | [![CircleCI](https://circleci.com/gh/eqcorrscan/EQcorrscan/tree/master.svg?style=svg)](https://circleci.com/gh/eqcorrscan/EQcorrscan/tree/master) # Licence From 66e32848025166034a2374d6f3e39602b6a150e1 Mon Sep 17 00:00:00 2001 From: Calum Chamberlain Date: Mon, 29 Mar 2021 17:02:57 +1300 Subject: [PATCH 078/132] Allow some slop in correlation precision in lag-calc test. --- eqcorrscan/tests/lag_calc_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eqcorrscan/tests/lag_calc_test.py b/eqcorrscan/tests/lag_calc_test.py index 7b25aeccc..45f0772d2 100644 --- a/eqcorrscan/tests/lag_calc_test.py +++ b/eqcorrscan/tests/lag_calc_test.py @@ -213,12 +213,12 @@ def test_correlation_max_and_position(self): detect_stream[0].stats.endtime) if d_start <= t_start and d_end >= t_end: for ccc_chan in _ccc: - self.assertEqual(ccc_chan.max(), 1.0) + self.assertEqual(round(ccc_chan.max(), 5), 1.0) self.assertEqual(ccc_chan.argmax(), samp_rate * (t_start - d_start)) else: for ccc_chan in _ccc: - self.assertNotEqual(ccc_chan.max(), 1.0) + self.assertNotEqual(round(ccc_chan.max(), 5), 1.0) def test_correlation_precision(self): """Compare to correlation function outputs""" From 5e4a5f0892887bdee174edc757943720dd0d8e32 Mon Sep 17 00:00:00 2001 From: Calum Chamberlain Date: Mon, 29 Mar 2021 17:04:15 +1300 Subject: [PATCH 079/132] Try to debug network test This works fine locally. Same detections every-time. --- eqcorrscan/tests/match_filter_test.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/eqcorrscan/tests/match_filter_test.py b/eqcorrscan/tests/match_filter_test.py index d61dcac4d..abe081aaf 100644 --- a/eqcorrscan/tests/match_filter_test.py +++ b/eqcorrscan/tests/match_filter_test.py @@ -401,7 +401,7 @@ def test_normxcorr(self): pads = [0 for _ in range(len(template_array))] ccc_numpy, no_chans = numpy_normxcorr(template_array, stream, pads) ccc, no_chans = fftw_normxcorr(template_array, stream, pads) - self.assertTrue(np.allclose(ccc, ccc_numpy, atol=0.03)) + self.assertTrue(np.allclose(ccc, ccc_numpy, atol=0.04)) def test_catalog_extraction(self): detections, det_cat, detection_streams = \ @@ -441,6 +441,9 @@ def test_same_detections_individual_and_parallel(self): detection_dict = {'template_name': detection.template_name, 'time': detection.detect_time, 'cccsum': detection.detect_val.round(6)} + if detection_dict not in individual_dict: + print(f"Detection:\n{detection_dict}\nnot found in:" + f"\n{individual_dict}") self.assertTrue(detection_dict in individual_dict) def test_read_write_detections(self): From a27aac3ec7201cc19774ec1b7947c4a5332307b7 Mon Sep 17 00:00:00 2001 From: Calum Chamberlain Date: Mon, 29 Mar 2021 17:14:43 +1300 Subject: [PATCH 080/132] Round to lower precision. --- eqcorrscan/tests/match_filter_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eqcorrscan/tests/match_filter_test.py b/eqcorrscan/tests/match_filter_test.py index abe081aaf..1326e3d75 100644 --- a/eqcorrscan/tests/match_filter_test.py +++ b/eqcorrscan/tests/match_filter_test.py @@ -430,7 +430,7 @@ def test_same_detections_individual_and_parallel(self): for detection in individual_detections: individual_dict.append({'template_name': detection.template_name, 'time': detection.detect_time, - 'cccsum': detection.detect_val.round(6)}) + 'cccsum': detection.detect_val.round(4)}) detections = match_filter(template_names=self.template_names, template_list=self.templates, st=self.st, threshold=8.0, threshold_type='MAD', @@ -440,7 +440,7 @@ def test_same_detections_individual_and_parallel(self): for detection in detections: detection_dict = {'template_name': detection.template_name, 'time': detection.detect_time, - 'cccsum': detection.detect_val.round(6)} + 'cccsum': detection.detect_val.round(4)} if detection_dict not in individual_dict: print(f"Detection:\n{detection_dict}\nnot found in:" f"\n{individual_dict}") From f23e702c0920d172f36e04074af6d191f3e879ba Mon Sep 17 00:00:00 2001 From: Calum Chamberlain Date: Mon, 29 Mar 2021 17:59:54 +1300 Subject: [PATCH 081/132] Update matched_filter.py --- eqcorrscan/core/match_filter/matched_filter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eqcorrscan/core/match_filter/matched_filter.py b/eqcorrscan/core/match_filter/matched_filter.py index 910ccf986..9343d9d06 100644 --- a/eqcorrscan/core/match_filter/matched_filter.py +++ b/eqcorrscan/core/match_filter/matched_filter.py @@ -662,7 +662,7 @@ def match_filter(template_names, template_list, st, threshold, Logger.info("Copying data to keep your input safe") stream = st.copy() templates = [t.copy() for t in template_list] - _template_names = template_names.copy() # This can just be a shallow copy + _template_names = template_names.copy() # This can be a shallow copy else: stream, templates, _template_names = st, template_list, template_names From e6badb72af9f1ddd5f217acd075b79a9bd67ddb6 Mon Sep 17 00:00:00 2001 From: flixha Date: Mon, 29 Mar 2021 14:53:38 +0200 Subject: [PATCH 082/132] resolve order for filtering and NaN-trace replacement for template and stream --- eqcorrscan/utils/pre_processing.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/eqcorrscan/utils/pre_processing.py b/eqcorrscan/utils/pre_processing.py index c381fd0d1..241560309 100644 --- a/eqcorrscan/utils/pre_processing.py +++ b/eqcorrscan/utils/pre_processing.py @@ -850,17 +850,25 @@ def _prep_data_for_correlation(stream, templates, template_names=None, if len(trace_ids.intersection(stream_ids)) == 0: filt[i] = 0 + _out = dict(zip( + [_tn for _tn, _filt in zip(template_names, filt) if _filt], + [_t for _t, _filt in zip(templates, filt) if _filt])) + flt_templates = list(_out.values()) + + if len(_out) != len(templates): + Logger.debug("Some templates not used due to no matching channels") + # Ensure that the templates' earliest traces are kept, even if there is no # continuous data for them. If this happens, we need to add a NaN-stream to # the continuous data to avoid inconsistent detection times. - n_template_traces = np.array([len(temp) for temp in templates]) + n_template_traces = np.array([len(temp) for temp in flt_templates]) n_stream_traces = sum([n+1 for s, n in seed_ids]) # These checks are not necessary if all templates will get NaN-traces, # because the NaN-traces will save the right starttime for the template. nan_stream_ids = list() if any(n_template_traces > n_stream_traces): - earliest_templ_trace_ids = list(set( - [template.sort(['starttime'])[0].id for template in templates])) + earliest_templ_trace_ids = set( + [template.sort(['starttime'])[0].id for template in flt_templates]) for earliest_templ_trace_id in earliest_templ_trace_ids: if earliest_templ_trace_id not in template_ids: nan_stream_ids.append(earliest_templ_trace_id) @@ -879,13 +887,6 @@ def _prep_data_for_correlation(stream, templates, template_names=None, 'npts': stream_length, 'sampling_rate': samp_rate})) seed_ids.append((earliest_templ_trace_id, 0)) - _out = dict(zip( - [_tn for _tn, _filt in zip(template_names, filt) if _filt], - [_t for _t, _filt in zip(templates, filt) if _filt])) - - if len(_out) != len(templates): - Logger.debug("Some templates not used due to no matching channels") - incomplete_templates = { template_name for template_name, template in _out.items() if sorted([tr.id for tr in template]) != [tr.id for tr in nan_template]} From 0c415bb298b83aaa4216fab45d58639f700e3942 Mon Sep 17 00:00:00 2001 From: flixha Date: Mon, 29 Mar 2021 15:33:08 +0200 Subject: [PATCH 083/132] fix pep8 and family-IO test --- eqcorrscan/tests/match_filter_test.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/eqcorrscan/tests/match_filter_test.py b/eqcorrscan/tests/match_filter_test.py index 5a9790e42..30b36d08d 100644 --- a/eqcorrscan/tests/match_filter_test.py +++ b/eqcorrscan/tests/match_filter_test.py @@ -697,11 +697,11 @@ def test_tribe_detect(self): compare_families( party=party, party_in=self.party, float_tol=0.05, check_event=True) - + def test_tribe_detect_with_empty_streams(self): """ Compare the detect method for a tribe of one vs two templates and check - that the detection has the same detect time, in a case where the + that the detection has the same detect time, in a case where the continuous data is incomplete. This test should fail in v0.4.2 due to a bug. """ @@ -709,18 +709,18 @@ def test_tribe_detect_with_empty_streams(self): st = self.unproc_st.copy().remove( self.unproc_st.copy().select(station='PHA')[0]) tribe1 = Tribe([t.copy() for t in self.tribe - if (t.name=='2004_09_28t17_19_08' or - t.name=='2004_09_28t17_19_25')]) + if (t.name == '2004_09_28t17_19_08' or + t.name == '2004_09_28t17_19_25')]) # run detection with 2 templates in tribe party1 = tribe1.detect( stream=st, threshold=8.0, threshold_type='MAD', trig_int=6.0, daylong=False, plotvar=False, parallel_process=False) self.assertEqual(len(party1), 2) party1 = Party([f for f in party1 - if f.template.name=='2004_09_28t17_19_25']) + if f.template.name == '2004_09_28t17_19_25']) # run detection with only 1 template in tribe tribe2 = Tribe([t.copy() for t in self.tribe - if t.name=='2004_09_28t17_19_25']) + if t.name == '2004_09_28t17_19_25']) party2 = tribe2.detect( stream=st, threshold=8.0, threshold_type='MAD', trig_int=6.0, daylong=False, plotvar=False, parallel_process=False) @@ -1409,7 +1409,7 @@ def test_family_io(self): """Test the write method of family.""" family = self.family.copy() try: - family.write('test_family') + family.write('test_family', overwrite=True) party_back = read_party('test_family.tgz') self.assertEqual(len(party_back), 1) self.assertEqual(party_back[0], family) From 5c2f661577efd22ae94d3750eaf54107e30ca7a0 Mon Sep 17 00:00:00 2001 From: flixha Date: Mon, 29 Mar 2021 16:16:02 +0200 Subject: [PATCH 084/132] add overwrite-option of party.write to family.write --- eqcorrscan/core/match_filter/family.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/eqcorrscan/core/match_filter/family.py b/eqcorrscan/core/match_filter/family.py index e997f011c..48bf8bbe0 100644 --- a/eqcorrscan/core/match_filter/family.py +++ b/eqcorrscan/core/match_filter/family.py @@ -456,7 +456,7 @@ def plot(self, plot_grouped=False): cumulative_detections( detections=self.detections, plot_grouped=plot_grouped) - def write(self, filename, format='tar'): + def write(self, filename, format='tar', overwrite=False): """ Write Family out, select output format. @@ -466,6 +466,10 @@ def write(self, filename, format='tar'): catalog output. :type filename: str :param filename: Path to write file to. + :type overwrite: bool + :param overwrite: + Specifies whether detection-files are overwritten if they exist + already. By default, no files are overwritten. .. Note:: csv format will write out detection objects, all other outputs will write the catalog. These cannot be rebuilt into @@ -497,7 +501,8 @@ def write(self, filename, format='tar'): """ from eqcorrscan.core.match_filter.party import Party - Party(families=[self]).write(filename=filename, format=format) + Party(families=[self]).write(filename=filename, format=format, + overwrite=overwrite) return def lag_calc(self, stream, pre_processed, shift_len=0.2, min_cc=0.4, From b32a582d4842549835a6006463e44c0c1bbcf4e2 Mon Sep 17 00:00:00 2001 From: flixha Date: Mon, 29 Mar 2021 16:28:11 +0200 Subject: [PATCH 085/132] fix pep8 --- eqcorrscan/core/match_filter/party.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eqcorrscan/core/match_filter/party.py b/eqcorrscan/core/match_filter/party.py index 318df69f1..8eff414e9 100644 --- a/eqcorrscan/core/match_filter/party.py +++ b/eqcorrscan/core/match_filter/party.py @@ -507,7 +507,7 @@ def decluster(self, trig_int, timing='detect', metric='avg_cor', :param metric: What metric to sort peaks by. Either 'avg_cor' which takes the single station average correlation, 'cor_sum' which takes the total correlation sum across all channels, or - 'thresh_exc' which takes the factor by how much the detection + 'thresh_exc' which takes the factor by how much the detection exceeded the input threshold. :type timing: str :param timing: From c6d25a87ecf7e2fa74ddcde208a34f498bac1fef Mon Sep 17 00:00:00 2001 From: Calum Chamberlain Date: Wed, 31 Mar 2021 16:15:19 +1300 Subject: [PATCH 086/132] Enforce channel order for distance matrix calculation --- eqcorrscan/utils/clustering.py | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/eqcorrscan/utils/clustering.py b/eqcorrscan/utils/clustering.py index 8b591331a..83a057951 100644 --- a/eqcorrscan/utils/clustering.py +++ b/eqcorrscan/utils/clustering.py @@ -27,7 +27,8 @@ def cross_chan_correlation(st1, streams, shift_len=0.0, xcorr_func='fftw', - concurrency="concurrent", cores=1, **kwargs): + concurrency="concurrent", cores=1, + channel_order=None, **kwargs): """ Calculate cross-channel correlation. @@ -49,6 +50,12 @@ def cross_chan_correlation(st1, streams, shift_len=0.0, xcorr_func='fftw', :param concurrency: Concurrency for xcorr-func. :type cores: int :param cores: Number of threads to parallel over + :type channel_order: list of str + :param channel_order: + Ordered list of seed-ids to enforce order of correlations. See PR #439. + To ensure correlations are the same independent of what stream st1 is, + order must be enforced - this is due to small (10^-5) errors introduced + with weak correlations in the 2D FFT used for correlations. :returns: cross channel correlation, float - normalized by number of channels. @@ -78,17 +85,31 @@ def cross_chan_correlation(st1, streams, shift_len=0.0, xcorr_func='fftw', st1, streams, stream_indexes = _prep_data_for_correlation( stream=st1, templates=streams, template_names=list(range(len(streams))), force_stream_epoch=False) + # Enforce order of channels + if channel_order: + _st1 = Stream() + _streams = [Stream() for _ in streams] + for channel_id in channel_order: + if len(st1.select(id=channel_id)): + continue + _st1 += st1.select(id=channel_id) + for st, _st in zip(streams, _streams): + _st += st.select(id=channel_id) # Run the correlations multichannel_normxcorr = get_stream_xcorr(xcorr_func, concurrency) [cccsums, no_chans, _] = multichannel_normxcorr( templates=streams, stream=st1, cores=cores, stack=False, **kwargs) # Find maximas, sum and divide by no_chans - coherances = cccsums.max(axis=-1).sum(axis=-1) / no_chans + coherances = cccsums.max(axis=-1).astype( + np.float64).sum(axis=-1) / no_chans positions = cccsums.argmax(axis=-1) # positions should probably have half the length of the correlogram # subtracted, and possibly be converted to seconds? + + # This section re-orders the coherences to correspond to the order of the + # input streams _coherances = np.empty(n_streams) - _positions = np.empty((n_streams, no_chans.max())) + _positions = np.empty_like(positions) _coherances.fill(np.nan) _positions.fill(np.nan) for coh_ind, stream_ind in enumerate(stream_indexes): @@ -129,6 +150,9 @@ def distance_matrix(stream_list, shift_len=0.0, cores=1): # Initialize square matrix dist_mat = np.array([np.array([0.0] * len(stream_list))] * len(stream_list)) + # Set up channel order to enforce internally to ensure the same 2D + # matrix is used for correlation. + channel_order = sorted(list({tr.id for st in stream_list for tr in st})) for i, master in enumerate(stream_list): dist_list, _ = cross_chan_correlation( st1=master.copy(), streams=stream_list, From 5f1bc112afe93cd246cb7d5936eb6b0b1dc22093 Mon Sep 17 00:00:00 2001 From: Calum Chamberlain Date: Wed, 31 Mar 2021 16:16:52 +1300 Subject: [PATCH 087/132] Stickler and use order --- eqcorrscan/utils/clustering.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/eqcorrscan/utils/clustering.py b/eqcorrscan/utils/clustering.py index 83a057951..b4e193fd5 100644 --- a/eqcorrscan/utils/clustering.py +++ b/eqcorrscan/utils/clustering.py @@ -105,7 +105,7 @@ def cross_chan_correlation(st1, streams, shift_len=0.0, xcorr_func='fftw', positions = cccsums.argmax(axis=-1) # positions should probably have half the length of the correlogram # subtracted, and possibly be converted to seconds? - + # This section re-orders the coherences to correspond to the order of the # input streams _coherances = np.empty(n_streams) @@ -156,7 +156,8 @@ def distance_matrix(stream_list, shift_len=0.0, cores=1): for i, master in enumerate(stream_list): dist_list, _ = cross_chan_correlation( st1=master.copy(), streams=stream_list, - shift_len=shift_len, xcorr_func='fftw', cores=cores) + shift_len=shift_len, xcorr_func='fftw', cores=cores, + channel_order=channel_order) dist_mat[i] = 1 - dist_list assert np.allclose(dist_mat, dist_mat.T, atol=0.00001) # Force perfect symmetry From ff07b61e591d0f0c35bd6d6fe83a7220e0ff3df3 Mon Sep 17 00:00:00 2001 From: Calum Chamberlain Date: Thu, 1 Apr 2021 09:50:27 +1300 Subject: [PATCH 088/132] Copy data before giving it to `_prep_data_for_correlation` --- eqcorrscan/utils/clustering.py | 36 +++++++++------------------------- 1 file changed, 9 insertions(+), 27 deletions(-) diff --git a/eqcorrscan/utils/clustering.py b/eqcorrscan/utils/clustering.py index b4e193fd5..e648ddb69 100644 --- a/eqcorrscan/utils/clustering.py +++ b/eqcorrscan/utils/clustering.py @@ -27,8 +27,7 @@ def cross_chan_correlation(st1, streams, shift_len=0.0, xcorr_func='fftw', - concurrency="concurrent", cores=1, - channel_order=None, **kwargs): + concurrency="concurrent", cores=1, **kwargs): """ Calculate cross-channel correlation. @@ -50,12 +49,6 @@ def cross_chan_correlation(st1, streams, shift_len=0.0, xcorr_func='fftw', :param concurrency: Concurrency for xcorr-func. :type cores: int :param cores: Number of threads to parallel over - :type channel_order: list of str - :param channel_order: - Ordered list of seed-ids to enforce order of correlations. See PR #439. - To ensure correlations are the same independent of what stream st1 is, - order must be enforced - this is due to small (10^-5) errors introduced - with weak correlations in the 2D FFT used for correlations. :returns: cross channel correlation, float - normalized by number of channels. @@ -81,27 +74,20 @@ def cross_chan_correlation(st1, streams, shift_len=0.0, xcorr_func='fftw', raise NotImplementedError("Sampling rates differ") _streams.append(_stream) streams = _streams + else: + # _prep_data_for_correlation works in place on data. + # We need to copy it first. + streams = [stream.copy() for stream in streams] # Check which channels are in st1 and match those in the stream_list st1, streams, stream_indexes = _prep_data_for_correlation( - stream=st1, templates=streams, + stream=st1.copy(), templates=streams, template_names=list(range(len(streams))), force_stream_epoch=False) - # Enforce order of channels - if channel_order: - _st1 = Stream() - _streams = [Stream() for _ in streams] - for channel_id in channel_order: - if len(st1.select(id=channel_id)): - continue - _st1 += st1.select(id=channel_id) - for st, _st in zip(streams, _streams): - _st += st.select(id=channel_id) # Run the correlations multichannel_normxcorr = get_stream_xcorr(xcorr_func, concurrency) [cccsums, no_chans, _] = multichannel_normxcorr( templates=streams, stream=st1, cores=cores, stack=False, **kwargs) # Find maximas, sum and divide by no_chans - coherances = cccsums.max(axis=-1).astype( - np.float64).sum(axis=-1) / no_chans + coherances = cccsums.max(axis=-1).sum(axis=-1) / no_chans positions = cccsums.argmax(axis=-1) # positions should probably have half the length of the correlogram # subtracted, and possibly be converted to seconds? @@ -150,14 +136,10 @@ def distance_matrix(stream_list, shift_len=0.0, cores=1): # Initialize square matrix dist_mat = np.array([np.array([0.0] * len(stream_list))] * len(stream_list)) - # Set up channel order to enforce internally to ensure the same 2D - # matrix is used for correlation. - channel_order = sorted(list({tr.id for st in stream_list for tr in st})) for i, master in enumerate(stream_list): dist_list, _ = cross_chan_correlation( - st1=master.copy(), streams=stream_list, - shift_len=shift_len, xcorr_func='fftw', cores=cores, - channel_order=channel_order) + st1=master, streams=stream_list, + shift_len=shift_len, xcorr_func='fftw', cores=cores) dist_mat[i] = 1 - dist_list assert np.allclose(dist_mat, dist_mat.T, atol=0.00001) # Force perfect symmetry From ac07f097a82ac0e37bf0385884cfb50e30f29e12 Mon Sep 17 00:00:00 2001 From: Calum Chamberlain Date: Thu, 1 Apr 2021 12:14:03 +1300 Subject: [PATCH 089/132] Check for negative values The test for abs_value use should ensure that it actually makes a difference! --- eqcorrscan/tests/match_filter_test.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/eqcorrscan/tests/match_filter_test.py b/eqcorrscan/tests/match_filter_test.py index 4f201da5b..aaeb2aec5 100644 --- a/eqcorrscan/tests/match_filter_test.py +++ b/eqcorrscan/tests/match_filter_test.py @@ -1248,10 +1248,15 @@ def test_party_rethreshold(self): self.assertEqual(d.threshold_input, 9.0) self.assertGreaterEqual(d.detect_val, d.threshold) party2 = party.copy().rethreshold(new_threshold=9, abs_values=True) + negative_count = 0 for family in party2: for d in family: self.assertEqual(d.threshold_input, 9.0) self.assertGreaterEqual(abs(d.detect_val), d.threshold) + if d.detect_val < 0: + negative_count += 1 + # Check that there actually are some negative detections... + self.assertGreater(negative_count, 0) def test_family_init(self): """Test generating a family with various things.""" From e655d1df3784f40d66198fcf559f975078269ba9 Mon Sep 17 00:00:00 2001 From: Calum Chamberlain Date: Thu, 1 Apr 2021 12:19:19 +1300 Subject: [PATCH 090/132] Make sure there are some negative detections --- eqcorrscan/tests/match_filter_test.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/eqcorrscan/tests/match_filter_test.py b/eqcorrscan/tests/match_filter_test.py index aaeb2aec5..b0c039efb 100644 --- a/eqcorrscan/tests/match_filter_test.py +++ b/eqcorrscan/tests/match_filter_test.py @@ -1238,10 +1238,17 @@ def test_party_rethreshold(self): for i in range(200): det = party[0][0].copy() det.detect_time += i * 20 + # Include some negative detections! + fudge = np.random.randint(-1, 2) + if fudge == 0: + fudge += 1 det.detect_val = det.threshold + (i * 1e-1) + det.detect_val *= fudge det.id = str(i) party[0].detections.append(det) self.assertEqual(len(party), 204) + negative_count = len([d for f in party for d in f if d.detect_val < 0]) + self.assertGreater(negative_count, 0) party1 = party.copy().rethreshold(new_threshold=9) for family in party1: for d in family: From 202c62c2260d343b3ef43af2a94aea29c643e883 Mon Sep 17 00:00:00 2001 From: Calum Chamberlain Date: Sun, 4 Apr 2021 15:42:04 +1200 Subject: [PATCH 091/132] Add internal check for P and S pick types --- eqcorrscan/utils/catalog_to_dd.py | 71 +++++++++++++++++++++---------- 1 file changed, 49 insertions(+), 22 deletions(-) diff --git a/eqcorrscan/utils/catalog_to_dd.py b/eqcorrscan/utils/catalog_to_dd.py index ae7717f6e..09ed45bdf 100644 --- a/eqcorrscan/utils/catalog_to_dd.py +++ b/eqcorrscan/utils/catalog_to_dd.py @@ -170,7 +170,7 @@ def _prepare_stream(stream, event, extract_len, pre_pick, seed_pick_ids=None): """ seed_pick_ids = seed_pick_ids or { SeedPickID(pick.waveform_id.get_seed_string(), pick.phase_hint[0]) - for pick in event.picks} + for pick in event.picks if pick.phase_hint.startswith(("P", "S"))} stream_sliced = defaultdict(lambda: Stream()) for seed_pick_id in seed_pick_ids: pick = [pick for pick in event.picks @@ -186,6 +186,14 @@ def _prepare_stream(stream, event, extract_len, pre_pick, seed_pick_ids=None): elif len(pick) == 0: continue pick = pick[0] + tr = stream.select(id=seed_pick_id.seed_id).merge() + if len(tr) == 0: + continue + else: + tr = tr[0] + Logger.debug(f"Trimming trace on {tr.id} between {tr.stats.starttime} - " + f"{tr.stats.endtime} to {pick.time - pre_pick} - " + f"{(pick.time - pre_pick) + extract_len}") tr = stream.select(id=seed_pick_id.seed_id).slice( starttime=pick.time - pre_pick, endtime=(pick.time - pre_pick) + extract_len).merge() @@ -195,9 +203,13 @@ def _prepare_stream(stream, event, extract_len, pre_pick, seed_pick_ids=None): Logger.error("Multiple traces for {seed_id}".format( seed_id=seed_pick_id.seed_id)) continue + tr = tr[0] + if tr.stats.endtime - tr.stats.starttime != extract_len: + Logger.warning(f"Insufficient data for {tr.id}, discarding") + continue stream_sliced.update( {seed_pick_id.phase_hint: - stream_sliced[seed_pick_id.phase_hint] + tr[0]}) + stream_sliced[seed_pick_id.phase_hint] + tr}) return stream_sliced @@ -215,13 +227,13 @@ def _compute_dt_correlations(catalog, master, min_link, event_id_mapper, stream=stream_dict[master.resource_id.id], event=master, extract_len=extract_len, pre_pick=pre_pick) available_seed_ids = {tr.id for st in master_stream.values() for tr in st} - Logger.info(f"The channels provided are: {available_seed_ids}") + Logger.debug(f"The channels provided are: {available_seed_ids}") master_seed_ids = { SeedPickID(pick.waveform_id.get_seed_string(), pick.phase_hint[0]) for pick in master.picks if pick.phase_hint[0] in "PS" and pick.waveform_id.get_seed_string() in available_seed_ids} - Logger.info(f"Using channels: {master_seed_ids}") + Logger.debug(f"Using channels: {master_seed_ids}") # Dictionary of travel-times for master keyed by {station}_{phase_hint} master_tts = dict() master_origin_time = (master.preferred_origin() or master.origins[0]).time @@ -237,7 +249,14 @@ def _compute_dt_correlations(catalog, master, min_link, event_id_mapper, matched_pre_pick = pre_pick + shift_len # We will use this to maintain order event_dict = {event.resource_id.id: event for event in catalog} - event_ids = list(event_dict.keys()) + event_ids = set(event_dict.keys()) + # Check for overlap + _stream_event_ids = set(stream_dict.keys()) + if len(event_ids.difference(_stream_event_ids)): + Logger.warning( + f"Missing streams for {event_ids.difference(_stream_event_ids)}") + # Just use the event ids that we actually have streams for! + event_ids = event_ids.intersection(_stream_event_ids) matched_streams = { event_id: _prepare_stream( stream=stream_dict[event_id], event=event_dict[event_id], @@ -252,6 +271,8 @@ def _compute_dt_correlations(catalog, master, min_link, event_id_mapper, delta = 1.0 / sampling_rate _master_stream = master_stream[phase_hint].select( sampling_rate=sampling_rate) + if len(_master_stream) == 0: + continue _matched_streams = dict() for key, value in matched_streams.items(): _st = value[phase_hint].select(sampling_rate=sampling_rate) @@ -268,15 +289,17 @@ def _compute_dt_correlations(catalog, master, min_link, event_id_mapper, "are providing sufficient data") master_length = Counter(master_length).most_common(1)[0][0] _master_stream = _master_stream.select(npts=master_length) - - matched_length = [ - tr.stats.npts for st in _matched_streams.values() - for tr in st] - if len(set(matched_length)) > 1: - Logger.warning( - "Multiple lengths found in matched data - check that you " - "are providing sufficient data") - matched_length = Counter(matched_length).most_common(1)[0][0] + matched_length = Counter( + (tr.stats.npts for st in _matched_streams.values() + for tr in st)) + if len(matched_length) > 1: + Logger.warning("Multiple lengths of stream found - taking " + "the most common. Check that you are " + "providing sufficient data") + matched_length = matched_length.most_common(1)[0][0] + if matched_length < master_length: + Logger.error("Matched streams are shorter than the master, will not correlate") + continue # Remove empty streams and generate an ordered list of event_ids used_event_ids, used_matched_streams = [], [] for event_id, _matched_stream in _matched_streams.items(): @@ -294,6 +317,7 @@ def _compute_dt_correlations(catalog, master, min_link, event_id_mapper, f"master: {master_seed_ids}, matched: {matched_seed_ids}") continue # Do the correlations + Logger.debug(f"Correlating channels: {[tr.id for tr in _master_stream]}") ccc_out, used_chans = _concatenate_and_correlate( template=_master_stream, streams=used_matched_streams, cores=max_workers) @@ -451,15 +475,18 @@ def compute_differential_times(catalog, correlation, stream_dict=None, additional_args = dict(min_link=min_link, event_id_mapper=event_id_mapper) if correlation: - sub_catalogs = ([ev for i, ev in enumerate(catalog) - if master_filter[i]] - for master_filter in distance_filter) + differential_times = {} additional_args.update(correlation_kwargs) - differential_times = { - master.resource_id.id: - _compute_dt_correlations( - sub_catalog, master, **additional_args) - for sub_catalog, master in zip(sub_catalogs, catalog)} + n = len(catalog) + for i, master in enumerate(catalog): + sub_catalog = [ev for j, ev in enumerate(catalog) + if distance_filter[i][j]] + differential_times.update({ + master.resource_id.id: + _compute_dt_correlations( + sub_catalog, master, **additional_args)}) + Logger.info( + f"Completed correlations for core event {i} of {n}") else: # Reformat catalog to sparse catalog sparse_catalog = [_make_sparse_event(ev) for ev in catalog] From 2fa76e1ee5b7124bf23c3c9c2850af2413b9ca03 Mon Sep 17 00:00:00 2001 From: calum-chamberlain Date: Mon, 5 Apr 2021 07:49:43 +1200 Subject: [PATCH 092/132] Stickler --- eqcorrscan/utils/catalog_to_dd.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/eqcorrscan/utils/catalog_to_dd.py b/eqcorrscan/utils/catalog_to_dd.py index 09ed45bdf..ae45ea1c3 100644 --- a/eqcorrscan/utils/catalog_to_dd.py +++ b/eqcorrscan/utils/catalog_to_dd.py @@ -191,9 +191,10 @@ def _prepare_stream(stream, event, extract_len, pre_pick, seed_pick_ids=None): continue else: tr = tr[0] - Logger.debug(f"Trimming trace on {tr.id} between {tr.stats.starttime} - " - f"{tr.stats.endtime} to {pick.time - pre_pick} - " - f"{(pick.time - pre_pick) + extract_len}") + Logger.debug( + f"Trimming trace on {tr.id} between {tr.stats.starttime} - " + f"{tr.stats.endtime} to {pick.time - pre_pick} - " + f"{(pick.time - pre_pick) + extract_len}") tr = stream.select(id=seed_pick_id.seed_id).slice( starttime=pick.time - pre_pick, endtime=(pick.time - pre_pick) + extract_len).merge() @@ -298,7 +299,8 @@ def _compute_dt_correlations(catalog, master, min_link, event_id_mapper, "providing sufficient data") matched_length = matched_length.most_common(1)[0][0] if matched_length < master_length: - Logger.error("Matched streams are shorter than the master, will not correlate") + Logger.error("Matched streams are shorter than the master, " + "will not correlate") continue # Remove empty streams and generate an ordered list of event_ids used_event_ids, used_matched_streams = [], [] @@ -317,7 +319,8 @@ def _compute_dt_correlations(catalog, master, min_link, event_id_mapper, f"master: {master_seed_ids}, matched: {matched_seed_ids}") continue # Do the correlations - Logger.debug(f"Correlating channels: {[tr.id for tr in _master_stream]}") + Logger.debug( + f"Correlating channels: {[tr.id for tr in _master_stream]}") ccc_out, used_chans = _concatenate_and_correlate( template=_master_stream, streams=used_matched_streams, cores=max_workers) @@ -381,7 +384,8 @@ def _make_event_pair(sparse_event, master, event_id_mapper, min_link): event_id_1=event_id_mapper[master.resource_id], event_id_2=event_id_mapper[sparse_event.resource_id]) for master_pick in master.picks: - if master_pick.phase and master_pick.phase not in "PS": # pragma: no cover + if master_pick.phase and \ + master_pick.phase not in "PS": # pragma: no cover continue matched_picks = [p for p in sparse_event.picks if p.station == master_pick.station @@ -479,7 +483,7 @@ def compute_differential_times(catalog, correlation, stream_dict=None, additional_args.update(correlation_kwargs) n = len(catalog) for i, master in enumerate(catalog): - sub_catalog = [ev for j, ev in enumerate(catalog) + sub_catalog = [ev for j, ev in enumerate(catalog) if distance_filter[i][j]] differential_times.update({ master.resource_id.id: From c7d15688d2f4992ea259b5c39857a3e3e07b52ef Mon Sep 17 00:00:00 2001 From: calum-chamberlain Date: Mon, 5 Apr 2021 07:53:34 +1200 Subject: [PATCH 093/132] Add changelog, clean changelog from previous merges --- CHANGES.md | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 2a784a522..a0f583280 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,10 +5,10 @@ - match_filter: - Provide option of exporting the cross-correlation sums for additional later analysis. -* Added the ability of saving correlation data of the lag_calc. -* lag_calc: +* core.lag_calc: - Added option to set minimum CC threshold individually for detections based on: min(detect_val / n_chans * min_cc_from_mean_cc_factor, min_cc). + - Added the ability to save correlation data from lag_calc. * party.rethreshold: - added option to rethreshold based on absolute values to keep relevant detections with large negative detect_val. @@ -22,13 +22,21 @@ when a filename without '.tgz'-suffix was supplied, then the file was overwritten against the function's intention. - Add option `overwrite=True` to allow overwriting of existing files. -* utils/archive_read.py +* utils.archive_read - Add support for wildcard-comparisons in the list of requested stations and channels. - New option `arctype='SDS'` to read from a SeisComp Data Structure (SDS). This option is also available in `utils.clustering.extract_detections` and in `utils.archive_read._check_available_data`. -* Added the ability of saving correlation data of the lag_calc. +* utils.catalog_to_dd + - Bug-fixes in #424: + - only P and S phases are used now (previously spurious amplitude picks + were included in correlations); + - Checks for length are done prior to correlations and more helpful error + outputs are provided. + - Progress is not reported within dt.cc computation + - `write_station` now supports writing elevations: #424. + ## 0.4.2 * Add seed-ids to the _spike_test's message. From 02d3e1c7fb710d24592b430449c1a10cf7ff353b Mon Sep 17 00:00:00 2001 From: calum-chamberlain Date: Mon, 5 Apr 2021 07:58:17 +1200 Subject: [PATCH 094/132] Add skeleton tests - these should fail at the moment. --- eqcorrscan/tests/catalog_to_dd_test.py | 36 ++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/eqcorrscan/tests/catalog_to_dd_test.py b/eqcorrscan/tests/catalog_to_dd_test.py index 098305e03..0ffa4c509 100644 --- a/eqcorrscan/tests/catalog_to_dd_test.py +++ b/eqcorrscan/tests/catalog_to_dd_test.py @@ -43,6 +43,26 @@ def test_event_pair(self): '# 12 54 0.0\nFOZ 1.982 0.8733 P\n' 'GCSZ -1.237 1.0000 S') + def test_event_pair_spurious_phases(self): + """ Make sure that only P and S phases are included. """ + event_pair = _EventPair(event_id_1=12, event_id_2=54) + event_pair.obs = [ + _DTObs(station="FOZ", tt1=3.268, tt2=1.2857650, + weight=0.873265, phase="P"), + _DTObs(station="GCSZ", tt1=0.263, tt2=1.50, + weight=1.0, phase="S"), + _DTObs(station="GCSZ", tt1=0.263, tt2=1.50, + weight=1.0, phase="IAML"), + ] + self.assertEqual( + event_pair.ct_string, + '# 12 54\nFOZ 3.268 1.286 0.8733 P\n' + 'GCSZ 0.263 1.500 1.0000 S') + self.assertEqual( + event_pair.cc_string, + '# 12 54 0.0\nFOZ 1.982 0.8733 P\n' + 'GCSZ -1.237 1.0000 S') + class TestCatalogMethods(unittest.TestCase): @classmethod @@ -212,6 +232,10 @@ def test_compute_correlation_times(self): abs(obs.tt2 - cat_obs.tt2), shift_len) self.assertLessEqual(obs.weight, 1.0) + def test_compute_correlations_strange_lengths(self): + """ Check that streams with too short data are unused. PR #424 """ + self.assertEqual(True, False) # To write! + def test_write_catalog(self): # Contents checked elsewhere write_catalog(catalog=self.catalog, event_id_mapper=None, @@ -270,6 +294,18 @@ def test_write_station(self): station = f.read() self.assertEqual(station, original_station) + def test_write_station_elevations(self): + """ Include elevations in station.dat: PR #424. """ + write_station(self.inventory, use_elevation=True) + test_data_path = os.path.join( + os.path.abspath(os.path.dirname(__file__)), 'test_data') + # To do: create this file and test with ph2dt! + with open(os.path.join(test_data_path, "station_elev.dat"), "r") as f: + original_station = f.read() + with open("station.dat") as f: + station = f.read() + self.assertEqual(station, original_station) + def test_write_event(self): # Contents checked below write_event(self.catalog) From 1f6e25a786a0e60c411f5c433d17c8ca9fe7bc34 Mon Sep 17 00:00:00 2001 From: Calum Chamberlain Date: Mon, 5 Apr 2021 21:38:54 +1200 Subject: [PATCH 095/132] Skip masters without streams --- eqcorrscan/utils/catalog_to_dd.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/eqcorrscan/utils/catalog_to_dd.py b/eqcorrscan/utils/catalog_to_dd.py index 09ed45bdf..aab862fd0 100644 --- a/eqcorrscan/utils/catalog_to_dd.py +++ b/eqcorrscan/utils/catalog_to_dd.py @@ -481,6 +481,10 @@ def compute_differential_times(catalog, correlation, stream_dict=None, for i, master in enumerate(catalog): sub_catalog = [ev for j, ev in enumerate(catalog) if distance_filter[i][j]] + if master.resource_id.id not in additional_args["stream_dict"].keys(): + Logger.warning( + f"{master.resource_id.id} not in waveforms, skipping") + continue differential_times.update({ master.resource_id.id: _compute_dt_correlations( From 435a5492f4254f8008b94bd0a574b02916411bde Mon Sep 17 00:00:00 2001 From: flixha Date: Mon, 12 Apr 2021 10:50:37 +0200 Subject: [PATCH 096/132] fix distance-matrix for shift_len > 0, return shift-matrix in seconds --- eqcorrscan/utils/clustering.py | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/eqcorrscan/utils/clustering.py b/eqcorrscan/utils/clustering.py index e648ddb69..bc196587d 100644 --- a/eqcorrscan/utils/clustering.py +++ b/eqcorrscan/utils/clustering.py @@ -39,7 +39,9 @@ def cross_chan_correlation(st1, streams, shift_len=0.0, xcorr_func='fftw', :type streams: list :param streams: Streams to compare to. :type shift_len: float - :param shift_len: Seconds to shift, only used if `allow_shift=True` + :param shift_len: + Seconds to shift the streams by (total value for negative and positive + direction together) :type xcorr_func: str, callable :param xcorr_func: The method for performing correlations. Accepts either a string or @@ -88,14 +90,13 @@ def cross_chan_correlation(st1, streams, shift_len=0.0, xcorr_func='fftw', templates=streams, stream=st1, cores=cores, stack=False, **kwargs) # Find maximas, sum and divide by no_chans coherances = cccsums.max(axis=-1).sum(axis=-1) / no_chans - positions = cccsums.argmax(axis=-1) - # positions should probably have half the length of the correlogram - # subtracted, and possibly be converted to seconds? + # Subtract half length of correlogram and convert positions to seconds + positions = (cccsums.argmax(axis=-1) - end_trim) / df # This section re-orders the coherences to correspond to the order of the # input streams _coherances = np.empty(n_streams) - _positions = np.empty_like(positions) + _positions = np.empty_like(_coherances) _coherances.fill(np.nan) _positions.fill(np.nan) for coh_ind, stream_ind in enumerate(stream_indexes): @@ -136,16 +137,28 @@ def distance_matrix(stream_list, shift_len=0.0, cores=1): # Initialize square matrix dist_mat = np.array([np.array([0.0] * len(stream_list))] * len(stream_list)) + shift_mat = np.zeros_like(dist_mat) for i, master in enumerate(stream_list): - dist_list, _ = cross_chan_correlation( + dist_list, shift_list = cross_chan_correlation( st1=master, streams=stream_list, shift_len=shift_len, xcorr_func='fftw', cores=cores) dist_mat[i] = 1 - dist_list - assert np.allclose(dist_mat, dist_mat.T, atol=0.00001) - # Force perfect symmetry - dist_mat = (dist_mat + dist_mat.T) / 2 + shift_mat[i] = shift_list + if shift_len == 0: + assert np.allclose(dist_mat, dist_mat.T, atol=0.00001) + # Force perfect symmetry + dist_mat = (dist_mat + dist_mat.T) / 2 + else: + # get the shortest distance for each correlation pair + dist_mat_shortest = np.minimum(dist_mat, dist_mat.T) + # Get index for which matrix has shortest dist: value 0: mat2; 1: mat1 + dist_mat_index = dist_mat_shortest == dist_mat + # Get shift for the shortest distances + shift_mat =\ + shift_mat * dist_mat_index + shift_mat.T * (1 - dist_mat_index) + dist_mat = dist_mat_shortest np.fill_diagonal(dist_mat, 0) - return dist_mat + return dist_mat, shift_mat def cluster(template_list, show=True, corr_thresh=0.3, From 9b6cfb26074238e751b16ed14be2835e32111099 Mon Sep 17 00:00:00 2001 From: flixha Date: Mon, 12 Apr 2021 18:17:11 +0200 Subject: [PATCH 097/132] define shift-matrices when individual traces can shift wihtin template streams --- eqcorrscan/utils/clustering.py | 77 ++++++++++++++++++++++++++-------- 1 file changed, 60 insertions(+), 17 deletions(-) diff --git a/eqcorrscan/utils/clustering.py b/eqcorrscan/utils/clustering.py index bc196587d..43c7a1b0a 100644 --- a/eqcorrscan/utils/clustering.py +++ b/eqcorrscan/utils/clustering.py @@ -26,8 +26,9 @@ Logger = logging.getLogger(__name__) -def cross_chan_correlation(st1, streams, shift_len=0.0, xcorr_func='fftw', - concurrency="concurrent", cores=1, **kwargs): +def cross_chan_correlation( + st1, streams, shift_len=0.0, allow_individual_trace_shifts=True, + xcorr_func='fftw', concurrency="concurrent", cores=1, **kwargs): """ Calculate cross-channel correlation. @@ -42,6 +43,11 @@ def cross_chan_correlation(st1, streams, shift_len=0.0, xcorr_func='fftw', :param shift_len: Seconds to shift the streams by (total value for negative and positive direction together) + :type allow_individual_trace_shifts: bool + :param allow_individual_trace_shifts: + Controls whether templates are shifted by shift_len in relation to the + picks as a whole, or whether each trace can be shifted individually. + Defaults to True. :type xcorr_func: str, callable :param xcorr_func: The method for performing correlations. Accepts either a string or @@ -63,6 +69,8 @@ def cross_chan_correlation(st1, streams, shift_len=0.0, xcorr_func='fftw', """ # Cut all channels in stream-list to be the correct length (shorter than # st1 if stack = False by shift_len). + allow_individual_trace_shifts =\ + allow_individual_trace_shifts and shift_len > 0 n_streams = len(streams) df = st1[0].stats.sampling_rate end_trim = int((shift_len * df) / 2) @@ -81,31 +89,44 @@ def cross_chan_correlation(st1, streams, shift_len=0.0, xcorr_func='fftw', # We need to copy it first. streams = [stream.copy() for stream in streams] # Check which channels are in st1 and match those in the stream_list - st1, streams, stream_indexes = _prep_data_for_correlation( + st1, prep_streams, stream_indexes = _prep_data_for_correlation( stream=st1.copy(), templates=streams, template_names=list(range(len(streams))), force_stream_epoch=False) # Run the correlations multichannel_normxcorr = get_stream_xcorr(xcorr_func, concurrency) [cccsums, no_chans, _] = multichannel_normxcorr( - templates=streams, stream=st1, cores=cores, stack=False, **kwargs) + templates=prep_streams, stream=st1, cores=cores, stack=False, **kwargs) # Find maximas, sum and divide by no_chans - coherances = cccsums.max(axis=-1).sum(axis=-1) / no_chans + if allow_individual_trace_shifts: + coherances = cccsums.max(axis=-1).sum(axis=-1) / no_chans + else: + cccsums = cccsums.sum(axis=1) + coherances = cccsums.max(axis=-1) / no_chans # Subtract half length of correlogram and convert positions to seconds positions = (cccsums.argmax(axis=-1) - end_trim) / df # This section re-orders the coherences to correspond to the order of the # input streams _coherances = np.empty(n_streams) - _positions = np.empty_like(_coherances) + if allow_individual_trace_shifts: + n_max_traces = max([len(st) for st in streams]) + n_shifts_per_stream = positions.shape[1] + _positions = np.empty([positions.shape[0], n_max_traces]) + else: + # _positions = np.empty_like(positions) + _positions = np.empty([positions.shape[0], 1]) + n_shifts_per_stream = 1 + _coherances.fill(np.nan) _positions.fill(np.nan) for coh_ind, stream_ind in enumerate(stream_indexes): _coherances[stream_ind] = coherances[coh_ind] - _positions[stream_ind] = positions[coh_ind] - return _coherances, _positions + _positions[stream_ind, :n_shifts_per_stream] = positions[coh_ind] + return _coherances, _positions.squeeze() -def distance_matrix(stream_list, shift_len=0.0, cores=1): +def distance_matrix(stream_list, shift_len=0.0, + allow_individual_trace_shifts=True, cores=1): """ Compute distance matrix for waveforms based on cross-correlations. @@ -120,6 +141,11 @@ def distance_matrix(stream_list, shift_len=0.0, cores=1): matrix for :type shift_len: float :param shift_len: How many seconds for templates to shift + :type allow_individual_trace_shifts: bool + :param allow_individual_trace_shifts: + Controls whether templates are shifted by shift_len in relation to the + picks as a whole, or whether each trace can be shifted individually. + Defaults to True. :type cores: int :param cores: Number of cores to parallel process using, defaults to 1. @@ -134,28 +160,45 @@ def distance_matrix(stream_list, shift_len=0.0, cores=1): .. note:: Requires all traces to have the same sampling rate and same length. """ + allow_individual_trace_shifts =\ + allow_individual_trace_shifts and shift_len > 0 # Initialize square matrix dist_mat = np.array([np.array([0.0] * len(stream_list))] * len(stream_list)) shift_mat = np.zeros_like(dist_mat) + shift_mat = np.zeros([len(stream_list), + len(stream_list), + max([len(st) for st in stream_list])]) + n_shifts_per_stream = 1 for i, master in enumerate(stream_list): dist_list, shift_list = cross_chan_correlation( - st1=master, streams=stream_list, - shift_len=shift_len, xcorr_func='fftw', cores=cores) + st1=master, streams=stream_list, shift_len=shift_len, + allow_individual_trace_shifts=allow_individual_trace_shifts, + xcorr_func='fftw', cores=cores) dist_mat[i] = 1 - dist_list - shift_mat[i] = shift_list + if allow_individual_trace_shifts: + n_shifts_per_stream = shift_list.shape[1] + shift_mat[i, 0:, 0:n_shifts_per_stream] = shift_list + axes = [1, 0, 2] + else: + shift_mat[i, 0:, 0:n_shifts_per_stream] = shift_list[:, np.newaxis] + axes = [1, 0] if shift_len == 0: assert np.allclose(dist_mat, dist_mat.T, atol=0.00001) # Force perfect symmetry dist_mat = (dist_mat + dist_mat.T) / 2 + shift_mat = shift_mat[:, :, 0:n_shifts_per_stream].squeeze() else: # get the shortest distance for each correlation pair dist_mat_shortest = np.minimum(dist_mat, dist_mat.T) - # Get index for which matrix has shortest dist: value 0: mat2; 1: mat1 - dist_mat_index = dist_mat_shortest == dist_mat + # Indicator says which matrix has shortest dist: value 0: mat2; 1: mat1 + mat_indicator = dist_mat_shortest == dist_mat + mat_indicator = np.repeat(mat_indicator[:, :, np.newaxis], + n_shifts_per_stream, axis=2).squeeze() # Get shift for the shortest distances - shift_mat =\ - shift_mat * dist_mat_index + shift_mat.T * (1 - dist_mat_index) + shift_mat = shift_mat[:, :, 0:n_shifts_per_stream].squeeze() + shift_mat = shift_mat * mat_indicator +\ + np.transpose(shift_mat, axes) * (1 - mat_indicator) dist_mat = dist_mat_shortest np.fill_diagonal(dist_mat, 0) return dist_mat, shift_mat @@ -208,7 +251,7 @@ def cluster(template_list, show=True, corr_thresh=0.3, stream_list = [x[0] for x in template_list] # Compute the distance matrix Logger.info('Computing the distance matrix using %i cores' % num_cores) - dist_mat = distance_matrix( + dist_mat, __ = distance_matrix( stream_list=stream_list, shift_len=shift_len, cores=num_cores) if save_corrmat: np.save('dist_mat.npy', dist_mat) From a2155cea9014c6e2082c4f0620573f3eab6c1958 Mon Sep 17 00:00:00 2001 From: flixha Date: Mon, 12 Apr 2021 18:18:00 +0200 Subject: [PATCH 098/132] add tests for clustering with shift_len, for full templates and individual traces --- eqcorrscan/tests/clustering_test.py | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/eqcorrscan/tests/clustering_test.py b/eqcorrscan/tests/clustering_test.py index 3e8bef99e..305bb38ed 100644 --- a/eqcorrscan/tests/clustering_test.py +++ b/eqcorrscan/tests/clustering_test.py @@ -84,10 +84,32 @@ def test_distance_matrix(self): for st in stream_list: for tr in st: tr.data = tr.data[0:shortest_tr] - dist_mat = distance_matrix(stream_list=stream_list, cores=4) + # Test with zero shift-length + dist_mat, shift_mat = distance_matrix(stream_list=stream_list, cores=4) self.assertEqual(dist_mat.shape[0], len(stream_list)) self.assertEqual(dist_mat.shape[1], len(stream_list)) + # Test with some shift-length, but only shift templates as a whole + dist_mat, shift_mat = distance_matrix( + stream_list=stream_list, cores=4, shift_len=0.2, + allow_individual_trace_shifts=False) + self.assertEqual(dist_mat.shape[0], len(stream_list)) + self.assertEqual(dist_mat.shape[1], len(stream_list)) + self.assertEqual(np.array(dist_mat == dist_mat.T).all(), True) + self.assertEqual(shift_mat.shape[0], len(stream_list)) + self.assertEqual(shift_mat.shape[1], len(stream_list)) + self.assertEqual(np.array(shift_mat == shift_mat.T).all(), True) + + # Test with shift_len that individual traces are allowed to shift by + dist_mat, shift_mat = distance_matrix( + stream_list=stream_list, cores=4, shift_len=0.2, + allow_individual_trace_shifts=True) + self.assertEqual(dist_mat.shape[0], len(stream_list)) + self.assertEqual(dist_mat.shape[1], len(stream_list)) + self.assertEqual(np.array(dist_mat == dist_mat.T).all(), True) + self.assertEqual(len(shift_mat.shape), 3) + np.testing.assert_equal(shift_mat, np.transpose(shift_mat, [1, 0, 2])) + def test_unclustered(self): """Test clustering on unclustered data...""" testing_path = os.path.join(self.testing_path, 'WAV', 'TEST_') From c2a03d470b28dd3576fa4c01aa8d381b968f41d8 Mon Sep 17 00:00:00 2001 From: flixha Date: Mon, 12 Apr 2021 18:22:25 +0200 Subject: [PATCH 099/132] pep8 --- eqcorrscan/utils/clustering.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eqcorrscan/utils/clustering.py b/eqcorrscan/utils/clustering.py index 43c7a1b0a..d33ce83c8 100644 --- a/eqcorrscan/utils/clustering.py +++ b/eqcorrscan/utils/clustering.py @@ -251,7 +251,7 @@ def cluster(template_list, show=True, corr_thresh=0.3, stream_list = [x[0] for x in template_list] # Compute the distance matrix Logger.info('Computing the distance matrix using %i cores' % num_cores) - dist_mat, __ = distance_matrix( + dist_mat, _ = distance_matrix( stream_list=stream_list, shift_len=shift_len, cores=num_cores) if save_corrmat: np.save('dist_mat.npy', dist_mat) From 4a4570f52f66065211fbd39c3f51aa802afb1975 Mon Sep 17 00:00:00 2001 From: flixha Date: Mon, 12 Apr 2021 19:14:01 +0200 Subject: [PATCH 100/132] fix distance_matrix for single-trace templates --- eqcorrscan/utils/clustering.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/eqcorrscan/utils/clustering.py b/eqcorrscan/utils/clustering.py index d33ce83c8..05276a1ae 100644 --- a/eqcorrscan/utils/clustering.py +++ b/eqcorrscan/utils/clustering.py @@ -122,7 +122,9 @@ def cross_chan_correlation( for coh_ind, stream_ind in enumerate(stream_indexes): _coherances[stream_ind] = coherances[coh_ind] _positions[stream_ind, :n_shifts_per_stream] = positions[coh_ind] - return _coherances, _positions.squeeze() + if not allow_individual_trace_shifts: # remove empty third axis from array + _positions = _positions[:, ] + return _coherances, _positions def distance_matrix(stream_list, shift_len=0.0, @@ -179,10 +181,8 @@ def distance_matrix(stream_list, shift_len=0.0, if allow_individual_trace_shifts: n_shifts_per_stream = shift_list.shape[1] shift_mat[i, 0:, 0:n_shifts_per_stream] = shift_list - axes = [1, 0, 2] else: - shift_mat[i, 0:, 0:n_shifts_per_stream] = shift_list[:, np.newaxis] - axes = [1, 0] + shift_mat[i, 0:, 0:n_shifts_per_stream] = shift_list if shift_len == 0: assert np.allclose(dist_mat, dist_mat.T, atol=0.00001) # Force perfect symmetry @@ -194,14 +194,14 @@ def distance_matrix(stream_list, shift_len=0.0, # Indicator says which matrix has shortest dist: value 0: mat2; 1: mat1 mat_indicator = dist_mat_shortest == dist_mat mat_indicator = np.repeat(mat_indicator[:, :, np.newaxis], - n_shifts_per_stream, axis=2).squeeze() + n_shifts_per_stream, axis=2)[:, :] # Get shift for the shortest distances - shift_mat = shift_mat[:, :, 0:n_shifts_per_stream].squeeze() + shift_mat = shift_mat[:, :, 0:n_shifts_per_stream][:, :] shift_mat = shift_mat * mat_indicator +\ - np.transpose(shift_mat, axes) * (1 - mat_indicator) + np.transpose(shift_mat, [1, 0, 2]) * (1 - mat_indicator) dist_mat = dist_mat_shortest np.fill_diagonal(dist_mat, 0) - return dist_mat, shift_mat + return dist_mat, shift_mat.squeeze() def cluster(template_list, show=True, corr_thresh=0.3, From 2f6fa20fd0afe0e5f5a90e7c1ebeac9e4149161a Mon Sep 17 00:00:00 2001 From: Calum Chamberlain Date: Tue, 13 Apr 2021 20:42:46 +1200 Subject: [PATCH 101/132] Use brackets --- eqcorrscan/utils/clustering.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eqcorrscan/utils/clustering.py b/eqcorrscan/utils/clustering.py index 05276a1ae..2c43e2479 100644 --- a/eqcorrscan/utils/clustering.py +++ b/eqcorrscan/utils/clustering.py @@ -69,8 +69,8 @@ def cross_chan_correlation( """ # Cut all channels in stream-list to be the correct length (shorter than # st1 if stack = False by shift_len). - allow_individual_trace_shifts =\ - allow_individual_trace_shifts and shift_len > 0 + allow_individual_trace_shifts = ( + allow_individual_trace_shifts and shift_len > 0) n_streams = len(streams) df = st1[0].stats.sampling_rate end_trim = int((shift_len * df) / 2) From 1bef67525440af1936af7ff68c12d7edc6060fc1 Mon Sep 17 00:00:00 2001 From: Calum Chamberlain Date: Tue, 13 Apr 2021 20:43:05 +1200 Subject: [PATCH 102/132] Use brackets 2 --- eqcorrscan/utils/clustering.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eqcorrscan/utils/clustering.py b/eqcorrscan/utils/clustering.py index 2c43e2479..421b9ff0f 100644 --- a/eqcorrscan/utils/clustering.py +++ b/eqcorrscan/utils/clustering.py @@ -162,8 +162,8 @@ def distance_matrix(stream_list, shift_len=0.0, .. note:: Requires all traces to have the same sampling rate and same length. """ - allow_individual_trace_shifts =\ - allow_individual_trace_shifts and shift_len > 0 + allow_individual_trace_shifts = ( + allow_individual_trace_shifts and shift_len > 0) # Initialize square matrix dist_mat = np.array([np.array([0.0] * len(stream_list))] * len(stream_list)) From ea8d3f96f44073ddaab63f10386381e50dbbfd84 Mon Sep 17 00:00:00 2001 From: Calum Chamberlain Date: Tue, 13 Apr 2021 20:43:20 +1200 Subject: [PATCH 103/132] Use brackets 3 --- eqcorrscan/utils/clustering.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/eqcorrscan/utils/clustering.py b/eqcorrscan/utils/clustering.py index 421b9ff0f..b17b99872 100644 --- a/eqcorrscan/utils/clustering.py +++ b/eqcorrscan/utils/clustering.py @@ -197,8 +197,9 @@ def distance_matrix(stream_list, shift_len=0.0, n_shifts_per_stream, axis=2)[:, :] # Get shift for the shortest distances shift_mat = shift_mat[:, :, 0:n_shifts_per_stream][:, :] - shift_mat = shift_mat * mat_indicator +\ - np.transpose(shift_mat, [1, 0, 2]) * (1 - mat_indicator) + shift_mat = ( + shift_mat * mat_indicator + + np.transpose(shift_mat, [1, 0, 2]) * (1 - mat_indicator)) dist_mat = dist_mat_shortest np.fill_diagonal(dist_mat, 0) return dist_mat, shift_mat.squeeze() From 320512d9f7f24e56802d439b3ae89d2949a5ede6 Mon Sep 17 00:00:00 2001 From: Calum Chamberlain Date: Tue, 13 Apr 2021 09:08:56 +0000 Subject: [PATCH 104/132] Test wildcards and ensure they work! --- eqcorrscan/core/match_filter/party.py | 7 ++++--- eqcorrscan/tests/match_filter_test.py | 23 +++++++++++++++++------ 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/eqcorrscan/core/match_filter/party.py b/eqcorrscan/core/match_filter/party.py index ef0084a63..3afb8041b 100644 --- a/eqcorrscan/core/match_filter/party.py +++ b/eqcorrscan/core/match_filter/party.py @@ -766,8 +766,8 @@ def read(self, filename=None, read_detection_catalog=True, :param read_detection_catalog: Whether to read the detection catalog or not, if False, catalog will be regenerated - for large catalogs this can be faster. - :type estimate_origins: bool - :param estimate_origins: + :type estimate_origin: bool + :param estimate_origin: If True and no catalog is found, or read_detection_catalog is False then new events with origins estimated from the template origin time will be created. @@ -795,6 +795,7 @@ def read(self, filename=None, read_detection_catalog=True, # Expand wildcards filenames = glob.glob(filename) for _filename in filenames: + Logger.info(f"Reading from {_filename}") with tarfile.open(_filename, "r:*") as arc: temp_dir = tempfile.mkdtemp() arc.extractall(path=temp_dir, members=_safemembers(arc)) @@ -822,7 +823,7 @@ def read(self, filename=None, read_detection_catalog=True, f for f in families if f.template.name == family.template.name][0] new_family = False - family.detections = _read_family( + family.detections += _read_family( fname=family_file, all_cat=all_cat, template=template[0], estimate_origin=estimate_origin) if new_family: diff --git a/eqcorrscan/tests/match_filter_test.py b/eqcorrscan/tests/match_filter_test.py index b0c039efb..a8dc6aab9 100644 --- a/eqcorrscan/tests/match_filter_test.py +++ b/eqcorrscan/tests/match_filter_test.py @@ -1044,15 +1044,26 @@ def test_party_io_list(self): def test_party_io_wildcards(self): """Test reading and writing party objects.""" - if os.path.isfile('test_party_walrus.tgz'): - os.remove('test_party_walrus.tgz') + party_0 = self.party.copy() + for f in party_0: + for d in f: + detect_time = d.detect_time + 3600 + d.detect_time = detect_time + d.id = (''.join(d.template_name.split(' ')) + '_' + + detect_time.strftime('%Y%m%d_%H%M%S%f')) + + for f in ["0", "1"]: + if os.path.isfile(f'test_party_walrus_{f}.tgz'): + os.remove(f'test_party_walrus_{f}.tgz') try: - self.party.write(filename='test_party_walrus') + self.party.write(filename='test_party_walrus_0') + party_0.write(filename='test_party_walrus_1') party_back = read_party(fname='test_party_w*.tgz') - self.assertEqual(self.party, party_back) + self.assertEqual(self.party + party_0, party_back) finally: - if os.path.isfile('test_party_walrus.tgz'): - os.remove('test_party_walrus.tgz') + for f in ["0", "1"]: + if os.path.isfile(f'test_party_walrus_{f}.tgz'): + os.remove(f'test_party_walrus_{f}.tgz') def test_tribe_internal_methods(self): self.assertEqual(len(self.tribe), 4) From 0b300db115ff5e40de293f84cd0981572d9752bb Mon Sep 17 00:00:00 2001 From: Calum Chamberlain Date: Tue, 13 Apr 2021 09:14:31 +0000 Subject: [PATCH 105/132] add changes and clean log --- CHANGES.md | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 2a784a522..cfd00c2f9 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,35 +1,36 @@ ## Current -* utils.plotting - - Function added (twoD_seismplot) for plotting seismicity (#365). * core.match_filter - match_filter: - Provide option of exporting the cross-correlation sums for additional later analysis. -* Added the ability of saving correlation data of the lag_calc. -* lag_calc: - - Added option to set minimum CC threshold individually for detections based - on: min(detect_val / n_chans * min_cc_from_mean_cc_factor, min_cc). -* party.rethreshold: +* core.match_filter.party.write + - BUG-FIX: When `format='tar'` is selected, added a check for .tgz-file + suffix before checking the filename against an existing file. Previously, + when a filename without '.tgz'-suffix was supplied, then the file was + overwritten against the function's intention. + - Add option `overwrite=True` to allow overwriting of existing files. +* core.match_filter.party.read + - BUG-FIX: Ensure wildcard reading works as expected: #453 +* core.match_filter.party.rethreshold: - added option to rethreshold based on absolute values to keep relevant detections with large negative detect_val. +* core.lag_calc: + - Added option to set minimum CC threshold individually for detections based + on: min(detect_val / n_chans * min_cc_from_mean_cc_factor, min_cc). + - Added the ability of saving correlation data of the lag_calc. * utils.mag_calc.calc_b_value: - Added useful information to doc-string regarding method and meaning of residuals - Changed the number of magnitudes used to an int (from a string!?) -* core.party.write - - BUG-FIX: When `format='tar'` is selected, added a check for .tgz-file - suffix before checking the filename against an existing file. Previously, - when a filename without '.tgz'-suffix was supplied, then the file was - overwritten against the function's intention. - - Add option `overwrite=True` to allow overwriting of existing files. -* utils/archive_read.py +* utils.archive_read - Add support for wildcard-comparisons in the list of requested stations and channels. - New option `arctype='SDS'` to read from a SeisComp Data Structure (SDS). This option is also available in `utils.clustering.extract_detections` and in `utils.archive_read._check_available_data`. -* Added the ability of saving correlation data of the lag_calc. - +* utils.plotting + - Function added (twoD_seismplot) for plotting seismicity (#365). + ## 0.4.2 * Add seed-ids to the _spike_test's message. * utils.correlation From 6fa12dd6bef8efd21c23e970ab0f9122ad425d08 Mon Sep 17 00:00:00 2001 From: Calum Chamberlain Date: Tue, 13 Apr 2021 09:22:59 +0000 Subject: [PATCH 106/132] Cope with undefined time errors --- eqcorrscan/utils/catalog_to_dd.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eqcorrscan/utils/catalog_to_dd.py b/eqcorrscan/utils/catalog_to_dd.py index 18bc0767a..450421abd 100644 --- a/eqcorrscan/utils/catalog_to_dd.py +++ b/eqcorrscan/utils/catalog_to_dd.py @@ -692,7 +692,7 @@ def _hypodd_phase_str(event, event_id_mapper): Logger.warning("No magnitude") magnitude = 0.0 try: - time_error = origin.quality['standard_error'] + time_error = origin.quality['standard_error'] or 0.0 except (TypeError, AttributeError): Logger.warning('No time residual in header') time_error = 0.0 @@ -853,7 +853,7 @@ def _hypodd_event_str(event, event_id): Logger.warning("No magnitude") magnitude = 0.0 try: - time_error = origin.quality['standard_error'] + time_error = origin.quality['standard_error'] or 0.0 except (TypeError, AttributeError): Logger.warning('No time residual in header') time_error = 0.0 From 77f09c092aecc297b30caa9d78a04bf1252648ee Mon Sep 17 00:00:00 2001 From: Calum Chamberlain Date: Tue, 13 Apr 2021 09:43:48 +0000 Subject: [PATCH 107/132] Fix two failing tests --- eqcorrscan/tests/catalog_to_dd_test.py | 27 ++++++++++---------------- eqcorrscan/utils/catalog_to_dd.py | 2 -- 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/eqcorrscan/tests/catalog_to_dd_test.py b/eqcorrscan/tests/catalog_to_dd_test.py index 0ffa4c509..dd220cd95 100644 --- a/eqcorrscan/tests/catalog_to_dd_test.py +++ b/eqcorrscan/tests/catalog_to_dd_test.py @@ -46,22 +46,15 @@ def test_event_pair(self): def test_event_pair_spurious_phases(self): """ Make sure that only P and S phases are included. """ event_pair = _EventPair(event_id_1=12, event_id_2=54) - event_pair.obs = [ - _DTObs(station="FOZ", tt1=3.268, tt2=1.2857650, - weight=0.873265, phase="P"), - _DTObs(station="GCSZ", tt1=0.263, tt2=1.50, - weight=1.0, phase="S"), - _DTObs(station="GCSZ", tt1=0.263, tt2=1.50, - weight=1.0, phase="IAML"), - ] - self.assertEqual( - event_pair.ct_string, - '# 12 54\nFOZ 3.268 1.286 0.8733 P\n' - 'GCSZ 0.263 1.500 1.0000 S') - self.assertEqual( - event_pair.cc_string, - '# 12 54 0.0\nFOZ 1.982 0.8733 P\n' - 'GCSZ -1.237 1.0000 S') + with self.assertRaises(AssertionError): + event_pair.obs = [ + _DTObs(station="FOZ", tt1=3.268, tt2=1.2857650, + weight=0.873265, phase="P"), + _DTObs(station="GCSZ", tt1=0.263, tt2=1.50, + weight=1.0, phase="S"), + _DTObs(station="GCSZ", tt1=0.263, tt2=1.50, + weight=1.0, phase="IAML"), + ] class TestCatalogMethods(unittest.TestCase): @@ -102,7 +95,7 @@ def setUpClass(cls): picked_stations = set(picked_stations) inv_bulk = [(sta.network, sta.station, sta.location, "HH?", starttime, endtime) for sta in picked_stations] - inventory = client.get_stations_bulk(inv_bulk, level="station") + inventory = client.get_stations_bulk(inv_bulk, level="channel") cls.streams = streams cls.catalog = catalog diff --git a/eqcorrscan/utils/catalog_to_dd.py b/eqcorrscan/utils/catalog_to_dd.py index 450421abd..2d0862d81 100644 --- a/eqcorrscan/utils/catalog_to_dd.py +++ b/eqcorrscan/utils/catalog_to_dd.py @@ -8,11 +8,9 @@ GNU Lesser General Public License, Version 3 (https://www.gnu.org/copyleft/lesser.html) """ -import os import numpy as np import logging from collections import namedtuple, defaultdict, Counter -from concurrent.futures import ProcessPoolExecutor from functools import partial from multiprocessing import cpu_count, Pool From 04c730ba7fa8503bd255d12e0b7d0f001912729d Mon Sep 17 00:00:00 2001 From: flixha Date: Tue, 13 Apr 2021 19:39:53 +0200 Subject: [PATCH 108/132] split distance-matrix tests --- eqcorrscan/tests/clustering_test.py | 41 ++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/eqcorrscan/tests/clustering_test.py b/eqcorrscan/tests/clustering_test.py index 305bb38ed..fad3449b3 100644 --- a/eqcorrscan/tests/clustering_test.py +++ b/eqcorrscan/tests/clustering_test.py @@ -66,7 +66,7 @@ def test_known_coherence(self): cccoh, _ = cross_chan_correlation(st1=st1, streams=[st2]) self.assertTrue(cccoh[0] < 0.01) - def test_distance_matrix(self): + def test_distance_matrix_no_shift(self): """Test that we can create a useful distance matrix.""" testing_path = os.path.join(self.testing_path, 'WAV', 'TEST_') stream_files = glob.glob(os.path.join(testing_path, '*DFDPC*'))[0:10] @@ -84,12 +84,28 @@ def test_distance_matrix(self): for st in stream_list: for tr in st: tr.data = tr.data[0:shortest_tr] - # Test with zero shift-length dist_mat, shift_mat = distance_matrix(stream_list=stream_list, cores=4) self.assertEqual(dist_mat.shape[0], len(stream_list)) self.assertEqual(dist_mat.shape[1], len(stream_list)) - # Test with some shift-length, but only shift templates as a whole + def test_distance_matrix_with_shift(self): + """Test that we can create a useful distance matrix.""" + testing_path = os.path.join(self.testing_path, 'WAV', 'TEST_') + stream_files = glob.glob(os.path.join(testing_path, '*DFDPC*'))[0:10] + stream_list = [read(stream_file) for stream_file in stream_files] + for st in stream_list: + for tr in st: + if tr.stats.sampling_rate != 100.0: + ratio = tr.stats.sampling_rate / 100 + if int(ratio) == ratio: + tr.decimate(int(ratio)) + else: + tr.resample(100) + shortest_tr = min( + [tr.stats.npts for st in stream_list for tr in st]) + for st in stream_list: + for tr in st: + tr.data = tr.data[0:shortest_tr] dist_mat, shift_mat = distance_matrix( stream_list=stream_list, cores=4, shift_len=0.2, allow_individual_trace_shifts=False) @@ -100,7 +116,24 @@ def test_distance_matrix(self): self.assertEqual(shift_mat.shape[1], len(stream_list)) self.assertEqual(np.array(shift_mat == shift_mat.T).all(), True) - # Test with shift_len that individual traces are allowed to shift by + def test_distance_matrix_with_shifted_traces(self): + """Test that we can create a useful distance matrix.""" + testing_path = os.path.join(self.testing_path, 'WAV', 'TEST_') + stream_files = glob.glob(os.path.join(testing_path, '*DFDPC*'))[0:10] + stream_list = [read(stream_file) for stream_file in stream_files] + for st in stream_list: + for tr in st: + if tr.stats.sampling_rate != 100.0: + ratio = tr.stats.sampling_rate / 100 + if int(ratio) == ratio: + tr.decimate(int(ratio)) + else: + tr.resample(100) + shortest_tr = min( + [tr.stats.npts for st in stream_list for tr in st]) + for st in stream_list: + for tr in st: + tr.data = tr.data[0:shortest_tr] dist_mat, shift_mat = distance_matrix( stream_list=stream_list, cores=4, shift_len=0.2, allow_individual_trace_shifts=True) From 788f93b71b4ef670b37afbc4012757bd7235fa13 Mon Sep 17 00:00:00 2001 From: flixha Date: Tue, 13 Apr 2021 19:42:28 +0200 Subject: [PATCH 109/132] more vectorized numpy-indexing --- eqcorrscan/utils/clustering.py | 54 ++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 22 deletions(-) diff --git a/eqcorrscan/utils/clustering.py b/eqcorrscan/utils/clustering.py index b17b99872..56789a78e 100644 --- a/eqcorrscan/utils/clustering.py +++ b/eqcorrscan/utils/clustering.py @@ -40,9 +40,7 @@ def cross_chan_correlation( :type streams: list :param streams: Streams to compare to. :type shift_len: float - :param shift_len: - Seconds to shift the streams by (total value for negative and positive - direction together) + :param shift_len: How many seconds for templates to shift :type allow_individual_trace_shifts: bool :param allow_individual_trace_shifts: Controls whether templates are shifted by shift_len in relation to the @@ -89,13 +87,14 @@ def cross_chan_correlation( # We need to copy it first. streams = [stream.copy() for stream in streams] # Check which channels are in st1 and match those in the stream_list - st1, prep_streams, stream_indexes = _prep_data_for_correlation( + st1_preped, prep_streams, stream_indexes = _prep_data_for_correlation( stream=st1.copy(), templates=streams, template_names=list(range(len(streams))), force_stream_epoch=False) # Run the correlations multichannel_normxcorr = get_stream_xcorr(xcorr_func, concurrency) [cccsums, no_chans, _] = multichannel_normxcorr( - templates=prep_streams, stream=st1, cores=cores, stack=False, **kwargs) + templates=prep_streams, stream=st1_preped, cores=cores, stack=False, + **kwargs) # Find maximas, sum and divide by no_chans if allow_individual_trace_shifts: coherances = cccsums.max(axis=-1).sum(axis=-1) / no_chans @@ -110,18 +109,26 @@ def cross_chan_correlation( _coherances = np.empty(n_streams) if allow_individual_trace_shifts: n_max_traces = max([len(st) for st in streams]) - n_shifts_per_stream = positions.shape[1] - _positions = np.empty([positions.shape[0], n_max_traces]) + # _positions = np.empty([n_streams, n_max_traces]) else: # _positions = np.empty_like(positions) - _positions = np.empty([positions.shape[0], 1]) - n_shifts_per_stream = 1 + # _positions = np.empty([n_streams, 1]) + + positions = positions[:, np.newaxis] + n_max_traces = 1 + n_shifts_per_stream = positions.shape[1] + _positions = np.empty([n_streams, n_max_traces]) + # Insert the correlations and shifts at the correct index for the templates _coherances.fill(np.nan) _positions.fill(np.nan) + _coherances[np.ix_(stream_indexes)] = coherances + _positions[np.ix_(stream_indexes, range(n_shifts_per_stream))] = ( + positions) + for coh_ind, stream_ind in enumerate(stream_indexes): _coherances[stream_ind] = coherances[coh_ind] - _positions[stream_ind, :n_shifts_per_stream] = positions[coh_ind] + _positions[stream_ind, 0:n_shifts_per_stream] = positions[coh_ind] if not allow_individual_trace_shifts: # remove empty third axis from array _positions = _positions[:, ] return _coherances, _positions @@ -164,13 +171,12 @@ def distance_matrix(stream_list, shift_len=0.0, """ allow_individual_trace_shifts = ( allow_individual_trace_shifts and shift_len > 0) + n_streams = len(stream_list) + n_traces_max = max([len(st) for st in stream_list]) # Initialize square matrix - dist_mat = np.array([np.array([0.0] * len(stream_list))] * - len(stream_list)) - shift_mat = np.zeros_like(dist_mat) - shift_mat = np.zeros([len(stream_list), - len(stream_list), - max([len(st) for st in stream_list])]) + # dist_mat = np.array([np.array([0.0] * n_streams)] * n_streams) + dist_mat = np.zeros([n_streams, n_streams]) + shift_mat = np.zeros([n_streams, n_streams, n_traces_max]) n_shifts_per_stream = 1 for i, master in enumerate(stream_list): dist_list, shift_list = cross_chan_correlation( @@ -178,11 +184,15 @@ def distance_matrix(stream_list, shift_len=0.0, allow_individual_trace_shifts=allow_individual_trace_shifts, xcorr_func='fftw', cores=cores) dist_mat[i] = 1 - dist_list - if allow_individual_trace_shifts: - n_shifts_per_stream = shift_list.shape[1] - shift_mat[i, 0:, 0:n_shifts_per_stream] = shift_list - else: - shift_mat[i, 0:, 0:n_shifts_per_stream] = shift_list + shift_mat[i, :, :] = shift_list + #if allow_individual_trace_shifts: + # shift_mat[i, :, :] = shift_list + # n_correlations = shift_list.shape[0] + # n_shifts_per_stream = shift_list.shape[1] + # shift_mat[i, 0:n_correlations, 0:n_shifts_per_stream] = shift_list + #else: + # shift_mat[i, 0:, 0:n_shifts_per_stream] = shift_list + n_shifts_per_stream = shift_list.shape[1] if shift_len == 0: assert np.allclose(dist_mat, dist_mat.T, atol=0.00001) # Force perfect symmetry @@ -198,7 +208,7 @@ def distance_matrix(stream_list, shift_len=0.0, # Get shift for the shortest distances shift_mat = shift_mat[:, :, 0:n_shifts_per_stream][:, :] shift_mat = ( - shift_mat * mat_indicator + + shift_mat * mat_indicator + np.transpose(shift_mat, [1, 0, 2]) * (1 - mat_indicator)) dist_mat = dist_mat_shortest np.fill_diagonal(dist_mat, 0) From 55309205d0253410db490243ef1c549fdcce4b68 Mon Sep 17 00:00:00 2001 From: flixha Date: Tue, 13 Apr 2021 19:43:02 +0200 Subject: [PATCH 110/132] remove out-commented lines --- eqcorrscan/utils/clustering.py | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/eqcorrscan/utils/clustering.py b/eqcorrscan/utils/clustering.py index 56789a78e..ede036c8e 100644 --- a/eqcorrscan/utils/clustering.py +++ b/eqcorrscan/utils/clustering.py @@ -109,26 +109,19 @@ def cross_chan_correlation( _coherances = np.empty(n_streams) if allow_individual_trace_shifts: n_max_traces = max([len(st) for st in streams]) - # _positions = np.empty([n_streams, n_max_traces]) else: - # _positions = np.empty_like(positions) - # _positions = np.empty([n_streams, 1]) - positions = positions[:, np.newaxis] n_max_traces = 1 n_shifts_per_stream = positions.shape[1] _positions = np.empty([n_streams, n_max_traces]) - # Insert the correlations and shifts at the correct index for the templates _coherances.fill(np.nan) _positions.fill(np.nan) + # Insert the correlations and shifts at the correct index for the templates _coherances[np.ix_(stream_indexes)] = coherances _positions[np.ix_(stream_indexes, range(n_shifts_per_stream))] = ( positions) - for coh_ind, stream_ind in enumerate(stream_indexes): - _coherances[stream_ind] = coherances[coh_ind] - _positions[stream_ind, 0:n_shifts_per_stream] = positions[coh_ind] if not allow_individual_trace_shifts: # remove empty third axis from array _positions = _positions[:, ] return _coherances, _positions @@ -174,7 +167,6 @@ def distance_matrix(stream_list, shift_len=0.0, n_streams = len(stream_list) n_traces_max = max([len(st) for st in stream_list]) # Initialize square matrix - # dist_mat = np.array([np.array([0.0] * n_streams)] * n_streams) dist_mat = np.zeros([n_streams, n_streams]) shift_mat = np.zeros([n_streams, n_streams, n_traces_max]) n_shifts_per_stream = 1 @@ -185,13 +177,6 @@ def distance_matrix(stream_list, shift_len=0.0, xcorr_func='fftw', cores=cores) dist_mat[i] = 1 - dist_list shift_mat[i, :, :] = shift_list - #if allow_individual_trace_shifts: - # shift_mat[i, :, :] = shift_list - # n_correlations = shift_list.shape[0] - # n_shifts_per_stream = shift_list.shape[1] - # shift_mat[i, 0:n_correlations, 0:n_shifts_per_stream] = shift_list - #else: - # shift_mat[i, 0:, 0:n_shifts_per_stream] = shift_list n_shifts_per_stream = shift_list.shape[1] if shift_len == 0: assert np.allclose(dist_mat, dist_mat.T, atol=0.00001) From 2c9af7ee1303f236dbae432653dccb30e96cd1fc Mon Sep 17 00:00:00 2001 From: flixha Date: Tue, 13 Apr 2021 19:55:39 +0200 Subject: [PATCH 111/132] fix typo --- eqcorrscan/utils/clustering.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eqcorrscan/utils/clustering.py b/eqcorrscan/utils/clustering.py index ede036c8e..da16b4a53 100644 --- a/eqcorrscan/utils/clustering.py +++ b/eqcorrscan/utils/clustering.py @@ -1153,8 +1153,8 @@ def re_thresh_csv(path, old_thresh, new_thresh, chan_thresh): detections_in += 1 con1 = (new_thresh / old_thresh) * detection.threshold con2 = detection.no_chans >= chan_thresh - requirted_thresh = (new_thresh / old_thresh) * detection.threshold - con3 = abs(detection.detect_val) >= requirted_thresh + required_thresh = (new_thresh / old_thresh) * detection.threshold + con3 = abs(detection.detect_val) >= required_thresh if all([con1, con2, con3]): detections_out += 1 detections.append(detection) From 74740c6430dd2c5f661985054930c00bcbeb3d19 Mon Sep 17 00:00:00 2001 From: flixha Date: Tue, 13 Apr 2021 20:17:04 +0200 Subject: [PATCH 112/132] set shifts for nan-traces to nan --- eqcorrscan/utils/clustering.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/eqcorrscan/utils/clustering.py b/eqcorrscan/utils/clustering.py index da16b4a53..b3c24a1d0 100644 --- a/eqcorrscan/utils/clustering.py +++ b/eqcorrscan/utils/clustering.py @@ -109,6 +109,10 @@ def cross_chan_correlation( _coherances = np.empty(n_streams) if allow_individual_trace_shifts: n_max_traces = max([len(st) for st in streams]) + # Set shifts for nan-traces to nan + for i, tr in enumerate(st1_preped): + if np.ma.is_masked(tr.data): + positions[:, i] = np.nan else: positions = positions[:, np.newaxis] n_max_traces = 1 From 2f6d57bd24910d5da31ede8749d780520a6660ca Mon Sep 17 00:00:00 2001 From: calum-chamberlain Date: Sat, 17 Apr 2021 20:03:55 +1200 Subject: [PATCH 113/132] Station elevation fixing --- conftest.py | 1 + eqcorrscan/tests/catalog_to_dd_test.py | 5 +- eqcorrscan/tests/test_data/station.dat | 122 ++++++++++---------- eqcorrscan/tests/test_data/station_elev.dat | 61 ++++++++++ eqcorrscan/utils/catalog_to_dd.py | 46 +++++--- 5 files changed, 157 insertions(+), 78 deletions(-) create mode 100644 eqcorrscan/tests/test_data/station_elev.dat diff --git a/conftest.py b/conftest.py index e02bc1f1a..8e1af9f70 100644 --- a/conftest.py +++ b/conftest.py @@ -49,6 +49,7 @@ def clean_up_test_files(): 'test_waveforms.ms', 'mag_calc.out', 'station.dat', + 'station_elev.dat', 'test_waveform.ms', '01-0410-35L.S201309', '04-0007-55R.S201601', diff --git a/eqcorrscan/tests/catalog_to_dd_test.py b/eqcorrscan/tests/catalog_to_dd_test.py index dd220cd95..20213cb4c 100644 --- a/eqcorrscan/tests/catalog_to_dd_test.py +++ b/eqcorrscan/tests/catalog_to_dd_test.py @@ -289,13 +289,14 @@ def test_write_station(self): def test_write_station_elevations(self): """ Include elevations in station.dat: PR #424. """ - write_station(self.inventory, use_elevation=True) + write_station(self.inventory, use_elevation=True, + filename="station_elev.dat") test_data_path = os.path.join( os.path.abspath(os.path.dirname(__file__)), 'test_data') # To do: create this file and test with ph2dt! with open(os.path.join(test_data_path, "station_elev.dat"), "r") as f: original_station = f.read() - with open("station.dat") as f: + with open("station_elev.dat") as f: station = f.read() self.assertEqual(station, original_station) diff --git a/eqcorrscan/tests/test_data/station.dat b/eqcorrscan/tests/test_data/station.dat index 1cfb55c8c..b31708fdf 100644 --- a/eqcorrscan/tests/test_data/station.dat +++ b/eqcorrscan/tests/test_data/station.dat @@ -1,61 +1,61 @@ -APZ -46.832 167.989 -BFZ -40.680 176.246 -BHW -41.408 174.871 -BKZ -39.166 176.493 -COVZ -39.200 175.542 -CTZ -43.735 -176.617 -CVZ -44.383 171.006 -DCZ -45.465 167.154 -DSZ -41.745 171.805 -EAZ -45.231 169.308 -ETVZ -39.136 175.711 -FOZ -43.532 169.815 -FWVZ -39.255 175.553 -GRZ -36.250 175.458 -GVZ -42.967 173.035 -HAZ -37.756 177.783 -HIZ -38.513 174.856 -INZ -42.724 171.444 -JCZ -44.073 168.785 -KHEZ -39.294 174.014 -KHZ -42.416 173.539 -KNZ -39.022 177.674 -KUZ -36.745 175.721 -LBZ -44.386 170.184 -LTZ -42.782 172.271 -MAVZ -39.268 175.562 -MKAZ -37.104 175.161 -MLZ -45.367 168.118 -MQZ -43.706 172.654 -MRZ -40.661 175.579 -MSZ -44.673 167.926 -MWZ -38.334 177.528 -NNZ -41.217 173.379 -ODZ -45.044 170.645 -OPRZ -37.844 176.555 -OPZ -45.884 170.598 -OTVZ -39.163 175.665 -OUZ -35.220 173.596 -OXZ -43.326 172.038 -PXZ -40.031 176.862 -PYZ -46.166 166.681 -QRZ -40.826 172.529 -RATZ -38.866 175.772 -RPZ -43.715 171.054 -RTZ -38.615 176.981 -SYZ -46.537 169.139 -THZ -41.762 172.905 -TLZ -38.329 175.538 -TMVZ -39.116 175.704 -TOZ -37.731 175.502 -TRVZ -39.299 175.548 -TSZ -40.059 175.961 -TUZ -45.954 169.631 -VRZ -39.124 174.758 -WAZ -39.755 174.986 -WCZ -35.939 174.345 -WEL -41.284 174.768 -WHVZ -39.282 175.589 -WHZ -45.892 167.947 -WKZ -44.827 169.018 -WVZ -43.074 170.737 \ No newline at end of file +APZ -46.83181 167.98883 +BFZ -40.67965 176.24625 +BHW -41.40823 174.87111 +BKZ -39.16567 176.49254 +COVZ -39.19991 175.54240 +CTZ -43.73549 -176.61719 +CVZ -44.38318 171.00616 +DCZ -45.46471 167.15353 +DSZ -41.74496 171.80461 +EAZ -45.23105 169.30825 +ETVZ -39.13570 175.71060 +FOZ -43.53210 169.81548 +FWVZ -39.25495 175.55295 +GRZ -36.25020 175.45780 +GVZ -42.96737 173.03475 +HAZ -37.75610 177.78260 +HIZ -38.51293 174.85569 +INZ -42.72450 171.44410 +JCZ -44.07321 168.78547 +KHEZ -39.29420 174.01450 +KHZ -42.41598 173.53897 +KNZ -39.02176 177.67367 +KUZ -36.74523 175.72087 +LBZ -44.38555 170.18442 +LTZ -42.78167 172.27104 +MAVZ -39.26791 175.56165 +MKAZ -37.10413 175.16117 +MLZ -45.36654 168.11841 +MQZ -43.70608 172.65377 +MRZ -40.66055 175.57853 +MSZ -44.67333 167.92640 +MWZ -38.33400 177.52778 +NNZ -41.21710 173.37948 +ODZ -45.04398 170.64462 +OPRZ -37.84430 176.55493 +OPZ -45.88436 170.59777 +OTVZ -39.16311 175.66507 +OUZ -35.21969 173.59613 +OXZ -43.32590 172.03830 +PXZ -40.03064 176.86215 +PYZ -46.16625 166.68069 +QRZ -40.82552 172.52915 +RATZ -38.86650 175.77218 +RPZ -43.71461 171.05386 +RTZ -38.61544 176.98052 +SYZ -46.53689 169.13882 +THZ -41.76247 172.90522 +TLZ -38.32940 175.53800 +TMVZ -39.11561 175.70406 +TOZ -37.73096 175.50185 +TRVZ -39.29882 175.54782 +TSZ -40.05855 175.96112 +TUZ -45.95397 169.63114 +VRZ -39.12434 174.75845 +WAZ -39.75464 174.98553 +WCZ -35.93864 174.34504 +WEL -41.28405 174.76818 +WHVZ -39.28250 175.58860 +WHZ -45.89243 167.94703 +WKZ -44.82702 169.01756 +WVZ -43.07435 170.73675 \ No newline at end of file diff --git a/eqcorrscan/tests/test_data/station_elev.dat b/eqcorrscan/tests/test_data/station_elev.dat new file mode 100644 index 000000000..67b0229c2 --- /dev/null +++ b/eqcorrscan/tests/test_data/station_elev.dat @@ -0,0 +1,61 @@ +APZ -46.83181 167.98883 601 +BFZ -40.67965 176.24625 283 +BHW -41.40823 174.87111 100 +BKZ -39.16567 176.49254 706 +COVZ -39.19991 175.54240 1069 +CTZ -43.73549 -176.61719 99 +CVZ -44.38318 171.00616 454 +DCZ -45.46471 167.15353 71 +DSZ -41.74496 171.80461 650 +EAZ -45.23105 169.30825 350 +ETVZ -39.13570 175.71060 1236 +FOZ -43.53210 169.81548 54 +FWVZ -39.25495 175.55295 2043 +GRZ -36.25020 175.45780 146 +GVZ -42.96737 173.03475 400 +HAZ -37.75610 177.78260 81 +HIZ -38.51293 174.85569 237 +INZ -42.72450 171.44410 165 +JCZ -44.07321 168.78547 1062 +KHEZ -39.29420 174.01450 929 +KHZ -42.41598 173.53897 64 +KNZ -39.02176 177.67367 32 +KUZ -36.74523 175.72087 76 +LBZ -44.38555 170.18442 438 +LTZ -42.78167 172.27104 648 +MAVZ -39.26791 175.56165 2574 +MKAZ -37.10413 175.16117 140 +MLZ -45.36654 168.11841 594 +MQZ -43.70608 172.65377 57 +MRZ -40.66055 175.57853 286 +MSZ -44.67333 167.92640 55 +MWZ -38.33400 177.52778 573 +NNZ -41.21710 173.37948 130 +ODZ -45.04398 170.64462 274 +OPRZ -37.84430 176.55493 134 +OPZ -45.88436 170.59777 375 +OTVZ -39.16311 175.66507 1506 +OUZ -35.21969 173.59613 63 +OXZ -43.32590 172.03830 359 +PXZ -40.03064 176.86215 103 +PYZ -46.16625 166.68069 277 +QRZ -40.82552 172.52915 263 +RATZ -38.86650 175.77218 653 +RPZ -43.71461 171.05386 403 +RTZ -38.61544 176.98052 867 +SYZ -46.53689 169.13882 52 +THZ -41.76247 172.90522 747 +TLZ -38.32940 175.53800 660 +TMVZ -39.11561 175.70406 1200 +TOZ -37.73096 175.50185 85 +TRVZ -39.29882 175.54782 2062 +TSZ -40.05855 175.96112 531 +TUZ -45.95397 169.63114 110 +VRZ -39.12434 174.75845 166 +WAZ -39.75464 174.98553 382 +WCZ -35.93864 174.34504 108 +WEL -41.28405 174.76818 138 +WHVZ -39.28250 175.58860 2105 +WHZ -45.89243 167.94703 345 +WKZ -44.82702 169.01756 558 +WVZ -43.07435 170.73675 91 \ No newline at end of file diff --git a/eqcorrscan/utils/catalog_to_dd.py b/eqcorrscan/utils/catalog_to_dd.py index 2d0862d81..11343c200 100644 --- a/eqcorrscan/utils/catalog_to_dd.py +++ b/eqcorrscan/utils/catalog_to_dd.py @@ -905,25 +905,41 @@ def write_event(catalog, event_id_mapper=None): # Station.dat functions -def write_station(inventory, use_elevation=False): +def write_station(inventory, use_elevation=False, filename="station.dat"): + """ + Write a hypoDD formatted station file. + + :type inventory: obspy.core.Inventory + :param inventory: + Inventory of stations to write - should include channels if + use_elevation=True to incorporate channel depths. + :type use_elevation: bool + :param use_elevation: Whether to write elevations (requires hypoDD >= 2) + :type filename: str + :param filename: File to write stations to. + """ station_strings = [] + formatter = "{sta:<7s} {lat:>9.5f} {lon:>10.5f}" + if use_elevation: + formatter = " ".join([formatter, "{elev:>5.0f}"]) + for network in inventory: for station in network: + parts = dict(sta=station.code, lat=station.latitude, + lon=station.longitude) if use_elevation: - station_strings.append( - """{station:<7s} {latitude:6.3f} {longitude:6.3f} - {elevation:5.0f}""".format( - station=station.code, - latitude=station.latitude, - longitude=station.longitude, - elevation=station.elevation - station[0].depth)) - else: - station_strings.append( - "{station:<7s} {latitude:6.3f} {longitude:6.3f}".format( - station=station.code, - latitude=station.latitude, - longitude=station.longitude)) - with open("station.dat", "w") as f: + channel_depths = {chan.depth for chan in station} + if len(channel_depths) == 0: + Logger.warning("No channels provided, using 0 depth.") + depth = 0.0 + else: + depth = channel_depths.pop() + if len(channel_depths) > 1: + Logger.warning( + f"Multiple depths for {station.code}, using {depth}") + parts.update(dict(elev=station.elevation - depth)) + station_strings.append(formatter.format(**parts)) + with open(filename, "w") as f: f.write("\n".join(station_strings)) From cb26f818c2f9a217a87efd0da11e8a4d6908998e Mon Sep 17 00:00:00 2001 From: calum-chamberlain Date: Sat, 17 Apr 2021 20:21:33 +1200 Subject: [PATCH 114/132] Add test for strange lengths --- eqcorrscan/tests/catalog_to_dd_test.py | 37 +++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/eqcorrscan/tests/catalog_to_dd_test.py b/eqcorrscan/tests/catalog_to_dd_test.py index 20213cb4c..1e935d304 100644 --- a/eqcorrscan/tests/catalog_to_dd_test.py +++ b/eqcorrscan/tests/catalog_to_dd_test.py @@ -227,7 +227,42 @@ def test_compute_correlation_times(self): def test_compute_correlations_strange_lengths(self): """ Check that streams with too short data are unused. PR #424 """ - self.assertEqual(True, False) # To write! + shift_len = 2 + short_cat = self.catalog[0:10] + cat_dict = {ev.resource_id.id: ev for ev in short_cat} + # Need to copy the stream because we are going to trim it! + stream_dict = {event.resource_id.id: stream.copy() + for event, stream in zip(short_cat, self.streams)} + # Trim to lengths shorter than required. + shuffler = [-.5, -3, -5, -4, 1, 3, 4, 8, 5, 10] + keys = list(stream_dict.keys()) # Need to retain order for testing + for key, shuffle in zip(keys, shuffler): + st = stream_dict[key] + ev = cat_dict[key] + for pick in ev.picks: + if pick.phase_hint.startswith("P"): + _st = st.select(station=pick.waveform_id.station_code) + if len(_st) == 0: + continue + _st.trim(pick.time + shuffle, _st[0].stats.endtime) + diff_times, mapper = compute_differential_times( + catalog=short_cat, correlation=True, event_id_mapper=None, + max_sep=8., min_link=0, min_cc=0.0, stream_dict=stream_dict, + extract_len=2.0, pre_pick=0.5, shift_len=shift_len, + interpolate=False, include_master=True) + + self.assertEqual(len(diff_times[keys[-1]]), 0) + self.assertEqual(len(diff_times[keys[-2]]), 0) + # There should still be all the events. + self.assertEqual(len(diff_times), len(short_cat)) + for master_id, linked in diff_times.items(): + for link in linked: + if link.event_id_2 == link.event_id_1: + # This is the event matched with itself, check that tt1 + # and tt2 are the same. + for obs in link.obs: + self.assertTrue( + np.allclose(obs.tt1, obs.tt2, atol=0.000001)) def test_write_catalog(self): # Contents checked elsewhere From 226bf39bb3e4db5ec9682f2807c6b47e2b544d5f Mon Sep 17 00:00:00 2001 From: calum-chamberlain Date: Sat, 17 Apr 2021 20:43:03 +1200 Subject: [PATCH 115/132] Ensure cc_exported is killed --- conftest.py | 1 + 1 file changed, 1 insertion(+) diff --git a/conftest.py b/conftest.py index e02bc1f1a..cf9ae7764 100644 --- a/conftest.py +++ b/conftest.py @@ -83,6 +83,7 @@ def clean_up_test_directories(): 'test_party_out', 'test_tar_write', 'tmp1', + 'cc_exported,' ] yield From 0bb33f4ec7a239a8683755978ddb2643cd2b17e3 Mon Sep 17 00:00:00 2001 From: calum-chamberlain Date: Sat, 17 Apr 2021 21:05:34 +1200 Subject: [PATCH 116/132] Stickler --- conftest.py | 2 +- eqcorrscan/utils/catalog_to_dd.py | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/conftest.py b/conftest.py index 57811c9d5..0549ad04f 100644 --- a/conftest.py +++ b/conftest.py @@ -84,7 +84,7 @@ def clean_up_test_directories(): 'test_party_out', 'test_tar_write', 'tmp1', - 'cc_exported,' + 'cc_exported', ] yield diff --git a/eqcorrscan/utils/catalog_to_dd.py b/eqcorrscan/utils/catalog_to_dd.py index 11343c200..cce276b82 100644 --- a/eqcorrscan/utils/catalog_to_dd.py +++ b/eqcorrscan/utils/catalog_to_dd.py @@ -481,16 +481,16 @@ def compute_differential_times(catalog, correlation, stream_dict=None, additional_args.update(correlation_kwargs) n = len(catalog) for i, master in enumerate(catalog): + master_id = master.resource_id.id sub_catalog = [ev for j, ev in enumerate(catalog) if distance_filter[i][j]] - if master.resource_id.id not in additional_args["stream_dict"].keys(): + if master_id not in additional_args["stream_dict"].keys(): Logger.warning( - f"{master.resource_id.id} not in waveforms, skipping") + f"{master_id} not in waveforms, skipping") continue differential_times.update({ - master.resource_id.id: - _compute_dt_correlations( - sub_catalog, master, **additional_args)}) + master_id: _compute_dt_correlations( + sub_catalog, master, **additional_args)}) Logger.info( f"Completed correlations for core event {i} of {n}") else: From 9e0f925efbffad5d1f6559cf6ba2045af1e817e6 Mon Sep 17 00:00:00 2001 From: calum-chamberlain Date: Sun, 18 Apr 2021 11:29:34 +1200 Subject: [PATCH 117/132] Try to cope with exceptions in testing --- eqcorrscan/tests/match_filter_test.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/eqcorrscan/tests/match_filter_test.py b/eqcorrscan/tests/match_filter_test.py index a8dc6aab9..95a8f8a08 100644 --- a/eqcorrscan/tests/match_filter_test.py +++ b/eqcorrscan/tests/match_filter_test.py @@ -9,6 +9,7 @@ import numpy as np from obspy import read, UTCDateTime, read_events, Catalog, Stream, Trace from obspy.clients.fdsn import Client +from obspy.clients.fdsn.header import FDSNException from obspy.clients.earthworm import Client as EWClient from obspy.core.event import Pick, Event from obspy.core.util.base import NamedTemporaryFile @@ -652,7 +653,12 @@ def setUpClass(cls): bulk_info = [(stachan[0], stachan[1], '*', stachan[2], t1 - 5, t2 + 5) for stachan in template_stachans] # Just downloading an hour of data - st = client.get_waveforms_bulk(bulk_info) + try: + st = client.get_waveforms_bulk(bulk_info) + except FDSNException: + st = Stream() + for _bulk in bulk_info: + st += client.get_waveforms(*_bulk) st.merge() st.trim(t1, t2) for tr in st: @@ -962,7 +968,12 @@ def test_day_long_methods(self): for stachan in self.template_stachans] # Just downloading an hour of data print('Downloading continuous day-long data') - st = client.get_waveforms_bulk(bulk_info) + try: + st = client.get_waveforms_bulk(bulk_info) + except FDSNException: + st = Stream() + for _bulk in bulk_info: + st += client.get_waveforms(*_bulk) st.merge(fill_value='interpolate') # Hack day-long templates daylong_tribe = self.onehztribe.copy() From 70b3a99af763881cef37754056dc26e167593d19 Mon Sep 17 00:00:00 2001 From: Calum Chamberlain Date: Mon, 19 Apr 2021 09:01:08 +1200 Subject: [PATCH 118/132] Use min_cc regardless. --- CHANGES.md | 3 +++ eqcorrscan/tutorials/lag_calc.py | 10 ++++++-- eqcorrscan/utils/mag_calc.py | 44 +++++++++++++++++--------------- 3 files changed, 35 insertions(+), 22 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 611723402..a40ca6afe 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -22,6 +22,9 @@ - Added useful information to doc-string regarding method and meaning of residuals - Changed the number of magnitudes used to an int (from a string!?) +* utils.mag_calc.relative_magnitude: + - Refactor so that `min_cc` is used regardless of whether + `weight_by_correlation` is set. See issue #455. * utils.archive_read - Add support for wildcard-comparisons in the list of requested stations and channels. diff --git a/eqcorrscan/tutorials/lag_calc.py b/eqcorrscan/tutorials/lag_calc.py index 1da742a54..2320750cb 100644 --- a/eqcorrscan/tutorials/lag_calc.py +++ b/eqcorrscan/tutorials/lag_calc.py @@ -3,8 +3,9 @@ from multiprocessing import cpu_count from obspy.clients.fdsn import Client +from obspy.clients.fdsn.header import FDSNException from obspy.core.event import Catalog -from obspy import UTCDateTime +from obspy import UTCDateTime, Stream from eqcorrscan.core import template_gen, match_filter, lag_calc from eqcorrscan.utils import pre_processing, catalog_utils @@ -66,7 +67,12 @@ def run_tutorial(min_magnitude=2, shift_len=0.2, num_cores=4, min_cc=0.5): bulk_info = [(tr.stats.network, tr.stats.station, '*', tr.stats.channel, t1, t2) for tr in templates[0]] # Just downloading a chunk of data - st = client.get_waveforms_bulk(bulk_info) + try: + st = client.get_waveforms_bulk(bulk_info) + except FDSNException: + st = Stream() + for _bulk in bulk_info: + st += client.get_waveforms(*_bulk) st.merge(fill_value='interpolate') st = pre_processing.shortproc( st, lowcut=2.0, highcut=9.0, filt_order=4, samp_rate=50.0, diff --git a/eqcorrscan/utils/mag_calc.py b/eqcorrscan/utils/mag_calc.py index 46751850b..0b989f5fd 100644 --- a/eqcorrscan/utils/mag_calc.py +++ b/eqcorrscan/utils/mag_calc.py @@ -549,14 +549,17 @@ def relative_magnitude(st1, st2, event1, event2, noise_window=(-20, -1), See :func:`eqcorrscan.utils.mag_calc.relative_amplitude` for information on how relative amplitudes are calculated. To compute relative magnitudes - from relative amplitudes this function weights the amplitude ratios by + from relative amplitudes this function can weight the amplitude ratios by the cross-correlation of the two events. The relation used is similar to - Schaff and Richards (2014) and is: + Schaff and Richards (2014), equation 4 and is: .. math:: \\Delta m = \\log{\\frac{std(tr2)}{std(tr1)}} \\times CC + If you decide to use this function you should definitely read the paper + to understand what you can use this for and cite the paper! + :type st1: `obspy.core.stream.Stream` :param st1: Stream for event1 :type st2: `obspy.core.stream.Stream` @@ -621,28 +624,29 @@ def relative_magnitude(st1, st2, event1, event2, noise_window=(-20, -1), event=event1, station=tr1.stats.station, use_s_picks=use_s_picks) pick2 = _get_pick_for_station( event=event2, station=tr2.stats.station, use_s_picks=use_s_picks) - if weight_by_correlation: - if compute_correlations: - cc = correlate( - tr1.slice( - starttime=pick1.time + signal_window[0], - endtime=pick1.time + signal_window[1]), - tr2.slice( - starttime=pick2.time + signal_window[0], - endtime=pick2.time + signal_window[1]), - shift=int(shift * tr1.stats.sampling_rate)) - cc = cc.max() - correlations.update({seed_id: cc}) - else: - cc = correlations.get(seed_id, 0.0) - if cc < min_cc: - continue + if compute_correlations: + cc = correlate( + tr1.slice( + starttime=pick1.time + signal_window[0], + endtime=pick1.time + signal_window[1]), + tr2.slice( + starttime=pick2.time + signal_window[0], + endtime=pick2.time + signal_window[1]), + shift=int(shift * tr1.stats.sampling_rate)) + cc = cc.max() + correlations.update({seed_id: cc}) else: + cc = correlations.get(seed_id, 0.0) + if cc < min_cc: + Logger.info( + f"Correlation of {cc} less than {min_cc} for {seed_id}, " + "skipping.") + continue + if not weight_by_correlation: cc = 1.0 # Weight and add to relative_magnitudes rel_mag = math.log10(amplitude_ratio) * cc - Logger.debug("Channel: {0} Magnitude change {1:.2f}".format( - tr1.id, rel_mag)) + Logger.info(f"Channel: {seed_id} Magnitude change {rel_mag:.2f}") relative_magnitudes.update({seed_id: rel_mag}) if return_correlations: return relative_magnitudes, correlations From 0ea1e9da657b5fca21a42a5684311c2621440365 Mon Sep 17 00:00:00 2001 From: flixha Date: Mon, 19 Apr 2021 17:33:51 +0200 Subject: [PATCH 119/132] fix shape and symmetry of shift-matrix; return shift-dict; update tests --- eqcorrscan/tests/clustering_test.py | 26 +++++++++--- eqcorrscan/utils/clustering.py | 64 +++++++++++++++++++++-------- 2 files changed, 67 insertions(+), 23 deletions(-) diff --git a/eqcorrscan/tests/clustering_test.py b/eqcorrscan/tests/clustering_test.py index fad3449b3..d4dfa7586 100644 --- a/eqcorrscan/tests/clustering_test.py +++ b/eqcorrscan/tests/clustering_test.py @@ -84,12 +84,19 @@ def test_distance_matrix_no_shift(self): for st in stream_list: for tr in st: tr.data = tr.data[0:shortest_tr] - dist_mat, shift_mat = distance_matrix(stream_list=stream_list, cores=4) + dist_mat, shift_mat, shift_dict = distance_matrix( + stream_list=stream_list, cores=4) self.assertEqual(dist_mat.shape[0], len(stream_list)) self.assertEqual(dist_mat.shape[1], len(stream_list)) + self.assertEqual(len(shift_dict), len(stream_list)) + for j, key in enumerate(shift_dict.keys()): + self.assertEqual(len(shift_dict[key]), len(stream_list[j])) def test_distance_matrix_with_shift(self): - """Test that we can create a useful distance matrix.""" + """ + Test that we can create a useful distance and shift matrix with some + shift. + """ testing_path = os.path.join(self.testing_path, 'WAV', 'TEST_') stream_files = glob.glob(os.path.join(testing_path, '*DFDPC*'))[0:10] stream_list = [read(stream_file) for stream_file in stream_files] @@ -106,7 +113,7 @@ def test_distance_matrix_with_shift(self): for st in stream_list: for tr in st: tr.data = tr.data[0:shortest_tr] - dist_mat, shift_mat = distance_matrix( + dist_mat, shift_mat, shift_dict = distance_matrix( stream_list=stream_list, cores=4, shift_len=0.2, allow_individual_trace_shifts=False) self.assertEqual(dist_mat.shape[0], len(stream_list)) @@ -115,9 +122,15 @@ def test_distance_matrix_with_shift(self): self.assertEqual(shift_mat.shape[0], len(stream_list)) self.assertEqual(shift_mat.shape[1], len(stream_list)) self.assertEqual(np.array(shift_mat == shift_mat.T).all(), True) + self.assertEqual(len(shift_dict), len(stream_list)) + for j, key in enumerate(shift_dict.keys()): + self.assertEqual(len(shift_dict[key]), len(stream_list[j])) def test_distance_matrix_with_shifted_traces(self): - """Test that we can create a useful distance matrix.""" + """ + Test that we can create a useful distance and shift matrix with + individual traces allowed to shift. + """ testing_path = os.path.join(self.testing_path, 'WAV', 'TEST_') stream_files = glob.glob(os.path.join(testing_path, '*DFDPC*'))[0:10] stream_list = [read(stream_file) for stream_file in stream_files] @@ -134,7 +147,7 @@ def test_distance_matrix_with_shifted_traces(self): for st in stream_list: for tr in st: tr.data = tr.data[0:shortest_tr] - dist_mat, shift_mat = distance_matrix( + dist_mat, shift_mat, shift_dict = distance_matrix( stream_list=stream_list, cores=4, shift_len=0.2, allow_individual_trace_shifts=True) self.assertEqual(dist_mat.shape[0], len(stream_list)) @@ -142,6 +155,9 @@ def test_distance_matrix_with_shifted_traces(self): self.assertEqual(np.array(dist_mat == dist_mat.T).all(), True) self.assertEqual(len(shift_mat.shape), 3) np.testing.assert_equal(shift_mat, np.transpose(shift_mat, [1, 0, 2])) + self.assertEqual(len(shift_dict), len(stream_list)) + for j, key in enumerate(shift_dict.keys()): + self.assertEqual(len(shift_dict[key]), len(stream_list[j])) def test_unclustered(self): """Test clustering on unclustered data...""" diff --git a/eqcorrscan/utils/clustering.py b/eqcorrscan/utils/clustering.py index b3c24a1d0..d9657ead5 100644 --- a/eqcorrscan/utils/clustering.py +++ b/eqcorrscan/utils/clustering.py @@ -108,7 +108,7 @@ def cross_chan_correlation( # input streams _coherances = np.empty(n_streams) if allow_individual_trace_shifts: - n_max_traces = max([len(st) for st in streams]) + n_max_traces = max([len(st) for st in prep_streams]) # Set shifts for nan-traces to nan for i, tr in enumerate(st1_preped): if np.ma.is_masked(tr.data): @@ -155,8 +155,16 @@ def distance_matrix(stream_list, shift_len=0.0, :type cores: int :param cores: Number of cores to parallel process using, defaults to 1. - :returns: distance matrix - :rtype: :class:`numpy.ndarray` + :returns: + - distance matrix (:py:class:`numpy.ndarray`) of size + len(stream_list)**2 + - shift matrix (:py:class:`numpy.ndarray`) containing shifts between + traces of the sorted streams. Size is len(stream_list)**2 * x, where + x is 1 for shift_len=0 and/or allow_individual_trace_shifts=False. + Missing correlations are indicated by nans. + - shift dict (:py:class:`dict`): + dictionary of (template_id: trace_dict) where trace_dict contains + (trace.id: shift matrix (size `len(stream_list)**2`) for trace.id) .. warning:: Because distance is given as :math:`1-abs(coherence)`, negatively @@ -166,46 +174,60 @@ def distance_matrix(stream_list, shift_len=0.0, .. note:: Requires all traces to have the same sampling rate and same length. """ - allow_individual_trace_shifts = ( - allow_individual_trace_shifts and shift_len > 0) n_streams = len(stream_list) - n_traces_max = max([len(st) for st in stream_list]) + # May have to allow duplicate channels for P- and S-picks at each station + stream_list = [st.sort() for st in stream_list] + uniq_traces = set([tr.id for st in stream_list for tr in st]) + n_uniq_traces = len(uniq_traces) # Initialize square matrix dist_mat = np.zeros([n_streams, n_streams]) - shift_mat = np.zeros([n_streams, n_streams, n_traces_max]) - n_shifts_per_stream = 1 + shift_mat = np.empty([n_streams, n_streams, n_uniq_traces]) + shift_mat[:] = np.nan + shift_dict = dict() for i, master in enumerate(stream_list): dist_list, shift_list = cross_chan_correlation( st1=master, streams=stream_list, shift_len=shift_len, allow_individual_trace_shifts=allow_individual_trace_shifts, xcorr_func='fftw', cores=cores) dist_mat[i] = 1 - dist_list - shift_mat[i, :, :] = shift_list - n_shifts_per_stream = shift_list.shape[1] + master_ids = [tr.id for tr in master] + master_trace_indcs = [ + j for j, tr_id in enumerate(uniq_traces) if tr_id in master_ids] + # Sort computed shifts into shift-matrix. shift_list could contain a + # nan-column that needs to be ignored here (only when earliest trace is + # missing) + shift_mat[np.ix_([i], list(range(n_streams)), master_trace_indcs)] = ( + shift_list[:, ~np.all(np.isnan(shift_list), axis=0)]) + # Add trace-id with corresponding shift-matrix to shift-dictionary + shift_mat_list = [shift_mat[:, :, mti] for mti in master_trace_indcs] + trace_shift_dict = dict(zip(master_ids, shift_mat_list)) + shift_dict[i] = trace_shift_dict if shift_len == 0: assert np.allclose(dist_mat, dist_mat.T, atol=0.00001) # Force perfect symmetry dist_mat = (dist_mat + dist_mat.T) / 2 - shift_mat = shift_mat[:, :, 0:n_shifts_per_stream].squeeze() else: # get the shortest distance for each correlation pair dist_mat_shortest = np.minimum(dist_mat, dist_mat.T) # Indicator says which matrix has shortest dist: value 0: mat2; 1: mat1 mat_indicator = dist_mat_shortest == dist_mat mat_indicator = np.repeat(mat_indicator[:, :, np.newaxis], - n_shifts_per_stream, axis=2)[:, :] + n_uniq_traces, axis=2)[:, :] # Get shift for the shortest distances - shift_mat = shift_mat[:, :, 0:n_shifts_per_stream][:, :] shift_mat = ( shift_mat * mat_indicator + np.transpose(shift_mat, [1, 0, 2]) * (1 - mat_indicator)) dist_mat = dist_mat_shortest + # Squeeze matrix to 2 axis (ignore nans) if 3rd dimension not needed + if shift_len == 0 or allow_individual_trace_shifts is False: + shift_mat = np.nanmean(shift_mat, axis=2) np.fill_diagonal(dist_mat, 0) - return dist_mat, shift_mat.squeeze() + return dist_mat, shift_mat.squeeze(), shift_dict -def cluster(template_list, show=True, corr_thresh=0.3, - shift_len=0, save_corrmat=False, cores='all'): +def cluster(template_list, show=True, corr_thresh=0.3, shift_len=0, + allow_individual_trace_shifts=True, save_corrmat=False, + cores='all'): """ Cluster template waveforms based on average correlations. @@ -230,6 +252,11 @@ def cluster(template_list, show=True, corr_thresh=0.3, :param corr_thresh: Cross-channel correlation threshold for grouping :type shift_len: float :param shift_len: How many seconds to allow the templates to shift + :type allow_individual_trace_shifts: bool + :param allow_individual_trace_shifts: + Controls whether templates are shifted by shift_len in relation to the + picks as a whole, or whether each trace can be shifted individually. + Defaults to True. :type save_corrmat: bool :param save_corrmat: If True will save the distance matrix to dist_mat.npy in the local @@ -251,8 +278,9 @@ def cluster(template_list, show=True, corr_thresh=0.3, stream_list = [x[0] for x in template_list] # Compute the distance matrix Logger.info('Computing the distance matrix using %i cores' % num_cores) - dist_mat, _ = distance_matrix( - stream_list=stream_list, shift_len=shift_len, cores=num_cores) + dist_mat, shift_mat, shift_dict = distance_matrix( + stream_list=stream_list, shift_len=shift_len, cores=num_cores, + allow_individual_trace_shifts=allow_individual_trace_shifts) if save_corrmat: np.save('dist_mat.npy', dist_mat) Logger.info('Saved the distance matrix as dist_mat.npy') From 3528d7cd7a4b6b13337108e611d3f7354e410a52 Mon Sep 17 00:00:00 2001 From: flixha Date: Mon, 19 Apr 2021 18:29:36 +0200 Subject: [PATCH 120/132] add Change message --- CHANGES.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 611723402..9fd5f7be0 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -36,6 +36,13 @@ outputs are provided. - Progress is not reported within dt.cc computation - `write_station` now supports writing elevations: #424. +* utils.clustering + - For `cluster`, `distance_matrix` and `cross_chan_correlation`, implemented + full support for `shift_len != 0`. The latter two functions now return, in + addition to the distance-matrix, a shift-matrix (both functions) and a + shift-dictionary (for `distance_matrix`). New option for shifting streams + as a whole or letting traces shift individually + (`allow_individual_trace_shifts=True`). * utils.plotting - Function added (twoD_seismplot) for plotting seismicity (#365). From 4f680f88feaa516ea70ee217bc9bb11439a9f919 Mon Sep 17 00:00:00 2001 From: Calum Chamberlain Date: Tue, 20 Apr 2021 08:29:47 +1200 Subject: [PATCH 121/132] Bump version --- CHANGES.md | 2 +- eqcorrscan/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index ceb687b7f..7ff6869f6 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,4 +1,4 @@ -## Current +## 0.4.3 * core.match_filter - match_filter: - Provide option of exporting the cross-correlation sums for additional later diff --git a/eqcorrscan/__init__.py b/eqcorrscan/__init__.py index 88e3e9c28..55a7ae5ac 100755 --- a/eqcorrscan/__init__.py +++ b/eqcorrscan/__init__.py @@ -25,7 +25,7 @@ __all__ = ['core', 'utils', 'tutorials', 'tests'] -__version__ = '0.4.2' +__version__ = '0.4.3' # Cope with changes to name-space to remove most of the camel-case _import_map = {} From b07aeec01d5fda5441664cac3e43b2e35964e3e2 Mon Sep 17 00:00:00 2001 From: Calum Chamberlain Date: Tue, 20 Apr 2021 08:32:50 +1200 Subject: [PATCH 122/132] Stickler --- eqcorrscan/core/match_filter/matched_filter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eqcorrscan/core/match_filter/matched_filter.py b/eqcorrscan/core/match_filter/matched_filter.py index 47b6ad18c..d7f680721 100644 --- a/eqcorrscan/core/match_filter/matched_filter.py +++ b/eqcorrscan/core/match_filter/matched_filter.py @@ -385,7 +385,7 @@ def match_filter(template_names, template_list, st, threshold, xcorr_func=None, concurrency=None, cores=None, plot_format='png', output_cat=False, output_event=True, extract_detections=False, arg_check=True, full_peaks=False, - peak_cores=None, spike_test=True, copy_data=True, + peak_cores=None, spike_test=True, copy_data=True, export_cccsums=False, **kwargs): """ Main matched-filter detection function. From 2d73ef757da5e01f16109d2fe68a33b4ab60487e Mon Sep 17 00:00:00 2001 From: derrick chambers Date: Mon, 19 Apr 2021 15:41:57 -0700 Subject: [PATCH 123/132] implement #454 --- CHANGES.md | 3 ++ eqcorrscan/core/match_filter/tribe.py | 4 +- eqcorrscan/core/template_gen.py | 16 ++++--- eqcorrscan/tests/template_gen_test.py | 60 ++++++++++++++++++++++++++- 4 files changed, 75 insertions(+), 8 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 7ff6869f6..1cb84405a 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -18,6 +18,9 @@ - Added option to set minimum CC threshold individually for detections based on: min(detect_val / n_chans * min_cc_from_mean_cc_factor, min_cc). - Added the ability of saving correlation data of the lag_calc. +* core.template_gen: + - Added support for generating templates from any object with a + get_waveforms method. See #459. * utils.mag_calc.calc_b_value: - Added useful information to doc-string regarding method and meaning of residuals diff --git a/eqcorrscan/core/match_filter/tribe.py b/eqcorrscan/core/match_filter/tribe.py index 3e6ceab30..3af57bb11 100644 --- a/eqcorrscan/core/match_filter/tribe.py +++ b/eqcorrscan/core/match_filter/tribe.py @@ -986,8 +986,8 @@ def construct(self, method, lowcut, highcut, samp_rate, filt_order, - `from_client` requires: :param str client_id: - string passable by obspy to generate Client, or a Client - instance + string passable by obspy to generate Client, or any object + with a `get_waveforms` method, including a Client instance. :param `obspy.core.event.Catalog` catalog: Catalog of events to generate template for :param float data_pad: Pad length for data-downloads in seconds diff --git a/eqcorrscan/core/template_gen.py b/eqcorrscan/core/template_gen.py index bf159d200..bcf530c65 100644 --- a/eqcorrscan/core/template_gen.py +++ b/eqcorrscan/core/template_gen.py @@ -148,8 +148,8 @@ def template_gen(method, lowcut, highcut, samp_rate, filt_order, - `from_client` requires: :param str client_id: - string passable by obspy to generate Client, or a Client - instance + string passable by obspy to generate Client, or any object + with a `get_waveforms` method, including a Client instance. :param `obspy.core.event.Catalog` catalog: Catalog of events to generate template for :param float data_pad: Pad length for data-downloads in seconds @@ -251,10 +251,16 @@ def template_gen(method, lowcut, highcut, samp_rate, filt_order, catalog=catalog, process_len=process_len, template_length=length, data_pad=data_pad) if method == 'from_client': - if isinstance(kwargs.get('client_id'), str): - client = FDSNClient(kwargs.get('client_id', None)) + client_id = kwargs.get('client_id', None) + if hasattr(client_id, 'get_waveforms'): + client = client_id + elif isinstance(client_id, str): + client = FDSNClient(client_id) else: - client = kwargs.get('client_id', None) + raise NotImplementedError( + "client_id must be an FDSN client string, or a Client " + "with a get_waveforms method" + ) available_stations = [] else: client = SeisHubClient(kwargs.get('url', None), timeout=10) diff --git a/eqcorrscan/tests/template_gen_test.py b/eqcorrscan/tests/template_gen_test.py index 364d0ded3..b37c1b2fd 100644 --- a/eqcorrscan/tests/template_gen_test.py +++ b/eqcorrscan/tests/template_gen_test.py @@ -10,6 +10,8 @@ import inspect import copy import shutil +from functools import reduce +from operator import add from obspy import read, UTCDateTime, read_events from obspy.clients.fdsn import Client @@ -17,13 +19,47 @@ from eqcorrscan.core import template_gen as template_gen_module from eqcorrscan.core.template_gen import ( - _group_events, extract_from_stack, _template_gen, template_gen) + _group_events, extract_from_stack, _template_gen, template_gen, + TemplateGenError) from eqcorrscan.tutorials.template_creation import mktemplates from eqcorrscan.utils.catalog_utils import filter_picks from eqcorrscan.utils.sac_util import sactoevent from eqcorrscan.helpers.mock_logger import MockLoggingHandler +class _StreamTestClient: + """A simple waveform client using a stream.""" + + def __init__(self, st=None): + self.st = st or read() + + def get_waveforms(self, network, station, location, channel, + starttime, endtime): + """Get waveforms contained by stream.""" + out = self.st.copy() + st_trimed = out.trim(starttime=starttime, endtime=endtime) + st_filtered = st_trimed.select(network=network, station=station, + location=location, channel=channel) + return st_filtered + + def get_default_catalog(self): + """Get a catalog with picks from the default stream.""" + pick1 = Pick( + time=UTCDateTime(2009, 8, 24, 0, 20, 7, 696381), + waveform_id=WaveformStreamID(seed_string='BW.RJOB..EHZ'), + phase_hint='P' + ) + origin = Origin( + time=UTCDateTime(2009, 8, 24, 0, 20, 6, 410034), + longitude=0, + latitude=0, + depth=0, + ) + event = Event(picks=[pick1], origins=[origin]) + return Catalog(events=[event]) + + + class TestTemplateGeneration(unittest.TestCase): """Test the reading a writing of pick info.""" def test_sac_template_gen(self): @@ -303,6 +339,28 @@ def test_missing_waveform_id(self): swin='S') self.assertEqual(len(templates), 1) + def test_from_client(self): + """Test for using a waveform client not related to obspy's Clients.""" + client = _StreamTestClient() + cat = client.get_default_catalog() + temps = template_gen('from_client', client_id=client, catalog=cat, + highcut=None, lowcut=None, filt_order=4, + samp_rate=100, prepick=0.1, length=10, + process_len=20, data_pad=5) + self.assertEqual(len(temps), 1) # there should be one template stream + self.assertEqual(len(temps[0]), 1) # with one trace + self.assertGreater(len(temps[0][0].data), 1) # with some data + + def test_bad_client(self): + """Ensure passing a non-client raises.""" + client = _StreamTestClient() + cat = client.get_default_catalog() + with self.assertRaises(TemplateGenError): + template_gen('from_client', client_id=cat, catalog=cat, + highcut=None, lowcut=None, filt_order=4, + samp_rate=100, prepick=0.1, length=10, + process_len=20, data_pad=5) + class TestEdgeGen(unittest.TestCase): @classmethod From 5f68c526c2ef9e81691ca999bb6fd900e23d7fa5 Mon Sep 17 00:00:00 2001 From: derrick chambers Date: Mon, 19 Apr 2021 15:45:49 -0700 Subject: [PATCH 124/132] stickler fixes --- eqcorrscan/tests/template_gen_test.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/eqcorrscan/tests/template_gen_test.py b/eqcorrscan/tests/template_gen_test.py index b37c1b2fd..cb59d953c 100644 --- a/eqcorrscan/tests/template_gen_test.py +++ b/eqcorrscan/tests/template_gen_test.py @@ -10,8 +10,6 @@ import inspect import copy import shutil -from functools import reduce -from operator import add from obspy import read, UTCDateTime, read_events from obspy.clients.fdsn import Client From e27f5a1cacc6496422228baf899b85059856c201 Mon Sep 17 00:00:00 2001 From: Calum Chamberlain Date: Tue, 20 Apr 2021 14:51:51 +1200 Subject: [PATCH 125/132] Update Error check --- eqcorrscan/tests/template_gen_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eqcorrscan/tests/template_gen_test.py b/eqcorrscan/tests/template_gen_test.py index cb59d953c..dad3e3506 100644 --- a/eqcorrscan/tests/template_gen_test.py +++ b/eqcorrscan/tests/template_gen_test.py @@ -353,7 +353,7 @@ def test_bad_client(self): """Ensure passing a non-client raises.""" client = _StreamTestClient() cat = client.get_default_catalog() - with self.assertRaises(TemplateGenError): + with self.assertRaises(NotImplementedError): template_gen('from_client', client_id=cat, catalog=cat, highcut=None, lowcut=None, filt_order=4, samp_rate=100, prepick=0.1, length=10, From ecccdbebdd8eece6d3169f12955969a1bb60c853 Mon Sep 17 00:00:00 2001 From: calum-chamberlain Date: Tue, 20 Apr 2021 15:41:09 +1200 Subject: [PATCH 126/132] Run non-network related tests first --- .github/workflows/runtest.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/runtest.yml b/.github/workflows/runtest.yml index f22f74ba7..754e81683 100644 --- a/.github/workflows/runtest.yml +++ b/.github/workflows/runtest.yml @@ -53,19 +53,19 @@ jobs: conda info -a conda list - - name: run main test suite + - name: run serial test shell: bash -l {0} run: | - py.test -n 2 -m "not serial and not network and not superslow" --cov-report=xml + export OMP_NUM_THREADS=2 + py.test -m "serial and not network" --cov-report=xml --cov-append - name: run slow tests shell: bash -l {0} run: | py.test -v -m "slow and not serial and not network" --cov-report=xml --cov-append - - name: run serial test + - name: run main test suite shell: bash -l {0} run: | - export OMP_NUM_THREADS=2 - py.test -m "serial and not network" --cov-report=xml --cov-append + py.test -n 2 -m "not serial and not network and not superslow" --cov-report=xml - name: upload coverage uses: codecov/codecov-action@v1 From ca67c477df45aaa0a978b351ff4b5d8d93abd997 Mon Sep 17 00:00:00 2001 From: calum-chamberlain Date: Tue, 20 Apr 2021 15:54:13 +1200 Subject: [PATCH 127/132] Just run them all please. --- .github/workflows/runtest.yml | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/.github/workflows/runtest.yml b/.github/workflows/runtest.yml index 754e81683..04ec294b9 100644 --- a/.github/workflows/runtest.yml +++ b/.github/workflows/runtest.yml @@ -53,19 +53,27 @@ jobs: conda info -a conda list - - name: run serial test + - name: run all tests shell: bash -l {0} run: | + py.test -n 2 -m "not serial and not network and not superslow" --cov-report=xml export OMP_NUM_THREADS=2 py.test -m "serial and not network" --cov-report=xml --cov-append - - name: run slow tests - shell: bash -l {0} - run: | py.test -v -m "slow and not serial and not network" --cov-report=xml --cov-append - - name: run main test suite - shell: bash -l {0} - run: | - py.test -n 2 -m "not serial and not network and not superslow" --cov-report=xml + +# - name: run main test suite +# shell: bash -l {0} +# run: | +# py.test -n 2 -m "not serial and not network and not superslow" --cov-report=xml +# - name: run serial test +# shell: bash -l {0} +# run: | +# export OMP_NUM_THREADS=2 +# py.test -m "serial and not network" --cov-report=xml --cov-append +# - name: run slow tests +# shell: bash -l {0} +# run: | +# py.test -v -m "slow and not serial and not network" --cov-report=xml --cov-append - name: upload coverage uses: codecov/codecov-action@v1 From 8253b0c2c63932939df8eb61d0d5210588cad80e Mon Sep 17 00:00:00 2001 From: calum-chamberlain Date: Tue, 20 Apr 2021 16:36:49 +1200 Subject: [PATCH 128/132] Try always run. --- .github/workflows/runtest.yml | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/.github/workflows/runtest.yml b/.github/workflows/runtest.yml index 04ec294b9..3519d31de 100644 --- a/.github/workflows/runtest.yml +++ b/.github/workflows/runtest.yml @@ -10,6 +10,7 @@ jobs: os: [ubuntu-latest, macos-latest, windows-latest] python-version: [3.7, 3.8] fail-fast: false +# continue-on-error: true steps: - uses: actions/checkout@v2 @@ -53,28 +54,31 @@ jobs: conda info -a conda list - - name: run all tests - shell: bash -l {0} - run: | - py.test -n 2 -m "not serial and not network and not superslow" --cov-report=xml - export OMP_NUM_THREADS=2 - py.test -m "serial and not network" --cov-report=xml --cov-append - py.test -v -m "slow and not serial and not network" --cov-report=xml --cov-append - -# - name: run main test suite +# - name: run all tests # shell: bash -l {0} # run: | # py.test -n 2 -m "not serial and not network and not superslow" --cov-report=xml -# - name: run serial test -# shell: bash -l {0} -# run: | # export OMP_NUM_THREADS=2 # py.test -m "serial and not network" --cov-report=xml --cov-append -# - name: run slow tests -# shell: bash -l {0} -# run: | # py.test -v -m "slow and not serial and not network" --cov-report=xml --cov-append + - name: run main test suite + shell: bash -l {0} + run: | + py.test -n 2 -m "not serial and not network and not superslow" --cov-report=xml + - name: run serial test + if: always() + shell: bash -l {0} + run: | + export OMP_NUM_THREADS=2 + py.test -m "serial and not network" --cov-report=xml --cov-append + - name: run slow tests + if: always() + shell: bash -l {0} + run: | + if: always + py.test -v -m "slow and not serial and not network" --cov-report=xml --cov-append + - name: upload coverage uses: codecov/codecov-action@v1 with: From 8cd108430db6994b5dbc2f6ca3f2cbdfa1a53837 Mon Sep 17 00:00:00 2001 From: calum-chamberlain Date: Tue, 20 Apr 2021 17:34:50 +1200 Subject: [PATCH 129/132] syntax --- .github/workflows/runtest.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/runtest.yml b/.github/workflows/runtest.yml index 3519d31de..5e118a6bb 100644 --- a/.github/workflows/runtest.yml +++ b/.github/workflows/runtest.yml @@ -66,12 +66,14 @@ jobs: shell: bash -l {0} run: | py.test -n 2 -m "not serial and not network and not superslow" --cov-report=xml + - name: run serial test if: always() shell: bash -l {0} run: | export OMP_NUM_THREADS=2 py.test -m "serial and not network" --cov-report=xml --cov-append + - name: run slow tests if: always() shell: bash -l {0} From a99716447e094dff039783813ceb227ca42e2bb6 Mon Sep 17 00:00:00 2001 From: calum-chamberlain Date: Tue, 20 Apr 2021 18:07:16 +1200 Subject: [PATCH 130/132] syntax --- .github/workflows/runtest.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/runtest.yml b/.github/workflows/runtest.yml index 5e118a6bb..38522ca6f 100644 --- a/.github/workflows/runtest.yml +++ b/.github/workflows/runtest.yml @@ -75,7 +75,6 @@ jobs: py.test -m "serial and not network" --cov-report=xml --cov-append - name: run slow tests - if: always() shell: bash -l {0} run: | if: always From 1038aba9554be89ecc321046ad7566fc142f6dca Mon Sep 17 00:00:00 2001 From: calum-chamberlain Date: Tue, 20 Apr 2021 18:40:57 +1200 Subject: [PATCH 131/132] syntax --- .github/workflows/runtest.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/runtest.yml b/.github/workflows/runtest.yml index 38522ca6f..cde6ec258 100644 --- a/.github/workflows/runtest.yml +++ b/.github/workflows/runtest.yml @@ -75,9 +75,9 @@ jobs: py.test -m "serial and not network" --cov-report=xml --cov-append - name: run slow tests + if: always() shell: bash -l {0} run: | - if: always py.test -v -m "slow and not serial and not network" --cov-report=xml --cov-append - name: upload coverage From 84595cb3a71b66ede87dc57af2b734c4b9aad6df Mon Sep 17 00:00:00 2001 From: calum-chamberlain Date: Tue, 20 Apr 2021 19:43:31 +1200 Subject: [PATCH 132/132] syntax --- .github/workflows/runtest.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/runtest.yml b/.github/workflows/runtest.yml index cde6ec258..2271f52b6 100644 --- a/.github/workflows/runtest.yml +++ b/.github/workflows/runtest.yml @@ -138,10 +138,12 @@ jobs: run: | py.test -n 2 -m "network" --cov-report=xml - name: run tutorials + if: always() shell: bash -l {0} run: | py.test eqcorrscan/doc/tutorials/*.rst eqcorrscan/doc/submodules/*.rst --cov-report=xml --cov-append - name: run superslow tests + if: always() shell: bash -l {0} run: | py.test -m "superslow" -s eqcorrscan/tests/tutorials_test.py eqcorrscan/tests/subspace_test.py --cov-report=xml --cov-append