def export_results(scenario_directory, subproblem, stage, m, d): """ Export operations results. :param scenario_directory: :param subproblem: :param stage: :param m: The Pyomo abstract model :param d: Dynamic components :return: Nothing """ # Export module-specific results # Operational type modules required_operational_modules = get_required_subtype_modules_from_projects_file( scenario_directory=scenario_directory, subproblem=subproblem, stage=stage, which_type="operational_type") imported_operational_modules = load_operational_type_modules( required_operational_modules) # Add any components specific to the operational modules for op_m in required_operational_modules: if hasattr(imported_operational_modules[op_m], "export_module_specific_results"): imported_operational_modules[op_m].\ export_module_specific_results( m, d, scenario_directory, subproblem, stage, ) else: pass
def validate_inputs(scenario_id, subscenarios, 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: """ # Load in the required operational modules c = conn.cursor() required_opchar_modules = get_required_opchar_modules(scenario_id, c) imported_operational_modules = load_operational_type_modules( required_opchar_modules) # Validate module-specific inputs for op_m in required_opchar_modules: if hasattr(imported_operational_modules[op_m], "validate_module_specific_inputs"): imported_operational_modules[op_m]. \ validate_module_specific_inputs( scenario_id, subscenarios, subproblem, stage, conn) else: pass
def load_model_data(m, d, data_portal, scenario_directory, subproblem, stage): """ :param m: :param d: :param data_portal: :param scenario_directory: :param subproblem: :param stage: :return: """ # Import needed operational modules required_operational_modules = get_required_subtype_modules_from_projects_file( scenario_directory=scenario_directory, subproblem=subproblem, stage=stage, which_type="operational_type") imported_operational_modules = load_operational_type_modules( required_operational_modules) # Add any components specific to the operational modules for op_m in required_operational_modules: if hasattr(imported_operational_modules[op_m], "load_module_specific_data"): imported_operational_modules[op_m].load_module_specific_data( m, data_portal, scenario_directory, subproblem, stage) else: pass
def process_results(db, c, scenario_id, subscenarios, quiet): """ :param db: :param c: :param subscenarios: :param quiet: :return: """ # Load in the required operational modules required_opchar_modules = get_required_opchar_modules(scenario_id, c) imported_operational_modules = load_operational_type_modules( required_opchar_modules) # Process module-specific results for op_m in required_opchar_modules: if hasattr(imported_operational_modules[op_m], "process_module_specific_results"): imported_operational_modules[op_m]. \ process_module_specific_results( db, c, scenario_id, subscenarios, quiet) else: pass
def write_model_inputs(scenario_directory, scenario_id, subscenarios, subproblem, stage, conn): """ Get inputs from database and write out the model input .tab files :param scenario_directory: string, the scenario directory :param subscenarios: SubScenarios object with all subscenario info :param subproblem: :param stage: :param conn: database connection :return: """ # Load in the required operational modules c = conn.cursor() required_opchar_modules = get_required_opchar_modules(scenario_id, c) imported_operational_modules = load_operational_type_modules( required_opchar_modules) # Write module-specific inputs for op_m in required_opchar_modules: if hasattr(imported_operational_modules[op_m], "write_module_specific_model_inputs"): imported_operational_modules[op_m].\ write_module_specific_model_inputs( scenario_directory, scenario_id, subscenarios, subproblem, stage, conn) else: pass
def fix_variables(m, d, scenario_directory, subproblem, stage): """ This function fixes the commitment of all fixed commitment projects by running the :code:`fix_commitment` function in the appropriate operational module. :param m: :param d: :param scenario_directory: :param subproblem: :param stage: :return: """ required_operational_modules = get_required_subtype_modules_from_projects_file( scenario_directory=scenario_directory, subproblem=subproblem, stage=stage, which_type="operational_type", ) imported_operational_modules = load_operational_type_modules( required_operational_modules) for g in m.FXD_COMMIT_PRJS: op_m = m.operational_type[g] imp_op_m = imported_operational_modules[op_m] if hasattr(imp_op_m, "fix_commitment"): for tmp in m.TMPS: imp_op_m.fix_commitment(m, g, tmp)
def add_model_components(m, d, scenario_directory, subproblem, stage): """ The following Pyomo model components are defined in this module: +-------------------------------------------------------------------------+ | Expressions | +=========================================================================+ | | :code:`Power_Provision_MW` | | | *Defined over*: :code:`PRJ_OPR_TMPS` | | | | Defines the power a project is producing in each of its operational | | timepoints. The exact formulation of the expression depends | | on the project's *operational_type*. For each project, we call its | | *capacity_type* module's *power_provision_rule* method in order to | | formulate the expression. E.g. a project of the *gen_must_run* | | operational_type will be producing power equal to its capacity while a | | dispatchable project will have a variable in its power provision | | expression. This expression will then be used by other modules. | +-------------------------------------------------------------------------+ """ # Dynamic Inputs ########################################################################### required_operational_modules = get_required_subtype_modules_from_projects_file( scenario_directory=scenario_directory, subproblem=subproblem, stage=stage, which_type="operational_type", ) imported_operational_modules = load_operational_type_modules( required_operational_modules) # Expressions ########################################################################### def power_provision_rule(mod, prj, tmp): """ **Expression Name**: Power_Provision_MW **Defined Over**: PRJ_OPR_TMPS Power provision is a variable for some generators, but not others; get the appropriate expression for each generator based on its operational type. """ gen_op_type = mod.operational_type[prj] if hasattr(imported_operational_modules[gen_op_type], "power_provision_rule"): return imported_operational_modules[ gen_op_type].power_provision_rule(mod, prj, tmp) else: return op_type_init.power_provision_rule(mod, prj, tmp) m.Power_Provision_MW = Expression(m.PRJ_OPR_TMPS, rule=power_provision_rule)
def add_model_components(m, d, scenario_directory, subproblem, stage): """ :param m: :param d: :return: """ # Import needed operational modules required_operational_modules = get_required_subtype_modules_from_projects_file( scenario_directory=scenario_directory, subproblem=subproblem, stage=stage, which_type="operational_type") imported_operational_modules = load_operational_type_modules( required_operational_modules) # Add any components specific to the operational modules for op_m in required_operational_modules: imp_op_m = imported_operational_modules[op_m] if hasattr(imp_op_m, "add_model_components"): imp_op_m.add_model_components(m, d, scenario_directory, subproblem, stage)
def add_model_components(m, d, scenario_directory, subproblem, stage): """ The following Pyomo model components are defined in this module: +-------------------------------------------------------------------------+ | Sets | +=========================================================================+ | | :code:`FUEL_PRJ_OPR_TMPS` | | | *Within*: :code:`PRJ_OPR_TMPS` | | | | The two-dimensional set of projects for which a fuel is specified and | | their operational timepoints. | +-------------------------------------------------------------------------+ | | :code:`HR_CURVE_PRJS_OPR_TMPS_SGMS` | | | | The three-dimensional set of projects for which a heat rate curve is | | specified along with the heat rate curve segments and the project | | operational timepoints. | +-------------------------------------------------------------------------+ | | :code:`HR_CURVE_PRJS_OPR_TMPS` | | | *Within*: :code:`PRJ_OPR_TMPS` | | | | The two-dimensional set of projects for which a heat rate curve is | | specified along with their operational timepoints. | +-------------------------------------------------------------------------+ | | :code:`STARTUP_FUEL_PRJ_OPR_TMPS` | | | *Within*: :code:`FUEL_PRJ_OPR_TMPS` | | | | The two-dimensional set of projects for which startup fuel burn is | | specified and their operational timepoints. | +-------------------------------------------------------------------------+ | | +-------------------------------------------------------------------------+ | Variables | +=========================================================================+ | | :code:`HR_Curve_Prj_Fuel_Burn` | | | *Defined over*: :code:`HR_CURVE_PRJS_OPR_TMPS` | | | *Within*: :code:`NonNegativeReals` | | | | Fuel burn in each operational timepoint of projects with a heat rate | | curve. | +-------------------------------------------------------------------------+ | | +-------------------------------------------------------------------------+ | Constraints | +=========================================================================+ | | :code:`HR_Curve_Prj_Fuel_Burn_Constraint` | | | *Defined over*: :code:`HR_CURVE_PRJS_OPR_TMPS_SGMS` | | | | Determines fuel burn from the project in each timepoint based on its | | heat rate curve. | +-------------------------------------------------------------------------+ | | +-------------------------------------------------------------------------+ | Expressions | +=========================================================================+ | | :code:`Operations_Fuel_Burn_MMBtu` | | | *Within*: :code:`PRJ_OPR_TMPS` | | | | This expression describes each project's operational fuel consumption | | (in MMBtu) in all operational timepoints. We obtain it by calling the | | *fuel_burn_rule* method in the relevant *operational_type*. This does | | not include fuel burn for startups, which has a separate expression. | +-------------------------------------------------------------------------+ | | :code:`Startup_Fuel_Burn_MMBtu` | | | *Within*: :code:`PRJ_OPR_TMPS` | | | | This expression describes each project's startup fuel consumption | | (in MMBtu) in all operational timepoints. We obtain it by calling the | | *startup_fuel_burn_rule* method in the relevant *operational_type*. | | Only operational types with commitment variables can have startup fuel | | burn (for others it will always return zero). | +-------------------------------------------------------------------------+ | | :code:`Total_Fuel_Burn_MMBtu` | | | *Within*: :code:`PRJ_OPR_TMPS` | | | | Total fuel burn is the sum of operational fuel burn for power | | production and startup fuel burn. | +-------------------------------------------------------------------------+ """ # Dynamic Inputs ########################################################################### required_operational_modules = get_required_subtype_modules_from_projects_file( scenario_directory=scenario_directory, subproblem=subproblem, stage=stage, which_type="operational_type" ) imported_operational_modules = load_operational_type_modules( required_operational_modules ) # Sets ########################################################################### m.FUEL_PRJ_OPR_TMPS = Set( dimen=2, within=m.PRJ_OPR_TMPS, initialize=lambda mod: [(p, tmp) for (p, tmp) in mod.PRJ_OPR_TMPS if p in mod.FUEL_PRJS] ) m.HR_CURVE_PRJS_OPR_TMPS_SGMS = Set( dimen=3, initialize=lambda mod: set((g, tmp, s) for (g, tmp) in mod.PRJ_OPR_TMPS for _g, p, s in mod.HR_CURVE_PRJS_PRDS_SGMS if g == _g and mod.period[tmp] == p) ) m.HR_CURVE_PRJS_OPR_TMPS = Set( dimen=2, within=m.FUEL_PRJ_OPR_TMPS, initialize=lambda mod: set((g, tmp) for (g, tmp, s) in mod.HR_CURVE_PRJS_OPR_TMPS_SGMS) ) m.STARTUP_FUEL_PRJ_OPR_TMPS = Set( dimen=2, within=m.FUEL_PRJ_OPR_TMPS, initialize=lambda mod: [(p, tmp) for (p, tmp) in mod.FUEL_PRJ_OPR_TMPS if p in mod.STARTUP_FUEL_PRJS] ) # Variables ########################################################################### m.HR_Curve_Prj_Fuel_Burn = Var( m.HR_CURVE_PRJS_OPR_TMPS, within=NonNegativeReals ) # Constraints ########################################################################### def fuel_burn_by_ll_constraint_rule(mod, prj, tmp, s): """ **Constraint Name**: HR_Curve_Prj_Fuel_Burn_Constraint **Enforced Over**: HR_CURVE_PRJS_OPR_TMPS_SGMS Fuel burn is set by piecewise linear representation of input/output curve. Note: we assume that when projects are de-rated for availability, the input/output curve is de-rated by the same amount. The implicit assumption is that when a generator is de-rated, some of its units are out rather than it being forced to run below minimum stable level at very inefficient operating points. """ gen_op_type = mod.operational_type[prj] if hasattr(imported_operational_modules[gen_op_type], "fuel_burn_by_ll_rule"): fuel_burn_by_ll = imported_operational_modules[gen_op_type]. \ fuel_burn_by_ll_rule(mod, prj, tmp, s) else: fuel_burn_by_ll = \ op_type.fuel_burn_by_ll_rule(mod, prj, tmp, s) return mod.HR_Curve_Prj_Fuel_Burn[prj, tmp] >= fuel_burn_by_ll m.HR_Curve_Prj_Fuel_Burn_Constraint = Constraint( m.HR_CURVE_PRJS_OPR_TMPS_SGMS, rule=fuel_burn_by_ll_constraint_rule ) # Expressions ########################################################################### def fuel_burn_rule(mod, prj, tmp): """ Emissions from each project based on operational type (and whether a project burns fuel) """ gen_op_type = mod.operational_type[prj] if hasattr(imported_operational_modules[gen_op_type], "fuel_burn_rule"): fuel_burn_simple = imported_operational_modules[gen_op_type]. \ fuel_burn_rule(mod, prj, tmp) else: fuel_burn_simple = op_type.fuel_burn_rule(mod, prj, tmp) return fuel_burn_simple \ + (mod.HR_Curve_Prj_Fuel_Burn[prj, tmp] if prj in mod.HR_CURVE_PRJS else 0) m.Operations_Fuel_Burn_MMBtu = Expression( m.FUEL_PRJ_OPR_TMPS, rule=fuel_burn_rule ) def startup_fuel_burn_rule(mod, prj, tmp): """ Startup fuel burn is defined for some operational types while they are zero for others. Get the appropriate expression for each generator based on its operational type. """ gen_op_type = mod.operational_type[prj] if hasattr(imported_operational_modules[gen_op_type], "startup_fuel_burn_rule"): return imported_operational_modules[gen_op_type]. \ startup_fuel_burn_rule(mod, prj, tmp) else: return op_type.startup_fuel_burn_rule(mod, prj, tmp) m.Startup_Fuel_Burn_MMBtu = Expression( m.STARTUP_FUEL_PRJ_OPR_TMPS, rule=startup_fuel_burn_rule ) def total_fuel_burn_rule(mod, g, tmp): """ *Expression Name*: :code:`Total_Fuel_Burn_MMBtu` *Defined Over*: :code:`PRJ_OPR_TMPS` Total fuel burn is the sum of operational fuel burn (power production) and startup fuel burn. """ return mod.Operations_Fuel_Burn_MMBtu[g, tmp] \ + (mod.Startup_Fuel_Burn_MMBtu[g, tmp] if g in mod.STARTUP_FUEL_PRJS else 0) m.Total_Fuel_Burn_MMBtu = Expression( m.FUEL_PRJ_OPR_TMPS, rule=total_fuel_burn_rule )
def add_model_components(m, d, scenario_directory, subproblem, stage): """ The following Pyomo model components are defined in this module: +-------------------------------------------------------------------------+ | Sets | +=========================================================================+ | | :code:`VAR_OM_COST_SIMPLE_PRJ_OPR_TMPS` | | | *Within*: :code:`PRJ_OPR_TMPS` | | | | The two-dimensional set of projects for which a simple variable O&M | | cost is specified and their operational timepoints. | +-------------------------------------------------------------------------+ | | :code:`VAR_OM_COST_CURVE_PRJS_OPR_TMPS_SGMS` | | | | The three-dimensional set of projects for which a VOM cost curve is | | specified along with the VOM curve segments and the project | | operational timepoints. | +-------------------------------------------------------------------------+ | | :code:`VAR_OM_COST_CURVE_PRJS_OPR_TMPS` | | | *Within*: :code:`PRJ_OPR_TMPS` | | | | The two-dimensional set of projects for which a VOM cost curve is | | specified along with their operational timepoints. | +-------------------------------------------------------------------------+ | | :code:`VAR_OM_COST_ALL_PRJS_OPR_TMPS` | | | *Within*: :code:`PRJ_OPR_TMPS` | | | | The two-dimensional set of projects for which either or both a simple | | VOM or a VOM curve is specified along with their operational | | timepoints. | +-------------------------------------------------------------------------+ | | :code:`STARTUP_COST_PRJ_OPR_TMPS` | | | *Within*: :code:`PRJ_OPR_TMPS` | | | | The two-dimensional set of projects for which a startup cost is | | specified along with their operational timepoints. | +-------------------------------------------------------------------------+ | | :code:`SHUTDOWN_COST_PRJ_OPR_TMPS` | | | *Within*: :code:`PRJ_OPR_TMPS` | | | | The two-dimensional set of projects for which a shutdown cost curve is | | specified along with their operational timepoints. | +-------------------------------------------------------------------------+ | | :code:`VIOL_ALL_PRJ_OPR_TMPS` | | | *Within*: :code:`PRJ_OPR_TMPS` | | | | The two-dimensional set of projects for which an operational constraint | | can be violated along with their operational timepoints. | +-------------------------------------------------------------------------+ | | :code:`CURTAILMENT_COST_PRJ_OPR_TMPS` | | | *Within*: :code:`PRJ_OPR_TMPS` | | | | The two-dimensional set of projects for which an curtailment costs are | | incurred along with their operational timepoints. | +-------------------------------------------------------------------------+ | | +-------------------------------------------------------------------------+ | Variables | +=========================================================================+ | | :code:`Variable_OM_Curve_Cost` | | | *Defined over*: :code:`VAR_OM_COST_CURVE_PRJS_OPR_TMPS` | | | *Within*: :code:`NonNegativeReals` | | | | Variable cost in each operational timepoint of projects with a VOM cost | | curve. | +-------------------------------------------------------------------------+ | | +-------------------------------------------------------------------------+ | Constraints | +=========================================================================+ | | :code:`Variable_OM_Curve_Constraint` | | | *Defined over*: :code:`VAR_OM_COST_CURVE_PRJS_OPR_TMPS_SGMS` | | | | Determines variable cost from the project in each timepoint based on | | its VOM curve. | +-------------------------------------------------------------------------+ | | +-------------------------------------------------------------------------+ | Expressions | +=========================================================================+ | | :code:`Variable_OM_Cost` | | | *Defined over*: :code:`VAR_OM_COST_ALL_PRJS_OPR_TMPS` | | | | This is the variable cost incurred in each operational timepoints for | | projects for which either a simple VOM or a VOM curve is specified. | | If both are specified, the two are additive. We obtain the simple VOM | | by calling the *variable_om_cost_rule* method of a project's | | *operational_type* module. We obtain the VOM curve cost by calling the | | *variable_om_cost_by_ll_rule* method of a project's operational type, | | using that to create the *Variable_OM_Curve_Constraint* on the | | Variable_OM_Curve_Cost variable, and the using the variable in this | | expression. | +-------------------------------------------------------------------------+ | | :code:`Fuel_Cost` | | | *Defined over*: :code:`FUEL_PRJ_OPR_TMPS` | | | | This expression defines the fuel cost of a project in all of its | | operational timepoints. We obtain the expression by calling the | | *fuel_cost_rule* method of a project's *operational_type* module. | +-------------------------------------------------------------------------+ | | :code:`Startup_Cost` | | | *Defined over*: :code:`STARTUP_COST_PRJ_OPR_TMPS` | | | | This expression defines the startup cost of a project in all of its | | operational timepoints. We obtain the expression by calling the | | *startup_cost_rule* method of a project's *operational_type* module. | +-------------------------------------------------------------------------+ | | :code:`Shutdown_Cost` | | | *Defined over*: :code:`SHUTDOWN_COST_PRJ_OPR_TMPS` | | | | This expression defines the shutdown cost of a project in all of its | | operational timepoints. We obtain the expression by calling the | | *shutdown_cost_rule* method of a project's *operational_type* module. | +-------------------------------------------------------------------------+ | | :code:`Operational_Violation_Cost` | | | *Defined over*: :code:`VIOL_ALL_PRJ_OPR_TMPS` | | | | This expression defines the operational constraint violation cost of a | | project in all of its operational timepoints. We obtain the expression | | by calling the *operational_violation_cost_rule* method of a project's | | *operational_type* module. | +-------------------------------------------------------------------------+ | | :code:`Curtailment_Cost` | | | *Defined over*: :code:`CURTAILMENT_COST_PRJ_OPR_TMPS` | | | | This expression defines the curtailment cost of a project in all of its | | operational timepoints. We obtain the expression by calling the | | *curtailment_cost_rule* method of a project's *operational_type* module.| +-------------------------------------------------------------------------+ """ # Dynamic Inputs ########################################################################### required_operational_modules = get_required_subtype_modules_from_projects_file( scenario_directory=scenario_directory, subproblem=subproblem, stage=stage, which_type="operational_type") imported_operational_modules = load_operational_type_modules( required_operational_modules) # Sets ########################################################################### m.VAR_OM_COST_SIMPLE_PRJ_OPR_TMPS = Set( dimen=2, within=m.PRJ_OPR_TMPS, initialize=lambda mod: [(p, tmp) for (p, tmp) in mod.PRJ_OPR_TMPS if p in mod.VAR_OM_COST_SIMPLE_PRJS]) m.VAR_OM_COST_CURVE_PRJS_OPR_TMPS_SGMS = Set( dimen=3, initialize=lambda mod: list( set((g, tmp, s) for (g, tmp) in mod.PRJ_OPR_TMPS for _g, p, s in mod.VAR_OM_COST_CURVE_PRJS_PRDS_SGMS if g == _g and mod.period[tmp] == p))) m.VAR_OM_COST_CURVE_PRJS_OPR_TMPS = Set( dimen=2, within=m.PRJ_OPR_TMPS, initialize=lambda mod: list( set((g, tmp) for (g, tmp, s) in mod.VAR_OM_COST_CURVE_PRJS_OPR_TMPS_SGMS))) # All VOM projects m.VAR_OM_COST_ALL_PRJS_OPR_TMPS = Set( within=m.PRJ_OPR_TMPS, initialize=lambda mod: list( set(mod.VAR_OM_COST_SIMPLE_PRJ_OPR_TMPS | mod.VAR_OM_COST_CURVE_PRJS_OPR_TMPS))) m.STARTUP_COST_PRJ_OPR_TMPS = Set( dimen=2, within=m.PRJ_OPR_TMPS, initialize=lambda mod: [(p, tmp) for (p, tmp) in mod.PRJ_OPR_TMPS if p in mod.STARTUP_COST_PRJS]) m.SHUTDOWN_COST_PRJ_OPR_TMPS = Set( dimen=2, within=m.PRJ_OPR_TMPS, initialize=lambda mod: [(p, tmp) for (p, tmp) in mod.PRJ_OPR_TMPS if p in mod.SHUTDOWN_COST_PRJS]) m.VIOL_ALL_PRJ_OPR_TMPS = Set( dimen=2, within=m.PRJ_OPR_TMPS, initialize=lambda mod: [(p, tmp) for (p, tmp) in mod.PRJ_OPR_TMPS if p in mod.VIOL_ALL_PRJS]) m.CURTAILMENT_COST_PRJ_OPR_TMPS = Set( dimen=2, within=m.PRJ_OPR_TMPS, initialize=lambda mod: [(p, tmp) for (p, tmp) in mod.PRJ_OPR_TMPS if p in mod.CURTAILMENT_COST_PRJS]) # Variables ########################################################################### m.Variable_OM_Curve_Cost = Var(m.VAR_OM_COST_CURVE_PRJS_OPR_TMPS, within=NonNegativeReals) # Constraints ########################################################################### def variable_om_cost_curve_constraint_rule(mod, prj, tmp, s): """ **Constraint Name**: GenCommitBin_Variable_OM_Constraint **Enforced Over**: GEN_COMMIT_BIN_VOM_PRJS_OPR_TMPS_SGMS Variable O&M cost by loading level is set by piecewise linear representation of the input/output curve (variable O&M cost vs.loading level). Note: we assume that when projects are derated for availability, the input/output curve is derated by the same amount. The implicit assumption is that when a generator is de-rated, some of its units are out rather than it being forced to run below minimum stable level at very costly operating points. """ gen_op_type = mod.operational_type[prj] if hasattr(imported_operational_modules[gen_op_type], "variable_om_cost_by_ll_rule"): var_cost_by_ll = imported_operational_modules[gen_op_type]. \ variable_om_cost_by_ll_rule(mod, prj, tmp, s) else: var_cost_by_ll = \ op_type.variable_om_cost_by_ll_rule(mod, prj, tmp, s) return mod.Variable_OM_Curve_Cost[prj, tmp] \ >= var_cost_by_ll m.Variable_OM_Curve_Constraint = Constraint( m.VAR_OM_COST_CURVE_PRJS_OPR_TMPS_SGMS, rule=variable_om_cost_curve_constraint_rule) # Expressions ########################################################################### def variable_om_cost_rule(mod, prj, tmp): """ **Expression Name**: Variable_OM_Cost **Defined Over**: VAR_OM_COST_ALL_PRJS_OPR_TMPS This is the variable cost incurred in each operational timepoints for projects for which either a simple VOM or a VOM curve is specified. If both are specified, the two are additive. """ # Simple VOM cost gen_op_type = mod.operational_type[prj] if prj in mod.VAR_OM_COST_SIMPLE_PRJS: if hasattr(imported_operational_modules[gen_op_type], "variable_om_cost_rule"): var_cost_simple = imported_operational_modules[gen_op_type]. \ variable_om_cost_rule(mod, prj, tmp) else: var_cost_simple = op_type.variable_om_cost_rule(mod, prj, tmp) else: var_cost_simple = 0 # VOM curve cost if prj in mod.VAR_OM_COST_CURVE_PRJS: var_cost_curve = mod.Variable_OM_Curve_Cost[prj, tmp] else: var_cost_curve = 0 # The two are additive return var_cost_simple + var_cost_curve m.Variable_OM_Cost = Expression(m.VAR_OM_COST_ALL_PRJS_OPR_TMPS, rule=variable_om_cost_rule) def fuel_cost_rule(mod, prj, tmp): """ **Expression Name**: Fuel_Cost **Defined Over**: FUEL_PRJS_OPR_TMPS """ return mod.Total_Fuel_Burn_MMBtu[prj, tmp] * \ mod.fuel_price_per_mmbtu[ mod.fuel[prj], mod.period[tmp], mod.month[tmp] ] m.Fuel_Cost = Expression(m.FUEL_PRJ_OPR_TMPS, rule=fuel_cost_rule) def startup_cost_rule(mod, prj, tmp): """ Startup costs are defined for some operational types while they are zero for others. Get the appropriate expression for each generator based on its operational type. """ gen_op_type = mod.operational_type[prj] if prj in mod.STARTUP_COST_SIMPLE_PRJS: if hasattr(imported_operational_modules[gen_op_type], "startup_cost_simple_rule"): startup_cost_simple = \ imported_operational_modules[gen_op_type]. \ startup_cost_simple_rule(mod, prj, tmp) else: startup_cost_simple = \ op_type.startup_cost_simple_rule(mod, prj, tmp) else: startup_cost_simple = 0 if prj in mod.STARTUP_BY_ST_PRJS: if hasattr(imported_operational_modules[gen_op_type], "startup_cost_by_st_rule"): startup_cost_by_st = \ imported_operational_modules[gen_op_type]. \ startup_cost_by_st_rule(mod, prj, tmp) else: startup_cost_by_st = \ op_type.startup_cost_by_st_rule(mod, prj, tmp) else: startup_cost_by_st = 0 return startup_cost_simple + startup_cost_by_st m.Startup_Cost = Expression(m.STARTUP_COST_PRJ_OPR_TMPS, rule=startup_cost_rule) def shutdown_cost_rule(mod, prj, tmp): """ Shutdown costs are defined for some operational types while they are zero for others. Get the appropriate expression for each generator based on its operational type. """ gen_op_type = mod.operational_type[prj] if hasattr(imported_operational_modules[gen_op_type], "shutdown_cost_rule"): return imported_operational_modules[gen_op_type]. \ shutdown_cost_rule(mod, prj, tmp) else: return op_type.shutdown_cost_rule(mod, prj, tmp) m.Shutdown_Cost = Expression(m.SHUTDOWN_COST_PRJ_OPR_TMPS, rule=shutdown_cost_rule) def operational_violation_cost_rule(mod, prj, tmp): """ Get any operational constraint violation costs. """ gen_op_type = mod.operational_type[prj] if hasattr(imported_operational_modules[gen_op_type], "operational_violation_cost_rule"): return imported_operational_modules[gen_op_type]. \ operational_violation_cost_rule(mod, prj, tmp) else: return op_type.operational_violation_cost_rule(mod, prj, tmp) m.Operational_Violation_Cost = Expression( m.VIOL_ALL_PRJ_OPR_TMPS, rule=operational_violation_cost_rule) def curtailment_cost_rule(mod, prj, tmp): """ Curtailment costs are defined for some operational types while they are zero for others. Get the appropriate expression for each generator based on its operational type. """ gen_op_type = mod.operational_type[prj] if hasattr(imported_operational_modules[gen_op_type], "curtailment_cost_rule"): return imported_operational_modules[gen_op_type]. \ curtailment_cost_rule(mod, prj, tmp) else: return op_type.curtailment_cost_rule(mod, prj, tmp) m.Curtailment_Cost = Expression(m.CURTAILMENT_COST_PRJ_OPR_TMPS, rule=curtailment_cost_rule)
def add_model_components(m, d, scenario_directory, subproblem, stage): """ The following Pyomo model components are defined in this module: +-------------------------------------------------------------------------+ | Input Params | +=========================================================================+ | | :code:`ramp_tuning_cost_per_mw` | | | *Default*: :code:`0` | | | | The tuning cost for ramping in $ per MW of ramp. The cost is the same | | for upward and downward ramping. | +-------------------------------------------------------------------------+ | +-------------------------------------------------------------------------+ | 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_from_projects_file( scenario_directory=scenario_directory, subproblem=subproblem, stage=stage, which_type="operational_type", ) imported_operational_modules = load_operational_type_modules( required_operational_modules) # Input Params ########################################################################### m.ramp_tuning_cost_per_mw = Param(default=0) # 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)
def import_results_into_database(scenario_id, subproblem, stage, c, db, results_directory, quiet): """ :param scenario_id: :param c: :param db: :param results_directory: :param quiet: :return: """ if not quiet: print("project dispatch all") # dispatch_all.csv # Delete prior results and create temporary import table for ordering setup_results_import(conn=db, cursor=c, table="results_project_dispatch", scenario_id=scenario_id, subproblem=subproblem, stage=stage) # Load results into the temporary table results = [] with open(os.path.join(results_directory, "dispatch_all.csv"), "r") as \ dispatch_file: reader = csv.reader(dispatch_file) next(reader) # skip header for row in reader: project = row[0] period = row[1] horizon = row[2] timepoint = row[3] operational_type = row[4] balancing_type = row[5] timepoint_weight = row[6] number_of_hours_in_timepoint = row[7] load_zone = row[8] technology = row[9] power_mw = row[10] results.append( (scenario_id, project, period, subproblem, stage, timepoint, operational_type, balancing_type, horizon, timepoint_weight, number_of_hours_in_timepoint, load_zone, technology, power_mw)) insert_temp_sql = """ INSERT INTO temp_results_project_dispatch{} (scenario_id, project, period, subproblem_id, stage_id, timepoint, operational_type, balancing_type, horizon, timepoint_weight, number_of_hours_in_timepoint, load_zone, technology, power_mw) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); """.format(scenario_id) spin_on_database_lock(conn=db, cursor=c, sql=insert_temp_sql, data=results) # Insert sorted results into permanent results table insert_sql = """ INSERT INTO results_project_dispatch (scenario_id, project, period, subproblem_id, stage_id, timepoint, operational_type, balancing_type, horizon, timepoint_weight, number_of_hours_in_timepoint, load_zone, technology, power_mw) SELECT scenario_id, project, period, subproblem_id, stage_id, timepoint, operational_type, balancing_type, horizon, timepoint_weight, number_of_hours_in_timepoint, load_zone, technology, power_mw FROM temp_results_project_dispatch{} ORDER BY scenario_id, project, subproblem_id, stage_id, timepoint; """.format(scenario_id) spin_on_database_lock(conn=db, cursor=c, sql=insert_sql, data=(), many=False) # Load in the required operational modules required_opchar_modules = get_required_opchar_modules(scenario_id, c) imported_operational_modules = \ load_operational_type_modules(required_opchar_modules) # Import module-specific results for op_m in required_opchar_modules: if hasattr(imported_operational_modules[op_m], "import_module_specific_results_to_database"): imported_operational_modules[op_m]. \ import_module_specific_results_to_database( scenario_id, subproblem, stage, c, db, results_directory, quiet ) else: pass
def add_model_components(m, d, scenario_directory, subproblem, stage): """ The following Pyomo model components are defined in this module: +-------------------------------------------------------------------------+ | Sets | +=========================================================================+ | | :code:`RPS_PRJS` | | | *Within*: :code:`PROJECTS` | | | | The set of all RPS-eligible projects. | +-------------------------------------------------------------------------+ | | :code:`RPS_PRJ_OPR_TMPS` | | | | Two-dimensional set that defines all project-timepoint combinations | | when an RPS-elgible project can be operational. | +-------------------------------------------------------------------------+ | | :code:`RPS_PRJS_BY_RPS_ZONE` | | | *Defined over*: :code:`RPS_ZONES` | | | *Within*: :code:`RPS_PRJS` | | | | Indexed set that describes the RPS projects for each RPS zone. | +-------------------------------------------------------------------------+ | +-------------------------------------------------------------------------+ | Input Params | +=========================================================================+ | | :code:`rps_zone` | | | *Defined over*: :code:`RPS_PRJS` | | | *Within*: :code:`RPS_ZONES` | | | | This param describes the RPS zone for each RPS project. | +-------------------------------------------------------------------------+ | +-------------------------------------------------------------------------+ | Expressions | +=========================================================================+ | | :code:`Scheduled_RPS_Energy_MW` | | | *Defined over*: :code:`RPS_PRJ_OPR_TMPS` | | | | Describes how many RECs (in MW) are scheduled for each RPS-eligible | | project in each timepoint. | +-------------------------------------------------------------------------+ | | :code:`Scheduled_Curtailment_MW` | | | *Defined over*: :code:`RPS_PRJ_OPR_TMPS` | | | | Describes the amount of scheduled curtailment (in MW) for each | | RPS-eligible project in each timepoint. | +-------------------------------------------------------------------------+ | | :code:`Subhourly_RPS_Energy_MW` | | | *Defined over*: :code:`RPS_PRJ_OPR_TMPS` | | | | Describes how many RECs (in MW) are delivered subhourly for each | | RPS-eligible project in each timepoint. Subhourly RPS energy delivery | | can occur due to sub-hourly upward reserve dispatch (e.g. reg-up). | +-------------------------------------------------------------------------+ | | :code:`Subhourly_Curtailment_MW` | | | *Defined over*: :code:`RPS_PRJ_OPR_TMPS` | | | | Describes the amount of subhourly curtailment (in MW) for each | | RPS-eligible project in each timepoint. Subhourly curtailment can | | occur due to sub-hourly downward reserve dispatch (e.g. reg-down). | +-------------------------------------------------------------------------+ """ # Dynamic Inputs ########################################################################### required_operational_modules = get_required_subtype_modules_from_projects_file( scenario_directory=scenario_directory, subproblem=subproblem, stage=stage, which_type="operational_type") imported_operational_modules = load_operational_type_modules( required_operational_modules) # Sets ########################################################################### m.RPS_PRJS = Set(within=m.PROJECTS) m.RPS_PRJ_OPR_TMPS = Set( within=m.PRJ_OPR_TMPS, initialize=lambda mod: [(p, tmp) for (p, tmp) in mod.PRJ_OPR_TMPS if p in mod.RPS_PRJS]) # Input Params ########################################################################### m.rps_zone = Param(m.RPS_PRJS, within=m.RPS_ZONES) # Derived Sets (requires input params) ########################################################################### m.RPS_PRJS_BY_RPS_ZONE = Set( m.RPS_ZONES, within=m.RPS_PRJS, initialize=determine_rps_generators_by_rps_zone) # Expressions ########################################################################### def scheduled_recs_rule(mod, prj, tmp): """ This how many RECs are scheduled to be delivered at the timepoint (hourly) schedule. """ gen_op_type = mod.operational_type[prj] if hasattr(imported_operational_modules[gen_op_type], "rec_provision_rule"): return imported_operational_modules[gen_op_type]. \ rec_provision_rule(mod, prj, tmp) else: return op_type.rec_provision_rule(mod, prj, tmp) m.Scheduled_RPS_Energy_MW = Expression(m.RPS_PRJ_OPR_TMPS, rule=scheduled_recs_rule) def scheduled_curtailment_rule(mod, prj, tmp): """ Keep track of curtailment to make it easier to calculate total curtailed RPS energy for example -- this is the scheduled curtailment component. """ gen_op_type = mod.operational_type[prj] if hasattr(imported_operational_modules[gen_op_type], "scheduled_curtailment_rule"): return imported_operational_modules[gen_op_type]. \ scheduled_curtailment_rule(mod, prj, tmp) else: return op_type.scheduled_curtailment_rule(mod, prj, tmp) m.Scheduled_Curtailment_MW = Expression(m.RPS_PRJ_OPR_TMPS, rule=scheduled_curtailment_rule) def subhourly_recs_delivered_rule(mod, prj, tmp): """ This how many RECs are scheduled to be delivered through sub-hourly dispatch (upward reserve dispatch). """ gen_op_type = mod.operational_type[prj] if hasattr(imported_operational_modules[gen_op_type], "subhourly_energy_delivered_rule"): return imported_operational_modules[gen_op_type]. \ subhourly_energy_delivered_rule(mod, prj, tmp) else: return op_type.subhourly_energy_delivered_rule(mod, prj, tmp) m.Subhourly_RPS_Energy_MW = Expression(m.RPS_PRJ_OPR_TMPS, rule=subhourly_recs_delivered_rule) def subhourly_curtailment_rule(mod, prj, tmp): """ Keep track of curtailment to make it easier to calculate total curtailed RPS energy for example -- this is the subhourly curtailment component (downward reserve dispatch). """ gen_op_type = mod.operational_type[prj] if hasattr(imported_operational_modules[gen_op_type], "subhourly_curtailment_rule"): return imported_operational_modules[gen_op_type]. \ subhourly_curtailment_rule(mod, prj, tmp) else: return op_type.subhourly_curtailment_rule(mod, prj, tmp) m.Subhourly_Curtailment_MW = Expression(m.RPS_PRJ_OPR_TMPS, rule=subhourly_curtailment_rule)
def generic_add_model_components( m, d, scenario_directory, subproblem, stage, reserve_projects_set, reserve_project_operational_timepoints_set, reserve_provision_variable_name, reserve_provision_ramp_rate_limit_param, reserve_provision_ramp_rate_limit_constraint, ): """ Reserve-related components that will be used by the operational_type modules :param m: :param d: :param reserve_projects_set: :param reserve_project_operational_timepoints_set: :param reserve_provision_variable_name: :param reserve_provision_ramp_rate_limit_param: :param reserve_provision_ramp_rate_limit_constraint: :return: """ # Ramp rate reserve limit (response time reserve limit) # Some reserve products may require that generators respond within a # certain amount of time, e.g. 1 minute, 10 minutes, etc. # The maximum amount of reserves that a generator can provide is # therefore limited by its ramp rate, e.g. if it can ramp up 60 MW an hour, # then it will only be able to provide 10 MW of upward reserve for a # reserve product with a 10-minute response requirement \ # Here, this derate param is specified as a fraction of generator capacity # Defaults to 1 if not specified setattr( m, reserve_provision_ramp_rate_limit_param, Param(getattr(m, reserve_projects_set), within=PercentFraction, default=1), ) # Import needed operational modules required_operational_modules = get_required_subtype_modules_from_projects_file( scenario_directory=scenario_directory, subproblem=subproblem, stage=stage, which_type="operational_type", ) imported_operational_modules = load_operational_type_modules( required_operational_modules) def reserve_provision_ramp_rate_limit_rule(mod, g, tmp): """ Don't create constraint if the project can ramp its full capacity in the timepoint :param mod: :param p: :param tmp: :return: """ gen_op_type = mod.operational_type[g] online_capacity = ( imported_operational_modules[gen_op_type].online_capacity_rule( mod, g, tmp) if hasattr( imported_operational_modules[gen_op_type], "online_capacity_rule") else op_type.online_capacity_rule( mod, g, tmp)) if getattr(m, reserve_provision_ramp_rate_limit_param) == 1: return Constraint.Skip else: return (getattr(mod, reserve_provision_variable_name)[g, tmp] <= getattr(mod, reserve_provision_ramp_rate_limit_param)[g] * online_capacity) setattr( m, reserve_provision_ramp_rate_limit_constraint, Constraint( getattr(m, reserve_project_operational_timepoints_set), rule=reserve_provision_ramp_rate_limit_rule, ), )
def add_model_components(m, d, scenario_directory, subproblem, stage): """ The following Pyomo model components are defined in this module: +-------------------------------------------------------------------------+ | Sets | +=========================================================================+ | | :code:`FNL_COMMIT_PRJS` | | | | The set of generators for which the current stage or any of the | | previous stages is the final commitment stage. | +-------------------------------------------------------------------------+ | | :code:`FXD_COMMIT_PRJS` | | | | The set of generators that have already had their commitment fixed in a | | prior commitment stage. | +-------------------------------------------------------------------------+ | | :code:`FNL_COMMIT_PRJS_OPR_TMPS` | | | | Two-dimensional set of all final commitment projects and their | | operational timepoints. | +-------------------------------------------------------------------------+ | | :code:`FXD_COMMIT_PRJS_OPR_TMPS` | | | | Two-dimensional set of all fixed commitment projects and their | | operational timepoints. | +-------------------------------------------------------------------------+ | +-------------------------------------------------------------------------+ | Input Params | +=========================================================================+ | | :code:`fixed_commitment` | | | *Defined over*: :code:`FXD_COMMIT_PRJ_OPR_TMPS` | | | | This param describes the fixed commitment from the prior commitment | | stage for each fixed commitment project and their operational | | timepoints. | +-------------------------------------------------------------------------+ | +-------------------------------------------------------------------------+ | Expressions | +=========================================================================+ | | :code:`Commitment` | | | *Defined over*: :code:`FNL_COMMIT_PRJ_OPR_TMPS` | | | | Describes the commitment for all final commitment projects and their | | operational timepoints. For the :code:`gen_commit_cap` operational | | type, it describes the committed capacity in MW whereas for the | | :code:`gen_commit_lin` and :code:`gen_commit_bin` operational types it | | describes the binary commitment variable. This expression will be | | exported so that the next stage's optimization can read it in through | | the :code:`fixed_commitment` param and fix the commitment to this value.| +-------------------------------------------------------------------------+ """ # Dynamic Inputs required_operational_modules = get_required_subtype_modules_from_projects_file( scenario_directory=scenario_directory, subproblem=subproblem, stage=stage, which_type="operational_type", ) imported_operational_modules = load_operational_type_modules( required_operational_modules) # Sets ########################################################################### m.FNL_COMMIT_PRJS = Set() m.FXD_COMMIT_PRJS = Set() m.FNL_COMMIT_PRJ_OPR_TMPS = Set( dimen=2, initialize=lambda mod: set((g, tmp) for (g, tmp) in mod.PRJ_OPR_TMPS if g in mod.FNL_COMMIT_PRJS), ) m.FXD_COMMIT_PRJ_OPR_TMPS = Set( dimen=2, initialize=lambda mod: set((g, tmp) for (g, tmp) in mod.PRJ_OPR_TMPS if g in mod.FXD_COMMIT_PRJS), ) # Input Params ########################################################################### m.fixed_commitment = Param(m.FXD_COMMIT_PRJ_OPR_TMPS, within=NonNegativeReals) # Expressions ########################################################################### def commitment_rule(mod, g, tmp): """ **Expression Name**: Commitment **Defined Over**: FNL_COMMIT_PRJ_OPR_TMPS """ gen_op_type = mod.operational_type[g] return imported_operational_modules[gen_op_type].commitment_rule( mod, g, tmp) m.Commitment = Expression(m.FNL_COMMIT_PRJ_OPR_TMPS, rule=commitment_rule)