enerdatasynth 0.4.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. enerdatasynth/__init__.py +71 -0
  2. enerdatasynth/cli.py +214 -0
  3. enerdatasynth/data/__init__.py +0 -0
  4. enerdatasynth/data/preprocess.py +447 -0
  5. enerdatasynth/data/temperature.py +386 -0
  6. enerdatasynth/diffusion/__init__.py +0 -0
  7. enerdatasynth/diffusion/ddpm.py +120 -0
  8. enerdatasynth/diffusion/schedules.py +38 -0
  9. enerdatasynth/evaluation/__init__.py +0 -0
  10. enerdatasynth/evaluation/baselines.py +72 -0
  11. enerdatasynth/evaluation/calibration.py +140 -0
  12. enerdatasynth/evaluation/failure_analysis.py +192 -0
  13. enerdatasynth/evaluation/metrics.py +58 -0
  14. enerdatasynth/evaluation/results_report.py +123 -0
  15. enerdatasynth/generators/__init__.py +13 -0
  16. enerdatasynth/generators/base.py +59 -0
  17. enerdatasynth/generators/load.py +165 -0
  18. enerdatasynth/models/__init__.py +54 -0
  19. enerdatasynth/models/denoiser.py +87 -0
  20. enerdatasynth/models/transformer.py +96 -0
  21. enerdatasynth/sampling/__init__.py +0 -0
  22. enerdatasynth/sampling/generate.py +91 -0
  23. enerdatasynth/sdk.py +281 -0
  24. enerdatasynth/training/__init__.py +0 -0
  25. enerdatasynth/training/sweep.py +224 -0
  26. enerdatasynth/training/train.py +183 -0
  27. enerdatasynth/utils/__init__.py +0 -0
  28. enerdatasynth/utils/config.py +183 -0
  29. enerdatasynth/visualization/__init__.py +0 -0
  30. enerdatasynth/visualization/plots.py +218 -0
  31. enerdatasynth-0.4.1.dist-info/METADATA +237 -0
  32. enerdatasynth-0.4.1.dist-info/RECORD +36 -0
  33. enerdatasynth-0.4.1.dist-info/WHEEL +5 -0
  34. enerdatasynth-0.4.1.dist-info/entry_points.txt +2 -0
  35. enerdatasynth-0.4.1.dist-info/licenses/LICENSE +21 -0
  36. enerdatasynth-0.4.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,71 @@
