Source code for gridpath.project.operations.tuning_costs

# Copyright 2016-2025 Blue Marble Analytics LLC.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
Operational tuning costs that prevent erratic dispatch in case of degeneracy.
Tuning costs can be applied to hydro up and down ramps (gen_hydro
and gen_hydro_must_take operational types) and to storage up-ramps (
stor operational type) in order to force smoother dispatch.
"""

import csv
import os.path
from pyomo.environ import Param, Var, Expression, Constraint, NonNegativeReals

from gridpath.auxiliary.auxiliary import get_required_subtype_modules
from gridpath.auxiliary.db_interface import directories_to_db_values
from gridpath.project.operations.common_functions import load_operational_type_modules
from gridpath.project.common_functions import check_if_boundary_type_and_first_timepoint


[docs] def add_model_components( m, d, scenario_directory, weather_iteration, hydro_iteration, availability_iteration, subproblem, stage, ): """ The following Pyomo model components are defined in this module: +-------------------------------------------------------------------------+ | Variables | +=========================================================================+ | | :code:`Ramp_Up_Tuning_Cost` | | | *Defined over*: :code:`PRJ_OPR_TMPS` | | | *Within*: :code:`NonNegativeReals` | | | | This variable represents the total upward ramping tuning cost for each | | project in each operational timepoint. | +-------------------------------------------------------------------------+ | | :code:`Ramp_Up_Tuning_Cost` | | | *Defined over*: :code:`PRJ_OPR_TMPS` | | | *Within*: :code:`NonNegativeReals` | | | | This variable represents the total downwward ramping tuning cost for | | each project in each operational timepoint. | +-------------------------------------------------------------------------+ | +-------------------------------------------------------------------------+ | Expressions | +=========================================================================+ | | :code:`Ramp_Expression` | | | *Defined over*: :code:`PRJ_OPR_TMPS` | | | | This expression pulls the ramping expression from the appropriate | | operational type module. It represents the difference in power output | | (in MW) between 2 timepoints; i.e. a positive number means upward ramp | | and a negative number means downward ramp. For simplicity, we only look | | at the difference in power setpoints, i.e. ignore the effect of | | providing any reserves. | +-------------------------------------------------------------------------+ | +-------------------------------------------------------------------------+ | Constraints | +=========================================================================+ | | :code:`Ramp_Up_Tuning_Cost_Constraint` | | | *Defined over*: :code:`PRJ_OPR_TMPS` | | | | Sets the upward ramping tuning cost to be equal to the ramp expression | | times the tuning cost (for the appropriate operational types only). | +-------------------------------------------------------------------------+ | | :code:`Ramp_Down_Tuning_Cost_Constraint` | | | *Defined over*: :code:`PRJ_OPR_TMPS` | | | | Sets the downward ramping tuning cost to be equal to the ramp | | expression times the tuning cost (for the appropriate operational types | | only). | +-------------------------------------------------------------------------+ """ # Dynamic Inputs ########################################################################### required_operational_modules = get_required_subtype_modules( scenario_directory=scenario_directory, weather_iteration=weather_iteration, hydro_iteration=hydro_iteration, availability_iteration=availability_iteration, subproblem=subproblem, stage=stage, which_type="operational_type", ) imported_operational_modules = load_operational_type_modules( required_operational_modules ) # Expressions ########################################################################### def ramp_rule(mod, g, tmp): gen_op_type = mod.operational_type[g] return imported_operational_modules[gen_op_type].power_delta_rule(mod, g, tmp) m.Ramp_Expression = Expression(m.PRJ_OPR_TMPS, rule=ramp_rule) # Variables ########################################################################### m.Ramp_Up_Tuning_Cost = Var(m.PRJ_OPR_TMPS, within=NonNegativeReals) m.Ramp_Down_Tuning_Cost = Var(m.PRJ_OPR_TMPS, within=NonNegativeReals) # Constraints ########################################################################### m.Ramp_Up_Tuning_Cost_Constraint = Constraint(m.PRJ_OPR_TMPS, rule=ramp_up_rule) m.Ramp_Down_Tuning_Cost_Constraint = Constraint(m.PRJ_OPR_TMPS, rule=ramp_down_rule)
# Constraint Rules ############################################################################### def ramp_up_rule(mod, prj, tmp): """ **Constraint Name**: Ramp_Up_Tuning_Cost_Constraint **Enforced Over**: PRJ_OPR_TMPS """ if check_if_boundary_type_and_first_timepoint( mod=mod, tmp=tmp, balancing_type=mod.balancing_type_project[prj], boundary_type="linear", ): return Constraint.Skip elif mod.ramp_tuning_cost_per_mw[prj] == 0: return Constraint.Skip else: return ( mod.Ramp_Up_Tuning_Cost[prj, tmp] >= mod.Ramp_Expression[prj, tmp] * mod.ramp_tuning_cost_per_mw[prj] ) def ramp_down_rule(mod, prj, tmp): """ **Constraint Name**: Ramp_Down_Tuning_Cost_Constraint **Enforced Over**: PRJ_OPR_TMPS """ if check_if_boundary_type_and_first_timepoint( mod=mod, tmp=tmp, balancing_type=mod.balancing_type_project[prj], boundary_type="linear", ): return Constraint.Skip elif mod.ramp_tuning_cost_per_mw[prj] == 0: return Constraint.Skip else: return ( mod.Ramp_Down_Tuning_Cost[prj, tmp] >= mod.Ramp_Expression[prj, tmp] * -mod.ramp_tuning_cost_per_mw[prj] ) # Validation ############################################################################### def validate_inputs( scenario_id, subscenarios, weather_iteration, hydro_iteration, availability_iteration, subproblem, stage, conn, ): """ Get inputs from database and validate the inputs :param subscenarios: SubScenarios object with all subscenario info :param subproblem: :param stage: :param conn: database connection :return: """ # ramp_tuning_cost = get_inputs_from_database( # scenario_id, subscenarios, subproblem, stage, conn) # do stuff here to validate inputs