Skip to content

Commit c544c15

Browse files
authored
Merge pull request #223 from JuliaDynamics/hw/despecialize
despecialize VertexModel/EdgeModel
2 parents 6ffaf5a + 336619f commit c544c15

17 files changed

+197
-184
lines changed

.github/workflows/tests.yml

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ on:
88
concurrency:
99
# Skip intermediate builds: always.
1010
group: ${{ github.workflow }}-${{ github.ref }}
11-
cancel-in-progress: true # allways cancle old runs on new push
11+
cancel-in-progress: true # always cancle old runs on new push
1212
jobs:
1313
test:
1414
name: Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }}
@@ -38,6 +38,28 @@ jobs:
3838
- uses: julia-actions/cache@v2
3939
- uses: julia-actions/julia-buildpkg@v1
4040
- uses: julia-actions/julia-runtest@v1
41+
with:
42+
coverage: false
43+
44+
test-coverage:
45+
name: Test Coverage
46+
runs-on: ubuntu-latest
47+
permissions: # needed to allow julia-actions/cache to proactively delete old caches that it has created
48+
actions: write
49+
contents: read
50+
steps:
51+
- uses: actions/checkout@v4
52+
- uses: julia-actions/setup-julia@v2
53+
with:
54+
version: 1
55+
arch: x64
56+
- uses: julia-actions/cache@v2
57+
- uses: julia-actions/julia-buildpkg@v1
58+
- uses: julia-actions/julia-runtest@v1
59+
env:
60+
JULIA_COVERAGE: true
61+
with:
62+
coverage: true
4163
- uses: julia-actions/julia-processcoverage@v1
4264
- uses: codecov/codecov-action@v4
4365
with:

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ KernelAbstractions = "0.9.18"
5959
LinearAlgebra = "1"
6060
MacroTools = "0.5.15"
6161
Mixers = "0.1.2"
62-
ModelingToolkit = "9.61"
62+
ModelingToolkit = "9.67"
6363
NNlib = "0.9.13"
6464
NonlinearSolve = "4"
6565
Polyester = "0.7.12"

docs/examples/cascading_failure.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -245,8 +245,8 @@ prob = ODEProblem(nw, uflat(u0), (0,6), pflat(u0); callback=cbset)
245245
Main.test_execution_styles(prob) # testing all ex styles #src
246246
sol2 = solve(prob, Tsit5());
247247
## we want to test the reconstruction of the observables # 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
248+
@test all(!iszero, sol2(sol2.t; idxs=eidxs(sol2,:,:P)).u[begin]) # hide
249+
@test all(iszero, sol2(sol2.t; idxs=eidxs(sol2,:,:P)).u[end][[1:5...,7]]) # hide
250250
nothing #hide
251251

252252
# Then again we plot the solution:

ext/MTKExt.jl

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -475,11 +475,9 @@ end
475475

476476
_all_rhs_symbols(eqs) = mapreduce(eq->get_variables(eq.rhs), , eqs, init=Set{Symbolic}())
477477

478-
using PrecompileTools: @setup_workload, @compile_workload
479-
@setup_workload begin
480-
@compile_workload begin
481-
# include("precompile_workload.jl")
482-
end
478+
using PrecompileTools: @compile_workload
479+
@compile_workload begin
480+
include("precompile_workload.jl")
483481
end
484482

485483
end

ext/precompile_workload.jl

Lines changed: 18 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,28 @@
1-
is_precompiling() = ccall(:jl_generating_output, Cint, ()) == 1
2-
31
using NetworkDynamics
42
using ModelingToolkit
53
using ModelingToolkit: t_nounits as t, D_nounits as Dt
64

