Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions debian/changelog
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
[Christopher Brooks]
* Extended recurSet/recurRow epistemic uncertainties to simple fault
sources and added a rateSplit uncertainty to partition rate between
an area source and embedded faults, for the BC Hydro NVA alt2 LT
(tested inside logictree/case_25)
an area source and embedded faults, for the BC Hydro NVA alt2/alt3
LTs (tested inside logictree/case_25)

[Michele Simionato]
* Fixed a bug in `oq show rlz` showing wrong information for some complex trees
Expand Down
6 changes: 6 additions & 0 deletions openquake/calculators/tests/logictree_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,12 @@ def test_case_25(self):
'expected/hazard_curve-mean-PGA_alt2.csv', got_alt2)
self.assertEqual(len(self.calc.full_lt.get_realizations()), 16)

self.run_calc(case_25.__file__, 'job_alt3.ini', exports='csv')
[got_alt3] = export(('hcurves', 'csv'), self.calc.datastore)
self.assertEqualFiles(
'expected/hazard_curve-mean-PGA_alt3.csv', got_alt3)
self.assertEqual(len(self.calc.full_lt.get_realizations()), 8)

def test_case_28(self): # North Africa
# MultiPointSource with modify MFD logic tree
out = self.run_calc(case_28.__file__, 'job.ini', exports='csv')
Expand Down
5 changes: 4 additions & 1 deletion openquake/hazardlib/lt.py
Original file line number Diff line number Diff line change
Expand Up @@ -478,8 +478,11 @@ def _set_recurrow(utype, source, value):
# BCHydro NVA epistemic uncertainty
@apply_uncertainty.add('recurSet')
def _set_recurset(utype, source, value):
# A per-source mmax_offset (parsed from the optional mmaxOffset XML
# attribute) shifts the branchset max_mag. The alt3 uses this to enforce
# bg_mmax = fault_mmax - 0.5 while still sharing one recurSet branchset
source.recur_model = value["recur_model"]
source.mmax = float(value["max_mag"])
source.mmax = float(value["max_mag"]) + getattr(source, 'mmax_offset', 0.0)
return


Expand Down
33 changes: 22 additions & 11 deletions openquake/hazardlib/source/area.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,30 +129,41 @@ def modify_set_recurrow(self, recurrow):
"""
Modify the recurrence parameters by values given in a dict.

If a rateSplit uncertainty has previously set self.rate_split_bg_frac,
the resulting MFD is a piecewise EvenlyDiscretizedMFD that scales
rates at or above Mmax-1 by that fraction (bg side of an alt2-style
partition between an area source and embedded faults).
Params are read from the recurrow dict, preferring bg-prefixed keys
e.g., bg_b_value, bg_ref_mag, bg_rate) so a single alt3-style
recurRow branch can carry different but correlated bg and fault
parameters; otherwise the unprefixed alt1/alt2 keys are used.

How it works is determined by if rate_split_bg_frac is present:

- Alt1/Alt3 (no rate_split_bg_frac): Build the TE or AC MFD from the row
params and use it as it is.

- Alt2 (rate_split_bg_frac present): Build the same MFD, then
piecewise-scale bins at or above Mmax-1 by rate_split_bg_frac (bg
side of the alt2 partition between the area source and its faults
and make an EvenlyDiscretizedMFD.

NOTE: This is currently only intended for support of the BC Hydro
NVA SSC logic tree. We may expand it to become a more general
capability.

:param recur_row:
Dict of values to use in given type of MFD
:param recurrow:
Dict of values to use in given type of MFD e.g.b_value, ref_mag,
rate). Alt3-style rows use prefixes of "bg" for the same keys.
"""
# Constants for BC Hydro NVA model
b_ac = 0.3
delta_mac = 1.0
gamma_eff = 0.9185 # Corrected gamma_eff from eq 1.2 of BCHydro AC memo
bin_width = 0.1

