Skip to content

Commit

Permalink
Merge pull request #4 from NREL-Sienna/jd/sim_implementationv1
Browse files Browse the repository at this point in the history
Jd/sim implementationv1
  • Loading branch information
jd-lara authored May 28, 2024
2 parents b344ddb + 1d36fb5 commit 89c44da
Show file tree
Hide file tree
Showing 5 changed files with 174 additions and 41 deletions.
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),
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"

0 comments on commit 89c44da

Please sign in to comment.