def network_trigger(st, parameters, thr_coincidence_sum, moveout,
                    max_trigger_length=60, despike=True, debug=0):
    """
    Main function to compute triggers for a network of stations.
    Computes single-channel characteristic functions using given parameters,
    then combines these to find network triggers on a number of stations
    within a set moveout window.

    :type st: obspy.core.stream.Stream
    :param st: Stream to compute detections within
    :type parameters: list
    :param parameters: List of parameter class
    :type thr_coincidence_sum: int
    :param thr_coincidence_sum:
        Minimum number of stations required to raise a network trigger.
    :type moveout: float
    :param moveout: Window to find triggers within in the network detection \
        stage.
    :type max_trigger_length: float
    :param max_trigger_length: Maximum trigger length in seconds, used to \
        remove long triggers - can set to False to not use.
    :type despike: bool
    :param despike: Whether to apply simple despiking routine or not
    :type debug: int
    :param debug: Debug output level, higher is more output.

    :returns: List of triggers
    :rtype: list

    .. rubric:: Example

    >>> from obspy import read
    >>> from eqcorrscan.utils.trigger import TriggerParameters, network_trigger
    >>> st = read("https://examples.obspy.org/" +
    ...           "example_local_earthquake_3stations.mseed")
    >>> parameters = []
    >>> for tr in st:
    ...    parameters.append(TriggerParameters({'station': tr.stats.station,
    ...                                          'channel': tr.stats.channel,
    ...                                          'sta_len': 0.5,
    ...                                          'lta_len': 10.0,
    ...                                          'thr_on': 10.0,
    ...                                          'thr_off': 3.0,
    ...                                          'lowcut': 2.0,
    ...                                          'highcut': 15.0}))
    >>> triggers = network_trigger(st=st, parameters=parameters,
    ...                            thr_coincidence_sum=5, moveout=30,
    ...                            max_trigger_length=60, despike=False)
    Looking for coincidence triggers ...
    Found 1 Coincidence triggers
    """
    triggers = []
    trace_ids = [tr.id for tr in st]
    trace_ids = dict.fromkeys(trace_ids, 1)
    if debug > 3:
        print('Not running in parallel')
        # Don't run in parallel
        for tr in st:
            triggers += _channel_loop(tr=tr, parameters=parameters,
                                      max_trigger_length=max_trigger_length,
                                      despike=despike, debug=debug)
    else:
        # Needs to be pickleable
        parameters = [par.__dict__ for par in parameters]
        pool = Pool(processes=cpu_count())
        results = [pool.apply_async(_channel_loop,
                                    args=(tr, parameters, max_trigger_length,
                                          despike, debug))
                   for tr in st]
        pool.close()
        triggers = [p.get() for p in results]
        pool.join()
        triggers = [item for sublist in triggers for item in sublist]
    triggers.sort()

    if debug > 0:
        details = True
    else:
        details = False

    print('Looking for coincidence triggers ...')
    # the coincidence triggering and coincidence sum computation
    coincidence_triggers = []
    last_off_time = 0.0
    while triggers:
        # remove first trigger from list and look for overlaps
        on, off, tr_id, cft_peak, cft_std = triggers.pop(0)
        event = {}
        event['time'] = UTCDateTime(on)
        event['stations'] = [tr_id.split(".")[1]]
        event['trace_ids'] = [tr_id]
        event['coincidence_sum'] = trace_ids[tr_id]
        if details:
            event['cft_peaks'] = [cft_peak]
            event['cft_stds'] = [cft_std]
        # compile the list of stations that overlap with the current trigger
        for trigger in triggers:
            tmp_on, tmp_off, tmp_tr_id, tmp_cft_peak, tmp_cft_std = trigger
            # skip retriggering of already present station in current
            # coincidence trigger
            if tmp_tr_id in event['trace_ids']:
                continue
            # check for overlapping trigger
            if tmp_on <= off + moveout:
                event['stations'].append(tmp_tr_id.split(".")[1])
                event['trace_ids'].append(tmp_tr_id)
                event['coincidence_sum'] += trace_ids[tmp_tr_id]
                if details:
                    event['cft_peaks'].append(tmp_cft_peak)
                    event['cft_stds'].append(tmp_cft_std)
                # allow sets of triggers that overlap only on subsets of all
                # stations (e.g. A overlaps with B and B overlaps w/ C => ABC)
                off = max(off, tmp_off)
            # break if there is a gap in between the two triggers
            else:
                break
        # skip if coincidence sum threshold is not met
        if event['coincidence_sum'] < thr_coincidence_sum:
            continue
        # skip coincidence trigger if it is just a subset of the previous
        # (determined by a shared off-time, this is a bit sloppy)
        if off == last_off_time:
            continue
        event['duration'] = off - on
        if details:
            weights = np.array([trace_ids[i] for i in event['trace_ids']])
            weighted_values = np.array(event['cft_peaks']) * weights
            event['cft_peak_wmean'] = weighted_values.sum() / weights.sum()
            weighted_values = np.array(event['cft_stds']) * weights
            event['cft_std_wmean'] = \
                (np.array(event['cft_stds']) * weights).sum() / weights.sum()
        coincidence_triggers.append(event)
        last_off_time = off

    if debug > 1:
        print('Coincidence triggers :')
        pprint(coincidence_triggers)

    print('Found %s Coincidence triggers' % len(coincidence_triggers))
    return coincidence_triggers
Main function to compute triggers for a network of stations.
    Computes single-channel characteristic functions using given parameters,
    then combines these to find network triggers on a number of stations
    within a set moveout window.

    :type st: obspy.core.stream.Stream
    :param st: Stream to compute detections within
    :type parameters: list
    :param parameters: List of parameter class
    :type thr_coincidence_sum: int
    :param thr_coincidence_sum:
        Minimum number of stations required to raise a network trigger.
    :type moveout: float
    :param moveout: Window to find triggers within in the network detection \
        stage.
    :type max_trigger_length: float
    :param max_trigger_length: Maximum trigger length in seconds, used to \
        remove long triggers - can set to False to not use.
    :type despike: bool
    :param despike: Whether to apply simple despiking routine or not
    :type debug: int
    :param debug: Debug output level, higher is more output.

    :returns: List of triggers
    :rtype: list

    .. rubric:: Example

    >>> from obspy import read
    >>> from eqcorrscan.utils.trigger import TriggerParameters, network_trigger
    >>> st = read("https://examples.obspy.org/" +
    ...           "example_local_earthquake_3stations.mseed")
    >>> parameters = []
    >>> for tr in st:
    ...    parameters.append(TriggerParameters({'station': tr.stats.station,
    ...                                          'channel': tr.stats.channel,
    ...                                          'sta_len': 0.5,
    ...                                          'lta_len': 10.0,
    ...                                          'thr_on': 10.0,
    ...                                          'thr_off': 3.0,
    ...                                          'lowcut': 2.0,
    ...                                          'highcut': 15.0}))
    >>> triggers = network_trigger(st=st, parameters=parameters,
    ...                            thr_coincidence_sum=5, moveout=30,
    ...                            max_trigger_length=60, despike=False)
    Looking for coincidence triggers ...
    Found 1 Coincidence triggers