def match_filter(template_names, template_list, st, threshold,<EOL>threshold_type, trig_int, plotvar, plotdir='<STR_LIT:.>',<EOL>xcorr_func=None, concurrency=None, cores=None,<EOL>debug=<NUM_LIT:0>, plot_format='<STR_LIT>', output_cat=False,<EOL>output_event=True, extract_detections=False,<EOL>arg_check=True, full_peaks=False, peak_cores=None, **kwargs):
from eqcorrscan.utils.plotting import _match_filter_plot<EOL>if arg_check:<EOL><INDENT>if not isinstance(template_names, list):<EOL><INDENT>raise MatchFilterError('<STR_LIT>')<EOL><DEDENT>if not isinstance(template_list, list):<EOL><INDENT>raise MatchFilterError('<STR_LIT>')<EOL><DEDENT>if not len(template_list) == len(template_names):<EOL><INDENT>raise MatchFilterError('<STR_LIT>')<EOL><DEDENT>for template in template_list:<EOL><INDENT>if not isinstance(template, Stream):<EOL><INDENT>msg = '<STR_LIT>' +'<STR_LIT>'<EOL>raise MatchFilterError(msg)<EOL><DEDENT><DEDENT>if not isinstance(st, Stream):<EOL><INDENT>msg = '<STR_LIT>'<EOL>raise MatchFilterError(msg)<EOL><DEDENT>if str(threshold_type) not in [str('<STR_LIT>'), str('<STR_LIT>'),<EOL>str('<STR_LIT>')]:<EOL><INDENT>msg = '<STR_LIT>'<EOL>raise MatchFilterError(msg)<EOL><DEDENT>for tr in st:<EOL><INDENT>if not tr.stats.sampling_rate == st[<NUM_LIT:0>].stats.sampling_rate:<EOL><INDENT>raise MatchFilterError('<STR_LIT>' %<EOL>(tr.stats.sampling_rate,<EOL>st[<NUM_LIT:0>].stats.sampling_rate))<EOL><DEDENT><DEDENT>for template in template_list:<EOL><INDENT>for tr in template:<EOL><INDENT>if not tr.stats.sampling_rate == st[<NUM_LIT:0>].stats.sampling_rate:<EOL><INDENT>raise MatchFilterError(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>')<EOL><DEDENT><DEDENT><DEDENT><DEDENT>_spike_test(st)<EOL>if cores is not None:<EOL><INDENT>parallel = True<EOL><DEDENT>else:<EOL><INDENT>parallel = False<EOL><DEDENT>stream = st.copy()<EOL>templates = copy.deepcopy(template_list)<EOL>_template_names = copy.deepcopy(template_names)<EOL>if debug >= <NUM_LIT:2>:<EOL><INDENT>template_stachan = []<EOL>data_stachan = []<EOL>for template in templates:<EOL><INDENT>for tr in template:<EOL><INDENT>if isinstance(tr.data, np.ma.core.MaskedArray):<EOL><INDENT>raise MatchFilterError('<STR_LIT>'<EOL>'<STR_LIT>')<EOL><DEDENT>template_stachan.append(tr.stats.station + '<STR_LIT:.>' +<EOL>tr.stats.channel)<EOL><DEDENT><DEDENT>for tr in stream:<EOL><INDENT>data_stachan.append(tr.stats.station + '<STR_LIT:.>' + tr.stats.channel)<EOL><DEDENT>template_stachan = list(set(template_stachan))<EOL>data_stachan = list(set(data_stachan))<EOL>debug_print('<STR_LIT>' +<EOL>template_stachan.__str__() +<EOL>'<STR_LIT>' +<EOL>data_stachan.__str__(), <NUM_LIT:3>, debug)<EOL><DEDENT>min_start_time = min([tr.stats.starttime for tr in stream])<EOL>max_end_time = max([tr.stats.endtime for tr in stream])<EOL>longest_trace_length = stream[<NUM_LIT:0>].stats.sampling_rate * (max_end_time -<EOL>min_start_time)<EOL>longest_trace_length += <NUM_LIT:1><EOL>for tr in stream:<EOL><INDENT>if not tr.stats.npts == longest_trace_length:<EOL><INDENT>msg = '<STR_LIT>'<EOL>warnings.warn(msg)<EOL>start_pad = np.zeros(int(tr.stats.sampling_rate *<EOL>(tr.stats.starttime - min_start_time)))<EOL>end_pad = np.zeros(int(tr.stats.sampling_rate *<EOL>(max_end_time - tr.stats.endtime)))<EOL>if len(start_pad) == <NUM_LIT:0> and len(end_pad) == <NUM_LIT:0>:<EOL><INDENT>debug_print("<STR_LIT>"<EOL>"<STR_LIT:end>", <NUM_LIT:2>, debug)<EOL>if (tr.stats.starttime - min_start_time) > (<EOL>max_end_time - tr.stats.endtime):<EOL><INDENT>start_pad = np.zeros(<EOL>int(longest_trace_length - tr.stats.npts))<EOL><DEDENT>else:<EOL><INDENT>end_pad = np.zeros(<EOL>int(longest_trace_length - tr.stats.npts))<EOL><DEDENT><DEDENT>tr.data = np.concatenate([start_pad, tr.data, end_pad])<EOL><DEDENT><DEDENT>for i, temp in enumerate(template_list):<EOL><INDENT>if len(set([tr.stats.npts for tr in temp])) > <NUM_LIT:1>:<EOL><INDENT>msg = ('<STR_LIT>'<EOL>'<STR_LIT>' % _template_names[i])<EOL>raise MatchFilterError(msg)<EOL><DEDENT><DEDENT>outtic = time.clock()<EOL>debug_print('<STR_LIT>'<EOL>'<STR_LIT>', <NUM_LIT:2>, debug)<EOL>template_stachan = {}<EOL>for template in templates:<EOL><INDENT>stachans_in_template = []<EOL>for tr in template:<EOL><INDENT>stachans_in_template.append((tr.stats.network, tr.stats.station,<EOL>tr.stats.location, tr.stats.channel))<EOL><DEDENT>stachans_in_template = dict(Counter(stachans_in_template))<EOL>for stachan in stachans_in_template.keys():<EOL><INDENT>stachans = stachans_in_template[stachan]<EOL>if stachan not in template_stachan.keys():<EOL><INDENT>template_stachan.update({stachan: stachans})<EOL><DEDENT>elif stachans_in_template[stachan] > template_stachan[stachan]:<EOL><INDENT>template_stachan.update({stachan: stachans})<EOL><DEDENT><DEDENT><DEDENT>_template_stachan = copy.deepcopy(template_stachan)<EOL>for stachan in template_stachan.keys():<EOL><INDENT>if not stream.select(network=stachan[<NUM_LIT:0>], station=stachan[<NUM_LIT:1>],<EOL>location=stachan[<NUM_LIT:2>], channel=stachan[<NUM_LIT:3>]):<EOL><INDENT>_template_stachan.pop(stachan)<EOL>for template in templates:<EOL><INDENT>if template.select(network=stachan[<NUM_LIT:0>], station=stachan[<NUM_LIT:1>],<EOL>location=stachan[<NUM_LIT:2>], channel=stachan[<NUM_LIT:3>]):<EOL><INDENT>for tr in template.select(<EOL>network=stachan[<NUM_LIT:0>], station=stachan[<NUM_LIT:1>],<EOL>location=stachan[<NUM_LIT:2>], channel=stachan[<NUM_LIT:3>]):<EOL><INDENT>template.remove(tr)<EOL>print('<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(stachan[<NUM_LIT:0>], stachan[<NUM_LIT:1>], stachan[<NUM_LIT:2>], stachan[<NUM_LIT:3>]))<EOL><DEDENT><DEDENT><DEDENT><DEDENT><DEDENT>template_stachan = _template_stachan<EOL>for tr in stream:<EOL><INDENT>if not (tr.stats.network, tr.stats.station,<EOL>tr.stats.location, tr.stats.channel) intemplate_stachan.keys():<EOL><INDENT>print('<STR_LIT>'<EOL>'<STR_LIT>' %<EOL>(tr.stats.network, tr.stats.station, tr.stats.location,<EOL>tr.stats.channel))<EOL>stream.remove(tr)<EOL><DEDENT><DEDENT>stachans = [(tr.stats.network, tr.stats.station,<EOL>tr.stats.location, tr.stats.channel) for tr in stream]<EOL>c_stachans = Counter(stachans)<EOL>for key in c_stachans.keys():<EOL><INDENT>if c_stachans[key] > <NUM_LIT:1>:<EOL><INDENT>msg = ('<STR_LIT>'<EOL>% (key[<NUM_LIT:0>], key[<NUM_LIT:1>], key[<NUM_LIT:2>], key[<NUM_LIT:3>]))<EOL>raise MatchFilterError(msg)<EOL><DEDENT><DEDENT>_templates = []<EOL>used_template_names = []<EOL>for template, template_name in zip(templates, _template_names):<EOL><INDENT>if len(template) == <NUM_LIT:0>:<EOL><INDENT>msg = ('<STR_LIT>' +<EOL>'<STR_LIT>' + template_name)<EOL>warnings.warn(msg)<EOL>continue<EOL><DEDENT>for stachan in template_stachan.keys():<EOL><INDENT>number_of_channels = len(template.select(<EOL>network=stachan[<NUM_LIT:0>], station=stachan[<NUM_LIT:1>], location=stachan[<NUM_LIT:2>],<EOL>channel=stachan[<NUM_LIT:3>]))<EOL>if number_of_channels < template_stachan[stachan]:<EOL><INDENT>missed_channels = template_stachan[stachan] -number_of_channels<EOL>nulltrace = Trace()<EOL>nulltrace.stats.update(<EOL>{'<STR_LIT>': stachan[<NUM_LIT:0>], '<STR_LIT>': stachan[<NUM_LIT:1>],<EOL>'<STR_LIT:location>': stachan[<NUM_LIT:2>], '<STR_LIT>': stachan[<NUM_LIT:3>],<EOL>'<STR_LIT>': template[<NUM_LIT:0>].stats.sampling_rate,<EOL>'<STR_LIT>': template[<NUM_LIT:0>].stats.starttime,<EOL>'<STR_LIT>': True})<EOL>nulltrace.data = np.array([np.NaN] * len(template[<NUM_LIT:0>].data),<EOL>dtype=np.float32)<EOL>for dummy in range(missed_channels):<EOL><INDENT>template += nulltrace<EOL><DEDENT><DEDENT><DEDENT>template.sort()<EOL>_templates.append(template)<EOL>used_template_names.append(template_name)<EOL>if len(template) != max([len(t) for t in templates]):<EOL><INDENT>raise MatchFilterError('<STR_LIT>'<EOL>'<STR_LIT>')<EOL><DEDENT><DEDENT>templates = _templates<EOL>_template_names = used_template_names<EOL>debug_print('<STR_LIT>', <NUM_LIT:2>, debug)<EOL>for template in templates:<EOL><INDENT>debug_print(template.__str__(), <NUM_LIT:3>, debug)<EOL><DEDENT>debug_print(stream.__str__(), <NUM_LIT:3>, debug)<EOL>multichannel_normxcorr = get_stream_xcorr(xcorr_func, concurrency)<EOL>[cccsums, no_chans, chans] = multichannel_normxcorr(<EOL>templates=templates, stream=stream, cores=cores, **kwargs)<EOL>if len(cccsums[<NUM_LIT:0>]) == <NUM_LIT:0>:<EOL><INDENT>raise MatchFilterError('<STR_LIT>')<EOL><DEDENT>outtoc = time.clock()<EOL>debug_print('<STR_LIT:U+0020>'.join(['<STR_LIT>',<EOL>str(outtoc - outtic), '<STR_LIT:s>']), <NUM_LIT:0>, debug)<EOL>debug_print('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT:data>' % (cccsums.shape, len(templates), len(stream)), <NUM_LIT:2>,<EOL>debug)<EOL>detections = []<EOL>if output_cat:<EOL><INDENT>det_cat = Catalog()<EOL><DEDENT>if str(threshold_type) == str("<STR_LIT>"):<EOL><INDENT>thresholds = [threshold for _ in range(len(cccsums))]<EOL><DEDENT>elif str(threshold_type) == str('<STR_LIT>'):<EOL><INDENT>thresholds = [threshold * np.median(np.abs(cccsum))<EOL>for cccsum in cccsums]<EOL><DEDENT>else:<EOL><INDENT>thresholds = [threshold * no_chans[i] for i in range(len(cccsums))]<EOL><DEDENT>if peak_cores is None:<EOL><INDENT>peak_cores = cores<EOL><DEDENT>all_peaks = multi_find_peaks(<EOL>arr=cccsums, thresh=thresholds, debug=debug, parallel=parallel,<EOL>trig_int=int(trig_int * stream[<NUM_LIT:0>].stats.sampling_rate),<EOL>full_peaks=full_peaks, cores=peak_cores)<EOL>for i, cccsum in enumerate(cccsums):<EOL><INDENT>if np.abs(np.mean(cccsum)) > <NUM_LIT>:<EOL><INDENT>warnings.warn('<STR_LIT>')<EOL><DEDENT>if plotvar:<EOL><INDENT>_match_filter_plot(<EOL>stream=stream, cccsum=cccsum, template_names=_template_names,<EOL>rawthresh=thresholds[i], plotdir=plotdir,<EOL>plot_format=plot_format, i=i)<EOL><DEDENT>if debug >= <NUM_LIT:4>:<EOL><INDENT>np.save(_template_names[i] +<EOL>stream[<NUM_LIT:0>].stats.starttime.datetime.strftime('<STR_LIT>'),<EOL>cccsum)<EOL><DEDENT>debug_print(<EOL>'<STR_LIT:U+0020>'.join(['<STR_LIT>', _template_names[i],<EOL>stream[<NUM_LIT:0>].stats.starttime.datetime.strftime('<STR_LIT>')]),<EOL><NUM_LIT:4>, debug)<EOL>if all_peaks[i]:<EOL><INDENT>for peak in all_peaks[i]:<EOL><INDENT>detecttime = (<EOL>stream[<NUM_LIT:0>].stats.starttime +<EOL>peak[<NUM_LIT:1>] / stream[<NUM_LIT:0>].stats.sampling_rate)<EOL>detection = Detection(<EOL>template_name=_template_names[i], detect_time=detecttime,<EOL>no_chans=no_chans[i], detect_val=peak[<NUM_LIT:0>],<EOL>threshold=thresholds[i], typeofdet='<STR_LIT>', chans=chans[i],<EOL>threshold_type=threshold_type, threshold_input=threshold)<EOL>if output_cat or output_event:<EOL><INDENT>detection._calculate_event(template_st=templates[i])<EOL><DEDENT>detections.append(detection)<EOL>if output_cat:<EOL><INDENT>det_cat.append(detection.event)<EOL><DEDENT><DEDENT><DEDENT>if extract_detections:<EOL><INDENT>detection_streams = extract_from_stream(stream, detections)<EOL><DEDENT><DEDENT>del stream, templates<EOL>if output_cat and not extract_detections:<EOL><INDENT>return detections, det_cat<EOL><DEDENT>elif not extract_detections:<EOL><INDENT>return detections<EOL><DEDENT>elif extract_detections and not output_cat:<EOL><INDENT>return detections, detection_streams<EOL><DEDENT>else:<EOL><INDENT>return detections, det_cat, detection_streams<EOL><DEDENT>
Main matched-filter detection function.