# Get params from recurRow
# Get params from recurRow, preferring bg-prefixed keys (alt3)
mmax = self.mmax
recur_model = self.recur_model
bval = float(recurrow["b_value"])
ref_mag = float(recurrow["ref_mag"])
rate = float(recurrow["rate"])
bval = float(recurrow.get("bg_b_value", recurrow.get("b_value")))
ref_mag = float(recurrow.get("bg_ref_mag", recurrow.get("ref_mag")))
rate = float(recurrow.get("bg_rate", recurrow.get("rate")))

# Build the MFD
if recur_model == "TE":
Expand All @@ -169,7 +180,7 @@ def modify_set_recurrow(self, recurrow):
total_rate=rate,
)

# Piecewise partition above Mmax-1 if a rateSplit is active
# Piecewise partition above Mmax-1 if a rate_split_bg_frac is active
bg_frac = getattr(self, 'rate_split_bg_frac', None)
if bg_frac is not None:
bins = self.mfd.get_annual_occurrence_rates()
Expand Down
62 changes: 45 additions & 17 deletions openquake/hazardlib/source/simple_fault.py
Original file line number Diff line number Diff line change
Expand Up @@ -523,34 +523,52 @@ def modify_set_dip(self, dip):
def modify_set_recurrow(self, recurrow):
"""
Rebuild the MFD from a recurrow using self.recur_model + self.mmax
set by an earlier recurSet application. Intended for the BC Hydro
NVA alt2 model where fault sources take a scenario-dependent share
of the total rate above Mmax-1 and receive no rate below.
set by an earlier recurSet application.

Requires rate_split_fault_frac to be set on the source. The per-source
rate_frac attribute (fault-length fraction of the total fault share) is
used if set, otherwise defaults to 1.0.
Params are read from the recurrow dict, preferring fault-prefixed
keys (e.g. fault_b_value, fault_ref_mag, fault_rate) so a single
alt3-style recurRow branch can carry different but correlated
background and fault parameters; otherwise the unprefixed alt2-style
keys are used.

How it works is determined by the values of rate_split_fault_frac
(set by an earlier rateSplit application, absent otherwise) and
rate_frac (from the source's rateFrac XML attribute, defaults to
1.0 if not set):

- No rateSplit and rate_frac == 1.0: build the parametric TE or
AC MFD from the row params and use it as it is.

- Alt3 (no rateSplit, rate_frac != 1.0): scale every bin of the
parametric MFD by rate_frac and make an EvenlyDiscretizedMFD.

- Alt2 (rateSplit present): zero bins below Mmax-1 (their rate
belongs to the background via the alt2 partition, not the
fault) and scale the remaining bins by
rate_split_fault_frac * rate_frac; make an EvenlyDiscretizedMFD.

NOTE: This is currently only intended for support of the BC Hydro
NVA SSC logic tree. We may expand it to become a more general
capability.

:param recur_row:
Dict of values to use in given type of MFD (b_value, ref_mag,
rate)
:param recurrow:
Dict of values to use in given type of MFD (e.g. b_value,
ref_mag, rate). Alt3-style rows use prefixes of "fault" for
the same keys.
"""
# Constants for BC Hydro NVA model
b_ac = 0.3
delta_mac = 1.0
gamma_eff = 0.9185 # Corrected gamma_eff from eq 1.2 of BCHydro AC memo
bin_width = 0.1

# Get params from recurRow
# Get params from recurRow, preferring fault-prefixed keys (alt3)
mmax = self.mmax
recur_model = self.recur_model
bval = float(recurrow["b_value"])
ref_mag = float(recurrow["ref_mag"])
rate = float(recurrow["rate"])
bval = float(recurrow.get("fault_b_value", recurrow.get("b_value")))
ref_mag = float(
recurrow.get("fault_ref_mag", recurrow.get("ref_mag")))
rate = float(recurrow.get("fault_rate", recurrow.get("rate")))

# Build the MFD
if recur_model == "TE":
Expand All @@ -567,14 +585,24 @@ def modify_set_recurrow(self, recurrow):
total_rate=rate,
)

