Example #1
0
def _plot_radiation_pattern_quiver(ax3d, ned_mt, type):
    """
    Private routine that plots the wave farfield into an
    :class:`~mpl_toolkits.mplot3d.axes3d.Axes3D` object

    :type ax3d: :class:`mpl_toolkits.mplot3d.axes3d.Axes3D`
    :param ax3d: matplotlib Axes3D object
    :param ned_mt: the 6 comp moment tensor in NED orientation
    :type type: str
    :param type: 'P' or 'S' (P or S wave).
    """
    import matplotlib.pyplot as plt
    if MATPLOTLIB_VERSION < [1, 4]:
        msg = ("Matplotlib 3D quiver plot needs matplotlib version >= 1.4.")
        raise ImportError(msg)

    type = type.upper()
    if type not in ("P", "S"):
        msg = ("type must be 'P' or 'S'")
        raise ValueError(msg)
    is_p_wave = type == "P"

    # precompute even spherical grid and directional cosine array
    points = _equalarea_spherical_grid(nlat=14)

    if is_p_wave:
        # get radiation pattern
        disp = farfield(ned_mt, points, type="P")
        # normalized magnitude:
        magn = np.sum(disp * points, axis=0)
        magn /= np.max(np.abs(magn))
        cmap = get_cmap('bwr')
    else:
        # get radiation pattern
        disp = farfield(ned_mt, points, type="S")
        # normalized magnitude (positive only):
        magn = np.sqrt(np.sum(disp * disp, axis=0))
        magn /= np.max(np.abs(magn))
        cmap = get_cmap('Greens')

    # plot
    # there is a mlab3d bug that quiver vector colors and lengths
    # can only be changed if we plot each arrow independently
    for loc, vec, mag in zip(points.T, disp.T, magn.T):
        norm = plt.Normalize(-1., 1.)
        color = cmap(norm(mag))
        if is_p_wave:
            loc *= (1. + mag / 2.)
            length = abs(mag) / 2.0
        else:
            length = abs(mag) / 5.0
        ax3d.quiver(loc[0], loc[1], loc[2], vec[0], vec[1], vec[2],
                    length=length, color=color)
    ax3d.set(xlim=(-1.5, 1.5), ylim=(-1.5, 1.5), zlim=(-1.5, 1.5),
             xticks=[-1, 1], yticks=[-1, 1], zticks=[-1, 1],
             xticklabels=['South', 'North'],
             yticklabels=['West', 'East'],
             zticklabels=['Up', 'Down'],
             title='{} wave farfield'.format(type))
    ax3d.view_init(elev=-110., azim=0.)
Example #2
0
def _plot_radiation_pattern_quiver(ax3d, ned_mt, type):
    """
    Private routine that plots the wave farfield into an
    :class:`~mpl_toolkits.mplot3d.axes3d.Axes3D` object

    :type ax3d: :class:`mpl_toolkits.mplot3d.axes3d.Axes3D`
    :param ax3d: matplotlib Axes3D object
    :param ned_mt: the 6 comp moment tensor in NED orientation
    :type type: str
    :param type: 'P' or 'S' (P or S wave).
    """
    import matplotlib.pyplot as plt
    if MATPLOTLIB_VERSION < [1, 4]:
        msg = ("Matplotlib 3D quiver plot needs matplotlib version >= 1.4.")
        raise ImportError(msg)

    type = type.upper()
    if type not in ("P", "S"):
        msg = ("type must be 'P' or 'S'")
        raise ValueError(msg)
    is_p_wave = type == "P"

    # precompute even spherical grid and directional cosine array
    points = _equalarea_spherical_grid(nlat=14)

    if is_p_wave:
        # get radiation pattern
        disp = farfield(ned_mt, points, type="P")
        # normalized magnitude:
        magn = np.sum(disp * points, axis=0)
        magn /= np.max(np.abs(magn))
        cmap = get_cmap('bwr')
    else:
        # get radiation pattern
        disp = farfield(ned_mt, points, type="S")
        # normalized magnitude (positive only):
        magn = np.sqrt(np.sum(disp * disp, axis=0))
        magn /= np.max(np.abs(magn))
        cmap = get_cmap('Greens')

    # plot
    # there is a mlab3d bug that quiver vector colors and lengths
    # can only be changed if we plot each arrow independently
    for loc, vec, mag in zip(points.T, disp.T, magn.T):
        norm = plt.Normalize(-1., 1.)
        color = cmap(norm(mag))
        if is_p_wave:
            loc *= (1. + mag/2.)
            length = abs(mag) / 2.0
        else:
            length = abs(mag) / 5.0
        ax3d.quiver(loc[0], loc[1], loc[2], vec[0], vec[1], vec[2],
                    length=length, color=color)
    ax3d.set(xlim=(-1.5, 1.5), ylim=(-1.5, 1.5), zlim=(-1.5, 1.5),
             xticks=[-1, 1], yticks=[-1, 1], zticks=[-1, 1],
             xticklabels=['South', 'North'],
             yticklabels=['West', 'East'],
             zticklabels=['Up', 'Down'],
             title='{} wave farfield'.format(type))
    ax3d.view_init(elev=-110., azim=0.)
