示例#1
0
 def test_SVD_mag(self):
     """Test the SVD magnitude calculator."""
     # Do the set-up
     testing_path = os.path.join(os.path.abspath(os.path.dirname(__file__)),
                                 'test_data', 'similar_events_processed')
     stream_files = glob.glob(os.path.join(testing_path, '*DFDPC*'))
     stream_list = [read(stream_file) for stream_file in stream_files]
     event_list = []
     for i, stream in enumerate(stream_list):
         st_list = []
         for tr in stream:
             if (tr.stats.station, tr.stats.channel) not in\
                     [('WHAT2', 'SH1'), ('WV04', 'SHZ'), ('GCSZ', 'EHZ')]:
                 stream.remove(tr)
                 continue
             st_list.append(i)
         event_list.append(st_list)
     event_list = np.asarray(event_list).T.tolist()
     SVectors, SValues, Uvectors, stachans = svd(stream_list=stream_list)
     M, events_out = svd_moments(u=Uvectors,
                                 s=SValues,
                                 v=SVectors,
                                 stachans=stachans,
                                 event_list=event_list)
     self.assertEqual(len(M), len(stream_list))
     self.assertEqual(len(events_out), len(stream_list))
示例#2
0
 def test_svd_plot(self):
     from eqcorrscan.utils.clustering import svd, svd_to_stream
     uvec, sval, svec, stachans = svd(stream_list=self.stream_list)
     svstreams = svd_to_stream(uvectors=uvec, stachans=stachans, k=3,
                               sampling_rate=100)
     fig = svd_plot(svstreams=svstreams, svalues=sval, stachans=stachans,
                    show=False, return_figure=True)
     return fig[0]
示例#3
0
 def test_svd_to_stream(self):
     """Test the conversion of SVD to stream."""
     samp_rate = 100
     testing_path = os.path.join(
         self.testing_path, 'similar_events_processed')
     stream_files = glob.glob(os.path.join(testing_path, '*'))
     stream_list = [read(stream_file) for stream_file in stream_files]
     SVectors, SValues, Uvectors, stachans = svd(stream_list=stream_list)
     svstreams = svd_to_stream(uvectors=SVectors, stachans=stachans, k=4,
                               sampling_rate=samp_rate)
     self.assertEqual(len(svstreams), 4)
示例#4
0
 def test_svd(self):
     """Test the svd method."""
     testing_path = os.path.join(self.testing_path,
                                 'similar_events_processed')
     stream_files = glob.glob(os.path.join(testing_path, '*'))
     stream_list = [read(stream_file) for stream_file in stream_files]
     UVectors, SValues, SVectors, stachans = svd(stream_list=stream_list)
     self.assertEqual(len(SVectors), len(stachans))
     self.assertEqual(len(SValues), len(stachans))
     self.assertEqual(len(UVectors), len(stachans))
     for SVec in SVectors:
         self.assertEqual(len(SVec), len(stream_list))
示例#5
0
 def test_svd(self):
     """Test the svd method."""
     testing_path = os.path.join(self.testing_path, 'similar_events')
     stream_files = glob.glob(os.path.join(testing_path, '*'))
     stream_list = [read(stream_file) for stream_file in stream_files]
     for stream in stream_list:
         for tr in stream:
             if tr.stats.station not in ['WHAT2', 'WV04', 'GCSZ']:
                 stream.remove(tr)
                 continue
             tr.detrend('simple')
             tr.filter('bandpass', freqmin=5.0, freqmax=15.0)
             tr.trim(tr.stats.starttime + 40, tr.stats.endtime - 45)
     UVectors, SValues, SVectors, stachans = svd(stream_list=stream_list)
     self.assertEqual(len(SVectors), len(stachans))
     self.assertEqual(len(SValues), len(stachans))
     self.assertEqual(len(UVectors), len(stachans))
     for SVec in SVectors:
         self.assertEqual(len(SVec), len(stream_list))
     with warnings.catch_warnings(record=True) as w:
         SVD(stream_list=stream_list)
         self.assertEqual(len(w), 1)
         self.assertTrue('Depreciated' in str(w[0].message))
