monee solver

The public names below are re-exported from monee.solver (e.g. from monee.solver import GEKKOSolver, PyomoSolver). Most code does not instantiate a back-end directly - pass a solver name such as "ipopt" or "gurobi" to the top-level entry points and let resolve_solver() pick the back-end.

Core

Back-end-agnostic machinery: the abstract SolverInterface, the SolverResult returned by every solve, and the shared solve-pipeline helpers (variable injection/withdrawal, islanding-aware component pruning, warm starting, post-processing).

class monee.solver.core.InterStepState[source]

Bases: ABC

Abstract base. step: negative = relative to current, non-negative = absolute.

dt_h: float = 1.0
abstractmethod get(component_id, attr: str, step: int = -1)[source]

Float (StepState) / live var (PeriodState), or None if no data.

has(component_id, attr: str)[source]
Return type:

bool

class monee.solver.core.OperatorEquationAssembly[source]

Bases: object

Equation-assembly passes shared by backends whose model object exposes operator-overloaded symbols plus GEKKO-style hooks (m.sin/m.cos/…, m.Equation(s), m.Obj, m.Intermediate): the GEKKO and CasADi backends.

monee’s component equations() bodies are backend-agnostic - they build expressions from the injected variable objects and the math hooks passed in - so a single set of passes drives both backends. Pyomo and Gurobi construct constraints differently (their own intermediate handling / objective accumulation) and provide their own overrides instead of using this mixin.

Hosts must set self._simulation (the per-solve simulation flag, read by the branch pass to drop operational flow limits) and may override _pwl_impl().

process_equations_branches(m, network, branches, ignored_nodes, objs_exprs)[source]
process_equations_compounds(m, network, compounds, ignored_nodes)[source]
process_equations_nodes_childs(m, network: monee.model.network.Network, nodes, ignored_nodes)[source]
process_internal_oxf_components(m, network)[source]
process_oxf_components(m, network: monee.model.network.Network, optimization_problem, period_index=None)[source]
class monee.solver.core.PeriodState(networks: list, current_t: int, dt_h: float = 1.0, initial_state: dict | None = None)[source]

Bases: InterStepState

All period networks (multi-period). get returns live solver vars after injection, so reading from another period becomes an algebraic cross-period constraint. Both past and future absolute indices are accessible.

Note

Absolute (non-negative) step indices are window-local under run_mpc(): self._networks is only the current rolling window’s networks, so step=0 means the first period of this window, not the global start of the run. This differs from StepState, whose absolute indices stay globally meaningful via its dropped-prefix bookkeeping. Relative (negative) lookbacks behave identically in both. Prefer relative indices in inter_step_equations if you need MPC-window-independent behaviour.

property T: int
get(component_id, attr: str, step: int = -1)[source]

Float (StepState) / live var (PeriodState), or None if no data.

class monee.solver.core.SinglePeriodSolverProtocol[source]

Bases: object

Documents the contract a solver backend must expose to act as a delegate inside GekkoMultiPeriodSolver / PyomoMultiPeriodSolver. Not enforced at runtime.

class monee.solver.core.SolverInterface[source]

Bases: ABC

Abstract base class for solver backends (GEKKO, Pyomo, …).

init_branches(branches)[source]
static mark_temporal_components(network, ignored_nodes: set)[source]

Set _temporal_active on every model carrying a temporal method, so static-only constraints can be suppressed when coupling is active.

Return type:

None

process_inter_period_equations(solver_obj, network: monee.model.network.Network, nodes, branches, compounds, ignored_nodes: set, period_state, optimization_problem=None, period_index=None)[source]

Collect inter_period_equations + inter_temporal_equations plus user temporal constraints for multi-period solves.

process_inter_step_equations(solver_obj, network: monee.model.network.Network, nodes, branches, compounds, ignored_nodes: set, step_state, optimization_problem=None, period_index=None)[source]

Collect inter_step_equations + inter_temporal_equations plus user temporal constraints for timeseries solves.

