diff --git a/debian/changelog b/debian/changelog
index 27919d63e8c..c8769c10ccc 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -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
diff --git a/openquake/calculators/tests/logictree_test.py b/openquake/calculators/tests/logictree_test.py
index c635ab76a3f..2a89c234aef 100644
--- a/openquake/calculators/tests/logictree_test.py
+++ b/openquake/calculators/tests/logictree_test.py
@@ -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')
diff --git a/openquake/hazardlib/lt.py b/openquake/hazardlib/lt.py
index 0518befdb9c..2b313ae3779 100644
--- a/openquake/hazardlib/lt.py
+++ b/openquake/hazardlib/lt.py
@@ -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
diff --git a/openquake/hazardlib/source/area.py b/openquake/hazardlib/source/area.py
index 5b95fc47ccb..dd97cc0e6b5 100644
--- a/openquake/hazardlib/source/area.py
+++ b/openquake/hazardlib/source/area.py
@@ -129,17 +129,28 @@ 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
@@ -147,12 +158,12 @@ def modify_set_recurrow(self, recurrow):
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":
@@ -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()
diff --git a/openquake/hazardlib/source/simple_fault.py b/openquake/hazardlib/source/simple_fault.py
index 21fe1a8e352..f6cd5939579 100644
--- a/openquake/hazardlib/source/simple_fault.py
+++ b/openquake/hazardlib/source/simple_fault.py
@@ -523,21 +523,38 @@ 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
@@ -545,12 +562,13 @@ def modify_set_recurrow(self, recurrow):
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":
@@ -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()
diff --git a/openquake/hazardlib/sourceconverter.py b/openquake/hazardlib/sourceconverter.py
index e737b69d5b3..febe25faf42 100644
--- a/openquake/hazardlib/sourceconverter.py
+++ b/openquake/hazardlib/sourceconverter.py
@@ -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'),
@@ -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):
"""
diff --git a/openquake/qa_tests_data/logictree/case_25/alt12_AB.xml b/openquake/qa_tests_data/logictree/case_25/alt12_AB.xml
index 8366e14cf55..0e5de46c2d8 100644
--- a/openquake/qa_tests_data/logictree/case_25/alt12_AB.xml
+++ b/openquake/qa_tests_data/logictree/case_25/alt12_AB.xml
@@ -43,25 +43,12 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
diff --git a/openquake/qa_tests_data/logictree/case_25/alt12_UBN.xml b/openquake/qa_tests_data/logictree/case_25/alt12_UBN.xml
index 655fffd7268..40c2b1c77b4 100644
--- a/openquake/qa_tests_data/logictree/case_25/alt12_UBN.xml
+++ b/openquake/qa_tests_data/logictree/case_25/alt12_UBN.xml
@@ -42,25 +42,12 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
diff --git a/openquake/qa_tests_data/logictree/case_25/alt2_NVA-AB.xml b/openquake/qa_tests_data/logictree/case_25/alt2_NVA-AB.xml
index c8aae8299e2..c767f383b54 100644
--- a/openquake/qa_tests_data/logictree/case_25/alt2_NVA-AB.xml
+++ b/openquake/qa_tests_data/logictree/case_25/alt2_NVA-AB.xml
@@ -32,25 +32,13 @@
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
@@ -81,20 +69,12 @@
1.0
90.0
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
@@ -123,20 +103,12 @@
1.0
90.0
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
@@ -164,20 +136,12 @@
1.0
90.0
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
@@ -205,20 +169,12 @@
1.0
90.0
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
diff --git a/openquake/qa_tests_data/logictree/case_25/alt2_NVA-UBN.xml b/openquake/qa_tests_data/logictree/case_25/alt2_NVA-UBN.xml
index 60fbb4696e5..dd52e9531f6 100644
--- a/openquake/qa_tests_data/logictree/case_25/alt2_NVA-UBN.xml
+++ b/openquake/qa_tests_data/logictree/case_25/alt2_NVA-UBN.xml
@@ -33,25 +33,13 @@
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
@@ -82,20 +70,12 @@
1.0
90.0
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
@@ -124,20 +104,12 @@
1.0
90.0
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
@@ -165,20 +137,12 @@
1.0
90.0
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
@@ -206,20 +170,12 @@
1.0
90.0
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
diff --git a/openquake/qa_tests_data/logictree/case_25/alt3_NVA-AB.xml b/openquake/qa_tests_data/logictree/case_25/alt3_NVA-AB.xml
new file mode 100644
index 00000000000..c55905d0707
--- /dev/null
+++ b/openquake/qa_tests_data/logictree/case_25/alt3_NVA-AB.xml
@@ -0,0 +1,184 @@
+
+
+
+
+
+
+
+
+
+
+
+ -121.7803 49.2349 -121.9131 49.3456 -123.0849 50.2956 -125.9767 51.7779 -125.6634 51.906 -124.7858 51.9227 -123.7428 51.4624 -122.6619 51.1255 -121.9429 50.772 -121.4579 49.8895 -121.2884 49.5455 -121.2242 49.4137 -121.7803 49.2349
+
+
+
+ 0.0
+ 20
+
+ BCHydroNVAMSR
+
+ linear_piecewise
+
+
+
+
+
+
+ 3.25
+ 1.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -121.7334 49.2502 -121.8623 49.5943 -122.3035 49.8454 -122.5585 50.0895
+ -122.6188 50.2273 -123.0106 50.5333 -123.287 50.6697 -123.6021 50.7102
+ -123.8088 50.8176 -124.2442 50.9267 -124.457 51.0984 -124.7655 51.2026
+ -125.7099 51.665 -125.8893 51.8138
+
+
+ 45.0
+ 0.0
+ 15.0
+
+ BCHydroNVAMSR
+
+ linear_piecewise
+
+
+
+
+
+
+ 6.0
+ 1.0
+
+ 90.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -121.6843 50.2959 -121.888 50.4635 -123.0619 50.9694 -123.218 51.0624
+ -124.0714 51.2956 -124.3707 51.4605 -124.797 51.7831 -125.0291 51.9188
+
+
+ 45.0
+ 0.0
+ 15.0
+
+ BCHydroNVAMSR
+
+ linear_piecewise
+
+
+
+
+
+
+ 6.0
+ 1.0
+
+ 90.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -121.7976 50.5025 -122.0891 50.6951 -122.5077 50.8825 -122.6765 50.9768 -122.9555 51.2188
+
+
+ 45.0
+ 0.0
+ 15.0
+
+ BCHydroNVAMSR
+
+ linear_piecewise
+
+
+
+
+
+
+ 6.0
+ 1.0
+
+ 90.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -121.2264 49.418 -121.4578 49.8895 -121.943 50.772 -122.6618 51.1255 -123.7429 51.4624 -124.7859 51.9227 -124.7911 51.9226
+
+
+ 45.0
+ 0.0
+ 15.0
+
+ BCHydroNVAMSR
+
+ linear_piecewise
+
+
+
+
+
+
+ 6.0
+ 1.0
+
+ 90.0
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/openquake/qa_tests_data/logictree/case_25/alt3_NVA-UBN.xml b/openquake/qa_tests_data/logictree/case_25/alt3_NVA-UBN.xml
new file mode 100644
index 00000000000..946a61ea4ee
--- /dev/null
+++ b/openquake/qa_tests_data/logictree/case_25/alt3_NVA-UBN.xml
@@ -0,0 +1,185 @@
+
+
+
+
+
+
+
+
+
+
+
+ -121.2884 49.5455 -121.9131 49.3456 -122.1555 49.2666 -122.2759 49.4109 -123.0124 49.8213 -124.6899 50.7152 -125.1361 50.9117 -125.8091 51.111 -126.562 51.3272 -126.4772 51.5697 -126.2179 51.678 -125.9767 51.7779 -125.6634 51.906 -124.7858 51.9227 -123.7428 51.4624 -122.6619 51.1255 -121.9429 50.772 -121.4579 49.8895 -121.2884 49.5455
+
+
+
+ 0.0
+ 20
+
+ BCHydroNVAMSR
+
+ linear_piecewise
+
+
+
+
+
+
+
+ 3.25
+ 1.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -121.7334 49.2502 -121.8623 49.5943 -122.3035 49.8454 -122.5585 50.0895
+ -122.6188 50.2273 -123.0106 50.5333 -123.287 50.6697 -123.6021 50.7102
+ -123.8088 50.8176 -124.2442 50.9267 -124.457 51.0984 -124.7655 51.2026
+ -125.7099 51.665 -125.8893 51.8138
+
+
+ 45.0
+ 0.0
+ 15.0
+
+ BCHydroNVAMSR
+
+ linear_piecewise
+
+
+
+
+
+
+ 6.0
+ 1.0
+
+ 90.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -121.6843 50.2959 -121.888 50.4635 -123.0619 50.9694 -123.218 51.0624
+ -124.0714 51.2956 -124.3707 51.4605 -124.797 51.7831 -125.0291 51.9188
+
+
+ 45.0
+ 0.0
+ 15.0
+
+ BCHydroNVAMSR
+
+ linear_piecewise
+
+
+
+
+
+
+ 6.0
+ 1.0
+
+ 90.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -121.7976 50.5025 -122.0891 50.6951 -122.5077 50.8825 -122.6765 50.9768 -122.9555 51.2188
+
+
+ 45.0
+ 0.0
+ 15.0
+
+ BCHydroNVAMSR
+
+ linear_piecewise
+
+
+
+
+
+
+ 6.0
+ 1.0
+
+ 90.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -121.2264 49.418 -121.4578 49.8895 -121.943 50.772 -122.6618 51.1255 -123.7429 51.4624 -124.7859 51.9227 -124.7911 51.9226
+
+
+ 45.0
+ 0.0
+ 15.0
+
+ BCHydroNVAMSR
+
+ linear_piecewise
+
+
+
+
+
+
+ 6.0
+ 1.0
+
+ 90.0
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/openquake/qa_tests_data/logictree/case_25/expected/hazard_curve-mean-PGA_alt1.csv b/openquake/qa_tests_data/logictree/case_25/expected/hazard_curve-mean-PGA_alt1.csv
index a2a5b1f6ec0..5315e90c966 100644
--- a/openquake/qa_tests_data/logictree/case_25/expected/hazard_curve-mean-PGA_alt1.csv
+++ b/openquake/qa_tests_data/logictree/case_25/expected/hazard_curve-mean-PGA_alt1.csv
@@ -1,3 +1,3 @@
-#,,,,,,,,"generated_by='OpenQuake engine 3.27.0-giteba4ab5ce3', start_date='2026-07-19T07:37:00', checksum=1753173620, kind='mean', investigation_time=50.0, imt='PGA'"
+#,,,,,,,,"generated_by='OpenQuake engine 3.27.0-gitc7e2866a0b', start_date='2026-07-20T11:15:38', checksum=2161630964, kind='mean', investigation_time=50.0, imt='PGA'"
lon,lat,depth,poe-0.0100000,poe-0.0500000,poe-0.1000000,poe-0.2000000,poe-0.5000000,poe-1.0000000
--121.80000,49.10640,0.00000,1.119916E-01,1.213262E-02,2.737377E-03,3.321296E-04,3.116762E-06,0.000000E+00
+-121.80000,49.10640,0.00000,1.081894E-01,1.166617E-02,2.622868E-03,3.166347E-04,2.968191E-06,0.000000E+00
diff --git a/openquake/qa_tests_data/logictree/case_25/expected/hazard_curve-mean-PGA_alt2.csv b/openquake/qa_tests_data/logictree/case_25/expected/hazard_curve-mean-PGA_alt2.csv
index 72b5757f99f..db7da748ae9 100644
--- a/openquake/qa_tests_data/logictree/case_25/expected/hazard_curve-mean-PGA_alt2.csv
+++ b/openquake/qa_tests_data/logictree/case_25/expected/hazard_curve-mean-PGA_alt2.csv
@@ -1,3 +1,3 @@
-#,,,,,,,,"generated_by='OpenQuake engine 3.27.0-giteba4ab5ce3', start_date='2026-07-19T07:37:06', checksum=1954854747, kind='mean', investigation_time=50.0, imt='PGA'"
+#,,,,,,,,"generated_by='OpenQuake engine 3.27.0-gitc7e2866a0b', start_date='2026-07-20T11:16:02', checksum=1614135368, kind='mean', investigation_time=50.0, imt='PGA'"
lon,lat,depth,poe-0.0100000,poe-0.0500000,poe-0.1000000,poe-0.2000000,poe-0.5000000,poe-1.0000000
--121.80000,49.10640,0.00000,1.242654E-01,1.298556E-02,3.304175E-03,6.399101E-04,2.288344E-05,2.801620E-09
+-121.80000,49.10640,0.00000,1.256763E-01,1.314337E-02,3.338275E-03,6.434025E-04,2.291842E-05,2.779808E-09
diff --git a/openquake/qa_tests_data/logictree/case_25/expected/hazard_curve-mean-PGA_alt3.csv b/openquake/qa_tests_data/logictree/case_25/expected/hazard_curve-mean-PGA_alt3.csv
new file mode 100644
index 00000000000..42f4de60d45
--- /dev/null
+++ b/openquake/qa_tests_data/logictree/case_25/expected/hazard_curve-mean-PGA_alt3.csv
@@ -0,0 +1,3 @@
+#,,,,,,,,"generated_by='OpenQuake engine 3.27.0-gitc7e2866a0b', start_date='2026-07-20T11:16:28', checksum=2600948032, kind='mean', investigation_time=50.0, imt='PGA'"
+lon,lat,depth,poe-0.0100000,poe-0.0500000,poe-0.1000000,poe-0.2000000,poe-0.5000000,poe-1.0000000
+-121.80000,49.10640,0.00000,6.269630E-01,1.532334E-01,5.476460E-02,1.365837E-02,5.509108E-04,0.000000E+00
diff --git a/openquake/qa_tests_data/logictree/case_25/job_alt3.ini b/openquake/qa_tests_data/logictree/case_25/job_alt3.ini
new file mode 100644
index 00000000000..792784c6854
--- /dev/null
+++ b/openquake/qa_tests_data/logictree/case_25/job_alt3.ini
@@ -0,0 +1,38 @@
+[general]
+
+description = BCHydro-style correlated uncertainties (alt3)
+calculation_mode = classical
+random_seed = 23
+
+[geometry]
+
+sites = -121.8 49.1064
+
+[logic_tree]
+
+number_of_logic_tree_samples = 0
+
+[erf]
+area_source_discretization = 40.0
+rupture_mesh_spacing = 15.0
+width_of_mfd_bin = 0.1
+
+[site_params]
+
+reference_vs30_type = measured
+reference_vs30_value = 760.0
+reference_depth_to_2pt5km_per_sec = 2.5
+reference_depth_to_1pt0km_per_sec = 50.0
+
+[calculation]
+
+source_model_logic_tree_file = smlt_alt3.xml
+gsim_logic_tree_file = gsim_logic_tree.xml
+investigation_time = 50.0
+intensity_measure_types_and_levels = {"PGA": [0.01, 0.05, 0.1, 0.2, 0.5, 1.0]}
+truncation_level = 3.0
+maximum_distance = 200.0
+
+[output]
+
+mean = true
diff --git a/openquake/qa_tests_data/logictree/case_25/smlt_alt3.xml b/openquake/qa_tests_data/logictree/case_25/smlt_alt3.xml
new file mode 100644
index 00000000000..83b05fa3e7a
--- /dev/null
+++ b/openquake/qa_tests_data/logictree/case_25/smlt_alt3.xml
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+ alt3_NVA-UBN.xml
+ 0.5
+
+
+ alt3_NVA-AB.xml
+ 0.5
+
+
+
+
+
+
+
+ 1.0
+
+
+
+
+
+
+ 1.0
+
+
+
+
+
+
+
+ 0.5
+
+
+
+ 0.5
+
+
+
+
+
+
+ 0.5
+
+
+
+ 0.5
+
+
+
+
+
+
+ 45.0
+ 0.5
+
+
+ 60.0
+ 0.5
+
+
+
+
+
+
+ 15.0
+ 1.0
+
+
+
+
+