Skip to content

Commit 7db8773

Browse files
authored
Merge pull request #1243 from NREL-Sienna/mb/cross-horizon-outages
Mb/cross horizon outages
2 parents f6331e9 + 0378b91 commit 7db8773

File tree

9 files changed

+203
-103
lines changed

9 files changed

+203
-103
lines changed

src/PowerSimulations.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,7 @@ export FixValueParameter
320320

321321
# Event Parameters
322322
export AvailableStatusParameter
323-
export AvailableStatusChangeParameter
323+
export AvailableStatusChangeCountdownParameter
324324

325325
# Expressions
326326
export SystemBalanceExpressions

src/contingency_model/contingency.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22
get_parameter_type(::Type{<:PSY.Outage}, ::EventModel, ::Type{<:PSY.Device}) = AvailableStatusParameter
33
# This value could change depending on the event modeling choices
44
get_parameter_multiplier(::EventParameter, ::PSY.Device, ::EventModel) = 1.0
5-
get_initial_parameter_value(::AvailableStatusChangeParameter, ::PSY.Device, ::EventModel) = 0.0
5+
get_initial_parameter_value(::AvailableStatusChangeCountdownParameter, ::PSY.Device, ::EventModel) = 0.0
66
get_initial_parameter_value(::AvailableStatusParameter, ::PSY.Device, ::EventModel) = 1.0
77
#! format: on