Over-arching code to run the correlations of given templates with a
day of seismic data and output the detections based on a given threshold.
For a functional example see the tutorials.

:type template_names: list
:param template_names:
    List of template names in the same order as template_list
:type template_list: list
:param template_list:
    A list of templates of which each template is a
    :class:`obspy.core.stream.Stream` of obspy traces containing seismic
    data and header information.
:type st: :class:`obspy.core.stream.Stream`
:param st:
    A Stream object containing all the data available and
    required for the correlations with templates given.  For efficiency
    this should contain no excess traces which are not in one or more of
    the templates.  This will now remove excess traces internally, but
    will copy the stream and work on the copy, leaving your input stream
    untouched.
:type threshold: float
:param threshold: A threshold value set based on the threshold_type
:type threshold_type: str
:param threshold_type:
    The type of threshold to be used, can be MAD, absolute or av_chan_corr.
    See Note on thresholding below.
:type trig_int: float
:param trig_int: Minimum gap between detections in seconds.
:type plotvar: bool
:param plotvar: Turn plotting on or off
:type plotdir: str
:param plotdir:
    Path to plotting folder, plots will be output here, defaults to run
    location.
:type xcorr_func: str or callable
:param xcorr_func:
    A str of a registered xcorr function or a callable for implementing
    a custom xcorr function. For more information see:
    :func:`eqcorrscan.utils.correlate.register_array_xcorr`
