fugacio-sim 0.0.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.
Files changed (69) hide show
  1. fugacio_sim-0.0.1/.gitignore +32 -0
  2. fugacio_sim-0.0.1/PKG-INFO +150 -0
  3. fugacio_sim-0.0.1/README.md +134 -0
  4. fugacio_sim-0.0.1/pyproject.toml +37 -0
  5. fugacio_sim-0.0.1/src/fugacio/sim/__init__.py +529 -0
  6. fugacio_sim-0.0.1/src/fugacio/sim/column.py +466 -0
  7. fugacio_sim-0.0.1/src/fugacio/sim/control/__init__.py +110 -0
  8. fugacio_sim-0.0.1/src/fugacio/sim/control/blocks.py +159 -0
  9. fugacio_sim-0.0.1/src/fugacio/sim/control/linearize.py +190 -0
  10. fugacio_sim-0.0.1/src/fugacio/sim/control/metrics.py +152 -0
  11. fugacio_sim-0.0.1/src/fugacio/sim/control/pid.py +195 -0
  12. fugacio_sim-0.0.1/src/fugacio/sim/control/tuning.py +174 -0
  13. fugacio_sim-0.0.1/src/fugacio/sim/design.py +312 -0
  14. fugacio_sim-0.0.1/src/fugacio/sim/diagrams.py +346 -0
  15. fugacio_sim-0.0.1/src/fugacio/sim/dynamics/__init__.py +76 -0
  16. fugacio_sim-0.0.1/src/fugacio/sim/dynamics/flowsheet.py +292 -0
  17. fugacio_sim-0.0.1/src/fugacio/sim/dynamics/integrate.py +517 -0
  18. fugacio_sim-0.0.1/src/fugacio/sim/dynamics/optimize.py +255 -0
  19. fugacio_sim-0.0.1/src/fugacio/sim/dynamics/units.py +580 -0
  20. fugacio_sim-0.0.1/src/fugacio/sim/economics.py +384 -0
  21. fugacio_sim-0.0.1/src/fugacio/sim/flowsheet.py +286 -0
  22. fugacio_sim-0.0.1/src/fugacio/sim/integration/__init__.py +89 -0
  23. fugacio_sim-0.0.1/src/fugacio/sim/integration/area.py +447 -0
  24. fugacio_sim-0.0.1/src/fugacio/sim/integration/network.py +429 -0
  25. fugacio_sim-0.0.1/src/fugacio/sim/integration/streams.py +169 -0
  26. fugacio_sim-0.0.1/src/fugacio/sim/integration/targeting.py +348 -0
  27. fugacio_sim-0.0.1/src/fugacio/sim/models.py +221 -0
  28. fugacio_sim-0.0.1/src/fugacio/sim/mpc/__init__.py +116 -0
  29. fugacio_sim-0.0.1/src/fugacio/sim/mpc/estimation.py +413 -0
  30. fugacio_sim-0.0.1/src/fugacio/sim/mpc/linear.py +608 -0
  31. fugacio_sim-0.0.1/src/fugacio/sim/mpc/nonlinear.py +336 -0
  32. fugacio_sim-0.0.1/src/fugacio/sim/mpc/qp.py +409 -0
  33. fugacio_sim-0.0.1/src/fugacio/sim/mpc/riccati.py +279 -0
  34. fugacio_sim-0.0.1/src/fugacio/sim/mpc/simulate.py +302 -0
  35. fugacio_sim-0.0.1/src/fugacio/sim/optimize.py +758 -0
  36. fugacio_sim-0.0.1/src/fugacio/sim/properties.py +186 -0
  37. fugacio_sim-0.0.1/src/fugacio/sim/py.typed +0 -0
  38. fugacio_sim-0.0.1/src/fugacio/sim/reactive.py +398 -0
  39. fugacio_sim-0.0.1/src/fugacio/sim/reactors.py +516 -0
  40. fugacio_sim-0.0.1/src/fugacio/sim/separations.py +146 -0
  41. fugacio_sim-0.0.1/src/fugacio/sim/stream.py +71 -0
  42. fugacio_sim-0.0.1/src/fugacio/sim/units.py +356 -0
  43. fugacio_sim-0.0.1/src/fugacio/sim/utilities.py +358 -0
  44. fugacio_sim-0.0.1/src/fugacio/sim/vle.py +58 -0
  45. fugacio_sim-0.0.1/tests/test_column_rigorous.py +108 -0
  46. fugacio_sim-0.0.1/tests/test_column_shortcut.py +96 -0
  47. fugacio_sim-0.0.1/tests/test_control.py +298 -0
  48. fugacio_sim-0.0.1/tests/test_design.py +86 -0
  49. fugacio_sim-0.0.1/tests/test_dynamic_flowsheet.py +119 -0
  50. fugacio_sim-0.0.1/tests/test_dynamic_optimize.py +122 -0
  51. fugacio_sim-0.0.1/tests/test_dynamic_oracles.py +95 -0
  52. fugacio_sim-0.0.1/tests/test_dynamic_units.py +277 -0
  53. fugacio_sim-0.0.1/tests/test_economics.py +109 -0
  54. fugacio_sim-0.0.1/tests/test_energy_units.py +139 -0
  55. fugacio_sim-0.0.1/tests/test_flowsheet.py +117 -0
  56. fugacio_sim-0.0.1/tests/test_flowsheet_opt.py +73 -0
  57. fugacio_sim-0.0.1/tests/test_integrate.py +220 -0
  58. fugacio_sim-0.0.1/tests/test_integration.py +235 -0
  59. fugacio_sim-0.0.1/tests/test_integration_oracles.py +106 -0
  60. fugacio_sim-0.0.1/tests/test_mpc.py +489 -0
  61. fugacio_sim-0.0.1/tests/test_mpc_oracles.py +90 -0
  62. fugacio_sim-0.0.1/tests/test_nonideal.py +195 -0
  63. fugacio_sim-0.0.1/tests/test_optimize.py +151 -0
  64. fugacio_sim-0.0.1/tests/test_reactive.py +183 -0
  65. fugacio_sim-0.0.1/tests/test_reactors.py +229 -0
  66. fugacio_sim-0.0.1/tests/test_stream_properties.py +94 -0
  67. fugacio_sim-0.0.1/tests/test_units.py +77 -0
  68. fugacio_sim-0.0.1/tests/test_utilities.py +146 -0
  69. fugacio_sim-0.0.1/tests/test_vle.py +22 -0
