Repository navigation
Rewrite bb-sim on dask and switch to the site-calculation models - #130
Conversation
|
Caution The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased. |
There was a problem hiding this comment.
Pull request overview
Updates the broadband simulation pipeline to use the BA2018 + CB2014 site amplification models from the site-calculation package, while refactoring bb-sim to operate lazily with dask/xarray for lower memory usage and adding metadata to outputs.
Changes:
- Refactors broadband merging to dask/xarray, including station-chunked processing and per-chunk site amplification + filtering.
- Adds signal resampling to handle LF/HF mismatched sample rates and embeds Vs30 + site amp parameters in output metadata.
- Introduces
SiteAmpModelenum and extends broadband parameter schemas/defaults to support BA2018/CB2014 selection.
Reviewed changes
Copilot reviewed 9 out of 10 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| workflow/scripts/bb_sim.py | Reworks broadband merge to dask/xarray, adds resampling/alignment, and applies BA2018/CB2014 amplification from site-calculation. |
| workflow/schemas.py | Adds SiteAmpModel and tightens broadband parameter validation (including new taper params). |
| workflow/realisations.py | Updates BroadbandParameters dataclass to include fhightop, fmax, and typed site_amp_version. |
| workflow/default_parameters/v24_2_2_4/defaults.yaml | Removes per-version bb defaults (now inherited from root). |
| workflow/default_parameters/v24_2_2_2/defaults.yaml | Removes per-version bb defaults (now inherited from root). |
| workflow/default_parameters/v24_2_2_1/defaults.yaml | Removes per-version bb defaults (now inherited from root). |
| workflow/default_parameters/root/defaults.yaml | Adds/updates broadband defaults including BA2018 model selection and taper frequencies. |
| uv.lock | Adds site-calculation and updates lock entries accordingly. |
| pyproject.toml | Declares dependency on site-calculation>=2026.7.1. |
| tests/test_realisation.py | Updates broadband parameter serialization test for new fields and enum. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
884767f to
cd47e92
Compare
10b1ffb to
df1f207
Compare
df1f207 to
3ea7ac6
Compare
3ea7ac6 to
d31d016
Compare
d31d016 to
cf2ea99
Compare
720c102 to
fcd361b
Compare
fcd361b to
17d8dd1
Compare
17d8dd1 to
35b6ec2
Compare
35b6ec2 to
0dcef94
Compare
5b9721a to
9441be5
Compare
4d4f0d7 to
b874fa5
Compare
b874fa5 to
37ba1cc
Compare
b27b715 to
ef58053
Compare
ef58053 to
e34c32c
Compare
lispandfound
left a comment
There was a problem hiding this comment.
Code review by Claude Code (run locally, since the review action is currently broken). 10 finding(s).
Two changes to the same function body, which is why they are one commit. **Larger than memory.** `bb-sim` read both waveform files entirely into memory and looped over the three components in Python. Now LF and HF are opened lazily, the common stations are selected on the *backend* arrays before chunking -- selecting after chunking makes station reordering an all-to-all dask shuffle, which materialises the whole array -- and the recombination runs per chunk under `map_blocks`. Chunking is over stations only, so each chunk holds complete traces for resampling, alignment and filtering. `resample_signal` and `align_datasets` replace the old pad-and-align: the two legs no longer have to share a timestep, so an SW4 LF run at one dt can be combined with HF at another. `relabel_hf_components` maps HF's 090/000/ver onto LF's x/y/z once, up front. **Site amplification.** Replaces `qcore.siteamp_models.cb_amp_multi` with the `site-calculation` models, selected by `bb.site_amp_version`: CB2014 as before, or BA2018. The amplification is now constrained to an explicit [fmin, fmax] band with logarithmic tapers at both ends, which is what the two new `fhightop` and `fmax` parameters are for -- the old code had a lowpass taper only. `site_amp_version` becomes an enum rather than a free string. It was previously declared, defaulted to "2014", and read by nothing at all. The shared broadband parameters move from each defaults version into root; the versions now carry only `flo`, which is the one value that genuinely differs between them. Station-dimension coordinates -- `supergrid_depth` among them -- ride through `map_blocks` untouched, which is why the supergrid penetration is carried as a coordinate rather than a data variable. This changes broadband results: different site amplification model, and a highpass taper where there was none. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
lf-to-xarray now writes supergrid_width(_gp) rather than SW4's SGWIDTH(GP), so bb-sim was silently dropping the width. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The site amplification models only accept float64, so a float32 vref in the HF file would fail inside the first chunk. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This reverts commit 6715e32.
lispandfound
left a comment
There was a problem hiding this comment.
Review of 8e1b574b. One finding is outside this PR's diff, so it is here rather than inline:
cylc/flow.cylc:60: the cylc workflow still calls bb-sim with the old 8-positional-argument form (stations.ll, the OutBin directory, Velocity_Model, ...), while bb-sim now takes 5 and expects an LF file.
Failure scenario: running the cylc flow passes extra, wrongly typed positional arguments (a directory for LOW_FREQUENCY_WAVEFORM_FILE, which is dir_okay=False), so typer rejects the call and the broadband task fails.
| # Chunk over stations only, so every chunk holds complete time | ||
| # series for resampling, alignment and filtering. | ||
| nt = max(len(lf["time"]), len(hf["time"])) | ||
| n_stations = max(1, TARGET_CHUNK_BYTES // (3 * nt * np.float64().itemsize)) |
There was a problem hiding this comment.
The station chunk size is computed from the time lengths before resampling and alignment, so after resampling a chunk can hold several times TARGET_CHUNK_BYTES.
Failure scenario: An SW4 1 Hz LF at dt=0.02 that runs longer than a dt=0.005 HF: nt is max(lf_nt, hf_nt), but the resampled, aligned axis is about 4 * lf_nt. Each chunk is then up to 4x the 256 MiB target before the float64 amplification and FFT intermediates, which risks running out of memory on cluster nodes. If this moves after alignment, vs30 still has to be chunked to match the LF/HF station chunks or map_blocks rejects it.
There was a problem hiding this comment.
I've decided to leave this as-is. Will address at a later point, but I haven't noticed this becoming an issue in our runs.
|
|
||
| resampled_waveform = xr.apply_ufunc( | ||
| sp.signal.resample, | ||
| _taper_tail(dset["waveform"]), |
There was a problem hiding this comment.
_resample_signal tapers the tail of whichever dataset it resamples, so the last 5% of the LF waveform is tapered only when the LF dt differs from the HF dt.
Failure scenario: A 1 Hz SW4 run (LF dt=0.02, HF dt=0.005) has its final 5% of LF motion faded by a Hanning window in the broadband output, while the same simulation with matching dt keeps the untapered LF. The broadband output then depends on the solver's output dt, not just the physics.
There was a problem hiding this comment.
I think this is acceptable given that the broadband will have to resample in the first case so it is already dependent on solver dt. There is no way around that with the way SW4 has a variable dt.
| fft_freqs = np.fft.rfftfreq(n_fft, dt) | ||
|
|
||
| # The amplification models require float64 inputs. | ||
| amp = amp_model_fn( |
There was a problem hiding this comment.
The site_calculation amplification models raise ValueError if any single vs30 or vs30_sim value is <= 0, while NaN values are not rejected and spread silently into the waveforms.
Failure scenario: One station with a 0 or -1 sentinel Vs30 in the vs30 file aborts the whole broadband job; the old qcore cb_amp_multi path did not validate. A NaN Vs30 passes and produces an all-NaN broadband waveform for that station with no warning.
There was a problem hiding this comment.
This is ok I think. We've never encountered this issue before.
As described, but I took the opportunity to further refactor bb-sim: