def main(args=None):

    if args is None:
        # Run Input Parser
        args = get_cleanspec_arguments()

    # Load Database
    # stdb>0.1.3
    try:
        db, stkeys = stdb.io.load_db(fname=args.indb, keys=args.stkeys)

    # stdb=0.1.3
    except:
        db = stdb.io.load_db(fname=args.indb)

        # Construct station key loop
        allkeys = db.keys()
        sorted(allkeys)

        # Extract key subset
        if len(args.stkeys) > 0:
            stkeys = []
            for skey in args.stkeys:
                stkeys.extend([s for s in allkeys if skey in s])
        else:
            stkeys = db.keys()
            sorted(stkeys)

    # Loop over station keys
    for stkey in list(stkeys):

        # Extract station information from dictionary
        sta = db[stkey]

        # Path where spectra are located
        specpath = Path('SPECTRA') / stkey
        if not specpath.is_dir():
            raise(Exception("Path to "+str(specpath)+" doesn`t exist - aborting"))

        # Path where average spectra will be saved
        avstpath = Path('AVG_STA') / stkey
        if not avstpath.is_dir():
            print("Path to "+str(avstpath)+" doesn`t exist - creating it")
            avstpath.mkdir(parents=True)

        # Path where plots will be saved
        if args.saveplot:
            plotpath = avstpath / 'PLOTS'
            if not plotpath.is_dir():
                plotpath.mkdir(parents=True)
        else:
            plotpath = False

        # Get catalogue search start time
        if args.startT is None:
            tstart = sta.startdate
        else:
            tstart = args.startT

        # Get catalogue search end time
        if args.endT is None:
            tend = sta.enddate
        else:
            tend = args.endT

        if tstart > sta.enddate or tend < sta.startdate:
            continue

        # Temporary print locations
        tlocs = sta.location
        if len(tlocs) == 0:
            tlocs = ['']
        for il in range(0, len(tlocs)):
            if len(tlocs[il]) == 0:
                tlocs[il] = "--"
        sta.location = tlocs

        # Update Display
        print()
        print("|===============================================|")
        print("|===============================================|")
        print("|                   {0:>8s}                    |".format(
            sta.station))
        print("|===============================================|")
        print("|===============================================|")
        print("|  Station: {0:>2s}.{1:5s}                            |".format(
            sta.network, sta.station))
        print("|      Channel: {0:2s}; Locations: {1:15s}  |".format(
            sta.channel, ",".join(tlocs)))
        print("|      Lon: {0:7.2f}; Lat: {1:6.2f}                |".format(
            sta.longitude, sta.latitude))
        print("|      Start time: {0:19s}          |".format(
            sta.startdate.strftime("%Y-%m-%d %H:%M:%S")))
        print("|      End time:   {0:19s}          |".format(
            sta.enddate.strftime("%Y-%m-%d %H:%M:%S")))
        print("|-----------------------------------------------|")

        # Filename for output average spectra
        dstart = str(tstart.year).zfill(4)+'.'+str(tstart.julday).zfill(3)+'-'
        dend = str(tend.year).zfill(4)+'.'+str(tend.julday).zfill(3)+'.'
        fileavst = avstpath / (dstart+dend+'avg_sta.pkl')

        if fileavst.exists():
            if not args.ovr:
                print("*   -> file "+str(fileavst)+" exists - continuing")
                continue

        # Containers for power and cross spectra
        coh_all = []
        ph_all = []
        coh_12_all = []
        coh_1Z_all = []
        coh_1P_all = []
        coh_2Z_all = []
        coh_2P_all = []
        coh_ZP_all = []
        ph_12_all = []
        ph_1Z_all = []
        ph_1P_all = []
        ph_2Z_all = []
        ph_2P_all = []
        ph_ZP_all = []
        ad_12_all = []
        ad_1Z_all = []
        ad_1P_all = []
        ad_2Z_all = []
        ad_2P_all = []
        ad_ZP_all = []
        nwins = []

        t1 = tstart

        # Initialize StaNoise object
        stanoise = StaNoise()

        # Loop through each day withing time range
        while t1 < tend:

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

            tstamp = year+'.'+jday+'.'
            filespec = specpath / (tstamp + 'spectra.pkl')

            # Load file if it exists
            if filespec.exists():
                print()
                print("*"*60)
                print('* Calculating noise spectra for key ' +
                      stkey+' and day '+year+'.'+jday)
                print("*   -> file "+str(filespec)+" found - loading")
                file = open(filespec, 'rb')
                daynoise = pickle.load(file)
                file.close()
                stanoise += daynoise
            else:
                t1 += 3600.*24.
                continue

            coh_all.append(daynoise.rotation.coh)
            ph_all.append(daynoise.rotation.ph)

            # Coherence
            coh_12_all.append(
                utils.smooth(
                    utils.coherence(
                        daynoise.cross.c12,
                        daynoise.power.c11,
                        daynoise.power.c22), 50))
            coh_1Z_all.append(
                utils.smooth(
                    utils.coherence(
                        daynoise.cross.c1Z,
                        daynoise.power.c11,
                        daynoise.power.cZZ), 50))
            coh_1P_all.append(
                utils.smooth(
                    utils.coherence(
                        daynoise.cross.c1P,
                        daynoise.power.c11,
                        daynoise.power.cPP), 50))
            coh_2Z_all.append(
                utils.smooth(
                    utils.coherence(
                        daynoise.cross.c2Z,
                        daynoise.power.c22,
                        daynoise.power.cZZ), 50))
            coh_2P_all.append(
                utils.smooth(
                    utils.coherence(
                        daynoise.cross.c2P,
                        daynoise.power.c22,
                        daynoise.power.cPP), 50))
            coh_ZP_all.append(
                utils.smooth(
                    utils.coherence(
                        daynoise.cross.cZP,
                        daynoise.power.cZZ,
                        daynoise.power.cPP), 50))

            # Phase
            try:
                ph_12_all.append(
                    180./np.pi*utils.phase(daynoise.cross.c12))
            except:
                ph_12_all.append(None)
            try:
                ph_1Z_all.append(
                    180./np.pi*utils.phase(daynoise.cross.c1Z))
            except:
                ph_1Z_all.append(None)
            try:
                ph_1P_all.append(
                    180./np.pi*utils.phase(daynoise.cross.c1P))
            except:
                ph_1P_all.append(None)
            try:
                ph_2Z_all.append(
                    180./np.pi*utils.phase(daynoise.cross.c2Z))
            except:
                ph_2Z_all.append(None)
            try:
                ph_2P_all.append(
                    180./np.pi*utils.phase(daynoise.cross.c2P))
            except:
                ph_2P_all.append(None)
            try:
                ph_ZP_all.append(
                    180./np.pi*utils.phase(daynoise.cross.cZP))
            except:
                ph_ZP_all.append(None)

            # Admittance
            ad_12_all.append(utils.smooth(utils.admittance(
                daynoise.cross.c12, daynoise.power.c11), 50))
            ad_1Z_all.append(utils.smooth(utils.admittance(
                daynoise.cross.c1Z, daynoise.power.c11), 50))
            ad_1P_all.append(utils.smooth(utils.admittance(
                daynoise.cross.c1P, daynoise.power.c11), 50))
            ad_2Z_all.append(utils.smooth(utils.admittance(
                daynoise.cross.c2Z, daynoise.power.c22), 50))
            ad_2P_all.append(utils.smooth(utils.admittance(
                daynoise.cross.c2P, daynoise.power.c22), 50))
            ad_ZP_all.append(utils.smooth(utils.admittance(
                daynoise.cross.cZP, daynoise.power.cZZ), 50))

            t1 += 3600.*24.

        # Convert to numpy arrays
        coh_all = np.array(coh_all)
        ph_all = np.array(ph_all)
        coh_12_all = np.array(coh_12_all)
        coh_1Z_all = np.array(coh_1Z_all)
        coh_1P_all = np.array(coh_1P_all)
        coh_2Z_all = np.array(coh_2Z_all)
        coh_2P_all = np.array(coh_2P_all)
        coh_ZP_all = np.array(coh_ZP_all)
        ph_12_all = np.array(ph_12_all)
        ph_1Z_all = np.array(ph_1Z_all)
        ph_1P_all = np.array(ph_1P_all)
        ph_2Z_all = np.array(ph_2Z_all)
        ph_2P_all = np.array(ph_2P_all)
        ph_ZP_all = np.array(ph_ZP_all)
        ad_12_all = np.array(ad_12_all)
        ad_1Z_all = np.array(ad_1Z_all)
        ad_1P_all = np.array(ad_1P_all)
        ad_2Z_all = np.array(ad_2Z_all)
        ad_2P_all = np.array(ad_2P_all)
        ad_ZP_all = np.array(ad_ZP_all)

        # Store transfer functions as objects for plotting
        coh = Cross(coh_12_all, coh_1Z_all, coh_1P_all,
                    coh_2Z_all, coh_2P_all, coh_ZP_all)
        ph = Cross(ph_12_all, ph_1Z_all, ph_1P_all,
                   ph_2Z_all, ph_2P_all, ph_ZP_all)
        ad = Cross(ad_12_all, ad_1Z_all, ad_1P_all,
                   ad_2Z_all, ad_2P_all, ad_ZP_all)

        # Quality control to identify outliers
        stanoise.QC_sta_spectra(pd=args.pd, tol=args.tol, alpha=args.alpha,
                                fig_QC=args.fig_QC, debug=args.debug,
                                save=plotpath, form=args.form)

        # Average spectra for good days
        stanoise.average_sta_spectra(
            fig_average=args.fig_average,
            save=plotpath, form=args.form)

        if args.fig_av_cross:
            fname = stkey + '.' + 'av_coherence'
            plot = plotting.fig_av_cross(stanoise.f, coh, stanoise.gooddays,
                              'Coherence', stanoise.ncomp, key=stkey, lw=0.5)
            # if plotpath.is_dir():
            if plotpath:
                plot.savefig(str(plotpath / (fname + '.' + args.form)),
                            dpi=300, bbox_inches='tight', format=args.form)
            else:
                plot.show()

            fname = stkey + '.' + 'av_admittance'
            plot = plotting.fig_av_cross(stanoise.f, ad, stanoise.gooddays,
                              'Admittance', stanoise.ncomp, key=stkey, lw=0.5)

            if plotpath:
                plot.savefig(str(plotpath / (fname + '.' + args.form)),
                            dpi=300, bbox_inches='tight', format=args.form)
            else:
                plot.show()

            fname = stkey + '.' + 'av_phase'
            plot = plotting.fig_av_cross(stanoise.f, ph, stanoise.gooddays,
                              'Phase', stanoise.ncomp, key=stkey, marker=',', lw=0)

            if plotpath:
                plot.savefig(str(plotpath / (fname + '.' + args.form)),
                            dpi=300, bbox_inches='tight', format=args.form)
            else:
                plot.show()

        if args.fig_coh_ph and stanoise.direc is not None:
            fname = stkey + '.' + 'coh_ph'
            plot = plotting.fig_coh_ph(coh_all, ph_all, stanoise.direc)
            if plotpath:
                plot.savefig(str(plotpath / (fname + '.' + args.form)),
                            dpi=300, bbox_inches='tight', format=args.form)
            else:
                plot.show()

        # Save to file
        stanoise.save(fileavst)
