-
Notifications
You must be signed in to change notification settings - Fork 0
Pipeline Walkthrough
This page is the annotated tour of the two bundled entry-point scripts:
-
Research Workflow β
main.pyβ one-shot calculate β train β predict β evaluate on a fixed date split. -
Scenarios Workflow β
scenarios.pyβ same pipeline executed once per scenario in a nine-scenario sweep.
Both scripts share the same ForecastModel instance and the same calculate() output; they differ in how the train β predict β evaluate legs are sequenced.
main.py runs a single, linear pipeline: it computes tremor over the whole year, trains on the first seven months, forecasts the next four weeks, and evaluates against the held-out eruptions.
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β main.py β Stage Flow β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
fm = ForecastModel(network="VG", station="OJN", location="00",
channel="EHZ", day_to_forecast=2,
n_jobs=8, verbose=True)
β
βΌ
βββββββββββββββββββββββ
β fm.calculate() β CalculateTremor β tremor_*.csv
β β source = SDS (D:\Data\OJN)
β β methods = rsam, dsar, entropy
β β dates: 2025-01-01 β 2025-12-31
ββββββββββββ¬βββββββββββ
β
βΌ
βββββββββββββββββββββββ
β fm.train() β TrainingModel β ClassifierEnsemble
β β build_label (window_step = 6 h, dtf = 2)
β β extract_features (tsfresh, 5 tremor columns)
β β fit (4 classifiers Γ 25 seeds)
β β cv = shuffle-stratified, scoring = recall
β β resample = under, n_jobs = 4, n_grids = 4
ββββββββββββ¬βββββββββββ
β cached β {station_dir}/cache/TrainingModel/{hash}.pkl
β
βΌ
βββββββββββββββββββββββ
β fm.predict() β PredictionModel β results
β β build_label (window_step = 10 min)
β β extract_features (same tremor columns)
β β forecast (4 clf Γ 25 seeds β consensus)
β β plot_threshold = 0.7, save_seed_result = True
ββββββββββββ¬βββββββββββ
β cached β {station_dir}/cache/PredictionModel/{hash}.pkl
β
βΌ
βββββββββββββββββββββββ
β fm.evaluate( β EvaluationModel(model="prediction")
β model= β MetricsEnsemble.compute()
β "prediction") β aggregate per-classifier metrics
β β plot_per_seed = True
ββββββββββββ¬βββββββββββ
β
βΌ
βββββββββββββββββββββββ
β fm.EvaluationModel β ClassifierComparator
β .compare() β ranking CSV + comparison plots
βββββββββββββββββββββββ
- Runs once across the full year so the same tremor frame is reused by every downstream stage.
-
start_dateis internally shifted back byday_to_forecastdays (forecast_model.py:154) so the first label window has enough lead-in. -
interpolate=Truefills miniSEED gaps so tsfresh receives a continuous signal. -
plot_daily=Trueemits per-day band plots undertremor/figures/β useful for spotting station outages before training.
-
classifiers=["lite-rf", "rf", "gb", "xgb"]β four classifiers fit independently; their fittedSeedEnsembles are bundled into a singleClassifierEnsemble. -
eruption_dateslists every known eruption β both the training-window eruptions and the held-out ones the forecast will be evaluated against. -
scoring="recall"instructsGridSearchCVto maximise positive recall β false negatives are worse than false positives for eruption forecasting. -
seeds=25inmain.pyis a quick run; the default inscenarios.pyisseeds=10per scenario. -
n_jobs=4, n_grids=4β 4 outer seed workers Γ 4 inner CV workers. Clamped byBaseModel.validate()if the box has fewer cores.
-
window_step=10, window_step_unit="minutes"β 144 forecasts/day. The dense grid is what makes the forecast plot smooth. -
save_seed_result=Truewrites one CSV per seed underprediction/results/{clf-slug}/for downstream uncertainty analysis. -
use_cache=Falseforces a fresh forecast β flip toTrueto short-circuit when nothing upstream changed. - The cache identity threads in
_training_cache_hash, so re-training automatically invalidates downstream predictions.
- Reuses the in-memory
PredictionModelβ no re-extraction of features, no re-fit. - Falls back to
train()'seruption_dateswhen called without an explicit list. - Writes per-seed JSON under
evaluation/prediction/classifiers/{clf}/metrics/json/{seed:05d}.jsonplus aggregatemetrics_summary_*.csv. -
plot_per_seed=Trueis expensive β flip off for fast iteration.
- One
MultiModelEvaluatorper classifier β fed to aClassifierComparator. -
comparator.get_ranking()writescomparison/metrics/ranking_recall.csv(defaults to recall ranking β matches the trainingscoring). -
comparator.plot_all()writes ROC overlay, metric bars, seed stability violins, and a comparison grid underevaluation/prediction/comparison/figures/.
scenarios.py keeps the same ForecastModel instance and the same tremor frame, but loops the train β predict β evaluate legs over nine scenarios that vary the training and prediction date splits. Each scenario's outputs land in its own directory so they can be compared side-by-side.
| # | Train window | Forecast window | Goal |
|---|---|---|---|
| 1 | 2025-01-01 β 2025-03-31 | 2025-04-01 β 2025-04-30 | Train on 1 eruption, forecast eruption 2 |
| 2 | 2025-01-01 β 2025-03-31 | 2025-05-01 β 2025-05-31 | Train on 1 eruption, forecast eruption 3 |
| 3 | 2025-01-01 β 2025-03-31 | 2025-06-01 β 2025-06-30 | Train on 1 eruption, forecast eruption 4 |
| 5 | 2025-01-01 β 2025-04-30 | 2025-05-01 β 2025-05-31 | Train on 1+2, forecast eruption 3 |
| 6 | 2025-01-01 β 2025-05-31 | 2025-06-01 β 2025-06-30 | Train on 1+2+3, forecast eruption 4 |
| 7 | 2025-01-01 β 2025-06-30 | 2025-07-01 β 2025-07-13 | Train on 1β4, forecast eruption 5 |
| 8 | 2025-01-01 β 2025-07-26 | 2025-07-27 β 2025-08-22 | Train on 1β5, forecast eruptions 6+7 |
| 9 | 2025-01-01 β 2025-08-22 | 2025-01-01 β 2025-08-22 | Sanity check β train and predict over the full record |
(Scenario 4 is intentionally absent in scenarios.py.)
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β scenarios.py β Outer-Loop Flow β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
fm = ForecastModel(...) # one ForecastModel reused
β
βΌ
βββββββββββββββββββββββ
β fm.calculate() β one full-year tremor CSV (shared across scenarios)
ββββββββββββ¬βββββββββββ
β
βΌ
for scenario in scenarios: # nine scenarios in scenarios.py
β
β output_dir = os.path.join(
β root_dir, "output", fm.nslc,
β "scenarios", slugify(name))
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β (scoped to scenario.output_dir) β
β β
β fm.train(start, end, eruption_dates, β¦, output_dir=output_dir) β
β β β
β βΌ β
β fm.predict(start, end, β¦, output_dir=output_dir, β
β eruption_dates=plot_kwargs["eruption_dates"]) β
β β β
β βΌ β
β send_telegram_notification( β
β message=f"{name}: {description}", β
β files=[fm.PredictionModel.forecast_plot_path], β
β file_caption=f"{name}: {description}") β
β β β
β βΌ β
β fm.evaluate(model="prediction", plot_per_seed=True, β
β output_dir=output_dir) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
next scenario β loop back
-
output_diris built once per scenario fromslugify(name)("Scenario 1"β"scenario-1"). Every stage call inside the loop forwards thatoutput_dir, so artefacts land atoutput/{nslc}/scenarios/{slug}/. - The outer
fm.calculate(...)runs once before the loop. Its tremor frame is captured onfm.tremor_dfand reused on every iteration βfm.train()reads fromfm.tremor_df, not from disk. -
eruption_datesis the full list of eight known eruptions on every scenario. The training window simply excludes the eruptions that haven't happened yet, and the prediction window picks them up later. -
plot_kwargs["eruption_dates"]is forwarded intofm.predict(...)as**plot_kwargs, which routes them toforecast_plotsso eruption-day markers are drawn on the per-scenario forecast plot. - The Telegram hook (
send_telegram_notification) ships the per-scenario forecast PNG to the configured chat the momentpredict()returns. The bundledsend_as_document=Trueflag forces the file to be uploaded as a document rather than re-encoded as an image β preserves the full DPI plot. -
fm.evaluate(...)runs after the notification, so by the time you see the plot in Telegram, the per-seed metrics JSON is already being computed in the background.
output/
βββ VG.OJN.00.EHZ/
βββ tremor/ # shared across all scenarios
β βββ VG.OJN.00.EHZ_2025-01-01_2025-12-31.csv
βββ scenarios/
βββ scenario-1/
β βββ training/
β βββ prediction/
β βββ evaluation/prediction/
β βββ cache/
βββ scenario-2/
...
βββ scenario-9/
See Output Structure for the full per-scenario tree.
Research (main.py) |
Scenarios (scenarios.py) |
|
|---|---|---|
| Number of forecasts | 1 | N (9 in the bundled script) |
| Tremor computation | once | once (reused) |
| Training | once | once per scenario |
| Output isolation | flat | one directory per scenario |
| Telegram notifications | per-stage via @notify decorator |
per-scenario forecast plot via send_telegram_notification(...)
|
| Use case | a single research run on a fixed split | leave-one-out style sweeps, ablation over training windows |
When the goal is to publish a forecast plot, use main.py. When the goal is to compare how forecast quality degrades as the training-window shifts, use scenarios.py.