示例#1
0
def hypo_dist(trace):
    """Compute hypocentral and epicentral distance (in km) for a trace."""
    try:
        coords = trace.stats.coords
        hypo = trace.stats.hypo
    except (KeyError, AttributeError):
        return None
    if None in (coords, hypo):
        return None
    stla = coords.latitude
    stlo = coords.longitude
    stel = coords.elevation
    evla = hypo.latitude
    evlo = hypo.longitude
    evdp = hypo.depth
    if None in (stla, stlo, stel, evla, evlo, evdp):
        return None
    epi_dist, az, baz = gps2dist_azimuth(
        hypo.latitude, hypo.longitude,
        trace.stats.coords.latitude, trace.stats.coords.longitude)
    epi_dist /= 1e3   # in km
    gcarc = kilometers2degrees(epi_dist)
    hypo_dist = math.sqrt(epi_dist**2 + (stel+evdp)**2)
    trace.stats.azimuth = az
    trace.stats.back_azimuth = baz
    trace.stats.epi_dist = epi_dist
    trace.stats.hypo_dist = hypo_dist
    trace.stats.gcarc = gcarc
    return hypo_dist
示例#2
0
 def _download_crandall(self):
     """download waveform/station info for dataset."""
     bank = WaveBank(self.waveform_path)
     domain = CircularDomain(
         self.latitude,
         self.longitude,
         minradius=0,
         maxradius=kilometers2degrees(self.max_dist),
     )
     cat = obspy.read_events(str(self.source_path / "events.xml"))
     df = events_to_df(cat)
     for _, row in df.iterrows():
         starttime = row.time - self.time_before
         endtime = row.time + self.time_after
         restrictions = Restrictions(
             starttime=UTC(starttime),
             endtime=UTC(endtime),
             minimum_length=0.90,
             minimum_interstation_distance_in_m=100,
             channel_priorities=["HH[ZNE]", "BH[ZNE]"],
             location_priorities=["", "00", "01", "--"],
         )
         kwargs = dict(
             domain=domain,
             restrictions=restrictions,
             mseed_storage=str(self.waveform_path),
             stationxml_storage=str(self.station_path),
         )
         MassDownloader(providers=[self._download_client]).download(
             **kwargs)
         # ensure data have actually been downloaded
         bank.update_index()
         assert not bank.read_index(starttime=starttime,
                                    endtime=endtime).empty
示例#3
0
def kernel(event_pair, stations=None):
    """
    kernel: the core function to get the information.
    """
    model = TauPyModel(model="ak135")
    # for each station, we calculate the travel time
    result = {}
    evla = event_pair.lat
    evlo = event_pair.lon
    evdp = event_pair.dep / 1000
    event_time = event_pair.time

    for row in stations:
        result_template = {
            "event_time": event_time,
            "evla": evla,
            "evlo": evlo,
            "evdp": evdp,
            "gcarc": None,
            "az": None,
            "baz": None,
            "S": None,
            "sS": None,
            "SS": None,
            "P": None,
            "pP": None,
            "sP": None,
            "PP": None,
            "3.3kmps": None,
            "4.6kmps": None,
            "ScS": None
        }
        station = row[0]
        network = row[1]
        net_sta = f"{network}.{station}"
        stla = float(row[2])
        stlo = float(row[3])
        arrivals = model.get_travel_times_geo(evdp, evla, evlo, stla, stlo,
                                              PHASE_LIST)

        gcarc_m, az, baz = gps2dist_azimuth(evla, evlo, stla, stlo)
        gcarc = kilometers2degrees(gcarc_m / 1000)
        result_template["gcarc"] = gcarc
        result_template["az"] = az
        result_template["baz"] = baz

        for each_arrival in arrivals:
            name = each_arrival.name
            time = each_arrival.time
            if ((name in PHASE_LIST)):
                if (name == "p"):
                    name = "P"
                if (name == "s"):
                    name = "S"
                if (result_template[name] == None):
                    result_template[name] = time
        result[net_sta] = result_template
    return result
def dist_baz_az2(eve, sta):
    global StaDict
    global AllEveDict
    gcarcinfo = gps2dist_azimuth(StaDict[sta]['stla'], StaDict[sta]['stlo'],
                                 AllEveDict[eve]['EVLA'],
                                 AllEveDict[eve]['EVLO'])
    gcarc = kilometers2degrees(gcarcinfo[0] / 1000)
    dist = gcarcinfo[0] / 1000
    baz = gcarcinfo[1]
    az = gcarcinfo[2]

    return f"{gcarc:.3f} {dist:.3f} {baz:.3f} {az:.3f}"
示例#5
0
def cal_derivative(model_path,
                   eqlon,
                   eqlat,
                   eqdep,
                   stlon,
                   stlat,
                   phase,
                   dx=0.1,
                   dy=0.1,
                   dz=0.1,
                   dt=0.04):
    from obspy.taup import TauPyModel
    from obspy.geodetics import kilometers2degrees
    #model_path: path of velocity npz file
    #eqlon,eqlat,eqdep:longitude/lat/depth(km) of earthquake
    #stlon,stlat: array of stations lon/lat
    #phase: calculate in P or S phase (array same length as stlon/stlat)
    #dx,dy,dz: perturtabation used for calculating gradient. [input unit in km]
    model = TauPyModel(model=model_path)
    #convert km to degree
    dx = kilometers2degrees(dx)
    dy = kilometers2degrees(dy)
    G = []
    #avail_idx = [] #all the available index. sometime the P or S arrival is not available,
    T0 = travel_time(model, stlon, stlat, phase, eqlon, eqlat, eqdep)
    T_dx = travel_time(model, stlon, stlat, phase, eqlon + dx, eqlat, eqdep)
    T_dy = travel_time(model, stlon, stlat, phase, eqlon, eqlat + dy, eqdep)
    T_dz = travel_time(model, stlon, stlat, phase, eqlon, eqlat, eqdep + dz)
    #time changes
    dT_dx = T_dx - T0
    dT_dy = T_dy - T0
    dT_dz = T_dz - T0
    #combine all into a G array
    G = np.hstack(
        [dT_dx.reshape(-1, 1),
         dT_dy.reshape(-1, 1),
         dT_dz.reshape(-1, 1)])
    return G
示例#6
0
def _get_bounding_box(circular_kwargs: dict) -> dict:
    """
    Return a dict containing the bounding box for circular params.
    """
    circular_kwargs = dict(circular_kwargs)  # we dont want to mutate this dict
    out = {}  # init empty dict for outputs
    if "maxradius" in circular_kwargs.keys():
        maxradius = circular_kwargs["maxradius"]
        if not circular_kwargs.get("degrees", True):
            # If distance is in m we will just assume a spherical earth
            maxradius = kilometers2degrees(maxradius / 1000.0)
        # Make the approximated box a bit bigger to cope with flattening.
        out.update(
            dict(
                minlatitude=circular_kwargs["latitude"] - (1.2 * maxradius),
                maxlatitude=circular_kwargs["latitude"] + (1.2 * maxradius),
                minlongitude=circular_kwargs["longitude"] - (1.2 * maxradius),
                maxlongitude=circular_kwargs["longitude"] + (1.2 * maxradius),
            ))
    return out
def get_dist_and_parrivals(stations, depth):
    """
    Calculate distance between the source and each station for an event and
    the theoretical p-wave arrival times and appends them to the station stats.

    Args:
        stations (array): Combined streams of acceleration data for
            each station.
        depth (float): Depth of earthquake origin in km.

    Returns:
    """

    # Define TauPyModel.
    model = TauPyModel(model="iasp91")

    for sta in stations:
        for i in range(len(sta)):
            trace = sta[i]

            # Compute distance.
            dist_az_baz = gps2dist_azimuth(
                trace.stats.coordinates['latitude'],
                trace.stats.coordinates['longitude'], trace.stats.source_lat,
                trace.stats.source_lon)
            distance_meters = dist_az_baz[0]
            distance_km = distance_meters / 1000.0
            dd = kilometers2degrees(distance_km)
            trace.stats.distance = distance_meters
            trace.stats.distkm = distance_km

            # Estimate travel time for p wave.
            p = model.get_travel_times(depth, dd, phase_list=['p', 'P'])
            trace.stats.P_arriv = p[0].time

    return ()