src/contingency_model/contingency_arguments.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ function add_event_arguments!(
1313
[d for d in devices if PSY.has_supplemental_attributes(d, event_type)]
1414
@assert !isempty(devices_with_attrbts)
1515
parameter_type = get_parameter_type(event_type, event_model, U)
16-
for p_type in [AvailableStatusChangeParameter, parameter_type]
16+
for p_type in [AvailableStatusChangeCountdownParameter, parameter_type]
1717
add_parameters!(
1818
container,
1919
p_type,

src/core/event_model.jl

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,22 +68,42 @@ get_condition_function(c::DiscreteEventCondition) = c.condition_function
6868

6969
mutable struct EventModel{D <: PSY.Contingency, B <: AbstractEventCondition}
7070
condition::B
71+
timeseries_mapping::Dict{Symbol, Union{String, Nothing}}
7172
attribute_device_map::Dict{Symbol, Dict{Base.UUID, Dict{DataType, Set{String}}}}
7273
attributes::Dict{String, Any}
7374

7475
function EventModel(
75-
::Type{D},
76+
contingency_type::Type{D},
7677
condition::B;
78+
timeseries_mapping = get_empty_timeseries_mapping(contingency_type),
7779
attributes = Dict{String, Any}(),
7880
) where {D <: PSY.Contingency, B <: AbstractEventCondition}
7981
new{D, B}(
8082
condition,
83+
timeseries_mapping,
8184
Dict{Symbol, Dict{Base.UUID, Dict{DataType, Set{String}}}}(),
8285
attributes,
8386
)
8487
end
8588
end
8689

90+
function get_empty_timeseries_mapping(
91+
::Type{PSY.TimeSeriesForcedOutage},
92+
) where {D <: PSY.Contingency}
93+
return Dict{Symbol, Union{String, Nothing}}(
94+
:availability => nothing,
95+
)
96+
end
97+
98+
function get_empty_timeseries_mapping(
99+
::Type{PSY.GeometricDistributionForcedOutage},
100+
) where {D <: PSY.Contingency}
101+
return Dict{Symbol, Union{String, Nothing}}(
102+
:mean_time_to_recovery => nothing,
103+
:outage_transition_probability => nothing,
104+
)
105+
end
106+
87107
get_event_type(
88108
::EventModel{D, B},
89109
) where {D <: PSY.Contingency, B <: AbstractEventCondition} = D

src/core/parameters.jl

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,6 @@ function get_parameter_values(
166166
param_array::DenseAxisArray,
167167
multiplier_array::DenseAxisArray,
168168
)
169-
@error "$attr"
170-
@show jump_value.(param_array)
171169
return jump_value.(param_array)
172170
end
173171

@@ -342,7 +340,7 @@ struct AvailableStatusParameter <: EventParameter end
342340
"""
343341
Parameter to record that the component changed in the availability status
344342
"""
345-
struct AvailableStatusChangeParameter <: EventParameter end
343+
struct AvailableStatusChangeCountdownParameter <: EventParameter end
346344

347345
should_write_resulting_value(::Type{<:RightHandSideParameter}) = true
348346
should_write_resulting_value(::Type{<:EventParameter}) = true

src/parameters/update_container_parameter_values.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -390,9 +390,9 @@ function _update_parameter_values!(
390390
Consider reviewing your models' horizon and interval definitions",
391391
)
392392
end
393-
if 0.0 > value || value > 1.0
393+
if 0.0 > value
394394
error(
395-
"The value for the system state used in $(encode_key_as_string(get_attribute_key(attributes))): $(value) is out of the [0, 1] range",
395+
"The value for the system state used in $(encode_key_as_string(get_attribute_key(attributes))): $(value) is less than 0.0",
396396
)
397397
end
398398
_set_param_value!(parameter_array, value, name, t)

src/simulation/simulation_events.jl

Lines changed: 58 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,65 @@ function apply_simulation_events!(simulation::Simulation)
33
events = get_events(sequence)
44
simulation_state = get_simulation_state(simulation)
55
for event_model in events
6+
extend_event_parameters!(simulation, event_model)
67
if check_condition(simulation_state, event_model)
7-
@warn "Condition evaluated to true at time $(get_current_time(simulation))"
88
# TODO: for other event categories we need to do something else
99
em_model = get_emulation_model(get_models(simulation))
1010
sys = get_system(em_model)
1111
model_name = get_name(em_model)
1212
for (event_uuid, device_type_maps) in
1313
event_model.attribute_device_map[model_name]
1414
event = PSY.get_supplemental_attribute(sys, event_uuid)
15-
@warn "Applying affect for $device_type_maps"
1615
apply_affect!(simulation, event_model, event, device_type_maps)
1716
end
1817
end
1918
end
2019
end
2120

21+
function extend_event_parameters!(simulation::Simulation, event_model)
22+
sequence = get_sequence(simulation)
23+
sim_state = get_simulation_state(simulation)
24+
em_model = get_emulation_model(get_models(simulation))
25+
model_name = get_name(em_model)
26+
for (event_uuid, device_type_maps) in
27+
event_model.attribute_device_map[model_name]
28+
sim_time = get_current_time(simulation)
29+
for (dtype, device_names) in device_type_maps
30+
if dtype == PSY.RenewableDispatch
31+
continue
32+
end
33+
em_model = get_emulation_model(get_models(simulation))
34+
status_change_countdown_data = get_decision_state_data(
35+
sim_state,
36+
ParameterKey(AvailableStatusChangeCountdownParameter, dtype),
37+
)
38+
status_data = get_decision_state_data(
39+
sim_state,
40+
ParameterKey(AvailableStatusParameter, dtype),
41+
)
42+
state_timestamps = status_data.timestamps
43+
state_data_index = find_timestamp_index(state_timestamps, sim_time)
44+
if state_data_index == 1
45+
for name in device_names
46+
if status_change_countdown_data.values[name, 1] > 1.0
47+
starting_count = status_change_countdown_data.values[name, 1]
48+
for i in 1:length(status_change_countdown_data.values[name, :])
49+
countdown_val = max(starting_count + 1 - i, 0.0)
50+
if countdown_val == 0.0
51+
status_val = 1.0
52+
else
53+
status_val = 0.0
54+
end
55+
status_change_countdown_data.values[name, i] = countdown_val
56+
status_data.values[name, i] = status_val
57+
end
58+
end
59+
end
60+
end
61+
end
62+
end
63+
end
64+
2265
function check_condition(
2366
::SimulationState,
2467
::EventModel{<:PSY.Contingency, ContinuousCondition},
@@ -77,7 +120,7 @@ end
77120

78121
function apply_affect!(
79122
simulation::Simulation,
80-
::EventModel{
123+
event_model::EventModel{
81124
T,
82125
<:AbstractEventCondition,
83126
},
@@ -93,13 +136,14 @@ function apply_affect!(
93136
end
94137
em_model = get_emulation_model(get_models(simulation))
95138
em_model_store = get_store_params(em_model)
96-
# Order is required here. The AvailableStatusChangeParameter needs to be updated first
139+
# Order is required here. The AvailableStatusChangeCountdownParameter needs to be updated first
97140
# to indicate that there is a change in the othe parameters
98141
update_system_state!(
99142
sim_state,
100-
ParameterKey(AvailableStatusChangeParameter, dtype),
143+
ParameterKey(AvailableStatusChangeCountdownParameter, dtype),
101144
device_names,
102145
event,
146+
event_model,
103147
sim_time,
104148
rng,
105149
)
@@ -108,6 +152,7 @@ function apply_affect!(
108152
ParameterKey(AvailableStatusParameter, dtype),
109153
device_names,
110154
event,
155+
event_model,
111156
sim_time,
112157
rng,
113158
)
@@ -116,6 +161,7 @@ function apply_affect!(
116161
VariableKey(ActivePowerVariable, dtype),
117162
device_names,
118163
event,
164+
event_model,
119165
sim_time,
120166
rng,
121167
)
@@ -124,16 +170,18 @@ function apply_affect!(
124170
VariableKey(OnVariable, dtype),
125171
device_names,
126172
event,
173+
event_model,
127174
sim_time,
128175
rng,
129176
)
130-
# Order is required here too AvailableStatusChangeParameter needs to
177+
# Order is required here too AvailableStatusChangeCountdownParameter needs to
131178
# go first to indicate that there is a change in the other values
132179
update_decision_state!(
133180
sim_state,
134-
ParameterKey(AvailableStatusChangeParameter, dtype),
181+
ParameterKey(AvailableStatusChangeCountdownParameter, dtype),
135182
device_names,
136183
event,
184+
event_model,
137185
sim_time,
138186
em_model_store,
139187
)
@@ -142,6 +190,7 @@ function apply_affect!(
142190
ParameterKey(AvailableStatusParameter, dtype),
143191
device_names,
144192
event,
193+
event_model,
145194
sim_time,
146195
em_model_store,
147196
)
@@ -150,6 +199,7 @@ function apply_affect!(
150199
VariableKey(ActivePowerVariable, dtype),
151200
device_names,
152201
event,
202+
event_model,
153203
sim_time,
154204
em_model_store,
155205
)
@@ -158,6 +208,7 @@ function apply_affect!(
158208
VariableKey(OnVariable, dtype),
159209
device_names,
160210
event,
211+
event_model,
161212
sim_time,
162213
em_model_store,
163214
)

src/simulation/simulation_sequence.jl

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,37 @@ function _add_event_to_model(
212212
return
213213
end
214214

215+
function _validate_event_timeseries_data(
216+
sys::PSY.System,
217+
event::PSY.Contingency,
218+
event_model::EventModel,
219+
)
220+
devices_with_attribute = PSY.get_components(sys, event)
221+
for (k, v) in event_model.timeseries_mapping
222+
if v !== nothing
223+
try
224+
PSY.get_time_series(
225+
IS.SingleTimeSeries,
226+
event,
227+
v,
228+
)
229+
catch e
230+
devices_with_attribute = PSY.get_components(sys, event)
231+
device_names_with_attribute =
232+
[PSY.get_name(d) for d in devices_with_attribute]
233+
error(
234+
"Event $event belonging to devices $device_names_with_attribute missing time series with name $v",
235+
)
236+
end
237+
end
238+
if !haskey(get_empty_timeseries_mapping(typeof(event)), k)
239+
error(
240+
"Key $k passed as part of event time series mapping does not correspond to a parameter.",
241+
)
242+
end
243+
end
244+
end
245+
215246
function _add_model_to_event_map!(
216247
model::OperationModel,
217248
sys::PSY.System,
@@ -231,6 +262,7 @@ function _add_model_to_event_map!(
231262
Dict{Base.UUID, Dict{DataType, Set{String}}}()
232263
event_model.attribute_device_map[model_name]
233264
for event in PSY.get_supplemental_attributes(event_type, sys)
265+
_validate_event_timeseries_data(sys, event, event_model)
234266
event_uuid = PSY.IS.get_uuid(event)
235267
@debug "Attaching $event_uuid to $model_name"
236268
devices_with_attribute = PSY.get_components(sys, event)

0 commit comments

Comments
 (0)