示例#6
0
def SVD_sim(sp, lowcut, highcut, samp_rate, amp_range=np.arange(-10, 10,
                                                                0.01)):
    """
    Generate basis vectors of a set of simulated seismograms.

    Inputs should have a range of S-P amplitude ratios, in theory to simulate \
    a range of focal mechanisms.

    :type sp: int
    :param sp: S-P time in seconds - will be converted to samples according \
        to samp_rate.
    :type lowcut: float
    :param lowcut: Low-cut for bandpass filter in Hz
    :type highcut: float
    :param highcut: High-cut for bandpass filter in Hz
    :type samp_rate: float
    :param samp_rate: Sampling rate in Hz
    :type amp_range: numpy.ndarray
    :param amp_range: Amplitude ratio range to generate synthetics for.

    :returns: set of output basis vectors
    :rtype: :class:`numpy.ndarray`
    """
    # Convert SP to samples
    sp = int(sp * samp_rate)
    # Scan through a range of amplitude ratios
    synthetics = [Stream(Trace(seis_sim(sp, a))) for a in amp_range]
    for st in synthetics:
        for tr in st:
            tr.stats.station = 'SYNTH'
            tr.stats.channel = 'SH1'
            tr.stats.sampling_rate = samp_rate
            tr.filter('bandpass', freqmin=lowcut, freqmax=highcut)
    # We have a list of obspy Trace objects, we can pass this to EQcorrscan's
    # SVD functions
    U, s, V, stachans = clustering.svd(synthetics)
    return U, s, V, stachans
示例#7
0
 def test_svd_to_stream(self):
     """Test the conversion of SVD to stream."""
     samp_rate = 100
     testing_path = os.path.join(self.testing_path, 'similar_events')
     stream_files = glob.glob(os.path.join(testing_path, '*'))
     stream_list = [read(stream_file) for stream_file in stream_files]
     for stream in stream_list:
         for tr in stream:
             if tr.stats.station not in ['WHAT2', 'WV04', 'GCSZ']:
                 stream.remove(tr)
                 continue
             tr.detrend('simple')
             tr.filter('bandpass', freqmin=5.0, freqmax=15.0)
             tr.resample(sampling_rate=samp_rate)
             tr.trim(tr.stats.starttime + 40, tr.stats.endtime - 45)
     SVectors, SValues, Uvectors, stachans = svd(stream_list=stream_list)
     svstreams = svd_to_stream(uvectors=SVectors, stachans=stachans, k=4,
                               sampling_rate=samp_rate)
     self.assertEqual(len(svstreams), 4)
     with warnings.catch_warnings(record=True) as w:
         SVD_2_stream(uvectors=SVectors, stachans=stachans, k=4,
                      sampling_rate=samp_rate)
         self.assertEqual(len(w), 1)
         self.assertTrue('Depreciated' in str(w[0].message))