示例#8
0
文件: core.py 项目: mbyt/obspy
def _read_picks(f, new_event):
    """
    Internal pick reader. Use read_nordic instead.

    :type f: file
    :param f: File open in read mode
    :type wav_names: list
    :param wav_names: List of waveform files in the sfile
    :type new_event: :class:`~obspy.core.event.event.Event`
    :param new_event: event to associate picks with.

    :returns: :class:`~obspy.core.event.event.Event`
    """
    f.seek(0)
    evtime = new_event.origins[0].time
    pickline = []
    # Set a default, ignored later unless overwritten
    snr = None
    for lineno, line in enumerate(f):
        if line[79] == '7':
            header = line
            break
    for lineno, line in enumerate(f):
        if len(line.rstrip('\n').rstrip('\r')) in [80, 79] and \
           line[79] in ' 4\n':
            pickline += [line]
    for line in pickline:
        if line[18:28].strip() == '':  # If line is empty miss it
            continue
        weight = line[14]
        if weight == '_':
            phase = line[10:17]
            weight = 0
            polarity = ''
        else:
            phase = line[10:14].strip()
            polarity = line[16]
            if weight == ' ':
                weight = 0
        polarity_maps = {"": "undecidable", "C": "positive", "D": "negative"}
        try:
            polarity = polarity_maps[polarity]
        except KeyError:
            polarity = "undecidable"
        # It is valid nordic for the origin to be hour 23 and picks to be hour
        # 00 or 24: this signifies a pick over a day boundary.
        if int(line[18:20]) == 0 and evtime.hour == 23:
            day_add = 86400
            pick_hour = 0
        elif int(line[18:20]) == 24:
            day_add = 86400
            pick_hour = 0
        else:
            day_add = 0
            pick_hour = int(line[18:20])
        try:
            time = UTCDateTime(evtime.year, evtime.month, evtime.day,
                               pick_hour, int(line[20:22]),
                               float(line[23:28])) + day_add
        except ValueError:
            time = UTCDateTime(evtime.year, evtime.month, evtime.day,
                               int(line[18:20]), pick_hour,
                               float("0." + line[23:38].split('.')[1])) +\
                60 + day_add
            # Add 60 seconds on to the time, this copes with s-file
            # preference to write seconds in 1-60 rather than 0-59 which
            # datetime objects accept
        if header[57:60] == 'AIN':
            ain = _float_conv(line[57:60])
            warnings.warn('AIN: %s in header, currently unsupported' % ain)
        elif header[57:60] == 'SNR':
            snr = _float_conv(line[57:60])
        else:
            warnings.warn('%s is not currently supported' % header[57:60])
        # finalweight = _int_conv(line[68:70])
        # Create a new obspy.event.Pick class for this pick
        _waveform_id = WaveformStreamID(station_code=line[1:6].strip(),
                                        channel_code=line[6:8].strip(),
                                        network_code='NA')
        pick = Pick(waveform_id=_waveform_id, phase_hint=phase,
                    polarity=polarity, time=time)
        try:
            pick.onset = onsets[line[9]]
        except KeyError:
            pass
        if line[15] == 'A':
            pick.evaluation_mode = 'automatic'
        else:
            pick.evaluation_mode = 'manual'
        # Note these two are not always filled - velocity conversion not yet
        # implemented, needs to be converted from km/s to s/deg
        # if not velocity == 999.0:
            # new_event.picks[pick_index].horizontal_slowness = 1.0 / velocity
        if _float_conv(line[46:51]) is not None:
            pick.backazimuth = _float_conv(line[46:51])
        # Create new obspy.event.Amplitude class which references above Pick
        # only if there is an amplitude picked.
        if _float_conv(line[33:40]) is not None:
            _amplitude = Amplitude(generic_amplitude=_float_conv(line[33:40]),
                                   period=_float_conv(line[41:45]),
                                   pick_id=pick.resource_id,
                                   waveform_id=pick.waveform_id)
            if pick.phase_hint == 'IAML':
                # Amplitude for local magnitude
                _amplitude.type = 'AML'
                # Set to be evaluating a point in the trace
                _amplitude.category = 'point'
                # Default AML unit in seisan is nm (Page 139 of seisan
                # documentation, version 10.0)
                _amplitude.generic_amplitude /= 1e9
                _amplitude.unit = 'm'
                _amplitude.magnitude_hint = 'ML'
            else:
                # Generic amplitude type
                _amplitude.type = 'A'
            if snr:
                _amplitude.snr = snr
            new_event.amplitudes.append(_amplitude)
        elif _int_conv(line[28:33]) is not None:
            # Create an amplitude instance for code duration also
            _amplitude = Amplitude(generic_amplitude=_int_conv(line[28:33]),
                                   pick_id=pick.resource_id,
                                   waveform_id=pick.waveform_id)
            # Amplitude for coda magnitude
            _amplitude.type = 'END'
            # Set to be evaluating a point in the trace
            _amplitude.category = 'duration'
            _amplitude.unit = 's'
            _amplitude.magnitude_hint = 'Mc'
            if snr is not None:
                _amplitude.snr = snr
            new_event.amplitudes.append(_amplitude)
        # Create new obspy.event.Arrival class referencing above Pick
        if _float_conv(line[33:40]) is None:
            arrival = Arrival(phase=pick.phase_hint, pick_id=pick.resource_id)
            if weight is not None:
                arrival.time_weight = weight
            if _int_conv(line[60:63]) is not None:
                arrival.backazimuth_residual = _int_conv(line[60:63])
            if _float_conv(line[63:68]) is not None:
                arrival.time_residual = _float_conv(line[63:68])
            if _float_conv(line[70:75]) is not None:
                arrival.distance = kilometers2degrees(_float_conv(line[70:75]))
            if _int_conv(line[76:79]) is not None:
                arrival.azimuth = _int_conv(line[76:79])
            new_event.origins[0].arrivals.append(arrival)
        new_event.picks.append(pick)
    return new_event
示例#9
0
def travel_times(ref, deg=None, km=None, depth=0.):
    """
    Get *approximate* relative travel time(s).

    Parameters
    ----------
    ref : list or tuple of strings and/or floats
        Reference phase names or horizontal velocities [km/sec].
    deg : float, optional
        Degrees of arc between two points of interest (spherical earth).
    km : float, optional
        Horizontal kilometers between two points of interest (spherical earth).
    depth : float, optional. default, 0.
        Depth (positive down) of event, in kilometers.

    Returns
    -------
    numpy.ndarray
        Relative times, in seconds, same length as "ref". NaN if requested time
        is undefined.

    Examples
    --------
    Get relative P arrival and 2.7 km/sec surface wave arrival at 35 degrees
    distance.
    >>> times = travel_times(['P', 2.7], deg=35.0)
    To get absolute window, add the origin time like:
    >>> w1, w2 = times + epoch_origin_time

    Notes
    -----
    Either deg or km must be indicated.
    The user is responsible for adding/subtracting time (such as origin
    time, pre-window noise time, etc.) from those predicted in order to define
    a window.
    Phase travel times use ak135.

    """
    times = np.zeros(len(ref), dtype='float')
    tt = None
    for i, iref in enumerate(ref):
        if isinstance(iref, str):
            # phase time requested
            if not tt:
                if not deg:
                    deg = geod.kilometers2degrees(km)
                tt = taup.getTravelTimes(deg, depth, model='ak135')
            try:
                idx = [ph['phase_name'] for ph in tt].index(iref)
                itt = [ph['time'] for ph in tt][idx]
            except ValueError:
                # phase not found
                itt = None
        else:
            # horizontal velocity
            if not km:
                km = deg * (2 * math.pi / 360.0) * 6371.0
            itt = km / iref
        times[i] = itt

    return times
示例#10
0
def _get_event_data(tr, tt_model, phase, acc_type, depth_unit="km"):
    """
    Update a sac trace to a obspy trace and update trace header,
    and calculate theoretical traveltime of a specific model and phase

    :param tr:
    :param tt_model:
    :param phase:
    :param acc_type:
    :param depth_unit:
    :return:

    .. Note::
        The input trace should be read from sac-formatted files.

        depth_unit is not used. if depth>1000 then unit should be meter,
        since no events deeper than 700 km on the earth.

    """

    model = TauPyModel(model=tt_model)

    event_longitude = tr.stats.sac.evlo
    event_latitude = tr.stats.sac.evla
    event_depth = tr.stats.sac.evdp
    try:
        event_magnitude = tr.stats.sac.mag
    except:
        event_magnitude = 6.66

    # if depth_unit == "m":
    #     event_depth /= 1000.0
    # in this case, the depth_unit is considered to be m.
    if event_depth > 1000:
        event_depth /= 1000

    station_longitude = tr.stats.sac.stlo
    station_latitude = tr.stats.sac.stla
    station_elevation = tr.stats.sac.stel

    try:
        component_azimuth = tr.stats.sac.cmpaz
        component_inclination = tr.stats.sac.cmpinc
    except:
        # print(tr.stats)
        if tr.stats.channel[-1] == "Z":
            component_azimuth = 0
            component_inclination = 0
        elif tr.stats.channel[-1] == "N":
            component_azimuth = 0
            component_inclination = 90
        elif tr.stats.channel[-1] == "E":
            component_azimuth = 90
            component_inclination = 90
        else:
            print("component is not ZNE. ", tr.stats.channel)
            os._exit(0)

    event_time = _get_sac_origin(tr)

    distance, azimuth, back_azimuth = gps2dist_azimuth(lat1=event_latitude,
                                                       lon1=event_longitude,
                                                       lat2=station_latitude,
                                                       lon2=station_longitude,
                                                       a=6378137.0,
                                                       f=0.0033528106647474805)
    distance = kilometers2degrees(kilometer=distance / 1000.0)

    # travel time, slowness, inclinations
    arrivals = model.get_travel_times(source_depth_in_km=event_depth,
                                      distance_in_degree=distance,
                                      phase_list=[phase])
    if len(arrivals) < 1:
        return None

    arr = arrivals[0]

    onset = event_time + arr.time
    phase = phase
    inclination = arr.incident_angle
    slowness = arr.ray_param

    # pierce points
    # pp_latitude
    # pp_longitude
    # pp_depth

    # ray paths
    # arrivals = model.get_travel_times(source_depth_in_km=event_depth,
    #                                   distance_in_degree=distance,
    #                                   phase_list=[phase])
    header = {
        "model": tt_model,
        "type": acc_type,
        "event_latitude": event_latitude,
        "event_longitude": event_longitude,
        "event_depth": event_depth,
        "event_time": event_time,
        "event_magnitude": event_magnitude,
        "station_latitude": station_latitude,
        "station_longitude": station_longitude,
        "station_elevation": station_elevation,
        "component_azimuth": component_azimuth,
        "component_inclination": component_inclination,
        "onset": onset,
        "phase": phase,
        "inclination": inclination,
        "slowness": slowness,
        "distance": distance,
        "azimuth": azimuth,
        "back_azimuth": back_azimuth
    }

    tr.stats.update(header)

    return tr
示例#11
0
for i, center in enumerate(seislist):
    print('#### Start sorting ' + ' #' + str(i) + '/' + str(len(seislist)) +
          ' ' + center + ' ########')
    center_seis = read(center, format='PICKLE')  # read seismogram
    if center_seis[0].stats['dist']<dist_min or center_seis[0].stats['dist']>dist_max \
    or center_seis[0].stats['az']<az_min or center_seis[0].stats['az']>az_max:
        continue

    distance_rank = dict()
    name = os.path.splitext(os.path.split(center)[1])[0]
    category_folder = newfilefolder + name + '/'

    for periphery in seislist:
        periphery_seis = read(periphery, format='PICKLE')
        distm, az, baz = obspy.geodetics.base.gps2dist_azimuth(
            center_seis[0].stats['stla'], center_seis[0].stats['stlo'],
            periphery_seis[0].stats['stla'], periphery_seis[0].stats['stlo'])
        distdg = kilometers2degrees(distm / 1.0e3)
        distance_rank[periphery] = distdg

    distance_rank_sorted = sorted(distance_rank.items(), key=lambda kv: kv[1])
    if distance_rank_sorted[20][
            1] < 2:  # Make sure the closest 20 stations are within 4 degree grid
        if not os.path.exists(category_folder):
            os.makedirs(category_folder)
        np.save(category_folder + 'stla.npy', center_seis[0].stats['stla'])
        np.save(category_folder + 'stlo.npy', center_seis[0].stats['stlo'])
        for name, distance in distance_rank_sorted[:20]:
            copy2(name, category_folder)
            print(name + ' : ' + str(distance) + ' successfully copied !!')
