Skip to content

Commit

Permalink
Merge pull request #421 from NREL-Sienna/gks/fast_deepcopy_system
Browse files Browse the repository at this point in the history
Add `fast_deepcopy_system` function
  • Loading branch information
jd-lara authored Dec 26, 2024
2 parents 180ab67 + 47c4ff6 commit 77358d9
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 0 deletions.
64 changes: 64 additions & 0 deletions src/system_data.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1198,3 +1198,67 @@ clear_supplemental_attributes!(data::SystemData) =

stores_time_series_in_memory(data::SystemData) =
data.time_series_manager.data_store isa InMemoryTimeSeriesStorage

"""
Make a `deepcopy` of a [`SystemData`](@ref) more quickly by skipping the copying of time
series and/or supplemental attributes.
# Arguments
- `data::SystemData`: the `SystemData` to copy
- `skip_time_series::Bool = true`: whether to skip copying time series
- `skip_supplemental_attributes::Bool = true`: whether to skip copying supplemental
attributes
Note that setting both `skip_time_series` and `skip_supplemental_attributes` to `false`
results in the same behavior as `deepcopy` with no performance improvement.
"""
function fast_deepcopy_system(
data::SystemData;
skip_time_series::Bool = true,
skip_supplemental_attributes::Bool = true,
)
# The approach taken here is to swap out the data we don't want to copy with blank data,
# then do a deepcopy, then swap it back. We can't just construct a new instance with
# different fields because we also need to change references within components.
old_time_series_manager = data.time_series_manager
old_supplemental_attribute_manager = data.supplemental_attribute_manager

new_time_series_manager = if skip_time_series
TimeSeriesManager(InMemoryTimeSeriesStorage(), TimeSeriesMetadataStore(), true)
else
old_time_series_manager
end
new_supplemental_attribute_manager = if skip_supplemental_attributes
SupplementalAttributeManager()
else
old_supplemental_attribute_manager
end

data.time_series_manager = new_time_series_manager
data.supplemental_attribute_manager = new_supplemental_attribute_manager

old_refs = Dict{Tuple{DataType, String}, SharedSystemReferences}()
for comp in iterate_components(data)
old_refs[(typeof(comp), get_name(comp))] =
comp.internal.shared_system_references
new_refs = SharedSystemReferences(;
time_series_manager = new_time_series_manager,
supplemental_attribute_manager = new_supplemental_attribute_manager,
)
set_shared_system_references!(comp, new_refs)
end

new_data = try
deepcopy(data)
finally
data.time_series_manager = old_time_series_manager
data.supplemental_attribute_manager = old_supplemental_attribute_manager

for comp in iterate_components(data)
set_shared_system_references!(comp,
old_refs[(typeof(comp), get_name(comp))])
end
end
return new_data
end
28 changes: 28 additions & 0 deletions test/test_system_data.jl
Original file line number Diff line number Diff line change
Expand Up @@ -650,3 +650,31 @@ end
@test ts2.data == array
end
end

@testset "Test fast deepcopy of system" begin
@testset for (in_memory, skip_ts, skip_sa) in # Iterate over all permutations
Iterators.product(repeat([(true, false)], 3)...)
sys = IS.SystemData(; time_series_in_memory = in_memory)
initial_time = Dates.DateTime("2020-09-01")
resolution = Dates.Hour(1)
len = 24
timestamps = range(initial_time; length = len, step = resolution)
array = TimeSeries.TimeArray(timestamps, rand(len))
ts_name = "test"
name = "component"
component = IS.TestComponent(name, 3)
IS.add_component!(sys, component)
ts = IS.SingleTimeSeries(; data = array, name = ts_name)
IS.add_time_series!(sys, component, ts)

sys2 = IS.fast_deepcopy_system(sys;
skip_time_series = skip_ts, skip_supplemental_attributes = skip_sa)
@test IS.compare_values(
sys,
sys2;
exclude = Set(
[:time_series_manager, :supplemental_attribute_manager][[skip_ts, skip_sa]],
),
)
end
end

0 comments on commit 77358d9

Please sign in to comment.