示例#8
0
    def construct(self,
                  streams,
                  lowcut,
                  highcut,
                  filt_order,
                  sampling_rate,
                  multiplex,
                  name,
                  align,
                  shift_len=0,
                  reject=0.3,
                  no_missed=True,
                  plot=False):
        """
        Construct a subspace detector from a list of streams, full rank.

        Subspace detector will be full-rank, further functions can be used \
        to select the desired dimensions.

        :type streams: list
        :param streams:
            List of :class:`obspy.core.stream.Stream` to be used to generate
            the subspace detector.  These should be pre-clustered and aligned.
        :type lowcut: float
        :param lowcut: Lowcut in Hz, can be None to not apply filter
        :type highcut: float
        :param highcut: Highcut in Hz, can be None to not apply filter
        :type filt_order: int
        :param filt_order: Number of corners for filter.
        :type sampling_rate: float
        :param sampling_rate: Desired sampling rate in Hz
        :type multiplex: bool
        :param multiplex:
            Whether to multiplex the data or not.  Data are multiplexed
            according to the method of Harris, see the multi function for
            details.
        :type name: str
        :param name: Name of the detector, used for book-keeping.
        :type align: bool
        :param align:
            Whether to align the data or not - needs to be done at some point
        :type shift_len: float
        :param shift_len: Maximum shift allowed for alignment in seconds.
        :type reject: float
        :param reject:
            Minimum correlation to include traces - only used if align=True.
        :type no_missed: bool
        :param no_missed:
            Reject streams with missed traces, defaults to True. A missing
            trace from lots of events will reduce the quality of the subspace
            detector if multiplexed.  Only used when multi is set to True.
        :type plot: bool
        :param plot: Whether to plot the alignment stage or not.

        .. note::
            The detector will be normalized such that the data, before
            computing the singular-value decomposition, will have unit energy.
            e.g. We divide the amplitudes of the data by the L1 norm of the
            data.

        .. warning::
            EQcorrscan's alignment will attempt to align over the whole data
            window given.  For long (more than 2s) chunks of data this can give
            poor results and you might be better off using the
            :func:`eqcorrscan.utils.stacking.align_traces` function externally,
            focusing on a smaller window of data.  To do this you would align
            the data prior to running construct.
        """
        self.lowcut = lowcut
        self.highcut = highcut
        self.filt_order = filt_order
        self.sampling_rate = sampling_rate
        self.name = name
        self.multiplex = multiplex
        # Pre-process data
        p_streams, stachans = _subspace_process(streams=copy.deepcopy(streams),
                                                lowcut=lowcut,
                                                highcut=highcut,
                                                filt_order=filt_order,
                                                sampling_rate=sampling_rate,
                                                multiplex=multiplex,
                                                align=align,
                                                shift_len=shift_len,
                                                reject=reject,
                                                plot=plot,
                                                no_missed=no_missed)
        # Compute the SVD, use the cluster.SVD function
        u, sigma, v, svd_stachans = svd(stream_list=p_streams, full=True)
        self.stachans = stachans
        # self.delays = delays
        self.u = u
        self.v = v
        self.sigma = sigma
        self.data = copy.deepcopy(u)  # Set the data matrix to be full rank U.
        self.dimension = np.inf
        return self
