Updates in the files include: - New manta files now use an platform independent gzopen function - Adjusted argument name for vorticity
2820 lines
86 KiB
C++
2820 lines
86 KiB
C++
|
|
|
|
// DO NOT EDIT !
|
|
// This file is generated using the MantaFlow preprocessor (prep generate).
|
|
|
|
/******************************************************************************
|
|
*
|
|
* MantaFlow fluid solver framework
|
|
* Copyright 2011 Tobias Pfaff, Nils Thuerey
|
|
*
|
|
* This program is free software, distributed under the terms of the
|
|
* Apache License, Version 2.0
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* FLIP (fluid implicit particles)
|
|
* for use with particle data fields
|
|
*
|
|
******************************************************************************/
|
|
|
|
#include "particle.h"
|
|
#include "general.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 φ
|
|
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 φ
|
|
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
|
|
|
|
// 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 = clamp(correction,
|
|
Real(0),
|
|
Real(1)); // 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 φ
|
|
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> >mp,
|
|
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> >mp,
|
|
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> ⌖
|
|
Grid<Real> >mp;
|
|
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> ⌖
|
|
};
|
|
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
|