This repository has been archived on 2023-10-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
blender-archive/extern/mantaflow/preprocessed/fastmarch.cpp
Sebastián Barschkis 4ff7c5eed6 Mantaflow [Part 1]: Added preprocessed Mantaflow source files
Includes preprocessed Mantaflow source files for both OpenMP and TBB (if OpenMP is not present, TBB files will be used instead).

These files come directly from the Mantaflow repository. Future updates to the core fluid solver will take place by updating the files.

Reviewed By: sergey, mont29

Maniphest Tasks: T59995

Differential Revision: https://developer.blender.org/D3850
2019-12-16 16:27:26 +01:00

1201 lines
31 KiB
C++

// DO NOT EDIT !
// This file is generated using the MantaFlow preprocessor (prep generate).
/******************************************************************************
*
* MantaFlow fluid solver framework
* Copyright 2011 Tobias Pfaff, Nils Thuerey
*
* This program is free software, distributed under the terms of the
* Apache License, Version 2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Fast marching and extrapolation
*
******************************************************************************/
#include "fastmarch.h"
#include "levelset.h"
#include "kernel.h"
#include <algorithm>
using namespace std;
namespace Manta {
template<class COMP, int TDIR>
FastMarch<COMP, TDIR>::FastMarch(const FlagGrid &flags,
Grid<int> &fmFlags,
Grid<Real> &levelset,
Real maxTime,
MACGrid *velTransport)
: mLevelset(levelset), mFlags(flags), mFmFlags(fmFlags)
{
if (velTransport)
mVelTransport.initMarching(velTransport, &flags);
mMaxTime = maxTime * TDIR;
}
// helper for individual components to calculateDistance
template<class COMP, int TDIR>
template<int C>
Real FastMarch<COMP, TDIR>::calcWeights(int &okcnt, int &invcnt, Real *v, const Vec3i &idx)
{
Real val = 0.;
Vec3i idxPlus(idx), idxMinus(idx);
idxPlus[C]++;
idxMinus[C]--;
mWeights[C * 2] = mWeights[C * 2 + 1] = 0.;
if (mFmFlags(idxPlus) == FlagInited) {
// somewhat arbitrary - choose +1 value over -1 ...
val = mLevelset(idxPlus);
v[okcnt] = val;
okcnt++;
mWeights[C * 2] = 1.;
}
else if (mFmFlags(idxMinus) == FlagInited) {
val = mLevelset(idxMinus);
v[okcnt] = val;
okcnt++;
mWeights[C * 2 + 1] = 1.;
}
else {
invcnt++;
}
return val;
}
template<class COMP, int TDIR>
inline Real FastMarch<COMP, TDIR>::calculateDistance(const Vec3i &idx)
{
// int invflag = 0;
int invcnt = 0;
Real v[3];
int okcnt = 0;
Real aVal = calcWeights<0>(okcnt, invcnt, v, idx);
Real bVal = calcWeights<1>(okcnt, invcnt, v, idx);
Real cVal = 0.;
if (mLevelset.is3D())
cVal = calcWeights<2>(okcnt, invcnt, v, idx);
else {
invcnt++;
mWeights[4] = mWeights[5] = 0.;
}
Real ret = InvalidTime();
switch (invcnt) {
case 0: {
// take all values
const Real ca = v[0], cb = v[1], cc = v[2];
const Real csqrt = max(0.,
-2. * (ca * ca + cb * cb - cb * cc + cc * cc - ca * (cb + cc)) + 3);
// clamp to make sure the sqrt is valid
ret = 0.333333 * (ca + cb + cc + TDIR * sqrt(csqrt));
// weights needed for transport (transpTouch)
mWeights[0] *= fabs(ret - ca);
mWeights[1] *= fabs(ret - ca);
mWeights[2] *= fabs(ret - cb);
mWeights[3] *= fabs(ret - cb);
mWeights[4] *= fabs(ret - cc);
mWeights[5] *= fabs(ret - cc);
Real norm = 0.0; // try to force normalization
for (int i = 0; i < 6; i++) {
norm += mWeights[i];
}
norm = 1.0 / norm;
for (int i = 0; i < 6; i++) {
mWeights[i] *= norm;
}
} break;
case 1: {
// take just the 2 ok values
// t=0.5*( a+b+ (2*g*g-(b-a)*(b-a))^0.5)
const Real csqrt = max(0., 2. - (v[1] - v[0]) * (v[1] - v[0]));
// clamp to make sure the sqrt is valid
ret = 0.5 * (v[0] + v[1] + TDIR * sqrt(csqrt));
// weights needed for transport (transpTouch)
mWeights[0] *= fabs(ret - aVal);
mWeights[1] *= fabs(ret - aVal);
mWeights[2] *= fabs(ret - bVal);
mWeights[3] *= fabs(ret - bVal);
mWeights[4] *= fabs(ret - cVal);
mWeights[5] *= fabs(ret - cVal);
Real norm = 0.0; // try to force normalization
for (int i = 0; i < 6; i++) {
norm += mWeights[i];
}
norm = 1.0 / norm;
for (int i = 0; i < 6; i++) {
mWeights[i] *= norm;
}
// */
} break;
case 2: {
// just use the one remaining value
ret = v[0] + (Real)(TDIR); // direction = +- 1
} break;
default:
errMsg("FastMarch :: Invalid invcnt");
break;
}
return ret;
}
template<class COMP, int TDIR>
void FastMarch<COMP, TDIR>::addToList(const Vec3i &p, const Vec3i &src)
{
if (!mLevelset.isInBounds(p, 1))
return;
const IndexInt idx = mLevelset.index(p);
// already known value, value alreay set to valid value? skip cell...
if (mFmFlags[idx] == FlagInited)
return;
// discard by source time now , TODO do instead before calling all addtolists?
Real srct = mLevelset(src);
if (COMP::compare(srct, mMaxTime))
return;
Real ttime = calculateDistance(p);
// remove old entry if larger
bool found = false;
Real oldt = mLevelset[idx];
if (mFmFlags[idx] == FlagIsOnHeap) {
found = true;
// is old time better?
if (COMP::compare(ttime, oldt))
return;
}
// update field
mFmFlags[idx] = FlagIsOnHeap;
mLevelset[idx] = ttime;
// debug info std::cout<<"set "<< idx <<","<< ttime <<"\n";
if (mVelTransport.isInitialized())
mVelTransport.transpTouch(p.x, p.y, p.z, mWeights, ttime);
// the following adds entries to the heap of active cells
// current: (!found) , previous: always add, might lead to duplicate
// entries, but the earlier will be handled earlier, the second one will skip to the
// FlagInited check above
if (!found) {
// add list entry with source value
COMP entry;
entry.p = p;
entry.time = mLevelset[idx];
mHeap.push(entry);
// debug info std::cout<<"push "<< entry.p <<","<< entry.time <<"\n";
}
}
//! Enforce delta_phi = 0 on boundaries
struct SetLevelsetBoundaries : public KernelBase {
SetLevelsetBoundaries(Grid<Real> &phi) : KernelBase(&phi, 0), phi(phi)
{
runMessage();
run();
}
inline void op(int i, int j, int k, Grid<Real> &phi)
{
if (i == 0)
phi(i, j, k) = phi(1, j, k);
if (i == maxX - 1)
phi(i, j, k) = phi(i - 1, j, k);
if (j == 0)
phi(i, j, k) = phi(i, 1, k);
if (j == maxY - 1)
phi(i, j, k) = phi(i, j - 1, k);
if (phi.is3D()) {
if (k == 0)
phi(i, j, k) = phi(i, j, 1);
if (k == maxZ - 1)
phi(i, j, k) = phi(i, j, k - 1);
}
}
inline Grid<Real> &getArg0()
{
return phi;
}
typedef Grid<Real> type0;
void runMessage()
{
debMsg("Executing kernel SetLevelsetBoundaries ", 3);
debMsg("Kernel range"
<< " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
4);
};
void run()
{
const int _maxX = maxX;
const int _maxY = maxY;
for (int k = minZ; k < maxZ; k++)
for (int j = 0; j < _maxY; j++)
for (int i = 0; i < _maxX; i++)
op(i, j, k, phi);
}
Grid<Real> &phi;
};
/*****************************************************************************/
//! Walk...
template<class COMP, int TDIR> void FastMarch<COMP, TDIR>::performMarching()
{
mReheapVal = 0.0;
while (mHeap.size() > 0) {
const COMP &ce = mHeap.top();
Vec3i p = ce.p;
mFmFlags(p) = FlagInited;
mHeap.pop();
// debug info std::cout<<"pop "<< ce.p <<","<< ce.time <<"\n";
addToList(Vec3i(p.x - 1, p.y, p.z), p);
addToList(Vec3i(p.x + 1, p.y, p.z), p);
addToList(Vec3i(p.x, p.y - 1, p.z), p);
addToList(Vec3i(p.x, p.y + 1, p.z), p);
if (mLevelset.is3D()) {
addToList(Vec3i(p.x, p.y, p.z - 1), p);
addToList(Vec3i(p.x, p.y, p.z + 1), p);
}
}
// set boundary for plain array
SetLevelsetBoundaries setls(mLevelset);
setls.getArg0(); // get rid of compiler warning...
}
// explicit instantiation
template class FastMarch<FmHeapEntryIn, -1>;
template class FastMarch<FmHeapEntryOut, +1>;
/*****************************************************************************/
// simpler extrapolation functions (primarily for FLIP)
struct knExtrapolateMACSimple : public KernelBase {
knExtrapolateMACSimple(MACGrid &vel, int distance, Grid<int> &tmp, const int d, const int c)
: KernelBase(&vel, 1), vel(vel), distance(distance), tmp(tmp), d(d), c(c)
{
runMessage();
run();
}
inline void op(int i,
int j,
int k,
MACGrid &vel,
int distance,
Grid<int> &tmp,
const int d,
const int c) const
{
static const Vec3i nb[6] = {Vec3i(1, 0, 0),
Vec3i(-1, 0, 0),
Vec3i(0, 1, 0),
Vec3i(0, -1, 0),
Vec3i(0, 0, 1),
Vec3i(0, 0, -1)};
const int dim = (vel.is3D() ? 3 : 2);
if (tmp(i, j, k) != 0)
return;
// copy from initialized neighbors
Vec3i p(i, j, k);
int nbs = 0;
Real avgVel = 0.;
for (int n = 0; n < 2 * dim; ++n) {
if (tmp(p + nb[n]) == d) {
// vel(p)[c] = (c+1.)*0.1;
avgVel += vel(p + nb[n])[c];
nbs++;
}
}
if (nbs > 0) {
tmp(p) = d + 1;
vel(p)[c] = avgVel / nbs;
}
}
inline MACGrid &getArg0()
{
return vel;
}
typedef MACGrid type0;
inline int &getArg1()
{
return distance;
}
typedef int type1;
inline Grid<int> &getArg2()
{
return tmp;
}
typedef Grid<int> type2;
inline const int &getArg3()
{
return d;
}
typedef int type3;
inline const int &getArg4()
{
return c;
}
typedef int type4;
void runMessage()
{
debMsg("Executing kernel knExtrapolateMACSimple ", 3);
debMsg("Kernel range"
<< " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
4);
};
void operator()(const tbb::blocked_range<IndexInt> &__r) const
{
const int _maxX = maxX;
const int _maxY = maxY;
if (maxZ > 1) {
for (int k = __r.begin(); k != (int)__r.end(); k++)
for (int j = 1; j < _maxY; j++)
for (int i = 1; i < _maxX; i++)
op(i, j, k, vel, distance, tmp, d, c);
}
else {
const int k = 0;
for (int j = __r.begin(); j != (int)__r.end(); j++)
for (int i = 1; i < _maxX; i++)
op(i, j, k, vel, distance, tmp, d, c);
}
}
void run()
{
if (maxZ > 1)
tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
else
tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
}
MACGrid &vel;
int distance;
Grid<int> &tmp;
const int d;
const int c;
};
//! copy velocity into domain side, note - don't read & write same grid, hence velTmp copy
struct knExtrapolateIntoBnd : public KernelBase {
knExtrapolateIntoBnd(FlagGrid &flags, MACGrid &vel, const MACGrid &velTmp)
: KernelBase(&flags, 0), flags(flags), vel(vel), velTmp(velTmp)
{
runMessage();
run();
}
inline void op(int i, int j, int k, FlagGrid &flags, MACGrid &vel, const MACGrid &velTmp) const
{
int c = 0;
Vec3 v(0, 0, 0);
const bool isObs = flags.isObstacle(i, j, k);
if (i == 0) {
v = velTmp(i + 1, j, k);
if (isObs && v[0] < 0.)
v[0] = 0.;
c++;
}
else if (i == (flags.getSizeX() - 1)) {
v = velTmp(i - 1, j, k);
if (isObs && v[0] > 0.)
v[0] = 0.;
c++;
}
if (j == 0) {
v = velTmp(i, j + 1, k);
if (isObs && v[1] < 0.)
v[1] = 0.;
c++;
}
else if (j == (flags.getSizeY() - 1)) {
v = velTmp(i, j - 1, k);
if (isObs && v[1] > 0.)
v[1] = 0.;
c++;
}
if (flags.is3D()) {
if (k == 0) {
v = velTmp(i, j, k + 1);
if (isObs && v[2] < 0.)
v[2] = 0.;
c++;
}
else if (k == (flags.getSizeZ() - 1)) {
v = velTmp(i, j, k - 1);
if (isObs && v[2] > 0.)
v[2] = 0.;
c++;
}
}
if (c > 0) {
vel(i, j, k) = v / (Real)c;
}
}
inline FlagGrid &getArg0()
{
return flags;
}
typedef FlagGrid type0;
inline MACGrid &getArg1()
{
return vel;
}
typedef MACGrid type1;
inline const MACGrid &getArg2()
{
return velTmp;
}
typedef MACGrid type2;
void runMessage()
{
debMsg("Executing kernel knExtrapolateIntoBnd ", 3);
debMsg("Kernel range"
<< " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
4);
};
void operator()(const tbb::blocked_range<IndexInt> &__r) const
{
const int _maxX = maxX;
const int _maxY = maxY;
if (maxZ > 1) {
for (int k = __r.begin(); k != (int)__r.end(); k++)
for (int j = 0; j < _maxY; j++)
for (int i = 0; i < _maxX; i++)
op(i, j, k, flags, vel, velTmp);
}
else {
const int k = 0;
for (int j = __r.begin(); j != (int)__r.end(); j++)
for (int i = 0; i < _maxX; i++)
op(i, j, k, flags, vel, velTmp);
}
}
void run()
{
if (maxZ > 1)
tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
else
tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
}
FlagGrid &flags;
MACGrid &vel;
const MACGrid &velTmp;
};
// todo - use getGradient instead?
inline Vec3 getNormal(const Grid<Real> &data, int i, int j, int k)
{
if (i > data.getSizeX() - 2)
i = data.getSizeX() - 2;
if (i < 1)
i = 1;
if (j > data.getSizeY() - 2)
j = data.getSizeY() - 2;
if (j < 1)
j = 1;
int kd = 1;
if (data.is3D()) {
if (k > data.getSizeZ() - 2)
k = data.getSizeZ() - 2;
if (k < 1)
k = 1;
}
else {
kd = 0;
}
return Vec3(data(i + 1, j, k) - data(i - 1, j, k),
data(i, j + 1, k) - data(i, j - 1, k),
data(i, j, k + kd) - data(i, j, k - kd));
}
struct knUnprojectNormalComp : public KernelBase {
knUnprojectNormalComp(FlagGrid &flags, MACGrid &vel, Grid<Real> &phi, Real maxDist)
: KernelBase(&flags, 1), flags(flags), vel(vel), phi(phi), maxDist(maxDist)
{
runMessage();
run();
}
inline void op(
int i, int j, int k, FlagGrid &flags, MACGrid &vel, Grid<Real> &phi, Real maxDist) const
{
// apply inside, within range near obstacle surface
if (phi(i, j, k) > 0. || phi(i, j, k) < -maxDist)
return;
Vec3 n = getNormal(phi, i, j, k);
Vec3 v = vel(i, j, k);
if (dot(n, v) < 0.) {
normalize(n);
Real l = dot(n, v);
vel(i, j, k) -= n * l;
}
}
inline FlagGrid &getArg0()
{
return flags;
}
typedef FlagGrid type0;
inline MACGrid &getArg1()
{
return vel;
}
typedef MACGrid type1;
inline Grid<Real> &getArg2()
{
return phi;
}
typedef Grid<Real> type2;
inline Real &getArg3()
{
return maxDist;
}
typedef Real type3;
void runMessage()
{
debMsg("Executing kernel knUnprojectNormalComp ", 3);
debMsg("Kernel range"
<< " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
4);
};
void operator()(const tbb::blocked_range<IndexInt> &__r) const
{
const int _maxX = maxX;
const int _maxY = maxY;
if (maxZ > 1) {
for (int k = __r.begin(); k != (int)__r.end(); k++)
for (int j = 1; j < _maxY; j++)
for (int i = 1; i < _maxX; i++)
op(i, j, k, flags, vel, phi, maxDist);
}
else {
const int k = 0;
for (int j = __r.begin(); j != (int)__r.end(); j++)
for (int i = 1; i < _maxX; i++)
op(i, j, k, flags, vel, phi, maxDist);
}
}
void run()
{
if (maxZ > 1)
tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
else
tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
}
FlagGrid &flags;
MACGrid &vel;
Grid<Real> &phi;
Real maxDist;
};
// a simple extrapolation step , used for cases where there's no levelset
// (note, less accurate than fast marching extrapolation.)
// into obstacle is a special mode for second order obstable boundaries (extrapolating
// only fluid velocities, not those at obstacles)
void extrapolateMACSimple(FlagGrid &flags,
MACGrid &vel,
int distance = 4,
LevelsetGrid *phiObs = NULL,
bool intoObs = false)
{
Grid<int> tmp(flags.getParent());
int dim = (flags.is3D() ? 3 : 2);
for (int c = 0; c < dim; ++c) {
Vec3i dir = 0;
dir[c] = 1;
tmp.clear();
// remove all fluid cells (not touching obstacles)
FOR_IJK_BND(flags, 1)
{
Vec3i p(i, j, k);
bool mark = false;
if (!intoObs) {
if (flags.isFluid(p) || flags.isFluid(p - dir))
mark = true;
}
else {
if ((flags.isFluid(p) || flags.isFluid(p - dir)) && (!flags.isObstacle(p)) &&
(!flags.isObstacle(p - dir)))
mark = true;
}
if (mark)
tmp(p) = 1;
}
// extrapolate for distance
for (int d = 1; d < 1 + distance; ++d) {
knExtrapolateMACSimple(vel, distance, tmp, d, c);
} // d
}
if (phiObs) {
knUnprojectNormalComp(flags, vel, *phiObs, distance);
}
// copy tangential values into sides of domain
MACGrid velTmp(flags.getParent());
velTmp.copyFrom(vel);
knExtrapolateIntoBnd(flags, vel, velTmp);
}
static PyObject *_W_0(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
{
try {
PbArgs _args(_linargs, _kwds);
FluidSolver *parent = _args.obtainParent();
bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
pbPreparePlugin(parent, "extrapolateMACSimple", !noTiming);
PyObject *_retval = 0;
{
ArgLocker _lock;
FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
MACGrid &vel = *_args.getPtr<MACGrid>("vel", 1, &_lock);
int distance = _args.getOpt<int>("distance", 2, 4, &_lock);
LevelsetGrid *phiObs = _args.getPtrOpt<LevelsetGrid>("phiObs", 3, NULL, &_lock);
bool intoObs = _args.getOpt<bool>("intoObs", 4, false, &_lock);
_retval = getPyNone();
extrapolateMACSimple(flags, vel, distance, phiObs, intoObs);
_args.check();
}
pbFinalizePlugin(parent, "extrapolateMACSimple", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("extrapolateMACSimple", e.what());
return 0;
}
}
static const Pb::Register _RP_extrapolateMACSimple("", "extrapolateMACSimple", _W_0);
extern "C" {
void PbRegister_extrapolateMACSimple()
{
KEEP_UNUSED(_RP_extrapolateMACSimple);
}
}
struct knExtrapolateMACFromWeight : public KernelBase {
knExtrapolateMACFromWeight(
MACGrid &vel, Grid<Vec3> &weight, int distance, const int d, const int c)
: KernelBase(&vel, 1), vel(vel), weight(weight), distance(distance), d(d), c(c)
{
runMessage();
run();
}
inline void op(int i,
int j,
int k,
MACGrid &vel,
Grid<Vec3> &weight,
int distance,
const int d,
const int c) const
{
static const Vec3i nb[6] = {Vec3i(1, 0, 0),
Vec3i(-1, 0, 0),
Vec3i(0, 1, 0),
Vec3i(0, -1, 0),
Vec3i(0, 0, 1),
Vec3i(0, 0, -1)};
const int dim = (vel.is3D() ? 3 : 2);
if (weight(i, j, k)[c] != 0)
return;
// copy from initialized neighbors
Vec3i p(i, j, k);
int nbs = 0;
Real avgVel = 0.;
for (int n = 0; n < 2 * dim; ++n) {
if (weight(p + nb[n])[c] == d) {
avgVel += vel(p + nb[n])[c];
nbs++;
}
}
if (nbs > 0) {
weight(p)[c] = d + 1;
vel(p)[c] = avgVel / nbs;
}
}
inline MACGrid &getArg0()
{
return vel;
}
typedef MACGrid type0;
inline Grid<Vec3> &getArg1()
{
return weight;
}
typedef Grid<Vec3> type1;
inline int &getArg2()
{
return distance;
}
typedef int type2;
inline const int &getArg3()
{
return d;
}
typedef int type3;
inline const int &getArg4()
{
return c;
}
typedef int type4;
void runMessage()
{
debMsg("Executing kernel knExtrapolateMACFromWeight ", 3);
debMsg("Kernel range"
<< " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
4);
};
void operator()(const tbb::blocked_range<IndexInt> &__r) const
{
const int _maxX = maxX;
const int _maxY = maxY;
if (maxZ > 1) {
for (int k = __r.begin(); k != (int)__r.end(); k++)
for (int j = 1; j < _maxY; j++)
for (int i = 1; i < _maxX; i++)
op(i, j, k, vel, weight, distance, d, c);
}
else {
const int k = 0;
for (int j = __r.begin(); j != (int)__r.end(); j++)
for (int i = 1; i < _maxX; i++)
op(i, j, k, vel, weight, distance, d, c);
}
}
void run()
{
if (maxZ > 1)
tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
else
tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
}
MACGrid &vel;
Grid<Vec3> &weight;
int distance;
const int d;
const int c;
};
// same as extrapolateMACSimple, but uses weight vec3 grid instead of flags to check
// for valid values (to be used in combination with mapPartsToMAC)
// note - the weight grid values are destroyed! the function is necessary due to discrepancies
// between velocity mapping on surface-levelset / fluid-flag creation. With this
// extrapolation we make sure the fluid region is covered by initial velocities
void extrapolateMACFromWeight(MACGrid &vel, Grid<Vec3> &weight, int distance = 2)
{
const int dim = (vel.is3D() ? 3 : 2);
for (int c = 0; c < dim; ++c) {
Vec3i dir = 0;
dir[c] = 1;
// reset weight values to 0 (uninitialized), and 1 (initialized inner values)
FOR_IJK_BND(vel, 1)
{
Vec3i p(i, j, k);
if (weight(p)[c] > 0.)
weight(p)[c] = 1.0;
}
// extrapolate for distance
for (int d = 1; d < 1 + distance; ++d) {
knExtrapolateMACFromWeight(vel, weight, distance, d, c);
} // d
}
}
static PyObject *_W_1(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
{
try {
PbArgs _args(_linargs, _kwds);
FluidSolver *parent = _args.obtainParent();
bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
pbPreparePlugin(parent, "extrapolateMACFromWeight", !noTiming);
PyObject *_retval = 0;
{
ArgLocker _lock;
MACGrid &vel = *_args.getPtr<MACGrid>("vel", 0, &_lock);
Grid<Vec3> &weight = *_args.getPtr<Grid<Vec3>>("weight", 1, &_lock);
int distance = _args.getOpt<int>("distance", 2, 2, &_lock);
_retval = getPyNone();
extrapolateMACFromWeight(vel, weight, distance);
_args.check();
}
pbFinalizePlugin(parent, "extrapolateMACFromWeight", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("extrapolateMACFromWeight", e.what());
return 0;
}
}
static const Pb::Register _RP_extrapolateMACFromWeight("", "extrapolateMACFromWeight", _W_1);
extern "C" {
void PbRegister_extrapolateMACFromWeight()
{
KEEP_UNUSED(_RP_extrapolateMACFromWeight);
}
}
// simple extrapolation functions for levelsets
static const Vec3i nb[6] = {Vec3i(1, 0, 0),
Vec3i(-1, 0, 0),
Vec3i(0, 1, 0),
Vec3i(0, -1, 0),
Vec3i(0, 0, 1),
Vec3i(0, 0, -1)};
template<class S> struct knExtrapolateLsSimple : public KernelBase {
knExtrapolateLsSimple(Grid<S> &val, int distance, Grid<int> &tmp, const int d, S direction)
: KernelBase(&val, 1), val(val), distance(distance), tmp(tmp), d(d), direction(direction)
{
runMessage();
run();
}
inline void op(int i,
int j,
int k,
Grid<S> &val,
int distance,
Grid<int> &tmp,
const int d,
S direction) const
{
const int dim = (val.is3D() ? 3 : 2);
if (tmp(i, j, k) != 0)
return;
// copy from initialized neighbors
Vec3i p(i, j, k);
int nbs = 0;
S avg(0.);
for (int n = 0; n < 2 * dim; ++n) {
if (tmp(p + nb[n]) == d) {
avg += val(p + nb[n]);
nbs++;
}
}
if (nbs > 0) {
tmp(p) = d + 1;
val(p) = avg / nbs + direction;
}
}
inline Grid<S> &getArg0()
{
return val;
}
typedef Grid<S> type0;
inline int &getArg1()
{
return distance;
}
typedef int type1;
inline Grid<int> &getArg2()
{
return tmp;
}
typedef Grid<int> type2;
inline const int &getArg3()
{
return d;
}
typedef int type3;
inline S &getArg4()
{
return direction;
}
typedef S type4;
void runMessage()
{
debMsg("Executing kernel knExtrapolateLsSimple ", 3);
debMsg("Kernel range"
<< " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
4);
};
void operator()(const tbb::blocked_range<IndexInt> &__r) const
{
const int _maxX = maxX;
const int _maxY = maxY;
if (maxZ > 1) {
for (int k = __r.begin(); k != (int)__r.end(); k++)
for (int j = 1; j < _maxY; j++)
for (int i = 1; i < _maxX; i++)
op(i, j, k, val, distance, tmp, d, direction);
}
else {
const int k = 0;
for (int j = __r.begin(); j != (int)__r.end(); j++)
for (int i = 1; i < _maxX; i++)
op(i, j, k, val, distance, tmp, d, direction);
}
}
void run()
{
if (maxZ > 1)
tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
else
tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
}
Grid<S> &val;
int distance;
Grid<int> &tmp;
const int d;
S direction;
};
template<class S> struct knSetRemaining : public KernelBase {
knSetRemaining(Grid<S> &phi, Grid<int> &tmp, S distance)
: KernelBase(&phi, 1), phi(phi), tmp(tmp), distance(distance)
{
runMessage();
run();
}
inline void op(int i, int j, int k, Grid<S> &phi, Grid<int> &tmp, S distance) const
{
if (tmp(i, j, k) != 0)
return;
phi(i, j, k) = distance;
}
inline Grid<S> &getArg0()
{
return phi;
}
typedef Grid<S> type0;
inline Grid<int> &getArg1()
{
return tmp;
}
typedef Grid<int> type1;
inline S &getArg2()
{
return distance;
}
typedef S type2;
void runMessage()
{
debMsg("Executing kernel knSetRemaining ", 3);
debMsg("Kernel range"
<< " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
4);
};
void operator()(const tbb::blocked_range<IndexInt> &__r) const
{
const int _maxX = maxX;
const int _maxY = maxY;
if (maxZ > 1) {
for (int k = __r.begin(); k != (int)__r.end(); k++)
for (int j = 1; j < _maxY; j++)
for (int i = 1; i < _maxX; i++)
op(i, j, k, phi, tmp, distance);
}
else {
const int k = 0;
for (int j = __r.begin(); j != (int)__r.end(); j++)
for (int i = 1; i < _maxX; i++)
op(i, j, k, phi, tmp, distance);
}
}
void run()
{
if (maxZ > 1)
tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
else
tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
}
Grid<S> &phi;
Grid<int> &tmp;
S distance;
};
void extrapolateLsSimple(Grid<Real> &phi, int distance = 4, bool inside = false)
{
Grid<int> tmp(phi.getParent());
tmp.clear();
const int dim = (phi.is3D() ? 3 : 2);
// by default, march outside
Real direction = 1.;
if (!inside) {
// mark all inside
FOR_IJK_BND(phi, 1)
{
if (phi(i, j, k) < 0.) {
tmp(i, j, k) = 1;
}
}
}
else {
direction = -1.;
FOR_IJK_BND(phi, 1)
{
if (phi(i, j, k) > 0.) {
tmp(i, j, k) = 1;
}
}
}
// + first layer around
FOR_IJK_BND(phi, 1)
{
Vec3i p(i, j, k);
if (tmp(p))
continue;
for (int n = 0; n < 2 * dim; ++n) {
if (tmp(p + nb[n]) == 1) {
tmp(i, j, k) = 2;
n = 2 * dim;
}
}
}
// extrapolate for distance
for (int d = 2; d < 1 + distance; ++d) {
knExtrapolateLsSimple<Real>(phi, distance, tmp, d, direction);
}
// set all remaining cells to max
knSetRemaining<Real>(phi, tmp, Real(direction * (distance + 2)));
}
static PyObject *_W_2(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
{
try {
PbArgs _args(_linargs, _kwds);
FluidSolver *parent = _args.obtainParent();
bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
pbPreparePlugin(parent, "extrapolateLsSimple", !noTiming);
PyObject *_retval = 0;
{
ArgLocker _lock;
Grid<Real> &phi = *_args.getPtr<Grid<Real>>("phi", 0, &_lock);
int distance = _args.getOpt<int>("distance", 1, 4, &_lock);
bool inside = _args.getOpt<bool>("inside", 2, false, &_lock);
_retval = getPyNone();
extrapolateLsSimple(phi, distance, inside);
_args.check();
}
pbFinalizePlugin(parent, "extrapolateLsSimple", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("extrapolateLsSimple", e.what());
return 0;
}
}
static const Pb::Register _RP_extrapolateLsSimple("", "extrapolateLsSimple", _W_2);
extern "C" {
void PbRegister_extrapolateLsSimple()
{
KEEP_UNUSED(_RP_extrapolateLsSimple);
}
}
// extrapolate centered vec3 values from marked fluid cells
void extrapolateVec3Simple(Grid<Vec3> &vel, Grid<Real> &phi, int distance = 4, bool inside = false)
{
Grid<int> tmp(vel.getParent());
tmp.clear();
const int dim = (vel.is3D() ? 3 : 2);
// mark initial cells, by default, march outside
if (!inside) {
// mark all inside
FOR_IJK_BND(phi, 1)
{
if (phi(i, j, k) < 0.) {
tmp(i, j, k) = 1;
}
}
}
else {
FOR_IJK_BND(phi, 1)
{
if (phi(i, j, k) > 0.) {
tmp(i, j, k) = 1;
}
}
}
// + first layer next to initial cells
FOR_IJK_BND(vel, 1)
{
Vec3i p(i, j, k);
if (tmp(p))
continue;
for (int n = 0; n < 2 * dim; ++n) {
if (tmp(p + nb[n]) == 1) {
tmp(i, j, k) = 2;
n = 2 * dim;
}
}
}
for (int d = 2; d < 1 + distance; ++d) {
knExtrapolateLsSimple<Vec3>(vel, distance, tmp, d, Vec3(0.));
}
knSetRemaining<Vec3>(vel, tmp, Vec3(0.));
}
static PyObject *_W_3(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
{
try {
PbArgs _args(_linargs, _kwds);
FluidSolver *parent = _args.obtainParent();
bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
pbPreparePlugin(parent, "extrapolateVec3Simple", !noTiming);
PyObject *_retval = 0;
{
ArgLocker _lock;
Grid<Vec3> &vel = *_args.getPtr<Grid<Vec3>>("vel", 0, &_lock);
Grid<Real> &phi = *_args.getPtr<Grid<Real>>("phi", 1, &_lock);
int distance = _args.getOpt<int>("distance", 2, 4, &_lock);
bool inside = _args.getOpt<bool>("inside", 3, false, &_lock);
_retval = getPyNone();
extrapolateVec3Simple(vel, phi, distance, inside);
_args.check();
}
pbFinalizePlugin(parent, "extrapolateVec3Simple", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("extrapolateVec3Simple", e.what());
return 0;
}
}
static const Pb::Register _RP_extrapolateVec3Simple("", "extrapolateVec3Simple", _W_3);
extern "C" {
void PbRegister_extrapolateVec3Simple()
{
KEEP_UNUSED(_RP_extrapolateVec3Simple);
}
}
} // namespace Manta