// 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 * * Tools to setup fields and inflows * ******************************************************************************/ #include "vectorbase.h" #include "shapes.h" #include "commonkernels.h" #include "particle.h" #include "noisefield.h" #include "simpleimage.h" #include "mesh.h" using namespace std; namespace Manta { //! Apply noise to grid struct KnApplyNoiseInfl : public KernelBase { KnApplyNoiseInfl(const FlagGrid &flags, Grid &density, const WaveletNoiseField &noise, const Grid &sdf, Real scale, Real sigma) : KernelBase(&flags, 0), flags(flags), density(density), noise(noise), sdf(sdf), scale(scale), sigma(sigma) { runMessage(); run(); } inline void op(int i, int j, int k, const FlagGrid &flags, Grid &density, const WaveletNoiseField &noise, const Grid &sdf, Real scale, Real sigma) const { if (!flags.isFluid(i, j, k) || sdf(i, j, k) > sigma) return; Real factor = clamp(1.0 - 0.5 / sigma * (sdf(i, j, k) + sigma), 0.0, 1.0); Real target = noise.evaluate(Vec3(i, j, k)) * scale * factor; if (density(i, j, k) < target) density(i, j, k) = target; } inline const FlagGrid &getArg0() { return flags; } typedef FlagGrid type0; inline Grid &getArg1() { return density; } typedef Grid type1; inline const WaveletNoiseField &getArg2() { return noise; } typedef WaveletNoiseField type2; inline const Grid &getArg3() { return sdf; } typedef Grid type3; inline Real &getArg4() { return scale; } typedef Real type4; inline Real &getArg5() { return sigma; } typedef Real type5; void runMessage() { debMsg("Executing kernel KnApplyNoiseInfl ", 3); debMsg("Kernel range" << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ", 4); }; void operator()(const tbb::blocked_range &__r) const { const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) { for (int k = __r.begin(); k != (int)__r.end(); k++) for (int j = 0; j < _maxY; j++) for (int i = 0; i < _maxX; i++) op(i, j, k, flags, density, noise, sdf, scale, sigma); } else { const int k = 0; for (int j = __r.begin(); j != (int)__r.end(); j++) for (int i = 0; i < _maxX; i++) op(i, j, k, flags, density, noise, sdf, scale, sigma); } } void run() { if (maxZ > 1) tbb::parallel_for(tbb::blocked_range(minZ, maxZ), *this); else tbb::parallel_for(tbb::blocked_range(0, maxY), *this); } const FlagGrid &flags; Grid &density; const WaveletNoiseField &noise; const Grid &sdf; Real scale; Real sigma; }; //! Init noise-modulated density inside shape void densityInflow(const FlagGrid &flags, Grid &density, const WaveletNoiseField &noise, Shape *shape, Real scale = 1.0, Real sigma = 0) { Grid sdf = shape->computeLevelset(); KnApplyNoiseInfl(flags, density, noise, sdf, scale, sigma); } static PyObject *_W_0(PyObject *_self, PyObject *_linargs, PyObject *_kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt("notiming", -1, 0); pbPreparePlugin(parent, "densityInflow", !noTiming); PyObject *_retval = 0; { ArgLocker _lock; const FlagGrid &flags = *_args.getPtr("flags", 0, &_lock); Grid &density = *_args.getPtr>("density", 1, &_lock); const WaveletNoiseField &noise = *_args.getPtr("noise", 2, &_lock); Shape *shape = _args.getPtr("shape", 3, &_lock); Real scale = _args.getOpt("scale", 4, 1.0, &_lock); Real sigma = _args.getOpt("sigma", 5, 0, &_lock); _retval = getPyNone(); densityInflow(flags, density, noise, shape, scale, sigma); _args.check(); } pbFinalizePlugin(parent, "densityInflow", !noTiming); return _retval; } catch (std::exception &e) { pbSetError("densityInflow", e.what()); return 0; } } static const Pb::Register _RP_densityInflow("", "densityInflow", _W_0); extern "C" { void PbRegister_densityInflow() { KEEP_UNUSED(_RP_densityInflow); } } //! Apply noise to real grid based on an SDF struct KnAddNoise : public KernelBase { KnAddNoise(const FlagGrid &flags, Grid &density, const WaveletNoiseField &noise, const Grid *sdf, Real scale) : KernelBase(&flags, 0), flags(flags), density(density), noise(noise), sdf(sdf), scale(scale) { runMessage(); run(); } inline void op(int i, int j, int k, const FlagGrid &flags, Grid &density, const WaveletNoiseField &noise, const Grid *sdf, Real scale) const { if (!flags.isFluid(i, j, k) || (sdf && (*sdf)(i, j, k) > 0.)) return; density(i, j, k) += noise.evaluate(Vec3(i, j, k)) * scale; } inline const FlagGrid &getArg0() { return flags; } typedef FlagGrid type0; inline Grid &getArg1() { return density; } typedef Grid type1; inline const WaveletNoiseField &getArg2() { return noise; } typedef WaveletNoiseField type2; inline const Grid *getArg3() { return sdf; } typedef Grid type3; inline Real &getArg4() { return scale; } typedef Real type4; void runMessage() { debMsg("Executing kernel KnAddNoise ", 3); debMsg("Kernel range" << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ", 4); }; void operator()(const tbb::blocked_range &__r) const { const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) { for (int k = __r.begin(); k != (int)__r.end(); k++) for (int j = 0; j < _maxY; j++) for (int i = 0; i < _maxX; i++) op(i, j, k, flags, density, noise, sdf, scale); } else { const int k = 0; for (int j = __r.begin(); j != (int)__r.end(); j++) for (int i = 0; i < _maxX; i++) op(i, j, k, flags, density, noise, sdf, scale); } } void run() { if (maxZ > 1) tbb::parallel_for(tbb::blocked_range(minZ, maxZ), *this); else tbb::parallel_for(tbb::blocked_range(0, maxY), *this); } const FlagGrid &flags; Grid &density; const WaveletNoiseField &noise; const Grid *sdf; Real scale; }; void addNoise(const FlagGrid &flags, Grid &density, const WaveletNoiseField &noise, const Grid *sdf = NULL, Real scale = 1.0) { KnAddNoise(flags, density, noise, sdf, scale); } static PyObject *_W_1(PyObject *_self, PyObject *_linargs, PyObject *_kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt("notiming", -1, 0); pbPreparePlugin(parent, "addNoise", !noTiming); PyObject *_retval = 0; { ArgLocker _lock; const FlagGrid &flags = *_args.getPtr("flags", 0, &_lock); Grid &density = *_args.getPtr>("density", 1, &_lock); const WaveletNoiseField &noise = *_args.getPtr("noise", 2, &_lock); const Grid *sdf = _args.getPtrOpt>("sdf", 3, NULL, &_lock); Real scale = _args.getOpt("scale", 4, 1.0, &_lock); _retval = getPyNone(); addNoise(flags, density, noise, sdf, scale); _args.check(); } pbFinalizePlugin(parent, "addNoise", !noTiming); return _retval; } catch (std::exception &e) { pbSetError("addNoise", e.what()); return 0; } } static const Pb::Register _RP_addNoise("", "addNoise", _W_1); extern "C" { void PbRegister_addNoise() { KEEP_UNUSED(_RP_addNoise); } } //! sample noise field and set pdata with its values (for convenience, scale the noise values) template struct knSetPdataNoise : public KernelBase { knSetPdataNoise(const BasicParticleSystem &parts, ParticleDataImpl &pdata, const WaveletNoiseField &noise, Real scale) : KernelBase(parts.size()), parts(parts), pdata(pdata), noise(noise), scale(scale) { runMessage(); run(); } inline void op(IndexInt idx, const BasicParticleSystem &parts, ParticleDataImpl &pdata, const WaveletNoiseField &noise, Real scale) const { pdata[idx] = noise.evaluate(parts.getPos(idx)) * scale; } inline const BasicParticleSystem &getArg0() { return parts; } typedef BasicParticleSystem type0; inline ParticleDataImpl &getArg1() { return pdata; } typedef ParticleDataImpl type1; inline const WaveletNoiseField &getArg2() { return noise; } typedef WaveletNoiseField type2; inline Real &getArg3() { return scale; } typedef Real type3; void runMessage() { debMsg("Executing kernel knSetPdataNoise ", 3); debMsg("Kernel range" << " size " << size << " ", 4); }; void operator()(const tbb::blocked_range &__r) const { for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++) op(idx, parts, pdata, noise, scale); } void run() { tbb::parallel_for(tbb::blocked_range(0, size), *this); } const BasicParticleSystem &parts; ParticleDataImpl &pdata; const WaveletNoiseField &noise; Real scale; }; template struct knSetPdataNoiseVec : public KernelBase { knSetPdataNoiseVec(const BasicParticleSystem &parts, ParticleDataImpl &pdata, const WaveletNoiseField &noise, Real scale) : KernelBase(parts.size()), parts(parts), pdata(pdata), noise(noise), scale(scale) { runMessage(); run(); } inline void op(IndexInt idx, const BasicParticleSystem &parts, ParticleDataImpl &pdata, const WaveletNoiseField &noise, Real scale) const { pdata[idx] = noise.evaluateVec(parts.getPos(idx)) * scale; } inline const BasicParticleSystem &getArg0() { return parts; } typedef BasicParticleSystem type0; inline ParticleDataImpl &getArg1() { return pdata; } typedef ParticleDataImpl type1; inline const WaveletNoiseField &getArg2() { return noise; } typedef WaveletNoiseField type2; inline Real &getArg3() { return scale; } typedef Real type3; void runMessage() { debMsg("Executing kernel knSetPdataNoiseVec ", 3); debMsg("Kernel range" << " size " << size << " ", 4); }; void operator()(const tbb::blocked_range &__r) const { for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++) op(idx, parts, pdata, noise, scale); } void run() { tbb::parallel_for(tbb::blocked_range(0, size), *this); } const BasicParticleSystem &parts; ParticleDataImpl &pdata; const WaveletNoiseField &noise; Real scale; }; void setNoisePdata(const BasicParticleSystem &parts, ParticleDataImpl &pd, const WaveletNoiseField &noise, Real scale = 1.) { knSetPdataNoise(parts, pd, noise, scale); } static PyObject *_W_2(PyObject *_self, PyObject *_linargs, PyObject *_kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt("notiming", -1, 0); pbPreparePlugin(parent, "setNoisePdata", !noTiming); PyObject *_retval = 0; { ArgLocker _lock; const BasicParticleSystem &parts = *_args.getPtr("parts", 0, &_lock); ParticleDataImpl &pd = *_args.getPtr>("pd", 1, &_lock); const WaveletNoiseField &noise = *_args.getPtr("noise", 2, &_lock); Real scale = _args.getOpt("scale", 3, 1., &_lock); _retval = getPyNone(); setNoisePdata(parts, pd, noise, scale); _args.check(); } pbFinalizePlugin(parent, "setNoisePdata", !noTiming); return _retval; } catch (std::exception &e) { pbSetError("setNoisePdata", e.what()); return 0; } } static const Pb::Register _RP_setNoisePdata("", "setNoisePdata", _W_2); extern "C" { void PbRegister_setNoisePdata() { KEEP_UNUSED(_RP_setNoisePdata); } } void setNoisePdataVec3(const BasicParticleSystem &parts, ParticleDataImpl &pd, const WaveletNoiseField &noise, Real scale = 1.) { knSetPdataNoiseVec(parts, pd, noise, scale); } static PyObject *_W_3(PyObject *_self, PyObject *_linargs, PyObject *_kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt("notiming", -1, 0); pbPreparePlugin(parent, "setNoisePdataVec3", !noTiming); PyObject *_retval = 0; { ArgLocker _lock; const BasicParticleSystem &parts = *_args.getPtr("parts", 0, &_lock); ParticleDataImpl &pd = *_args.getPtr>("pd", 1, &_lock); const WaveletNoiseField &noise = *_args.getPtr("noise", 2, &_lock); Real scale = _args.getOpt("scale", 3, 1., &_lock); _retval = getPyNone(); setNoisePdataVec3(parts, pd, noise, scale); _args.check(); } pbFinalizePlugin(parent, "setNoisePdataVec3", !noTiming); return _retval; } catch (std::exception &e) { pbSetError("setNoisePdataVec3", e.what()); return 0; } } static const Pb::Register _RP_setNoisePdataVec3("", "setNoisePdataVec3", _W_3); extern "C" { void PbRegister_setNoisePdataVec3() { KEEP_UNUSED(_RP_setNoisePdataVec3); } } void setNoisePdataInt(const BasicParticleSystem &parts, ParticleDataImpl &pd, const WaveletNoiseField &noise, Real scale = 1.) { knSetPdataNoise(parts, pd, noise, scale); } static PyObject *_W_4(PyObject *_self, PyObject *_linargs, PyObject *_kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt("notiming", -1, 0); pbPreparePlugin(parent, "setNoisePdataInt", !noTiming); PyObject *_retval = 0; { ArgLocker _lock; const BasicParticleSystem &parts = *_args.getPtr("parts", 0, &_lock); ParticleDataImpl &pd = *_args.getPtr>("pd", 1, &_lock); const WaveletNoiseField &noise = *_args.getPtr("noise", 2, &_lock); Real scale = _args.getOpt("scale", 3, 1., &_lock); _retval = getPyNone(); setNoisePdataInt(parts, pd, noise, scale); _args.check(); } pbFinalizePlugin(parent, "setNoisePdataInt", !noTiming); return _retval; } catch (std::exception &e) { pbSetError("setNoisePdataInt", e.what()); return 0; } } static const Pb::Register _RP_setNoisePdataInt("", "setNoisePdataInt", _W_4); extern "C" { void PbRegister_setNoisePdataInt() { KEEP_UNUSED(_RP_setNoisePdataInt); } } //! SDF gradient from obstacle flags, for turbulence.py // FIXME, slow, without kernel... Grid obstacleGradient(const FlagGrid &flags) { LevelsetGrid levelset(flags.getParent(), false); Grid gradient(flags.getParent()); // rebuild obstacle levelset FOR_IDX(levelset) { levelset[idx] = flags.isObstacle(idx) ? -0.5 : 0.5; } levelset.reinitMarching(flags, 6.0, 0, true, false, FlagGrid::TypeReserved); // build levelset gradient GradientOp(gradient, levelset); FOR_IDX(levelset) { Vec3 grad = gradient[idx]; Real s = normalize(grad); if (s <= 0.1 || levelset[idx] >= 0) grad = Vec3(0.); gradient[idx] = grad * levelset[idx]; } return gradient; } static PyObject *_W_5(PyObject *_self, PyObject *_linargs, PyObject *_kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt("notiming", -1, 0); pbPreparePlugin(parent, "obstacleGradient", !noTiming); PyObject *_retval = 0; { ArgLocker _lock; const FlagGrid &flags = *_args.getPtr("flags", 0, &_lock); _retval = toPy(obstacleGradient(flags)); _args.check(); } pbFinalizePlugin(parent, "obstacleGradient", !noTiming); return _retval; } catch (std::exception &e) { pbSetError("obstacleGradient", e.what()); return 0; } } static const Pb::Register _RP_obstacleGradient("", "obstacleGradient", _W_5); extern "C" { void PbRegister_obstacleGradient() { KEEP_UNUSED(_RP_obstacleGradient); } } //! SDF from obstacle flags, for turbulence.py LevelsetGrid obstacleLevelset(const FlagGrid &flags) { LevelsetGrid levelset(flags.getParent(), false); // rebuild obstacle levelset FOR_IDX(levelset) { levelset[idx] = flags.isObstacle(idx) ? -0.5 : 0.5; } levelset.reinitMarching(flags, 6.0, 0, true, false, FlagGrid::TypeReserved); return levelset; } static PyObject *_W_6(PyObject *_self, PyObject *_linargs, PyObject *_kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt("notiming", -1, 0); pbPreparePlugin(parent, "obstacleLevelset", !noTiming); PyObject *_retval = 0; { ArgLocker _lock; const FlagGrid &flags = *_args.getPtr("flags", 0, &_lock); _retval = toPy(obstacleLevelset(flags)); _args.check(); } pbFinalizePlugin(parent, "obstacleLevelset", !noTiming); return _retval; } catch (std::exception &e) { pbSetError("obstacleLevelset", e.what()); return 0; } } static const Pb::Register _RP_obstacleLevelset("", "obstacleLevelset", _W_6); extern "C" { void PbRegister_obstacleLevelset() { KEEP_UNUSED(_RP_obstacleLevelset); } } //***************************************************************************** // blender init functions struct KnApplyEmission : public KernelBase { KnApplyEmission(const FlagGrid &flags, Grid &target, const Grid &source, const Grid *emissionTexture, bool isAbsolute, int type) : KernelBase(&flags, 0), flags(flags), target(target), source(source), emissionTexture(emissionTexture), isAbsolute(isAbsolute), type(type) { runMessage(); run(); } inline void op(int i, int j, int k, const FlagGrid &flags, Grid &target, const Grid &source, const Grid *emissionTexture, bool isAbsolute, int type) const { // if type is given, only apply emission when celltype matches type from flaggrid // and if emission texture is given, only apply emission when some emission is present at cell // (important for emit from particles) bool isInflow = (type & FlagGrid::TypeInflow && flags.isInflow(i, j, k)); bool isOutflow = (type & FlagGrid::TypeOutflow && flags.isOutflow(i, j, k)); if ((type && !isInflow && !isOutflow) && (emissionTexture && !(*emissionTexture)(i, j, k))) return; if (isAbsolute) target(i, j, k) = source(i, j, k); else target(i, j, k) += source(i, j, k); } inline const FlagGrid &getArg0() { return flags; } typedef FlagGrid type0; inline Grid &getArg1() { return target; } typedef Grid type1; inline const Grid &getArg2() { return source; } typedef Grid type2; inline const Grid *getArg3() { return emissionTexture; } typedef Grid type3; inline bool &getArg4() { return isAbsolute; } typedef bool type4; inline int &getArg5() { return type; } typedef int type5; void runMessage() { debMsg("Executing kernel KnApplyEmission ", 3); debMsg("Kernel range" << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ", 4); }; void operator()(const tbb::blocked_range &__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, target, source, emissionTexture, isAbsolute, type); } 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, target, source, emissionTexture, isAbsolute, type); } } void run() { if (maxZ > 1) tbb::parallel_for(tbb::blocked_range(minZ, maxZ), *this); else tbb::parallel_for(tbb::blocked_range(0, maxY), *this); } const FlagGrid &flags; Grid ⌖ const Grid &source; const Grid *emissionTexture; bool isAbsolute; int type; }; //! Add emission values // isAbsolute: whether to add emission values to existing, or replace void applyEmission(FlagGrid &flags, Grid &target, Grid &source, Grid *emissionTexture = NULL, bool isAbsolute = true, int type = 0) { KnApplyEmission(flags, target, source, emissionTexture, isAbsolute, type); } static PyObject *_W_7(PyObject *_self, PyObject *_linargs, PyObject *_kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt("notiming", -1, 0); pbPreparePlugin(parent, "applyEmission", !noTiming); PyObject *_retval = 0; { ArgLocker _lock; FlagGrid &flags = *_args.getPtr("flags", 0, &_lock); Grid &target = *_args.getPtr>("target", 1, &_lock); Grid &source = *_args.getPtr>("source", 2, &_lock); Grid *emissionTexture = _args.getPtrOpt>( "emissionTexture", 3, NULL, &_lock); bool isAbsolute = _args.getOpt("isAbsolute", 4, true, &_lock); int type = _args.getOpt("type", 5, 0, &_lock); _retval = getPyNone(); applyEmission(flags, target, source, emissionTexture, isAbsolute, type); _args.check(); } pbFinalizePlugin(parent, "applyEmission", !noTiming); return _retval; } catch (std::exception &e) { pbSetError("applyEmission", e.what()); return 0; } } static const Pb::Register _RP_applyEmission("", "applyEmission", _W_7); extern "C" { void PbRegister_applyEmission() { KEEP_UNUSED(_RP_applyEmission); } } // blender init functions for meshes struct KnApplyDensity : public KernelBase { KnApplyDensity( const FlagGrid &flags, Grid &density, const Grid &sdf, Real value, Real sigma) : KernelBase(&flags, 0), flags(flags), density(density), sdf(sdf), value(value), sigma(sigma) { runMessage(); run(); } inline void op(int i, int j, int k, const FlagGrid &flags, Grid &density, const Grid &sdf, Real value, Real sigma) const { if (!flags.isFluid(i, j, k) || sdf(i, j, k) > sigma) return; density(i, j, k) = value; } inline const FlagGrid &getArg0() { return flags; } typedef FlagGrid type0; inline Grid &getArg1() { return density; } typedef Grid type1; inline const Grid &getArg2() { return sdf; } typedef Grid type2; inline Real &getArg3() { return value; } typedef Real type3; inline Real &getArg4() { return sigma; } typedef Real type4; void runMessage() { debMsg("Executing kernel KnApplyDensity ", 3); debMsg("Kernel range" << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ", 4); }; void operator()(const tbb::blocked_range &__r) const { const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) { for (int k = __r.begin(); k != (int)__r.end(); k++) for (int j = 0; j < _maxY; j++) for (int i = 0; i < _maxX; i++) op(i, j, k, flags, density, sdf, value, sigma); } else { const int k = 0; for (int j = __r.begin(); j != (int)__r.end(); j++) for (int i = 0; i < _maxX; i++) op(i, j, k, flags, density, sdf, value, sigma); } } void run() { if (maxZ > 1) tbb::parallel_for(tbb::blocked_range(minZ, maxZ), *this); else tbb::parallel_for(tbb::blocked_range(0, maxY), *this); } const FlagGrid &flags; Grid &density; const Grid &sdf; Real value; Real sigma; }; //! Init noise-modulated density inside mesh void densityInflowMeshNoise(const FlagGrid &flags, Grid &density, const WaveletNoiseField &noise, Mesh *mesh, Real scale = 1.0, Real sigma = 0) { LevelsetGrid sdf(density.getParent(), false); mesh->computeLevelset(sdf, 1.); KnApplyNoiseInfl(flags, density, noise, sdf, scale, sigma); } static PyObject *_W_8(PyObject *_self, PyObject *_linargs, PyObject *_kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt("notiming", -1, 0); pbPreparePlugin(parent, "densityInflowMeshNoise", !noTiming); PyObject *_retval = 0; { ArgLocker _lock; const FlagGrid &flags = *_args.getPtr("flags", 0, &_lock); Grid &density = *_args.getPtr>("density", 1, &_lock); const WaveletNoiseField &noise = *_args.getPtr("noise", 2, &_lock); Mesh *mesh = _args.getPtr("mesh", 3, &_lock); Real scale = _args.getOpt("scale", 4, 1.0, &_lock); Real sigma = _args.getOpt("sigma", 5, 0, &_lock); _retval = getPyNone(); densityInflowMeshNoise(flags, density, noise, mesh, scale, sigma); _args.check(); } pbFinalizePlugin(parent, "densityInflowMeshNoise", !noTiming); return _retval; } catch (std::exception &e) { pbSetError("densityInflowMeshNoise", e.what()); return 0; } } static const Pb::Register _RP_densityInflowMeshNoise("", "densityInflowMeshNoise", _W_8); extern "C" { void PbRegister_densityInflowMeshNoise() { KEEP_UNUSED(_RP_densityInflowMeshNoise); } } //! Init constant density inside mesh void densityInflowMesh(const FlagGrid &flags, Grid &density, Mesh *mesh, Real value = 1., Real cutoff = 7, Real sigma = 0) { LevelsetGrid sdf(density.getParent(), false); mesh->computeLevelset(sdf, 2., cutoff); KnApplyDensity(flags, density, sdf, value, sigma); } static PyObject *_W_9(PyObject *_self, PyObject *_linargs, PyObject *_kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt("notiming", -1, 0); pbPreparePlugin(parent, "densityInflowMesh", !noTiming); PyObject *_retval = 0; { ArgLocker _lock; const FlagGrid &flags = *_args.getPtr("flags", 0, &_lock); Grid &density = *_args.getPtr>("density", 1, &_lock); Mesh *mesh = _args.getPtr("mesh", 2, &_lock); Real value = _args.getOpt("value", 3, 1., &_lock); Real cutoff = _args.getOpt("cutoff", 4, 7, &_lock); Real sigma = _args.getOpt("sigma", 5, 0, &_lock); _retval = getPyNone(); densityInflowMesh(flags, density, mesh, value, cutoff, sigma); _args.check(); } pbFinalizePlugin(parent, "densityInflowMesh", !noTiming); return _retval; } catch (std::exception &e) { pbSetError("densityInflowMesh", e.what()); return 0; } } static const Pb::Register _RP_densityInflowMesh("", "densityInflowMesh", _W_9); extern "C" { void PbRegister_densityInflowMesh() { KEEP_UNUSED(_RP_densityInflowMesh); } } struct KnResetInObstacle : public KernelBase { KnResetInObstacle(FlagGrid &flags, MACGrid &vel, Grid *density, Grid *heat, Grid *fuel, Grid *flame, Grid *red, Grid *green, Grid *blue, Real resetValue) : KernelBase(&flags, 0), flags(flags), vel(vel), density(density), heat(heat), fuel(fuel), flame(flame), red(red), green(green), blue(blue), resetValue(resetValue) { runMessage(); run(); } inline void op(int i, int j, int k, FlagGrid &flags, MACGrid &vel, Grid *density, Grid *heat, Grid *fuel, Grid *flame, Grid *red, Grid *green, Grid *blue, Real resetValue) const { if (!flags.isObstacle(i, j, k)) return; vel(i, j, k).x = resetValue; vel(i, j, k).y = resetValue; vel(i, j, k).z = resetValue; if (density) { (*density)(i, j, k) = resetValue; } if (heat) { (*heat)(i, j, k) = resetValue; } if (fuel) { (*fuel)(i, j, k) = resetValue; (*flame)(i, j, k) = resetValue; } if (red) { (*red)(i, j, k) = resetValue; (*green)(i, j, k) = resetValue; (*blue)(i, j, k) = resetValue; } } inline FlagGrid &getArg0() { return flags; } typedef FlagGrid type0; inline MACGrid &getArg1() { return vel; } typedef MACGrid type1; inline Grid *getArg2() { return density; } typedef Grid type2; inline Grid *getArg3() { return heat; } typedef Grid type3; inline Grid *getArg4() { return fuel; } typedef Grid type4; inline Grid *getArg5() { return flame; } typedef Grid type5; inline Grid *getArg6() { return red; } typedef Grid type6; inline Grid *getArg7() { return green; } typedef Grid type7; inline Grid *getArg8() { return blue; } typedef Grid type8; inline Real &getArg9() { return resetValue; } typedef Real type9; void runMessage() { debMsg("Executing kernel KnResetInObstacle ", 3); debMsg("Kernel range" << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ", 4); }; void operator()(const tbb::blocked_range &__r) const { const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) { for (int k = __r.begin(); k != (int)__r.end(); k++) for (int j = 0; j < _maxY; j++) for (int i = 0; i < _maxX; i++) op(i, j, k, flags, vel, density, heat, fuel, flame, red, green, blue, resetValue); } else { const int k = 0; for (int j = __r.begin(); j != (int)__r.end(); j++) for (int i = 0; i < _maxX; i++) op(i, j, k, flags, vel, density, heat, fuel, flame, red, green, blue, resetValue); } } void run() { if (maxZ > 1) tbb::parallel_for(tbb::blocked_range(minZ, maxZ), *this); else tbb::parallel_for(tbb::blocked_range(0, maxY), *this); } FlagGrid &flags; MACGrid &vel; Grid *density; Grid *heat; Grid *fuel; Grid *flame; Grid *red; Grid *green; Grid *blue; Real resetValue; }; void resetInObstacle(FlagGrid &flags, MACGrid &vel, Grid *density, Grid *heat = NULL, Grid *fuel = NULL, Grid *flame = NULL, Grid *red = NULL, Grid *green = NULL, Grid *blue = NULL, Real resetValue = 0) { KnResetInObstacle(flags, vel, density, heat, fuel, flame, red, green, blue, resetValue); } static PyObject *_W_10(PyObject *_self, PyObject *_linargs, PyObject *_kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt("notiming", -1, 0); pbPreparePlugin(parent, "resetInObstacle", !noTiming); PyObject *_retval = 0; { ArgLocker _lock; FlagGrid &flags = *_args.getPtr("flags", 0, &_lock); MACGrid &vel = *_args.getPtr("vel", 1, &_lock); Grid *density = _args.getPtr>("density", 2, &_lock); Grid *heat = _args.getPtrOpt>("heat", 3, NULL, &_lock); Grid *fuel = _args.getPtrOpt>("fuel", 4, NULL, &_lock); Grid *flame = _args.getPtrOpt>("flame", 5, NULL, &_lock); Grid *red = _args.getPtrOpt>("red", 6, NULL, &_lock); Grid *green = _args.getPtrOpt>("green", 7, NULL, &_lock); Grid *blue = _args.getPtrOpt>("blue", 8, NULL, &_lock); Real resetValue = _args.getOpt("resetValue", 9, 0, &_lock); _retval = getPyNone(); resetInObstacle(flags, vel, density, heat, fuel, flame, red, green, blue, resetValue); _args.check(); } pbFinalizePlugin(parent, "resetInObstacle", !noTiming); return _retval; } catch (std::exception &e) { pbSetError("resetInObstacle", e.what()); return 0; } } static const Pb::Register _RP_resetInObstacle("", "resetInObstacle", _W_10); extern "C" { void PbRegister_resetInObstacle() { KEEP_UNUSED(_RP_resetInObstacle); } } //***************************************************************************** //! check for symmetry , optionally enfore by copying void checkSymmetry( Grid &a, Grid *err = NULL, bool symmetrize = false, int axis = 0, int bound = 0) { const int c = axis; const int s = a.getSize()[c]; FOR_IJK(a) { Vec3i idx(i, j, k), mdx(i, j, k); mdx[c] = s - 1 - idx[c]; if (bound > 0 && ((!a.isInBounds(idx, bound)) || (!a.isInBounds(mdx, bound)))) continue; if (err) (*err)(idx) = fabs((double)(a(idx) - a(mdx))); if (symmetrize && (idx[c] < s / 2)) { a(idx) = a(mdx); } } } static PyObject *_W_11(PyObject *_self, PyObject *_linargs, PyObject *_kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt("notiming", -1, 0); pbPreparePlugin(parent, "checkSymmetry", !noTiming); PyObject *_retval = 0; { ArgLocker _lock; Grid &a = *_args.getPtr>("a", 0, &_lock); Grid *err = _args.getPtrOpt>("err", 1, NULL, &_lock); bool symmetrize = _args.getOpt("symmetrize", 2, false, &_lock); int axis = _args.getOpt("axis", 3, 0, &_lock); int bound = _args.getOpt("bound", 4, 0, &_lock); _retval = getPyNone(); checkSymmetry(a, err, symmetrize, axis, bound); _args.check(); } pbFinalizePlugin(parent, "checkSymmetry", !noTiming); return _retval; } catch (std::exception &e) { pbSetError("checkSymmetry", e.what()); return 0; } } static const Pb::Register _RP_checkSymmetry("", "checkSymmetry", _W_11); extern "C" { void PbRegister_checkSymmetry() { KEEP_UNUSED(_RP_checkSymmetry); } } //! check for symmetry , mac grid version void checkSymmetryVec3(Grid &a, Grid *err = NULL, bool symmetrize = false, int axis = 0, int bound = 0, int disable = 0) { if (err) err->setConst(0.); // each dimension is measured separately for flexibility (could be combined) const int c = axis; const int o1 = (c + 1) % 3; const int o2 = (c + 2) % 3; // x if (!(disable & 1)) { const int s = a.getSize()[c] + 1; FOR_IJK(a) { Vec3i idx(i, j, k), mdx(i, j, k); mdx[c] = s - 1 - idx[c]; if (mdx[c] >= a.getSize()[c]) continue; if (bound > 0 && ((!a.isInBounds(idx, bound)) || (!a.isInBounds(mdx, bound)))) continue; // special case: center "line" of values , should be zero! if (mdx[c] == idx[c]) { if (err) (*err)(idx) += fabs((double)(a(idx)[c])); if (symmetrize) a(idx)[c] = 0.; continue; } // note - the a(mdx) component needs to be inverted here! if (err) (*err)(idx) += fabs((double)(a(idx)[c] - (a(mdx)[c] * -1.))); if (symmetrize && (idx[c] < s / 2)) { a(idx)[c] = a(mdx)[c] * -1.; } } } // y if (!(disable & 2)) { const int s = a.getSize()[c]; FOR_IJK(a) { Vec3i idx(i, j, k), mdx(i, j, k); mdx[c] = s - 1 - idx[c]; if (bound > 0 && ((!a.isInBounds(idx, bound)) || (!a.isInBounds(mdx, bound)))) continue; if (err) (*err)(idx) += fabs((double)(a(idx)[o1] - a(mdx)[o1])); if (symmetrize && (idx[c] < s / 2)) { a(idx)[o1] = a(mdx)[o1]; } } } // z if (!(disable & 4)) { const int s = a.getSize()[c]; FOR_IJK(a) { Vec3i idx(i, j, k), mdx(i, j, k); mdx[c] = s - 1 - idx[c]; if (bound > 0 && ((!a.isInBounds(idx, bound)) || (!a.isInBounds(mdx, bound)))) continue; if (err) (*err)(idx) += fabs((double)(a(idx)[o2] - a(mdx)[o2])); if (symmetrize && (idx[c] < s / 2)) { a(idx)[o2] = a(mdx)[o2]; } } } } static PyObject *_W_12(PyObject *_self, PyObject *_linargs, PyObject *_kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt("notiming", -1, 0); pbPreparePlugin(parent, "checkSymmetryVec3", !noTiming); PyObject *_retval = 0; { ArgLocker _lock; Grid &a = *_args.getPtr>("a", 0, &_lock); Grid *err = _args.getPtrOpt>("err", 1, NULL, &_lock); bool symmetrize = _args.getOpt("symmetrize", 2, false, &_lock); int axis = _args.getOpt("axis", 3, 0, &_lock); int bound = _args.getOpt("bound", 4, 0, &_lock); int disable = _args.getOpt("disable", 5, 0, &_lock); _retval = getPyNone(); checkSymmetryVec3(a, err, symmetrize, axis, bound, disable); _args.check(); } pbFinalizePlugin(parent, "checkSymmetryVec3", !noTiming); return _retval; } catch (std::exception &e) { pbSetError("checkSymmetryVec3", e.what()); return 0; } } static const Pb::Register _RP_checkSymmetryVec3("", "checkSymmetryVec3", _W_12); extern "C" { void PbRegister_checkSymmetryVec3() { KEEP_UNUSED(_RP_checkSymmetryVec3); } } // from simpleimage.cpp void projectImg(SimpleImage &img, const Grid &val, int shadeMode = 0, Real scale = 1.); //! output shaded (all 3 axes at once for 3D) //! shading modes: 0 smoke, 1 surfaces void projectPpmFull(const Grid &val, string name, int shadeMode = 0, Real scale = 1.) { SimpleImage img; projectImg(img, val, shadeMode, scale); img.writePpm(name); } static PyObject *_W_13(PyObject *_self, PyObject *_linargs, PyObject *_kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt("notiming", -1, 0); pbPreparePlugin(parent, "projectPpmFull", !noTiming); PyObject *_retval = 0; { ArgLocker _lock; const Grid &val = *_args.getPtr>("val", 0, &_lock); string name = _args.get("name", 1, &_lock); int shadeMode = _args.getOpt("shadeMode", 2, 0, &_lock); Real scale = _args.getOpt("scale", 3, 1., &_lock); _retval = getPyNone(); projectPpmFull(val, name, shadeMode, scale); _args.check(); } pbFinalizePlugin(parent, "projectPpmFull", !noTiming); return _retval; } catch (std::exception &e) { pbSetError("projectPpmFull", e.what()); return 0; } } static const Pb::Register _RP_projectPpmFull("", "projectPpmFull", _W_13); extern "C" { void PbRegister_projectPpmFull() { KEEP_UNUSED(_RP_projectPpmFull); } } // helper functions for pdata operator tests //! init some test particles at the origin void addTestParts(BasicParticleSystem &parts, int num) { for (int i = 0; i < num; ++i) parts.addBuffered(Vec3(0, 0, 0)); parts.doCompress(); parts.insertBufferedParticles(); } static PyObject *_W_14(PyObject *_self, PyObject *_linargs, PyObject *_kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt("notiming", -1, 0); pbPreparePlugin(parent, "addTestParts", !noTiming); PyObject *_retval = 0; { ArgLocker _lock; BasicParticleSystem &parts = *_args.getPtr("parts", 0, &_lock); int num = _args.get("num", 1, &_lock); _retval = getPyNone(); addTestParts(parts, num); _args.check(); } pbFinalizePlugin(parent, "addTestParts", !noTiming); return _retval; } catch (std::exception &e) { pbSetError("addTestParts", e.what()); return 0; } } static const Pb::Register _RP_addTestParts("", "addTestParts", _W_14); extern "C" { void PbRegister_addTestParts() { KEEP_UNUSED(_RP_addTestParts); } } //! calculate the difference between two pdata fields (note - slow!, not parallelized) template Real getPdataMaxDiff(const ParticleDataImpl *a, const ParticleDataImpl *b) { assertMsg(a->getType() == b->getType(), "pdataMaxDiff problem - different pdata types!"); assertMsg(a->getSizeSlow() == b->getSizeSlow(), "pdataMaxDiff problem - different pdata sizes!"); Real maxVal = 0.; FOR_PARTS(*a) { T diff = a->get(idx) - b->get(idx); Real s = (Real)sum(abs(diff)); maxVal = std::max(maxVal, s); } return maxVal; } Real pdataMaxDiff(const ParticleDataImpl *a, const ParticleDataImpl *b) { return getPdataMaxDiff(a, b); } static PyObject *_W_15(PyObject *_self, PyObject *_linargs, PyObject *_kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt("notiming", -1, 0); pbPreparePlugin(parent, "pdataMaxDiff", !noTiming); PyObject *_retval = 0; { ArgLocker _lock; const ParticleDataImpl *a = _args.getPtr>("a", 0, &_lock); const ParticleDataImpl *b = _args.getPtr>("b", 1, &_lock); _retval = toPy(pdataMaxDiff(a, b)); _args.check(); } pbFinalizePlugin(parent, "pdataMaxDiff", !noTiming); return _retval; } catch (std::exception &e) { pbSetError("pdataMaxDiff", e.what()); return 0; } } static const Pb::Register _RP_pdataMaxDiff("", "pdataMaxDiff", _W_15); extern "C" { void PbRegister_pdataMaxDiff() { KEEP_UNUSED(_RP_pdataMaxDiff); } } Real pdataMaxDiffInt(const ParticleDataImpl *a, const ParticleDataImpl *b) { return getPdataMaxDiff(a, b); } static PyObject *_W_16(PyObject *_self, PyObject *_linargs, PyObject *_kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt("notiming", -1, 0); pbPreparePlugin(parent, "pdataMaxDiffInt", !noTiming); PyObject *_retval = 0; { ArgLocker _lock; const ParticleDataImpl *a = _args.getPtr>("a", 0, &_lock); const ParticleDataImpl *b = _args.getPtr>("b", 1, &_lock); _retval = toPy(pdataMaxDiffInt(a, b)); _args.check(); } pbFinalizePlugin(parent, "pdataMaxDiffInt", !noTiming); return _retval; } catch (std::exception &e) { pbSetError("pdataMaxDiffInt", e.what()); return 0; } } static const Pb::Register _RP_pdataMaxDiffInt("", "pdataMaxDiffInt", _W_16); extern "C" { void PbRegister_pdataMaxDiffInt() { KEEP_UNUSED(_RP_pdataMaxDiffInt); } } Real pdataMaxDiffVec3(const ParticleDataImpl *a, const ParticleDataImpl *b) { return getPdataMaxDiff(a, b); } static PyObject *_W_17(PyObject *_self, PyObject *_linargs, PyObject *_kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt("notiming", -1, 0); pbPreparePlugin(parent, "pdataMaxDiffVec3", !noTiming); PyObject *_retval = 0; { ArgLocker _lock; const ParticleDataImpl *a = _args.getPtr>("a", 0, &_lock); const ParticleDataImpl *b = _args.getPtr>("b", 1, &_lock); _retval = toPy(pdataMaxDiffVec3(a, b)); _args.check(); } pbFinalizePlugin(parent, "pdataMaxDiffVec3", !noTiming); return _retval; } catch (std::exception &e) { pbSetError("pdataMaxDiffVec3", e.what()); return 0; } } static const Pb::Register _RP_pdataMaxDiffVec3("", "pdataMaxDiffVec3", _W_17); extern "C" { void PbRegister_pdataMaxDiffVec3() { KEEP_UNUSED(_RP_pdataMaxDiffVec3); } } //! calculate center of mass given density grid, for re-centering Vec3 calcCenterOfMass(const Grid &density) { Vec3 p(0.0f); Real w = 0.0f; FOR_IJK(density) { p += density(i, j, k) * Vec3(i + 0.5f, j + 0.5f, k + 0.5f); w += density(i, j, k); } if (w > 1e-6f) p /= w; return p; } static PyObject *_W_18(PyObject *_self, PyObject *_linargs, PyObject *_kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt("notiming", -1, 0); pbPreparePlugin(parent, "calcCenterOfMass", !noTiming); PyObject *_retval = 0; { ArgLocker _lock; const Grid &density = *_args.getPtr>("density", 0, &_lock); _retval = toPy(calcCenterOfMass(density)); _args.check(); } pbFinalizePlugin(parent, "calcCenterOfMass", !noTiming); return _retval; } catch (std::exception &e) { pbSetError("calcCenterOfMass", e.what()); return 0; } } static const Pb::Register _RP_calcCenterOfMass("", "calcCenterOfMass", _W_18); extern "C" { void PbRegister_calcCenterOfMass() { KEEP_UNUSED(_RP_calcCenterOfMass); } } //***************************************************************************** // helper functions for volume fractions (which are needed for second order obstacle boundaries) inline static Real calcFraction(Real phi1, Real phi2, Real fracThreshold) { if (phi1 > 0. && phi2 > 0.) return 1.; if (phi1 < 0. && phi2 < 0.) return 0.; // make sure phi1 < phi2 if (phi2 < phi1) { Real t = phi1; phi1 = phi2; phi2 = t; } Real denom = phi1 - phi2; if (denom > -1e-04) return 0.5; Real frac = 1. - phi1 / denom; if (frac < fracThreshold) frac = 0.; // stomp small values , dont mark as fluid return std::min(Real(1), frac); } struct KnUpdateFractions : public KernelBase { KnUpdateFractions(const FlagGrid &flags, const Grid &phiObs, MACGrid &fractions, const int &boundaryWidth, const Real fracThreshold) : KernelBase(&flags, 1), flags(flags), phiObs(phiObs), fractions(fractions), boundaryWidth(boundaryWidth), fracThreshold(fracThreshold) { runMessage(); run(); } inline void op(int i, int j, int k, const FlagGrid &flags, const Grid &phiObs, MACGrid &fractions, const int &boundaryWidth, const Real fracThreshold) const { // walls at domain bounds and inner objects fractions(i, j, k).x = calcFraction(phiObs(i, j, k), phiObs(i - 1, j, k), fracThreshold); fractions(i, j, k).y = calcFraction(phiObs(i, j, k), phiObs(i, j - 1, k), fracThreshold); if (phiObs.is3D()) { fractions(i, j, k).z = calcFraction(phiObs(i, j, k), phiObs(i, j, k - 1), fracThreshold); } // remaining BCs at the domain boundaries const int w = boundaryWidth; // only set if not in obstacle if (phiObs(i, j, k) < 0.) return; // x-direction boundaries if (i <= w + 1) { // min x if ((flags.isInflow(i - 1, j, k)) || (flags.isOutflow(i - 1, j, k)) || (flags.isOpen(i - 1, j, k))) { fractions(i, j, k).x = fractions(i, j, k).y = 1.; if (flags.is3D()) fractions(i, j, k).z = 1.; } } if (i >= flags.getSizeX() - w - 2) { // max x if ((flags.isInflow(i + 1, j, k)) || (flags.isOutflow(i + 1, j, k)) || (flags.isOpen(i + 1, j, k))) { fractions(i + 1, j, k).x = fractions(i + 1, j, k).y = 1.; if (flags.is3D()) fractions(i + 1, j, k).z = 1.; } } // y-direction boundaries if (j <= w + 1) { // min y if ((flags.isInflow(i, j - 1, k)) || (flags.isOutflow(i, j - 1, k)) || (flags.isOpen(i, j - 1, k))) { fractions(i, j, k).x = fractions(i, j, k).y = 1.; if (flags.is3D()) fractions(i, j, k).z = 1.; } } if (j >= flags.getSizeY() - w - 2) { // max y if ((flags.isInflow(i, j + 1, k)) || (flags.isOutflow(i, j + 1, k)) || (flags.isOpen(i, j + 1, k))) { fractions(i, j + 1, k).x = fractions(i, j + 1, k).y = 1.; if (flags.is3D()) fractions(i, j + 1, k).z = 1.; } } // z-direction boundaries if (flags.is3D()) { if (k <= w + 1) { // min z if ((flags.isInflow(i, j, k - 1)) || (flags.isOutflow(i, j, k - 1)) || (flags.isOpen(i, j, k - 1))) { fractions(i, j, k).x = fractions(i, j, k).y = 1.; if (flags.is3D()) fractions(i, j, k).z = 1.; } } if (j >= flags.getSizeZ() - w - 2) { // max z if ((flags.isInflow(i, j, k + 1)) || (flags.isOutflow(i, j, k + 1)) || (flags.isOpen(i, j, k + 1))) { fractions(i, j, k + 1).x = fractions(i, j, k + 1).y = 1.; if (flags.is3D()) fractions(i, j, k + 1).z = 1.; } } } } inline const FlagGrid &getArg0() { return flags; } typedef FlagGrid type0; inline const Grid &getArg1() { return phiObs; } typedef Grid type1; inline MACGrid &getArg2() { return fractions; } typedef MACGrid type2; inline const int &getArg3() { return boundaryWidth; } typedef int type3; inline const Real &getArg4() { return fracThreshold; } typedef Real type4; void runMessage() { debMsg("Executing kernel KnUpdateFractions ", 3); debMsg("Kernel range" << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ", 4); }; void operator()(const tbb::blocked_range &__r) const { const int _maxX = maxX; const int _maxY = maxY; if (maxZ > 1) { for (int k = __r.begin(); k != (int)__r.end(); k++) for (int j = 1; j < _maxY; j++) for (int i = 1; i < _maxX; i++) op(i, j, k, flags, phiObs, fractions, boundaryWidth, fracThreshold); } else { const int k = 0; for (int j = __r.begin(); j != (int)__r.end(); j++) for (int i = 1; i < _maxX; i++) op(i, j, k, flags, phiObs, fractions, boundaryWidth, fracThreshold); } } void run() { if (maxZ > 1) tbb::parallel_for(tbb::blocked_range(minZ, maxZ), *this); else tbb::parallel_for(tbb::blocked_range(1, maxY), *this); } const FlagGrid &flags; const Grid &phiObs; MACGrid &fractions; const int &boundaryWidth; const Real fracThreshold; }; //! update fill fraction values void updateFractions(const FlagGrid &flags, const Grid &phiObs, MACGrid &fractions, const int &boundaryWidth = 0, const Real fracThreshold = 0.01) { fractions.setConst(Vec3(0.)); KnUpdateFractions(flags, phiObs, fractions, boundaryWidth, fracThreshold); } static PyObject *_W_19(PyObject *_self, PyObject *_linargs, PyObject *_kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt("notiming", -1, 0); pbPreparePlugin(parent, "updateFractions", !noTiming); PyObject *_retval = 0; { ArgLocker _lock; const FlagGrid &flags = *_args.getPtr("flags", 0, &_lock); const Grid &phiObs = *_args.getPtr>("phiObs", 1, &_lock); MACGrid &fractions = *_args.getPtr("fractions", 2, &_lock); const int &boundaryWidth = _args.getOpt("boundaryWidth", 3, 0, &_lock); const Real fracThreshold = _args.getOpt("fracThreshold", 4, 0.01, &_lock); _retval = getPyNone(); updateFractions(flags, phiObs, fractions, boundaryWidth, fracThreshold); _args.check(); } pbFinalizePlugin(parent, "updateFractions", !noTiming); return _retval; } catch (std::exception &e) { pbSetError("updateFractions", e.what()); return 0; } } static const Pb::Register _RP_updateFractions("", "updateFractions", _W_19); extern "C" { void PbRegister_updateFractions() { KEEP_UNUSED(_RP_updateFractions); } } struct KnUpdateFlagsObs : public KernelBase { KnUpdateFlagsObs(FlagGrid &flags, const MACGrid *fractions, const Grid &phiObs, const Grid *phiOut, const Grid *phiIn, int boundaryWidth) : KernelBase(&flags, boundaryWidth), flags(flags), fractions(fractions), phiObs(phiObs), phiOut(phiOut), phiIn(phiIn), boundaryWidth(boundaryWidth) { runMessage(); run(); } inline void op(int i, int j, int k, FlagGrid &flags, const MACGrid *fractions, const Grid &phiObs, const Grid *phiOut, const Grid *phiIn, int boundaryWidth) const { bool isObs = false; if (fractions) { Real f = 0.; f += fractions->get(i, j, k).x; f += fractions->get(i + 1, j, k).x; f += fractions->get(i, j, k).y; f += fractions->get(i, j + 1, k).y; if (flags.is3D()) { f += fractions->get(i, j, k).z; f += fractions->get(i, j, k + 1).z; } if (f == 0.) isObs = true; } else { if (phiObs(i, j, k) < 0.) isObs = true; } bool isOutflow = false; bool isInflow = false; if (phiOut && (*phiOut)(i, j, k) < 0.) isOutflow = true; if (phiIn && (*phiIn)(i, j, k) < 0.) isInflow = true; if (isObs) flags(i, j, k) = FlagGrid::TypeObstacle; else if (isInflow) flags(i, j, k) = (FlagGrid::TypeFluid | FlagGrid::TypeInflow); else if (isOutflow) flags(i, j, k) = (FlagGrid::TypeEmpty | FlagGrid::TypeOutflow); else flags(i, j, k) = FlagGrid::TypeEmpty; } inline FlagGrid &getArg0() { return flags; } typedef FlagGrid type0; inline const MACGrid *getArg1() { return fractions; } typedef MACGrid type1; inline const Grid &getArg2() { return phiObs; } typedef Grid type2; inline const Grid *getArg3() { return phiOut; } typedef Grid type3; inline const Grid *getArg4() { return phiIn; } typedef Grid type4; inline int &getArg5() { return boundaryWidth; } typedef int type5; void runMessage() { debMsg("Executing kernel KnUpdateFlagsObs ", 3); debMsg("Kernel range" << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ", 4); }; void operator()(const tbb::blocked_range &__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 = boundaryWidth; j < _maxY; j++) for (int i = boundaryWidth; i < _maxX; i++) op(i, j, k, flags, fractions, phiObs, phiOut, phiIn, boundaryWidth); } else { const int k = 0; for (int j = __r.begin(); j != (int)__r.end(); j++) for (int i = boundaryWidth; i < _maxX; i++) op(i, j, k, flags, fractions, phiObs, phiOut, phiIn, boundaryWidth); } } void run() { if (maxZ > 1) tbb::parallel_for(tbb::blocked_range(minZ, maxZ), *this); else tbb::parallel_for(tbb::blocked_range(boundaryWidth, maxY), *this); } FlagGrid &flags; const MACGrid *fractions; const Grid &phiObs; const Grid *phiOut; const Grid *phiIn; int boundaryWidth; }; //! update obstacle and outflow flags from levelsets //! optionally uses fill fractions for obstacle void setObstacleFlags(FlagGrid &flags, const Grid &phiObs, const MACGrid *fractions = NULL, const Grid *phiOut = NULL, const Grid *phiIn = NULL, int boundaryWidth = 1) { KnUpdateFlagsObs(flags, fractions, phiObs, phiOut, phiIn, boundaryWidth); } static PyObject *_W_20(PyObject *_self, PyObject *_linargs, PyObject *_kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt("notiming", -1, 0); pbPreparePlugin(parent, "setObstacleFlags", !noTiming); PyObject *_retval = 0; { ArgLocker _lock; FlagGrid &flags = *_args.getPtr("flags", 0, &_lock); const Grid &phiObs = *_args.getPtr>("phiObs", 1, &_lock); const MACGrid *fractions = _args.getPtrOpt("fractions", 2, NULL, &_lock); const Grid *phiOut = _args.getPtrOpt>("phiOut", 3, NULL, &_lock); const Grid *phiIn = _args.getPtrOpt>("phiIn", 4, NULL, &_lock); int boundaryWidth = _args.getOpt("boundaryWidth", 5, 1, &_lock); _retval = getPyNone(); setObstacleFlags(flags, phiObs, fractions, phiOut, phiIn, boundaryWidth); _args.check(); } pbFinalizePlugin(parent, "setObstacleFlags", !noTiming); return _retval; } catch (std::exception &e) { pbSetError("setObstacleFlags", e.what()); return 0; } } static const Pb::Register _RP_setObstacleFlags("", "setObstacleFlags", _W_20); extern "C" { void PbRegister_setObstacleFlags() { KEEP_UNUSED(_RP_setObstacleFlags); } } //! small helper for test case test_1040_secOrderBnd.py struct kninitVortexVelocity : public KernelBase { kninitVortexVelocity(const Grid &phiObs, MACGrid &vel, const Vec3 ¢er, const Real &radius) : KernelBase(&phiObs, 0), phiObs(phiObs), vel(vel), center(center), radius(radius) { runMessage(); run(); } inline void op(int i, int j, int k, const Grid &phiObs, MACGrid &vel, const Vec3 ¢er, const Real &radius) const { if (phiObs(i, j, k) >= -1.) { Real dx = i - center.x; if (dx >= 0) dx -= .5; else dx += .5; Real dy = j - center.y; Real r = std::sqrt(dx * dx + dy * dy); Real alpha = atan2(dy, dx); vel(i, j, k).x = -std::sin(alpha) * (r / radius); dx = i - center.x; dy = j - center.y; if (dy >= 0) dy -= .5; else dy += .5; r = std::sqrt(dx * dx + dy * dy); alpha = atan2(dy, dx); vel(i, j, k).y = std::cos(alpha) * (r / radius); } } inline const Grid &getArg0() { return phiObs; } typedef Grid type0; inline MACGrid &getArg1() { return vel; } typedef MACGrid type1; inline const Vec3 &getArg2() { return center; } typedef Vec3 type2; inline const Real &getArg3() { return radius; } typedef Real type3; void runMessage() { debMsg("Executing kernel kninitVortexVelocity ", 3); debMsg("Kernel range" << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ", 4); }; void operator()(const tbb::blocked_range &__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, phiObs, vel, center, radius); } 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, phiObs, vel, center, radius); } } void run() { if (maxZ > 1) tbb::parallel_for(tbb::blocked_range(minZ, maxZ), *this); else tbb::parallel_for(tbb::blocked_range(0, maxY), *this); } const Grid &phiObs; MACGrid &vel; const Vec3 ¢er; const Real &radius; }; void initVortexVelocity(const Grid &phiObs, MACGrid &vel, const Vec3 ¢er, const Real &radius) { kninitVortexVelocity(phiObs, vel, center, radius); } static PyObject *_W_21(PyObject *_self, PyObject *_linargs, PyObject *_kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt("notiming", -1, 0); pbPreparePlugin(parent, "initVortexVelocity", !noTiming); PyObject *_retval = 0; { ArgLocker _lock; const Grid &phiObs = *_args.getPtr>("phiObs", 0, &_lock); MACGrid &vel = *_args.getPtr("vel", 1, &_lock); const Vec3 ¢er = _args.get("center", 2, &_lock); const Real &radius = _args.get("radius", 3, &_lock); _retval = getPyNone(); initVortexVelocity(phiObs, vel, center, radius); _args.check(); } pbFinalizePlugin(parent, "initVortexVelocity", !noTiming); return _retval; } catch (std::exception &e) { pbSetError("initVortexVelocity", e.what()); return 0; } } static const Pb::Register _RP_initVortexVelocity("", "initVortexVelocity", _W_21); extern "C" { void PbRegister_initVortexVelocity() { KEEP_UNUSED(_RP_initVortexVelocity); } } //***************************************************************************** // helper functions for blurring //! class for Gaussian Blur struct GaussianKernelCreator { public: float mSigma; int mDim; float *mMat1D; GaussianKernelCreator() : mSigma(0.0f), mDim(0), mMat1D(NULL) { } GaussianKernelCreator(float sigma, int dim = 0) : mSigma(0.0f), mDim(0), mMat1D(NULL) { setGaussianSigma(sigma, dim); } Real getWeiAtDis(float disx, float disy) { float m = 1.0 / (sqrt(2.0 * M_PI) * mSigma); float v = m * exp(-(1.0 * disx * disx + 1.0 * disy * disy) / (2.0 * mSigma * mSigma)); return v; } Real getWeiAtDis(float disx, float disy, float disz) { float m = 1.0 / (sqrt(2.0 * M_PI) * mSigma); float v = m * exp(-(1.0 * disx * disx + 1.0 * disy * disy + 1.0 * disz * disz) / (2.0 * mSigma * mSigma)); return v; } void setGaussianSigma(float sigma, int dim = 0) { mSigma = sigma; if (dim < 3) mDim = (int)(2.0 * 3.0 * sigma + 1.0f); else mDim = dim; if (mDim < 3) mDim = 3; if (mDim % 2 == 0) ++mDim; // make dim odd float s2 = mSigma * mSigma; int c = mDim / 2; float m = 1.0 / (sqrt(2.0 * M_PI) * mSigma); // create 1D matrix if (mMat1D) delete[] mMat1D; mMat1D = new float[mDim]; for (int i = 0; i < (mDim + 1) / 2; i++) { float v = m * exp(-(1.0 * i * i) / (2.0 * s2)); mMat1D[c + i] = v; mMat1D[c - i] = v; } } ~GaussianKernelCreator() { if (mMat1D) delete[] mMat1D; } float get1DKernelValue(int off) { assertMsg(off >= 0 && off < mDim, "off exceeded boundary in Gaussian Kernel 1D!"); return mMat1D[off]; } }; template T convolveGrid(Grid &originGrid, GaussianKernelCreator &gkSigma, Vec3 pos, int cdir) { // pos should be the centre pos, e.g., 1.5, 4.5, 0.5 for grid pos 1,4,0 Vec3 step(1.0, 0.0, 0.0); if (cdir == 1) // todo, z step = Vec3(0.0, 1.0, 0.0); else if (cdir == 2) step = Vec3(0.0, 0.0, 1.0); T pxResult(0); for (int i = 0; i < gkSigma.mDim; ++i) { Vec3i curpos = toVec3i(pos - step * (i - gkSigma.mDim / 2)); if (originGrid.isInBounds(curpos)) pxResult += gkSigma.get1DKernelValue(i) * originGrid.get(curpos); else { // TODO , improve... Vec3i curfitpos = curpos; if (curfitpos.x < 0) curfitpos.x = 0; else if (curfitpos.x >= originGrid.getSizeX()) curfitpos.x = originGrid.getSizeX() - 1; if (curfitpos.y < 0) curfitpos.y = 0; else if (curfitpos.y >= originGrid.getSizeY()) curfitpos.y = originGrid.getSizeY() - 1; if (curfitpos.z < 0) curfitpos.z = 0; else if (curfitpos.z >= originGrid.getSizeZ()) curfitpos.z = originGrid.getSizeZ() - 1; pxResult += gkSigma.get1DKernelValue(i) * originGrid.get(curfitpos); } } return pxResult; } template struct knBlurGrid : public KernelBase { knBlurGrid(Grid &originGrid, Grid &targetGrid, GaussianKernelCreator &gkSigma, int cdir) : KernelBase(&originGrid, 0), originGrid(originGrid), targetGrid(targetGrid), gkSigma(gkSigma), cdir(cdir) { runMessage(); run(); } inline void op(int i, int j, int k, Grid &originGrid, Grid &targetGrid, GaussianKernelCreator &gkSigma, int cdir) const { targetGrid(i, j, k) = convolveGrid(originGrid, gkSigma, Vec3(i, j, k), cdir); } inline Grid &getArg0() { return originGrid; } typedef Grid type0; inline Grid &getArg1() { return targetGrid; } typedef Grid type1; inline GaussianKernelCreator &getArg2() { return gkSigma; } typedef GaussianKernelCreator type2; inline int &getArg3() { return cdir; } typedef int type3; void runMessage() { debMsg("Executing kernel knBlurGrid ", 3); debMsg("Kernel range" << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ", 4); }; void operator()(const tbb::blocked_range &__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, originGrid, targetGrid, gkSigma, cdir); } 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, originGrid, targetGrid, gkSigma, cdir); } } void run() { if (maxZ > 1) tbb::parallel_for(tbb::blocked_range(minZ, maxZ), *this); else tbb::parallel_for(tbb::blocked_range(0, maxY), *this); } Grid &originGrid; Grid &targetGrid; GaussianKernelCreator &gkSigma; int cdir; }; template int blurGrid(Grid &originGrid, Grid &targetGrid, float sigma) { GaussianKernelCreator tmGK(sigma); Grid tmpGrid(originGrid); knBlurGrid(originGrid, tmpGrid, tmGK, 0); // blur x knBlurGrid(tmpGrid, targetGrid, tmGK, 1); // blur y if (targetGrid.is3D()) { tmpGrid.copyFrom(targetGrid); knBlurGrid(tmpGrid, targetGrid, tmGK, 2); } return tmGK.mDim; } struct KnBlurMACGridGauss : public KernelBase { KnBlurMACGridGauss(MACGrid &originGrid, MACGrid &target, GaussianKernelCreator &gkSigma, int cdir) : KernelBase(&originGrid, 0), originGrid(originGrid), target(target), gkSigma(gkSigma), cdir(cdir) { runMessage(); run(); } inline void op(int i, int j, int k, MACGrid &originGrid, MACGrid &target, GaussianKernelCreator &gkSigma, int cdir) const { Vec3 pos(i, j, k); Vec3 step(1.0, 0.0, 0.0); if (cdir == 1) step = Vec3(0.0, 1.0, 0.0); else if (cdir == 2) step = Vec3(0.0, 0.0, 1.0); Vec3 pxResult(0.0f); for (int di = 0; di < gkSigma.mDim; ++di) { Vec3i curpos = toVec3i(pos - step * (di - gkSigma.mDim / 2)); if (!originGrid.isInBounds(curpos)) { if (curpos.x < 0) curpos.x = 0; else if (curpos.x >= originGrid.getSizeX()) curpos.x = originGrid.getSizeX() - 1; if (curpos.y < 0) curpos.y = 0; else if (curpos.y >= originGrid.getSizeY()) curpos.y = originGrid.getSizeY() - 1; if (curpos.z < 0) curpos.z = 0; else if (curpos.z >= originGrid.getSizeZ()) curpos.z = originGrid.getSizeZ() - 1; } pxResult += gkSigma.get1DKernelValue(di) * originGrid.get(curpos); } target(i, j, k) = pxResult; } inline MACGrid &getArg0() { return originGrid; } typedef MACGrid type0; inline MACGrid &getArg1() { return target; } typedef MACGrid type1; inline GaussianKernelCreator &getArg2() { return gkSigma; } typedef GaussianKernelCreator type2; inline int &getArg3() { return cdir; } typedef int type3; void runMessage() { debMsg("Executing kernel KnBlurMACGridGauss ", 3); debMsg("Kernel range" << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ", 4); }; void operator()(const tbb::blocked_range &__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, originGrid, target, gkSigma, cdir); } 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, originGrid, target, gkSigma, cdir); } } void run() { if (maxZ > 1) tbb::parallel_for(tbb::blocked_range(minZ, maxZ), *this); else tbb::parallel_for(tbb::blocked_range(0, maxY), *this); } MACGrid &originGrid; MACGrid ⌖ GaussianKernelCreator &gkSigma; int cdir; }; int blurMacGrid(MACGrid &oG, MACGrid &tG, float si) { GaussianKernelCreator tmGK(si); MACGrid tmpGrid(oG); KnBlurMACGridGauss(oG, tmpGrid, tmGK, 0); // blur x KnBlurMACGridGauss(tmpGrid, tG, tmGK, 1); // blur y if (tG.is3D()) { tmpGrid.copyFrom(tG); KnBlurMACGridGauss(tmpGrid, tG, tmGK, 2); } return tmGK.mDim; } static PyObject *_W_22(PyObject *_self, PyObject *_linargs, PyObject *_kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt("notiming", -1, 0); pbPreparePlugin(parent, "blurMacGrid", !noTiming); PyObject *_retval = 0; { ArgLocker _lock; MACGrid &oG = *_args.getPtr("oG", 0, &_lock); MACGrid &tG = *_args.getPtr("tG", 1, &_lock); float si = _args.get("si", 2, &_lock); _retval = toPy(blurMacGrid(oG, tG, si)); _args.check(); } pbFinalizePlugin(parent, "blurMacGrid", !noTiming); return _retval; } catch (std::exception &e) { pbSetError("blurMacGrid", e.what()); return 0; } } static const Pb::Register _RP_blurMacGrid("", "blurMacGrid", _W_22); extern "C" { void PbRegister_blurMacGrid() { KEEP_UNUSED(_RP_blurMacGrid); } } int blurRealGrid(Grid &oG, Grid &tG, float si) { return blurGrid(oG, tG, si); } static PyObject *_W_23(PyObject *_self, PyObject *_linargs, PyObject *_kwds) { try { PbArgs _args(_linargs, _kwds); FluidSolver *parent = _args.obtainParent(); bool noTiming = _args.getOpt("notiming", -1, 0); pbPreparePlugin(parent, "blurRealGrid", !noTiming); PyObject *_retval = 0; { ArgLocker _lock; Grid &oG = *_args.getPtr>("oG", 0, &_lock); Grid &tG = *_args.getPtr>("tG", 1, &_lock); float si = _args.get("si", 2, &_lock); _retval = toPy(blurRealGrid(oG, tG, si)); _args.check(); } pbFinalizePlugin(parent, "blurRealGrid", !noTiming); return _retval; } catch (std::exception &e) { pbSetError("blurRealGrid", e.what()); return 0; } } static const Pb::Register _RP_blurRealGrid("", "blurRealGrid", _W_23); extern "C" { void PbRegister_blurRealGrid() { KEEP_UNUSED(_RP_blurRealGrid); } } } // namespace Manta