Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Jd/sim implementationv1 #4

Merged
merged 8 commits into from
May 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions src/algorithms/sequential_algorithm.jl
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ function write_results_to_main_container(container::MultiOptimizationContainer)
main_container_data_field = getproperty(container, field)
for (key, src) in subproblem_data_field
if src isa JuMP.Containers.SparseAxisArray
@warn "Skip SparseAxisArray" field key
# @warn "Skip SparseAxisArray" field key
continue
end
num_dims = ndims(src)
Expand All @@ -45,7 +45,7 @@ function write_results_to_main_container(container::MultiOptimizationContainer)
data = PSI.jump_value.(src)
catch e
if e isa UndefRefError
@warn "Skip UndefRefError for" field key
#@warn "Skip UndefRefError for" field key
continue
end
rethrow()
Expand All @@ -68,7 +68,6 @@ function write_results_to_main_container(container::MultiOptimizationContainer)
end
_write_parameter_results_to_main_container(container, subproblem)
end
# Parameters need a separate approach due to the way the containers work
return
end

Expand Down
45 changes: 23 additions & 22 deletions src/multi_optimization_container.jl
Original file line number Diff line number Diff line change
Expand Up @@ -42,28 +42,28 @@ function MultiOptimizationContainer(
)

return MultiOptimizationContainer{T}(;
main_problem = PSI.OptimizationContainer(sys, settings, nothing, U),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You must be using the wrong formatter settings.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am running the formatter in the scripts folder in the repo.

subproblems = subproblems,
time_steps = 1:1,
resolution = IS.time_period_conversion(resolution),
settings = settings,
settings_copy = PSI.copy_for_serialization(settings),
variables = Dict{PSI.VariableKey, AbstractArray}(),
aux_variables = Dict{PSI.AuxVarKey, AbstractArray}(),
duals = Dict{PSI.ConstraintKey, AbstractArray}(),
constraints = Dict{PSI.ConstraintKey, AbstractArray}(),
objective_function = PSI.ObjectiveFunction(),
expressions = Dict{PSI.ExpressionKey, AbstractArray}(),
parameters = Dict{PSI.ParameterKey, PSI.ParameterContainer}(),
primal_values_cache = PSI.PrimalValuesCache(),
initial_conditions = Dict{PSI.ICKey, Vector{PSI.InitialCondition}}(),
initial_conditions_data = PSI.InitialConditionsData(),
base_power = PSY.get_base_power(sys),
optimizer_stats = PSI.OptimizerStats(),
built_for_recurrent_solves = false,
metadata = PSI.OptimizationContainerMetadata(),
default_time_series_type = U,
mpi_info = nothing,
main_problem=PSI.OptimizationContainer(sys, settings, nothing, U),
subproblems=subproblems,
time_steps=1:1,
resolution=IS.time_period_conversion(resolution),
settings=settings,
settings_copy=PSI.copy_for_serialization(settings),
variables=Dict{PSI.VariableKey, AbstractArray}(),
aux_variables=Dict{PSI.AuxVarKey, AbstractArray}(),
duals=Dict{PSI.ConstraintKey, AbstractArray}(),
constraints=Dict{PSI.ConstraintKey, AbstractArray}(),
objective_function=PSI.ObjectiveFunction(),
expressions=Dict{PSI.ExpressionKey, AbstractArray}(),
parameters=Dict{PSI.ParameterKey, PSI.ParameterContainer}(),
primal_values_cache=PSI.PrimalValuesCache(),
initial_conditions=Dict{PSI.ICKey, Vector{PSI.InitialCondition}}(),
initial_conditions_data=PSI.InitialConditionsData(),
base_power=PSY.get_base_power(sys),
optimizer_stats=PSI.OptimizerStats(),
built_for_recurrent_solves=false,
metadata=PSI.OptimizationContainerMetadata(),
default_time_series_type=U,
mpi_info=nothing,
)
end

