89 lines
3.8 KiB
Python
89 lines
3.8 KiB
Python
#!/usr/bin/env python3
|
|
"""Materialize selected burst demo months from one normal day and event runs."""
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import asyncio
|
|
import json
|
|
import os
|
|
import sys
|
|
from datetime import datetime
|
|
from pathlib import Path
|
|
|
|
|
|
def main() -> int:
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
parser.add_argument(
|
|
"--manifest", type=Path,
|
|
default=Path("resources/benchmarks/tjwater2-v2-burst-demo.json"),
|
|
)
|
|
parser.add_argument(
|
|
"--generation-state", type=Path,
|
|
default=Path("data/benchmark-generation/tjwater2-20261105/state.json"),
|
|
)
|
|
parser.add_argument(
|
|
"--state", type=Path,
|
|
default=Path("data/benchmark-generation/tjwater2-20261105/demo-scada-state.json"),
|
|
)
|
|
args = parser.parse_args()
|
|
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
|
os.umask(0o077)
|
|
|
|
from psycopg.conninfo import make_conninfo
|
|
from scripts.benchmark.calibration import digest, save_json
|
|
from scripts.benchmark.generation import write_demo_scada_window
|
|
from scripts.benchmark.simulation_design import load_simulation_design
|
|
from scripts.check_burst_simulation_design import resolve_project
|
|
|
|
manifest = json.loads(args.manifest.read_text(encoding="utf-8"))
|
|
generation = json.loads(args.generation_state.read_text(encoding="utf-8"))
|
|
if manifest["project_code"] != generation["target"] or generation.get("status") != "prepared":
|
|
raise ValueError("manifest and isolated generation state do not match")
|
|
design = load_simulation_design(Path("resources/benchmarks/tjwater2-v2-burst-balanced.json"))
|
|
source_biz, source_iot = asyncio.run(resolve_project(design))
|
|
business_dsn = make_conninfo(source_biz, dbname=generation["target"])
|
|
timescale_dsn = make_conninfo(source_iot, dbname=generation["target"])
|
|
state_path = args.state.resolve()
|
|
state_path.parent.mkdir(parents=True, exist_ok=True, mode=0o700)
|
|
manifest_sha256 = digest(args.manifest)
|
|
state = json.loads(state_path.read_text(encoding="utf-8")) if state_path.exists() else {
|
|
"version": "burst-demo-scada-state@1",
|
|
"target": generation["target"],
|
|
"manifest_sha256": manifest_sha256,
|
|
"cases": {},
|
|
"status": "materializing",
|
|
}
|
|
if state["target"] != generation["target"] or state["manifest_sha256"] != manifest_sha256:
|
|
raise ValueError("demo state belongs to different inputs")
|
|
save_json(state_path, state)
|
|
normal_source_start = datetime.fromisoformat(manifest["normal_source_start"])
|
|
for case in manifest["cases"]:
|
|
source_case = generation["cases"].get(case["case_key"])
|
|
if not source_case or source_case.get("status") != "scada_materialized":
|
|
raise ValueError(f"event source is unavailable: {case['case_key']}")
|
|
summary = write_demo_scada_window(
|
|
business_dsn=business_dsn,
|
|
timescale_dsn=timescale_dsn,
|
|
normal_source_start=normal_source_start,
|
|
target_start=datetime.fromisoformat(case["target_start"]),
|
|
day_count=int(manifest["day_count"]),
|
|
event_start=datetime.fromisoformat(case["event_start"]),
|
|
event_run_id=source_case["analysis_run_id"],
|
|
noise_seed=manifest["noise_seed"],
|
|
)
|
|
state["cases"][case["demo_id"]] = {
|
|
"case_key": case["case_key"],
|
|
"entry_mode": case["entry_mode"],
|
|
**summary,
|
|
}
|
|
save_json(state_path, state)
|
|
print({"demo_id": case["demo_id"], "rows": summary["rows"]}, flush=True)
|
|
state["status"] = "completed"
|
|
save_json(state_path, state)
|
|
print(json.dumps({"status": state["status"], "cases": state["cases"]}, ensure_ascii=False), flush=True)
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|