Skip to content

Add empirical calculations to intensity measures - #127

Open
lispandfound wants to merge 1 commit into
nzvm/bb-matched-filterfrom
empirical_ims
Open

Add empirical calculations to intensity measures#127
lispandfound wants to merge 1 commit into
nzvm/bb-matched-filterfrom
empirical_ims

Conversation

@lispandfound

@lispandfound lispandfound commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Adds empirical calculations to intensity measure outputs where empirical models support a given tectonic type and intensity measure.

To support this structure, I have also refactored im calc so that it finally outputs in xarray data tree format instead of dataset format. The upshot of doing this is that we can uncouple the components so that each intensity measure carries only components it actually computes. Especially for models like NSHM2022 that only support pSA it's kind of silly to have every intensity measure carry all-NaN EAS and empirical model components.

Copilot AI review requested due to automatic review settings July 21, 2026 04:30

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces the capability to calculate empirical intensity measures from ground motion models using OpenQuake wrappers. It updates dependencies, default parameters, and schemas, and adds helper methods to average multi-fault parameters (rakes, magnitudes) weighted by fault moment. The im_calc.py script is refactored to calculate source-to-site distances, site parameters, and empirical IMs, outputting the results as an xr.DataTree in NetCDF format. The review feedback highlights critical issues where running the script with empirical=False or with broadband data lacking vs30 coordinates will result in NameError or AttributeError exceptions.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread workflow/scripts/im_calc.py
Comment thread workflow/scripts/im_calc.py Outdated
Comment thread workflow/scripts/im_calc.py Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Refactors intensity-measure (IM) calculation output to an xarray.DataTree netCDF structure and adds optional empirical (GMM-based) IM calculations driven by per-realisation configuration (tectonic type + model list), carrying through per-station parameters like Vs30 and derived basin depths.

Changes:

  • Refactor im-calc output from a single xarray.Dataset to a structured xarray.DataTree, with per-IM datasets and shared station/source metadata.
  • Add empirical IM calculation via oq_wrapper for supported IMs/tectonic types and store results under {im}/empirical/{model}.
  • Add vs30 to broadband waveform outputs and introduce realisation/schema/default support for empirical configuration.

Reviewed changes

Copilot reviewed 6 out of 7 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
workflow/scripts/im_calc.py Major refactor to DataTree output; adds empirical GMM evaluation and metadata/unit annotation.
workflow/scripts/bb_sim.py Adds vs30 coordinate to broadband netCDF output for downstream site parameter usage.
workflow/schemas.py Adds EMPIRICAL_PARAMETERS schema for validating empirical config in realisations/defaults.
workflow/realisations.py Adds moment-weighted averaging helpers and EmpiricalParameters realisation configuration.
workflow/default_parameters/root/defaults.yaml Introduces default empirical configuration (active_shallow + NSHM2022).
uv.lock Lockfile change related to dependency resolution (cffi/pycparser marker).
pyproject.toml Adds netCDF4 dependency to enforce safe import order vs OpenQuake/HDF5 stack.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread workflow/scripts/im_calc.py
Comment thread workflow/scripts/im_calc.py
Comment thread workflow/scripts/im_calc.py Outdated
Comment thread workflow/scripts/im_calc.py

Ground motion models describe a rupture with a single magnitude, rake,
dip and depth. Multi-fault realisations are collapsed into these by
averaging each fault's contribution, weighted by its moment.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on what we have done before for empirical results for multi fault events we averaged based on the area of the fault not the moment. There was a few discussions regarding what to use and we landed on using area, however could be open to reconsider this adjustment if there has been a new development for this.

https://github.com/ucgmsim/Empirical_Engine/blob/1d39ae9d620767969f71b63748bbac9eea4e18d6/oq_wrapper/estimations.py#L67

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah didn't see this, I will change the calculation to use that averaging.

The site parameters, with basin depths estimated using the Chiou
and Youngs (2008) relations.
"""
z1pt0 = chiou_young_08_calc_z1p0(vs30) # ty: ignore[invalid-argument-type]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to estimate for all of the sites? Wondering if we have any "real sites" in this where we have a better measured / estimate value of z1.0 / 2.5 etc to use those instead from the site database.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah this is a stand-in at the moment, I intend to replace this with actual site database values at a later date.

@lispandfound
lispandfound changed the base branch from pegasus to nzvm/bb-matched-filter August 31, 2026 09:09

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please change the following dependencies for consistency.

Comment thread pyproject.toml
@@ -14,12 +14,13 @@ dependencies = [
"im-calculation @ git+https://github.com/ucgmsim/IM_calculation@no_parallel",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"im-calculation @ git+https://github.com/ucgmsim/IM_calculation@no_parallel",
"im-calculation @ git+https://github.com/ucgmsim/IM_calculation.git@no_parallel",

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please change the following dependencies for consistency.

Comment thread pyproject.toml
@@ -14,12 +14,13 @@ dependencies = [
"im-calculation @ git+https://github.com/ucgmsim/IM_calculation@no_parallel",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"im-calculation @ git+https://github.com/ucgmsim/IM_calculation@no_parallel",
"im-calculation @ git+https://github.com/ucgmsim/IM_calculation.git@no_parallel",

`im-calc` now also evaluates the ground motion models named in the
realisation, writing them alongside the simulated measures at
`{im}/empirical/{model}` in the same data tree. Having both in one file
is the point: comparing a simulation against a GMM should not require
joining two files on station and period.

A multi-fault realisation has to be reduced to the single rupture a GMM
describes -- one magnitude, rake, dip, ztor, zbot -- which
`calculate_source_parameters` does by moment-weighted averaging, with
rakes and dips averaged as unit vectors rather than as angles. Site
parameters come from vs30 via the Chiou & Young z1pt0/z2pt5
estimators, and the distances are the ones already computed for the
simulated measures, so both sides see identical geometry.

Combinations a model does not support are skipped with a warning rather
than failing the run -- the NSHM2022 logic tree configures pSA but not
PGA or PGV, and that is not an error.

Two deliberate awkwardnesses:

`netCDF4` is imported before anything that pulls in OpenQuake. OpenQuake
brings h5py, which is linked against a different HDF5 build than netCDF4
is, and whichever loads second cannot open our waveform files. The
import order is load bearing, not stylistic.

`EmpiricalParameters` types its fields as `Any` and its schema validates
plain strings rather than `oq_wrapper.constants` enum members. Importing
that module pulls in OpenQuake, which is expensive and must be
precompiled; the strings are resolved to enum members inside the
calculation instead, so `workflow.realisations` stays cheap to import.

vs30 is loaded eagerly rather than left as a dask array -- it is one
float per station, and letting it stay lazy propagates dask into every
station coordinate.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants