use crate::auxilary::{DL, G_GLOBAL};
use crate::gmm::{Earthquake, GmpePoint, GmpePointKind, GroundMotionModeling, Vs30Point};
use geo::{Distance, Haversine, Point};
#[derive(Debug)]
pub struct MF2013 {
pub mw0: f64,
pub a: f64,
pub b: f64,
pub c: f64,
pub d: f64,
pub e: f64,
pub sigma: f64,
pub pd: f64,
pub dl_min: f64,
pub d0: f64,
pub ps: f64,
pub vs_max: f64,
pub v0: f64,
pub gamma: f64,
pub asid: bool,
pub motion_kind: GmpePointKind,
}
impl MF2013 {
fn get_gmpe_by_distnace(
&self,
epicentral_distance: f64,
eq_mag: f64,
eq_depth: f64,
vs_30: f64,
dl: f64,
xvf: f64,
) -> f64 {
let r_rup = (epicentral_distance.powi(2) + eq_depth.powi(2)).sqrt();
let magnitude = eq_mag.min(self.mw0);
let a_m_w = self.a * magnitude;
let g_d = self.pd * (dl.max(self.dl_min) / self.d0).log10();
let log_a = (a_m_w + self.b * r_rup + self.c)
- (r_rup + self.d * 10.0_f64.powf(self.e * magnitude)).log10();
let log_agd = log_a + g_d;
let gs = self.ps * (vs_30.min(self.vs_max) / self.v0).log10();
let log_ags = log_agd + gs;
if self.asid {
let ai = self.gamma + xvf * (eq_depth - 30.);
10.0_f64.powf(log_ags + ai)
} else {
10.0_f64.powf(log_ags)
}
}
}
impl GroundMotionModeling for MF2013 {
fn calc_from_point(&self, point: &Vs30Point, eq: &Earthquake) -> GmpePoint {
let epicentral_distance = Haversine
.distance(Point::new(eq.lon, eq.lat), Point::new(point.lon, point.lat))
/ 1000.;
let vs_30 = point.vs30;
let dl = match point.dl {
None => DL as f64,
Some(dl) => dl,
};
let xvf = match point.xvf {
None => 0.,
Some(_) => 1.,
};
let mut ground_motion =
self.get_gmpe_by_distnace(epicentral_distance, eq.magnitude, eq.depth, vs_30, dl, xvf);
if matches!(self.motion_kind, GmpePointKind::Pga | GmpePointKind::Psa) {
ground_motion = ((ground_motion / 100.) / G_GLOBAL) * 100.;
};
GmpePoint {
lon: point.lon,
lat: point.lat,
value: ground_motion,
kind: self.motion_kind,
}
}
}