Example #3
0
 def test_farfield_2xn_input(self):
     """
     Tests to compute P/S wave farfield radiation pattern using (theta,phi)
     pairs as input
     """
     # Peru 2001/6/23 20:34:23:
     #  RTP system: [2.245, -0.547, -1.698, 1.339, -3.728, 1.444]
     #  NED system: [-0.547, -1.698, 2.245, -1.444, 1.339, 3.728]
     mt = [-0.547, -1.698, 2.245, -1.444, 1.339, 3.728]
     theta = np.arange(0, 360, 60)
     phi = np.zeros(len(theta))
     rays = np.array([theta, phi]) * np.pi / 180.0
     result = farfield(mt, rays, 'P')
     ref = np.array([[0., 1.13501984, -0.873480164, 2.749332e-16,
                     -1.13501984, 0.873480164], [0, 0, -0, 0, -0, 0],
                     [2.245, 0.655304008, 0.504304008, -2.245,
                      -0.655304008, -0.504304008]])
     np.testing.assert_allclose(result, ref, rtol=1e-5, atol=1e-8)
Example #4
0
 def test_farfield_2xn_input(self):
     """
     Tests to compute P/S wave farfield radiation pattern using (theta,phi)
     pairs as input
     """
     # Peru 2001/6/23 20:34:23:
     #  RTP system: [2.245, -0.547, -1.698, 1.339, -3.728, 1.444]
     #  NED system: [-0.547, -1.698, 2.245, -1.444, 1.339, 3.728]
     mt = [-0.547, -1.698, 2.245, -1.444, 1.339, 3.728]
     theta = np.arange(0, 360, 60)
     phi = np.zeros(len(theta))
     rays = np.array([theta, phi]) * np.pi / 180.0
     result = farfield(mt, rays, 'P')
     ref = np.array([[0., 1.13501984, -0.873480164, 2.749332e-16,
                     -1.13501984, 0.873480164], [0, 0, -0, 0, -0, 0],
                     [2.245, 0.655304008, 0.504304008, -2.245,
                      -0.655304008, -0.504304008]])
     np.testing.assert_allclose(result, ref, rtol=1e-5, atol=1e-8)
Example #5
0
 def test_farfield_2xn_input(self):
     """
     Tests to compute P/S wave farfield radiation pattern using (theta,phi)
     pairs as input
     """
     # Peru 2001/6/23 20:34:23:
     mt = [2.245, -0.547, -1.698, 1.339, -3.728, 1.444]
     theta = np.arange(0, 360, 60)
     phi = np.zeros(len(theta))
     rays = np.array([theta, phi])
     result = farfield(mt, rays, 'P')
     ref = np.array([[
         -0., 1.06567166, -2.26055006, 2.19679324, -0.44435406, -2.07785517
     ], [-0., 0., -0., 0., -0., -0.],
                     [
                         -1.698, 3.32980367, -3.16993006, 1.64100194,
                         -0.15311543, -0.04592479
                     ]])
     np.testing.assert_allclose(result, ref)