1
+ """
2
+ enerdatasynth
3
+ ================
4
+ A research SDK for synthetic PJM energy resource profiles. Today that
5
+ means electric load; the public interface is designed so a future
6
+ resource type (e.g. wind) can be added through the same contract —
7
+ see `docs/extending.md`.
8
+
9
+ Primary entry point — you should not need anything else for everyday
10
+ generation:
11
+
12
+ import enerdatasynth
13
+
14
+ load = enerdatasynth.model("pjm_load", zone="PS")
15
+ load.set(month=7, Tmax=86, Tmin=70, weekday=True, holiday=False)
16
+ samples = load.sample(n=100) # (100, 24) array, MW
17
+
18
+ `enerdatasynth.model(...)` never exposes tensors, architecture
19
+ classes, checkpoint paths, or the fact that a DDPM/transformer is
20
+ involved at all. See `docs/api_reference.md` for the full contract.
21
+
22
+ For research/development use — training new checkpoints, computing
23
+ evaluation metrics, running calibration — this top-level namespace
24
+ also re-exports the lower-level building blocks:
25
+
26
+ from enerdatasynth import RunConfig, train_one_config, LoadDiffusionModel
27
+
28
+ For anything not re-exported here, import directly from the relevant
29
+ submodule (`enerdatasynth.data`, `enerdatasynth.models`,
30
+ `enerdatasynth.diffusion`, `enerdatasynth.training`,
31
+ `enerdatasynth.sampling`, `enerdatasynth.evaluation`,
32
+ `enerdatasynth.visualization`, `enerdatasynth.generators`,
33
+ `enerdatasynth.utils`).
34
+
35
+ Production code in this package never imports from `research_history/`
36
+ — that directory exists only for reproducibility/provenance and is
37
+ not installed as part of the package.
38
+ """
39
+
40
+ from enerdatasynth.sdk import model, ResourceModel
41
+ from enerdatasynth.utils.config import RunConfig, set_seed, DEFAULT_ARCHITECTURE
42
+ from enerdatasynth.models import build_denoiser, TransformerDenoiser, SimpleMLPDenoiser
43
+ from enerdatasynth.diffusion.ddpm import DDPM
44
+ from enerdatasynth.data.preprocess import run_preprocessing
45
+ from enerdatasynth.training.train import train_one_config
46
+ from enerdatasynth.sampling.generate import generate_for_run
47
+ from enerdatasynth.evaluation.metrics import compute_metrics
48
+ from enerdatasynth.evaluation.calibration import calibrate_checkpoint
49
+ from enerdatasynth.generators import BaseGenerator, LoadDiffusionModel
50
+
51
+ __version__ = "0.4.1"
52
+
53
+ __all__ = [
54
+ "__version__",
55
+ "model",
56
+ "ResourceModel",
57
+ "BaseGenerator",
58
+ "LoadDiffusionModel",
59
+ "RunConfig",
60
+ "set_seed",
61
+ "DEFAULT_ARCHITECTURE",
62
+ "build_denoiser",
63
+ "TransformerDenoiser",
64
+ "SimpleMLPDenoiser",
65
+ "DDPM",
66
+ "run_preprocessing",
67
+ "train_one_config",
68
+ "generate_for_run",
69
+ "calibrate_checkpoint",
70
+ "compute_metrics",
71
+ ]
enerdatasynth/cli.py ADDED
@@ -0,0 +1,214 @@
1
+ """
2
+ enerdatasynth.cli
3
+ ====================
4
+ Console-script entry point (`enerdatasynth`, installed via
5
+ `[project.scripts]` in pyproject.toml). Thin argparse wrapper around
6
+ the existing pipeline functions — no new logic lives here, only
7
+ argument parsing and dispatch, so behavior matches calling the
8
+ underlying functions directly.
9
+
10
+ Usage:
11
+ enerdatasynth preprocess
12
+ enerdatasynth train [--architecture transformer|mlp] [--diffusion-steps T] [--hidden-dim H] [--n-layers L] ...
13
+ enerdatasynth sweep [--epochs N] [--full-grid]
14
+ enerdatasynth generate --diffusion-steps T --hidden-dim H --n-layers L
15
+ enerdatasynth calibrate --run-id transformer_T1000_H64_L2
16
+ enerdatasynth evaluate --run-id transformer_T1000_H64_L2
17
+ enerdatasynth report
18
+ enerdatasynth pipeline [--epochs N] [--full-grid] [--skip-preprocess]
19
+ """
20
+
21
+ from __future__ import annotations
22
+ import argparse
23
+
24
+ import numpy as np
25
+
26
+ from enerdatasynth.utils.config import (
27
+ RunConfig, PROCESSED_DIR, DEFAULT_ARCHITECTURE,
28
+ DEFAULT_T, DEFAULT_HIDDEN_DIM, DEFAULT_N_LAYERS, DEFAULT_N_HEADS,
29
+ )
30
+
31
+
32
+ def _add_run_config_args(parser: argparse.ArgumentParser) -> None:
33
+ parser.add_argument("--config", type=str, default=None,
34
+ help="Load a RunConfig from YAML (e.g. configs/transformer.yaml). "
35
+ "Takes precedence over the flags below.")
36
+ parser.add_argument("--architecture", choices=["transformer", "mlp"], default=DEFAULT_ARCHITECTURE)
37
+ parser.add_argument("--diffusion-steps", type=int, default=DEFAULT_T)
38
+ parser.add_argument("--hidden-dim", type=int, default=DEFAULT_HIDDEN_DIM)
39
+ parser.add_argument("--n-layers", type=int, default=DEFAULT_N_LAYERS)
40
+ parser.add_argument("--n-heads", type=int, default=DEFAULT_N_HEADS)
41
+ parser.add_argument("--batch-size", type=int, default=None)
42
+ parser.add_argument("--lr", type=float, default=None)
43
+ parser.add_argument("--max-epochs", type=int, default=None)
44
+ parser.add_argument("--patience", type=int, default=None)
45
+ parser.add_argument("--seed", type=int, default=None)
46
+
47
+
48
+ def _run_config_from_args(args: argparse.Namespace) -> RunConfig:
49
+ if getattr(args, "config", None):
50
+ return RunConfig.from_yaml(args.config)
51
+
52
+ kwargs = dict(
53
+ architecture=args.architecture,
54
+ diffusion_steps=args.diffusion_steps,
55
+ hidden_dim=args.hidden_dim,
56
+ n_layers=args.n_layers,
57
+ n_heads=args.n_heads,
58
+ )
59
+ for field in ("batch_size", "lr", "max_epochs", "patience", "seed"):
60
+ value = getattr(args, field, None)
61
+ if value is not None:
62
+ kwargs[field] = value
63
+ return RunConfig(**kwargs)
64
+
65
+
66
+ def cmd_preprocess(args: argparse.Namespace) -> None:
67
+ from enerdatasynth.data.preprocess import run_preprocessing
68
+ run_preprocessing()
69
+
70
+
71
+ def cmd_train(args: argparse.Namespace) -> None:
72
+ from enerdatasynth.training.train import train_one_config
73
+ cfg = _run_config_from_args(args)
74
+ X_train = np.load(PROCESSED_DIR / "X_daily_profiles.npy")
75
+ Z_train = np.load(PROCESSED_DIR / "Z_conditions.npy")
76
+ X_val = np.load(PROCESSED_DIR / "X_daily_profiles_val.npy")
77
+ Z_val = np.load(PROCESSED_DIR / "Z_conditions_val.npy")
78
+ train_one_config(X_train, Z_train, X_val, Z_val, cfg)
79
+
80
+
81
+ def cmd_sweep(args: argparse.Namespace) -> None:
82
+ from enerdatasynth.training.sweep import run_sweep
83
+ run_sweep(max_epochs=args.epochs, full_grid=args.full_grid)
84
+
85
+
86
+ def cmd_generate(args: argparse.Namespace) -> None:
87
+ from enerdatasynth.sampling.generate import generate_for_run
88
+ cfg = _run_config_from_args(args)
89
+ generate_for_run(
90
+ run_id=cfg.run_id,
91
+ diffusion_steps=cfg.diffusion_steps,
92
+ hidden_dim=cfg.hidden_dim,
93
+ n_layers=cfg.n_layers,
94
+ architecture=cfg.architecture,
95
+ n_heads=cfg.n_heads,
96
+ )
97
+
98
+
99
+ def cmd_calibrate(args: argparse.Namespace) -> None:
100
+ from enerdatasynth.evaluation.calibration import calibrate_checkpoint
101
+ result = calibrate_checkpoint(
102
+ run_id=args.run_id,
103
+ architecture=args.architecture,
104
+ diffusion_steps=args.diffusion_steps,
105
+ hidden_dim=args.hidden_dim,
106
+ n_layers=args.n_layers,
107
+ n_heads=args.n_heads,
108
+ )
109
+ print(f"Scalar offset: {result['scalar']:+.5f} (saved to {result['path']})")
110
+
111
+
112
+ def cmd_evaluate(args: argparse.Namespace) -> None:
113
+ from enerdatasynth.visualization.plots import run_all_validation_plots
114
+ from enerdatasynth.evaluation.failure_analysis import analyze, write_failure_analysis_md
115
+ run_all_validation_plots(args.run_id)
116
+ result = analyze(args.run_id)
117
+ write_failure_analysis_md(result)
118
+ print(f"Issues detected: {len(result['issues'])}")
119
+
120
+
121
+ def cmd_report(args: argparse.Namespace) -> None:
122
+ from enerdatasynth.evaluation.results_report import generate_results_summary
123
+ path = generate_results_summary()
124
+ print(f"Saved: {path}")
125
+
126
+
127
+ def cmd_pipeline(args: argparse.Namespace) -> None:
128
+ from enerdatasynth.data.preprocess import run_preprocessing
129
+ from enerdatasynth.training.sweep import run_sweep
130
+ from enerdatasynth.sampling.generate import generate_for_run
131
+ from enerdatasynth.evaluation.calibration import calibrate_checkpoint
132
+ from enerdatasynth.visualization.plots import run_all_validation_plots
133
+ from enerdatasynth.evaluation.failure_analysis import analyze, write_failure_analysis_md
134
+ from enerdatasynth.evaluation.results_report import generate_results_summary
135
+
136
+ if not args.skip_preprocess:
137
+ run_preprocessing()
138
+
139
+ df = run_sweep(max_epochs=args.epochs, full_grid=args.full_grid)
140
+ best_row = df.sort_values("best_val_loss").iloc[0]
141
+ run_id = best_row["run_id"]
142
+ architecture = best_row.get("architecture", DEFAULT_ARCHITECTURE)
143
+ n_heads = int(best_row["n_heads"]) if "n_heads" in best_row else DEFAULT_N_HEADS
144
+
145
+ generate_for_run(
146
+ run_id=run_id,
147
+ diffusion_steps=int(best_row["diffusion_steps"]),
148
+ hidden_dim=int(best_row["hidden_dim"]),
149
+ n_layers=int(best_row["n_layers"]),
150
+ architecture=architecture,
151
+ n_heads=n_heads,
152
+ )
153
+ calibrate_checkpoint(
154
+ run_id=run_id, architecture=architecture,
155
+ diffusion_steps=int(best_row["diffusion_steps"]),
156
+ hidden_dim=int(best_row["hidden_dim"]),
157
+ n_layers=int(best_row["n_layers"]), n_heads=n_heads,
158
+ )
159
+ run_all_validation_plots(run_id)
160
+ result = analyze(run_id)
161
+ write_failure_analysis_md(result)
162
+ generate_results_summary()
163
+ print(f"\nPipeline complete. Best run: {run_id}")
164
+
165
+
166
+ def build_parser() -> argparse.ArgumentParser:
167
+ parser = argparse.ArgumentParser(prog="enerdatasynth")
168
+ subparsers = parser.add_subparsers(dest="command", required=True)
169
+
170
+ p_preprocess = subparsers.add_parser("preprocess", help="Build X/Z tensors from raw CSVs")
171
+ p_preprocess.set_defaults(func=cmd_preprocess)
172
+
173
+ p_train = subparsers.add_parser("train", help="Train a single model configuration")
174
+ _add_run_config_args(p_train)
175
+ p_train.set_defaults(func=cmd_train)
176
+
177
+ p_sweep = subparsers.add_parser("sweep", help="Run the hyperparameter sweep")
178
+ p_sweep.add_argument("--epochs", type=int, default=60)
179
+ p_sweep.add_argument("--full-grid", action="store_true")
180
+ p_sweep.set_defaults(func=cmd_sweep)
181
+
182
+ p_generate = subparsers.add_parser("generate", help="Generate synthetic profiles from a trained checkpoint")
183
+ _add_run_config_args(p_generate)
184
+ p_generate.set_defaults(func=cmd_generate)
185
+
186
+ p_calibrate = subparsers.add_parser("calibrate", help="Fit the scalar bias correction for a trained checkpoint")
187
+ _add_run_config_args(p_calibrate)
188
+ p_calibrate.add_argument("--run-id", required=True)
189
+ p_calibrate.set_defaults(func=cmd_calibrate)
190
+
191
+ p_evaluate = subparsers.add_parser("evaluate", help="Run validation plots + failure analysis for a run")
192
+ p_evaluate.add_argument("--run-id", required=True)
193
+ p_evaluate.set_defaults(func=cmd_evaluate)
194
+
195
+ p_report = subparsers.add_parser("report", help="Regenerate reports/results_summary.md")
196
+ p_report.set_defaults(func=cmd_report)
197
+
198
+ p_pipeline = subparsers.add_parser("pipeline", help="Run the full pipeline end-to-end")
199
+ p_pipeline.add_argument("--epochs", type=int, default=60)
200
+ p_pipeline.add_argument("--full-grid", action="store_true")
201
+ p_pipeline.add_argument("--skip-preprocess", action="store_true")
202
+ p_pipeline.set_defaults(func=cmd_pipeline)
203
+
204
+ return parser
205
+
206
+
207
+ def main(argv: list[str] | None = None) -> None:
208
+ parser = build_parser()
209
+ args = parser.parse_args(argv)
210
+ args.func(args)
211
+
212
+
213
+ if __name__ == "__main__":
214
+ main()
File without changes