source_modelling.scripts.plot_srf_moment

Utility script to plot moment over time for an SRF.

  1"""Utility script to plot moment over time for an SRF."""
  2
  3from pathlib import Path
  4from typing import Annotated, Optional
  5
  6import typer
  7from matplotlib import pyplot as plt
  8
  9from source_modelling import moment, rupture_propagation, srf
 10
 11app = typer.Typer()
 12
 13
 14@app.command(help="Plot released moment for an SRF over time.")
 15def plot_srf_moment(
 16    srf_ffp: Annotated[
 17        Path,
 18        typer.Argument(
 19            help="SRF filepath to plot", exists=True, readable=True, dir_okay=False
 20        ),
 21    ],
 22    output_png_ffp: Annotated[
 23        Path, typer.Argument(help="Output plot path", writable=True, dir_okay=False)
 24    ],
 25    dpi: Annotated[
 26        int, typer.Option(help="Plot image pixel density (higher = better)", min=300)
 27    ] = 300,
 28    realisation_ffp: Annotated[
 29        Optional[Path],
 30        typer.Option(
 31            help="Path to realisation, used to plot individual fault contribution."
 32        ),
 33    ] = None,
 34) -> None:
 35    """Plot released moment for an SRF over time.
 36
 37    Parameters
 38    ----------
 39    srf_ffp : Path
 40        SRF filepath to plot.
 41    output_png_ffp : Path
 42        Output plot path.
 43    dpi : float, default 300
 44        Plot image pixel density (higher = better).
 45    realisation_ffp : Optional[Path], default None
 46        Path to realisation, used to plot individual fault contribution.
 47    """
 48    srf_data = srf.read_srf(srf_ffp)
 49
 50    magnitude = moment.moment_to_magnitude(
 51        moment.MU * (srf_data.points["area"] * srf_data.points["slip"] / (100**3)).sum()
 52    )
 53
 54    dt = srf_data.points["dt"].iloc[0]
 55
 56    overall_moment_rate = moment.moment_rate_over_time_from_slip(
 57        srf_data.points["area"], srf_data.slip, dt, srf_data.nt
 58    )
 59    fig, ax = plt.subplots()
 60    ax.plot(
 61        overall_moment_rate.index.values,
 62        overall_moment_rate["moment_rate"],
 63        label="Overall Moment Rate",
 64    )
 65
 66    if realisation_ffp: # pragma: no cover
 67        # NOTE: this import is here because the workflow is, as yet,
 68        # not ready to be installed along-side source modelling.
 69        from workflow.realisations import RupturePropagationConfig, SourceConfig
 70
 71        source_config = SourceConfig.read_from_realisation(realisation_ffp)
 72        rupture_propogation_config = RupturePropagationConfig.read_from_realisation(
 73            realisation_ffp
 74        )
 75        segment_counter = 0
 76        point_counter = 0
 77        for fault_name in rupture_propagation.tree_nodes_in_order(
 78            rupture_propogation_config.rupture_causality_tree
 79        ):
 80            plane_count = len(source_config.source_geometries[fault_name].planes)
 81            segments = srf_data.header.iloc[
 82                segment_counter : segment_counter + plane_count
 83            ]
 84            num_points = (segments["nstk"] * segments["ndip"]).sum()
 85            individual_moment_rate = moment.moment_rate_over_time_from_slip(
 86                srf_data.points["area"]
 87                .iloc[point_counter : point_counter + num_points]
 88                .to_numpy(),
 89                srf_data.slip[point_counter : point_counter + num_points],
 90                dt,
 91                srf_data.nt,
 92            )
 93            ax.plot(
 94                individual_moment_rate.index.values,
 95                individual_moment_rate["moment_rate"],
 96                label=fault_name,
 97            )
 98            segment_counter += plane_count
 99            point_counter += num_points