Example #6
0
 def test_farfield_2xn_input(self):
     """
     Tests to compute P/S wave farfield radiation pattern using (theta,phi)
     pairs as input
     """
     # Peru 2001/6/23 20:34:23:
     mt = [2.245, -0.547, -1.698, 1.339, -3.728, 1.444]
     theta = np.arange(0, 360, 60)
     phi = np.zeros(len(theta))
     rays = np.array([theta, phi])
     result = farfield(mt, rays, "P")
     ref = np.array(
         [
             [-0.0, 1.06567166, -2.26055006, 2.19679324, -0.44435406, -2.07785517],
             [-0.0, 0.0, -0.0, 0.0, -0.0, -0.0],
             [-1.698, 3.32980367, -3.16993006, 1.64100194, -0.15311543, -0.04592479],
         ]
     )
     np.testing.assert_allclose(result, ref)
Example #7
0
def _write_radiation_pattern_vtk(ned_mt,
                                 fname_rpattern='rpattern.vtk',
                                 fname_beachlines='beachlines.vtk'):
    # output a vtkfile that can for exampled be displayed by ParaView
    mtensor = MomentTensor(ned_mt, system='NED')
    bb = BeachBall(mtensor, npoints=200)
    bb._setup_BB(unit_circle=False)

    # extract the coordinates of the nodal lines
    neg_nodalline = bb._nodalline_negative
    pos_nodalline = bb._nodalline_positive

    # plot radiation pattern and nodal lines
    points = _equalarea_spherical_grid()
    ndim, npoints = points.shape
    dispp = farfield(ned_mt, points, type="P")
    disps = farfield(ned_mt, points, type="S")

    # write vector field
    with open(fname_rpattern, 'w') as vtk_file:
        vtk_header = '# vtk DataFile Version 2.0\n' + \
                     'radiation pattern vector field\n' + \
                     'ASCII\n' + \
                     'DATASET UNSTRUCTURED_GRID\n' + \
                     'POINTS {:d} float\n'.format(npoints)

        vtk_file.write(vtk_header)
        # write point locations
        for x, y, z in np.transpose(points):
            vtk_file.write('{:.3e} {:.3e} {:.3e}\n'.format(x, y, z))
        # write vector field
        vtk_file.write('POINT_DATA {:d}\n'.format(npoints))
        vtk_file.write('VECTORS s_radiation float\n')
        for x, y, z in np.transpose(disps):
            vtk_file.write('{:.3e} {:.3e} {:.3e}\n'.format(x, y, z))
        vtk_file.write('VECTORS p_radiation float\n'.format(npoints))
        for x, y, z in np.transpose(dispp):
            vtk_file.write('{:.3e} {:.3e} {:.3e}\n'.format(x, y, z))

    # write nodal lines
    with open(fname_beachlines, 'w') as vtk_file:
        npts_neg = neg_nodalline.shape[1]
        npts_pos = pos_nodalline.shape[1]
        npts_tot = npts_neg + npts_pos
        vtk_header = '# vtk DataFile Version 2.0\n' + \
                     'beachball nodal lines\n' + \
                     'ASCII\n' + \
                     'DATASET UNSTRUCTURED_GRID\n' + \
                     'POINTS {:d} float\n'.format(npts_tot)

        vtk_file.write(vtk_header)
        # write point locations
        for x, y, z in np.transpose(neg_nodalline):
            vtk_file.write('{:.3e} {:.3e} {:.3e}\n'.format(x, y, z))
        for x, y, z in np.transpose(pos_nodalline):
            vtk_file.write('{:.3e} {:.3e} {:.3e}\n'.format(x, y, z))

        # write line segments
        vtk_file.write('\nCELLS 2 {:d}\n'.format(npts_tot + 4))

        ipoints = list(range(0, npts_neg)) + [0]
        vtk_file.write('{:d} '.format(npts_neg + 1))
        for ipoint in ipoints:
            if ipoint % 30 == 29:
                vtk_file.write('\n')
            vtk_file.write('{:d} '.format(ipoint))
        vtk_file.write('\n')

        ipoints = list(range(0, npts_pos)) + [0]
        vtk_file.write('{:d} '.format(npts_pos + 1))
        for ipoint in ipoints:
            if ipoint % 30 == 29:
                vtk_file.write('\n')
            vtk_file.write('{:d} '.format(ipoint + npts_neg))
        vtk_file.write('\n')

        # cell types. 4 means cell type is a poly_line
        vtk_file.write('\nCELL_TYPES 2\n')
        vtk_file.write('4\n4')
