Source code for MDI.Storage.StorageBuilder

"""
Storage Builder Module
======================
EELT7030 — Operation and Expansion Planning of Electric Power Systems  
Federal University of Paraná (UFPR)

Author
------
Augusto Mathias Adams <augusto.adams@ufpr.br>

Summary
-------
This module defines the construction logic of the **energy storage subsystem**
within the MDI optimization framework. It provides high-level builder functions
that assemble the complete storage model — including sets, parameters,
variables, constraints, and the objective function — from structured input data.

Description
-----------
Two functions are defined in this module:

1. **`build_storage(data, include_objective=True)`**  
   Creates and initializes a standalone Pyomo model for the storage subsystem,
   suitable for testing or modular integration.

2. **`add_storage_problem(m, data, include_objective=False)`**  
   Extends an existing Pyomo model with the complete storage problem definition,
   including constraints and (optionally) the objective function.

The builder integrates all necessary symbolic components:
sets and parameters, decision variables, constraints on power,
energy balance, state-of-charge (SoC), and investment logic.

Mathematical Overview
---------------------
The storage subsystem typically includes the following formulations:

**Energy balance**
\[
E_{t} = E_{t-1} + \eta_c P^{ch}_{t} - \frac{1}{\eta_d} P^{dis}_{t}
\]

**Power limits**
\[
0 \leq P^{ch}_{t}, P^{dis}_{t} \leq P^{max} \, x_{t}
\]

**State of charge bounds**
\[
E^{min} \leq E_{t} \leq E^{max}
\]

**Investment linkage**
\[
x_{t} = x_{t-1} + y_{t}
\]

where:
- \(E_t\): energy stored at period *t*  
- \(P^{ch}_t, P^{dis}_t\): charging/discharging power  
- \(\eta_c, \eta_d\): charging/discharging efficiencies  
- \(x_t, y_t\): operational and investment binary decisions  

Functions
---------
build_storage(data, include_objective=True)
    Creates and returns a complete Pyomo model for the storage subsystem.

add_storage_problem(m, data, include_objective=False)
    Adds the storage problem definition to an existing model.

Notes
-----
- The `include_objective` flag controls whether the subsystem-level
  objective (minimization of total storage cost) is included.
- The modular structure mirrors that of the generator subsystem
  to ensure composability within hybrid systems (hydrothermal or
  generation-storage models).
- All internal components (sets, variables, constraints) are
  imported from specialized modules to maintain separation of concerns.

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.

Module Dependencies
-------------------
- **Internal:**  
  - ``StorageDataTypes``  
  - ``StorageObjective``  
  - ``StorageVars``  
  - ``StorageConstraints``  

- **External:**  
  - ``pyomo.environ`` (ConcreteModel, Objective, minimize)
"""

from pyomo.environ import ConcreteModel, Objective, minimize
from .StorageDataTypes import StorageData
from .StorageObjective import set_objective_storage
from .StorageVars import storage_add_sets_and_params, storage_add_variables
from .StorageConstraints import (
    add_storage_energy_balance_constraint,
    add_storage_investment_link_constraint,
    add_storage_power_limits_constraint,
    add_storage_soc_bounds_constraint
)


[docs] def build_storage(data: StorageData, include_objective: bool = True) -> ConcreteModel: """ Build a standalone Pyomo model for the storage subsystem. This function creates a new ConcreteModel instance and populates it with all the sets, parameters, variables, and constraints required to represent an energy storage unit within the optimization framework. Parameters ---------- data : StorageData Structured input data describing storage characteristics and parameters. include_objective : bool, optional If True, includes the subsystem objective function. Default is True. Returns ------- pyomo.environ.ConcreteModel A fully defined storage model ready for integration or standalone analysis. """ m = ConcreteModel() m = add_storage_problem(m=m, data=data, include_objective=include_objective) return m
[docs] def add_storage_problem(m: ConcreteModel, data: StorageData, include_objective: bool = False) -> ConcreteModel: """ Add the complete storage problem definition to a given model. Extends an existing Pyomo model with the full symbolic formulation of the energy storage subsystem, including all relevant constraints and, optionally, the objective function. Parameters ---------- m : pyomo.environ.ConcreteModel Pyomo model to which the storage subsystem will be appended. data : StorageData Structured data object defining all storage parameters and time horizon. include_objective : bool, optional If True, includes the storage cost minimization objective. Default is False. Returns ------- pyomo.environ.ConcreteModel The same model instance extended with storage sets, variables, constraints, and (optionally) the objective function. Notes ----- The following constraints are added to the model: - Power limits (charging/discharging capacity) - Energy balance (state-of-charge dynamics) - Investment linkage (capacity expansion logic) - SoC bounds (minimum and maximum limits) """ # Sets and parameters storage_add_sets_and_params(m, data) # Variables storage_add_variables(m) # Constraints add_storage_power_limits_constraint(m) add_storage_energy_balance_constraint(m) add_storage_investment_link_constraint(m) add_storage_soc_bounds_constraint(m) # Objective (optional) if include_objective: set_objective_storage(m) return m