Source code for openquake.hmtk.parsers.faults.fault_yaml_parser

# -*- coding: utf-8 -*-
# vim: tabstop=4 shiftwidth=4 softtabstop=4

#
# LICENSE
#
# Copyright (C) 2010-2020 GEM Foundation, G. Weatherill, M. Pagani,
# D. Monelli.
#
# The Hazard Modeller's Toolkit is free software: you can redistribute
# it and/or modify it under the terms of the GNU Affero General Public
# License as published by the Free Software Foundation, either version
# 3 of the License, or (at your option) any later version.
#
# You should have received a copy of the GNU Affero General Public License
# along with OpenQuake. If not, see <http://www.gnu.org/licenses/>
#
# DISCLAIMER
#
# The software Hazard Modeller's Toolkit (openquake.hmtk) provided herein
# is released as a prototype implementation on behalf of
# scientists and engineers working within the GEM Foundation (Global
# Earthquake Model).
#
# It is distributed for the purpose of open collaboration and in the
# hope that it will be useful to the scientific, engineering, disaster
# risk and software design communities.
#
# The software is NOT distributed as part of GEM's OpenQuake suite
# (https://www.globalquakemodel.org/tools-products) and must be considered as a
# separate entity. The software provided herein is designed and implemented
# by scientific staff. It is not developed to the design standards, nor
# subject to same level of critical review by professional software
# developers, as GEM's OpenQuake software suite.
#
# Feedback and contribution to the software is welcome, and can be
# directed to the hazard scientific staff of the GEM Model Facility
# (hazard@globalquakemodel.org).
#
# The Hazard Modeller's Toolkit (openquake.hmtk) is therefore distributed WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
#
# The GEM Foundation, and the authors of the software, assume no
# liability for use of the software.

'''
Module: openquake.hmtk.parsers.fault.fault_yaml_parser implements parser of a fault
model from the Yaml format

'''

import yaml
import numpy as np
from math import fabs
from openquake.hazardlib.geo.point import Point
from openquake.hazardlib.geo.line import Line
from openquake.hazardlib.scalerel import get_available_scalerel
from openquake.hmtk.faults.fault_geometries import (
    SimpleFaultGeometry, ComplexFaultGeometry)
from openquake.hmtk.faults.fault_models import mtkActiveFault
from openquake.hmtk.faults.active_fault_model import mtkActiveFaultModel
from openquake.hmtk.faults.tectonic_regionalisation import (
    TectonicRegionalisation)


SCALE_REL_MAP = get_available_scalerel()