Example #8
0
def _plot_radiation_pattern_mayavi(ned_mt):
    """
    Plot the radiation pattern using MayaVi.

    This private function uses the mayavi (vtk) library to plot the radiation
    pattern to screen. Note that you might have to set the QT_API environmental
    variable to e.g. export QT_API=pyqt that mayavi works properly.

    :param ned_mt: moment tensor in NED convention
    """
    # use mayavi if possible.
    try:
        from mayavi import mlab
    except Exception as err:
        print(err)
        msg = ("ObsPy failed to import MayaVi. "
               "You need to install the mayavi module "
               "(e.g. 'conda install mayavi', 'pip install mayavi'). "
               "If it is installed and still doesn't work, "
               "try setting the environmental variable QT_API to "
               "pyqt (e.g. export QT_API=pyqt) before running the "
               "code. Another option is to avoid mayavi and "
               "directly use kind='vtk' for vtk file output of the "
               "radiation pattern that can be used by external "
               "software like ParaView")
        raise ImportError(msg)

    # get mopad moment tensor
    mopad_mt = MomentTensor(ned_mt, system='NED')
    bb = BeachBall(mopad_mt, npoints=200)
    bb._setup_BB(unit_circle=False)

    # extract the coordinates of the nodal lines
    neg_nodalline = bb._nodalline_negative
    pos_nodalline = bb._nodalline_positive

    # add the first point to the end to close the nodal line
    neg_nodalline = np.hstack((neg_nodalline, neg_nodalline[:, 0][:, None]))
    pos_nodalline = np.hstack((pos_nodalline, pos_nodalline[:, 0][:, None]))

    # plot radiation pattern and nodal lines
    points = _equalarea_spherical_grid(nlat=20)
    dispp = farfield(ned_mt, points, type="P")
    disps = farfield(ned_mt, points, type="S")

    # get vector lengths
    normp = np.sum(dispp * points, axis=0)
    normp /= np.max(np.abs(normp))

    norms = np.sqrt(np.sum(disps * disps, axis=0))
    norms /= np.max(np.abs(norms))

    # make sphere to block view to the other side of the beachball
    rad = 0.8
    pi = np.pi
    cos = np.cos
    sin = np.sin
    phi, theta = np.mgrid[0:pi:101j, 0:2 * pi:101j]

    x = rad * sin(phi) * cos(theta)
    y = rad * sin(phi) * sin(theta)
    z = rad * cos(phi)

    # p wave radiation pattern
    mlab.figure(size=(800, 800), bgcolor=(0, 0, 0))
    pts1 = mlab.quiver3d(points[0],
                         points[1],
                         points[2],
                         dispp[0],
                         dispp[1],
                         dispp[2],
                         scalars=normp,
                         vmin=-1.,
                         vmax=1.)
    pts1.glyph.color_mode = 'color_by_scalar'
    mlab.plot3d(*neg_nodalline, color=(0, 0.5, 0), tube_radius=0.01)
    mlab.plot3d(*pos_nodalline, color=(0, 0.5, 0), tube_radius=0.01)
    mlab.mesh(x, y, z, color=(0, 0, 0))

    # s wave radiation pattern
    mlab.figure(size=(800, 800), bgcolor=(0, 0, 0))
    pts2 = mlab.quiver3d(points[0],
                         points[1],
                         points[2],
                         disps[0],
                         disps[1],
                         disps[2],
                         scalars=norms,
                         vmin=-0.,
                         vmax=1.)
    pts2.glyph.color_mode = 'color_by_scalar'
    mlab.plot3d(*neg_nodalline, color=(0, 0.5, 0), tube_radius=0.01)
    mlab.plot3d(*pos_nodalline, color=(0, 0.5, 0), tube_radius=0.01)
    mlab.mesh(x, y, z, color=(0, 0, 0))

    mlab.show()
