Library
Documentation for SpineOpt.jl.
Contents
Index
SpineOpt.connection_flow_capacitySpineOpt.connection_flow_lower_limitSpineOpt.node_state_capacitySpineOpt.node_state_lower_limitSpineOpt.unit_flow_capacitySpineOpt.SpineOptExtSpineInterface.indicesSpineOpt.active_stochastic_pathsSpineOpt.add_event_handler!SpineOpt.add_expression_capacity_margin!SpineOpt.build_model!SpineOpt.connection_flow_indicesSpineOpt.create_modelSpineOpt.current_windowSpineOpt.forced_outage_time_seriesSpineOpt.generate_direction_and_reorganise_classesSpineOpt.generate_economic_structure!SpineOpt.generate_forced_outagesSpineOpt.generate_stochastic_structure!SpineOpt.generate_temporal_structure!SpineOpt.master_modelSpineOpt.node_state_indicesSpineOpt.prepare_spineoptSpineOpt.rewind_temporal_structure!SpineOpt.roll_temporal_structure!SpineOpt.run_spineoptSpineOpt.run_spineopt!SpineOpt.solve_model!SpineOpt.stage_modelSpineOpt.t_before_tSpineOpt.t_in_tSpineOpt.t_in_t_exclSpineOpt.t_overlaps_tSpineOpt.time_sliceSpineOpt.to_time_sliceSpineOpt.unit_flow_indicesSpineOpt.unit_flow_op_indicesSpineOpt.units_invested_available_indicesSpineOpt.units_on_indicesSpineOpt.upgrade_dbSpineOpt.write_model_fileSpineOpt.write_reportSpineOpt.write_report_from_intermediate_resultsSpineOpt.@fetchSpineOpt.@logSpineOpt.@timelog
Public interface
SpineOpt.@fetch — Macro
@fetch x, y, ... = dAssign mapping of :x and :y in d to x and y respectively
SpineOpt.@log — Macro
@log(level, threshold, msg)SpineOpt.@timelog — Macro
@timelog(level, threshold, msg, expr)SpineOpt.active_stochastic_paths — Function
active_stochastic_paths(
m; stochastic_structure::Union{Object,Vector{Object}}, t::Union{TimeSlice,Vector{TimeSlice}}
)An Array of stochastic paths, where each path is itself an Array of stochastic_scenario Objects.
The paths are obtained as follows.
- Start with the stochastic DAG associated to model
m. - Remove all the scenarios that are not in the given
stochastic_structure. - Remove scenarios that don't overlap the given
t. - Return all the paths from root to leaf in the remaining sub-DAG.
SpineOpt.add_event_handler! — Function
add_event_handler!(fn, m, event)Add an event handler for given model. event must be a Symbol corresponding to an event. fn must be a function callable with the arguments corresponding to that event. Below is a table of events, arguments, and when do they fire.
| event | arguments | when does it fire |
|---|---|---|
:model_built | m | Right after model m is built. |
:model_about_to_solve | m | Right before model m is solved. |
:model_solved | m | Right after model m is solved. |
:window_about_to_solve | (m, k) | Right before window k for model m is solved. |
:window_solved | (m, k) | Right after window k for model m is solved. |
:window_failed | (m, k) | Right after window k for model m fails to solve. |
Example
run_spineopt("sqlite:///path-to-input-db", "sqlite:///path-to-output-db") do m
add_event_handler!(println, m, :model_built) # Print the model right after it's built
endSpineOpt.build_model! — Function
build_model!(m; log_level)Build given SpineOpt model:
- create temporal and stochastic structures
- add variables
- add expressions
- add constraints
- set objective
- initialize outputs
Arguments
log_level::Int: an integer to control the log level.
SpineOpt.connection_flow_capacity — Constant
connection_flow_capacity(
f; connection=connection, node=node, direction=direction, _default=nothing, kwargs...
)ParameterFunction calculating the capacity of a connection_flow variable.
Returns the product of:
each evaluated for f with the given kwargs. Returns nothing if the product yields nothing.
SpineOpt.connection_flow_indices — Function
connection_flow_indices(
connection=anything,
node=anything,
direction=anything,
t=anything
)A list of NamedTuples corresponding to indices of the connection_flow variable. The keyword arguments act as filters for each dimension.
SpineOpt.connection_flow_lower_limit — Constant
connection_flow_lower_limit(
f; connection=connection, node=node, direction=direction, _default=0, kwargs...
)ParameterFunction calculating the lower limit of a connection_flow variable.
Returns the product of:
each evaluated for f with the given kwargs. Returns nothing if the product yields nothing.
SpineOpt.create_model — Function
create_model(mip_solver, lp_solver, use_direct_model, use_model_names, add_bridges)A JuMP.Model extended to be used with SpineOpt. mip_solver and lp_solver are 'optimizer factories' to be passed to JuMP.Model or JuMP.direct_model; use_direct_model is a Bool indicating whether JuMP.Model or JuMP.direct_model should be used. use_model_names is a Bool indicating whether the names in the model should be used. add_bridges is a Bool indicating whether bridges from JuMP to the solver should be added to the model.
SpineOpt.current_window — Function
current_window(m)A TimeSlice corresponding to the current window of given model.
SpineOpt.forced_outage_time_series — Function
forced_outage_time_series(t_start, t_end, mttf, mttr, nb_of_units; seed=nothing, resolution=Hour)Generates a forced outage time series as a part of generate_forced_outages.
SpineOpt.generate_economic_structure! — Function
generate_economic_structure!(m)SpineOpt.generate_forced_outages — Function
generate_forced_outages(url_in, url_out; <keyword arguments>)Generate forced outages from the contents of url_in and write them to url_out. At least url_in must point to a valid Spine database. A new Spine database is created at url_out if one doesn't exist.
To generate forced outages for a unit, specify mean_time_to_failure and optionally mean_time_to_repair for that unit as a duration in the input DB.
Parameter out_of_service_count_fix will be written for those units in the output DB holding a time series.
Arguments
alternative::String="": if non empty, write results to the given alternative in the output DB.filters::Dict{String,String}=Dict("tool" => "object_activity_control"): a dictionary to specify filters. Possible keys are "tool" and "scenario". Values should be a tool or scenario name in the input DB.
Example
using SpineOpt
m = generate_forced_outages(
raw"sqlite:///C:\path\to\your\input_db.sqlite",
raw"sqlite:///C:\path\to\your\output_db.sqlite"
)SpineOpt.generate_stochastic_structure! — Function
generate_stochastic_structure(m::Model)Generate the stochastic structure for given SpineOpt model.
The stochastic structure is a directed acyclic graph (DAG) where the vertices are the stochastic_scenario objects, and the edges are given by the parent_stochastic_scenario__child_stochastic_scenario relationships.
After this, you can call active_stochastic_paths to slice the generated structure.
SpineOpt.generate_temporal_structure! — Function
generate_temporal_structure!(m)Create the temporal structure for the given SpineOpt model. After this, you can call the following functions to query the generated structure:
time_slicet_before_tt_in_tt_in_t_exclt_overlaps_tto_time_slicecurrent_window
SpineOpt.master_model — Function
master_model(m)The Benders master model for given model.
SpineOpt.node_state_capacity — Constant
node_state_capacity(f; node=node, _default=nothing, kwargs...)ParameterFunction calculating the capacity of a node_state variable.
Returns the product of:
both evaluated for f with the given kwargs. Returns nothing if the product yields nothing.
SpineOpt.node_state_indices — Function
node_state_indices(filtering_options...)A set of tuples for indexing the node_state variable where filtering options can be specified for node, s, and t.
SpineOpt.node_state_lower_limit — Constant
node_state_lower_limit(f; node=node, _default=0, kwargs...)ParameterFunction calculating the lower limit of a node_state variable.
Returns the product of:
- storage_state_max
- storage_state_min_fraction
- OR storage_state_min if it is higher than the above product.
each evaluated for f with the given kwargs. Returns nothing if the product yields nothing.
SpineOpt.prepare_spineopt — Function
prepare_spineopt(url_in; <keyword arguments>)A SpineOpt model from the contents of url_in - ready to be passed to run_spineopt!. The argument url_in must be either a String pointing to a valid Spine database, or a Dict (e.g. manually created or parsed from a json file).
Arguments
log_levelupgradefilterstemplatesmip_solverlp_solveruse_direct_modeluse_model_namesadd_bridges
See run_spineopt for the description of the keyword arguments.
SpineOpt.rewind_temporal_structure! — Function
rewind_temporal_structure!(m)Rewind the temporal structure of given SpineOpt model back to the first window.
SpineOpt.roll_temporal_structure! — Function
roll_temporal_structure!(m[, window_number=1]; rev=false)Roll the temporal structure of given SpineOpt model forward a period of time equal to the value of the roll_forward parameter. If roll_forward is an array, then window_number can be given either as an Integer or a UnitRange indicating the position or successive positions in that array.
If rev is true, then the structure is rolled backwards instead of forward.
SpineOpt.run_spineopt — Function
run_spineopt(url_in, url_out; <keyword arguments>)Run SpineOpt using the contents of url_in and write report(s) to url_out. The argument url_in must be either a String pointing to a valid Spine database, or a Dict (e.g. manually created or parsed from a json file). A new Spine database is created at url_out if one doesn't exist.
Arguments
log_level::Int=3: an integer to control the log level.upgrade::Bool=false: whether or not to automatically upgrade the data structure inurl_into latest.filters::Dict{String,String}=Dict("tool" => "object_activity_control"): a dictionary to specify filters. Possible keys are "tool" and "scenario". Values should be a tool or scenario name in the input DB.templates: a collection of templates to load on top of the SpineOpt template. Each template must be aDictwith the same structure as the one returned bySpineOpt.template().mip_solver=nothing: a MIP solver to use if no MIP solver specified in the DB.lp_solver=nothing: a LP solver to use if no LP solver specified in the DB.use_direct_model::Bool=false: whether or not to useJuMP.direct_modelto build theModelobject.use_model_names::Bool=true: whether or not to use the names in the model.add_bridges::Bool=truewhether or not bridges from JuMP to the solver should be added to the model.optimize::Bool=true: whether or not to optimise the model (useful for running tests).update_names::Bool=false: whether or not to update variable and constraint names after the model rolls (expensive).alternative::String="": if non empty, write results to the given alternative in the output DB.write_as_roll::Int=0: if greater than 0 and the run has a rolling horizon, then write results every that many windows.log_file_path::String=nothing: if not nothing, log all console output to a file at the given path. The file is overwritten at each call.resume_file_path::String=nothing: only relevant in rolling horizon optimisations withwrite_as_rollgreater or equal than one. If the file at given path contains resume data from a previous run, start the run from that point. Also, save resume data to that same file as the model rolls and results are written to the output database.
Example
using SpineOpt
m = run_spineopt(
raw"sqlite:///C:\path\to\your\input_db.sqlite",
raw"sqlite:///C:\path\to\your\output_db.sqlite";
filters=Dict("tool" => "object_activity_control", "scenario" => "scenario_to_run"),
alternative="alternative_to_write_results"
)run_spineopt(f, url_in, url_out; <keyword arguments>)Same as run_spineopt(url_in, url_out; kwargs...) but call function f with the SpineOpt model as argument right after its creation (but before building and solving it).
This is intended to be called using do block syntax.
run_spineopt(url_in, url_out) do m
# Do something with m after its creation
end # Building and solving begins after quiting this blockSpineOpt.run_spineopt! — Function
run_spineopt!(m, url_out; <keyword arguments>)Build SpineOpt on the given m and solve it; write report(s) to url_out. A new Spine database is created at url_out if one doesn't exist.
Arguments
log_leveloptimizeupdate_namesalternativewrite_as_rolllog_file_pathresume_file_path
See run_spineopt for the description of the keyword arguments.
SpineOpt.solve_model! — Function
solve_model!(m; <keyword arguments>)Solve given SpineOpt model and save outputs.
Arguments
log_level::Int=3: an integer to control the log level.update_names::Bool=false: whether or not to update variable and constraint names after the model rolls (expensive).write_as_roll::Int=0: if greater than 0 and the run has a rolling horizon, then write results every that many windows.resume_file_path::String=nothing: only relevant in rolling horizon optimisations withwrite_as_rollgreater or equal than one. If the file at given path contains resume data from a previous run, start the run from that point. Also, save resume data to that same file as the model rolls and results are written to the output database.calculate_duals::Bool=false: whether or not to calculate duals after the model solve.output_suffix::NamedTuple=(;): to add to the outputs.log_prefix::String="": to prepend to log messages.
SpineOpt.SpineOptExt — Type
SpineOptExtThe struct storing SpineOpt data inside <JuMP.Model>.ext[:spineopt].
You can inspect the fields via the following promt:
julia> fieldnames(SpineOptExt)SpineOpt.stage_model — Function
stage_model(m, stage_name)A stage model associated to given model.
SpineOpt.t_before_t — Function
t_before_t(m; t_before=anything, t_after=anything)An Array where each element is a Tuple of two consecutive TimeSlices in model m, i.e., the second starting when the first ends.
Arguments
t_before: if given, return anArrayofTimeSlices that start whent_beforeends.t_after: if given, return anArrayofTimeSlices that end whent_afterstarts.
SpineOpt.t_in_t — Function
t_in_t(m; t_short=anything, t_long=anything)An Array where each element is a Tuple of two TimeSlices in model m, the second containing the first.
Keyword arguments
t_short: if given, return anArrayofTimeSlices that containt_short.t_long: if given, return anArrayofTimeSlices that are contained int_long.
SpineOpt.t_in_t_excl — Function
t_in_t_excl(m; t_short=anything, t_long=anything)Same as t_in_t but exclude tuples of the same TimeSlice.
Keyword arguments
t_short: if given, return anArrayofTimeSlices that containt_short(other thant_shortitself).t_long: if given, return anArrayofTimeSlices that are contained int_long(other thant_longitself).
SpineOpt.t_overlaps_t — Function
t_overlaps_t(m; t)An Array of TimeSlices in model m that overlap the given t, where t must be in m.
SpineOpt.time_slice — Function
time_slice(m; temporal_block=anything, t=anything)An Array of TimeSlices in model m.
Arguments
temporal_block::Union{Object,Vector{Object}}: only returnTimeSlices in these blocks.t::Union{TimeSlice,Vector{TimeSlice}}: only returnTimeSlices that are also in this collection.
SpineOpt.to_time_slice — Function
to_time_slice(m; t)An Array of TimeSlices in model m overlapping the given TimeSlice (where t may not be in m).
SpineOpt.unit_flow_capacity — Constant
unit_flow_capacity(f; unit=unit, node=node, direction=direction, _default=nothing, kwargs...)ParameterFunction calculating the capacity of a unit_flow variable.
Returns the product of:
each evaluated for f with the given kwargs. Returns nothing if the product yields nothing.
SpineOpt.unit_flow_indices — Function
unit_flow_indices(
unit=anything,
node=anything,
direction=anything,
s=anything
t=anything
)A list of NamedTuples corresponding to indices of the unit_flow variable where the keyword arguments act as filters for each dimension.
SpineOpt.unit_flow_op_indices — Function
unit_flow_op_indices(
unit=anything,
node=anything,
direction=anything,
operating_point=anything,
s=anything
t=anything
)A list of NamedTuples corresponding to indices of the unit_flow variable. The keyword arguments act as filters for each dimension.
SpineOpt.units_invested_available_indices — Function
units_invested_available_indices(unit=anything, t=anything)A list of NamedTuples corresponding to indices of the units_invested_available variable where the keyword arguments act as filters for each dimension.
SpineOpt.units_on_indices — Function
units_on_indices(unit=anything, stochastic_scenario=anything, t=anything)A list of NamedTuples corresponding to indices of the units_on variable where the keyword arguments act as filters for each dimension.
SpineOpt.upgrade_db — Function
upgrade_db(url_in; log_level=3, version=nothing, force::Bool=false)Upgrade the data structure in url_in to latest.
The version (Int) keyword forces the migration to start at a specific number if given, while force=true suppresses some errors and warnings in migration to try and force output.
SpineOpt.write_model_file — Function
write_model_file(m; file_name="model")Write model file for given model.
SpineOpt.write_report — Function
write_report(m, url_out; <keyword arguments>)Write report(s) from given SpineOpt model to url_out. A new Spine database is created at url_out if one doesn't exist.
Arguments
alternative::String="": if non empty, write results to the given alternative in the output DB.log_level::Int=3: an integer to control the log level.
SpineOpt.write_report_from_intermediate_results — Function
write_report_from_intermediate_results(intermediate_results_folder, default_url; <keyword arguments>)Collect results generated on a previous, unsuccessful SpineOpt run from intermediate_results_folder, and write the corresponding report(s) to url_out. A new Spine database is created at url_out if one doesn't exist.
Arguments
alternative::String="": if non empty, write results to the given alternative in the output DB.log_level::Int=3: an integer to control the log level.
Internals
SpineOpt.add_expression_capacity_margin! — Function
add_expression_capacity_margin!(m::Model)Create an expression for capacity_margin. This represents the available production capacity (considering variations in variable renewables) after demand has been fulfilled and after the contribution of actual storage operation has been taken into account. It is used in the minimum capacity margin constraint
\[\begin{aligned} expr^{capacity\_margin}_{n,s,t} = \\ & + \sum_{u\in{U_{n\_to}}}(p^{capacity\_per\_unit}_{u,s,t} \cdot p^{availability\_factor}_{u,s,t} \cdot v^{units\_available}_{u,s,t}) \\ & + \sum_{u\in{U_{storage_n}}}(v^{unit\_flow}_{u,n,to,s,t}) \\ & - \sum_{u\in{U_{storage_n}}}(v^{unit\_flow}_{u,n,from,s,t}) \\ & - p^{demand}_{n,s,t} \\ & - p^{demand\_fraction}_{n,s,t} \cdot p^{group\_demand}_{n_{group},s,t} \\ & \forall n \in node: p^{capacity\_margin\_min} \\ \end{aligned}\]
where math U_{storage_n} is the set of all storage units connected to node n and math U_{n\_to} is the set of all non-storage units connected to node n
See also capacity_margin_min, capacity_margin_penalty, node__to_unit, unit__to_node, demand, demand_fraction, storage_active
SpineOpt.generate_direction_and_reorganise_classes — Function
generate_direction_and_reorganise_classes()Generate direction Objects and reorganise affected relationships.
SpineInterface.indices — Function
indices(p::Parameter, [c::EntityClass]; kwargs...)An iterator over all objects and relationships where the value of p is different than nothing.
Arguments
- For each object class where
pis defined, there is a keyword argument named after it; similarly, for each relationship class wherepis defined, there is a keyword argument named after each object class in it. The purpose of these arguments is to filter the result by an object or list of objects of an specific class, or to accept all objects of that class by specifyinganythingfor the corresponding argument.
Examples
julia> using SpineInterface;
julia> url = "sqlite:///" * joinpath(dirname(pathof(SpineInterface)), "..", "examples/data/example.sqlite");
julia> using_spinedb(url)
julia> collect(indices(tax_net_flow))
1-element Vector{@NamedTuple{node::Object, commodity::Object}}:
(node = Sthlm, commodity = water)
julia> collect(indices(demand))
5-element Vector{Object}:
Dublin
Espoo
Leuven
Nimes
Sthlm