abstractmethod solve(input_network: monee.model.network.Network, optimization_problem: monee.problem.core.OptimizationProblem = None, draw_debug=False, exclude_unconnected_nodes=False, step_state=None, simulation=False, formulation=None)[source]

Solve the energy-flow / optimisation problem for input_network.

Parameters:
  • input_network (monee.model.network.Network) – The network to solve.

  • optimization_problem (monee.problem.core.OptimizationProblem) – Optional optimisation problem with objectives and constraints. If None, performs a plain energy-flow solve.

  • draw_debug – If True, emit debug output from the solver.

  • exclude_unconnected_nodes – Legacy flag; prefer islanding config.

  • step_state – Inter-step state from the previous timeseries step.

  • simulation – If True, square the model (pin phantom vars, drop operational flow limits) and solve it as a steady-state simulation. GEKKO runs this as IMODE=1 (falling back to IMODE=3 if not square); backends without a simulation mode ignore it.

  • formulation – Solve-time formulation override - a registry key string ("smooth_nlp", "convex_miqcqp", …), a NetworkFormulation, or a sequence of either (merged left to right). Overrides the network-level apply_formulation choice; components without any choice fall back to DEFAULT_SIMULATION_FORMULATION.

Returns:

monee.solver.core.SolverResult – A SolverResult with updated variable values and result DataFrames.

class monee.solver.core.SolverResult(network: monee.model.network.Network, dataframes: dict[str, pandas.DataFrame], objective: float | None, success: bool, violations: dict[str, float] = <factory>, solver_status: str | None = None, termination_condition: str | None = None, mode_used: str | None = None, infeasibility_report: object | None = None)[source]

Bases: object

Outcome of a single solve. objective=0.0 for plain energy flow; None when not meaningful (e.g. MultiPeriodResult.get_period_result).

Termination metadata

solver_status and termination_condition mirror the Pyomo SolverStatus / TerminationCondition strings (or None if not populated by the backend). They let downstream consumers distinguish a converged-optimal solution from a witness incumbent Gurobi returns when it hits a time limit — the witness has success=True and looks identical otherwise. Callers that care about convergence (e.g. the MC resilience pipeline, which must drop aborted samples rather than averaging in a non-converged shed value) can inspect termination_condition to detect the time-limit case.

dataframes: dict[str, DataFrame]
full()[source]
get(model_type)[source]

Result DataFrame for model_type (typo-safe vs. dict access).

Return type:

pandas.DataFrame

infeasibility_report: object | None = None

Diagnostic infeasibility report when the solve failed (success=False); None on success. Declaring it as a field gives both backends a single, documented place to surface the report instead of the GEKKO-raises / Pyomo-dynamic-attribute split. (GEKKO additionally raises GekkoSolveError carrying the same report.)

mode_used: str | None = None

"simulation" (square IMODE=1 steady-state) or "optimization" (IMODE=3). When a simulation was requested but the model was not square, this reads "optimization" - the signal that the fast steady-state path silently fell back. None when the backend doesn’t distinguish the two (e.g. Pyomo).

Type:

Which solve mode actually ran

network: Network
objective: float | None
plot(title: str | None = None, show_children: bool = True, use_monee_positions: bool = False, write_to: str | None = None)[source]

Plotly interactive network graph; delegates to plot_result().

solver_status: str | None = None
success: bool
summary()[source]
termination_condition: str | None = None
violations: dict[str, float]
class monee.solver.core.StepState(initial_state: dict | None = None, max_steps: int | None = None)[source]

Bases: InterStepState

All previously-solved network copies (sequential timeseries). get returns floats.

initial_state falls back when no prior solve has written the attribute. max_steps caps how many solved networks are retained (None = unlimited): each network is a full copy, so an open-ended run (e.g. a Stepper paced by a co-simulation framework) would otherwise grow memory without bound. Absolute step indices keep their meaning when old networks are dropped; reading a dropped step falls back to initial_state.

get(component_id, attr: str, step: int = -1)[source]

Float (StepState) / live var (PeriodState), or None if no data.

