Skip to content

logic_tree

Classes for the combined SRM + GMCM logic trees used to define a seismic hazard model.

HazardComponentBranch

A component branch of the combined (SRM + GMCM) logic tree comprised of an srm branch and a gmcm branch.

The HazardComposite branch is the smallest unit necessary to create a hazard curve realization.

Source code in toshi_hazard_post/logic_tree.py
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
class HazardComponentBranch:
    """A component branch of the combined (SRM + GMCM) logic tree comprised of an srm branch and a gmcm branch.

    The HazardComposite branch is the smallest unit necessary to create a hazard curve realization.
    """

    def __init__(self, source_branch: 'SourceBranch', gmcm_branches: Tuple['GMCMBranch']):
        """Initialize a new HazardComponentBranch object.

        Args:
            source_branch: The source branch of the composite branch.
            gmcm_branches: The GMCM branches that make up the composite branch.
        """
        self.source_branch = source_branch
        self.gmcm_branches = gmcm_branches
        self.weight = math.prod([self.source_branch.weight] + [b.weight for b in self.gmcm_branches])
        self.gmcm_branches = tuple(self.gmcm_branches)
        self.hash_digest = self.source_hash_digest + self.gmcm_hash_digest

    @property
    def registry_identity(self) -> str:
        """The registry identity of the component branch.

        The registry identity is formed as concatinations of the source and gmcm identities.
        {source branch id}{gmcm branch1}|{gmcm branch2}...
        """
        return self.source_branch.registry_identity + '|'.join(
            [branch.registry_identity for branch in self.gmcm_branches]
        )

    # @property
    # def hash_digest(self) -> str:
    #     return self.source_hash_digest + self.gmcm_hash_digest

    @property
    def gmcm_hash_digest(self) -> str:
        """The hash digest of the gmcm branch."""
        if len(self.gmcm_branches) != 1:
            raise NotImplementedError("multiple gmcm branches for a component branch is not implemented")
        return registry.gmm_registry.get_by_identity(self.gmcm_branches[0].registry_identity).hash_digest

    @property
    def source_hash_digest(self) -> str:
        """The hash digest of the source branch."""
        return registry.source_registry.get_by_identity(self.source_branch.registry_identity).hash_digest

gmcm_hash_digest property

The hash digest of the gmcm branch.

registry_identity property

The registry identity of the component branch.

The registry identity is formed as concatinations of the source and gmcm identities. {source branch id}{gmcm branch1}|{gmcm branch2}...

source_hash_digest property

The hash digest of the source branch.

__init__(source_branch, gmcm_branches)

Initialize a new HazardComponentBranch object.

Parameters:

Name Type Description Default
source_branch SourceBranch

The source branch of the composite branch.

required
gmcm_branches Tuple[GMCMBranch]

The GMCM branches that make up the composite branch.

required
Source code in toshi_hazard_post/logic_tree.py
27
28
29
30
31
32
33
34
35
36
37
38
def __init__(self, source_branch: 'SourceBranch', gmcm_branches: Tuple['GMCMBranch']):
    """Initialize a new HazardComponentBranch object.

    Args:
        source_branch: The source branch of the composite branch.
        gmcm_branches: The GMCM branches that make up the composite branch.
    """
    self.source_branch = source_branch
    self.gmcm_branches = gmcm_branches
    self.weight = math.prod([self.source_branch.weight] + [b.weight for b in self.gmcm_branches])
    self.gmcm_branches = tuple(self.gmcm_branches)
    self.hash_digest = self.source_hash_digest + self.gmcm_hash_digest

HazardCompositeBranch

A composite branch of the combined (SRM + GMCM) logic tree.

A HazardCompositeBranch will have multiple sources and multiple ground motion models and is formed by taking all combinations of branches from the branch sets. The HazardComposite branch is an Iterable and will return HazardComponentBranch when iterated.

Source code in toshi_hazard_post/logic_tree.py
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
class HazardCompositeBranch:
    """A composite branch of the combined (SRM + GMCM) logic tree.

    A HazardCompositeBranch will have multiple sources and
    multiple ground motion models and is formed by taking all combinations of branches from the branch sets. The
    HazardComposite branch is an Iterable and will return HazardComponentBranch when iterated.
    """

    def __init__(self, branches: list[HazardComponentBranch], source_weight: float):
        """Initialize a new HazardCompositeBranch object.

        Args:
            branches: The source-ground motion pairs that comprise the HazardCompositeBranch
            source_weight: The weight of the source branch.
        """
        self.branches = branches

        # to avoid double counting gmcm branches when calculating the weight we find the unique gmcm branches
        # since GMCMBranch objects are not hashable, we cannot use set()
        gsims = []
        for branch in self.branches:
            for gsim in branch.gmcm_branches:
                if gsim not in gsims:
                    gsims.append(gsim)
        gsim_weights = [gsim.weight for gsim in gsims]
        self.weight = math.prod(gsim_weights) * source_weight

    def __iter__(self) -> 'HazardCompositeBranch':
        """Iterate over all HazardComponentBranches that make up the HazardCompositeBranch."""
        self.__counter = 0
        return self

    def __next__(self) -> HazardComponentBranch:
        """Get the next HazardComponentBranch."""
        if self.__counter >= len(self.branches):
            raise StopIteration
        else:
            self.__counter += 1
            return self.branches[self.__counter - 1]

