Optimisation: building and solving problems with GemsPy
GemsPy offers three levels of abstraction for running an optimisation:
| Level | Entry point | Best for |
|---|---|---|
| High-level (recommended) | run_study() |
Directory-based studies, no custom logic |
| Mid-level | SimulationSession |
Full control over config and resolution mode |
| Low-level | build_problem() |
Fine-grained programmatic control |
High-level: run_study()
The simplest way to run a study is a single function call. It reads the study
directory, loads input/optim-config.yml (using defaults when absent), solves
the problem, and writes results to output/<run_id>/.
An alternative optim-config.yml path can be provided:
Mid-level: SimulationSession
SimulationSession gives you explicit control over which configuration is used
and lets you inspect the returned SimulationTable in memory.
from pathlib import Path
from gems.study.folder import load_study
from gems.session import SimulationSession
from gems.optim_config import load_optim_config
study = load_study(Path("my_study"))
optim_config = load_optim_config(Path("my_study/input/optim-config.yml"))
session = SimulationSession(study=study, optim_config=optim_config)
results = session.run() # returns a SimulationTable
The resolution strategy (frontal, sequential, parallel, Benders) is selected
automatically from optim_config.resolution.mode. See
Optimisation configuration for details.
Low-level: build_problem()
Use build_problem() when you need direct access to the OptimizationProblem
object — for example to export an LP file, inspect variable labels, or chain
multiple solve calls.
Building the optimisation problem
from pathlib import Path
from gems.study import Study
from gems.study.folder import load_study
from gems.simulation import build_problem, TimeBlock
study = load_study(Path("my_study"))
problem = build_problem(
study,
TimeBlock(1, list(range(timespan))),
scenario_ids=list(range(nb_scenarios)),
)
scenario_ids is a list of Monte-Carlo scenario indices (0-based). For
example, scenario_ids=[0, 1, 2] runs three scenarios.
Solving the optimisation problem
problem.solve() # uses HiGHS by default
print(problem.objective_value) # float
print(problem.status) # 'ok' or 'warning'
A different solver or additional solver options can be passed via solver_name.
HiGHS, Xpress (≥ 9.8), and Gurobi (≥ 10.0) are supported:
problem.solve(solver_name="highs", threads=4) # HiGHS
problem.solve(solver_name="xpress") # Xpress
problem.solve(solver_name="gurobi") # Gurobi
Note — dual variables and reduced costs are available as model outputs when using any of these solvers. Xpress and Gurobi require their respective Python packages (
xpress>=9.8,gurobipy>=10.0) and a valid licence.