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