# No rateSplit: fault keeps the parametric MFD
fault_frac = getattr(self, 'rate_split_fault_frac', None)
if fault_frac is None:
rate_frac = getattr(self, 'rate_frac', 1.0)

# Neither rateSplit nor rateFrac set: no BC Hydro partition to apply
if fault_frac is None and rate_frac == 1.0:
self.mfd = parent
return

# Zero rates below Mmax-1, scale rest by fault_frac x rate_frac
rate_frac = getattr(self, 'rate_frac', 1.0)
# Alt3-style: rate_frac scaling
if fault_frac is None:
bins = parent.get_annual_occurrence_rates()
occ = [r * rate_frac for _, r in bins]
self.mfd = EvenlyDiscretizedMFD(
min_mag=bins[0][0], bin_width=bin_width,
occurrence_rates=occ)
return

# Alt2-style: zero rates below Mmax-1, scale rest by fault_frac x rate_frac
scale = fault_frac * rate_frac
threshold = mmax - 1.0
bins = parent.get_annual_occurrence_rates()
Expand Down
8 changes: 7 additions & 1 deletion openquake/hazardlib/sourceconverter.py
Original file line number Diff line number Diff line change
Expand Up @@ -708,7 +708,7 @@ def convert_areaSource(self, node):
fracs = self.convert_hypo_dip_fracs(node)
if fracs is not None:
hdd.hypo_dip_fracs = fracs
return source.AreaSource(
area = source.AreaSource(
source_id=node['id'],
name=node['name'],
tectonic_region_type=node.attrib.get('tectonicRegion'),
Expand All @@ -723,6 +723,12 @@ def convert_areaSource(self, node):
polygon=polygon,
area_discretization=area_discretization,
temporal_occurrence_model=self.get_tom(node))
# Optional per-source offset applied to recurSet's max_mag
# (used by the BC Hydro NVA alt3 bg sources: bg_mmax = fault_mmax - 0.5)
mmax_offset = node.attrib.get('mmaxOffset')
if mmax_offset is not None:
area.mmax_offset = float(mmax_offset)
return area

def convert_pointSource(self, node):
"""
Expand Down
25 changes: 6 additions & 19 deletions openquake/qa_tests_data/logictree/case_25/alt12_AB.xml
Original file line number Diff line number Diff line change
Expand Up @@ -43,25 +43,12 @@
<nodalPlane dip="75.0" probability="0.3" rake="90.0" strike="320.0"/>
</nodalPlaneDist>
<hypoDepthDist>
<!-- Depth entries deeper than LSD are dropped/renormalised in modify_set_lower_seismogenic_depth -->
<hypoDepth depth="2.5" probability="0.01378954" fixedDipFrac="0.6667"/>
<hypoDepth depth="3.5" probability="0.04826637" fixedDipFrac="0.6667"/>
<hypoDepth depth="4.5" probability="0.05517597" fixedDipFrac="0.6667"/>
<hypoDepth depth="5.5" probability="0.05793388" fixedDipFrac="0.6667"/>
<hypoDepth depth="6.5" probability="0.05793388" fixedDipFrac="0.6667"/>
<hypoDepth depth="7.5" probability="0.05793388" fixedDipFrac="0.6667"/>
<hypoDepth depth="8.5" probability="0.05793388" fixedDipFrac="0.6667"/>
<hypoDepth depth="9.5" probability="0.05793388" fixedDipFrac="0.6667"/>
<hypoDepth depth="10.5" probability="0.05930987" fixedDipFrac="0.6667"/>
<hypoDepth depth="11.5" probability="0.05930987" fixedDipFrac="0.6667"/>
<hypoDepth depth="12.5" probability="0.05930987" fixedDipFrac="0.6667"/>
<hypoDepth depth="13.5" probability="0.05930987" fixedDipFrac="0.6667"/>
<hypoDepth depth="14.5" probability="0.05930987" fixedDipFrac="0.6667"/>
<hypoDepth depth="15.5" probability="0.05930987" fixedDipFrac="0.6667"/>
<hypoDepth depth="16.5" probability="0.05930987" fixedDipFrac="0.6667"/>
<hypoDepth depth="17.5" probability="0.05930987" fixedDipFrac="0.6667"/>
<hypoDepth depth="18.5" probability="0.05930987" fixedDipFrac="0.6667"/>
<hypoDepth depth="19.5" probability="0.05930987" fixedDipFrac="0.6667"/>
<!-- 5-entry hypo depth dist -->
<hypoDepth depth="2.5" probability="0.15" fixedDipFrac="0.6667"/>
<hypoDepth depth="6.5" probability="0.25" fixedDipFrac="0.6667"/>
<hypoDepth depth="10.5" probability="0.25" fixedDipFrac="0.6667"/>
<hypoDepth depth="14.5" probability="0.25" fixedDipFrac="0.6667"/>
<hypoDepth depth="18.5" probability="0.10" fixedDipFrac="0.6667"/>
</hypoDepthDist>
</areaSource>
</sourceGroup>
Expand Down
25 changes: 6 additions & 19 deletions openquake/qa_tests_data/logictree/case_25/alt12_UBN.xml
Original file line number Diff line number Diff line change
Expand Up @@ -42,25 +42,12 @@
<nodalPlane dip="75.0" probability="0.3" rake="90.0" strike="320.0"/>
</nodalPlaneDist>
<hypoDepthDist>
<!-- Depth entries deeper than LSD are dropped/renormalised in modify_set_lower_seismogenic_depth -->
<hypoDepth depth="2.5" probability="0.01378954" fixedDipFrac="0.6667"/>
<hypoDepth depth="3.5" probability="0.04826637" fixedDipFrac="0.6667"/>
<hypoDepth depth="4.5" probability="0.05517597" fixedDipFrac="0.6667"/>
<hypoDepth depth="5.5" probability="0.05793388" fixedDipFrac="0.6667"/>
<hypoDepth depth="6.5" probability="0.05793388" fixedDipFrac="0.6667"/>
<hypoDepth depth="7.5" probability="0.05793388" fixedDipFrac="0.6667"/>
<hypoDepth depth="8.5" probability="0.05793388" fixedDipFrac="0.6667"/>
<hypoDepth depth="9.5" probability="0.05793388" fixedDipFrac="0.6667"/>
<hypoDepth depth="10.5" probability="0.05930987" fixedDipFrac="0.6667"/>
<hypoDepth depth="11.5" probability="0.05930987" fixedDipFrac="0.6667"/>
<hypoDepth depth="12.5" probability="0.05930987" fixedDipFrac="0.6667"/>
<hypoDepth depth="13.5" probability="0.05930987" fixedDipFrac="0.6667"/>
<hypoDepth depth="14.5" probability="0.05930987" fixedDipFrac="0.6667"/>
<hypoDepth depth="15.5" probability="0.05930987" fixedDipFrac="0.6667"/>
<hypoDepth depth="16.5" probability="0.05930987" fixedDipFrac="0.6667"/>
<hypoDepth depth="17.5" probability="0.05930987" fixedDipFrac="0.6667"/>
<hypoDepth depth="18.5" probability="0.05930987" fixedDipFrac="0.6667"/>
<hypoDepth depth="19.5" probability="0.05930987" fixedDipFrac="0.6667"/>
<!-- 5-entry hypo depth dist -->
<hypoDepth depth="2.5" probability="0.15" fixedDipFrac="0.6667"/>
<hypoDepth depth="6.5" probability="0.25" fixedDipFrac="0.6667"/>
<hypoDepth depth="10.5" probability="0.25" fixedDipFrac="0.6667"/>
<hypoDepth depth="14.5" probability="0.25" fixedDipFrac="0.6667"/>
<hypoDepth depth="18.5" probability="0.10" fixedDipFrac="0.6667"/>
</hypoDepthDist>
</areaSource>
</sourceGroup>
Expand Down
Loading