Model Formulations#

Documentation for model formulation modules.

System Formulations#

sdom.models.formulations_system.objective_rule(model)[source]#

Calculates the total objective value for the optimization model. This function computes the sum of annual fixed costs and variable costs for the system. Fixed costs include VRE (Variable Renewable Energy), storage, and gas combined cycle (Gas CC) fixed costs. Variable costs include Gas CC fuel and variable operation & maintenance (VOM) costs, as well as storage VOM costs. :param model: The optimization model instance containing relevant parameters and variables.

Returns:

The total objective value as the sum of fixed and variable costs.

sdom.models.formulations_system.net_load_rule(model, h)[source]#
sdom.models.formulations_system.add_system_expressions(model)[source]#
sdom.models.formulations_system.create_supply_balance_rule(has_imports, has_exports)[source]#

Creates a supply balance rule function based on whether imports and exports are enabled.

Parameters:
  • has_imports (bool) – Whether imports are included in the model.

  • has_exports (bool) – Whether exports are included in the model.

Returns:

A Pyomo constraint rule function for supply balance.

Return type:

function

sdom.models.formulations_system.genmix_share_rule(model)[source]#

Defines the carbon-free generation target constraint.

This constraint ensures that total thermal (balancing unit) generation plus imports does not exceed (1 - GenMix_Target) of the adjusted demand. The adjusted demand accounts for net storage loading (charging minus discharging).

The constraint is:

thermal_generation + imports <= (1 - tau) * (demand + storage_charging - storage_discharging)

Where tau (GenMix_Target) represents the minimum clean-energy generation share. Imports are treated as non-clean energy in this constraint.

Parameters:

model (pyomo.core.base.PyomoModel.ConcreteModel) – The optimization model containing thermal generation, imports, demand, storage variables, and GenMix_Target parameter.

Returns:

The constraint expression for the generation mix target.

Return type:

pyomo.core.expr.relational_expr.InequalityExpression

Notes

  • If imports are not modeled (Imports formulation is “NotModel”), only thermal generation is constrained.

  • The constraint uses hasattr() to check if imports are available, making it robust to different model configurations.

sdom.models.formulations_system.add_system_constraints(model, data)[source]#

Adds system constraints to the optimization model.

Parameters:
Return type:

None

VRE Formulations#

sdom.models.formulations_vre.add_vre_parameters(model, data: dict)[source]#
sdom.models.formulations_vre.add_vre_variables(model)[source]#

Add variables related to variable renewable energy (VRE) to the model.

Parameters: model: The optimization model to which VRE variables will be added.

Returns: None

sdom.models.formulations_vre.add_vre_expressions(model)[source]#
sdom.models.formulations_vre.add_vre_fixed_costs(model)[source]#

Add cost-related variables for variable renewable energy (VRE) to the model.

Parameters: model: The optimization model to which VRE cost variables will be added.

Returns: Costs sum for solar PV and wind energy, including capital and fixed O&M costs.

sdom.models.formulations_vre.vre_balance_rule(block, h)[source]#
sdom.models.formulations_vre.add_vre_balance_constraints(model)[source]#

Add constraints related to variable renewable energy (VRE) to the model.

Parameters: model: The optimization model to which VRE constraints will be added.

Returns: None

Storage Formulations#

sdom.models.formulations_storage.initialize_storage_sets(block, data: dict)[source]#
sdom.models.formulations_storage.add_storage_parameters(model, data: dict)[source]#
sdom.models.formulations_storage.add_storage_variables(model)[source]#
sdom.models.formulations_storage.storage_power_capex_cost_expr_rule(block, j)[source]#
sdom.models.formulations_storage.storage_energy_capex_cost_expr_rule(block, j)[source]#
sdom.models.formulations_storage.storage_fixed_om_cost_expr_rule(block, j)[source]#
sdom.models.formulations_storage.add_storage_expressions(model)[source]#
sdom.models.formulations_storage.add_storage_fixed_costs(model)[source]#

Add cost-related variables for storage technologies to the model.

Parameters: model: The optimization model to which storage cost variables will be added.

Returns: Costs sum for storage technologies, including capital and fixed O&M costs.

sdom.models.formulations_storage.add_storage_variable_costs(model)[source]#

