Skip to content

Equation-oriented flowsheeting

The equation-oriented (EO) engine assembles every unit's equations, the stream connectivity, the recycles, and any design specs into one residual system and solves it simultaneously by Newton's method, with the Jacobian supplied exactly by JAX autodiff and the converged solution differentiable by the implicit function theorem.

See the equation-oriented flowsheeting guide for worked examples. Import the public surface from the subpackage root:

from fugacio.sim.eo import EOFlowsheet, Flash, Heater, Mixer, optimize_flowsheet_eo

Flowsheet, solution & DOF analysis

flowsheet

Equation-oriented flowsheeting: solve the whole flowsheet as one system.

Where the sequential-modular engine (fugacio.sim.flowsheet) evaluates units in order and converges recycles by tearing, the equation-oriented (EO) engine collects every unit's equations, the stream connectivity, the recycles, and any design specs into a single residual system F(x, theta) = 0 and solves it simultaneously with Newton's method. There is no tear stream and no unit ordering: a recycle is just a stream that two blocks happen to share, and the global solve closes it like any other equation.

This is the formulation a differentiable core is built for. The one expensive ingredient of an EO solver, the Jacobian dF/dx, is supplied exactly by JAX autodiff rather than by finite differences or hand-coded analytic blocks, and the converged solution is itself differentiable with respect to the parameters theta (operating conditions, feeds, prices, model parameters) by the implicit function theorem (fugacio.thermo.implicit.newton_system). So a gradient of any product spec, duty, or cost through the entire converged plant, recycles and all, costs a single adjoint solve.

The unknowns are the flowsheet's internal streams (per-component molar flows plus temperature and pressure) together with any block auxiliary variables and any freed design-spec variables. Everything is carried in a non-dimensional form (see fugacio.sim.eo.blocks.Scales) so the Newton system stays well conditioned. EOFlowsheet.degrees_of_freedom reports the unknown/equation balance, the EO analogue of a specification check.

Classes:

Name Description
DOFReport

Degrees-of-freedom analysis of an EO flowsheet.

EOSolution

Converged equation-oriented flowsheet solution.

EOFlowsheet

Declarative equation-oriented flowsheet.

DOFReport

Bases: NamedTuple

Degrees-of-freedom analysis of an EO flowsheet.

Attributes:

Name Type Description
n_unknowns int

Total scalar unknowns (internal stream variables + block auxiliaries + freed design-spec variables).

n_equations int

Total scalar equations (block residuals + design specs).

degrees_of_freedom int

n_unknowns - n_equations. Zero means the flowsheet is exactly specified and solvable; positive means under-specified (add specs); negative means over-specified.

per_block dict[str, int]

Equation count contributed by each block (keyed by the block's first outlet name).

EOSolution dataclass

EOSolution(
    streams: dict[str, Stream],
    aux: dict[str, Array],
    specs: dict[str, Array],
    residual_norm: Array,
    n_unknowns: int,
    n_equations: int,
)

Converged equation-oriented flowsheet solution.

Attributes:

Name Type Description
streams dict[str, Stream]

All named streams (feeds plus solved internal streams).

aux dict[str, Array]

Solved block auxiliary variables (e.g. isentropic temperatures).

specs dict[str, Array]

Solved values of any freed design-spec manipulated variables.

residual_norm Array

Max-norm of the (scaled) residual at the solution.

n_unknowns int

Number of scalar unknowns solved.

n_equations int

Number of scalar equations.

EOFlowsheet dataclass

EOFlowsheet(
    eos: CubicEOS = PR,
    kij: Array | None = None,
    scales: Scales | None = None,
    feeds: dict[str, Stream] = dict(),
    blocks: list[Block] = list(),
    specs: list[_DesignSpec] = list(),
)

Declarative equation-oriented flowsheet.

Register feeds and blocks, optionally add design specs, then call solve. Streams are referenced by name; a block's outlet names become the system unknowns and recycles need no special handling (just reuse a downstream stream name as an upstream block's inlet).

