void IterativeLevelSetSolver2::extrapolate( const FaceCenteredGrid2& input, const ScalarField2& sdf, double maxDistance, FaceCenteredGrid2* output) { JET_THROW_INVALID_ARG_IF(!input.hasSameShape(*output)); const Vector2D gridSpacing = input.gridSpacing(); auto u = input.uConstAccessor(); auto uPos = input.uPosition(); Array2<double> sdfAtU(u.size()); input.parallelForEachUIndex([&](size_t i, size_t j) { sdfAtU(i, j) = sdf.sample(uPos(i, j)); }); extrapolate( u, sdfAtU, gridSpacing, maxDistance, output->uAccessor()); auto v = input.vConstAccessor(); auto vPos = input.vPosition(); Array2<double> sdfAtV(v.size()); input.parallelForEachVIndex([&](size_t i, size_t j) { sdfAtV(i, j) = sdf.sample(vPos(i, j)); }); extrapolate( v, sdfAtV, gridSpacing, maxDistance, output->vAccessor()); }
void IterativeLevelSetSolver2::extrapolate( const CollocatedVectorGrid2& input, const ScalarField2& sdf, double maxDistance, CollocatedVectorGrid2* output) { JET_THROW_INVALID_ARG_IF(!input.hasSameShape(*output)); Array2<double> sdfGrid(input.dataSize()); auto pos = input.dataPosition(); sdfGrid.parallelForEachIndex([&](size_t i, size_t j) { sdfGrid(i, j) = sdf.sample(pos(i, j)); }); const Vector2D gridSpacing = input.gridSpacing(); Array2<double> u(input.dataSize()); Array2<double> u0(input.dataSize()); Array2<double> v(input.dataSize()); Array2<double> v0(input.dataSize()); input.parallelForEachDataPointIndex([&](size_t i, size_t j) { u(i, j) = input(i, j).x; v(i, j) = input(i, j).y; }); extrapolate( u, sdfGrid.constAccessor(), gridSpacing, maxDistance, u0); extrapolate( v, sdfGrid.constAccessor(), gridSpacing, maxDistance, v0); output->parallelForEachDataPointIndex([&](size_t i, size_t j) { (*output)(i, j).x = u(i, j); (*output)(i, j).y = v(i, j); }); }
void IterativeLevelSetSolver2::extrapolate( const ScalarGrid2& input, const ScalarField2& sdf, double maxDistance, ScalarGrid2* output) { JET_THROW_INVALID_ARG_IF(!input.hasSameShape(*output)); Array2<double> sdfGrid(input.dataSize()); auto pos = input.dataPosition(); sdfGrid.parallelForEachIndex([&](size_t i, size_t j) { sdfGrid(i, j) = sdf.sample(pos(i, j)); }); extrapolate( input.constDataAccessor(), sdfGrid.constAccessor(), input.gridSpacing(), maxDistance, output->dataAccessor()); }
void GridFractionalSinglePhasePressureSolver2::buildWeights( const FaceCenteredGrid2& input, const ScalarField2& boundarySdf, const VectorField2& boundaryVelocity, const ScalarField2& fluidSdf) { auto size = input.resolution(); // Build levels size_t maxLevels = 1; if (_mgSystemSolver != nullptr) { maxLevels = _mgSystemSolver->params().maxNumberOfLevels; } FdmMgUtils2::resizeArrayWithFinest(size, maxLevels, &_fluidSdf); _uWeights.resize(_fluidSdf.size()); _vWeights.resize(_fluidSdf.size()); for (size_t l = 0; l < _fluidSdf.size(); ++l) { _uWeights[l].resize(_fluidSdf[l].size() + Size2(1, 0)); _vWeights[l].resize(_fluidSdf[l].size() + Size2(0, 1)); } // Build top-level grids auto cellPos = input.cellCenterPosition(); auto uPos = input.uPosition(); auto vPos = input.vPosition(); _boundaryVel = boundaryVelocity.sampler(); Vector2D h = input.gridSpacing(); _fluidSdf[0].parallelForEachIndex([&](size_t i, size_t j) { _fluidSdf[0](i, j) = static_cast<float>(fluidSdf.sample(cellPos(i, j))); }); _uWeights[0].parallelForEachIndex([&](size_t i, size_t j) { Vector2D pt = uPos(i, j); double phi0 = boundarySdf.sample(pt - Vector2D(0.5 * h.x, 0.0)); double phi1 = boundarySdf.sample(pt + Vector2D(0.5 * h.x, 0.0)); double frac = fractionInsideSdf(phi0, phi1); double weight = clamp(1.0 - frac, 0.0, 1.0); // Clamp non-zero weight to kMinWeight. Having nearly-zero element // in the matrix can be an issue. if (weight < kMinWeight && weight > 0.0) { weight = kMinWeight; } _uWeights[0](i, j) = static_cast<float>(weight); }); _vWeights[0].parallelForEachIndex([&](size_t i, size_t j) { Vector2D pt = vPos(i, j); double phi0 = boundarySdf.sample(pt - Vector2D(0.0, 0.5 * h.y)); double phi1 = boundarySdf.sample(pt + Vector2D(0.0, 0.5 * h.y)); double frac = fractionInsideSdf(phi0, phi1); double weight = clamp(1.0 - frac, 0.0, 1.0); // Clamp non-zero weight to kMinWeight. Having nearly-zero element // in the matrix can be an issue. if (weight < kMinWeight && weight > 0.0) { weight = kMinWeight; } _vWeights[0](i, j) = static_cast<float>(weight); }); // Build sub-levels for (size_t l = 1; l < _fluidSdf.size(); ++l) { const auto& finerFluidSdf = _fluidSdf[l - 1]; auto& coarserFluidSdf = _fluidSdf[l]; const auto& finerUWeight = _uWeights[l - 1]; auto& coarserUWeight = _uWeights[l]; const auto& finerVWeight = _vWeights[l - 1]; auto& coarserVWeight = _vWeights[l]; // Fluid SDF restrict(finerFluidSdf, &coarserFluidSdf); restrict(finerUWeight, &coarserUWeight); restrict(finerVWeight, &coarserVWeight); } }