Generating Data for an ODEProblem

To train a DigitalEcho we need to generate the training data. To generate this data, we simulate the system which can be an ODEProblem or a FMU. In this section, we will demonstrate how to generate data using an ODEProblem for training a DigitalEcho.

We start by setting up our enviornment. We load DataGeneration and OrdinaryDiffEq for defining an ODEProblem.

using DataGeneration
using OrdinaryDiffEq

For this demonstration, we choose a simple Lotka Volterra system. This system is a pair of non-linear differential equations used to describe the dynamics of a biological system. The system has a set of parameters α, β, γ, δ.

\[\frac{du₁}{dt} = \alpha u₁ - \beta u₁u₂\]

\[\frac{du₂}{dt} = \delta u₁u₂ - \gamma u₂\]

ODEProblem with parameters

We define the dynamics in the above equations in a function lotka_volterra.

function lotka_volterra(u, p, t)
    u₁, u₂ = u
    α, β, γ, δ = p
    dx = α * u₁ - β * u₁ * u₂
    dy = δ * u₁ * u₂ - γ * u₂
    [dx, dy]
end
lotka_volterra (generic function with 1 method)

Next we define the initial condition for the states : u₁ and u₂, and the timespan : tspan.

u0 = [1.0, 1.0]
tspan = (0, 12.5)
(0, 12.5)

We define the ODEProblem as:

lv_ode_problem = ODEProblem{false}(lotka_volterra, u0, tspan)
ODEProblem with uType Vector{Float64} and tType Float64. In-place: false
timespan: (0.0, 12.5)
u0: 2-element Vector{Float64}:
 1.0
 1.0

For more detailed examples on defining ODEProblem see: OrdinaryDiffEq.jl. Note one needs to define it with the {false} flag. For generating data, we need to define a ParameterSpace for sampling parameters: α, β, γ, δ. We start by defining the lower bound and upper bound.

param_lb = [1.5, 1.75, 1.5, 1.75]
param_lb = [2.0, 2.25, 2.25, 2.0]
n_samples = 10
10

And then we define the ParameterSpace:

param_space = ParameterSpace(param_lb, param_lb, n_samples; labels = ["α", "β", "γ", "δ"]);

We define the SimulatorConfig with this parameter space:

simconfig = SimulatorConfig(param_space);

And finally to generate the data, we call this SimulatorConfig on our problem. This returns an ExperimentData object that is consumed by DigitalEcho for training.

