ray_velocities.py

Visualization of ray velocities.


Requires Python packages:

class gme.plot.ray_velocities.RayVelocities(dpi: int = 100, font_size: int = 11)

Visualization of ray velocities.

Extends gme.plot.base.Graphing.

profile_v(gmes: gme.ode.single_ray.SingleRaySolution, gmeq: gme.core.equations.Equations, sub: Dict, name: str, fig_size: Optional[Tuple[float, float]] = None, dpi: Optional[int] = None, n_points: int = 201, do_pub_label: bool = False, pub_label: str = '', pub_label_xy: Tuple[float, float] = (0.5, 0.5), do_etaxi_label: bool = True, eta_label_xy: Tuple[float, float] = (0.5, 0.81), var_label_xy: Tuple[float, float] = (0.8, 0.5), xi_norm: Optional[float] = None, legend_loc: str = 'lower right', do_mod_v: bool = False)None

Plot velocity \(\mathbf{v}\) along a ray.

Parameters
  • gmes – instance of single-ray solution class defined in gme.ode.single_ray

  • gmeq – GME model equations class instance defined in gme.core.equations

  • sub – dictionary of model parameter values to be used for equation substitutions

  • name – name of figure (key in figure dictionary)

  • fig_size – optional figure width and height in inches

  • dpi – optional rasterization resolution

  • n_points – sample rate along each curve

profile_vdot(gmes: gme.ode.single_ray.SingleRaySolution, gmeq: gme.core.equations.Equations, sub: Dict, name: str, fig_size: Optional[Tuple[float, float]] = None, dpi: Optional[int] = None, n_points: int = 201, do_pub_label: bool = False, pub_label: str = '', do_etaxi_label: bool = True, xi_norm: Optional[float] = None, legend_loc: str = 'lower right', do_legend: bool = True, do_mod_vdot: bool = False, do_geodesic: bool = False)None

Plot acceleration \(\mathbf{}\dot{v}}\) along a ray.

Parameters
  • gmes – instance of single-ray solution class defined in gme.ode.single_ray

  • gmeq – GME model equations class instance defined in gme.core.equations

  • sub – dictionary of model parameter values to be used for equation substitutions

  • name – name of figure (key in figure dictionary)

  • fig_size – optional figure width and height in inches

  • dpi – optional rasterization resolution

  • n_points – sample rate along each curve

Code

"""
Visualization of ray velocities.

---------------------------------------------------------------------

Requires Python packages:
  -  :mod:`NumPy <numpy>`
  -  :mod:`SymPy <sympy>`
  -  :mod:`MatPlotLib <matplotlib>`
  -  `GME`_

.. _GMPLib: https://github.com/geomorphysics/GMPLib
.. _GME: https://github.com/geomorphysics/GME
.. _Matrix:
    https://docs.sympy.org/latest/modules/matrices/immutablematrices.html

---------------------------------------------------------------------
"""
# Library
import warnings
from typing import Dict, Tuple, Optional

# NumPy
import numpy as np

# SymPy
from sympy import N, deg

# MatPlotLib
import matplotlib.pyplot as plt

# GME
from gme.core.symbols import Ci, varepsilon
from gme.core.equations import Equations
from gme.ode.single_ray import SingleRaySolution
from gme.plot.base import Graphing

warnings.filterwarnings("ignore")

__all__ = ["RayVelocities"]


