Beispiel #1
0
    def distance_to(self, source):
        src_lats = num_full_like(self.lats, fill_value=source.lat)
        src_lons = num_full_like(self.lons, fill_value=source.lon)

        target_coords = self.get_latlon()
        target_lats = target_coords[:, 0]
        target_lons = target_coords[:, 1]
        return distance_accurate50m_numpy(
            src_lats, src_lons, target_lats, target_lons)
Beispiel #2
0
    def distance_to(self, source):
        src_lats = num_full_like(self.lats, fill_value=source.lat)
        src_lons = num_full_like(self.lons, fill_value=source.lon)

        target_coords = self.get_latlon()
        target_lats = target_coords[:, 0]
        target_lons = target_coords[:, 1]
        return distance_accurate50m_numpy(
            src_lats, src_lons, target_lats, target_lons)
Beispiel #3
0
def plot_directivity(engine,
                     source,
                     store_id,
                     distance=300 * km,
                     azi_begin=0.,
                     azi_end=360.,
                     dazi=1.,
                     phase_begin='first{stored:any_P}-10%',
                     phase_end='last{stored:any_S}+50',
                     quantity='displacement',
                     envelope=False,
                     component='R',
                     fmin=0.01,
                     fmax=0.1,
                     hillshade=True,
                     cmap=None,
                     plot_mt='full',
                     show_phases=True,
                     show_description=True,
                     reverse_time=False,
                     show_nucleations=True,
                     axes=None,
                     nthreads=0):
    '''Plot the directivity and radiation characteristics of source models

    Synthetic seismic traces (R, T or Z) are forward-modelled at a defined
    radius, covering the full or partial azimuthal range and projected on a
    polar plot. Difference in the amplitude are enhanced by hillshading
    the data.

    :param engine: Forward modelling engine
    :type engine: :py:class:`~pyrocko.gf.seismosizer.Engine`
    :param source: Parametrized source model
    :type source: :py:class:`~pyrocko.gf.seismosizer.Source`
    :param store_id: Store ID used for forward modelling
    :type store_id: str
    :param distance: Distance in [m]
    :type distance: float
    :param azi_begin: Begin azimuth in [deg]
    :type azi_begin: float
    :param azi_end: End azimuth in [deg]
    :type azi_end: float
    :param dazi: Delta azimuth, bin size [deg]
    :type dazi: float
    :param phase_begin: Start time of the window
    :type phase_begin: :py:class:`~pyrocko.gf.meta.Timing`
    :param phase_end: End time of the window
    :type phase_end: :py:class:`~pyrocko.gf.meta.Timing`
    :param quantity: Seismogram quantity, default ``displacement``
    :type quantity: str
    :param envelope: Plot envelop instead of seismic trace
    :type envelope: bool
    :param component: Forward modelled component, default ``R``. Choose from
        `RTZ`
    :type component: str
    :param fmin: Bandpass lower frequency [Hz], default ``0.01``
    :type fmin: float
    :param fmax: Bandpass upper frequency [Hz], default ``0.1``
    :type fmax: float
    :param hillshade: Enable hillshading, default ``True``
    :type hillshade: bool
    :param cmap: Matplotlit colormap to use, default ``seismic``.
        When ``envelope`` is ``True`` the default colormap will be ``Reds``.
    :type cmap: str
    :param plot_mt: Plot a centered moment tensor, default ``full``.
        Choose from ``full, deviatoric, dc or False``
    :type plot_mt: str, bool
    :param show_phases: Show annotations, default ``True``
    :type show_phases: bool
    :param show_description: Show desciption, default ``True``
    :type show_description: bool
    :param reverse_time: Reverse time axis. First phases arrive at the center,
        default ``False``
    :type reverse_time: bool
    :param show_nucleations: Show nucleation piercing points on the moment
        tensor, default ``True``
    :type show_nucleations: bool
    :param axes: Give axes to plot into
    :type axes: :py:class:`matplotlib.axes.Axes`
    :param nthreads: Number of threads used for forward modelling,
        default ``0`` - all available cores
    :type nthreads: int
    '''

    if axes is None:
        fig = plt.figure()
        ax = fig.add_subplot(111, polar=True)
    else:
        fig = axes.figure
        ax = axes

    if envelope and cmap is None:
        cmap = 'Reds'
    elif cmap is None:
        cmap = 'seismic'

    targets, azimuths = get_azimuthal_targets(store_id,
                                              source,
                                              distance,
                                              azi_begin,
                                              azi_end,
                                              dazi,
                                              components='R',
                                              quantity=quantity)
    store = engine.get_store(store_id)
    mt = source.pyrocko_moment_tensor(store=store, target=targets[0])

    resp = engine.process(source, targets, nthreads=nthreads)
    data, times = get_seismogram_array(resp,
                                       fmin,
                                       fmax,
                                       component=component,
                                       envelope=envelope)

    timing_begin = Timing(phase_begin)
    timing_end = Timing(phase_end)

    nucl_depth = source.depth
    nucl_distance = distance

    if hasattr(source, 'nucleation_x') and hasattr(source, 'nucleation_y'):
        try:
            iter(source.nucleation_x)
            nx = float(source.nucleation_x[0])
            ny = float(source.nucleation_y[0])

        except TypeError:
            nx = source.nucleation_x
            ny = source.nucleation_y

        nucl_distance += nx * source.length / 2.
        nucl_depth += ny * num.sin(source.dip * d2r) * source.width / 2.

    if hasattr(source, 'anchor'):
        anch_x, anch_y = map_anchor[source.anchor]
        nucl_distance -= anch_x * source.length / 2.
        nucl_depth -= anch_y * num.sin(source.dip * d2r) * source.width / 2.

    tbegin = store.t(timing_begin, (nucl_depth, nucl_distance))
    tend = store.t(timing_end, (nucl_depth, nucl_distance))
    tsel = num.logical_and(times >= tbegin, times <= tend)

    data = data[:, tsel].T
    times = times[tsel]
    duration = times[-1] - times[0]

    vmax = num.abs(data).max()
    cmw = ScalarMappable(cmap=cmap)
    cmw.set_array(data)
    cmw.set_clim(-vmax, vmax)

    if envelope:
        cmw.set_clim(0., vmax)

    ax.set_theta_zero_location("N")
    ax.set_theta_direction(-1)

    strike_label = mt.strike1
    if hasattr(source, 'strike'):
        strike_label = source.strike

    try:
        ax.set_rlabel_position(strike_label % 180.)
    except AttributeError:
        logger.warn('Old matplotlib version: cannot set label positions')

    def r_fmt(v, p):
        if v < tbegin or v > tend:
            return ''
        return '%g s' % v

    ax.yaxis.set_major_formatter(FuncFormatter(r_fmt))
    if reverse_time:
        ax.set_rlim(times[0] - .3 * duration, times[-1])
    else:
        ax.set_rlim(times[-1] + .3 * duration, times[0])

    ax.grid(zorder=20)

    if isinstance(plot_mt, str):
        mt_size = .15
        beachball.plot_beachball_mpl(mt,
                                     ax,
                                     beachball_type=plot_mt,
                                     size=mt_size,
                                     size_units='axes',
                                     color_t=(0.7, 0.4, 0.4),
                                     position=(.5, .5),
                                     linewidth=1.)

        if hasattr(source, 'nucleation_x') and hasattr(source, 'nucleation_y')\
                and show_nucleations:
            try:
                iter(source.nucleation_x)
                nucleation_x = source.nucleation_x
                nucleation_y = source.nucleation_y
            except TypeError:
                nucleation_x = [source.nucleation_x]
                nucleation_y = [source.nucleation_y]

            for nx, ny in zip(nucleation_x, nucleation_y):
                angle = float(num.arctan2(ny, nx))
                rtp = num.array([[1., angle, (90. - source.strike) * d2r]])
                points = beachball.numpy_rtp2xyz(rtp)
                x, y = beachball.project(points, projection='lambert').T
                norm = num.sqrt(x**2 + y**2)
                x = x / norm * mt_size / 2.
                y = y / norm * mt_size / 2.
                ax.plot(x + .5,
                        y + .5,
                        'x',
                        ms=6,
                        mew=2,
                        mec='darkred',
                        mfc='red',
                        transform=ax.transAxes,
                        zorder=10)

    mesh = ax.pcolormesh(azimuths * d2r,
                         times,
                         data,
                         cmap=cmw.cmap,
                         shading='gouraud',
                         zorder=0)

    if hillshade:
        mesh.update_scalarmappable()
        color = mesh.get_facecolor()
        color = hillshade_seismogram_array(data,
                                           color,
                                           shad_lim=(.85, 1.),
                                           blend_mode='multiply')
        mesh.set_facecolor(color)

    if show_phases:
        _phase_begin = Timing(phase_begin)
        _phase_end = Timing(phase_end)

        for p in (_phase_begin, _phase_end):
            p.offset = 0.
            p.offset_is_slowness = False
            p.offset_is_percent = False

        tphase_first = store.t(_phase_begin, (nucl_depth, nucl_distance))
        tphase_last = store.t(_phase_end, (nucl_depth, nucl_distance))

        theta = num.linspace(0, 2 * num.pi, 360)
        tfirst = num_full_like(theta, tphase_first)
        tlast = num_full_like(theta, tphase_last)

        ax.plot(theta, tfirst, color='k', alpha=.3, lw=1.)
        ax.plot(theta, tlast, color='k', alpha=.3, lw=1.)

        ax.text(num.pi * 7 / 5,
                tphase_first,
                '|'.join(_phase_begin.phase_defs),
                ha='left',
                color='k',
                fontsize='small')

        ax.text(num.pi * 6 / 5,
                tphase_last,
                '|'.join(_phase_end.phase_defs),
                ha='left',
                color='k',
                fontsize='small')

    description = ('Component {component:s}\n'
                   'Distance {distance:g} km').format(component=component,
                                                      distance=distance / km)

    if show_description:
        if fmin and fmax:
            description += '\nBandpass {fmin:g} - {fmax:g} Hz'.format(
                fmin=fmin, fmax=fmax)
        elif fmin:
            description += '\nHighpass {fmin:g} Hz'.format(fmin=fmin)
        elif fmax:
            description += '\nLowpass {fmax:g} Hz'.format(fmax=fmax)
        ax.text(-.05,
                -.05,
                description,
                fontsize='small',
                ha='left',
                va='bottom',
                transform=ax.transAxes)

    cbar_label = QUANTITY_LABEL[quantity]
    if envelope:
        cbar_label = 'Envelope ' + cbar_label

    cb = fig.colorbar(cmw, ax=ax, orientation='vertical', shrink=.8, pad=0.11)

    cb.set_label(cbar_label)

    if axes is None:
        plt.show()
    return resp