Example #9
0
def _plot_radiation_pattern_sphere(ax3d,
                                   ned_mt,
                                   type,
                                   p_sphere_direction='inwards'):
    """
    Private function that plots a radiation pattern sphere into an
    :class:`~mpl_toolkits.mplot3d.axes3d.Axes3D`.

    :type ax3d: :class:`mpl_toolkits.mplot3d.axes3d.Axes3D`
    :param ax3d: matplotlib Axes3D object
    :param ned_mt: moment tensor in NED convention
    :param p_sphere_direction: If this is 'inwards', the tension regions of the
        beachball deform the radiation sphere inwards. If 'outwards' it deforms
        outwards.
    :param type: 'P' or 'S' (P or S wave).
    """
    import matplotlib.pyplot as plt
    type = type.upper()
    if type not in ("P", "S"):
        msg = ("type must be 'P' or 'S'")
        raise ValueError(msg)
    is_p_wave = type == "P"

    # generate spherical mesh that is aligned with the moment tensor null
    # axis. MOPAD should use NED coordinate system to avoid internal
    # coordinate transformations
    mtensor = MomentTensor(ned_mt, system='NED')

    # use the most isolated eigenvector as axis of symmetry
    evecs = mtensor.get_eigvecs()
    evals = np.abs(mtensor.get_eigvals())**2
    evals_dev = np.abs(evals - np.mean(evals))
    if is_p_wave:
        if p_sphere_direction == 'outwards':
            evec_max = evecs[np.argmax(evals_dev)]
        elif p_sphere_direction == 'inwards':
            evec_max = evecs[np.argmax(evals)]
    else:
        evec_max = evecs[np.argmax(evals_dev)]
    orientation = np.ravel(evec_max)

    # get a uv sphere that is oriented along the moment tensor axes
    ntheta, nphi = 100, 100
    points = _oriented_uv_sphere(ntheta=ntheta,
                                 nphi=nphi,
                                 orientation=orientation)
    sshape = (ntheta, nphi)

    # get radiation pattern
    if is_p_wave:
        disp = farfield(ned_mt, points, type="P")
        magn = np.sum(disp * points, axis=0)
        cmap = get_cmap('bwr')
        norm = plt.Normalize(-1, 1)
    else:
        disp = farfield(ned_mt, points, type="S")
        magn = np.sqrt(np.sum(disp * disp, axis=0))
        cmap = get_cmap('Greens')
        norm = plt.Normalize(0, 1)
    magn /= np.max(np.abs(magn))

    # compute colours and displace points along normal
    if is_p_wave:
        if p_sphere_direction == 'outwards':
            points *= (1. + np.abs(magn) / 2.)
        elif p_sphere_direction == 'inwards':
            points *= (1. + magn / 2.)
    else:
        points *= (1. + magn / 2.)
    colors = np.array([cmap(norm(val)) for val in magn])
    colors = colors.reshape(ntheta, nphi, 4)

    x = points[0].reshape(sshape)
    y = points[1].reshape(sshape)
    z = points[2].reshape(sshape)

    # plot 3d radiation pattern
    ax3d.plot_surface(x, y, z, rstride=4, cstride=4, facecolors=colors)
    ax3d.set(xlim=(-1.5, 1.5),
             ylim=(-1.5, 1.5),
             zlim=(-1.5, 1.5),
             xticks=[-1, 1],
             yticks=[-1, 1],
             zticks=[-1, 1],
             xticklabels=['South', 'North'],
             yticklabels=['West', 'East'],
             zticklabels=['Up', 'Down'],
             title='{} wave farfield'.format(type))
    ax3d.view_init(elev=-110., azim=0.)