[docs]def weight_list_to_tuple(data, attr_name): ''' Converts a list of values and corresponding weights to a tuple of values ''' if len(data['Value']) != len(data['Weight']): raise ValueError('Number of weights do not correspond to number of ' 'attributes in %s' % attr_name) weight = np.array(data['Weight']) if fabs(np.sum(weight) - 1.) > 1E-7: raise ValueError('Weights do not sum to 1.0 in %s' % attr_name) data_tuple = [] for iloc, value in enumerate(data['Value']): data_tuple.append((value, weight[iloc])) return data_tuple
[docs]def parse_tect_region_dict_to_tuples(region_dict): ''' Parses the tectonic regionalisation dictionary attributes to tuples ''' output_region_dict = [] tuple_keys = ['Displacement_Length_Ratio', 'Shear_Modulus'] # Convert MSR string name to openquake.hazardlib.scalerel object for region in region_dict: for val_name in tuple_keys: region[val_name] = weight_list_to_tuple(region[val_name], val_name) # MSR works differently - so call get_scaling_relation_tuple region['Magnitude_Scaling_Relation'] = weight_list_to_tuple( region['Magnitude_Scaling_Relation'], 'Magnitude Scaling Relation') output_region_dict.append(region) return output_region_dict
[docs]def get_scaling_relation_tuple(msr_dict): ''' For a dictionary of scaling relation values convert string list to object list and then to tuple ''' # Convert MSR string name to openquake.hazardlib.scalerel object for iloc, value in enumerate(msr_dict['Value']): if not value in SCALE_REL_MAP.keys(): raise ValueError('Scaling relation %s not supported!' % value) msr_dict['Value'][iloc] = SCALE_REL_MAP[value]() return weight_list_to_tuple(msr_dict, 'Magnitude Scaling Relation')
[docs]class FaultYmltoSource(object): ''' Class to parse a fault model definition from Yaml format to a fault model class ''' def __init__(self, filename): ''' :param str filename: Name of input file (in yml format) ''' self.data = yaml.safe_load(open(filename, 'rt')) if 'Fault_Model' not in self.data: raise ValueError('Fault Model not defined in input file!')
[docs] def read_file(self, mesh_spacing=1.0): ''' Reads the file and returns an instance of the FaultSource class. :param float mesh_spacing: Fault mesh spacing (km) ''' # Process the tectonic regionalisation tectonic_reg = self.process_tectonic_regionalisation() model = mtkActiveFaultModel(self.data['Fault_Model_ID'], self.data['Fault_Model_Name']) for fault in self.data['Fault_Model']: fault_geometry = self.read_fault_geometry(fault['Fault_Geometry'], mesh_spacing) if fault['Shear_Modulus']: fault['Shear_Modulus'] = weight_list_to_tuple( fault['Shear_Modulus'], '%s Shear Modulus' % fault['ID']) if fault['Displacement_Length_Ratio']: fault['Displacement_Length_Ratio'] = weight_list_to_tuple( fault['Displacement_Length_Ratio'], '%s Displacement to Length Ratio' % fault['ID']) fault_source = mtkActiveFault( fault['ID'], fault['Fault_Name'], fault_geometry, weight_list_to_tuple(fault['Slip'], '%s - Slip' % fault['ID']), float(fault['Rake']), fault['Tectonic_Region'], float(fault['Aseismic']), weight_list_to_tuple( fault['Scaling_Relation_Sigma'], '%s Scaling_Relation_Sigma' % fault['ID']), neotectonic_fault=None, scale_rel=get_scaling_relation_tuple( fault['Magnitude_Scaling_Relation']), aspect_ratio=fault['Aspect_Ratio'], shear_modulus=fault['Shear_Modulus'], disp_length_ratio=fault['Displacement_Length_Ratio']) if tectonic_reg: fault_source.get_tectonic_regionalisation( tectonic_reg, fault['Tectonic_Region']) assert isinstance(fault['MFD_Model'], list) fault_source.generate_config_set(fault['MFD_Model']) model.faults.append(fault_source) return model, tectonic_reg
[docs] def process_tectonic_regionalisation(self): ''' Processes the tectonic regionalisation from the yaml file ''' if 'tectonic_regionalisation' in self.data.keys(): tectonic_reg = TectonicRegionalisation() tectonic_reg.populate_regions( parse_tect_region_dict_to_tuples( self.data['tectonic_regionalisation'])) else: tectonic_reg = None return tectonic_reg
[docs] def read_fault_geometry(self, geo_dict, mesh_spacing=1.0): ''' Creates the fault geometry from the parameters specified in the dictionary. :param dict geo_dict: Sub-dictionary of main fault dictionary containing only the geometry attributes :param float mesh_spacing: Fault mesh spacing (km) :returns: Instance of SimpleFaultGeometry or ComplexFaultGeometry, depending on typology ''' if geo_dict['Fault_Typology'] == 'Simple': # Simple fault geometry raw_trace = geo_dict['Fault_Trace'] trace = Line([Point(raw_trace[ival], raw_trace[ival + 1]) for ival in range(0, len(raw_trace), 2)]) geometry = SimpleFaultGeometry(trace, geo_dict['Dip'], geo_dict['Upper_Depth'], geo_dict['Lower_Depth'], mesh_spacing) elif geo_dict['Fault_Typology'] == 'Complex': # Complex Fault Typology trace = [] for raw_trace in geo_dict['Fault_Trace']: fault_edge = Line( [Point(raw_trace[ival], raw_trace[ival + 1], raw_trace[ival + 2]) for ival in range(0, len(raw_trace), 3)]) trace.append(fault_edge) geometry = ComplexFaultGeometry(trace, mesh_spacing) else: raise ValueError('Unrecognised or unsupported fault geometry!') return geometry