Hi Jamie,
Indeed, that's a bug that needs fixing. The new LinearSparseFieldInterp needs to make sure the block truly is unallocated before returning the empty value, if not, it should fall back to calling fastValue();
Also, I realize that LinearSparseFieldInterp isn't quite thread safe when using the load cache - it doesn't guarantee that the block data stays in memory while the pointer dereferencing happens. I need to add calls to the manager->incBlockRef.
The solution to the first part should be the following, so if you want to give that a spin it should definitely help.
if (vi < blockSize - 1 && vj < blockSize - 1 && vk < blockSize - 1) {
// Only do work if the block is allocated
const Data_T * const p = field.blockData(bi, bj, bk);
if (p) {
const Data_T * const c111 = p + vi + vj * blockSize + vk * blockSize * blockSize;
const Data_T * const c121 = c111 + blockSize * (c2.y - c1.y);
const Data_T * const c112 = c111 + blockSize * blockSize * (c2.z - c1.z);
const Data_T * const c122 = c112 + blockSize * (c2.y - c1.y);
int xInc = c2.x - c1.x;
return static_cast<Data_T>
(f1.x * (f1.y * (f1.z * *c111 +
f2.z * *c112) +
f2.y * (f1.z * *c121 +
f2.z * *c122)) +
f2.x * (f1.y * (f1.z * *(c111 + xInc) +
f2.z * *(c112 + xInc)) +
f2.y * (f1.z * *(c121 + xInc) +
f2.z * *(c122 + xInc))));
} else if (!field.blockIsAllocated(bi, bj, bk) {
return static_cast<Data_T>(field.getBlockEmptyValue(bi, bj, bk));
}
}
return static_cast<Data_T>
(f1.x * (f1.y * (f1.z * field.fastValue(c1.x, c1.y, c1.z) +
f2.z * field.fastValue(c1.x, c1.y, c2.z)) +
f2.y * (f1.z * field.fastValue(c1.x, c2.y, c1.z) +
f2.z * field.fastValue(c1.x, c2.y, c2.z))) +
f2.x * (f1.y * (f1.z * field.fastValue(c2.x, c1.y, c1.z) +
f2.z * field.fastValue(c2.x, c1.y, c2.z)) +
f2.y * (f1.z * field.fastValue(c2.x, c2.y, c1.z) +
f2.z * field.fastValue(c2.x, c2.y, c2.z))));
I'll make updates for thread safety once I can run it through some tests to verify.
Magnus