"""
EELT 7030 — Operation and Expansion Planning of Electric Power Systems
Federal University of Paraná (UFPR)
Utility: Solve Pyomo Model from YAML Configuration
Author
------
Augusto Mathias Adams <augusto.adams@ufpr.br>
Description
-----------
This utility builds and solves a Pyomo optimization model using input
data provided in a YAML or JSON configuration file. The solver is selected
based on metadata, and can include support for decomposition strategies
(e.g., MIN-DT via MindtPy).
Features:
- Automatic model construction via modular subsystems (thermal, hydro, storage, renewable).
- Solver selection and configuration via YAML metadata.
- Support for MINLP solvers such as MindtPy with strategy and time limits.
- Termination condition validation to ensure feasibility or optimality.
References
----------
[1] CEPEL, DESSEM. Manual de Metodologia, 2023
[2] Unsihuay Vila, C. Introdução aos Sistemas de Energia Elétrica, Lecture Notes, EELT7030/UFPR, 2023.
"""
from pyomo.opt import SolverFactory, TerminationCondition
from pyomo.common.errors import ApplicationError
from pyomo.environ import ConcreteModel, Suffix, value
from typing import Any, Tuple, Dict
from colorama import Fore, Style, init as colorama_init
from .Builder import build_model_from_file
from .Reporting import *
from .ModelCheck import *
from .ModelFormatters import *
colorama_init(autoreset=True)
[docs]
def solve(path: str) -> Tuple[ConcreteModel, Dict]:
"""
Build and solve a Pyomo optimization model from a configuration file.
This function loads a model and its configuration from a structured YAML or JSON
file using the `build_model_from_file` routine. It then selects the appropriate
solver based on the 'meta' section, applies any solver-specific options (including
for MIN-DT decomposition), and executes the optimization.
Parameters
----------
path : str
Path to the configuration file containing model metadata and data sections.
Returns
-------
model : ConcreteModel
The Pyomo model after the solve routine, with variables populated.
case : dict
Parsed dictionary containing the original configuration, metadata,
solver options, and problem data.
Raises
------
RuntimeError
If the solver is not available, solve fails, or model is infeasible.
"""
model, case = build_model_from_file(path)
solver_str = case['meta']['Solver']
options = case['meta'].get('Solver_Options', {})
print_welcome_message(model, case)
# Habilita captura dos valores duais
model.dual = Suffix(direction=Suffix.IMPORT_EXPORT)
# Create solver instance
opt = SolverFactory(solver_str)
if not opt.available():
raise RuntimeError(
f"Solver '{solver_str}' is not available on this system.")
try:
if solver_str.lower() == 'mindtpy':
res = opt.solve(
model,
mip_solver=options.get('mip_solver', 'glpk'),
nlp_solver=options.get('nlp_solver', 'cyipopt'),
strategy=options.get('strategy', 'OA'),
tee=False,
suffixes=["dual"]
)
else:
res = opt.solve(model, tee=False,
suffixes=["dual"])
# Check termination condition
term_cond = res.solver.termination_condition
if term_cond not in [TerminationCondition.optimal,
TerminationCondition.feasible]:
raise RuntimeError(f"Solve terminated with condition: {term_cond}")
except ApplicationError as e:
raise RuntimeError(f"Solver execution failed: {e}")
dispatch_summary(model)
generator_dispatch_summary(model)
storage_dispatch_summary(model)
return model, case