operange 0.1.0__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.
- operange-0.1.0/LICENSE +21 -0
- operange-0.1.0/MANIFEST.in +7 -0
- operange-0.1.0/PKG-INFO +247 -0
- operange-0.1.0/README.md +221 -0
- operange-0.1.0/docs/api.md +194 -0
- operange-0.1.0/docs/conf.py +18 -0
- operange-0.1.0/docs/engineering-changes.md +143 -0
- operange-0.1.0/docs/failure-distance.md +174 -0
- operange-0.1.0/docs/index.md +177 -0
- operange-0.1.0/docs/linear-dispatch.md +145 -0
- operange-0.1.0/docs/methods.md +100 -0
- operange-0.1.0/docs/pinch.md +164 -0
- operange-0.1.0/docs/startup.md +131 -0
- operange-0.1.0/examples/__init__.py +1 -0
- operange-0.1.0/examples/affine_utility.py +95 -0
- operange-0.1.0/examples/coupled_design.py +654 -0
- operange-0.1.0/examples/engineering_changes.py +97 -0
- operange-0.1.0/examples/failure_distance.py +74 -0
- operange-0.1.0/examples/heat_recovery.py +151 -0
- operange-0.1.0/examples/linear_dispatch.py +121 -0
- operange-0.1.0/examples/pinch.py +63 -0
- operange-0.1.0/examples/quadratic_residopt.py +273 -0
- operange-0.1.0/examples/reporting.py +366 -0
- operange-0.1.0/examples/startup.py +78 -0
- operange-0.1.0/examples/steam_header.py +99 -0
- operange-0.1.0/examples/thermal_storage.py +172 -0
- operange-0.1.0/notes/README.md +126 -0
- operange-0.1.0/notes/affine-process-adapter.md +204 -0
- operange-0.1.0/notes/coupled-design-experiment.md +237 -0
- operange-0.1.0/notes/dsl-primitives.md +176 -0
- operange-0.1.0/notes/evidence-and-backends.md +184 -0
- operange-0.1.0/notes/heat-recovery-example.md +195 -0
- operange-0.1.0/notes/package-boundary.md +150 -0
- operange-0.1.0/notes/quadratic-residopt-experiment.md +207 -0
- operange-0.1.0/notes/result-contract-cases.md +201 -0
- operange-0.1.0/notes/result-contract.md +269 -0
- operange-0.1.0/notes/roadmap.md +181 -0
- operange-0.1.0/notes/thermal-storage-example.md +197 -0
- operange-0.1.0/notes/uncertainty-and-recourse.md +188 -0
- operange-0.1.0/notes/uncertainty-geometries.md +242 -0
- operange-0.1.0/pyproject.toml +52 -0
- operange-0.1.0/setup.cfg +4 -0
- operange-0.1.0/src/operange/__init__.py +136 -0
- operange-0.1.0/src/operange/_affine_distance.py +341 -0
- operange-0.1.0/src/operange/_affine_distance_results.py +282 -0
- operange-0.1.0/src/operange/_basic_support.py +75 -0
- operange-0.1.0/src/operange/_change_contracts.py +271 -0
- operange-0.1.0/src/operange/_finite_audit.py +91 -0
- operange-0.1.0/src/operange/_geometry.py +226 -0
- operange-0.1.0/src/operange/_heat_cascade.py +128 -0
- operange-0.1.0/src/operange/_linear_process_results.py +223 -0
- operange-0.1.0/src/operange/_linear_recourse.py +213 -0
- operange-0.1.0/src/operange/_numeric.py +65 -0
- operange-0.1.0/src/operange/_pinch_results.py +198 -0
- operange-0.1.0/src/operange/_reference.py +65 -0
- operange-0.1.0/src/operange/_startup_results.py +307 -0
- operange-0.1.0/src/operange/_storage_reference.py +73 -0
- operange-0.1.0/src/operange/adapters.py +246 -0
- operange-0.1.0/src/operange/affine.py +332 -0
- operange-0.1.0/src/operange/affine_results.py +599 -0
- operange-0.1.0/src/operange/changes.py +373 -0
- operange-0.1.0/src/operange/claim.py +234 -0
- operange-0.1.0/src/operange/composition.py +179 -0
- operange-0.1.0/src/operange/contract_types.py +583 -0
- operange-0.1.0/src/operange/distance.py +51 -0
- operange-0.1.0/src/operange/domain_io.py +68 -0
- operange-0.1.0/src/operange/domains.py +331 -0
- operange-0.1.0/src/operange/engineering_results.py +494 -0
- operange-0.1.0/src/operange/experimental/__init__.py +1 -0
- operange-0.1.0/src/operange/experimental/_quadratic_bounds.py +161 -0
- operange-0.1.0/src/operange/experimental/_residopt_quadratic.py +181 -0
- operange-0.1.0/src/operange/experimental/quadratic.py +563 -0
- operange-0.1.0/src/operange/geometries.py +270 -0
- operange-0.1.0/src/operange/heat_recovery.py +354 -0
- operange-0.1.0/src/operange/heat_results.py +542 -0
- operange-0.1.0/src/operange/heat_sensitivity.py +309 -0
- operange-0.1.0/src/operange/linear.py +100 -0
- operange-0.1.0/src/operange/linear_process.py +230 -0
- operange-0.1.0/src/operange/pinch.py +272 -0
- operange-0.1.0/src/operange/policy.py +115 -0
- operange-0.1.0/src/operange/polytope.py +212 -0
- operange-0.1.0/src/operange/primitives.py +247 -0
- operange-0.1.0/src/operange/profiles.py +53 -0
- operange-0.1.0/src/operange/recourse.py +66 -0
- operange-0.1.0/src/operange/reference.py +102 -0
- operange-0.1.0/src/operange/results.py +87 -0
- operange-0.1.0/src/operange/startup.py +291 -0
- operange-0.1.0/src/operange/storage.py +459 -0
- operange-0.1.0/src/operange/storage_contract.py +488 -0
- operange-0.1.0/src/operange/storage_results.py +58 -0
- operange-0.1.0/src/operange/storage_types.py +154 -0
- operange-0.1.0/src/operange/vector.py +101 -0
- operange-0.1.0/src/operange.egg-info/PKG-INFO +247 -0
- operange-0.1.0/src/operange.egg-info/SOURCES.txt +114 -0
- operange-0.1.0/src/operange.egg-info/dependency_links.txt +1 -0
- operange-0.1.0/src/operange.egg-info/requires.txt +5 -0
- operange-0.1.0/src/operange.egg-info/top_level.txt +1 -0
- operange-0.1.0/tests/acceptance/wheel.py +334 -0
- operange-0.1.0/tests/fixtures/prototype_result_v1.json +3087 -0
- operange-0.1.0/tests/test_affine.py +544 -0
- operange-0.1.0/tests/test_affine_distance.py +491 -0
- operange-0.1.0/tests/test_changes.py +491 -0
- operange-0.1.0/tests/test_compact_results.py +163 -0
- operange-0.1.0/tests/test_coupled_design.py +197 -0
- operange-0.1.0/tests/test_dsl.py +482 -0
- operange-0.1.0/tests/test_examples.py +168 -0
- operange-0.1.0/tests/test_geometries.py +527 -0
- operange-0.1.0/tests/test_heat_recovery.py +371 -0
- operange-0.1.0/tests/test_linear_process.py +390 -0
- operange-0.1.0/tests/test_numerical_regressions.py +246 -0
- operange-0.1.0/tests/test_pinch.py +519 -0
- operange-0.1.0/tests/test_quadratic_experiment.py +329 -0
- operange-0.1.0/tests/test_release_boundary.py +84 -0
- operange-0.1.0/tests/test_result_contract.py +507 -0
- operange-0.1.0/tests/test_startup.py +359 -0
- operange-0.1.0/tests/test_storage.py +333 -0
operange-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 updatesupport contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
operange-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: operange
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Process-engineering sensitivity and robustness DSL with portable evidence
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Project-URL: Homepage, https://github.com/nahuaque/operange
|
|
7
|
+
Project-URL: Repository, https://github.com/nahuaque/operange
|
|
8
|
+
Project-URL: Documentation, https://nahuaque.github.io/operange/
|
|
9
|
+
Project-URL: Issues, https://github.com/nahuaque/operange/issues
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Science/Research
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Topic :: Scientific/Engineering
|
|
18
|
+
Requires-Python: >=3.10
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
License-File: LICENSE
|
|
21
|
+
Requires-Dist: numpy>=2.2.6
|
|
22
|
+
Requires-Dist: scipy>=1.15.3
|
|
23
|
+
Provides-Extra: cvxpy
|
|
24
|
+
Requires-Dist: cvxpy>=1.5; extra == "cvxpy"
|
|
25
|
+
Dynamic: license-file
|
|
26
|
+
|
|
27
|
+
# Operange
|
|
28
|
+
|
|
29
|
+
**Check whether a process can keep meeting its requirements as operating
|
|
30
|
+
conditions change, and identify what limits its flexibility.**
|
|
31
|
+
|
|
32
|
+
`operange` is a Python library for process engineers studying
|
|
33
|
+
uncertain loads, feed conditions, equipment capacities and operating decisions.
|
|
34
|
+
It provides a small engineering language for specifying a robustness study and
|
|
35
|
+
returning process values, sensitivities, failing conditions and the evidence
|
|
36
|
+
behind a verdict.
|
|
37
|
+
|
|
38
|
+
**Status:** alpha, developed as an independent project.
|
|
39
|
+
The implemented models are deliberately bounded; current capabilities are
|
|
40
|
+
listed below. The distribution is independent of `updatesupport` and requires
|
|
41
|
+
Python 3.10+, NumPy and SciPy. The development version is `0.1.0`.
|
|
42
|
+
|
|
43
|
+
## Install from this checkout
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
python -m pip install .
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Or build a wheel from the repository root and install it:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
uv build --wheel --out-dir dist
|
|
53
|
+
python -m pip install dist/operange-0.1.0-py3-none-any.whl
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Try the shared-steam example
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
from operange import (
|
|
60
|
+
AffineOutput, AffineProcessAdapter, AffineRequirement, AffineTerm,
|
|
61
|
+
BoxSet, BudgetSet, Parameter,
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
loads = BoxSet((
|
|
65
|
+
Parameter("dryer", "MW", 10, 8, 12, 2, "Synthetic dryer envelope"),
|
|
66
|
+
Parameter("evaporator", "MW", 6, 4, 8, 2, "Synthetic evaporator envelope"),
|
|
67
|
+
))
|
|
68
|
+
model = AffineProcessAdapter(
|
|
69
|
+
name="Shared steam header",
|
|
70
|
+
input_space=loads.space,
|
|
71
|
+
outputs=(AffineOutput(
|
|
72
|
+
"steam", "MW", "thermal_power", 0,
|
|
73
|
+
tuple(AffineTerm(n, 1, "MW/MW") for n in loads.space.names),
|
|
74
|
+
"Sum of process steam loads",
|
|
75
|
+
),),
|
|
76
|
+
requirements=(AffineRequirement("header_capacity", "steam", 19),),
|
|
77
|
+
)
|
|
78
|
+
claim = model.as_claim(loads)
|
|
79
|
+
print(claim.evaluate_result(loads.nominal).to_json())
|
|
80
|
+
print(claim.sensitivity_result(loads.nominal).to_json())
|
|
81
|
+
print(claim.audit_result().payload.verdict) # fail: peak demand is 20 MW
|
|
82
|
+
print(model.as_claim(BudgetSet(loads, 1)).audit_result().payload.verdict) # pass
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Nominal steam demand is 16 MW. The box permits both users to peak at once;
|
|
86
|
+
the budget allows only one full normalized deviation in total. Changing that
|
|
87
|
+
assumption creates a different claim, not an equipment repair.
|
|
88
|
+
|
|
89
|
+
The [getting-started guide](docs/index.md)
|
|
90
|
+
extends this model with a shared boiler, evidence inspection, an equipment
|
|
91
|
+
change and JSON round trips. The complete consumer example is
|
|
92
|
+
[`examples/steam_header.py`](examples/steam_header.py).
|
|
93
|
+
|
|
94
|
+
## What works today
|
|
95
|
+
|
|
96
|
+
| Model | Implemented questions | Scope |
|
|
97
|
+
| --- | --- | --- |
|
|
98
|
+
| Caller-declared affine model: constant plus weighted inputs and fixed controls | Point evaluation, analytical first sensitivities, requirement audits and boundary/positive-violation distances | Audits over supported uncertainty domains; distance searches over boxes and polytopes with explicit normalized L-infinity scales; controls remain fixed |
|
|
99
|
+
| Caller-declared linear model with bounded controls | Joint dispatch feasibility, finite-scenario audits and checked infeasibility witnesses | Fixed or fully observed single-stage operation; coupled equipment limits always apply; no dispatch derivatives or distance searches |
|
|
100
|
+
| Heat-recovery reference model | Heat-delivery evaluation, optimized-response sensitivities, full-box audits, feasibility boundary, positive-shortfall breaking search and engineering-change comparison | Static, constant COP, two uncertain inputs and fully observed electrical-power recourse |
|
|
101
|
+
| Thermal-storage reference model | Fixed, causal and perfect-foresight audits; conflicting futures; equipment and earlier-information changes | Complete declared finite two-period tree; no general trajectory solver or sensitivity operator |
|
|
102
|
+
| Supplied startup profiles | Peak and integrated load, shared-capacity audits and comparison of fixed start schedules | Finite amplitude/duration/timing scenarios; all time segments of the declared piecewise-linear profiles; no motor dynamics or adaptive scheduler |
|
|
103
|
+
| Heat-cascade reference model | Minimum heating/cooling targets, maximum heat recovery, pinch locations and utility-target audits | Finite steady-state sensible-heat scenarios at fixed ΔTmin; no installed exchanger-network feasibility or sensitivity operator |
|
|
104
|
+
|
|
105
|
+
The [linear dispatch guide](docs/linear-dispatch.md) adds two adjustable boilers
|
|
106
|
+
and a shared fuel supply. Redispatch handles either individual process-load peak;
|
|
107
|
+
the combined peak remains infeasible. Increasing the shared fuel capacity passes
|
|
108
|
+
all four declared scenarios. Each pass includes checked physical controls, and
|
|
109
|
+
each failure includes a constraint combination that rules out all permitted
|
|
110
|
+
controls. Solver termination alone cannot establish either conclusion.
|
|
111
|
+
|
|
112
|
+
The [failure-distance guide](docs/failure-distance.md) finds which fixed affine
|
|
113
|
+
requirement first reaches its limit. The shared steam header reaches its boundary
|
|
114
|
+
at normalized distance 0.75; a 0.01 MW violation requires distance 0.7525.
|
|
115
|
+
Distances carry verified lower and upper bounds, and an unresolved branch cannot
|
|
116
|
+
silently disappear from the search for the nearest failure.
|
|
117
|
+
|
|
118
|
+
The [engineering-change guide](docs/engineering-changes.md) uses one common API
|
|
119
|
+
to re-audit named candidate claims. It distinguishes equipment and operating
|
|
120
|
+
changes from revised domains or service requirements, retaining full audits,
|
|
121
|
+
witnesses and observed margins in a portable comparison. A passing candidate
|
|
122
|
+
is labelled `restored` only when it preserves the original commitment.
|
|
123
|
+
|
|
124
|
+
The [startup example](docs/startup.md)
|
|
125
|
+
keeps a compressor start distinct from ordinary load variation. Two synthetic
|
|
126
|
+
starts reach 700 kVA across the 65 declared scenarios; staggering the commands
|
|
127
|
+
reduces that maximum to 480 kVA against a 500 kVA limit. The uncertainty and
|
|
128
|
+
equipment remain unchanged. `PiecewiseLinearProfile` makes interpolation and
|
|
129
|
+
the running tail explicit, so the audit checks between supplied knots as well
|
|
130
|
+
as at them. Coverage does not extend to unmeasured waveform spikes or uncertain
|
|
131
|
+
values between the finite scenarios.
|
|
132
|
+
|
|
133
|
+
The [heat-cascade example](docs/pinch.md)
|
|
134
|
+
screens heat-integration targets across four steady operating cases. Nominal
|
|
135
|
+
heating needs 10 kW; reduced hot-stream flow or increased cold-stream flow each
|
|
136
|
+
raise it to 40 kW, while both together require 100 kW and exceed a 50 kW limit.
|
|
137
|
+
The pinch location changes between scenarios. A passing target screen does not
|
|
138
|
+
prove an installed exchanger network works: connections, area, fouling and
|
|
139
|
+
controls require a network model. Heat-cascade data are returned for downstream
|
|
140
|
+
use without plotting or economics in the package.
|
|
141
|
+
|
|
142
|
+
Uncertainty declarations include independent bounds (`BoxSet`), explicit finite
|
|
143
|
+
cases, fractions summing to one (`SimplexSet`), budgets limiting simultaneous
|
|
144
|
+
deviations, ellipsoids and linear coupled restrictions (`PolytopeSet`). Named
|
|
145
|
+
vector inputs and domain composition are also available. Representing a domain
|
|
146
|
+
does not automatically give every model an optimizer or a proof over it.
|
|
147
|
+
|
|
148
|
+
The intended model boundary can cover a coupled system, as the shared-utility
|
|
149
|
+
example does. Current implementations do not establish whole-plant scalability
|
|
150
|
+
or arbitrary nonlinear flowsheet robustness. External simulator adapters,
|
|
151
|
+
general dynamics, degradation, faults, model ensembles and distributional
|
|
152
|
+
ambiguity remain future work. Your model supplies the equations and consistent
|
|
153
|
+
units; the package does not supply thermodynamic property packages or automatic
|
|
154
|
+
unit conversion.
|
|
155
|
+
|
|
156
|
+
## The engineering question
|
|
157
|
+
|
|
158
|
+
Suppose a dryer and an evaporator share a steam header rated for 19 MW.
|
|
159
|
+
Their nominal demands are 10 MW and 6 MW, and each can vary by 2 MW.
|
|
160
|
+
|
|
161
|
+
| Operating condition | Steam demand | Within 19 MW capacity? |
|
|
162
|
+
| --- | --- | --- |
|
|
163
|
+
| Nominal production | 16 MW | Yes |
|
|
164
|
+
| Dryer at maximum, evaporator nominal | 18 MW | Yes |
|
|
165
|
+
| Evaporator at maximum, dryer nominal | 18 MW | Yes |
|
|
166
|
+
| Both at maximum | 20 MW | No |
|
|
167
|
+
|
|
168
|
+
Both individual demand increases fit. The combined increase does not. An audit
|
|
169
|
+
of the full declared load envelope finds this failing combination and identifies
|
|
170
|
+
the shared capacity constraint.
|
|
171
|
+
|
|
172
|
+
There are different engineering responses. A larger header can accommodate the
|
|
173
|
+
original load envelope. A scheduling restriction can prevent the two peaks
|
|
174
|
+
from coinciding, but that changes the operating commitment. Reducing required
|
|
175
|
+
production changes the service requirement. Keeping those distinctions explicit
|
|
176
|
+
is central to the package.
|
|
177
|
+
|
|
178
|
+
The same workflow applies to a supported model of heat recovery or storage:
|
|
179
|
+
which disturbance causes a requirement to fail, can permitted operating
|
|
180
|
+
adjustments recover it, and does a proposed engineering change withstand the
|
|
181
|
+
whole original envelope?
|
|
182
|
+
|
|
183
|
+
## What you specify, and what you get back
|
|
184
|
+
|
|
185
|
+
A study makes five things explicit:
|
|
186
|
+
|
|
187
|
+
1. **The process model and design.** Balances, capacities and calculated outputs,
|
|
188
|
+
such as steam demand, heat delivery or stored energy.
|
|
189
|
+
2. **What can vary together.** Bounds or coupled restrictions on uncertain
|
|
190
|
+
inputs, with units, nominal values and the source of those assumptions.
|
|
191
|
+
3. **What operators may adjust.** The allowed controls and when the information
|
|
192
|
+
needed to choose them becomes available.
|
|
193
|
+
4. **What must remain true.** Named engineering requirements, such as meeting
|
|
194
|
+
heat demand or staying within a shared utility capacity.
|
|
195
|
+
5. **The question to evaluate.** A particular operating point, a sensitivity,
|
|
196
|
+
an audit of the declared envelope, or a supported search for a nearby failure.
|
|
197
|
+
|
|
198
|
+
The outputs are structured engineering results for your own code to consume:
|
|
199
|
+
physical quantities and constraint margins; derivatives with their units and
|
|
200
|
+
operating assumptions; pass, fail or inconclusive audit outcomes; and witnesses,
|
|
201
|
+
bounds and coverage explaining what was established. A **witness** is a concrete
|
|
202
|
+
admissible condition, or a conflicting set of futures, that demonstrates failure
|
|
203
|
+
under the declared operating permissions.
|
|
204
|
+
|
|
205
|
+
A failed numerical solve is kept separate from physical infeasibility. A pass
|
|
206
|
+
over an explicitly finite set of scenarios has that finite scope. A nearest
|
|
207
|
+
failure is reported as such only when the search evidence supports it. Numerical
|
|
208
|
+
tolerances remain part of the result.
|
|
209
|
+
|
|
210
|
+
## Public API and evidence scope
|
|
211
|
+
|
|
212
|
+
- `operange`: shared DSL, uncertainty geometry, fixed affine model
|
|
213
|
+
adapter and typed `process_result/v1` results.
|
|
214
|
+
- `operange.reference`: bounded heat-recovery and two-period
|
|
215
|
+
storage models, supplied-startup profile audits, heat-cascade target audits,
|
|
216
|
+
and model-specific engineering changes and numerical records.
|
|
217
|
+
- `operange.experimental`: opt-in research APIs without a stability
|
|
218
|
+
promise. The residopt experiment is parked and adds no runtime dependency.
|
|
219
|
+
|
|
220
|
+
See the [API and capability guide](docs/api.md)
|
|
221
|
+
for supported declarations, result fields and model-specific restrictions.
|
|
222
|
+
Unsupported operations return explicit statuses rather than an inferred pass.
|
|
223
|
+
|
|
224
|
+
## Consumer examples
|
|
225
|
+
|
|
226
|
+
From the repository root:
|
|
227
|
+
|
|
228
|
+
```bash
|
|
229
|
+
uv run python -m examples.steam_header
|
|
230
|
+
uv run python -m examples.heat_recovery
|
|
231
|
+
uv run python -m examples.thermal_storage
|
|
232
|
+
uv run python -m examples.startup
|
|
233
|
+
uv run python -m examples.pinch
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
These repository examples own Markdown, prices, ranking and selected-repair
|
|
237
|
+
logic. They are not installed with the process wheel. Core repair comparisons
|
|
238
|
+
return engineering audits in caller order and do not select an investment.
|
|
239
|
+
|
|
240
|
+
Engineering results use `process_result/v1`. Saved result bundles and frozen
|
|
241
|
+
static heat contracts are tested against the installed wheel.
|
|
242
|
+
|
|
243
|
+
## Methods and background
|
|
244
|
+
|
|
245
|
+
See [methods, scope and design lineage](docs/methods.md) for the connections to
|
|
246
|
+
classical flexibility analysis, robust optimization, sensitivity methods,
|
|
247
|
+
downstream techno-economic analysis and the original `updatesupport` extraction.
|
operange-0.1.0/README.md
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
# Operange
|
|
2
|
+
|
|
3
|
+
**Check whether a process can keep meeting its requirements as operating
|
|
4
|
+
conditions change, and identify what limits its flexibility.**
|
|
5
|
+
|
|
6
|
+
`operange` is a Python library for process engineers studying
|
|
7
|
+
uncertain loads, feed conditions, equipment capacities and operating decisions.
|
|
8
|
+
It provides a small engineering language for specifying a robustness study and
|
|
9
|
+
returning process values, sensitivities, failing conditions and the evidence
|
|
10
|
+
behind a verdict.
|
|
11
|
+
|
|
12
|
+
**Status:** alpha, developed as an independent project.
|
|
13
|
+
The implemented models are deliberately bounded; current capabilities are
|
|
14
|
+
listed below. The distribution is independent of `updatesupport` and requires
|
|
15
|
+
Python 3.10+, NumPy and SciPy. The development version is `0.1.0`.
|
|
16
|
+
|
|
17
|
+
## Install from this checkout
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
python -m pip install .
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Or build a wheel from the repository root and install it:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
uv build --wheel --out-dir dist
|
|
27
|
+
python -m pip install dist/operange-0.1.0-py3-none-any.whl
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Try the shared-steam example
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
from operange import (
|
|
34
|
+
AffineOutput, AffineProcessAdapter, AffineRequirement, AffineTerm,
|
|
35
|
+
BoxSet, BudgetSet, Parameter,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
loads = BoxSet((
|
|
39
|
+
Parameter("dryer", "MW", 10, 8, 12, 2, "Synthetic dryer envelope"),
|
|
40
|
+
Parameter("evaporator", "MW", 6, 4, 8, 2, "Synthetic evaporator envelope"),
|
|
41
|
+
))
|
|
42
|
+
model = AffineProcessAdapter(
|
|
43
|
+
name="Shared steam header",
|
|
44
|
+
input_space=loads.space,
|
|
45
|
+
outputs=(AffineOutput(
|
|
46
|
+
"steam", "MW", "thermal_power", 0,
|
|
47
|
+
tuple(AffineTerm(n, 1, "MW/MW") for n in loads.space.names),
|
|
48
|
+
"Sum of process steam loads",
|
|
49
|
+
),),
|
|
50
|
+
requirements=(AffineRequirement("header_capacity", "steam", 19),),
|
|
51
|
+
)
|
|
52
|
+
claim = model.as_claim(loads)
|
|
53
|
+
print(claim.evaluate_result(loads.nominal).to_json())
|
|
54
|
+
print(claim.sensitivity_result(loads.nominal).to_json())
|
|
55
|
+
print(claim.audit_result().payload.verdict) # fail: peak demand is 20 MW
|
|
56
|
+
print(model.as_claim(BudgetSet(loads, 1)).audit_result().payload.verdict) # pass
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Nominal steam demand is 16 MW. The box permits both users to peak at once;
|
|
60
|
+
the budget allows only one full normalized deviation in total. Changing that
|
|
61
|
+
assumption creates a different claim, not an equipment repair.
|
|
62
|
+
|
|
63
|
+
The [getting-started guide](docs/index.md)
|
|
64
|
+
extends this model with a shared boiler, evidence inspection, an equipment
|
|
65
|
+
change and JSON round trips. The complete consumer example is
|
|
66
|
+
[`examples/steam_header.py`](examples/steam_header.py).
|
|
67
|
+
|
|
68
|
+
## What works today
|
|
69
|
+
|
|
70
|
+
| Model | Implemented questions | Scope |
|
|
71
|
+
| --- | --- | --- |
|
|
72
|
+
| Caller-declared affine model: constant plus weighted inputs and fixed controls | Point evaluation, analytical first sensitivities, requirement audits and boundary/positive-violation distances | Audits over supported uncertainty domains; distance searches over boxes and polytopes with explicit normalized L-infinity scales; controls remain fixed |
|
|
73
|
+
| Caller-declared linear model with bounded controls | Joint dispatch feasibility, finite-scenario audits and checked infeasibility witnesses | Fixed or fully observed single-stage operation; coupled equipment limits always apply; no dispatch derivatives or distance searches |
|
|
74
|
+
| Heat-recovery reference model | Heat-delivery evaluation, optimized-response sensitivities, full-box audits, feasibility boundary, positive-shortfall breaking search and engineering-change comparison | Static, constant COP, two uncertain inputs and fully observed electrical-power recourse |
|
|
75
|
+
| Thermal-storage reference model | Fixed, causal and perfect-foresight audits; conflicting futures; equipment and earlier-information changes | Complete declared finite two-period tree; no general trajectory solver or sensitivity operator |
|
|
76
|
+
| Supplied startup profiles | Peak and integrated load, shared-capacity audits and comparison of fixed start schedules | Finite amplitude/duration/timing scenarios; all time segments of the declared piecewise-linear profiles; no motor dynamics or adaptive scheduler |
|
|
77
|
+
| Heat-cascade reference model | Minimum heating/cooling targets, maximum heat recovery, pinch locations and utility-target audits | Finite steady-state sensible-heat scenarios at fixed ΔTmin; no installed exchanger-network feasibility or sensitivity operator |
|
|
78
|
+
|
|
79
|
+
The [linear dispatch guide](docs/linear-dispatch.md) adds two adjustable boilers
|
|
80
|
+
and a shared fuel supply. Redispatch handles either individual process-load peak;
|
|
81
|
+
the combined peak remains infeasible. Increasing the shared fuel capacity passes
|
|
82
|
+
all four declared scenarios. Each pass includes checked physical controls, and
|
|
83
|
+
each failure includes a constraint combination that rules out all permitted
|
|
84
|
+
controls. Solver termination alone cannot establish either conclusion.
|
|
85
|
+
|
|
86
|
+
The [failure-distance guide](docs/failure-distance.md) finds which fixed affine
|
|
87
|
+
requirement first reaches its limit. The shared steam header reaches its boundary
|
|
88
|
+
at normalized distance 0.75; a 0.01 MW violation requires distance 0.7525.
|
|
89
|
+
Distances carry verified lower and upper bounds, and an unresolved branch cannot
|
|
90
|
+
silently disappear from the search for the nearest failure.
|
|
91
|
+
|
|
92
|
+
The [engineering-change guide](docs/engineering-changes.md) uses one common API
|
|
93
|
+
to re-audit named candidate claims. It distinguishes equipment and operating
|
|
94
|
+
changes from revised domains or service requirements, retaining full audits,
|
|
95
|
+
witnesses and observed margins in a portable comparison. A passing candidate
|
|
96
|
+
is labelled `restored` only when it preserves the original commitment.
|
|
97
|
+
|
|
98
|
+
The [startup example](docs/startup.md)
|
|
99
|
+
keeps a compressor start distinct from ordinary load variation. Two synthetic
|
|
100
|
+
starts reach 700 kVA across the 65 declared scenarios; staggering the commands
|
|
101
|
+
reduces that maximum to 480 kVA against a 500 kVA limit. The uncertainty and
|
|
102
|
+
equipment remain unchanged. `PiecewiseLinearProfile` makes interpolation and
|
|
103
|
+
the running tail explicit, so the audit checks between supplied knots as well
|
|
104
|
+
as at them. Coverage does not extend to unmeasured waveform spikes or uncertain
|
|
105
|
+
values between the finite scenarios.
|
|
106
|
+
|
|
107
|
+
The [heat-cascade example](docs/pinch.md)
|
|
108
|
+
screens heat-integration targets across four steady operating cases. Nominal
|
|
109
|
+
heating needs 10 kW; reduced hot-stream flow or increased cold-stream flow each
|
|
110
|
+
raise it to 40 kW, while both together require 100 kW and exceed a 50 kW limit.
|
|
111
|
+
The pinch location changes between scenarios. A passing target screen does not
|
|
112
|
+
prove an installed exchanger network works: connections, area, fouling and
|
|
113
|
+
controls require a network model. Heat-cascade data are returned for downstream
|
|
114
|
+
use without plotting or economics in the package.
|
|
115
|
+
|
|
116
|
+
Uncertainty declarations include independent bounds (`BoxSet`), explicit finite
|
|
117
|
+
cases, fractions summing to one (`SimplexSet`), budgets limiting simultaneous
|
|
118
|
+
deviations, ellipsoids and linear coupled restrictions (`PolytopeSet`). Named
|
|
119
|
+
vector inputs and domain composition are also available. Representing a domain
|
|
120
|
+
does not automatically give every model an optimizer or a proof over it.
|
|
121
|
+
|
|
122
|
+
The intended model boundary can cover a coupled system, as the shared-utility
|
|
123
|
+
example does. Current implementations do not establish whole-plant scalability
|
|
124
|
+
or arbitrary nonlinear flowsheet robustness. External simulator adapters,
|
|
125
|
+
general dynamics, degradation, faults, model ensembles and distributional
|
|
126
|
+
ambiguity remain future work. Your model supplies the equations and consistent
|
|
127
|
+
units; the package does not supply thermodynamic property packages or automatic
|
|
128
|
+
unit conversion.
|
|
129
|
+
|
|
130
|
+
## The engineering question
|
|
131
|
+
|
|
132
|
+
Suppose a dryer and an evaporator share a steam header rated for 19 MW.
|
|
133
|
+
Their nominal demands are 10 MW and 6 MW, and each can vary by 2 MW.
|
|
134
|
+
|
|
135
|
+
| Operating condition | Steam demand | Within 19 MW capacity? |
|
|
136
|
+
| --- | --- | --- |
|
|
137
|
+
| Nominal production | 16 MW | Yes |
|
|
138
|
+
| Dryer at maximum, evaporator nominal | 18 MW | Yes |
|
|
139
|
+
| Evaporator at maximum, dryer nominal | 18 MW | Yes |
|
|
140
|
+
| Both at maximum | 20 MW | No |
|
|
141
|
+
|
|
142
|
+
Both individual demand increases fit. The combined increase does not. An audit
|
|
143
|
+
of the full declared load envelope finds this failing combination and identifies
|
|
144
|
+
the shared capacity constraint.
|
|
145
|
+
|
|
146
|
+
There are different engineering responses. A larger header can accommodate the
|
|
147
|
+
original load envelope. A scheduling restriction can prevent the two peaks
|
|
148
|
+
from coinciding, but that changes the operating commitment. Reducing required
|
|
149
|
+
production changes the service requirement. Keeping those distinctions explicit
|
|
150
|
+
is central to the package.
|
|
151
|
+
|
|
152
|
+
The same workflow applies to a supported model of heat recovery or storage:
|
|
153
|
+
which disturbance causes a requirement to fail, can permitted operating
|
|
154
|
+
adjustments recover it, and does a proposed engineering change withstand the
|
|
155
|
+
whole original envelope?
|
|
156
|
+
|
|
157
|
+
## What you specify, and what you get back
|
|
158
|
+
|
|
159
|
+
A study makes five things explicit:
|
|
160
|
+
|
|
161
|
+
1. **The process model and design.** Balances, capacities and calculated outputs,
|
|
162
|
+
such as steam demand, heat delivery or stored energy.
|
|
163
|
+
2. **What can vary together.** Bounds or coupled restrictions on uncertain
|
|
164
|
+
inputs, with units, nominal values and the source of those assumptions.
|
|
165
|
+
3. **What operators may adjust.** The allowed controls and when the information
|
|
166
|
+
needed to choose them becomes available.
|
|
167
|
+
4. **What must remain true.** Named engineering requirements, such as meeting
|
|
168
|
+
heat demand or staying within a shared utility capacity.
|
|
169
|
+
5. **The question to evaluate.** A particular operating point, a sensitivity,
|
|
170
|
+
an audit of the declared envelope, or a supported search for a nearby failure.
|
|
171
|
+
|
|
172
|
+
The outputs are structured engineering results for your own code to consume:
|
|
173
|
+
physical quantities and constraint margins; derivatives with their units and
|
|
174
|
+
operating assumptions; pass, fail or inconclusive audit outcomes; and witnesses,
|
|
175
|
+
bounds and coverage explaining what was established. A **witness** is a concrete
|
|
176
|
+
admissible condition, or a conflicting set of futures, that demonstrates failure
|
|
177
|
+
under the declared operating permissions.
|
|
178
|
+
|
|
179
|
+
A failed numerical solve is kept separate from physical infeasibility. A pass
|
|
180
|
+
over an explicitly finite set of scenarios has that finite scope. A nearest
|
|
181
|
+
failure is reported as such only when the search evidence supports it. Numerical
|
|
182
|
+
tolerances remain part of the result.
|
|
183
|
+
|
|
184
|
+
## Public API and evidence scope
|
|
185
|
+
|
|
186
|
+
- `operange`: shared DSL, uncertainty geometry, fixed affine model
|
|
187
|
+
adapter and typed `process_result/v1` results.
|
|
188
|
+
- `operange.reference`: bounded heat-recovery and two-period
|
|
189
|
+
storage models, supplied-startup profile audits, heat-cascade target audits,
|
|
190
|
+
and model-specific engineering changes and numerical records.
|
|
191
|
+
- `operange.experimental`: opt-in research APIs without a stability
|
|
192
|
+
promise. The residopt experiment is parked and adds no runtime dependency.
|
|
193
|
+
|
|
194
|
+
See the [API and capability guide](docs/api.md)
|
|
195
|
+
for supported declarations, result fields and model-specific restrictions.
|
|
196
|
+
Unsupported operations return explicit statuses rather than an inferred pass.
|
|
197
|
+
|
|
198
|
+
## Consumer examples
|
|
199
|
+
|
|
200
|
+
From the repository root:
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
uv run python -m examples.steam_header
|
|
204
|
+
uv run python -m examples.heat_recovery
|
|
205
|
+
uv run python -m examples.thermal_storage
|
|
206
|
+
uv run python -m examples.startup
|
|
207
|
+
uv run python -m examples.pinch
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
These repository examples own Markdown, prices, ranking and selected-repair
|
|
211
|
+
logic. They are not installed with the process wheel. Core repair comparisons
|
|
212
|
+
return engineering audits in caller order and do not select an investment.
|
|
213
|
+
|
|
214
|
+
Engineering results use `process_result/v1`. Saved result bundles and frozen
|
|
215
|
+
static heat contracts are tested against the installed wheel.
|
|
216
|
+
|
|
217
|
+
## Methods and background
|
|
218
|
+
|
|
219
|
+
See [methods, scope and design lineage](docs/methods.md) for the connections to
|
|
220
|
+
classical flexibility analysis, robust optimization, sensitivity methods,
|
|
221
|
+
downstream techno-economic analysis and the original `updatesupport` extraction.
|