Example::

fs = EOFlowsheet(eos=PR)
fs.feed("fresh", fresh_stream)
fs.add(Mixer(inlets=("fresh", "recycle"), outlets=("mixed",)))
fs.add(Flash(inlets=("mixed",), outlets=("vapor", "liquid"), t="T", p="P"))
fs.add(Splitter(inlets=("liquid",), outlets=("recycle", "purge"),
                fractions=("r_recycle",)))
sol = fs.solve({"T": 320.0, "P": 20e5, "r_recycle": [0.5, 0.5]})
product = sol["vapor"]

Attributes:

Name Type Description
eos CubicEOS

Cubic equation of state used everywhere in the flowsheet.

kij Array | None

Optional binary-interaction matrix.

scales Scales | None

Residual/variable scales (auto-derived from the feeds by solve when left at the default).

Methods:

Name Description
feed

Register a fresh feed stream by name. Returns self for chaining.

add

Register a unit block. Returns self for chaining.

spec

Add a design spec: free parameter manipulated to hit measure = target.

degrees_of_freedom

Report the unknown/equation balance for the flowsheet (see DOFReport).

solve

Solve the flowsheet simultaneously and return all streams.

feed

feed(name: str, stream: Stream) -> EOFlowsheet

Register a fresh feed stream by name. Returns self for chaining.

add

add(block: Block) -> EOFlowsheet

Register a unit block. Returns self for chaining.

spec

spec(
    manipulated: str,
    measure: Measure,
    target: float | Array,
    *,
    init: float | Array,
) -> EOFlowsheet

Add a design spec: free parameter manipulated to hit measure = target.

In EO form a design spec is simply one more equation (measure(streams) - target = 0) and one more unknown (the freed value of manipulated, seeded at init), solved simultaneously with the flowsheet, so coupled specs converge together with no nested loop.

Parameters:

Name Type Description Default
manipulated str

A parameter key read by some block (the degree of freedom). Its value becomes an unknown; the value passed in params for this key, if any, is ignored.

required
measure Measure

Reads the controlled variable from the solved streams.

required
target float | Array

Desired value of the controlled variable.

required
init float | Array

Initial guess for the manipulated variable.

required

Returns:

Type Description
EOFlowsheet

self for chaining.

degrees_of_freedom

degrees_of_freedom() -> DOFReport

Report the unknown/equation balance for the flowsheet (see DOFReport).

solve

solve(
    params: Mapping[str, Any] | None = None,
    *,
    guess: Mapping[str, Stream] | None = None,
    sweeps: int = 6,
    tol: float = 1e-10,
    max_iter: int = 60,
    check_dof: bool = True,
) -> EOSolution

Solve the flowsheet simultaneously and return all streams.

Parameters:

Name Type Description Default
params Mapping[str, Any] | None

Parameter mapping read by blocks (operating conditions, split fractions, ...). Gradients with respect to these (and the feeds) flow through the converged solution by implicit differentiation.

None
guess Mapping[str, Stream] | None

Optional initial guesses for specific internal streams (useful to seed a recycle); other streams get a default interior seed.

None
sweeps int

Forward sweeps used to build the initial guess.

6
tol float

Newton convergence tolerance on the scaled step.

1e-10
max_iter int

Newton iteration cap.

60
check_dof bool

If True, raise when the flowsheet is not square (degrees_of_freedom != 0).

True

Returns:

Type Description
EOSolution

An EOSolution with every solved stream, differentiable in params

EOSolution

and the feeds.

Raises:

Type Description
ValueError

if check_dof and the flowsheet is under/over-specified.

Unit blocks

blocks

Equation-oriented unit blocks: each unit as a residual contribution.

A sequential-modular unit (fugacio.sim.units) is an explicit function of its inlet streams: it computes outlets, internally converging any flash or isentropic solve. An equation-oriented (EO) block is the same physics written as residual equations instead. Its outlet streams are unknowns of a global system, and the block contributes the equations that those unknowns must satisfy (material balances, an energy balance, phase-equilibrium equifugacity, a pressure spec, ...). The whole flowsheet, recycles and design specs included, is then one residual system solved simultaneously by Newton's method, with the Jacobian supplied exactly by JAX autodiff (see fugacio.sim.eo.flowsheet).