push(net)[source]
Return type:

None

monee.solver.core.apply_post_process(model: monee.model.core.GenericModel)[source]

Evaluate the model’s PostProcess attributes from its solved values - runs after withdraw_vars and fully outside the solver. Lambdas receive a namespace, so they read fields as v.vm_pu (not v["vm_pu"]).

Return type:

None

monee.solver.core.apply_post_process_all(nodes, branches, compounds, network)[source]

Run apply_post_process() over every solved component.

Return type:

None

monee.solver.core.as_iter(possible_iter)[source]
monee.solver.core.col_summary(series: pandas.Series)

One-line numeric summary for a single attribute column.

Returns 'val' for a constant column, '[lo, hi]' when values vary, or None when the series is empty or entirely NaN.

Return type:

str | None

monee.solver.core.compute_bound_violations(nodes, branches, compounds, network, tol: float = 1e-06)[source]

{"<Type>.<id>.<attr>": magnitude} for Var.value violations beyond tol.

Return type:

dict[str, float]

monee.solver.core.display_df(df: pandas.DataFrame)

Return df with internal bookkeeping columns removed.

Return type:

pandas.DataFrame

monee.solver.core.filter_bool_eqs(eqs, context=None)[source]

Drop Python-bool sentinel equations, identically for both backends.

An equations() body can collapse a constraint to a Python bool when a component is over-deactivated (e.g. an attribute overwritten by a Const so a == b evaluates eagerly):

  • True → tautology, a no-op; dropped silently.

  • False → structurally infeasible (contradictory) constraint. Feeding it into model construction either crashes the build (GEKKO) or - if it were kept - injects an unsatisfiable constraint. We drop it so the load-shedding objective can resolve the situation, but emit a warning so the modelling error is surfaced rather than silently hidden.

context is an optional label (e.g. "node_3") included in the warning.

monee.solver.core.filter_intermediate_eqs(eqs)[source]
monee.solver.core.find_ignored_nodes(network: monee.model.network.Network, islanding_config=None)[source]

Return node IDs to exclude from the solve.

Default: active topology, only ExtPowerGrid/ExtHydrGrid children are “leading”. With islanding_config: full topology (backup lines included) and any GridFormingMixin child counts as leading for an islanding-enabled carrier.

monee.solver.core.generate_real_topology(nx_net)[source]
monee.solver.core.ignore_branch(branch, network: monee.model.network.Network, ignored_nodes)[source]
monee.solver.core.ignore_child(child, ignored_nodes)[source]
monee.solver.core.ignore_compound(compound, ignored_nodes)[source]
monee.solver.core.ignore_node(node, network: monee.model.network.Network, ignored_nodes)[source]
monee.solver.core.inject_nans(target: monee.model.core.GenericModel)[source]

Replace Var/Const fields with NaN placeholders; zero regulation.

monee.solver.core.inject_vars(inject_fn, nodes, branches, compounds, network, ignored_nodes)[source]

Call inject_fn(model, component, category) on each active component; ignored components get inject_nans() instead.

category ∈ {branch, node, child, compound}.

monee.solver.core.mark_he_flow_prescription(network: monee.model.network.Network, ignored_nodes)[source]

Decide for each dynamic heat exchanger (compound-internal SubHE) whether it prescribes its design mass flow or yields to the network.

A SubHE bridges water islands through its multi-grid control node (the islands stay separate because _carrier_islands() only spans pure water nodes). In a supply/return structure every adjacent island has a slack child with a free mass flow (ExtHydrGrid / ConsumeHydrGrid), so the through-flow is otherwise undetermined and the design flow must prescribe it. If any adjacent island lacks such a slack (e.g. a fixed-mass-flow Sink fed only through the compound), that island’s balance already fixes the through-flow - pinning it to the design flow would over-determine the system, so the HE yields and its energy balance runs on the actual flow instead (_he_flow_prescribed = False).

monee.solver.core.mark_heat_balance_slacks(network: monee.model.network.Network, ignored_nodes)[source]