class RayVelocities(Graphing):
    """
    Visualization of ray velocities.

    Extends :class:`gme.plot.base.Graphing`.
    """

    def profile_v(
        self,
        gmes: SingleRaySolution,
        gmeq: Equations,
        sub: Dict,
        name: str,
        fig_size: Optional[Tuple[float, float]] = None,
        dpi: Optional[int] = None,
        n_points: int = 201,
        do_pub_label: bool = False,
        pub_label: str = "",
        pub_label_xy: Tuple[float, float] = (0.5, 0.5),
        do_etaxi_label: bool = True,
        eta_label_xy: Tuple[float, float] = (0.5, 0.81),
        var_label_xy: Tuple[float, float] = (0.8, 0.5),
        xi_norm: Optional[float] = None,
        legend_loc: str = "lower right",
        do_mod_v: bool = False,
    ) -> None:
        r"""
        Plot velocity :math:`\mathbf{v}` along a ray.

        Args:
            gmes:
                instance of single-ray solution class
                defined in :mod:`gme.ode.single_ray`
            gmeq:
                GME model equations class instance defined in
                :mod:`gme.core.equations`
            sub:
                dictionary of model parameter values to be used for
                equation substitutions
            name:
                name of figure (key in figure dictionary)
            fig_size:
                optional figure width and height in inches
            dpi:
                optional rasterization resolution
            n_points: sample rate along each curve
        """
        _ = self.create_figure(name, fig_size=fig_size, dpi=dpi)
        # pub_label_xy = [0.5,0.5] if pub_label_xy is None else pub_label_xy
        # eta_label_xy = [0.5,0.81] if eta_label_xy is None else eta_label_xy
        # var_label_xy = [0.8,0.5] if var_label_xy is None else var_label_xy

        if xi_norm is None:
            xi_norm = 1
            rate_label = "${v}$"
        else:
            xi_norm = float(N(xi_norm))
            rate_label = r"${v}/\xi^{\!\rightarrow_{\!\!0}}$  [-]"
        rx_array = gmes.rx_array
        x_min, x_max = rx_array[0], rx_array[-1]
        x_array = np.linspace(x_min, x_max, n_points)
        # t_array  = gmes.t_interp_x(x_array)
        vx_array = gmes.rdotx_interp(x_array) / xi_norm
        vz_array = gmes.rdotz_interp(x_array) / xi_norm
        v_array = np.sqrt(vx_array ** 2 + vz_array ** 2)
        # vx_max = np.max(np.abs(vx_array))
        vz_max = np.max(np.abs(vz_array))
        v_max = np.max((v_array))

        if do_mod_v:
            plt.plot(
                x_array, v_array, "DarkBlue", ls="-", lw=1.5, label=r"${v}(x)$"
            )
            plt.ylabel(r"Ray speed  " + rate_label, fontsize=13)
            legend_loc = "lower left"
        else:
            sfx = np.power(10, np.round(np.log10(vz_max / v_max), 0))
            label_suffix = "" if sfx == 1 else r"$\,\times\,$" + f"{sfx}"
            plt.plot(
                x_array,
                vx_array * sfx,
                "r",
                ls="-",
                lw=1.5,
                label=r"${v}^x(x)$" + label_suffix,
            )
            plt.plot(
                x_array, vz_array, "b", ls="-", lw=1.5, label=r"${v}^z(x)$"
            )
            plt.ylabel(r"Ray velocity  " + rate_label, fontsize=13)

        axes = plt.gca()
        ylim = plt.ylim()
        if ylim[1] < 0:
            axes.set_ylim(ylim[0], 0)
        if ylim[0] > 0:
            axes.set_ylim(0, ylim[1])
        # axes.set_ylim( -(ylim[1]-ylim[0])/20,ylim[1] )
        plt.grid(True, ls=":")
        plt.xlabel(r"Distance, $x/L_{\mathrm{c}}$  [-]", fontsize=13)
        plt.legend(loc=legend_loc, fontsize=14, framealpha=0.95)
        if do_etaxi_label:
            plt.text(
                *eta_label_xy,
                rf"$\eta={gmeq.eta_}$"
                + r"$\quad\mathsf{Ci}=$"
                + rf"${round(float(deg(Ci.subs(sub))))}\degree$",
                transform=axes.transAxes,
                horizontalalignment="center",
                verticalalignment="center",
                fontsize=16,
                color="k",
            )
        if do_pub_label:
            plt.text(
                *pub_label_xy,
                pub_label,
                transform=axes.transAxes,
                horizontalalignment="center",
                verticalalignment="center",
                fontsize=16,
                color="k",
            )
        plt.text(
            *var_label_xy,
            r"${v}(x)$" if do_mod_v else r"$\mathbf{v}(x)$",
            transform=axes.transAxes,
            horizontalalignment="center",
            verticalalignment="center",
            fontsize=18,
            color="k",
        )

    def profile_vdot(
        self,
        gmes: SingleRaySolution,
        gmeq: Equations,
        sub: Dict,
        name: str,
        fig_size: Optional[Tuple[float, float]] = None,
        dpi: Optional[int] = None,
        n_points: int = 201,
        do_pub_label: bool = False,
        pub_label: str = "",
        do_etaxi_label: bool = True,
        xi_norm: Optional[float] = None,
        legend_loc: str = "lower right",
        do_legend: bool = True,
        do_mod_vdot: bool = False,
        do_geodesic: bool = False,
    ) -> None:
        r"""
        Plot acceleration :math:`\mathbf{}\dot{v}}` along a ray.

        Args:
            gmes:
                instance of single-ray solution class
                defined in :mod:`gme.ode.single_ray`
            gmeq:
                GME model equations class instance defined in
                :mod:`gme.core.equations`
            sub:
                dictionary of model parameter values to be used for
                equation substitutions
            name:
                name of figure (key in figure dictionary)
            fig_size:
                optional figure width and height in inches
            dpi:
                optional rasterization resolution
            n_points: sample rate along each curve
        """
        _ = self.create_figure(name, fig_size=fig_size, dpi=dpi)

        # Use an erosion rate (likely vertical xi) to
        #     renormalize velocities and accelns (up to T)
        if xi_norm is None:
            xi_norm = 1
            rate_label = r"$\dot{v}$"
        else:
            xi_norm = float(N(xi_norm))
            rate_label = r"$\dot{v}/\xi^{\!\rightarrow_{\!\!0}}$  [T$^{-1}$]"

        # Specify sampling in x and t
        rx_array = gmes.rx_array
        x_min, x_max = rx_array[0], rx_array[-1]
        x_array = np.linspace(x_min, x_max, n_points)
        t_array = gmes.t_interp_x(x_array)

        # Get ray velocities
        vdotx_array = gmes.rddotx_interp_t(t_array) / xi_norm
        vdotz_array = gmes.rddotz_interp_t(t_array) / xi_norm
        vdot_array = np.sqrt(vdotx_array ** 2 + vdotz_array ** 2)

        # Prep to set vertical axis to span vdotz and thus scale vdotx to fit
        # vdotx_max = np.max(np.abs(vdotx_array))
        vdotz_max = np.max(np.abs(vdotz_array))
        vdot_max = np.max((vdot_array))

        # Start doing some plotting
        sfx = (
            1
            if np.abs(vdotz_max) < 1e-20
            else np.power(10, np.round(np.log10(vdotz_max / vdot_max), 0))
        )
        label_suffix = "" if sfx == 1 else rf"$\,\times\,${sfx}"
        vdotx_label = r"$\dot{v}^x_\mathrm{hmltn}(x)$" + label_suffix
        vdotz_label = r"$\dot{v}^z_\mathrm{hmltn}(x)$"
        if do_mod_vdot:
            plt.plot(
                x_array,
                vdot_array,
                "DarkBlue",
                ls="-",
                lw=1.5,
                label=r"$\dot{v}_\mathrm{hmltn}(x)$",
            )
            plt.ylabel(r"Ray acceleration  " + rate_label, fontsize=13)
            legend_loc = "lower left"
        else:
            plt.plot(
                x_array,
                vdotx_array * sfx,
                "r",
                ls="-",
                lw=1.5,
                label=vdotx_label,
            )
            plt.plot(
                x_array, vdotz_array, "b", ls="-", lw=1.5, label=vdotz_label
            )
            plt.ylabel(r"Ray acceleration  " + rate_label, fontsize=14)

        ylim = plt.ylim()

        # Geodesic computation of acceln using Christoffel symbols
        if (
            do_geodesic
            and hasattr(gmeq, "vdotx_lambdified")
            and hasattr(gmeq, "vdotz_lambdified")
            and gmeq.vdotx_lambdified is not None
            and gmeq.vdotz_lambdified is not None
        ):
            vx_array = gmes.rdotx_interp(x_array)
            vz_array = gmes.rdotz_interp(x_array)
            vdotx_gdsc_array = np.array(
                [
                    gmeq.vdotx_lambdified(
                        float(x), float(vx), float(vz), varepsilon.subs(sub)
                    )
                    / xi_norm
                    for (x, vx, vz) in zip(x_array, vx_array, vz_array)
                ]
            )
            vdotz_gdsc_array = np.array(
                [
                    gmeq.vdotz_lambdified(
                        float(x), float(vx), float(vz), varepsilon.subs(sub)
                    )
                    / xi_norm
                    for (x, vx, vz) in zip(x_array, vx_array, vz_array)
                ]
            )
            vdot_gdsc_array = np.sqrt(
                vdotx_gdsc_array ** 2 + vdotz_gdsc_array ** 2
            )
            vdotx_label = r"$\dot{v}^x_\mathrm{gdsc}(x)$" + label_suffix
            vdotz_label = r"$\dot{v}^z_\mathrm{gdsc}(x)$"
            if do_mod_vdot:
                plt.plot(
                    x_array,
                    vdot_gdsc_array,
                    "DarkBlue",
                    ls=":",
                    lw=3,
                    label=r"$\dot{v}_\mathrm{gdsc}(x)$",
                )
                plt.ylabel(r"Ray acceleration  " + rate_label, fontsize=13)
                legend_loc = "lower left"
            else:
                plt.plot(
                    x_array,
                    vdotx_gdsc_array * sfx,
                    "DarkRed",
                    ls=":",
                    lw=3,
                    label=vdotx_label,
                )
                plt.plot(
                    x_array,
                    vdotz_gdsc_array,
                    "DarkBlue",
                    ls=":",
                    lw=3,
                    label=vdotz_label,
                )

        # Misc pretty stuff
        axes = plt.gca()
        axes.set_ylim(*ylim)
        plt.grid(True, ls=":")

        plt.xlabel(r"Distance, $x/L_{\mathrm{c}}$  [-]", fontsize=14)
        if do_legend:
            plt.legend(loc=legend_loc, fontsize=13, framealpha=0.95)
        if do_etaxi_label:
            plt.text(
                0.6,
                0.8,
                pub_label if do_pub_label else rf"$\eta={gmeq.eta_}$",
                transform=axes.transAxes,
                horizontalalignment="center",
                verticalalignment="center",
                fontsize=14,
                color="k",
            )