4ff7c5eed6
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
1560 lines
48 KiB
C++
1560 lines
48 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, automatically adapts to different grid sizes
|
|
void addGravity(const FlagGrid &flags,
|
|
MACGrid &vel,
|
|
Vec3 gravity,
|
|
const Grid<Real> *exclude = NULL)
|
|
{
|
|
Vec3 f = gravity * flags.getParent()->getDt() / flags.getDx();
|
|
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 = 0;
|
|
{
|
|
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, NULL, &_lock);
|
|
_retval = getPyNone();
|
|
addGravity(flags, vel, gravity, exclude);
|
|
_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);
|
|
}
|
|
}
|
|
|
|
//! add gravity forces to all fluid cells , but dont account for changing cell size
|
|
void addGravityNoScale(const FlagGrid &flags,
|
|
MACGrid &vel,
|
|
const Vec3 &gravity,
|
|
const Grid<Real> *exclude = NULL)
|
|
{
|
|
const Vec3 f = gravity * flags.getParent()->getDt();
|
|
KnApplyForce(flags, vel, f, exclude, true);
|
|
}
|
|
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 = 0;
|
|
{
|
|
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, NULL, &_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 fctor (e.g. smoke density)
|
|
void addBuoyancy(const FlagGrid &flags,
|
|
const Grid<Real> &density,
|
|
MACGrid &vel,
|
|
Vec3 gravity,
|
|
Real coefficient = 1.)
|
|
{
|
|
Vec3 f = -gravity * flags.getParent()->getDt() / flags.getParent()->getDx() * 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 = 0;
|
|
{
|
|
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);
|
|
_retval = getPyNone();
|
|
addBuoyancy(flags, density, vel, gravity, coefficient);
|
|
_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 = 0;
|
|
{
|
|
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 = 0,
|
|
BasicParticleSystem *parts = 0,
|
|
Grid<Real> *real = 0,
|
|
Grid<int> *index = 0,
|
|
ParticleIndexSystem *indexSys = 0)
|
|
{
|
|
// 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 = 0;
|
|
{
|
|
ArgLocker _lock;
|
|
FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
|
|
Grid<Real> *phi = _args.getPtrOpt<Grid<Real>>("phi", 1, 0, &_lock);
|
|
BasicParticleSystem *parts = _args.getPtrOpt<BasicParticleSystem>("parts", 2, 0, &_lock);
|
|
Grid<Real> *real = _args.getPtrOpt<Grid<Real>>("real", 3, 0, &_lock);
|
|
Grid<int> *index = _args.getPtrOpt<Grid<int>>("index", 4, 0, &_lock);
|
|
ParticleIndexSystem *indexSys = _args.getPtrOpt<ParticleIndexSystem>(
|
|
"indexSys", 5, 0, &_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 = 0;
|
|
{
|
|
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 currentlyl not
|
|
// needed)
|
|
void setWallBcs(const FlagGrid &flags,
|
|
MACGrid &vel,
|
|
const MACGrid *obvel = 0,
|
|
const MACGrid *fractions = 0,
|
|
const Grid<Real> *phiObs = 0,
|
|
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 = 0;
|
|
{
|
|
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, 0, &_lock);
|
|
const MACGrid *fractions = _args.getPtrOpt<MACGrid>("fractions", 3, 0, &_lock);
|
|
const Grid<Real> *phiObs = _args.getPtrOpt<Grid<Real>>("phiObs", 4, 0, &_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;
|
|
|
|
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);
|
|
Real min = std::min(vel(i, j, k).x, forceMACX);
|
|
Real max = std::max(vel(i, j, k).x, forceMACX);
|
|
Real sum = vel(i, j, k).x + forceMACX;
|
|
vel(i, j, k).x = (forceMACX > 0) ? std::min(sum, max) : std::max(sum, min);
|
|
}
|
|
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);
|
|
Real min = std::min(vel(i, j, k).y, forceMACY);
|
|
Real max = std::max(vel(i, j, k).y, forceMACY);
|
|
Real sum = vel(i, j, k).y + forceMACY;
|
|
vel(i, j, k).y = (forceMACY > 0) ? std::min(sum, max) : std::max(sum, min);
|
|
}
|
|
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);
|
|
Real min = std::min(vel(i, j, k).z, forceMACZ);
|
|
Real max = std::max(vel(i, j, k).z, forceMACZ);
|
|
Real sum = vel(i, j, k).z + forceMACZ;
|
|
vel(i, j, k).z = (forceMACZ > 0) ? std::min(sum, max) : std::max(sum, min);
|
|
}
|
|
}
|
|
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 = 0;
|
|
{
|
|
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 strengthGlobal = 0,
|
|
const Grid<Real> *strengthCell = NULL)
|
|
{
|
|
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, strengthGlobal, strengthCell);
|
|
KnApplyForceField(flags, vel, force, NULL, 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 = 0;
|
|
{
|
|
ArgLocker _lock;
|
|
MACGrid &vel = *_args.getPtr<MACGrid>("vel", 0, &_lock);
|
|
const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 1, &_lock);
|
|
Real strengthGlobal = _args.getOpt<Real>("strengthGlobal", 2, 0, &_lock);
|
|
const Grid<Real> *strengthCell = _args.getPtrOpt<Grid<Real>>(
|
|
"strengthCell", 3, NULL, &_lock);
|
|
_retval = getPyNone();
|
|
vorticityConfinement(vel, flags, strengthGlobal, 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 = NULL,
|
|
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 = 0;
|
|
{
|
|
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, NULL, &_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 = NULL,
|
|
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 = 0;
|
|
{
|
|
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, NULL, &_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);
|
|
}
|
|
}
|
|
|
|
void dissolveSmoke(const FlagGrid &flags,
|
|
Grid<Real> &density,
|
|
Grid<Real> *heat = NULL,
|
|
Grid<Real> *red = NULL,
|
|
Grid<Real> *green = NULL,
|
|
Grid<Real> *blue = NULL,
|
|
int speed = 5,
|
|
bool logFalloff = true)
|
|
{
|
|
float dydx = 1.0f / (float)speed; // max density/speed = dydx
|
|
float fac = 1.0f - dydx;
|
|
|
|
FOR_IJK_BND(density, 0)
|
|
{
|
|
bool curFluid = flags.isFluid(i, j, k);
|
|
if (!curFluid)
|
|
continue;
|
|
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
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 = 0;
|
|
{
|
|
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, NULL, &_lock);
|
|
Grid<Real> *red = _args.getPtrOpt<Grid<Real>>("red", 3, NULL, &_lock);
|
|
Grid<Real> *green = _args.getPtrOpt<Grid<Real>>("green", 4, NULL, &_lock);
|
|
Grid<Real> *blue = _args.getPtrOpt<Grid<Real>>("blue", 5, NULL, &_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
|