|
| 1 | +# Data Structure |
| 2 | + |
| 3 | +A [`Network`](@ref) contains a list of vertex and edge models along with a graph. |
| 4 | + |
| 5 | +However, in tight numerical loops, it will never access these lists of models directly. |
| 6 | +Instead, the network maintains an internal representation that tracks all symbolic indices, defining the precise ordering of states and parameters in a flat array representation. To optimize performance, especially for heterogeneous networks, the network employs specialized data structures that batch identical models together. |
| 7 | + |
| 8 | +This disconnect between the explicit lists and the internal data structures |
| 9 | +can be confusing. |
| 10 | + |
| 11 | + |
| 12 | +## Flat Parameter and State Arrays |
| 13 | + |
| 14 | +The vertex and edge models may contain metadata, such as initial values for states and parameters. |
| 15 | +Crucially, this metadata is **only** for building and initialization of the |
| 16 | +simulation. |
| 17 | +During actual simulation, the state and parameters are handled as **flat arrays**, i.e., plain `Vector{Float64}` objects. |
| 18 | + |
| 19 | +[`NWState`](@ref) and [`NWParameter`](@ref) serve as wrappers around flat arrays and the [`Network`](@ref) objects, allowing you to inspect and modify those flat arrays by addressing vertices and edges directly. |
| 20 | + |
| 21 | +A typical workflow is: |
| 22 | + |
| 23 | +1. Set default values in the models using the metadata (see [Metadata](@ref)) |
| 24 | +2. Create a network |
| 25 | +3. Generate a state `s = NWState(nw)` which will be prefilled with the default values from the component metadata |
| 26 | +4. Change the values of `s`, i.e., `s.v[1,:x] = 1.0`: This changes the **underlying flat array** but not the metadata of the model |
| 27 | +5. Build a problem with the updated flat arrays using `uflat(s)` and `pflat(s)` |
| 28 | + |
| 29 | +## Accessing Components |
| 30 | +Per default, the models are not copied on Network construction: |
| 31 | + |
| 32 | +```@example data_structure |
| 33 | +using NetworkDynamics # hide |
| 34 | +using Graphs #hide |
| 35 | +include(joinpath(pkgdir(NetworkDynamics), "test", "ComponentLibrary.jl")) # hide |
| 36 | +kuramoto_first = Lib.kuramoto_vertex! # hide |
| 37 | +kuramoto_secnd = Lib.kuramoto_inertia! # hide |
| 38 | +kuramoto_edge = Lib.kuramoto_edge! # hide |
| 39 | +
|
| 40 | +v1 = VertexModel(f=kuramoto_first, sym=[:θ], psym=[:ω], g=1) |
| 41 | +v2 = VertexModel(f=kuramoto_secnd, sym=[:δ, :ω], psym=[:M, :D, :Pm], g=1) |
| 42 | +e = EdgeModel(;g=AntiSymmetric(kuramoto_edge), outsym=[:P], psym=[:K]) |
| 43 | +nw = Network(complete_graph(2), [v1, v2], e) |
| 44 | +``` |
| 45 | +You can access the models using `getindex`/`[]` with `VIndex` or `EIndex`: |
| 46 | +```@example data_structure |
| 47 | +v1 === nw[VIndex(1)] |
| 48 | +``` |
| 49 | +This can be important when changing metadata of components. i.e., both lines below are equivalent: |
| 50 | +```@example data_structure |
| 51 | +set_position!(v1, (1,0)) |
| 52 | +set_position!(nw[VIndex(1)], (1,0)) |
| 53 | +nothing #hide |
| 54 | +``` |
| 55 | + |
| 56 | +!!! note "Aliasing of component models" |
| 57 | + Since components are not copied, multiple entries in vertex and edge lists might point to the same instance of a model. |
| 58 | + ```@example data_structure |
| 59 | + nw = Network(complete_graph(3), [v1,v2,v1], e) |
| 60 | + v1 === nw[VIndex(1)] === nw[VIndex(3)] |
| 61 | + ``` |
| 62 | + Consequently, metadata set for one model might affect another model. |
| 63 | + This behavior can be beneficial for performance reasons. |
| 64 | + To force copying of components, use the `dealias` keyword: |
| 65 | + ```@example data_structure |
| 66 | + nw = Network(complete_graph(3), [v1,v2,v1], e; dealias=true) |
| 67 | + nw[VIndex(1)] === nw[VIndex(3)] # neither of them === v1 |
| 68 | + ``` |
0 commit comments