From 4bc4d9ab117eb014bb29311c83ec9146e373ff14 Mon Sep 17 00:00:00 2001 From: Michele Simionato Date: Sat, 30 May 2026 05:17:04 +0200 Subject: [PATCH 1/4] Added strict checking --- openquake/calculators/preclassical.py | 14 ++++++++------ openquake/commonlib/oqvalidation.py | 6 ++++++ openquake/hazardlib/contexts.py | 2 ++ 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/openquake/calculators/preclassical.py b/openquake/calculators/preclassical.py index da27c129788..e7728dec39f 100644 --- a/openquake/calculators/preclassical.py +++ b/openquake/calculators/preclassical.py @@ -35,7 +35,7 @@ from openquake.commonlib import readinput from openquake.calculators import base -MAX_NUM_RUPTURES = 20_000 # only on fault sources +MAX_NUM_RUPTURES = 27_000 # only on fault sources U16 = numpy.uint16 U32 = numpy.uint32 F32 = numpy.float32 @@ -94,12 +94,13 @@ def collapse_nphc(src): src.magnitude_scaling_relationship = PointMSR() -def _filter_mag(srcs, min_mag): +def _filter_mag(srcs, min_mag, strict): # filter by magnitude and count the ruptures mmag = getdefault(min_mag, srcs[0].tectonic_region_type) out = [src for src in srcs if src.get_mags()[-1] >= mmag] for ss in out: - if ss.num_ruptures > MAX_NUM_RUPTURES and ss.code in b'FSCXKN': + if ss.num_ruptures > MAX_NUM_RUPTURES and strict and not hasattr( + ss, 'location'): # same condition as in `get_ctxs` raise RuntimeError('%s has too many ruptures' % ss) return out @@ -109,6 +110,7 @@ def filter_weight(srcs, sf, cmaker, secparams, monitor): Filter and weight the sources. Also split them, except for pointlike and multifault sources, which have been split already. """ + oq = cmaker.oq mon1 = monitor('building top of ruptures', measuremem=True) mon2 = monitor('setting msparams', measuremem=False) ry0 = 'ry0' in cmaker.REQUIRES_DISTANCES @@ -118,7 +120,7 @@ def filter_weight(srcs, sf, cmaker, secparams, monitor): splits = [] for src in srcs: if src.code == b'F': - if N and N <= cmaker.max_sites_disagg: + if N and N <= oq.max_sites_disagg: mask = sf.get_close(secparams) > 0 # shape S else: mask = None @@ -136,14 +138,14 @@ def filter_weight(srcs, sf, cmaker, secparams, monitor): src.nsites = 1 # NB: it is crucial to split only the close sources, for # performance reasons (think of Ecuador in SAM) - if cmaker.split_sources and src.nsites and src.code != b'F': + if oq.split_sources and src.nsites and src.code != b'F': # multifault source have been already split in save_and_split splits.extend(split_source(src)) else: splits.append(src) # filter by magnitude and count ruptures - splits = _filter_mag(splits, cmaker.oq.minimum_magnitude) + splits = _filter_mag(splits, oq.minimum_magnitude, oq.strict) if not splits: return {} diff --git a/openquake/commonlib/oqvalidation.py b/openquake/commonlib/oqvalidation.py index b1fdeea8b41..47b462ab4cf 100644 --- a/openquake/commonlib/oqvalidation.py +++ b/openquake/commonlib/oqvalidation.py @@ -855,6 +855,11 @@ Example: *steps_per_interval = 4*. Default: 1 +strict: + Enable strict checking on fault sources and ps_grid_spacing + Example: *strict = false* + Default: True + tectonic_region_type: Used to specify a tectonic region type. Example: *tectonic_region_type = Active Shallow Crust*. @@ -1230,6 +1235,7 @@ class OqParam(valid.ParamSet): split_sources = valid.Param(valid.boolean, True) split_time = valid.Param(valid.positiveint, None) split_by_gsim = valid.Param(valid.positiveint, 0) + strict = valid.Param(valid.boolean, True) tectonic_region_type = valid.Param(valid.utf8, '*') time_event = valid.Param( valid.Choice('avg', 'day', 'night', 'transit'), 'avg') diff --git a/openquake/hazardlib/contexts.py b/openquake/hazardlib/contexts.py index 411c257505d..05669288f38 100644 --- a/openquake/hazardlib/contexts.py +++ b/openquake/hazardlib/contexts.py @@ -1048,6 +1048,8 @@ def get_ctxs(self, src, sitecol, src_id=0, step=1): with self.ir_mon: allrups = list(src.iter_ruptures( shift_hypo=self.shift_hypo, step=step)) + if src.code == b'A': + breakpoint() for i, rup in enumerate(allrups): rup.rup_id = src.offset + i allrups = sorted([rup for rup in allrups From e385ace1872914a3aae5060238fe4ee335d373fd Mon Sep 17 00:00:00 2001 From: Michele Simionato Date: Sat, 30 May 2026 05:52:49 +0200 Subject: [PATCH 2/4] Fixed test --- debian/changelog | 1 + openquake/calculators/preclassical.py | 2 +- openquake/hazardlib/contexts.py | 2 -- openquake/hazardlib/source_reader.py | 14 ++++++++++++++ .../event_based_risk/case_4a/jobs.toml | 2 +- 5 files changed, 17 insertions(+), 4 deletions(-) diff --git a/debian/changelog b/debian/changelog index 802fa95616d..dcfe769bc26 100644 --- a/debian/changelog +++ b/debian/changelog @@ -2,6 +2,7 @@ * Added additional magnitude-scaling relationships to thingbaijam2017.py [Michele Simionato] + * Added checks on MAX_NUM_RUPTURES and ps_grid_spacing * Added command `oq info db` to extract the path to the sqlite file * Implemented a workflow to run the 2026 Global Risk Model diff --git a/openquake/calculators/preclassical.py b/openquake/calculators/preclassical.py index e7728dec39f..a5387193f45 100644 --- a/openquake/calculators/preclassical.py +++ b/openquake/calculators/preclassical.py @@ -35,7 +35,7 @@ from openquake.commonlib import readinput from openquake.calculators import base -MAX_NUM_RUPTURES = 27_000 # only on fault sources +MAX_NUM_RUPTURES = 27_000 # so that the drouet calculation run U16 = numpy.uint16 U32 = numpy.uint32 F32 = numpy.float32 diff --git a/openquake/hazardlib/contexts.py b/openquake/hazardlib/contexts.py index 05669288f38..411c257505d 100644 --- a/openquake/hazardlib/contexts.py +++ b/openquake/hazardlib/contexts.py @@ -1048,8 +1048,6 @@ def get_ctxs(self, src, sitecol, src_id=0, step=1): with self.ir_mon: allrups = list(src.iter_ruptures( shift_hypo=self.shift_hypo, step=step)) - if src.code == b'A': - breakpoint() for i, rup in enumerate(allrups): rup.rup_id = src.offset + i allrups = sorted([rup for rup in allrups diff --git a/openquake/hazardlib/source_reader.py b/openquake/hazardlib/source_reader.py index 4bef7db916f..8ed5611ce35 100644 --- a/openquake/hazardlib/source_reader.py +++ b/openquake/hazardlib/source_reader.py @@ -235,6 +235,20 @@ def get_csm(oq, full_lt, dstore=None): save_read_times(dstore, smdict.values()) check_duplicates(smdict, strict=oq.disagg_by_src) + # checking ps_grid_spacing + pointlike_sources = 0 + for sm in smdict.values(): + for sg in sm.src_groups: + for src in sg: + if src.code in b'PAM': + pointlike_sources += 1 + break + if (oq.strict and oq.mosaic_model and pointlike_sources and + 'classical' in oq.calculation_mode and oq.ps_grid_spacing == 0 + and not oq.sites): + raise InvalidFile(f'{oq.inputs["job_ini"]}: ' + 'missing ps_grid_spacing') + logging.info('Applying uncertainties') groups = _build_groups(full_lt, smdict) diff --git a/openquake/qa_tests_data/event_based_risk/case_4a/jobs.toml b/openquake/qa_tests_data/event_based_risk/case_4a/jobs.toml index 5de2a393b87..cab4041a419 100644 --- a/openquake/qa_tests_data/event_based_risk/case_4a/jobs.toml +++ b/openquake/qa_tests_data/event_based_risk/case_4a/jobs.toml @@ -1,6 +1,6 @@ [multi.workflow] description = "multi-workflow" -env.OQ_SAMPLE_ASSETS = 0.1 +env.OQ_SAMPLE_ASSETS = 1 may_fail = ["riskJob"] override = {out_file="SES.hdf5", hazard_calculation_id="SES.hdf5"} From 83292ab11a5506568aba32237dc97b04e274f890 Mon Sep 17 00:00:00 2001 From: Michele Simionato Date: Sat, 30 May 2026 06:08:59 +0200 Subject: [PATCH 3/4] Small refactoring --- openquake/hazardlib/source_reader.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/openquake/hazardlib/source_reader.py b/openquake/hazardlib/source_reader.py index 8ed5611ce35..73706fbf79c 100644 --- a/openquake/hazardlib/source_reader.py +++ b/openquake/hazardlib/source_reader.py @@ -193,7 +193,7 @@ def save_read_times(dstore, source_models): def get_csm(oq, full_lt, dstore=None): """ - Build source models from the logic tree and to store + Build source models from the logic tree and store them inside the `source_full_lt` dataset. """ converter = sourceconverter.SourceConverter( @@ -249,6 +249,14 @@ def get_csm(oq, full_lt, dstore=None): raise InvalidFile(f'{oq.inputs["job_ini"]}: ' 'missing ps_grid_spacing') + return build_csm(oq, full_lt, smdict, dstore) + + +def build_csm(oq, full_lt, smdict, dstore): + """ + Applies uncertainties, builds the source groups and returns + a CompositeSourceModel instance + """ logging.info('Applying uncertainties') groups = _build_groups(full_lt, smdict) From ff6d1c963e8e1ab7c625813743115ce5a1261c3c Mon Sep 17 00:00:00 2001 From: Michele Simionato Date: Sat, 30 May 2026 06:37:53 +0200 Subject: [PATCH 4/4] Changed comment [ci skip] --- openquake/calculators/preclassical.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openquake/calculators/preclassical.py b/openquake/calculators/preclassical.py index a5387193f45..86b7723c54b 100644 --- a/openquake/calculators/preclassical.py +++ b/openquake/calculators/preclassical.py @@ -35,7 +35,7 @@ from openquake.commonlib import readinput from openquake.calculators import base -MAX_NUM_RUPTURES = 27_000 # so that the drouet calculation run +MAX_NUM_RUPTURES = 20_000 # tentative U16 = numpy.uint16 U32 = numpy.uint32 F32 = numpy.float32