示例#12
0
def iter_inv(model_path, eqlon, eqlat, eqdep, eqlon_init, eqlat_init,
             eqdep_init, stlon, stlat, phase, D, invsion_params):
    from obspy.taup import TauPyModel
    from obspy.geodetics import kilometers2degrees
    #=====iterative inversion=========
    '''
    model_path: path of the velocity model .npz file
    eqlon,eqlat,eqdep: original EQlocation (i.e. a referenced location that we known)
    eqlon_init,eqlat_init,eqdep_init: initial guess of the unknown location
    stlon,stlat: station location
    phase: array or list of P,S wave
    D: measured travel time differences from the reference location to an unknown location
    invsion_params={
        'CCC_threshold':0.3,  #use observed shift with CCC greater than this threshold
        'min_stan':5,         #minumim observations
        'max_shift':2,        #maximum shift seconds(observation)
        'update_thres':1e-9,  #if update smaller than this, but inversion havent converged, add a perturbation
        'misfit_thres':1e-3,  #modeled arrival time close enough to observation, inversion converged
        'max_iter':50,        #maximum iterations
        'dx':0.05,            #small step in x-dir to calculate time changes
        'dy':0.05,            #
        'dz':0.05,            #
        'dt':0.04,            #
    }
    '''
    #----------set default values----------
    if not ('update_thres' in invsion_params):
        invsion_params['update_thres'] = 1e-9  #set default iter
    if not ('misfit_thres' in invsion_params):
        invsion_params['misfit_thres'] = 1e-3  #set default iter
    if not ('max_iter' in invsion_params):
        invsion_params['max_iter'] = 50  #set default iter
    if not ('dx' in invsion_params):
        invsion_params['dx'] = 0.05  #set default dx
    if not ('dy' in invsion_params):
        invsion_params['dy'] = 0.05  #set default dy
    if not ('dz' in invsion_params):
        invsion_params['dz'] = 0.05  #set default dz
    if not ('dt' in invsion_params):
        invsion_params['dt'] = 0.04  #set default dt
    dx = invsion_params['dx']
    dy = invsion_params['dy']
    dz = invsion_params['dz']
    dt = invsion_params['dt']
    update_thres = invsion_params['update_thres']
    misfit_thres = invsion_params['misfit_thres']
    #--------------------------------------
    model = TauPyModel(model=model_path)
    #calculate original time, this will be then compared with new_time calculated by new location
    orig_time = travel_time(model, stlon, stlat, phase, eqlon, eqlat, eqdep)
    converged_flag = 0
    sav_invlon = []
    sav_invlat = []
    sav_invdep = []
    sav_misft = [
    ]  #save all misfit. if inversion cannot converge, find the best result
    pre_time = orig_time.copy()
    for i in range(invsion_params['max_iter']):
        G = cal_derivative(model_path, eqlon_init, eqlat_init, eqdep_init,
                           stlon, stlat, phase, dx, dy, dz, dt)
        availid_G = np.where(~np.isnan(G.sum(axis=1)))[0]
        availid_D = np.where(~np.isnan(D))[
            0]  #the index without nan value in D
        intersect_availid = list(set(availid_G).intersection(set(availid_D)))
        intersect_availid.sort()
        availid = np.array(intersect_availid)
        M = GMD_solve(G[availid], D[availid])
        MM = M * np.array([
            dx, dy, dz
        ])  # M to the real original scale dx,dy,dz [unit:km], dt [sec]
        sh_deg = kilometers2degrees(
            MM[:2])  # convert shifted_km to shifted_deg
        eqlon_init += sh_deg[0]
        eqlat_init += sh_deg[1]
        #prevent depth become negative value
        if eqdep_init + MM[2] < 0:
            #print('depth become negative, assign depth')
            eqdep_init = 0.1  # np.random.rand()*10
        else:
            eqdep_init += MM[2]
        new_time = travel_time(model, stlon, stlat, phase, eqlon_init,
                               eqlat_init, eqdep_init)
        diff_time = new_time - pre_time
        D = D - diff_time
        pre_time = new_time.copy()
        #print(np.mean(np.abs(diff_time))) #update value
        #print(np.abs(D).sum()) #print D misfit to see how D converge
        sav_invlon.append(eqlon_init)
        sav_invlat.append(eqlat_init)
        sav_invdep.append(eqdep_init)
        sav_misft.append(np.abs(D).sum())
        #case 1. no update(diff_time almost zero), D still large
        if (np.mean(np.abs(diff_time)) < update_thres) & (np.abs(D).sum() >
                                                          misfit_thres):
            #print('Add a small perturbation')
            eqlon_init += np.random.randn() * 0.05  #std=0.05 deg
            eqlat_init += np.random.randn() * 0.05  #std=0.05 deg
            eqdep_init += np.random.randn() * 0.05  #std=0.05 deg
            continue
        #case 2. Converged, D very small, no need to update
        if np.abs(D).sum() < misfit_thres:
            print('Inversion converged after %d iterations' % (i + 1),
                  eqlon_init, eqlat_init, eqdep_init)
            converged_flag = 1
            break

    sav_misft = np.array(sav_misft)
    sav_invlon = np.array(sav_invlon)
    sav_invlat = np.array(sav_invlat)
    sav_invdep = np.array(sav_invdep)
    if converged_flag:
        pass
    else:
        #compare not nan value
        notnan = np.where(~np.isnan(sav_misft))[0]
        if len(notnan) == 0:
            return eqlon_init, eqlat_init, eqdep_init, -1
        sav_misft = sav_misft[notnan]
        sav_invlon = sav_invlon[notnan]
        sav_invlat = sav_invlat[notnan]
        sav_invdep = sav_invdep[notnan]
        idx_minmisft = np.where(sav_misft == np.min(sav_misft))[0][0]
        eqlon_init = sav_invlon[idx_minmisft]
        eqlat_init = sav_invlat[idx_minmisft]
        eqdep_init = sav_invdep[idx_minmisft]


#        print('Inversion result:',sav_invlon[idx_minmisft],sav_invlat[idx_minmisft],sav_invdep[idx_minmisft])
    return eqlon_init, eqlat_init, eqdep_init, converged_flag
示例#13
0
 def buffer(self, minutes, speed):
     self.max_traveled_dist(minutes, speed)
     self.buff = gpd.GeoDataFrame(geometry=[
         self.station_xy.buffer(kilometers2degrees(self.max_distance))
     ])
     self.buff.crs = "EPSG:4326"