Every block carries two complementary methods:

  • Block.residuals returns the block's residual vector for the EO solve. The residuals are scaled (material by a flow scale, energy by an enthalpy scale, pressures by a pressure scale, equifugacity left dimensionless) so the global Newton system is well conditioned regardless of the unit system.
  • Block.forward evaluates the unit explicitly by reusing the corresponding sequential-modular unit operation. It is used to build a high-quality initial guess for the EO solve (a few forward sweeps) and lets a test cross-check the two formulations against each other.

The blocks mirror the sequential-modular units one-for-one, so the same physics backs both engines and the EO solution must equal the sequential-modular solution on any flowsheet both can express (the central differential test for this layer).

Classes:

Name Description
Scales

Characteristic scales that non-dimensionalise the EO residual system.

Context

Static (non-differentiated) data shared by every block during a solve.

Block

Base class for an equation-oriented unit block.

Mixer

Adiabatic (or isothermal) mixer: combine inlet streams into one outlet.

Splitter

Flow splitter: one inlet to several outlets sharing composition and state.

Heater

Heater/cooler on a temperature or a duty specification.

Valve

Isenthalpic (Joule-Thomson) pressure letdown to p_out.

Pump

Incompressible-liquid pump to p_out with an isentropic-equivalent efficiency.

Compressor

Isentropic compressor to p_out with an isentropic efficiency (< 1).

Turbine

Isentropic turbine (expander) to p_out with an isentropic efficiency (< 1).

Flash

Isothermal-isobaric two-phase flash: one inlet to vapour and liquid outlets.

ComponentSeparator

Idealised separator with a per-component recovery to the top product.

Functions:

Name Description
resolve

Resolve a Spec to a JAX array.

Scales dataclass

Scales(
    flow: float = 1.0,
    temperature: float = 100.0,
    pressure: float = 100000.0,
    enthalpy_flow: float = 10000.0,
    enthalpy_molar: float = 10000.0,
    entropy_molar: float = 10.0,
)

Characteristic scales that non-dimensionalise the EO residual system.

The unknowns and residuals are divided by these so the Newton system is well conditioned: molar flows and material balances by flow, temperatures and temperature specs by temperature, pressures and pressure specs by pressure, total-enthalpy balances by enthalpy_flow, molar-enthalpy balances by enthalpy_molar, and molar-entropy relations by entropy_molar. Phase-equilibrium (equifugacity) residuals are already dimensionless and are left unscaled.

Attributes:

Name Type Description
flow float

Characteristic molar flow (mol/s).

temperature float

Characteristic temperature (K).

pressure float

Characteristic pressure (Pa).

enthalpy_flow float

Characteristic total enthalpy flow (W).

enthalpy_molar float

Characteristic molar enthalpy (J/mol).

entropy_molar float

Characteristic molar entropy (J/mol/K).

Context dataclass

Context(
    components: tuple[str, ...],
    eos: CubicEOS = PR,
    kij: Array | None = None,
    scales: Scales = Scales(),
)

Static (non-differentiated) data shared by every block during a solve.

Attributes:

Name Type Description
components tuple[str, ...]

The flowsheet's component names (shared by all streams).

eos CubicEOS

Cubic equation of state used for every equilibrium / property call.

kij Array | None

Optional binary-interaction matrix for the EOS.

scales Scales

Residual / variable scales (see Scales).

n_components property

n_components: int

Number of components (the per-stream material-balance count).

Block dataclass

Block(inlets: tuple[str, ...], outlets: tuple[str, ...])

Base class for an equation-oriented unit block.

A block names its inlet and outlet streams (by the keys used in the flowsheet) and supplies the equations relating them. Outlet streams are unknowns of the global EO system; each block "defines" its outlet streams by contributing exactly enough residual equations.

