Skip to main content

fugacio-sim

Differentiable process-simulation layer for the Fugacio stack: flowsheet and unit-operation models built on top of fugacio.thermo.

The core abstraction is the Stream, a JAX pytree whose molar flows, temperature, and pressure are differentiable leaves (component names are static metadata). Because the underlying EOS phase equilibrium is differentiable, unit operations are too: you can take a gradient of any downstream quantity (a product flow, a recovery, a purity) with respect to feed conditions or operating variables, which is the basis for gradient-based flowsheet optimisation.

Stream properties

Any Stream has a two-phase-aware enthalpy and entropy (via the fugacio.thermo energy core), so unit operations close energy balances, not just material balances: molar_enthalpy, molar_entropy, enthalpy_flow, entropy_flow, mass_flow, molar_mass.

Unit operations (rigorous material + energy balances)

  • flash_drum: isothermal-isobaric vapour/liquid separator.
  • heater: heater/cooler on a temperature or a duty specification.
  • valve: isenthalpic (Joule-Thomson) pressure letdown.
  • pump: incompressible-liquid pump with an efficiency.
  • compressor / turbine: isentropic machines with an efficiency.
  • mix: adiabatic, energy-balanced mixer (exact material balance).
  • splitter / component_separator: flow split and idealised component split.
  • bubble_pressure / antoine_psat: lightweight modified-Raoult helpers.

Flowsheets with recycle

tear_solve closes a recycle by solving the tear fixed point tear = g(tear, theta) with a Wegstein-accelerated iteration, and differentiates the converged flowsheet by the implicit function theorem: a gradient through the recycle costs one adjoint solve regardless of iteration count. Flowsheet is a small declarative builder on top of it.

Equation-oriented flowsheeting

fugacio.sim.eo solves a whole flowsheet as one system of equations instead of unit by unit. EOFlowsheet assembles every block's residual equations, the stream connectivity, the recycles, and any design specs into a single residual system and solves it simultaneously by Newton's method, with the Jacobian supplied exactly by JAX autodiff. A recycle needs no tear stream and no ordering, the converged plant is differentiable by the implicit function theorem, degrees_of_freedom checks the unknown/equation balance, and optimize_flowsheet_eo runs nested or full-space simultaneous optimization. The blocks mirror the sequential-modular units (Mixer, Splitter, Heater, Valve, Pump, Compressor, Turbine, Flash, ComponentSeparator), so the two engines agree on any flowsheet both can express.

import jax.numpy as jnp
from fugacio.sim import Stream
from fugacio.sim.eo import EOFlowsheet, Mixer, Flash, Splitter

fresh = Stream.from_fractions(
    ("methane", "propane", "n-pentane"), jnp.array([0.5, 0.3, 0.2]), 100.0, 320.0, 20e5
)

fs = (
    EOFlowsheet()
    .feed("fresh", fresh)
    .add(Mixer(inlets=("fresh", "recycle"), outlets=("mixed",), t=320.0))
    .add(Flash(inlets=("mixed",), outlets=("vapor", "liquid"), t="T", p="P"))
    .add(Splitter(inlets=("liquid",), outlets=("recycle", "purge"), fractions="r"))
)
sol = fs.solve({"T": 320.0, "P": 20e5, "r": jnp.array([0.5, 0.5])})  # recycle closed, no tear
sol["vapor"].total

Distillation

  • Shortcut (Fenske-Underwood-Gilliland): fenske_min_stages, underwood_min_reflux, gilliland_stages, kirkbride_feed_stage, and the shortcut_column wrapper.
  • Rigorous solve_column: a multistage equilibrium-stage column (Wang-Henke bubble-point, constant molar overflow) with EOS K-values on every stage, differentiable through the fixed-point iteration.

Non-ideal separations & diagrams

Built on the fugacio.thermo property system (via the eos_model_for, nrtl_model_for, uniquac_model_for, unifac_model_for, and saft_model_for bridges, the last building a molecular PC-SAFT model from component names):

  • flash_vle, decanter, three_phase_flash: activity-based VLE / LLE / VLLE drums for real, non-ideal mixtures.
  • pxy_diagram, txy_diagram, azeotrope_pressure, azeotrope_temperature: binary phase diagrams and azeotrope finders.
  • residue_curve, residue_curve_map: ternary open-evaporation trajectories for laying out distillation boundaries.