75
@connector Terminal begin
8-
u_r(t), [description="d-voltage"]
9-
u_i(t), [description="q-voltage"]
10-
i_r(t), [description="d-current", connect=Flow]
11-
i_i(t), [description="q-current", connect=Flow]
6+
u_r(t)
7+
u_i(t)
8+
i_r(t), [connect=Flow]
9+
i_i(t), [connect=Flow]
1210
end
1311
@mtkmodel Swing begin
1412
@components begin
1513
terminal = Terminal()
1614
end
1715
@variables begin
18-
ω(t)=0.0, [description="Rotor frequency"]
19-
θ(t)=0.0, [description="Rotor angle"]
20-
Pel(t), [description="Electrical Power injected into the grid"]
16+
ω(t), [description="Rotor frequency", guess=0]
17+
θ(t), [description="Rotor angle", guess=0]
18+
Pel(t)
2119
end
2220
@parameters begin
23-
M=1, [description="Inertia"]
24-
D=0.1, [description="Damping"]
25-
V=1.0, [description="Voltage magnitude"]
26-
ω_ref=0, [description="Reference frequency"]
27-
Pm, [description="Mechanical Power"]
21+
M=0.005
22+
D=0.1
23+
V, [guess=1]
24+
ω_ref=0
25+
Pm, [description="Mechanical Power", guess=-1]
2826
end
2927
@equations begin
3028
Dt(θ) ~ ω - ω_ref
@@ -36,26 +34,10 @@ end
3634
end
3735
@mtkmodel BusBase begin
3836
@variables begin
39-
u_r(t)=1, [description="bus d-voltage", output=true]
40-
u_i(t)=0, [description="bus q-voltage", output=true]
41-
i_r(t), [description="bus d-current (flowing into bus)", input=true]
42-
i_i(t), [description="bus d-current (flowing into bus)", input=true]
43-
P(t), [description="bus active power (flowing into network)"]
44-
Q(t), [description="bus reactive power (flowing into network)"]
45-
u_mag(t), [description="bus voltage magnitude"]
46-
u_arg(t), [description="bus voltage argument"]
47-
i_mag(t), [description="bus current magnitude"]
48-
i_arg(t), [description="bus current argument"]
49-
ω(t), [description="bus angular frequency"]
50-
end
51-
@equations begin
52-
P ~ u_r * (-i_r) + u_i * (-i_i)
53-
Q ~ u_i * (-i_r) - u_r * (-i_i)
54-
u_mag ~ sqrt(u_r^2 + u_i^2)
55-
u_arg ~ atan(u_i, u_r)
56-
i_mag ~ sqrt(i_r^2 + i_i^2)
57-
i_arg ~ atan(i_i, i_r)
58-
ω ~ Dt(u_arg)
37+
u_r(t)=1.0
38+
u_i(t)=0.0
39+
i_r(t)=1.0
40+
i_i(t)=0.0
5941
end
6042
end
6143
@mtkmodel BusBar begin
@@ -80,10 +62,5 @@ end
8062
end
8163
end
8264
@named swingbus = Bus()
83-
84-
if is_precompiling()
85-
VertexModel(swingbus, [:busbar₊i_r, :busbar₊i_i], [:busbar₊u_r, :busbar₊u_i]; verbose=false)
86-
else
87-
@info "ODEVertex"
88-
@time @eval VertexModel(swingbus, [:busbar₊i_r, :busbar₊i_i], [:busbar₊u_r, :busbar₊u_i]; verbose=false)
89-
end
65+
vm = VertexModel(swingbus, [:busbar₊i_r, :busbar₊i_i], [:busbar₊u_r, :busbar₊u_i]; verbose=false)
66+
NetworkDynamics.initialize_component!(vm; verbose=false)

src/NetworkDynamics.jl

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -125,11 +125,9 @@ function reloadfaces!()
125125
end
126126
# NetworkDynamics.reloadfaces!()
127127

128-
using PrecompileTools: @setup_workload, @compile_workload
129-
@setup_workload begin
130-
@compile_workload begin
131-
# include("precompile_workload.jl")
132-
end
128+
using PrecompileTools: @compile_workload
129+
@compile_workload begin
130+
include("precompile_workload.jl")
133131
end
134132

135133
end

