generated from ucgmsim/template
-
Notifications
You must be signed in to change notification settings - Fork 0
Rupture Propagation #3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
eed9805
add rupture propagation module
lispandfound 1b1a7f7
make Fault.corners a property for consistency
lispandfound 25e9598
fix bug in dip calculation
lispandfound 8aba38f
fix namedtuple using keyword arguments
lispandfound 190cfa9
Merge branch 'sources' into rupture_propagation
lispandfound 6e1d66a
correct comment
lispandfound 23c69de
add centroid, make algorithms more numerically stable
lispandfound 76bb1d6
small fix for centroid -> plane
lispandfound b1126a9
format and sort
lispandfound b3793e9
formatting
lispandfound 3f5be58
Merge branch 'main' into rupture_propagation
lispandfound 7d4fb1d
docstring formatting + linting checks
lispandfound f6782dc
add type signatures to d0 and delta
lispandfound File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,229 @@ | ||
| """ | ||
| Rupture Propagation Module | ||
|
|
||
| This module provides functions for computing likely rupture paths from | ||
| information about the distances between faults. | ||
|
|
||
| Functions: | ||
| - shaw_dieterich_distance_model: | ||
| Compute fault jump probabilities using the Shaw-Dieterich distance model. | ||
| - prune_distance_graph: Prune the distance graph based on a cutoff value. | ||
| - probability_graph: | ||
| Convert a graph of distances between faults into a graph of jump | ||
| probabilities using the Shaw-Dieterich model. | ||
| - probabilistic_minimum_spanning_tree: Generate a probabilistic minimum spanning tree. | ||
|
|
||
| Typing Aliases: | ||
| - DistanceGraph: A graph representing distances between faults. | ||
| - ProbabilityGraph: A graph representing jump probabilities between faults. | ||
| - RuptureCausalityTree: A tree representing the causality of ruptures between faults. | ||
| """ | ||
|
|
||
| from collections import defaultdict, namedtuple | ||
| from typing import Optional | ||
|
|
||
| import numpy as np | ||
|
|
||
| from qcore import coordinates | ||
| from source_modelling import sources | ||
|
|
||
| DistanceGraph = dict[str, dict[str, int]] | ||
| ProbabilityGraph = defaultdict[str, dict[str, float]] | ||
| RuptureCausalityTree = dict[str, Optional[str]] | ||
|
|
||
| JumpPair = namedtuple("JumpPair", ["from_point", "to_point"]) | ||
|
|
||
|
|
||
| def shaw_dieterich_distance_model(distance: float, d0: float, delta: float) -> float: | ||
| """ | ||
| Compute fault jump probabilities using the Shaw-Dieterich distance model[0]. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| distance : float | ||
| The distance between two faults. | ||
| d0 : float | ||
| The characteristic distance parameter. | ||
| delta : float | ||
| The characteristic slip distance parameter. | ||
|
|
||
| Returns | ||
| ------- | ||
| float | ||
| The calculated probability. | ||
|
|
||
| References | ||
| ---------- | ||
| [0]: Shaw, B. E., & Dieterich, J. H. (2007). Probabilities for jumping fault | ||
| segment stepovers. Geophysical Research Letters, 34(1). | ||
| """ | ||
| return min(1, np.exp(-(distance - delta) / d0)) | ||
|
|
||
|
|
||
| def prune_distance_graph(distances: DistanceGraph, cutoff: int) -> DistanceGraph: | ||
| """ | ||
| Prune the distance graph based on a cutoff value. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| distances : DistanceGraph | ||
| The graph of distances between faults. | ||
| cutoff : int | ||
| The cutoff distance in metres. | ||
|
|
||
| Returns | ||
| ------- | ||
| DistanceGraph | ||
| A copy of the input distance graph, keeping only edges that are less | ||
| than the cutoff. | ||
| """ | ||
| return { | ||
| fault_u: { | ||
| fault_v: distance | ||
| for fault_v, distance in neighbours_fault_u.items() | ||
| if distance < cutoff | ||
| } | ||
| for fault_u, neighbours_fault_u in distances.items() | ||
| } | ||
|
|
||
|
|
||
| def probability_graph( | ||
| distances: DistanceGraph, d0: float = 3, delta: float = 1 | ||
| ) -> ProbabilityGraph: | ||
| """ | ||
| Convert a graph of distances between faults into a graph of jump | ||
| probablities using the Shaw-Dieterich model. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| distances : DistanceGraph | ||
| The distance graph between faults. | ||
| d0 : float, optional | ||
| The d0 parameter for the Shaw_Dieterich model. See `shaw_dieterich_distance_model`. | ||
| delta : float, optional | ||
| The delta parameter for the Shaw_Dieterich model. See `shaw_dieterich_distance_model`. | ||
|
|
||
| Returns | ||
| ------- | ||
| ProbabilityGraph | ||
| The graph with faults as vertices. Each edge (fault_u, fault_v) | ||
| has a log-probability -p as a weight. The log-probability -p here | ||
| is the negative of the log-probability a rupture propogates from | ||
| fault_u to fault_v, relative to the probability it propogates to | ||
| any of the other neighbours of fault_u. | ||
| """ | ||
| probabilities_raw = { | ||
| fault_u: { | ||
| fault_v: shaw_dieterich_distance_model(distance / 1000, d0, delta) | ||
| for fault_v, distance in neighbours_fault_u.items() | ||
| } | ||
| for fault_u, neighbours_fault_u in distances.items() | ||
| } | ||
| probabilities_log = defaultdict(dict) | ||
| for fault_u, neighbours_fault_u in probabilities_raw.items(): | ||
| normalising_constant = sum(neighbours_fault_u.values()) | ||
| if normalising_constant == 0: | ||
| for fault_v, _ in neighbours_fault_u.items(): | ||
| probabilities_log[fault_u][fault_v] = 1 / len(neighbours_fault_u) | ||
| for fault_v, prob in neighbours_fault_u.items(): | ||
| probabilities_log[fault_u][fault_v] = prob / normalising_constant | ||
| return probabilities_log | ||
|
|
||
|
|
||
| def probabilistic_minimum_spanning_tree( | ||
| probability_graph: ProbabilityGraph, initial_fault: str | ||
| ) -> RuptureCausalityTree: | ||
| """ | ||
| Generate a probabilistic minimum spanning tree. | ||
|
|
||
| The minimum spanning tree of the probability graph represents rupture | ||
| causality tree with the highest likelihood of occuring assuming that | ||
| rupture jumps are independent. | ||
|
|
||
| NOTE: While the overall probability of the minimum spanning tree is high, | ||
| the paths from the initial fault may not be the most likely. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| probability_graph : ProbabilityGraph | ||
| The probability graph. | ||
| initial_fault : str | ||
| The initial fault. | ||
|
|
||
| Returns | ||
| ------- | ||
| RuptureCausalityTree | ||
| The probabilistic minimum spanning tree. | ||
| """ | ||
| rupture_causality_tree = {initial_fault: None} | ||
| path_probabilities = defaultdict(lambda: np.inf) | ||
| path_probabilities[initial_fault] = 0 | ||
| processed_faults = set() | ||
| for _ in range(len(probability_graph)): | ||
| current_fault = min( | ||
| (fault for fault in probability_graph if fault not in processed_faults), | ||
| key=lambda fault: path_probabilities[fault], | ||
| ) | ||
| processed_faults.add(current_fault) | ||
| for fault_neighbour, probability in probability_graph[current_fault].items(): | ||
| if ( | ||
| fault_neighbour not in processed_faults | ||
| and probability < path_probabilities[fault_neighbour] | ||
| ): | ||
| path_probabilities[fault_neighbour] = probability | ||
| rupture_causality_tree[fault_neighbour] = current_fault | ||
| return rupture_causality_tree | ||
|
|
||
|
|
||
| def distance_between( | ||
| source_a: sources.IsSource, | ||
| source_b: sources.IsSource, | ||
| source_a_point: np.ndarray, | ||
| source_b_point: np.ndarray, | ||
| ) -> float: | ||
| global_point_a = source_a.fault_coordinates_to_wgs_depth_coordinates(source_a_point) | ||
| global_point_b = source_b.fault_coordinates_to_wgs_depth_coordinates(source_b_point) | ||
| return coordinates.distance_between_wgs_depth_coordinates( | ||
| global_point_a, global_point_b | ||
| ) | ||
|
|
||
|
|
||
| def estimate_most_likely_rupture_propagation( | ||
| sources_map: dict[str, sources.IsSource], | ||
| initial_source: str, | ||
| jump_impossibility_limit_distance: int = 15000, | ||
| ) -> RuptureCausalityTree: | ||
| distance_graph = { | ||
| source_a_name: { | ||
| source_b_name: distance_between( | ||
| source_a, | ||
| source_b, | ||
| *sources.closest_point_between_sources(source_a, source_b), | ||
| ) | ||
| for source_b_name, source_b in sources_map.items() | ||
| if source_a_name != source_b_name | ||
| } | ||
| for source_a_name, source_a in sources_map.items() | ||
| } | ||
| distance_graph = prune_distance_graph( | ||
| distance_graph, jump_impossibility_limit_distance | ||
| ) | ||
| jump_probability_graph = probability_graph(distance_graph) | ||
| return probabilistic_minimum_spanning_tree( | ||
| jump_probability_graph, initial_fault=initial_source | ||
| ) | ||
|
|
||
|
|
||
| def jump_points_from_rupture_tree( | ||
| source_map: dict[str, sources.IsSource], | ||
| rupture_causality_tree: RuptureCausalityTree, | ||
| ) -> dict[str, JumpPair]: | ||
| jump_points = {} | ||
| for source, parent in rupture_causality_tree.items(): | ||
| if parent is None: | ||
| continue | ||
| source_point, parent_point = sources.closest_point_between_sources( | ||
| source_map[source], source_map[parent] | ||
| ) | ||
| jump_points[source] = JumpPair(parent_point, source_point) | ||
| return jump_points | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.