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 da27c129788..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 = 20_000 # only on fault sources +MAX_NUM_RUPTURES = 20_000 # tentative 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/source_reader.py b/openquake/hazardlib/source_reader.py index 4bef7db916f..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( @@ -235,6 +235,28 @@ 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') + + 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) 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"}