__init__(branches, source_weight)

Initialize a new HazardCompositeBranch object.

Parameters:

Name Type Description Default
branches list[HazardComponentBranch]

The source-ground motion pairs that comprise the HazardCompositeBranch

required
source_weight float

The weight of the source branch.

required
Source code in toshi_hazard_post/logic_tree.py
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
def __init__(self, branches: list[HazardComponentBranch], source_weight: float):
    """Initialize a new HazardCompositeBranch object.

    Args:
        branches: The source-ground motion pairs that comprise the HazardCompositeBranch
        source_weight: The weight of the source branch.
    """
    self.branches = branches

    # to avoid double counting gmcm branches when calculating the weight we find the unique gmcm branches
    # since GMCMBranch objects are not hashable, we cannot use set()
    gsims = []
    for branch in self.branches:
        for gsim in branch.gmcm_branches:
            if gsim not in gsims:
                gsims.append(gsim)
    gsim_weights = [gsim.weight for gsim in gsims]
    self.weight = math.prod(gsim_weights) * source_weight

__iter__()

Iterate over all HazardComponentBranches that make up the HazardCompositeBranch.

Source code in toshi_hazard_post/logic_tree.py
95
96
97
98
def __iter__(self) -> 'HazardCompositeBranch':
    """Iterate over all HazardComponentBranches that make up the HazardCompositeBranch."""
    self.__counter = 0
    return self

__next__()

Get the next HazardComponentBranch.

Source code in toshi_hazard_post/logic_tree.py
100
101
102
103
104
105
106
def __next__(self) -> HazardComponentBranch:
    """Get the next HazardComponentBranch."""
    if self.__counter >= len(self.branches):
        raise StopIteration
    else:
        self.__counter += 1
        return self.branches[self.__counter - 1]

HazardLogicTree

The combined (SRM + GMCM) logic tree needed to define the complete hazard model.