100
101    ax.set_ylabel("Moment Rate (Nm/s)")
102    ax.set_xlabel("Time (s)")
103    ax.legend()
104    ax.set_title(f"Moment over Time (Total Mw: {magnitude:.2f})")
105
106    fig.savefig(output_png_ffp, dpi=dpi)
107
108
109if __name__ == "__main__":
110    app()
app = <typer.main.Typer object>
@app.command(help='Plot released moment for an SRF over time.')
def plot_srf_moment( srf_ffp: Annotated[pathlib.Path, <typer.models.ArgumentInfo object>], output_png_ffp: Annotated[pathlib.Path, <typer.models.ArgumentInfo object>], dpi: Annotated[int, <typer.models.OptionInfo object>] = 300, realisation_ffp: Annotated[Optional[pathlib.Path], <typer.models.OptionInfo object>] = None) -> None:
 15@app.command(help="Plot released moment for an SRF over time.")
 16def plot_srf_moment(
 17    srf_ffp: Annotated[
 18        Path,
 19        typer.Argument(
 20            help="SRF filepath to plot", exists=True, readable=True, dir_okay=False
 21        ),
 22    ],
 23    output_png_ffp: Annotated[
 24        Path, typer.Argument(help="Output plot path", writable=True, dir_okay=False)
 25    ],
 26    dpi: Annotated[
 27        int, typer.Option(help="Plot image pixel density (higher = better)", min=300)
 28    ] = 300,
 29    realisation_ffp: Annotated[
 30        Optional[Path],
 31        typer.Option(
 32            help="Path to realisation, used to plot individual fault contribution."
 33        ),
 34    ] = None,
 35) -> None:
 36    """Plot released moment for an SRF over time.
 37
 38    Parameters
 39    ----------
 40    srf_ffp : Path
 41        SRF filepath to plot.
 42    output_png_ffp : Path
 43        Output plot path.
 44    dpi : float, default 300
 45        Plot image pixel density (higher = better).
 46    realisation_ffp : Optional[Path], default None
 47        Path to realisation, used to plot individual fault contribution.
 48    """
 49    srf_data = srf.read_srf(srf_ffp)
 50
 51    magnitude = moment.moment_to_magnitude(
 52        moment.MU * (srf_data.points["area"] * srf_data.points["slip"] / (100**3)).sum()
 53    )
 54
 55    dt = srf_data.points["dt"].iloc[0]
 56
 57    overall_moment_rate = moment.moment_rate_over_time_from_slip(
 58        srf_data.points["area"], srf_data.slip, dt, srf_data.nt
 59    )
 60    fig, ax = plt.subplots()
 61    ax.plot(
 62        overall_moment_rate.index.values,
 63        overall_moment_rate["moment_rate"],
 64        label="Overall Moment Rate",
 65    )
 66
 67    if realisation_ffp: # pragma: no cover
 68        # NOTE: this import is here because the workflow is, as yet,
 69        # not ready to be installed along-side source modelling.
 70        from workflow.realisations import RupturePropagationConfig, SourceConfig
 71
 72        source_config = SourceConfig.read_from_realisation(realisation_ffp)
 73        rupture_propogation_config = RupturePropagationConfig.read_from_realisation(
 74            realisation_ffp
 75        )
 76        segment_counter = 0
 77        point_counter = 0
 78        for fault_name in rupture_propagation.tree_nodes_in_order(
 79            rupture_propogation_config.rupture_causality_tree
 80        ):
 81            plane_count = len(source_config.source_geometries[fault_name].planes)
 82            segments = srf_data.header.iloc[
 83                segment_counter : segment_counter + plane_count
 84            ]
 85            num_points = (segments["nstk"] * segments["ndip"]).sum()
 86            individual_moment_rate = moment.moment_rate_over_time_from_slip(
 87                srf_data.points["area"]
 88                .iloc[point_counter : point_counter + num_points]
 89                .to_numpy(),
 90                srf_data.slip[point_counter : point_counter + num_points],
 91                dt,
 92                srf_data.nt,
 93            )
 94            ax.plot(
 95                individual_moment_rate.index.values,
 96                individual_moment_rate["moment_rate"],
 97                label=fault_name,
 98            )
 99            segment_counter += plane_count
100            point_counter += num_points
101
102    ax.set_ylabel("Moment Rate (Nm/s)")
103    ax.set_xlabel("Time (s)")
104    ax.legend()
105    ax.set_title(f"Moment over Time (Total Mw: {magnitude:.2f})")
106
107    fig.savefig(output_png_ffp, dpi=dpi)

Plot released moment for an SRF over time.

Parameters
  • srf_ffp (Path): SRF filepath to plot.
  • output_png_ffp (Path): Output plot path.
  • dpi (float, default 300): Plot image pixel density (higher = better).
  • realisation_ffp (Optional[Path], default None): Path to realisation, used to plot individual fault contribution.