ADLoc 1.0.2__tar.gz → 1.0.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ADLoc
3
- Version: 1.0.2
3
+ Version: 1.0.4
4
4
  Description-Content-Type: text/markdown
5
5
  Requires-Dist: numpy
6
6
  Requires-Dist: h5py
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ADLoc
3
- Version: 1.0.2
3
+ Version: 1.0.4
4
4
  Description-Content-Type: text/markdown
5
5
  Requires-Dist: numpy
6
6
  Requires-Dist: h5py
@@ -244,6 +244,47 @@ def calc_traveltime(event_locs, station_locs, phase_type, eikonal):
244
244
  return tt
245
245
 
246
246
 
247
+ def calc_grad_traveltime(event_loc, station_loc, phase_type, eikonal):
248
+ """
249
+ Gradient of the eikonal traveltime w.r.t. event location, computed directly from coordinates.
250
+ event_loc: (num_event, 3) or (1, 3) array of event locations
251
+ station_loc: (num_station, 3) array of station locations
252
+ phase_type: (num_station,) array of phase type (0 for P, 1 for S)
253
+ eikonal: dictionary of the eikonal timetable
254
+ """
255
+ x = event_loc[:, 0] - station_loc[:, 0]
256
+ y = event_loc[:, 1] - station_loc[:, 1]
257
+ z = event_loc[:, 2] - station_loc[:, 2]
258
+ r = np.sqrt(x**2 + y**2)
259
+
260
+ rgrid0 = eikonal["rgrid"][0]
261
+ zgrid0 = eikonal["zgrid"][0]
262
+ nr = eikonal["nr"]
263
+ nz = eikonal["nz"]
264
+ h = eikonal["h"]
265
+
266
+ if isinstance(phase_type, list):
267
+ phase_type = np.array(phase_type)
268
+
269
+ dt_dr = np.zeros(len(phase_type))
270
+ dt_dz = np.zeros(len(phase_type))
271
+
272
+ p_index = phase_type == 0
273
+ s_index = phase_type == 1
274
+
275
+ dt_dr[p_index] = _interp(eikonal["grad_up"][0], r[p_index], z[p_index], rgrid0, zgrid0, nr, nz, h)
276
+ dt_dr[s_index] = _interp(eikonal["grad_us"][0], r[s_index], z[s_index], rgrid0, zgrid0, nr, nz, h)
277
+ dt_dz[p_index] = _interp(eikonal["grad_up"][1], r[p_index], z[p_index], rgrid0, zgrid0, nr, nz, h)
278
+ dt_dz[s_index] = _interp(eikonal["grad_us"][1], r[s_index], z[s_index], rgrid0, zgrid0, nr, nz, h)
279
+
280
+ dt_dx = dt_dr * x / (r + 1e-6)
281
+ dt_dy = dt_dr * y / (r + 1e-6)
282
+
283
+ grad = np.column_stack((dt_dx, dt_dy, dt_dz))
284
+
285
+ return grad
286
+
287
+
247
288
  # def grad_traveltime(event_loc, station_loc, phase_type, eikonal):
248
289
  def grad_traveltime(event_index, station_index, phase_type, events, stations, eikonal):
249
290
 
@@ -4,7 +4,7 @@ import scipy
4
4
  from sklearn.base import BaseEstimator
5
5
 
6
6
  from ._ransac import RANSACRegressor
7
- from .eikonal2d import grad_traveltime, init_eikonal2d, traveltime
7
+ from .eikonal2d import calc_grad_traveltime, calc_traveltime, init_eikonal2d
8
8
  from .gmpe import calc_amp, calc_mag
9
9
 
10
10
  # from sklearn.linear_model import RANSACRegressor
@@ -13,9 +13,12 @@ np.random.seed(0)
13
13
 
14
14
 
15
15
  class ADLoc(BaseEstimator):
16
- def __init__(self, config, stations, num_event=1, events=None, eikonal=None):
16
+ def __init__(self, config, num_event=1, events=None, eikonal=None):
17
17
  """
18
18
  events: [x, y, z, t]
19
+ Station locations are not stored on the estimator; they are carried in the
20
+ forward call via X columns [x_km, y_km, z_km] so that a per-event projection
21
+ stays consistent between the picks, the initial location and the inversion.
19
22
  """
