Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide a clearer error message in case the rupture can not be converted from the USGS format #10412

Merged
merged 7 commits into from
Mar 5, 2025
10 changes: 7 additions & 3 deletions openquake/commonlib/readinput.py
Original file line number Diff line number Diff line change
Expand Up @@ -851,7 +851,9 @@ def get_rupture(oqparam):
elif rupture_model and rupture_model.endswith('.json'):
with open(rupture_model) as f:
rup_data = json.load(f)
rup = convert_to_oq_rupture(rup_data)
rup, err_msg = convert_to_oq_rupture(rup_data)
if err_msg:
logging.warning(err_msg)
if rup is None: # assume rupture_dict
rup = build_planar_rupture_from_dict(oqparam.rupture_dict)
return rup
Expand Down Expand Up @@ -1022,7 +1024,8 @@ def _cons_coeffs(df, perils, loss_dt, limit_states):
if len(the_df) == 1:
coeffs[peril][loss_type] = the_df[limit_states].to_numpy()[0]
elif len(the_df) > 1:
raise ValueError(f'Multiple consequences for {loss_type=}, {peril=}\n%s' % the_df)
raise ValueError(
f'Multiple consequences for {loss_type=}, {peril=}\n%s' % the_df)
return coeffs


Expand Down Expand Up @@ -1339,7 +1342,8 @@ def _taxonomy_mapping(filename, taxidx):
if 'conversion' in tmap_df.columns:
# conversion was the old name in the header for engine <= 3.12
tmap_df = tmap_df.rename(columns={'conversion': 'risk_id'})
assert set(tmap_df) == {'country', 'peril', 'taxonomy', 'risk_id', 'weight'}, set(tmap_df)
assert set(tmap_df) == {'country', 'peril', 'taxonomy',
'risk_id', 'weight'}, set(tmap_df)
taxos = set()
for (taxo, per), df in tmap_df.groupby(['taxonomy', 'peril']):
taxos.add(taxo)
Expand Down
28 changes: 19 additions & 9 deletions openquake/hazardlib/shakemap/parsers.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,8 @@ def convert_to_oq_rupture(rup_json):
"""
Convert USGS json (output of download_rupture_data) into an hazardlib rupture

:returns: None if not convertible
:returns: a openquake.hazardlib.source.rupture.BaseRupture object if convertible and
an error message if not convertible
"""
ftype = rup_json['features'][0]['geometry']['type']
multicoords = rup_json['features'][0]['geometry']['coordinates'][0]
Expand All @@ -235,7 +236,14 @@ def convert_to_oq_rupture(rup_json):
trt = 'Active Shallow Crust' if hyp_depth < 50 else 'Subduction IntraSlab'
mag = rup_json['metadata']['mag']
rup = get_multiplanar(multicoords, mag, rake, trt)
return rup
return rup, None
else:
if ftype != 'MultiPolygon':
reason = f'only MultiPolygon geometries are accepted (not {ftype})'
else:
reason = 'at least one surface is not rectangular'
err_msg = f'Unable to convert the rupture from the USGS format: {reason}'
return None, err_msg


def utc_to_local_time(utc_timestamp, lon, lat):
Expand Down Expand Up @@ -379,7 +387,7 @@ def usgs_stations_to_oq_format(stations, exclude_imts=(), seismic_only=False):
imts = []
for col in stations.columns:
if ('_VALUE' in col or '_LN_SIGMA' in col or
'_STDDEV' in col and col != 'DISTANCE_STDDEV'):
'_STDDEV' in col and col != 'DISTANCE_STDDEV'):
imt = col.split('_')[0]
if imt not in exclude_imts:
assert col not in imts
Expand Down Expand Up @@ -779,8 +787,8 @@ def _get_rup_from_json(usgs_id, rupture_file, station_data_file):
if usgs_id == 'FromFile':
rupdic = convert_rup_data(rup_data, usgs_id, rupture_file)
rupdic['station_data_file'] = station_data_file
rup = convert_to_oq_rupture(rup_data)
return rup, rupdic, rup_data
rup, err_msg = convert_to_oq_rupture(rup_data)
return rup, rupdic, rup_data, err_msg


def get_rup_dic(dic, user=User(),
Expand Down Expand Up @@ -824,8 +832,10 @@ def get_rup_dic(dic, user=User(),
rup, rupdic, err = _get_rup_dic_from_xml(
usgs_id, user, rupture_file, station_data_file)
elif rupture_file.endswith('.json'):
rup, rupdic, rup_data = _get_rup_from_json(usgs_id, rupture_file,
station_data_file)
rup, rupdic, rup_data, err_msg = _get_rup_from_json(
usgs_id, rupture_file, station_data_file)
if err_msg:
err = {"status": "failed", "error_msg": err_msg}
if err or usgs_id == 'FromFile':
return rup, rupdic, err
assert usgs_id
Expand Down Expand Up @@ -885,10 +895,10 @@ def get_rup_dic(dic, user=User(),
except ValueError as exc:
err = {"status": "failed", "error_msg": str(exc)}
return rup, rupdic, err
rup = convert_to_oq_rupture(rup_data)
rup, err_msg = convert_to_oq_rupture(rup_data)
if rup is None:
# in parsers_test for us6000jllz
rupdic['rupture_issue'] = 'Unable to convert the rupture from the USGS format'
rupdic['rupture_issue'] = err_msg
rupdic['require_dip_strike'] = True
# in parsers_test for usp0001ccb
return rup, rupdic, err
Expand Down
5 changes: 3 additions & 2 deletions openquake/hazardlib/tests/shakemap/parsers_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,9 @@ def test_5(self):
user=user, use_shakemap=True)
self.assertIsNone(rup)
self.assertEqual(dic['require_dip_strike'], True)
self.assertEqual(dic['rupture_issue'],
'Unable to convert the rupture from the USGS format')
rupture_issue = ('Unable to convert the rupture from the USGS format: at'
' least one surface is not rectangular')
self.assertEqual(dic['rupture_issue'], rupture_issue)

def test_6(self):
_rup, dic, _err = get_rup_dic(
Expand Down