fugacio-sim 0.2.0__tar.gz → 0.3.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.
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/PKG-INFO +48 -20
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/README.md +45 -17
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/pyproject.toml +2 -2
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/src/fugacio/sim/__init__.py +53 -2
- fugacio_sim-0.3.0/src/fugacio/sim/distillation.py +939 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/src/fugacio/sim/eo/__init__.py +8 -1
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/src/fugacio/sim/eo/blocks.py +397 -74
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/src/fugacio/sim/eo/flowsheet.py +19 -4
- fugacio_sim-0.3.0/src/fugacio/sim/flowsheet.py +704 -0
- fugacio_sim-0.3.0/src/fugacio/sim/heat_exchanger.py +358 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/src/fugacio/sim/models.py +103 -1
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/src/fugacio/sim/properties.py +142 -13
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/src/fugacio/sim/stream.py +3 -2
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/src/fugacio/sim/units.py +74 -56
- fugacio_sim-0.3.0/tests/test_distillation.py +145 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/tests/test_eo.py +62 -0
- fugacio_sim-0.3.0/tests/test_flowsheet.py +277 -0
- fugacio_sim-0.3.0/tests/test_heat_exchanger.py +110 -0
- fugacio_sim-0.3.0/tests/test_plants.py +290 -0
- fugacio_sim-0.2.0/src/fugacio/sim/flowsheet.py +0 -286
- fugacio_sim-0.2.0/tests/test_flowsheet.py +0 -117
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/.gitignore +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/src/fugacio/sim/column.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/src/fugacio/sim/control/__init__.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/src/fugacio/sim/control/blocks.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/src/fugacio/sim/control/linearize.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/src/fugacio/sim/control/metrics.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/src/fugacio/sim/control/pid.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/src/fugacio/sim/control/tuning.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/src/fugacio/sim/design.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/src/fugacio/sim/diagrams.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/src/fugacio/sim/dynamics/__init__.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/src/fugacio/sim/dynamics/flowsheet.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/src/fugacio/sim/dynamics/integrate.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/src/fugacio/sim/dynamics/optimize.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/src/fugacio/sim/dynamics/units.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/src/fugacio/sim/economics.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/src/fugacio/sim/eo/optimize.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/src/fugacio/sim/integration/__init__.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/src/fugacio/sim/integration/area.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/src/fugacio/sim/integration/network.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/src/fugacio/sim/integration/streams.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/src/fugacio/sim/integration/targeting.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/src/fugacio/sim/mpc/__init__.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/src/fugacio/sim/mpc/estimation.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/src/fugacio/sim/mpc/linear.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/src/fugacio/sim/mpc/nonlinear.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/src/fugacio/sim/mpc/qp.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/src/fugacio/sim/mpc/riccati.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/src/fugacio/sim/mpc/simulate.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/src/fugacio/sim/optimize.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/src/fugacio/sim/py.typed +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/src/fugacio/sim/reactive.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/src/fugacio/sim/reactors.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/src/fugacio/sim/separations.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/src/fugacio/sim/utilities.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/src/fugacio/sim/vle.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/tests/test_column_rigorous.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/tests/test_column_shortcut.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/tests/test_control.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/tests/test_design.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/tests/test_dynamic_flowsheet.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/tests/test_dynamic_optimize.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/tests/test_dynamic_oracles.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/tests/test_dynamic_units.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/tests/test_economics.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/tests/test_energy_units.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/tests/test_flowsheet_opt.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/tests/test_integrate.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/tests/test_integration.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/tests/test_integration_oracles.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/tests/test_mpc.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/tests/test_mpc_oracles.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/tests/test_nonideal.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/tests/test_optimize.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/tests/test_reactive.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/tests/test_reactors.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/tests/test_stream_properties.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/tests/test_units.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/tests/test_utilities.py +0 -0
- {fugacio_sim-0.2.0 → fugacio_sim-0.3.0}/tests/test_vle.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: fugacio-sim
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Differentiable steady-state and dynamic process flowsheet simulator (Fugacio).
|
|
5
5
|
Author-email: Owen Carey <37121709+owenthcarey@users.noreply.github.com>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -10,7 +10,7 @@ Classifier: Intended Audience :: Science/Research
|
|
|
10
10
|
Classifier: Programming Language :: Python :: 3
|
|
11
11
|
Classifier: Topic :: Scientific/Engineering :: Chemistry
|
|
12
12
|
Requires-Python: >=3.11
|
|
13
|
-
Requires-Dist: fugacio-thermo==0.
|
|
13
|
+
Requires-Dist: fugacio-thermo==0.3.0
|
|
14
14
|
Requires-Dist: jax>=0.4.34
|
|
15
15
|
Description-Content-Type: text/markdown
|
|
16
16
|
|
|
@@ -34,6 +34,15 @@ Any `Stream` has a two-phase-aware enthalpy and entropy (via the
|
|
|
34
34
|
just material balances: `molar_enthalpy`, `molar_entropy`, `enthalpy_flow`,
|
|
35
35
|
`entropy_flow`, `mass_flow`, `molar_mass`.
|
|
36
36
|
|
|
37
|
+
## Property packages
|
|
38
|
+
|
|
39
|
+
Every energy-balanced unit, the rigorous column, the two-sided heat exchanger,
|
|
40
|
+
and the equation-oriented engine take a `model=` argument: a
|
|
41
|
+
`fugacio.thermo.PropertyPackage` built with `package_for(components, method)`
|
|
42
|
+
for any method in `METHODS` (`"pr"`, `"srk"`, `"rk"`, `"vdw"`, `"nrtl"`,
|
|
43
|
+
`"uniquac"`, `"unifac"`, `"dortmund"`, `"pcsaft"`, `"iapws"`). Omitting it keeps
|
|
44
|
+
the Peng-Robinson default.
|
|
45
|
+
|
|
37
46
|
## Unit operations (rigorous material + energy balances)
|
|
38
47
|
|
|
39
48
|
- `flash_drum`: isothermal-isobaric vapour/liquid separator.
|
|
@@ -43,15 +52,22 @@ just material balances: `molar_enthalpy`, `molar_entropy`, `enthalpy_flow`,
|
|
|
43
52
|
- `compressor` / `turbine`: isentropic machines with an efficiency.
|
|
44
53
|
- `mix`: adiabatic, energy-balanced mixer (exact material balance).
|
|
45
54
|
- `splitter` / `component_separator`: flow split and idealised component split.
|
|
55
|
+
- `heat_exchanger`: two-sided countercurrent (or parallel) exchanger with
|
|
56
|
+
rigorous T-Q curves on both sides, zone-wise LMTD, and one closing spec
|
|
57
|
+
(`duty`, `t_hot_out`, `t_cold_out`, `min_approach`, or `ua`); each side may
|
|
58
|
+
use its own property package.
|
|
46
59
|
- `bubble_pressure` / `antoine_psat`: lightweight modified-Raoult helpers.
|
|
47
60
|
|
|
48
61
|
## Flowsheets with recycle
|
|
49
62
|
|
|
50
63
|
`tear_solve` closes a recycle by solving the tear fixed point
|
|
51
|
-
`tear = g(tear, theta)`
|
|
52
|
-
differentiates the *converged* flowsheet by the implicit
|
|
53
|
-
gradient through the recycle costs one adjoint solve
|
|
54
|
-
count. `Flowsheet` is
|
|
64
|
+
`tear = g(tear, theta)` by Wegstein acceleration, Broyden, or full Newton
|
|
65
|
+
(`method=`), and differentiates the *converged* flowsheet by the implicit
|
|
66
|
+
function theorem: a gradient through the recycle costs one adjoint solve
|
|
67
|
+
regardless of iteration count. `Flowsheet` is the declarative builder on top of
|
|
68
|
+
it: register feeds and units in any order and `partition` finds the strongly
|
|
69
|
+
connected blocks (Tarjan), orders them, and selects the tear streams; `solve`
|
|
70
|
+
converges every loop and returns all named streams, differentiable in `theta`.
|
|
55
71
|
|
|
56
72
|
## Equation-oriented flowsheeting
|
|
57
73
|
|
|
@@ -64,8 +80,9 @@ the converged plant is differentiable by the implicit function theorem,
|
|
|
64
80
|
`degrees_of_freedom` checks the unknown/equation balance, and
|
|
65
81
|
`optimize_flowsheet_eo` runs nested or full-space simultaneous optimization. The
|
|
66
82
|
blocks mirror the sequential-modular units (`Mixer`, `Splitter`, `Heater`,
|
|
67
|
-
`Valve`, `Pump`, `Compressor`, `Turbine`, `Flash`, `ComponentSeparator`),
|
|
68
|
-
|
|
83
|
+
`Valve`, `Pump`, `Compressor`, `Turbine`, `Flash`, `ComponentSeparator`), plus
|
|
84
|
+
`HeatExchanger`, `StoichiometricReactor`, and `Column` (an embedded rigorous
|
|
85
|
+
MESH column), so the two engines agree on any flowsheet both can express.
|
|
69
86
|
|
|
70
87
|
```python
|
|
71
88
|
import jax.numpy as jnp
|
|
@@ -92,9 +109,15 @@ sol["vapor"].total
|
|
|
92
109
|
- **Shortcut** (Fenske-Underwood-Gilliland): `fenske_min_stages`,
|
|
93
110
|
`underwood_min_reflux`, `gilliland_stages`, `kirkbride_feed_stage`, and the
|
|
94
111
|
`shortcut_column` wrapper.
|
|
95
|
-
- **Rigorous** `
|
|
96
|
-
|
|
97
|
-
|
|
112
|
+
- **Rigorous MESH** `rigorous_column`: simultaneous-correction
|
|
113
|
+
(Naphtali-Sandholm) column with full stage energy balances on any property
|
|
114
|
+
package; multiple feeds (`ColumnFeed`), side draws, stage duties, a pressure
|
|
115
|
+
profile, Murphree efficiency, total/partial/no condenser, kettle/no reboiler,
|
|
116
|
+
and design specs as equations (`reflux_ratio`, `distillate_rate`,
|
|
117
|
+
`bottoms_rate`, `boilup_ratio`, `condenser_duty`, `purity`, `recovery`,
|
|
118
|
+
`component_flow`, `stage_temperature`). `absorber` and `stripper` wrap it.
|
|
119
|
+
- **Constant molar overflow** `solve_column`: the lighter Wang-Henke
|
|
120
|
+
bubble-point column, kept for quick estimates.
|
|
98
121
|
|
|
99
122
|
## Non-ideal separations & diagrams
|
|
100
123
|
|
|
@@ -168,16 +191,21 @@ recycle = tear_solve(one_pass, guess, {"T": 320.0, "P": 20e5, "r": 0.5})
|
|
|
168
191
|
```python
|
|
169
192
|
import jax
|
|
170
193
|
import jax.numpy as jnp
|
|
171
|
-
from fugacio.sim import Stream,
|
|
194
|
+
from fugacio.sim import ColumnFeed, Stream, distillate_rate, purity, reflux_ratio, rigorous_column
|
|
172
195
|
|
|
173
196
|
feed = Stream.from_fractions(("propane", "n-butane"), jnp.array([0.5, 0.5]), 100.0, 320.0, 10e5)
|
|
174
|
-
col =
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
#
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
197
|
+
col = rigorous_column([ColumnFeed(feed, 6)], 12, p=10e5,
|
|
198
|
+
specs=[reflux_ratio(2.0), distillate_rate(50.0)])
|
|
199
|
+
col.distillate.z # propane overhead
|
|
200
|
+
col.reboiler_duty, col.t # duty from the stage energy balances; T profile
|
|
201
|
+
|
|
202
|
+
# Impose the purity instead and ask for the reflux it takes, and its energy cost:
|
|
203
|
+
def reboiler_duty(x_target):
|
|
204
|
+
res = rigorous_column([ColumnFeed(feed, 6)], 12, p=10e5,
|
|
205
|
+
specs=[distillate_rate(50.0), purity("distillate", 0, x_target)])
|
|
206
|
+
return res.reboiler_duty
|
|
207
|
+
|
|
208
|
+
jax.grad(reboiler_duty)(0.97) # W per unit mole fraction, exact
|
|
181
209
|
```
|
|
182
210
|
|
|
183
211
|
Part of the `fugacio` namespace; installs independently:
|
|
@@ -18,6 +18,15 @@ Any `Stream` has a two-phase-aware enthalpy and entropy (via the
|
|
|
18
18
|
just material balances: `molar_enthalpy`, `molar_entropy`, `enthalpy_flow`,
|
|
19
19
|
`entropy_flow`, `mass_flow`, `molar_mass`.
|
|
20
20
|
|
|
21
|
+
## Property packages
|
|
22
|
+
|
|
23
|
+
Every energy-balanced unit, the rigorous column, the two-sided heat exchanger,
|
|
24
|
+
and the equation-oriented engine take a `model=` argument: a
|
|
25
|
+
`fugacio.thermo.PropertyPackage` built with `package_for(components, method)`
|
|
26
|
+
for any method in `METHODS` (`"pr"`, `"srk"`, `"rk"`, `"vdw"`, `"nrtl"`,
|
|
27
|
+
`"uniquac"`, `"unifac"`, `"dortmund"`, `"pcsaft"`, `"iapws"`). Omitting it keeps
|
|
28
|
+
the Peng-Robinson default.
|
|
29
|
+
|
|
21
30
|
## Unit operations (rigorous material + energy balances)
|
|
22
31
|
|
|
23
32
|
- `flash_drum`: isothermal-isobaric vapour/liquid separator.
|
|
@@ -27,15 +36,22 @@ just material balances: `molar_enthalpy`, `molar_entropy`, `enthalpy_flow`,
|
|
|
27
36
|
- `compressor` / `turbine`: isentropic machines with an efficiency.
|
|
28
37
|
- `mix`: adiabatic, energy-balanced mixer (exact material balance).
|
|
29
38
|
- `splitter` / `component_separator`: flow split and idealised component split.
|
|
39
|
+
- `heat_exchanger`: two-sided countercurrent (or parallel) exchanger with
|
|
40
|
+
rigorous T-Q curves on both sides, zone-wise LMTD, and one closing spec
|
|
41
|
+
(`duty`, `t_hot_out`, `t_cold_out`, `min_approach`, or `ua`); each side may
|
|
42
|
+
use its own property package.
|
|
30
43
|
- `bubble_pressure` / `antoine_psat`: lightweight modified-Raoult helpers.
|
|
31
44
|
|
|
32
45
|
## Flowsheets with recycle
|
|
33
46
|
|
|
34
47
|
`tear_solve` closes a recycle by solving the tear fixed point
|
|
35
|
-
`tear = g(tear, theta)`
|
|
36
|
-
differentiates the *converged* flowsheet by the implicit
|
|
37
|
-
gradient through the recycle costs one adjoint solve
|
|
38
|
-
count. `Flowsheet` is
|
|
48
|
+
`tear = g(tear, theta)` by Wegstein acceleration, Broyden, or full Newton
|
|
49
|
+
(`method=`), and differentiates the *converged* flowsheet by the implicit
|
|
50
|
+
function theorem: a gradient through the recycle costs one adjoint solve
|
|
51
|
+
regardless of iteration count. `Flowsheet` is the declarative builder on top of
|
|
52
|
+
it: register feeds and units in any order and `partition` finds the strongly
|
|
53
|
+
connected blocks (Tarjan), orders them, and selects the tear streams; `solve`
|
|
54
|
+
converges every loop and returns all named streams, differentiable in `theta`.
|
|
39
55
|
|
|
40
56
|
## Equation-oriented flowsheeting
|
|
41
57
|
|
|
@@ -48,8 +64,9 @@ the converged plant is differentiable by the implicit function theorem,
|
|
|
48
64
|
`degrees_of_freedom` checks the unknown/equation balance, and
|
|
49
65
|
`optimize_flowsheet_eo` runs nested or full-space simultaneous optimization. The
|
|
50
66
|
blocks mirror the sequential-modular units (`Mixer`, `Splitter`, `Heater`,
|
|
51
|
-
`Valve`, `Pump`, `Compressor`, `Turbine`, `Flash`, `ComponentSeparator`),
|
|
52
|
-
|
|
67
|
+
`Valve`, `Pump`, `Compressor`, `Turbine`, `Flash`, `ComponentSeparator`), plus
|
|
68
|
+
`HeatExchanger`, `StoichiometricReactor`, and `Column` (an embedded rigorous
|
|
69
|
+
MESH column), so the two engines agree on any flowsheet both can express.
|
|
53
70
|
|
|
54
71
|
```python
|
|
55
72
|
import jax.numpy as jnp
|
|
@@ -76,9 +93,15 @@ sol["vapor"].total
|
|
|
76
93
|
- **Shortcut** (Fenske-Underwood-Gilliland): `fenske_min_stages`,
|
|
77
94
|
`underwood_min_reflux`, `gilliland_stages`, `kirkbride_feed_stage`, and the
|
|
78
95
|
`shortcut_column` wrapper.
|
|
79
|
-
- **Rigorous** `
|
|
80
|
-
|
|
81
|
-
|
|
96
|
+
- **Rigorous MESH** `rigorous_column`: simultaneous-correction
|
|
97
|
+
(Naphtali-Sandholm) column with full stage energy balances on any property
|
|
98
|
+
package; multiple feeds (`ColumnFeed`), side draws, stage duties, a pressure
|
|
99
|
+
profile, Murphree efficiency, total/partial/no condenser, kettle/no reboiler,
|
|
100
|
+
and design specs as equations (`reflux_ratio`, `distillate_rate`,
|
|
101
|
+
`bottoms_rate`, `boilup_ratio`, `condenser_duty`, `purity`, `recovery`,
|
|
102
|
+
`component_flow`, `stage_temperature`). `absorber` and `stripper` wrap it.
|
|
103
|
+
- **Constant molar overflow** `solve_column`: the lighter Wang-Henke
|
|
104
|
+
bubble-point column, kept for quick estimates.
|
|
82
105
|
|
|
83
106
|
## Non-ideal separations & diagrams
|
|
84
107
|
|
|
@@ -152,16 +175,21 @@ recycle = tear_solve(one_pass, guess, {"T": 320.0, "P": 20e5, "r": 0.5})
|
|
|
152
175
|
```python
|
|
153
176
|
import jax
|
|
154
177
|
import jax.numpy as jnp
|
|
155
|
-
from fugacio.sim import Stream,
|
|
178
|
+
from fugacio.sim import ColumnFeed, Stream, distillate_rate, purity, reflux_ratio, rigorous_column
|
|
156
179
|
|
|
157
180
|
feed = Stream.from_fractions(("propane", "n-butane"), jnp.array([0.5, 0.5]), 100.0, 320.0, 10e5)
|
|
158
|
-
col =
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
#
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
181
|
+
col = rigorous_column([ColumnFeed(feed, 6)], 12, p=10e5,
|
|
182
|
+
specs=[reflux_ratio(2.0), distillate_rate(50.0)])
|
|
183
|
+
col.distillate.z # propane overhead
|
|
184
|
+
col.reboiler_duty, col.t # duty from the stage energy balances; T profile
|
|
185
|
+
|
|
186
|
+
# Impose the purity instead and ask for the reflux it takes, and its energy cost:
|
|
187
|
+
def reboiler_duty(x_target):
|
|
188
|
+
res = rigorous_column([ColumnFeed(feed, 6)], 12, p=10e5,
|
|
189
|
+
specs=[distillate_rate(50.0), purity("distillate", 0, x_target)])
|
|
190
|
+
return res.reboiler_duty
|
|
191
|
+
|
|
192
|
+
jax.grad(reboiler_duty)(0.97) # W per unit mole fraction, exact
|
|
165
193
|
```
|
|
166
194
|
|
|
167
195
|
Part of the `fugacio` namespace; installs independently:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "fugacio-sim"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.3.0"
|
|
4
4
|
description = "Differentiable steady-state and dynamic process flowsheet simulator (Fugacio)."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.11"
|
|
@@ -22,7 +22,7 @@ classifiers = [
|
|
|
22
22
|
"Topic :: Scientific/Engineering :: Chemistry",
|
|
23
23
|
]
|
|
24
24
|
dependencies = [
|
|
25
|
-
"fugacio-thermo==0.
|
|
25
|
+
"fugacio-thermo==0.3.0",
|
|
26
26
|
"jax>=0.4.34",
|
|
27
27
|
]
|
|
28
28
|
|
|
@@ -116,6 +116,27 @@ from fugacio.sim.diagrams import (
|
|
|
116
116
|
residue_curve_map,
|
|
117
117
|
txy_diagram,
|
|
118
118
|
)
|
|
119
|
+
from fugacio.sim.distillation import (
|
|
120
|
+
ColumnFeed,
|
|
121
|
+
ColumnSpec,
|
|
122
|
+
RigorousColumnResult,
|
|
123
|
+
SideDraw,
|
|
124
|
+
StageDuty,
|
|
125
|
+
absorber,
|
|
126
|
+
boilup_ratio,
|
|
127
|
+
bottoms_rate,
|
|
128
|
+
component_flow,
|
|
129
|
+
condenser_duty,
|
|
130
|
+
distillate_rate,
|
|
131
|
+
purity,
|
|
132
|
+
reboiler_duty,
|
|
133
|
+
recovery,
|
|
134
|
+
reflux_rate,
|
|
135
|
+
reflux_ratio,
|
|
136
|
+
rigorous_column,
|
|
137
|
+
stage_temperature,
|
|
138
|
+
stripper,
|
|
139
|
+
)
|
|
119
140
|
from fugacio.sim.dynamics import (
|
|
120
141
|
DynamicCSTR,
|
|
121
142
|
DynamicEstimateResult,
|
|
@@ -184,7 +205,8 @@ from fugacio.sim.eo import (
|
|
|
184
205
|
Valve,
|
|
185
206
|
optimize_flowsheet_eo,
|
|
186
207
|
)
|
|
187
|
-
from fugacio.sim.flowsheet import Flowsheet, tear_solve
|
|
208
|
+
from fugacio.sim.flowsheet import TEAR_METHODS, Flowsheet, Partition, tear_solve
|
|
209
|
+
from fugacio.sim.heat_exchanger import HeatExchangerResult, heat_exchanger
|
|
188
210
|
from fugacio.sim.integration import (
|
|
189
211
|
CompositeCurves,
|
|
190
212
|
Exchanger,
|
|
@@ -213,9 +235,12 @@ from fugacio.sim.integration import (
|
|
|
213
235
|
verify_network,
|
|
214
236
|
)
|
|
215
237
|
from fugacio.sim.models import (
|
|
238
|
+
METHODS,
|
|
216
239
|
UnifacModel,
|
|
217
240
|
eos_model_for,
|
|
241
|
+
helmholtz_package_for,
|
|
218
242
|
nrtl_model_for,
|
|
243
|
+
package_for,
|
|
219
244
|
saft_model_for,
|
|
220
245
|
unifac_model_for,
|
|
221
246
|
uniquac_model_for,
|
|
@@ -331,12 +356,16 @@ from fugacio.sim.vle import antoine_psat, bubble_pressure
|
|
|
331
356
|
__all__ = [
|
|
332
357
|
"CEPCI_DEFAULT",
|
|
333
358
|
"CEPCI_REF",
|
|
359
|
+
"METHODS",
|
|
334
360
|
"PID",
|
|
335
361
|
"STEAM_LEVELS",
|
|
362
|
+
"TEAR_METHODS",
|
|
336
363
|
"AzeotropeResult",
|
|
337
364
|
"Block",
|
|
338
365
|
"ClosedLoop",
|
|
366
|
+
"ColumnFeed",
|
|
339
367
|
"ColumnResult",
|
|
368
|
+
"ColumnSpec",
|
|
340
369
|
"ComponentSeparator",
|
|
341
370
|
"CompositeCurves",
|
|
342
371
|
"Compressor",
|
|
@@ -365,6 +394,7 @@ __all__ = [
|
|
|
365
394
|
"GrandComposite",
|
|
366
395
|
"HeatCascade",
|
|
367
396
|
"HeatExchangerNetwork",
|
|
397
|
+
"HeatExchangerResult",
|
|
368
398
|
"HeatStream",
|
|
369
399
|
"Heater",
|
|
370
400
|
"HeaterResult",
|
|
@@ -383,6 +413,7 @@ __all__ = [
|
|
|
383
413
|
"OptimalDtMin",
|
|
384
414
|
"OptimizeResult",
|
|
385
415
|
"PIDState",
|
|
416
|
+
"Partition",
|
|
386
417
|
"PinchResult",
|
|
387
418
|
"Pump",
|
|
388
419
|
"PumpResult",
|
|
@@ -393,10 +424,13 @@ __all__ = [
|
|
|
393
424
|
"ReactiveFlashResult",
|
|
394
425
|
"ReactorResult",
|
|
395
426
|
"ResidueCurve",
|
|
427
|
+
"RigorousColumnResult",
|
|
396
428
|
"Scales",
|
|
397
429
|
"ShortcutResult",
|
|
430
|
+
"SideDraw",
|
|
398
431
|
"SpecResult",
|
|
399
432
|
"Splitter",
|
|
433
|
+
"StageDuty",
|
|
400
434
|
"StateSpace",
|
|
401
435
|
"SteamHeatingResult",
|
|
402
436
|
"SteamTurbineResult",
|
|
@@ -412,6 +446,7 @@ __all__ = [
|
|
|
412
446
|
"Utility",
|
|
413
447
|
"Valve",
|
|
414
448
|
"WorkResult",
|
|
449
|
+
"absorber",
|
|
415
450
|
"amigo",
|
|
416
451
|
"annualized_capital",
|
|
417
452
|
"antoine_psat",
|
|
@@ -422,6 +457,8 @@ __all__ = [
|
|
|
422
457
|
"bare_module_cost",
|
|
423
458
|
"batch_reactor",
|
|
424
459
|
"bode",
|
|
460
|
+
"boilup_ratio",
|
|
461
|
+
"bottoms_rate",
|
|
425
462
|
"bubble_pressure",
|
|
426
463
|
"c2d",
|
|
427
464
|
"capital_cost_target",
|
|
@@ -432,10 +469,12 @@ __all__ = [
|
|
|
432
469
|
"column_diameter",
|
|
433
470
|
"column_diameter_for",
|
|
434
471
|
"column_height",
|
|
472
|
+
"component_flow",
|
|
435
473
|
"component_separator",
|
|
436
474
|
"composite_curves",
|
|
437
475
|
"compressor",
|
|
438
476
|
"condensate_flash_fraction",
|
|
477
|
+
"condenser_duty",
|
|
439
478
|
"constant_setpoint",
|
|
440
479
|
"controller",
|
|
441
480
|
"conversion",
|
|
@@ -447,6 +486,7 @@ __all__ = [
|
|
|
447
486
|
"decanter",
|
|
448
487
|
"discounted_payback",
|
|
449
488
|
"discretize",
|
|
489
|
+
"distillate_rate",
|
|
450
490
|
"dlqr",
|
|
451
491
|
"enthalpy_flow",
|
|
452
492
|
"entropy_flow",
|
|
@@ -463,9 +503,11 @@ __all__ = [
|
|
|
463
503
|
"gilliland_stages",
|
|
464
504
|
"grand_composite_curve",
|
|
465
505
|
"heat_cascade",
|
|
506
|
+
"heat_exchanger",
|
|
466
507
|
"heat_exchanger_area",
|
|
467
508
|
"heat_stream",
|
|
468
509
|
"heater",
|
|
510
|
+
"helmholtz_package_for",
|
|
469
511
|
"iae",
|
|
470
512
|
"imc_tuning",
|
|
471
513
|
"installed_capital",
|
|
@@ -507,6 +549,7 @@ __all__ = [
|
|
|
507
549
|
"optimize_flowsheet_eo",
|
|
508
550
|
"overshoot",
|
|
509
551
|
"p_only",
|
|
552
|
+
"package_for",
|
|
510
553
|
"pfr",
|
|
511
554
|
"pi",
|
|
512
555
|
"pinch_analysis",
|
|
@@ -514,13 +557,19 @@ __all__ = [
|
|
|
514
557
|
"pressure_factor",
|
|
515
558
|
"pump",
|
|
516
559
|
"purchased_cost",
|
|
560
|
+
"purity",
|
|
517
561
|
"pxy_diagram",
|
|
518
562
|
"quadratic_tracking",
|
|
519
563
|
"reactive_distillation",
|
|
520
564
|
"reactive_flash",
|
|
565
|
+
"reboiler_duty",
|
|
566
|
+
"recovery",
|
|
567
|
+
"reflux_rate",
|
|
568
|
+
"reflux_ratio",
|
|
521
569
|
"relative_volatility",
|
|
522
570
|
"residue_curve",
|
|
523
571
|
"residue_curve_map",
|
|
572
|
+
"rigorous_column",
|
|
524
573
|
"rise_time",
|
|
525
574
|
"saft_model_for",
|
|
526
575
|
"saturated_steam_temperature",
|
|
@@ -534,12 +583,14 @@ __all__ = [
|
|
|
534
583
|
"solve_qp",
|
|
535
584
|
"solve_qp_canonical",
|
|
536
585
|
"splitter",
|
|
586
|
+
"stage_temperature",
|
|
537
587
|
"steam_enthalpy",
|
|
538
588
|
"steam_heating",
|
|
539
589
|
"steam_quality_after_letdown",
|
|
540
590
|
"steam_turbine",
|
|
541
591
|
"step_info",
|
|
542
592
|
"stoichiometric_reactor",
|
|
593
|
+
"stripper",
|
|
543
594
|
"supertarget",
|
|
544
595
|
"surface_tension",
|
|
545
596
|
"synthesize_network",
|
|
@@ -567,4 +618,4 @@ __all__ = [
|
|
|
567
618
|
"ziegler_nichols",
|
|
568
619
|
]
|
|
569
620
|
|
|
570
|
-
__version__ = "0.
|
|
621
|
+
__version__ = "0.3.0"
|