20
23
  xlim = config["xlim_km"]
21
24
  ylim = config["ylim_km"]
@@ -27,7 +30,6 @@ class ADLoc(BaseEstimator):
27
30
  if eikonal is None:
28
31
  print(f"Using default velocity: {vel}")
29
32
  self.config = config
30
- self.stations = stations
31
33
  self.vel = vel
32
34
 
33
35
  self.num_event = num_event
@@ -48,19 +50,21 @@ class ADLoc(BaseEstimator):
48
50
  self.use_amplitude = False
49
51
 
50
52
  @staticmethod
51
- def l2_loss_grad(event, X, y, vel={0: 6.0, 1: 6.0 / 1.75}, stations=None, eikonal=None, reduce_loss=False):
53
+ def l2_loss_grad(event, X, y, vel={0: 6.0, 1: 6.0 / 1.75}, eikonal=None, reduce_loss=False):
52
54
  """
53
- X: data_frame with columns ["timestamp", "x_km", "y_km", "z_km", "type"]
55
+ X: columns [station_index, phase_type, phase_weight, x_km, y_km, z_km]
56
+ Station locations are carried in X[:, 3:6] so they follow the (per-event) projection.
54
57
  """
55
58
  station_index = X[:, 0].astype(int)
56
59
  phase_type = X[:, 1].astype(int)
57
60
  phase_weight = X[:, 2]
61
+ station_loc = X[:, 3:6]
58
62
 
59
63
  if eikonal is None:
60
64
  v = np.array([vel[t] for t in phase_type])
61
- tt = np.linalg.norm(event[:3] - stations[station_index, :3], axis=-1) / v + event[3]
65
+ tt = np.linalg.norm(event[:3] - station_loc, axis=-1) / v + event[3]
62
66
  else:
63
- tt = traveltime(0, station_index, phase_type, event[np.newaxis, :3], stations, eikonal) + event[3]
67
+ tt = calc_traveltime(event[np.newaxis, :3], station_loc, phase_type, eikonal) + event[3]
64
68
 
65
69
  if reduce_loss:
66
70
  loss = 0.5 * np.sum((tt - y) ** 2 * phase_weight)
@@ -70,12 +74,12 @@ class ADLoc(BaseEstimator):
70
74
  J = np.ones((len(X), 4))
71
75
  if eikonal is None:
72
76
  J[:, :3] = (
73
- (event[:3] - stations[station_index, :3])
74
- / np.linalg.norm(event[:3] - stations[station_index, :3], axis=-1, keepdims=True)
77
+ (event[:3] - station_loc)
78
+ / np.linalg.norm(event[:3] - station_loc, axis=-1, keepdims=True)
75
79
  / v[:, np.newaxis]
76
80
  )
77
81
  else:
78
- grad = grad_traveltime(0, station_index, phase_type, event[np.newaxis, :3], stations, eikonal)
82
+ grad = calc_grad_traveltime(event[np.newaxis, :3], station_loc, phase_type, eikonal)
79
83
  J[:, :3] = grad
80
84
 
81
85
  if reduce_loss:
@@ -86,17 +90,18 @@ class ADLoc(BaseEstimator):
86
90
  return loss, J
87
91
 
88
92
  @staticmethod
89
- def huber_loss_grad(event, X, y, vel={0: 6.0, 1: 6.0 / 1.75}, stations=None, eikonal=None, sigma=1.0):
93
+ def huber_loss_grad(event, X, y, vel={0: 6.0, 1: 6.0 / 1.75}, eikonal=None, sigma=1.0):
90
94
 
91
95
  station_index = X[:, 0].astype(int)
92
96
  phase_type = X[:, 1].astype(int)
93
97
  phase_weight = X[:, 2]
98
+ station_loc = X[:, 3:6]
94
99
 
95
100
  if eikonal is None:
96
101
  v = np.array([vel[t] for t in phase_type])
97
- tt = np.linalg.norm(event[:3] - stations[station_index, :3], axis=-1) / v + event[3]
102
+ tt = np.linalg.norm(event[:3] - station_loc, axis=-1) / v + event[3]
98
103
  else:
