# Nested struct as state variable in DifferentialEquations

**URL:** <https://discourse.julialang.org/t/nested-struct-as-state-variable-in-differentialequations/88583>\
**Category:** Modelling & Simulations\
**Created:** [October 11, 2022, 4:16pm UTC](https://discourse.julialang.org/t/nested-struct-as-state-variable-in-differentialequations/88583 "2022-10-11T16:16:23Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![maxkapur](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/maxkapur/32/21208_2.png) [@maxkapur](https://discourse.julialang.org/u/maxkapur)\
**Post date:** [October 11, 2022, 4:16pm UTC](https://discourse.julialang.org/t/nested-struct-as-state-variable-in-differentialequations/88583/1 "2022-10-11T16:16:23Z")

</div>

I’m learning to use the DifferentialEquations ecosystem, and my goal is to simulate dynamic systems in which the state variable is a custom struct.

In the simplest case, my state variable is just the x and y coordinates of a particle in space, as in the following example:

```julia
using DifferentialEquations

# State variable: A point in Cartesian space
mutable struct Point2D{T}
    x::T
    y::T
end

function f!(du::Point2D, u::Point2D, _, __)
    du.x = u.x + 0.1u.y
    du.y = -0.2u.x + u.y
end

let u0 = Point2D(25.0, 30.0)
    prob = ODEProblem(f!, u0, (0, 100))
    sol = solve(prob, AutoTsit5(Rosenbrock23()))
end

```

Now, if you run this example, you get the following error, because DifferentialEquations doesn’t know how to initialize `du` inside of the solver:

```julia
ERROR: MethodError: no method matching oneunit(::Type{Any})
Closest candidates are:
  oneunit(::Type{Union{Missing, T}}) where T at missing.jl:105
  oneunit(::Type{T}) where T at number.jl:358
  oneunit(::T) where T at number.jl:357

```

The solution, as pointed out by @lmiq [in this other thread of mine](https://discourse.julialang.org/t/feedback-on-a-2d-spring-simulation/88350/10), is to define `Point2D` as a subtype of the abstract type `FieldVector{2, T}` from the `StaticArrays` package. Then it automatically inherits all the algebra necessary for the DE solvers to run. The following example works properly:

> **Same code but with \`using StaticArrays\` and \`Point2D{T} \<: FieldVector{2, T}\`**
>
> ```julia
> using DifferentialEquations
> using StaticArrays
> 
> # State variable: A point in Cartesian space
> mutable struct Point2D{T} <: FieldVector{2, T}
> x::T
> y::T
> end
> 
> function f!(du::Point2D, u::Point2D, _, __)
> du.x = u.x + 0.1u.y
> du.y = -0.2u.x + u.y
> end
> 
> let u0 = Point2D(25.0, 30.0)
> prob = ODEProblem(f!, u0, (0, 100))
> sol = solve(prob, AutoTsit5(Rosenbrock23()))
> end
> 
> ```

My question is, essentially, **how do I extend this approach for cases where my state variable is not a simple field vector/matrix/array**?

For example, consider the following code, in which the state variable is a particle with both a position and a velocity, which themselves are given by `Point2D` structs:

> **Example where state variable is \`PointWithVelocity{T}\` having fields \`pos::Point2D{T}\` and \`vel::Point2D{T}\`**
>
> ```julia
> using DifferentialEquations
> using StaticArrays
> 
> mutable struct Point2D{T} <: FieldVector{2, T}
> x::T
> y::T
> end
> 
> # State variable: A point in Cartesian space and its velocity
> # I want to be able to access fields by name, e.g. p.pos.x
> mutable struct PointWithVelocity{T} # <: WhatGoesHere?{T}
> pos::Point2D{T}
> vel::Point2D{T}
> end
> 
> function g!(du::PointWithVelocity, u::PointWithVelocity, _, __)
> du.pos.x = u.vel.x
> du.pos.y = u.vel.y
> du.vel.x = u.vel.x
> du.vel.y = u.vel.y - 9.8
> end
> 
> let u0 = PointWithVelocity(
> Point2D(25.0, 30.0),
> Point2D(4.0, 0.0)
> )
> prob = ODEProblem(g!, u0, (0, 100))
> sol = solve(prob, AutoTsit5(Rosenbrock23()))
> end
> 
> ```

Running this example produces the same `no method matching oneunit(::Type{Any})` error as above.

Needless to say, inheriting from `FieldMatrix{2, 2, T}` does not work (and even if it did, this wouldn’t really solve my larger problem because not all of the situations I want to model have a “rectangular” state space that can be arranged as the entries of a matrix):

> **Same code but with \`PointWithVelocity{T} \<: FieldMatrix{2, 2, T}\`; produces a \`BoundsError\`**
>
> ```julia
> using DifferentialEquations
> using StaticArrays
> 
> mutable struct Point2D{T} <: FieldVector{2, T}
> x::T
> y::T
> end
> 
> mutable struct PointWithVelocity{T} <: FieldMatrix{2, 2, T}
> pos::Point2D{T}
> vel::Point2D{T}
> end
> 
> function g!(du::PointWithVelocity, u::PointWithVelocity, _, __)
> du.pos.x = u.vel.x
> du.pos.y = u.vel.y
> du.vel.x = u.vel.x
> du.vel.y = u.vel.y - 9.8
> end
> 
> let u0 = PointWithVelocity(
> Point2D(25.0, 30.0),
> Point2D(4.0, 0.0)
> )
> prob = ODEProblem(g!, u0, (0, 100))
> sol = solve(prob, AutoTsit5(Rosenbrock23()))
> end
> 
> ```
> 
> yields
> 
> ```julia
> ERROR: BoundsError: attempt to access 2×2 PointWithVelocity{Float64} with indices SOneTo(2)×SOneTo(2) at index [3]
> 
> ```

As a workaround, you can use

```julia
mutable struct PointWithVelocity{T} <: FieldVector{4, T}
    pos_x::T
    pos_y::T
    vel_x::T
    vel_y::T
end

```

but this approach does not scale well to a more complicated system where you have multiple particles, etc.

What’s the best way to use nested structs as the state variable in DifferentialEquations? Is this a wrongheaded approach?

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [October 11, 2022, 4:18pm UTC](https://discourse.julialang.org/t/nested-struct-as-state-variable-in-differentialequations/88583/2 "2022-10-11T16:18:44Z")

</div>

> [@maxkapur](#):
>
> What’s the best way to use nested structs as the state variable in DifferentialEquations?

> **[GitHub - jonniedie/ComponentArrays.jl: Arrays with arbitrarily nested named...](https://github.com/jonniedie/ComponentArrays.jl)**
>
> Arrays with arbitrarily nested named components. Contribute to jonniedie/ComponentArrays.jl development by creating an account on GitHub.

That’s the best way.

The key is you need to define enough of the array interface for it to “work”. ComponentArrays is probably the nicest structure for this, and is designed to work without overhead of just using a flat array.

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [October 11, 2022, 4:19pm UTC](https://discourse.julialang.org/t/nested-struct-as-state-variable-in-differentialequations/88583/3 "2022-10-11T16:19:59Z")

</div>

The other thing is to figure out if this is a concern of representation or computation. Are you building a hierarchy to model, or is to achieve some performance end? The two can be different. In that sense, using a symbolic modeling system like ModelingToolkit.jl could be useful to build and interact with a hierarchical model, but without enforcing such a constraint on the computed structure.

[https://mtk.sciml.ai/dev/](https://mtk.sciml.ai/dev/)

---

<div class="post-metadata">

**Author:** ![maxkapur](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/maxkapur/32/21208_2.png) [@maxkapur](https://discourse.julialang.org/u/maxkapur)\
**Post date:** [October 11, 2022, 6:45pm UTC](https://discourse.julialang.org/t/nested-struct-as-state-variable-in-differentialequations/88583/4 "2022-10-11T18:45:49Z")

</div>

Thank you. ComponentArrays.jl is quite slick indeed. Would be neat if it could use StaticArrays.jl as a backend to achieve similar performance to a flat static array (or does this matter?).

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [October 11, 2022, 6:53pm UTC](https://discourse.julialang.org/t/nested-struct-as-state-variable-in-differentialequations/88583/5 "2022-10-11T18:53:52Z")

</div>

> **[GitHub - SciML/LabelledArrays.jl: Arrays which also have a label for each...](https://github.com/SciML/LabelledArrays.jl)**
>
> Arrays which also have a label for each element for easy scientific machine learning (SciML) - GitHub - SciML/LabelledArrays.jl: Arrays which also have a label for each element for easy scientific ...

LabelledArrays.jl has SLArray for that. No hierarchy, but it’s not like you can have a huge hierarchy given that static arrays will be less performant by the time you get to about 8 elements.

---

<div class="post-metadata">

**Author:** ![jewh](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jewh/32/28586_2.png) [@jewh](https://discourse.julialang.org/u/jewh)\
**Post date:** [July 24, 2023, 3:06pm UTC](https://discourse.julialang.org/t/nested-struct-as-state-variable-in-differentialequations/88583/6 "2023-07-24T15:06:00Z")

</div>

Would you be able to provide an example of how you’d use ComponentArrays to achieve this, please?

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [July 24, 2023, 4:08pm UTC](https://discourse.julialang.org/t/nested-struct-as-state-variable-in-differentialequations/88583/7 "2023-07-24T16:08:08Z")

</div>

[Neural ODEs with DiffEqFlux · ComponentArrays.jl](https://jonniedie.github.io/ComponentArrays.jl/dev/examples/DiffEqFlux/) is a nice example.

---

<div class="post-metadata">

**Author:** ![jewh](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jewh/32/28586_2.png) [@jewh](https://discourse.julialang.org/u/jewh)\
**Post date:** [August 3, 2023, 8:53am UTC](https://discourse.julialang.org/t/nested-struct-as-state-variable-in-differentialequations/88583/8 "2023-08-03T08:53:41Z")

</div>

Thanks, sorry just saw this
