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/plugin/extforces.cpp
Sebastián Barschkis 635694c0ff Fluid: Added new viscosity solver
Mainly updated the Mantaflow version. It includes the new viscosity solver plugin based on the method from 'Accurate Viscous Free Surfaces for Buckling, Coiling, and Rotating Liquids' (Batty & Bridson).

In the UI, this update adds a new 'Viscosity' section to the fluid modifier UI (liquid domains only). For now, there is a single 'strength' value to control the viscosity of liquids.
2020-12-23 15:48:38 +01:00

1700 lines
51 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
* GNU General Public License (GPL)
* http://www.gnu.org/licenses
*
* Set boundary conditions, gravity
*
******************************************************************************/
#include "vectorbase.h"
#include "grid.h"
#include "commonkernels.h"
#include "particle.h"
using namespace std;
namespace Manta {
//! add constant force between fl/fl and fl/em cells
struct KnApplyForceField : public KernelBase {
KnApplyForceField(const FlagGrid &flags,
MACGrid &vel,
const Grid<Vec3> &force,
const Grid<Real> *include,
bool additive,
bool isMAC)
: KernelBase(&flags, 1),
flags(flags),
vel(vel),
force(force),
include(include),
additive(additive),
isMAC(isMAC)
{
runMessage();
run();
}
inline void op(int i,
int j,
int k,
const FlagGrid &flags,
MACGrid &vel,
const Grid<Vec3> &force,
const Grid<Real> *include,
bool additive,
bool isMAC) const
{
bool curFluid = flags.isFluid(i, j, k);
bool curEmpty = flags.isEmpty(i, j, k);
if (!curFluid && !curEmpty)
return;
if (include && ((*include)(i, j, k) > 0.))
return;
Real forceX = (isMAC) ? force(i, j, k).x : 0.5 * (force(i - 1, j, k).x + force(i, j, k).x);
Real forceY = (isMAC) ? force(i, j, k).y : 0.5 * (force(i, j - 1, k).y + force(i, j, k).y);
Real forceZ = 0.;
if (vel.is3D())
forceZ = (isMAC) ? force(i, j, k).z : 0.5 * (force(i, j, k - 1).z + force(i, j, k).z);
if (flags.isFluid(i - 1, j, k) || (curFluid && flags.isEmpty(i - 1, j, k)))
vel(i, j, k).x = (additive) ? vel(i, j, k).x + forceX : forceX;
if (flags.isFluid(i, j - 1, k) || (curFluid && flags.isEmpty(i, j - 1, k)))
vel(i, j, k).y = (additive) ? vel(i, j, k).y + forceY : forceY;
if (vel.is3D() && (flags.isFluid(i, j, k - 1) || (curFluid && flags.isEmpty(i, j, k - 1))))
vel(i, j, k).z = (additive) ? vel(i, j, k).z + forceZ : forceZ;
}
inline const FlagGrid &getArg0()
{
return flags;
}
typedef FlagGrid type0;
inline MACGrid &getArg1()
{
return vel;
}
typedef MACGrid type1;
inline const Grid<Vec3> &getArg2()
{
return force;
}
typedef Grid<Vec3> type2;
inline const Grid<Real> *getArg3()
{
return include;
}
typedef Grid<Real> type3;
inline bool &getArg4()
{
return additive;
}
typedef bool type4;
inline bool &getArg5()
{
return isMAC;
}
typedef bool type5;
void runMessage()
{
debMsg("Executing kernel KnApplyForceField ", 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, force, include, additive, isMAC);
}
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, force, include, additive, isMAC);
}
}
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);
}
const FlagGrid &flags;
MACGrid &vel;
const Grid<Vec3> &force;
const Grid<Real> *include;
bool additive;
bool isMAC;
};
//! add constant force between fl/fl and fl/em cells
struct KnApplyForce : public KernelBase {
KnApplyForce(
const FlagGrid &flags, MACGrid &vel, Vec3 force, const Grid<Real> *exclude, bool additive)
: KernelBase(&flags, 1),
flags(flags),
vel(vel),
force(force),
exclude(exclude),
additive(additive)
{
runMessage();
run();
}
inline void op(int i,
int j,
int k,
const FlagGrid &flags,
MACGrid &vel,
Vec3 force,
const Grid<Real> *exclude,
bool additive) const
{
bool curFluid = flags.isFluid(i, j, k);
bool curEmpty = flags.isEmpty(i, j, k);
if (!curFluid && !curEmpty)
return;
if (exclude && ((*exclude)(i, j, k) < 0.))
return;
if (flags.isFluid(i - 1, j, k) || (curFluid && flags.isEmpty(i - 1, j, k)))
vel(i, j, k).x = (additive) ? vel(i, j, k).x + force.x : force.x;
if (flags.isFluid(i, j - 1, k) || (curFluid && flags.isEmpty(i, j - 1, k)))
vel(i, j, k).y = (additive) ? vel(i, j, k).y + force.y : force.y;
if (vel.is3D() && (flags.isFluid(i, j, k - 1) || (curFluid && flags.isEmpty(i, j, k - 1))))
vel(i, j, k).z = (additive) ? vel(i, j, k).z + force.z : force.z;
}
inline const FlagGrid &getArg0()
{
return flags;
}
typedef FlagGrid type0;
inline MACGrid &getArg1()
{
return vel;
}
typedef MACGrid type1;
inline Vec3 &getArg2()
{
return force;
}
typedef Vec3 type2;
inline const Grid<Real> *getArg3()
{
return exclude;
}
typedef Grid<Real> type3;
inline bool &getArg4()
{
return additive;
}
typedef bool type4;
void runMessage()
{
debMsg("Executing kernel KnApplyForce ", 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, force, exclude, additive);
}
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, force, exclude, additive);
}
}
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);
}
const FlagGrid &flags;
MACGrid &vel;
Vec3 force;
const Grid<Real> *exclude;
bool additive;
};
//! add gravity forces to all fluid cells, optionally adapts to different grid sizes automatically
void addGravity(const FlagGrid &flags,
MACGrid &vel,
Vec3 gravity,
const Grid<Real> *exclude = nullptr,
bool scale = true)
{
float gridScale = (scale) ? flags.getDx() : 1;
Vec3 f = gravity * flags.getParent()->getDt() / gridScale;
KnApplyForce(flags, vel, f, exclude, true);
}
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, "addGravity", !noTiming);
PyObject *_retval = nullptr;
{
ArgLocker _lock;
const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
MACGrid &vel = *_args.getPtr<MACGrid>("vel", 1, &_lock);
Vec3 gravity = _args.get<Vec3>("gravity", 2, &_lock);
const Grid<Real> *exclude = _args.getPtrOpt<Grid<Real>>("exclude", 3, nullptr, &_lock);
bool scale = _args.getOpt<bool>("scale", 4, true, &_lock);
_retval = getPyNone();
addGravity(flags, vel, gravity, exclude, scale);
_args.check();
}
pbFinalizePlugin(parent, "addGravity", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("addGravity", e.what());
return 0;
}
}
static const Pb::Register _RP_addGravity("", "addGravity", _W_0);
extern "C" {
void PbRegister_addGravity()
{
KEEP_UNUSED(_RP_addGravity);
}
}
//! Deprecated: use addGravity(scale=false) instead
void addGravityNoScale(const FlagGrid &flags,
MACGrid &vel,
const Vec3 &gravity,
const Grid<Real> *exclude = nullptr)
{
addGravity(flags, vel, gravity, exclude, false);
}
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, "addGravityNoScale", !noTiming);
PyObject *_retval = nullptr;
{
ArgLocker _lock;
const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
MACGrid &vel = *_args.getPtr<MACGrid>("vel", 1, &_lock);
const Vec3 &gravity = _args.get<Vec3>("gravity", 2, &_lock);
const Grid<Real> *exclude = _args.getPtrOpt<Grid<Real>>("exclude", 3, nullptr, &_lock);
_retval = getPyNone();
addGravityNoScale(flags, vel, gravity, exclude);
_args.check();
}
pbFinalizePlugin(parent, "addGravityNoScale", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("addGravityNoScale", e.what());
return 0;
}
}
static const Pb::Register _RP_addGravityNoScale("", "addGravityNoScale", _W_1);
extern "C" {
void PbRegister_addGravityNoScale()
{
KEEP_UNUSED(_RP_addGravityNoScale);
}
}
//! kernel to add Buoyancy force
struct KnAddBuoyancy : public KernelBase {
KnAddBuoyancy(const FlagGrid &flags, const Grid<Real> &factor, MACGrid &vel, Vec3 strength)
: KernelBase(&flags, 1), flags(flags), factor(factor), vel(vel), strength(strength)
{
runMessage();
run();
}
inline void op(int i,
int j,
int k,
const FlagGrid &flags,
const Grid<Real> &factor,
MACGrid &vel,
Vec3 strength) const
{
if (!flags.isFluid(i, j, k))
return;
if (flags.isFluid(i - 1, j, k))
vel(i, j, k).x += (0.5 * strength.x) * (factor(i, j, k) + factor(i - 1, j, k));
if (flags.isFluid(i, j - 1, k))
vel(i, j, k).y += (0.5 * strength.y) * (factor(i, j, k) + factor(i, j - 1, k));
if (vel.is3D() && flags.isFluid(i, j, k - 1))
vel(i, j, k).z += (0.5 * strength.z) * (factor(i, j, k) + factor(i, j, k - 1));
}
inline const FlagGrid &getArg0()
{
return flags;
}
typedef FlagGrid type0;
inline const Grid<Real> &getArg1()
{
return factor;
}
typedef Grid<Real> type1;
inline MACGrid &getArg2()
{
return vel;
}
typedef MACGrid type2;
inline Vec3 &getArg3()
{
return strength;
}
typedef Vec3 type3;
void runMessage()
{
debMsg("Executing kernel KnAddBuoyancy ", 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, factor, vel, strength);
}
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, factor, vel, strength);
}
}
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);
}
const FlagGrid &flags;
const Grid<Real> &factor;
MACGrid &vel;
Vec3 strength;
};
//! add Buoyancy force based on factor (e.g. smoke density), optionally adapts to different grid
//! sizes automatically
void addBuoyancy(const FlagGrid &flags,
const Grid<Real> &density,
MACGrid &vel,
Vec3 gravity,
Real coefficient = 1.,
bool scale = true)
{
float gridScale = (scale) ? flags.getDx() : 1;
Vec3 f = -gravity * flags.getParent()->getDt() / gridScale * coefficient;
KnAddBuoyancy(flags, density, vel, f);
}
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, "addBuoyancy", !noTiming);
PyObject *_retval = nullptr;
{
ArgLocker _lock;
const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
const Grid<Real> &density = *_args.getPtr<Grid<Real>>("density", 1, &_lock);
MACGrid &vel = *_args.getPtr<MACGrid>("vel", 2, &_lock);
Vec3 gravity = _args.get<Vec3>("gravity", 3, &_lock);
Real coefficient = _args.getOpt<Real>("coefficient", 4, 1., &_lock);
bool scale = _args.getOpt<bool>("scale", 5, true, &_lock);
_retval = getPyNone();
addBuoyancy(flags, density, vel, gravity, coefficient, scale);
_args.check();
}
pbFinalizePlugin(parent, "addBuoyancy", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("addBuoyancy", e.what());
return 0;
}
}
static const Pb::Register _RP_addBuoyancy("", "addBuoyancy", _W_2);
extern "C" {
void PbRegister_addBuoyancy()
{
KEEP_UNUSED(_RP_addBuoyancy);
}
}
// inflow / outflow boundaries
//! helper to parse openbounds string [xXyYzZ] , convert to vec3
inline void convertDescToVec(const string &desc, Vector3D<bool> &lo, Vector3D<bool> &up)
{
for (size_t i = 0; i < desc.size(); i++) {
if (desc[i] == 'x')
lo.x = true;
else if (desc[i] == 'y')
lo.y = true;
else if (desc[i] == 'z')
lo.z = true;
else if (desc[i] == 'X')
up.x = true;
else if (desc[i] == 'Y')
up.y = true;
else if (desc[i] == 'Z')
up.z = true;
else
errMsg("invalid character in boundary description string. Only [xyzXYZ] allowed.");
}
}
//! add empty and outflow flag to cells of open boundaries
void setOpenBound(FlagGrid &flags,
int bWidth,
string openBound = "",
int type = FlagGrid::TypeOutflow | FlagGrid::TypeEmpty)
{
if (openBound == "")
return;
Vector3D<bool> lo, up;
convertDescToVec(openBound, lo, up);
FOR_IJK(flags)
{
bool loX = lo.x && i <= bWidth; // a cell which belongs to the lower x open bound
bool loY = lo.y && j <= bWidth;
bool upX = up.x && i >= flags.getSizeX() - bWidth -
1; // a cell which belongs to the upper x open bound
bool upY = up.y && j >= flags.getSizeY() - bWidth - 1;
bool innerI = i > bWidth &&
i < flags.getSizeX() - bWidth -
1; // a cell which does not belong to the lower or upper x bound
bool innerJ = j > bWidth && j < flags.getSizeY() - bWidth - 1;
// when setting boundaries to open: don't set shared part of wall to empty if neighboring wall
// is not open
if ((!flags.is3D()) && (loX || upX || loY || upY)) {
if ((loX || upX || innerI) && (loY || upY || innerJ) && flags.isObstacle(i, j, k))
flags(i, j, k) = type;
}
else {
bool loZ = lo.z && k <= bWidth; // a cell which belongs to the lower z open bound
bool upZ = up.z && k >= flags.getSizeZ() - bWidth -
1; // a cell which belongs to the upper z open bound
bool innerK = k > bWidth &&
k < flags.getSizeZ() - bWidth -
1; // a cell which does not belong to the lower or upper z bound
if (loX || upX || loY || upY || loZ || upZ) {
if ((loX || upX || innerI) && (loY || upY || innerJ) && (loZ || upZ || innerK) &&
flags.isObstacle(i, j, k))
flags(i, j, k) = type;
}
}
}
}
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, "setOpenBound", !noTiming);
PyObject *_retval = nullptr;
{
ArgLocker _lock;
FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
int bWidth = _args.get<int>("bWidth", 1, &_lock);
string openBound = _args.getOpt<string>("openBound", 2, "", &_lock);
int type = _args.getOpt<int>("type", 3, FlagGrid::TypeOutflow | FlagGrid::TypeEmpty, &_lock);
_retval = getPyNone();
setOpenBound(flags, bWidth, openBound, type);
_args.check();
}
pbFinalizePlugin(parent, "setOpenBound", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("setOpenBound", e.what());
return 0;
}
}
static const Pb::Register _RP_setOpenBound("", "setOpenBound", _W_3);
extern "C" {
void PbRegister_setOpenBound()
{
KEEP_UNUSED(_RP_setOpenBound);
}
}
//! delete fluid and ensure empty flag in outflow cells, delete particles and density and set phi
//! to 0.5
void resetOutflow(FlagGrid &flags,
Grid<Real> *phi = nullptr,
BasicParticleSystem *parts = nullptr,
Grid<Real> *real = nullptr,
Grid<int> *index = nullptr,
ParticleIndexSystem *indexSys = nullptr)
{
// check if phi and parts -> pindex and gpi already created -> access particles from cell index,
// avoid extra looping over particles
if (parts && (!index || !indexSys)) {
if (phi)
debMsg(
"resetOpenBound for phi and particles, but missing index and indexSys for enhanced "
"particle access!",
1);
for (int idx = 0; idx < (int)parts->size(); idx++)
if (parts->isActive(idx) && flags.isInBounds(parts->getPos(idx)) &&
flags.isOutflow(parts->getPos(idx)))
parts->kill(idx);
}
FOR_IJK(flags)
{
if (flags.isOutflow(i, j, k)) {
flags(i, j, k) = (flags(i, j, k) | FlagGrid::TypeEmpty) &
~FlagGrid::TypeFluid; // make sure there is not fluid flag set and to reset
// the empty flag
// the particles in a cell i,j,k are particles[index(i,j,k)] to particles[index(i+1,j,k)-1]
if (parts && index && indexSys) {
int isysIdxS = index->index(i, j, k);
int pStart = (*index)(isysIdxS), pEnd = 0;
if (flags.isInBounds(isysIdxS + 1))
pEnd = (*index)(isysIdxS + 1);
else
pEnd = indexSys->size();
// now loop over particles in cell
for (int p = pStart; p < pEnd; ++p) {
int psrc = (*indexSys)[p].sourceIndex;
if (parts->isActive(psrc) && flags.isInBounds(parts->getPos(psrc)))
parts->kill(psrc);
}
}
if (phi)
(*phi)(i, j, k) = 0.5;
if (real)
(*real)(i, j, k) = 0;
}
}
if (parts)
parts->doCompress();
}
static PyObject *_W_4(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, "resetOutflow", !noTiming);
PyObject *_retval = nullptr;
{
ArgLocker _lock;
FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
Grid<Real> *phi = _args.getPtrOpt<Grid<Real>>("phi", 1, nullptr, &_lock);
BasicParticleSystem *parts = _args.getPtrOpt<BasicParticleSystem>(
"parts", 2, nullptr, &_lock);
Grid<Real> *real = _args.getPtrOpt<Grid<Real>>("real", 3, nullptr, &_lock);
Grid<int> *index = _args.getPtrOpt<Grid<int>>("index", 4, nullptr, &_lock);
ParticleIndexSystem *indexSys = _args.getPtrOpt<ParticleIndexSystem>(
"indexSys", 5, nullptr, &_lock);
_retval = getPyNone();
resetOutflow(flags, phi, parts, real, index, indexSys);
_args.check();
}
pbFinalizePlugin(parent, "resetOutflow", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("resetOutflow", e.what());
return 0;
}
}
static const Pb::Register _RP_resetOutflow("", "resetOutflow", _W_4);
extern "C" {
void PbRegister_resetOutflow()
{
KEEP_UNUSED(_RP_resetOutflow);
}
}
//! enforce a constant inflow/outflow at the grid boundaries
struct KnSetInflow : public KernelBase {
KnSetInflow(MACGrid &vel, int dim, int p0, const Vec3 &val)
: KernelBase(&vel, 0), vel(vel), dim(dim), p0(p0), val(val)
{
runMessage();
run();
}
inline void op(int i, int j, int k, MACGrid &vel, int dim, int p0, const Vec3 &val) const
{
Vec3i p(i, j, k);
if (p[dim] == p0 || p[dim] == p0 + 1)
vel(i, j, k) = val;
}
inline MACGrid &getArg0()
{
return vel;
}
typedef MACGrid type0;
inline int &getArg1()
{
return dim;
}
typedef int type1;
inline int &getArg2()
{
return p0;
}
typedef int type2;
inline const Vec3 &getArg3()
{
return val;
}
typedef Vec3 type3;
void runMessage()
{
debMsg("Executing kernel KnSetInflow ", 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, vel, dim, p0, val);
}
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, vel, dim, p0, val);
}
}
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);
}
MACGrid &vel;
int dim;
int p0;
const Vec3 &val;
};
//! enforce a constant inflow/outflow at the grid boundaries
void setInflowBcs(MACGrid &vel, string dir, Vec3 value)
{
for (size_t i = 0; i < dir.size(); i++) {
if (dir[i] >= 'x' && dir[i] <= 'z') {
int dim = dir[i] - 'x';
KnSetInflow(vel, dim, 0, value);
}
else if (dir[i] >= 'X' && dir[i] <= 'Z') {
int dim = dir[i] - 'X';
KnSetInflow(vel, dim, vel.getSize()[dim] - 1, value);
}
else
errMsg("invalid character in direction string. Only [xyzXYZ] allowed.");
}
}
static PyObject *_W_5(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, "setInflowBcs", !noTiming);
PyObject *_retval = nullptr;
{
ArgLocker _lock;
MACGrid &vel = *_args.getPtr<MACGrid>("vel", 0, &_lock);
string dir = _args.get<string>("dir", 1, &_lock);
Vec3 value = _args.get<Vec3>("value", 2, &_lock);
_retval = getPyNone();
setInflowBcs(vel, dir, value);
_args.check();
}
pbFinalizePlugin(parent, "setInflowBcs", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("setInflowBcs", e.what());
return 0;
}
}
static const Pb::Register _RP_setInflowBcs("", "setInflowBcs", _W_5);
extern "C" {
void PbRegister_setInflowBcs()
{
KEEP_UNUSED(_RP_setInflowBcs);
}
}
// set obstacle boundary conditions
//! set no-stick wall boundary condition between ob/fl and ob/ob cells
struct KnSetWallBcs : public KernelBase {
KnSetWallBcs(const FlagGrid &flags, MACGrid &vel, const MACGrid *obvel)
: KernelBase(&flags, 0), flags(flags), vel(vel), obvel(obvel)
{
runMessage();
run();
}
inline void op(
int i, int j, int k, const FlagGrid &flags, MACGrid &vel, const MACGrid *obvel) const
{
bool curFluid = flags.isFluid(i, j, k);
bool curObs = flags.isObstacle(i, j, k);
Vec3 bcsVel(0., 0., 0.);
if (!curFluid && !curObs)
return;
if (obvel) {
bcsVel.x = (*obvel)(i, j, k).x;
bcsVel.y = (*obvel)(i, j, k).y;
if ((*obvel).is3D())
bcsVel.z = (*obvel)(i, j, k).z;
}
// we use i>0 instead of bnd=1 to check outer wall
if (i > 0 && flags.isObstacle(i - 1, j, k))
vel(i, j, k).x = bcsVel.x;
if (i > 0 && curObs && flags.isFluid(i - 1, j, k))
vel(i, j, k).x = bcsVel.x;
if (j > 0 && flags.isObstacle(i, j - 1, k))
vel(i, j, k).y = bcsVel.y;
if (j > 0 && curObs && flags.isFluid(i, j - 1, k))
vel(i, j, k).y = bcsVel.y;
if (!vel.is3D()) {
vel(i, j, k).z = 0;
}
else {
if (k > 0 && flags.isObstacle(i, j, k - 1))
vel(i, j, k).z = bcsVel.z;
if (k > 0 && curObs && flags.isFluid(i, j, k - 1))
vel(i, j, k).z = bcsVel.z;
}
if (curFluid) {
if ((i > 0 && flags.isStick(i - 1, j, k)) ||
(i < flags.getSizeX() - 1 && flags.isStick(i + 1, j, k)))
vel(i, j, k).y = vel(i, j, k).z = 0;
if ((j > 0 && flags.isStick(i, j - 1, k)) ||
(j < flags.getSizeY() - 1 && flags.isStick(i, j + 1, k)))
vel(i, j, k).x = vel(i, j, k).z = 0;
if (vel.is3D() && ((k > 0 && flags.isStick(i, j, k - 1)) ||
(k < flags.getSizeZ() - 1 && flags.isStick(i, j, k + 1))))
vel(i, j, k).x = vel(i, j, k).y = 0;
}
}
inline const FlagGrid &getArg0()
{
return flags;
}
typedef FlagGrid type0;
inline MACGrid &getArg1()
{
return vel;
}
typedef MACGrid type1;
inline const MACGrid *getArg2()
{
return obvel;
}
typedef MACGrid type2;
void runMessage()
{
debMsg("Executing kernel KnSetWallBcs ", 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, obvel);
}
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, obvel);
}
}
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);
}
const FlagGrid &flags;
MACGrid &vel;
const MACGrid *obvel;
};
//! set wall BCs for fill fraction mode, note - only needs obstacle SDF
struct KnSetWallBcsFrac : public KernelBase {
KnSetWallBcsFrac(const FlagGrid &flags,
const MACGrid &vel,
MACGrid &velTarget,
const MACGrid *obvel,
const Grid<Real> *phiObs,
const int &boundaryWidth = 0)
: KernelBase(&flags, 0),
flags(flags),
vel(vel),
velTarget(velTarget),
obvel(obvel),
phiObs(phiObs),
boundaryWidth(boundaryWidth)
{
runMessage();
run();
}
inline void op(int i,
int j,
int k,
const FlagGrid &flags,
const MACGrid &vel,
MACGrid &velTarget,
const MACGrid *obvel,
const Grid<Real> *phiObs,
const int &boundaryWidth = 0) const
{
bool curFluid = flags.isFluid(i, j, k);
bool curObs = flags.isObstacle(i, j, k);
velTarget(i, j, k) = vel(i, j, k);
if (!curFluid && !curObs)
return;
// zero normal component in all obstacle regions
if (flags.isInBounds(Vec3i(i, j, k), 1)) {
if (curObs | flags.isObstacle(i - 1, j, k)) {
Vec3 dphi(0., 0., 0.);
const Real tmp1 = (phiObs->get(i, j, k) + phiObs->get(i - 1, j, k)) * .5;
Real tmp2 = (phiObs->get(i, j + 1, k) + phiObs->get(i - 1, j + 1, k)) * .5;
Real phi1 = (tmp1 + tmp2) * .5;
tmp2 = (phiObs->get(i, j - 1, k) + phiObs->get(i - 1, j - 1, k)) * .5;
Real phi2 = (tmp1 + tmp2) * .5;
dphi.x = phiObs->get(i, j, k) - phiObs->get(i - 1, j, k);
dphi.y = phi1 - phi2;
if (phiObs->is3D()) {
tmp2 = (phiObs->get(i, j, k + 1) + phiObs->get(i - 1, j, k + 1)) * .5;
phi1 = (tmp1 + tmp2) * .5;
tmp2 = (phiObs->get(i, j, k - 1) + phiObs->get(i - 1, j, k - 1)) * .5;
phi2 = (tmp1 + tmp2) * .5;
dphi.z = phi1 - phi2;
}
normalize(dphi);
Vec3 velMAC = vel.getAtMACX(i, j, k);
velTarget(i, j, k).x = velMAC.x - dot(dphi, velMAC) * dphi.x;
}
if (curObs | flags.isObstacle(i, j - 1, k)) {
Vec3 dphi(0., 0., 0.);
const Real tmp1 = (phiObs->get(i, j, k) + phiObs->get(i, j - 1, k)) * .5;
Real tmp2 = (phiObs->get(i + 1, j, k) + phiObs->get(i + 1, j - 1, k)) * .5;
Real phi1 = (tmp1 + tmp2) * .5;
tmp2 = (phiObs->get(i - 1, j, k) + phiObs->get(i - 1, j - 1, k)) * .5;
Real phi2 = (tmp1 + tmp2) * .5;
dphi.x = phi1 - phi2;
dphi.y = phiObs->get(i, j, k) - phiObs->get(i, j - 1, k);
if (phiObs->is3D()) {
tmp2 = (phiObs->get(i, j, k + 1) + phiObs->get(i, j - 1, k + 1)) * .5;
phi1 = (tmp1 + tmp2) * .5;
tmp2 = (phiObs->get(i, j, k - 1) + phiObs->get(i, j - 1, k - 1)) * .5;
phi2 = (tmp1 + tmp2) * .5;
dphi.z = phi1 - phi2;
}
normalize(dphi);
Vec3 velMAC = vel.getAtMACY(i, j, k);
velTarget(i, j, k).y = velMAC.y - dot(dphi, velMAC) * dphi.y;
}
if (phiObs->is3D() && (curObs | flags.isObstacle(i, j, k - 1))) {
Vec3 dphi(0., 0., 0.);
const Real tmp1 = (phiObs->get(i, j, k) + phiObs->get(i, j, k - 1)) * .5;
Real tmp2;
tmp2 = (phiObs->get(i + 1, j, k) + phiObs->get(i + 1, j, k - 1)) * .5;
Real phi1 = (tmp1 + tmp2) * .5;
tmp2 = (phiObs->get(i - 1, j, k) + phiObs->get(i - 1, j, k - 1)) * .5;
Real phi2 = (tmp1 + tmp2) * .5;
dphi.x = phi1 - phi2;
tmp2 = (phiObs->get(i, j + 1, k) + phiObs->get(i, j + 1, k - 1)) * .5;
phi1 = (tmp1 + tmp2) * .5;
tmp2 = (phiObs->get(i, j - 1, k) + phiObs->get(i, j - 1, k - 1)) * .5;
phi2 = (tmp1 + tmp2) * .5;
dphi.y = phi1 - phi2;
dphi.z = phiObs->get(i, j, k) - phiObs->get(i, j, k - 1);
normalize(dphi);
Vec3 velMAC = vel.getAtMACZ(i, j, k);
velTarget(i, j, k).z = velMAC.z - dot(dphi, velMAC) * dphi.z;
}
} // not at boundary
}
inline const FlagGrid &getArg0()
{
return flags;
}
typedef FlagGrid type0;
inline const MACGrid &getArg1()
{
return vel;
}
typedef MACGrid type1;
inline MACGrid &getArg2()
{
return velTarget;
}
typedef MACGrid type2;
inline const MACGrid *getArg3()
{
return obvel;
}
typedef MACGrid type3;
inline const Grid<Real> *getArg4()
{
return phiObs;
}
typedef Grid<Real> type4;
inline const int &getArg5()
{
return boundaryWidth;
}
typedef int type5;
void runMessage()
{
debMsg("Executing kernel KnSetWallBcsFrac ", 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, velTarget, obvel, phiObs, boundaryWidth);
}
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, velTarget, obvel, phiObs, boundaryWidth);
}
}
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);
}
const FlagGrid &flags;
const MACGrid &vel;
MACGrid &velTarget;
const MACGrid *obvel;
const Grid<Real> *phiObs;
const int &boundaryWidth;
};
//! set zero normal velocity boundary condition on walls
// (optionally with second order accuracy using the obstacle SDF , fractions grid currently not
// needed)
void setWallBcs(const FlagGrid &flags,
MACGrid &vel,
const MACGrid *obvel = nullptr,
const MACGrid *fractions = nullptr,
const Grid<Real> *phiObs = nullptr,
int boundaryWidth = 0)
{
if (!phiObs || !fractions) {
KnSetWallBcs(flags, vel, obvel);
}
else {
MACGrid tmpvel(vel.getParent());
KnSetWallBcsFrac(flags, vel, tmpvel, obvel, phiObs, boundaryWidth);
vel.swap(tmpvel);
}
}
static PyObject *_W_6(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, "setWallBcs", !noTiming);
PyObject *_retval = nullptr;
{
ArgLocker _lock;
const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
MACGrid &vel = *_args.getPtr<MACGrid>("vel", 1, &_lock);
const MACGrid *obvel = _args.getPtrOpt<MACGrid>("obvel", 2, nullptr, &_lock);
const MACGrid *fractions = _args.getPtrOpt<MACGrid>("fractions", 3, nullptr, &_lock);
const Grid<Real> *phiObs = _args.getPtrOpt<Grid<Real>>("phiObs", 4, nullptr, &_lock);
int boundaryWidth = _args.getOpt<int>("boundaryWidth", 5, 0, &_lock);
_retval = getPyNone();
setWallBcs(flags, vel, obvel, fractions, phiObs, boundaryWidth);
_args.check();
}
pbFinalizePlugin(parent, "setWallBcs", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("setWallBcs", e.what());
return 0;
}
}
static const Pb::Register _RP_setWallBcs("", "setWallBcs", _W_6);
extern "C" {
void PbRegister_setWallBcs()
{
KEEP_UNUSED(_RP_setWallBcs);
}
}
//! add Forces between fl/fl and fl/em cells (interpolate cell centered forces to MAC grid)
struct KnAddForceIfLower : public KernelBase {
KnAddForceIfLower(const FlagGrid &flags, MACGrid &vel, const Grid<Vec3> &force)
: KernelBase(&flags, 1), flags(flags), vel(vel), force(force)
{
runMessage();
run();
}
inline void op(
int i, int j, int k, const FlagGrid &flags, MACGrid &vel, const Grid<Vec3> &force) const
{
bool curFluid = flags.isFluid(i, j, k);
bool curEmpty = flags.isEmpty(i, j, k);
if (!curFluid && !curEmpty)
return;
Real minVal, maxVal, sum;
if (flags.isFluid(i - 1, j, k) || (curFluid && flags.isEmpty(i - 1, j, k))) {
Real forceMACX = 0.5 * (force(i - 1, j, k).x + force(i, j, k).x);
minVal = min(vel(i, j, k).x, forceMACX);
maxVal = max(vel(i, j, k).x, forceMACX);
sum = vel(i, j, k).x + forceMACX;
vel(i, j, k).x = (forceMACX > 0) ? min(sum, maxVal) : max(sum, minVal);
}
if (flags.isFluid(i, j - 1, k) || (curFluid && flags.isEmpty(i, j - 1, k))) {
Real forceMACY = 0.5 * (force(i, j - 1, k).y + force(i, j, k).y);
minVal = min(vel(i, j, k).y, forceMACY);
maxVal = max(vel(i, j, k).y, forceMACY);
sum = vel(i, j, k).y + forceMACY;
vel(i, j, k).y = (forceMACY > 0) ? min(sum, maxVal) : max(sum, minVal);
}
if (vel.is3D() && (flags.isFluid(i, j, k - 1) || (curFluid && flags.isEmpty(i, j, k - 1)))) {
Real forceMACZ = 0.5 * (force(i, j, k - 1).z + force(i, j, k).z);
minVal = min(vel(i, j, k).z, forceMACZ);
maxVal = max(vel(i, j, k).z, forceMACZ);
sum = vel(i, j, k).z + forceMACZ;
vel(i, j, k).z = (forceMACZ > 0) ? min(sum, maxVal) : max(sum, minVal);
}
}
inline const FlagGrid &getArg0()
{
return flags;
}
typedef FlagGrid type0;
inline MACGrid &getArg1()
{
return vel;
}
typedef MACGrid type1;
inline const Grid<Vec3> &getArg2()
{
return force;
}
typedef Grid<Vec3> type2;
void runMessage()
{
debMsg("Executing kernel KnAddForceIfLower ", 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, force);
}
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, force);
}
}
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);
}
const FlagGrid &flags;
MACGrid &vel;
const Grid<Vec3> &force;
};
// Initial velocity for smoke
void setInitialVelocity(const FlagGrid &flags, MACGrid &vel, const Grid<Vec3> &invel)
{
KnAddForceIfLower(flags, vel, invel);
}
static PyObject *_W_7(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, "setInitialVelocity", !noTiming);
PyObject *_retval = nullptr;
{
ArgLocker _lock;
const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
MACGrid &vel = *_args.getPtr<MACGrid>("vel", 1, &_lock);
const Grid<Vec3> &invel = *_args.getPtr<Grid<Vec3>>("invel", 2, &_lock);
_retval = getPyNone();
setInitialVelocity(flags, vel, invel);
_args.check();
}
pbFinalizePlugin(parent, "setInitialVelocity", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("setInitialVelocity", e.what());
return 0;
}
}
static const Pb::Register _RP_setInitialVelocity("", "setInitialVelocity", _W_7);
extern "C" {
void PbRegister_setInitialVelocity()
{
KEEP_UNUSED(_RP_setInitialVelocity);
}
}
//! Kernel: gradient norm operator
struct KnConfForce : public KernelBase {
KnConfForce(Grid<Vec3> &force,
const Grid<Real> &grid,
const Grid<Vec3> &curl,
Real str,
const Grid<Real> *strGrid)
: KernelBase(&force, 1), force(force), grid(grid), curl(curl), str(str), strGrid(strGrid)
{
runMessage();
run();
}
inline void op(int i,
int j,
int k,
Grid<Vec3> &force,
const Grid<Real> &grid,
const Grid<Vec3> &curl,
Real str,
const Grid<Real> *strGrid) const
{
Vec3 grad = 0.5 * Vec3(grid(i + 1, j, k) - grid(i - 1, j, k),
grid(i, j + 1, k) - grid(i, j - 1, k),
0.);
if (grid.is3D())
grad[2] = 0.5 * (grid(i, j, k + 1) - grid(i, j, k - 1));
normalize(grad);
if (strGrid)
str += (*strGrid)(i, j, k);
force(i, j, k) = str * cross(grad, curl(i, j, k));
}
inline Grid<Vec3> &getArg0()
{
return force;
}
typedef Grid<Vec3> type0;
inline const Grid<Real> &getArg1()
{
return grid;
}
typedef Grid<Real> type1;
inline const Grid<Vec3> &getArg2()
{
return curl;
}
typedef Grid<Vec3> type2;
inline Real &getArg3()
{
return str;
}
typedef Real type3;
inline const Grid<Real> *getArg4()
{
return strGrid;
}
typedef Grid<Real> type4;
void runMessage()
{
debMsg("Executing kernel KnConfForce ", 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, force, grid, curl, str, strGrid);
}
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, force, grid, curl, str, strGrid);
}
}
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<Vec3> &force;
const Grid<Real> &grid;
const Grid<Vec3> &curl;
Real str;
const Grid<Real> *strGrid;
};
void vorticityConfinement(MACGrid &vel,
const FlagGrid &flags,
Real strength = 0,
const Grid<Real> *strengthCell = nullptr)
{
Grid<Vec3> velCenter(flags.getParent()), curl(flags.getParent()), force(flags.getParent());
Grid<Real> norm(flags.getParent());
GetCentered(velCenter, vel);
CurlOp(velCenter, curl);
GridNorm(norm, curl);
KnConfForce(force, norm, curl, strength, strengthCell);
KnApplyForceField(flags, vel, force, nullptr, true, false);
}
static PyObject *_W_8(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, "vorticityConfinement", !noTiming);
PyObject *_retval = nullptr;
{
ArgLocker _lock;
MACGrid &vel = *_args.getPtr<MACGrid>("vel", 0, &_lock);
const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 1, &_lock);
Real strength = _args.getOpt<Real>("strength", 2, 0, &_lock);
const Grid<Real> *strengthCell = _args.getPtrOpt<Grid<Real>>(
"strengthCell", 3, nullptr, &_lock);
_retval = getPyNone();
vorticityConfinement(vel, flags, strength, strengthCell);
_args.check();
}
pbFinalizePlugin(parent, "vorticityConfinement", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("vorticityConfinement", e.what());
return 0;
}
}
static const Pb::Register _RP_vorticityConfinement("", "vorticityConfinement", _W_8);
extern "C" {
void PbRegister_vorticityConfinement()
{
KEEP_UNUSED(_RP_vorticityConfinement);
}
}
void addForceField(const FlagGrid &flags,
MACGrid &vel,
const Grid<Vec3> &force,
const Grid<Real> *region = nullptr,
bool isMAC = false)
{
KnApplyForceField(flags, vel, force, region, true, isMAC);
}
static PyObject *_W_9(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, "addForceField", !noTiming);
PyObject *_retval = nullptr;
{
ArgLocker _lock;
const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
MACGrid &vel = *_args.getPtr<MACGrid>("vel", 1, &_lock);
const Grid<Vec3> &force = *_args.getPtr<Grid<Vec3>>("force", 2, &_lock);
const Grid<Real> *region = _args.getPtrOpt<Grid<Real>>("region", 3, nullptr, &_lock);
bool isMAC = _args.getOpt<bool>("isMAC", 4, false, &_lock);
_retval = getPyNone();
addForceField(flags, vel, force, region, isMAC);
_args.check();
}
pbFinalizePlugin(parent, "addForceField", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("addForceField", e.what());
return 0;
}
}
static const Pb::Register _RP_addForceField("", "addForceField", _W_9);
extern "C" {
void PbRegister_addForceField()
{
KEEP_UNUSED(_RP_addForceField);
}
}
void setForceField(const FlagGrid &flags,
MACGrid &vel,
const Grid<Vec3> &force,
const Grid<Real> *region = nullptr,
bool isMAC = false)
{
KnApplyForceField(flags, vel, force, region, false, isMAC);
}
static PyObject *_W_10(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, "setForceField", !noTiming);
PyObject *_retval = nullptr;
{
ArgLocker _lock;
const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
MACGrid &vel = *_args.getPtr<MACGrid>("vel", 1, &_lock);
const Grid<Vec3> &force = *_args.getPtr<Grid<Vec3>>("force", 2, &_lock);
const Grid<Real> *region = _args.getPtrOpt<Grid<Real>>("region", 3, nullptr, &_lock);
bool isMAC = _args.getOpt<bool>("isMAC", 4, false, &_lock);
_retval = getPyNone();
setForceField(flags, vel, force, region, isMAC);
_args.check();
}
pbFinalizePlugin(parent, "setForceField", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("setForceField", e.what());
return 0;
}
}
static const Pb::Register _RP_setForceField("", "setForceField", _W_10);
extern "C" {
void PbRegister_setForceField()
{
KEEP_UNUSED(_RP_setForceField);
}
}
struct KnDissolveSmoke : public KernelBase {
KnDissolveSmoke(const FlagGrid &flags,
Grid<Real> &density,
Grid<Real> *heat,
Grid<Real> *red,
Grid<Real> *green,
Grid<Real> *blue,
int speed,
bool logFalloff,
float dydx,
float fac)
: KernelBase(&flags, 0),
flags(flags),
density(density),
heat(heat),
red(red),
green(green),
blue(blue),
speed(speed),
logFalloff(logFalloff),
dydx(dydx),
fac(fac)
{
runMessage();
run();
}
inline void op(int i,
int j,
int k,
const FlagGrid &flags,
Grid<Real> &density,
Grid<Real> *heat,
Grid<Real> *red,
Grid<Real> *green,
Grid<Real> *blue,
int speed,
bool logFalloff,
float dydx,
float fac) const
{
bool curFluid = flags.isFluid(i, j, k);
if (!curFluid)
return;
if (logFalloff) {
density(i, j, k) *= fac;
if (heat) {
(*heat)(i, j, k) *= fac;
}
if (red) {
(*red)(i, j, k) *= fac;
(*green)(i, j, k) *= fac;
(*blue)(i, j, k) *= fac;
}
}
else { // linear falloff
float d = density(i, j, k);
density(i, j, k) -= dydx;
if (density(i, j, k) < 0.0f)
density(i, j, k) = 0.0f;
if (heat) {
if (fabs((*heat)(i, j, k)) < dydx)
(*heat)(i, j, k) = 0.0f;
else if ((*heat)(i, j, k) > 0.0f)
(*heat)(i, j, k) -= dydx;
else if ((*heat)(i, j, k) < 0.0f)
(*heat)(i, j, k) += dydx;
}
if (red && notZero(d)) {
(*red)(i, j, k) *= (density(i, j, k) / d);
(*green)(i, j, k) *= (density(i, j, k) / d);
(*blue)(i, j, k) *= (density(i, j, k) / d);
}
}
}
inline const FlagGrid &getArg0()
{
return flags;
}
typedef FlagGrid type0;
inline Grid<Real> &getArg1()
{
return density;
}
typedef Grid<Real> type1;
inline Grid<Real> *getArg2()
{
return heat;
}
typedef Grid<Real> type2;
inline Grid<Real> *getArg3()
{
return red;
}
typedef Grid<Real> type3;
inline Grid<Real> *getArg4()
{
return green;
}
typedef Grid<Real> type4;
inline Grid<Real> *getArg5()
{
return blue;
}
typedef Grid<Real> type5;
inline int &getArg6()
{
return speed;
}
typedef int type6;
inline bool &getArg7()
{
return logFalloff;
}
typedef bool type7;
inline float &getArg8()
{
return dydx;
}
typedef float type8;
inline float &getArg9()
{
return fac;
}
typedef float type9;
void runMessage()
{
debMsg("Executing kernel KnDissolveSmoke ", 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, density, heat, red, green, blue, speed, logFalloff, dydx, fac);
}
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, density, heat, red, green, blue, speed, logFalloff, dydx, fac);
}
}
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);
}
const FlagGrid &flags;
Grid<Real> &density;
Grid<Real> *heat;
Grid<Real> *red;
Grid<Real> *green;
Grid<Real> *blue;
int speed;
bool logFalloff;
float dydx;
float fac;
};
void dissolveSmoke(const FlagGrid &flags,
Grid<Real> &density,
Grid<Real> *heat = nullptr,
Grid<Real> *red = nullptr,
Grid<Real> *green = nullptr,
Grid<Real> *blue = nullptr,
int speed = 5,
bool logFalloff = true)
{
float dydx = 1.0f / (float)speed; // max density/speed = dydx
float fac = 1.0f - dydx;
KnDissolveSmoke(flags, density, heat, red, green, blue, speed, logFalloff, dydx, fac);
}
static PyObject *_W_11(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, "dissolveSmoke", !noTiming);
PyObject *_retval = nullptr;
{
ArgLocker _lock;
const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
Grid<Real> &density = *_args.getPtr<Grid<Real>>("density", 1, &_lock);
Grid<Real> *heat = _args.getPtrOpt<Grid<Real>>("heat", 2, nullptr, &_lock);
Grid<Real> *red = _args.getPtrOpt<Grid<Real>>("red", 3, nullptr, &_lock);
Grid<Real> *green = _args.getPtrOpt<Grid<Real>>("green", 4, nullptr, &_lock);
Grid<Real> *blue = _args.getPtrOpt<Grid<Real>>("blue", 5, nullptr, &_lock);
int speed = _args.getOpt<int>("speed", 6, 5, &_lock);
bool logFalloff = _args.getOpt<bool>("logFalloff", 7, true, &_lock);
_retval = getPyNone();
dissolveSmoke(flags, density, heat, red, green, blue, speed, logFalloff);
_args.check();
}
pbFinalizePlugin(parent, "dissolveSmoke", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("dissolveSmoke", e.what());
return 0;
}
}
static const Pb::Register _RP_dissolveSmoke("", "dissolveSmoke", _W_11);
extern "C" {
void PbRegister_dissolveSmoke()
{
KEEP_UNUSED(_RP_dissolveSmoke);
}
}
} // namespace Manta