Add variable costs for storage technologies to the model.

Parameters: model: The optimization model to which storage variable costs will be added.

Returns: Variable costs sum for storage technologies, including variable O&M costs.

sdom.models.formulations_storage.soc_balance_rule(model, h, j)[source]#
sdom.models.formulations_storage.max_cycle_year_rule(model, j)[source]#
sdom.models.formulations_storage.add_storage_constraints(model)[source]#

Add storage-related constraints to the model.

Parameters: model: The optimization model to which storage constraints will be added.

Returns: None

Thermal Formulations#

sdom.models.formulations_thermal.initialize_thermal_sets(block, data)[source]#
sdom.models.formulations_thermal.add_thermal_parameters(model, data: dict)[source]#
sdom.models.formulations_thermal.add_thermal_variables(model)[source]#
sdom.models.formulations_thermal.total_thermal_expr_rule(m)[source]#

Expression to calculate the total generation from thermal units.

Parameters: m: The optimization model instance. h: Time period index. bu: Balancing unit index.

Returns: The sum of generation from the specified thermal unit across all time periods.

sdom.models.formulations_thermal.add_thermal_expressions(model)[source]#
sdom.models.formulations_thermal.add_thermal_constraints(model)[source]#
sdom.models.formulations_thermal.add_thermal_fixed_costs(model)[source]#

Add cost-related variables for thermal units to the model.

Parameters: model: The optimization model to which thermal cost variables will be added.

Returns: Costs sum for each thermal unit, including capital and fixed O&M costs.

sdom.models.formulations_thermal.add_thermal_variable_costs(model)[source]#

Add variable costs (Fuel cost + VOM cost) for thermal units to the model.

Parameters: model: The optimization model to which thermal variable costs will be added.

Returns: Variable costs sum for thermal units, including fuel costs.

Hydropower Formulations#

sdom.models.formulations_hydro.add_large_hydro_parameters(model, data: dict)[source]#
sdom.models.formulations_hydro.add_large_hydro_bound_parameters(model, data: dict)[source]#
sdom.models.formulations_hydro.add_hydro_variables(model)[source]#
sdom.models.formulations_hydro.add_hydro_run_of_river_constraints(model, data: dict)[source]#
sdom.models.formulations_hydro.add_hydro_budget_constraints(model, data: dict)[source]#

Import/Export Formulations#

sdom.models.formulations_imports_exports.add_import_export_ts_parameters(block, hourly_set, data: dict, key_ts: str, key_col: str)[source]#
sdom.models.formulations_imports_exports.add_imports_parameters(model, data: dict)[source]#
sdom.models.formulations_imports_exports.add_exports_parameters(model, data: dict)[source]#
sdom.models.formulations_imports_exports.add_imports_variables(model)[source]#
sdom.models.formulations_imports_exports.add_exports_variables(model)[source]#
sdom.models.formulations_imports_exports.add_imports_exports_cost_expressions(model, data: dict)[source]#
sdom.models.formulations_imports_exports.add_import_export_binary_variable(model, big_m_constant)[source]#
sdom.models.formulations_imports_exports.add_imports_constraints(model, data: dict)[source]#
sdom.models.formulations_imports_exports.add_exports_constraints(model, data: dict)[source]#
sdom.models.formulations_imports_exports.add_imports_exports_cost(model)[source]#

Model Utilities#

Helper functions for building model components.

sdom.models.models_utils.fcr_rule(model, lifetime=30)[source]#

Calculate the Fixed Charge Rate (FCR) for capital cost annualization.

Computes the fixed charge rate used to annualize capital expenditures for VRE technologies (solar PV, wind) and thermal generators. The FCR converts upfront capital costs into equivalent annual payments.

Parameters:
  • model – The Pyomo model instance containing the discount rate parameter (model.r).

  • lifetime (int, optional) – Expected lifetime of the technology in years. Defaults to 30.

Returns:

The calculated fixed charge rate as a fraction.

Return type:

float

Notes

Formula: FCR = [r * (1+r)^lifetime] / [(1+r)^lifetime - 1] where r is the discount rate from model.r.

sdom.models.models_utils.crf_rule(model, j)[source]#

Calculate the Capital Recovery Factor (CRF) for storage technologies.