:type concurrency: str
:param concurrency:
    The type of concurrency to apply to the xcorr function. Options are
    'multithread', 'multiprocess', 'concurrent'. For more details see
    :func:`eqcorrscan.utils.correlate.get_stream_xcorr`
:type cores: int
:param cores: Number of cores to use
:type debug: int
:param debug:
    Debug output level, the bigger the number, the more the output.
:type plot_format: str
:param plot_format: Specify format of output plots if saved
:type output_cat: bool
:param output_cat:
    Specifies if matched_filter will output an obspy.Catalog class
    containing events for each detection. Default is False, in which case
    matched_filter will output a list of detection classes, as normal.
:type output_event: bool
:param output_event:
    Whether to include events in the Detection objects, defaults to True,
    but for large cases you may want to turn this off as Event objects
    can be quite memory intensive.
:type extract_detections: bool
:param extract_detections:
    Specifies whether or not to return a list of streams, one stream per
    detection.
:type arg_check: bool
:param arg_check:
    Check arguments, defaults to True, but if running in bulk, and you are
    certain of your arguments, then set to False.
:type full_peaks: bool
:param full_peaks: See `eqcorrscan.core.findpeaks.find_peaks2_short`.
:type peak_cores: int
:param peak_cores:
    Number of processes to use for parallel peak-finding (if different to
    `cores`).