Mark one grid-forming reference node per energized heat island so its (dependent) nodal heat balance is dropped - the heat carrier’s slack, mirroring the free mass-flow / angle slack the other carriers already have.

The nodal heat balances over a connected island are linearly dependent (one is redundant); the grid-forming node absorbs the imbalance. Islands are connected components of the active water subgraph; references are GridFormingMixin children, matching the islanding extension’s criterion.

monee.solver.core.mark_ignored_components(network, ignored_nodes)[source]

Pre-mark component.ignored so optimization_problem._apply excludes them.

monee.solver.core.persist_solution(solved_copy: monee.model.network.Network, original: monee.model.network.Network)[source]

Propagate solved values back so the next inject_vars warm-starts.

Return type:

None

monee.solver.core.pin_floating_hydraulic_gauges(network: monee.model.network.Network, ignored_nodes)[source]

Pin one node’s pressure per energized gas/water island that has no grid-forming source.

A grid-forming child (ExtHydrGrid / GridFormingSource) pins an absolute pressure reference via its overwrite. An island with none references pressure only through the (relative) pipe pressure-drop equations - its absolute level is a free gauge degree of freedom, which IPOPT can only resolve by regularising a rank-deficient block (slow, fragile). Such islands arise routinely: e.g. a heat-exchanger-fed return loop, where the coupling HE transfers mass and temperature but imposes no pressure drop.

Pinning any one node’s pressure to the carrier nominal removes the rank-deficiency without changing flows or pressure differences (only the arbitrary absolute level). Temperature is left free: where present it is referenced through the heat-exchanger coupling, not a nodal pin.

monee.solver.core.remove_cps(network: monee.model.network.Network)[source]
monee.solver.core.withdraw_vars(withdraw_fn, nodes, branches, compounds, network)[source]

Call withdraw_fn(model) on each component to materialise solved Vars.

GEKKO back-end

class monee.solver.gekko.GEKKOSolver(solver=1)[source]

Bases: OperatorEquationAssembly, SolverInterface

static inject_gekko_vars_attr(gekko: gekko.gekko.GEKKO, target: monee.model.core.GenericModel, id, name_map=None)[source]
solve(input_network: monee.model.network.Network, optimization_problem: monee.problem.core.OptimizationProblem = None, draw_debug=False, exclude_unconnected_nodes=False, step_state: monee.solver.core.StepState = None, simulation=False, formulation=None)[source]

Solve the energy-flow / optimisation problem for input_network.

Parameters:
  • input_network (monee.model.network.Network) – The network to solve.

  • optimization_problem (monee.problem.core.OptimizationProblem) – Optional optimisation problem with objectives and constraints. If None, performs a plain energy-flow solve.

  • draw_debug – If True, emit debug output from the solver.

  • exclude_unconnected_nodes – Legacy flag; prefer islanding config.

  • step_state (monee.solver.core.StepState) – Inter-step state from the previous timeseries step.

  • simulation – If True, square the model (pin phantom vars, drop operational flow limits) and solve it as a steady-state simulation. GEKKO runs this as IMODE=1 (falling back to IMODE=3 if not square); backends without a simulation mode ignore it.

  • formulation – Solve-time formulation override - a registry key string ("smooth_nlp", "convex_miqcqp", …), a NetworkFormulation, or a sequence of either (merged left to right). Overrides the network-level apply_formulation choice; components without any choice fall back to DEFAULT_SIMULATION_FORMULATION.

Returns:

A SolverResult with updated variable values and result DataFrames.

static withdraw_gekko_vars_attr(target: monee.model.core.GenericModel)[source]
class monee.solver.gekko.GekkoCubicSplineImpl(m)[source]

Bases: object

piecewise_eq(y, x, xs, ys, name=None)[source]

Pyomo back-end

class monee.solver.pyo.PyomoPWLImpl(pm: pyomo.core.base.PyomoModel.ConcreteModel, pw_repn: str = 'SOS2')[source]

Bases: object

