<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def template_grid(stations, nodes, travel_times, phase, PS_ratio=1.68, samp_rate=100, flength=False, phaseout='all'):
 """ Generate a group of synthetic seismograms for a grid of sources. Used to simulate phase arrivals from a grid of known sources in a three-dimensional model. Lags must be known and supplied, these can be generated from the bright_lights function: read_tt, and resampled to fit the desired grid dimensions and spacing using other functions therein. These synthetic seismograms are very simple models of seismograms using the seis_sim function herein. These approximate body-wave P and S first arrivals as spikes convolved with damped sine waves. :type stations: list :param stations: List of the station names :type nodes: list :param nodes: List of node locations in (lon,lat,depth) :type travel_times: numpy.ndarray :param travel_times: Array of travel times where travel_times[i][:] \ refers to the travel times for station=stations[i], and \ travel_times[i][j] refers to stations[i] for nodes[j] :type phase: str :param phase: Can be either 'P' or 'S' :type PS_ratio: float :param PS_ratio: P/S velocity ratio, defaults to 1.68 :type samp_rate: float :param samp_rate: Desired sample rate in Hz, defaults to 100.0 :type flength: int :param flength: Length of template in samples, defaults to False :type phaseout: str :param phaseout: Either 'S', 'P', 'all' or 'both', determines which \ phases to clip around. 'all' Encompasses both phases in one channel, \ but will return nothing if the flength is not long enough, 'both' \ will return two channels for each stations, one SYN_Z with the \ synthetic P-phase, and one SYN_H with the synthetic S-phase. :returns: List of :class:`obspy.core.stream.Stream` """

    if phase not in ['S', 'P']:
        raise IOError('Phase is neither P nor S')
    # Initialize empty list for templates
    templates = []
    # Loop through the nodes, for every node generate a template!
    for i, node in enumerate(nodes):
        st = []  # Empty list to be filled with synthetics
        # Loop through stations
        for j, station in enumerate(stations):
            tr = Trace()
            tr.stats.sampling_rate = samp_rate
            tr.stats.station = station
            tr.stats.channel = 'SYN'
            tt = travel_times[j][i]
            if phase == 'P':
                # If the input travel-time is the P-wave travel-time
                SP_time = (tt * PS_ratio) - tt
                if phaseout == 'S':
                    tr.stats.starttime += tt + SP_time
                else:
                    tr.stats.starttime += tt
            elif phase == 'S':
                # If the input travel-time is the S-wave travel-time
                SP_time = tt - (tt / PS_ratio)
                if phaseout == 'S':
                    tr.stats.starttime += tt
                else:
                    tr.stats.starttime += tt - SP_time
            # Set start-time of trace to be travel-time for P-wave
            # Check that the template length is long enough to include the SP
            if flength and SP_time * samp_rate < flength - 11 \
               and phaseout == 'all':
                tr.data = seis_sim(sp=int(SP_time * samp_rate), amp_ratio=1.5,
                                   flength=flength, phaseout=phaseout)
                st.append(tr)
            elif flength and phaseout == 'all':
                warnings.warn('Cannot make a bulk synthetic with this fixed ' +
                              'length for station ' + station)
            elif phaseout == 'all':
                tr.data = seis_sim(sp=int(SP_time * samp_rate), amp_ratio=1.5,
                                   flength=flength, phaseout=phaseout)
                st.append(tr)
            elif phaseout in ['P', 'S']:
                tr.data = seis_sim(sp=int(SP_time * samp_rate), amp_ratio=1.5,
                                   flength=flength, phaseout=phaseout)
                st.append(tr)
            elif phaseout == 'both':
                for _phaseout in ['P', 'S']:
                    _tr = tr.copy()
                    _tr.data = seis_sim(sp=int(SP_time * samp_rate),
                                        amp_ratio=1.5, flength=flength,
                                        phaseout=_phaseout)
                    if _phaseout == 'P':
                        _tr.stats.channel = 'SYN_Z'
                        # starttime defaults to S-time
                        _tr.stats.starttime = _tr.stats.starttime - SP_time
                    elif _phaseout == 'S':
                        _tr.stats.channel = 'SYN_H'
                    st.append(_tr)
        templates.append(Stream(st))
        # Stream(st).plot(size=(800,600))
    return templates