示例#9
0
def relative_mag_calc(cat, template_dict, n_SVs=4, plot=False, debug=1):
    """
    Now we're going to loop through templates, filter out poorly correlated waveforms,
    compute SVD and relative magnitudes using EQcorrscan functions, then map relative
    mags to real magnitudes using template local magnitudes
    """
    from eqcorrscan.utils.plotting import multi_trace_plot
    from obspy.core.event import ResourceIdentifier
    import matplotlib.pyplot as plt
    # Assign shifts for detections to template dictionary
    new_cat = Catalog()
    # Random sample of template ids for plotting
    samp_ids = [
        id for i, id in enumerate(template_dict.keys())
        if i in np.random.choice(
            range(len(template_dict)), len(template_dict) // 20, replace=False)
    ]
    for tid, det_dict in template_dict.iteritems():
        # Perform some checks on the dictionary first
        if len(det_dict) <= 1:
            print('%s has <= one detection. No magnitude will be calculated.' %
                  str(tid))
            continue
        else:
            print('Working on detections for template: %s' % str(tid))
            if 'self' not in [
                    str(key).split('/')[-1].split('_')[-1]
                    for key in det_dict.keys()
            ]:
                print(
                    'Self detection not located in catalog. Moving to next template.'
                )
                continue
            inds = det_dict['aligned_inds']
            stream_list = det_dict['aligned']
            # Do SVD
            if len(stream_list) <= n_SVs:
                warnings.warn(
                    'Fewer streams then nSVs passed to SVD. Moving to next template'
                )
                continue
            svd_dict = clustering.svd(stream_list, full=True)
            if plot:
                if tid in samp_ids:
                    for stachan in svd_dict:
                        if 'svectors' in svd_dict[stachan]:
                            if len(svd_dict[stachan]['svectors']) > 0:
                                if len(svd_dict[stachan]['events']) < 5:
                                    # we will not plot stachans with only one event
                                    continue
                                fig, axes = plt.subplots(len(
                                    svd_dict[stachan]['events']),
                                                         1,
                                                         sharex=True,
                                                         figsize=(14, 24),
                                                         squeeze=False)
                                first_SV = svd_dict[stachan]['svectors'][0]
                                first_SVal = svd_dict[stachan]['svalues'][0]
                                for i, ev_ind in enumerate(
                                        svd_dict[stachan]['events']):
                                    data_tr = stream_list[ev_ind].select(
                                        station=stachan.split('.')[0],
                                        channel=stachan.split('.')[1])[0]
                                    samp_rate = data_tr.stats.sampling_rate
                                    SV_y = first_SV * first_SVal
                                    SV_x = np.arange(len(SV_y))
                                    SV_x = SV_x / samp_rate
                                    dat_y = data_tr.data
                                    U_wt = np.matrix(
                                        copy.deepcopy(
                                            svd_dict[stachan]['uvectors']))
                                    svd_wts = np.array(
                                        U_wt[:, 0]).reshape(-1).tolist()
                                    axes[i, 0].plot(SV_x,
                                                    SV_y * svd_wts[i],
                                                    color='r')
                                    axes[i, 0].plot(SV_x, dat_y, color='k')
                                    axes[i,
                                         0].text(0.9,
                                                 0.15,
                                                 str(svd_wts[i]),
                                                 bbox=dict(facecolor='white',
                                                           alpha=0.95),
                                                 transform=axes[i,
                                                                0].transAxes)
                                    axes[i, 0].text(
                                        0.7,
                                        0.85,
                                        data_tr.stats.starttime.datetime.
                                        strftime('%Y/%m/%d %H:%M:%S'),
                                        bbox=dict(facecolor='white',
                                                  alpha=0.95),
                                        transform=axes[i, 0].transAxes)
                                fig.suptitle('%s\nChannel: %s First SVal: %f' %
                                             (str(tid), stachan, first_SVal))
                                fig.show()
            # Feed output vectors and values to mag_calc.SVD_moments
            M, events_out = mag_calc.SVD_moments(svd_dict, n_SVs, debug=debug)
            # Find rel_amp of self detection
            try:
                rel_amp_t = [
                    M[i] for i, cat_ind in enumerate(inds)
                    if i in events_out and cat_ind == det_dict['temp_ind']
                ][0]
            except:
                warnings.warn(
                    'Relative amp not calculated for template in this case....investigate'
                )
                continue
            # Convert relative values to template values
            Mls = [
                np.log10(rel_amp_i / rel_amp_t) + det_dict['temp_mag']
                for rel_amp_i in M
            ]
            if len(Mls) != len(events_out):
                warnings.warn('Not same number of local mags and out events')
            for i, cat_ind in enumerate(inds):
                if i in events_out:
                    Mls_ind = [
                        k for k, ev in enumerate(events_out) if ev == i
                    ][0]
                    if cat_ind == det_dict['temp_ind']:
                        event = cat[cat_ind].copy()
                        event.magnitudes.append(
                            Magnitude(mag=det_dict['temp_mag'],
                                      creation_info=(CreationInfo(
                                          author='SeisComp'))))
                        new_cat.append(event)
                    else:
                        event = cat[cat_ind].copy()
                        event.magnitudes.append(
                            Magnitude(
                                mag=Mls[Mls_ind],
                                creation_info=(CreationInfo(
                                    author=
                                    'eqcorrscan.utils.mag_calc.SVD_moment'))))
                        new_cat.append(event)

    return new_cat
示例#10
0
def party_relative_mags(party, self_files, shift_len, align_len, svd_len,
                        reject, sac_dir, min_amps, calibrate=False,
                        method='PCA'):
    """
    Calculate the relative moments for detections in a Family using
    mag_calc.svd_moments()

    :param party: Party of detections
    :param shift_len: Maximum shift length used in waveform alignment
    :param align_len: Length of waveform used for correlation in alignment
    :param svd_len: Length of waveform used in relative amplitude calc
    :param reject: Min cc threshold for accepted measurement
    :param sac_dir: Root directory of waveforms
    :param min_amps: Minimum number of relative measurements per pair
    :param calibrate: Flag for calibration to a priori Ml's
    :param method: 'PCA' or 'LSQR'
    :return:
    """

    # First read-in self detection names
    selfs = []
    for self_file in self_files:
        with open(self_file, 'r') as f:
            rdr = csv.reader(f)
            for row in rdr:
                selfs.append(str(row[0]))
    for fam in party.families:
        print('Starting work on family %s' % fam.template.name)
        if len(fam) == 1:
            print('Only self-detection. Moving on.')
            continue
        temp = fam.template
        prepick = temp.prepick
        events = [det.event for det in fam.detections]
        # Here we'll read in the waveforms and trim from stefan's directory
        # of SAC files so as not to duplicate data
        ev_dirs = ['%s%s' % (sac_dir, str(ev.resource_id).split('/')[-1])
                   for ev in events]
        streams = []
        if len([i for i, ev_dir in enumerate(ev_dirs)
                    if ev_dir.split('/')[-1] in selfs]) == 0:
            print('Family %s has no self detection. Investigate'
                  % fam.template.name)
            continue
        self_ind = [i for i, ev_dir in enumerate(ev_dirs)
                    if ev_dir.split('/')[-1] in selfs][0]
        # Read in Z components of events which we wrote for stefan
        # Many of these ev_dirs will not exist!
        for i, ev_dir in enumerate(ev_dirs):
            raw_st = Stream()
            print('Reading %s' % ev_dir)
            for wav_file in glob('%s/*Z.sac' % ev_dir):
                print('...file %s' % wav_file)
                raw_tr = read(wav_file)[0]
                start = raw_tr.stats.starttime + raw_tr.stats.sac['a'] - 3.
                end = start + 10
                raw_tr.trim(starttime=start, endtime=end)
                raw_st.traces.append(raw_tr)
            streams.append(raw_st)
        print('Moved self detection to top of list')
        # Move the self detection to the first element
        streams.insert(0, streams.pop(self_ind))
        print('Template Stream: %s' % str(streams[0]))
        if len(streams[0]) == 0:
            print('Template %s waveforms did not get written to SAC.' %
                  temp.name)
            continue
        # Front/back clip hardcoded relative to wavs starting 3 s before pick
        front_clip = 3.0 - shift_len - 0.05 - prepick
        back_clip = front_clip + align_len + (2 * shift_len) + 0.05
        wrk_streams = [] # For aligning
        # Process streams then copy to both ccc_streams and svd_streams
        bad_streams = []
        for i, st in enumerate(list(streams)):
            try:
                shortproc(st=streams[i], lowcut=temp.lowcut,
                          highcut=temp.highcut, filt_order=temp.filt_order,
                          samp_rate=temp.samp_rate)
                wrk_streams.append(st.copy())
            except ValueError as e:
                print('ValueError reads:')
                print(str(e))
                print('Attempting to remove bad trace at {}'.format(
                    str(e).split(' ')[-1]))
                bad_tr = str(e).split(' ')[-1][:-1] # Eliminate trailing "'"
                print('Sta and chan names: {}'.format(bad_tr.split('.')))
                try:
                    tr = streams[i].select(station=bad_tr.split('.')[0],
                                           channel=bad_tr.split('.')[1])[0]
                    streams[i].traces.remove(tr)
                    shortproc(st=streams[i], lowcut=temp.lowcut,
                              highcut=temp.highcut,
                              filt_order=temp.filt_order,
                              samp_rate=temp.samp_rate)
                    wrk_streams.append(st.copy())
                except IndexError as e:
                    print(str(e))
                    print('Funkyness. Removing entire stream')
                    bad_streams.append(st)
        if len(bad_streams) > 0:
            for bst in bad_streams:
                streams.remove(bst)
        svd_streams = copy.deepcopy(streams) # For svd
        ccc_streams = copy.deepcopy(streams)
        # work out cccoh for each event with template
        cccohs = cc_coh_dets(streams=ccc_streams, shift=shift_len,
                             length=svd_len, wav_prepick=3.,
                             corr_prepick=0.05)
        for st in wrk_streams:
            for tr in st:
                tr.trim(starttime=tr.stats.starttime + front_clip,
                        endtime=tr.stats.starttime + back_clip)
        st_chans = list(set([(tr.stats.station, tr.stats.channel)
                             for st in wrk_streams for tr in st]))
        st_chans.sort()
        # Align streams with just P arrivals, then use longer st for svd
        print('Now aligning svd_streams')
        shift_inds = int(shift_len * fam.template.samp_rate)
        for st_chan in st_chans:
            trs = []
            for i, st in enumerate(wrk_streams):
                if len(st.select(station=st_chan[0], channel=st_chan[-1])) > 0:
                    trs.append((i, st.select(station=st_chan[0],
                                             channel=st_chan[-1])[0]))
            inds, traces = zip(*trs)
            shifts, ccs = stacking.align_traces(trace_list=list(traces),
                                                shift_len=shift_inds,
                                                positive=True,
                                                master=traces[0].copy())
            # We now have shifts based on P correlation, shift and trim
            # larger wavs for svd
            for j, shift in enumerate(shifts):
                st = svd_streams[inds[j]]
                if ccs[j] < reject:
                    svd_streams[inds[j]].remove(st.select(
                        station=st_chan[0], channel=st_chan[-1])[0])
                    print('Removing trace due to low cc value: %s' % ccs[j])
                    continue
                strt_tr = st.select(
                    station=st_chan[0], channel=st_chan[-1])[0].stats.starttime
                strt_tr += (3.0 - prepick - shift)
                st.select(station=st_chan[0],
                          channel=st_chan[-1])[0].trim(strt_tr,strt_tr
                                                       + svd_len)
        if method == 'LSQR':
            print('Using least-squares method')
            event_list = []
            for stachan in st_chans:
                st_list = []
                for i, st in enumerate(svd_streams):
                    if len(st.select(station=stachan[0],
                                     channel=stachan[-1])) > 0:
                        st_list.append(i)
                event_list.append(st_list)
            # event_list = np.asarray(event_list).tolist()
            u, sigma, v, sta_chans = svd(stream_list=svd_streams, full=True)
            try:
                M, events_out = svd_moments(u, sigma, v, sta_chans, event_list)
            except IOError as e:
                print('Family %s raised error %s' % (fam.template.name, e))
                continue
        elif method == 'PCA':
            print('Using principal component method')
            # Now loop over all detections and do svd for each matching
            # chan with temp
            events_out = []
            template = svd_streams[0]
            M = []
            for i, st in enumerate(svd_streams):
                if len(st) == 0:
                    print('Event not located, skipping')
                    continue
                ev_r_amps = []
                # For each pair of template:detection (including temp:temp)
                for tr in template:
                    if len(st.select(station=tr.stats.station,
                                     channel=tr.stats.channel)) > 0:
                        det_tr = st.select(station=tr.stats.station,
                                           channel=tr.stats.channel)[0]
                        # Convoluted way of getting two 'vert' vectors
                        data_mat = np.vstack((tr.data, det_tr.data)).T
                        U, sig, Vt = scipy.linalg.svd(data_mat,
                                                      full_matrices=True)
                        # Vt is 2x2 for two events
                        # Per Shelly et al., 2016 eq. 4
                        ev_r_amps.append(Vt[0][1] / Vt[0][0])
                if len(ev_r_amps) < min_amps:
                    print('Fewer than 4 amplitude picks, skipping.')
                    continue
                M.append(np.median(ev_r_amps))
                events_out.append(i)
        # If we have a Mag for template, calibrate moments
        if calibrate and len(fam.template.event.magnitudes) > 0:
            # Convert the template magnitude to seismic moment
            temp_mag = fam.template.event.magnitudes[-1].mag
            temp_mo = local_to_moment(temp_mag)
            # Extrapolate from the template moment - relative moment relationship to
            # Get the moment for relative moment = 1.0
            norm_mo = temp_mo / M[0]
            # Template is the last event in the list
            # Now these are weights which we can multiple the moments by
            moments = np.multiply(M, norm_mo)
            # Now convert to Mw
            Mw = [2.0 / 3.0 * (np.log10(m) - 9.0) for m in moments]
            Mw2, evs2 = remove_outliers(Mw, events_out)
            # Convert to local
            Ml = [0.88 * m + 0.73 for m in Mw2]
            #Normalize moments to template mag
            # Add calibrated mags to detection events
            for i, eind in enumerate(evs2):
                fam.detections[eind-1].event.magnitudes = [
                    Magnitude(mag=Mw2[i], magnitude_type='Mw')]
                fam.detections[eind-1].event.comments.append(
                    Comment(text=str(cccohs[eind-1])))
                fam.detections[eind-1].event.magnitudes.append(
                    Magnitude(mag=Ml[i], magnitude_type='ML'))
            fam.catalog = Catalog(events=[det.event for det in fam.detections])
    return party, cccohs
示例#11
0
def party_relative_mags(party, self_files, shift_len, align_len, svd_len,
                        reject, wav_dir, min_amps, m, c, calibrate=False,
                        method='PCA', plot_svd=False):
    """
    Calculate the relative moments for detections in a Family using
    mag_calc.svd_moments()

    :param party: Party of detections
    :param self_files: List of self-detection wav files (in order of families)
    :param shift_len: Maximum shift length used in waveform alignment
    :param align_len: Length of waveform used for correlation in alignment
    :param svd_len: Length of waveform used in relative amplitude calc
    :param reject: Min cc threshold for accepted measurement
    :param wav_dir: Root directory of waveforms
    :param min_amps: Minimum number of relative measurements per pair
    :param m: m in Mw = (m * ML) + c regression between Ml and Mw
    :param c: c in Mw = (m * ML) + c regression between Ml and Mw
    :param calibrate: Flag for calibration to a priori Ml's
    :param method: 'PCA' or 'LSQR'
    :param plot_svd: Bool to plot results of svd relative amplitude calcs
    :return:
    """
    pty = party.copy()
    # sort self files and parties by template name
    pty.families.sort(key=lambda x: x.template.name)
    self_files.sort()
    ev_files = glob('{}/*'.format(wav_dir))
    ev_files.sort()
    ev_files = {os.path.basename(f).rstrip('.ms'): f for f in ev_files}
    for i, fam in enumerate(pty.families):
        temp_wav = read(self_files[i])
        print('Starting work on family %s' % fam.template.name)
        if len(fam) == 0:
            print('No detections. Moving on.')
            continue
        temp = fam.template
        prepick = temp.prepick
        det_ids = [d.id for d in fam]
        # Read in waveforms for detections in family
        streams = [read(ev_files[id]) for id in det_ids]
        # Add template wav as the first element
        streams.insert(0, temp_wav)
        print('Template Stream: %s' % str(streams[0]))
        if len(streams[0]) == 0:
            print('Template %s waveforms did not get written. Investigate.' %
                  temp.name)
            continue
        # Process streams then copy to both ccc_streams and svd_streams
        print('Shortproc-ing streams')
        breakit = False
        for st in streams:
            # rms = [tr for tr in st if tr.stats.sampling_rate < temp.samp_rate]
            # for rm in rms:
            #     st.traces.remove(rm)
            try:
                shortproc(st=st, lowcut=temp.lowcut,
                          highcut=temp.highcut, filt_order=temp.filt_order,
                          samp_rate=temp.samp_rate)
            except ValueError as e:
                    breakit = True
        if breakit:
            print('Something wrong in shortproc. Skip family')
            continue
        # Remove all traces with no picks before copying
        for str_ind, st in enumerate(streams):
            if str_ind == 0:
                event = temp.event
            else:
                event = fam.detections[str_ind-1].event
            rms = []
            for tr in st:
                try:
                    [pk for pk in event.picks
                     if pk.waveform_id.get_seed_string() == tr.id][0]
                except IndexError:
                    rms.append(tr)
            for rm in rms:
                st.traces.remove(rm)
        print('Copying streams')
        wrk_streams = copy.deepcopy(streams)
        svd_streams = copy.deepcopy(streams)  # For svd
        ccc_streams = copy.deepcopy(streams)
        event_list = [temp.event] + [d.event for d in fam.detections]
        try:
            # work out cccoh for each event with template
            cccohs = cc_coh_dets(streams=ccc_streams, events=event_list,
                                 length=svd_len, corr_prepick=prepick,
                                 shift=shift_len)
        except (AssertionError, ValueError) as e:
            # Issue with trimming above?
            print(e)
            continue
        for eind, st in enumerate(wrk_streams):
            if eind == 0:
                event = temp.event
            else:
                event = fam.detections[eind-1].event
            for tr in st:
                pk = [pk for pk in event.picks
                      if pk.waveform_id.get_seed_string() == tr.id][0]
                tr.trim(starttime=pk.time - prepick - shift_len,
                        endtime=pk.time + shift_len + align_len)
        st_seeds = list(set([tr.id for st in wrk_streams for tr in st]))
        st_seeds.sort()
        # Align streams with just P arrivals, then use longer st for svd
        print('Now aligning svd_streams')
        shift_inds = int(shift_len * fam.template.samp_rate)
        for st_seed in st_seeds:
            trs = []
            for i, st in enumerate(wrk_streams):
                if len(st.select(id=st_seed)) > 0:
                    trs.append((i, st.select(id=st_seed)[0]))
            inds, traces = zip(*trs)
            shifts, ccs = stacking.align_traces(trace_list=list(traces),
                                                shift_len=shift_inds,
                                                positive=True,
                                                master=traces[0].copy())
            # We now have shifts based on P correlation, shift and trim
            # larger wavs for svd
            for j, shift in enumerate(shifts):
                st = svd_streams[inds[j]]
                if inds[j] == 0:
                    event = temp.event
                else:
                    event = fam.detections[inds[j]-1].event
                if ccs[j] < reject:
                    svd_streams[inds[j]].remove(st.select(id=st_seed)[0])
                    print('Removing trace due to low cc value: %s' % ccs[j])
                    continue
                pk = [pk for pk in event.picks
                      if pk.waveform_id.get_seed_string() == st_seed][0]
                strt_tr = pk.time - prepick - shift
                st.select(id=st_seed)[0].trim(strt_tr, strt_tr + svd_len)
        if method == 'LSQR':
            print('Using least-squares method')
            event_list = []
            for st_id in st_seeds:
                st_list = []
                for stind, st in enumerate(svd_streams):
                    if len(st.select(id=st_id)) > 0:
                        st_list.append(stind)
                event_list.append(st_list)
            # event_list = np.asarray(event_list).tolist()
            u, sigma, v, sta_chans = svd(stream_list=svd_streams, full=True)
            try:
                M, events_out = svd_moments(u, sigma, v, sta_chans, event_list)
            except IOError as e:
                print('Family %s raised error %s' % (fam.template.name, e))
                return
        elif method == 'PCA':
            print('Using principal component method')
            M, events_out = svd_relative_amps(fam, svd_streams, min_amps,
                                              plot=plot_svd)
            print(M, events_out)
            if len(M) == 0:
                print('No amplitudes calculated, skipping')
                continue
        else:
            print('{} not valid argument for mag calc method'.format(method))
            return
        # If we have a Mag for template, calibrate moments
        if calibrate and len(fam.template.event.magnitudes) > 0:
            print('Converting relative amps to magnitudes')
            # Convert the template magnitude to seismic moment
            temp_mag = fam.template.event.magnitudes[-1].mag
            temp_Mw = ML_to_Mw(temp_mag, m, c)
            temp_mo = Mw_to_M0(temp_Mw)
            # Extrapolate from the template moment - relative moment relationship to
            # Get the moment for relative moment = 1.0
            norm_mo = temp_mo / M[0]
            # Template is the last event in the list
            # Now these are weights which we can multiple the moments by
            moments = np.multiply(M, norm_mo)
            # Now convert to Mw
            Mw = [Mw_to_M0(mo, inverse=True) for mo in moments]
            # Convert to local
            Ml = [ML_to_Mw(mm, m, c, inverse=True) for mm in Mw]
            #Normalize moments to template mag
            # Add calibrated mags to detection events
            for jabba, eind in enumerate(events_out):
                # Skip template waveform
                if eind == 0:
                    continue
                fam.detections[eind].event.magnitudes = [
                    Magnitude(mag=Mw[jabba], magnitude_type='Mw')]
                fam.detections[eind].event.comments.append(
                    Comment(text=str(cccohs[eind])))
                fam.detections[eind].event.magnitudes.append(
                    Magnitude(mag=Ml[jabba], magnitude_type='ML'))
                fam.detections[eind].event.preferred_magnitude_id = (
                    fam.detections[eind].event.magnitudes[-1].resource_id.id)
    return pty, cccohs