piecewise_eq(y, x, xs, ys, name: str | None = None)[source]
class monee.solver.pyo.PyomoSolver(solver_name: str = 'scip')[source]

Bases: SolverInterface

Pyomo-backed solver. solver_name is overridable per solve().

static inject_pyomo_vars_attr(pm: pyomo.core.base.PyomoModel.ConcreteModel, target: monee.model.core.GenericModel, prefix: str)[source]

Replace Var/Const with Pyomo Var / numeric. Clamps stale initialize into [min, max] (suppresses W1002 when bounds tightened since last solve).

process_equations_branches(pm, network, branches, ignored_nodes)[source]
process_equations_compounds(pm, network, compounds, ignored_nodes)[source]
process_equations_nodes_childs(pm, network: monee.model.network.Network, nodes, ignored_nodes)[source]
process_internal_oxf_components(pm, network)[source]
process_oxf_components(pm, network, optimization_problem: monee.problem.core.OptimizationProblem, period_index=None)[source]
solve(input_network: monee.model.network.Network, optimization_problem: monee.problem.core.OptimizationProblem = None, draw_debug=False, exclude_unconnected_nodes: bool = False, step_state: monee.solver.core.StepState = None, simulation: bool = False, formulation=None, solver_name: str | None = None, **kwargs)[source]

Solve the energy-flow / optimisation problem for input_network.

Parameters:
  • input_network (monee.model.network.Network) – The network to solve.

  • optimization_problem (monee.problem.core.OptimizationProblem) – Optional optimisation problem with objectives and constraints. If None, performs a plain energy-flow solve.

  • draw_debug – If True, emit debug output from the solver.

  • exclude_unconnected_nodes (bool) – Legacy flag; prefer islanding config.

  • step_state (monee.solver.core.StepState) – Inter-step state from the previous timeseries step.

  • simulation (bool) – If True, square the model (pin phantom vars, drop operational flow limits) and solve it as a steady-state simulation. GEKKO runs this as IMODE=1 (falling back to IMODE=3 if not square); backends without a simulation mode ignore it.

  • formulation – Solve-time formulation override - a registry key string ("smooth_nlp", "convex_miqcqp", …), a NetworkFormulation, or a sequence of either (merged left to right). Overrides the network-level apply_formulation choice; components without any choice fall back to DEFAULT_SIMULATION_FORMULATION.

Returns:

A SolverResult with updated variable values and result DataFrames.

static withdraw_pyomo_vars_attr(target: monee.model.core.GenericModel)[source]

Pyomo Var → Var. Restores integer, snaps bound-noise to bounds, replaces NaN/None with 0 so the next solve’s warmstart survives.

class monee.solver.pyo.PyscipoptSolver[source]

Bases: object

Drive SCIP through the pyscipopt bindings when the classic scip executable is absent..

available(exception_flag: bool = False)[source]
Return type:

bool

solve(model, tee: bool = False, **kwargs)[source]
warm_start_capable()[source]
Return type:

bool

Dispatch

Solver dispatch - resolve (solver, backend) to a concrete solver.

Concrete instances pass through unchanged. IPOPT (the default solver) routes to the in-process CasADi backend when installed (falling back to GEKKO’s bundled IPOPT otherwise); the discrete GEKKO solvers (APOPT/BPOPT) route to GEKKO; any other name is forwarded to Pyomo. Default is therefore CasADi/IPOPT (GEKKO/IPOPT without casadi).

backend='gurobipy' selects the native in-memory Gurobi backend (GurobipySolver) instead of driving Gurobi through Pyomo’s file round-trip; it is single-period only and the solver name must be 'gurobi' (the sole solver it provides).

backend='casadi' selects the in-process CasADi/IPOPT backend (CasADiSolver), which builds the NLP once as an in-memory expression graph and calls IPOPT in-process (no subprocess). The solver name must be 'ipopt' (the sole solver it provides). It supports single-period solves, temporal timeseries (storage/linepack/LTC) via the per-step loop, and multi-period (CasADiMultiPeriodSolver); for memory-less timeseries it additionally enables a build-once / re-solve graph-reuse fast path in monee.run_timeseries().

