Skip to content

Commit 6dd64ff

Browse files
committed
update cascading failure script
1 parent 0f12878 commit 6dd64ff

File tree

1 file changed

+39
-31
lines changed

1 file changed

+39
-31
lines changed

docs/examples/cascading_failure.jl

Lines changed: 39 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -83,17 +83,20 @@ set_default!(nw, VIndex(5, :P_ref), 1.5) # generator
8383
nothing #hide #md
8484

8585
#=
86-
We can use `find_fixpoint` to find a valid initial condition of the network
86+
We can use `find_fixpoint` to find a valid initial condition of the network.
87+
We also use `set_defaults!` to overwirte all the default values for states and parameters
88+
with the one of the fixpoint, this means that we can allways re-extract this setpoint by
89+
using `u0 = NWState(nw)`.
8790
=#
8891
u0 = find_fixpoint(nw)
89-
set_defaults!(nw, u0) # overwrite the default values with the fixpoint values
92+
set_defaults!(nw, u0)
9093
nothing #hide #md
9194

9295
#=
9396
## Component-based Callbacks
9497
9598
For the component based callback we need to define a condtion and an affect.
96-
Both functions take trhee inputs:
99+
Both functions take three inputs:
97100
- the actual function `f`
98101
- the states which to be accessed `sym`
99102
- the parameters to be accessed `psym`
@@ -119,38 +122,45 @@ nothing #hide #md
119122
#=
120123
The system starts at a steady state.
121124
In order to see any dynamic, we need to fail a first line intentionally.
122-
For that we define a PresetTimecallback from DiffEqCallbacks library:
125+
For that we use a [`PresetTimeComponentCallback`](@ref), which triggers an
126+
`ComponentAffect` at a given time. We can reuse the previously defined component
127+
affect for that and just add it to line number 5 at time 1.0.
123128
=#
124-
trip_first_cb = PresetTimeCallback(1.0, integrator -> begin
125-
@info "Trip initial line 5 at t=$(integrator.t)"
126-
p = NWParameter(integrator)
127-
p.e[5,:K] = 0
128-
auto_dt_reset!(integrator)
129-
save_parameters!(integrator)
130-
end)
129+
trip_first_cb = PresetTimeComponentCallback(1.0, affect)
130+
add_callback!(nw[EIndex(5)], trip_first_cb)
131131
nothing
132-
133132
#=
134-
133+
When we inspect the edge model for 5 no, we see that we've registered 2 callbacks:
135134
=#
135+
nw[EIndex(5)]
136136

137+
#=
138+
Now we can simulate the network. We use [`get_callbacks(::Networl)`](@ref)
139+
to generate a callback set for the whole network which represents all of the individual
140+
component callbacks.
141+
=#
137142
u0 = NWState(nw)
138143
network_cb = get_callbacks(nw)
139-
all_cb = CallbackSet(network_cb, trip_first_cb)
140-
prob = ODEProblem(nw, uflat(u0), (0, 6), pflat(u0); callback=all_cb)
144+
prob = ODEProblem(nw, uflat(u0), (0, 6), pflat(u0); callback=network_cb)
141145
sol = solve(prob, Tsit5());
142146
nothing #hide #md
143147

144148
#=
145-
Lastly we can plot the power on all of the powerlines:
149+
Lastly we plot the power flow on all lines using the [`eidxs`](@ref) function to generate the
150+
symbolic indices for the states of interest:
146151
=#
147152
plot(sol; idxs=eidxs(sol, :, :P))
148153

149154
#=
150155
## System wide Callbacks
151156
152-
#
157+
The above solution relies on the `ComponentCallback` features of
158+
NetworkDyanmics. The "low-level" API would be to use `VectorContinousCallback`
159+
and `PresetTimeCallback` directly to achieve the same effect, essentially doing
160+
manually what [`get_callbacks(::Network)`](@ref) is doing for us.
153161
162+
While not necessary in this case, this method offers more flexiblity then the
163+
component based appraoch.
154164
155165
In order to implement the line failures, we need to create a `VectorContinousCallback`.
156166
In the callback, we compare the current flow on the line with the limit. If the limit is reached,
@@ -218,28 +228,26 @@ We can combine affect and condition to form the callback.
218228
trip_cb = VectorContinuousCallback(condition, affect!, ne(g));
219229

220230
#=
221-
However, there is another component missing. If we look at the powerflow on the
222-
lines in the initial steady state
223-
=#
224-
u0.e[:, :P]
225-
#=
231+
Similarily to before, we need to generate a initial perturbation by failing one line
232+
using a `PresetTimeCallback`.
226233
We see that every flow is below the trip value 1.0. Therefor we need to add a distrubance
227234
to the network. We do this by manually disabeling line 5 at time 1.
228235
=#
229236
trip_first_cb = PresetTimeCallback(1.0, integrator->affect!(integrator, 5));
230237

231238
#=
232-
With those components, we can create the problem and solve it.
239+
Now we are set for solving the system again. This time we create our own callback
240+
set by combining both Callbacks manually.
233241
=#
234-
235-
prob = ODEProblem(nw, uflat(u0), (0,6), copy(pflat(p));
236-
callback=CallbackSet(trip_cb, trip_first_cb))
242+
u0 = NWState(nw)
243+
cbset = CallbackSet(trip_cb, trip_first_cb)
244+
prob = ODEProblem(nw, uflat(u0), (0,6), pflat(u0); callback=cbset)
237245
Main.test_execution_styles(prob) # testing all ex styles #src
238-
sol = solve(prob, Tsit5());
246+
sol2 = solve(prob, Tsit5());
239247
## we want to test the reconstruction of the observables # hide
240-
@test all(!iszero, sol(sol.t; idxs=eidxs(sol,:,:P))[begin]) # hide
241-
@test all(iszero, sol(sol.t; idxs=eidxs(sol,:,:P))[end][[1:5...,7]]) # hide
248+
@test all(!iszero, sol2(sol2.t; idxs=eidxs(sol2,:,:P))[begin]) # hide
249+
@test all(iszero, sol2(sol2.t; idxs=eidxs(sol2,:,:P))[end][[1:5...,7]]) # hide
242250
nothing #hide
243251

244-
# Through the magic of symbolic indexing we can plot the power flows on all lines:
245-
plot(sol; idxs=eidxs(sol,:,:P))
252+
# Then again we plot the solution:
253+
plot(sol2; idxs=eidxs(sol2,:,:P))

0 commit comments

Comments
 (0)