source_modelling.scripts.plot_srf_cumulative_moment
Utility script to plot cumulative moment over time for an SRF.
1"""Utility script to plot cumulative moment over time for an SRF.""" 2 3from pathlib import Path 4from typing import Annotated, Optional 5 6import numpy as np 7import typer 8from matplotlib import pyplot as plt 9 10from source_modelling import moment, rupture_propagation, srf 11 12app = typer.Typer() 13 14 15@app.command(help="Plot cumulative moment for an SRF over time.") 16def plot_srf_cumulative_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 min_shade_cutoff: Annotated[ 36 float, typer.Option(help="Minimum shading cutoff", min=0, max=1) 37 ] = 0.05, 38 max_shade_cutoff: Annotated[ 39 float, typer.Option(help="Maximum shading cutoff", min=0, max=1) 40 ] = 0.95, 41): 42 """Plot cumulative moment for an SRF over time. 43 44 Parameters 45 ---------- 46 srf_ffp : Annotated[ Path, typer.Argument( help 47 SRF filepath to plot. 48 output_png_ffp : Annotated[ Path, typer.Argument(help 49 Output plot path. 50 dpi : Annotated[ int, typer.Option(help 51 Plot image pixel density (higher = better). 52 realisation_ffp : Annotated[ Optional[Path], typer.Option( help 53 Path to realisation, used to plot individual fault 54 contribution. 55 min_shade_cutoff : Annotated[ float, typer.Option(help 56 Minimum shading cutoff. 57 max_shade_cutoff : Annotated[ float, typer.Option(help 58 Maximum shading cutoff. 59 """ 60 srf_data = srf.read_srf(srf_ffp) 61 62 overall_moment = moment.moment_over_time_from_moment_rate( 63 moment.moment_rate_over_time_from_slip( 64 srf_data.points["area"], 65 srf_data.slip, 66 srf_data.dt, 67 srf_data.nt, 68 ) 69 ) 70 total_moment = overall_moment["moment"].iloc[-1] 71 72 shaded_moments = overall_moment[ 73 (overall_moment["moment"] >= total_moment * min_shade_cutoff) 74 & (overall_moment["moment"] <= total_moment * max_shade_cutoff) 75 ] 76 fig, ax = plt.subplots() 77 ax.fill_between(shaded_moments.index.values, shaded_moments["moment"], alpha=0.2) 78 ax.plot( 79 overall_moment.index.values, overall_moment["moment"], label="Overall Moment" 80 ) 81 82 if realisation_ffp: # pragma: no cover 83 # NOTE: this import is here because the workflow is, as yet, 84 # not ready to be installed along-side source modelling. 85 from workflow.realisations import RupturePropagationConfig, SourceConfig 86 87 source_config = SourceConfig.read_from_realisation(realisation_ffp) 88 rupture_propogation_config = RupturePropagationConfig.read_from_realisation( 89 realisation_ffp 90 ) 91 segment_counter = 0 92 point_counter = 0 93 for fault_name in rupture_propagation.tree_nodes_in_order( 94 rupture_propogation_config.rupture_causality_tree 95 ): 96 plane_count = len(source_config.source_geometries[fault_name].planes) 97 segments = srf_data.header.iloc[ 98 segment_counter : segment_counter + plane_count 99 ] 100 num_points = (segments["nstk"] * segments["ndip"]).sum() 101 segment_points = srf_data.points.iloc[ 102 point_counter : point_counter + num_points 103 ] 104 105 individual_moment = moment.moment_over_time_from_moment_rate( 106 moment.moment_rate_over_time_from_slip( 107 segment_points["area"], 108 srf_data.slip[point_counter : point_counter + num_points], 109 srf_data.dt, 110 srf_data.nt, 111 ) 112 ) 113 114 ax.plot( 115 individual_moment.index.values, 116 individual_moment["moment"], 117 label=fault_name, 118 ) 119 total_moment = individual_moment["moment"].iloc[-1] 120 shaded_moments = individual_moment[ 121 (individual_moment["moment"] >= total_moment * min_shade_cutoff) 122 & (individual_moment["moment"] <= total_moment * max_shade_cutoff) 123 ] 124 ax.fill_between( 125 shaded_moments.index.values, shaded_moments["moment"], alpha=0.2 126 ) 127 segment_counter += plane_count 128 point_counter += num_points 129 130 ax.set_ylabel("Cumulative Moment (Nm)") 131 ax.set_xlabel("Time (s)") 132 ax.legend() 133 min_shade_percent = int(np.round(min_shade_cutoff * 100)) 134 max_shade_percent = int(np.round(max_shade_cutoff * 100)) 135 ax.set_title( 136 f"Cumulative Moment over Time (Shaded Area: {min_shade_percent}% - {max_shade_percent}%)" 137 ) 138 139 fig.savefig(output_png_ffp, dpi=dpi) 140 141 142if __name__ == "__main__": 143 app()
app =
<typer.main.Typer object>
@app.command(help='Plot cumulative moment for an SRF over time.')
def
plot_srf_cumulative_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, min_shade_cutoff: Annotated[float, <typer.models.OptionInfo object>] = 0.05, max_shade_cutoff: Annotated[float, <typer.models.OptionInfo object>] = 0.95):
16@app.command(help="Plot cumulative moment for an SRF over time.") 17def plot_srf_cumulative_moment( 18 srf_ffp: Annotated[ 19 Path, 20 typer.Argument( 21 help="SRF filepath to plot", exists=True, readable=True, dir_okay=False 22 ), 23 ], 24 output_png_ffp: Annotated[ 25 Path, typer.Argument(help="Output plot path", writable=True, dir_okay=False) 26 ], 27 dpi: Annotated[ 28 int, typer.Option(help="Plot image pixel density (higher = better)", min=300) 29 ] = 300, 30 realisation_ffp: Annotated[ 31 Optional[Path], 32 typer.Option( 33 help="Path to realisation, used to plot individual fault contribution." 34 ), 35 ] = None, 36 min_shade_cutoff: Annotated[ 37 float, typer.Option(help="Minimum shading cutoff", min=0, max=1) 38 ] = 0.05, 39 max_shade_cutoff: Annotated[ 40 float, typer.Option(help="Maximum shading cutoff", min=0, max=1) 41 ] = 0.95, 42): 43 """Plot cumulative moment for an SRF over time. 44 45 Parameters 46 ---------- 47 srf_ffp : Annotated[ Path, typer.Argument( help 48 SRF filepath to plot. 49 output_png_ffp : Annotated[ Path, typer.Argument(help 50 Output plot path. 51 dpi : Annotated[ int, typer.Option(help 52 Plot image pixel density (higher = better). 53 realisation_ffp : Annotated[ Optional[Path], typer.Option( help 54 Path to realisation, used to plot individual fault 55 contribution. 56 min_shade_cutoff : Annotated[ float, typer.Option(help 57 Minimum shading cutoff. 58 max_shade_cutoff : Annotated[ float, typer.Option(help 59 Maximum shading cutoff. 60 """ 61 srf_data = srf.read_srf(srf_ffp) 62 63 overall_moment = moment.moment_over_time_from_moment_rate( 64 moment.moment_rate_over_time_from_slip( 65 srf_data.points["area"], 66 srf_data.slip, 67 srf_data.dt, 68 srf_data.nt, 69 ) 70 ) 71 total_moment = overall_moment["moment"].iloc[-1] 72 73 shaded_moments = overall_moment[ 74 (overall_moment["moment"] >= total_moment * min_shade_cutoff) 75 & (overall_moment["moment"] <= total_moment * max_shade_cutoff) 76 ] 77 fig, ax = plt.subplots() 78 ax.fill_between(shaded_moments.index.values, shaded_moments["moment"], alpha=0.2) 79 ax.plot( 80 overall_moment.index.values, overall_moment["moment"], label="Overall Moment" 81 ) 82 83 if realisation_ffp: # pragma: no cover 84 # NOTE: this import is here because the workflow is, as yet, 85 # not ready to be installed along-side source modelling. 86 from workflow.realisations import RupturePropagationConfig, SourceConfig 87 88 source_config = SourceConfig.read_from_realisation(realisation_ffp) 89 rupture_propogation_config = RupturePropagationConfig.read_from_realisation( 90 realisation_ffp 91 ) 92 segment_counter = 0 93 point_counter = 0 94 for fault_name in rupture_propagation.tree_nodes_in_order( 95 rupture_propogation_config.rupture_causality_tree 96 ): 97 plane_count = len(source_config.source_geometries[fault_name].planes) 98 segments = srf_data.header.iloc[ 99 segment_counter : segment_counter + plane_count 100 ] 101 num_points = (segments["nstk"] * segments["ndip"]).sum() 102 segment_points = srf_data.points.iloc[ 103 point_counter : point_counter + num_points 104 ] 105 106 individual_moment = moment.moment_over_time_from_moment_rate( 107 moment.moment_rate_over_time_from_slip( 108 segment_points["area"], 109 srf_data.slip[point_counter : point_counter + num_points], 110 srf_data.dt, 111 srf_data.nt, 112 ) 113 ) 114 115 ax.plot( 116 individual_moment.index.values, 117 individual_moment["moment"], 118 label=fault_name, 119 ) 120 total_moment = individual_moment["moment"].iloc[-1] 121 shaded_moments = individual_moment[ 122 (individual_moment["moment"] >= total_moment * min_shade_cutoff) 123 & (individual_moment["moment"] <= total_moment * max_shade_cutoff) 124 ] 125 ax.fill_between( 126 shaded_moments.index.values, shaded_moments["moment"], alpha=0.2 127 ) 128 segment_counter += plane_count 129 point_counter += num_points 130 131 ax.set_ylabel("Cumulative Moment (Nm)") 132 ax.set_xlabel("Time (s)") 133 ax.legend() 134 min_shade_percent = int(np.round(min_shade_cutoff * 100)) 135 max_shade_percent = int(np.round(max_shade_cutoff * 100)) 136 ax.set_title( 137 f"Cumulative Moment over Time (Shaded Area: {min_shade_percent}% - {max_shade_percent}%)" 138 ) 139 140 fig.savefig(output_png_ffp, dpi=dpi)
Plot cumulative moment for an SRF over time.
Parameters
- srf_ffp (Annotated[ Path, typer.Argument( help): SRF filepath to plot.
- output_png_ffp (Annotated[ Path, typer.Argument(help): Output plot path.
- dpi (Annotated[ int, typer.Option(help): Plot image pixel density (higher = better).
- realisation_ffp (Annotated[ Optional[Path], typer.Option( help): Path to realisation, used to plot individual fault contribution.
- min_shade_cutoff (Annotated[ float, typer.Option(help): Minimum shading cutoff.
- max_shade_cutoff (Annotated[ float, typer.Option(help): Maximum shading cutoff.