Computes the capital recovery factor used to annualize capital expenditures for storage technologies. The CRF is technology-specific based on each storage type’s expected lifetime.

Parameters:
  • model – The Pyomo model instance containing discount rate and storage data.

  • j (str) – Storage technology identifier (e.g., ‘Li-Ion’, ‘CAES’, ‘PHS’, ‘H2’).

Returns:

The calculated capital recovery factor for the specified storage technology.

Return type:

float

Notes

Formula: CRF = [r * (1+r)^lifetime] / [(1+r)^lifetime - 1] Lifetime is retrieved from model.data[‘Lifetime’, j] for technology j.

sdom.models.models_utils.get_filtered_ts_parameter_dict(hourly_set, data: dict, key_ts: str, key_col: str)[source]#

Extract and filter time-series parameter data for a specific hourly set.

Retrieves time-series data from a DataFrame and filters it to include only the hours present in the model’s hourly set. Used to initialize Pyomo Param objects with time-indexed data.

Parameters:
  • hourly_set – The Pyomo Set containing hour indices for the model (e.g., model.h).

  • data (dict) – Dictionary containing all input data DataFrames.

  • key_ts (str) – Key to access the time-series DataFrame in the data dict (e.g., ‘load_data’, ‘nuclear_data’).

  • key_col (str) – Column name in the DataFrame to extract values from (e.g., ‘Load’, ‘Nuclear’).

Returns:

Dictionary mapping hour indices to parameter values, filtered to

only include hours in hourly_set.

Return type:

dict

Notes

Expects DataFrame to have a ‘*Hour’ column for indexing.

sdom.models.models_utils.add_alpha_parameter(block, data, key_scalars: str)[source]#

Add a control parameter (alpha) to a Pyomo block to enable/disable a component.

Creates a scalar Pyomo Param named ‘alpha’ on the block if it doesn’t already exist. The alpha parameter acts as an activation flag (typically 0 or 1) for controlling whether a technology or component is included in the model.

Parameters:
  • block – The Pyomo Block where the parameter will be added.

  • data (dict) – Dictionary containing the ‘scalars’ DataFrame with parameter values.

  • key_scalars (str) – Index key to look up the alpha value in the scalars DataFrame. If empty string, no parameter is added.

Returns:

None

Notes

Only adds the parameter if the block doesn’t already have an ‘alpha’ attribute.

sdom.models.models_utils.add_alpha_and_ts_parameters(block, hourly_set, data: dict, key_scalars: str, key_ts: str, key_col: str)[source]#

Add both control parameter (alpha) and time-series parameter to a block.

Convenience function that adds an activation control parameter and a time-indexed parameter to a Pyomo block. Commonly used for fixed generation sources like nuclear, hydro, or other renewables.

Parameters:
  • block – The Pyomo Block where parameters will be added.

  • hourly_set – The Pyomo Set containing hour indices (e.g., model.h).

  • data (dict) – Dictionary containing input DataFrames.

  • key_scalars (str) – Index key for the alpha control parameter in scalars DataFrame.

  • key_ts (str) – Key to access the time-series DataFrame (e.g., ‘nuclear_data’).

  • key_col (str) – Column name in the time-series DataFrame to extract.

Returns:

None

Notes

Creates block.alpha as a scalar Param and block.ts_parameter as time-indexed Param.

sdom.models.models_utils.add_budget_parameter(block, formulation, valid_formulation_to_budget_map: dict)[source]#

Add a budget aggregation parameter to a block based on the selected formulation.

Creates a scalar Pyomo Param indicating the number of hours in each budget period (i.e., the budget period interval in hours, e.g., 730 for monthly, 24 for daily budgets). Used primarily for hydropower budget formulations.

Parameters:
  • block – The Pyomo Block where the parameter will be added.

  • formulation (str) – The selected formulation name (e.g., ‘MonthlyBudgetFormulation’).

  • valid_formulation_to_budget_map (dict) – Mapping from formulation names to

  • hours. (budget period intervals in)

Returns:

None

Notes

Only adds block.budget_scalar if it doesn’t already exist on the block.

sdom.models.models_utils.add_upper_bound_paramenters(block, hourly_set, data, key_ts: str = 'large_hydro_max', key_col: str = 'LargeHydro')[source]#