Example #10
0
def _write_radiation_pattern_vtk(
        ned_mt, fname_rpattern='rpattern.vtk',
        fname_beachlines='beachlines.vtk'):
    # output a vtkfile that can for exampled be displayed by ParaView
    mtensor = MomentTensor(ned_mt, system='NED')
    bb = BeachBall(mtensor, npoints=200)
    bb._setup_BB(unit_circle=False)

    # extract the coordinates of the nodal lines
    neg_nodalline = bb._nodalline_negative
    pos_nodalline = bb._nodalline_positive

    # plot radiation pattern and nodal lines
    points = _equalarea_spherical_grid()
    ndim, npoints = points.shape
    dispp = farfield(ned_mt, points, type="P")
    disps = farfield(ned_mt, points, type="S")

    # write vector field
    with open(fname_rpattern, 'w') as vtk_file:
        vtk_header = '# vtk DataFile Version 2.0\n' + \
                     'radiation pattern vector field\n' + \
                     'ASCII\n' + \
                     'DATASET UNSTRUCTURED_GRID\n' + \
                     'POINTS {:d} float\n'.format(npoints)

        vtk_file.write(vtk_header)
        # write point locations
        for x, y, z in np.transpose(points):
            vtk_file.write('{:.3e} {:.3e} {:.3e}\n'.format(x, y, z))
        # write vector field
        vtk_file.write('POINT_DATA {:d}\n'.format(npoints))
        vtk_file.write('VECTORS s_radiation float\n')
        for x, y, z in np.transpose(disps):
            vtk_file.write('{:.3e} {:.3e} {:.3e}\n'.format(x, y, z))
        vtk_file.write('VECTORS p_radiation float\n'.format(npoints))
        for x, y, z in np.transpose(dispp):
            vtk_file.write('{:.3e} {:.3e} {:.3e}\n'.format(x, y, z))

    # write nodal lines
    with open(fname_beachlines, 'w') as vtk_file:
        npts_neg = neg_nodalline.shape[1]
        npts_pos = pos_nodalline.shape[1]
        npts_tot = npts_neg + npts_pos
        vtk_header = '# vtk DataFile Version 2.0\n' + \
                     'beachball nodal lines\n' + \
                     'ASCII\n' + \
                     'DATASET UNSTRUCTURED_GRID\n' + \
                     'POINTS {:d} float\n'.format(npts_tot)

        vtk_file.write(vtk_header)
        # write point locations
        for x, y, z in np.transpose(neg_nodalline):
            vtk_file.write('{:.3e} {:.3e} {:.3e}\n'.format(x, y, z))
        for x, y, z in np.transpose(pos_nodalline):
            vtk_file.write('{:.3e} {:.3e} {:.3e}\n'.format(x, y, z))

        # write line segments
        vtk_file.write('\nCELLS 2 {:d}\n'.format(npts_tot + 4))

        ipoints = list(range(0, npts_neg)) + [0]
        vtk_file.write('{:d} '.format(npts_neg + 1))
        for ipoint in ipoints:
            if ipoint % 30 == 29:
                vtk_file.write('\n')
            vtk_file.write('{:d} '.format(ipoint))
        vtk_file.write('\n')

        ipoints = list(range(0, npts_pos)) + [0]
        vtk_file.write('{:d} '.format(npts_pos + 1))
        for ipoint in ipoints:
            if ipoint % 30 == 29:
                vtk_file.write('\n')
            vtk_file.write('{:d} '.format(ipoint + npts_neg))
        vtk_file.write('\n')

        # cell types. 4 means cell type is a poly_line
        vtk_file.write('\nCELL_TYPES 2\n')
        vtk_file.write('4\n4')
