Source code for openquake.hmtk.seismicity.max_magnitude.cumulative_moment_release

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

#
# LICENSE
#
# Copyright (C) 2010-2023 GEM Foundation, G. Weatherill, M. Pagani, D. Monelli
#
# The Hazard Modeller's Toolkit (openquake.hmtk) 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 :class: openquake.hmtk.seismicity.max_magnitude.cumulative_moment.CumulativeMoment
implements cumulative moment estimator of maximum magnitude from instrumental
seismicity
'''
from math import fabs
import numpy as np
from openquake.hmtk.seismicity.max_magnitude.base import (
    BaseMaximumMagnitude, MAX_MAGNITUDE_METHODS)


[docs]@MAX_MAGNITUDE_METHODS.add("get_mmax", number_bootstraps=int) class CumulativeMoment(BaseMaximumMagnitude): '''Class to implement the bootstrapped cumulative moment estimator of maximum magnitude. Adapted by G. Weatherill from the Cumulative Strain Energy approach originally suggested by Makropoulos & Burton (1983)'''
[docs] def get_mmax(self, catalogue, config): ''' Calculates Maximum magnitude and its uncertainty :param catalogue: Instance of openquake.hmtk.seismicity.catalogue.Catalogue class Earthquake calatalogue data as dictionary containing - * 'year' - Year of event * 'magnitude' - Magnitude of event * 'sigmaMagnitude' - Uncertainty on magnitude (optional) :param dict config: Configuration file for algorithm, containing thw following - * 'number_bootstraps' - Number of bootstraps for uncertainty :param int seed: Seed for random number generator (must be positive) :returns: * Maximum magnitude (float) * Uncertainty on maximum magnituse (float) ''' # If no bootstraps no uncertainty on magnitudes then simply calculate # Mmax without uncertainty self.check_config(config) cond = config['number_bootstraps'] == 1 or\ not isinstance(catalogue.data['sigmaMagnitude'], np.ndarray) or\ len(catalogue.data['sigmaMagnitude']) == 0 or\ np.all(np.isnan(catalogue.data['sigmaMagnitude'])) if cond: return self.cumulative_moment(catalogue.data['year'], catalogue.data['magnitude']), 0.0 neq = len(catalogue.data['magnitude']) mmax_samp = np.zeros(config['number_bootstraps'], dtype=float) # Sample magnitudes from catalogue and calculate MMax from sample for iloc in range(0, config['number_bootstraps']): mw_sample = catalogue.data['magnitude'] + \ catalogue.data['sigmaMagnitude'] * np.random.normal(0., 1., neq) mmax_samp[iloc] = self.cumulative_moment(catalogue.data['year'], mw_sample) # Return mean and standard deviation of samples return np.mean(mmax_samp), np.std(mmax_samp, ddof=1)
[docs] def check_config(self, config): ''' Checks the configuration file for the number of bootstraps. Returns 1 if not found or invalid (i.e. < 0) ''' nb = config['number_bootstraps'] or 0 if nb < 1: config['number_bootstraps'] = 1 return config
[docs] def cumulative_moment(self, year, mag): '''Calculation of Mmax using aCumulative Moment approach, adapted from the cumulative strain energy method of Makropoulos & Burton (1983) :param year: Year of Earthquake :type year: numpy.ndarray :param mag: Magnitude of Earthquake :type mag: numpy.ndarray :keyword iplot: Include cumulative moment plot :type iplot: Boolean :return mmax: Returns Maximum Magnitude :rtype mmax: Float ''' # Calculate seismic moment m_o = 10. ** (9.05 + 1.5 * mag) year_range = np.arange(np.min(year), np.max(year) + 1, 1) nyr = np.shape(year_range)[0] morate = np.zeros(nyr, dtype=float) # Get moment release per year for loc, tyr in enumerate(year_range): idx = np.abs(year - tyr) < 1E-5 if np.sum(idx) > 0: # Some moment release in that year morate[loc] = np.sum(m_o[idx]) ave_morate = np.sum(morate) / nyr # Average moment rate vector exp_morate = np.cumsum(ave_morate * np.ones(nyr)) modiff = (np.abs(np.max(np.cumsum(morate) - exp_morate)) + np.abs(np.min(np.cumsum(morate) - exp_morate))) # Return back to Mw if fabs(modiff) < 1E-20: return -np.inf mmax = (2. / 3.) * (np.log10(modiff) - 9.05) return mmax