Add time-series upper bound parameters to a block.

Extracts maximum capacity or generation limits from time-series data and adds them as a time-indexed Pyomo Param to the block. Used for technologies with hourly-varying upper bounds (e.g., hydro max generation).

Parameters:
  • block – The Pyomo Block where the parameter will be added.

  • hourly_set – The Pyomo Set containing hour indices.

  • data (dict) – Dictionary containing input DataFrames.

  • key_ts (str, optional) – Key to access the DataFrame with upper bound data. Defaults to ‘large_hydro_max’.

  • key_col (str, optional) – Column name to extract from the DataFrame. Defaults to ‘LargeHydro’.

Returns:

None

Notes

Creates block.ts_parameter_upper_bound as a time-indexed Param.

sdom.models.models_utils.add_lower_bound_paramenters(block, hourly_set, data: dict, key_ts: str = 'large_hydro_min', key_col: str = 'LargeHydro')[source]#

Add time-series lower bound parameters to a block.

Extracts minimum capacity or generation requirements from time-series data and adds them as a time-indexed Pyomo Param to the block. Used for technologies with hourly-varying lower bounds (e.g., hydro minimum flow requirements).

Parameters:
  • block – The Pyomo Block where the parameter will be added.

  • hourly_set – The Pyomo Set containing hour indices.

  • data (dict) – Dictionary containing input DataFrames.

  • key_ts (str, optional) – Key to access the DataFrame with lower bound data. Defaults to ‘large_hydro_min’.

  • key_col (str, optional) – Column name to extract from the DataFrame. Defaults to ‘LargeHydro’.

Returns:

None

Notes

Creates block.ts_parameter_lower_bound as a time-indexed Param.

sdom.models.models_utils.add_generation_variables(block, *sets, domain=<pyomo.core.base.set.DeclareGlobalSet.<locals>.GlobalSet object>, initialize=0)[source]#

Add a generation variable to a Pyomo block indexed over arbitrary sets.

Creates a Pyomo Var named ‘generation’ on the block, indexed over the provided sets. Supports flexible indexing (e.g., by hour only, or by plant and hour).

Parameters:
  • block – The Pyomo Block to which the variable will be added.

  • *sets – Variable number of Pyomo Sets to use as indices. Can be single set (e.g., hours) or multiple sets (e.g., plants, hours).

  • domain (pyomo.core.base.set, optional) – Domain constraint for the variable. Defaults to NonNegativeReals.

  • initialize (float, optional) – Initial value for all variable indices. Defaults to 0.

Returns:

None

Examples

>>> add_generation_variables(block, model.h)  # Indexed by hours
>>> add_generation_variables(block, model.plants_set, model.h)  # By plant and hour

Notes

Creates block.generation as a Var. Commonly used for hourly generation dispatch.

sdom.models.models_utils.sum_installed_capacity_by_plants_set_expr_rule(block)[source]#

Create a Pyomo expression for total installed capacity across all plants in a block.

Sums the plant_installed_capacity variable over all plants in block.plants_set. This expression is used to aggregate individual plant capacities into a total capacity metric for a technology (e.g., total PV capacity, total wind capacity).

Parameters:

block – The Pyomo Block containing plant_installed_capacity Var and plants_set Set.

Returns:

A Pyomo expression representing the sum of

installed capacities.

Return type:

Pyomo expression

Notes

Expects block.plant_installed_capacity to be indexed by block.plants_set. Used as a rule function for creating Pyomo Expression objects.

sdom.models.models_utils.generic_fixed_om_cost_expr_rule(block)[source]#

Create a Pyomo expression for total fixed O&M costs across all plants.

Calculates the annual fixed operation and maintenance costs for all plants in a technology block. Cost is based on fixed O&M rate ($/kW-yr) times installed capacity (MW).

Parameters:

block – The Pyomo Block containing FOM_M Param, plant_installed_capacity Var, and plants_set Set.

Returns:

Pyomo expression for total annual fixed O&M costs.

Return type:

pyomo.core.expr.numeric_expr

Notes

Formula: sum over plants of (FOM_M[k] * MW_TO_KW * capacity[k]) FOM_M is in $/kW-yr, capacity is in MW, so MW_TO_KW converts units.

