quantvolt 0.2.0__tar.gz → 0.2.1__tar.gz
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.
- {quantvolt-0.2.0 → quantvolt-0.2.1}/Cargo.lock +1 -1
- {quantvolt-0.2.0 → quantvolt-0.2.1}/Cargo.toml +1 -1
- {quantvolt-0.2.0 → quantvolt-0.2.1}/PKG-INFO +6 -8
- {quantvolt-0.2.0 → quantvolt-0.2.1}/README.md +5 -7
- {quantvolt-0.2.0 → quantvolt-0.2.1}/pyproject.toml +1 -1
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/__init__.py +1 -1
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/_validation.py +1 -1
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/assets/dispatch_approx.py +43 -43
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/assets/dispatch_deterministic.py +9 -11
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/assets/dispatch_sdp.py +54 -54
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/assets/long_dated.py +81 -85
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/assets/plant.py +4 -4
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/assets/storage.py +34 -34
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/cli.py +2 -4
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/curvemodels/__init__.py +1 -1
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/curvemodels/multifactor.py +13 -13
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/curvemodels/schwartz_smith.py +35 -38
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/curves/arbitrage.py +8 -10
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/curves/builder.py +10 -11
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/data/__init__.py +2 -2
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/data/base.py +12 -12
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/data/commercial.py +3 -3
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/data/entsoe.py +11 -11
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/data/entsog.py +5 -6
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/data/open_meteo.py +5 -5
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/exceptions.py +1 -1
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/hedging/__init__.py +3 -4
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/hedging/hybrid.py +11 -11
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/hedging/mean_variance.py +5 -5
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/hedging/variance_min.py +11 -11
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/market/outages.py +80 -83
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/market/transmission.py +2 -2
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/market/weather.py +1 -1
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/models/commodity.py +2 -2
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/models/curve.py +4 -4
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/models/discount_curve.py +1 -1
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/models/instruments.py +112 -119
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/models/ppa_terms.py +24 -24
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/models/schedule.py +1 -1
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/models/units.py +9 -9
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/models/vol_surface.py +1 -1
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/numerics/black76.py +2 -3
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/numerics/daycount.py +1 -1
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/numerics/interpolation.py +1 -1
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/numerics/monte_carlo.py +14 -13
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/numerics/risk_adjustment.py +3 -3
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/numerics/rootfind.py +1 -1
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/numerics/spread_models.py +1 -1
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/portfolio/model.py +6 -6
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/portfolio/valuation.py +81 -96
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/pricing/bachelier.py +3 -0
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/pricing/exotic.py +44 -46
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/pricing/futures.py +7 -7
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/pricing/implied_vol.py +7 -8
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/pricing/mark_to_market.py +8 -8
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/pricing/ppa.py +13 -16
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/pricing/ppa_valuation.py +16 -18
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/pricing/spread_option.py +13 -13
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/pricing/spreads.py +85 -90
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/pricing/swap.py +6 -6
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/pricing/tolling.py +52 -55
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/pricing/transmission_right.py +11 -12
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/pricing/vanilla.py +35 -24
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/risk/aggregation.py +3 -3
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/risk/cfar.py +9 -9
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/risk/covariance.py +2 -2
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/risk/credit_var.py +15 -15
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/risk/engine.py +9 -9
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/risk/mc_var.py +60 -61
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/risk/parametric_var.py +56 -59
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/risk/scenarios.py +5 -5
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/stats/correlation.py +2 -2
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/stats/descriptive.py +3 -3
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/stats/mean_reversion.py +1 -1
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/stats/normality.py +1 -1
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/stats/stationarity.py +1 -1
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/testing.py +1 -1
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/workflow/criteria.py +3 -3
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/workflow/modeling.py +10 -11
- {quantvolt-0.2.0 → quantvolt-0.2.1}/.gitignore +0 -0
- {quantvolt-0.2.0 → quantvolt-0.2.1}/LICENSE +0 -0
- {quantvolt-0.2.0 → quantvolt-0.2.1}/rust/src/asian_mc.rs +0 -0
- {quantvolt-0.2.0 → quantvolt-0.2.1}/rust/src/lib.rs +0 -0
- {quantvolt-0.2.0 → quantvolt-0.2.1}/rust/src/paths.rs +0 -0
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/_core.pyi +0 -0
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/assets/__init__.py +0 -0
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/assets/_tolerance.py +0 -0
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/curves/__init__.py +0 -0
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/data/dataset_catalog.json +0 -0
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/data/datasets.py +0 -0
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/data/netztransparenz.py +0 -0
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/data/smard.py +0 -0
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/hedging/_conditioning.py +0 -0
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/hedging/ppa_nomination.py +0 -0
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/hedging/ppa_walk_forward.py +0 -0
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/market/__init__.py +0 -0
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/models/__init__.py +0 -0
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/models/greeks.py +0 -0
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/models/interval.py +0 -0
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/models/power_hedge.py +0 -0
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/models/ppa.py +0 -0
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/numerics/__init__.py +0 -0
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/numerics/_degenerate.py +0 -0
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/numerics/_normal.py +0 -0
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/numerics/bachelier.py +0 -0
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/numerics/exotic.py +0 -0
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/portfolio/__init__.py +0 -0
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/portfolio/settlement.py +0 -0
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/pricing/__init__.py +0 -0
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/pricing/_dates.py +0 -0
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/pricing/power_hedge.py +0 -0
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/py.typed +0 -0
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/risk/__init__.py +0 -0
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/risk/_levels.py +0 -0
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/risk/cashflow_metrics.py +0 -0
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/stats/__init__.py +0 -0
- {quantvolt-0.2.0 → quantvolt-0.2.1}/src/quantvolt/workflow/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: quantvolt
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Classifier: Development Status :: 3 - Alpha
|
|
5
5
|
Classifier: Intended Audience :: Financial and Insurance Industry
|
|
6
6
|
Classifier: Intended Audience :: Science/Research
|
|
@@ -130,10 +130,11 @@ Call premium: 45,663 EUR (delta 5,288 EUR per EUR/MWh)
|
|
|
130
130
|
Book NPV: 9,133 EUR, VaR(95): 11,715 EUR
|
|
131
131
|
```
|
|
132
132
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
that last invariant in
|
|
133
|
+
Repeated calls with the same inputs, seed, QuantVolt version, architecture, and native build
|
|
134
|
+
produce identical results. Monte Carlo honours a `seed`, inputs are validated eagerly (no silent
|
|
135
|
+
partial results), results round-trip through plain dicts / JSON, and the library never mutates
|
|
136
|
+
caller data — `quantvolt.testing.assert_input_unchanged` lets you verify that last invariant in
|
|
137
|
+
your own tests.
|
|
137
138
|
|
|
138
139
|
### Settle a PPA with your own interval data
|
|
139
140
|
|
|
@@ -348,9 +349,6 @@ positions. See [docs/risk-and-assets.md](docs/risk-and-assets.md).
|
|
|
348
349
|
verify_tutorial_*.py` script): [spark spread to hedge](https://nimabahrami.github.io/quantvolt/#/guide/tutorial-spark),
|
|
349
350
|
[renewable PPA to CFaR](https://nimabahrami.github.io/quantvolt/#/guide/tutorial-ppa), and
|
|
350
351
|
[storage intrinsic to hedge](https://nimabahrami.github.io/quantvolt/#/guide/tutorial-storage)
|
|
351
|
-
- `.kiro/steering/` — product, tech, structure, and coding-style standards
|
|
352
|
-
- `.kiro/specs/power-energy-quant-analysis/` — requirements, design, and task breakdown
|
|
353
|
-
(the library is spec-driven; the design document is the source of truth for the maths)
|
|
354
352
|
|
|
355
353
|
## Development
|
|
356
354
|
|
|
@@ -91,10 +91,11 @@ Call premium: 45,663 EUR (delta 5,288 EUR per EUR/MWh)
|
|
|
91
91
|
Book NPV: 9,133 EUR, VaR(95): 11,715 EUR
|
|
92
92
|
```
|
|
93
93
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
that last invariant in
|
|
94
|
+
Repeated calls with the same inputs, seed, QuantVolt version, architecture, and native build
|
|
95
|
+
produce identical results. Monte Carlo honours a `seed`, inputs are validated eagerly (no silent
|
|
96
|
+
partial results), results round-trip through plain dicts / JSON, and the library never mutates
|
|
97
|
+
caller data — `quantvolt.testing.assert_input_unchanged` lets you verify that last invariant in
|
|
98
|
+
your own tests.
|
|
98
99
|
|
|
99
100
|
### Settle a PPA with your own interval data
|
|
100
101
|
|
|
@@ -309,9 +310,6 @@ positions. See [docs/risk-and-assets.md](docs/risk-and-assets.md).
|
|
|
309
310
|
verify_tutorial_*.py` script): [spark spread to hedge](https://nimabahrami.github.io/quantvolt/#/guide/tutorial-spark),
|
|
310
311
|
[renewable PPA to CFaR](https://nimabahrami.github.io/quantvolt/#/guide/tutorial-ppa), and
|
|
311
312
|
[storage intrinsic to hedge](https://nimabahrami.github.io/quantvolt/#/guide/tutorial-storage)
|
|
312
|
-
- `.kiro/steering/` — product, tech, structure, and coding-style standards
|
|
313
|
-
- `.kiro/specs/power-energy-quant-analysis/` — requirements, design, and task breakdown
|
|
314
|
-
(the library is spec-driven; the design document is the source of truth for the maths)
|
|
315
313
|
|
|
316
314
|
## Development
|
|
317
315
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"""Reusable boundary-validation guards. Public entry points validate through these before any
|
|
2
|
-
computation
|
|
2
|
+
computation, raising ``ValidationError`` on the first violated constraint."""
|
|
3
3
|
|
|
4
4
|
from __future__ import annotations
|
|
5
5
|
|
|
@@ -1,42 +1,42 @@
|
|
|
1
|
-
"""Dispatch heuristics and approximations
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
is measured against
|
|
10
|
-
Monte-Carlo
|
|
11
|
-
approximation's error
|
|
1
|
+
"""Dispatch heuristics and approximations.
|
|
2
|
+
|
|
3
|
+
Three caller-selectable approximations to the dispatch optimisation, each trading
|
|
4
|
+
fidelity for tractability, plus a specific warning when the state-aggregation
|
|
5
|
+
("bang-bang") one is used. This module implements them as documented input/problem
|
|
6
|
+
transformations around the exact deterministic solver
|
|
7
|
+
``quantvolt.assets.dispatch_deterministic.dispatch_deterministic``: the
|
|
8
|
+
perfect-foresight optimum that is itself the upper bound the stochastic value
|
|
9
|
+
is measured against. Wrapping the deterministic DP (rather than the
|
|
10
|
+
Monte-Carlo ``quantvolt.assets.dispatch_sdp.dispatch_value``) keeps every
|
|
11
|
+
approximation's error exactly comparable to a noise-free benchmark: the
|
|
12
12
|
block-constant, decoupling, and bias identities below are equalities up to float
|
|
13
13
|
tolerance, not statistical statements. The same three transformations apply
|
|
14
|
-
unchanged to the stochastic solver
|
|
14
|
+
unchanged to the stochastic solver: a caller may block-average the factor
|
|
15
15
|
model's per-step structure, divide the simulated horizon, or feed a bang-bang
|
|
16
|
-
plant to
|
|
16
|
+
plant to ``dispatch_value``, but the heuristic itself is the transform, and
|
|
17
17
|
it is cleanest to specify and test against the deterministic optimum.
|
|
18
18
|
|
|
19
19
|
The three approximations
|
|
20
20
|
------------------------
|
|
21
|
-
-
|
|
21
|
+
- ``time_aggregate``: time aggregation (hourly -> 4/8/16-hour blocks).
|
|
22
22
|
Averages the price/temperature series into equal blocks, solves the (much
|
|
23
23
|
shorter) coarse dispatch, and rescales the coarse value back to the original
|
|
24
24
|
number of hours. Exact on block-constant prices for a unit that incurs no start
|
|
25
25
|
within the horizon; the intra-block ramp/commitment freedom it drops is the
|
|
26
26
|
approximation.
|
|
27
|
-
-
|
|
28
|
-
Splits the horizon into consecutive sub-horizons solved
|
|
29
|
-
their values. The boundary-state approximation
|
|
27
|
+
- ``horizon_divide``: horizon division (weekly / monthly sub-horizons).
|
|
28
|
+
Splits the horizon into consecutive sub-horizons solved independently and sums
|
|
29
|
+
their values. The boundary-state approximation: each sub-horizon after the
|
|
30
30
|
first restarts from a cold, restart-ready offline state, dropping the true
|
|
31
|
-
carried-over commitment state
|
|
31
|
+
carried-over commitment state, decouples the subproblems. Exact when the
|
|
32
32
|
periods decouple (zero start costs and non-binding min-run / min-down / ramp).
|
|
33
|
-
-
|
|
33
|
+
- ``bang_bang``: state aggregation for steep heat-rate curves. Collapses
|
|
34
34
|
the online output grid to the single full-load level, so the unit is either off
|
|
35
|
-
or running at ``c_max`` ({0, c_max}). Exact for a
|
|
35
|
+
or running at ``c_max`` ({0, c_max}). Exact for a linear (constant marginal)
|
|
36
36
|
heat rate, where the optimal load is always a corner; a downward-biased lower
|
|
37
37
|
bound for a steep (rising-marginal) curve, where the exact optimum runs at an
|
|
38
38
|
efficient part load the approximation cannot represent. Emits
|
|
39
|
-
|
|
39
|
+
``BangBangHedgeWarning``: hedges are far more sensitive than
|
|
40
40
|
values to the heat-curve approximation.
|
|
41
41
|
|
|
42
42
|
Direction-of-bias summary (the "documented direction" the tests assert)
|
|
@@ -70,17 +70,17 @@ from .plant import MaxCapacityCurve, PlantModel
|
|
|
70
70
|
|
|
71
71
|
|
|
72
72
|
class BangBangHedgeWarning(UserWarning):
|
|
73
|
-
"""Advisory that bang-bang state aggregation biases hedges far more than values
|
|
73
|
+
"""Advisory that bang-bang state aggregation biases hedges far more than values.
|
|
74
74
|
|
|
75
75
|
Collapsing the output grid to {0, c_max} pins the operating point to full load,
|
|
76
76
|
so the plant value loses only the (often small) part-load optionality. The
|
|
77
|
-
|
|
77
|
+
sensitivities (the deltas and critical-dispatch surfaces used to hedge) are
|
|
78
78
|
a different matter: they read the slope of value against price, and the
|
|
79
79
|
approximation replaces the true, curved heat-rate response with a single kink
|
|
80
80
|
at the on/off boundary. A hedge derived from a bang-bang model can therefore be
|
|
81
81
|
badly wrong even when the headline value looks reasonable. The approximation is
|
|
82
|
-
not rejected
|
|
83
|
-
negligible
|
|
82
|
+
not rejected: for a sufficiently steep heat curve the value error is genuinely
|
|
83
|
+
negligible, but the caller is warned so the choice is deliberate.
|
|
84
84
|
"""
|
|
85
85
|
|
|
86
86
|
|
|
@@ -109,7 +109,7 @@ def time_aggregate(
|
|
|
109
109
|
output_step: float | None = None,
|
|
110
110
|
discount_factors: Sequence[float] | None = None,
|
|
111
111
|
) -> DispatchSchedule:
|
|
112
|
-
"""Time-aggregation heuristic: solve on ``block_hours``-hour blocks, rescale
|
|
112
|
+
"""Time-aggregation heuristic: solve on ``block_hours``-hour blocks, rescale.
|
|
113
113
|
|
|
114
114
|
Each consecutive run of ``block_hours`` periods is averaged into one coarse
|
|
115
115
|
period (power, fuel, temperature, and — if supplied — discount factor), the
|
|
@@ -229,21 +229,21 @@ def horizon_divide(
|
|
|
229
229
|
output_step: float | None = None,
|
|
230
230
|
discount_factors: Sequence[float] | None = None,
|
|
231
231
|
) -> DispatchSchedule:
|
|
232
|
-
"""Horizon-division heuristic: solve independent sub-horizons and sum
|
|
232
|
+
"""Horizon-division heuristic: solve independent sub-horizons and sum.
|
|
233
233
|
|
|
234
234
|
The horizon is cut into consecutive sub-horizons of length ``sub_horizon`` (the
|
|
235
|
-
last may be shorter) that are solved
|
|
235
|
+
last may be shorter) that are solved independently by the deterministic DP and
|
|
236
236
|
concatenated; ``total_value`` is the sum of the sub-values. This is the weekly /
|
|
237
237
|
monthly sub-period heuristic that keeps each solve small.
|
|
238
238
|
|
|
239
|
-
Boundary-state approximation. Only the
|
|
239
|
+
Boundary-state approximation. Only the first sub-horizon sees the caller's
|
|
240
240
|
initial condition; every later sub-horizon restarts from a cold, restart-ready
|
|
241
|
-
|
|
242
|
-
decouples the subproblems
|
|
241
|
+
offline state. Dropping the true carried-over commitment state is exactly what
|
|
242
|
+
decouples the subproblems, and is the approximation. It is exact when the
|
|
243
243
|
periods decouple (zero start costs and non-binding min-run / min-down / ramp),
|
|
244
244
|
because the dispatch is then myopic and the start-up state is immaterial. It
|
|
245
|
-
|
|
246
|
-
restart cost), but it
|
|
245
|
+
typically understates value otherwise (each boundary can pay a spurious
|
|
246
|
+
restart cost), but it can overstate value when a binding min-run / min-down
|
|
247
247
|
constraint that would span a boundary in the full solve is artificially relaxed
|
|
248
248
|
by the cut.
|
|
249
249
|
|
|
@@ -335,34 +335,34 @@ def bang_bang(
|
|
|
335
335
|
output_step: float | None = None,
|
|
336
336
|
discount_factors: Sequence[float] | None = None,
|
|
337
337
|
) -> DispatchSchedule:
|
|
338
|
-
"""Bang-bang state aggregation: run at full load or off, {0, c_max}
|
|
338
|
+
"""Bang-bang state aggregation: run at full load or off, {0, c_max}.
|
|
339
339
|
|
|
340
340
|
Collapses the online output grid to a single full-load level so the unit is
|
|
341
|
-
either off or running at ``c_max
|
|
342
|
-
|
|
341
|
+
either off or running at ``c_max``, recommended for a sufficiently steep
|
|
342
|
+
heat-rate curve, where the optimal load is (almost)
|
|
343
343
|
always a corner. Implemented by solving the deterministic DP on a derived plant
|
|
344
344
|
whose ``c_min`` and ``c_max`` are both pinned to that full-load level; every
|
|
345
345
|
other operating characteristic (heat-rate curve, start costs, ramp, durations)
|
|
346
|
-
is unchanged. The input plant is
|
|
346
|
+
is unchanged. The input plant is not mutated: a new ``PlantModel`` is
|
|
347
347
|
derived.
|
|
348
348
|
|
|
349
|
-
Full-load level. With a constant capacity the pinned level
|
|
349
|
+
Full-load level. With a constant capacity the pinned level is ``c_max``. With a
|
|
350
350
|
temperature-dependent ``c_max(temp)`` the level is the horizon-minimum ``c_max``
|
|
351
351
|
(the largest constant full-output level feasible in every period); a period
|
|
352
352
|
whose capacity falls below the plant's own ``c_min`` makes the plant infeasible
|
|
353
353
|
there and is rejected, mirroring the deterministic solver's curve check.
|
|
354
354
|
|
|
355
|
-
Exactness and bias. For a
|
|
355
|
+
Exactness and bias. For a linear (constant-marginal) heat rate the per-MWh
|
|
356
356
|
margin is output-independent, so the exact optimum is a corner and bang-bang is
|
|
357
|
-
exact. For a
|
|
357
|
+
exact. For a steep (rising-marginal) curve the exact optimum may run at an
|
|
358
358
|
efficient part load that bang-bang cannot represent, so the value is a
|
|
359
|
-
|
|
359
|
+
downward-biased lower bound: whenever the full-load level is reachable in one
|
|
360
360
|
step (ramp rate >= operating range) the bang-bang on/off policy set is a strict
|
|
361
361
|
subset of the exact one, and restricting the load choice can only lose value.
|
|
362
362
|
|
|
363
|
-
Warning
|
|
363
|
+
Warning. Emits ``BangBangHedgeWarning``: hedges (sensitivities
|
|
364
364
|
and critical-dispatch surfaces) are far more sensitive than the value itself to
|
|
365
|
-
the heat-rate-curve approximation, because they read the
|
|
365
|
+
the heat-rate-curve approximation, because they read the slope of value
|
|
366
366
|
against price, which the single on/off kink distorts even where the value error
|
|
367
367
|
is negligible.
|
|
368
368
|
|
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
"""Perfect-foresight thermal dispatch
|
|
1
|
+
"""Perfect-foresight thermal dispatch.
|
|
2
2
|
|
|
3
3
|
``dispatch_deterministic`` solves the deterministic optimization of Appendix B
|
|
4
4
|
eq. B.1: with all prices, fuel costs and temperatures known in advance, it finds
|
|
5
5
|
the commitment-and-output schedule that maximizes total margin subject to the
|
|
6
6
|
operational and state-transition constraints. Because it optimizes over the
|
|
7
|
-
|
|
8
|
-
(stochastic) policy is tested against
|
|
9
|
-
dispatch_deterministic`` guarantee
|
|
10
|
-
stochastic engine). ``total_value`` is therefore the headline field.
|
|
7
|
+
fully known path, its value is the upper bound that any non-anticipating
|
|
8
|
+
(stochastic) policy is tested against: the ``dispatch_value <=
|
|
9
|
+
dispatch_deterministic`` guarantee. ``total_value`` is therefore the headline field.
|
|
11
10
|
|
|
12
11
|
Objective (eq. B.1), per period ``t`` when producing ``q_t``::
|
|
13
12
|
|
|
@@ -61,8 +60,8 @@ Conventions (documented, standard unit-commitment)
|
|
|
61
60
|
lag is not itself a "start".
|
|
62
61
|
- **Full availability.** The deterministic perfect-foresight benchmark assumes
|
|
63
62
|
no forced outages (derate multiplier ``M ≡ 1``); the plant's ``outage_rate``
|
|
64
|
-
``λ`` is consumed only by the stochastic model
|
|
65
|
-
|
|
63
|
+
``λ`` is consumed only by the stochastic model. Perfect foresight
|
|
64
|
+
and no outages is exactly what the upper-bound property needs.
|
|
66
65
|
- **Terminal condition.** No salvage or penalty at the horizon end: the unit may
|
|
67
66
|
finish online without having completed its min-run (finite-window truncation).
|
|
68
67
|
- **Discounting.** ``discount_factors`` (default all 1.0, matching eq. B.1's
|
|
@@ -112,8 +111,7 @@ class DispatchSchedule:
|
|
|
112
111
|
stopped: Whether the unit shuts down in the period.
|
|
113
112
|
margins: Per-period contribution to ``total_value`` (discounted cash
|
|
114
113
|
flow, net of any start cost); ``sum(margins) == total_value``.
|
|
115
|
-
total_value: The optimal total value
|
|
116
|
-
(Property 62).
|
|
114
|
+
total_value: The optimal total value, the perfect-foresight upper bound.
|
|
117
115
|
"""
|
|
118
116
|
|
|
119
117
|
outputs: tuple[float, ...]
|
|
@@ -335,8 +333,8 @@ def dispatch_deterministic(
|
|
|
335
333
|
discount_factors: Per-period discount factors (default all 1.0).
|
|
336
334
|
|
|
337
335
|
Returns:
|
|
338
|
-
The optimal
|
|
339
|
-
perfect-foresight upper bound
|
|
336
|
+
The optimal ``DispatchSchedule``; ``total_value`` is the
|
|
337
|
+
perfect-foresight upper bound.
|
|
340
338
|
|
|
341
339
|
Raises:
|
|
342
340
|
ValidationError: If the series are empty or of unequal length; if a
|
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
"""Stochastic dispatch valuation
|
|
1
|
+
"""Stochastic dispatch valuation.
|
|
2
2
|
|
|
3
3
|
``dispatch_value`` computes the risk-adjusted expected value of a thermal unit by
|
|
4
|
-
stochastic dynamic programming
|
|
5
|
-
solved by backward induction over the
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
stochastic dynamic programming: the Bellman recursion of Appendix B eqs. B.2-B.3
|
|
5
|
+
solved by backward induction over the same commitment state machine as
|
|
6
|
+
``quantvolt.assets.dispatch_deterministic``. Two solution methods are offered:
|
|
7
|
+
``method="tree"`` (recombining lattice / binomial-forest backward
|
|
8
8
|
induction) and ``method="lsm"`` (least-squares Monte Carlo, Longstaff-Schwartz).
|
|
9
|
-
Both return a
|
|
9
|
+
Both return a ``DispatchResult`` carrying the value and the four critical
|
|
10
10
|
exercise surfaces of eq. B.5 (start-up / shutdown / ramp-up / ramp-down).
|
|
11
11
|
|
|
12
12
|
Relationship to the deterministic benchmark
|
|
13
13
|
--------------------------------------------
|
|
14
|
-
The perfect-foresight optimum (
|
|
14
|
+
The perfect-foresight optimum (``dispatch_deterministic``, eq. B.1) is the
|
|
15
15
|
upper bound of any non-anticipating policy: valuing each realised path with
|
|
16
|
-
perfect foresight and averaging bounds the stochastic value from above
|
|
17
|
-
|
|
16
|
+
perfect foresight and averaging bounds the stochastic value from above.
|
|
17
|
+
This module reuses the deterministic module's private state
|
|
18
18
|
machine (the status codes, output grid, initial-state translation and the
|
|
19
19
|
feasible-transition enumerator ``_transitions``) so the two solvers optimise over
|
|
20
|
-
an identical feasible set
|
|
21
|
-
|
|
22
|
-
arithmetic is recomputed here (vectorised over scenarios);
|
|
23
|
-
feasibility logic is never duplicated. Should ``dispatch_deterministic``
|
|
24
|
-
need to change those helpers, this module must be revisited (documented coupling).
|
|
20
|
+
an identical feasible set: the reuse, not a re-implementation, is what makes
|
|
21
|
+
the upper-bound property hold exactly on shared conventions. Only the
|
|
22
|
+
immediate-cash-flow arithmetic is recomputed here (vectorised over scenarios);
|
|
23
|
+
the intricate feasibility logic is never duplicated. Should ``dispatch_deterministic``
|
|
24
|
+
ever need to change those helpers, this module must be revisited (documented coupling).
|
|
25
25
|
|
|
26
26
|
Reused state machine (see ``dispatch_deterministic`` for the full account)
|
|
27
27
|
--------------------------------------------------------------------------
|
|
@@ -35,42 +35,42 @@ so the Bellman continuation is the plain (undiscounted-further) sum of future
|
|
|
35
35
|
discounted cash flows -- equivalent to eq. B.2's stepwise ``e^{-r dt}`` when the
|
|
36
36
|
factors are ``e^{-r t dt}``.
|
|
37
37
|
|
|
38
|
-
The Markov state and the on-peak / off-peak split (
|
|
39
|
-
|
|
40
|
-
Appendix B stresses that an hourly power-price
|
|
38
|
+
The Markov state and the on-peak / off-peak split (eq. B.4)
|
|
39
|
+
-------------------------------------------------------------
|
|
40
|
+
Appendix B stresses that an hourly power-price sequence is not Markovian:
|
|
41
41
|
tomorrow's on-peak price depends on recent on-peak prices, only weakly on the
|
|
42
|
-
current off-peak price. The fix (eq. B.4) is to carry
|
|
43
|
-
|
|
44
|
-
Markov property.
|
|
45
|
-
definition
|
|
42
|
+
current off-peak price. The fix (eq. B.4) is to carry two power spot processes,
|
|
43
|
+
one on-peak, one off-peak, as separate state coordinates, restoring the
|
|
44
|
+
Markov property. ``DispatchFactorModel`` implements the split in the factor
|
|
45
|
+
definition: ``power_on_index`` and ``power_off_index`` name two coordinates of the
|
|
46
46
|
simulated log-forward state (they may coincide when every period shares a peak
|
|
47
|
-
kind), and ``peak_kinds[t]`` selects which coordinate is the
|
|
47
|
+
kind), and ``peak_kinds[t]`` selects which coordinate is the active spot price
|
|
48
48
|
for period ``t``. Both coordinates evolve on every step and both enter the LSM
|
|
49
49
|
regression basis / the lattice, so the conditioning information is the full
|
|
50
|
-
Markov state ``(P_on, P_off, G, ...)
|
|
50
|
+
Markov state ``(P_on, P_off, G, ...)``, exactly the eq. B.4 construction.
|
|
51
51
|
|
|
52
|
-
Risk-adjusted expectation
|
|
53
|
-
|
|
54
|
-
eq. B.2 optimises under a
|
|
52
|
+
Risk-adjusted expectation
|
|
53
|
+
--------------------------
|
|
54
|
+
eq. B.2 optimises under a risk-adjusted expectation ``E*``. The factor model's
|
|
55
55
|
per-step drift ``mu`` is therefore tagged with
|
|
56
|
-
|
|
57
|
-
requires
|
|
56
|
+
``quantvolt.numerics.risk_adjustment.DriftKind``, and ``dispatch_value``
|
|
57
|
+
requires ``DriftKind.RISK_NEUTRAL``: the
|
|
58
58
|
pricing / valuation measure in this library's vocabulary ("arbitrage-free
|
|
59
|
-
valuation only"). A
|
|
59
|
+
valuation only"). A ``DriftKind.PHYSICAL`` drift is rejected: valuing a
|
|
60
60
|
not-fully-hedgeable asset under the real-world measure would overstate its value,
|
|
61
61
|
the very failure this optimiser guards against. The caller forms the risk-adjusted
|
|
62
62
|
drift ``mu* = mu - lambda_S * sigma`` (eq. 10.5, via
|
|
63
|
-
|
|
64
|
-
tradable factor this collapses to the risk-neutral ``r - y
|
|
63
|
+
``quantvolt.numerics.risk_adjustment.risk_adjusted_drift``): for a fully
|
|
64
|
+
tradable factor this collapses to the risk-neutral ``r - y``, and tags it
|
|
65
65
|
``RISK_NEUTRAL`` to signal "this drift is under the pricing measure ``E*``".
|
|
66
66
|
|
|
67
67
|
Forced outages (the outage seam)
|
|
68
68
|
--------------------------------
|
|
69
69
|
An optional per-period ``availability`` vector ``M`` in ``(0, 1]`` derates the
|
|
70
70
|
capacity ceiling to ``M_t * c_max(S_t)`` for period ``t`` (eq. B.1's ``M_ti``). A
|
|
71
|
-
caller with an
|
|
72
|
-
``M_t = dataset.forced_outage_multiplier(period_hours, installed_capacity_mw)
|
|
73
|
-
|
|
71
|
+
caller with an ``quantvolt.market.outages.OutageDataset`` supplies
|
|
72
|
+
``M_t = dataset.forced_outage_multiplier(period_hours, installed_capacity_mw)``.
|
|
73
|
+
Online outputs above the derated ceiling become infeasible that
|
|
74
74
|
period; if the derated ceiling falls below ``c_min`` the unit is forced offline
|
|
75
75
|
(eq. B.1 constraint 5).
|
|
76
76
|
|
|
@@ -234,8 +234,8 @@ class DispatchDiagnostics:
|
|
|
234
234
|
class DispatchFactorModel:
|
|
235
235
|
"""Risk-adjusted factor dynamics driving stochastic dispatch (eqs. B.2-B.4).
|
|
236
236
|
|
|
237
|
-
The stochastic factors are correlated log-forwards evolved by the
|
|
238
|
-
engine ``ΔZ = mu + L·ε`` (GBM). At least a power and a gas coordinate are
|
|
237
|
+
The stochastic factors are correlated log-forwards evolved by the shared
|
|
238
|
+
simulation engine ``ΔZ = mu + L·ε`` (GBM). At least a power and a gas coordinate are
|
|
239
239
|
required; the on-peak / off-peak Markov split (eq. B.4) is expressed by naming
|
|
240
240
|
two power coordinates (which may coincide) and a per-period peak label.
|
|
241
241
|
Temperature is supplied deterministically (``temperatures``) -- it drives
|
|
@@ -245,13 +245,13 @@ class DispatchFactorModel:
|
|
|
245
245
|
Attributes:
|
|
246
246
|
log_forward0: Initial log-forward vector ``z0 = log F(0, ·)`` over the
|
|
247
247
|
flattened factor state, dimension ``D`` (``>= 2``).
|
|
248
|
-
drift: Per-step drift ``mu`` (length ``D``). Must be the
|
|
248
|
+
drift: Per-step drift ``mu`` (length ``D``). Must be the risk-adjusted
|
|
249
249
|
(pricing-measure) drift and is tagged by ``drift_kind``.
|
|
250
250
|
covariance: Per-step covariance ``C`` (``D x D``), assembled by
|
|
251
|
-
|
|
251
|
+
``quantvolt.numerics.monte_carlo.build_covariance``.
|
|
252
252
|
drift_kind: Measure tag on ``drift``; ``dispatch_value`` requires
|
|
253
|
-
|
|
254
|
-
peak_kinds: Per-period
|
|
253
|
+
``DriftKind.RISK_NEUTRAL``.
|
|
254
|
+
peak_kinds: Per-period ``PeakKind`` selecting the active power
|
|
255
255
|
coordinate; its length is the dispatch horizon ``H`` (``>= 1``).
|
|
256
256
|
temperatures: Per-period ambient temperature ``S_t`` (length ``H``).
|
|
257
257
|
power_on_index: Coordinate of ``z0`` used as the on-peak power spot.
|
|
@@ -335,11 +335,11 @@ class DispatchFactorModel:
|
|
|
335
335
|
return self.power_off_index
|
|
336
336
|
|
|
337
337
|
def simulate(self, seed: int, path_count: int, *, antithetic: bool = True) -> Vector:
|
|
338
|
-
"""Simulate ``(n_paths, H + 1, D)`` log-forward paths
|
|
338
|
+
"""Simulate ``(n_paths, H + 1, D)`` log-forward paths.
|
|
339
339
|
|
|
340
340
|
Record 0 is ``log_forward0``; record ``t + 1`` holds the prices realised in
|
|
341
|
-
dispatch period ``t``. Deterministic under ``seed
|
|
342
|
-
|
|
341
|
+
dispatch period ``t``. Deterministic under ``seed``, so a caller can
|
|
342
|
+
reproduce the exact scenario set.
|
|
343
343
|
"""
|
|
344
344
|
if self.drift.ndim == 1 and self.covariance.ndim == 2:
|
|
345
345
|
return simulate_correlated_forwards(
|
|
@@ -431,8 +431,8 @@ def _moves(
|
|
|
431
431
|
for eq. B.1 constraint 5): a running unit whose min-run timer has not yet reached
|
|
432
432
|
``d_min`` cannot use ``_transitions``'s own shutdown transition, so if the derate
|
|
433
433
|
also drops every ramp target below ``eff_capacity`` the state machine would offer
|
|
434
|
-
|
|
435
|
-
never has to consider (it assumes full availability
|
|
434
|
+
no feasible action at all, a dead end the reused deterministic state space
|
|
435
|
+
never has to consider (it assumes full availability). A physical
|
|
436
436
|
derating below ``c_min`` overrides the min-run rule (the unit cannot keep
|
|
437
437
|
producing regardless of the timer), so when no ordinary move survives the filter
|
|
438
438
|
a forced shutdown at zero cash is appended, mirroring the already-documented
|
|
@@ -1107,7 +1107,7 @@ _SOLVERS: dict[str, _Solver] = {"lsm": _dispatch_lsm, "tree": _dispatch_tree}
|
|
|
1107
1107
|
|
|
1108
1108
|
|
|
1109
1109
|
def _require_risk_adjusted_drift(drift_kind: DriftKind) -> None:
|
|
1110
|
-
"""Reject a physical drift for valuation (
|
|
1110
|
+
"""Reject a physical drift for valuation (mirror of the VaR guard).
|
|
1111
1111
|
|
|
1112
1112
|
Valuation optimises under the risk-adjusted expectation ``E*`` (eq. B.2), whose
|
|
1113
1113
|
drift is ``RISK_NEUTRAL`` in this library's ``DriftKind`` vocabulary
|
|
@@ -1141,12 +1141,12 @@ def dispatch_value(
|
|
|
1141
1141
|
antithetic: bool = True,
|
|
1142
1142
|
regression_basis_degree: int = 2,
|
|
1143
1143
|
) -> DispatchResult:
|
|
1144
|
-
"""Value ``plant`` under uncertainty by stochastic DP (eqs. B.2-B.3
|
|
1144
|
+
"""Value ``plant`` under uncertainty by stochastic DP (eqs. B.2-B.3).
|
|
1145
1145
|
|
|
1146
1146
|
Solves the Bellman recursion over the deterministic module's commitment state
|
|
1147
|
-
machine, under the risk-adjusted expectation carried by ``factor_model
|
|
1148
|
-
|
|
1149
|
-
off-peak Markov split
|
|
1147
|
+
machine, under the risk-adjusted expectation carried by ``factor_model``.
|
|
1148
|
+
See the module docstring for the state machine, the on-peak /
|
|
1149
|
+
off-peak Markov split, the risk-adjusted-drift requirement, the
|
|
1150
1150
|
forced-outage seam, and the critical-surface representation. All inputs are
|
|
1151
1151
|
validated before any computation and never mutated.
|
|
1152
1152
|
|
|
@@ -1157,7 +1157,7 @@ def dispatch_value(
|
|
|
1157
1157
|
temperature context (also fixes the horizon ``H``).
|
|
1158
1158
|
method: ``"lsm"`` (least-squares Monte Carlo) or ``"tree"`` (recombining
|
|
1159
1159
|
lattice); selected via a dispatch table.
|
|
1160
|
-
seed: Monte Carlo / lattice seed (
|
|
1160
|
+
seed: Monte Carlo / lattice seed (determinism); ``>= 0``.
|
|
1161
1161
|
path_count: Simulated paths for ``"lsm"`` (ignored by ``"tree"``); ``>= 1``.
|
|
1162
1162
|
output_step: Output-grid spacing (MW); defaults to the ramp rate.
|
|
1163
1163
|
availability: Optional per-period forced-outage multiplier ``M`` in
|
|
@@ -1170,7 +1170,7 @@ def dispatch_value(
|
|
|
1170
1170
|
initial_uptime: Producing periods already accrued (min-run).
|
|
1171
1171
|
initial_downtime: Periods already offline (start bucket / min-down); must be
|
|
1172
1172
|
``>= 1`` when not ``initial_online`` (delegated to the reused
|
|
1173
|
-
|
|
1173
|
+
``quantvolt.assets.dispatch_deterministic._initial_state``).
|
|
1174
1174
|
evaluation: Independent LSM policy-evaluation sample. By default, the fitted
|
|
1175
1175
|
policy is evaluated on ``path_count`` fresh paths using ``seed + 1``.
|
|
1176
1176
|
antithetic: Whether ``"lsm"``'s simulated paths use antithetic variates
|
|
@@ -1184,11 +1184,11 @@ def dispatch_value(
|
|
|
1184
1184
|
``"tree"``. Must be ``>= 1``.
|
|
1185
1185
|
|
|
1186
1186
|
Returns:
|
|
1187
|
-
The
|
|
1187
|
+
The ``DispatchResult`` (value + eq. B.5 critical surfaces).
|
|
1188
1188
|
|
|
1189
1189
|
Raises:
|
|
1190
1190
|
ValidationError: If ``method`` is unknown; if ``factor_model.drift`` is not
|
|
1191
|
-
risk-adjusted
|
|
1191
|
+
risk-adjusted; if ``path_count`` / ``seed`` /
|
|
1192
1192
|
``discount_factors`` / ``availability`` / ``regression_basis_degree`` are
|
|
1193
1193
|
out of range or mis-sized; if a plant curve is infeasible at a supplied
|
|
1194
1194
|
temperature; if ``initial_downtime < 1`` while offline; or if the initial
|