Unsure why a function isn't assigning a new value to a view

I am writing code that goes through an array and does a calculation on each element, with the results previous calculations being used for future ones.

I have a function that did this one index at a time, step!, and it works fine, but it’s slow.

@views function step!(arr, U, M, dx, dt)
  (Nx, Ny) = size(arr)
  I1 = CartesianIndex(1, 1)
  for i in 2:(Nx-1)
    for j in 2:(Ny-1)
      loc = CartesianIndex(j, i)
      @inbounds calc!(arr[loc-I1:loc+I1], U, M, dx, dt)
    end
  end
end

I then wrote a function to calculate the indices that could be done all at the same time using SIMD, but were dependent on a previous calculation. However, this function doesn’t allocate to arr and I am not sure why.

@views function step_loc!(arr, inds, U, M, dx, dt)
  I1 = CartesianIndex(1, 1)
  for it in inds
    @simd for loc in it
      @inbounds calc!(arr[loc-I1:loc+I1], U, M, dx, dt)
    end
  end
end

I’m wondering what the difference between these two functions is. calc! hasn’t changed, but it assigns as expected in step!,. but not in step_loc!.

calc! has the signature

@views function calc(arr, U, M, dx, dt)

and assigns specifically to arr[5] by

arr[5] = result

Thank you in advance for the help!

Are you sure @views encapsulates the arr[loc-I1:loc+I1] in your inner loop? What happens if you move the @views to that indexing location?

From what you’ve given, it should work. Perhaps there’s a hidden copy in calc! somewhere? Hard to tell without a complete MWE.

I tried this

function step_loc!(arr, inds, U, M, dx, dt)
  I1 = CartesianIndex(1, 1)

  for it in inds
    @simd for loc in it
      @inbounds @views calc(arr[loc-I1:loc+I1], U, M, dx, dt)
    end
  end
end

Did you mean something different?

and, the calc code is the following:

@views function calc!(arr, U, M, dx, dt)
  corner_sum = arr[1] + arr[3] + arr[7] + arr[9]
  edge_sum = arr[2] + arr[4] + arr[6] + arr[8]

  ij = arr[5]

  grad = (2.0 / 3.0) * (edge_sum + 0.25 * corner_sum - 5.0 * ij) / dx / dx

  t1 = ij - ij * ij * ij
  t2 = -U * (1 - ij * ij) * (1 - ij * ij)

  dFdt = grad + t1 + t2

  arr[5] = ij + M * dFdt * dt
end

Hm, that looks fine - what indices are you calculating for inds? What are the exact differences you observe between the two functions - does step_loc! not assign at all? Do you perhaps have a complete example we could run on our end?

function get_diag(idx, arr)
  Ny, _ = size(arr)
  I2Right = CartesianIndex(0, 2)
  I1Up = CartesianIndex(1, 0)
  result = CartesianIndex[]
  index = idx

  while true
    push!(result, index)
    index += I2Right
    index -= I1Up
    all(i -> i > 1 && i < Ny, Tuple(index)) || break
  end

  return result

end

@views function indexes!(x, out)
  Ny, Nx = size(x)
  inds = CartesianIndices(x)
  lin_inds = LinearIndices(x)

  r1 = lin_inds[inds[2, begin+1:end-1]]
  r2 = lin_inds[inds[3, begin+1:end-1]]
  interleaved = inds[[r1 r2]'[:]]

  for i in union(interleaved, 2Ny-1:Ny:(Ny*Nx)-Ny)
    push!(out, get_diag(inds[i], x))
  end

end

@views function process!(arr, inds, U, M, dx, dt)
  I = CartesianIndex(1, 1)
  for locs in inds
    @simd for loc in locs
      @inbounds calc(arr[loc-I:loc+I], U, M, dx, dt)
    end
  end
end

@views function calc(arr, U, M, dx, dt)
  corner_sum = arr[1] + arr[3] + arr[7] + arr[9]
  edge_sum = arr[2] + arr[4] + arr[6] + arr[8]

  ij = arr[5]

  grad = (2.0 / 3.0) * (edge_sum + 0.25 * corner_sum - 5.0 * ij) / dx / dx

  t1 = ij - ij * ij * ij
  t2 = -U * (1 - ij * ij) * (1 - ij * ij)

  dFdt = grad + t1 + t2
  arr[5] = ij + M * dFdt * dt
end

U = -0.5
M = 1.0
dx = 0.5
dt = 0.03
Ny, Nx = 514, 514

result = Vector{CartesianIndex}[]

test_arr = Matrix{Float64}(undef, Ny, Nx)
indexes!(test_arr, result)


  process!(test_arr, result, U, M, dx, dt)

test_arr

I made a minimal example, but this works? test_arr gets assigned in this one.

Looks like the issue was in my get_diag! function! Thanks for all the help, even though it was just my silly mistake.

2 Likes