Beispiel #2
0
class atacr_monthly_sta(object):
    
    def __init__(self, inv, datadir, outdir, year, month, overlap = 0.5, window = 21000., chan_rank = ['L', 'H', 'B'], sps = 1.):
        network     = inv.networks[0]
        station     = network[0]
        channel     = station[0]
        self.stdb_inv   = stdb.StDbElement(network = network.code, station = station.code, channel = channel.code[:2],\
            location = channel.location_code, latitude = station.latitude, longitude = station.longitude,\
                elevation = station.elevation, polarity=1., azcorr=0., startdate = station.start_date,\
                    enddate = station.end_date, restricted_status = station.restricted_status)
        self.datadir    = datadir
        self.outdir     = outdir
        self.year       = year
        self.month      = month
        self.overlap    = overlap
        self.window     = window
        self.staid      = network.code+'.'+station.code
        self.chan_rank  = chan_rank
        self.stanoise   = StaNoise()
        self.stlo       = station.longitude
        self.stla       = station.latitude
        self.monthdir   = self.datadir + '/%04d.%s' %(self.year, monthdict[self.month])
        self.sps        = sps
        return
    
    def transfer_func(self):
        """compute monthly transfer function
        """
        targetdt    = 1./self.sps
        stime       = obspy.UTCDateTime('%04d%02d01' %(self.year, self.month))
        monthdir    = self.monthdir
        if not os.path.isdir(monthdir):
            return False
        chan_type   = None
        Nday        = 0
        while( (stime.year == self.year) and (stime.month == self.month)):
            daydir  = monthdir+'/%d.%s.%d' %(self.year, monthdict[self.month], stime.day)
            if not os.path.isdir(daydir):
                stime   += 86400.
                continue 
            fpattern= daydir+'/ft_%d.%s.%d.%s' %(self.year, monthdict[self.month], stime.day, self.staid)
            if chan_type is None:
                for chtype in self.chan_rank:
                    fname1  = fpattern+'.%sH1.SAC' %chtype
                    fname2  = fpattern+'.%sH2.SAC' %chtype
                    fnamez  = fpattern+'.%sHZ.SAC' %chtype
                    fnamep  = fpattern+'.%sDH.SAC' %chtype
                    if os.path.isfile(fname1) and os.path.isfile(fname1) and \
                        os.path.isfile(fnamez) and os.path.isfile(fnamep):
                        chan_type   = chtype
                        break
            if chan_type is None:
                stime   += 86400.
                continue
            fname1  = fpattern+'.%sH1.SAC' %chan_type
            fname2  = fpattern+'.%sH2.SAC' %chan_type
            fnamez  = fpattern+'.%sHZ.SAC' %chan_type
            fnamep  = fpattern+'.%sDH.SAC' %chan_type
            if not (os.path.isfile(fname1) and os.path.isfile(fname1) and \
                    os.path.isfile(fnamez) and os.path.isfile(fnamep)):
                stime   += 86400.
                continue
            tr1     = obspy.read(fname1)[0]
            stimetr = tr1.stats.starttime
            tr2     = obspy.read(fname2)[0]
            trZ     = obspy.read(fnamez)[0]
            trP     = obspy.read(fnamep)[0]
            
            if abs(tr1.stats.delta - targetdt) > 1e-3 or abs(tr2.stats.delta - targetdt) > 1e-3 or \
                abs(trZ.stats.delta - targetdt) > 1e-3 or abs(trP.stats.delta - targetdt) > 1e-3:
                raise ValueError('!!! CHECK fs :'+ self.staid)
            else:
                tr1.stats.delta     = targetdt
                tr2.stats.delta     = targetdt
                trP.stats.delta     = targetdt
                trZ.stats.delta     = targetdt
            # # # if np.all(tr1.data == 0.) or np.all(tr2.data == 0.) or np.all(trZ.data == 0.) or np.all(trP.data == 0.):
            # # #     stime   += 86400.
            # # #     continue
            tr1.trim(starttime = stimetr, endtime = stimetr + 8400.*10-1)
            tr2.trim(starttime = stimetr, endtime = stimetr + 8400.*10-1)
            trZ.trim(starttime = stimetr, endtime = stimetr + 8400.*10-1)
            trP.trim(starttime = stimetr, endtime = stimetr + 8400.*10-1)
            
            # # # print (self.staid)
            if np.all(trP.data == 0.) and not (np.all(tr1.data == 0.) or np.all(tr2.data == 0.)):
                self.stanoise   += DayNoise(tr1=tr1, tr2=tr2, trZ=trZ, trP=obspy.Trace(), overlap=self.overlap, window = self.window)
                self.out_dtype  = 'Z2-1'
            elif (np.all(tr1.data == 0.) or np.all(tr2.data == 0.)) and (not np.all(trP.data == 0.)):
                self.stanoise   += DayNoise(tr1=obspy.Trace(), tr2=obspy.Trace(), trZ=trZ, trP=trP, overlap=self.overlap, window = self.window)
                self.out_dtype  = 'ZP'
            elif (not (np.all(tr1.data == 0.) or np.all(tr2.data == 0.))) and (not np.all(trP.data == 0.)):
                self.stanoise   += DayNoise(tr1=tr1, tr2=tr2, trZ=trZ, trP=trP, overlap=self.overlap, window = self.window)
                self.out_dtype  = 'ZP-21'
            else:
                stime   += 86400.
                continue
            stime   += 86400.
            Nday    += 1
        if Nday <= 1:
            return False
        self.stanoise.QC_sta_spectra()
        self.stanoise.average_sta_spectra()
        self.tfnoise= TFNoise(self.stanoise)
        self.tfnoise.transfer_func()
        return True
    
    def correct(self):
        """compute monthly transfer function
        """
        targetdt    = 1./self.sps
        stime       = obspy.UTCDateTime('%04d%02d01' %(self.year, self.month))
        monthdir    = self.monthdir
        omonthdir   = self.outdir + '/%04d.%s' %(self.year, monthdict[self.month])
        if not os.path.isdir(monthdir):
            return False
        chan_type   = None
        while( (stime.year == self.year) and (stime.month == self.month)):
            daydir      = monthdir+'/%d.%s.%d' %(self.year, monthdict[self.month], stime.day)
            fpattern    = daydir+'/ft_%d.%s.%d.%s' %(self.year, monthdict[self.month], stime.day, self.staid)
            odaydir     = omonthdir+'/%d.%s.%d' %(self.year, monthdict[self.month], stime.day)
            if not os.path.isdir(odaydir):
                os.makedirs(odaydir)
            if chan_type is None:
                for chtype in self.chan_rank:
                    fname1  = fpattern+'.%sH1.SAC' %chtype
                    fname2  = fpattern+'.%sH2.SAC' %chtype
                    fnamez  = fpattern+'.%sHZ.SAC' %chtype
                    fnamep  = fpattern+'.%sDH.SAC' %chtype
                    if os.path.isfile(fname1) and os.path.isfile(fname2) and \
                        os.path.isfile(fnamez) and os.path.isfile(fnamep):
                        chan_type   = chtype
                        break
            if chan_type is None:
                stime   += 86400.
                continue
            fname1  = fpattern+'.%sH1.SAC' %chan_type
            fname2  = fpattern+'.%sH2.SAC' %chan_type
            fnamez  = fpattern+'.%sHZ.SAC' %chan_type
            fnamep  = fpattern+'.%sDH.SAC' %chan_type
            if not (os.path.isfile(fname1) and os.path.isfile(fname2) and \
                    os.path.isfile(fnamez) and os.path.isfile(fnamep)):
                stime   += 86400.
                continue
            tr1     = obspy.read(fname1)[0]
            stimetr = tr1.stats.starttime
            tr2     = obspy.read(fname2)[0]
            trZ     = obspy.read(fnamez)[0]
            trP     = obspy.read(fnamep)[0]
            
            if (np.all(tr1.data == 0.) or np.all(tr2.data == 0.)) and np.all(trP.data == 0.):
                stime   += 86400.
                continue
            
            if abs(tr1.stats.delta - targetdt) > 1e-3 or abs(tr2.stats.delta - targetdt) > 1e-3 or \
                abs(trZ.stats.delta - targetdt) > 1e-3 or abs(trP.stats.delta - targetdt) > 1e-3:
                raise ValueError('!!! CHECK fs :'+ self.staid)
            else:
                tr1.stats.delta     = targetdt
                tr2.stats.delta     = targetdt
                trP.stats.delta     = targetdt
                trZ.stats.delta     = targetdt
            
            outfnameZ   = odaydir+'/ft_%d.%s.%d.%s.%sHZ.SAC' %(self.year, monthdict[self.month], stime.day, self.staid, chan_type)
            # sliding window raw data
            StreamZ = obspy.Stream()
            overlap = 0.99
            for tmptr in trZ.slide(window_length = self.window-1, step = int((self.window-1)*overlap)):
                # print (tmptr.stats.npts)
                StreamZ += tmptr.copy()
            Stream1 = obspy.Stream()
            for tmptr in tr1.slide(window_length = self.window-1, step = int((self.window-1)*overlap)):
                Stream1 += tmptr.copy()
            Stream2 = obspy.Stream()
            for tmptr in tr2.slide(window_length = self.window-1, step = int((self.window-1)*overlap)):
                Stream2 += tmptr.copy()
            StreamP = obspy.Stream()
            for tmptr in trP.slide(window_length = self.window-1, step = int((self.window-1)*overlap)):
                StreamP += tmptr.copy()
            # remove tilt and compliance
            outStreamZ  = obspy.Stream()
            Ntraces     = len(StreamZ)
            for itr in range(Ntraces):
                sth     = obspy.Stream()
                if not (np.all(Stream1[itr].data == 0.) or np.all(Stream1[itr].data == 0.)):
                    sth     += Stream1[itr]
                    sth     += Stream2[itr]
                sth     += StreamZ[itr]
                stp     = obspy.Stream()
                if not np.all(StreamP[itr].data == 0.):
                    stp     += StreamP[itr]
                tmptime = StreamZ[itr].stats.starttime
                tstamp  = str(tmptime.year).zfill(4)+'.' + \
                    str(tmptime.julday).zfill(3)+'.'
                tstamp  = tstamp + str(tmptime.hour).zfill(2) + \
                            '.'+str(tmptime.minute).zfill(2)
                if self.out_dtype == 'ZP':
                    ncomp   = 2
                elif self.out_dtype == 'Z2-1':
                    ncomp   = 3
                elif self.out_dtype  == 'ZP-21':
                    ncomp   = 4
                
                eventstream = EventStream( sta = self.stdb_inv, sth = sth, stp = stp,\
                    tstamp = tstamp, lat = self.stla, lon = self.stlo, time = tmptime,\
                    window = self.window,
                    sampling_rate = 1., ncomp = ncomp)
                eventstream.correct_data(self.tfnoise)
                tmptr       = StreamZ[itr].copy()
                tmptr.data  = eventstream.correct[self.out_dtype].copy()
                outStreamZ  += tmptr
                # outStreamZ.data = 
            # merge data
            outStreamZ.merge(method = 1, fill_value = 'interpolate', interpolation_samples=2)
            outTrZ  = outStreamZ[0]
            if os.path.isfile(outfnameZ):
                shutil.copyfile(src = outfnameZ, dst = outfnameZ+'_old')
                os.remove(outfnameZ)
            outTrZ.write(outfnameZ, format = 'SAC')
            stime   += 86400.