Skip to content

Commit

Permalink
Add possibility to add a solver as solver option. Add reactive capaci…
Browse files Browse the repository at this point in the history
…ty limit to units.
  • Loading branch information
Mastomaki committed Sep 15, 2023
1 parent 43b7688 commit 53d2866
Show file tree
Hide file tree
Showing 9 changed files with 104 additions and 8 deletions.
1 change: 1 addition & 0 deletions src/SpineOpt.jl
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ include("objective/mp_objective_penalties.jl")
include("constraints/constraint_common.jl")
include("constraints/constraint_total_cumulated_unit_flow_bounds.jl")
include("constraints/constraint_unit_flow_capacity.jl")
include("constraints/constraint_unit_flow_capacity_reactive.jl")
include("constraints/constraint_operating_point_bounds.jl")
include("constraints/constraint_operating_point_rank.jl")
include("constraints/constraint_unit_flow_op_bounds.jl")
Expand Down
6 changes: 3 additions & 3 deletions src/constraints/constraint_nodal_reactive_balance.jl
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ function add_constraint_nodal_reactive_balance!(m::Model)
(node=n, stochastic_scenario=s, t=t1) => @constraint(
m,

# Commodity flows from connections
# Reactive power flows from connections (can be negative)
+ expr_sum(
connection_flow_reactive[conn, n1, d, s, t]
for (conn, n1, d, s, t) in connection_flow_indices(
Expand All @@ -44,7 +44,7 @@ function add_constraint_nodal_reactive_balance!(m::Model)
);
init=0,
)
# Commodity flows to connections
# Reactive power to connections (can be negative)
- expr_sum(
connection_flow_reactive[conn, n1, d, s, t]
for (conn, n1, d, s, t) in connection_flow_indices(
Expand All @@ -67,7 +67,7 @@ function add_constraint_nodal_reactive_balance!(m::Model)
);
init=0,
)
# Flows to units
# Flows to units (i.e. reactive power absorption)
- expr_sum(
unit_flow_reactive[u, n, d, s, t_short]
for (u, n, d, s, t_short) in unit_flow_reactive_indices(
Expand Down
63 changes: 63 additions & 0 deletions src/constraints/constraint_unit_flow_capacity_reactive.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#############################################################################
# Copyright (C) 2017 - 2023 Spine Project
#
# This file is part of SpineOpt.
#
# SpineOpt is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# SpineOpt is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#############################################################################

"""
add_constraint_unit_flow_capacity_reactive!(m::Model)
Limit the maximum in/out `unit_flow_reactive` of a `unit` for all `unit_capacity_reactive` indices.
"""
function add_constraint_unit_flow_capacity_reactive!(m::Model)
@fetch unit_flow_reactive, units_on = m.ext[:spineopt].variables
t0 = _analysis_time(m)
m.ext[:spineopt].constraints[:unit_flow_capacity_reactive] = Dict(
(unit=u, node=ng, direction=d, stochastic_path=s, t=t) => @constraint(
m,
expr_sum(
unit_flow_reactive[u, n, d, s, t] * duration(t)
for (u, n, d, s, t) in unit_flow_reactive_indices(
m; unit=u, node=ng, direction=d, stochastic_scenario=s, t=t_in_t(m; t_long=t)
)
if !is_non_spinning(node=n);
init=0,
)
<=
+ expr_sum(
units_on[u, s, t1]
* min(duration(t1), duration(t))
* unit_availability_factor[(unit=u, stochastic_scenario=s, analysis_time=t0, t=t)]
* unit_capacity_reactive[(unit=u, node=ng, direction=d, stochastic_scenario=s, analysis_time=t0, t=t)]
* unit_conv_cap_to_flow[(unit=u, node=ng, direction=d, stochastic_scenario=s, analysis_time=t0, t=t)]
for (u, s, t1) in units_on_indices(m; unit=u, stochastic_scenario=s, t=t_overlaps_t(m; t=t));
init=0,
)
)
for (u, ng, d, s, t) in constraint_unit_flow_capacity_reactive_indices(m)
)
end

function constraint_unit_flow_capacity_reactive_indices(m::Model)
unique(
(unit=u, node=ng, direction=d, stochastic_path=path, t=t)
for (u, ng, d) in indices(unit_capacity_reactive)
for (t, path) in t_lowest_resolution_path(
m, vcat(unit_flow_reactive_indices(m; unit=u, node=ng, direction=d), units_on_indices(m; unit=u))
)
)
end
24 changes: 22 additions & 2 deletions src/run_spineopt.jl
Original file line number Diff line number Diff line change
Expand Up @@ -347,9 +347,17 @@ function _db_lp_solver(instance)
end
end

"""
function _db_solver(f::Function, db_solver_name::Symbol, db_solver_options)
Creates the solver constructor for `db_solver_name`. `db_solver_options` is
assumed to be a Map with a key equal to db_solver_name, which points
to another Map, containing the actual options.
"""
function _db_solver(f::Function, db_solver_name::Symbol, db_solver_options)
db_solver_mod_name = Symbol(first(splitext(string(db_solver_name))))
db_solver_options_parsed = _parse_solver_options(db_solver_name, db_solver_options)

db_solver_mod = try
@eval Base.Main using $db_solver_mod_name
getproperty(Base.Main, db_solver_mod_name)
Expand All @@ -375,8 +383,9 @@ _parse_solver_options(db_solver_name, db_solver_options) = []
_parse_solver_option(value::Bool) = value
_parse_solver_option(value::Number) = isinteger(value) ? convert(Int64, value) : value

#_parse_solver_option(value) = string(value)
_parse_solver_option(value) = string(value)

#=
function _parse_solver_option(value)
#check if the option value contains "solver:"
if occursin(r"^solver:", string(value))
Expand All @@ -386,9 +395,20 @@ function _parse_solver_option(value)
else
return string(value)
end

end
=#

"""
function _parse_solver_option(value::Map)
When solver option is of the Map type, assume that the option means another solver.
Whose fields are "solver" and "options", where "options" points to another Map.
"""
function _parse_solver_option(value::Map)

return _db_solver(x->x, Symbol(value[:solver]),
Map([Symbol(value[:solver])], [value[:options]]) )
end

_do_create_model(mip_solver, use_direct_model) = use_direct_model ? direct_model(mip_solver) : Model(mip_solver)

Expand Down
1 change: 1 addition & 0 deletions src/run_spineopt_standard.jl
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ function _add_constraints!(m; add_constraints=m -> nothing, log_level=3)
add_constraint_connection_flow_real!,
add_constraint_connection_intact_flow_capacity!,
add_constraint_unit_flow_capacity!,
add_constraint_unit_flow_capacity_reactive!,
add_constraint_connections_invested_available!,
add_constraint_connection_lifetime!,
add_constraint_connections_invested_transition!,
Expand Down
1 change: 1 addition & 0 deletions src/variables/variable_node_voltages.jl
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ end
A list of `NamedTuple`s corresponding to indices of the `node_voltage_squared` variable.
Any filtering options can be specified for `node`, `s`, and `t`.
"""
function node_voltage_squared_indices(
m::Model;
Expand Down
10 changes: 8 additions & 2 deletions src/variables/variable_unit_flow.jl
Original file line number Diff line number Diff line change
Expand Up @@ -108,12 +108,18 @@ function add_variable_unit_flow!(m::Model)
)
end

"""
add_variable_unit_flow!(m::Model)
Add `unit_flow_reactive` variables to model `m`. The reactive power flow from unit to node
(injection of reactive power) or from node to unit (absorption of reactive power).
"""
function add_variable_unit_flow_reactive!(m::Model)
t0 = _analysis_time(m)
add_variable!(
m,
:unit_flow_reactive,
unit_flow_reactive_indices

unit_flow_reactive_indices;
lb=Constant(0)
)
end
1 change: 1 addition & 0 deletions templates/spineopt_template.json
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,7 @@
["unit__from_node", "unit_capacity", null, null, "Maximum `unit_flow` capacity of a single 'sub_unit' of the `unit`."],
["unit__from_node", "unit_conv_cap_to_flow", 1.0, null, "Optional coefficient for `unit_capacity` unit conversions in the case the `unit_capacity` value is incompatible with the desired `unit_flow` units."],
["unit__from_node", "vom_cost", null, null, "Variable operating costs of a `unit_flow` variable. E.g. EUR/MWh."],
["unit__from_node", "vom_cost_reactive", null, null, "Variable operating costs of a `unit_flow_reactive` variable (reactive power absorption). E.g. EUR/MVArh."],
["unit__from_node", "unit_flow_non_anticipativity_time", null, null, "Period of time where the value of the `unit_flow` variable has to be fixed to the result from the previous window."],
["unit__from_node", "unit_flow_non_anticipativity_margin", null, null, "Margin by which `unit_flow` variable can differ from the value in the previous window during `non_anticipativity_time`."],
["unit__from_node", "is_active", true, "boolean_value_list", "If false, the object is excluded from the model if the tool filter object activity control is specified"],
Expand Down
5 changes: 4 additions & 1 deletion test/constraints/constraint_node.jl
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,10 @@ end
function test_constraint_nodal_balance_reactive()
@testset "constraint_nodal_balance_reactive" begin

solver_options = unparse_db_value(Map(["Juniper.jl"], [Map(["nl_solver"], ["solver:SCS.jl"])]))
nl_solver_options = Map(["solver", "options"], ["SCS.jl", Map(["verbose"],[0])] )

#solver_options = unparse_db_value(Map(["Juniper.jl"], [Map(["nl_solver"], ["solver:SCS.jl"])]))
solver_options = unparse_db_value(Map(["Juniper.jl"], [Map(["nl_solver"], [nl_solver_options])]))

url_in = _test_constraint_node_setup()
object_parameter_values = [
Expand Down

0 comments on commit 53d2866

Please sign in to comment.