Skip to content

Commit

Permalink
Merge pull request #1062 from NREL-Sienna/serialize-everything-but-ti…
Browse files Browse the repository at this point in the history
…me-series

Serialize System components to HDF5
  • Loading branch information
jd-lara authored Feb 29, 2024
2 parents d4b67e1 + 6ff0a6f commit 0f50321
Show file tree
Hide file tree
Showing 5 changed files with 218 additions and 89 deletions.
27 changes: 27 additions & 0 deletions src/simulation/hdf_simulation_store.jl
Original file line number Diff line number Diff line change
Expand Up @@ -679,6 +679,33 @@ function write_result!(
return
end

function serialize_system!(store::HdfSimulationStore, sys::PSY.System)
root = store.file[HDF_SIMULATION_ROOT_PATH]
systems_group = _get_group_or_create(root, "systems")
uuid = string(IS.get_uuid(sys))
if haskey(systems_group, uuid)
@debug "System with UUID = $uuid is already stored" _group =
LOG_GROUP_SIMULATION_STORE
return
end

json_text = PSY.to_json(sys)
systems_group[uuid] = json_text
return
end

function deserialize_system(store::HdfSimulationStore, uuid::Base.UUID)
root = store.file[HDF_SIMULATION_ROOT_PATH]
systems_group = _get_group_or_create(root, "systems")
uuid_str = string(uuid)
if !haskey(systems_group, uuid_str)
error("No system with UUID $uuid_str is stored")
end

json_text = HDF5.read(systems_group[uuid_str])
return PSY.from_json(json_text, PSY.System)
end

function _check_state(store::HdfSimulationStore)
if has_dirty(store.cache)
error("BUG!!! dirty cache is present at shutdown: $(store.file)")
Expand Down
2 changes: 2 additions & 0 deletions src/simulation/in_memory_simulation_store.jl
Original file line number Diff line number Diff line change
Expand Up @@ -271,3 +271,5 @@ function write_optimizer_stats!(
write_optimizer_stats!(em_data, stats, index)
return
end

serialize_system!(::InMemorySimulationStore, ::PSY.System) = nothing
32 changes: 26 additions & 6 deletions src/simulation/simulation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -590,13 +590,17 @@ function _setup_simulation_partitions(sim::Simulation)

open_store(HdfSimulationStore, get_store_dir(sim), "w") do store
set_simulation_store!(sim, store)
_initialize_problem_storage!(
sim,
DEFAULT_SIMULATION_STORE_CACHE_SIZE_MiB,
MIN_CACHE_FLUSH_SIZE_MiB,
)
try
_initialize_problem_storage!(
sim,
DEFAULT_SIMULATION_STORE_CACHE_SIZE_MiB,
MIN_CACHE_FLUSH_SIZE_MiB,
)
_serialize_systems_to_store!(store, sim)
finally
set_simulation_store!(sim, nothing)
end
end
set_simulation_store!(sim, nothing)
end

"""
Expand Down Expand Up @@ -1000,6 +1004,10 @@ function execute!(sim::Simulation; kwargs...)
end
@info ("\n$(RUN_SIMULATION_TIMER)\n")
set_simulation_status!(sim, RunStatus.SUCCESSFUL)
if isnothing(sim.internal.partitions)
# Partitioned simulations serialize the systems once during build.
_serialize_systems_to_store!(store, sim)
end
log_cache_hit_percentages(store)
catch e
set_simulation_status!(sim, RunStatus.FAILED)
Expand Down Expand Up @@ -1084,6 +1092,18 @@ function serialize_simulation(sim::Simulation; path = nothing, force = false)
return directory
end

function _serialize_systems_to_store!(store::SimulationStore, sim::Simulation)
simulation_models = get_models(sim)
for dm in get_decision_models(simulation_models)
serialize_system!(store, get_system(dm))
end

em = get_emulation_model(simulation_models)
if !isnothing(em)
serialize_system!(store, get_system(em))
end
end

function deserialize_model(
::Type{Simulation},
directory::AbstractString,
Expand Down
45 changes: 38 additions & 7 deletions src/simulation/simulation_problem_results.jl
Original file line number Diff line number Diff line change
Expand Up @@ -113,18 +113,52 @@ get_timestamps(result::SimulationProblemResults) = result.timestamps
"""
Return the system used for the problem. If the system hasn't already been deserialized or
set with [`set_system!`](@ref) then deserialize and store it.
If the simulation was configured to serialize all systems to file then the returned system
will include all data. If that was not configured then the returned system will include
all data except time series data.
"""
function get_system!(results::SimulationProblemResults)
function get_system!(results::SimulationProblemResults; kwargs...)
!isnothing(results.system) && return results.system

file = joinpath(
results.execution_path,
"problems",
results.problem,
make_system_filename(results.system_uuid),
)
results.system = PSY.System(file; time_series_read_only = true)

# This flag should remain unpublished because it should never be needed
# by the general audience.
if !get(kwargs, :use_h5_system, false) && isfile(file)
system = PSY.System(file; time_series_read_only = true)
@info "De-serialized the system from files."
else
system = _deserialize_system(results, results.store)
end

results.system = system
return results.system
end

function _deserialize_system(results::SimulationProblemResults, ::Nothing)
open_store(
HdfSimulationStore,
joinpath(get_execution_path(results), "data_store"),
"r",
) do store
system = deserialize_system(store, results.system_uuid)
@info "De-serialized the system from the simulation store. The system does " *
"not include time series data."
return system
end
end

function _deserialize_system(::SimulationProblemResults, ::InMemorySimulationStore)
# This should never be necessary because the system is guaranteed to be in memory.
error("Deserializing a system from the InMemorySimulationStore is not supported.")
end

"""
Set the system in the results instance.
Expand Down Expand Up @@ -593,11 +627,8 @@ Return the optimizer stats for the problem as a DataFrame.
- `store::SimulationStore`: a store that has been opened for reading
"""
function read_optimizer_stats(res::SimulationProblemResults; store = nothing)
if store === nothing && res.store !== nothing
# In this case we have an InMemorySimulationStore.
store = res.store
end
return _read_optimizer_stats(res, store)
_store = isnothing(store) ? res.store : store
return _read_optimizer_stats(res, _store)
end

function _read_optimizer_stats(res::SimulationProblemResults, ::Nothing)
Expand Down
201 changes: 125 additions & 76 deletions test/test_simulation_results.jl
Original file line number Diff line number Diff line change
Expand Up @@ -125,89 +125,115 @@ function make_export_all(problems)
]
end

function test_simulation_results(file_path::String, export_path; in_memory = false)
@testset "Test simulation results in_memory = $in_memory" begin
template_uc = get_template_basic_uc_simulation()
template_ed = get_template_nomin_ed_simulation()
set_device_model!(template_ed, InterruptiblePowerLoad, StaticPowerLoad)
set_network_model!(
template_uc,
NetworkModel(CopperPlatePowerModel; duals = [CopperPlateBalanceConstraint]),
)
set_network_model!(
template_ed,
NetworkModel(
CopperPlatePowerModel;
duals = [CopperPlateBalanceConstraint],
use_slacks = true,
function run_simulation(
c_sys5_hy_uc,
c_sys5_hy_ed,
file_path::String,
export_path;
in_memory = false,
system_to_file = true,
)
template_uc = get_template_basic_uc_simulation()
template_ed = get_template_nomin_ed_simulation()
set_device_model!(template_ed, InterruptiblePowerLoad, StaticPowerLoad)
set_network_model!(
template_uc,
NetworkModel(CopperPlatePowerModel; duals = [CopperPlateBalanceConstraint]),
)
set_network_model!(
template_ed,
NetworkModel(
CopperPlatePowerModel;
duals = [CopperPlateBalanceConstraint],
use_slacks = true,
),
)
models = SimulationModels(;
decision_models = [
DecisionModel(
template_uc,
c_sys5_hy_uc;
name = "UC",
optimizer = GLPK_optimizer,
system_to_file = system_to_file,
),
)
c_sys5_hy_uc = PSB.build_system(PSITestSystems, "c_sys5_hy_uc")
c_sys5_hy_ed = PSB.build_system(PSITestSystems, "c_sys5_hy_ed")
models = SimulationModels(;
decision_models = [
DecisionModel(
template_uc,
c_sys5_hy_uc;
name = "UC",
optimizer = GLPK_optimizer,
),
DecisionModel(
template_ed,
c_sys5_hy_ed;
name = "ED",
optimizer = ipopt_optimizer,
DecisionModel(
template_ed,
c_sys5_hy_ed;
name = "ED",
optimizer = ipopt_optimizer,
system_to_file = system_to_file,
),
],
)

sequence = SimulationSequence(;
models = models,
feedforwards = Dict(
"ED" => [
SemiContinuousFeedforward(;
component_type = ThermalStandard,
source = OnVariable,
affected_values = [ActivePowerVariable],
),
],
)
),
ini_cond_chronology = InterProblemChronology(),
)
sim = Simulation(;
name = "no_cache",
steps = 2,
models = models,
sequence = sequence,
simulation_folder = file_path,
)

sequence = SimulationSequence(;
models = models,
feedforwards = Dict(
"ED" => [
SemiContinuousFeedforward(;
component_type = ThermalStandard,
source = OnVariable,
affected_values = [ActivePowerVariable],
),
],
build_out = build!(sim; console_level = Logging.Error)
@test build_out == PSI.BuildStatus.BUILT

exports = Dict(
"models" => [
Dict(
"name" => "UC",
"store_all_variables" => true,
"store_all_parameters" => true,
"store_all_duals" => true,
"store_all_aux_variables" => true,
),
ini_cond_chronology = InterProblemChronology(),
)
sim = Simulation(;
name = "no_cache",
steps = 2,
models = models,
sequence = sequence,
simulation_folder = file_path,
)
Dict(
"name" => "ED",
"store_all_variables" => true,
"store_all_parameters" => true,
"store_all_duals" => true,
"store_all_aux_variables" => true,
),
],
"path" => export_path,
"optimizer_stats" => true,
)
execute_out = execute!(sim; exports = exports, in_memory = in_memory)
@test execute_out == PSI.RunStatus.SUCCESSFUL

build_out = build!(sim; console_level = Logging.Error)
@test build_out == PSI.BuildStatus.BUILT

exports = Dict(
"models" => [
Dict(
"name" => "UC",
"store_all_variables" => true,
"store_all_parameters" => true,
"store_all_duals" => true,
"store_all_aux_variables" => true,
),
Dict(
"name" => "ED",
"store_all_variables" => true,
"store_all_parameters" => true,
"store_all_duals" => true,
"store_all_aux_variables" => true,
),
],
"path" => export_path,
"optimizer_stats" => true,
)
execute_out = execute!(sim; exports = exports, in_memory = in_memory)
@test execute_out == PSI.RunStatus.SUCCESSFUL
return sim
end

function test_simulation_results(
file_path::String,
export_path;
in_memory = false,
system_to_file = true,
)
@testset "Test simulation results in_memory = $in_memory" begin
c_sys5_hy_uc = PSB.build_system(PSITestSystems, "c_sys5_hy_uc")
c_sys5_hy_ed = PSB.build_system(PSITestSystems, "c_sys5_hy_ed")
sim = run_simulation(
c_sys5_hy_uc,
c_sys5_hy_ed,
file_path,
export_path;
in_memory = in_memory,
system_to_file = system_to_file,
)
results = SimulationResults(sim)
test_decision_problem_results(results, c_sys5_hy_ed, c_sys5_hy_uc, in_memory)
test_emulation_problem_results(results, in_memory)
Expand Down Expand Up @@ -704,3 +730,26 @@ end
test_simulation_results(file_path, export_path; in_memory = in_memory)
end
end

@testset "Test simulation results with system from store" begin
file_path = mktempdir(; cleanup = true)
export_path = mktempdir(; cleanup = true)
c_sys5_hy_uc = PSB.build_system(PSITestSystems, "c_sys5_hy_uc")
c_sys5_hy_ed = PSB.build_system(PSITestSystems, "c_sys5_hy_ed")
in_memory = false
sim = run_simulation(
c_sys5_hy_uc,
c_sys5_hy_ed,
file_path,
export_path;
system_to_file = false,
in_memory = in_memory,
)
results = SimulationResults(PSI.get_simulation_folder(sim))
uc = get_decision_problem_results(results, "UC")
ed = get_decision_problem_results(results, "ED")
sys_uc = get_system!(uc)
sys_ed = get_system!(ed)
test_decision_problem_results(results, sys_ed, sys_uc, in_memory)
test_emulation_problem_results(results, in_memory)
end

0 comments on commit 0f50321

Please sign in to comment.