sdom.models.models_utils.generic_capex_cost_expr_rule(block)[source]#

Create a Pyomo expression for total CAPEX costs with uniform FCR across plants.

Calculates the annualized capital expenditures for all plants in a technology block when all plants share the same fixed charge rate (FCR). Includes both technology CAPEX and transmission/interconnection costs.

Parameters:

block – The Pyomo Block containing CAPEX_M Param, trans_cap_cost Param, plant_installed_capacity Var, and plants_set Set.

Returns:

Pyomo expression for total annualized CAPEX.

Return type:

Pyomo Expression

Notes

Formula: sum over plants of [(CAPEX_M[k]*MW_TO_KW + trans_cap_cost[k]) * capacity[k]]. CAPEX_M is in $/kW, trans_cap_cost in $, capacity in MW.

sdom.models.models_utils.different_fcr_capex_cost_expr_rule(block)[source]#

Create a Pyomo expression for total annualized CAPEX with plant-specific FCRs.

Calculates the annualized capital expenditures when each plant has its own fixed charge rate based on technology-specific lifetime. The FCR is applied within this expression for each plant individually.

Parameters:

block – The Pyomo Block containing FCR Param, CAPEX_M Param, trans_cap_cost Param, plant_installed_capacity Var, and plants_set Set.

Returns:

Pyomo expression for total annualized CAPEX.

Return type:

pyomo.core.expr.numeric_expr

Notes

Formula: sum over plants of [FCR[k] * (CAPEX_M[k]*MW_TO_KW + trans_cap_cost[k]) * capacity[k]] Used when plants have different lifetimes, requiring plant-specific FCRs.

sdom.models.models_utils.generic_budget_rule(block, hhh)[source]#

Create a budget constraint ensuring generation matches fixed time-series over an interval.

Constraint rule that ensures total generation over a budget period (e.g., month, day) equals the sum of the time-series parameter over that same period. Used for technologies with energy budgets like hydropower with monthly/daily constraints.

Parameters:
  • block – The Pyomo Block containing generation Var, ts_parameter Param, and budget_scalar Param.

  • hhh – Index for the budget period (e.g., 1 for first month, 2 for second month).

Returns:

Constraint expression enforcing budget equality.

Return type:

pyomo.core.expr.relational_expr

Notes

Calculates start/end hours based on: start = (hhh-1)*budget_scalar + 1, end = hhh*budget_scalar. Constraint: sum(generation[h]) == sum(ts_parameter[h]) over budget period.

sdom.models.models_utils.add_generic_fixed_costs(block)[source]#

Calculate total fixed annual costs (CAPEX + FOM) for a technology block.

Aggregates annualized capital expenditures and fixed operation & maintenance costs for a technology. This function is used in objective function formulation to sum up the fixed cost components.

Parameters:

block – The Pyomo Block that must have capex_cost_expr and fixed_om_cost_expr Expression attributes already defined.

Returns:

Sum of CAPEX and FOM expressions representing

total annual fixed costs.

Return type:

pyomo.core.expr.numeric_expr

Notes

Requires block.capex_cost_expr and block.fixed_om_cost_expr to be defined before calling this function. Returns the sum that can be used directly in objective function or cost expressions.

Initialization Functions#

Functions for initializing model sets and parameters.

sdom.initializations.initialize_vre_sets(data, block, vre_type: str)[source]#

Initialize VRE (Variable Renewable Energy) plant sets and filter data for a technology.

Identifies common plants between capacity factor and CAPEX datasets, filters out incomplete records, and creates a Pyomo Set for the VRE plants. Also stores filtered capacity data back into the data dictionary for later use.

Parameters:
  • data (dict) – Dictionary containing all input DataFrames including capacity factors and CAPEX data for VRE technologies.

  • block – The Pyomo Block (e.g., model.pv or model.wind) where the plants_set will be created.

  • vre_type (str) – Type of VRE technology - either ‘solar’ or ‘wind’. Used to construct dictionary keys for accessing the appropriate DataFrames.

Returns:

None

