# -*- coding: utf-8 -*-
# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# Copyright (C) 2012-2021 GEM Foundation
#
# OpenQuake 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.
#
# OpenQuake is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with OpenQuake. If not, see <http://www.gnu.org/licenses/>.
"""
Module :mod:`openquake.hazardlib.imt` defines different intensity measure
types.
"""
import ast
import operator
import functools
import numpy
# NB: (MS) the management of the IMTs implemented here is complex, it would
# be better to have a single IMT class, but it is as it is for legacy reasons
registry = {} # IMT string -> IMT class
[docs]def positivefloat(val):
"""
Raise a ValueError if val <= 0
"""
if val <= 0:
raise ValueError(val)
[docs]def imt2tup(string):
"""
>>> imt2tup('PGA')
('PGA',)
>>> imt2tup('SA(1.0)')
('SA', 1.0)
>>> imt2tup('SA(1)')
('SA', 1.0)
"""
s = string.strip()
if not s.endswith(')'):
# no parenthesis, PGA is considered the same as PGA()
return (s,)
name, rest = s.split('(', 1)
return (name,) + tuple(float(x) for x in ast.literal_eval(rest[:-1] + ','))
[docs]def from_string(imt):
"""
Convert an IMT string into an hazardlib object.
:param str imt:
Intensity Measure Type.
"""
tup = imt2tup(imt)
return registry[tup[0]](*tup[1:])
[docs]@functools.total_ordering
class IMT(tuple, metaclass=IMTMeta):
"""
Base class for intensity measure type.
Subclasses may define class attribute ``_fields`` as a tuple with names
of parameters the specific intensity measure type requires (if there
are any).
"""
_fields = ()
_defaults = None
@property
def name(self):
"""The name of the Intensity Measure Type (ex. "PGA", "SA", ...)"""
return self[0]
def __getnewargs__(self):
return tuple(getattr(self, field) for field, check in self._fields)
def __lt__(self, other):
if not self._fields:
return self[0] < other[0] # ordered by name
return (self[0], self[1] or 0, self[2] or 0) < (
other[0], other[1] or 0, other[2] or 0)
def __repr__(self):
if not self._fields: # return the name
return self[0]
return '%s(%s)' % (type(self).__name__,
', '.join(str(getattr(self, field))
for field, check in self._fields))
[docs]class PGA(IMT):
"""
Peak ground acceleration during an earthquake measured in units
of ``g``, times of gravitational acceleration.
"""
period = 0.0
[docs]class PGV(IMT):
"""
Peak ground velocity during an earthquake measured in units of ``cm/sec``.
"""
[docs]class PGD(IMT):
"""
Peak ground displacement during an earthquake measured in units of ``cm``.
"""
[docs]class SA(IMT):
"""
Spectral acceleration, defined as the maximum acceleration of a damped,
single-degree-of-freedom harmonic oscillator. Units are ``g``, times
of gravitational acceleration.
:param period:
The natural period of the oscillator in seconds.
:param damping:
The degree of damping for the oscillator in percents.
:raises ValueError:
if period or damping is not positive.
"""
_fields = (('period', positivefloat), ('damping', positivefloat))
_defaults = (5.0,) # damping
def __repr__(self):
if self.damping != 5.0:
return '%s(%s, %s)' % (self.name, self.period, self.damping)
else:
return '%s(%s)' % (self.name, self.period)
[docs]class AvgSA(IMT):
"""
Dummy spectral acceleration to compute average ground motion over
several spectral ordinates.
"""
[docs]class IA(IMT):
"""
Arias intensity. Determines the intensity of shaking by measuring
the acceleration of transient seismic waves. Units are ``m/s``.
"""
[docs]class CAV(IMT):
"""
Cumulative Absolute Velocity. Defins the integral of the absolute
acceleration time series. Units are "g-sec"
"""
[docs]class RSD(IMT):
"""
Relative significant duration, 5-95% of :class:`Arias intensity
<IA>`, in seconds.
"""
[docs]class RSD595(IMT):
"""
Alias for RSD
"""
[docs]class RSD575(IMT):
"""
Relative significant duration, 5-75% of :class:`Arias intensity
<IA>`, in seconds.
"""
[docs]class RSD2080(IMT):
"""
Relative significant duration, 20-80% of :class:`Arias intensity
<IA>`, in seconds.
"""
[docs]class MMI(IMT):
"""
Modified Mercalli intensity, a Roman numeral describing the severity
of an earthquake in terms of its effects on the earth's surface
and on humans and their structures.
"""
[docs]class JMA(IMT):
"""
Modified Mercalli intensity, a Roman numeral describing the severity
of an earthquake in terms of its effects on the earth's surface
and on humans and their structures.
"""
# Volcanic IMTs
[docs]class ASH(IMT):
"""
Level of the ash fall in millimeters
"""
# secondary perils
[docs]class Disp(IMT):
"""
Displacement
"""
[docs]class DispProb(IMT):
"""
Displacement probability
"""
[docs]class LiqProb(IMT):
"""
Liquefaction probability
"""
[docs]class PGDMax(IMT):
"""
Maximum between vert_settlement and lat_spread
"""
def __call__(self, vert_settlement, lat_spread):
return numpy.maximum(vert_settlement, lat_spread)
[docs]class PGDGeomMean(IMT):
"""
Geometric mean between vert_settlement and lat_spread
"""
def __call__(cls, vert_settlement, lat_spread):
return numpy.sqrt(vert_settlement * lat_spread)