Attributes:

Name Type Description
inlets tuple[str, ...]

Inlet stream names (must already exist as feeds or other blocks' outlets).

outlets tuple[str, ...]

Outlet stream names defined by this block.

Methods:

Name Description
aux_scales

Auxiliary unknowns introduced by the block, mapped to their scale.

n_residuals

Number of residual equations this block contributes.

aux_init

Initial values for the block's auxiliary unknowns (unscaled).

forward

Evaluate the unit explicitly, returning its outlet streams.

residuals

Scaled residual vector for the block (length n_residuals).

aux_scales

aux_scales(ctx: Context) -> dict[str, float]

Auxiliary unknowns introduced by the block, mapped to their scale.

Most blocks have none. A block with an internal implicit variable (for example a compressor's isentropic outlet temperature) declares it here so the flowsheet allocates an unknown and the block can add its defining equation in residuals.

n_residuals

n_residuals(ctx: Context) -> int

Number of residual equations this block contributes.

aux_init

aux_init(
    streams: Mapping[str, Stream],
    params: Mapping[str, Any],
    ctx: Context,
) -> dict[str, Array]

Initial values for the block's auxiliary unknowns (unscaled).

forward

forward(
    streams: Mapping[str, Stream],
    params: Mapping[str, Any],
    ctx: Context,
) -> dict[str, Stream]

Evaluate the unit explicitly, returning its outlet streams.

Reuses the sequential-modular unit operation, so it is the reference the EO residuals are built to reproduce. Used to seed the EO solve.

residuals

residuals(
    streams: Mapping[str, Stream],
    aux: Mapping[str, Array],
    params: Mapping[str, Any],
    ctx: Context,
) -> Array

Scaled residual vector for the block (length n_residuals).

Mixer dataclass

Mixer(
    inlets: tuple[str, ...],
    outlets: tuple[str, ...],
    t: Spec | None = None,
    p: Spec | None = None,
)

Bases: Block

Adiabatic (or isothermal) mixer: combine inlet streams into one outlet.

Flows add component-by-component. With t unset the outlet temperature is set by an adiabatic energy balance (total enthalpy in equals total enthalpy out); set t to fix the outlet temperature. The outlet pressure defaults to the lowest inlet pressure, or is fixed by p.

Attributes:

Name Type Description
t Spec | None

Optional outlet temperature spec (literal or parameter key); None selects the adiabatic energy balance.

p Spec | None

Optional outlet pressure spec; None uses the minimum inlet pressure.

Methods:

Name Description
n_residuals

Material (per component) + pressure + energy: n_components + 2.

forward

Evaluate via fugacio.sim.units.mix.

residuals

Material balance, pressure spec, and the (adiabatic or fixed-T) energy balance.

n_residuals

n_residuals(ctx: Context) -> int

Material (per component) + pressure + energy: n_components + 2.

forward

forward(
    streams: Mapping[str, Stream],
    params: Mapping[str, Any],
    ctx: Context,
) -> dict[str, Stream]

Evaluate via fugacio.sim.units.mix.

residuals

residuals(
    streams: Mapping[str, Stream],
    aux: Mapping[str, Array],
    params: Mapping[str, Any],
    ctx: Context,
) -> Array

Material balance, pressure spec, and the (adiabatic or fixed-T) energy balance.

Splitter dataclass

Splitter(
    inlets: tuple[str, ...],
    outlets: tuple[str, ...],
    fractions: Spec = 1.0,
)

Bases: Block

Flow splitter: one inlet to several outlets sharing composition and state.

Attributes:

Name Type Description
fractions Spec

Per-outlet split fractions (literal sequence/array or a parameter key), one per name in outlets.

Methods:

Name Description
n_residuals

n_outlets * (n_components + 2) (each outlet fully defined).

forward

Evaluate via fugacio.sim.units.splitter.

residuals

Each outlet carries its split fraction of the feed at the feed's T and P.

n_residuals

n_residuals(ctx: Context) -> int

n_outlets * (n_components + 2) (each outlet fully defined).

forward

forward(
    streams: Mapping[str, Stream],
    params: Mapping[str, Any],
    ctx: Context,
) -> dict[str, Stream]

Evaluate via fugacio.sim.units.splitter.

residuals

residuals(
    streams: Mapping[str, Stream],
    aux: Mapping[str, Array],
    params: Mapping[str, Any],
    ctx: Context,
) -> Array

Each outlet carries its split fraction of the feed at the feed's T and P.

Heater dataclass

Heater(
    inlets: tuple[str, ...],
    outlets: tuple[str, ...],
    t_out: Spec | None = None,
    duty: Spec | None = None,
    dp: Spec = 0.0,
)

Bases: Block

Heater/cooler on a temperature or a duty specification.

Provide exactly one of t_out (outlet temperature) or duty (signed heat added, W). dp is the pressure drop across the block.

Attributes:

Name Type Description
t_out Spec | None

Outlet temperature spec, or None if a duty is given.

duty Spec | None

Heat-duty spec (W), or None if an outlet temperature is given.

dp Spec

Pressure drop (Pa).

Methods:

Name Description
n_residuals

Material + pressure + energy: n_components + 2.

forward

Evaluate via fugacio.sim.units.heater.

residuals

Material, pressure drop, and the temperature or duty energy balance.

n_residuals

n_residuals(ctx: Context) -> int

Material + pressure + energy: n_components + 2.

forward

forward(
    streams: Mapping[str, Stream],
    params: Mapping[str, Any],
    ctx: Context,
) -> dict[str, Stream]

Evaluate via fugacio.sim.units.heater.

residuals

residuals(
    streams: Mapping[str, Stream],
    aux: Mapping[str, Array],
    params: Mapping[str, Any],
    ctx: Context,
) -> Array

Material, pressure drop, and the temperature or duty energy balance.

Valve dataclass

Valve(
    inlets: tuple[str, ...],
    outlets: tuple[str, ...],
    p_out: Spec = 100000.0,
)

Bases: Block

Isenthalpic (Joule-Thomson) pressure letdown to p_out.

Attributes:

Name Type Description
p_out Spec

Outlet pressure spec (literal or parameter key).

Methods:

Name Description
n_residuals

Material + pressure + isenthalpic energy: n_components + 2.

forward

Evaluate via fugacio.sim.units.valve.

residuals

Material, outlet-pressure spec, and conserved molar enthalpy.

n_residuals

n_residuals(ctx: Context) -> int

Material + pressure + isenthalpic energy: n_components + 2.

forward

forward(
    streams: Mapping[str, Stream],
    params: Mapping[str, Any],
    ctx: Context,
) -> dict[str, Stream]

Evaluate via fugacio.sim.units.valve.

residuals

residuals(
    streams: Mapping[str, Stream],
    aux: Mapping[str, Array],
    params: Mapping[str, Any],
    ctx: Context,
) -> Array

Material, outlet-pressure spec, and conserved molar enthalpy.

Pump dataclass

Pump(
    inlets: tuple[str, ...],
    outlets: tuple[str, ...],
    p_out: Spec = 100000.0,
    efficiency: Spec = 0.75,
)

Bases: Block

Incompressible-liquid pump to p_out with an isentropic-equivalent efficiency.

Attributes:

Name Type Description
p_out Spec

Outlet pressure spec.

efficiency Spec

Pump efficiency in (0, 1]; the lost work heats the outlet.

Methods:

Name Description
n_residuals

Material + pressure + energy: n_components + 2.

forward

Evaluate via fugacio.sim.units.pump.

residuals

Material, outlet pressure, and the work-deposited enthalpy balance.

n_residuals

n_residuals(ctx: Context) -> int

Material + pressure + energy: n_components + 2.

forward

forward(
    streams: Mapping[str, Stream],
    params: Mapping[str, Any],
    ctx: Context,
) -> dict[str, Stream]

Evaluate via fugacio.sim.units.pump.

residuals

residuals(
    streams: Mapping[str, Stream],
    aux: Mapping[str, Array],
    params: Mapping[str, Any],
    ctx: Context,
) -> Array

Material, outlet pressure, and the work-deposited enthalpy balance.

Compressor dataclass

Compressor(
    inlets: tuple[str, ...],
    outlets: tuple[str, ...],
    p_out: Spec = 100000.0,
    efficiency: Spec = 0.75,
    _is_turbine: bool = False,
)

Bases: _Machine

Isentropic compressor to p_out with an isentropic efficiency (< 1).

Turbine dataclass

Turbine(
    inlets: tuple[str, ...],
    outlets: tuple[str, ...],
    p_out: Spec = 100000.0,
    efficiency: Spec = 0.75,
    _is_turbine: bool = True,
)

Bases: _Machine

Isentropic turbine (expander) to p_out with an isentropic efficiency (< 1).

Flash dataclass

Flash(
    inlets: tuple[str, ...],
    outlets: tuple[str, ...],
    t: Spec = 298.15,
    p: Spec = 100000.0,
)

Bases: Block

Isothermal-isobaric two-phase flash: one inlet to vapour and liquid outlets.

outlets must be (vapor_name, liquid_name). The block contributes the component material balances, the equifugacity equilibrium relations (phi_i^L x_i = phi_i^V y_i), and the temperature/pressure specs on both product streams, the same equations the sequential-modular flash_drum converges internally.

Attributes:

Name Type Description
t Spec

Drum temperature spec (literal or parameter key).

p Spec

Drum pressure spec (literal or parameter key).

Methods:

Name Description
n_residuals

Material + equilibrium + 2 T-specs + 2 P-specs: 2 * (n_components + 2).

forward

Evaluate via fugacio.sim.units.flash_drum.

residuals

Equifugacity + material balance + temperature/pressure specs on both phases.

n_residuals

n_residuals(ctx: Context) -> int

Material + equilibrium + 2 T-specs + 2 P-specs: 2 * (n_components + 2).

forward

forward(
    streams: Mapping[str, Stream],
    params: Mapping[str, Any],
    ctx: Context,
) -> dict[str, Stream]

Evaluate via fugacio.sim.units.flash_drum.

residuals

residuals(
    streams: Mapping[str, Stream],
    aux: Mapping[str, Array],
    params: Mapping[str, Any],
    ctx: Context,
) -> Array

Equifugacity + material balance + temperature/pressure specs on both phases.

ComponentSeparator dataclass

ComponentSeparator(
    inlets: tuple[str, ...],
    outlets: tuple[str, ...],
    split_to_top: Spec = 0.5,
    top_t: Spec | None = None,
    top_p: Spec | None = None,
    bottom_t: Spec | None = None,
    bottom_p: Spec | None = None,
)

Bases: Block

Idealised separator with a per-component recovery to the top product.

outlets must be (top_name, bottom_name). split_to_top is a per-component fraction sent to the top; the remainder leaves in the bottom.

Attributes:

Name Type Description
split_to_top Spec

Per-component recovery to the top (sequence/array or key).

top_t Spec | None

Optional top-product temperature (defaults to the feed's).

top_p Spec | None

Optional top-product pressure (defaults to the feed's).

bottom_t Spec | None

Optional bottom-product temperature (defaults to the feed's).

bottom_p Spec | None

Optional bottom-product pressure (defaults to the feed's).

Methods:

Name Description
n_residuals

Two fully-defined outlets: 2 * (n_components + 2).

forward

Evaluate via fugacio.sim.units.component_separator.

residuals

Per-component split to the top/bottom with their temperature/pressure specs.

n_residuals

n_residuals(ctx: Context) -> int

Two fully-defined outlets: 2 * (n_components + 2).

forward

forward(
    streams: Mapping[str, Stream],
    params: Mapping[str, Any],
    ctx: Context,
) -> dict[str, Stream]

Evaluate via fugacio.sim.units.component_separator.

residuals

residuals(
    streams: Mapping[str, Stream],
    aux: Mapping[str, Array],
    params: Mapping[str, Any],
    ctx: Context,
) -> Array

Per-component split to the top/bottom with their temperature/pressure specs.

resolve

resolve(spec: Spec, params: Mapping[str, Any]) -> Array

Resolve a Spec to a JAX array.

A string is looked up in params (so the value can be a differentiable parameter or a design-spec unknown); anything else is treated as a literal.

Parameters:

Name Type Description Default
spec Spec

A literal value or a key into params.

required
params Mapping[str, Any]

The parameter mapping passed to the solver.

required

Returns:

Type Description
Array

The resolved value as a float array.

Raises:

Type Description
KeyError

if spec is a string with no entry in params.

Optimization

optimize

Optimization over an equation-oriented flowsheet.

An EO flowsheet is differentiable end to end, so a design-optimization problem ("minimize the cost / maximize the yield over these operating variables") is a smooth program the gradient-based optimizers in fugacio.sim.optimize solve directly. Two equivalent formulations are offered:

  • Nested (simultaneous=False, the robust default): the decision variables parameterize the flowsheet, each objective evaluation solves the flowsheet to convergence (one Newton solve), and the optimizer descends the resulting reduced objective. The flowsheet solve is differentiable, so the reduced gradient is exact.
  • Simultaneous / full-space (simultaneous=True): the decision variables and the flowsheet state are optimized together, with the flowsheet equations imposed as equality constraints (an augmented-Lagrangian solve). No inner loop converges the flowsheet; feasibility and optimality are reached at once, the classic equation-oriented optimization paradigm.

Both return the optimal decision and the converged flowsheet at that optimum.

Classes:

Name Description
EOOptResult

Outcome of an equation-oriented flowsheet optimization.

Functions:

Name Description
optimize_flowsheet_eo

Optimize an EO flowsheet over named decision variables.

EOOptResult dataclass

EOOptResult(
    decision: dict[str, Array],
    objective: Array,
    solution: EOSolution,
    converged: Array,
    constraint_violation: Array,
)

Outcome of an equation-oriented flowsheet optimization.

Attributes:

Name Type Description
decision dict[str, Array]

Optimal value of each decision variable (keyed by name).

objective Array

Objective value at the optimum.

solution EOSolution

The converged EOSolution at the optimum.

converged Array

Whether the optimizer met its tolerances.

constraint_violation Array

Max flowsheet-equation violation (0 for the nested formulation; the feasibility residual for the simultaneous one).

optimize_flowsheet_eo

optimize_flowsheet_eo(
    flowsheet: EOFlowsheet,
    objective: Objective,
    decisions: Mapping[str, Decision],
    *,
    params: Mapping[str, Any] | None = None,
    simultaneous: bool = False,
    tol: float = 1e-06,
    max_iter: int = 200,
    solve_kwargs: Mapping[str, Any] | None = None,
) -> EOOptResult

Optimize an EO flowsheet over named decision variables.

Parameters:

Name Type Description Default
flowsheet EOFlowsheet

The EOFlowsheet to optimize.

required
objective Objective

Scalar objective objective(streams) -> () to minimize, read off the solved streams.

required
decisions Mapping[str, Decision]

Map of parameter key -> (init, lower, upper). Each key is read by some block; the optimizer varies it within its bounds.

required
params Mapping[str, Any] | None

Fixed parameters merged under the decisions for every solve.

None
simultaneous bool

Use the full-space formulation (flowsheet equations as equality constraints) instead of the nested one.

False
tol float

Optimizer tolerance.

1e-06
max_iter int

Optimizer outer-iteration cap.

200
solve_kwargs Mapping[str, Any] | None

Extra keyword arguments forwarded to EOFlowsheet.solve (e.g. sweeps, tol, max_iter) in the nested formulation.

None

Returns:

Type Description
EOOptResult

An EOOptResult with the optimal decision and the converged flowsheet.