Reactors

Energy-balanced reactor unit operations over one or more fugacio.thermo Reactions, each runnable isothermally (reporting the heat duty) or adiabatically (solving the outlet temperature) and returning a ReactorResult: equilibrium_reactor (chemical equilibrium), stoichiometric_reactor (specified extent or conversion), and kinetic cstr, pfr, and batch_reactor sized by volume (and time). conversion is a small helper on the inlet/outlet streams.

Reactive separations

Reaction coupled to phase separation, both differentiable through the joint solve: reactive_flash (simultaneous chemical + vapour-liquid equilibrium in a drum) and reactive_distillation (a rate-based column with per-stage reaction source terms).

Example: differentiate a flash drum

import jax
import jax.numpy as jnp
from fugacio.sim import Stream, flash_drum

feed = Stream.from_fractions(
    ("methane", "propane", "n-pentane"),
    jnp.array([0.5, 0.3, 0.2]),
    flow=100.0, t=320.0, p=20e5,
)
vapor, liquid = flash_drum(feed, 320.0, 20e5)
vapor.total, liquid.total  # ~74.7 and ~25.3 mol/s

# Sensitivity of vapour product flow to drum temperature:
d_vapor_dT = jax.grad(lambda T: flash_drum(feed, T, 20e5)[0].total)
d_vapor_dT(320.0)

Example: a recycle, differentiated end-to-end

import jax.numpy as jnp
from fugacio.sim import Stream, flash_drum, mix, splitter, tear_solve

components = ("methane", "propane", "n-pentane")
fresh = Stream.from_fractions(components, jnp.array([0.5, 0.3, 0.2]), 100.0, 320.0, 20e5)

def one_pass(recycle, theta):
    mixed = mix([fresh, recycle], t=320.0)
    _vapor, liquid = flash_drum(mixed, theta["T"], theta["P"])
    recycled, _purge = splitter(liquid, jnp.array([theta["r"], 1.0 - theta["r"]]))
    return recycled

guess = Stream.from_fractions(components, jnp.array([0.1, 0.3, 0.6]), 30.0, 320.0, 20e5)
recycle = tear_solve(one_pass, guess, {"T": 320.0, "P": 20e5, "r": 0.5})

Example: a rigorous distillation column

import jax
import jax.numpy as jnp
from fugacio.sim import Stream, solve_column

feed = Stream.from_fractions(("propane", "n-butane"), jnp.array([0.5, 0.5]), 100.0, 320.0, 10e5)
col = solve_column(feed, n_stages=12, feed_stage=6, reflux=2.0, distillate_rate=50.0)
col.distillate.z  # ~[0.97, 0.03] propane overhead

# Exact gradient of distillate purity w.r.t. reflux ratio:
jax.grad(
    lambda r: solve_column(feed, 12, 6, r, 50.0).distillate.z[0]
)(2.0)

Part of the fugacio namespace; installs independently: pip install fugacio-sim.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fugacio_sim-0.2.0.tar.gz (181.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fugacio_sim-0.2.0-py3-none-any.whl (168.8 kB view details)

Uploaded Python 3

File details

Details for the file fugacio_sim-0.2.0.tar.gz.

File metadata

  • Download URL: fugacio_sim-0.2.0.tar.gz
  • Upload date:
  • Size: 181.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.24 {"installer":{"name":"uv","version":"0.11.24","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for fugacio_sim-0.2.0.tar.gz
Algorithm Hash digest
SHA256 03c37de994344e9a7a964c09295a42021ad969b4263dccc15fe5c89041088d85
MD5 bb1b150595f065b643a4bef1f2dbd439
BLAKE2b-256 7efccababbeb89d7fb52943b0e25d924666896ceaa18ad6f33a4ecb6505b1e04

See more details on using hashes here.

File details

Details for the file fugacio_sim-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: fugacio_sim-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 168.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.24 {"installer":{"name":"uv","version":"0.11.24","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for fugacio_sim-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 eb400b6f9b562b42737069bfb2779d67d98ca83159fce6faba0a4f77d171e7c3
MD5 7905ebed59f6f6936db158c6cbe83808
BLAKE2b-256 b95e6b59be58fe870376981e05ab59d3ba74aa3bb05a8b030825ad2981469a07

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page