flexmeasures.data.models.planning.highspy_optimization

Direct HiGHS (highspy) implementation of the device scheduler.

Warning

TWO MODELS TO KEEP IN SYNC

This module deliberately duplicates the mathematical model of flexmeasures.data.models.planning.linear_optimization.device_scheduler() (the Pyomo implementation), building the LP/MILP directly with the HiGHS Python API (highspy) instead. The Pyomo implementation is the semantic reference: any change to the variables, constraints or objective in device_scheduler MUST be mirrored here (and vice versa), and the equivalence tests in tests/test_highspy_equivalence.py should be extended accordingly. This trade-off (a second model to maintain) was accepted because bypassing the Pyomo layer cuts roughly a second (single device) to several seconds (multiple devices) of model construction and solution-ingestion overhead per scheduling job, while the direct build takes milliseconds.

Deviations from the Pyomo implementation (all verified against the behavior of the appsi_highs path):

  • ems_flow_commitment_equalities is not built. On the Pyomo path this constraint family returns (None, expr, None), i.e. a constraint without bounds, which ends up as a free (vacuous) row in HiGHS. We skip building the free rows altogether.

  • Rows whose computed bounds are impossible to satisfy for any finite value (upper bound of -inf, or lower bound of +inf, as happens when a commitment quantity is +/-inf) are skipped. On the Pyomo path such rows are rejected by HiGHS’ addRow (called by appsi) and thereby silently dropped, with the same net effect.

  • Solver results and model objects are lightweight shims (see HighspySolverResults and HighspyModel) that expose the attributes callers actually consume, rather than Pyomo objects.

Functions

flexmeasures.data.models.planning.highspy_optimization.device_scheduler_highspy(device_constraints: list[DataFrame], ems_constraints: DataFrame | list[DataFrame], commitment_quantities: list[Series] | None = None, commitment_downwards_deviation_price: list[Series] | list[float] | None = None, commitment_upwards_deviation_price: list[Series] | list[float] | None = None, commitments: list[DataFrame] | list[Commitment] | None = None, initial_stock: float | list[float] = 0, stock_groups: dict[int, list[int]] | None = None, ems_constraint_groups: list[list[int]] | None = None, device_power_bands: list[list[tuple[float, float]] | None] | None = None) tuple[list[Series], float, HighspySolverResults, HighspyModel]

Direct HiGHS implementation of device_scheduler.

Same inputs and same return contract as flexmeasures.data.models.planning.linear_optimization.device_scheduler(), which also documents the semantics of all arguments; the third and fourth returned objects are lightweight shims rather than Pyomo objects (see HighspySolverResults and HighspyModel).

Classes

class flexmeasures.data.models.planning.highspy_optimization.HighspyModel

Small stand-in for the Pyomo ConcreteModel returned by device_scheduler.

Exposes the attributes that callers and tests consume:

  • commitment_costs: dict of realized costs per (original) commitment

  • commodity_costs: dict of realized costs per commodity

  • costs: the objective value (a float; pyomo.environ.value() passes floats through unchanged, so value(model.costs) keeps working)

  • d and j: the device and datetime index ranges

  • ems_power, device_power_up, device_power_down, device_power_sign: indexed variable views supporting var[d, j].value and var.extract_values()

__init__()
class flexmeasures.data.models.planning.highspy_optimization.HighspySolverResults(termination_condition: str, status: str)

Small stand-in for Pyomo’s SolverResults.

Callers only consume results.solver.termination_condition (a string containing “optimal”/”infeasible”) and results.solver.status.

__init__(termination_condition: str, status: str)