PhaseNet Documentation

repository·main·Indexed 18 days ago

https://github.com/ai4eps/phasenet

PhaseNet is a deep-learning-based method for seismic arrival time picking (P and S wave detection). It supports batch prediction on various seismic data formats including mseed, sac, hdf5, numpy, and mseed_array. The toolset includes scripts for training from pre-trained models, a CLI for batch processing via predict.py, and API endpoints for predictions and probability time series.

Tokens
5.9K
Snippets
18
Records
21
Agent score
64%

What's inside PhaseNet

  1. Understand the prediction output format

    main

    Prediction results are saved to results/picks.csv by default. The output is a CSV containing the following fields:

    • file_name: The name of the source file.
    • begin_time: The start time of the seismic trace.
    • station_id: The identifier for the seismic station.
    • phase_index: The index of the pick within the original sequence. Note that phase_time = begin_time + phase_index / sampling_rate (default sampling rate is 100Hz).
    • phase_time: The timestamp of the detected phase.
    • phase_score: The confidence score of the pick.
    • phase_amp: The amplitude of the phase.
    • phase_type: The type of phase detected (e.g., P or S).
  2. Train PhaseNet from a pre-trained model

    main

    To train PhaseNet, you can start from an existing checkpoint. First, download the test data to practice training:

    wget https://github.com/wayneweiqiang/PhaseNet/releases/download/test_data/test_data.zip
    unzip test_data.zip

    Run the training script using phasenet/train.py. Results and logs are stored in the log folder.

    python phasenet/train.py --model_dir=model/190703-214543/ --train_dir=test_data/npz --train_list=test_data/npz.csv --plot_figure --epochs=10 --batch_size=10
  3. Install PhaseNet using Conda

    main

    PhaseNet requires Miniconda. You can install it either into your default environment or a dedicated virtual environment. For Mac users with ARM chips, use the env_mac.yaml file.

    Clone the repository

    git clone https://github.com/wayneweiqiang/PhaseNet.git
    cd PhaseNet

    Option 1: Install to default environment

    conda env update -f=env.yaml -n base
    conda env create -f env.yaml
    conda activate phasenet

    Option 3: For Mac ARM chips

    conda env create -f env_mac.yaml
    conda activate phasenet
    git clone https://github.com/wayneweiqiang/PhaseNet.git
    cd PhaseNet
    conda env create -f env.yaml
    conda activate phasenet
  4. Perform batch seismic arrival time picking

    main

    Use phasenet/predict.py to run batch predictions on seismic data. PhaseNet supports several formats: mseed, sac, hdf5, numpy, and mseed_array (for seismic arrays used by QuakeFlow).

    Important Usage Notes:

    • Batch Size: If using mseed or sac formats, it is recommended to use --batch_size=1 because files often have varying lengths. To use a larger batch size for speed, you must pre-cut the data to a uniform length.
    • Performance: Remove the --plot_figure argument when processing large datasets to avoid significant slowdowns.
    • Pre-trained Model: The default pre-trained model is located in model/190703-214543.
    # Example for mseed format
    python phasenet/predict.py --model=model/190703-214543 --data_list=test_data/mseed.csv --data_dir=test_data/mseed --format=mseed --amplitude --response_xml=test_data/stations.xml --batch_size=1 --sampling_rate=100
    
    # Example for sac format
    python phasenet/predict.py --model=model/190703-214543 --data_list=test_data/sac.csv --data_dir=test_data/sac --format=sac --batch_size=1
    
    # Example for hdf5 format
    python phasenet/predict.py --model=model/190703-214543 --hdf5_file=test_data/data.h5 --hdf5_group=data --format=hdf5
  5. How PhaseNet preprocesses and normalizes seismic data

    main

    PhaseNet uses a specific normalization pipeline to prepare raw waveforms for the UNet model:

    1. Padding: Data is padded using reflect mode with a window size (default 3000) to handle edge effects.
    2. Sliding Window Statistics: It calculates the mean and std (standard deviation) using a sliding window across the time axis.
    3. Interpolation: Because window statistics are calculated at discrete intervals, scipy.interpolate.interp1d with slinear (linear interpolation) is used to create continuous mean_interp and std_interp arrays matching the original data length.
    4. Normalization: The final data is transformed using: (data - mean_interp) / std_interp.

    This ensures the model receives zero-mean, unit-variance data that is consistent across different seismic noise levels.

  6. Understand the output pick format

    main

    By default, PhaseNet saves picks to results/picks.csv. The output contains the following fields:

    • file_name: The name of the source file.
    • begin_time: The start time of the data segment.
    • station_id: The identifier for the seismic station.
    • phase_index: The index of the pick in the original sequence. Note that phase_time can be calculated as: phase_time = begin_time + (phase_index / sampling_rate). The default sampling rate is 100Hz.
    • phase_time: The timestamp of the detected phase.
    • phase_score: The confidence score of the pick.
    • phase_amp: The amplitude at the pick time.
    • phase_type: The type of phase detected (P or S).
  7. Prepare a filename list for PhaseNet

    main

    PhaseNet requires a CSV file (e.g., fname.csv) to map MiniSEED files to their respective seismic channels. The CSV must include a header fname,E,N,Z where:

    • fname: The name of the MiniSEED file.
    • E: The East component channel name.
    • N: The North component channel name.
    • Z: The Vertical component channel name.
    with open("fname.csv", 'w') as fp:
      fp.write("fname,E,N,Z\n")
      fp.write("CCC.mseed,HHE,HHN,HHZ\n")
      fp.write("CLC.mseed,HHE,HHN,HHZ\n")
  8. Prepare 3-component seismic waveforms for PhaseNet

    main

    To use PhaseNet via the Gradio client, you must prepare your seismic data as a 3-component array. This involves reading seismic data (e.g., using ObsPy), ensuring you have exactly three traces, and transposing the data into a shape where the last dimension represents the three components. You also need to extract a unique data_id and a formatted timestamp from the stream metadata.

    Steps:

    1. Load and sort the stream to ensure component consistency.
    2. Extract trace data into a NumPy array.
    3. Transpose the array so the shape is (samples, 3).
    4. Extract the data_id from the first trace's ID and the starttime as an ISO-formatted string.
    import obspy
    import numpy as np
    
    # Load and sort stream
    stream = obspy.read("data.mseed")
    stream = stream.sort()
    assert(len(stream) == 3)
    
    # Extract 3-component data
    data = []
    for trace in stream:
        data.append(trace.data)
    data = np.array(data).T
    assert(data.shape[-1] == 3)
    
    # Metadata extraction
    data_id = stream[0].get_id()[:-1]
    timestamp = stream[0].stats.starttime.datetime.strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3]
  9. Download seismic data using ObsPy

    main

    To use PhaseNet with real seismic data, you can use the obspy library to fetch waveforms from FDSN web services (e.g., SCEDC). You define a time range using UTCDateTime and fetch specific channels (e.g., HHE,HHN,HHZ). The retrieved waveforms can then be saved as MiniSEED files using the .write() method.

    import os
    import obspy
    from obspy import UTCDateTime
    from obspy.clients.fdsn import Client
    
    client = Client("SCEDC")
    data_dir = "mseed"
    if not os.path.exists(data_dir):
      os.makedirs(data_dir)
    
    starttime = UTCDateTime("2019-07-04T17:00:00")
    endtime = UTCDateTime("2019-07-05T00:00:00")
    
    # Fetch waveforms
    CCC = client.get_waveforms("CI", "CCC", "*", "HHE,HHN,HHZ", starttime, endtime)
    
    # Save to MiniSEED
    CCC.write(os.path.join(data_dir, "CCC.mseed"))
  10. Run batch prediction with PhaseNet

    main

    Use the phasenet/predict.py script to perform seismic arrival time picking on datasets. PhaseNet supports several input formats including mseed, sac, numpy, hdf5, and mseed_array (for seismic arrays used by QuakeFlow).

    Important Note: For large datasets, remove the --plot_figure argument to avoid significant performance slowdowns caused by plotting.

    # Example for mseed format
    python phasenet/predict.py --model=model/190703-214543 --data_list=test_data/mseed.csv --data_dir=test_data/mseed --format=mseed --plot_figure
    
    # Example for hdf5 format
    python phasenet/predict.py --model=model/190703-214543 --hdf5_file=test_data/data.h5 --hdf5_group=data --format=hdf5 --plot_figure
    
    # Example for a seismic array (QuakeFlow style)
    python phasenet/predict.py --model=model/190703-214543 --data_list=test_data/mseed_array.csv --data_dir=test_data/mseed_array --stations=test_data/stations.json --format=mseed_array --amplitude
  11. Read P/S picks from CSV or JSON

    main

    PhaseNet outputs results in both CSV and JSON formats. You can use pandas to read the CSV output or the standard json library for the JSON output.

    When reading the CSV, note that certain columns like p_idx, p_prob, s_idx, and s_prob may require string cleaning (stripping brackets and splitting by commas) depending on how they were serialized.

    import pandas as pd
    import json
    import os
    
    # Reading CSV
    picks_csv = pd.read_csv("results/picks.csv", sep="\t")
    picks_csv.loc[:, 'p_idx'] = picks_csv["p_idx"].apply(lambda x: x.strip("[]").split(","))
    # ... repeat for other index/prob columns
    
    # Reading JSON
    with open("results/picks.json") as fp:
        picks_json = json.load(fp)
  12. Visualize seismic waveforms and phase picks

    main

    After obtaining picks from PhaseNet, you can visualize them overlaid on the original seismic traces using Matplotlib.

    Common visualization logic:

    • Iterate through each trace in the stream.
    • Plot the waveform data.
    • For each pick in the DataFrame, draw a vertical line (axvline) at the relative time offset from the trace start time.
    • Use color coding: blue for 'P' phases and red for 'S' phases.
    • Use the phase_score to control the transparency (alpha) of the pick line.
    import matplotlib.pyplot as plt
    
    fig, ax = plt.subplots(len(stream), 1, figsize=(10, 10))
    for i, tr in enumerate(stream):
        ax[i].plot(tr.times(), tr.data, label=tr.stats.channel, c="k")
        for _, pick in picks.iterrows():
            # Color: Blue for P, Red for S
            c = "blue" if pick["phase_type"] == "P" else "red"
            label = pick["phase_type"] if i == 0 else None
            
            # Calculate relative time offset
    time_offset = (pick["phase_time"] - tr.stats.starttime.datetime).total_seconds()
            ax[i].axvline(time_offset, c=c, label=label, alpha=pick["phase_score"])
        ax[i].legend()
    plt.show()