.. note::
    **Returns:**

    If neither `output_cat` or `extract_detections` are set to `True`,
    then only the list of :class:`eqcorrscan.core.match_filter.Detection`'s
    will be output:

    :return:
        :class:`eqcorrscan.core.match_filter.Detection` detections for each
        detection made.
    :rtype: list

    If `output_cat` is set to `True`, then the
    :class:`obspy.core.event.Catalog` will also be output:

    :return: Catalog containing events for each detection, see above.
    :rtype: :class:`obspy.core.event.Catalog`

    If `extract_detections` is set to `True` then the list of
    :class:`obspy.core.stream.Stream`'s will also be output.

    :return:
        list of :class:`obspy.core.stream.Stream`'s for each detection, see
        above.
    :rtype: list

.. note::
    If your data contain gaps these must be padded with zeros before
    using this function. The `eqcorrscan.utils.pre_processing` functions
    will provide gap-filled data in the appropriate format.  Note that if
    you pad your data with zeros before filtering or resampling the gaps
    will not be all zeros after filtering. This will result in the
    calculation of spurious correlations in the gaps.

.. Note::
    Detections are not corrected for `pre-pick`, the
    detection.detect_time corresponds to the beginning of the earliest
    template channel at detection.

.. note::
    **Data overlap:**

    Internally this routine shifts and trims the data according to the
    offsets in the template (e.g. if trace 2 starts 2 seconds after trace 1
    in the template then the continuous data will be shifted by 2 seconds
    to align peak correlations prior to summing).  Because of this,
    detections at the start and end of continuous data streams
    **may be missed**.  The maximum time-period that might be missing
    detections is the maximum offset in the template.

    To work around this, if you are conducting matched-filter detections
    through long-duration continuous data, we suggest using some overlap
    (a few seconds, on the order of the maximum offset in the templates)
    in the continous data.  You will then need to post-process the
    detections (which should be done anyway to remove duplicates).

