void GridForwardEulerDiffusionSolver3::solve(
    const CollocatedVectorGrid3& source,
    double diffusionCoefficient,
    double timeIntervalInSeconds,
    CollocatedVectorGrid3* dest,
    const ScalarField3& boundarySdf,
    const ScalarField3& fluidSdf) {
    auto src = source.constDataAccessor();
    Vector3D h = source.gridSpacing();
    auto pos = source.dataPosition();

    buildMarkers(source.resolution(), pos, boundarySdf, fluidSdf);

    source.parallelForEachDataPointIndex(
        [&](size_t i, size_t j, size_t k) {
            if (_markers(i, j, k) == kFluid) {
                (*dest)(i, j, k)
                    = src(i, j, k)
                    + diffusionCoefficient
                    * timeIntervalInSeconds
                    * laplacian(src, _markers, h, i, j, k);
            } else {
                (*dest)(i, j, k) = source(i, j, k);
            }
        });
}
std::function<Vector3D(const Vector3D&)>
CubicSemiLagrangian3::getVectorSamplerFunc(
    const CollocatedVectorGrid3& source) const {
    auto sourceSampler = CubicArraySampler3<Vector3D, double>(
        source.constDataAccessor(),
        source.gridSpacing(),
        source.dataOrigin());
    return sourceSampler.functor();
}