@@ -0,0 +1,32 @@
1
+ # Byte-compiled / build artifacts
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ .eggs/
6
+ build/
7
+ dist/
8
+
9
+ # Virtual environments
10
+ .venv/
11
+ venv/
12
+
13
+ # Tooling caches
14
+ .pytest_cache/
15
+ .mypy_cache/
16
+ .ruff_cache/
17
+ .import_linter_cache/
18
+ .jax_cache/
19
+ .coverage
20
+ coverage.xml
21
+ htmlcov/
22
+
23
+ # Docs build
24
+ site/
25
+ # Material social-cards plugin cache (downloaded fonts + generated card layers)
26
+ .cache/
27
+
28
+ # OS / editor
29
+ .DS_Store
30
+ *.swp
31
+ .idea/
32
+ .vscode/
@@ -0,0 +1,150 @@
1
+ Metadata-Version: 2.4
2
+ Name: fugacio-sim
3
+ Version: 0.0.1
4
+ Summary: Differentiable steady-state and dynamic process flowsheet simulator (Fugacio).
5
+ Author-email: Owen Carey <37121709+owenthcarey@users.noreply.github.com>
6
+ License-Expression: Apache-2.0
7
+ Keywords: chemical-engineering,flowsheet,jax,process-simulation,vapor-liquid-equilibrium
8
+ Classifier: Development Status :: 2 - Pre-Alpha
9
+ Classifier: Intended Audience :: Science/Research
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Topic :: Scientific/Engineering :: Chemistry
12
+ Requires-Python: >=3.11
13
+ Requires-Dist: fugacio-thermo
14
+ Requires-Dist: jax>=0.4.34
15
+ Description-Content-Type: text/markdown
16
+
17
+ # fugacio-sim
18
+
19
+ Differentiable process-simulation layer for the
20
+ [Fugacio](https://github.com/fugacio/fugacio) stack: flowsheet and
21
+ unit-operation models built on top of `fugacio.thermo`.
22
+
23
+ The core abstraction is the `Stream`, a JAX pytree whose molar flows,
24
+ temperature, and pressure are differentiable leaves (component names are static
25
+ metadata). Because the underlying EOS phase equilibrium is differentiable, unit
26
+ operations are too: you can take a gradient of any downstream quantity (a product
27
+ flow, a recovery, a purity) with respect to feed conditions or operating
28
+ variables, which is the basis for gradient-based flowsheet optimisation.
29
+
30
+ ## Stream properties
31
+
32
+ Any `Stream` has a two-phase-aware enthalpy and entropy (via the
33
+ `fugacio.thermo` energy core), so unit operations close *energy* balances, not
34
+ just material balances: `molar_enthalpy`, `molar_entropy`, `enthalpy_flow`,
35
+ `entropy_flow`, `mass_flow`, `molar_mass`.
36
+
37
+ ## Unit operations (rigorous material + energy balances)
38
+
39
+ - `flash_drum`: isothermal-isobaric vapour/liquid separator.
40
+ - `heater`: heater/cooler on a temperature **or** a duty specification.
41
+ - `valve`: isenthalpic (Joule-Thomson) pressure letdown.
42
+ - `pump`: incompressible-liquid pump with an efficiency.
43
+ - `compressor` / `turbine`: isentropic machines with an efficiency.
44
+ - `mix`: adiabatic, energy-balanced mixer (exact material balance).
45
+ - `splitter` / `component_separator`: flow split and idealised component split.
46
+ - `bubble_pressure` / `antoine_psat`: lightweight modified-Raoult helpers.
47
+
48
+ ## Flowsheets with recycle
49
+
50
+ `tear_solve` closes a recycle by solving the tear fixed point
51
+ `tear = g(tear, theta)` with a Wegstein-accelerated iteration, and
52
+ differentiates the *converged* flowsheet by the implicit function theorem: a
53
+ gradient through the recycle costs one adjoint solve regardless of iteration
54
+ count. `Flowsheet` is a small declarative builder on top of it.
55
+
56
+ ## Distillation
57
+
58
+ - **Shortcut** (Fenske-Underwood-Gilliland): `fenske_min_stages`,
59
+ `underwood_min_reflux`, `gilliland_stages`, `kirkbride_feed_stage`, and the
60
+ `shortcut_column` wrapper.
61
+ - **Rigorous** `solve_column`: a multistage equilibrium-stage column (Wang-Henke
62
+ bubble-point, constant molar overflow) with EOS K-values on every stage,
63
+ differentiable through the fixed-point iteration.
64
+
65
+ ## Non-ideal separations & diagrams
66
+
67
+ Built on the `fugacio.thermo` property system (via the `eos_model_for`,
68
+ `nrtl_model_for`, `uniquac_model_for`, `unifac_model_for`, and `saft_model_for`
69
+ bridges, the last building a molecular PC-SAFT model from component names):
70
+
71
+ - `flash_vle`, `decanter`, `three_phase_flash`: activity-based VLE / LLE / VLLE
72
+ drums for real, non-ideal mixtures.
73
+ - `pxy_diagram`, `txy_diagram`, `azeotrope_pressure`, `azeotrope_temperature`:
74
+ binary phase diagrams and azeotrope finders.
75
+ - `residue_curve`, `residue_curve_map`: ternary open-evaporation trajectories for
76
+ laying out distillation boundaries.
77
+
78
+ ## Reactors
79
+
80
+ Energy-balanced reactor unit operations over one or more `fugacio.thermo`
81
+ `Reaction`s, each runnable isothermally (reporting the heat `duty`) or
82
+ adiabatically (solving the outlet temperature) and returning a `ReactorResult`:
83
+ `equilibrium_reactor` (chemical equilibrium), `stoichiometric_reactor` (specified
84
+ extent or conversion), and kinetic `cstr`, `pfr`, and `batch_reactor` sized by
85
+ volume (and time). `conversion` is a small helper on the inlet/outlet streams.
86
+
87
+ ## Reactive separations
88
+
89
+ Reaction coupled to phase separation, both differentiable through the joint solve:
90
+ `reactive_flash` (simultaneous chemical + vapour-liquid equilibrium in a drum) and
91
+ `reactive_distillation` (a rate-based column with per-stage reaction source terms).
92
+
93
+ ## Example: differentiate a flash drum
94
+
95
+ ```python
96
+ import jax
97
+ import jax.numpy as jnp
98
+ from fugacio.sim import Stream, flash_drum
99
+
100
+ feed = Stream.from_fractions(
101
+ ("methane", "propane", "n-pentane"),
102
+ jnp.array([0.5, 0.3, 0.2]),
103
+ flow=100.0, t=320.0, p=20e5,
104
+ )
105
+ vapor, liquid = flash_drum(feed, 320.0, 20e5)
106
+ vapor.total, liquid.total # ~74.7 and ~25.3 mol/s
107
+
108
+ # Sensitivity of vapour product flow to drum temperature:
109
+ d_vapor_dT = jax.grad(lambda T: flash_drum(feed, T, 20e5)[0].total)
110
+ d_vapor_dT(320.0)
111
+ ```
112
+
113
+ ## Example: a recycle, differentiated end-to-end
114
+
115
+ ```python
116
+ import jax.numpy as jnp
117
+ from fugacio.sim import Stream, flash_drum, mix, splitter, tear_solve
118
+
119
+ components = ("methane", "propane", "n-pentane")
120
+ fresh = Stream.from_fractions(components, jnp.array([0.5, 0.3, 0.2]), 100.0, 320.0, 20e5)
121
+
122
+ def one_pass(recycle, theta):
123
+ mixed = mix([fresh, recycle], t=320.0)
124
+ _vapor, liquid = flash_drum(mixed, theta["T"], theta["P"])
125
+ recycled, _purge = splitter(liquid, jnp.array([theta["r"], 1.0 - theta["r"]]))
126
+ return recycled
127
+
128
+ guess = Stream.from_fractions(components, jnp.array([0.1, 0.3, 0.6]), 30.0, 320.0, 20e5)
129
+ recycle = tear_solve(one_pass, guess, {"T": 320.0, "P": 20e5, "r": 0.5})
130
+ ```
131
+
132
+ ## Example: a rigorous distillation column
133
+
134
+ ```python
135
+ import jax
136
+ import jax.numpy as jnp
137
+ from fugacio.sim import Stream, solve_column
138
+
139
+ feed = Stream.from_fractions(("propane", "n-butane"), jnp.array([0.5, 0.5]), 100.0, 320.0, 10e5)
140
+ col = solve_column(feed, n_stages=12, feed_stage=6, reflux=2.0, distillate_rate=50.0)
141
+ col.distillate.z # ~[0.97, 0.03] propane overhead
142
+
143
+ # Exact gradient of distillate purity w.r.t. reflux ratio:
144
+ jax.grad(
145
+ lambda r: solve_column(feed, 12, 6, r, 50.0).distillate.z[0]
146
+ )(2.0)
147
+ ```
148
+
149
+ Part of the `fugacio` namespace; installs independently:
150
+ `pip install fugacio-sim`.
@@ -0,0 +1,134 @@
1
+ # fugacio-sim
2
+
3
+ Differentiable process-simulation layer for the
4
+ [Fugacio](https://github.com/fugacio/fugacio) stack: flowsheet and
5
+ unit-operation models built on top of `fugacio.thermo`.
6
+
7
+ The core abstraction is the `Stream`, a JAX pytree whose molar flows,
8
+ temperature, and pressure are differentiable leaves (component names are static
9
+ metadata). Because the underlying EOS phase equilibrium is differentiable, unit
10
+ operations are too: you can take a gradient of any downstream quantity (a product
11
+ flow, a recovery, a purity) with respect to feed conditions or operating
12
+ variables, which is the basis for gradient-based flowsheet optimisation.
13
+
14
+ ## Stream properties
15
+
16
+ Any `Stream` has a two-phase-aware enthalpy and entropy (via the
17
+ `fugacio.thermo` energy core), so unit operations close *energy* balances, not
18
+ just material balances: `molar_enthalpy`, `molar_entropy`, `enthalpy_flow`,
19
+ `entropy_flow`, `mass_flow`, `molar_mass`.
20
+
21
+ ## Unit operations (rigorous material + energy balances)
22
+
23
+ - `flash_drum`: isothermal-isobaric vapour/liquid separator.
24
+ - `heater`: heater/cooler on a temperature **or** a duty specification.
25
+ - `valve`: isenthalpic (Joule-Thomson) pressure letdown.
26
+ - `pump`: incompressible-liquid pump with an efficiency.
27
+ - `compressor` / `turbine`: isentropic machines with an efficiency.
28
+ - `mix`: adiabatic, energy-balanced mixer (exact material balance).
29
+ - `splitter` / `component_separator`: flow split and idealised component split.
30
+ - `bubble_pressure` / `antoine_psat`: lightweight modified-Raoult helpers.
31
+
32
+ ## Flowsheets with recycle
33
+
34
+ `tear_solve` closes a recycle by solving the tear fixed point
35
+ `tear = g(tear, theta)` with a Wegstein-accelerated iteration, and
36
+ differentiates the *converged* flowsheet by the implicit function theorem: a
37
+ gradient through the recycle costs one adjoint solve regardless of iteration
38
+ count. `Flowsheet` is a small declarative builder on top of it.
39
+
40
+ ## Distillation
41
+
42
+ - **Shortcut** (Fenske-Underwood-Gilliland): `fenske_min_stages`,
43
+ `underwood_min_reflux`, `gilliland_stages`, `kirkbride_feed_stage`, and the
44
+ `shortcut_column` wrapper.
45
+ - **Rigorous** `solve_column`: a multistage equilibrium-stage column (Wang-Henke
46
+ bubble-point, constant molar overflow) with EOS K-values on every stage,
47
+ differentiable through the fixed-point iteration.
48
+
49
+ ## Non-ideal separations & diagrams
50
+
51
+ Built on the `fugacio.thermo` property system (via the `eos_model_for`,
52
+ `nrtl_model_for`, `uniquac_model_for`, `unifac_model_for`, and `saft_model_for`
53
+ bridges, the last building a molecular PC-SAFT model from component names):
54
+
55
+ - `flash_vle`, `decanter`, `three_phase_flash`: activity-based VLE / LLE / VLLE
56
+ drums for real, non-ideal mixtures.
57
+ - `pxy_diagram`, `txy_diagram`, `azeotrope_pressure`, `azeotrope_temperature`:
58
+ binary phase diagrams and azeotrope finders.
59
+ - `residue_curve`, `residue_curve_map`: ternary open-evaporation trajectories for
60
+ laying out distillation boundaries.
61
+
62
+ ## Reactors
63
+
64
+ Energy-balanced reactor unit operations over one or more `fugacio.thermo`
65
+ `Reaction`s, each runnable isothermally (reporting the heat `duty`) or
66
+ adiabatically (solving the outlet temperature) and returning a `ReactorResult`:
67
+ `equilibrium_reactor` (chemical equilibrium), `stoichiometric_reactor` (specified
68
+ extent or conversion), and kinetic `cstr`, `pfr`, and `batch_reactor` sized by
69
+ volume (and time). `conversion` is a small helper on the inlet/outlet streams.
70
+
71
+ ## Reactive separations
72
+
73
+ Reaction coupled to phase separation, both differentiable through the joint solve:
74
+ `reactive_flash` (simultaneous chemical + vapour-liquid equilibrium in a drum) and
75
+ `reactive_distillation` (a rate-based column with per-stage reaction source terms).
76
+
77
+ ## Example: differentiate a flash drum
78
+
79
+ ```python
80
+ import jax
81
+ import jax.numpy as jnp
82
+ from fugacio.sim import Stream, flash_drum
83
+
84
+ feed = Stream.from_fractions(
85
+ ("methane", "propane", "n-pentane"),
86
+ jnp.array([0.5, 0.3, 0.2]),
87
+ flow=100.0, t=320.0, p=20e5,
88
+ )
89
+ vapor, liquid = flash_drum(feed, 320.0, 20e5)
90
+ vapor.total, liquid.total # ~74.7 and ~25.3 mol/s
91
+
92
+ # Sensitivity of vapour product flow to drum temperature:
93
+ d_vapor_dT = jax.grad(lambda T: flash_drum(feed, T, 20e5)[0].total)
94
+ d_vapor_dT(320.0)
95
+ ```
96
+
97
+ ## Example: a recycle, differentiated end-to-end
98
+
99
+ ```python
100
+ import jax.numpy as jnp
101
+ from fugacio.sim import Stream, flash_drum, mix, splitter, tear_solve
102
+
103
+ components = ("methane", "propane", "n-pentane")
104
+ fresh = Stream.from_fractions(components, jnp.array([0.5, 0.3, 0.2]), 100.0, 320.0, 20e5)
105
+
106
+ def one_pass(recycle, theta):
107
+ mixed = mix([fresh, recycle], t=320.0)
108
+ _vapor, liquid = flash_drum(mixed, theta["T"], theta["P"])
109
+ recycled, _purge = splitter(liquid, jnp.array([theta["r"], 1.0 - theta["r"]]))
110
+ return recycled
111
+
112
+ guess = Stream.from_fractions(components, jnp.array([0.1, 0.3, 0.6]), 30.0, 320.0, 20e5)
113
+ recycle = tear_solve(one_pass, guess, {"T": 320.0, "P": 20e5, "r": 0.5})
114
+ ```
115
+
116
+ ## Example: a rigorous distillation column
117
+
118
+ ```python
119
+ import jax
120
+ import jax.numpy as jnp
121
+ from fugacio.sim import Stream, solve_column
122
+
123
+ feed = Stream.from_fractions(("propane", "n-butane"), jnp.array([0.5, 0.5]), 100.0, 320.0, 10e5)
124
+ col = solve_column(feed, n_stages=12, feed_stage=6, reflux=2.0, distillate_rate=50.0)
125
+ col.distillate.z # ~[0.97, 0.03] propane overhead
126
+
127
+ # Exact gradient of distillate purity w.r.t. reflux ratio:
128
+ jax.grad(
129
+ lambda r: solve_column(feed, 12, 6, r, 50.0).distillate.z[0]
130
+ )(2.0)
131
+ ```
132
+
133
+ Part of the `fugacio` namespace; installs independently:
134
+ `pip install fugacio-sim`.
@@ -0,0 +1,37 @@
1
+ [project]
2
+ name = "fugacio-sim"
3
+ version = "0.0.1"
4
+ description = "Differentiable steady-state and dynamic process flowsheet simulator (Fugacio)."
5
+ readme = "README.md"
6
+ requires-python = ">=3.11"
7
+ license = "Apache-2.0"
8
+ authors = [
9
+ { name = "Owen Carey", email = "37121709+owenthcarey@users.noreply.github.com" },
10
+ ]
11
+ keywords = [
12
+ "process-simulation",
13
+ "flowsheet",
14
+ "chemical-engineering",
15
+ "jax",
16
+ "vapor-liquid-equilibrium",
17
+ ]
18
+ classifiers = [
19
+ "Development Status :: 2 - Pre-Alpha",
20
+ "Intended Audience :: Science/Research",
21
+ "Programming Language :: Python :: 3",
22
+ "Topic :: Scientific/Engineering :: Chemistry",
23
+ ]
24
+ dependencies = [
25
+ "fugacio-thermo",
26
+ "jax>=0.4.34",
27
+ ]
28
+
29
+ [build-system]
30
+ requires = ["hatchling"]
31
+ build-backend = "hatchling.build"
32
+
33
+ [tool.hatch.build.targets.wheel]
34
+ packages = ["src/fugacio"]
35
+
36
+ [tool.uv.sources]
37
+ fugacio-thermo = { workspace = true }