Releases: seismoseo/PocketQuake
Release list
v1.14.2 — install fixes (issues #9/#10) + full-source ZIP bundle
Fixes (from external install reports, issues #9 and #10 — thanks!)
- Docs: SKHASH upstream moved
SKHASH.pytosrc/SKHASH/— all docs + tutorial now teach the invariant (SKHASH_DIR = the dir containing SKHASH.py) and both layouts; PhaseNet+ weights are no longer bundled in EQNet — added the PhaseNet-Plus-v1 release download step formodel_99.pth; example path corrected toexamples/chungju/chungju_catalog.csv. - environment.yml: added
pyproj(EikoNet imports it at module load). - korea-cluster-relocation: robust tectonic discovery (no dev-machine hard-coded fallback; clear skip when absent);
fetch_eikonet --velmodel allwarns-and-skips bundled models without release assets (neasia); bootstrap switches to LSQR on a slow SVD probe (63× on a real dt.ct branch); Haenam cluster registry. - necis-downloader: 🔴
submitted_aftersession filter fixed for non-KST machines (NECIS reqDt is KST server time — previously, machines behind KST silently pulled previous runs' ZIPs); event-search pagination.
New: full-source ZIP bundle (no git needed — Windows-friendly)
GitHub's automatic Source code (zip) ships empty submodule directories. PocketQuake-v1.14.2-full-source.zip (attached, ~7 MB) bundles the superproject plus both submodules at their pinned commits — no symlinks, extract anywhere, then follow docs/INSTALL.md as usual. Exact SHAs are recorded in BUNDLE_INFO.txt; the ~700 MB of generated per-cluster result notebooks are excluded (the pipeline regenerates them — browse the committed ones on GitHub). Future releases attach this bundle automatically via CI.
v1.14.1 — document the SVD fault frame, --augment and necis_zip
Documentation (no functional change)
- Documented the v1.14.0 SVD fault frame, which until now existed only in the
changelog and the generated notebook's own prose. New "The fault-coordinate frame
(FRAME_FROM)" section indocs/workflow.mdwith thesvd/auto/mechanismtable,
a README paragraph, and a tutorial slide — all stating that it is a notebook
parameter, not a CLI flag (there is no--frame), and carrying the near-equant
caveat: a flat but roughly circular cloud has a well-determined plane and a poorly
determined strike within it (2026 Haenam: 372/269/45 m — 6:1 out-of-plane flattening,
only 1.4:1 in-plane). --augmentandpython -m pocketquake.necis_zipreach the tutorial deck. Both were
already covered indocs/workflow.md,docs/cli.mdand the README, but the beamer
tutorial — the document a first-time user is pointed at — did not mention either. Added
an augmentation slide (reuse guarantees, additivity, idempotency, cuspid pinning), a
bulk-ZIP staging slide, and an--augmentrow in the options reference.- Version strings bumped 1.12.1 → 1.14.0 in
docs/index.md,mkdocs.ymland the
tutorial's\pqversion; tutorial PDF recompiled. - Removed
docs/tutorial/PocketQuake_manual.pdf— a stale v1.12.1 build of the same
beamer deck, uploaded separately and never regenerated, whichdocs/index.mdlinked to
instead of the maintainedpocketquake_tutorial.pdf. The link now points at the real
artifact, so the published tutorial can no longer silently lag the source.
v1.14.0 — SVD best-fit plane as the default fault frame
Changed
- The fault-coordinate frame now defaults to the SVD best-fit plane of the relocated
cloud (FRAME_FROM = "svd"in the results notebook;frame_from="svd"in
viz.fault_sections,viz.animate_seismicity,viz.plot_3d_plane— so the notebook,
the beamer PDF, the 3-D view and the time-lapse GIF all agree). The section frame is
then a property of the relocation: constrained by every relocated event, independent
of any focal mechanism, and free of the grade/size limitations of the single reference
event the previous"auto"default leaned on. The reference beachball is still drawn on
the map panel and the title reports both planes, so mechanism-vs-seismicity agreement
stays visible (2026_Haenam:strike 94°/dip 67° [SVD best-fit plane]; mechanism NP1=180°/77° (A))."auto"(the previous default) and"mechanism"are unchanged and
still selectable; explicitstrike=/dip=still wins over everything.
Caveat documented in the notebook and docstrings: for a near-equant cloud the SVD
strike is weakly determined even when the plane itself is well-defined (2026 Haenam's
singular values are 372/269/45 m — 6:1 flattening but only 1.4:1 in-plane elongation);
prefer"auto"or an explicit plane there.
v1.13.0 — incremental cluster augmentation (--augment)
Added
- Incremental cluster augmentation (
--augment). Given an augmented catalog for an
already-processed cluster (./pocketquake.sh NEW_CATALOG SLUG --augment), PocketQuake now
adds only the NEW events — download → gather → pick → locate — and re-relocates the whole
cluster, instead of redoing everything from scratch. Reuse guarantees:- Event identity is pinned by a
runs/<cluster>/event_manifest.csv
(evmap.pin_manifest): existing events keep their current HypoDD cuspids byte-identically
and new events append after, so cached.sum/event.dat/dt.ct/dt.cccontent stays
valid even for events that interleave in time with the existing ones. - Existing events are never re-gathered or re-picked (per-event
--eventssubsets);
their picks CSVs and SAC pick headers are untouched. - HYPOINVERSE re-runs whole-cluster (hyp1.40 locates each event independently, so
existing solutions reproduce) and that is verified against a pre-augment snapshot.
An existing event whose origin time moved beyond 5 ms has its cached dt.cc pairs
invalidated and recomputed (xcorr.invalidate_pairs) — dt.cc values reference the two
origin times, and a one-print-quantum 10 ms flip is 10× the 1 ms xcorr slide resolution.
Position-only moves (> 1e-4° / 0.05 km) are logged but do NOT invalidate: dt.cc does not
depend on epicenter/depth (those live in event.dat, rebuilt every run). - Events the waveform source can't serve yet are handled gracefully: they are skipped
with a warning and the run proceeds with the available subset; re-running the same
--augmentlater retries exactly the pending events (they still diff as "new"). - xcorr reuses every existing pair: the per-pair resume (
XCORR_RESUME) is promoted to
a first-class--xcorr-resumeCLI flag /run_cluster(xcorr_resume=)parameter; only
new-vs-all + new-vs-new pairs are computed (N existing + M new →M·N + C(M,2)instead
ofC(N+M,2)pairs). rereferencenow skips SACs already at the.sumorigin (2 ms tolerance — nzmsec
quantizes at 1 ms, genuine.sumorigin changes at 10 ms), preserving mtimes so the
xcorr interp disk cache and cached dt.cc pairs stay valid; a repeat run with the same
velmodel is now a true no-op.- dt.ct/dt.cc HypoDD, focal mechanisms, the results notebook and the PDF report re-run
over the full augmented cluster (they are cheap). Stale bootstrap error caches are
cleared, and the bootstrap provenance header now records the event set
(nev=/evhash=) so a changed cluster auto-invalidates old caches. - Strictly additive policy: if the new catalog is missing events that exist in the run,
the augment aborts listing them (removing events is a deliberate fresh-run decision).
Catalog metadata revisions for existing events are warned about but NOT applied (the
original rows are kept, guarding location reproducibility). The pre-augment catalog is
backed up asevent_catalog.csv.pre_augment_<timestamp>. --dry-runprints the catalog diff (new / missing events) and exits without changes.
- Event identity is pinned by a
- NECIS bulk-ZIP staging utility (
python -m pocketquake.necis_zip). Stages a
manually-downloaded NECIS "cart" ZIP (per-event<NECIS_ID>.{a,v}.ziparchives of flat
miniSEED) into a cluster'skma_waveforms/tree. Events are identified by their
origin-stamped miniSEED member names (KS.ADOA.BGE.2026.227.19.58.07→ event_id) and
matched against the cluster catalog — already-staged and out-of-catalog events are
skipped, per data type (a partial event, e.g.apresent butvfailed, is topped up).
miniSEED is converted to band-sorted SAC with the NECIS downloader's own converter.
Pairs naturally with augmentation: stage the ZIP, then--augment --skip-download.
Fixed
- Bootstrap per-replica timeout now scales to measured machine speed (engine:
hypodd.bootstrap_relocation). The fixed 120 s wall cap silently killed healthy
replicas on a loaded shared box (41-event SVD replicas at ~150 s under load ~3×), so
bootstrap_errors.csv came back with n_boot=0 — no error, just empty error bars. The
bootstrap now times its un-resampled probe inversion (and the LSQR calibration when
that path is taken) and caps replicas at 5× that (floor 120 s, ceiling 1 h) —
pathological resamples still die quickly relative to the machine's actual speed. - Bootstrap error bars are now precomputed before the results notebook executes (both
fresh and--augmentruns). The notebook's 2×1000-replica location-uncertainty
bootstraps previously ran inside a notebook cell, where a large cluster or a loaded
shared box could push them past nbconvert's 3600 s per-cell timeout and fail the whole
run (observed: 41-event SVD replicas at ~2.5 min each under load). They now run in the
orchestrator (no cell timeout; failure-safe — on any precompute error the notebook
computes in-cell as before), and the notebook cells load the cache instantly. - NECIS event search read only the first result page (engine:
necis-downloader
events.py). The results table is paginated at 10 rows/page; during an active swarm a
2-day search window spans several pages, so deeper rows were invisible and the closest
page-1 row failed the 10 s match tolerance ("Closest NECIS row differs by ...s") — the
event was wrongly declared "not found on NECIS". The search now walks everymovePage
page and matches across the full result set. Verified live on two previously-missed
Haenam aftershocks (both now match with Δ0 s).
Engine (korea-cluster-relocation)
evmap.pin_manifest: materialize/extend the manifest, freezing current cuspids.xcorr:resume=parameter (envXCORR_RESUMEstill honored) +invalidate_pairs.rereference:skip_tol_sskip-unchanged fast path.hypodd.bootstrap_relocation: event-set provenance (nev/evhash) in the cache header.core/augment.py(new):sum_snapshot/verify_sums/clear_bootstrap_caches.cli/run_pipeline.py:--xcorr-resume.
v1.12.1 — fix beachball take-off convention (focal-mechanism overlay)
Fixed
- Beachball polarity overlay used the wrong take-off convention.
viz._lower_hemisphere_xy
assumed take-off measured from the downward vertical (0 = down), but SKHASH writes HASH
notation (flip_takeoff=Falsedefault): 0 = upgoing, 180 = downgoing. The antipodal
flip was applied to the wrong rays, point-reflecting every first-motion triangle and S/P
circle through the beachball centre — markers landed in the wrong quadrants for steep
(near-source) rays. Fixed to the real HASH convention (downgoing = take-off > 90 plotted
directly; upgoing < 90 mapped antipodally) plus the matching station-label azimuth. Verified:
markers now fall in the correct quadrant at 100% of take-off angles (was 46–97%), and the
polarity_misfit = 0reference event renders 14/14 clean. Visualization-only — SKHASH
mechanisms,polarity_misfit, and A–D quality grades are computed internally and were never
affected; previously-rendered overlays were misleading but the underlying science is unchanged.
(engine:korea-cluster-relocationviz.py.)
v1.12.0 — automatic anti-aliasing before PhaseNet+ down-sampling
Added
- Automatic anti-aliasing before PhaseNet+ down-sampling. PhaseNet+ runs at 100 Hz, but the
underlying EQNet reader down-sampled higher-rate stations (200 Hz KMA/KG, 250 Hz nodal/geophone
arrays) with plain linear interpolation and no anti-alias lowpass, folding >50 Hz energy back
onto the P/S onsets — distorting pick times and first-motion polarity. PocketQuake now inserts a
proper guard before the picker: demean → taper → zero-phase Butterworth lowpass at 45 Hz
(0.9 × the new 50 Hz Nyquist) → resample (eqnet_backend._antialias_resample, applied in
_sac_to_mseed). Fires only when the native rate exceeds 100 Hz: 100 Hz archive data passes
through byte-identical and up-sampling (e.g. 40 Hz → 100 Hz) is alias-free and untouched.
Zero-phase keeps onset times in place (a causal lowpass would bias picks late). Verified on a real
200 Hz KG trace: energy above 45 Hz drops 0.064% → 0.003%. Largest benefit for close, high-corner
sources on dense high-rate deployments.
Engine (korea-cluster-relocation)
eqnet_backend: the anti-alias guard above.write_phs: lift the 999-event cuspid cap (cuspid_offset + idx, byte-identical foridx ≤ 999).viz.fault_sections: optionalsource_radiusto draw events as to-scale source-circle markers;
magnitude legend + "Local magnitude" axis in the fault-frame map view; inset A/A′/B/B′ section-end labels.
Docs
- New anti-aliasing coverage in the Workflow page, Troubleshooting (high-rate stations), and a
dedicated beamer tutorial slide ("High-rate stations: automatic anti-aliasing"). Tutorial PDF recompiled.
v1.11.1 — document waveform-similarity rendering
Docs
- Document the waveform-similarity results (1.11.0 feature) in the beamer tutorial — new
"Output 4 — Waveform similarity" slide showing the full-waveform gather + the Z CC matrix
(chronological + hierarchical) — and in the mkdocs Workflow page (Step 5 results notebook and
Step 6 beamer run-summary now list the gather + CC matrices). Tutorial PDF recompiled.
v1.11.0 — per-cluster waveform-similarity figures
Added
- Per-cluster waveform-similarity figures in the results notebook + beamer report. New results
section "3. Waveform similarity per dt.cc sub-cluster" (single-cluster runs are shown without a
sub-cluster index). For each dt.cc sub-cluster (hypoDDcid), at the station nearest to (and
common to) the sub-cluster's events:- a waveform gather of every event's full waveform (P + S + coda), P-aligned at t=0 (red)
with the S pick as a blue bar, ordered top→bottom = past→present (no stack), so a
near-repeating family reads as near-identical rows; - a waveform NCC matrix over the same full window, shown both in chronological order
(shares the gather's order) and in hierarchical-clustering order (with dendrogram) so
repeating sub-families gather into bright blocks regardless of when they occurred.
Bandpass 5–20 Hz (the dt.cc band). Newpipeline.analysis.similarity.{nearest_common_station, cluster_events_by_cid, cluster_cc_matrix}+pipeline.viz.{plot_cluster_similarity_gather, plot_cluster_cc_matrix}. Sub-clusters whose era has no station recording every event relax to the
max-coverage station (warned, never aborts). Verified end-to-end onwest_jeju(notebook 0 errors;
slides in the summary PDF).
- a waveform gather of every event's full waveform (P + S + coda), P-aligned at t=0 (red)
v1.10.0 — beamer PDF run summary (automatic workflow product)
A uniform, presentation-ready beamer PDF run summary is now a first-class PocketQuake product, compiled automatically alongside the results notebook at the end of every run.
Added
reportstage (pipeline.reporting.make_run_summary) →runs/<cluster>/summary/<cluster>_summary.pdf: stats overview (events located / dt.cc-relocated, period, depth range for both HYPOINVERSE and dt.cc, magnitude range, median RMS/gap, focal-mechanism count by quality), relocated epicenters, depth sections, focal-mechanism map, a best-quality beachball (per-station first-motion polarities + S/P amplitude ratios), cumulative seismicity, and a time-lapse of the sequence embedded both as a static key frame and a real\animategraphicsanimation. Compiled with tectonic.pipeline.cli.make_summarystandalone CLI (--no-animateto skip the GIF).- The orchestrator runs
reportafter the notebook, so./pocketquake.shemits the summary automatically. Failure-safe — a missing tectonic / bad figure logsreport: SKIPPEDand never fails the scientific run.
See the CHANGELOG (also backfilled 1.8.1–1.9.1).
v1.9.1 — dt.cc interpolation cache (faster re-runs)
Optional on-disk cache of interpolated+filtered traces (runs/<cluster>/wf_interp_cache/, cfg.xcorr_interp_cache, default on) for the GPU-batched dt.cc path.
Once correlation runs on the GPU, the 100→1000 Hz Lanczos interpolation (~0.3 s/trace) is the dominant remaining cost. The cache lets re-runs — e.g. tuning cc_threshold/slide_step/margin — skip it. Keyed by source file (path+mtime+size) and the exact interp/band params, so a changed SAC or band self-invalidates and only identical inputs hit. A hit yields the byte-identical Trace, so dt.cc stays bit-exact (validated: populate-vs-cache-hit dt.cc files identical).
🤖 Generated with Claude Code