示例#14
0
def plotw_rs(win,
             rssort=2,
             iabs=0,
             tshift=[],
             tmark=[],
             T1=[],
             T2=[],
             pmax=50,
             iintp=0,
             inorm=[1],
             tlims=[],
             nfac=1,
             azstart=[],
             iunit=1,
             imap=1,
             wsyn=[],
             bplotrs=True,
             displayfigs='on'):
    '''
    %PLOTW_RS processes waveform object and plots as a record section
    %
    % INPUT
    %   w       waveform object (WHAT ADDED FIELDS SHOULD WE REQUIRE?)
    % INPUT (OPTIONAL) -- these can be omitted or set as [] to get default settings
    %   rssort  =0 input sorting of records
    %           =1 azimuthal sorting of records
    %           =2 distance sorting of records
    %           =3 alphabetical sorting of records (by station name or event ID)
    %   iabs    =1 to plot by absolute distance or azimuth (this means unequal
    %              vertical spacing between the waveforms)
    %   tshift  time shift (in seconds) to apply to the waveforms ([] for none)
    %   tmark   absolute time markers (Matlab serial date) ([] for none)
    %           note: if tshift varies, then you can't use this option
    %   Tfilt   =[Tmin Inf] for high-pass filter
    %           =[0 Tmax] for low-pass filter
    %           =[Tmin Tmax] for band-pass filter
    %   T1      minimum period of filter: =[] for low-pass or no filter
    %   T2      maximum period of bandpass: =[] for high-pass or no filter
    %   pmax    maximum number of time series per record section
    %   iintp   =1 to integrate, =-1 to differentiate, =0 for nothing
    %   inorm   =0 for no amplitude scaling
    %           =1 for scaling by max(abs(d(t))) per trace
    %           =2 for no amplitude scaling except correcting for geometric spreading
    %              inorm can have up to 4 entries:
    %                   inorm(=2)
    %                   GEOFAC
    %                   plot_geometric_spreading
    %                   K
    %   tlims   time limits for x-axis ([] to use default)
    %           note that the 'tshift' field will shift each seismogram
    %   nfac    controls spacing between seismograms (use a smaller nfac value for more prominent peaks)
    %   azstart   azimuthal angle for top record (applies with rssort=1 only)
    %   iunit   units for distance record section (applies with rssort=2 only)
    %           =1 for km sphere, =2 for deg sphere, =3 for km flat
    %   imap    plot a simple map showing the station and source locations
    %   wsyn    second waveform object to superimpose on w (e.g., synthetic seismograms)
    %   bplotrs =true to plot record section (can have two additional arguments odir and ftag -- see below)
    %           =false to not plot record section (but presumably to return processed waveforms)
    %
    % OUTPUT (OPTIONAL)
    %   ivec  index in which w(i) are ordered in the plot;
    %            w(ivec) gives the plotting order from top to bottom (if iabs=0)
    %   w     processed waveform (typically data)
    %   wsyn  processed waveform (typically synthetics)
    %   K     2nd parameter for geometric spreading
    %   fH	  figure handles for plots
    %   
    %
    % DETAILS ABOUT THE TIME AXIS
    %   The following variables are pertinent to the time axis:
    %   tshift, tmark, and tlims. tmark is intended to mark absolute times with
    %   vertical bars. If tshift varies from station to station, then the time
    %   axis is relative time, and tmark cannot be used. If there is no tshift
    %   specified, then t=0 will be the earliest time of all the seismograms,
    %   and tlims will be specified w.r.t. this t=0.
    %
    % See examples in run_getwaveform_short.m
    %
    % To print figures to files, set bprint_record_section=true
    %
    % FUTURE WORK:
    %   - if padding zeros, it should be done AFTER demean, taper, etc
    %   - allow pmax to represent the first X sorted seismograms, while not
    %     plotting the rest (which may have too-high SNR, for example)
    %   - combine station and network code to allow for a station to have two
    %     different network codes (e.g., MCK)
    %
    % See GISMO plotting in GISMO/@waveform/plot.m
    %
    % Carl Tape 11/21/2011
    % Yun Wang 11/2011
    %
    % Translated to python -
    % Nealey Sims 1/2021
    %
    % Further upgrades -
    % Aakash Gupta 9/2021
    %==========================================================================
    '''

    ######################################### INITIALIZATION - 1 #################################################

    start = datetime.now()
    print('--> entering plotw_rs.m')

    narg0 = 18
    # number of input arguments
    spdy = 86400
    # seconds per day
    synplot = 'r'
    # plotting a second set of seismograms
    deg = 180 / np.pi
    GEOFAC = 0.5
    # default geometric spreading factor
    # =0.5 for surface waves (between 0.5 and 1.0 for regional surface waves)
    # note: GEOFAC = inorm(2)
    bplot_geometric_speading = True
    T1 = np.atleast_1d(T1)
    T2 = np.atleast_1d(T2)
    tshift = np.atleast_1d(tshift)
    tmark = np.atleast_1d(tmark)
    inorm = np.atleast_1d(inorm)
    tlims = np.atleast_1d(tlims)
    azstart = np.atleast_1d(azstart)
    # options for printing record sections (see also bplotrs)
    bprint_record_section = False
    odir = './'
    otag = ''
    bprint_map = False
    fhct = 1
    # initialize number of figure handle counts
    #--------------------

    ####################################### CHECK INPUT ARGUMENTS ############################################

    w = win.copy()
    print(len(w))
    #w.merge(method=1, fill_value=0)#,interpolation_samples=0)  ## merge any traces with duplicate sta/chans
    if len(w) == 0:
        print('empty w')
        return
    wtemp = Stream()
    for tr in w:
        if statistics.mean(tr.data) == 0:
            print('nan trace')
        else:
            wtemp.append(tr)
    w = wtemp
    #print('%i/%i input variables:' % (nargin,narg0))
    # note: the variable will not be listed if it is not present
    #whos w rssort iabs tshift tmark T1 T2 pmax iintp inorm tlims nfac azstart iunit imap wsyn bplotrs

    if len(wsyn) == 0:
        isyn = 0
        ws = None
    else:
        print(
            'second waveform object detected -- waveforms will be superimposed'
        )
        isyn = 1
        ws = wsyn.copy()
    geoinorm = inorm
    # exit here if user enters impermissible values
    if rssort not in [0, 1, 2, 3]:
        raise ValueError('input rssort = %f must be 0, 1, 2, 3' % (rssort))
    if iabs not in [0, 1]:
        raise ValueError('input iabs = %f must be 0 or 1' % (iabs))
    if len(inorm) >= 2:
        if len(inorm) == 3:
            bplot_geometric_speading = inorm[2]
        GEOFAC = inorm[1]
        inorm = inorm[0]
        print('seismogram normalization:')
        print('  inorm = %s' % (inorm))
        print('  bplot_geometric_speading = %s' % (bplot_geometric_speading))
        print('  GEOFAC = %.2f' % (GEOFAC))

    if iintp not in [-1, 0, 1]:
        raise ValueError('input iintp = %f must be -1 or 0 or 1' % (iintp))
    if bplotrs == False:
        raise ValueError(
            'check input: you say you do not want a plot and do not want to return any variables'
        )

    # if vertical axis is absolute (distance or azimuth), then plot all
    # waveforms on the same record section (pmax huge)
    if iabs == 1:
        pmax = 1000
        if rssort not in [1, 2]:
            print(iabs, rssort)
            raise ValueError(
                'if iabs=1, then rssort=1 (az) or rssort=2 (dist)')

    ##########################################################################################################

    nw = len(w)

    ncomp = 1  # w could be nw x ncomp
    # warning: a 1 x 3 w could still all have the same component
    if ncomp not in [1, 2, 3]:
        #w = w[:]
        #w = np.concatenate(w)
        nw, ncomp = np.shape(w)[0], np.shape(w)[1]

    #w = np.concatenate(w)               # convert w to vector
    #tshift = tshift[:]
    ##if len(tshift) != 0:
    ##tshift = np.concatenate(tshift)
    nseis = len(w)
    if pmax == 0:
        pmax = nseis

    ####################################### TIME SHIFTS AND MARKERS ###########################################
    # Allows for alignment of seismograms on a time that varies from one trace to the next, say, a P arrival

    if len(tshift) == 0:
        print('no time shift applied (default)')
        tshift = np.zeros((nseis, 1))

    elif len(tshift) == 1:
        print('time shift of %.2f s applied to all waveforms' % (tshift[0]))
        tshift = tshift * np.ones((nseis, 1))

    elif len(tshift) == nw:
        print('input tshift has dimension %i x %i' % (np.shape(tshift)))
        tshift = tshift[:]
        tshift = np.matlib.repmat(tshift, 1, ncomp)
        print('output tshift has dimension %i x %i' % (np.shape(tshift)))

    else:
        if nw != 1:
            raise ValueError('tshift (%i) must be same length as w (%i)' %
                             (len(tshift), nseis))

    # time markers (absolute times)
    if len(tmark) == 0:
        nmark = 0
        print('no time markers')
    else:
        if len(np.unique(tshift)) > 1:
            nmark = 0
            print(
                'variable time shifts, so there can be no absolute time markers'
            )
        else:
            nmark = len(tmark)
            print('%i time markers to plot' % (nmark))

    # relative time or absolute time
    if len(np.unique(tshift)) > 1:
        itrel = 1
    else:
        tshift0 = tshift[0]
        itrel = 0

    ######################################### INITIALIZATION - 2 #################################################

    starttime = []
    endtime = []
    netwk = []
    chans = []
    sta = []
    rlat = []
    rlon = []
    elat = []
    elon = []
    edep = []
    eid = []
    mag = []
    loc = []
    tdata = []
    trtimes = []
    evidst = []

    print(len(w))
    for i, tr in enumerate(w):
        chans.append(tr.stats.channel)
        try:
            rlat.append(tr.stats.sac.stla)
            rlon.append(tr.stats.sac.stlo)
        except:
            rlat.append(tr.stats.coordinates[0])
            rlon.append(tr.stats.coordinates[1])
        starttime.append(tr.stats.starttime)
        endtime.append(tr.stats.endtime)
        evid = str(tr.stats.starttime).replace(":", '')
        evidst.append(evid.replace("-", ''))
        netwk.append(tr.stats.network)
        sta.append(tr.stats.station)
        loc.append(tr.stats.location)
        edep.append('dep ')
        eid.append(evidst[0])
        mag.append('NaN')
        #elat= elat*np.ones((len(w),1))
        #elon= elon*np.ones((len(w),1))
        elat.append(tr.stats.sac.evla)
        elon.append(tr.stats.sac.evlo)
        tdata.append(tr.data)
        trtimes.append(tr.times("timestamp"))

    if nseis == 1:
        stchan = chans
    else:
        #unique channels
        uchan = np.unique(chans)
        nuchan = len(uchan)
        stchan = []
        ii = 0
        for ii in range(nuchan):
            stchan.append(uchan[ii])
    # FUTURE WORK
    # NEED TO EXIT IF ANY OF THE ABOVE FIELDS ARE EMPTY (isempty does not work)

    # we assume that there is either one event or one station in the set of waveforms

    if nseis == 1:
        nsta = 1
        neve = 1
        irs = 1
        eid = [str(ee) for ee in eid]
        ii = 0
        while ii < len(netwk):
            slabs.append(
                str(netwk[ii]) + '.' + str(sta[ii]) + '.' + str(loc[ii]))
            ii += 1
        sta = [str(ss) for ss in sta]
    else:
        #nsta = length(sta);     % temporary (MCK with two networks)
        nsta = len(np.unique(sta))
        neve = len(np.unique(eid))
        #[nsta,~] = size(unique([rlon(:) rlat(:)],'rows'));
        #[neve,~] = size(unique([elon(:) elat(:)],'rows'));
        if neve == 1 and nsta > 0:
            irs = 1
            # 1 event, multiple stations
            #nsta = nseis;
            #slabs = sta;
            #slabs = np.matlib.repmat(str(''),nseis,1)
            slabs = np.empty(((nseis), 1), dtype=object)
            ii = 0
            while ii < nseis:
                if nuchan > 1:
                    slabs[ii] = (str(netwk[ii]) + '.' + str(sta[ii]) + '.' +
                                 str(loc[ii]) + '.' + str(chans[ii]))
                else:
                    slabs[ii] = (str(netwk[ii]) + '.' + str(sta[ii]) + '.' +
                                 str(loc[ii]))
                ii += 1
        elif nsta == 1 and neve > 0:
            irs = 0
            # 1 station, multiple events
            slabs = eid
            #neve = nseis;
        else:
            # consider TCOL and COLA -- we might want to compare these in a
            # record section for the same event, so here we check the station
            # locations and do NOT exit with an error if the stations are close
            # to each other

            irs = 0  # 1 station, multiple events
            slabs = eid

            dmax = 1e6  # initialize to large number
            xdists = []
            i = 0
            if nsta > 1:
                #xdists = distance.distance(rlat[0]*np.ones(np.shape(rlon)), rlon[0]*np.ones(np.shape(rlon)), rlat, rlon).km
                while i < len(rlat):
                    xdists.append(
                        distance.distance((rlat[0], rlon[0]),
                                          (rlat[i], rlon[i])).km)
                    i += 1
                dmax = max(xdists)

            if dmax > 0.5:
                print('nsta = %i, neve = %i -- error with waveform data' %
                      (nsta, neve))
                print('check headers KEVNM and station:')
                print(eid)
                print(sta)
                print('check headers KEVNM and station')
                print(
                    'must have a single event or station common to all input waveforms'
                )

    print('%i event, %i station' % (neve, nsta))

    ####################################### REFERENCE START TIME #############################################

    tstartmin = min(starttime)
    imin = starttime.index(tstartmin)
    print('minimum start time of all waveforms is %s (%s)' %
          (tstartmin, sta[imin]))
    tref = dates.date2num(tstartmin) * spdy
    if itrel == 1 and len(tmark) == 1:
        tref = dates.date2num(tmark[0]) * spdy

    stref = print('reference time is %s' % (dates.num2date(tref / spdy)))
    #print(stref);
    print('--> this will be subtracted from all time vectors')

    ############################## STATION (OR EVENT) DISTANCES & AZIMUTHS #####################################

    if irs == 1:
        lat1 = elat
        lon1 = elon
        lat2 = rlat
        lon2 = rlon
    else:
        lat1 = rlat[0]
        lon1 = rlon[0]
        lat2 = elat
        lon2 = elon

    ###[dist] = distance(lat1,lon1,lat2,lon2, 'degrees')
    def get_bearing(lat1, long1, lat2, long2):
        dLon = (long2 - long1)
        x = math.cos(math.radians(lat2)) * math.sin(math.radians(dLon))
        y = math.cos(math.radians(lat1)) * math.sin(
            math.radians(lat2)) - math.sin(math.radians(lat1)) * math.cos(
                math.radians(lat2)) * math.cos(math.radians(dLon))
        brng = arctan2(x, y)
        brng = degrees(brng)
        return brng

    dist = []
    azi = []
    i = 0
    #while i < len(lat2):
    for i in range(len(lat2)):
        #dist.append(distance.distance((lat1[i], lon1[i]), (lat2[i], lon2[i])).km)
        dist.append(
            (gps2dist_azimuth(lat1[i], lon1[i], lat2[i], lon2[i])[0]) / 1000)
        #azimuth=get_bearing(lat1[i], lon1[i], lat2[i], lon2[i])
        azimuth = gps2dist_azimuth(lat1[i], lon1[i], lat2[i], lon2[i])[1]

        if azimuth < 0:
            azi.append(azimuth + 360)
            #azi.append(get_bearing(lat1[i], lon1[i], lat2[i], lon2[i]))
        else:
            azi.append(azimuth)

        #i+=1

    dist_deg = dist
    if iunit not in [1, 2, 3]:
        warnings.warn('iunit not 1,2,3 -- setting iunit = 1')
        iunit = 1
    if iunit == 1:
        sunit = 'km'
        #dist = deg2km(dist)
    if iunit == 2:
        sunit = 'deg'
        for d in range(len(dist)):
            dist[d] = kilometers2degrees(dist[d])
    if iunit == 3:
        # input lon2 and lon1 are assumed to be utmx and utmy,
        # so dist (from above) is over-written
        sunit = 'km'
        i = 0
        dist = []
        while i < len(lat2):
            dist.append(1e-3 * np.sqrt((lon2[i] - lon1[i]) ^ 2 +
                                       (lat2[i] - lat1[i]) ^ 2))
            i += 1

    dran = max(dist) - min(dist)
    aran = max(azi) - min(azi)
    print('distance range is %.1f - %.1f = %.1f %s' %
          (max(dist), min(dist), dran, sunit))
    print(' azimuth range is %.1f - %.1f = %.1f' % (max(azi), min(azi), aran))

    ################################################# SORT ######################################################

    # NEED TO IMPLEMENT A MULTI-SORT FOR THE CASE OF MULTIPLE SEISMOGRAMS AT
    # THE SAME SITE (if the distance or az are exactly the same, then sort
    # based on the net.sta.loc.chan string)
    sortlab = ['input', 'azimuth', 'distance', 'label']
    if rssort == 0:  # default is no sorting
        nsei = nseis + 1
        #ivec = [1:nseis].T
        ivec = np.arange(1, nsei)
    elif rssort == 1:  # azimuth
        if len(azstart) == 0:
            print(len(azstart))
            azstart = 0
            warnings.warn('azstart not specified -- setting azstart = 0')
        ###ivec = np.argsort((azi-azstart) % 360);
        ivec = np.argsort(azi)
        #[~,ivec] = np.argsort(azi-azstar)
    elif rssort == 2:  # distance
        ivec = np.argsort(dist)
    elif rssort == 3:  # alphabetical
        ivec = np.argsort(slabs)

    ################################# RECORD SECTION LABELS -- UNSORTED #########################################
    rlabels = np.empty(((nseis), 1), dtype=object)
    if iabs == 0:
        jj = 0
        for jj in range(nseis):
            # variable time shift
            if len(np.unique(tshift)) > 1:
                if max(tshift) < spdy:
                    if tshift[jj] < 100:
                        stshift = ('DT %.1f s' % (tshift[jj]))
                    else:
                        stshift = ('DT %.1f min' % (tshift[jj] / 60))

                else:
                    stshift = ''

                #stshift = sprintf('DT %.1f',tshift(jj)-min(tshift));
            else:
                stshift = ''

            if irs == 1:  # 1 event, multiple stations
                rlabels[jj] = ('%s (%.0f, %.0f %s) %s' %
                               (str(slabs[jj])[2:-2], math.floor(
                                   azi[jj]), dist[jj], sunit, stshift))
            else:  # 1 station, multiple events (list event depths)
                rlabels[jj] = (
                    '%s %s (%.0f, %.0f %s) %.0f km %.1f %s' %
                    (str(slabs[jj])[2:-2], chans[jj], math.floor(
                        azi[jj]), dist[jj], sunit, edep[jj], mag[jj], stshift))

    else:
        rlabels = slabs

    ########################################### FILTER WAVEFORMS ###############################################

    RTAPER = 0.05

    # filter
    if len(T1) == 0 and len(T2) == 0:
        ifilter = 0
        print('NO FILTER WILL BE APPLIED')
        stfilt = '--'
        wtemp = Stream()
        for tr in w:
            fval = statistics.mean(tr.data)
            #tr.trim(min(starttime), max(endtime), pad=True, fill_value=fval)
            tr.trim((tr.stats.starttime), (tr.stats.endtime),
                    pad=True,
                    fill_value=fval)
            wtemp.append(tr)
        w = wtemp

    else:
        ifilter = 1
        npoles = 2

        # fill gaps with mean value
        # w = fillgaps(w,'meanAll');
        wtemp = Stream()
        for tr in w:
            fval = statistics.mean(tr.data)
            tr.trim((tr.stats.starttime), (tr.stats.endtime),
                    pad=True,
                    fill_value=fval)
            #tr.trim(min(starttime), max(endtime), pad=True, fill_value=fval)
            wtemp.append(tr)
        w = wtemp
        print(max(w[0]))
        # these operations might depend on whether the input is displacements
        # (which could have static offsets) or velocities
        print('pre-processing: detrend, demean, taper')

        w.detrend('demean')
        '''wtemp=Stream()
        for tr in w:
            fval=statistics.mean(tr.data)
            dmean=tr.data/abs(fval)
            tr.data=dmean
            wtemp.append(tr)
        w=wtemp'''
        #w = demean(w);
        w.taper(max_percentage=RTAPER, type='cosine')
        wfilt = Stream()
        Tmax_for_mHz = 100  # list mHz, not Hz, for T2 >= Tmax_for_mHz
        if len(T1) != 0 and len(T2) == 0:
            print('%i-pole low-pass T > %.1f s (f < %.2f Hz)' %
                  (npoles, T1[0], 1 / T1[0]))
            #f = filterobject('L',1/T1,npoles);
            stfilt = ('T > %.1f s (f < %.2f Hz)' % (T1[0], 1 / T1[0]))
            if T1[0] >= Tmax_for_mHz:
                stfilt = ('T > %.1f s (f < %.1f mHz)' %
                          (T1[0], 1 / T1[0] * 1e3))
            try:
                wfilt = w.filter("lowpass", freq=1 / T1[0], zerophase=True)
            except:
                print("filter didn't work")

        elif len(T1) == 0 and len(T2) != 0:
            print('%i-pole high-pass T < %.1f s (f > %.2f Hz)' %
                  (npoles, T2[0], 1 / T2[0]))
            #f = filterobject('H',1/T2,npoles);
            stfilt = ('T < %.1f s (f > %.2f Hz)' % (T2[0], 1 / T2[0]))
            if T2[0] >= Tmax_for_mHz:
                stfilt = ('T < %.1f s (f > %.1f mHz)' %
                          (T2[0], 1 / T2[0] * 1e3))
            try:
                wfilt = w.filter("highpass", freq=1 / T2[0], zerophase=True)
            except:
                print("filter didn't work")

        elif len(T1) != 0 and len(T2) != 0:
            print('%i-pole band-pass filter between T = %.1f - %.1f s' %
                  (npoles, T1[0], T2[0]))
            #f = filterobject('B',[1/T2 1/T1],npoles);
            stfilt = ('T = %.1f-%.1f s (%.2f-%.2f Hz)' %
                      (T1[0], T2[0], 1 / T2[0], 1 / T1[0]))
            if T2[0] >= Tmax_for_mHz:
                stfilt = ('T = %.1f-%.1f s (%.1f-%.1f mHz)' %
                          (T1[0], T2[0], 1 / T2[0] * 1e3, 1 / T1[0] * 1e3))

            try:
                for tr in w:
                    #sos = butter(5, [1/T2[0], 1/T1[0]], 'bandpass', output='sos');
                    lowcut = 1 / T2[0]
                    highcut = 1 / T1[0]
                    nyq = 0.5 * tr.stats.sampling_rate
                    low = lowcut / nyq
                    high = highcut / nyq
                    sos = butter(5, [low, high],
                                 analog=False,
                                 btype='band',
                                 output='sos')
                    #y = filtfilt(b, a, tr.data, padtype = 'odd', padlen=3*(max(len(b),len(a))-1))
                    y = sosfiltfilt(sos, tr.data.copy())
                    tr.data = y
                    wfilt.append(tr)

                #wfilt=w.filter("bandpass", freqmin=1/T2[0], freqmax=1/T1[0],zerophase=True)
            except:
                print("filter didn't work")
        w = wfilt
        '''wtemp=Stream()
        for tr in w:
            fval=statistics.mean(tr.data)
            dmean=tr.data/abs(fval)
            tr.data=dmean
            wtemp.append(tr)
        w=wtemp'''

        # apply identical filtering to synthetics, if present

        if isyn == 1:
            ws.detrend()
            #wsyn = demean(wsyn);
            ws.taper(max_percentage=RTAPER)
            ws.filter("bandpass",
                      freqmin=1 / T2[0],
                      freqmax=1 / T1[0],
                      corners=npoles,
                      zerophase=True)
    ##for trr in w:
    ##trr.data=trr.data/max(abs(trr.data))
    # integrate or differentiate
    # note: units of w will automatically change
    units = 'nm / sec'
    if iintp == 1:
        if ifilter == 0:
            w.detrend()
        w = w.integrate()
        units = 'nm'
        if isyn == 1:
            if ifilter == 0:
                ws.detrend()
            ws.integrate()

    if iintp == -1:
        w.differentiate()  # help waveform/diff
        units = 'nm / sec^2'
        if isyn == 1:
            ws.differentiate()

    # compute amplitude scaling for plots
    # NOTE: This will normalize by the full time series, not simply by the time
    #       specified within the window denoted by tlims.
    nlabs = ['none', 'max(abs(d_i))', ('(sin D)^-%.2f' % (GEOFAC))]
    nlab = 'norm --> ' + str(nlabs[inorm[0]])
    nvec = np.ones((nseis, 1))  # normalization vector for seismograms
    #w.merge(fill_value=0)
    wmaxvec = []
    #w.normalize(global_max=True)
    ftrs = []
    fttimes = []
    for tra in w:
        #print(max(abs(tra.data)))
        wmaxvec.append(max(abs(tra.data[100:-100])))
        ftrs.append(tra.data)
        fttimes.append(tra.times("timestamp"))
        #tra.plot()

    #wmaxvec = max(abs(w.merge(fill_value=0)))          # will handle empty records
    #print(wmaxvec)

    ### come back to deal with synthetic arguments ###
    wsynmaxvec = []
    ftrs_syn = []
    fttimes_syn = []
    stimes_syn = []

    if isyn == 1:
        wtemp = Stream()
        for tr in ws:
            fval = statistics.mean(tr.data)
            tr.trim((tr.stats.starttime), (tr.stats.endtime),
                    pad=True,
                    fill_value=fval)
            wtemp.append(tr)
            wsynmaxvec.append(max(abs(tr.data[100:-100])))
            ftrs_syn.append(tr.data)
            fttimes_syn.append(tr.times("timestamp"))
            stimes_syn.append(tr.stats.starttime)

        ws = wtemp
        print('amplitude comparison between data and synthetics:')
        for ii in range(len(w)):
            print(' %5s %s ln(data/syn) = %6.2f' %
                  (sta[ii], chans[ii], np.log(wmaxvec[ii] / wsynmaxvec[ii])))
        #wmaxvec = max(max(wmaxvec),max(wsynmaxvec))

    K = []
    fH = []
    if geoinorm[0] == 2:
        #if inorm(1)==2
        # For information on geometric spreading, see Stein and Wysession,
        # Section 4.3.4, Eq 20 (which is for Rayleigh waves. GEOFAC = 0.5).
        # For our purposes, this will fold the attenuation factor into the same
        # single factor that accounts for geometric spreading.
        # WARNING: This does not take into account the variation in amplitude.
        print('correct for geometrical spreading using (sin x)^-%.2f' %
              (GEOFAC))
        sindel = np.sin(np.asarray(dist_deg) / deg)
        # note: stations that are father away get enhanced by a larger value
        Kvec = wmaxvec * (sindel**GEOFAC)
        # single parameter for fitting (GEOFAC fixed)
        if len(geoinorm) == 4:
            K = geoinorm[3]  # user-specified K value
        else:
            K = statistics.median(Kvec)

        wvec = K / (sindel**GEOFAC
                    )  # factor will depend on source-station distance
        # but not on source depth
        ii = 0
        while ii < len(w):
            # THIS CHANGES THE AMPLITUDE OF w(ii)
            w[ii].data = w[ii].data / wvec[ii]
            if isyn == 1:
                ws[ii] = ws[ii] / wvec[ii]
            print(
                '%5s %8.3f deg, max = %8.2e, maxG = %5.2f, K/sin(del)^x = %16.2f'
                % (sta[ii], dist_deg[ii], wmaxvec[ii], max(abs(
                    w[ii].data)), wvec[ii]))
            ii += 1
        # extra figure with best-fitting curve
        if bplot_geometric_speading:
            fsizeg = 14
            msizeg = 20
            if len(w) > 10:
                fsizeg = 10
                msizeg = 12

            geofig = plt.figure()
            plt.plot(dist_deg,
                     wmaxvec,
                     'ko',
                     markersize=msizeg,
                     markerfacecolor='r')
            plt.text(dist_deg, wmaxvec, sta, fontsize=fsizeg)
            # best-fitting curve
            x = np.linspace(0, min([1.1 * max(dist_deg), 180]))
            plt.plot(x, K / (sin(x / deg)**GEOFAC), 'r--', linewidth=2)
            plt.ylim(0, 1.05 * max(wmaxvec))
            plt.xlabel('\Delta, source-station arc distance, deg', fontsize=14)
            plt.ylabel('max( |v(t)| )', fontsize=14)
            plt.title('A(\\Delta) = %.2e / (sin \\Delta)^{%.2f}' % (K, GEOFAC),
                      fontsize=16)

        # update wmaxvec
        if isyn == 1:
            wtemp = Stream()
            for tr in ws:
                fval = statistics.mean(tr.data)
                tr.trim((tr.stats.starttime), (tr.stats.endtime),
                        pad=True,
                        fill_value=fval)
                wtemp.append(tr)
                wsynmaxvec.append(max(abs(tr.data[100:-100])))
            ws = wtemp
            #wmaxvec = max(max(wmaxvec),max(wsynmaxvec))

    wmax = max(wmaxvec)

    ################################### PLOT RECORD SECTIONS ########################################

    if bplotrs == False:
        return

    # get units, which may have changed
    units = 'nm / sec'
    if nseis == 1:
        stunit = units
    else:
        # unique units
        #uunit = np.unique(get(w,'units'));
        uunit = np.unique(units)
        nuunit = len(uunit)
        if nuunit > 1:
            warnings.warn('multiple units are present on waveforms')
        stunit = []
        ii = 0
        while ii < nuunit:
            stunit.append(uunit[ii])
            ii += 1

    nfig = np.ceil(nseis / pmax)
    fsize = 10
    kk = 0
    az1 = azstart
    azinc = 45
    #azbin = np.arange(azstart , azstart+360, azinc) % 360
    #print(azbin)
    try:
        azbin = np.arange(azstart, azstart + 360, azinc)  # %360
    except:
        azbin = []
    azbin_fwid = 0.1
    for a in range(len(azbin)):
        azbin[a] = azbin[a] % 360

    # vertical separation between seismograms
    wsep = 1.5 * statistics.mean(wmaxvec)
    yshift = wsep * nfac

    if inorm[0] == 1:
        #nvec = max(abs(w));
        nvec = wmaxvec
        yshift = nfac

    if iabs == 1:
        nvec = np.ones((len(wmaxvec), 1))
        if inorm[0] == 1:
            if rssort == 1:
                yran = aran
            else:
                yran = dran
                if iunit == 2:
                    yran = kilometers2degrees(dran)
            for ii in range(len(wmaxvec)):
                nvec[ii] = nfac * nseis / yran * wmaxvec[ii]

        else:  # inorm = 0 or 2
            wvec = wmax * np.ones((nseis, 1))
            for jj in range(len(wvec)):
                nvec[jj] = nfac * wvec[jj]

        # sign flip is needed, since y-axis direction is flipped
        nvec = -nvec

    print('wmax = %.3e, wsep = %.3e, yshift = %.3e' % (wmax, wsep, yshift))

    # debugging for variable nvec:
    #disp(sprintf('summary of nvec (%i): min/mean/median/max = %.3e / %.3e / %.3e / %.3e',...
    #    length(nvec),min(abs(nvec)),mean(abs(nvec)),median(abs(nvec)),max(abs(nvec))));

    # get time limits for record section
    # NOTE: THIS SHOULD BE AVOIDED SINCE IT INVOLVES READING ALL THE WAVEFORMS
    if len(tlims) == 0:
        #tic
        tlim1 = np.zeros((nw, 1))
        tlim2 = np.zeros((nw, 1))
        ii = 0
        while ii < nw:
            #ti3 = get(w(ii),'timevector')
            ti3 = trtimes[ii]
            # KEY: time vector for plotting
            tplot = (ti3 - tref) - tshift[ii]
            tlim1[ii] = min(tplot)
            tlim2[ii] = max(tplot)
            ii += 1
        #print('it took %.2f s to establish the time limits for plotting' % (toc))
        tlims = [min(tlim1), max(tlim2)]
        print('tlims', tlims)
    pp = 0
    jj = 0
    kk = 0

    while pp < nfig:
        print('record section page %i/%i (max %i per page)' % (pp, nfig, pmax))

        #tempfh = figure('Visible',displayfigs); hold on;
        figname = 'fig' + str(pp)
        figname = plt.figure(figsize=(9, 11))
        ax = plt.subplot(111)

        #fig=plt.figure()

        if nfig == 1:
            jmax = nseis
        else:
            jmax = pmax

        # initialize arrays
        dy = np.zeros((jmax, 1))
        rlabs = np.empty(((jmax), 1), dtype=object)
        dplotmax = 0

        wtemp = Stream()
        jj = 0

        for jj in range(jmax):  # loop over seismograms
            if kk < nseis:

                ii = ivec[kk]
                # key sorting
                rlabs[jj] = rlabels[ii]
                # get seismogram
                ti3 = fttimes[ii]
                di3 = ftrs[ii]

                # KEY: time vector for plotting
                tplot = (ti3 - tref) - tshift[ii]
                if iabs == 0:
                    # plot from top to bottom
                    dy[jj] = (jmax + 1 - jj) * yshift
                else:
                    # use absolute scaling (e.g., plot records at their actual distance)
                    if rssort == 1:
                        dy[jj] = azi[ii]
                    else:
                        dy[jj] = dist[ii]
                #norm=np.linalg.norm(di3)

                dplot = di3 / nvec[ii]  # key amplitude scaling
                dplotshift = dplot + dy[jj]

                # get the max value of the seismogram within the plotted time interval
                #btplot = and(tplot > tlims(1),tplot < tlims(2));
                #dplotmax = max([dplotmax max(abs(dplot(btplot)))]);
                #plt.plot(ti3,dplot,'b')

                ax.plot(tplot, dplotshift, 'b', linewidth=0.5)
                # PLOT LABELS FOR EACH WAVEFORM
                txtplace = max(rlabels, key=len)
                txtplce = len(str(rlabels[ii])[2:-2])

                plt.text(tlims[0],
                         statistics.mean(dplotshift),
                         str(rlabels[ii])[2:-2],
                         ha='right',
                         fontsize=8)

                # specify the amplitude of the first seismogram plotted
                # (note that this is not the maximum over all seismograms plotted)

                if jj == 0:
                    imx = np.argmax(abs(di3))
                    mx = di3.max()
                    stmx = ('%s max %.2e %s at t = %.1f s ' %
                            (sta[ii], di3[imx], units, tplot[imx]))

                ### come back to deal with synthetic arguments ###
                if isyn == 1:
                    # be careful about the reference time
                    tisyn = fttimes_syn[ii]
                    disyn = ftrs_syn[ii]
                    tstartsyn = stimes_syn[ii]
                    tplot = (tisyn -
                             dates.date2num(tstartsyn) * spdy) - tshift[ii]
                    dplotshift = disyn / nvec[ii] + dy[
                        jj]  # key amplitude scaling
                    ax.plot(tplot, dplotshift, synplot, linewidth=0.5)

                # partition if plotting by azimuth (see azbin above)
                if rssort == 1 and iabs == 0:
                    # azimuth of previous (az0) and current (az1) stations in the sorted list
                    az0 = az1
                    az1 = azi[ii]

                    # (this boolean clause could probably be simplified)
                    #if (az1 > az0 and (any(az1>azbin) and any(azbin>az0))) or(az1 < az0 and (any(az1>azbin)or any(azbin>az0))):
                    if az1 > az0:
                        for ii in range(len(azbin)):
                            if az1 > azbin[ii] and azbin[ii] > az0:

                                # note: it would nice if these bars extended to the LEFT,
                                # outside the plotting axes
                                tp1 = tlims[0]
                                tp2 = tlims[0] + azbin_fwid * (tlims[1] -
                                                               tlims[0])
                                #disp(sprintf('%i %i %.2f %.2f',pp,jj,tp1,tp2));  % testing
                                if ws != None:  # and var != None:
                                    pc = 'r'
                                else:
                                    pc = 'k'
                                plt.plot(
                                    [tp1, tp2],
                                    [dy[jj] + yshift / 2, dy[jj] + yshift / 2],
                                    pc, 'linewidth')
                                break
                    elif az1 < az0:
                        for ii in range(len(azbin)):
                            if az1 > azbin[ii] or azbin[ii] > az0:

                                # note: it would nice if these bars extended to the LEFT,
                                # outside the plotting axes
                                tp1 = tlims[0]
                                tp2 = tlims[0] + azbin_fwid * (tlims[1] -
                                                               tlims[0])
                                #disp(sprintf('%i %i %.2f %.2f',pp,jj,tp1,tp2));  % testing
                                if ws != None:  # and var != None:
                                    pc = 'r'
                                else:
                                    pc = 'k'
                                plt.plot(
                                    [tp1, tp2],
                                    [dy[jj] + yshift / 2, dy[jj] + yshift / 2],
                                    pc, 'linewidth')
                                break
                # exit early for the last page of the multi-page record section
                if pp == nfig and jj == nseis % pmax:
                    print('ending early')
                    if iabs == 0:
                        dy = (jmax + 1 - arange(jmax)) * yshift
                    return

                kk = kk + 1

        if iabs == 0:

            # this may chop off a large-amplitude trace near the boundary, but
            # at least the gap will be the same for a sequence of plots

            ylims = [0, yshift * (jmax + 2)]
            plt.yticks([])
            #plt.ylim(ylims)
            # this will provide more space if one of the traces has a large
            # amplitude, but the gap may vary for a sequence of plots
            #ylims = yshift*[1 ,jmax] + dplotmax*[-1 ,1]

        else:
            # using actual values of distance or azimuth
            ax.yaxis.tick_right()
            if rssort == 1:
                ylims = [min(azi) - 5, max(azi) + 5]
                if max(azi) - min(azi) > 300:
                    ylims = [-10, 370]

            else:
                ylims = [min(dist) - 0.1 * dran, max(dist) + 0.1 * dran]

        print('tlims = %.2f to %.2f' % (tlims[0], tlims[1]))
        print('ylims = %.3e to %.3e (yshift = %.3e, jmax=%i)' %
              (ylims[0], ylims[1], yshift, jmax))

        # plot tshift marker
        #plt.plot([0, 0],ax0[2:3],'r','linewidth')
        plt.vlines(0, ylims[0], ylims[1], 'r')
        # plot absolute-time marker
        mm = 0
        for mm in range(nmark):
            tm = (dates.date2num(tmark[mm]) -
                  dates.date2num(tstartmin)) * spdy - tshift0
            #print((dates.date2num(tmark[mm]) - dates.date2num(tstartmin))*spdy)
            #plt.plot(tm*[1, 1],ax0[2:3],'r','linewidth')
            plt.vlines(tm, ylims[0], ylims[1], 'r')
        plt.xlim(tlims)
        plt.ylim(ylims[0], ylims[1])
        if iabs == 1:
            #if rssort ==1:
            plt.gca().invert_yaxis()
        #plt.subplots_adjust(left=0.10)
        plt.xlabel('Time (s)', fontweight='bold')

        # title string explaining the time axis
        if itrel == 0:

            t1a = dates.date2num(tstartmin) + (tshift0 + tlims[0]) / spdy
            t2a = t1a + np.diff(tlims)

            stdur = ('%s + %.2f s' % (dates.num2date(np.double(t1a)), t1a))
        else:
            # relative time shifts
            stdur = ('variable time shifts: %s' % (stref))
            #  if length(tmark)==1
            #      stdur = sprintf('variable time shifts: %s',stref);
            #else
            #    % just pick the iith record as an example -- this should be the
            #    % bottom time series on the record section
            #    ix = ii;
            #    t1a = tstartmin + (tshift(ix)+tlims(1))/spdy;
            #    t2a = t1a + diff(tlims);
            #    stdur = sprintf('variable time shifts: w(%i) (%s) is %s + %.2f s',...
            #        ix,sta{ix},datestr(double(t1a),31),t2a-t1a);

        # plot title
        # note: might want to label the channel, too
        #if ifilter==1, stfilt = sprintf('T = %.1f-%.1f s (%.2f-%.2f Hz)',T1,T2,1/T2,1/T1); else stfilt = '--'; end

        st0 = ('%s [%s, %s]' % (stchan, stunit, stfilt))
        if irs == 1:

            stline1 = (
                'event %s (%s, M%s, %.1f, %.1f, z = %s km)' %
                (eid[0], starttime[0], mag[0], elon[0], elat[0], edep[0]))
            stline2 = ('%i / %i seismograms (%i stations) ordered by %s, %s' %
                       (jmax, nseis, nsta, sortlab[rssort], nlab))
        else:
            stline1 = ('station %s (%.1f, %.1f)' % (sta[0], rlon[0], rlat[0]))
            stline2 = ('%i / %i seismograms (%i events) ordered by %s, %s' %
                       (jmax, nseis, neve, sortlab[rssort], nlab))

        plt.title(str(stdur) + ';  ' + str(stmx) + '\n' + str(st0) + '\n' +
                  str(stline1) + '\n' + str(stline2),
                  fontsize=8)
        #title({[stdur ';  ' stmx],sprintf('%s %s',st0),stline1,stline2},'fontsize',fsize,'interpreter','none');

        #plt.ion
        plt.tight_layout()
        plt.show()
        pp += 1
    #return fig

    #--------------------------------------------------------------------------
    # plot map
    # future work would be to add some more options for alaska plots (alaska_basemap.m)
    if imap == 1:
        if iunit == 3:
            fac = 1e-3
        else:
            fac = 1
        iplotsrc = 1
        fsize = 10
        figsta = plt.figure(figsize=(8, 10))
        plt.plot(rlon * fac, rlat * fac, 'bv')
        #if iplotsrc==1:
        plt.plot(elon * fac,
                 elat * fac,
                 'k*',
                 markersize=15,
                 markerfacecolor='r')
        # plot station labels (or eid labels)
        if irs == 1:
            for i, lab in enumerate(sta):
                plt.text(rlon[i] * fac,
                         rlat[i] * fac,
                         str(lab),
                         fontsize=fsize)
        else:
            plt.text(elon[i] * fac, elat[i] * fac, eid[i], fontsize=fsize)

        plt.title(str(stline1) + '\n' + str(stchan), fontsize=8)
        plt.show()
    print('--> leaving plotw_rs.m')
    # Print download time
    d = datetime.now() - start
    print(d, " s to plot waveforms")
