Grond

The practical side

https://data.pyrocko.org/scratch/grond-presentation/

How to perform a

  • probabilistic ➞ bootstrap
  • centroid ➞ non-linear
  • moment tensor ➞ full / deviatoric / DC
  • optimisation ➞ BABO
  • from broadband seismograms ➞ surface waves

Requisites

Grond is incredibly flexible. Here we need:

  • Seismic waveforms ➞ Continuous Mini-SEED data
  • Station meta-data ➞ FDSN Station-XML
  • Preliminary event origin ➞ Pyrocko basic event file
  • Green's functions ➞ Pyrocko GF Store
  • Grond configuration files ➞ YAML format

Project directory layout


itc-seis-dataset-2023/
├── bin/                  # Downloading scripts to retrieve data and metadate
├── config/               # Grond configuration files
├── data/                 # Seismic waveforms and meta-data
│        └── events/
│                ├── 2023-02-07T154852/
│                │                └── waveforms/
│                │                └── event.txt    # catalog file
│                └── 2020-02-10T170049/
└── gf_stores/            # Green's functions
        └── crust2_pb/
                    

Looking at the data


$ cd ~/itc-seis-dataset-2023
$ snuffler \
     data/events/2023-02-07T154852/waveforms/prepared \
  --stations \
     data/events/2023-02-07T154852/waveforms/ \
     stations.prepared.txt \
  --events \
     data/events/2023-02-07T154852/event.txt
                    

This command line is long ...

➞ Let's create a script!

Create a new shell script:


$ touch bin/look.sh       # create file
$ chmod a+x bin/look.sh   # make it executable
$ gedit bin/look.sh    # open in editor
                    

Enter/copy script code:


#!/bin/bash
snuffler "$1/waveforms/prepared" \
  --stations "$1/waveforms/stations.prepared.txt" \
  --events "$1/event.txt"
                    

Use it:


$ bin/look.sh data/events/2023-02-07T154852   # Turkiye 02/07
$ bin/look.sh data/events/2023-02-10T170049   # Turkiye 02/10
                    

Visual data quality control (QC)

Aftershock of the Turkiye 2023 earthquake doublet

QC: Things to look for

  • Gaps
  • Data artifacts
  • Clipped traces
  • Incorrect gain factors
  • Noise patterns
  • Multi-events
  • Correct origin?
  • Usable frequency band?

Manual modelling

with the Seismosizer Snuffling

  • Open earthquake dataset with displacement (prepared)
  • Make the selected event the active event (press e key)
  • Filter to 0.02 - 0.08 Hz
  • Select station subset
    :s sari kmrs bnn dare gaz gula yoz urfa rsdy kamt
  • Get the Seismosizer: DCSource (builtin) panel
  • Use Add Stores and add the crust2_pb GFs
  • Sort by distance
  • Select Common scale per station
  • Select Subsort ... (Grouped by Location)
  • Play with the point source parameters...

Configuring Grond

Get example configuration


$ cd ~/itc-seis-dataset-2023
$ cd config
$ gedit regional_cmt_smaller2.gronf
                    

A walk through the configuration


%YAML 1.1
# Example: Inversion of W-Phase from teleseismic observations.
--- !grond.Config

# All file paths referenced below are treated relative to the location of this
# configuration file, here we may give a common prefix. E.g. setting it to '..'
# if the configuration file is in the sub-directory '${project_root}/config'
# allows us to give the paths below relative to '${project_root}'.
path_prefix: '..'

# Path, where to store output (run directories). The placeholder
# '${problem_name}' will be expanded to a name configured below in
# problem_config.name_template and will typically include a config identifier
# and the event name.
rundir_template: 'runs/${problem_name}.grun'

# If given, restrict to processing of listed events
#event_names:
#- 'gfz2015sfdd'


# -----------------------------------------------------------------------------
# Configuration section for dataset (input data)
#
# The placeholder '${event_name}' will be expanded to the current event. This
# enables us to use the same configuration for multiple events. The available 
# events are detected by looking into possible expansions of
# dataset_config.events_path
# -----------------------------------------------------------------------------