monee.solver.dispatch.resolve_multi_period_solver(solver=None, backend: str | None = None)[source]

Multi-period analogue of resolve_solver().

monee.solver.dispatch.resolve_solver(solver=None, backend: str | None = None)[source]

Single-step SolverInterface for (solver, backend).

Return type:

monee.solver.core.SolverInterface

monee.solver.dispatch.GEKKO_SOLVERS: dict[str, int] = {"apopt": 1, "bpopt": 2, "ipopt": 3}

Mapping of GEKKO solver name to the GEKKO SOLVER option integer. These are the names resolve_solver() routes to the GEKKO back-end.

Infeasibility diagnostics

Solver-specific infeasibility diagnostics.

pyo analyses a Pyomo model after an infeasible solve (constraint residuals, bound violations, Minimal Infeasible Subsystem); apm parses the APMonitor run-directory artifacts of a failed GEKKO solve (IPOPT/APOPT). Both produce structured reports with a uniform summary().

Pyomo

Pyomo infeasibility diagnostics. Translates Pyomo var names like child_3__p_mw back to monee component descriptions and wraps the Pyomo analysis utilities.

class monee.solver.infeasibility.pyo.BoundViolation(name: str, display_name: str, value: float, lower: float | None, upper: float | None, violation: float)[source]

Bases: object

A variable violating or sitting on its bounds.

display_name: str
lower: float | None
name: str
upper: float | None
value: float
violation: float
class monee.solver.infeasibility.pyo.ConstraintResidual(index: int | str, body_value: float, lower: float | None, upper: float | None, residual: float, expression: str | None = None)[source]

Bases: object

A constraint that is violated or close to violation.

body_value: float
expression: str | None = None
index: int | str
lower: float | None
residual: float
upper: float | None
class monee.solver.infeasibility.pyo.InfeasibilityReport(constraint_residuals: list[monee.solver.infeasibility.pyo.ConstraintResidual] = <factory>, bound_violations: list[monee.solver.infeasibility.pyo.BoundViolation] = <factory>, variables_at_bounds: list[dict] = <factory>, mis_constraints: list[str] = <factory>)[source]

Bases: object

Structured infeasibility report.

bound_violations: list[BoundViolation]
constraint_residuals: list[ConstraintResidual]
mis_constraints: list[str]
summary(max_items: int = 10)[source]
Return type:

str

variables_at_bounds: list[dict]
monee.solver.infeasibility.pyo.collect_constraint_residuals(pm: pyomo.core.base.PyomoModel.ConcreteModel, tol: float = 0.0001)[source]

List constraints whose residual exceeds tol, sorted by magnitude.

Return type:

list[monee.solver.infeasibility.pyo.ConstraintResidual]

monee.solver.infeasibility.pyo.collect_variable_bound_violations(pm: pyomo.core.base.PyomoModel.ConcreteModel, tol: float = 0.0001)[source]

Return variables whose current value violates their bounds.

Return type:

list[monee.solver.infeasibility.pyo.BoundViolation]

monee.solver.infeasibility.pyo.collect_variables_at_bounds(pm: pyomo.core.base.PyomoModel.ConcreteModel, tol: float = 0.0001)[source]

List variables whose value sits within tol of a bound (active bounds).

Return type:

list[dict]

monee.solver.infeasibility.pyo.compute_mis(pm: pyomo.core.base.PyomoModel.ConcreteModel, solver_name: str = 'scip')[source]

Names/indices of constraints/bounds forming a Minimal Infeasible Subsystem. Needs SCIP/Gurobi/CPLEX. Each internal solve is capped at _MIS_TIME_LIMIT_S so a hard MIS computation can’t stall the caller.

Return type:

list[str]

monee.solver.infeasibility.pyo.diagnose_infeasibility(pm: pyomo.core.base.PyomoModel.ConcreteModel, solver_name: str = 'scip', tol: float = 0.0001, compute_mis_flag: bool = True)[source]