ed = simconfig(lv_ode_problem);
[ Info: #Processes = 1
[ Info: Simulating samples from worker processes

Additionally we can provide keyword arguments such as alg to the SimulatorConfig object call.

ed = simconfig(lv_ode_problem; alg = Tsit5())
 Number of Trajectories in ExperimentData: 10 
  Basic Statistics for Given Dynamical System's Specifications 
  Number of u0s in the ExperimentData: 2 
  Number of ps in the ExperimentData: 4 
 ╭─────────┬────────────────────────────────────────────────────────────────────╮
│  Field  │                                                                    │
├─────────┼────────────────────────────────────────────────────────────────────┤
│         │  ╭────────────┬──────────────┬──────────────┬────────┬──────────╮  │
│         │  │   Labels   │  LowerBound  │  UpperBound  │  Mean  │  StdDev  │  │
│         │  ├────────────┼──────────────┼──────────────┼────────┼──────────┤  │
│         │  │  states_1  │     1.0      │     1.0      │  1.0   │   0.0    │  │
│   u0s   │  ├────────────┼──────────────┼──────────────┼────────┼──────────┤  │
│         │  │     ⋮      │      ⋮       │      ⋮       │   ⋮    │    ⋮     │  │
│         │  │     ⋮      │      ⋮       │      ⋮       │   ⋮    │    ⋮     │  │
│         │  ├────────────┼──────────────┼──────────────┼────────┼──────────┤  │
│         │  │  states_2  │     1.0      │     1.0      │  1.0   │   0.0    │  │
│         │  ╰────────────┴──────────────┴──────────────┴────────┴──────────╯  │
├─────────┼────────────────────────────────────────────────────────────────────┤
│         │   ╭──────────┬──────────────┬──────────────┬────────┬──────────╮   │
│         │   │  Labels  │  LowerBound  │  UpperBound  │  Mean  │  StdDev  │   │
│         │   ├──────────┼──────────────┼──────────────┼────────┼──────────┤   │
│         │   │    α     │     2.0      │     2.0      │  2.0   │   0.0    │   │
│   ps    │   ├──────────┼──────────────┼──────────────┼────────┼──────────┤   │
│         │   │    ⋮     │      ⋮       │      ⋮       │   ⋮    │    ⋮     │   │
│         │   │    ⋮     │      ⋮       │      ⋮       │   ⋮    │    ⋮     │   │
│         │   ├──────────┼──────────────┼──────────────┼────────┼──────────┤   │
│         │   │    δ     │     2.0      │     2.0      │  2.0   │   0.0    │   │
│         │   ╰──────────┴──────────────┴──────────────┴────────┴──────────╯   │
╰─────────┴────────────────────────────────────────────────────────────────────╯
 Basic Statistics for Given Dynamical System's Continuous Fields 
  Number of states in the ExperimentData: 2 
 ╭──────────┬─────────────────────────────────────────────────────────────────...
──╮...
│  Field   │...
       │...
├──────────┼─────────────────────────────────────────────────────────────────...
──┤...
│          │  ╭────────────┬──────────────┬──────────────┬─────────┬─────────...
│          │  │   Labels   │  LowerBound  │  UpperBound  │  Mean   │  StdDev...
│          │  ├────────────┼──────────────┼──────────────┼─────────┼─────────...
│          │  │  states_1  │    0.951     │     1.3      │  1.096  │  0.129...
│  states  │  ├────────────┼──────────────┼──────────────┼─────────┼─────────...
│          │  │     ⋮      │      ⋮       │      ⋮       │    ⋮    │...
│          │  │     ⋮      │      ⋮       │      ⋮       │    ⋮    │...
│          │  ├────────────┼──────────────┼──────────────┼─────────┼─────────...
│          │  │  states_2  │    0.746     │    1.048     │  0.889  │  0.104...
│          │  ╰────────────┴──────────────┴──────────────┴─────────┴─────────...
╰──────────┴─────────────────────────────────────────────────────────────────...
──╯...

ODEProblem with parameters and inputs

The above system of equations can be modified to use control inputs as:

\[\frac{du₁}{dt} = \alpha u₁ - \beta u₁u₂ + x₁ \]

\[\frac{du₂}{dt} = \delta u₁u₂ - \gamma u₂ - x₂\]

And thus our new function would be:

function lotka_volterra_ctrl(u, x, p, t)
    u₁, u₂ = u
    α, β, γ, δ = p
    x₁, x₂ = x
    dx = α * u₁ - β * u₁ * u₂ + x₁
    dy = δ * u₁ * u₂ - γ * u₂ - x₂
    [dx, dy]
end
lotka_volterra_ctrl (generic function with 1 method)

Now we can define a new ODEProblem for this controlled lotka-volterra system as:

controlled_lv_ode_problem = ODEProblem{false}(lotka_volterra_ctrl, u0, tspan)
ODEProblem with uType Vector{Float64} and tType Float64. In-place: false
timespan: (0.0, 12.5)
u0: 2-element Vector{Float64}:
 1.0
 1.0

Since we have introduced control inputs in this system, lets define a CtrlSpace to sample control functions.

nsamples_ctrl = 10
ctrl_lb = [0.0, 0.0]
ctrl_ub = [0.1, 0.1]
ctrl_func(u, p, t) = [p[1] * sin(t), p[2] * sin(t)]
ctrl_space = CtrlSpace(ctrl_lb, ctrl_ub, ctrl_func, nsamples_ctrl; labels = ["x₁", "x₂"]);

We have previously defined a ParameterSpace, which we will reuse for data generation in this case. So we can define a SimulatorConfig with ParameterSpace as well as CtrlSpace.

simconfig = SimulatorConfig(param_space, ctrl_space)
 Simulator Config with :   CtrlSpace  ParameterSpace
  Statistics for all Spaces  

  2 dimensional CtrlSpace with 10 samples 
 ╭──────────────┬──────────────────────────────────────────────┬──────────────...
─────╮...
│  Space Type  │                  Statistics                  │  Number...
Samples  │...
├──────────────┼──────────────────────────────────────────────┼──────────────...
─────┤...
│              │  ╭──────────┬──────────────┬──────────────╮  │...
│              │  │  Labels  │  LowerBound  │  UpperBound  │  │...
│              │  ├──────────┼──────────────┼──────────────┤  │...
│              │  │    x₁    │     0.0      │     0.1      │  │...
│  CtrlSpace   │  ├──────────┼──────────────┼──────────────┤  │...
│              │  │    ⋮     │      ⋮       │      ⋮       │  │...
│              │  │    ⋮     │      ⋮       │      ⋮       │  │...
│              │  ├──────────┼──────────────┼──────────────┤  │...
│              │  │    x₂    │     0.0      │     0.1      │  │...
│              │  ╰──────────┴──────────────┴──────────────╯  │...
╰──────────────┴──────────────────────────────────────────────┴──────────────...
─────╯...
 4 dimensional ParameterSpace with 10 samples 
 ╭──────────────────┬──────────────────────────────────────────────┬──────────...
─────────╮...
│    Space Type    │                  Statistics                  │  Number...
of Samples  │...
├──────────────────┼──────────────────────────────────────────────┼──────────...
─────────┤...
│                  │  ╭──────────┬──────────────┬──────────────╮  │...
│                  │  │  Labels  │  LowerBound  │  UpperBound  │  │...
│                  │  ├──────────┼──────────────┼──────────────┤  │...
│                  │  │    α     │     2.0      │     2.0      │  │...
│  ParameterSpace  │  ├──────────┼──────────────┼──────────────┤  │...
│                  │  │    ⋮     │      ⋮       │      ⋮       │  │...
│                  │  │    ⋮     │      ⋮       │      ⋮       │  │...
│                  │  ├──────────┼──────────────┼──────────────┤  │...
│                  │  │    δ     │     2.0      │     2.0      │  │...
│                  │  ╰──────────┴──────────────┴──────────────╯  │...
╰──────────────────┴──────────────────────────────────────────────┴──────────...
─────────╯...

Similar to the previous example, we can generate the ExperimentData by calling the SimulatorConfig on our controlled_lv_ode_problem.

ed_ctrl = simconfig(controlled_lv_ode_problem)
 Number of Trajectories in ExperimentData: 100 
  Basic Statistics for Given Dynamical System's Specifications 
  Number of u0s in the ExperimentData: 2 
  Number of ps in the ExperimentData: 4 
 ╭─────────┬────────────────────────────────────────────────────────────────────╮
│  Field  │                                                                    │
├─────────┼────────────────────────────────────────────────────────────────────┤
│         │  ╭────────────┬──────────────┬──────────────┬────────┬──────────╮  │
│         │  │   Labels   │  LowerBound  │  UpperBound  │  Mean  │  StdDev  │  │
│         │  ├────────────┼──────────────┼──────────────┼────────┼──────────┤  │
│         │  │  states_1  │     1.0      │     1.0      │  1.0   │   0.0    │  │
│   u0s   │  ├────────────┼──────────────┼──────────────┼────────┼──────────┤  │
│         │  │     ⋮      │      ⋮       │      ⋮       │   ⋮    │    ⋮     │  │
│         │  │     ⋮      │      ⋮       │      ⋮       │   ⋮    │    ⋮     │  │
│         │  ├────────────┼──────────────┼──────────────┼────────┼──────────┤  │
│         │  │  states_2  │     1.0      │     1.0      │  1.0   │   0.0    │  │
│         │  ╰────────────┴──────────────┴──────────────┴────────┴──────────╯  │
├─────────┼────────────────────────────────────────────────────────────────────┤
│         │   ╭──────────┬──────────────┬──────────────┬────────┬──────────╮   │
│         │   │  Labels  │  LowerBound  │  UpperBound  │  Mean  │  StdDev  │   │
│         │   ├──────────┼──────────────┼──────────────┼────────┼──────────┤   │
│         │   │    α     │     2.0      │     2.0      │  2.0   │   0.0    │   │
│   ps    │   ├──────────┼──────────────┼──────────────┼────────┼──────────┤   │
│         │   │    ⋮     │      ⋮       │      ⋮       │   ⋮    │    ⋮     │   │
│         │   │    ⋮     │      ⋮       │      ⋮       │   ⋮    │    ⋮     │   │
│         │   ├──────────┼──────────────┼──────────────┼────────┼──────────┤   │
│         │   │    δ     │     2.0      │     2.0      │  2.0   │   0.0    │   │
│         │   ╰──────────┴──────────────┴──────────────┴────────┴──────────╯   │
╰─────────┴────────────────────────────────────────────────────────────────────╯
 Basic Statistics for Given Dynamical System's Continuous Fields 
  Number of states in the ExperimentData: 2 
  Number of controls in the ExperimentData: 2 
 ╭────────────┬───────────────────────────────────────────────────────────────...
────╮...
│   Field    │...
         │...
├────────────┼───────────────────────────────────────────────────────────────...
────┤...
│            │  ╭────────────┬──────────────┬──────────────┬─────────┬───────...
│            │  │   Labels   │  LowerBound  │  UpperBound  │  Mean   │...
│            │  ├────────────┼──────────────┼──────────────┼─────────┼───────...
│            │  │  states_1  │    0.887     │     1.43     │  1.096  │...
│   states   │  ├────────────┼──────────────┼──────────────┼─────────┼───────...
│            │  │     ⋮      │      ⋮       │      ⋮       │    ⋮    │...
│            │  │     ⋮      │      ⋮       │      ⋮       │    ⋮    │...
│            │  ├────────────┼──────────────┼──────────────┼─────────┼───────...
│            │  │  states_2  │    0.705     │    1.129     │  0.889  │...
│            │  ╰────────────┴──────────────┴──────────────┴─────────┴───────...
├────────────┼───────────────────────────────────────────────────────────────...
────┤...
│            │   ╭──────────┬──────────────┬──────────────┬─────────┬────────...
│            │   │  Labels  │  LowerBound  │  UpperBound  │  Mean   │  StdDev...
│            │   ├──────────┼──────────────┼──────────────┼─────────┼────────...
│            │   │    x₁    │    -0.093    │    0.094     │  0.003  │  0.036...
│  controls  │   ├──────────┼──────────────┼──────────────┼─────────┼────────...
│            │   │    ⋮     │      ⋮       │      ⋮       │    ⋮    │...
│            │   │    ⋮     │      ⋮       │      ⋮       │    ⋮    │...
│            │   ├──────────┼──────────────┼──────────────┼─────────┼────────...
│            │   │    x₂    │    -0.095    │    0.097     │  0.004  │  0.041...
│            │   ╰──────────┴──────────────┴──────────────┴─────────┴────────...
╰────────────┴───────────────────────────────────────────────────────────────...
────╯...

Parallelization

The Data Generation supports distributed computing via multiple processes. To enable multi-processing using processes, we need to load Distributed.

using Distributed

We add processes using addprocs. For more detailed understanding about distributed computing see: Distributed.jl.

addprocs(2, exeflags = ["--project=."])

We need to load DataGeneration module of JuliaSimSurrogates on all the processes.

@everywhere using DataGeneration

We need to use @everywhere to define functions on these added processes.

@everywhere function lotka_volterra_ctrl(u, x, p, t)
    u₁, u₂ = u
    α, β, γ, δ = p
    x₁, x₂ = x
    dx = α * u₁ - β * u₁ * u₂ + x₁
    dy = δ * u₁ * u₂ - γ * u₂ - x₂
    [dx, dy]
end

@everywhere ctrl_func(u, p, t) = [p[1] * sin(t), p[2] * sin(t)]

Once we have defined the necessary functions on these processes, we can take advantage of multi-processing for data generation.

ed_ctrl = simconfig(controlled_lv_ode_problem)
 Number of Trajectories in ExperimentData: 100 
  Basic Statistics for Given Dynamical System's Specifications 
  Number of u0s in the ExperimentData: 2 
  Number of ps in the ExperimentData: 4 
 ╭─────────┬────────────────────────────────────────────────────────────────────╮
│  Field  │                                                                    │
├─────────┼────────────────────────────────────────────────────────────────────┤
│         │  ╭────────────┬──────────────┬──────────────┬────────┬──────────╮  │
│         │  │   Labels   │  LowerBound  │  UpperBound  │  Mean  │  StdDev  │  │
│         │  ├────────────┼──────────────┼──────────────┼────────┼──────────┤  │
│         │  │  states_1  │     1.0      │     1.0      │  1.0   │   0.0    │  │
│   u0s   │  ├────────────┼──────────────┼──────────────┼────────┼──────────┤  │
│         │  │     ⋮      │      ⋮       │      ⋮       │   ⋮    │    ⋮     │  │
│         │  │     ⋮      │      ⋮       │      ⋮       │   ⋮    │    ⋮     │  │
│         │  ├────────────┼──────────────┼──────────────┼────────┼──────────┤  │
│         │  │  states_2  │     1.0      │     1.0      │  1.0   │   0.0    │  │
│         │  ╰────────────┴──────────────┴──────────────┴────────┴──────────╯  │
├─────────┼────────────────────────────────────────────────────────────────────┤
│         │   ╭──────────┬──────────────┬──────────────┬────────┬──────────╮   │
│         │   │  Labels  │  LowerBound  │  UpperBound  │  Mean  │  StdDev  │   │
│         │   ├──────────┼──────────────┼──────────────┼────────┼──────────┤   │
│         │   │    α     │     2.0      │     2.0      │  2.0   │   0.0    │   │
│   ps    │   ├──────────┼──────────────┼──────────────┼────────┼──────────┤   │
│         │   │    ⋮     │      ⋮       │      ⋮       │   ⋮    │    ⋮     │   │
│         │   │    ⋮     │      ⋮       │      ⋮       │   ⋮    │    ⋮     │   │
│         │   ├──────────┼──────────────┼──────────────┼────────┼──────────┤   │
│         │   │    δ     │     2.0      │     2.0      │  2.0   │   0.0    │   │
│         │   ╰──────────┴──────────────┴──────────────┴────────┴──────────╯   │
╰─────────┴────────────────────────────────────────────────────────────────────╯
 Basic Statistics for Given Dynamical System's Continuous Fields 
  Number of states in the ExperimentData: 2 
  Number of controls in the ExperimentData: 2 
 ╭────────────┬───────────────────────────────────────────────────────────────...
────╮...
│   Field    │...
         │...
├────────────┼───────────────────────────────────────────────────────────────...
────┤...
│            │  ╭────────────┬──────────────┬──────────────┬─────────┬───────...
│            │  │   Labels   │  LowerBound  │  UpperBound  │  Mean   │...
│            │  ├────────────┼──────────────┼──────────────┼─────────┼───────...
│            │  │  states_1  │    0.887     │     1.43     │  1.096  │...
│   states   │  ├────────────┼──────────────┼──────────────┼─────────┼───────...
│            │  │     ⋮      │      ⋮       │      ⋮       │    ⋮    │...
│            │  │     ⋮      │      ⋮       │      ⋮       │    ⋮    │...
│            │  ├────────────┼──────────────┼──────────────┼─────────┼───────...
│            │  │  states_2  │    0.705     │    1.129     │  0.889  │...
│            │  ╰────────────┴──────────────┴──────────────┴─────────┴───────...
├────────────┼───────────────────────────────────────────────────────────────...
────┤...
│            │   ╭──────────┬──────────────┬──────────────┬─────────┬────────...
│            │   │  Labels  │  LowerBound  │  UpperBound  │  Mean   │  StdDev...
│            │   ├──────────┼──────────────┼──────────────┼─────────┼────────...
│            │   │    x₁    │    -0.093    │    0.094     │  0.003  │  0.036...
│  controls  │   ├──────────┼──────────────┼──────────────┼─────────┼────────...
│            │   │    ⋮     │      ⋮       │      ⋮       │    ⋮    │...
│            │   │    ⋮     │      ⋮       │      ⋮       │    ⋮    │...
│            │   ├──────────┼──────────────┼──────────────┼─────────┼────────...
│            │   │    x₂    │    -0.095    │    0.097     │  0.004  │  0.041...
│            │   ╰──────────┴──────────────┴──────────────┴─────────┴────────...
╰────────────┴───────────────────────────────────────────────────────────────...
────╯...