src/callbacks.jl

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ function wrap_component_callbacks(nw)
235235
end
236236
# group the callbacks such that they are in groups which are "batchequal"
237237
# batchequal groups can be wrapped into a single callback
238-
idx_per_type = _find_identical(callbacks, 1:length(components))
238+
idx_per_type = find_identical(callbacks; equality=_batchequal)
239239
batches = []
240240
for typeidx in idx_per_type
241241
batchcomps = components[typeidx]
@@ -251,21 +251,22 @@ function wrap_component_callbacks(nw)
251251
end
252252
return batches
253253
end
254-
function batchequal(a::ContinousComponentCallback, b::ContinousComponentCallback)
255-
batchequal(a.condition, b.condition) || return false
256-
batchequal(a.kwargs, b.kwargs) || return false
254+
_batchequal(a, b) = false
255+
function _batchequal(a::ContinousComponentCallback, b::ContinousComponentCallback)
256+
_batchequal(a.condition, b.condition) || return false
257+
_batchequal(a.kwargs, b.kwargs) || return false
257258
return true
258259
end
259-
function batchequal(a::VectorContinousComponentCallback, b::VectorContinousComponentCallback)
260-
batchequal(a.condition, b.condition) || return false
261-
batchequal(a.kwargs, b.kwargs) || return false
260+
function _batchequal(a::VectorContinousComponentCallback, b::VectorContinousComponentCallback)
261+
_batchequal(a.condition, b.condition) || return false
262+
_batchequal(a.kwargs, b.kwargs) || return false
262263
a.len == b.len || return false
263264
return true
264265
end
265-
function batchequal(a::T, b::T) where {T <: Union{ComponentCondition, ComponentAffect}}
266+
function _batchequal(a::T, b::T) where {T <: Union{ComponentCondition, ComponentAffect}}
266267
typeof(a) == typeof(b)
267268
end
268-
function batchequal(a::NamedTuple, b::NamedTuple)
269+
function _batchequal(a::NamedTuple, b::NamedTuple)
269270
length(a) == length(b) || return false
270271
for (k, v) in a
271272
haskey(b, k) || return false

src/component_functions.jl

Lines changed: 28 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -247,22 +247,22 @@ Directed(s::AbstractVector{<:Symbol}) = AnnotatedSym(Directed, s)
247247

248248
abstract type ComponentModel end
249249

250-
struct VertexModel{F,G,FFT,OF,MM,EX<:Union{Nothing,Vector{<:SymbolicIndex}}} <: ComponentModel
250+
struct VertexModel <: ComponentModel
251251
name::Symbol
252252
# main function
253-
f::F
253+
f::Any
254254
sym::Vector{Symbol}
255-
mass_matrix::MM
255+
mass_matrix::Any
256256
# outputs
257-
g::G
257+
g::Any
258258
outsym::Vector{Symbol}
259-
ff::FFT
259+
ff::FeedForwardType
260260
# parameters, optional input sym and optional external inputs
261261
psym::Vector{Symbol}
262262
insym::Union{Nothing, Vector{Symbol}}
263-
extin::EX
263+
extin::Union{Nothing, Vector{<:SymbolicIndex}}
264264
# observed
265-
obsf::OF
265+
obsf::Any
266266
obssym::Vector{Symbol}
267267
# metadata
268268
symmetadata::Dict{Symbol,Dict{Symbol, Any}}
@@ -299,25 +299,25 @@ Optional Arguments:
299299
300300
All Symbol arguments can be used to set default values, i.e. `psym=[:K=>1, :p]`.
301301
"""
302-
VertexModel(; kwargs...) = _construct_comp(VertexModel, Base.inferencebarrier(kwargs))
303-
VertexModel(v::VertexModel; kwargs...) = _reconstruct_comp(VertexModel, v, Base.inferencebarrier(kwargs))
302+
VertexModel(; kwargs...) = _construct_comp(VertexModel, kwargs)
303+
VertexModel(v::VertexModel; kwargs...) = _reconstruct_comp(VertexModel, v, kwargs)
304304

305-
struct EdgeModel{F,G,FFT,OF,MM,EX<:Union{Nothing,Vector{<:SymbolicIndex}}} <: ComponentModel
305+
struct EdgeModel <: ComponentModel
306306
name::Symbol
307307
# main function
308-
f::F
308+
f::Any
309309
sym::Vector{Symbol}
310-
mass_matrix::MM
310+
mass_matrix::Any
311311
# outputs
312-
g::G
312+
g::Any
313313
outsym::@NamedTuple{src::Vector{Symbol},dst::Vector{Symbol}}
314-
ff::FFT
314+
ff::FeedForwardType
315315
# parameters, optional input sym and optional external inputs
316316
psym::Vector{Symbol}
317317
insym::Union{Nothing, @NamedTuple{src::Vector{Symbol},dst::Vector{Symbol}}}
318-
extin::EX
318+
extin::Union{Nothing, Vector{<:SymbolicIndex}}
319319
# observed
320-
obsf::OF
320+
obsf::Any
321321
obssym::Vector{Symbol}
322322
# metadata
323323
symmetadata::Dict{Symbol,Dict{Symbol, Any}}
@@ -357,8 +357,8 @@ Optional Arguments:
357357
358358
All Symbol arguments can be used to set default values, i.e. `psym=[:K=>1, :p]`.
359359
"""
360-
EdgeModel(; kwargs...) = _construct_comp(EdgeModel, Base.inferencebarrier(kwargs))
361-
EdgeModel(v::EdgeModel; kwargs...) = _reconstruct_comp(EdgeModel, v, Base.inferencebarrier(kwargs))
360+
EdgeModel(; kwargs...) = _construct_comp(EdgeModel, kwargs)
361+
EdgeModel(v::EdgeModel; kwargs...) = _reconstruct_comp(EdgeModel, v, kwargs)
362362