Example #11
0
def _plot_radiation_pattern_mayavi(ned_mt):
    """
    Plot the radiation pattern using MayaVi.

    This private function uses the mayavi (vtk) library to plot the radiation
    pattern to screen. Note that you might have to set the QT_API environmental
    variable to e.g. export QT_API=pyqt that mayavi works properly.

    :param ned_mt: moment tensor in NED convention
    """
    # use mayavi if possible.
    try:
        from mayavi import mlab
    except Exception as err:
        print(err)
        msg = ("ObsPy failed to import MayaVi. "
               "You need to install the mayavi module "
               "(e.g. 'conda install mayavi', 'pip install mayavi'). "
               "If it is installed and still doesn't work, "
               "try setting the environmental variable QT_API to "
               "pyqt (e.g. export QT_API=pyqt) before running the "
               "code. Another option is to avoid mayavi and "
               "directly use kind='vtk' for vtk file output of the "
               "radiation pattern that can be used by external "
               "software like ParaView")
        raise ImportError(msg)

    # get mopad moment tensor
    mopad_mt = MomentTensor(ned_mt, system='NED')
    bb = BeachBall(mopad_mt, npoints=200)
    bb._setup_BB(unit_circle=False)

    # extract the coordinates of the nodal lines
    neg_nodalline = bb._nodalline_negative
    pos_nodalline = bb._nodalline_positive

    # add the first point to the end to close the nodal line
    neg_nodalline = np.hstack((neg_nodalline, neg_nodalline[:, 0][:, None]))
    pos_nodalline = np.hstack((pos_nodalline, pos_nodalline[:, 0][:, None]))

    # plot radiation pattern and nodal lines
    points = _equalarea_spherical_grid(nlat=20)
    dispp = farfield(ned_mt, points, type="P")
    disps = farfield(ned_mt, points, type="S")

    # get vector lengths
    normp = np.sum(dispp * points, axis=0)
    normp /= np.max(np.abs(normp))

    norms = np.sqrt(np.sum(disps * disps, axis=0))
    norms /= np.max(np.abs(norms))

    # make sphere to block view to the other side of the beachball
    rad = 0.8
    pi = np.pi
    cos = np.cos
    sin = np.sin
    phi, theta = np.mgrid[0:pi:101j, 0:2 * pi:101j]

    x = rad * sin(phi) * cos(theta)
    y = rad * sin(phi) * sin(theta)
    z = rad * cos(phi)

    # p wave radiation pattern
    mlab.figure(size=(800, 800), bgcolor=(0, 0, 0))
    pts1 = mlab.quiver3d(points[0], points[1], points[2],
                         dispp[0], dispp[1], dispp[2],
                         scalars=normp, vmin=-1., vmax=1.)
    pts1.glyph.color_mode = 'color_by_scalar'
    mlab.plot3d(*neg_nodalline, color=(0, 0.5, 0), tube_radius=0.01)
    mlab.plot3d(*pos_nodalline, color=(0, 0.5, 0), tube_radius=0.01)
    mlab.mesh(x, y, z, color=(0, 0, 0))

    # s wave radiation pattern
    mlab.figure(size=(800, 800), bgcolor=(0, 0, 0))
    pts2 = mlab.quiver3d(points[0], points[1], points[2],
                         disps[0], disps[1], disps[2], scalars=norms,
                         vmin=-0., vmax=1.)
    pts2.glyph.color_mode = 'color_by_scalar'
    mlab.plot3d(*neg_nodalline, color=(0, 0.5, 0), tube_radius=0.01)
    mlab.plot3d(*pos_nodalline, color=(0, 0.5, 0), tube_radius=0.01)
    mlab.mesh(x, y, z, color=(0, 0, 0))

    mlab.show()
