File size: 5,070 Bytes
2642322 4a945b5 2642322 4a945b5 2642322 4a945b5 2642322 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 |
# %%
import json
import multiprocessing as mp
import os
from dataclasses import dataclass, asdict
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from fastapi import FastAPI
from pyproj import Proj
import adloc
from adloc.eikonal2d import init_eikonal2d
from adloc.sacloc2d import ADLoc
from adloc.utils import invert_location, invert_location_iter
app = FastAPI()
@app.get("/")
def greet_json():
return {"Hello": "World!"}
@app.post("/predict/")
def predict(picks: dict, stations: dict, config: dict):
picks = picks["data"]
stations = stations["data"]
picks = pd.DataFrame(picks)
picks["phase_time"] = pd.to_datetime(picks["phase_time"])
stations = pd.DataFrame(stations)
picks_, events_ = run_adloc(picks, stations, config)
picks_ = picks_.to_dict(orient="records")
events_ = events_.to_dict(orient="records")
return {"picks": picks_, "events": events_}
def set_config(region="ridgecrest"):
config = {
"min_picks": 8,
"min_picks_ratio": 0.2,
"max_residual_time": 1.0,
"max_residual_amplitude": 1.0,
"min_score": 0.6,
"min_s_picks": 2,
"min_p_picks": 2,
"use_amplitude": False,
}
# ## Domain
if region.lower() == "ridgecrest":
config.update(
{
"region": "ridgecrest",
"minlongitude": -118.004,
"maxlongitude": -117.004,
"minlatitude": 35.205,
"maxlatitude": 36.205,
"mindepth_km": 0.0,
"maxdepth_km": 30.0,
}
)
lon0 = (config["minlongitude"] + config["maxlongitude"]) / 2
lat0 = (config["minlatitude"] + config["maxlatitude"]) / 2
proj = Proj(f"+proj=sterea +lon_0={lon0} +lat_0={lat0} +units=km")
xmin, ymin = proj(config["minlongitude"], config["minlatitude"])
xmax, ymax = proj(config["maxlongitude"], config["maxlatitude"])
zmin, zmax = config["mindepth_km"], config["maxdepth_km"]
xlim_km = (xmin, xmax)
ylim_km = (ymin, ymax)
zlim_km = (zmin, zmax)
config.update(
{
"xlim_km": xlim_km,
"ylim_km": ylim_km,
"zlim_km": zlim_km,
"proj": proj,
}
)
## Eikonal for 1D velocity model
zz = [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 30.0]
vp = [4.746, 4.793, 4.799, 5.045, 5.721, 5.879, 6.504, 6.708, 6.725, 7.800]
vs = [2.469, 2.470, 2.929, 2.930, 3.402, 3.403, 3.848, 3.907, 3.963, 4.500]
h = 0.3
vel = {"Z": zz, "P": vp, "S": vs}
eikonal = {
"vel": vel,
"h": h,
"xlim_km": xlim_km,
"ylim_km": ylim_km,
"zlim_km": zlim_km,
}
eikonal = init_eikonal2d(eikonal)
config["eikonal"] = eikonal
config["bfgs_bounds"] = (
(xlim_km[0] - 1, xlim_km[1] + 1), # x
(ylim_km[0] - 1, ylim_km[1] + 1), # y
(0, zlim_km[1] + 1), # z
(None, None), # t
)
config["event_index"] = 0
return config
config = set_config()
# %%
def run_adloc(picks, stations, config_):
# %%
config.update(config_)
proj = config["proj"]
# %%
stations[["x_km", "y_km"]] = stations.apply(
lambda x: pd.Series(proj(longitude=x.longitude, latitude=x.latitude)), axis=1
)
stations["z_km"] = stations["elevation_m"].apply(lambda x: -x / 1e3)
# %%
mapping_phase_type_int = {"P": 0, "S": 1}
picks["phase_type"] = picks["phase_type"].map(mapping_phase_type_int)
if "phase_amplitude" in picks.columns:
picks["phase_amplitude"] = picks["phase_amplitude"].apply(lambda x: np.log10(x) + 2.0) # convert to log10(cm/s)
# %%
# reindex in case the index does not start from 0 or is not continuous
stations["idx_sta"] = np.arange(len(stations))
picks = picks.merge(stations[["station_id", "idx_sta"]], on="station_id")
picks["idx_eve"] = config["event_index"]
# %%
estimator = ADLoc(config, stations=stations[["x_km", "y_km", "z_km"]].values, eikonal=config["eikonal"])
# %%
picks, events = invert_location_iter(picks, stations, config, estimator, events_init=None, iter=0)
if (picks is None) or (events is None):
return None, None
# %%
if "event_index" not in events.columns:
events["event_index"] = events.merge(picks[["idx_eve", "event_index"]], on="idx_eve")["event_index"]
events[["longitude", "latitude"]] = events.apply(
lambda x: pd.Series(proj(x["x_km"], x["y_km"], inverse=True)), axis=1
)
events["depth_km"] = events["z_km"]
events.drop(["idx_eve", "x_km", "y_km", "z_km"], axis=1, inplace=True, errors="ignore")
events.sort_values(["time"], inplace=True)
picks.rename({"mask": "adloc_mask", "residual_s": "adloc_residual_s"}, axis=1, inplace=True)
picks["phase_type"] = picks["phase_type"].map({0: "P", 1: "S"})
picks.drop(["idx_eve", "idx_sta"], axis=1, inplace=True, errors="ignore")
picks.sort_values(["phase_time"], inplace=True)
return picks, events
|