363363
"""
364364
compf(c::ComponentModel)
@@ -576,30 +576,17 @@ Fills up type parameters with `nothing` to ensure `Core.Compiler.isconstType`
576576
for GPU compatibility.
577577
"""
578578
dispatchT(::T) where {T<:ComponentModel} = dispatchT(T)
579-
dispatchT(T::Type{<:VertexModel}) = VertexModel{nothing,nothing,nothing,nothing,nothing,Nothing}
580-
dispatchT(T::Type{<:EdgeModel}) = EdgeModel{nothing,nothing,nothing,nothing,nothing,Nothing}
581-
582-
# TODO: introduce batchequal hash for faster batching of component models
583-
batchequal(a, b) = false
584-
function batchequal(a::ComponentModel, b::ComponentModel)
585-
compf(a) == compf(b) || return false
586-
compg(a) == compg(b) || return false
587-
fftype(a) == fftype(b) || return false
588-
dim(a) == dim(b) || return false
589-
outdim(a) == outdim(b) || return false
590-
pdim(a) == pdim(b) || return false
591-
extdim(a) == extdim(b) || return false
592-
return true
593-
end
579+
dispatchT(T::Type{<:VertexModel}) = VertexModel
580+
dispatchT(T::Type{<:EdgeModel}) = EdgeModel
594581

595582
"""
596583
_construct_comp(::Type{T}, kwargs) where {T}
597584
598585
Internal function to construct a component model from keyword arguments.
599586
Fills up kw arguments with default values and performs sanity checks.
600587
"""
601-
function _construct_comp(::Type{T}, @nospecialize(kwargs)) where {T}
602-
dict = _fill_defaults(T, Base.inferencebarrier(kwargs))
588+
Base.@nospecializeinfer function _construct_comp(::Type{T}, @nospecialize(kwargs)) where {T}
589+
dict = _fill_defaults(T, kwargs)
603590

604591
# check signature of f
605592
# if !_valid_signature(T, dict[:f])
@@ -625,7 +612,7 @@ function _construct_comp(::Type{T}, @nospecialize(kwargs)) where {T}
625612
return c
626613
end
627614

628-
function _reconstruct_comp(::Type{T}, cf::ComponentModel, kwargs) where {T}
615+
Base.@nospecializeinfer function _reconstruct_comp(::Type{T}, cf::ComponentModel, @nospecialize(kwargs)) where {T}
629616
fields = fieldnames(T)
630617
dict = Dict{Symbol, Any}()
631618
for f in fields
@@ -643,7 +630,7 @@ end
643630
Fill up keyword arguments `kwargs` for type T with default values.
644631
Also perfoms sanity check some properties like mass matrix, depth, ...
645632
"""
646-
function _fill_defaults(T, @nospecialize(kwargs))
633+
Base.@nospecializeinfer function _fill_defaults(T, @nospecialize(kwargs))
647634
dict = Dict{Symbol, Any}(kwargs)
648635
allow_output_sym_clash = pop!(dict, :allow_output_sym_clash, false)
649636

@@ -1121,11 +1108,12 @@ function Base.:(==)(cf1::ComponentModel, cf2::ComponentModel)
11211108
typeof(cf1) == typeof(cf2) && equal_fields(cf1, cf2)
11221109
end
11231110

1124-
function compfg(c)
1111+
# force specialization on f, g, fft
1112+
compfg(c) = _compfg(compf(c), compg(c), fftype(c))
1113+
function _compfg(f::F, g::G, fft::FFT) where {F, G, FFT}
11251114
(outs, du, u, ins, p, t) -> begin
1126-
f = compf(c)
11271115
isnothing(f) || f(du, u, ins..., p, t)
1128-
compg(c)(_gargs(fftype(c), outs, du, u, ins, p, t)...)
1116+
g(_gargs(fft, outs, du, u, ins, p, t)...)
11291117
nothing
11301118
end
11311119
end

0 commit comments

Comments
 (0)