PhaseNet 0.1.0__py3-none-any.whl

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.
phasenet/predict.py ADDED
@@ -0,0 +1,143 @@
1
+ import numpy as np
2
+ import tensorflow as tf
3
+ tf.compat.v1.disable_eager_execution()
4
+ tf.compat.v1.logging.set_verbosity(tf.compat.v1.logging.ERROR)
5
+ import argparse, os, time, logging
6
+ from tqdm import tqdm
7
+ import pandas as pd
8
+ import threading
9
+ import multiprocessing
10
+ from functools import partial
11
+ import pickle
12
+ from model import UNet, ModelConfig
13
+ from data_reader import DataReader_pred, DataReader_mseed
14
+ from util import *
15
+
16
+ def read_args():
17
+
18
+ parser = argparse.ArgumentParser()
19
+ parser.add_argument("--model_dir", help="Checkpoint directory (default: None)")
20
+ parser.add_argument("--data_dir", default="./dataset/waveform_pred/", help="Input file directory")
21
+ parser.add_argument("--data_list", default="./dataset/waveform.csv", help="Input csv file")
22
+ parser.add_argument("--result_dir", default="./results", help="Output directory")
23
+ parser.add_argument("--batch_size", default=20, type=int, help="batch size")
24
+ parser.add_argument("--tp_prob", default=0.3, type=float, help="Probability threshold for P pick")
25
+ parser.add_argument("--ts_prob", default=0.3, type=float, help="Probability threshold for S pick")
26
+ parser.add_argument("--input_mseed", action="store_true", help="mseed format")
27
+ parser.add_argument("--stations", default="./dataset/waveform.csv", help="seismic station info")
28
+ parser.add_argument("--plot_figure", action="store_true", help="If plot figure for test")
29
+ parser.add_argument("--save_prob", action="store_true", help="If save result for test")
30
+ args = parser.parse_args()
31
+ return args
32
+
33
+
34
+ def pred_fn(args, data_reader, figure_dir=None, result_dir=None, log_dir=None):
35
+ current_time = time.strftime("%y%m%d-%H%M%S")
36
+ if log_dir is None:
37
+ log_dir = os.path.join(args.log_dir, "pred", current_time)
38
+ logging.info("Pred log: %s" % log_dir)
39
+ logging.info("Dataset size: {}".format(data_reader.num_data))
40
+ if not os.path.exists(log_dir):
41
+ os.makedirs(log_dir)
42
+ if (args.plot_figure == True) and (figure_dir is None):
43
+ figure_dir = os.path.join(log_dir, 'figures')
44
+ if not os.path.exists(figure_dir):
45
+ os.makedirs(figure_dir)
46
+ if (args.save_prob == True) and (result_dir is None):
47
+ result_dir = os.path.join(log_dir, 'results')
48
+ if not os.path.exists(result_dir):
49
+ os.makedirs(result_dir)
50
+
51
+ with tf.compat.v1.name_scope('Input_Batch'):
52
+ dataset = data_reader.dataset().prefetch(10)
53
+ if args.input_mseed:
54
+ batch_size = 1
55
+ else:
56
+ batch_size = args.batch_size
57
+ dataset = dataset.batch(batch_size)
58
+ batch = tf.compat.v1.data.make_one_shot_iterator(dataset).get_next()
59
+
60
+ config = ModelConfig(X_shape=data_reader.X_shape)
61
+ with open(os.path.join(log_dir, 'config.log'), 'w') as fp:
62
+ fp.write('\n'.join("%s: %s" % item for item in vars(config).items()))
63
+
64
+ model = UNet(config=config, input_batch=batch, mode="pred")
65
+ sess_config = tf.compat.v1.ConfigProto()
66
+ sess_config.gpu_options.allow_growth = True
67
+ # sess_config.log_device_placement = False
68
+
69
+ with tf.compat.v1.Session(config=sess_config) as sess:
70
+
71
+ saver = tf.compat.v1.train.Saver(tf.compat.v1.global_variables(), max_to_keep=5)
72
+ init = tf.compat.v1.global_variables_initializer()
73
+ sess.run(init)
74
+
75
+ logging.info("restoring models...")
76
+ latest_check_point = tf.train.latest_checkpoint(args.model_dir)
77
+ saver.restore(sess, latest_check_point)
78
+
79
+ if args.plot_figure:
80
+ num_pool = multiprocessing.cpu_count()*2
81
+ elif args.save_prob:
82
+ num_pool = multiprocessing.cpu_count()
83
+ else:
84
+ num_pool = 2
85
+ pool = multiprocessing.Pool(num_pool)
86
+
87
+ fclog = open(os.path.join(log_dir, 'picks.csv'), 'w')
88
+ fclog.write("fname,itp,tp_prob,its,ts_prob\n")
89
+ picks = {}
90
+
91
+ for step in tqdm(range(0, data_reader.num_data, batch_size), desc="Pred"):
92
+ pred_batch, X_batch, fname_batch = sess.run([model.preds, batch[0], batch[1]],
93
+ feed_dict={model.drop_rate: 0,
94
+ model.is_training: False})
95
+ if args.input_mseed:
96
+ fname_batch = [(fname_batch.decode().split('/')[-1].rstrip(".mseed")+"."+data_reader.stations.iloc[i]["station"]).encode()
97
+ for i in range(len(pred_batch))]
98
+ picks_batch = pool.map(partial(postprocessing_thread,
99
+ pred = pred_batch,
100
+ X = X_batch,
101
+ fname = fname_batch,
102
+ result_dir = result_dir,
103
+ figure_dir = figure_dir,
104
+ args=args), range(len(pred_batch)))
105
+
106
+ for i in range(len(fname_batch)):
107
+ row = "{},[{}],[{}],[{}],[{}]".format(fname_batch[i].decode(), " ".join(map(str,picks_batch[i][0][0])), " ".join(map(str,picks_batch[i][0][1])),
108
+ " ".join(map(str,picks_batch[i][1][0])), " ".join(map(str,picks_batch[i][1][1])))
109
+ fclog.write(row+"\n")
110
+ picks[fname_batch[i].decode()]={"itp":picks_batch[i][0][0], "tp_prob":picks_batch[i][0][1], "its":picks_batch[i][1][0], "ts_prob":picks_batch[i][1][1]}
111
+
112
+ fclog.flush()
113
+
114
+ fclog.close()
115
+ with open(os.path.join(log_dir, 'picks.pkl'), 'wb') as fp:
116
+ pickle.dump(picks, fp)
117
+ print("Done")
118
+
119
+ return 0
120
+
121
+
122
+ def main(args):
123
+
124
+ logging.basicConfig(format='%(asctime)s %(message)s', level=logging.INFO)
125
+
126
+ with tf.compat.v1.name_scope('create_inputs'):
127
+
128
+ if args.input_mseed:
129
+ data_reader = DataReader_mseed(data_dir=args.data_dir,
130
+ data_list=args.data_list,
131
+ stations=args.stations)
132
+ else:
133
+ data_reader = DataReader_pred(data_dir=args.data_dir,
134
+ data_list=args.data_list)
135
+
136
+ pred_fn(args, data_reader, log_dir=args.result_dir)
137
+
138
+ return
139
+
140
+
141
+ if __name__ == '__main__':
142
+ args = read_args()
143
+ main(args)
phasenet/train.py ADDED
@@ -0,0 +1,297 @@
1
+ import numpy as np
2
+ import tensorflow as tf
3
+ tf.compat.v1.disable_eager_execution()
4
+ tf.compat.v1.logging.set_verbosity(tf.compat.v1.logging.ERROR)
5
+ import argparse, os, time, logging
6
+ from tqdm import tqdm
7
+ import pandas as pd
8
+ import threading
9
+ import multiprocessing
10
+ from functools import partial
11
+ import pickle
12
+ from model import UNet, ModelConfig
13
+ from data_reader import DataReader, DataReader_test
14
+ from util import *
15
+
16
+ def read_args():
17
+
18
+ parser = argparse.ArgumentParser()
19
+ parser.add_argument("--mode", default="train", help="train/train_valid/test/debug")
20
+ parser.add_argument("--epochs", default=100, type=int, help="number of epochs (default: 10)")
21
+ parser.add_argument("--batch_size", default=20, type=int, help="batch size")
22
+ parser.add_argument("--learning_rate", default=0.01, type=float, help="learning rate")
23
+ parser.add_argument("--decay_step", default=-1, type=int, help="decay step")
24
+ parser.add_argument("--decay_rate", default=0.9, type=float, help="decay rate")
25
+ parser.add_argument("--momentum", default=0.9, type=float, help="momentum")
26
+ parser.add_argument("--filters_root", default=8, type=int, help="filters root")
27
+ parser.add_argument("--depth", default=5, type=int, help="depth")
28
+ parser.add_argument("--kernel_size", nargs="+", type=int, default=[7, 1], help="kernel size")
29
+ parser.add_argument("--pool_size", nargs="+", type=int, default=[4, 1], help="pool size")
30
+ parser.add_argument("--drop_rate", default=0, type=float, help="drop out rate")
31
+ parser.add_argument("--dilation_rate", nargs="+", type=int, default=[1, 1], help="dilation rate")
32
+ parser.add_argument("--loss_type", default="cross_entropy", help="loss type: cross_entropy, IOU, mean_squared")
33
+ parser.add_argument("--weight_decay", default=0, type=float, help="weight decay")
34
+ parser.add_argument("--optimizer", default="adam", help="optimizer: adam, momentum")
35
+ parser.add_argument("--summary", default=True, type=bool, help="summary")
36
+ parser.add_argument("--class_weights", nargs="+", default=[1, 1, 1], type=float, help="class weights")
37
+ parser.add_argument("--log_dir", default="log", help="Tensorboard log directory (default: log)")
38
+ parser.add_argument("--model_dir", default=None, help="Checkpoint directory (default: None)")
39
+ parser.add_argument("--num_plots", default=10, type=int, help="Plotting trainning results")
40
+ parser.add_argument("--tp_prob", default=0.3, type=float, help="Probability threshold for P pick")
41
+ parser.add_argument("--ts_prob", default=0.3, type=float, help="Probability threshold for S pick")
42
+ parser.add_argument("--train_dir", default="./dataset/waveform_train/", help="Input file directory")
43
+ parser.add_argument("--train_list", default="./dataset/waveform.csv", help="Input csv file")
44
+ parser.add_argument("--valid_dir", default=None, help="Input file directory")
45
+ parser.add_argument("--valid_list", default=None, help="Input csv file")
46
+ parser.add_argument("--test_dir", default=None, help="Input file directory")
47
+ parser.add_argument("--test_list", default=None, help="Input csv file")
48
+ parser.add_argument("--plot_figure", action="store_true", help="If plot figure for test")
49
+ parser.add_argument("--save_prob", action="store_true", help="If save result for test")
50
+ args = parser.parse_args()
51
+ return args
52
+
53
+ def train_fn(args, data_reader, data_reader_valid=None):
54
+ current_time = time.strftime("%y%m%d-%H%M%S")
55
+ log_dir = os.path.join(args.log_dir, current_time)
56
+ logging.info("Training log: {}".format(log_dir))
57
+ if not os.path.exists(log_dir):
58
+ os.makedirs(log_dir)
59
+ figure_dir = os.path.join(log_dir, 'figures')
60
+ if not os.path.exists(figure_dir):
61
+ os.makedirs(figure_dir)
62
+
63
+ with tf.compat.v1.name_scope('Input_Batch'):
64
+ batch = data_reader.dequeue(args.batch_size)
65
+ if data_reader_valid is not None:
66
+ batch_valid = data_reader_valid.dequeue(args.batch_size)
67
+
68
+ config = ModelConfig(X_shape=data_reader.X_shape, Y_shape=data_reader.Y_shape)
69
+ if args.decay_step == -1:
70
+ args.decay_step = data_reader.num_data // args.batch_size
71
+ config.update_args(args)
72
+ with open(os.path.join(log_dir, 'config.log'), 'w') as fp:
73
+ fp.write('\n'.join("%s: %s" % item for item in vars(config).items()))
74
+
75
+ model = UNet(config)
76
+ sess_config = tf.compat.v1.ConfigProto()
77
+ sess_config.gpu_options.allow_growth = True
78
+ # sess_config.log_device_placement = False
79
+
80
+ with tf.compat.v1.Session(config=sess_config) as sess:
81
+
82
+ summary_writer = tf.compat.v1.summary.FileWriter(log_dir, sess.graph)
83
+ saver = tf.compat.v1.train.Saver(tf.compat.v1.global_variables(), max_to_keep=5)
84
+ init = tf.compat.v1.global_variables_initializer()
85
+ sess.run(init)
86
+
87
+ if args.model_dir is not None:
88
+ logging.info("restoring models...")
89
+ latest_check_point = tf.train.latest_checkpoint(args.model_dir)
90
+ saver.restore(sess, latest_check_point)
91
+
92
+ threads = data_reader.start_threads(sess, n_threads=multiprocessing.cpu_count())
93
+ if data_reader_valid is not None:
94
+ threads_valid = data_reader_valid.start_threads(sess, n_threads=multiprocessing.cpu_count())
95
+ flog = open(os.path.join(log_dir, 'loss.log'), 'w')
96
+ total_step = 0
97
+ mean_loss = 0
98
+ if args.plot_figure:
99
+ num_pool = multiprocessing.cpu_count()*2
100
+ elif args.save_prob:
101
+ num_pool = multiprocessing.cpu_count()
102
+ else:
103
+ num_pool = 2
104
+ pool = multiprocessing.Pool(num_pool)
105
+
106
+ for epoch in range(args.epochs):
107
+ progressbar = tqdm(range(0, data_reader.num_data, args.batch_size), desc="{}: epoch {}".format(log_dir.split("/")[-1], epoch))
108
+ for step in progressbar:
109
+ X_batch, Y_batch = sess.run(batch)
110
+ loss_batch = model.train_on_batch(sess, X_batch, Y_batch, summary_writer, args.drop_rate)
111
+ if epoch < 1:
112
+ mean_loss = loss_batch
113
+ else:
114
+ total_step += 1
115
+ mean_loss += (loss_batch-mean_loss)/total_step
116
+ progressbar.set_description("{}: epoch {}, loss={:.6f}, mean={:.6f}".format(log_dir.split("/")[-1], epoch, loss_batch, mean_loss))
117
+ flog.write("epoch: {}, mean loss: {}\n".format(epoch, mean_loss))
118
+
119
+ if data_reader_valid is not None:
120
+ valid_step = 0
121
+ valid_loss = 0
122
+ progressbar = tqdm(range(0, data_reader_valid.num_data, args.batch_size), desc="Valid:")
123
+ for step in progressbar:
124
+ X_batch, Y_batch = sess.run(batch_valid)
125
+ loss_batch, preds_batch = model.valid_on_batch(sess, X_batch, Y_batch, summary_writer)
126
+ valid_step += 1
127
+ valid_loss += (loss_batch-valid_loss)/valid_step
128
+ progressbar.set_description("valid, loss={:.6f}, mean={:.6f}".format(loss_batch, valid_loss))
129
+ flog.write("Valid: mean loss: {}\n".format(valid_loss))
130
+ else:
131
+ loss_batch, preds_batch = model.valid_on_batch(sess, X_batch, Y_batch, summary_writer)
132
+ # loss_batch, pred_batch, logits_batch, X_batch, Y_batch = model.train_on_batch(sess, summary_writer, args.drop_rate, raw_data=True)
133
+ try: ## IO Error on cluster
134
+ flog.flush()
135
+ pool.map(partial(plot_result_thread,
136
+ pred = preds_batch,
137
+ X = X_batch,
138
+ Y = Y_batch,
139
+ fname = ["{:03d}_{:03d}".format(epoch, x).encode() for x in range(args.num_plots)],
140
+ figure_dir = figure_dir),
141
+ range(args.num_plots))
142
+ saver.save(sess, os.path.join(log_dir, "model_{}.ckpt".format(epoch)))
143
+ except:
144
+ pass
145
+ flog.close()
146
+ pool.close()
147
+ data_reader.coord.request_stop()
148
+ try:
149
+ data_reader.coord.join(threads, stop_grace_period_secs=10, ignore_live_threads=True)
150
+ if data_reader_valid is not None:
151
+ data_reader_valid.coord.join(threads_valid, stop_grace_period_secs=10, ignore_live_threads=True)
152
+ except:
153
+ pass
154
+ sess.run(data_reader.queue.close(cancel_pending_enqueues=True))
155
+ if data_reader_valid is not None:
156
+ sess.run(data_reader_valid.queue.close(cancel_pending_enqueues=True))
157
+
158
+ return 0
159
+
160
+ def test_fn(args, data_reader, figure_dir=None, result_dir=None):
161
+ current_time = time.strftime("%y%m%d-%H%M%S")
162
+ logging.info("{} log: {}".format(args.mode, current_time))
163
+ log_dir = os.path.join(args.log_dir, args.mode, current_time)
164
+ if not os.path.exists(log_dir):
165
+ os.makedirs(log_dir)
166
+ if (args.plot_figure == True ) and (figure_dir is None):
167
+ figure_dir = os.path.join(log_dir, 'figures')
168
+ if not os.path.exists(figure_dir):
169
+ os.makedirs(figure_dir)
170
+ if (args.save_prob == True) and (result_dir is None):
171
+ result_dir = os.path.join(log_dir, 'results')
172
+ if not os.path.exists(result_dir):
173
+ os.makedirs(result_dir)
174
+
175
+ with tf.compat.v1.name_scope('Input_Batch'):
176
+ batch = data_reader.dequeue(args.batch_size)
177
+
178
+ config = ModelConfig(X_shape=data_reader.X_shape, Y_shape=data_reader.Y_shape)
179
+ if args.decay_step == -1:
180
+ args.decay_step = data_reader.num_data // args.batch_size
181
+ config.update_args(args)
182
+ with open(os.path.join(log_dir, 'config.log'), 'w') as fp:
183
+ fp.write('\n'.join("%s: %s" % item for item in vars(config).items()))
184
+
185
+ model = UNet(config, input_batch=batch, mode='valid')
186
+ sess_config = tf.compat.v1.ConfigProto()
187
+ sess_config.gpu_options.allow_growth = True
188
+ # sess_config.log_device_placement = False
189
+
190
+ with tf.compat.v1.Session(config=sess_config) as sess:
191
+
192
+ summary_writer = tf.compat.v1.summary.FileWriter(log_dir, sess.graph)
193
+ saver = tf.compat.v1.train.Saver(tf.compat.v1.global_variables(), max_to_keep=5)
194
+ init = tf.compat.v1.global_variables_initializer()
195
+ sess.run(init)
196
+
197
+ logging.info("restoring models...")
198
+ latest_check_point = tf.train.latest_checkpoint(args.model_dir)
199
+ saver.restore(sess, latest_check_point)
200
+
201
+ threads = data_reader.start_threads(sess, n_threads=8)
202
+ flog = open(os.path.join(log_dir, 'loss.log'), 'w')
203
+ total_step = 0
204
+ mean_loss = 0
205
+ picks = []
206
+ itp = []
207
+ its = []
208
+ progressbar = tqdm(range(0, data_reader.num_data, args.batch_size), desc=args.mode)
209
+ if args.plot_figure:
210
+ num_pool = multiprocessing.cpu_count()*2
211
+ elif args.save_prob:
212
+ num_pool = multiprocessing.cpu_count()
213
+ else:
214
+ num_pool = 2
215
+ pool = multiprocessing.Pool(num_pool)
216
+ for step in progressbar:
217
+
218
+ if step + args.batch_size >= data_reader.num_data:
219
+ for t in threads:
220
+ t.join()
221
+ sess.run(data_reader.queue.close())
222
+
223
+ loss_batch, pred_batch, X_batch, Y_batch, \
224
+ fname_batch, itp_batch, its_batch = model.test_on_batch(sess, summary_writer)
225
+ total_step += 1
226
+ mean_loss += (loss_batch-mean_loss)/total_step
227
+ progressbar.set_description("{}, loss={:.6f}, mean loss={:6f}".format(args.mode, loss_batch, mean_loss))
228
+
229
+ itp_batch = clean_queue(itp_batch)
230
+ its_batch = clean_queue(its_batch)
231
+ picks_batch = pool.map(partial(postprocessing_thread,
232
+ pred = pred_batch,
233
+ X = X_batch,
234
+ Y = Y_batch,
235
+ itp = itp_batch,
236
+ its = its_batch,
237
+ fname = fname_batch,
238
+ result_dir = result_dir,
239
+ figure_dir = figure_dir),
240
+ range(len(pred_batch)))
241
+ picks.extend(picks_batch)
242
+ itp.extend(itp_batch)
243
+ its.extend(its_batch)
244
+
245
+ flog.write("mean loss: {}\n".format(mean_loss))
246
+ metrics_p, metrics_s = calculate_metrics(picks, itp, its, tol=0.1)
247
+ flog.write("P-phase: Precision={}, Recall={}, F1={}\n".format(metrics_p[0], metrics_p[1], metrics_p[2]))
248
+ flog.write("S-phase: Precision={}, Recall={}, F1={}\n".format(metrics_s[0], metrics_s[1], metrics_s[2]))
249
+ flog.close()
250
+
251
+ return 0
252
+
253
+ def main(args):
254
+
255
+ logging.basicConfig(format='%(asctime)s %(message)s', level=logging.INFO)
256
+ coord = tf.train.Coordinator()
257
+
258
+ if (args.mode == "train") or (args.mode == "train_valid"):
259
+ with tf.compat.v1.name_scope('create_inputs'):
260
+ data_reader = DataReader(
261
+ data_dir=args.train_dir,
262
+ data_list=args.train_list,
263
+ mask_window=0.4,
264
+ queue_size=args.batch_size*3,
265
+ coord=coord)
266
+ if args.mode == "train_valid":
267
+ data_reader_valid = DataReader(
268
+ data_dir=args.valid_dir,
269
+ data_list=args.valid_list,
270
+ mask_window=0.4,
271
+ queue_size=args.batch_size*2,
272
+ coord=coord)
273
+ logging.info("Dataset size: train {}, valid {}".format(data_reader.num_data, data_reader_valid.num_data))
274
+ else:
275
+ data_reader_valid = None
276
+ logging.info("Dataset size: train {}".format(data_reader.num_data))
277
+ train_fn(args, data_reader, data_reader_valid)
278
+
279
+ elif args.mode == "test":
280
+ with tf.compat.v1.name_scope('create_inputs'):
281
+ data_reader = DataReader_test(
282
+ data_dir=args.test_dir,
283
+ data_list=args.test_list,
284
+ mask_window=0.4,
285
+ queue_size=args.batch_size*10,
286
+ coord=coord)
287
+ test_fn(args, data_reader)
288
+
289
+ else:
290
+ print("mode should be: train, train_valid, pred or debug")
291
+
292
+ return
293
+
294
+
295
+ if __name__ == '__main__':
296
+ args = read_args()
297
+ main(args)
phasenet/util.py ADDED
@@ -0,0 +1,203 @@
1
+ from __future__ import division
2
+ import matplotlib
3
+ matplotlib.use('agg')
4
+ import matplotlib.pyplot as plt
5
+ import numpy as np
6
+ import os
7
+ from data_reader import DataConfig
8
+ from detect_peaks import detect_peaks
9
+ import logging
10
+
11
+ def detect_peaks_thread(i, pred, fname=None, result_dir=None, args=None):
12
+ if args is None:
13
+ itp, prob_p = detect_peaks(pred[i,:,0,1], mph=0.5, mpd=0.5/DataConfig().dt, show=False)
14
+ its, prob_s = detect_peaks(pred[i,:,0,2], mph=0.5, mpd=0.5/DataConfig().dt, show=False)
15
+ else:
16
+ itp, prob_p = detect_peaks(pred[i,:,0,1], mph=args.tp_prob, mpd=0.5/DataConfig().dt, show=False)
17
+ its, prob_s = detect_peaks(pred[i,:,0,2], mph=args.ts_prob, mpd=0.5/DataConfig().dt, show=False)
18
+ if (fname is not None) and (result_dir is not None):
19
+ # np.savez(os.path.join(result_dir, fname[i].decode().split('/')[-1]), pred=pred[i], itp=itp, its=its, prob_p=prob_p, prob_s=prob_s)
20
+ try:
21
+ np.savez(os.path.join(result_dir, fname[i].decode()), pred=pred[i], itp=itp, its=its, prob_p=prob_p, prob_s=prob_s)
22
+ except FileNotFoundError:
23
+ #if not os.path.exists(os.path.dirname(os.path.join(result_dir, fname[i].decode()))):
24
+ os.makedirs(os.path.dirname(os.path.join(result_dir, fname[i].decode())), exist_ok=True)
25
+ np.savez(os.path.join(result_dir, fname[i].decode()), pred=pred[i], itp=itp, its=its, prob_p=prob_p, prob_s=prob_s)
26
+ return [(itp, prob_p), (its, prob_s)]
27
+
28
+ def plot_result_thread(i, pred, X, Y=None, itp=None, its=None,
29
+ itp_pred=None, its_pred=None, fname=None, figure_dir=None):
30
+ dt = DataConfig().dt
31
+ t = np.arange(0, pred.shape[1]) * dt
32
+ box = dict(boxstyle='round', facecolor='white', alpha=1)
33
+ text_loc = [0.05, 0.77]
34
+
35
+ plt.figure(i)
36
+ plt.clf()
37
+ # fig_size = plt.gcf().get_size_inches()
38
+ # plt.gcf().set_size_inches(fig_size*[1, 1.2])
39
+ plt.subplot(411)
40
+ plt.plot(t, X[i, :, 0, 0], 'k', label='E', linewidth=0.5)
41
+ plt.autoscale(enable=True, axis='x', tight=True)
42
+ tmp_min = np.min(X[i, :, 0, 0])
43
+ tmp_max = np.max(X[i, :, 0, 0])
44
+ if (itp is not None) and (its is not None):
45
+ for j in range(len(itp[i])):
46
+ if j == 0:
47
+ plt.plot([itp[i][j]*dt, itp[i][j]*dt], [tmp_min, tmp_max], 'b', label='P', linewidth=0.5)
48
+ else:
49
+ plt.plot([itp[i][j]*dt, itp[i][j]*dt], [tmp_min, tmp_max], 'b', linewidth=0.5)
50
+ for j in range(len(its[i])):
51
+ if j == 0:
52
+ plt.plot([its[i][j]*dt, its[i][j]*dt], [tmp_min, tmp_max], 'r', label='S', linewidth=0.5)
53
+ else:
54
+ plt.plot([its[i][j]*dt, its[i][j]*dt], [tmp_min, tmp_max], 'r', linewidth=0.5)
55
+ plt.ylabel('Amplitude')
56
+ plt.legend(loc='upper right', fontsize='small')
57
+ plt.gca().set_xticklabels([])
58
+ plt.text(text_loc[0], text_loc[1], '(i)', horizontalalignment='center',
59
+ transform=plt.gca().transAxes, fontsize="small", fontweight="normal", bbox=box)
60
+ plt.subplot(412)
61
+ plt.plot(t, X[i, :, 0, 1], 'k', label='N', linewidth=0.5)
62
+ plt.autoscale(enable=True, axis='x', tight=True)
63
+ tmp_min = np.min(X[i, :, 0, 1])
64
+ tmp_max = np.max(X[i, :, 0, 1])
65
+ if (itp is not None) and (its is not None):
66
+ for j in range(len(itp[i])):
67
+ plt.plot([itp[i][j]*dt, itp[i][j]*dt], [tmp_min, tmp_max], 'b', linewidth=0.5)
68
+ for j in range(len(its[i])):
69
+ plt.plot([its[i][j]*dt, its[i][j]*dt], [tmp_min, tmp_max], 'r', linewidth=0.5)
70
+ plt.ylabel('Amplitude')
71
+ plt.legend(loc='upper right', fontsize='small')
72
+ plt.gca().set_xticklabels([])
73
+ plt.text(text_loc[0], text_loc[1], '(ii)', horizontalalignment='center',
74
+ transform=plt.gca().transAxes, fontsize="small", fontweight="normal", bbox=box)
75
+ plt.subplot(413)
76
+ plt.plot(t, X[i, :, 0, 2], 'k', label='Z', linewidth=0.5)
77
+ plt.autoscale(enable=True, axis='x', tight=True)
78
+ tmp_min = np.min(X[i, :, 0, 2])
79
+ tmp_max = np.max(X[i, :, 0, 2])
80
+ if (itp is not None) and (its is not None):
81
+ for j in range(len(itp[i])):
82
+ plt.plot([itp[i][j]*dt, itp[i][j]*dt], [tmp_min, tmp_max], 'b', linewidth=0.5)
83
+ for j in range(len(its[i])):
84
+ plt.plot([its[i][j]*dt, its[i][j]*dt], [tmp_min, tmp_max], 'r', linewidth=0.5)
85
+ plt.ylabel('Amplitude')
86
+ plt.legend(loc='upper right', fontsize='small')
87
+ plt.gca().set_xticklabels([])
88
+ plt.text(text_loc[0], text_loc[1], '(iii)', horizontalalignment='center',
89
+ transform=plt.gca().transAxes, fontsize="small", fontweight="normal", bbox=box)
90
+ plt.subplot(414)
91
+ if Y is not None:
92
+ plt.plot(t, Y[i, :, 0, 1], 'b', label='P', linewidth=0.5)
93
+ plt.plot(t, Y[i, :, 0, 2], 'r', label='S', linewidth=0.5)
94
+ plt.plot(t, pred[i, :, 0, 1], '--g', label='$\hat{P}$', linewidth=0.5)
95
+ plt.plot(t, pred[i, :, 0, 2], '-.m', label='$\hat{S}$', linewidth=0.5)
96
+ plt.autoscale(enable=True, axis='x', tight=True)
97
+ if (itp_pred is not None) and (its_pred is not None):
98
+ for j in range(len(itp_pred)):
99
+ plt.plot([itp_pred[j]*dt, itp_pred[j]*dt], [-0.1, 1.1], '--g', linewidth=0.5)
100
+ for j in range(len(its_pred)):
101
+ plt.plot([its_pred[j]*dt, its_pred[j]*dt], [-0.1, 1.1], '-.m', linewidth=0.5)
102
+ plt.ylim([-0.05, 1.05])
103
+ plt.text(text_loc[0], text_loc[1], '(iv)', horizontalalignment='center',
104
+ transform=plt.gca().transAxes, fontsize="small", fontweight="normal", bbox=box)
105
+ plt.legend(loc='upper right', fontsize='small')
106
+ plt.xlabel('Time (s)')
107
+ plt.ylabel('Probability')
108
+
109
+ plt.tight_layout()
110
+ plt.gcf().align_labels()
111
+
112
+ try:
113
+ plt.savefig(os.path.join(figure_dir,
114
+ fname[i].decode().rstrip('.npz')+'.png'),
115
+ bbox_inches='tight')
116
+ except FileNotFoundError:
117
+ #if not os.path.exists(os.path.dirname(os.path.join(figure_dir, fname[i].decode()))):
118
+ os.makedirs(os.path.dirname(os.path.join(figure_dir, fname[i].decode())), exist_ok=True)
119
+ plt.savefig(os.path.join(figure_dir,
120
+ fname[i].decode().rstrip('.npz')+'.png'),
121
+ bbox_inches='tight')
122
+ #plt.savefig(os.path.join(figure_dir,
123
+ # fname[i].decode().split('/')[-1].rstrip('.npz')+'.png'),
124
+ # bbox_inches='tight')
125
+ # plt.savefig(os.path.join(figure_dir,
126
+ # fname[i].decode().split('/')[-1].rstrip('.npz')+'.pdf'),
127
+ # bbox_inches='tight')
128
+ plt.close(i)
129
+ return 0
130
+
131
+ def postprocessing_thread(i, pred, X, Y=None, itp=None, its=None, fname=None, result_dir=None, figure_dir=None, args=None):
132
+ (itp_pred, prob_p), (its_pred, prob_s) = detect_peaks_thread(i, pred, fname, result_dir, args)
133
+ if (fname is not None) and (figure_dir is not None):
134
+ plot_result_thread(i, pred, X, Y, itp, its, itp_pred, its_pred, fname, figure_dir)
135
+ return [(itp_pred, prob_p), (its_pred, prob_s)]
136
+
137
+
138
+ def clean_queue(picks):
139
+ clean = []
140
+ for i in range(len(picks)):
141
+ tmp = []
142
+ for j in picks[i]:
143
+ if j != 0:
144
+ tmp.append(j)
145
+ clean.append(tmp)
146
+ return clean
147
+
148
+ def clean_queue_thread(picks):
149
+ tmp = []
150
+ for j in picks:
151
+ if j != 0:
152
+ tmp.append(j)
153
+ return tmp
154
+
155
+
156
+ def metrics(TP, nP, nT):
157
+ '''
158
+ TP: true positive
159
+ nP: number of positive picks
160
+ nT: number of true picks
161
+ '''
162
+ precision = TP / nP
163
+ recall = TP / nT
164
+ F1 = 2* precision * recall / (precision + recall)
165
+ return [precision, recall, F1]
166
+
167
+ def correct_picks(picks, true_p, true_s, tol):
168
+ dt = DataConfig().dt
169
+ if len(true_p) != len(true_s):
170
+ print("The length of true P and S pickers are not the same")
171
+ num = len(true_p)
172
+ TP_p = 0; TP_s = 0; nP_p = 0; nP_s = 0; nT_p = 0; nT_s = 0
173
+ diff_p = []; diff_s = []
174
+ for i in range(num):
175
+ nT_p += len(true_p[i])
176
+ nT_s += len(true_s[i])
177
+ nP_p += len(picks[i][0][0])
178
+ nP_s += len(picks[i][1][0])
179
+
180
+ if len(true_p[i]) > 1 or len(true_s[i]) > 1:
181
+ print(i, picks[i], true_p[i], true_s[i])
182
+ tmp_p = np.array(picks[i][0][0]) - np.array(true_p[i])[:,np.newaxis]
183
+ tmp_s = np.array(picks[i][1][0]) - np.array(true_s[i])[:,np.newaxis]
184
+ TP_p += np.sum(np.abs(tmp_p) < tol/dt)
185
+ TP_s += np.sum(np.abs(tmp_s) < tol/dt)
186
+ diff_p.append(tmp_p[np.abs(tmp_p) < 0.5/dt])
187
+ diff_s.append(tmp_s[np.abs(tmp_s) < 0.5/dt])
188
+
189
+ return [TP_p, TP_s, nP_p, nP_s, nT_p, nT_s, diff_p, diff_s]
190
+
191
+ def calculate_metrics(picks, itp, its, tol=0.1):
192
+ TP_p, TP_s, nP_p, nP_s, nT_p, nT_s, diff_p, diff_s = correct_picks(picks, itp, its, tol)
193
+ precision_p, recall_p, f1_p = metrics(TP_p, nP_p, nT_p)
194
+ precision_s, recall_s, f1_s = metrics(TP_s, nP_s, nT_s)
195
+
196
+ logging.info("Total records: {}".format(len(picks)))
197
+ logging.info("P-phase:")
198
+ logging.info("True={}, Predict={}, TruePositive={}".format(nT_p, nP_p, TP_p))
199
+ logging.info("Precision={:.3f}, Recall={:.3f}, F1={:.3f}".format(precision_p, recall_p, f1_p))
200
+ logging.info("S-phase:")
201
+ logging.info("True={}, Predict={}, TruePositive={}".format(nT_s, nP_s, TP_s))
202
+ logging.info("Precision={:.3f}, Recall={:.3f}, F1={:.3f}".format(precision_s, recall_s, f1_s))
203
+ return [precision_p, recall_p, f1_p], [precision_s, recall_s, f1_s]