示例#15
0
def travel_times(ref, deg=None, km=None, depth=0.):
    """
    Get *approximate* relative travel time(s).

    Parameters
    ----------
    ref : list or tuple of strings and/or floats
        Reference phase names or horizontal velocities [km/sec].
    deg : float, optional
        Degrees of arc between two points of interest (spherical earth).
    km : float, optional
        Horizontal kilometers between two points of interest (spherical earth).
    depth : float, optional. default, 0.
        Depth (positive down) of event, in kilometers.

    Returns
    -------
    numpy.ndarray
        Relative times, in seconds, same length as "ref". NaN if requested time
        is undefined.

    Examples
    --------
    Get relative P arrival and 2.7 km/sec surface wave arrival at 35 degrees
    distance.
    >>> times = travel_times(['P', 2.7], deg=35.0)
    To get absolute window, add the origin time like:
    >>> w1, w2 = times + epoch_origin_time

    Notes
    -----
    Either deg or km must be indicated.
    The user is responsible for adding/subtracting time (such as origin
    time, pre-window noise time, etc.) from those predicted in order to define
    a window.
    Phase travel times use ak135.

    """
    times = np.zeros(len(ref), dtype='float')
    tt = None
    for i, iref in enumerate(ref):
        if isinstance(iref, str):
            # phase time requested
            if not tt:
                if not deg:
                    deg = geod.kilometers2degrees(km)
                tt = taup.getTravelTimes(deg, depth, model='ak135')
            try:
                idx = [ph['phase_name'] for ph in tt].index(iref)
                itt = [ph['time'] for ph in tt][idx]
            except ValueError:
                # phase not found
                itt = None
        else:
            # horizontal velocity
            if not km:
                km = deg*(2*math.pi/360.0)*6371.0
            itt = km/iref
        times[i] = itt

    return times
示例#16
0
def obs_kilometer2degrees(km):
    return kilometers2degrees(float(km))
示例#17
0
def _read_picks(f, new_event):
    """
    Internal pick reader. Use read_nordic instead.

    :type f: file
    :param f: File open in read mode
    :type wav_names: list
    :param wav_names: List of waveform files in the sfile
    :type new_event: :class:`~obspy.core.event.event.Event`
    :param new_event: event to associate picks with.

    :returns: :class:`~obspy.core.event.event.Event`
    """
    f.seek(0)
    evtime = new_event.origins[0].time
    pickline = []
    # Set a default, ignored later unless overwritten
    snr = None
    for line in f:
        if line[79] == '7':
            header = line
            break
    for line in f:
        if len(line.rstrip('\n').rstrip('\r')) in [80, 79] and \
           line[79] in ' 4\n':
            pickline += [line]
    for line in pickline:
        if line[18:28].strip() == '':  # If line is empty miss it
            continue
        weight = line[14]
        if weight == '_':
            phase = line[10:17]
            weight = 0
            polarity = ''
        else:
            phase = line[10:14].strip()
            polarity = line[16]
            if weight == ' ':
                weight = 0
        polarity_maps = {"": "undecidable", "C": "positive", "D": "negative"}
        try:
            polarity = polarity_maps[polarity]
        except KeyError:
            polarity = "undecidable"
        # It is valid nordic for the origin to be hour 23 and picks to be hour
        # 00 or 24: this signifies a pick over a day boundary.
        if int(line[18:20]) == 0 and evtime.hour == 23:
            day_add = 86400
            pick_hour = 0
        elif int(line[18:20]) == 24:
            day_add = 86400
            pick_hour = 0
        else:
            day_add = 0
            pick_hour = int(line[18:20])
        try:
            time = UTCDateTime(evtime.year, evtime.month,
                               evtime.day, pick_hour, int(line[20:22]),
                               float(line[23:28])) + day_add
        except ValueError:
            time = UTCDateTime(evtime.year, evtime.month, evtime.day,
                               int(line[18:20]), pick_hour,
                               float("0." + line[23:38].split('.')[1])) +\
                60 + day_add
            # Add 60 seconds on to the time, this copes with s-file
            # preference to write seconds in 1-60 rather than 0-59 which
            # datetime objects accept
        if header[57:60] == 'AIN':
            ain = _float_conv(line[57:60])
            warnings.warn('AIN: %s in header, currently unsupported' % ain)
        elif header[57:60] == 'SNR':
            snr = _float_conv(line[57:60])
        else:
            warnings.warn('%s is not currently supported' % header[57:60])
        # finalweight = _int_conv(line[68:70])
        # Create a new obspy.event.Pick class for this pick
        _waveform_id = WaveformStreamID(station_code=line[1:6].strip(),
                                        channel_code=line[6:8].strip(),
                                        network_code='NA')
        pick = Pick(waveform_id=_waveform_id,
                    phase_hint=phase,
                    polarity=polarity,
                    time=time)
        try:
            pick.onset = onsets[line[9]]
        except KeyError:
            pass
        if line[15] == 'A':
            pick.evaluation_mode = 'automatic'
        else:
            pick.evaluation_mode = 'manual'
        # Note these two are not always filled - velocity conversion not yet
        # implemented, needs to be converted from km/s to s/deg
        # if not velocity == 999.0:
        # new_event.picks[pick_index].horizontal_slowness = 1.0 / velocity
        if _float_conv(line[46:51]) is not None:
            pick.backazimuth = _float_conv(line[46:51])
        # Create new obspy.event.Amplitude class which references above Pick
        # only if there is an amplitude picked.
        if _float_conv(line[33:40]) is not None:
            _amplitude = Amplitude(generic_amplitude=_float_conv(line[33:40]),
                                   period=_float_conv(line[41:45]),
                                   pick_id=pick.resource_id,
                                   waveform_id=pick.waveform_id)
            if pick.phase_hint == 'IAML':
                # Amplitude for local magnitude
                _amplitude.type = 'AML'
                # Set to be evaluating a point in the trace
                _amplitude.category = 'point'
                # Default AML unit in seisan is nm (Page 139 of seisan
                # documentation, version 10.0)
                _amplitude.generic_amplitude /= 1e9
                _amplitude.unit = 'm'
                _amplitude.magnitude_hint = 'ML'
            else:
                # Generic amplitude type
                _amplitude.type = 'A'
            if snr:
                _amplitude.snr = snr
            new_event.amplitudes.append(_amplitude)
        elif _int_conv(line[28:33]) is not None:
            # Create an amplitude instance for code duration also
            _amplitude = Amplitude(generic_amplitude=_int_conv(line[28:33]),
                                   pick_id=pick.resource_id,
                                   waveform_id=pick.waveform_id)
            # Amplitude for coda magnitude
            _amplitude.type = 'END'
            # Set to be evaluating a point in the trace
            _amplitude.category = 'duration'
            _amplitude.unit = 's'
            _amplitude.magnitude_hint = 'Mc'
            if snr is not None:
                _amplitude.snr = snr
            new_event.amplitudes.append(_amplitude)
        # Create new obspy.event.Arrival class referencing above Pick
        if _float_conv(line[33:40]) is None:
            arrival = Arrival(phase=pick.phase_hint, pick_id=pick.resource_id)
            if weight is not None:
                arrival.time_weight = weight
            if _int_conv(line[60:63]) is not None:
                arrival.backazimuth_residual = _int_conv(line[60:63])
            if _float_conv(line[63:68]) is not None:
                arrival.time_residual = _float_conv(line[63:68])
            if _float_conv(line[70:75]) is not None:
                arrival.distance = kilometers2degrees(_float_conv(line[70:75]))
            if _int_conv(line[76:79]) is not None:
                arrival.azimuth = _int_conv(line[76:79])
            new_event.origins[0].arrivals.append(arrival)
        new_event.picks.append(pick)
    return new_event
示例#18
0
def km2deg(distance_in_km):
    return kilometers2degrees(distance_in_km, radius=6371.)
示例#19
0
def input_chen_tele_body(tensor_info, data_prop):
    """We write some text files, which are based on teleseismic body wave data,
    as inputs for Chen's scripts.

    :param tensor_info: dictionary with moment tensor information
    :param data_prop: dictionary with properties of waveform data
    :type tensor_info: dict
    :type data_prop: dict

    .. warning::

        Make sure the filters of teleseismic data agree with the values in
        sampling_filter.json!
    """
    if not os.path.isfile('tele_waves.json'):
        return
    traces_info = json.load(open('tele_waves.json'))
    date_origin = tensor_info['date_origin']
    dt = traces_info[0]['dt']
    dt = round(dt, 1)
    filtro = data_prop['tele_filter']
    low_freq = filtro['low_freq']
    high_freq = filtro['high_freq']

    with open('filtro_tele', 'w') as outfile:
        outfile.write('Corners: {} {}\n'.format(low_freq, high_freq))
        outfile.write('dt: {}'.format(dt))

    nsta = len(traces_info)
    model = TauPyModel(model="ak135f_no_mud")
    depth = tensor_info['depth']
    event_lat = tensor_info['lat']
    event_lon = tensor_info['lon']

    string = '{0:2d}   FAR GDSN {1:>6} {1:>6}BHZ.DAT {2:5.2f} {3:6.2f} '\
        '{4:5.2f} {5:6.2f} {6:6.2f} 0 0  {7}  {8} {9}  1 0\n'
    sin_fun = lambda p: p * 3.6 / 111.12
    angle_fun = lambda p:\
    np.arctan2(sin_fun(p), np.sqrt(1 - sin_fun(p)**2)) * 180.0 / np.pi
    string_fun1 = lambda i, name, dist, az, lat, lon, p_slowness, disp_or_vel:\
    string.format(
        i, name, dist, az, lat, lon, angle_fun(p_slowness), disp_or_vel, 1.0, 0)
    string_fun2 = lambda i, name, dist, az, lat, lon, s_slowness, disp_or_vel:\
    string.format(
        i, name, dist, az, lat, lon, angle_fun(s_slowness), disp_or_vel, 4.0, 2)

    with open('Readlp.das', 'w') as outfile:
        outfile.write('30 30 30 0 0 0 0 0 0 1.1e+20\n')
        outfile.write('3 10 {}\n{}{}{}{}{}{}.{}\n{}\n'.format(
            dt, date_origin.year, date_origin.month, date_origin.day,
            date_origin.hour, date_origin.minute, date_origin.second,
            date_origin.microsecond, nsta))
        i = 0
        for file in traces_info:  #header in headers:
            name = file['name']
            channel = file['component']
            lat, lon = file['location']
            dist, az, back_azimuth = mng._distazbaz(lat, lon, event_lat,
                                                    event_lon)
            dist = kilometers2degrees(dist)
            derivative = False if not 'derivative' in file\
                else file['derivative']
            derivative = int(derivative)
            arrivals = mng.theoretic_arrivals(model, dist, depth)
            p_slowness = arrivals['p_slowness']
            s_slowness = arrivals['s_slowness']
            if channel == 'BHZ':
                outfile.write(
                    string_fun1(i + 1, name, dist, az, lat, lon, p_slowness,
                                derivative))
            else:
                outfile.write(
                    string_fun2(i + 1, name, dist, az, lat, lon, s_slowness,
                                derivative))
            i = i + 1

    with open('Wave.tele', 'w') as file1, open('Obser.tele', 'w') as file2:
        write_files_wavelet_observed(file1, file2, dt, data_prop, traces_info)


#
# instrumental response common to all body waves
#
    string2 = '\n3\n' + '0. 0.\n' * 3 + '4\n-6.17E-03  6.17E-03\n'\
              '-6.17E-03 -6.17E-03\n-39.18    49.12\n-39.18   '\
              '-49.12\n3948\n'
    with open('instrumental_response', 'w') as outfile:
        outfile.write('{}\n'.format(nsta))
        outfile.write(string2 * len(traces_info))

    write_wavelet_freqs(dt, 'Wavelets_tele_body')

    with open('Weight', 'w') as outfile:
        for info in traces_info:
            sta = info['name']
            channel = info['component']
            weight = info['trace_weight']
            outfile.write('{} {} {}\n'.format(weight, sta, channel))
    return 'tele_body'