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

Serialize System components to HDF5 #1062

Merged
merged 2 commits into from
Feb 29, 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
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
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
Loading
Loading