How to correctly initialize mutable structures in Callback functions with DifferentialEquations.jl


As part of my ODE problem, I create a mutable struct Event to store data in a readable manner within the Callback framework of DifferentialEquations.jl. I have then implemented an instance Buffer of type Event to continuously track data for a fixed duration already before an event gets detected by a given Callback function. For some reason, I am not able to update the Buffer instance properly within my framework. My code looks like:

#Create new type "Event" with 4 fields
mutable struct Event

The 3-dimensional arrays u,v and θ each contain different properties for a series of [time, x position, y position] respectively.

I initialize the Buffer as zeros arrays and create a function to update the Buffer of fixed size with the latest values from the ode integrator:

#Update Buffer values with new integrator values
function buffer!(integrator,Buffer::Event)

where the function update! is given by:

#Functions to copy old values and add new ones at the end (updating buffer)
function update!(u::Array{Float64,3},v::Array{Float64,2})
    u[1:end-1,:,:] = u[2:end,:,:] #move each value
    u[end,:,:] = v #add new value at the end
function update!(u::Array{Float64,1},v::Float64)
    u[1:end-1] = u[2:end] #move each value
    u[end] = v #add new value at the end

Finally, I use the buffer! function within a condition and affect! function that I pass as a DiscreteCallback.

When I print the output of u,v and θ for the last five timesteps for a single position x=1, y=1 in order to check the buffer update at each iteration, I obtain:

#Iteration 1
"Buffer.u[end-5:end,1,1] = [0.0, 0.0, 0.0, -0.644079, -0.000371415, 0.0230215]"
"Buffer.v[...] = [0.0, 0.0, 0.0, -0.644079, -0.000371415, 0.0230215]"
"Buffer.θ[...] = [0.0, 0.0, 0.0, -0.644079, -0.000371415, 0.0230215]"
#Iteration 2
"Buffer.u[...] = [-0.644079, -0.000371415, 0.0230215, -0.644093, -0.000400668, 0.0242796]"
"Buffer.v[...] = [-0.644079, -0.000371415, 0.0230215, -0.644093, -0.000400668, 0.0242796]"
"Buffer.θ[...] = [-0.644079, -0.000371415, 0.0230215, -0.644093, -0.000400668, 0.0242796]"

What I would like to see is:

#Iteration 1
"Buffer.u[...] = [0.0, 0.0, 0.0, 0.0, 0.0, -0.644079]"
"Buffer.v[...] = [0.0, 0.0, 0.0, 0.0, 0.0, -0.000371415]"
"Buffer.θ[...] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0230215]"
#Iteration 2
"Buffer.u[...] = [0.0, 0.0, 0.0, 0.0, -0.644079, -0.644093]"
"Buffer.v[...] = [0.0, 0.0, 0.0, 0.0, -0.000371415, -0.000400668]"
"Buffer.θ[...] = [0.0, 0.0, 0.0, 0.0, 0.0230215, 0.0242796]"

As you can see, update! copies all three integrator.u arrays [:, :, 1], [:, :, 2] and [:, :, 3] to each field u,v and θ instead of copying them individually to the respective field. The update of Buffer.t works fine and if I just update a single field (u,v or θ) it also works fine. As additional information, my Buffer variable is global to be recognized in the callback function. I use Julia 1.1.1 and I have tried implementations with getfield and setfield! which do not change my issue.

Despite the limited information, I would be thankful for any advice on what I am doing wrong here and how I can address and update the individual fields correctly.


It kinda looks like your Buffer.u and Buffer.v etc are referencing the same array. Exactly, how do you create Buffer?

yes the referencing is the issue. I create Buffer calling the following function:

# size_priorbuffer, d and l are constant values
function initialize_buffer!()
    global Buffer
    init1D = zeros(size_priorbuffer)
    init2D = zeros(size_priorbuffer,d,l)
    Buffer = Event(init1D, init2D, init2D, init2D)

Is there a mistake at this level?

Yes, you need to create three separate init2D. Otherwise you have one array referred to by three names.