Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastián Barschkis <sebbas@sebbas.org>2019-12-16 17:40:15 +0300
committerSebastián Barschkis <sebbas@sebbas.org>2019-12-16 18:27:26 +0300
commit4ff7c5eed6b546ae42692f3a869a5ccc095a9cb4 (patch)
tree03f8233788ae46e66672f711e3cf42d8d00d01cc /extern/mantaflow/preprocessed/plugin/flip.cpp
parent6a3f2b30d206df23120cd212132adea821b6c20e (diff)
Mantaflow [Part 1]: Added preprocessed Mantaflow source files
Includes preprocessed Mantaflow source files for both OpenMP and TBB (if OpenMP is not present, TBB files will be used instead). These files come directly from the Mantaflow repository. Future updates to the core fluid solver will take place by updating the files. Reviewed By: sergey, mont29 Maniphest Tasks: T59995 Differential Revision: https://developer.blender.org/D3850
Diffstat (limited to 'extern/mantaflow/preprocessed/plugin/flip.cpp')
-rw-r--r--extern/mantaflow/preprocessed/plugin/flip.cpp2819
1 files changed, 2819 insertions, 0 deletions
diff --git a/extern/mantaflow/preprocessed/plugin/flip.cpp b/extern/mantaflow/preprocessed/plugin/flip.cpp
new file mode 100644
index 00000000000..f6d082900b5
--- /dev/null
+++ b/extern/mantaflow/preprocessed/plugin/flip.cpp
@@ -0,0 +1,2819 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * FLIP (fluid implicit particles)
+ * for use with particle data fields
+ *
+ ******************************************************************************/
+
+#include "particle.h"
+#include "grid.h"
+#include "commonkernels.h"
+#include "randomstream.h"
+#include "levelset.h"
+#include "shapes.h"
+#include "matrixbase.h"
+
+using namespace std;
+namespace Manta {
+
+// init
+
+//! note - this is a simplified version , sampleLevelsetWithParticles has more functionality
+
+void sampleFlagsWithParticles(const FlagGrid &flags,
+ BasicParticleSystem &parts,
+ const int discretization,
+ const Real randomness)
+{
+ const bool is3D = flags.is3D();
+ const Real jlen = randomness / discretization;
+ const Vec3 disp(1.0 / discretization, 1.0 / discretization, 1.0 / discretization);
+ RandomStream mRand(9832);
+
+ FOR_IJK_BND(flags, 0)
+ {
+ if (flags.isObstacle(i, j, k))
+ continue;
+ if (flags.isFluid(i, j, k)) {
+ const Vec3 pos(i, j, k);
+ for (int dk = 0; dk < (is3D ? discretization : 1); dk++)
+ for (int dj = 0; dj < discretization; dj++)
+ for (int di = 0; di < discretization; di++) {
+ Vec3 subpos = pos + disp * Vec3(0.5 + di, 0.5 + dj, 0.5 + dk);
+ subpos += jlen * (Vec3(1, 1, 1) - 2.0 * mRand.getVec3());
+ if (!is3D)
+ subpos[2] = 0.5;
+ parts.addBuffered(subpos);
+ }
+ }
+ }
+ parts.insertBufferedParticles();
+}
+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, "sampleFlagsWithParticles", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ BasicParticleSystem &parts = *_args.getPtr<BasicParticleSystem>("parts", 1, &_lock);
+ const int discretization = _args.get<int>("discretization", 2, &_lock);
+ const Real randomness = _args.get<Real>("randomness", 3, &_lock);
+ _retval = getPyNone();
+ sampleFlagsWithParticles(flags, parts, discretization, randomness);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "sampleFlagsWithParticles", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("sampleFlagsWithParticles", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_sampleFlagsWithParticles("", "sampleFlagsWithParticles", _W_0);
+extern "C" {
+void PbRegister_sampleFlagsWithParticles()
+{
+ KEEP_UNUSED(_RP_sampleFlagsWithParticles);
+}
+}
+
+//! sample a level set with particles, use reset to clear the particle buffer,
+//! and skipEmpty for a continuous inflow (in the latter case, only empty cells will
+//! be re-filled once they empty when calling sampleLevelsetWithParticles during
+//! the main loop).
+
+void sampleLevelsetWithParticles(const LevelsetGrid &phi,
+ const FlagGrid &flags,
+ BasicParticleSystem &parts,
+ const int discretization,
+ const Real randomness,
+ const bool reset = false,
+ const bool refillEmpty = false,
+ const int particleFlag = -1)
+{
+ const bool is3D = phi.is3D();
+ const Real jlen = randomness / discretization;
+ const Vec3 disp(1.0 / discretization, 1.0 / discretization, 1.0 / discretization);
+ RandomStream mRand(9832);
+
+ if (reset) {
+ parts.clear();
+ parts.doCompress();
+ }
+
+ FOR_IJK_BND(phi, 0)
+ {
+ if (flags.isObstacle(i, j, k))
+ continue;
+ if (refillEmpty && flags.isFluid(i, j, k))
+ continue;
+ if (phi(i, j, k) < 1.733) {
+ const Vec3 pos(i, j, k);
+ for (int dk = 0; dk < (is3D ? discretization : 1); dk++)
+ for (int dj = 0; dj < discretization; dj++)
+ for (int di = 0; di < discretization; di++) {
+ Vec3 subpos = pos + disp * Vec3(0.5 + di, 0.5 + dj, 0.5 + dk);
+ subpos += jlen * (Vec3(1, 1, 1) - 2.0 * mRand.getVec3());
+ if (!is3D)
+ subpos[2] = 0.5;
+ if (phi.getInterpolated(subpos) > 0.)
+ continue;
+ if (particleFlag < 0) {
+ parts.addBuffered(subpos);
+ }
+ else {
+ parts.addBuffered(subpos, particleFlag);
+ }
+ }
+ }
+ }
+
+ parts.insertBufferedParticles();
+}
+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, "sampleLevelsetWithParticles", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const LevelsetGrid &phi = *_args.getPtr<LevelsetGrid>("phi", 0, &_lock);
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 1, &_lock);
+ BasicParticleSystem &parts = *_args.getPtr<BasicParticleSystem>("parts", 2, &_lock);
+ const int discretization = _args.get<int>("discretization", 3, &_lock);
+ const Real randomness = _args.get<Real>("randomness", 4, &_lock);
+ const bool reset = _args.getOpt<bool>("reset", 5, false, &_lock);
+ const bool refillEmpty = _args.getOpt<bool>("refillEmpty", 6, false, &_lock);
+ const int particleFlag = _args.getOpt<int>("particleFlag", 7, -1, &_lock);
+ _retval = getPyNone();
+ sampleLevelsetWithParticles(
+ phi, flags, parts, discretization, randomness, reset, refillEmpty, particleFlag);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "sampleLevelsetWithParticles", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("sampleLevelsetWithParticles", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_sampleLevelsetWithParticles("", "sampleLevelsetWithParticles", _W_1);
+extern "C" {
+void PbRegister_sampleLevelsetWithParticles()
+{
+ KEEP_UNUSED(_RP_sampleLevelsetWithParticles);
+}
+}
+
+//! sample a shape with particles, use reset to clear the particle buffer,
+//! and skipEmpty for a continuous inflow (in the latter case, only empty cells will
+//! be re-filled once they empty when calling sampleShapeWithParticles during
+//! the main loop).
+
+void sampleShapeWithParticles(const Shape &shape,
+ const FlagGrid &flags,
+ BasicParticleSystem &parts,
+ const int discretization,
+ const Real randomness,
+ const bool reset = false,
+ const bool refillEmpty = false,
+ const LevelsetGrid *exclude = NULL)
+{
+ const bool is3D = flags.is3D();
+ const Real jlen = randomness / discretization;
+ const Vec3 disp(1.0 / discretization, 1.0 / discretization, 1.0 / discretization);
+ RandomStream mRand(9832);
+
+ if (reset) {
+ parts.clear();
+ parts.doCompress();
+ }
+
+ FOR_IJK_BND(flags, 0)
+ {
+ if (flags.isObstacle(i, j, k))
+ continue;
+ if (refillEmpty && flags.isFluid(i, j, k))
+ continue;
+ const Vec3 pos(i, j, k);
+ for (int dk = 0; dk < (is3D ? discretization : 1); dk++)
+ for (int dj = 0; dj < discretization; dj++)
+ for (int di = 0; di < discretization; di++) {
+ Vec3 subpos = pos + disp * Vec3(0.5 + di, 0.5 + dj, 0.5 + dk);
+ subpos += jlen * (Vec3(1, 1, 1) - 2.0 * mRand.getVec3());
+ if (!is3D)
+ subpos[2] = 0.5;
+ if (exclude && exclude->getInterpolated(subpos) <= 0.)
+ continue;
+ if (!shape.isInside(subpos))
+ continue;
+ parts.addBuffered(subpos);
+ }
+ }
+
+ parts.insertBufferedParticles();
+}
+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, "sampleShapeWithParticles", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const Shape &shape = *_args.getPtr<Shape>("shape", 0, &_lock);
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 1, &_lock);
+ BasicParticleSystem &parts = *_args.getPtr<BasicParticleSystem>("parts", 2, &_lock);
+ const int discretization = _args.get<int>("discretization", 3, &_lock);
+ const Real randomness = _args.get<Real>("randomness", 4, &_lock);
+ const bool reset = _args.getOpt<bool>("reset", 5, false, &_lock);
+ const bool refillEmpty = _args.getOpt<bool>("refillEmpty", 6, false, &_lock);
+ const LevelsetGrid *exclude = _args.getPtrOpt<LevelsetGrid>("exclude", 7, NULL, &_lock);
+ _retval = getPyNone();
+ sampleShapeWithParticles(
+ shape, flags, parts, discretization, randomness, reset, refillEmpty, exclude);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "sampleShapeWithParticles", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("sampleShapeWithParticles", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_sampleShapeWithParticles("", "sampleShapeWithParticles", _W_2);
+extern "C" {
+void PbRegister_sampleShapeWithParticles()
+{
+ KEEP_UNUSED(_RP_sampleShapeWithParticles);
+}
+}
+
+//! mark fluid cells and helpers
+struct knClearFluidFlags : public KernelBase {
+ knClearFluidFlags(FlagGrid &flags, int dummy = 0)
+ : KernelBase(&flags, 0), flags(flags), dummy(dummy)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i, int j, int k, FlagGrid &flags, int dummy = 0) const
+ {
+ if (flags.isFluid(i, j, k)) {
+ flags(i, j, k) = (flags(i, j, k) | FlagGrid::TypeEmpty) & ~FlagGrid::TypeFluid;
+ }
+ }
+ inline FlagGrid &getArg0()
+ {
+ return flags;
+ }
+ typedef FlagGrid type0;
+ inline int &getArg1()
+ {
+ return dummy;
+ }
+ typedef int type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel knClearFluidFlags ", 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, dummy);
+ }
+ 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, dummy);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ FlagGrid &flags;
+ int dummy;
+};
+
+struct knSetNbObstacle : public KernelBase {
+ knSetNbObstacle(FlagGrid &nflags, const FlagGrid &flags, const Grid<Real> &phiObs)
+ : KernelBase(&nflags, 1), nflags(nflags), flags(flags), phiObs(phiObs)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(
+ int i, int j, int k, FlagGrid &nflags, const FlagGrid &flags, const Grid<Real> &phiObs) const
+ {
+ if (phiObs(i, j, k) > 0.)
+ return;
+ if (flags.isEmpty(i, j, k)) {
+ bool set = false;
+ if ((flags.isFluid(i - 1, j, k)) && (phiObs(i + 1, j, k) <= 0.))
+ set = true;
+ if ((flags.isFluid(i + 1, j, k)) && (phiObs(i - 1, j, k) <= 0.))
+ set = true;
+ if ((flags.isFluid(i, j - 1, k)) && (phiObs(i, j + 1, k) <= 0.))
+ set = true;
+ if ((flags.isFluid(i, j + 1, k)) && (phiObs(i, j - 1, k) <= 0.))
+ set = true;
+ if (flags.is3D()) {
+ if ((flags.isFluid(i, j, k - 1)) && (phiObs(i, j, k + 1) <= 0.))
+ set = true;
+ if ((flags.isFluid(i, j, k + 1)) && (phiObs(i, j, k - 1) <= 0.))
+ set = true;
+ }
+ if (set)
+ nflags(i, j, k) = (flags(i, j, k) | FlagGrid::TypeFluid) & ~FlagGrid::TypeEmpty;
+ }
+ }
+ inline FlagGrid &getArg0()
+ {
+ return nflags;
+ }
+ typedef FlagGrid type0;
+ inline const FlagGrid &getArg1()
+ {
+ return flags;
+ }
+ typedef FlagGrid type1;
+ inline const Grid<Real> &getArg2()
+ {
+ return phiObs;
+ }
+ typedef Grid<Real> type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel knSetNbObstacle ", 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, nflags, flags, phiObs);
+ }
+ 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, nflags, flags, phiObs);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
+ }
+ FlagGrid &nflags;
+ const FlagGrid &flags;
+ const Grid<Real> &phiObs;
+};
+void markFluidCells(const BasicParticleSystem &parts,
+ FlagGrid &flags,
+ const Grid<Real> *phiObs = NULL,
+ const ParticleDataImpl<int> *ptype = NULL,
+ const int exclude = 0)
+{
+ // remove all fluid cells
+ knClearFluidFlags(flags, 0);
+
+ // mark all particles in flaggrid as fluid
+ for (IndexInt idx = 0; idx < parts.size(); idx++) {
+ if (!parts.isActive(idx) || (ptype && ((*ptype)[idx] & exclude)))
+ continue;
+ Vec3i p = toVec3i(parts.getPos(idx));
+ if (flags.isInBounds(p) && flags.isEmpty(p))
+ flags(p) = (flags(p) | FlagGrid::TypeFluid) & ~FlagGrid::TypeEmpty;
+ }
+
+ // special for second order obstacle BCs, check empty cells in boundary region
+ if (phiObs) {
+ FlagGrid tmp(flags);
+ knSetNbObstacle(tmp, flags, *phiObs);
+ flags.swap(tmp);
+ }
+}
+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, "markFluidCells", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const BasicParticleSystem &parts = *_args.getPtr<BasicParticleSystem>("parts", 0, &_lock);
+ FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 1, &_lock);
+ const Grid<Real> *phiObs = _args.getPtrOpt<Grid<Real>>("phiObs", 2, NULL, &_lock);
+ const ParticleDataImpl<int> *ptype = _args.getPtrOpt<ParticleDataImpl<int>>(
+ "ptype", 3, NULL, &_lock);
+ const int exclude = _args.getOpt<int>("exclude", 4, 0, &_lock);
+ _retval = getPyNone();
+ markFluidCells(parts, flags, phiObs, ptype, exclude);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "markFluidCells", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("markFluidCells", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_markFluidCells("", "markFluidCells", _W_3);
+extern "C" {
+void PbRegister_markFluidCells()
+{
+ KEEP_UNUSED(_RP_markFluidCells);
+}
+}
+
+// for testing purposes only...
+void testInitGridWithPos(Grid<Real> &grid)
+{
+ FOR_IJK(grid)
+ {
+ grid(i, j, k) = norm(Vec3(i, j, k));
+ }
+}
+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, "testInitGridWithPos", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Grid<Real> &grid = *_args.getPtr<Grid<Real>>("grid", 0, &_lock);
+ _retval = getPyNone();
+ testInitGridWithPos(grid);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "testInitGridWithPos", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("testInitGridWithPos", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_testInitGridWithPos("", "testInitGridWithPos", _W_4);
+extern "C" {
+void PbRegister_testInitGridWithPos()
+{
+ KEEP_UNUSED(_RP_testInitGridWithPos);
+}
+}
+
+//! helper to calculate particle radius factor to cover the diagonal of a cell in 2d/3d
+inline Real calculateRadiusFactor(const Grid<Real> &grid, Real factor)
+{
+ return (grid.is3D() ? sqrt(3.) : sqrt(2.)) *
+ (factor + .01); // note, a 1% safety factor is added here
+}
+
+//! re-sample particles based on an input levelset
+// optionally skip seeding new particles in "exclude" SDF
+
+void adjustNumber(BasicParticleSystem &parts,
+ const MACGrid &vel,
+ const FlagGrid &flags,
+ int minParticles,
+ int maxParticles,
+ const LevelsetGrid &phi,
+ Real radiusFactor = 1.,
+ Real narrowBand = -1.,
+ const Grid<Real> *exclude = NULL)
+{
+ // which levelset to use as threshold
+ const Real SURFACE_LS = -1.0 * calculateRadiusFactor(phi, radiusFactor);
+ Grid<int> tmp(vel.getParent());
+ std::ostringstream out;
+
+ // count particles in cells, and delete excess particles
+ for (IndexInt idx = 0; idx < (int)parts.size(); idx++) {
+ if (parts.isActive(idx)) {
+ Vec3i p = toVec3i(parts.getPos(idx));
+ if (!tmp.isInBounds(p)) {
+ parts.kill(idx); // out of domain, remove
+ continue;
+ }
+
+ Real phiv = phi.getInterpolated(parts.getPos(idx));
+ if (phiv > 0) {
+ parts.kill(idx);
+ continue;
+ }
+ if (narrowBand > 0. && phiv < -narrowBand) {
+ parts.kill(idx);
+ continue;
+ }
+
+ bool atSurface = false;
+ if (phiv > SURFACE_LS)
+ atSurface = true;
+ int num = tmp(p);
+
+ // dont delete particles in non fluid cells here, the particles are "always right"
+ if (num > maxParticles && (!atSurface)) {
+ parts.kill(idx);
+ }
+ else {
+ tmp(p) = num + 1;
+ }
+ }
+ }
+
+ // seed new particles
+ RandomStream mRand(9832);
+ FOR_IJK(tmp)
+ {
+ int cnt = tmp(i, j, k);
+
+ // skip cells near surface
+ if (phi(i, j, k) > SURFACE_LS)
+ continue;
+ if (narrowBand > 0. && phi(i, j, k) < -narrowBand) {
+ continue;
+ }
+ if (exclude && ((*exclude)(i, j, k) < 0.)) {
+ continue;
+ }
+
+ if (flags.isFluid(i, j, k) && cnt < minParticles) {
+ for (int m = cnt; m < minParticles; m++) {
+ Vec3 pos = Vec3(i, j, k) + mRand.getVec3();
+ // Vec3 pos (i + 0.5, j + 0.5, k + 0.5); // cell center
+ parts.addBuffered(pos);
+ }
+ }
+ }
+
+ parts.doCompress();
+ parts.insertBufferedParticles();
+}
+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, "adjustNumber", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ BasicParticleSystem &parts = *_args.getPtr<BasicParticleSystem>("parts", 0, &_lock);
+ const MACGrid &vel = *_args.getPtr<MACGrid>("vel", 1, &_lock);
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 2, &_lock);
+ int minParticles = _args.get<int>("minParticles", 3, &_lock);
+ int maxParticles = _args.get<int>("maxParticles", 4, &_lock);
+ const LevelsetGrid &phi = *_args.getPtr<LevelsetGrid>("phi", 5, &_lock);
+ Real radiusFactor = _args.getOpt<Real>("radiusFactor", 6, 1., &_lock);
+ Real narrowBand = _args.getOpt<Real>("narrowBand", 7, -1., &_lock);
+ const Grid<Real> *exclude = _args.getPtrOpt<Grid<Real>>("exclude", 8, NULL, &_lock);
+ _retval = getPyNone();
+ adjustNumber(
+ parts, vel, flags, minParticles, maxParticles, phi, radiusFactor, narrowBand, exclude);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "adjustNumber", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("adjustNumber", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_adjustNumber("", "adjustNumber", _W_5);
+extern "C" {
+void PbRegister_adjustNumber()
+{
+ KEEP_UNUSED(_RP_adjustNumber);
+}
+}
+
+// simple and slow helper conversion to show contents of int grids like a real grid in the ui
+// (use eg to quickly display contents of the particle-index grid)
+
+void debugIntToReal(const Grid<int> &source, Grid<Real> &dest, Real factor = 1.)
+{
+ FOR_IJK(source)
+ {
+ dest(i, j, k) = (Real)source(i, j, k) * factor;
+ }
+}
+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, "debugIntToReal", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const Grid<int> &source = *_args.getPtr<Grid<int>>("source", 0, &_lock);
+ Grid<Real> &dest = *_args.getPtr<Grid<Real>>("dest", 1, &_lock);
+ Real factor = _args.getOpt<Real>("factor", 2, 1., &_lock);
+ _retval = getPyNone();
+ debugIntToReal(source, dest, factor);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "debugIntToReal", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("debugIntToReal", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_debugIntToReal("", "debugIntToReal", _W_6);
+extern "C" {
+void PbRegister_debugIntToReal()
+{
+ KEEP_UNUSED(_RP_debugIntToReal);
+}
+}
+
+// build a grid that contains indices for a particle system
+// the particles in a cell i,j,k are particles[index(i,j,k)] to particles[index(i+1,j,k)-1]
+// (ie, particles[index(i+1,j,k)] already belongs to cell i+1,j,k)
+
+void gridParticleIndex(const BasicParticleSystem &parts,
+ ParticleIndexSystem &indexSys,
+ const FlagGrid &flags,
+ Grid<int> &index,
+ Grid<int> *counter = NULL)
+{
+ bool delCounter = false;
+ if (!counter) {
+ counter = new Grid<int>(flags.getParent());
+ delCounter = true;
+ }
+ else {
+ counter->clear();
+ }
+
+ // count particles in cells, and delete excess particles
+ index.clear();
+ int inactive = 0;
+ for (IndexInt idx = 0; idx < (IndexInt)parts.size(); idx++) {
+ if (parts.isActive(idx)) {
+ // check index for validity...
+ Vec3i p = toVec3i(parts.getPos(idx));
+ if (!index.isInBounds(p)) {
+ inactive++;
+ continue;
+ }
+
+ index(p)++;
+ }
+ else {
+ inactive++;
+ }
+ }
+
+ // note - this one might be smaller...
+ indexSys.resize(parts.size() - inactive);
+
+ // convert per cell number to continuous index
+ IndexInt idx = 0;
+ FOR_IJK(index)
+ {
+ int num = index(i, j, k);
+ index(i, j, k) = idx;
+ idx += num;
+ }
+
+ // add particles to indexed array, we still need a per cell particle counter
+ for (IndexInt idx = 0; idx < (IndexInt)parts.size(); idx++) {
+ if (!parts.isActive(idx))
+ continue;
+ Vec3i p = toVec3i(parts.getPos(idx));
+ if (!index.isInBounds(p)) {
+ continue;
+ }
+
+ // initialize position and index into original array
+ // indexSys[ index(p)+(*counter)(p) ].pos = parts[idx].pos;
+ indexSys[index(p) + (*counter)(p)].sourceIndex = idx;
+ (*counter)(p)++;
+ }
+
+ if (delCounter)
+ delete counter;
+}
+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, "gridParticleIndex", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const BasicParticleSystem &parts = *_args.getPtr<BasicParticleSystem>("parts", 0, &_lock);
+ ParticleIndexSystem &indexSys = *_args.getPtr<ParticleIndexSystem>("indexSys", 1, &_lock);
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 2, &_lock);
+ Grid<int> &index = *_args.getPtr<Grid<int>>("index", 3, &_lock);
+ Grid<int> *counter = _args.getPtrOpt<Grid<int>>("counter", 4, NULL, &_lock);
+ _retval = getPyNone();
+ gridParticleIndex(parts, indexSys, flags, index, counter);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "gridParticleIndex", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("gridParticleIndex", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_gridParticleIndex("", "gridParticleIndex", _W_7);
+extern "C" {
+void PbRegister_gridParticleIndex()
+{
+ KEEP_UNUSED(_RP_gridParticleIndex);
+}
+}
+
+struct ComputeUnionLevelsetPindex : public KernelBase {
+ ComputeUnionLevelsetPindex(const Grid<int> &index,
+ const BasicParticleSystem &parts,
+ const ParticleIndexSystem &indexSys,
+ LevelsetGrid &phi,
+ const Real radius,
+ const ParticleDataImpl<int> *ptype,
+ const int exclude)
+ : KernelBase(&index, 0),
+ index(index),
+ parts(parts),
+ indexSys(indexSys),
+ phi(phi),
+ radius(radius),
+ ptype(ptype),
+ exclude(exclude)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ const Grid<int> &index,
+ const BasicParticleSystem &parts,
+ const ParticleIndexSystem &indexSys,
+ LevelsetGrid &phi,
+ const Real radius,
+ const ParticleDataImpl<int> *ptype,
+ const int exclude) const
+ {
+ const Vec3 gridPos = Vec3(i, j, k) + Vec3(0.5); // shifted by half cell
+ Real phiv = radius * 1.0; // outside
+
+ int r = int(radius) + 1;
+ int rZ = phi.is3D() ? r : 0;
+ for (int zj = k - rZ; zj <= k + rZ; zj++)
+ for (int yj = j - r; yj <= j + r; yj++)
+ for (int xj = i - r; xj <= i + r; xj++) {
+ if (!phi.isInBounds(Vec3i(xj, yj, zj)))
+ continue;
+
+ // note, for the particle indices in indexSys the access is periodic (ie, dont skip for
+ // eg inBounds(sx,10,10)
+ IndexInt isysIdxS = index.index(xj, yj, zj);
+ IndexInt pStart = index(isysIdxS), pEnd = 0;
+ if (phi.isInBounds(isysIdxS + 1))
+ pEnd = index(isysIdxS + 1);
+ else
+ pEnd = indexSys.size();
+
+ // now loop over particles in cell
+ for (IndexInt p = pStart; p < pEnd; ++p) {
+ const int psrc = indexSys[p].sourceIndex;
+ if (ptype && ((*ptype)[psrc] & exclude))
+ continue;
+ const Vec3 pos = parts[psrc].pos;
+ phiv = std::min(phiv, fabs(norm(gridPos - pos)) - radius);
+ }
+ }
+ phi(i, j, k) = phiv;
+ }
+ inline const Grid<int> &getArg0()
+ {
+ return index;
+ }
+ typedef Grid<int> type0;
+ inline const BasicParticleSystem &getArg1()
+ {
+ return parts;
+ }
+ typedef BasicParticleSystem type1;
+ inline const ParticleIndexSystem &getArg2()
+ {
+ return indexSys;
+ }
+ typedef ParticleIndexSystem type2;
+ inline LevelsetGrid &getArg3()
+ {
+ return phi;
+ }
+ typedef LevelsetGrid type3;
+ inline const Real &getArg4()
+ {
+ return radius;
+ }
+ typedef Real type4;
+ inline const ParticleDataImpl<int> *getArg5()
+ {
+ return ptype;
+ }
+ typedef ParticleDataImpl<int> type5;
+ inline const int &getArg6()
+ {
+ return exclude;
+ }
+ typedef int type6;
+ void runMessage()
+ {
+ debMsg("Executing kernel ComputeUnionLevelsetPindex ", 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, index, parts, indexSys, phi, radius, ptype, exclude);
+ }
+ 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, index, parts, indexSys, phi, radius, ptype, exclude);
+ }
+ }
+ 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 Grid<int> &index;
+ const BasicParticleSystem &parts;
+ const ParticleIndexSystem &indexSys;
+ LevelsetGrid &phi;
+ const Real radius;
+ const ParticleDataImpl<int> *ptype;
+ const int exclude;
+};
+
+void unionParticleLevelset(const BasicParticleSystem &parts,
+ const ParticleIndexSystem &indexSys,
+ const FlagGrid &flags,
+ const Grid<int> &index,
+ LevelsetGrid &phi,
+ const Real radiusFactor = 1.,
+ const ParticleDataImpl<int> *ptype = NULL,
+ const int exclude = 0)
+{
+ // use half a cell diagonal as base radius
+ const Real radius = 0.5 * calculateRadiusFactor(phi, radiusFactor);
+ // no reset of phi necessary here
+ ComputeUnionLevelsetPindex(index, parts, indexSys, phi, radius, ptype, exclude);
+
+ phi.setBound(0.5, 0);
+}
+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, "unionParticleLevelset", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const BasicParticleSystem &parts = *_args.getPtr<BasicParticleSystem>("parts", 0, &_lock);
+ const ParticleIndexSystem &indexSys = *_args.getPtr<ParticleIndexSystem>(
+ "indexSys", 1, &_lock);
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 2, &_lock);
+ const Grid<int> &index = *_args.getPtr<Grid<int>>("index", 3, &_lock);
+ LevelsetGrid &phi = *_args.getPtr<LevelsetGrid>("phi", 4, &_lock);
+ const Real radiusFactor = _args.getOpt<Real>("radiusFactor", 5, 1., &_lock);
+ const ParticleDataImpl<int> *ptype = _args.getPtrOpt<ParticleDataImpl<int>>(
+ "ptype", 6, NULL, &_lock);
+ const int exclude = _args.getOpt<int>("exclude", 7, 0, &_lock);
+ _retval = getPyNone();
+ unionParticleLevelset(parts, indexSys, flags, index, phi, radiusFactor, ptype, exclude);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "unionParticleLevelset", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("unionParticleLevelset", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_unionParticleLevelset("", "unionParticleLevelset", _W_8);
+extern "C" {
+void PbRegister_unionParticleLevelset()
+{
+ KEEP_UNUSED(_RP_unionParticleLevelset);
+}
+}
+
+//! kernel for computing averaged particle level set weights
+
+struct ComputeAveragedLevelsetWeight : public KernelBase {
+ ComputeAveragedLevelsetWeight(const BasicParticleSystem &parts,
+ const Grid<int> &index,
+ const ParticleIndexSystem &indexSys,
+ LevelsetGrid &phi,
+ const Real radius,
+ const ParticleDataImpl<int> *ptype,
+ const int exclude,
+ Grid<Vec3> *save_pAcc = NULL,
+ Grid<Real> *save_rAcc = NULL)
+ : KernelBase(&index, 0),
+ parts(parts),
+ index(index),
+ indexSys(indexSys),
+ phi(phi),
+ radius(radius),
+ ptype(ptype),
+ exclude(exclude),
+ save_pAcc(save_pAcc),
+ save_rAcc(save_rAcc)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ const BasicParticleSystem &parts,
+ const Grid<int> &index,
+ const ParticleIndexSystem &indexSys,
+ LevelsetGrid &phi,
+ const Real radius,
+ const ParticleDataImpl<int> *ptype,
+ const int exclude,
+ Grid<Vec3> *save_pAcc = NULL,
+ Grid<Real> *save_rAcc = NULL) const
+ {
+ const Vec3 gridPos = Vec3(i, j, k) + Vec3(0.5); // shifted by half cell
+ Real phiv = radius * 1.0; // outside
+
+ // loop over neighborhood, similar to ComputeUnionLevelsetPindex
+ const Real sradiusInv = 1. / (4. * radius * radius);
+ int r = int(1. * radius) + 1;
+ int rZ = phi.is3D() ? r : 0;
+ // accumulators
+ Real wacc = 0.;
+ Vec3 pacc = Vec3(0.);
+ Real racc = 0.;
+
+ for (int zj = k - rZ; zj <= k + rZ; zj++)
+ for (int yj = j - r; yj <= j + r; yj++)
+ for (int xj = i - r; xj <= i + r; xj++) {
+ if (!phi.isInBounds(Vec3i(xj, yj, zj)))
+ continue;
+
+ IndexInt isysIdxS = index.index(xj, yj, zj);
+ IndexInt pStart = index(isysIdxS), pEnd = 0;
+ if (phi.isInBounds(isysIdxS + 1))
+ pEnd = index(isysIdxS + 1);
+ else
+ pEnd = indexSys.size();
+ for (IndexInt p = pStart; p < pEnd; ++p) {
+ IndexInt psrc = indexSys[p].sourceIndex;
+ if (ptype && ((*ptype)[psrc] & exclude))
+ continue;
+
+ Vec3 pos = parts[psrc].pos;
+ Real s = normSquare(gridPos - pos) * sradiusInv;
+ // Real w = std::max(0., cubed(1.-s) );
+ Real w = std::max(0., (1. - s)); // a bit smoother
+ wacc += w;
+ racc += radius * w;
+ pacc += pos * w;
+ }
+ }
+
+ if (wacc > VECTOR_EPSILON) {
+ racc /= wacc;
+ pacc /= wacc;
+ phiv = fabs(norm(gridPos - pacc)) - racc;
+
+ if (save_pAcc)
+ (*save_pAcc)(i, j, k) = pacc;
+ if (save_rAcc)
+ (*save_rAcc)(i, j, k) = racc;
+ }
+ phi(i, j, k) = phiv;
+ }
+ inline const BasicParticleSystem &getArg0()
+ {
+ return parts;
+ }
+ typedef BasicParticleSystem type0;
+ inline const Grid<int> &getArg1()
+ {
+ return index;
+ }
+ typedef Grid<int> type1;
+ inline const ParticleIndexSystem &getArg2()
+ {
+ return indexSys;
+ }
+ typedef ParticleIndexSystem type2;
+ inline LevelsetGrid &getArg3()
+ {
+ return phi;
+ }
+ typedef LevelsetGrid type3;
+ inline const Real &getArg4()
+ {
+ return radius;
+ }
+ typedef Real type4;
+ inline const ParticleDataImpl<int> *getArg5()
+ {
+ return ptype;
+ }
+ typedef ParticleDataImpl<int> type5;
+ inline const int &getArg6()
+ {
+ return exclude;
+ }
+ typedef int type6;
+ inline Grid<Vec3> *getArg7()
+ {
+ return save_pAcc;
+ }
+ typedef Grid<Vec3> type7;
+ inline Grid<Real> *getArg8()
+ {
+ return save_rAcc;
+ }
+ typedef Grid<Real> type8;
+ void runMessage()
+ {
+ debMsg("Executing kernel ComputeAveragedLevelsetWeight ", 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, parts, index, indexSys, phi, radius, ptype, exclude, save_pAcc, save_rAcc);
+ }
+ 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, parts, index, indexSys, phi, radius, ptype, exclude, save_pAcc, save_rAcc);
+ }
+ }
+ 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 BasicParticleSystem &parts;
+ const Grid<int> &index;
+ const ParticleIndexSystem &indexSys;
+ LevelsetGrid &phi;
+ const Real radius;
+ const ParticleDataImpl<int> *ptype;
+ const int exclude;
+ Grid<Vec3> *save_pAcc;
+ Grid<Real> *save_rAcc;
+};
+
+template<class T> T smoothingValue(const Grid<T> val, int i, int j, int k, T center)
+{
+ return val(i, j, k);
+}
+
+// smoothing, and
+
+template<class T> struct knSmoothGrid : public KernelBase {
+ knSmoothGrid(const Grid<T> &me, Grid<T> &tmp, Real factor)
+ : KernelBase(&me, 1), me(me), tmp(tmp), factor(factor)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i, int j, int k, const Grid<T> &me, Grid<T> &tmp, Real factor) const
+ {
+ T val = me(i, j, k) + me(i + 1, j, k) + me(i - 1, j, k) + me(i, j + 1, k) + me(i, j - 1, k);
+ if (me.is3D()) {
+ val += me(i, j, k + 1) + me(i, j, k - 1);
+ }
+ tmp(i, j, k) = val * factor;
+ }
+ inline const Grid<T> &getArg0()
+ {
+ return me;
+ }
+ typedef Grid<T> type0;
+ inline Grid<T> &getArg1()
+ {
+ return tmp;
+ }
+ typedef Grid<T> type1;
+ inline Real &getArg2()
+ {
+ return factor;
+ }
+ typedef Real type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel knSmoothGrid ", 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, me, tmp, factor);
+ }
+ 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, me, tmp, factor);
+ }
+ }
+ 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 Grid<T> &me;
+ Grid<T> &tmp;
+ Real factor;
+};
+
+template<class T> struct knSmoothGridNeg : public KernelBase {
+ knSmoothGridNeg(const Grid<T> &me, Grid<T> &tmp, Real factor)
+ : KernelBase(&me, 1), me(me), tmp(tmp), factor(factor)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i, int j, int k, const Grid<T> &me, Grid<T> &tmp, Real factor) const
+ {
+ T val = me(i, j, k) + me(i + 1, j, k) + me(i - 1, j, k) + me(i, j + 1, k) + me(i, j - 1, k);
+ if (me.is3D()) {
+ val += me(i, j, k + 1) + me(i, j, k - 1);
+ }
+ val *= factor;
+ if (val < tmp(i, j, k))
+ tmp(i, j, k) = val;
+ else
+ tmp(i, j, k) = me(i, j, k);
+ }
+ inline const Grid<T> &getArg0()
+ {
+ return me;
+ }
+ typedef Grid<T> type0;
+ inline Grid<T> &getArg1()
+ {
+ return tmp;
+ }
+ typedef Grid<T> type1;
+ inline Real &getArg2()
+ {
+ return factor;
+ }
+ typedef Real type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel knSmoothGridNeg ", 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, me, tmp, factor);
+ }
+ 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, me, tmp, factor);
+ }
+ }
+ 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 Grid<T> &me;
+ Grid<T> &tmp;
+ Real factor;
+};
+
+//! Zhu & Bridson particle level set creation
+
+void averagedParticleLevelset(const BasicParticleSystem &parts,
+ const ParticleIndexSystem &indexSys,
+ const FlagGrid &flags,
+ const Grid<int> &index,
+ LevelsetGrid &phi,
+ const Real radiusFactor = 1.,
+ const int smoothen = 1,
+ const int smoothenNeg = 1,
+ const ParticleDataImpl<int> *ptype = NULL,
+ const int exclude = 0)
+{
+ // use half a cell diagonal as base radius
+ const Real radius = 0.5 * calculateRadiusFactor(phi, radiusFactor);
+ ComputeAveragedLevelsetWeight(parts, index, indexSys, phi, radius, ptype, exclude);
+
+ // post-process level-set
+ for (int i = 0; i < std::max(smoothen, smoothenNeg); ++i) {
+ LevelsetGrid tmp(flags.getParent());
+ if (i < smoothen) {
+ knSmoothGrid<Real>(phi, tmp, 1. / (phi.is3D() ? 7. : 5.));
+ phi.swap(tmp);
+ }
+ if (i < smoothenNeg) {
+ knSmoothGridNeg<Real>(phi, tmp, 1. / (phi.is3D() ? 7. : 5.));
+ phi.swap(tmp);
+ }
+ }
+ phi.setBound(0.5, 0);
+}
+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, "averagedParticleLevelset", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const BasicParticleSystem &parts = *_args.getPtr<BasicParticleSystem>("parts", 0, &_lock);
+ const ParticleIndexSystem &indexSys = *_args.getPtr<ParticleIndexSystem>(
+ "indexSys", 1, &_lock);
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 2, &_lock);
+ const Grid<int> &index = *_args.getPtr<Grid<int>>("index", 3, &_lock);
+ LevelsetGrid &phi = *_args.getPtr<LevelsetGrid>("phi", 4, &_lock);
+ const Real radiusFactor = _args.getOpt<Real>("radiusFactor", 5, 1., &_lock);
+ const int smoothen = _args.getOpt<int>("smoothen", 6, 1, &_lock);
+ const int smoothenNeg = _args.getOpt<int>("smoothenNeg", 7, 1, &_lock);
+ const ParticleDataImpl<int> *ptype = _args.getPtrOpt<ParticleDataImpl<int>>(
+ "ptype", 8, NULL, &_lock);
+ const int exclude = _args.getOpt<int>("exclude", 9, 0, &_lock);
+ _retval = getPyNone();
+ averagedParticleLevelset(
+ parts, indexSys, flags, index, phi, radiusFactor, smoothen, smoothenNeg, ptype, exclude);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "averagedParticleLevelset", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("averagedParticleLevelset", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_averagedParticleLevelset("", "averagedParticleLevelset", _W_9);
+extern "C" {
+void PbRegister_averagedParticleLevelset()
+{
+ KEEP_UNUSED(_RP_averagedParticleLevelset);
+}
+}
+
+//! kernel for improvedParticleLevelset
+
+struct correctLevelset : public KernelBase {
+ correctLevelset(LevelsetGrid &phi,
+ const Grid<Vec3> &pAcc,
+ const Grid<Real> &rAcc,
+ const Real radius,
+ const Real t_low,
+ const Real t_high)
+ : KernelBase(&phi, 1),
+ phi(phi),
+ pAcc(pAcc),
+ rAcc(rAcc),
+ radius(radius),
+ t_low(t_low),
+ t_high(t_high)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ LevelsetGrid &phi,
+ const Grid<Vec3> &pAcc,
+ const Grid<Real> &rAcc,
+ const Real radius,
+ const Real t_low,
+ const Real t_high) const
+ {
+ if (rAcc(i, j, k) <= VECTOR_EPSILON)
+ return; // outside nothing happens
+ Real x = pAcc(i, j, k).x;
+
+ // create jacobian of pAcc via central differences
+ Matrix3x3f jacobian = Matrix3x3f(0.5 * (pAcc(i + 1, j, k).x - pAcc(i - 1, j, k).x),
+ 0.5 * (pAcc(i, j + 1, k).x - pAcc(i, j - 1, k).x),
+ 0.5 * (pAcc(i, j, k + 1).x - pAcc(i, j, k - 1).x),
+ 0.5 * (pAcc(i + 1, j, k).y - pAcc(i - 1, j, k).y),
+ 0.5 * (pAcc(i, j + 1, k).y - pAcc(i, j - 1, k).y),
+ 0.5 * (pAcc(i, j, k + 1).y - pAcc(i, j, k - 1).y),
+ 0.5 * (pAcc(i + 1, j, k).z - pAcc(i - 1, j, k).z),
+ 0.5 * (pAcc(i, j + 1, k).z - pAcc(i, j - 1, k).z),
+ 0.5 * (pAcc(i, j, k + 1).z - pAcc(i, j, k - 1).z));
+
+ // compute largest eigenvalue of jacobian
+ Vec3 EV = jacobian.eigenvalues();
+ Real maxEV = std::max(std::max(EV.x, EV.y), EV.z);
+
+ // calculate correction factor
+ Real correction = 1;
+ if (maxEV >= t_low) {
+ Real t = (t_high - maxEV) / (t_high - t_low);
+ correction = t * t * t - 3 * t * t + 3 * t;
+ }
+ correction = (correction < 0) ?
+ 0 :
+ correction; // enforce correction factor to [0,1] (not explicitly in paper)
+
+ const Vec3 gridPos = Vec3(i, j, k) + Vec3(0.5); // shifted by half cell
+ const Real correctedPhi = fabs(norm(gridPos - pAcc(i, j, k))) - rAcc(i, j, k) * correction;
+ phi(i, j, k) = (correctedPhi > radius) ?
+ radius :
+ correctedPhi; // adjust too high outside values when too few particles are
+ // nearby to make smoothing possible (not in paper)
+ }
+ inline LevelsetGrid &getArg0()
+ {
+ return phi;
+ }
+ typedef LevelsetGrid type0;
+ inline const Grid<Vec3> &getArg1()
+ {
+ return pAcc;
+ }
+ typedef Grid<Vec3> type1;
+ inline const Grid<Real> &getArg2()
+ {
+ return rAcc;
+ }
+ typedef Grid<Real> type2;
+ inline const Real &getArg3()
+ {
+ return radius;
+ }
+ typedef Real type3;
+ inline const Real &getArg4()
+ {
+ return t_low;
+ }
+ typedef Real type4;
+ inline const Real &getArg5()
+ {
+ return t_high;
+ }
+ typedef Real type5;
+ void runMessage()
+ {
+ debMsg("Executing kernel correctLevelset ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 1; j < _maxY; j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, phi, pAcc, rAcc, radius, t_low, t_high);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, phi, pAcc, rAcc, radius, t_low, t_high);
+ }
+ }
+ 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);
+ }
+ LevelsetGrid &phi;
+ const Grid<Vec3> &pAcc;
+ const Grid<Real> &rAcc;
+ const Real radius;
+ const Real t_low;
+ const Real t_high;
+};
+
+//! Approach from "A unified particle model for fluid-solid interactions" by Solenthaler et al. in
+//! 2007
+
+void improvedParticleLevelset(const BasicParticleSystem &parts,
+ const ParticleIndexSystem &indexSys,
+ const FlagGrid &flags,
+ const Grid<int> &index,
+ LevelsetGrid &phi,
+ const Real radiusFactor = 1.,
+ const int smoothen = 1,
+ const int smoothenNeg = 1,
+ const Real t_low = 0.4,
+ const Real t_high = 3.5,
+ const ParticleDataImpl<int> *ptype = NULL,
+ const int exclude = 0)
+{
+ // create temporary grids to store values from levelset weight computation
+ Grid<Vec3> save_pAcc(flags.getParent());
+ Grid<Real> save_rAcc(flags.getParent());
+
+ const Real radius = 0.5 * calculateRadiusFactor(
+ phi, radiusFactor); // use half a cell diagonal as base radius
+ ComputeAveragedLevelsetWeight(
+ parts, index, indexSys, phi, radius, ptype, exclude, &save_pAcc, &save_rAcc);
+ correctLevelset(phi, save_pAcc, save_rAcc, radius, t_low, t_high);
+
+ // post-process level-set
+ for (int i = 0; i < std::max(smoothen, smoothenNeg); ++i) {
+ LevelsetGrid tmp(flags.getParent());
+ if (i < smoothen) {
+ knSmoothGrid<Real>(phi, tmp, 1. / (phi.is3D() ? 7. : 5.));
+ phi.swap(tmp);
+ }
+ if (i < smoothenNeg) {
+ knSmoothGridNeg<Real>(phi, tmp, 1. / (phi.is3D() ? 7. : 5.));
+ phi.swap(tmp);
+ }
+ }
+ phi.setBound(0.5, 0);
+}
+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, "improvedParticleLevelset", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const BasicParticleSystem &parts = *_args.getPtr<BasicParticleSystem>("parts", 0, &_lock);
+ const ParticleIndexSystem &indexSys = *_args.getPtr<ParticleIndexSystem>(
+ "indexSys", 1, &_lock);
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 2, &_lock);
+ const Grid<int> &index = *_args.getPtr<Grid<int>>("index", 3, &_lock);
+ LevelsetGrid &phi = *_args.getPtr<LevelsetGrid>("phi", 4, &_lock);
+ const Real radiusFactor = _args.getOpt<Real>("radiusFactor", 5, 1., &_lock);
+ const int smoothen = _args.getOpt<int>("smoothen", 6, 1, &_lock);
+ const int smoothenNeg = _args.getOpt<int>("smoothenNeg", 7, 1, &_lock);
+ const Real t_low = _args.getOpt<Real>("t_low", 8, 0.4, &_lock);
+ const Real t_high = _args.getOpt<Real>("t_high", 9, 3.5, &_lock);
+ const ParticleDataImpl<int> *ptype = _args.getPtrOpt<ParticleDataImpl<int>>(
+ "ptype", 10, NULL, &_lock);
+ const int exclude = _args.getOpt<int>("exclude", 11, 0, &_lock);
+ _retval = getPyNone();
+ improvedParticleLevelset(parts,
+ indexSys,
+ flags,
+ index,
+ phi,
+ radiusFactor,
+ smoothen,
+ smoothenNeg,
+ t_low,
+ t_high,
+ ptype,
+ exclude);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "improvedParticleLevelset", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("improvedParticleLevelset", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_improvedParticleLevelset("", "improvedParticleLevelset", _W_10);
+extern "C" {
+void PbRegister_improvedParticleLevelset()
+{
+ KEEP_UNUSED(_RP_improvedParticleLevelset);
+}
+}
+
+struct knPushOutofObs : public KernelBase {
+ knPushOutofObs(BasicParticleSystem &parts,
+ const FlagGrid &flags,
+ const Grid<Real> &phiObs,
+ const Real shift,
+ const Real thresh,
+ const ParticleDataImpl<int> *ptype,
+ const int exclude)
+ : KernelBase(parts.size()),
+ parts(parts),
+ flags(flags),
+ phiObs(phiObs),
+ shift(shift),
+ thresh(thresh),
+ ptype(ptype),
+ exclude(exclude)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ BasicParticleSystem &parts,
+ const FlagGrid &flags,
+ const Grid<Real> &phiObs,
+ const Real shift,
+ const Real thresh,
+ const ParticleDataImpl<int> *ptype,
+ const int exclude) const
+ {
+ if (!parts.isActive(idx) || (ptype && ((*ptype)[idx] & exclude)))
+ return;
+ Vec3i p = toVec3i(parts.getPos(idx));
+
+ if (!flags.isInBounds(p))
+ return;
+ Real v = phiObs.getInterpolated(parts.getPos(idx));
+ if (v < thresh) {
+ Vec3 grad = getGradient(phiObs, p.x, p.y, p.z);
+ if (normalize(grad) < VECTOR_EPSILON)
+ return;
+ parts.setPos(idx, parts.getPos(idx) + grad * (thresh - v + shift));
+ }
+ }
+ inline BasicParticleSystem &getArg0()
+ {
+ return parts;
+ }
+ typedef BasicParticleSystem type0;
+ inline const FlagGrid &getArg1()
+ {
+ return flags;
+ }
+ typedef FlagGrid type1;
+ inline const Grid<Real> &getArg2()
+ {
+ return phiObs;
+ }
+ typedef Grid<Real> type2;
+ inline const Real &getArg3()
+ {
+ return shift;
+ }
+ typedef Real type3;
+ inline const Real &getArg4()
+ {
+ return thresh;
+ }
+ typedef Real type4;
+ inline const ParticleDataImpl<int> *getArg5()
+ {
+ return ptype;
+ }
+ typedef ParticleDataImpl<int> type5;
+ inline const int &getArg6()
+ {
+ return exclude;
+ }
+ typedef int type6;
+ void runMessage()
+ {
+ debMsg("Executing kernel knPushOutofObs ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, parts, flags, phiObs, shift, thresh, ptype, exclude);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ BasicParticleSystem &parts;
+ const FlagGrid &flags;
+ const Grid<Real> &phiObs;
+ const Real shift;
+ const Real thresh;
+ const ParticleDataImpl<int> *ptype;
+ const int exclude;
+};
+//! push particles out of obstacle levelset
+
+void pushOutofObs(BasicParticleSystem &parts,
+ const FlagGrid &flags,
+ const Grid<Real> &phiObs,
+ const Real shift = 0,
+ const Real thresh = 0,
+ const ParticleDataImpl<int> *ptype = NULL,
+ const int exclude = 0)
+{
+ knPushOutofObs(parts, flags, phiObs, shift, thresh, ptype, exclude);
+}
+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, "pushOutofObs", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ BasicParticleSystem &parts = *_args.getPtr<BasicParticleSystem>("parts", 0, &_lock);
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 1, &_lock);
+ const Grid<Real> &phiObs = *_args.getPtr<Grid<Real>>("phiObs", 2, &_lock);
+ const Real shift = _args.getOpt<Real>("shift", 3, 0, &_lock);
+ const Real thresh = _args.getOpt<Real>("thresh", 4, 0, &_lock);
+ const ParticleDataImpl<int> *ptype = _args.getPtrOpt<ParticleDataImpl<int>>(
+ "ptype", 5, NULL, &_lock);
+ const int exclude = _args.getOpt<int>("exclude", 6, 0, &_lock);
+ _retval = getPyNone();
+ pushOutofObs(parts, flags, phiObs, shift, thresh, ptype, exclude);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "pushOutofObs", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("pushOutofObs", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_pushOutofObs("", "pushOutofObs", _W_11);
+extern "C" {
+void PbRegister_pushOutofObs()
+{
+ KEEP_UNUSED(_RP_pushOutofObs);
+}
+}
+
+//******************************************************************************
+// grid interpolation functions
+
+template<class T> struct knSafeDivReal : public KernelBase {
+ knSafeDivReal(Grid<T> &me, const Grid<Real> &other, Real cutoff = VECTOR_EPSILON)
+ : KernelBase(&me, 0), me(me), other(other), cutoff(cutoff)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ Grid<T> &me,
+ const Grid<Real> &other,
+ Real cutoff = VECTOR_EPSILON) const
+ {
+ if (other[idx] < cutoff) {
+ me[idx] = 0.;
+ }
+ else {
+ T div(other[idx]);
+ me[idx] = safeDivide(me[idx], div);
+ }
+ }
+ inline Grid<T> &getArg0()
+ {
+ return me;
+ }
+ typedef Grid<T> type0;
+ inline const Grid<Real> &getArg1()
+ {
+ return other;
+ }
+ typedef Grid<Real> type1;
+ inline Real &getArg2()
+ {
+ return cutoff;
+ }
+ typedef Real type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel knSafeDivReal ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, me, other, cutoff);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ Grid<T> &me;
+ const Grid<Real> &other;
+ Real cutoff;
+};
+
+// Set velocities on the grid from the particle system
+
+struct knMapLinearVec3ToMACGrid : public KernelBase {
+ knMapLinearVec3ToMACGrid(const BasicParticleSystem &p,
+ const FlagGrid &flags,
+ const MACGrid &vel,
+ Grid<Vec3> &tmp,
+ const ParticleDataImpl<Vec3> &pvel,
+ const ParticleDataImpl<int> *ptype,
+ const int exclude)
+ : KernelBase(p.size()),
+ p(p),
+ flags(flags),
+ vel(vel),
+ tmp(tmp),
+ pvel(pvel),
+ ptype(ptype),
+ exclude(exclude)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ const BasicParticleSystem &p,
+ const FlagGrid &flags,
+ const MACGrid &vel,
+ Grid<Vec3> &tmp,
+ const ParticleDataImpl<Vec3> &pvel,
+ const ParticleDataImpl<int> *ptype,
+ const int exclude)
+ {
+ unusedParameter(flags);
+ if (!p.isActive(idx) || (ptype && ((*ptype)[idx] & exclude)))
+ return;
+ vel.setInterpolated(p[idx].pos, pvel[idx], &tmp[0]);
+ }
+ inline const BasicParticleSystem &getArg0()
+ {
+ return p;
+ }
+ typedef BasicParticleSystem type0;
+ inline const FlagGrid &getArg1()
+ {
+ return flags;
+ }
+ typedef FlagGrid type1;
+ inline const MACGrid &getArg2()
+ {
+ return vel;
+ }
+ typedef MACGrid type2;
+ inline Grid<Vec3> &getArg3()
+ {
+ return tmp;
+ }
+ typedef Grid<Vec3> type3;
+ inline const ParticleDataImpl<Vec3> &getArg4()
+ {
+ return pvel;
+ }
+ typedef ParticleDataImpl<Vec3> type4;
+ inline const ParticleDataImpl<int> *getArg5()
+ {
+ return ptype;
+ }
+ typedef ParticleDataImpl<int> type5;
+ inline const int &getArg6()
+ {
+ return exclude;
+ }
+ typedef int type6;
+ void runMessage()
+ {
+ debMsg("Executing kernel knMapLinearVec3ToMACGrid ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void run()
+ {
+ const IndexInt _sz = size;
+ for (IndexInt i = 0; i < _sz; i++)
+ op(i, p, flags, vel, tmp, pvel, ptype, exclude);
+ }
+ const BasicParticleSystem &p;
+ const FlagGrid &flags;
+ const MACGrid &vel;
+ Grid<Vec3> &tmp;
+ const ParticleDataImpl<Vec3> &pvel;
+ const ParticleDataImpl<int> *ptype;
+ const int exclude;
+};
+
+// optionally , this function can use an existing vec3 grid to store the weights
+// this is useful in combination with the simple extrapolation function
+
+void mapPartsToMAC(const FlagGrid &flags,
+ MACGrid &vel,
+ MACGrid &velOld,
+ const BasicParticleSystem &parts,
+ const ParticleDataImpl<Vec3> &partVel,
+ Grid<Vec3> *weight = NULL,
+ const ParticleDataImpl<int> *ptype = NULL,
+ const int exclude = 0)
+{
+ // interpol -> grid. tmpgrid for particle contribution weights
+ bool freeTmp = false;
+ if (!weight) {
+ weight = new Grid<Vec3>(flags.getParent());
+ freeTmp = true;
+ }
+ else {
+ weight->clear(); // make sure we start with a zero grid!
+ }
+ vel.clear();
+ knMapLinearVec3ToMACGrid(parts, flags, vel, *weight, partVel, ptype, exclude);
+
+ // stomp small values in weight to zero to prevent roundoff errors
+ weight->stomp(Vec3(VECTOR_EPSILON));
+ vel.safeDivide(*weight);
+
+ // store original state
+ velOld.copyFrom(vel);
+ if (freeTmp)
+ delete weight;
+}
+static PyObject *_W_12(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, "mapPartsToMAC", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ MACGrid &vel = *_args.getPtr<MACGrid>("vel", 1, &_lock);
+ MACGrid &velOld = *_args.getPtr<MACGrid>("velOld", 2, &_lock);
+ const BasicParticleSystem &parts = *_args.getPtr<BasicParticleSystem>("parts", 3, &_lock);
+ const ParticleDataImpl<Vec3> &partVel = *_args.getPtr<ParticleDataImpl<Vec3>>(
+ "partVel", 4, &_lock);
+ Grid<Vec3> *weight = _args.getPtrOpt<Grid<Vec3>>("weight", 5, NULL, &_lock);
+ const ParticleDataImpl<int> *ptype = _args.getPtrOpt<ParticleDataImpl<int>>(
+ "ptype", 6, NULL, &_lock);
+ const int exclude = _args.getOpt<int>("exclude", 7, 0, &_lock);
+ _retval = getPyNone();
+ mapPartsToMAC(flags, vel, velOld, parts, partVel, weight, ptype, exclude);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "mapPartsToMAC", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("mapPartsToMAC", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_mapPartsToMAC("", "mapPartsToMAC", _W_12);
+extern "C" {
+void PbRegister_mapPartsToMAC()
+{
+ KEEP_UNUSED(_RP_mapPartsToMAC);
+}
+}
+
+template<class T> struct knMapLinear : public KernelBase {
+ knMapLinear(const BasicParticleSystem &p,
+ const FlagGrid &flags,
+ const Grid<T> &target,
+ Grid<Real> &gtmp,
+ const ParticleDataImpl<T> &psource)
+ : KernelBase(p.size()), p(p), flags(flags), target(target), gtmp(gtmp), psource(psource)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ const BasicParticleSystem &p,
+ const FlagGrid &flags,
+ const Grid<T> &target,
+ Grid<Real> &gtmp,
+ const ParticleDataImpl<T> &psource)
+ {
+ unusedParameter(flags);
+ if (!p.isActive(idx))
+ return;
+ target.setInterpolated(p[idx].pos, psource[idx], gtmp);
+ }
+ inline const BasicParticleSystem &getArg0()
+ {
+ return p;
+ }
+ typedef BasicParticleSystem type0;
+ inline const FlagGrid &getArg1()
+ {
+ return flags;
+ }
+ typedef FlagGrid type1;
+ inline const Grid<T> &getArg2()
+ {
+ return target;
+ }
+ typedef Grid<T> type2;
+ inline Grid<Real> &getArg3()
+ {
+ return gtmp;
+ }
+ typedef Grid<Real> type3;
+ inline const ParticleDataImpl<T> &getArg4()
+ {
+ return psource;
+ }
+ typedef ParticleDataImpl<T> type4;
+ void runMessage()
+ {
+ debMsg("Executing kernel knMapLinear ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void run()
+ {
+ const IndexInt _sz = size;
+ for (IndexInt i = 0; i < _sz; i++)
+ op(i, p, flags, target, gtmp, psource);
+ }
+ const BasicParticleSystem &p;
+ const FlagGrid &flags;
+ const Grid<T> &target;
+ Grid<Real> &gtmp;
+ const ParticleDataImpl<T> &psource;
+};
+
+template<class T>
+void mapLinearRealHelper(const FlagGrid &flags,
+ Grid<T> &target,
+ const BasicParticleSystem &parts,
+ const ParticleDataImpl<T> &source)
+{
+ Grid<Real> tmp(flags.getParent());
+ target.clear();
+ knMapLinear<T>(parts, flags, target, tmp, source);
+ knSafeDivReal<T>(target, tmp);
+}
+
+void mapPartsToGrid(const FlagGrid &flags,
+ Grid<Real> &target,
+ const BasicParticleSystem &parts,
+ const ParticleDataImpl<Real> &source)
+{
+ mapLinearRealHelper<Real>(flags, target, parts, source);
+}
+static PyObject *_W_13(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, "mapPartsToGrid", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ Grid<Real> &target = *_args.getPtr<Grid<Real>>("target", 1, &_lock);
+ const BasicParticleSystem &parts = *_args.getPtr<BasicParticleSystem>("parts", 2, &_lock);
+ const ParticleDataImpl<Real> &source = *_args.getPtr<ParticleDataImpl<Real>>(
+ "source", 3, &_lock);
+ _retval = getPyNone();
+ mapPartsToGrid(flags, target, parts, source);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "mapPartsToGrid", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("mapPartsToGrid", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_mapPartsToGrid("", "mapPartsToGrid", _W_13);
+extern "C" {
+void PbRegister_mapPartsToGrid()
+{
+ KEEP_UNUSED(_RP_mapPartsToGrid);
+}
+}
+
+void mapPartsToGridVec3(const FlagGrid &flags,
+ Grid<Vec3> &target,
+ const BasicParticleSystem &parts,
+ const ParticleDataImpl<Vec3> &source)
+{
+ mapLinearRealHelper<Vec3>(flags, target, parts, source);
+}
+static PyObject *_W_14(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, "mapPartsToGridVec3", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ Grid<Vec3> &target = *_args.getPtr<Grid<Vec3>>("target", 1, &_lock);
+ const BasicParticleSystem &parts = *_args.getPtr<BasicParticleSystem>("parts", 2, &_lock);
+ const ParticleDataImpl<Vec3> &source = *_args.getPtr<ParticleDataImpl<Vec3>>(
+ "source", 3, &_lock);
+ _retval = getPyNone();
+ mapPartsToGridVec3(flags, target, parts, source);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "mapPartsToGridVec3", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("mapPartsToGridVec3", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_mapPartsToGridVec3("", "mapPartsToGridVec3", _W_14);
+extern "C" {
+void PbRegister_mapPartsToGridVec3()
+{
+ KEEP_UNUSED(_RP_mapPartsToGridVec3);
+}
+}
+
+// integers need "max" mode, not yet implemented
+// PYTHON() void mapPartsToGridInt ( FlagGrid& flags, Grid<int >& target , BasicParticleSystem&
+// parts , ParticleDataImpl<int >& source ) { mapLinearRealHelper<int >(flags,target,parts,source);
+//}
+
+template<class T> struct knMapFromGrid : public KernelBase {
+ knMapFromGrid(const BasicParticleSystem &p, const Grid<T> &gsrc, ParticleDataImpl<T> &target)
+ : KernelBase(p.size()), p(p), gsrc(gsrc), target(target)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ const BasicParticleSystem &p,
+ const Grid<T> &gsrc,
+ ParticleDataImpl<T> &target) const
+ {
+ if (!p.isActive(idx))
+ return;
+ target[idx] = gsrc.getInterpolated(p[idx].pos);
+ }
+ inline const BasicParticleSystem &getArg0()
+ {
+ return p;
+ }
+ typedef BasicParticleSystem type0;
+ inline const Grid<T> &getArg1()
+ {
+ return gsrc;
+ }
+ typedef Grid<T> type1;
+ inline ParticleDataImpl<T> &getArg2()
+ {
+ return target;
+ }
+ typedef ParticleDataImpl<T> type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel knMapFromGrid ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, p, gsrc, target);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ const BasicParticleSystem &p;
+ const Grid<T> &gsrc;
+ ParticleDataImpl<T> &target;
+};
+void mapGridToParts(const Grid<Real> &source,
+ const BasicParticleSystem &parts,
+ ParticleDataImpl<Real> &target)
+{
+ knMapFromGrid<Real>(parts, source, target);
+}
+static PyObject *_W_15(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, "mapGridToParts", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const Grid<Real> &source = *_args.getPtr<Grid<Real>>("source", 0, &_lock);
+ const BasicParticleSystem &parts = *_args.getPtr<BasicParticleSystem>("parts", 1, &_lock);
+ ParticleDataImpl<Real> &target = *_args.getPtr<ParticleDataImpl<Real>>("target", 2, &_lock);
+ _retval = getPyNone();
+ mapGridToParts(source, parts, target);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "mapGridToParts", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("mapGridToParts", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_mapGridToParts("", "mapGridToParts", _W_15);
+extern "C" {
+void PbRegister_mapGridToParts()
+{
+ KEEP_UNUSED(_RP_mapGridToParts);
+}
+}
+
+void mapGridToPartsVec3(const Grid<Vec3> &source,
+ const BasicParticleSystem &parts,
+ ParticleDataImpl<Vec3> &target)
+{
+ knMapFromGrid<Vec3>(parts, source, target);
+}
+static PyObject *_W_16(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, "mapGridToPartsVec3", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const Grid<Vec3> &source = *_args.getPtr<Grid<Vec3>>("source", 0, &_lock);
+ const BasicParticleSystem &parts = *_args.getPtr<BasicParticleSystem>("parts", 1, &_lock);
+ ParticleDataImpl<Vec3> &target = *_args.getPtr<ParticleDataImpl<Vec3>>("target", 2, &_lock);
+ _retval = getPyNone();
+ mapGridToPartsVec3(source, parts, target);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "mapGridToPartsVec3", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("mapGridToPartsVec3", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_mapGridToPartsVec3("", "mapGridToPartsVec3", _W_16);
+extern "C" {
+void PbRegister_mapGridToPartsVec3()
+{
+ KEEP_UNUSED(_RP_mapGridToPartsVec3);
+}
+}
+
+// Get velocities from grid
+
+struct knMapLinearMACGridToVec3_PIC : public KernelBase {
+ knMapLinearMACGridToVec3_PIC(const BasicParticleSystem &p,
+ const FlagGrid &flags,
+ const MACGrid &vel,
+ ParticleDataImpl<Vec3> &pvel,
+ const ParticleDataImpl<int> *ptype,
+ const int exclude)
+ : KernelBase(p.size()),
+ p(p),
+ flags(flags),
+ vel(vel),
+ pvel(pvel),
+ ptype(ptype),
+ exclude(exclude)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ const BasicParticleSystem &p,
+ const FlagGrid &flags,
+ const MACGrid &vel,
+ ParticleDataImpl<Vec3> &pvel,
+ const ParticleDataImpl<int> *ptype,
+ const int exclude) const
+ {
+ if (!p.isActive(idx) || (ptype && ((*ptype)[idx] & exclude)))
+ return;
+ // pure PIC
+ pvel[idx] = vel.getInterpolated(p[idx].pos);
+ }
+ inline const BasicParticleSystem &getArg0()
+ {
+ return p;
+ }
+ typedef BasicParticleSystem type0;
+ inline const FlagGrid &getArg1()
+ {
+ return flags;
+ }
+ typedef FlagGrid type1;
+ inline const MACGrid &getArg2()
+ {
+ return vel;
+ }
+ typedef MACGrid type2;
+ inline ParticleDataImpl<Vec3> &getArg3()
+ {
+ return pvel;
+ }
+ typedef ParticleDataImpl<Vec3> type3;
+ inline const ParticleDataImpl<int> *getArg4()
+ {
+ return ptype;
+ }
+ typedef ParticleDataImpl<int> type4;
+ inline const int &getArg5()
+ {
+ return exclude;
+ }
+ typedef int type5;
+ void runMessage()
+ {
+ debMsg("Executing kernel knMapLinearMACGridToVec3_PIC ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, p, flags, vel, pvel, ptype, exclude);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ const BasicParticleSystem &p;
+ const FlagGrid &flags;
+ const MACGrid &vel;
+ ParticleDataImpl<Vec3> &pvel;
+ const ParticleDataImpl<int> *ptype;
+ const int exclude;
+};
+
+void mapMACToParts(const FlagGrid &flags,
+ const MACGrid &vel,
+ const BasicParticleSystem &parts,
+ ParticleDataImpl<Vec3> &partVel,
+ const ParticleDataImpl<int> *ptype = NULL,
+ const int exclude = 0)
+{
+ knMapLinearMACGridToVec3_PIC(parts, flags, vel, partVel, ptype, exclude);
+}
+static PyObject *_W_17(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, "mapMACToParts", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ const MACGrid &vel = *_args.getPtr<MACGrid>("vel", 1, &_lock);
+ const BasicParticleSystem &parts = *_args.getPtr<BasicParticleSystem>("parts", 2, &_lock);
+ ParticleDataImpl<Vec3> &partVel = *_args.getPtr<ParticleDataImpl<Vec3>>(
+ "partVel", 3, &_lock);
+ const ParticleDataImpl<int> *ptype = _args.getPtrOpt<ParticleDataImpl<int>>(
+ "ptype", 4, NULL, &_lock);
+ const int exclude = _args.getOpt<int>("exclude", 5, 0, &_lock);
+ _retval = getPyNone();
+ mapMACToParts(flags, vel, parts, partVel, ptype, exclude);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "mapMACToParts", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("mapMACToParts", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_mapMACToParts("", "mapMACToParts", _W_17);
+extern "C" {
+void PbRegister_mapMACToParts()
+{
+ KEEP_UNUSED(_RP_mapMACToParts);
+}
+}
+
+// with flip delta interpolation
+
+struct knMapLinearMACGridToVec3_FLIP : public KernelBase {
+ knMapLinearMACGridToVec3_FLIP(const BasicParticleSystem &p,
+ const FlagGrid &flags,
+ const MACGrid &vel,
+ const MACGrid &oldVel,
+ ParticleDataImpl<Vec3> &pvel,
+ const Real flipRatio,
+ const ParticleDataImpl<int> *ptype,
+ const int exclude)
+ : KernelBase(p.size()),
+ p(p),
+ flags(flags),
+ vel(vel),
+ oldVel(oldVel),
+ pvel(pvel),
+ flipRatio(flipRatio),
+ ptype(ptype),
+ exclude(exclude)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ const BasicParticleSystem &p,
+ const FlagGrid &flags,
+ const MACGrid &vel,
+ const MACGrid &oldVel,
+ ParticleDataImpl<Vec3> &pvel,
+ const Real flipRatio,
+ const ParticleDataImpl<int> *ptype,
+ const int exclude) const
+ {
+ if (!p.isActive(idx) || (ptype && ((*ptype)[idx] & exclude)))
+ return;
+ Vec3 v = vel.getInterpolated(p[idx].pos);
+ Vec3 delta = v - oldVel.getInterpolated(p[idx].pos);
+ pvel[idx] = flipRatio * (pvel[idx] + delta) + (1.0 - flipRatio) * v;
+ }
+ inline const BasicParticleSystem &getArg0()
+ {
+ return p;
+ }
+ typedef BasicParticleSystem type0;
+ inline const FlagGrid &getArg1()
+ {
+ return flags;
+ }
+ typedef FlagGrid type1;
+ inline const MACGrid &getArg2()
+ {
+ return vel;
+ }
+ typedef MACGrid type2;
+ inline const MACGrid &getArg3()
+ {
+ return oldVel;
+ }
+ typedef MACGrid type3;
+ inline ParticleDataImpl<Vec3> &getArg4()
+ {
+ return pvel;
+ }
+ typedef ParticleDataImpl<Vec3> type4;
+ inline const Real &getArg5()
+ {
+ return flipRatio;
+ }
+ typedef Real type5;
+ inline const ParticleDataImpl<int> *getArg6()
+ {
+ return ptype;
+ }
+ typedef ParticleDataImpl<int> type6;
+ inline const int &getArg7()
+ {
+ return exclude;
+ }
+ typedef int type7;
+ void runMessage()
+ {
+ debMsg("Executing kernel knMapLinearMACGridToVec3_FLIP ", 3);
+ debMsg("Kernel range"
+ << " size " << size << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, p, flags, vel, oldVel, pvel, flipRatio, ptype, exclude);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ const BasicParticleSystem &p;
+ const FlagGrid &flags;
+ const MACGrid &vel;
+ const MACGrid &oldVel;
+ ParticleDataImpl<Vec3> &pvel;
+ const Real flipRatio;
+ const ParticleDataImpl<int> *ptype;
+ const int exclude;
+};
+
+void flipVelocityUpdate(const FlagGrid &flags,
+ const MACGrid &vel,
+ const MACGrid &velOld,
+ const BasicParticleSystem &parts,
+ ParticleDataImpl<Vec3> &partVel,
+ const Real flipRatio,
+ const ParticleDataImpl<int> *ptype = NULL,
+ const int exclude = 0)
+{
+ knMapLinearMACGridToVec3_FLIP(parts, flags, vel, velOld, partVel, flipRatio, ptype, exclude);
+}
+static PyObject *_W_18(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, "flipVelocityUpdate", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
+ const MACGrid &vel = *_args.getPtr<MACGrid>("vel", 1, &_lock);
+ const MACGrid &velOld = *_args.getPtr<MACGrid>("velOld", 2, &_lock);
+ const BasicParticleSystem &parts = *_args.getPtr<BasicParticleSystem>("parts", 3, &_lock);
+ ParticleDataImpl<Vec3> &partVel = *_args.getPtr<ParticleDataImpl<Vec3>>(
+ "partVel", 4, &_lock);
+ const Real flipRatio = _args.get<Real>("flipRatio", 5, &_lock);
+ const ParticleDataImpl<int> *ptype = _args.getPtrOpt<ParticleDataImpl<int>>(
+ "ptype", 6, NULL, &_lock);
+ const int exclude = _args.getOpt<int>("exclude", 7, 0, &_lock);
+ _retval = getPyNone();
+ flipVelocityUpdate(flags, vel, velOld, parts, partVel, flipRatio, ptype, exclude);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "flipVelocityUpdate", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("flipVelocityUpdate", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_flipVelocityUpdate("", "flipVelocityUpdate", _W_18);
+extern "C" {
+void PbRegister_flipVelocityUpdate()
+{
+ KEEP_UNUSED(_RP_flipVelocityUpdate);
+}
+}
+
+//******************************************************************************
+// narrow band
+
+struct knCombineVels : public KernelBase {
+ knCombineVels(MACGrid &vel,
+ const Grid<Vec3> &w,
+ MACGrid &combineVel,
+ const LevelsetGrid *phi,
+ Real narrowBand,
+ Real thresh)
+ : KernelBase(&vel, 0),
+ vel(vel),
+ w(w),
+ combineVel(combineVel),
+ phi(phi),
+ narrowBand(narrowBand),
+ thresh(thresh)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ MACGrid &vel,
+ const Grid<Vec3> &w,
+ MACGrid &combineVel,
+ const LevelsetGrid *phi,
+ Real narrowBand,
+ Real thresh) const
+ {
+ int idx = vel.index(i, j, k);
+
+ for (int c = 0; c < 3; ++c) {
+ // Correct narrow-band FLIP
+ if (phi) {
+ Vec3 pos(i, j, k);
+ pos[(c + 1) % 3] += Real(0.5);
+ pos[(c + 2) % 3] += Real(0.5);
+ Real p = phi->getInterpolated(pos);
+ if (p < -narrowBand) {
+ vel[idx][c] = 0;
+ continue;
+ }
+ }
+
+ if (w[idx][c] > thresh) {
+ combineVel[idx][c] = vel[idx][c];
+ vel[idx][c] = -1;
+ }
+ else {
+ vel[idx][c] = 0;
+ }
+ }
+ }
+ inline MACGrid &getArg0()
+ {
+ return vel;
+ }
+ typedef MACGrid type0;
+ inline const Grid<Vec3> &getArg1()
+ {
+ return w;
+ }
+ typedef Grid<Vec3> type1;
+ inline MACGrid &getArg2()
+ {
+ return combineVel;
+ }
+ typedef MACGrid type2;
+ inline const LevelsetGrid *getArg3()
+ {
+ return phi;
+ }
+ typedef LevelsetGrid type3;
+ inline Real &getArg4()
+ {
+ return narrowBand;
+ }
+ typedef Real type4;
+ inline Real &getArg5()
+ {
+ return thresh;
+ }
+ typedef Real type5;
+ void runMessage()
+ {
+ debMsg("Executing kernel knCombineVels ", 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, w, combineVel, phi, narrowBand, thresh);
+ }
+ 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, w, combineVel, phi, narrowBand, thresh);
+ }
+ }
+ 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;
+ const Grid<Vec3> &w;
+ MACGrid &combineVel;
+ const LevelsetGrid *phi;
+ Real narrowBand;
+ Real thresh;
+};
+
+//! narrow band velocity combination
+
+void combineGridVel(MACGrid &vel,
+ const Grid<Vec3> &weight,
+ MACGrid &combineVel,
+ const LevelsetGrid *phi = NULL,
+ Real narrowBand = 0.0,
+ Real thresh = 0.0)
+{
+ knCombineVels(vel, weight, combineVel, phi, narrowBand, thresh);
+}
+static PyObject *_W_19(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, "combineGridVel", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ MACGrid &vel = *_args.getPtr<MACGrid>("vel", 0, &_lock);
+ const Grid<Vec3> &weight = *_args.getPtr<Grid<Vec3>>("weight", 1, &_lock);
+ MACGrid &combineVel = *_args.getPtr<MACGrid>("combineVel", 2, &_lock);
+ const LevelsetGrid *phi = _args.getPtrOpt<LevelsetGrid>("phi", 3, NULL, &_lock);
+ Real narrowBand = _args.getOpt<Real>("narrowBand", 4, 0.0, &_lock);
+ Real thresh = _args.getOpt<Real>("thresh", 5, 0.0, &_lock);
+ _retval = getPyNone();
+ combineGridVel(vel, weight, combineVel, phi, narrowBand, thresh);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "combineGridVel", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("combineGridVel", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_combineGridVel("", "combineGridVel", _W_19);
+extern "C" {
+void PbRegister_combineGridVel()
+{
+ KEEP_UNUSED(_RP_combineGridVel);
+}
+}
+
+//! surface tension helper
+void getLaplacian(Grid<Real> &laplacian, const Grid<Real> &grid)
+{
+ LaplaceOp(laplacian, grid);
+}
+static PyObject *_W_20(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, "getLaplacian", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Grid<Real> &laplacian = *_args.getPtr<Grid<Real>>("laplacian", 0, &_lock);
+ const Grid<Real> &grid = *_args.getPtr<Grid<Real>>("grid", 1, &_lock);
+ _retval = getPyNone();
+ getLaplacian(laplacian, grid);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "getLaplacian", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("getLaplacian", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_getLaplacian("", "getLaplacian", _W_20);
+extern "C" {
+void PbRegister_getLaplacian()
+{
+ KEEP_UNUSED(_RP_getLaplacian);
+}
+}
+
+void getCurvature(Grid<Real> &curv, const Grid<Real> &grid, const Real h = 1.0)
+{
+ CurvatureOp(curv, grid, h);
+}
+static PyObject *_W_21(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, "getCurvature", !noTiming);
+ PyObject *_retval = 0;
+ {
+ ArgLocker _lock;
+ Grid<Real> &curv = *_args.getPtr<Grid<Real>>("curv", 0, &_lock);
+ const Grid<Real> &grid = *_args.getPtr<Grid<Real>>("grid", 1, &_lock);
+ const Real h = _args.getOpt<Real>("h", 2, 1.0, &_lock);
+ _retval = getPyNone();
+ getCurvature(curv, grid, h);
+ _args.check();
+ }
+ pbFinalizePlugin(parent, "getCurvature", !noTiming);
+ return _retval;
+ }
+ catch (std::exception &e) {
+ pbSetError("getCurvature", e.what());
+ return 0;
+ }
+}
+static const Pb::Register _RP_getCurvature("", "getCurvature", _W_21);
+extern "C" {
+void PbRegister_getCurvature()
+{
+ KEEP_UNUSED(_RP_getCurvature);
+}
+}
+
+} // namespace Manta