dataset_config: !grond.DatasetConfig
  # List of files with station coordinates.
  events_path: 'data/events/${event_name}/event.txt' 
  
  stations_stationxml_paths: 
  - 'data/events/${event_name}/waveforms/stations.koeri.0.xml'                  
  - 'data/events/${event_name}/waveforms/stations.koeri.1.xml'                  

  # List of directories with raw waveform data
  waveform_paths: ['data/events/${event_name}/waveforms/raw']

  # List of stations/components to be excluded according to their STA, NET.STA,
  # NET.STA.LOC, or NET.STA.2LOC.CHA codes
  blacklist: []

  # List of files with additional exclusion lists (one entry per line, same 
  # format as above)'
  responses_stationxml_paths:
  - 'data/events/${event_name}/waveforms/stations.koeri.0.xml'                  
  - 'data/events/${event_name}/waveforms/stations.koeri.1.xml'                  

# Apply correction factors from station corrections.                          
  apply_correction_factors: false                                               
                                                                                
  # Extend incomplete seismic traces                                            
  extend_incomplete: true  
                                                 
# -----------------------------------------------------------------------------
# Configuration section for the observational data fitting
#
# This defines the objective function to be minimized in the optimisation. It
# can be composed of one or more contributions, each represented by a
# !grond.*TargetGroup section.
# -----------------------------------------------------------------------------

target_groups:
- !grond.WaveformTargetGroup

  # Normalisation family (see the Grond documentation for how it works).
  # Use distinct normalisation families when mixing misfit contributors with
  # different magnitude scaling, like e.g. cross-correlation based misfit and 
  # time-domain Lx norm.
  normalisation_family: 'td'

  # Just a name used to identfy targets from this group. Use dot-separated path
  # notation to group related contributors
  path: 'td.full'

  # Epicentral distance range of stations to be considered in meter
  distance_min: 100e3
  distance_max: 250e3

  # Names of components to be included. Available: N=north, E=east, Z=vertical
  # (up), R=radial (away), T=transverse (right)
  channels: ['Z', 'T']

  # How to weight contributions from this group in the global misfit
  weight: 1.0

  # subsection on how to fit the traces
  misfit_config: !grond.WaveformMisfitConfig

    # Frequency band [Hz] of acausal filter (flat part of frequency taper)
    fmin: 0.025
    fmax: 0.075

    # Factor defining fall-off of frequency taper (zero at fmin/ffactor and
    # fmax*ffactor)
    ffactor: 1.5

    # Time window to include in the data fitting. Times can be defined offset
    # to given phase arrivals. E.g. '{stored:P}-600' would mean 600 s
    # before arrival of the phase named 'P'. The phase must be defined in the
    # travel time tables in the GF store.
    tmin: '{stored:any_P}'
    tmax: '{vel_surface:2.5}'
    # tfade: 120.0

    # How to fit the data (available: 'time_domain', 'frequency_domain',
    # 'log_frequency_domain', 'absolute', 'envelope', 'cc_max_norm')
    domain: 'time_domain'

    # If non-zero, allow synthetic and observed traces to be shifted
    # against each other by up to +/- the given value [s].
    tautoshift_max: 1.0

    # If non-zero, a penalty misfit is added for non-zero shift values.
    # The penalty value is computed as
    # autoshift_penalty_max * normalization_factor * tautoshift**2 / tautoshift_max**2
    autoshift_penalty_max: 0.05
    
    # For L1 norm: 1, L2 norm: 2, etc.
    norm_exponent: 1

  # How to interpolate the Green's functions (available choices:
  # 'nearest_neighbor', 'multilinear'). Choices other than 'nearest_neighbor'
  # may require dense GF stores to avoid aliasing artifacts in the forward 
  # modelling.
  interpolation: 'nearest_neighbor'

  # Name of the GF Store to use
  store_id: 'crust2_pb'

  # limit number of targets to N, keeping a good coverage
  # limit: 40
  