99
- tt = traveltime(0, station_index, phase_type, event[np.newaxis, :3], stations, eikonal) + event[3]
104
+ tt = calc_traveltime(event[np.newaxis, :3], station_loc, phase_type, eikonal) + event[3]
100
105
 
101
106
  t_diff = tt - y
102
107
  l1 = np.squeeze((np.abs(t_diff) > sigma))
@@ -109,12 +114,12 @@ class ADLoc(BaseEstimator):
109
114
  J = np.ones((len(X), 4))
110
115
  if eikonal is None:
111
116
  J[:, :3] = (
112
- (event[:3] - stations[station_index, :3])
113
- / np.linalg.norm(event[:3] - stations[station_index, :3], axis=-1, keepdims=True)
117
+ (event[:3] - station_loc)
118
+ / np.linalg.norm(event[:3] - station_loc, axis=-1, keepdims=True)
114
119
  / v[:, np.newaxis]
115
120
  )
116
121
  else:
117
- grad = grad_traveltime(0, station_index, phase_type, event[np.newaxis, :3], stations, eikonal)
122
+ grad = calc_grad_traveltime(event[np.newaxis, :3], station_loc, phase_type, eikonal)
118
123
  J[:, :3] = grad
119
124
 
120
125
  J = np.sum(
@@ -137,7 +142,7 @@ class ADLoc(BaseEstimator):
137
142
  x0=self.events[event_index],
138
143
  method="L-BFGS-B",
139
144
  jac=True,
140
- args=(X, yt, self.vel, self.stations, self.eikonal),
145
+ args=(X, yt, self.vel, self.eikonal),
141
146
  # bounds=[
142
147
  # (self.config["xlim_km"][0], self.config["xlim_km"][1]),
143
148
  # (self.config["ylim_km"][0], self.config["ylim_km"][1]),
@@ -153,8 +158,9 @@ class ADLoc(BaseEstimator):
153
158
  if self.use_amplitude:
154
159
  station_index = X[:, 0].astype(int)
155
160
  phase_weight = X[:, 2:3]
161
+ station_loc = X[:, 3:6]
156
162
  self.magnitudes[event_index] = calc_mag(
157
- ya[:, np.newaxis], self.events[event_index, :3], self.stations[station_index, :3], phase_weight
163
+ ya[:, np.newaxis], self.events[event_index, :3], station_loc, phase_weight
158
164
  )
159
165
 
160
166
  return self
@@ -170,7 +176,7 @@ class ADLoc(BaseEstimator):
170
176
  # event0 = self.events[event_index]
171
177
  # delta = np.inf
172
178
  # for i in range(max_iter):
173
- # loss, grad = self.l2_loss_grad(event0, X, yt, self.vel, self.stations, self.eikonal)
179
+ # loss, grad = self.l2_loss_grad(event0, X, yt, self.vel, self.eikonal)
174
180
  # A, b = grad, loss
175
181
  # dx = scipy.sparse.linalg.lsqr(A, b, damp=damp)[0]
176
182
  # self.events[event_index] -= dx
@@ -180,36 +186,37 @@ class ADLoc(BaseEstimator):
180
186
  # break
181
187
 
182
188
  # if self.use_amplitude:
183
- # station_index = X[:, 0].astype(int)
184
189
  # phase_weight = X[:, 2:3]
190
+ # station_loc = X[:, 3:6]
185
191
  # self.magnitudes[event_index] = calc_mag(
186
- # ya[:, np.newaxis], self.events[event_index, :3], self.stations[station_index, :3], phase_weight
192
+ # ya[:, np.newaxis], self.events[event_index, :3], station_loc, phase_weight
187
193
  # )
188
194
 
189
195
  # return self
190
196
 
191
197
  def predict(self, X, event_index=0):
192
198
  """
193
- X: data_frame with columns ["timestamp", "x_km", "y_km", "z_km", "type"]
199
+ X: columns [station_index, phase_type, phase_weight, x_km, y_km, z_km]
194
200
  """
195
201
  station_index = X[:, 0].astype(int)
196
202
  phase_type = X[:, 1].astype(int)
203
+ station_loc = X[:, 3:6]
197
204
 
198
205
  if self.eikonal is None:
199
206
  v = np.array([self.vel[t] for t in phase_type])
200
207
  tt = (
201
- np.linalg.norm(self.events[event_index, :3] - self.stations[station_index, :3], axis=-1) / v
208
+ np.linalg.norm(self.events[event_index, :3] - station_loc, axis=-1) / v
202
209
  + self.events[event_index, 3]
203
210
  )
204
211
  else:
205
212
  tt = (
206
- traveltime(event_index, station_index, phase_type, self.events, self.stations, self.eikonal)
213
+ calc_traveltime(self.events[event_index][np.newaxis, :3], station_loc, phase_type, self.eikonal)
207
214
  + self.events[event_index, 3]
208
215
  )
209
216
 
210
217
  if self.use_amplitude:
211
218
  amp = calc_amp(
212
- self.magnitudes[event_index], self.events[event_index, :3], self.stations[station_index, :3]
219
+ self.magnitudes[event_index], self.events[event_index, :3], station_loc
213
220
  ).squeeze()
214
221
  return np.array([tt, amp]).T
215
222
  else:
@@ -217,16 +224,17 @@ class ADLoc(BaseEstimator):
217
224
 
218
225
  def weight(self, X, event_index=0):
219
226
  """
220
- X: data_frame with columns ["timestamp", "x_km", "y_km", "z_km", "type"]
227
+ X: columns [station_index, phase_type, phase_weight, x_km, y_km, z_km]
221
228
  """
222
229
  station_index = X[:, 0].astype(int)
223
230
  phase_type = X[:, 1].astype(int)
231
+ station_loc = X[:, 3:6]
224
232
 
225
233
  if self.eikonal is None:
226
234
  v = np.array([self.vel[t] for t in phase_type])
227
- tt = np.linalg.norm(self.events[event_index, :3] - self.stations[station_index, :3], axis=-1) / v
235
+ tt = np.linalg.norm(self.events[event_index, :3] - station_loc, axis=-1) / v
228
236
  else:
229
- tt = traveltime(event_index, station_index, phase_type, self.events, self.stations, self.eikonal)
237
+ tt = calc_traveltime(self.events[event_index][np.newaxis, :3], station_loc, phase_type, self.eikonal)
230
238
 
231
239
  return np.array([tt]).T
232
240
 
@@ -562,21 +570,20 @@ if __name__ == "__main__":
562
570
  estimator = ADLoc(
563
571
  config,
564
572
  # events=events[["x_km", "y_km", "z_km", "event_time"]].values + np.random.rand(num_event, 4) * 10,
565
- stations=stations[["x_km", "y_km", "z_km"]].values,
566
573
  num_event=num_event,
567
574
  eikonal=eikonal_config,
568
575
  )
569
- output = estimator.predict(X[["idx_sta", "type"]].values, event_index=event_index)
576
+ output = estimator.predict(X[["idx_sta", "type", "score", "x_km", "y_km", "z_km"]].values, event_index=event_index)
570
577
  tt_init = output[:, 0]
571
578
  amp_init = output[:, 1]
572
- estimator.score(X[["idx_sta", "type"]].values, y=X[["t_s", "amp"]].values, event_index=event_index)
579
+ estimator.score(X[["idx_sta", "type", "score", "x_km", "y_km", "z_km"]].values, y=X[["t_s", "amp"]].values, event_index=event_index)
573
580
 
574
581
  print(f"Init event loc: {estimator.events[event_index].round(3)}")
575
582
 
576
583
  # %%
577
- estimator.fit(X[["idx_sta", "type", "score", "amp"]].values, y=X[["t_s", "amp"]].values, event_index=event_index)
578
- estimator.score(X[["idx_sta", "type"]].values, y=X[["t_s", "amp"]].values, event_index=event_index)
579
- output = estimator.predict(X[["idx_sta", "type"]].values, event_index=event_index)
584
+ estimator.fit(X[["idx_sta", "type", "score", "x_km", "y_km", "z_km"]].values, y=X[["t_s", "amp"]].values, event_index=event_index)
585
+ estimator.score(X[["idx_sta", "type", "score", "x_km", "y_km", "z_km"]].values, y=X[["t_s", "amp"]].values, event_index=event_index)
586
+ output = estimator.predict(X[["idx_sta", "type", "score", "x_km", "y_km", "z_km"]].values, event_index=event_index)
580
587
  tt = output[:, 0]
581
588
  amp = output[:, 1]
582
589
  print("Basic:")
@@ -605,24 +612,23 @@ if __name__ == "__main__":
605
612
  fig.savefig(f"{data_path}/picks_xt_{event_index}_adloc.png")
606
613
 
607
614
  # %%
615
+ # RANSAC locates a single event, so drive it with a one-event estimator (slot 0).
608
616
  reg = RANSACRegressor(
609
- estimator=ADLoc(
610
- config, stations=stations[["x_km", "y_km", "z_km"]].values, num_event=num_event, eikonal=eikonal_config
611
- ),
617
+ estimator=ADLoc(config, num_event=1, eikonal=eikonal_config),
612
618
  random_state=0,
613
619
  min_samples=4,
614
620
  residual_threshold=[1.0, 0.5],
615
621
  )
616
- reg.fit(X[["idx_sta", "type", "score", "amp"]].values, X[["t_s", "amp"]].values, event_index=event_index)
622
+ reg.fit(X[["idx_sta", "type", "score", "x_km", "y_km", "z_km"]].values, X[["t_s", "amp"]].values)
617
623
  mask_invt = reg.inlier_mask_
618
624
  estimator = reg.estimator_
619
- estimator.score(X[["idx_sta", "type"]].values, y=X[["t_s", "amp"]].values, event_index=event_index)
620
- output = estimator.predict(X[["idx_sta", "type"]].values, event_index=event_index)
625
+ estimator.score(X[["idx_sta", "type", "score", "x_km", "y_km", "z_km"]].values, y=X[["t_s", "amp"]].values)
626
+ output = estimator.predict(X[["idx_sta", "type", "score", "x_km", "y_km", "z_km"]].values)
621
627
  tt = output[:, 0]
622
628
  amp = output[:, 1]
623
629
  print("RANSAC:")
624
630
  print(f"True event loc: {event_loc[['x_km', 'y_km', 'z_km']].values.astype(float).round(3)}")
625
- print(f"Invt event loc: {estimator.events[event_index].round(3)}")
631
+ print(f"Invt event loc: {estimator.events[0].round(3)}")
626
632
 
627
633
  # %% add random picks
628
634
  config["vel"] = {"P": 6.0, "S": 6.0 / 1.73}
@@ -680,24 +686,23 @@ if __name__ == "__main__":
680
686
  plt.savefig(f"{data_path}/picks_xt_{event_index}_noise.png")
681
687
 
682
688
  # %%
689
+ # RANSAC locates a single event, so drive it with a one-event estimator (slot 0).
683
690
  reg = RANSACRegressor(
684
- estimator=ADLoc(
685
- config, stations=stations[["x_km", "y_km", "z_km"]].values, num_event=num_event, eikonal=eikonal_config
686
- ),
691
+ estimator=ADLoc(config, num_event=1, eikonal=eikonal_config),
687
692
  random_state=0,
688
693
  min_samples=4,
689
694
  residual_threshold=[1.0, 0.5],
690
695
  )
691
- reg.fit(X[["idx_sta", "type", "score", "amp"]].values, X[["t_s", "amp"]].values, event_index=event_index)
696
+ reg.fit(X[["idx_sta", "type", "score", "x_km", "y_km", "z_km"]].values, X[["t_s", "amp"]].values)
692
697
  mask_invt = reg.inlier_mask_
693
698
  estimator = reg.estimator_
694
- estimator.score(X[["idx_sta", "type"]].values, y=X[["t_s", "amp"]].values, event_index=event_index)
695
- output = estimator.predict(X[["idx_sta", "type"]].values, event_index=event_index)
699
+ estimator.score(X[["idx_sta", "type", "score", "x_km", "y_km", "z_km"]].values, y=X[["t_s", "amp"]].values)
700
+ output = estimator.predict(X[["idx_sta", "type", "score", "x_km", "y_km", "z_km"]].values)
696
701
  tt = output[:, 0]
697
702
  amp = output[:, 1]
698
703
  print("RANSAC with noise picks:")
699
704
  print(f"True event loc: {event_loc[['x_km', 'y_km', 'z_km']].values.astype(float).round(3)}")
700
- print(f"Invt event loc: {estimator.events[event_index].round(3)}")
705
+ print(f"Invt event loc: {estimator.events[0].round(3)}")
701
706
 
702
707
  # %%
703
708
  fig, ax = plt.subplots(2, 2, figsize=(8, 8), squeeze=False)
@@ -719,7 +724,7 @@ if __name__ == "__main__":
719
724
  ax[0, 1].scatter(np.log10(X["dist_km"][mask_invt]), amp[mask_invt], c="g", s=50, marker="x", label="Invert")
720
725
 
721
726
  X["dist_km"] = X[["x_km", "y_km", "z_km"]].apply(
722
- lambda x: np.linalg.norm(x - estimator.events[event_index, :3]), axis=1
727
+ lambda x: np.linalg.norm(x - estimator.events[0, :3]), axis=1
723
728
  )
724
729
  colors = lambda x: "r" if x == 0 else "b"
725
730
  ax[1, 0].scatter(X["dist_km"], X["t_s"], c=X["type"].apply(colors), s=30, marker="o", label="Picks")
@@ -4,6 +4,7 @@ from contextlib import nullcontext
4
4
  import numpy as np
5
5
  import pandas as pd
6
6
  from tqdm import tqdm
7
+ from pyproj import Proj
7
8
 
8
9
  from ._ransac import RANSACRegressor
9
10
 
@@ -57,10 +58,22 @@ def invert(picks, stations, config, estimator, event_index, event_init):
57
58
  if config["use_amplitude"] and ("station_term_amplitude" not in stations.columns):
58
59
  stations["station_term_amplitude"] = 0.0
59
60
 
61
+
62
+ stations_ = stations[stations["station_id"].isin(picks["station_id"].unique())].copy()
63
+ if "proj" not in config or config["proj"] is None:
64
+ lat0 = stations_["latitude"].mean()
65
+ lon0 = stations_["longitude"].mean()
66
+ proj = Proj(f"+proj=aeqd +lon_0={lon0} +lat_0={lat0} +units=km")
67
+ else:
68
+ proj = config["proj"]
69
+ x_km, y_km = proj(stations_["longitude"].values, stations_["latitude"].values)
70
+ stations_["x_km"] = x_km
71
+ stations_["y_km"] = y_km
72
+
60
73
  if config["use_amplitude"]:
61
74
  X = picks.merge(
62
75
  # stations[["x_km", "y_km", "z_km", "station_id", "station_term_time", "station_term_amplitude"]],
63
- stations[
76
+ stations_[
64
77
  [
65
78
  "x_km",
66
79
  "y_km",
@@ -76,7 +89,7 @@ def invert(picks, stations, config, estimator, event_index, event_init):
76
89
  else:
77
90
  X = picks.merge(
78
91
  # stations[["x_km", "y_km", "z_km", "station_id", "station_term_time"]],
79
- stations[
92
+ stations_[
80
93
  ["x_km", "y_km", "z_km", "station_id", "station_term_time_p", "station_term_time_s"]
81
94
  ], ## Separate P and S station term
82
95
  on="station_id",
@@ -113,6 +126,13 @@ def invert(picks, stations, config, estimator, event_index, event_init):
113
126
 
114
127
  ## Location using RANSAC
115
128
  num_picks = len(X)
129
+ if num_picks < max(MIN_PICKS, int(MIN_PICKS_RATIO * num_picks)):
130
+ picks["mask"] = 0
131
+ picks["residual_time"] = 0.0
132
+ if config["use_amplitude"]:
133
+ picks["residual_amplitude"] = 0.0
134
+ return picks, None
135
+
116
136
  reg = RANSACRegressor(
117
137
  estimator=estimator,
118
138
  random_state=0,
@@ -124,15 +144,14 @@ def invert(picks, stations, config, estimator, event_index, event_init):
124
144
  )
125
145
  try:
126
146
  if config["use_amplitude"]:
127
- reg.fit(X[["idx_sta", "type", "score", "amp"]].values, X[["t_s", "amp"]].values)
147
+ reg.fit(X[["idx_sta", "type", "score", "x_km", "y_km", "z_km"]].values, X[["t_s", "amp"]].values)
128
148
  else:
129
- reg.fit(X[["idx_sta", "type", "score"]].values, X[["t_s"]].values)
149
+ reg.fit(X[["idx_sta", "type", "score", "x_km", "y_km", "z_km"]].values, X[["t_s"]].values)
130
150
  except Exception as e:
131
151
  # print(f"No valid model for event_index {event_index}.")
132
152
  message = "RANSAC could not find a valid consensus set."
133
153
  if str(e)[: len(message)] != message:
134
154
  print(e)
135
- raise
136
155
  picks["mask"] = 0
137
156
  picks["residual_time"] = 0.0
138
157
  if config["use_amplitude"]:
@@ -143,7 +162,7 @@ def invert(picks, stations, config, estimator, event_index, event_init):
143
162
  inlier_mask = reg.inlier_mask_
144
163
 
145
164
  ## Predict travel time
146
- output = estimator.predict(X[["idx_sta", "type"]].values)
165
+ output = estimator.predict(X[["idx_sta", "type", "score", "x_km", "y_km", "z_km"]].values)
147
166
  if config["use_amplitude"]:
148
167
  tt = output[:, 0]
149
168
  amp = output[:, 1]
@@ -151,10 +170,13 @@ def invert(picks, stations, config, estimator, event_index, event_init):
151
170
  tt = output[:, 0]
152
171
  if config["use_amplitude"]:
153
172
  score = estimator.score(
154
- X[["idx_sta", "type", "score", "amp"]].values[inlier_mask], y=X[["t_s", "amp"]].values[inlier_mask]
173
+ X[["idx_sta", "type", "score", "x_km", "y_km", "z_km"]].values[inlier_mask],
174
+ y=X[["t_s", "amp"]].values[inlier_mask],
155
175
  )
156
176
  else:
157
- score = estimator.score(X[["idx_sta", "type", "score"]].values[inlier_mask], y=X[["t_s"]].values[inlier_mask])
177
+ score = estimator.score(
178
+ X[["idx_sta", "type", "score", "x_km", "y_km", "z_km"]].values[inlier_mask], y=X[["t_s"]].values[inlier_mask]
179
+ )
158
180
 
159
181
  if (np.sum(inlier_mask) > MIN_PICKS) and (score > config["min_score"]):
160
182
  mean_residual_time = np.sum(np.abs(X["t_s"].values - tt) * inlier_mask) / np.sum(inlier_mask)
@@ -166,11 +188,16 @@ def invert(picks, stations, config, estimator, event_index, event_init):
166
188
  if config["use_amplitude"]:
167
189
  mag = estimator.magnitudes[0]
168
190
 
191
+ longitude, latitude = proj(x, y, inverse=True)
192
+
169
193
  event = {
170
194
  "idx_eve": event_index, ## inside adloc, idx_eve is used which starts from 0 to N events
171
195
  "x_km": x,
172
196
  "y_km": y,
173
197
  "z_km": z,
198
+ "longitude": longitude,
199
+ "latitude": latitude,
200
+ "depth_km": z,
174
201
  "time": t0 + pd.Timedelta(t, unit="s"),
175
202
  "adloc_score": score,
176
203
  "adloc_residual_time": mean_residual_time,
@@ -228,6 +255,7 @@ def invert_location(picks, stations, config, estimator, events_init=None, iter=0
228
255
  NCPU = config["ncpu"]
229
256
  else:
230
257
  NCPU = min(64, mp.cpu_count() * 2 - 1)
258
+ print(f"Using {NCPU} CPUs for ADLoc inversion.")
231
259
 
232
260
  jobs = []
233
261
  num_events = len(picks["idx_eve"].unique())
@@ -2,7 +2,7 @@ from setuptools import setup
2
2
 
3
3
  setup(
4
4
  name="ADLoc",
5
- version="1.0.2",
5
+ version="1.0.4",
6
6
  long_description="ADLoc",
7
7
  long_description_content_type="text/markdown",
8
8
  packages=["adloc"],
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes