Skip to content

Releases: seismoseo/PocketQuake

v1.14.2 — install fixes (issues #9/#10) + full-source ZIP bundle

Choose a tag to compare

@seismoseo seismoseo released this 26 Aug 14:30

Fixes (from external install reports, issues #9 and #10 — thanks!)

  • Docs: SKHASH upstream moved SKHASH.py to src/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 for model_99.pth; example path corrected to examples/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 all warns-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_after session 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

Choose a tag to compare

@seismoseo seismoseo released this 21 Aug 09:22

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 in docs/workflow.md with the svd/auto/mechanism table,
    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).
  • --augment and python -m pocketquake.necis_zip reach the tutorial deck. Both were
    already covered in docs/workflow.md, docs/cli.md and 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 --augment row in the options reference.
  • Version strings bumped 1.12.1 → 1.14.0 in docs/index.md, mkdocs.yml and 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, which docs/index.md linked to
    instead of the maintained pocketquake_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

Choose a tag to compare

@seismoseo seismoseo released this 21 Aug 09:22

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; explicit strike=/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)

Choose a tag to compare

@seismoseo seismoseo released this 21 Aug 09:22

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.cc content stays
      valid even for events that interleave in time with the existing ones.
    • Existing events are never re-gathered or re-picked (per-event --events subsets);
      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
      --augment later 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-resume CLI 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
      of C(N+M,2) pairs).
    • rereference now skips SACs already at the .sum origin (2 ms tolerance — nzmsec
      quantizes at 1 ms, genuine .sum origin 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 as event_catalog.csv.pre_augment_<timestamp>.
    • --dry-run prints the catalog diff (new / missing events) and exits without changes.
  • NECIS bulk-ZIP staging utility (python -m pocketquake.necis_zip). Stages a
    manually-downloaded NECIS "cart" ZIP (per-event <NECIS_ID>.{a,v}.zip archives of flat
    miniSEED) into a cluster's kma_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. a present but v failed, 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 --augment runs). 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 every movePage
    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 (env XCORR_RESUME still honored) + invalidate_pairs.
  • rereference: skip_tol_s skip-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)

Choose a tag to compare

@seismoseo seismoseo released this 15 Jun 15:20

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=False default): 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 = 0 reference 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-relocation viz.py.)

v1.12.0 — automatic anti-aliasing before PhaseNet+ down-sampling

Choose a tag to compare

@seismoseo seismoseo released this 14 Jun 22:40

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 for idx ≤ 999).
  • viz.fault_sections: optional source_radius to 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

Choose a tag to compare

@seismoseo seismoseo released this 14 Jun 22:40

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

Choose a tag to compare

@seismoseo seismoseo released this 14 Jun 22:40

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 (hypoDD cid), 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). New pipeline.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 on west_jeju (notebook 0 errors;
      slides in the summary PDF).

v1.10.0 — beamer PDF run summary (automatic workflow product)

Choose a tag to compare

@seismoseo seismoseo released this 09 Jun 01:47

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

  • report stage (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 \animategraphics animation. Compiled with tectonic.
  • pipeline.cli.make_summary standalone CLI (--no-animate to skip the GIF).
  • The orchestrator runs report after the notebook, so ./pocketquake.sh emits the summary automatically. Failure-safe — a missing tectonic / bad figure logs report: SKIPPED and 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)

Choose a tag to compare

@seismoseo seismoseo released this 09 Jun 00:53

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