Skip to content

Commit

Permalink
Merge pull request #10352 from gem/aspectratio
Browse files Browse the repository at this point in the history
Some improvements to the OQ-Impact level 2 interface
  • Loading branch information
ptormene authored Feb 18, 2025
2 parents 8004b78 + 2ee4e1a commit 7784660
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 41 deletions.
17 changes: 12 additions & 5 deletions openquake/hazardlib/shakemap/parsers.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@
from openquake.hazardlib import nrml, sourceconverter
from openquake.hazardlib.source.rupture import (
get_multiplanar, is_matrix, build_planar_rupture_from_dict)
from openquake.hazardlib.scalerel import get_available_magnitude_scalerel

NOT_FOUND = 'No file with extension \'.%s\' file found'
US_GOV = 'https://earthquake.usgs.gov'
Expand Down Expand Up @@ -788,6 +787,10 @@ def get_rup_dic(dic, user=User(), approach='use_shakemap_from_usgs',
rupdic.update(rupture_file=rupture_file,
station_data_file=station_data_file,
require_dip_strike=True)
try:
rup = build_planar_rupture_from_dict(rupdic)
except ValueError as exc:
err = {"status": "failed", "error_msg": str(exc)}
return rup, rupdic, err

if rupture_file and rupture_file.endswith('.xml'):
Expand Down Expand Up @@ -823,12 +826,13 @@ def get_rup_dic(dic, user=User(), approach='use_shakemap_from_usgs',

if approach == 'build_rup_from_usgs':
rupdic['nodal_planes'], err = _get_nodal_planes(properties)
rupdic['msrs'] = [msr.__class__.__name__
for msr in get_available_magnitude_scalerel()]
rupdic['aspect_ratio'] = dic['aspect_ratio']
rupdic['msr'] = dic['msr']
if err:
return None, rupdic, err

if not rup_data and approach != 'use_pnt_rup_from_usgs':
if not rup_data and approach not in ['use_pnt_rup_from_usgs',
'build_rup_from_usgs']:
with monitor('Downloading rupture json'):
rup_data, rupture_file = download_rupture_data(
usgs_id, contents, user)
Expand All @@ -846,7 +850,10 @@ def get_rup_dic(dic, user=User(), approach='use_shakemap_from_usgs',
rupdic['station_data_file_from_usgs'] = False
if not rup_data:
# in parsers_test
rup = build_planar_rupture_from_dict(rupdic)
try:
rup = build_planar_rupture_from_dict(rupdic)
except ValueError as exc:
err = {"status": "failed", "error_msg": str(exc)}
return rup, rupdic, err

rup = convert_to_oq_rupture(rup_data)
Expand Down
9 changes: 6 additions & 3 deletions openquake/hazardlib/shakemap/validate.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ def get_oqparams(self, usgs_id, mosaic_models, trts, use_shakemap):
'lat': 'Latitude (degrees)',
'dep': 'Depth (km)',
'mag': 'Magnitude (Mw)',
'aspect_ratio': 'Aspect ratio',
'rake': 'Rake (degrees)',
'local_timestamp': 'Local timestamp of the event',
'time_event': 'Time of the event',
Expand Down Expand Up @@ -141,6 +142,7 @@ def get_oqparams(self, usgs_id, mosaic_models, trts, use_shakemap):
'lat': '-90 ≤ float ≤ 90',
'dep': 'float ≥ 0',
'mag': 'float ≥ 0',
'aspect_ratio': 'float ≥ 0',
'rake': '-180 ≤ float ≤ 180',
'local_timestamp': '',
'time_event': 'day|night|transit',
Expand All @@ -166,6 +168,7 @@ def get_oqparams(self, usgs_id, mosaic_models, trts, use_shakemap):
'lat': valid.latitude,
'dep': valid.positivefloat,
'mag': valid.positivefloat,
'aspect_ratio': valid.positivefloat,
'rake': valid.rake_range,
'dip': valid.dip_range,
'strike': valid.strike_range,
Expand All @@ -188,7 +191,7 @@ def _validate(POST):
invalid_inputs = []
params = {}
dic = dict(usgs_id=None, lon=None, lat=None, dep=None,
mag=None, rake=None, dip=None, strike=None)
mag=None, msr=None, aspect_ratio=None, rake=None, dip=None, strike=None)
for field, validation_func in validators.items():
if field not in POST:
continue
Expand Down Expand Up @@ -267,6 +270,8 @@ def impact_validate(POST, user, rupture_file=None, station_data_file=None,
if 'use_shakemap' in POST:
use_shakemap = POST['use_shakemap'] == 'true'
approach = POST['approach']
if approach == 'build_rup_from_usgs':
dic['msr'] = POST['msr']

rup, rupdic, err = get_rup_dic(
dic, user, approach, use_shakemap, rupture_file, station_data_file,
Expand All @@ -288,8 +293,6 @@ def impact_validate(POST, user, rupture_file=None, station_data_file=None,
rupdic['trts'] = trts
rupdic['mosaic_models'] = mosaic_models
rupdic['rupture_from_usgs'] = rup is not None
if 'msr' in POST:
rupdic['msr'] = POST['msr']
if len(params) > 1: # called by impact_run
params['rupture_dict'] = rupdic
params['station_data_file'] = rupdic['station_data_file']
Expand Down
9 changes: 6 additions & 3 deletions openquake/hazardlib/tests/shakemap/parsers_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,14 +105,17 @@ def test_6(self):
'3 stations were found, but none of them are seismic')

def test_7(self):
dic_in = {'usgs_id': 'us6000jllz', 'lon': None, 'lat': None, 'dep': None,
'mag': None, 'msr': '', 'aspect_ratio': 2.0, 'rake': None,
'dip': None, 'strike': None}
_rup, dic, _err = get_rup_dic(
{'usgs_id': 'us6000jllz'}, user=user, approach='build_rup_from_usgs',
use_shakemap=True)
dic_in, user=user, approach='build_rup_from_usgs', use_shakemap=True)
self.assertEqual(
dic['nodal_planes'],
{'NP1': {'dip': 88.71, 'rake': -179.18, 'strike': 317.63},
'NP2': {'dip': 89.18, 'rake': -1.29, 'strike': 227.61}})
self.assertIn('WC1994', dic['msrs'])
self.assertEqual(dic['msr'], '')
self.assertEqual(dic['aspect_ratio'], 2.0)


"""
Expand Down
31 changes: 24 additions & 7 deletions openquake/hazardlib/tests/shakemap/validate_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import unittest
from openquake.hazardlib.shakemap.parsers import User
from openquake.hazardlib.shakemap.validate import impact_validate
from openquake.hazardlib.source.rupture import BaseRupture

user = User(level=2, testdir=os.path.join(os.path.dirname(__file__), 'data'))

Expand All @@ -46,17 +47,32 @@ def setUp(cls):
del timezonefinder

def test_1(self):
# no rupture, yes stations
POST = {'usgs_id': 'us6000jllz', 'approach': 'build_rup_from_usgs'}
POST = {'usgs_id': 'us6000jllz', 'approach': 'use_shakemap_from_usgs'}
_rup, rupdic, _params, err = impact_validate(POST, user)
self.assertEqual(rupdic['require_dip_strike'], True)
self.assertIsNone(rupdic['station_data_file'])
self.assertEqual(err, {})

def test_1b(self):
# no rupture, yes stations
POST = {'usgs_id': 'us6000jllz', 'approach': 'build_rup_from_usgs',
'msr': 'WC1994', 'aspect_ratio': '3'}
rup, rupdic, _params, err = impact_validate(POST, user)
self.assertIsInstance(rup, BaseRupture)
self.assertIn('stations', rupdic['station_data_file'])
self.assertEqual(err, {})

def test_1c(self):
# giving a ValueError with aspect_ratio 2
POST = {'usgs_id': 'us6000jllz', 'approach': 'build_rup_from_usgs',
'msr': 'WC1994', 'aspect_ratio': '2'}
_rup, _rupdic, _params, err = impact_validate(POST, user)
self.assertIn('The depth must be greater', err['error_msg'])

def test_2(self):
POST = {'usgs_id': 'us7000n05d', 'approach': 'build_rup_from_usgs'}
POST = {'usgs_id': 'us7000n05d', 'approach': 'build_rup_from_usgs',
'msr': ''}
_rup, rupdic, _params, err = impact_validate(POST, user)
self.assertEqual(rupdic['rupture_from_usgs'], False)
self.assertEqual(rupdic['rupture_from_usgs'], True)
self.assertEqual(rupdic['require_dip_strike'], True)
self.assertEqual(rupdic['mosaic_models'], ['SAM'])
self.assertIn('stations', rupdic['station_data_file'])
Expand Down Expand Up @@ -129,7 +145,8 @@ def test_3(self):

def test_4(self):
# for us7000n7n8 the stations.json does not contain stations
POST = {'usgs_id': 'us7000n7n8', 'approach': 'build_rup_from_usgs'}
POST = {'usgs_id': 'us7000n7n8', 'approach': 'build_rup_from_usgs',
'msr': ''}
_rup, rupdic, _oqparams, err = impact_validate(POST, user)
self.assertEqual(rupdic['require_dip_strike'], True)
self.assertEqual(rupdic['mag'], 7.0)
Expand All @@ -142,6 +159,6 @@ def test_4(self):

def test_5(self):
POST = {'usgs_id': 'us7000n7n8', 'approach': 'build_rup_from_usgs',
'msr': 'WC1994'}
'aspect_ratio': 2, 'msr': 'WC1994'}
_rup, rupdic, _oqparams, _err = impact_validate(POST, user)
self.assertIn('msr', rupdic)
41 changes: 20 additions & 21 deletions openquake/server/static/js/engine.js
Original file line number Diff line number Diff line change
Expand Up @@ -628,16 +628,18 @@ function capitalizeFirstLetter(val) {
} else {
$('#rupture_from_usgs_grp').addClass('hidden');
$('#usgs_id_grp').addClass('hidden');
$('#usgs_id').val('');
}
if (selected_approach == 'provide_rup') {
$('#upload_rupture_grp').removeClass('hidden');
$("#usgs_id").val('FromFile');
} else {
$('#upload_rupture_grp').addClass('hidden');
$('#usgs_id').val('');
}
if (['provide_rup_params', 'build_rup_from_usgs'].includes(selected_approach)) {
$('#rup_params').removeClass('hidden');
$('div#msr').removeClass('hidden');
$('div#aspect_ratio').removeClass('hidden');
$('#rake').prop('disabled', false);
$('#dip').prop('disabled', false);
$('#strike').prop('disabled', false);
Expand All @@ -648,13 +650,13 @@ function capitalizeFirstLetter(val) {
}
} else {
$('#rup_params').addClass('hidden');
$('div#msr').addClass('hidden');
$('div#aspect_ratio').addClass('hidden');
}
if (selected_approach == 'build_rup_from_usgs') {
$('div#nodal_plane').removeClass('hidden');
$('div#msr').removeClass('hidden');
} else {
$('div#nodal_plane').addClass('hidden');
$('div#msr').addClass('hidden');
}
if (selected_approach == 'use_shakemap_from_usgs') {
$('div.hidden-for-shakemap').addClass('hidden');
Expand Down Expand Up @@ -685,14 +687,20 @@ function capitalizeFirstLetter(val) {
formData.append('usgs_id', usgs_id);
}
formData.append('use_shakemap', use_shakemap());
if (selected_approach == 'provide_rup_params') {
formData.append('lon', $("#lon").val());
formData.append('lat', $("#lat").val());
formData.append('dep', $("#dep").val());
formData.append('mag', $("#mag").val());
formData.append('rake', $("#rake").val());
formData.append('dip', $("#dip").val());
formData.append('strike', $("#strike").val());
if (['provide_rup_params', 'build_rup_from_usgs'].includes(selected_approach)) {
// NOTE: for...of works like array.forEach(str => {
for (const param of ['lon', 'lat', 'dep', 'mag', 'rake', 'dip', 'strike', 'aspect_ratio']) {
var value = $('input#' + param).val();
if (selected_approach == 'provide_rup_params') {
formData.append(param, value);
}
else if (value != '') {
// 'build_rup_from_usgs' permits some params to be left blank by the user
// and to be populated from USGS data
formData.append(param, value);
}
}
formData.append('msr', $("select#msr").find(':selected').val());
}
$.ajax({
type: "POST",
Expand Down Expand Up @@ -770,16 +778,6 @@ function capitalizeFirstLetter(val) {
$('#dip').val(nodal_plane.dip);
$('#strike').val(nodal_plane.strike);
}
if ('msrs' in data) {
const msrs = data.msrs;
const $select = $('select#msr');
$select.empty();
msrs.forEach(msr => {
$select.append($("<option>").text(msr).val(msr));
});
$select.append($("<option>").text('').val(''));
$select.val('');
}
$('#mosaic_model').empty();
$.each(data.mosaic_models, function(index, mosaic_model) {
var selected = '';
Expand Down Expand Up @@ -889,6 +887,7 @@ function capitalizeFirstLetter(val) {
formData.append('lat', $("#lat").val());
formData.append('dep', $("#dep").val());
formData.append('mag', $("#mag").val());
formData.append('aspect_ratio', $("input#aspect_ratio").val());
formData.append('rake', $("#rake").val());
formData.append('dip', $("#dip").val());
formData.append('strike', $("#strike").val());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,16 @@
</div>
<div id="msr" class="impact_form_row hidden">
<label for="msr">{{ impact_form_labels.msr }}</label>
<select name="msr" id="msr" class="impact-select"></select>
<select name="msr" id="msr" class="impact-select">
<option value="" selected></option>
{% for msr in msrs %}
<option value="{{ msr }}">{{ msr }}</option>
{% endfor %}
</select>
</div>
<div id="aspect_ratio" class="impact_form_row hidden">
<label for="aspect_ratio">{{ impact_form_labels.aspect_ratio }}</label>
<input class="impact-input" type="text" id="aspect_ratio" name="aspect_ratio" placeholder="{{ impact_form_placeholders.aspect_ratio }}" value="2"/>
</div>
<div class="impact_form_row">
<label for"rake">{{ impact_form_labels.rake }}</label>
Expand Down
5 changes: 4 additions & 1 deletion openquake/server/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
from openquake.baselib import hdf5, config, parallel
from openquake.baselib.general import groupby, gettemp, zipfiles, mp
from openquake.hazardlib import nrml, gsim, valid
from openquake.hazardlib.scalerel import get_available_magnitude_scalerel
from openquake.hazardlib.shakemap.validate import (
impact_validate, ARISTOTLE_FORM_LABELS, ARISTOTLE_FORM_PLACEHOLDERS)
from openquake.commonlib import readinput, oqvalidation, logs, datastore, dbapi
Expand Down Expand Up @@ -769,7 +770,7 @@ def impact_run(request):
:param request:
a `django.http.HttpRequest` object containing
usgs_id, rupture_file,
lon, lat, dep, mag, rake, dip, strike,
lon, lat, dep, mag, aspect_ratio, rake, dip, strike,
local_timestamp, time_event,
maximum_distance, trt,
truncation_level, number_of_ground_motion_fields,
Expand Down Expand Up @@ -1273,6 +1274,8 @@ def web_engine(request, **kwargs):
params['impact_form_placeholders'] = ARISTOTLE_FORM_PLACEHOLDERS
params['impact_default_usgs_id'] = \
settings.ARISTOTLE_DEFAULT_USGS_ID
params['msrs'] = [msr.__class__.__name__
for msr in get_available_magnitude_scalerel()]
return render(
request, "engine/index.html", params)

Expand Down

0 comments on commit 7784660

Please sign in to comment.