Build an InfeasibilityReport. compute_mis_flag triggers the Minimal Infeasible Subsystem analysis (slow).

Return type:

monee.solver.infeasibility.pyo.InfeasibilityReport

GEKKO / APMonitor

GEKKO/APMonitor infeasibility diagnostics (IPOPT and APOPT).

On a failed local solve APMonitor leaves two artifacts in the run directory (m._path) before GEKKO raises its bare @error: Solution Not Found:

  • infeasibilities.txt - the equations with the largest residuals at the final iterate, each with the involved variables (value, bounds, marginal),

  • results.json - the final (failed) iterate for every variable.

This module parses both into a structured GekkoInfeasibilityReport analogous to the Pyomo InfeasibilityReport. APMonitor sanitises variable names with re.sub(r"\W+", "_", name).lower() (powergenerator-5.p_mwpowergenerator_5_p_mw), which is not reversible; callers therefore pass a name_map of sanitised → original monee names, built while injecting the GEKKO variables.

class monee.solver.infeasibility.apm.ApmEquationResidual(number: int, lower: float, residual: float, upper: float, infeasibility: float, equation: str, variables: list[monee.solver.infeasibility.apm.ApmVariableState] = <factory>)[source]

Bases: object

An equation flagged by APMonitor as possibly infeasible.

equation: str
infeasibility: float
lower: float
number: int
residual: float
upper: float
variables: list[ApmVariableState]
class monee.solver.infeasibility.apm.ApmVariableState(name: str, display_name: str, value: float, lower: float, upper: float, marginal: float)[source]

Bases: object

A variable as listed under an infeasible equation.

display_name: str
lower: float
marginal: float
name: str
upper: float
value: float
class monee.solver.infeasibility.apm.GekkoInfeasibilityReport(solver_message: str = '', infeasible_equations: list[monee.solver.infeasibility.apm.ApmEquationResidual] = <factory>, bound_violations: list[dict] = <factory>, variables_at_bounds: list[dict] = <factory>)[source]

Bases: object

Structured report of a failed GEKKO/APMonitor solve.

bound_violations: list[dict]
infeasible_equations: list[ApmEquationResidual]
solver_message: str = ''
summary(max_items: int = 10)[source]
Return type:

str

variables_at_bounds: list[dict]
exception monee.solver.infeasibility.apm.GekkoSolveError(message: str, report: monee.solver.infeasibility.apm.GekkoInfeasibilityReport | None = None)[source]

Bases: RuntimeError

Failed GEKKO solve with attached GekkoInfeasibilityReport.

monee.solver.infeasibility.apm.collect_gekko_bound_violations(m, tol: float = 0.0001, name_map: dict[str, str] | None = None)[source]

Variables whose failed-iterate value violates their declared bounds.

Return type:

list[dict]

monee.solver.infeasibility.apm.collect_gekko_variables_at_bounds(m, tol: float = 0.0001, name_map: dict[str, str] | None = None)[source]

Variables whose failed-iterate value sits within tol of a bound.

Return type:

list[dict]

monee.solver.infeasibility.apm.diagnose_gekko_infeasibility(m, name_map: dict[str, str] | None = None, solver_message: str = '', tol: float = 0.0001)[source]

Build a GekkoInfeasibilityReport from the run directory of a failed local solve. Best-effort: returns None when no artifacts exist (e.g. remote solve) and never raises.

Return type:

monee.solver.infeasibility.apm.GekkoInfeasibilityReport | None

monee.solver.infeasibility.apm.parse_infeasibilities(text: str, name_map: dict[str, str] | None = None)[source]

Parse the ‘POSSIBLE INFEASIBLE EQUATIONS’ section of infeasibilities.txt.

Return type:

list[monee.solver.infeasibility.apm.ApmEquationResidual]

monee.solver.infeasibility.apm.sanitize_apm_name(name: str)[source]

Replicate GEKKO’s variable-name sanitisation (gekko.Var).

Return type:

str