Skip to content

Commit 152fd02

Browse files
authored
Merge pull request #499 from NREL-Sienna/issue-498
Duplicate Deterministic forecasts
2 parents b132d74 + 1b16250 commit 152fd02

File tree

2 files changed

+125
-0
lines changed

2 files changed

+125
-0
lines changed

src/system_data.jl

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -666,6 +666,34 @@ function _check_transform_single_time_series(
666666
)
667667
check_params_compatibility(system_params, params)
668668
component = get_component(data, item.owner_uuid)
669+
670+
# We do not allow a component to have both Deterministic and
671+
# DeterministicSingleTimeSeries with the same parameters.
672+
# The user might be calling this function because some components are missing
673+
# Deterministic forecasts. If other components already have Deterministic forecasts,
674+
# this check will fail.
675+
# transform_single_time_series! cannot be called at the component level.
676+
ts_name = get_name(item.metadata)
677+
ts_resolution = get_resolution(item.metadata)
678+
ts_features = get_features(item.metadata)
679+
ts_features_symbols = Dict{Symbol, Any}(Symbol(k) => v for (k, v) in ts_features)
680+
if has_metadata(
681+
data.time_series_manager.metadata_store,
682+
component;
683+
time_series_type = Deterministic,
684+
name = ts_name,
685+
resolution = ts_resolution,
686+
ts_features_symbols...,
687+
)
688+
throw(
689+
ConflictingInputsError(
690+
"Cannot transform SingleTimeSeries to DeterministicSingleTimeSeries: " *
691+
"A Deterministic forecast already exists for component $(summary(component)) " *
692+
"with name='$ts_name', resolution=$ts_resolution, and features=$ts_features",
693+
),
694+
)
695+
end
696+
669697
components_with_params_and_metadata[i] =
670698
(component = component, params = params, metadata = item.metadata)
671699
end

test/test_time_series.jl

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1472,6 +1472,103 @@ end
14721472
)
14731473
end
14741474

1475+
@testset "Test transform_single_time_series with conflicting Deterministic" begin
1476+
# Test 1: Transformation fails when Deterministic exists with same name, resolution, and features
1477+
sys1 = IS.SystemData()
1478+
component1 = IS.TestComponent("Component1", 1)
1479+
IS.add_component!(sys1, component1)
1480+
1481+
resolution = Dates.Hour(1)
1482+
initial_time = Dates.DateTime("2020-01-01T00:00:00")
1483+
1484+
# Add a Deterministic forecast with interval = 1 hour, horizon = 24 hours, 2 windows
1485+
horizon_count = 24
1486+
interval = Dates.Hour(1)
1487+
other_time = initial_time + interval
1488+
name = "power"
1489+
forecast_data = SortedDict(
1490+
initial_time => ones(horizon_count),
1491+
other_time => ones(horizon_count) * 2,
1492+
)
1493+
forecast =
1494+
IS.Deterministic(; data = forecast_data, name = name, resolution = resolution)
1495+
IS.add_time_series!(sys1, component1, forecast)
1496+
1497+
# Add a SingleTimeSeries with the same name, resolution, and no features
1498+
dates = create_dates("2020-01-01T00:00:00", resolution, "2020-01-02T00:00:00")
1499+
data = collect(1:length(dates))
1500+
ta = TimeSeries.TimeArray(dates, data, [IS.get_name(component1)])
1501+
ts = IS.SingleTimeSeries(name, ta)
1502+
IS.add_time_series!(sys1, component1, ts)
1503+
1504+
# Attempt to transform - this should fail because there's already a Deterministic
1505+
# with the same name, resolution, and features
1506+
horizon = horizon_count * resolution
1507+
@test_throws IS.ConflictingInputsError IS.transform_single_time_series!(
1508+
sys1,
1509+
IS.DeterministicSingleTimeSeries,
1510+
horizon,
1511+
interval,
1512+
)
1513+
1514+
# Test 2: Transformation succeeds when features are different
1515+
sys2 = IS.SystemData()
1516+
component2 = IS.TestComponent("Component2", 2)
1517+
IS.add_component!(sys2, component2)
1518+
1519+
forecast2 =
1520+
IS.Deterministic(; data = forecast_data, name = name, resolution = resolution)
1521+
IS.add_time_series!(sys2, component2, forecast2)
1522+
1523+
ts_with_features = IS.SingleTimeSeries(name, ta)
1524+
IS.add_time_series!(sys2, component2, ts_with_features; scenario = "high")
1525+
1526+
IS.transform_single_time_series!(
1527+
sys2,
1528+
IS.DeterministicSingleTimeSeries,
1529+
horizon,
1530+
interval,
1531+
)
1532+
@test IS.has_time_series(component2, IS.DeterministicSingleTimeSeries, name)
1533+
@test IS.has_time_series(component2, IS.Deterministic, name)
1534+
@test IS.has_time_series(component2, IS.SingleTimeSeries, name; scenario = "high")
1535+
1536+
# Test 3: Transformation succeeds when resolution is different
1537+
sys3 = IS.SystemData()
1538+
component3 = IS.TestComponent("Component3", 3)
1539+
IS.add_component!(sys3, component3)
1540+
1541+
forecast3 =
1542+
IS.Deterministic(; data = forecast_data, name = name, resolution = resolution)
1543+
IS.add_time_series!(sys3, component3, forecast3)
1544+
1545+
# Add SingleTimeSeries with different resolution (30 minutes)
1546+
resolution_30min = Dates.Minute(30)
1547+
dates_30min =
1548+
create_dates("2020-01-01T00:00:00", resolution_30min, "2020-01-02T00:00:00")
1549+
data_30min = collect(1:length(dates_30min))
1550+
ta_30min = TimeSeries.TimeArray(dates_30min, data_30min, [IS.get_name(component3)])
1551+
ts_different_resolution =
1552+
IS.SingleTimeSeries(name, ta_30min; resolution = resolution_30min)
1553+
IS.add_time_series!(sys3, component3, ts_different_resolution)
1554+
1555+
horizon_30min = 48 * resolution_30min # 24 hours
1556+
interval_30min = Dates.Minute(30)
1557+
IS.transform_single_time_series!(
1558+
sys3,
1559+
IS.DeterministicSingleTimeSeries,
1560+
horizon_30min,
1561+
interval_30min,
1562+
)
1563+
@test IS.has_time_series(
1564+
component3,
1565+
IS.DeterministicSingleTimeSeries,
1566+
name;
1567+
resolution = resolution_30min,
1568+
)
1569+
@test IS.has_time_series(component3, IS.Deterministic, name; resolution = resolution)
1570+
end
1571+
14751572
function _test_add_single_time_series_type(test_value, type_name)
14761573
sys = IS.SystemData()
14771574
name = "Component1"

0 commit comments

Comments
 (0)