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.0, 1.0, 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.0 ** (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.0 / 3.0) * (np.log10(modiff) - 9.05)
return mmax