diff --git a/debian/changelog b/debian/changelog index 5021c74df6fe..8a541c1682be 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,5 @@ [Michele Simionato] + * Added support for consequence=losses for liquefaction and landslides * Added a check for missing secondary perils * Added loss types liquefaction and landslide * Removed support for XML consequences, after 3 years of deprecation diff --git a/openquake/calculators/event_based_damage.py b/openquake/calculators/event_based_damage.py index c847c82bb39f..e3d26d5f29ab 100644 --- a/openquake/calculators/event_based_damage.py +++ b/openquake/calculators/event_based_damage.py @@ -18,6 +18,7 @@ import os.path import logging +from dataclasses import dataclass import numpy import pandas @@ -36,6 +37,19 @@ U32 = numpy.uint32 F32 = numpy.float32 +@dataclass +class Dparam: + """ + Parameters for a damage calculation + """ + eids: U32 + aggids: U16 + rlzs: U32 + ci: dict + D: int + Dc: int + rng: scientific.MultiEventRNG + def zero_dmgcsq(A, R, crmodel): """ @@ -66,43 +80,39 @@ def damage_from_gmfs(gmfslices, oqparam, dstore, monitor): return event_based_damage(df, oqparam, dstore, monitor) -def _update(asset_df, gmf_df, aggids, allrlzs, sec_sims, - crmodel, ci, R, Dc, dmgcsq, dddict): +def _gen_d4(asset_df, gmf_df, crmodel, dparam): + # yields (aids, d4) triples oq = crmodel.oqparam - loss_types = oq.loss_types - eids = gmf_df.eid.to_numpy() - if R > 1: - rlzs = allrlzs[eids] - if sec_sims or not oq.float_dmg_dist: - rng = scientific.MultiEventRNG( - oq.master_seed, numpy.unique(eids)) + sec_sims = oq.secondary_simulations.items() for prob_field, num_sims in sec_sims: probs = gmf_df[prob_field].to_numpy() # LiqProb if not oq.float_dmg_dist: - dprobs = rng.boolean_dist(probs, num_sims).mean(axis=1) + dprobs = dparam.rng.boolean_dist(probs, num_sims).mean(axis=1) + E = len(dparam.eids) + L = len(oq.loss_types) for taxo, adf in asset_df.groupby('taxonomy'): out = crmodel.get_output(adf, gmf_df) aids = adf.index.to_numpy() + A = len(aids) assets = adf.to_records() if oq.float_dmg_dist: number = assets['value-number'] else: number = U32(assets['value-number']) - for lti, lt in enumerate(loss_types): + d4 = numpy.zeros((L, A, E, dparam.Dc), F32) + D = dparam.D + for lti, lt in enumerate(oq.loss_types): fractions = out[lt] - Asid, E, D = fractions.shape - assert len(eids) == E - d3 = numpy.zeros((Asid, E, Dc), F32) if oq.float_dmg_dist: - d3[:, :, :D] = fractions - for a in range(Asid): - d3[a] *= number[a] + d4[lti, :, :, :D] = fractions + for a in range(A): + d4[lti, a] *= number[a] else: # this is a performance distaster; for instance # the Messina test in oq-risk-tests becomes 12x # slower even if it has only 25_736 assets - d3[:, :, :D] = rng.discrete_dmg_dist( - eids, fractions, number) + d4[lti, :, :, :D] = dparam.rng.discrete_dmg_dist( + dparam.eids, fractions, number) # secondary perils and consequences for a, asset in enumerate(assets): @@ -110,27 +120,16 @@ def _update(asset_df, gmf_df, aggids, allrlzs, sec_sims, for d in range(1, D): # doing the mean on the secondary simulations if oq.float_dmg_dist: - d3[a, :, d] *= probs + d4[lti, a, :, d] *= probs else: - d3[a, :, d] *= dprobs + d4[lti, a, :, d] *= dprobs csq = crmodel.compute_csq( - asset, d3[a, :, :D] / number[a], lt, + asset, d4[lti, a, :, :D] / number[a], lt, oq.time_event) for name, values in csq.items(): - d3[a, :, ci[name]] = values - if R == 1: - dmgcsq[aids, 0, lti] += d3.sum(axis=1) - else: - for e, rlz in enumerate(rlzs): - dmgcsq[aids, rlz, lti] += d3[:, e] - tot = d3.sum(axis=0) # sum on the assets - for e, eid in enumerate(eids): - dddict[eid, oq.K][lti] += tot[e] - if oq.K: - for kids in aggids: - for a, aid in enumerate(aids): - dddict[eid, kids[aid]][lti] += d3[a, e] + d4[lti, a, :, dparam.ci[name]] = values + yield aids, d4 # d4 has shape (L, A, E, Dc) def event_based_damage(df, oq, dstore, monitor): @@ -144,27 +143,21 @@ def event_based_damage(df, oq, dstore, monitor): mon_risk = monitor('computing risk', measuremem=False) with monitor('reading gmf_data'): if oq.parentdir: - dstore = datastore.read( - oq.hdf5path, parentdir=oq.parentdir) + dstore = datastore.read(oq.hdf5path, parentdir=oq.parentdir) else: dstore.open('r') assetcol = dstore['assetcol'] - if oq.K: - # TODO: move this in the controller! - aggids, _ = assetcol.build_aggids( - oq.aggregate_by, oq.max_aggregations) - else: - aggids = numpy.zeros(len(assetcol), U16) crmodel = monitor.read('crmodel') - sec_sims = oq.secondary_simulations.items() + aggids = monitor.read('aggids') dmg_csq = crmodel.get_dmg_csq() ci = {dc: i + 1 for i, dc in enumerate(dmg_csq)} dmgcsq = zero_dmgcsq(len(assetcol), oq.R, crmodel) _A, R, L, Dc = dmgcsq.shape + D = Dc - len(crmodel.get_consequences()) if R > 1: allrlzs = dstore['events']['rlz_id'] else: - allrlzs = [0] + allrlzs = U32([0]) assert len(oq.loss_types) == L with mon_risk: dddict = general.AccumDict(accum=numpy.zeros((L, Dc), F32)) # eid, kid @@ -173,8 +166,33 @@ def event_based_damage(df, oq, dstore, monitor): gmf_df = df[df.sid == sid] if len(gmf_df) == 0: continue - _update(asset_df, gmf_df, aggids, allrlzs, sec_sims, - crmodel, ci, R, Dc, dmgcsq, dddict) + oq = crmodel.oqparam + eids = gmf_df.eid.to_numpy() + if R > 1: + rlzs = allrlzs[eids] + else: + rlzs = allrlzs + if oq.secondary_simulations or not oq.float_dmg_dist: + rng = scientific.MultiEventRNG( + oq.master_seed, numpy.unique(eids)) + else: + rng = None + dparam = Dparam(eids, aggids, rlzs, ci, D, Dc, rng) + for aids, d4 in _gen_d4(asset_df, gmf_df, crmodel, dparam): + for lti, d3 in enumerate(d4): + if R == 1: + dmgcsq[aids, 0, lti] += d3.sum(axis=1) + else: + for e, rlz in enumerate(dparam.rlzs): + dmgcsq[aids, rlz, lti] += d3[:, e] + tot = d3.sum(axis=0) # sum on the assets + for e, eid in enumerate(eids): + dddict[eid, oq.K][lti] += tot[e] + if oq.K: + for kids in dparam.aggids: + for a, aid in enumerate(aids): + dddict[eid, kids[aid]][lti] += d3[a, e] + return _dframe(dddict, ci, oq.loss_types), dmgcsq @@ -226,8 +244,14 @@ def execute(self): if oq.investigation_time: # event based self.builder = get_loss_builder(self.datastore, oq) # check self.dmgcsq = zero_dmgcsq(len(self.assetcol), self.R, self.crmodel) - smap = calc.starmap_from_gmfs(damage_from_gmfs, oq, self.datastore, - self._monitor) + if oq.K: + aggids, _ = self.assetcol.build_aggids( + oq.aggregate_by, oq.max_aggregations) + else: + aggids = 0 + smap = calc.starmap_from_gmfs(damage_from_gmfs, oq, + self.datastore, self._monitor) + smap.monitor.save('aggids', aggids) smap.monitor.save('assets', self.assetcol.to_dframe('id')) smap.monitor.save('crmodel', self.crmodel) return smap.reduce(self.combine) diff --git a/openquake/calculators/event_based_risk.py b/openquake/calculators/event_based_risk.py index b978e6dfb196..917dcaf54ef8 100644 --- a/openquake/calculators/event_based_risk.py +++ b/openquake/calculators/event_based_risk.py @@ -247,7 +247,7 @@ def gen_outputs(df, crmodel, rng, monitor): yield out -def check_tot_loss_unit_consistency(units, total_losses, loss_types): +def _tot_loss_unit_consistency(units, total_losses, loss_types): total_losses_units = set() for separate_lt in total_losses.split('+'): assert separate_lt in loss_types @@ -279,10 +279,12 @@ def set_oqparam(oq, assetcol, dstore): partial(insurance_losses, policy_df=policy_df)) ideduc = assetcol['ideductible'].any() - if oq.total_losses: - units = dstore['exposure'].cost_calculator.get_units(oq.loss_types) - check_tot_loss_unit_consistency( - units.split(), oq.total_losses, oq.loss_types) + cc = dstore['exposure'].cost_calculator + if oq.total_losses and cc.cost_types: + # cc.cost_types is empty in scenario_damage/case_21 (consequences) + units = cc.get_units(oq.total_loss_types) + _tot_loss_unit_consistency( + units.split(), oq.total_losses, oq.total_loss_types) sec_losses.append( partial(total_losses, kind=oq.total_losses, ideduc=ideduc)) elif ideduc: diff --git a/openquake/calculators/tests/scenario_damage_test.py b/openquake/calculators/tests/scenario_damage_test.py index dfb8379d476c..0be8252c566b 100644 --- a/openquake/calculators/tests/scenario_damage_test.py +++ b/openquake/calculators/tests/scenario_damage_test.py @@ -24,7 +24,7 @@ from openquake.qa_tests_data.scenario_damage import ( case_1, case_1c, case_2, case_3, case_4, case_4b, case_5, case_5a, case_6, case_7, case_8, case_9, case_10, case_11, case_12, case_13, - case_14, case_16, case_17, case_18, case_19, case_20, case_21) + case_14, case_16, case_17, case_18, case_19, case_20, case_21, case_22) from openquake.calculators.tests import CalculatorTestCase, strip_calc_id from openquake.calculators.extract import extract from openquake.calculators.export import export @@ -298,12 +298,18 @@ def test_case_20(self): self.assertEqualFiles('expected/aggrisk.csv', fname) def test_case_21(self): - # infrastructure risk for structural and liquefaction loss types + # infrastructure risk for structural, liquefaction and landslides out = self.run_calc(case_21.__file__, 'job.ini', exports='csv') [agg_csv, aggparent_csv] = out[('aggrisk', 'csv')] self.assertEqualFiles('expected/aggrisk.csv', agg_csv) self.assertEqualFiles('expected/aggrisk-parent.csv', aggparent_csv) + def test_case_22(self): + # losses with liquefaction and landslides + out = self.run_calc(case_22.__file__, 'job.ini', exports='csv') + [agg_csv] = out[('aggrisk', 'csv')] + self.assertEqualFiles('expected/aggrisk.csv', agg_csv) + def losses(aid, alt): E = len(alt.event_id.unique()) diff --git a/openquake/commonlib/oqvalidation.py b/openquake/commonlib/oqvalidation.py index 6611ef54200a..3afa63badcca 100644 --- a/openquake/commonlib/oqvalidation.py +++ b/openquake/commonlib/oqvalidation.py @@ -1745,6 +1745,18 @@ def ext_loss_types(self): etypes = self.loss_types + itypes return etypes + @property + def total_loss_types(self): + """ + :returns: the loss types in total_losses or the single loss type + """ + if self.total_losses: + return self.total_losses.split('+') + elif len(self.loss_types) == 1: + return self.loss_types + else: + self.raise_invalid('please specify total_losses') + def loss_dt(self, dtype=F64): """ :returns: a composite dtype based on the loss types including occupants diff --git a/openquake/hazardlib/valid.py b/openquake/hazardlib/valid.py index b0086fb120dc..585b630196d3 100644 --- a/openquake/hazardlib/valid.py +++ b/openquake/hazardlib/valid.py @@ -980,20 +980,11 @@ def dictionary(value): raise ValueError('%r is not a valid Python dictionary' % value) for key, val in dic.items(): - try: - has_logscale = (val[0] == 'logscale') - except IndexError: # no val[0] - continue - if has_logscale: - dic[key] = list(logscale(*val[1:])) - - try: - has_linscale = (val[0] == 'linscale') - except IndexError: # no val[0] - continue - if has_linscale: - dic[key] = list(linscale(*val[1:])) - + if isinstance(val, tuple): + if val[0] == 'logscale': + dic[key] = list(logscale(*val[1:])) + elif val[0] == 'linscale': + dic[key] = list(linscale(*val[1:])) return dic diff --git a/openquake/qa_tests_data/scenario_damage/case_21/job.ini b/openquake/qa_tests_data/scenario_damage/case_21/job.ini index bc8975a7d1c9..764c6b2ed2b1 100644 --- a/openquake/qa_tests_data/scenario_damage/case_21/job.ini +++ b/openquake/qa_tests_data/scenario_damage/case_21/job.ini @@ -30,6 +30,7 @@ liquefaction_fragility_file = fragility_model_liquefaction.xml landslide_fragility_file = fragility_model_landslide.xml [consequence] +total_losses = structural consequence_file = {'taxonomy': 'consequence_multiple_loss_types.csv'} [risk_calculation] diff --git a/openquake/qa_tests_data/scenario_damage/case_22/__init__.py b/openquake/qa_tests_data/scenario_damage/case_22/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/openquake/qa_tests_data/scenario_damage/case_22/consequences.csv b/openquake/qa_tests_data/scenario_damage/case_22/consequences.csv new file mode 100644 index 000000000000..c4a55750cfe9 --- /dev/null +++ b/openquake/qa_tests_data/scenario_damage/case_22/consequences.csv @@ -0,0 +1,7 @@ +taxonomy,consequence,loss_type,slight,moderate,extreme,complete +Concrete,losses,structural,0.04,0.31,0.6,1 +Wood,losses,structural,0.04,0.31,0.6,1 +Concrete,losses,liquefaction,0,0,0,1 +Wood,losses,liquefaction,0,0,0,1 +Concrete,losses,landslide,0,0,0,1 +Wood,losses,landslide,0,0,0,1 diff --git a/openquake/qa_tests_data/scenario_damage/case_22/expected/aggrisk.csv b/openquake/qa_tests_data/scenario_damage/case_22/expected/aggrisk.csv new file mode 100644 index 000000000000..87b4af7d46fd --- /dev/null +++ b/openquake/qa_tests_data/scenario_damage/case_22/expected/aggrisk.csv @@ -0,0 +1,5 @@ +#,,,,,,,"generated_by='OpenQuake engine 3.22.0-gitff750fe4b4', start_date='2024-10-21T11:16:00', checksum=2624933730, investigation_time=None, risk_investigation_time=None" +loss_type,no_damage,slight,moderate,extreme,complete,losses_value,losses_ratio +structural,1.06701E+01,1.41803E+00,1.39786E+00,9.49061E-01,5.64993E-01,1.84217E+04,1.08299E-01 +liquefaction,1.26268E+01,0.00000E+00,0.00000E+00,0.00000E+00,2.37321E+00,0.00000E+00,nan +landslide,9.00000E+00,0.00000E+00,0.00000E+00,0.00000E+00,6.00000E+00,0.00000E+00,nan diff --git a/openquake/qa_tests_data/scenario_damage/case_22/exposure_model.csv b/openquake/qa_tests_data/scenario_damage/case_22/exposure_model.csv new file mode 100644 index 000000000000..279ebef04460 --- /dev/null +++ b/openquake/qa_tests_data/scenario_damage/case_22/exposure_model.csv @@ -0,0 +1,16 @@ +id,lon,lat,number,structural,night,taxonomy,NAME_1 +a1,83.31382,29.46117,1,11340,5,Wood1,a +a2,83.31382,29.23617,1,11340,5,Wood1,a +a3,83.53882,29.08617,1,11340,5,Wood1,a +a4,80.68882,28.93617,1,11340,5,Wood1,a +a5,83.53882,29.01117,1,11340,5,Wood1,a +a6,81.13882,28.78617,1,11340,5,Wood1,a +a7,83.98882,28.48617,1,11340,5,Wood1,a +a8,83.23882,29.38617,1,11340,5,Concrete1,a +a9,83.01382,29.08617,1,11340,5,Concrete1,a +a10,83.31382,28.71117,1,11340,5,Concrete1,a +a11,86.91382,27.73617,1,11340,5,Concrete1,a +a12,83.16382,29.31117,1,11340,5,Concrete1,a +a13,80.61382,28.93617,1,11340,5,Concrete1,a +a14,83.91382,29.01117,1,11340,5,Concrete1,a +a15,82.03882,30.28617,1,11340,5,Concrete1,a diff --git a/openquake/qa_tests_data/scenario_damage/case_22/exposure_model.xml b/openquake/qa_tests_data/scenario_damage/case_22/exposure_model.xml new file mode 100644 index 000000000000..70ef9443dc3d --- /dev/null +++ b/openquake/qa_tests_data/scenario_damage/case_22/exposure_model.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + night + + + NAME_1 + + + exposure_model.csv + + + diff --git a/openquake/qa_tests_data/scenario_damage/case_22/fault_rupture.xml b/openquake/qa_tests_data/scenario_damage/case_22/fault_rupture.xml new file mode 100644 index 000000000000..b65de560282e --- /dev/null +++ b/openquake/qa_tests_data/scenario_damage/case_22/fault_rupture.xml @@ -0,0 +1,19 @@ + + + + 7.0 + 90 + + + + + 85.0 27.3 + 83.8 27.8 + + + 30.0 + 20.0 + 50.0 + + + diff --git a/openquake/qa_tests_data/scenario_damage/case_22/fragility_model_landslide.xml b/openquake/qa_tests_data/scenario_damage/case_22/fragility_model_landslide.xml new file mode 100644 index 000000000000..0d5702a8ed3d --- /dev/null +++ b/openquake/qa_tests_data/scenario_damage/case_22/fragility_model_landslide.xml @@ -0,0 +1,21 @@ + + + + Road Network + slight moderate extreme complete + + 0 0.3 0.6 1 + 0 0 0 1 + 0 0 0 1 + 0 0 0 1 + 0 0 0 1 + + + 0 0.3 0.6 1 + 0 1 1 1 + 0 1 1 1 + 0 1 1 1 + 0 1 1 1 + + + diff --git a/openquake/qa_tests_data/scenario_damage/case_22/fragility_model_liquefaction.xml b/openquake/qa_tests_data/scenario_damage/case_22/fragility_model_liquefaction.xml new file mode 100644 index 000000000000..4c14181d25fa --- /dev/null +++ b/openquake/qa_tests_data/scenario_damage/case_22/fragility_model_liquefaction.xml @@ -0,0 +1,21 @@ + + + + Road Network + slight moderate extreme complete + + 0 0.3 0.6 1 + 0 0 0 1 + 0 0 0 1 + 0 0 0 1 + 0 0 0 1 + + + 0 0.3 0.6 1 + 0 1 1 1 + 0 1 1 1 + 0 1 1 1 + 0 1 1 1 + + + diff --git a/openquake/qa_tests_data/scenario_damage/case_22/fragility_model_structural.xml b/openquake/qa_tests_data/scenario_damage/case_22/fragility_model_structural.xml new file mode 100644 index 000000000000..890d1a1ed3e5 --- /dev/null +++ b/openquake/qa_tests_data/scenario_damage/case_22/fragility_model_structural.xml @@ -0,0 +1,47 @@ + + + + + Fragility model for Nepal (discrete) + + + slight moderate extreme complete + + + + 0.0 0.2 0.4 0.6 0.8 1.0 1.2 1.4 + + + 0.0 0.788 0.97 0.994 0.998 1.0 1.0 1.0 + + + 0.0 0.6 0.909 0.976 0.992 0.997 0.999 1.0 + + + 0.0 0.341 0.75 0.904 0.96 0.982 0.992 0.996 + + + 0.0 0.109 0.441 0.686 0.825 0.9 0.942 0.965 + + + + + + 0.0 0.2 0.4 0.6 0.8 1.0 1.2 1.4 + + + 0.0 0.5 0.861 0.957 0.985 0.994 0.997 0.999 + + + 0.0 0.204 0.6 0.813 0.909 0.954 0.976 0.986 + + + 0.0 0.041 0.255 0.49 0.664 0.78 0.855 0.903 + + + 0.0 0.007 0.088 0.236 0.394 0.532 0.642 0.728 + + + + + diff --git a/openquake/qa_tests_data/scenario_damage/case_22/job.ini b/openquake/qa_tests_data/scenario_damage/case_22/job.ini new file mode 100644 index 000000000000..b1cee9bce20a --- /dev/null +++ b/openquake/qa_tests_data/scenario_damage/case_22/job.ini @@ -0,0 +1,36 @@ +[general] +description = Scenario Damage and Consequences Demo (Nepal) +calculation_mode = scenario_damage + +[exposure] +exposure_file = exposure_model.xml +taxonomy_mapping_csv = mapping_multiple_loss_types.csv + +[rupture] +rupture_model_file = fault_rupture.xml +rupture_mesh_spacing = 15 + +[Secondary perils] +secondary_perils = NewmarkDisplacement, AllstadtEtAl2022Liquefaction + +[site_params] +site_model_file = site_model.csv + +[calculation] +intensity_measure_types = PGA, PGV +truncation_level = 3.0 +maximum_distance = 200 +gsim = ChiouYoungs2008 +number_of_ground_motion_fields = 10 + +[fragility] +structural_fragility_file = fragility_model_structural.xml +liquefaction_fragility_file = fragility_model_liquefaction.xml +landslide_fragility_file = fragility_model_landslide.xml + +[consequence] +total_losses = structural +consequence_file = {'taxonomy': 'consequences.csv'} + +[export] +export_dir = /tmp/ diff --git a/openquake/qa_tests_data/scenario_damage/case_22/mapping_multiple_loss_types.csv b/openquake/qa_tests_data/scenario_damage/case_22/mapping_multiple_loss_types.csv new file mode 100644 index 000000000000..6871342b83a2 --- /dev/null +++ b/openquake/qa_tests_data/scenario_damage/case_22/mapping_multiple_loss_types.csv @@ -0,0 +1,7 @@ +taxonomy,conversion,weight,loss_type +Wood1,Wood,1,structural +Concrete1,Concrete,1,structural +Wood1,Wood,1,liquefaction +Concrete1,Concrete,1,liquefaction +Wood1,Wood,1,landslide +Concrete1,Concrete,1,landslide diff --git a/openquake/qa_tests_data/scenario_damage/case_22/site_model.csv b/openquake/qa_tests_data/scenario_damage/case_22/site_model.csv new file mode 100644 index 000000000000..105cfdaadfe1 --- /dev/null +++ b/openquake/qa_tests_data/scenario_damage/case_22/site_model.csv @@ -0,0 +1,16 @@ +site_id,lon,lat,vs30,z1pt0,z2pt5,gwd,precip,dc,dr,dw,slope,cohesion_mid,friction_mid,saturation,dry_density +0,83.31382,29.46117,183,513.4083567,3.093638299,0.946059358,1796,187,1.80517065,1.80517065,20,20000,35,2,1500 +1,83.31382,29.23617,221,502.7851667,2.493037557,2.853437095,1833,183,5.991748144,5.991748144,20,20000,35,2,1500 +2,83.53882,29.08617,211,506.1375293,2.628660223,0.076295109,1775,195,2.63670763,2.63670763,20,20000,35,2,1500 +3,80.68882,28.93617,183,513.4083567,3.093638299,0.946059358,1796,187,1.80517065,1.80517065,20,20000,35,2,1500 +4,83.53882,29.01117,221,502.7851667,2.493037557,2.853437095,1833,183,5.991748144,5.991748144,20,20000,35,2,1500 +5,81.13882,28.78617,211,506.1375293,2.628660223,0.076295109,1775,195,2.63670763,2.63670763,20,20000,35,2,1500 +6,83.98882,28.48617,183,513.4083567,3.093638299,0.946059358,1796,187,1.80517065,1.80517065,20,20000,35,2,1500 +7,83.23882,29.38617,221,502.7851667,2.493037557,2.853437095,1833,183,5.991748144,5.991748144,20,20000,35,2,1500 +8,83.01382,29.08617,211,506.1375293,2.628660223,0.076295109,1775,195,2.63670763,2.63670763,20,20000,35,2,1500 +9,83.31382,28.71117,183,513.4083567,3.093638299,0.946059358,1796,187,1.80517065,1.80517065,20,20000,35,2,1500 +10,86.91382,27.73617,221,502.7851667,2.493037557,2.853437095,1833,183,5.991748144,5.991748144,20,20000,35,2,1500 +11,83.16382,29.31117,211,506.1375293,2.628660223,0.076295109,1775,195,2.63670763,2.63670763,20,20000,35,2,1500 +12,80.61382,28.93617,183,513.4083567,3.093638299,0.946059358,1796,187,1.80517065,1.80517065,20,20000,35,2,1500 +13,83.91382,29.01117,221,502.7851667,2.493037557,2.853437095,1833,183,5.991748144,5.991748144,20,20000,35,2,1500 +14,82.03882,30.28617,211,506.1375293,2.628660223,0.076295109,1775,195,2.63670763,2.63670763,20,20000,35,2,1500 diff --git a/openquake/risklib/scientific.py b/openquake/risklib/scientific.py index a1ed615873de..6565859698b0 100644 --- a/openquake/risklib/scientific.py +++ b/openquake/risklib/scientific.py @@ -1722,7 +1722,11 @@ def consequence(consequence, coeffs, asset, dmgdist, loss_type, time_event): if consequence not in KNOWN_CONSEQUENCES: raise NotImplementedError(consequence) if consequence.startswith(('loss', 'losses')): - return dmgdist @ coeffs * asset['value-' + loss_type] + try: + value = asset['value-' + loss_type] + except ValueError: # landslide, liquefaction + return 0 + return dmgdist @ coeffs * value elif consequence in ['collapsed', 'non_operational']: return dmgdist @ coeffs * asset['value-number'] elif consequence in ['injured', 'fatalities']: @@ -1754,7 +1758,10 @@ def get_agg_value(consequence, agg_values, agg_id, xltype, time_event): xltype = xltype[:-4] if '+' in xltype: # total loss type return sum(aval[lt] for lt in xltype.split('+')) - return aval[xltype] + try: + return aval[xltype] + except ValueError: # liquefaction, landslide + return 0 else: raise NotImplementedError(consequence)