# -----------------------------------------------------------------------------
# Definition of the problem to be solved
#
# In this section the source model to be fitted is chosen, the parameter space
# defined, and how to combine the misfit contributions defined in the
# target_groups section above.
# 
# The marker !grond.CMTProblemConfig selects a centroid moment tensor source
# model. 
# -----------------------------------------------------------------------------
problem_config: !grond.CMTProblemConfig

  # Name used to identify the output
  name_template: 'cmt_${event_name}_full_onlyZT'

  # Definition of model parameter space to be searched in the optimisation
  ranges:
    # Time relative to hypocenter origin time [s]
    time: '-5 .. 15 | add'

    # Centroid location with respect to hypocenter origin [m]
    north_shift: '-20e3 .. 20e3'
    east_shift: '-20e3 .. 20e3'
    depth: '1e3 .. 20e3'

    # Range of magnitudes to allow
    magnitude: '3.7 .. 6.5'

    # Relative moment tensor component ranges (don't touch)
    rmnn: '-1.41421 .. 1.41421'
    rmee: '-1.41421 .. 1.41421'
    rmdd: '-1.41421 .. 1.41421'
    rmne: '-1 .. 1'
    rmnd: '-1 .. 1'
    rmed: '-1 .. 1'

    # Source duration range [s]
    duration: '1. .. 10.'

  # Clearance distance around stations (no models with origin closer than this
  # distance to any station are produced by the sampler)
  distance_min: 1e3

  # Type of moment tensor to restrict to (choices: 'full', 'deviatoric', 'dc')
  mt_type: 'full'

  # How to combine the target misfits. For L1 norm: 1, L2 norm: 2, etc.
  norm_exponent: 1


# -----------------------------------------------------------------------------
# Configuration of pre-optimisation analysis phases. 
# determined during this phase.
# -----------------------------------------------------------------------------
#
analyser_configs:

# Balancing weights are determined with this analyser
- !grond.TargetBalancingAnalyserConfig

  # Number of models to forward model in the analysis, larger number -> better
  # statistics)
  niterations: 1000

#- !grond.NoiseAnalyserConfig
#  pre_event_noise_duration: 200.
#  phase_def: '{stored:any_P}'
#  statistic: 'std'
#  mode: 'weeding'
#  cutoff: 2.0
#  cutoff_exception_on_high_snr: 3.0


# -----------------------------------------------------------------------------
# Configuration of the optimisation procedure
# -----------------------------------------------------------------------------
optimiser_config: !grond.HighScoreOptimiserConfig

  # Number of bootstrap realisations to be tracked simultaneously in the
  # optimisation
  nbootstrap: 100

  # stages of the sampler. Start with uniform sampling of the model space
  # (!grond.UniformSamplerPhase), then narrow down to the interesting regions
  # (!grond.DirectedSamplerPhase).
  sampler_phases:

  - !grond.UniformSamplerPhase
      # Number of iterations
      niterations: 1000

  - !grond.DirectedSamplerPhase
      # Number of iterations
      niterations: 15000

      # Multiplicator for width of sampler distribution at start of this phase
      scatter_scale_begin: 2.0

      # Multiplicator for width of sampler distribution at end of this phase
      scatter_scale_end: 0.8


# -----------------------------------------------------------------------------
# Configuration section for synthetic seismogram engine
#
# Configures where to look for GF stores.
# -----------------------------------------------------------------------------

engine_config: !grond.EngineConfig

  # Whether to use GF store directories listed in ~/.pyrocko/config.pf
  gf_stores_from_pyrocko_config: false

  # List of directories with GF stores
  gf_store_superdirs: ['gf_stores']

                    

Preflight checks


$ grond check config/regional_cmt_smaller2.gronf \
    2023-02-07T154852
                    

Run optimization


$ grond go config/regional_cmt_smaller2.gronf \
    2023-02-07T154852
                    

Create report


$ grond report \
    runs/cmt_2023-02-07T154852_full_onlyZT.grun
                    

Understanding the optimizer

Single chain

Global + 3 bootstrap chains

Illposed, no eccentricity correction

Illposed, eccentricity correction applied

Bimodal, standard deviation from high score models

Bimodal, standard deviation from median density

Grond reports

Test reports