Example #12
0
def _plot_radiation_pattern_sphere(
        ax3d, ned_mt, type, p_sphere_direction='inwards'):
    """
    Private function that plots a radiation pattern sphere into an
    :class:`~mpl_toolkits.mplot3d.axes3d.Axes3D`.

    :type ax3d: :class:`mpl_toolkits.mplot3d.axes3d.Axes3D`
    :param ax3d: matplotlib Axes3D object
    :param ned_mt: moment tensor in NED convention
    :param p_sphere_direction: If this is 'inwards', the tension regions of the
        beachball deform the radiation sphere inwards. If 'outwards' it deforms
        outwards.
    :param type: 'P' or 'S' (P or S wave).
    """
    import matplotlib.pyplot as plt
    type = type.upper()
    if type not in ("P", "S"):
        msg = ("type must be 'P' or 'S'")
        raise ValueError(msg)
    is_p_wave = type == "P"

    # generate spherical mesh that is aligned with the moment tensor null
    # axis. MOPAD should use NED coordinate system to avoid internal
    # coordinate transformations
    mtensor = MomentTensor(ned_mt, system='NED')

    # use the most isolated eigenvector as axis of symmetry
    evecs = mtensor.get_eigvecs()
    evals = np.abs(mtensor.get_eigvals())**2
    evals_dev = np.abs(evals - np.mean(evals))
    if is_p_wave:
        if p_sphere_direction == 'outwards':
            evec_max = evecs[np.argmax(evals_dev)]
        elif p_sphere_direction == 'inwards':
            evec_max = evecs[np.argmax(evals)]
    else:
        evec_max = evecs[np.argmax(evals_dev)]
    orientation = np.ravel(evec_max)

    # get a uv sphere that is oriented along the moment tensor axes
    ntheta, nphi = 100, 100
    points = _oriented_uv_sphere(ntheta=ntheta, nphi=nphi,
                                 orientation=orientation)
    sshape = (ntheta, nphi)

    # get radiation pattern
    if is_p_wave:
        disp = farfield(ned_mt, points, type="P")
        magn = np.sum(disp * points, axis=0)
        cmap = get_cmap('bwr')
        norm = plt.Normalize(-1, 1)
    else:
        disp = farfield(ned_mt, points, type="S")
        magn = np.sqrt(np.sum(disp * disp, axis=0))
        cmap = get_cmap('Greens')
        norm = plt.Normalize(0, 1)
    magn /= np.max(np.abs(magn))

    # compute colours and displace points along normal
    if is_p_wave:
        if p_sphere_direction == 'outwards':
            points *= (1. + np.abs(magn) / 2.)
        elif p_sphere_direction == 'inwards':
            points *= (1. + magn / 2.)
    else:
        points *= (1. + magn / 2.)
    colors = np.array([cmap(norm(val)) for val in magn])
    colors = colors.reshape(ntheta, nphi, 4)

    x = points[0].reshape(sshape)
    y = points[1].reshape(sshape)
    z = points[2].reshape(sshape)

    # plot 3d radiation pattern
    ax3d.plot_surface(x, y, z, rstride=4, cstride=4, facecolors=colors)
    ax3d.set(xlim=(-1.5, 1.5), ylim=(-1.5, 1.5), zlim=(-1.5, 1.5),
             xticks=[-1, 1], yticks=[-1, 1], zticks=[-1, 1],
             xticklabels=['South', 'North'],
             yticklabels=['West', 'East'],
             zticklabels=['Up', 'Down'],
             title='{} wave farfield'.format(type))
    ax3d.view_init(elev=-110., azim=0.)
Example #13
0
def radiation_pattern(mt,
                      takeoff_angle,
                      azimuth,
                      wavetype='P',
                      system='RTP',
                      normalize=False):
    """Wrapper of obspy.core.event.source.farfield.

    Parameters
    ----------
    mt: list(float)
        Six component moment tensor ([Mxx, Myy, Mzz, Mxy, Mxz, Myz])
    takeoff_angle: float or list(float)
        Takeoff angle of seismic ray (in degree)
    azimuth: float or list(float)
        Azimuth of seismic ray (in degree)
    wavetype: str
        Specify wave type, 'P' or 'S'
    system: str
        Coordinate system of mt, NED|USE|RTP
    normalize: bool
        Return normalized radiation pattern

    Returns
    -------
    float
        Magnitude of radiation pattern

    Examples
    --------
    (1) Explosion source:

        >>> mt = [1, 1, 1, 0, 0, 0]
        >>> mag = radiation_pattern(mt, 35, 44, wavetype='P', system='RTP')
        >>> print(mag)
        1.0

    (2) Event 2001/6/23 20:34:23

        >>> mt = [2.245, -0.547, -1.698, 1.339, -3.728, 1.444]
        >>> mag_P = radiation_pattern(mt, 80, 30, wavetype='P', system='RTP')
        >>> print(mag_P)
        0.92058159502
        >>> mag_S = radiation_pattern(mt, 80, 30, wavetype='S', system='RTP')
        >>> print(mag_S)
        3.66100655525
    """
    from obspy import __version__ as obspy_version

    if obspy_version == '1.0.2':
        msg = ("farfield in ObsPy version {} has known issues."
               "(see issue #1499 and PR #1553).").format(obspy_version)
        warnings.warn(msg)

    if system in ('RTP', 'USE'):
        ned_mt = mt_converter(mt, system_in='RTP', system_out='NED')
    elif system == 'NED':
        ned_mt = mt
    else:
        raise ValueError("Wrong coordinate system of moment tensor")

    ray = np.array([[takeoff_angle], [azimuth]]) / 180.0 * np.pi
    # farfield return three component displacement
    disp = farfield(ned_mt, ray, wavetype)
    mag = np.sqrt(np.sum(disp * disp, axis=0))[0]

    if normalize:
        mag /= get_scalar_moment(ned_mt)

    return mag