Notes

  • Creates block.plants_set as a Pyomo Set containing plant identifiers

  • Filters plants that have complete data (CAPEX_M, trans_cap_cost, FOM_M, capacity)

  • Updates data dict with ‘filtered_cap_{vre_type}_dict’ and ‘complete_{vre_type}_data’

  • Plant IDs are converted to strings for consistent indexing

sdom.initializations.check_n_hours(n_hours: int, interval: int)[source]#

Validate and adjust the number of simulation hours to match budget interval.

Ensures that the number of hours is a multiple of the budget aggregation interval (e.g., 24 for daily budgets, 730 for monthly budgets). If not, rounds up to the nearest multiple and logs a warning.

Parameters:
  • n_hours (int) – Requested number of simulation hours.

  • interval (int) – Budget aggregation interval in hours (e.g., 24, 730).

Returns:

Validated number of hours that is a multiple of the interval. Returns

n_hours unchanged if already valid, otherwise returns rounded-up value.

Return type:

int

Notes

Logs a warning when adjustment is needed, informing the user of the approximation.

sdom.initializations.create_budget_set(model, block, n_hours_checked: int, budget_hours_aggregation: int)[source]#

Create a Pyomo Set representing budget periods for aggregated constraints.

Generates a set of budget period indices based on the aggregation interval. For example, with 8760 hours and 730-hour intervals (monthly), creates a set {1, 2, 3, …, 12} representing 12 monthly budget periods.

Parameters:
  • model – The Pyomo ConcreteModel instance containing the hourly set (model.h).

  • block – The Pyomo Block (e.g., model.hydro) where budget_set will be created.

  • n_hours_checked (int) – Total number of simulation hours (validated/adjusted).

  • budget_hours_aggregation (int) – Number of hours per budget period (e.g., 24 for daily, 730 for monthly).

Returns:

None

Notes

Creates block.budget_set as a Pyomo Set indexed 1, 2, 3, …, n_periods. The set is declared within=model.h to maintain consistency with hourly indices.

sdom.initializations.initialize_sets(model, data, n_hours=8760)[source]#

Initialize all Pyomo Sets for the SDOM optimization model.

Creates sets for all model components including VRE plants, storage technologies, thermal units, and hourly time steps. Handles different hydro formulations by adjusting the hourly set and creating budget sets when needed.

Parameters:
  • model – The Pyomo ConcreteModel instance to initialize.

  • data (dict) – Dictionary containing all input data including DataFrames for capacity factors, CAPEX data, storage data, and formulation specifications.

  • n_hours (int, optional) – Number of simulation hours. Defaults to 8760 (full year). May be adjusted if using budget formulations requiring specific intervals.

Returns:

None

Notes

  • Initializes model.pv.plants_set and model.wind.plants_set for VRE plants

  • Creates model.storage.j (all storage techs) and model.storage.b (coupled techs)

  • Initializes model.thermal.plants_set for thermal balancing units

  • Creates model.h as the hourly RangeSet (1-based indexing)

  • For budget hydro formulations, adjusts n_hours and creates model.hydro.budget_set

  • Logs information about storage technologies being modeled

sdom.initializations.initialize_params(model, data)[source]#

Initialize all Pyomo Parameters for the SDOM optimization model.

Adds parameters to the model for all components including VRE technologies, storage, thermal units, fixed generation sources (hydro, nuclear, other renewables), demand, imports/exports, and system-level scalars. Parameter initialization is conditional based on the selected formulations.

Parameters:
  • model – The Pyomo ConcreteModel instance to initialize. Must have Sets already initialized via initialize_sets().

  • data (dict) – Dictionary containing all input data including: - scalars DataFrame: discount rate (r), GenMix_Target, alpha values - Time-series DataFrames: load, nuclear, hydro, other renewables - Technology data: VRE CAPEX/FOM, storage characteristics, thermal parameters - Import/export data (if applicable)

Returns:

None

Notes

  • Creates Pyomo parameters model.r (discount rate) and model.GenMix_Target (carbon-free target)

  • Initializes time-series parameters for each hour in model.h

  • For budget hydro formulations, adds upper/lower bound parameters

  • Conditionally adds import/export parameters based on formulation selection

  • model.GenMix_Target is mutable to allow sensitivity analysis across runs

  • All monetary values use MW/kW conversion via MW_TO_KW constant