Expand Down Expand Up @@ -163,6 +163,7 @@ function init_optimization_container!(
PSI.LOG_GROUP_OPTIMIZATION_CONTAINER
subproblem.settings = deepcopy(settings)
PSI.init_optimization_container!(subproblem, network_model, sys)
subproblem.built_for_recurrent_solves = true
end
_finalize_jump_model!(container, settings)
return
Expand Down
34 changes: 28 additions & 6 deletions src/multiproblem_template.jl
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,26 @@ function get_sub_problem_keys(template::MultiProblemTemplate)
return sort!(collect(keys(get_sub_templates(template))))
end

function PSI.get_component_types(template::MultiProblemTemplate)::Vector{DataType}
base_template = template.base_template
return vcat(
get_component_type.(values(get_device_models(base_template))),
get_component_type.(values(get_branch_models(base_template))),
get_component_type.(values(get_service_models(base_template))),
)
end

function PSI.get_model(template::MultiProblemTemplate, ::Type{T}) where {T <: PSY.Device}
base_template = template.base_template
if T <: PSY.Branch
return get(base_template.branches, Symbol(T), nothing)
elseif T <: PSY.Device
return get(base_template.devices, Symbol(T), nothing)
else
error("Component $T not present in the template")
end
end

"""
Sets the network model in a template.
"""
Expand Down Expand Up @@ -92,8 +112,9 @@ function PSI.set_device_model!(
)
PSI.set_device_model!(template.base_template, model)
for (id, sub_template) in get_sub_templates(template)
PSI.set_subsystem!(model, id)
PSI.set_device_model!(sub_template, model)
new_model = deepcopy(model)
PSI.set_subsystem!(new_model, id)
PSI.set_device_model!(sub_template, new_model)
end
return
end
Expand All @@ -104,8 +125,9 @@ function PSI.set_device_model!(
)
PSI.set_device_model!(template.base_template, model)
for (id, sub_template) in get_sub_templates(template)
PSI.set_subsystem!(model, id)
PSI.set_device_model!(sub_template, PSI.DeviceModel(component_type, formulation))
new_model = deepcopy(model)
PSI.set_subsystem!(new_model, id)
PSI.set_device_model!(sub_template, new_model)
end
return
end
Expand All @@ -123,10 +145,10 @@ function PSI.set_service_model!(
PSI.set_service_model!(
template.base_template,
service_name,
ServiceModel(service_type, formulation; use_service_name = true),
ServiceModel(service_type, formulation; use_service_name=true),
)
for (id, sub_template) in get_sub_templates(template)
service_model = ServiceModel(service_type, formulation; use_service_name = true)
service_model = ServiceModel(service_type, formulation; use_service_name=true)
PSI.set_subsystem!(service_model, id)
PSI.set_service_model!(sub_template, service_name, service_model)
end
Expand Down
129 changes: 119 additions & 10 deletions src/problems/multi_region_problem.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ struct MultiRegionProblem <: PSI.DecisionProblem end
function PSI.DecisionModel{MultiRegionProblem}(
template::MultiProblemTemplate,
sys::PSY.System,
::Union{Nothing, JuMP.Model} = nothing;
::Union{Nothing, JuMP.Model}=nothing;
kwargs...,
)
name = Symbol(get(kwargs, :name, nameof(MultiRegionProblem)))
Expand Down Expand Up @@ -126,19 +126,15 @@ function _make_parameter_attributes(subproblem_parameters)
if !haskey(data, key)
data[key] = deepcopy(val.attributes)
else
existing = data[key]
if val.attributes.name != existing.name
error("Mismatch in attributes name: $key $val $(existing.name)")
end
_merge_attributes!(existing, val.attributes)
_merge_attributes!(data[key], val.attributes)
end
end
end

return data
end

function _merge_attributes(attributes::T, other::T) where {T <: PSI.ParameterAttributes}
function _merge_attributes!(attributes::T, other::T) where {T <: PSI.ParameterAttributes}
for field in fieldnames(T)
val1 = getproperty(attributes, field)
val2 = getproperty(other, field)
Expand All @@ -151,6 +147,9 @@ function _merge_attributes(attributes::T, other::T) where {T <: PSI.ParameterAtt
end

function _merge_attributes!(attributes::T, other::T) where {T <: PSI.TimeSeriesAttributes}
if attributes.name != other.name
error("Mismatch in attributes name: $(attributes.name) $(other.name)")
end
intersection = intersect(
keys(attributes.component_name_to_ts_uuid),
keys(other.component_name_to_ts_uuid),
Expand Down Expand Up @@ -185,9 +184,9 @@ function _make_parameter_arrays(subproblem_parameters, field_name)
end

function _make_array_joined_by_axes(
a1::JuMP.Containers.DenseAxisArray{Float64, 2},
a2::JuMP.Containers.DenseAxisArray{Float64, 2},
)
a1::JuMP.Containers.DenseAxisArray{T, 2},
a2::JuMP.Containers.DenseAxisArray{U, 2},
) where {T <: Union{Float64, JuMP.VariableRef}, U <: Union{Float64, JuMP.VariableRef}}
ax1 = axes(a1)
ax2 = axes(a2)
if ax1[2] != ax2[2]
Expand All @@ -209,6 +208,8 @@ function PSI.build_impl!(model::PSI.DecisionModel{MultiRegionProblem})
handle_initial_conditions!(model)
PSI.build_model!(model)
_map_containers(model)
container = PSI.get_optimization_container(model)
container.built_for_recurrent_solves = true
# Might need custom implementation for this container type
# serialize_metadata!(get_optimization_container(model), get_output_dir(model))
PSI.log_values(PSI.get_settings(model))
Expand Down Expand Up @@ -261,3 +262,111 @@ function PSI.solve_impl!(model::PSI.DecisionModel{MultiRegionProblem})
end

function PSI._check_numerical_bounds(model::PSI.DecisionModel{MultiRegionProblem}) end

### Simulation Related methods ###
# These code blocks are duplicative from PSI, refactoring might be required on the PSI side to
# avoid duplication.

function PSI._add_feedforward_to_model(
sim_model::PSI.DecisionModel{MultiRegionProblem},
ff::T,
::Type{U},
) where {T <: PSI.AbstractAffectFeedforward, U <: PSY.Device}
template = PSI.get_template(sim_model)
for (id, sub_template) in get_sub_templates(template)
device_model = PSI.get_model(sub_template, PSI.get_component_type(ff))
if device_model === nothing
model_name = PSI.get_name(sim_model)
throw(
IS.ConflictingInputsError(
"Device model $(PSI.get_component_type(ff)) not found in model $model_name",
),
)
end
@info "attaching $T to $(PSI.get_component_type(ff)) to Template $id"
PSI.attach_feedforward!(device_model, ff)
end
return
end

function PSI._add_feedforward_to_model(
sim_model::PSI.DecisionModel{MultiRegionProblem},
ff::T,
::Type{U},
) where {T <: PSI.AbstractAffectFeedforward, U <: PSY.Service}
template = PSI.get_template(sim_model)
name_provided = PSI.get_feedforward_meta(ff) != PSI.NO_SERVICE_NAME_PROVIDED
for (id, sub_template) in get_sub_templates(template)
if name_provided
service_model = PSI.get_model(
sub_template,
PSI.get_component_type(ff),
PSI.get_feedforward_meta(ff),
)
if service_model === nothing
throw(
IS.ConflictingInputsError(
"Service model $(get_component_type(ff)) not found in model $(get_name(sim_model))",
),
)
end
@info "attaching $T to $(PSI.get_component_type(ff)) $(PSI.get_feedforward_meta(ff)) to Template $id"
PSI.attach_feedforward!(service_model, ff)
else
service_found = false
for (key, model) in PSI.get_service_models(sub_template)
if key[2] == Symbol(PSI.get_component_type(ff))
service_found = true
@info "attaching $T to $(PSI.get_component_type(ff))"
PSI.attach_feedforward!(model, ff)
end
end
end
end
return
end

function PSI.update_parameters!(
model::PSI.DecisionModel{MultiRegionProblem},
decision_states::PSI.DatasetContainer{PSI.InMemoryDataset},
)
container = PSI.get_optimization_container(model)
for (ix, subproblem) in container.subproblems
@info "Updating subproblem $ix"
PSI.cost_function_unsynch(subproblem)
for key in keys(PSI.get_parameters(subproblem))
PSI.update_container_parameter_values!(subproblem, model, key, decision_states)
end
end

if !PSI.is_synchronized(model)
for subproblem in values(container.subproblems)
PSI.update_objective_function!(subproblem)
obj_func = PSI.get_objective_expression(subproblem)
PSI.set_synchronized_status(obj_func, true)
end
end
return
end

"""
Default problem update function for most problems with no customization
"""
function PSI.update_model!(
model::PSI.DecisionModel{MultiRegionProblem},
sim::PSI.Simulation,
)
PSI.update_model!(
model,
PSI.get_simulation_state(sim),
PSI.get_ini_cond_chronology(sim),
)
#=
if get_rebuild_model(model)
container = get_optimization_container(model)
reset_optimization_model!(container)
build_impl!(container, get_template(model), get_system(model))
end
=#
return
end
2 changes: 2 additions & 0 deletions test/Project.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
[deps]
HydroPowerSimulations = "fc1677e0-6ad7-4515-bf3a-bd6bf20a0b1b"
InfrastructureSystems = "2cd47ed4-ca9b-11e9-27f2-ab636a7671f1"
PowerSimulations = "e690365d-45e2-57bb-ac84-44ba829e73c4"
PowerSimulationsDecomposition = "bed98974-b02a-5e2f-9ee0-a103f5c450dd"
PowerSystemCaseBuilder = "f00506e0-b84f-492a-93c2-c0a9afc4364e"
PowerSystems = "bcd98974-b02a-5e2f-9ee0-a103f5c450dd"
Revise = "295af30f-e4ad-537b-8983-00126c2a3abe"
StorageSystemsSimulations = "e2f1a126-19d0-4674-9252-42b2384f8e3c"
Xpress = "9e70acf3-d6c9-5be6-b5bd-4e2c73e3e054"
Loading