.. note::
    **Thresholding:**

    **MAD** threshold is calculated as the:

    .. math::

        threshold {\\times} (median(abs(cccsum)))

    where :math:`cccsum` is the cross-correlation sum for a given template.

    **absolute** threshold is a true absolute threshold based on the
    cccsum value.

    **av_chan_corr** is based on the mean values of single-channel
    cross-correlations assuming all data are present as required for the
    template, e.g:

    .. math::

        av\_chan\_corr\_thresh=threshold \\times (cccsum\ /\ len(template))

    where :math:`template` is a single template from the input and the
    length is the number of channels within this template.

.. note::
    The output_cat flag will create an :class:`obspy.core.event.Catalog`
    containing one event for each
    :class:`eqcorrscan.core.match_filter.Detection`'s generated by
    match_filter. Each event will contain a number of comments dealing
    with correlation values and channels used for the detection. Each
    channel used for the detection will have a corresponding
    :class:`obspy.core.event.Pick` which will contain time and
    waveform information. **HOWEVER**, the user should note that
    the pick times do not account for the prepick times inherent in
    each template. For example, if a template trace starts 0.1 seconds
    before the actual arrival of that phase, then the pick time generated
    by match_filter for that phase will be 0.1 seconds early.

.. Note::
    xcorr_func can be used as follows:

    .. rubric::xcorr_func argument example

    >>> import obspy
    >>> import numpy as np
    >>> from eqcorrscan.core.match_filter import match_filter
    >>> from eqcorrscan.utils.correlate import time_multi_normxcorr
    >>> # define a custom xcorr function
    >>> def custom_normxcorr(templates, stream, pads, *args, **kwargs):
    ...     # Just to keep example short call other xcorr function
    ...     # in practice you would define your own function here
    ...     print('calling custom xcorr function')
    ...     return time_multi_normxcorr(templates, stream, pads)
    >>> # generate some toy templates and stream
    >>> random = np.random.RandomState(42)
    >>> template = obspy.read()
    >>> stream = obspy.read()
    >>> for num, tr in enumerate(stream):  # iter st and embed templates
    ...     data = tr.data
    ...     tr.data = random.randn(6000) * 5
    ...     tr.data[100: 100 + len(data)] = data
    >>> # call match_filter ane ensure the custom function is used
    >>> detections = match_filter(
    ...     template_names=['1'], template_list=[template], st=stream,
    ...     threshold=.5, threshold_type='absolute', trig_int=1,
    ...     plotvar=False,
    ...     xcorr_func=custom_normxcorr)  # doctest:+ELLIPSIS
    calling custom xcorr function...