Skip to content

Commit

Permalink
Serialize System components to HDF5
Browse files Browse the repository at this point in the history
  • Loading branch information
daniel-thom committed Feb 24, 2024
1 parent 12288cd commit b869ccd
Show file tree
Hide file tree
Showing 7 changed files with 219 additions and 92 deletions.
4 changes: 2 additions & 2 deletions src/operation/decision_model.jl
Original file line number Diff line number Diff line change
Expand Up @@ -268,8 +268,8 @@ end

function validate_time_series(model::DecisionModel{<:DefaultDecisionProblem})
sys = get_system(model)
_, _, forecast_count = PSY.get_time_series_counts(sys)
if forecast_count < 1
counts = PSY.get_time_series_counts(sys)
if counts.forecast_count < 1
error(
"The system does not contain forecast data. A DecisionModel can't be built.",
)
Expand Down
4 changes: 2 additions & 2 deletions src/operation/emulation_model.jl
Original file line number Diff line number Diff line change
Expand Up @@ -247,8 +247,8 @@ end

function validate_time_series(model::EmulationModel{<:DefaultEmulationProblem})
sys = get_system(model)
_, ts_count, _ = PSY.get_time_series_counts(sys)
if ts_count < 1
counts = PSY.get_time_series_counts(sys)
if counts.static_time_series_count < 1
error(
"The system does not contain Static TimeSeries data. An Emulation model can't be formulated.",
)
Expand Down
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
41 changes: 35 additions & 6 deletions src/simulation/simulation_problem_results.jl
Original file line number Diff line number Diff line change
Expand Up @@ -113,18 +113,50 @@ 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)
!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)

if 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 +625,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
Loading

0 comments on commit b869ccd

Please sign in to comment.