Source code in toshi_hazard_post/logic_tree.py
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
class HazardLogicTree:
    """The combined (SRM + GMCM) logic tree needed to define the complete hazard model."""

    def __init__(self, srm_logic_tree: 'SourceLogicTree', gmcm_logic_tree: 'GMCMLogicTree') -> None:
        """Initialize a new HazardLogicTree object.

        Args:
            srm_logic_tree: The seismicity rate model logic tree.
            gmcm_logic_tree: The ground motion characterisation model logic tree.
        """
        self.srm_logic_tree = srm_logic_tree

        # remove the TRTs from the GMCM logic tree that are not in the SRM logic tree
        # 1. find which TRTs are included in the source logic tree
        self.trts = set(chain(*[bs.tectonic_region_types for bs in self.srm_logic_tree.branch_sets]))

        # 2. make a copy of the gmcm logic tree. Eliminate any BranchSets with a TRT not included in the source tree
        self.gmcm_logic_tree = copy.deepcopy(gmcm_logic_tree)
        self.gmcm_logic_tree.branch_sets[:] = filter(
            lambda bs: bs.tectonic_region_type in self.trts, gmcm_logic_tree.branch_sets
        )

        self._composite_branches: list[HazardCompositeBranch] = []
        self._component_branches: list[HazardComponentBranch] = []

    @property
    def composite_branches(self) -> list[HazardCompositeBranch]:
        """Get the composite branches combining the SRM branches with the appropraite GMCM branches.

        The tectonic region types will be matched between SRM and GMCM branches.

        Returns:
            composite_branches: the composite branches that make up all full realizations of the complete hazard
            logic tree
        """
        if not self._composite_branches:
            self._generate_composite_branches()
        return self._composite_branches

    @property
    def component_branches(self) -> list[HazardComponentBranch]:
        """Get the component branches (each SRM branch with all possible GMCM branch matches).

        Returns:
            component_branches: the component branches that make up the independent realizations of the logic tree
        """
        if not self._component_branches:
            self._generate_component_branches()
        return self._component_branches

    @property
    def weights(self) -> 'npt.NDArray':
        """The weights for every enumerated branch (srm + gmcm) of the logic tree.

        Returns:
            weights: one dimensional array of branch weights
        """
        return np.array([branch.weight for branch in self.composite_branches])

    @property
    def branch_hash_table(self) -> list[list[str]]:
        """The simplest structure used to iterate though the realization hashes.

        Each element of the list represents a composite branch as a list of hashes of the component branches
        that make up the composite branch.

        Returns:
            hash_list: the list of composite branches, each of wich is a list of component branch hashes.
        """
        hashes = []
        for composite_branch in self.composite_branches:
            hashes.append([branch.hash_digest for branch in composite_branch])
        return hashes

    def _generate_composite_branches(self) -> None:
        log.debug("generating composite branches")
        self._composite_branches = []
        for srm_composite_branch, gmcm_composite_branch in product(
            self.srm_logic_tree.composite_branches, self.gmcm_logic_tree.composite_branches
        ):
            # for each srm component branch, find the matching GMCM branches (by TRT)
            hbranches = []
            for srm_branch in srm_composite_branch:
                trts = srm_branch.tectonic_region_types
                gmcm_branches = tuple(branch for branch in gmcm_composite_branch if branch.tectonic_region_type in trts)
                hbranches.append(HazardComponentBranch(source_branch=srm_branch, gmcm_branches=gmcm_branches))

            # to use the correct weight for correlated source branches we
            # must use the source branch weight which is correctly set
            self._composite_branches.append(HazardCompositeBranch(hbranches, source_weight=srm_composite_branch.weight))

    def _generate_component_branches(self) -> None:
        self._component_branches = []
        for srm_branch in self.srm_logic_tree:
            trts = srm_branch.tectonic_region_types
            branch_sets = [
                branch_set for branch_set in self.gmcm_logic_tree.branch_sets if branch_set.tectonic_region_type in trts
            ]
            for gmcm_branches in product(*[bs.branches for bs in branch_sets]):
                self._component_branches.append(
                    HazardComponentBranch(source_branch=srm_branch.to_branch(), gmcm_branches=gmcm_branches)
                )

branch_hash_table property

The simplest structure used to iterate though the realization hashes.

Each element of the list represents a composite branch as a list of hashes of the component branches that make up the composite branch.

Returns:

Name Type Description
hash_list list[list[str]]

the list of composite branches, each of wich is a list of component branch hashes.

component_branches property

Get the component branches (each SRM branch with all possible GMCM branch matches).

Returns:

Name Type Description
component_branches list[HazardComponentBranch]

the component branches that make up the independent realizations of the logic tree

composite_branches property

Get the composite branches combining the SRM branches with the appropraite GMCM branches.

The tectonic region types will be matched between SRM and GMCM branches.

Returns:

Name Type Description
composite_branches list[HazardCompositeBranch]

the composite branches that make up all full realizations of the complete hazard

list[HazardCompositeBranch]

logic tree

weights property

The weights for every enumerated branch (srm + gmcm) of the logic tree.

Returns:

Name Type Description
weights NDArray

one dimensional array of branch weights

__init__(srm_logic_tree, gmcm_logic_tree)

Initialize a new HazardLogicTree object.

Parameters:

Name Type Description Default
srm_logic_tree SourceLogicTree

The seismicity rate model logic tree.

required
gmcm_logic_tree GMCMLogicTree

The ground motion characterisation model logic tree.

required
Source code in toshi_hazard_post/logic_tree.py
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
def __init__(self, srm_logic_tree: 'SourceLogicTree', gmcm_logic_tree: 'GMCMLogicTree') -> None:
    """Initialize a new HazardLogicTree object.

    Args:
        srm_logic_tree: The seismicity rate model logic tree.
        gmcm_logic_tree: The ground motion characterisation model logic tree.
    """
    self.srm_logic_tree = srm_logic_tree

    # remove the TRTs from the GMCM logic tree that are not in the SRM logic tree
    # 1. find which TRTs are included in the source logic tree
    self.trts = set(chain(*[bs.tectonic_region_types for bs in self.srm_logic_tree.branch_sets]))

    # 2. make a copy of the gmcm logic tree. Eliminate any BranchSets with a TRT not included in the source tree
    self.gmcm_logic_tree = copy.deepcopy(gmcm_logic_tree)
    self.gmcm_logic_tree.branch_sets[:] = filter(
        lambda bs: bs.tectonic_region_type in self.trts, gmcm_logic_tree.branch_sets
    )

    self._composite_branches: list[HazardCompositeBranch] = []
    self._component_branches: list[HazardComponentBranch] = []