From ade7c55c0bb79502adb4025f8d2419751ecbd905 Mon Sep 17 00:00:00 2001 From: Art Barnes Date: Wed, 4 Dec 2024 20:40:02 -0700 Subject: [PATCH] add multiple scenario problem --- src/core/objective.jl | 3 +- src/prob/gmd_blocker_placement.jl | 145 +++++++++++++++++------------- 2 files changed, 85 insertions(+), 63 deletions(-) diff --git a/src/core/objective.jl b/src/core/objective.jl index 6538281..5e70c6b 100644 --- a/src/core/objective.jl +++ b/src/core/objective.jl @@ -7,9 +7,10 @@ "OBJECTIVE: minimize cost of installing GIC blocker" function objective_blocker_placement_cost(pm::_PM.AbstractPowerModel) + # don't need to sum across all scenarios - objective will be somewhat confusing return JuMP.@objective(pm.model, Min, sum( - sum( blocker["multiplier"]*blocker["construction_cost"]*_PM.var(pm, n, :z_blocker, i) for (i,blocker) in nw_ref[:gmd_ne_blocker] ) + sum( get(blocker, "multiplier", 1.0) * get(blocker, "construction_cost", 1.0) *_PM.var(pm, n, :z_blocker, i) for (i,blocker) in nw_ref[:gmd_ne_blocker] ) for (n, nw_ref) in _PM.nws(pm)) ) diff --git a/src/prob/gmd_blocker_placement.jl b/src/prob/gmd_blocker_placement.jl index ae68321..32a3d62 100644 --- a/src/prob/gmd_blocker_placement.jl +++ b/src/prob/gmd_blocker_placement.jl @@ -113,71 +113,89 @@ function build_blocker_placement(pm::_PM.AbstractPowerModel; kwargs...) end -"FUNCTION: build the multi-time-series coupled quasi-dc-pf and ac-ots with ac-mls problem -as a generator dispatch minimization problem" -function build_blocker_placement_ts(pm::_PM.AbstractPowerModel; kwargs...) -# Reference: -# built minimum loadshedding problem specification corresponds to the "Model C4" of -# Mowen et al., "Optimal Transmission Line Switching under Geomagnetic Disturbances", 2018. +"FUNCTION: build the multi-scenario or time-series blocker placement problem. +This requires that PowerModelsGMD.get_connected_components() be run to generate the +connected components prior to running PowerModels.replicate()" +function solve_blocker_placement_ts(file, model_type::Type, optimizer; kwargs...) + return _PM.solve_model( + file, + model_type, + optimizer, + build_blocker_placement_ts; + ref_extensions = [ + _PMG.ref_add_gmd! + _PMG.ref_add_ne_blocker! + ], + solution_processors = [ + _PMG.solution_gmd!, + _PMG.solution_gmd_qloss!, + ], + kwargs..., + ) +end +"FUNCTION: build the multi-scenario or time-series blocker placement problem" +function build_blocker_placement_multi_scenario(pm::_PM.AbstractPowerModel; kwargs...) + # Reference: + # built minimum loadshedding problem specification corresponds to the "Model C4" of + # Mowen et al., "Optimal Transmission Line Switching under Geomagnetic Disturbances", 2018. + network_ids = sort(collect(_PM.nw_ids(pm))) + n_1 = network_ids[1] + + _PMG.variable_ne_blocker_indicator(pm, nw=n_1) + + for n_2 in network_ids[2:end] + _PM.var(pm, n_2)[:z_blocker] = _PM.var(pm, n_1)[:z_blocker] + _PM.var(pm, n_2)[:zv_dc] = _PM.var(pm, n_1)[:zv_dc] + end + for (n, network) in _PM.nws(pm) - _PMR.variable_bus_voltage_on_off(pm, nw=n) - _PM.variable_gen_indicator(pm, nw=n) + _PMG.variable_bus_voltage(pm, nw=n) _PM.variable_gen_power(pm, nw=n) - _PM.variable_branch_indicator(pm, nw=n) _PM.variable_branch_power(pm, nw=n) _PM.variable_dcline_power(pm, nw=n) - _PM.variable_load_power_factor(pm, relax=true) - _PM.variable_shunt_admittance_factor(pm, relax=true) - - variable_dc_voltage_on_off(pm, nw=n) - variable_dc_line_flow(pm, nw=n, bounded=false) - variable_dc_current_mag(pm, nw=n) - variable_qloss(pm, nw=n) - - variable_delta_oil_ss(pm, nw=n, bounded=true) - variable_delta_oil(pm, nw=n, bounded=true) - variable_delta_hotspot_ss(pm, nw=n, bounded=true) - variable_delta_hotspot(pm, nw=n, bounded=true) - variable_hotspot(pm, nw=n, bounded=true) - - _PM.constraint_model_voltage_on_off(pm, nw=n) + # For MLD + _PM.variable_load_power_factor(pm, relax=true, nw=n) + _PM.variable_shunt_admittance_factor(pm, relax=true, nw=n) + + _PMG.variable_dc_voltage(pm, nw=n) + _PMG.variable_gic_current(pm, nw=n) + _PMG.variable_dc_line_flow(pm, nw=n) + _PMG.variable_qloss(pm, nw=n) + + if get(pm.setting, "ts", false) + _PMG.variable_delta_oil_ss(pm, nw=n, bounded=true) + _PMG.variable_delta_oil(pm, nw=n, bounded=true) + _PMG.variable_delta_hotspot_ss(pm, nw=n, bounded=true) + _PMG.variable_delta_hotspot(pm, nw=n, bounded=true) + _PMG.variable_hotspot(pm, nw=n, bounded=true) + end + + # What's dis? + _PMG.constraint_model_voltage(pm, nw=n) for i in _PM.ids(pm, :ref_buses, nw=n) _PM.constraint_theta_ref(pm, i, nw=n) end for i in _PM.ids(pm, :bus, nw=n) - constraint_power_balance_gmd_shunt_ls(pm, i, nw=n) - end - - for i in _PM.ids(pm, :bus, nw=n) - _PM.constraint_gen_power_on_off(pm, i, nw=n) - constraint_gen_ots_on_off(pm, i, nw=n) - constraint_gen_perspective(pm, i, nw=n) + _PMG.constraint_power_balance_gmd_shunt_ls(pm, i, nw=n) end for i in _PM.ids(pm, :branch, nw=n) + _PM.constraint_ohms_yt_from(pm, i, nw=n) + _PM.constraint_ohms_yt_to(pm, i, nw=n) - _PM.constraint_ohms_yt_from_on_off(pm, i, nw=n) - _PM.constraint_ohms_yt_to_on_off(pm, i, nw=n) + _PM.constraint_voltage_angle_difference(pm, i, nw=n) - _PM.constraint_voltage_angle_difference_on_off(pm, i, nw=n) - - _PM.constraint_thermal_limit_from_on_off(pm, i, nw=n) - _PM.constraint_thermal_limit_to_on_off(pm, i, nw=n) - - constraint_qloss_vnom(pm, i, nw=n) - constraint_dc_current_mag(pm, i, nw=n) - constraint_dc_current_mag_on_off(pm, i, nw=n) - - constraint_temperature_state_ss(pm, i, nw=n) - constraint_hotspot_temperature_state_ss(pm, i, nw=n) - constraint_hotspot_temperature_state(pm, i, nw=n) - constraint_absolute_hotspot_temperature_state(pm, i, nw=n) + _PM.constraint_thermal_limit_from(pm, i, nw=n) + _PM.constraint_thermal_limit_to(pm, i, nw=n) + # consider using constraint_qloss_vnom + _PMG.constraint_qloss_pu(pm, i, nw=n) + _PMG.constraint_dc_current_mag(pm, i, nw=n) end for i in _PM.ids(pm, :dcline, nw=n) @@ -185,28 +203,31 @@ function build_blocker_placement_ts(pm::_PM.AbstractPowerModel; kwargs...) end for i in _PM.ids(pm, :gmd_bus, nw=n) - constraint_dc_kcl(pm, i, nw=n) + _PMG.constraint_dc_kcl_ne_blocker(pm, i, nw=n) end for i in _PM.ids(pm, :gmd_branch, nw=n) - constraint_dc_ohms_on_off(pm, i, nw=n) + _PMG.constraint_dc_ohms(pm, i, nw=n) end - end + # If not using blocker status this can be a single constraint + # across all scenarios + for i in _PM.ids(pm, :gmd_connections, nw=n) + _PMG.constraint_gmd_connections(pm, i, nw=n) + end - network_ids = sort(collect(nw_ids(pm))) - n_1 = network_ids[1] - for i in _PM.ids(pm, :branch, nw=n_1) - constraint_temperature_state(pm, i, nw=n_1) + _PMG.constraint_load_served(pm, nw=n) end - for n_2 in network_ids[2:end] - for i in _PM.ids(pm, :branch, nw=n_2) - constraint_temperature_state(pm, i, n_1, n_2) + + if get(pm.setting, "ts", false) + for n_2 in network_ids[2:end] + for i in _PM.ids(pm, :branch, nw=n_2) + _PMG.constraint_temperature_state(pm, i, n_1, n_2) + end + + n_1 = n_2 end - n_1 = n_2 end - - _PM.objective_min_fuel_and_flow_cost(pm) -end - - + + _PMG.objective_blocker_placement_cost(pm) +end \ No newline at end of file