Add Chromium-only Blender WebEngine parity work

This commit is contained in:
mes123456
2026-08-12 04:47:48 -04:00
commit 9fd26010f6
18225 changed files with 11622124 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,597 @@
// DO NOT EDIT !
// This file is generated using the MantaFlow preprocessor (prep generate).
// ----------------------------------------------------------------------------
//
// MantaFlow fluid solver framework
// Copyright 2016-2020 Kiwon Um, 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
//
// Affine Particle-In-Cell
//
// ----------------------------------------------------------------------------
#include "particle.h"
#include "grid.h"
namespace Manta {
#define FOR_INT_IJK(num) \
for (int i = 0; i < num; ++i) \
for (int j = 0; j < num; ++j) \
for (int k = 0; k < num; ++k)
static inline IndexInt indexUFace(const Vec3 &pos, const MACGrid &ref)
{
const Vec3i f = toVec3i(pos), c = toVec3i(pos - 0.5);
const IndexInt index = f.x * ref.getStrideX() + c.y * ref.getStrideY() + c.z * ref.getStrideZ();
assertDeb(ref.isInBounds(index),
"U face index out of bounds for particle position [" << pos.x << ", " << pos.y << ", "
<< pos.z << "]");
return (ref.isInBounds(index)) ? index : -1;
}
static inline IndexInt indexVFace(const Vec3 &pos, const MACGrid &ref)
{
const Vec3i f = toVec3i(pos), c = toVec3i(pos - 0.5);
const IndexInt index = c.x * ref.getStrideX() + f.y * ref.getStrideY() + c.z * ref.getStrideZ();
assertDeb(ref.isInBounds(index),
"V face index out of bounds for particle position [" << pos.x << ", " << pos.y << ", "
<< pos.z << "]");
return (ref.isInBounds(index)) ? index : -1;
}
static inline IndexInt indexWFace(const Vec3 &pos, const MACGrid &ref)
{
const Vec3i f = toVec3i(pos), c = toVec3i(pos - 0.5);
const IndexInt index = c.x * ref.getStrideX() + c.y * ref.getStrideY() + f.z * ref.getStrideZ();
assertDeb(ref.isInBounds(index),
"W face index out of bounds for particle position [" << pos.x << ", " << pos.y << ", "
<< pos.z << "]");
return (ref.isInBounds(index)) ? index : -1;
}
static inline IndexInt indexOffset(
const IndexInt gidx, const int i, const int j, const int k, const MACGrid &ref)
{
const IndexInt dX[2] = {0, ref.getStrideX()};
const IndexInt dY[2] = {0, ref.getStrideY()};
const IndexInt dZ[2] = {0, ref.getStrideZ()};
const IndexInt index = gidx + dX[i] + dY[j] + dZ[k];
assertDeb(ref.isInBounds(index), "Offset index " << index << " is out of bounds");
return (ref.isInBounds(index)) ? index : -1;
}
struct knApicMapLinearVec3ToMACGrid : public KernelBase {
knApicMapLinearVec3ToMACGrid(const BasicParticleSystem &p,
MACGrid &mg,
MACGrid &vg,
const ParticleDataImpl<Vec3> &vp,
const ParticleDataImpl<Vec3> &cpx,
const ParticleDataImpl<Vec3> &cpy,
const ParticleDataImpl<Vec3> &cpz,
const ParticleDataImpl<int> *ptype,
const int exclude,
const int boundaryWidth)
: KernelBase(p.size()),
p(p),
mg(mg),
vg(vg),
vp(vp),
cpx(cpx),
cpy(cpy),
cpz(cpz),
ptype(ptype),
exclude(exclude),
boundaryWidth(boundaryWidth)
{
runMessage();
run();
}
inline void op(IndexInt idx,
const BasicParticleSystem &p,
MACGrid &mg,
MACGrid &vg,
const ParticleDataImpl<Vec3> &vp,
const ParticleDataImpl<Vec3> &cpx,
const ParticleDataImpl<Vec3> &cpy,
const ParticleDataImpl<Vec3> &cpz,
const ParticleDataImpl<int> *ptype,
const int exclude,
const int boundaryWidth)
{
if (!p.isActive(idx) || (ptype && ((*ptype)[idx] & exclude)))
return;
if (!vg.isInBounds(p.getPos(idx), boundaryWidth)) {
debMsg("Skipping particle at index " << idx
<< ". Is out of bounds and cannot be applied to grid.",
1);
return;
}
const Vec3 &pos = p.getPos(idx), &vel = vp[idx];
const Vec3i f = toVec3i(pos);
const Vec3i c = toVec3i(pos - 0.5);
const Vec3 wf = clamp(pos - toVec3(f), Vec3(0.), Vec3(1.));
const Vec3 wc = clamp(pos - toVec3(c) - 0.5, Vec3(0.), Vec3(1.));
{ // u-face
const IndexInt gidx = indexUFace(pos, vg);
if (gidx < 0)
return; // debug will fail before
const Vec3 gpos(f.x, c.y + 0.5, c.z + 0.5);
const Real wi[2] = {Real(1) - wf.x, wf.x};
const Real wj[2] = {Real(1) - wc.y, wc.y};
const Real wk[2] = {Real(1) - wc.z, wc.z};
FOR_INT_IJK(2)
{
const Real w = wi[i] * wj[j] * wk[k];
const IndexInt vidx = indexOffset(gidx, i, j, k, vg);
if (vidx < 0)
continue; // debug will fail before
mg[vidx].x += w;
vg[vidx].x += w * vel.x;
vg[vidx].x += w * dot(cpx[idx], gpos + Vec3(i, j, k) - pos);
}
}
{ // v-face
const IndexInt gidx = indexVFace(pos, vg);
if (gidx < 0)
return;
const Vec3 gpos(c.x + 0.5, f.y, c.z + 0.5);
const Real wi[2] = {Real(1) - wc.x, wc.x};
const Real wj[2] = {Real(1) - wf.y, wf.y};
const Real wk[2] = {Real(1) - wc.z, wc.z};
FOR_INT_IJK(2)
{
const Real w = wi[i] * wj[j] * wk[k];
const IndexInt vidx = indexOffset(gidx, i, j, k, vg);
if (vidx < 0)
continue;
mg[vidx].y += w;
vg[vidx].y += w * vel.y;
vg[vidx].y += w * dot(cpy[idx], gpos + Vec3(i, j, k) - pos);
}
}
if (!vg.is3D())
return;
{ // w-face
const IndexInt gidx = indexWFace(pos, vg);
if (gidx < 0)
return;
const Vec3 gpos(c.x + 0.5, c.y + 0.5, f.z);
const Real wi[2] = {Real(1) - wc.x, wc.x};
const Real wj[2] = {Real(1) - wc.y, wc.y};
const Real wk[2] = {Real(1) - wf.z, wf.z};
FOR_INT_IJK(2)
{
const Real w = wi[i] * wj[j] * wk[k];
const IndexInt vidx = indexOffset(gidx, i, j, k, vg);
if (vidx < 0)
continue;
mg[vidx].z += w;
vg[vidx].z += w * vel.z;
vg[vidx].z += w * dot(cpz[idx], gpos + Vec3(i, j, k) - pos);
}
}
}
inline const BasicParticleSystem &getArg0()
{
return p;
}
typedef BasicParticleSystem type0;
inline MACGrid &getArg1()
{
return mg;
}
typedef MACGrid type1;
inline MACGrid &getArg2()
{
return vg;
}
typedef MACGrid type2;
inline const ParticleDataImpl<Vec3> &getArg3()
{
return vp;
}
typedef ParticleDataImpl<Vec3> type3;
inline const ParticleDataImpl<Vec3> &getArg4()
{
return cpx;
}
typedef ParticleDataImpl<Vec3> type4;
inline const ParticleDataImpl<Vec3> &getArg5()
{
return cpy;
}
typedef ParticleDataImpl<Vec3> type5;
inline const ParticleDataImpl<Vec3> &getArg6()
{
return cpz;
}
typedef ParticleDataImpl<Vec3> type6;
inline const ParticleDataImpl<int> *getArg7()
{
return ptype;
}
typedef ParticleDataImpl<int> type7;
inline const int &getArg8()
{
return exclude;
}
typedef int type8;
inline const int &getArg9()
{
return boundaryWidth;
}
typedef int type9;
void runMessage()
{
debMsg("Executing kernel knApicMapLinearVec3ToMACGrid ", 3);
debMsg("Kernel range"
<< " size " << size << " ",
4);
};
void run()
{
const IndexInt _sz = size;
for (IndexInt i = 0; i < _sz; i++)
op(i, p, mg, vg, vp, cpx, cpy, cpz, ptype, exclude, boundaryWidth);
}
const BasicParticleSystem &p;
MACGrid &mg;
MACGrid &vg;
const ParticleDataImpl<Vec3> &vp;
const ParticleDataImpl<Vec3> &cpx;
const ParticleDataImpl<Vec3> &cpy;
const ParticleDataImpl<Vec3> &cpz;
const ParticleDataImpl<int> *ptype;
const int exclude;
const int boundaryWidth;
};
void apicMapPartsToMAC(const FlagGrid &flags,
MACGrid &vel,
const BasicParticleSystem &parts,
const ParticleDataImpl<Vec3> &partVel,
const ParticleDataImpl<Vec3> &cpx,
const ParticleDataImpl<Vec3> &cpy,
const ParticleDataImpl<Vec3> &cpz,
MACGrid *mass = nullptr,
const ParticleDataImpl<int> *ptype = nullptr,
const int exclude = 0,
const int boundaryWidth = 0)
{
// affine map: let's assume that the particle mass is constant, 1.0
MACGrid tmpmass(vel.getParent());
tmpmass.clear();
vel.clear();
knApicMapLinearVec3ToMACGrid(
parts, tmpmass, vel, partVel, cpx, cpy, cpz, ptype, exclude, boundaryWidth);
tmpmass.stomp(VECTOR_EPSILON);
vel.safeDivide(tmpmass);
if (mass)
(*mass).swap(tmpmass);
}
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, "apicMapPartsToMAC", !noTiming);
PyObject *_retval = nullptr;
{
ArgLocker _lock;
const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
MACGrid &vel = *_args.getPtr<MACGrid>("vel", 1, &_lock);
const BasicParticleSystem &parts = *_args.getPtr<BasicParticleSystem>("parts", 2, &_lock);
const ParticleDataImpl<Vec3> &partVel = *_args.getPtr<ParticleDataImpl<Vec3>>(
"partVel", 3, &_lock);
const ParticleDataImpl<Vec3> &cpx = *_args.getPtr<ParticleDataImpl<Vec3>>("cpx", 4, &_lock);
const ParticleDataImpl<Vec3> &cpy = *_args.getPtr<ParticleDataImpl<Vec3>>("cpy", 5, &_lock);
const ParticleDataImpl<Vec3> &cpz = *_args.getPtr<ParticleDataImpl<Vec3>>("cpz", 6, &_lock);
MACGrid *mass = _args.getPtrOpt<MACGrid>("mass", 7, nullptr, &_lock);
const ParticleDataImpl<int> *ptype = _args.getPtrOpt<ParticleDataImpl<int>>(
"ptype", 8, nullptr, &_lock);
const int exclude = _args.getOpt<int>("exclude", 9, 0, &_lock);
const int boundaryWidth = _args.getOpt<int>("boundaryWidth", 10, 0, &_lock);
_retval = getPyNone();
apicMapPartsToMAC(
flags, vel, parts, partVel, cpx, cpy, cpz, mass, ptype, exclude, boundaryWidth);
_args.check();
}
pbFinalizePlugin(parent, "apicMapPartsToMAC", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("apicMapPartsToMAC", e.what());
return 0;
}
}
static const Pb::Register _RP_apicMapPartsToMAC("", "apicMapPartsToMAC", _W_0);
extern "C" {
void PbRegister_apicMapPartsToMAC()
{
KEEP_UNUSED(_RP_apicMapPartsToMAC);
}
}
struct knApicMapLinearMACGridToVec3 : public KernelBase {
knApicMapLinearMACGridToVec3(ParticleDataImpl<Vec3> &vp,
ParticleDataImpl<Vec3> &cpx,
ParticleDataImpl<Vec3> &cpy,
ParticleDataImpl<Vec3> &cpz,
const BasicParticleSystem &p,
const MACGrid &vg,
const FlagGrid &flags,
const ParticleDataImpl<int> *ptype,
const int exclude,
const int boundaryWidth)
: KernelBase(vp.size()),
vp(vp),
cpx(cpx),
cpy(cpy),
cpz(cpz),
p(p),
vg(vg),
flags(flags),
ptype(ptype),
exclude(exclude),
boundaryWidth(boundaryWidth)
{
runMessage();
run();
}
inline void op(IndexInt idx,
ParticleDataImpl<Vec3> &vp,
ParticleDataImpl<Vec3> &cpx,
ParticleDataImpl<Vec3> &cpy,
ParticleDataImpl<Vec3> &cpz,
const BasicParticleSystem &p,
const MACGrid &vg,
const FlagGrid &flags,
const ParticleDataImpl<int> *ptype,
const int exclude,
const int boundaryWidth) const
{
if (!p.isActive(idx) || (ptype && ((*ptype)[idx] & exclude)))
return;
if (!vg.isInBounds(p.getPos(idx), boundaryWidth)) {
debMsg("Skipping particle at index " << idx
<< ". Is out of bounds and cannot get value from grid.",
1);
return;
}
vp[idx] = cpx[idx] = cpy[idx] = cpz[idx] = Vec3(Real(0));
const Real gw[2] = {-Real(1), Real(1)};
const Vec3 &pos = p.getPos(idx);
const Vec3i f = toVec3i(pos);
const Vec3i c = toVec3i(pos - 0.5);
const Vec3 wf = clamp(pos - toVec3(f), Vec3(0.), Vec3(1.));
const Vec3 wc = clamp(pos - toVec3(c) - 0.5, Vec3(0.), Vec3(1.));
{ // u-face
const IndexInt gidx = indexUFace(pos, vg);
if (gidx < 0)
return; // debug will fail before
const Real wx[2] = {Real(1) - wf.x, wf.x};
const Real wy[2] = {Real(1) - wc.y, wc.y};
const Real wz[2] = {Real(1) - wc.z, wc.z};
FOR_INT_IJK(2)
{
const IndexInt vidx = indexOffset(gidx, i, j, k, vg);
if (vidx < 0)
continue; // debug will fail before
const Real vgx = vg[vidx].x;
vp[idx].x += wx[i] * wy[j] * wz[k] * vgx;
cpx[idx].x += gw[i] * wy[j] * wz[k] * vgx;
cpx[idx].y += wx[i] * gw[j] * wz[k] * vgx;
cpx[idx].z += wx[i] * wy[j] * gw[k] * vgx;
}
}
{ // v-face
const IndexInt gidx = indexVFace(pos, vg);
if (gidx < 0)
return;
const Real wx[2] = {Real(1) - wc.x, wc.x};
const Real wy[2] = {Real(1) - wf.y, wf.y};
const Real wz[2] = {Real(1) - wc.z, wc.z};
FOR_INT_IJK(2)
{
const IndexInt vidx = indexOffset(gidx, i, j, k, vg);
if (vidx < 0)
continue;
const Real vgy = vg[vidx].y;
vp[idx].y += wx[i] * wy[j] * wz[k] * vgy;
cpy[idx].x += gw[i] * wy[j] * wz[k] * vgy;
cpy[idx].y += wx[i] * gw[j] * wz[k] * vgy;
cpy[idx].z += wx[i] * wy[j] * gw[k] * vgy;
}
}
if (!vg.is3D())
return;
{ // w-face
const IndexInt gidx = indexWFace(pos, vg);
if (gidx < 0)
return;
const Real wx[2] = {Real(1) - wc.x, wc.x};
const Real wy[2] = {Real(1) - wc.y, wc.y};
const Real wz[2] = {Real(1) - wf.z, wf.z};
FOR_INT_IJK(2)
{
const IndexInt vidx = indexOffset(gidx, i, j, k, vg);
if (vidx < 0)
continue;
const Real vgz = vg[vidx].z;
vp[idx].z += wx[i] * wy[j] * wz[k] * vgz;
cpz[idx].x += gw[i] * wy[j] * wz[k] * vgz;
cpz[idx].y += wx[i] * gw[j] * wz[k] * vgz;
cpz[idx].z += wx[i] * wy[j] * gw[k] * vgz;
}
}
}
inline ParticleDataImpl<Vec3> &getArg0()
{
return vp;
}
typedef ParticleDataImpl<Vec3> type0;
inline ParticleDataImpl<Vec3> &getArg1()
{
return cpx;
}
typedef ParticleDataImpl<Vec3> type1;
inline ParticleDataImpl<Vec3> &getArg2()
{
return cpy;
}
typedef ParticleDataImpl<Vec3> type2;
inline ParticleDataImpl<Vec3> &getArg3()
{
return cpz;
}
typedef ParticleDataImpl<Vec3> type3;
inline const BasicParticleSystem &getArg4()
{
return p;
}
typedef BasicParticleSystem type4;
inline const MACGrid &getArg5()
{
return vg;
}
typedef MACGrid type5;
inline const FlagGrid &getArg6()
{
return flags;
}
typedef FlagGrid type6;
inline const ParticleDataImpl<int> *getArg7()
{
return ptype;
}
typedef ParticleDataImpl<int> type7;
inline const int &getArg8()
{
return exclude;
}
typedef int type8;
inline const int &getArg9()
{
return boundaryWidth;
}
typedef int type9;
void runMessage()
{
debMsg("Executing kernel knApicMapLinearMACGridToVec3 ", 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, vp, cpx, cpy, cpz, p, vg, flags, ptype, exclude, boundaryWidth);
}
void run()
{
tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
}
ParticleDataImpl<Vec3> &vp;
ParticleDataImpl<Vec3> &cpx;
ParticleDataImpl<Vec3> &cpy;
ParticleDataImpl<Vec3> &cpz;
const BasicParticleSystem &p;
const MACGrid &vg;
const FlagGrid &flags;
const ParticleDataImpl<int> *ptype;
const int exclude;
const int boundaryWidth;
};
void apicMapMACGridToParts(ParticleDataImpl<Vec3> &partVel,
ParticleDataImpl<Vec3> &cpx,
ParticleDataImpl<Vec3> &cpy,
ParticleDataImpl<Vec3> &cpz,
const BasicParticleSystem &parts,
const MACGrid &vel,
const FlagGrid &flags,
const ParticleDataImpl<int> *ptype = nullptr,
const int exclude = 0,
const int boundaryWidth = 0)
{
knApicMapLinearMACGridToVec3(
partVel, cpx, cpy, cpz, parts, vel, flags, ptype, exclude, boundaryWidth);
}
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, "apicMapMACGridToParts", !noTiming);
PyObject *_retval = nullptr;
{
ArgLocker _lock;
ParticleDataImpl<Vec3> &partVel = *_args.getPtr<ParticleDataImpl<Vec3>>(
"partVel", 0, &_lock);
ParticleDataImpl<Vec3> &cpx = *_args.getPtr<ParticleDataImpl<Vec3>>("cpx", 1, &_lock);
ParticleDataImpl<Vec3> &cpy = *_args.getPtr<ParticleDataImpl<Vec3>>("cpy", 2, &_lock);
ParticleDataImpl<Vec3> &cpz = *_args.getPtr<ParticleDataImpl<Vec3>>("cpz", 3, &_lock);
const BasicParticleSystem &parts = *_args.getPtr<BasicParticleSystem>("parts", 4, &_lock);
const MACGrid &vel = *_args.getPtr<MACGrid>("vel", 5, &_lock);
const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 6, &_lock);
const ParticleDataImpl<int> *ptype = _args.getPtrOpt<ParticleDataImpl<int>>(
"ptype", 7, nullptr, &_lock);
const int exclude = _args.getOpt<int>("exclude", 8, 0, &_lock);
const int boundaryWidth = _args.getOpt<int>("boundaryWidth", 9, 0, &_lock);
_retval = getPyNone();
apicMapMACGridToParts(
partVel, cpx, cpy, cpz, parts, vel, flags, ptype, exclude, boundaryWidth);
_args.check();
}
pbFinalizePlugin(parent, "apicMapMACGridToParts", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("apicMapMACGridToParts", e.what());
return 0;
}
}
static const Pb::Register _RP_apicMapMACGridToParts("", "apicMapMACGridToParts", _W_1);
extern "C" {
void PbRegister_apicMapMACGridToParts()
{
KEEP_UNUSED(_RP_apicMapMACGridToParts);
}
}
} // namespace Manta

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,435 @@
// DO NOT EDIT !
// This file is generated using the MantaFlow preprocessor (prep generate).
/******************************************************************************
*
* MantaFlow fluid solver framework
* Copyright 2016 Sebastian Barschkis, 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
*
* Fire modeling plugin
*
******************************************************************************/
#include "general.h"
#include "grid.h"
#include "vectorbase.h"
using namespace std;
namespace Manta {
struct KnProcessBurn : public KernelBase {
KnProcessBurn(Grid<Real> &fuel,
Grid<Real> &density,
Grid<Real> &react,
Grid<Real> *red,
Grid<Real> *green,
Grid<Real> *blue,
Grid<Real> *heat,
Real burningRate,
Real flameSmoke,
Real ignitionTemp,
Real maxTemp,
Real dt,
Vec3 flameSmokeColor)
: KernelBase(&fuel, 1),
fuel(fuel),
density(density),
react(react),
red(red),
green(green),
blue(blue),
heat(heat),
burningRate(burningRate),
flameSmoke(flameSmoke),
ignitionTemp(ignitionTemp),
maxTemp(maxTemp),
dt(dt),
flameSmokeColor(flameSmokeColor)
{
runMessage();
run();
}
inline void op(int i,
int j,
int k,
Grid<Real> &fuel,
Grid<Real> &density,
Grid<Real> &react,
Grid<Real> *red,
Grid<Real> *green,
Grid<Real> *blue,
Grid<Real> *heat,
Real burningRate,
Real flameSmoke,
Real ignitionTemp,
Real maxTemp,
Real dt,
Vec3 flameSmokeColor) const
{
// Save initial values
Real origFuel = fuel(i, j, k);
Real origSmoke = density(i, j, k);
Real smokeEmit = 0.0f;
Real flame = 0.0f;
// Process fuel
fuel(i, j, k) -= burningRate * dt;
if (fuel(i, j, k) < 0.0f)
fuel(i, j, k) = 0.0f;
// Process reaction coordinate
if (origFuel > VECTOR_EPSILON) {
react(i, j, k) *= fuel(i, j, k) / origFuel;
flame = pow(react(i, j, k), 0.5f);
}
else {
react(i, j, k) = 0.0f;
}
// Set fluid temperature based on fuel burn rate and "flameSmoke" factor
smokeEmit = (origFuel < 1.0f) ? (1.0 - origFuel) * 0.5f : 0.0f;
smokeEmit = (smokeEmit + 0.5f) * (origFuel - fuel(i, j, k)) * 0.1f * flameSmoke;
density(i, j, k) += smokeEmit;
clamp(density(i, j, k), (Real)0.0f, (Real)1.0f);
// Set fluid temperature from the flame temperature profile
if (heat && flame)
(*heat)(i, j, k) = (1.0f - flame) * ignitionTemp + flame * maxTemp;
// Mix new color
if (smokeEmit > VECTOR_EPSILON) {
float smokeFactor = density(i, j, k) / (origSmoke + smokeEmit);
if (red)
(*red)(i, j, k) = ((*red)(i, j, k) + flameSmokeColor.x * smokeEmit) * smokeFactor;
if (green)
(*green)(i, j, k) = ((*green)(i, j, k) + flameSmokeColor.y * smokeEmit) * smokeFactor;
if (blue)
(*blue)(i, j, k) = ((*blue)(i, j, k) + flameSmokeColor.z * smokeEmit) * smokeFactor;
}
}
inline Grid<Real> &getArg0()
{
return fuel;
}
typedef Grid<Real> type0;
inline Grid<Real> &getArg1()
{
return density;
}
typedef Grid<Real> type1;
inline Grid<Real> &getArg2()
{
return react;
}
typedef Grid<Real> type2;
inline Grid<Real> *getArg3()
{
return red;
}
typedef Grid<Real> type3;
inline Grid<Real> *getArg4()
{
return green;
}
typedef Grid<Real> type4;
inline Grid<Real> *getArg5()
{
return blue;
}
typedef Grid<Real> type5;
inline Grid<Real> *getArg6()
{
return heat;
}
typedef Grid<Real> type6;
inline Real &getArg7()
{
return burningRate;
}
typedef Real type7;
inline Real &getArg8()
{
return flameSmoke;
}
typedef Real type8;
inline Real &getArg9()
{
return ignitionTemp;
}
typedef Real type9;
inline Real &getArg10()
{
return maxTemp;
}
typedef Real type10;
inline Real &getArg11()
{
return dt;
}
typedef Real type11;
inline Vec3 &getArg12()
{
return flameSmokeColor;
}
typedef Vec3 type12;
void runMessage()
{
debMsg("Executing kernel KnProcessBurn ", 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,
fuel,
density,
react,
red,
green,
blue,
heat,
burningRate,
flameSmoke,
ignitionTemp,
maxTemp,
dt,
flameSmokeColor);
}
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,
fuel,
density,
react,
red,
green,
blue,
heat,
burningRate,
flameSmoke,
ignitionTemp,
maxTemp,
dt,
flameSmokeColor);
}
}
void run()
{
if (maxZ > 1)
tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
else
tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
}
Grid<Real> &fuel;
Grid<Real> &density;
Grid<Real> &react;
Grid<Real> *red;
Grid<Real> *green;
Grid<Real> *blue;
Grid<Real> *heat;
Real burningRate;
Real flameSmoke;
Real ignitionTemp;
Real maxTemp;
Real dt;
Vec3 flameSmokeColor;
};
void processBurn(Grid<Real> &fuel,
Grid<Real> &density,
Grid<Real> &react,
Grid<Real> *red = nullptr,
Grid<Real> *green = nullptr,
Grid<Real> *blue = nullptr,
Grid<Real> *heat = nullptr,
Real burningRate = 0.75f,
Real flameSmoke = 1.0f,
Real ignitionTemp = 1.25f,
Real maxTemp = 1.75f,
Vec3 flameSmokeColor = Vec3(0.7f, 0.7f, 0.7f))
{
Real dt = fuel.getParent()->getDt();
KnProcessBurn(fuel,
density,
react,
red,
green,
blue,
heat,
burningRate,
flameSmoke,
ignitionTemp,
maxTemp,
dt,
flameSmokeColor);
}
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, "processBurn", !noTiming);
PyObject *_retval = nullptr;
{
ArgLocker _lock;
Grid<Real> &fuel = *_args.getPtr<Grid<Real>>("fuel", 0, &_lock);
Grid<Real> &density = *_args.getPtr<Grid<Real>>("density", 1, &_lock);
Grid<Real> &react = *_args.getPtr<Grid<Real>>("react", 2, &_lock);
Grid<Real> *red = _args.getPtrOpt<Grid<Real>>("red", 3, nullptr, &_lock);
Grid<Real> *green = _args.getPtrOpt<Grid<Real>>("green", 4, nullptr, &_lock);
Grid<Real> *blue = _args.getPtrOpt<Grid<Real>>("blue", 5, nullptr, &_lock);
Grid<Real> *heat = _args.getPtrOpt<Grid<Real>>("heat", 6, nullptr, &_lock);
Real burningRate = _args.getOpt<Real>("burningRate", 7, 0.75f, &_lock);
Real flameSmoke = _args.getOpt<Real>("flameSmoke", 8, 1.0f, &_lock);
Real ignitionTemp = _args.getOpt<Real>("ignitionTemp", 9, 1.25f, &_lock);
Real maxTemp = _args.getOpt<Real>("maxTemp", 10, 1.75f, &_lock);
Vec3 flameSmokeColor = _args.getOpt<Vec3>(
"flameSmokeColor", 11, Vec3(0.7f, 0.7f, 0.7f), &_lock);
_retval = getPyNone();
processBurn(fuel,
density,
react,
red,
green,
blue,
heat,
burningRate,
flameSmoke,
ignitionTemp,
maxTemp,
flameSmokeColor);
_args.check();
}
pbFinalizePlugin(parent, "processBurn", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("processBurn", e.what());
return 0;
}
}
static const Pb::Register _RP_processBurn("", "processBurn", _W_0);
extern "C" {
void PbRegister_processBurn()
{
KEEP_UNUSED(_RP_processBurn);
}
}
struct KnUpdateFlame : public KernelBase {
KnUpdateFlame(const Grid<Real> &react, Grid<Real> &flame)
: KernelBase(&react, 1), react(react), flame(flame)
{
runMessage();
run();
}
inline void op(int i, int j, int k, const Grid<Real> &react, Grid<Real> &flame) const
{
if (react(i, j, k) > 0.0f)
flame(i, j, k) = pow(react(i, j, k), 0.5f);
else
flame(i, j, k) = 0.0f;
}
inline const Grid<Real> &getArg0()
{
return react;
}
typedef Grid<Real> type0;
inline Grid<Real> &getArg1()
{
return flame;
}
typedef Grid<Real> type1;
void runMessage()
{
debMsg("Executing kernel KnUpdateFlame ", 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, react, flame);
}
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, react, flame);
}
}
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<Real> &react;
Grid<Real> &flame;
};
void updateFlame(const Grid<Real> &react, Grid<Real> &flame)
{
KnUpdateFlame(react, flame);
}
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, "updateFlame", !noTiming);
PyObject *_retval = nullptr;
{
ArgLocker _lock;
const Grid<Real> &react = *_args.getPtr<Grid<Real>>("react", 0, &_lock);
Grid<Real> &flame = *_args.getPtr<Grid<Real>>("flame", 1, &_lock);
_retval = getPyNone();
updateFlame(react, flame);
_args.check();
}
pbFinalizePlugin(parent, "updateFlame", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("updateFlame", e.what());
return 0;
}
}
static const Pb::Register _RP_updateFlame("", "updateFlame", _W_1);
extern "C" {
void PbRegister_updateFlame()
{
KEEP_UNUSED(_RP_updateFlame);
}
}
} // namespace Manta

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,801 @@
// 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
*
* Plugins for pressure correction: solve_pressure, and ghost fluid helpers
*
******************************************************************************/
#include "vectorbase.h"
#include "grid.h"
#include "kernel.h"
#include "conjugategrad.h"
#include "rcmatrix.h"
using namespace std;
namespace Manta {
// only supports a single blur size for now, globals stored here
bool gBlurPrecomputed = false;
int gBlurKernelRadius = -1;
Matrix gBlurKernel;
// *****************************************************************************
// Helper functions for fluid guiding
//! creates a 1D (horizontal) Gaussian blur kernel of size n and standard deviation sigma
Matrix get1DGaussianBlurKernel(const int n, const int sigma)
{
Matrix x(n), y(n);
for (int j = 0; j < n; j++) {
x.add_to_element(0, j, -(n - 1) * 0.5);
y.add_to_element(0, j, j - (n - 1) * 0.5);
}
Matrix G(n);
Real sumG = 0;
for (int j = 0; j < n; j++) {
G.add_to_element(0,
j,
1 / (2 * M_PI * sigma * sigma) *
exp(-(x(0, j) * x(0, j) + y(0, j) * y(0, j)) / (2 * sigma * sigma)));
sumG += G(0, j);
}
G = G * (1.0 / sumG);
return G;
}
//! convolves in with 1D kernel (centred at the kernel's midpoint) in the x-direction
//! (out must be a grid of zeros)
struct apply1DKernelDirX : public KernelBase {
apply1DKernelDirX(const MACGrid &in, MACGrid &out, const Matrix &kernel)
: KernelBase(&in, 0), in(in), out(out), kernel(kernel)
{
runMessage();
run();
}
inline void op(int i, int j, int k, const MACGrid &in, MACGrid &out, const Matrix &kernel) const
{
int nx = in.getSizeX();
int kn = kernel.n;
int kCentre = kn / 2;
for (int m = 0, ind = kn - 1, ii = i - kCentre; m < kn; m++, ind--, ii++) {
if (ii < 0)
continue;
else if (ii >= nx)
break;
else
out(i, j, k) += in(ii, j, k) * kernel(0, ind);
}
}
inline const MACGrid &getArg0()
{
return in;
}
typedef MACGrid type0;
inline MACGrid &getArg1()
{
return out;
}
typedef MACGrid type1;
inline const Matrix &getArg2()
{
return kernel;
}
typedef Matrix type2;
void runMessage()
{
debMsg("Executing kernel apply1DKernelDirX ", 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, in, out, kernel);
}
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, in, out, kernel);
}
}
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 MACGrid &in;
MACGrid &out;
const Matrix &kernel;
};
//! convolves in with 1D kernel (centred at the kernel's midpoint) in the y-direction
//! (out must be a grid of zeros)
struct apply1DKernelDirY : public KernelBase {
apply1DKernelDirY(const MACGrid &in, MACGrid &out, const Matrix &kernel)
: KernelBase(&in, 0), in(in), out(out), kernel(kernel)
{
runMessage();
run();
}
inline void op(int i, int j, int k, const MACGrid &in, MACGrid &out, const Matrix &kernel) const
{
int ny = in.getSizeY();
int kn = kernel.n;
int kCentre = kn / 2;
for (int m = 0, ind = kn - 1, jj = j - kCentre; m < kn; m++, ind--, jj++) {
if (jj < 0)
continue;
else if (jj >= ny)
break;
else
out(i, j, k) += in(i, jj, k) * kernel(0, ind);
}
}
inline const MACGrid &getArg0()
{
return in;
}
typedef MACGrid type0;
inline MACGrid &getArg1()
{
return out;
}
typedef MACGrid type1;
inline const Matrix &getArg2()
{
return kernel;
}
typedef Matrix type2;
void runMessage()
{
debMsg("Executing kernel apply1DKernelDirY ", 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, in, out, kernel);
}
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, in, out, kernel);
}
}
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 MACGrid &in;
MACGrid &out;
const Matrix &kernel;
};
//! convolves in with 1D kernel (centred at the kernel's midpoint) in the z-direction
//! (out must be a grid of zeros)
struct apply1DKernelDirZ : public KernelBase {
apply1DKernelDirZ(const MACGrid &in, MACGrid &out, const Matrix &kernel)
: KernelBase(&in, 0), in(in), out(out), kernel(kernel)
{
runMessage();
run();
}
inline void op(int i, int j, int k, const MACGrid &in, MACGrid &out, const Matrix &kernel) const
{
int nz = in.getSizeZ();
int kn = kernel.n;
int kCentre = kn / 2;
for (int m = 0, ind = kn - 1, kk = k - kCentre; m < kn; m++, ind--, kk++) {
if (kk < 0)
continue;
else if (kk >= nz)
break;
else
out(i, j, k) += in(i, j, kk) * kernel(0, ind);
}
}
inline const MACGrid &getArg0()
{
return in;
}
typedef MACGrid type0;
inline MACGrid &getArg1()
{
return out;
}
typedef MACGrid type1;
inline const Matrix &getArg2()
{
return kernel;
}
typedef Matrix type2;
void runMessage()
{
debMsg("Executing kernel apply1DKernelDirZ ", 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, in, out, kernel);
}
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, in, out, kernel);
}
}
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 MACGrid &in;
MACGrid &out;
const Matrix &kernel;
};
//! Apply separable Gaussian blur in 2D
void applySeparableKernel2D(MACGrid &grid, const FlagGrid &flags, const Matrix &kernel)
{
// int nx = grid.getSizeX(), ny = grid.getSizeY();
// int kn = kernel.n;
// int kCentre = kn / 2;
FluidSolver *parent = grid.getParent();
MACGrid orig = MACGrid(parent);
orig.copyFrom(grid);
MACGrid gridX = MACGrid(parent);
apply1DKernelDirX(grid, gridX, kernel);
MACGrid gridXY = MACGrid(parent);
apply1DKernelDirY(gridX, gridXY, kernel);
grid.copyFrom(gridXY);
FOR_IJK(grid)
{
if ((i > 0 && flags.isObstacle(i - 1, j, k)) || (j > 0 && flags.isObstacle(i, j - 1, k)) ||
flags.isObstacle(i, j, k)) {
grid(i, j, k).x = orig(i, j, k).x;
grid(i, j, k).y = orig(i, j, k).y;
grid(i, j, k).z = orig(i, j, k).z;
}
}
}
//! Apply separable Gaussian blur in 3D
void applySeparableKernel3D(MACGrid &grid, const FlagGrid &flags, const Matrix &kernel)
{
// int nx = grid.getSizeX(), ny = grid.getSizeY(), nz = grid.getSizeZ();
// int kn = kernel.n;
// int kCentre = kn / 2;
FluidSolver *parent = grid.getParent();
MACGrid orig = MACGrid(parent);
orig.copyFrom(grid);
MACGrid gridX = MACGrid(parent);
apply1DKernelDirX(grid, gridX, kernel);
MACGrid gridXY = MACGrid(parent);
apply1DKernelDirY(gridX, gridXY, kernel);
MACGrid gridXYZ = MACGrid(parent);
apply1DKernelDirZ(gridXY, gridXYZ, kernel);
grid.copyFrom(gridXYZ);
FOR_IJK(grid)
{
if ((i > 0 && flags.isObstacle(i - 1, j, k)) || (j > 0 && flags.isObstacle(i, j - 1, k)) ||
(k > 0 && flags.isObstacle(i, j, k - 1)) || flags.isObstacle(i, j, k)) {
grid(i, j, k).x = orig(i, j, k).x;
grid(i, j, k).y = orig(i, j, k).y;
grid(i, j, k).z = orig(i, j, k).z;
}
}
}
//! Apply separable Gaussian blur in 2D or 3D depending on input dimensions
void applySeparableKernel(MACGrid &grid, const FlagGrid &flags, const Matrix &kernel)
{
if (!grid.is3D())
applySeparableKernel2D(grid, flags, kernel);
else
applySeparableKernel3D(grid, flags, kernel);
}
//! Compute r-norm for the stopping criterion
Real getRNorm(const MACGrid &x, const MACGrid &z)
{
MACGrid r = MACGrid(x.getParent());
r.copyFrom(x);
r.sub(z);
return r.getMaxAbs();
}
//! Compute s-norm for the stopping criterion
Real getSNorm(const Real rho, const MACGrid &z, const MACGrid &z_prev)
{
MACGrid s = MACGrid(z_prev.getParent());
s.copyFrom(z_prev);
s.sub(z);
s.multConst(rho);
return s.getMaxAbs();
}
//! Compute primal eps for the stopping criterion
Real getEpsPri(const Real eps_abs, const Real eps_rel, const MACGrid &x, const MACGrid &z)
{
Real max_norm = max(x.getMaxAbs(), z.getMaxAbs());
Real eps_pri = sqrt(x.is3D() ? 3.0 : 2.0) * eps_abs + eps_rel * max_norm;
return eps_pri;
}
//! Compute dual eps for the stopping criterion
Real getEpsDual(const Real eps_abs, const Real eps_rel, const MACGrid &y)
{
Real eps_dual = sqrt(y.is3D() ? 3.0 : 2.0) * eps_abs + eps_rel * y.getMaxAbs();
return eps_dual;
}
//! Create a spiral velocity field in 2D as a test scene (optionally in 3D)
void getSpiralVelocity(const FlagGrid &flags,
MACGrid &vel,
Real strength = 1.0,
bool with3D = false)
{
int nx = flags.getSizeX(), ny = flags.getSizeY(), nz = 1;
if (with3D)
nz = flags.getSizeZ();
Real midX = 0.5 * (Real)(nx - 1);
Real midY = 0.5 * (Real)(ny - 1);
for (int i = 0; i < nx; i++) {
for (int j = 0; j < ny; j++) {
for (int k = 0; k < nz; k++) {
int idx = flags.index(i, j, k);
Real diffX = midX - i;
Real diffY = midY - j;
Real hypotenuse = sqrt(diffX * diffX + diffY * diffY);
if (hypotenuse > 0) {
vel[idx].x = diffY / hypotenuse;
vel[idx].y = -diffX / hypotenuse;
}
}
}
}
vel.multConst(strength);
}
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, "getSpiralVelocity", !noTiming);
PyObject *_retval = nullptr;
{
ArgLocker _lock;
const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
MACGrid &vel = *_args.getPtr<MACGrid>("vel", 1, &_lock);
Real strength = _args.getOpt<Real>("strength", 2, 1.0, &_lock);
bool with3D = _args.getOpt<bool>("with3D", 3, false, &_lock);
_retval = getPyNone();
getSpiralVelocity(flags, vel, strength, with3D);
_args.check();
}
pbFinalizePlugin(parent, "getSpiralVelocity", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("getSpiralVelocity", e.what());
return 0;
}
}
static const Pb::Register _RP_getSpiralVelocity("", "getSpiralVelocity", _W_0);
extern "C" {
void PbRegister_getSpiralVelocity()
{
KEEP_UNUSED(_RP_getSpiralVelocity);
}
}
//! Set the guiding weight W as a gradient in the y-direction
void setGradientYWeight(
Grid<Real> &W, const int minY, const int maxY, const Real valAtMin, const Real valAtMax)
{
FOR_IJK(W)
{
if (minY <= j && j <= maxY) {
Real val = valAtMin;
if (valAtMax != valAtMin) {
Real ratio = (Real)(j - minY) / (Real)(maxY - minY);
val = ratio * valAtMax + (1.0 - ratio) * valAtMin;
}
W(i, j, k) = val;
}
}
}
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, "setGradientYWeight", !noTiming);
PyObject *_retval = nullptr;
{
ArgLocker _lock;
Grid<Real> &W = *_args.getPtr<Grid<Real>>("W", 0, &_lock);
const int minY = _args.get<int>("minY", 1, &_lock);
const int maxY = _args.get<int>("maxY", 2, &_lock);
const Real valAtMin = _args.get<Real>("valAtMin", 3, &_lock);
const Real valAtMax = _args.get<Real>("valAtMax", 4, &_lock);
_retval = getPyNone();
setGradientYWeight(W, minY, maxY, valAtMin, valAtMax);
_args.check();
}
pbFinalizePlugin(parent, "setGradientYWeight", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("setGradientYWeight", e.what());
return 0;
}
}
static const Pb::Register _RP_setGradientYWeight("", "setGradientYWeight", _W_1);
extern "C" {
void PbRegister_setGradientYWeight()
{
KEEP_UNUSED(_RP_setGradientYWeight);
}
}
// *****************************************************************************
// More helper functions for fluid guiding
//! Apply Gaussian blur (either 2D or 3D) in a separable way
void applySeparableGaussianBlur(MACGrid &grid, const FlagGrid &flags, const Matrix &kernel1D)
{
assertMsg(gBlurPrecomputed, "Error - blue kernel not precomputed");
applySeparableKernel(grid, flags, kernel1D);
}
//! Precomputation performed before the first PD iteration
void ADMM_precompute_Separable(int blurRadius)
{
if (gBlurPrecomputed) {
assertMsg(gBlurKernelRadius == blurRadius,
"More than a single blur radius not supported at the moment.");
return;
}
int kernelSize = 2 * blurRadius + 1;
gBlurKernel = get1DGaussianBlurKernel(kernelSize, kernelSize);
gBlurPrecomputed = true;
gBlurKernelRadius = blurRadius;
}
//! Apply approximate multiplication of inverse(M)
void applyApproxInvM(MACGrid &v, const FlagGrid &flags, const MACGrid &invA)
{
MACGrid v_new = MACGrid(v.getParent());
v_new.copyFrom(v);
v_new.mult(invA);
applySeparableGaussianBlur(v_new, flags, gBlurKernel);
applySeparableGaussianBlur(v_new, flags, gBlurKernel);
v_new.multConst(2.0);
v_new.mult(invA);
v.mult(invA);
v.sub(v_new);
}
//! Precompute Q, a reused quantity in the PD iterations
//! Q = 2*G*G*(velT-velC)-sigma*velC
void precomputeQ(MACGrid &Q,
const FlagGrid &flags,
const MACGrid &velT_region,
const MACGrid &velC,
const Matrix &gBlurKernel,
const Real sigma)
{
Q.copyFrom(velT_region);
Q.sub(velC);
applySeparableGaussianBlur(Q, flags, gBlurKernel);
applySeparableGaussianBlur(Q, flags, gBlurKernel);
Q.multConst(2.0);
Q.addScaled(velC, -sigma);
}
//! Precompute inverse(A), a reused quantity in the PD iterations
//! A = 2*S^2 + p*I, invA = elementwise 1/A
void precomputeInvA(MACGrid &invA, const Grid<Real> &weight, const Real sigma)
{
FOR_IJK(invA)
{
Real val = 2 * weight(i, j, k) * weight(i, j, k) + sigma;
if (val < 0.01)
val = 0.01;
Real invVal = 1.0 / val;
invA(i, j, k).x = invVal;
invA(i, j, k).y = invVal;
invA(i, j, k).z = invVal;
}
}
//! proximal operator of f , guiding
void prox_f(MACGrid &v,
const FlagGrid &flags,
const MACGrid &Q,
const MACGrid &velC,
const Real sigma,
const MACGrid &invA)
{
v.multConst(sigma);
v.add(Q);
applyApproxInvM(v, flags, invA);
v.add(velC);
}
// *****************************************************************************
// re-uses main pressure solve from pressure.cpp
void solvePressure(MACGrid &vel,
Grid<Real> &pressure,
const FlagGrid &flags,
Real cgAccuracy = 1e-3,
const Grid<Real> *phi = nullptr,
const Grid<Real> *perCellCorr = nullptr,
const MACGrid *fractions = nullptr,
const MACGrid *obvel = nullptr,
Real gfClamp = 1e-04,
Real cgMaxIterFac = 1.5,
bool precondition = true,
int preconditioner = 1,
bool enforceCompatibility = false,
bool useL2Norm = false,
bool zeroPressureFixing = false,
const Grid<Real> *curv = nullptr,
const Real surfTens = 0.0,
Grid<Real> *retRhs = nullptr);
//! Main function for fluid guiding , includes "regular" pressure solve
void PD_fluid_guiding(MACGrid &vel,
MACGrid &velT,
Grid<Real> &pressure,
FlagGrid &flags,
Grid<Real> &weight,
int blurRadius = 5,
Real theta = 1.0,
Real tau = 1.0,
Real sigma = 1.0,
Real epsRel = 1e-3,
Real epsAbs = 1e-3,
int maxIters = 200,
Grid<Real> *phi = nullptr,
Grid<Real> *perCellCorr = nullptr,
MACGrid *fractions = nullptr,
MACGrid *obvel = nullptr,
Real gfClamp = 1e-04,
Real cgMaxIterFac = 1.5,
Real cgAccuracy = 1e-3,
int preconditioner = 1,
bool zeroPressureFixing = false,
const Grid<Real> *curv = nullptr,
const Real surfTens = 0.)
{
FluidSolver *parent = vel.getParent();
// initialize dual/slack variables
MACGrid velC = MACGrid(parent);
velC.copyFrom(vel);
MACGrid x = MACGrid(parent);
MACGrid y = MACGrid(parent);
MACGrid z = MACGrid(parent);
MACGrid x0 = MACGrid(parent);
MACGrid z0 = MACGrid(parent);
// precomputation
ADMM_precompute_Separable(blurRadius);
MACGrid Q = MACGrid(parent);
precomputeQ(Q, flags, velT, velC, gBlurKernel, sigma);
MACGrid invA = MACGrid(parent);
precomputeInvA(invA, weight, sigma);
// loop
int iter = 0;
for (iter = 0; iter < maxIters; iter++) {
// x-update
x0.copyFrom(x);
x.multConst(1.0 / sigma);
x.add(y);
prox_f(x, flags, Q, velC, sigma, invA);
x.multConst(-sigma);
x.addScaled(y, sigma);
x.add(x0);
// z-update
z0.copyFrom(z);
z.addScaled(x, -tau);
Real cgAccuracyAdaptive = cgAccuracy;
solvePressure(z,
pressure,
flags,
cgAccuracyAdaptive,
phi,
perCellCorr,
fractions,
obvel,
gfClamp,
cgMaxIterFac,
true,
preconditioner,
false,
false,
zeroPressureFixing,
curv,
surfTens);
// y-update
y.copyFrom(z);
y.sub(z0);
y.multConst(theta);
y.add(z);
// stopping criterion
bool stop = (iter > 0 && getRNorm(z, z0) < getEpsDual(epsAbs, epsRel, z));
if (stop || (iter == maxIters - 1))
break;
}
// vel_new = z
vel.copyFrom(z);
debMsg("PD_fluid_guiding iterations:" << iter, 1);
}
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, "PD_fluid_guiding", !noTiming);
PyObject *_retval = nullptr;
{
ArgLocker _lock;
MACGrid &vel = *_args.getPtr<MACGrid>("vel", 0, &_lock);
MACGrid &velT = *_args.getPtr<MACGrid>("velT", 1, &_lock);
Grid<Real> &pressure = *_args.getPtr<Grid<Real>>("pressure", 2, &_lock);
FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 3, &_lock);
Grid<Real> &weight = *_args.getPtr<Grid<Real>>("weight", 4, &_lock);
int blurRadius = _args.getOpt<int>("blurRadius", 5, 5, &_lock);
Real theta = _args.getOpt<Real>("theta", 6, 1.0, &_lock);
Real tau = _args.getOpt<Real>("tau", 7, 1.0, &_lock);
Real sigma = _args.getOpt<Real>("sigma", 8, 1.0, &_lock);
Real epsRel = _args.getOpt<Real>("epsRel", 9, 1e-3, &_lock);
Real epsAbs = _args.getOpt<Real>("epsAbs", 10, 1e-3, &_lock);
int maxIters = _args.getOpt<int>("maxIters", 11, 200, &_lock);
Grid<Real> *phi = _args.getPtrOpt<Grid<Real>>("phi", 12, nullptr, &_lock);
Grid<Real> *perCellCorr = _args.getPtrOpt<Grid<Real>>("perCellCorr", 13, nullptr, &_lock);
MACGrid *fractions = _args.getPtrOpt<MACGrid>("fractions", 14, nullptr, &_lock);
MACGrid *obvel = _args.getPtrOpt<MACGrid>("obvel", 15, nullptr, &_lock);
Real gfClamp = _args.getOpt<Real>("gfClamp", 16, 1e-04, &_lock);
Real cgMaxIterFac = _args.getOpt<Real>("cgMaxIterFac", 17, 1.5, &_lock);
Real cgAccuracy = _args.getOpt<Real>("cgAccuracy", 18, 1e-3, &_lock);
int preconditioner = _args.getOpt<int>("preconditioner", 19, 1, &_lock);
bool zeroPressureFixing = _args.getOpt<bool>("zeroPressureFixing", 20, false, &_lock);
const Grid<Real> *curv = _args.getPtrOpt<Grid<Real>>("curv", 21, nullptr, &_lock);
const Real surfTens = _args.getOpt<Real>("surfTens", 22, 0., &_lock);
_retval = getPyNone();
PD_fluid_guiding(vel,
velT,
pressure,
flags,
weight,
blurRadius,
theta,
tau,
sigma,
epsRel,
epsAbs,
maxIters,
phi,
perCellCorr,
fractions,
obvel,
gfClamp,
cgMaxIterFac,
cgAccuracy,
preconditioner,
zeroPressureFixing,
curv,
surfTens);
_args.check();
}
pbFinalizePlugin(parent, "PD_fluid_guiding", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("PD_fluid_guiding", e.what());
return 0;
}
}
static const Pb::Register _RP_PD_fluid_guiding("", "PD_fluid_guiding", _W_2);
extern "C" {
void PbRegister_PD_fluid_guiding()
{
KEEP_UNUSED(_RP_PD_fluid_guiding);
}
}
//! reset precomputation
void releaseBlurPrecomp()
{
gBlurPrecomputed = false;
gBlurKernelRadius = -1;
gBlurKernel = 0.f;
}
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, "releaseBlurPrecomp", !noTiming);
PyObject *_retval = nullptr;
{
ArgLocker _lock;
_retval = getPyNone();
releaseBlurPrecomp();
_args.check();
}
pbFinalizePlugin(parent, "releaseBlurPrecomp", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("releaseBlurPrecomp", e.what());
return 0;
}
}
static const Pb::Register _RP_releaseBlurPrecomp("", "releaseBlurPrecomp", _W_3);
extern "C" {
void PbRegister_releaseBlurPrecomp()
{
KEEP_UNUSED(_RP_releaseBlurPrecomp);
}
}
} // namespace Manta

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,578 @@
// 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
*
* Turbulence modeling plugins
*
******************************************************************************/
#include "grid.h"
#include "commonkernels.h"
#include "vortexsheet.h"
#include "conjugategrad.h"
using namespace std;
namespace Manta {
// k-epsilon model constants
const Real keCmu = 0.09;
const Real keC1 = 1.44;
const Real keC2 = 1.92;
const Real keS1 = 1.0;
const Real keS2 = 1.3;
// k-epsilon limiters
const Real keU0 = 1.0;
const Real keImin = 2e-3;
const Real keImax = 1.0;
const Real keNuMin = 1e-3;
const Real keNuMax = 5.0;
//! clamp k and epsilon to limits
struct KnTurbulenceClamp : public KernelBase {
KnTurbulenceClamp(
Grid<Real> &kgrid, Grid<Real> &egrid, Real minK, Real maxK, Real minNu, Real maxNu)
: KernelBase(&kgrid, 0),
kgrid(kgrid),
egrid(egrid),
minK(minK),
maxK(maxK),
minNu(minNu),
maxNu(maxNu)
{
runMessage();
run();
}
inline void op(IndexInt idx,
Grid<Real> &kgrid,
Grid<Real> &egrid,
Real minK,
Real maxK,
Real minNu,
Real maxNu) const
{
Real eps = egrid[idx];
Real ke = clamp(kgrid[idx], minK, maxK);
Real nu = keCmu * square(ke) / eps;
if (nu > maxNu)
eps = keCmu * square(ke) / maxNu;
if (nu < minNu)
eps = keCmu * square(ke) / minNu;
kgrid[idx] = ke;
egrid[idx] = eps;
}
inline Grid<Real> &getArg0()
{
return kgrid;
}
typedef Grid<Real> type0;
inline Grid<Real> &getArg1()
{
return egrid;
}
typedef Grid<Real> type1;
inline Real &getArg2()
{
return minK;
}
typedef Real type2;
inline Real &getArg3()
{
return maxK;
}
typedef Real type3;
inline Real &getArg4()
{
return minNu;
}
typedef Real type4;
inline Real &getArg5()
{
return maxNu;
}
typedef Real type5;
void runMessage()
{
debMsg("Executing kernel KnTurbulenceClamp ", 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, kgrid, egrid, minK, maxK, minNu, maxNu);
}
void run()
{
tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
}
Grid<Real> &kgrid;
Grid<Real> &egrid;
Real minK;
Real maxK;
Real minNu;
Real maxNu;
};
//! Compute k-epsilon production term P = 2*nu_T*sum_ij(Sij^2) and the turbulent viscosity
//! nu_T=C_mu*k^2/eps
struct KnComputeProduction : public KernelBase {
KnComputeProduction(const MACGrid &vel,
const Grid<Vec3> &velCenter,
const Grid<Real> &ke,
const Grid<Real> &eps,
Grid<Real> &prod,
Grid<Real> &nuT,
Grid<Real> *strain,
Real pscale = 1.0f)
: KernelBase(&vel, 1),
vel(vel),
velCenter(velCenter),
ke(ke),
eps(eps),
prod(prod),
nuT(nuT),
strain(strain),
pscale(pscale)
{
runMessage();
run();
}
inline void op(int i,
int j,
int k,
const MACGrid &vel,
const Grid<Vec3> &velCenter,
const Grid<Real> &ke,
const Grid<Real> &eps,
Grid<Real> &prod,
Grid<Real> &nuT,
Grid<Real> *strain,
Real pscale = 1.0f) const
{
Real curEps = eps(i, j, k);
if (curEps > 0) {
// turbulent viscosity: nu_T = C_mu * k^2/eps
Real curNu = keCmu * square(ke(i, j, k)) / curEps;
// compute Sij = 1/2 * (dU_i/dx_j + dU_j/dx_i)
Vec3 diag = Vec3(vel(i + 1, j, k).x, vel(i, j + 1, k).y, vel(i, j, k + 1).z) - vel(i, j, k);
Vec3 ux = 0.5 * (velCenter(i + 1, j, k) - velCenter(i - 1, j, k));
Vec3 uy = 0.5 * (velCenter(i, j + 1, k) - velCenter(i, j - 1, k));
Vec3 uz = 0.5 * (velCenter(i, j, k + 1) - velCenter(i, j, k - 1));
Real S12 = 0.5 * (ux.y + uy.x);
Real S13 = 0.5 * (ux.z + uz.x);
Real S23 = 0.5 * (uy.z + uz.y);
Real S2 = square(diag.x) + square(diag.y) + square(diag.z) + 2.0 * square(S12) +
2.0 * square(S13) + 2.0 * square(S23);
// P = 2*nu_T*sum_ij(Sij^2)
prod(i, j, k) = 2.0 * curNu * S2 * pscale;
nuT(i, j, k) = curNu;
if (strain)
(*strain)(i, j, k) = sqrt(S2);
}
else {
prod(i, j, k) = 0;
nuT(i, j, k) = 0;
if (strain)
(*strain)(i, j, k) = 0;
}
}
inline const MACGrid &getArg0()
{
return vel;
}
typedef MACGrid type0;
inline const Grid<Vec3> &getArg1()
{
return velCenter;
}
typedef Grid<Vec3> type1;
inline const Grid<Real> &getArg2()
{
return ke;
}
typedef Grid<Real> type2;
inline const Grid<Real> &getArg3()
{
return eps;
}
typedef Grid<Real> type3;
inline Grid<Real> &getArg4()
{
return prod;
}
typedef Grid<Real> type4;
inline Grid<Real> &getArg5()
{
return nuT;
}
typedef Grid<Real> type5;
inline Grid<Real> *getArg6()
{
return strain;
}
typedef Grid<Real> type6;
inline Real &getArg7()
{
return pscale;
}
typedef Real type7;
void runMessage()
{
debMsg("Executing kernel KnComputeProduction ", 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, vel, velCenter, ke, eps, prod, nuT, strain, pscale);
}
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, vel, velCenter, ke, eps, prod, nuT, strain, pscale);
}
}
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 MACGrid &vel;
const Grid<Vec3> &velCenter;
const Grid<Real> &ke;
const Grid<Real> &eps;
Grid<Real> &prod;
Grid<Real> &nuT;
Grid<Real> *strain;
Real pscale;
};
//! Compute k-epsilon production term P = 2*nu_T*sum_ij(Sij^2) and the turbulent viscosity
//! nu_T=C_mu*k^2/eps
void KEpsilonComputeProduction(const MACGrid &vel,
Grid<Real> &k,
Grid<Real> &eps,
Grid<Real> &prod,
Grid<Real> &nuT,
Grid<Real> *strain = 0,
Real pscale = 1.0f)
{
// get centered velocity grid
Grid<Vec3> vcenter(k.getParent());
GetCentered(vcenter, vel);
FillInBoundary(vcenter, 1);
// compute limits
const Real minK = 1.5 * square(keU0) * square(keImin);
const Real maxK = 1.5 * square(keU0) * square(keImax);
KnTurbulenceClamp(k, eps, minK, maxK, keNuMin, keNuMax);
KnComputeProduction(vel, vcenter, k, eps, prod, nuT, strain, pscale);
}
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, "KEpsilonComputeProduction", !noTiming);
PyObject *_retval = nullptr;
{
ArgLocker _lock;
const MACGrid &vel = *_args.getPtr<MACGrid>("vel", 0, &_lock);
Grid<Real> &k = *_args.getPtr<Grid<Real>>("k", 1, &_lock);
Grid<Real> &eps = *_args.getPtr<Grid<Real>>("eps", 2, &_lock);
Grid<Real> &prod = *_args.getPtr<Grid<Real>>("prod", 3, &_lock);
Grid<Real> &nuT = *_args.getPtr<Grid<Real>>("nuT", 4, &_lock);
Grid<Real> *strain = _args.getPtrOpt<Grid<Real>>("strain", 5, 0, &_lock);
Real pscale = _args.getOpt<Real>("pscale", 6, 1.0f, &_lock);
_retval = getPyNone();
KEpsilonComputeProduction(vel, k, eps, prod, nuT, strain, pscale);
_args.check();
}
pbFinalizePlugin(parent, "KEpsilonComputeProduction", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("KEpsilonComputeProduction", e.what());
return 0;
}
}
static const Pb::Register _RP_KEpsilonComputeProduction("", "KEpsilonComputeProduction", _W_0);
extern "C" {
void PbRegister_KEpsilonComputeProduction()
{
KEEP_UNUSED(_RP_KEpsilonComputeProduction);
}
}
//! Integrate source terms of k-epsilon equation
struct KnAddTurbulenceSource : public KernelBase {
KnAddTurbulenceSource(Grid<Real> &kgrid, Grid<Real> &egrid, const Grid<Real> &pgrid, Real dt)
: KernelBase(&kgrid, 0), kgrid(kgrid), egrid(egrid), pgrid(pgrid), dt(dt)
{
runMessage();
run();
}
inline void op(
IndexInt idx, Grid<Real> &kgrid, Grid<Real> &egrid, const Grid<Real> &pgrid, Real dt) const
{
Real eps = egrid[idx], prod = pgrid[idx], ke = kgrid[idx];
if (ke <= 0)
ke = 1e-3; // pre-clamp to avoid nan
Real newK = ke + dt * (prod - eps);
Real newEps = eps + dt * (prod * keC1 - eps * keC2) * (eps / ke);
if (newEps <= 0)
newEps = 1e-4; // pre-clamp to avoid nan
kgrid[idx] = newK;
egrid[idx] = newEps;
}
inline Grid<Real> &getArg0()
{
return kgrid;
}
typedef Grid<Real> type0;
inline Grid<Real> &getArg1()
{
return egrid;
}
typedef Grid<Real> type1;
inline const Grid<Real> &getArg2()
{
return pgrid;
}
typedef Grid<Real> type2;
inline Real &getArg3()
{
return dt;
}
typedef Real type3;
void runMessage()
{
debMsg("Executing kernel KnAddTurbulenceSource ", 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, kgrid, egrid, pgrid, dt);
}
void run()
{
tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
}
Grid<Real> &kgrid;
Grid<Real> &egrid;
const Grid<Real> &pgrid;
Real dt;
};
//! Integrate source terms of k-epsilon equation
void KEpsilonSources(Grid<Real> &k, Grid<Real> &eps, Grid<Real> &prod)
{
Real dt = k.getParent()->getDt();
KnAddTurbulenceSource(k, eps, prod, dt);
// compute limits
const Real minK = 1.5 * square(keU0) * square(keImin);
const Real maxK = 1.5 * square(keU0) * square(keImax);
KnTurbulenceClamp(k, eps, minK, maxK, keNuMin, keNuMax);
}
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, "KEpsilonSources", !noTiming);
PyObject *_retval = nullptr;
{
ArgLocker _lock;
Grid<Real> &k = *_args.getPtr<Grid<Real>>("k", 0, &_lock);
Grid<Real> &eps = *_args.getPtr<Grid<Real>>("eps", 1, &_lock);
Grid<Real> &prod = *_args.getPtr<Grid<Real>>("prod", 2, &_lock);
_retval = getPyNone();
KEpsilonSources(k, eps, prod);
_args.check();
}
pbFinalizePlugin(parent, "KEpsilonSources", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("KEpsilonSources", e.what());
return 0;
}
}
static const Pb::Register _RP_KEpsilonSources("", "KEpsilonSources", _W_1);
extern "C" {
void PbRegister_KEpsilonSources()
{
KEEP_UNUSED(_RP_KEpsilonSources);
}
}
//! Initialize the domain or boundary conditions
void KEpsilonBcs(
const FlagGrid &flags, Grid<Real> &k, Grid<Real> &eps, Real intensity, Real nu, bool fillArea)
{
// compute limits
const Real vk = 1.5 * square(keU0) * square(intensity);
const Real ve = keCmu * square(vk) / nu;
FOR_IDX(k)
{
if (fillArea || flags.isObstacle(idx)) {
k[idx] = vk;
eps[idx] = ve;
}
}
}
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, "KEpsilonBcs", !noTiming);
PyObject *_retval = nullptr;
{
ArgLocker _lock;
const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
Grid<Real> &k = *_args.getPtr<Grid<Real>>("k", 1, &_lock);
Grid<Real> &eps = *_args.getPtr<Grid<Real>>("eps", 2, &_lock);
Real intensity = _args.get<Real>("intensity", 3, &_lock);
Real nu = _args.get<Real>("nu", 4, &_lock);
bool fillArea = _args.get<bool>("fillArea", 5, &_lock);
_retval = getPyNone();
KEpsilonBcs(flags, k, eps, intensity, nu, fillArea);
_args.check();
}
pbFinalizePlugin(parent, "KEpsilonBcs", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("KEpsilonBcs", e.what());
return 0;
}
}
static const Pb::Register _RP_KEpsilonBcs("", "KEpsilonBcs", _W_2);
extern "C" {
void PbRegister_KEpsilonBcs()
{
KEEP_UNUSED(_RP_KEpsilonBcs);
}
}
//! Gradient diffusion smoothing. Not unconditionally stable -- should probably do substepping etc.
void ApplyGradDiff(
const Grid<Real> &grid, Grid<Real> &res, const Grid<Real> &nu, Real dt, Real sigma)
{
// should do this (but requires better boundary handling)
/*MACGrid grad(grid.getParent());
GradientOpMAC(grad, grid);
grad *= nu;
DivergenceOpMAC(res, grad);
res *= dt/sigma; */
LaplaceOp(res, grid);
res *= nu;
res *= dt / sigma;
}
//! Compute k-epsilon turbulent viscosity
void KEpsilonGradientDiffusion(
Grid<Real> &k, Grid<Real> &eps, Grid<Real> &nuT, Real sigmaU = 4.0, MACGrid *vel = 0)
{
Real dt = k.getParent()->getDt();
Grid<Real> res(k.getParent());
// gradient diffusion of k
ApplyGradDiff(k, res, nuT, dt, keS1);
k += res;
// gradient diffusion of epsilon
ApplyGradDiff(eps, res, nuT, dt, keS2);
eps += res;
// gradient diffusion of velocity
if (vel) {
Grid<Real> vc(k.getParent());
for (int c = 0; c < 3; c++) {
GetComponent(*vel, vc, c);
ApplyGradDiff(vc, res, nuT, dt, sigmaU);
vc += res;
SetComponent(*vel, vc, c);
}
}
}
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, "KEpsilonGradientDiffusion", !noTiming);
PyObject *_retval = nullptr;
{
ArgLocker _lock;
Grid<Real> &k = *_args.getPtr<Grid<Real>>("k", 0, &_lock);
Grid<Real> &eps = *_args.getPtr<Grid<Real>>("eps", 1, &_lock);
Grid<Real> &nuT = *_args.getPtr<Grid<Real>>("nuT", 2, &_lock);
Real sigmaU = _args.getOpt<Real>("sigmaU", 3, 4.0, &_lock);
MACGrid *vel = _args.getPtrOpt<MACGrid>("vel", 4, 0, &_lock);
_retval = getPyNone();
KEpsilonGradientDiffusion(k, eps, nuT, sigmaU, vel);
_args.check();
}
pbFinalizePlugin(parent, "KEpsilonGradientDiffusion", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("KEpsilonGradientDiffusion", e.what());
return 0;
}
}
static const Pb::Register _RP_KEpsilonGradientDiffusion("", "KEpsilonGradientDiffusion", _W_3);
extern "C" {
void PbRegister_KEpsilonGradientDiffusion()
{
KEEP_UNUSED(_RP_KEpsilonGradientDiffusion);
}
}
} // namespace Manta

View File

@@ -0,0 +1,780 @@
// 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
*
* Smoothing etc. for meshes
*
******************************************************************************/
/******************************************************************************/
// Copyright note:
//
// These functions (C) Chris Wojtan
// Long-term goal is to unify with his split&merge codebase
//
/******************************************************************************/
#include <queue>
#include <algorithm>
#include "mesh.h"
#include "kernel.h"
#include "edgecollapse.h"
#include <mesh.h>
#include <stack>
using namespace std;
namespace Manta {
//! Mesh smoothing
/*! see Desbrun 99 "Implicit fairing of of irregular meshes using diffusion and curvature flow"*/
void smoothMesh(Mesh &mesh, Real strength, int steps = 1, Real minLength = 1e-5)
{
const Real dt = mesh.getParent()->getDt();
const Real str = min(dt * strength, (Real)1);
mesh.rebuildQuickCheck();
// calculate original mesh volume
Vec3 origCM;
Real origVolume = mesh.computeCenterOfMass(origCM);
// temp vertices
const int numCorners = mesh.numTris() * 3;
const int numNodes = mesh.numNodes();
vector<Vec3> temp(numNodes);
vector<bool> visited(numNodes);
for (int s = 0; s < steps; s++) {
// reset markers
for (size_t i = 0; i < visited.size(); i++)
visited[i] = false;
for (int c = 0; c < numCorners; c++) {
const int node = mesh.corners(c).node;
if (visited[node])
continue;
const Vec3 pos = mesh.nodes(node).pos;
Vec3 dx(0.0);
Real totalLen = 0;
// rotate around vertex
set<int> &ring = mesh.get1Ring(node).nodes;
for (set<int>::iterator it = ring.begin(); it != ring.end(); it++) {
Vec3 edge = mesh.nodes(*it).pos - pos;
Real len = norm(edge);
if (len > minLength) {
dx += edge * (1.0 / len);
totalLen += len;
}
else {
totalLen = 0.0;
break;
}
}
visited[node] = true;
temp[node] = pos;
if (totalLen != 0)
temp[node] += dx * (str / totalLen);
}
// copy back
for (int n = 0; n < numNodes; n++)
if (!mesh.isNodeFixed(n))
mesh.nodes(n).pos = temp[n];
}
// calculate new mesh volume
Vec3 newCM;
Real newVolume = mesh.computeCenterOfMass(newCM);
// preserve volume : scale relative to CM
Real beta;
#if defined(WIN32) || defined(_WIN32)
beta = pow((Real)std::abs(origVolume / newVolume), (Real)(1. / 3.));
#else
beta = cbrt(origVolume / newVolume);
#endif
for (int n = 0; n < numNodes; n++)
if (!mesh.isNodeFixed(n))
mesh.nodes(n).pos = origCM + (mesh.nodes(n).pos - newCM) * beta;
}
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, "smoothMesh", !noTiming);
PyObject *_retval = nullptr;
{
ArgLocker _lock;
Mesh &mesh = *_args.getPtr<Mesh>("mesh", 0, &_lock);
Real strength = _args.get<Real>("strength", 1, &_lock);
int steps = _args.getOpt<int>("steps", 2, 1, &_lock);
Real minLength = _args.getOpt<Real>("minLength", 3, 1e-5, &_lock);
_retval = getPyNone();
smoothMesh(mesh, strength, steps, minLength);
_args.check();
}
pbFinalizePlugin(parent, "smoothMesh", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("smoothMesh", e.what());
return 0;
}
}
static const Pb::Register _RP_smoothMesh("", "smoothMesh", _W_0);
extern "C" {
void PbRegister_smoothMesh()
{
KEEP_UNUSED(_RP_smoothMesh);
}
}
//! Subdivide and edgecollapse to guarantee mesh with edgelengths between
//! min/maxLength and an angle below minAngle
void subdivideMesh(
Mesh &mesh, Real minAngle, Real minLength, Real maxLength, bool cutTubes = false)
{
// gather some statistics
int edgeSubdivs = 0, edgeCollsAngle = 0, edgeCollsLen = 0, edgeKill = 0;
mesh.rebuildQuickCheck();
vector<int> deletedNodes;
map<int, bool> taintedTris;
priority_queue<pair<Real, int>> pq;
//////////////////////////////////////////
// EDGE COLLAPSE //
// - particles marked for deletation //
//////////////////////////////////////////
for (int t = 0; t < mesh.numTris(); t++) {
if (taintedTris.find(t) != taintedTris.end())
continue;
// check if at least 2 nodes are marked for delete
bool k[3];
int numKill = 0;
for (int i = 0; i < 3; i++) {
k[i] = mesh.nodes(mesh.tris(t).c[i]).flags & Mesh::NfKillme;
if (k[i])
numKill++;
}
if (numKill < 2)
continue;
if (k[0] && k[1])
CollapseEdge(mesh,
t,
2,
mesh.getEdge(t, 0),
mesh.getNode(t, 0),
deletedNodes,
taintedTris,
edgeKill,
cutTubes);
else if (k[1] && k[2])
CollapseEdge(mesh,
t,
0,
mesh.getEdge(t, 1),
mesh.getNode(t, 1),
deletedNodes,
taintedTris,
edgeKill,
cutTubes);
else if (k[2] && k[0])
CollapseEdge(mesh,
t,
1,
mesh.getEdge(t, 2),
mesh.getNode(t, 2),
deletedNodes,
taintedTris,
edgeKill,
cutTubes);
}
//////////////////////////////////////////
// EDGE COLLAPSING //
// - based on small triangle angle //
//////////////////////////////////////////
if (minAngle > 0) {
for (int t = 0; t < mesh.numTris(); t++) {
// we only want to run through the edge list ONCE.
// we achieve this in a method very similar to the above subdivision method.
// if this triangle has already been deleted, ignore it
if (taintedTris.find(t) != taintedTris.end())
continue;
// first we find the angles of this triangle
Vec3 e0 = mesh.getEdge(t, 0), e1 = mesh.getEdge(t, 1), e2 = mesh.getEdge(t, 2);
Vec3 ne0 = e0;
Vec3 ne1 = e1;
Vec3 ne2 = e2;
normalize(ne0);
normalize(ne1);
normalize(ne2);
// Real thisArea = sqrMag(cross(-e2,e0));
// small angle approximation says sin(x) = arcsin(x) = x,
// arccos(x) = pi/2 - arcsin(x),
// cos(x) = dot(A,B),
// so angle is approximately 1 - dot(A,B).
Real angle[3];
angle[0] = 1.0 - dot(ne0, -ne2);
angle[1] = 1.0 - dot(ne1, -ne0);
angle[2] = 1.0 - dot(ne2, -ne1);
Real worstAngle = angle[0];
int which = 0;
if (angle[1] < worstAngle) {
worstAngle = angle[1];
which = 1;
}
if (angle[2] < worstAngle) {
worstAngle = angle[2];
which = 2;
}
// then we see if the angle is too small
if (worstAngle < minAngle) {
Vec3 edgevect;
Vec3 endpoint;
switch (which) {
case 0:
endpoint = mesh.getNode(t, 1);
edgevect = e1;
break;
case 1:
endpoint = mesh.getNode(t, 2);
edgevect = e2;
break;
case 2:
endpoint = mesh.getNode(t, 0);
edgevect = e0;
break;
default:
break;
}
CollapseEdge(mesh,
t,
which,
edgevect,
endpoint,
deletedNodes,
taintedTris,
edgeCollsAngle,
cutTubes);
}
}
}
//////////////////////
// EDGE SUBDIVISION //
//////////////////////
Real maxLength2 = maxLength * maxLength;
for (int t = 0; t < mesh.numTris(); t++) {
// first we find the maximum length edge in this triangle
Vec3 e0 = mesh.getEdge(t, 0), e1 = mesh.getEdge(t, 1), e2 = mesh.getEdge(t, 2);
Real d0 = normSquare(e0);
Real d1 = normSquare(e1);
Real d2 = normSquare(e2);
Real longest = max(d0, max(d1, d2));
if (longest > maxLength2) {
pq.push(pair<Real, int>(longest, t));
}
}
if (maxLength > 0) {
while (!pq.empty() && pq.top().first > maxLength2) {
// we only want to run through the edge list ONCE
// and we want to subdivide the original edges before we subdivide any newer, shorter edges,
// so whenever we subdivide, we add the 2 new triangles on the end of the SurfaceTri vector
// and mark the original subdivided triangles for deletion.
// when we are done subdividing, we delete the obsolete triangles
int triA = pq.top().second;
pq.pop();
if (taintedTris.find(triA) != taintedTris.end())
continue;
// first we find the maximum length edge in this triangle
Vec3 e0 = mesh.getEdge(triA, 0), e1 = mesh.getEdge(triA, 1), e2 = mesh.getEdge(triA, 2);
Real d0 = normSquare(e0);
Real d1 = normSquare(e1);
Real d2 = normSquare(e2);
Vec3 edgevect;
Vec3 endpoint;
int which;
if (d0 > d1) {
if (d0 > d2) {
edgevect = e0;
endpoint = mesh.getNode(triA, 0);
;
which = 2; // 2 opposite of edge 0-1
}
else {
edgevect = e2;
endpoint = mesh.getNode(triA, 2);
which = 1; // 1 opposite of edge 2-0
}
}
else {
if (d1 > d2) {
edgevect = e1;
endpoint = mesh.getNode(triA, 1);
which = 0; // 0 opposite of edge 1-2
}
else {
edgevect = e2;
endpoint = mesh.getNode(triA, 2);
which = 1; // 1 opposite of edge 2-0
}
}
// This edge is too long, so we split it in the middle
// *
// / \.
// /C0 \.
// / \.
// / \.
// / B \.
// / \.
// /C1 C2 \.
// *---------------*
// \C2 C1 /
// \ /
// \ A /
// \ /
// \ /
// \C0 /
// \ /
// *
//
// BECOMES
//
// *
// /|\.
// / | \.
// /C0|C0\.
// / | \.
// / B1 | B2 \.
// / | \.
// /C1 C2|C1 C2 \.
// *-------*-------*
// \C2 C1|C2 C1/
// \ | /
// \ A2 | A1 /
// \ | /
// \C0|C0/
// \ | /
// \|/
// *
int triB = -1;
bool haveB = false;
Corner ca_old[3], cb_old[3];
ca_old[0] = mesh.corners(triA, which);
ca_old[1] = mesh.corners(ca_old[0].next);
ca_old[2] = mesh.corners(ca_old[0].prev);
if (ca_old[0].opposite >= 0) {
cb_old[0] = mesh.corners(ca_old[0].opposite);
cb_old[1] = mesh.corners(cb_old[0].next);
cb_old[2] = mesh.corners(cb_old[0].prev);
triB = cb_old[0].tri;
haveB = true;
}
// else throw Error("nonmanifold");
// subdivide in the middle of the edge and create new triangles
Node newNode;
newNode.flags = 0;
newNode.pos = endpoint + 0.5 * edgevect; // fallback: linear average
// default: use butterfly
if (haveB)
newNode.pos = ModifiedButterflySubdivision(mesh, ca_old[0], cb_old[0], newNode.pos);
// find indices of two points of 'which'-edge
// merge flags
int P0 = ca_old[1].node;
int P1 = ca_old[2].node;
newNode.flags = mesh.nodes(P0).flags | mesh.nodes(P1).flags;
Real len0 = norm(mesh.nodes(P0).pos - newNode.pos);
Real len1 = norm(mesh.nodes(P1).pos - newNode.pos);
// remove P0/P1 1-ring connection
mesh.get1Ring(P0).nodes.erase(P1);
mesh.get1Ring(P1).nodes.erase(P0);
mesh.get1Ring(P0).tris.erase(triA);
mesh.get1Ring(P1).tris.erase(triA);
mesh.get1Ring(ca_old[0].node).tris.erase(triA);
if (haveB) {
mesh.get1Ring(P0).tris.erase(triB);
mesh.get1Ring(P1).tris.erase(triB);
mesh.get1Ring(cb_old[0].node).tris.erase(triB);
}
// init channel properties for new node
for (int i = 0; i < mesh.numNodeChannels(); i++) {
mesh.nodeChannel(i)->addInterpol(P0, P1, len0 / (len0 + len1));
}
// write to array
mesh.addTri(Triangle(ca_old[0].node, ca_old[1].node, mesh.numNodes()));
mesh.addTri(Triangle(ca_old[0].node, mesh.numNodes(), ca_old[2].node));
if (haveB) {
mesh.addTri(Triangle(cb_old[0].node, cb_old[1].node, mesh.numNodes()));
mesh.addTri(Triangle(cb_old[0].node, mesh.numNodes(), cb_old[2].node));
}
mesh.addNode(newNode);
const int nt = haveB ? 4 : 2;
int triA1 = mesh.numTris() - nt;
int triA2 = mesh.numTris() - nt + 1;
int triB1 = 0, triB2 = 0;
if (haveB) {
triB1 = mesh.numTris() - nt + 2;
triB2 = mesh.numTris() - nt + 3;
}
mesh.tris(triA1).flags = mesh.tris(triA).flags;
mesh.tris(triA2).flags = mesh.tris(triA).flags;
mesh.tris(triB1).flags = mesh.tris(triB).flags;
mesh.tris(triB2).flags = mesh.tris(triB).flags;
// connect new triangles to outside triangles,
// and connect outside triangles to these new ones
for (int c = 0; c < 3; c++)
mesh.addCorner(Corner(triA1, mesh.tris(triA1).c[c]));
for (int c = 0; c < 3; c++)
mesh.addCorner(Corner(triA2, mesh.tris(triA2).c[c]));
if (haveB) {
for (int c = 0; c < 3; c++)
mesh.addCorner(Corner(triB1, mesh.tris(triB1).c[c]));
for (int c = 0; c < 3; c++)
mesh.addCorner(Corner(triB2, mesh.tris(triB2).c[c]));
}
int baseIdx = 3 * (mesh.numTris() - nt);
Corner *cBase = &mesh.corners(baseIdx);
// set next/prev
for (int t = 0; t < nt; t++)
for (int c = 0; c < 3; c++) {
cBase[t * 3 + c].next = baseIdx + t * 3 + ((c + 1) % 3);
cBase[t * 3 + c].prev = baseIdx + t * 3 + ((c + 2) % 3);
}
// set opposites
// A1
cBase[0].opposite = haveB ? (baseIdx + 9) : -1;
cBase[1].opposite = baseIdx + 5;
cBase[2].opposite = -1;
if (ca_old[2].opposite >= 0) {
cBase[2].opposite = ca_old[2].opposite;
mesh.corners(cBase[2].opposite).opposite = baseIdx + 2;
}
// A2
cBase[3].opposite = haveB ? (baseIdx + 6) : -1;
cBase[4].opposite = -1;
if (ca_old[1].opposite >= 0) {
cBase[4].opposite = ca_old[1].opposite;
mesh.corners(cBase[4].opposite).opposite = baseIdx + 4;
}
cBase[5].opposite = baseIdx + 1;
if (haveB) {
// B1
cBase[6].opposite = baseIdx + 3;
cBase[7].opposite = baseIdx + 11;
cBase[8].opposite = -1;
if (cb_old[2].opposite >= 0) {
cBase[8].opposite = cb_old[2].opposite;
mesh.corners(cBase[8].opposite).opposite = baseIdx + 8;
}
// B2
cBase[9].opposite = baseIdx + 0;
cBase[10].opposite = -1;
if (cb_old[1].opposite >= 0) {
cBase[10].opposite = cb_old[1].opposite;
mesh.corners(cBase[10].opposite).opposite = baseIdx + 10;
}
cBase[11].opposite = baseIdx + 7;
}
////////////////////
// mark the two original triangles for deletion
taintedTris[triA] = true;
mesh.removeTriFromLookup(triA);
if (haveB) {
taintedTris[triB] = true;
mesh.removeTriFromLookup(triB);
}
Real areaA1 = mesh.getFaceArea(triA1), areaA2 = mesh.getFaceArea(triA2);
Real areaB1 = 0, areaB2 = 0;
if (haveB) {
areaB1 = mesh.getFaceArea(triB1);
areaB2 = mesh.getFaceArea(triB2);
}
// add channel props for new triangles
for (int i = 0; i < mesh.numTriChannels(); i++) {
mesh.triChannel(i)->addSplit(triA, areaA1 / (areaA1 + areaA2));
mesh.triChannel(i)->addSplit(triA, areaA2 / (areaA1 + areaA2));
if (haveB) {
mesh.triChannel(i)->addSplit(triB, areaB1 / (areaB1 + areaB2));
mesh.triChannel(i)->addSplit(triB, areaB2 / (areaB1 + areaB2));
}
}
// add the four new triangles to the prority queue
for (int i = mesh.numTris() - nt; i < mesh.numTris(); i++) {
// find the maximum length edge in this triangle
Vec3 ne0 = mesh.getEdge(i, 0), ne1 = mesh.getEdge(i, 1), ne2 = mesh.getEdge(i, 2);
Real nd0 = normSquare(ne0);
Real nd1 = normSquare(ne1);
Real nd2 = normSquare(ne2);
Real longest = max(nd0, max(nd1, nd2));
// longest = (int)(longest * 1e2) / 1e2; // HACK: truncate
pq.push(pair<Real, int>(longest, i));
}
edgeSubdivs++;
}
}
//////////////////////////////////////////
// EDGE COLLAPSING //
// - based on short edge length //
//////////////////////////////////////////
if (minLength > 0) {
const Real minLength2 = minLength * minLength;
for (int t = 0; t < mesh.numTris(); t++) {
// we only want to run through the edge list ONCE.
// we achieve this in a method very similar to the above subdivision method.
// NOTE:
// priority queue does not work so great in the edge collapse case,
// because collapsing one triangle affects the edge lengths
// of many neighbor triangles,
// and we do not update their maximum edge length in the queue.
// if this triangle has already been deleted, ignore it
// if(taintedTris[t])
// continue;
if (taintedTris.find(t) != taintedTris.end())
continue;
// first we find the minimum length edge in this triangle
Vec3 e0 = mesh.getEdge(t, 0), e1 = mesh.getEdge(t, 1), e2 = mesh.getEdge(t, 2);
Real d0 = normSquare(e0);
Real d1 = normSquare(e1);
Real d2 = normSquare(e2);
Vec3 edgevect;
Vec3 endpoint;
Real dist2;
int which;
if (d0 < d1) {
if (d0 < d2) {
dist2 = d0;
edgevect = e0;
endpoint = mesh.getNode(t, 0);
which = 2; // 2 opposite of edge 0-1
}
else {
dist2 = d2;
edgevect = e2;
endpoint = mesh.getNode(t, 2);
which = 1; // 1 opposite of edge 2-0
}
}
else {
if (d1 < d2) {
dist2 = d1;
edgevect = e1;
endpoint = mesh.getNode(t, 1);
which = 0; // 0 opposite of edge 1-2
}
else {
dist2 = d2;
edgevect = e2;
endpoint = mesh.getNode(t, 2);
which = 1; // 1 opposite of edge 2-0
}
}
// then we see if the min length edge is too short
if (dist2 < minLength2) {
CollapseEdge(
mesh, t, which, edgevect, endpoint, deletedNodes, taintedTris, edgeCollsLen, cutTubes);
}
}
}
// cleanup nodes and triangles marked for deletion
// we run backwards through the deleted array,
// replacing triangles with ones from the back
// (this avoids the potential problem of overwriting a triangle
// with a to-be-deleted triangle)
std::map<int, bool>::reverse_iterator tti = taintedTris.rbegin();
for (; tti != taintedTris.rend(); tti++)
mesh.removeTri(tti->first);
mesh.removeNodes(deletedNodes);
cout << "Surface subdivision finished with " << mesh.numNodes() << " surface nodes and "
<< mesh.numTris();
cout << " surface triangles, edgeSubdivs:" << edgeSubdivs << ", edgeCollapses: " << edgeCollsLen;
cout << " + " << edgeCollsAngle << " + " << edgeKill << endl;
// mesh.sanityCheck();
}
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, "subdivideMesh", !noTiming);
PyObject *_retval = nullptr;
{
ArgLocker _lock;
Mesh &mesh = *_args.getPtr<Mesh>("mesh", 0, &_lock);
Real minAngle = _args.get<Real>("minAngle", 1, &_lock);
Real minLength = _args.get<Real>("minLength", 2, &_lock);
Real maxLength = _args.get<Real>("maxLength", 3, &_lock);
bool cutTubes = _args.getOpt<bool>("cutTubes", 4, false, &_lock);
_retval = getPyNone();
subdivideMesh(mesh, minAngle, minLength, maxLength, cutTubes);
_args.check();
}
pbFinalizePlugin(parent, "subdivideMesh", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("subdivideMesh", e.what());
return 0;
}
}
static const Pb::Register _RP_subdivideMesh("", "subdivideMesh", _W_1);
extern "C" {
void PbRegister_subdivideMesh()
{
KEEP_UNUSED(_RP_subdivideMesh);
}
}
void killSmallComponents(Mesh &mesh, int elements = 10)
{
const int num = mesh.numTris();
vector<int> comp(num);
vector<int> numEl;
vector<int> deletedNodes;
vector<bool> isNodeDel(mesh.numNodes());
map<int, bool> taintedTris;
// enumerate components
int cur = 0;
for (int i = 0; i < num; i++) {
if (comp[i] == 0) {
cur++;
comp[i] = cur;
stack<int> stack;
stack.push(i);
int cnt = 1;
while (!stack.empty()) {
int tri = stack.top();
stack.pop();
for (int c = 0; c < 3; c++) {
int op = mesh.corners(tri, c).opposite;
if (op < 0)
continue;
int ntri = mesh.corners(op).tri;
if (comp[ntri] == 0) {
comp[ntri] = cur;
stack.push(ntri);
cnt++;
}
}
}
numEl.push_back(cnt);
}
}
// kill small components
for (int j = 0; j < num; j++) {
if (numEl[comp[j] - 1] < elements) {
taintedTris[j] = true;
for (int c = 0; c < 3; c++) {
int n = mesh.tris(j).c[c];
if (!isNodeDel[n]) {
isNodeDel[n] = true;
deletedNodes.push_back(n);
}
}
}
}
std::map<int, bool>::reverse_iterator tti = taintedTris.rbegin();
for (; tti != taintedTris.rend(); tti++)
mesh.removeTri(tti->first);
mesh.removeNodes(deletedNodes);
if (!taintedTris.empty())
cout << "Killed small components : " << deletedNodes.size() << " nodes, " << taintedTris.size()
<< " tris deleted." << endl;
}
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, "killSmallComponents", !noTiming);
PyObject *_retval = nullptr;
{
ArgLocker _lock;
Mesh &mesh = *_args.getPtr<Mesh>("mesh", 0, &_lock);
int elements = _args.getOpt<int>("elements", 1, 10, &_lock);
_retval = getPyNone();
killSmallComponents(mesh, elements);
_args.check();
}
pbFinalizePlugin(parent, "killSmallComponents", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("killSmallComponents", e.what());
return 0;
}
}
static const Pb::Register _RP_killSmallComponents("", "killSmallComponents", _W_2);
extern "C" {
void PbRegister_killSmallComponents()
{
KEEP_UNUSED(_RP_killSmallComponents);
}
}
} // namespace Manta

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,502 @@
// DO NOT EDIT !
// This file is generated using the MantaFlow preprocessor (prep generate).
// ----------------------------------------------------------------------------
//
// MantaFlow fluid solver framework
// Copyright 2018 Kiwon Um, Nils Thuerey
//
// This program is free software, distributed under the terms of the
// GNU General Public License (GPL)
// http://www.gnu.org/licenses
//
// Particle system helper
//
// ----------------------------------------------------------------------------
#include "particle.h"
namespace Manta {
struct KnAddForcePvel : public KernelBase {
KnAddForcePvel(ParticleDataImpl<Vec3> &v,
const Vec3 &da,
const ParticleDataImpl<int> *ptype,
const int exclude)
: KernelBase(v.size()), v(v), da(da), ptype(ptype), exclude(exclude)
{
runMessage();
run();
}
inline void op(IndexInt idx,
ParticleDataImpl<Vec3> &v,
const Vec3 &da,
const ParticleDataImpl<int> *ptype,
const int exclude) const
{
if (ptype && ((*ptype)[idx] & exclude))
return;
v[idx] += da;
}
inline ParticleDataImpl<Vec3> &getArg0()
{
return v;
}
typedef ParticleDataImpl<Vec3> type0;
inline const Vec3 &getArg1()
{
return da;
}
typedef Vec3 type1;
inline const ParticleDataImpl<int> *getArg2()
{
return ptype;
}
typedef ParticleDataImpl<int> type2;
inline const int &getArg3()
{
return exclude;
}
typedef int type3;
void runMessage()
{
debMsg("Executing kernel KnAddForcePvel ", 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, v, da, ptype, exclude);
}
void run()
{
tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
}
ParticleDataImpl<Vec3> &v;
const Vec3 &da;
const ParticleDataImpl<int> *ptype;
const int exclude;
};
//! add force to vec3 particle data; a: acceleration
void addForcePvel(ParticleDataImpl<Vec3> &vel,
const Vec3 &a,
const Real dt,
const ParticleDataImpl<int> *ptype,
const int exclude)
{
KnAddForcePvel(vel, a * dt, ptype, exclude);
}
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, "addForcePvel", !noTiming);
PyObject *_retval = nullptr;
{
ArgLocker _lock;
ParticleDataImpl<Vec3> &vel = *_args.getPtr<ParticleDataImpl<Vec3>>("vel", 0, &_lock);
const Vec3 &a = _args.get<Vec3>("a", 1, &_lock);
const Real dt = _args.get<Real>("dt", 2, &_lock);
const ParticleDataImpl<int> *ptype = _args.getPtr<ParticleDataImpl<int>>("ptype", 3, &_lock);
const int exclude = _args.get<int>("exclude", 4, &_lock);
_retval = getPyNone();
addForcePvel(vel, a, dt, ptype, exclude);
_args.check();
}
pbFinalizePlugin(parent, "addForcePvel", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("addForcePvel", e.what());
return 0;
}
}
static const Pb::Register _RP_addForcePvel("", "addForcePvel", _W_0);
extern "C" {
void PbRegister_addForcePvel()
{
KEEP_UNUSED(_RP_addForcePvel);
}
}
struct KnUpdateVelocityFromDeltaPos : public KernelBase {
KnUpdateVelocityFromDeltaPos(const BasicParticleSystem &p,
ParticleDataImpl<Vec3> &v,
const ParticleDataImpl<Vec3> &x_prev,
const Real over_dt,
const ParticleDataImpl<int> *ptype,
const int exclude)
: KernelBase(p.size()),
p(p),
v(v),
x_prev(x_prev),
over_dt(over_dt),
ptype(ptype),
exclude(exclude)
{
runMessage();
run();
}
inline void op(IndexInt idx,
const BasicParticleSystem &p,
ParticleDataImpl<Vec3> &v,
const ParticleDataImpl<Vec3> &x_prev,
const Real over_dt,
const ParticleDataImpl<int> *ptype,
const int exclude) const
{
if (ptype && ((*ptype)[idx] & exclude))
return;
v[idx] = (p[idx].pos - x_prev[idx]) * over_dt;
}
inline const BasicParticleSystem &getArg0()
{
return p;
}
typedef BasicParticleSystem type0;
inline ParticleDataImpl<Vec3> &getArg1()
{
return v;
}
typedef ParticleDataImpl<Vec3> type1;
inline const ParticleDataImpl<Vec3> &getArg2()
{
return x_prev;
}
typedef ParticleDataImpl<Vec3> type2;
inline const Real &getArg3()
{
return over_dt;
}
typedef Real 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 KnUpdateVelocityFromDeltaPos ", 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, v, x_prev, over_dt, ptype, exclude);
}
void run()
{
tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
}
const BasicParticleSystem &p;
ParticleDataImpl<Vec3> &v;
const ParticleDataImpl<Vec3> &x_prev;
const Real over_dt;
const ParticleDataImpl<int> *ptype;
const int exclude;
};
//! retrieve velocity from position change
void updateVelocityFromDeltaPos(const BasicParticleSystem &parts,
ParticleDataImpl<Vec3> &vel,
const ParticleDataImpl<Vec3> &x_prev,
const Real dt,
const ParticleDataImpl<int> *ptype,
const int exclude)
{
KnUpdateVelocityFromDeltaPos(parts, vel, x_prev, 1.0 / dt, ptype, exclude);
}
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, "updateVelocityFromDeltaPos", !noTiming);
PyObject *_retval = nullptr;
{
ArgLocker _lock;
const BasicParticleSystem &parts = *_args.getPtr<BasicParticleSystem>("parts", 0, &_lock);
ParticleDataImpl<Vec3> &vel = *_args.getPtr<ParticleDataImpl<Vec3>>("vel", 1, &_lock);
const ParticleDataImpl<Vec3> &x_prev = *_args.getPtr<ParticleDataImpl<Vec3>>(
"x_prev", 2, &_lock);
const Real dt = _args.get<Real>("dt", 3, &_lock);
const ParticleDataImpl<int> *ptype = _args.getPtr<ParticleDataImpl<int>>("ptype", 4, &_lock);
const int exclude = _args.get<int>("exclude", 5, &_lock);
_retval = getPyNone();
updateVelocityFromDeltaPos(parts, vel, x_prev, dt, ptype, exclude);
_args.check();
}
pbFinalizePlugin(parent, "updateVelocityFromDeltaPos", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("updateVelocityFromDeltaPos", e.what());
return 0;
}
}
static const Pb::Register _RP_updateVelocityFromDeltaPos("", "updateVelocityFromDeltaPos", _W_1);
extern "C" {
void PbRegister_updateVelocityFromDeltaPos()
{
KEEP_UNUSED(_RP_updateVelocityFromDeltaPos);
}
}
struct KnStepEuler : public KernelBase {
KnStepEuler(BasicParticleSystem &p,
const ParticleDataImpl<Vec3> &v,
const Real dt,
const ParticleDataImpl<int> *ptype,
const int exclude)
: KernelBase(p.size()), p(p), v(v), dt(dt), ptype(ptype), exclude(exclude)
{
runMessage();
run();
}
inline void op(IndexInt idx,
BasicParticleSystem &p,
const ParticleDataImpl<Vec3> &v,
const Real dt,
const ParticleDataImpl<int> *ptype,
const int exclude) const
{
if (ptype && ((*ptype)[idx] & exclude))
return;
p[idx].pos += v[idx] * dt;
}
inline BasicParticleSystem &getArg0()
{
return p;
}
typedef BasicParticleSystem type0;
inline const ParticleDataImpl<Vec3> &getArg1()
{
return v;
}
typedef ParticleDataImpl<Vec3> type1;
inline const Real &getArg2()
{
return dt;
}
typedef Real type2;
inline const ParticleDataImpl<int> *getArg3()
{
return ptype;
}
typedef ParticleDataImpl<int> type3;
inline const int &getArg4()
{
return exclude;
}
typedef int type4;
void runMessage()
{
debMsg("Executing kernel KnStepEuler ", 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, v, dt, ptype, exclude);
}
void run()
{
tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
}
BasicParticleSystem &p;
const ParticleDataImpl<Vec3> &v;
const Real dt;
const ParticleDataImpl<int> *ptype;
const int exclude;
};
//! simple foward Euler integration for particle system
void eulerStep(BasicParticleSystem &parts,
const ParticleDataImpl<Vec3> &vel,
const ParticleDataImpl<int> *ptype,
const int exclude)
{
KnStepEuler(parts, vel, parts.getParent()->getDt(), ptype, exclude);
}
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, "eulerStep", !noTiming);
PyObject *_retval = nullptr;
{
ArgLocker _lock;
BasicParticleSystem &parts = *_args.getPtr<BasicParticleSystem>("parts", 0, &_lock);
const ParticleDataImpl<Vec3> &vel = *_args.getPtr<ParticleDataImpl<Vec3>>("vel", 1, &_lock);
const ParticleDataImpl<int> *ptype = _args.getPtr<ParticleDataImpl<int>>("ptype", 2, &_lock);
const int exclude = _args.get<int>("exclude", 3, &_lock);
_retval = getPyNone();
eulerStep(parts, vel, ptype, exclude);
_args.check();
}
pbFinalizePlugin(parent, "eulerStep", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("eulerStep", e.what());
return 0;
}
}
static const Pb::Register _RP_eulerStep("", "eulerStep", _W_2);
extern "C" {
void PbRegister_eulerStep()
{
KEEP_UNUSED(_RP_eulerStep);
}
}
struct KnSetPartType : public KernelBase {
KnSetPartType(ParticleDataImpl<int> &ptype,
const BasicParticleSystem &part,
const int mark,
const int stype,
const FlagGrid &flags,
const int cflag)
: KernelBase(ptype.size()),
ptype(ptype),
part(part),
mark(mark),
stype(stype),
flags(flags),
cflag(cflag)
{
runMessage();
run();
}
inline void op(IndexInt idx,
ParticleDataImpl<int> &ptype,
const BasicParticleSystem &part,
const int mark,
const int stype,
const FlagGrid &flags,
const int cflag) const
{
if (flags.isInBounds(part.getPos(idx), 0) && (flags.getAt(part.getPos(idx)) & cflag) &&
(ptype[idx] & stype))
ptype[idx] = mark;
}
inline ParticleDataImpl<int> &getArg0()
{
return ptype;
}
typedef ParticleDataImpl<int> type0;
inline const BasicParticleSystem &getArg1()
{
return part;
}
typedef BasicParticleSystem type1;
inline const int &getArg2()
{
return mark;
}
typedef int type2;
inline const int &getArg3()
{
return stype;
}
typedef int type3;
inline const FlagGrid &getArg4()
{
return flags;
}
typedef FlagGrid type4;
inline const int &getArg5()
{
return cflag;
}
typedef int type5;
void runMessage()
{
debMsg("Executing kernel KnSetPartType ", 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, ptype, part, mark, stype, flags, cflag);
}
void run()
{
tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
}
ParticleDataImpl<int> &ptype;
const BasicParticleSystem &part;
const int mark;
const int stype;
const FlagGrid &flags;
const int cflag;
};
//! if particle is stype and in cflag cell, set ptype as mark
void setPartType(const BasicParticleSystem &parts,
ParticleDataImpl<int> &ptype,
const int mark,
const int stype,
const FlagGrid &flags,
const int cflag)
{
KnSetPartType(ptype, parts, mark, stype, flags, cflag);
}
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, "setPartType", !noTiming);
PyObject *_retval = nullptr;
{
ArgLocker _lock;
const BasicParticleSystem &parts = *_args.getPtr<BasicParticleSystem>("parts", 0, &_lock);
ParticleDataImpl<int> &ptype = *_args.getPtr<ParticleDataImpl<int>>("ptype", 1, &_lock);
const int mark = _args.get<int>("mark", 2, &_lock);
const int stype = _args.get<int>("stype", 3, &_lock);
const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 4, &_lock);
const int cflag = _args.get<int>("cflag", 5, &_lock);
_retval = getPyNone();
setPartType(parts, ptype, mark, stype, flags, cflag);
_args.check();
}
pbFinalizePlugin(parent, "setPartType", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("setPartType", e.what());
return 0;
}
}
static const Pb::Register _RP_setPartType("", "setPartType", _W_3);
extern "C" {
void PbRegister_setPartType()
{
KEEP_UNUSED(_RP_setPartType);
}
}
} // namespace Manta

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,697 @@
// 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
*
* Plugins for using vortex sheet meshes
*
******************************************************************************/
#include <iostream>
#include "vortexsheet.h"
#include "vortexpart.h"
#include "shapes.h"
#include "commonkernels.h"
#include "conjugategrad.h"
#include "randomstream.h"
#include "levelset.h"
using namespace std;
namespace Manta {
//! Mark area of mesh inside shape as fixed nodes.
//! Remove all other fixed nodes if 'exclusive' is set
void markAsFixed(Mesh &mesh, const Shape *shape, bool exclusive = true)
{
for (int i = 0; i < mesh.numNodes(); i++) {
if (shape->isInside(mesh.nodes(i).pos))
mesh.nodes(i).flags |= Mesh::NfFixed;
else if (exclusive)
mesh.nodes(i).flags &= ~Mesh::NfFixed;
}
}
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, "markAsFixed", !noTiming);
PyObject *_retval = nullptr;
{
ArgLocker _lock;
Mesh &mesh = *_args.getPtr<Mesh>("mesh", 0, &_lock);
const Shape *shape = _args.getPtr<Shape>("shape", 1, &_lock);
bool exclusive = _args.getOpt<bool>("exclusive", 2, true, &_lock);
_retval = getPyNone();
markAsFixed(mesh, shape, exclusive);
_args.check();
}
pbFinalizePlugin(parent, "markAsFixed", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("markAsFixed", e.what());
return 0;
}
}
static const Pb::Register _RP_markAsFixed("", "markAsFixed", _W_0);
extern "C" {
void PbRegister_markAsFixed()
{
KEEP_UNUSED(_RP_markAsFixed);
}
}
//! Adapt texture coordinates of mesh inside shape
//! to obtain an effective inflow effect
void texcoordInflow(VortexSheetMesh &mesh, const Shape *shape, const MACGrid &vel)
{
static Vec3 t0 = Vec3::Zero;
// get mean velocity
int cnt = 0;
Vec3 meanV(0.0);
FOR_IJK(vel)
{
if (shape->isInsideGrid(i, j, k)) {
cnt++;
meanV += vel.getCentered(i, j, k);
}
}
meanV /= (Real)cnt;
t0 -= mesh.getParent()->getDt() * meanV;
mesh.setReferenceTexOffset(t0);
// apply mean velocity
for (int i = 0; i < mesh.numNodes(); i++) {
if (shape->isInside(mesh.nodes(i).pos)) {
Vec3 tc = mesh.nodes(i).pos + t0;
mesh.tex1(i) = tc;
mesh.tex2(i) = tc;
}
}
}
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, "texcoordInflow", !noTiming);
PyObject *_retval = nullptr;
{
ArgLocker _lock;
VortexSheetMesh &mesh = *_args.getPtr<VortexSheetMesh>("mesh", 0, &_lock);
const Shape *shape = _args.getPtr<Shape>("shape", 1, &_lock);
const MACGrid &vel = *_args.getPtr<MACGrid>("vel", 2, &_lock);
_retval = getPyNone();
texcoordInflow(mesh, shape, vel);
_args.check();
}
pbFinalizePlugin(parent, "texcoordInflow", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("texcoordInflow", e.what());
return 0;
}
}
static const Pb::Register _RP_texcoordInflow("", "texcoordInflow", _W_1);
extern "C" {
void PbRegister_texcoordInflow()
{
KEEP_UNUSED(_RP_texcoordInflow);
}
}
;
//! Init smoke density values of the mesh surface inside source shape
void meshSmokeInflow(VortexSheetMesh &mesh, const Shape *shape, Real amount)
{
for (int t = 0; t < mesh.numTris(); t++) {
if (shape->isInside(mesh.getFaceCenter(t)))
mesh.sheet(t).smokeAmount = amount;
}
}
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, "meshSmokeInflow", !noTiming);
PyObject *_retval = nullptr;
{
ArgLocker _lock;
VortexSheetMesh &mesh = *_args.getPtr<VortexSheetMesh>("mesh", 0, &_lock);
const Shape *shape = _args.getPtr<Shape>("shape", 1, &_lock);
Real amount = _args.get<Real>("amount", 2, &_lock);
_retval = getPyNone();
meshSmokeInflow(mesh, shape, amount);
_args.check();
}
pbFinalizePlugin(parent, "meshSmokeInflow", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("meshSmokeInflow", e.what());
return 0;
}
}
static const Pb::Register _RP_meshSmokeInflow("", "meshSmokeInflow", _W_2);
extern "C" {
void PbRegister_meshSmokeInflow()
{
KEEP_UNUSED(_RP_meshSmokeInflow);
}
}
struct KnAcceleration : public KernelBase {
KnAcceleration(MACGrid &a, const MACGrid &v1, const MACGrid &v0, const Real idt)
: KernelBase(&a, 0), a(a), v1(v1), v0(v0), idt(idt)
{
runMessage();
run();
}
inline void op(
IndexInt idx, MACGrid &a, const MACGrid &v1, const MACGrid &v0, const Real idt) const
{
a[idx] = (v1[idx] - v0[idx]) * idt;
}
inline MACGrid &getArg0()
{
return a;
}
typedef MACGrid type0;
inline const MACGrid &getArg1()
{
return v1;
}
typedef MACGrid type1;
inline const MACGrid &getArg2()
{
return v0;
}
typedef MACGrid type2;
inline const Real &getArg3()
{
return idt;
}
typedef Real type3;
void runMessage()
{
debMsg("Executing kernel KnAcceleration ", 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, a, v1, v0, idt);
}
void run()
{
tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
}
MACGrid &a;
const MACGrid &v1;
const MACGrid &v0;
const Real idt;
};
//! Add vorticity to vortex sheets based on buoyancy
void vorticitySource(VortexSheetMesh &mesh,
Vec3 gravity,
const MACGrid *vel = nullptr,
const MACGrid *velOld = nullptr,
Real scale = 0.1,
Real maxAmount = 0,
Real mult = 1.0)
{
Real dt = mesh.getParent()->getDt();
Real dx = mesh.getParent()->getDx();
MACGrid acceleration(mesh.getParent());
if (vel)
KnAcceleration(acceleration, *vel, *velOld, 1.0 / dt);
const Real A = -1.0;
Real maxV = 0, meanV = 0;
for (int t = 0; t < mesh.numTris(); t++) {
Vec3 fn = mesh.getFaceNormal(t);
Vec3 source;
if (vel) {
Vec3 a = acceleration.getInterpolated(mesh.getFaceCenter(t));
source = A * cross(fn, a - gravity) * scale;
}
else {
source = A * cross(fn, -gravity) * scale;
}
if (mesh.isTriangleFixed(t))
source = 0;
mesh.sheet(t).vorticity *= mult;
mesh.sheet(t).vorticity += dt * source / dx;
// upper limit
Real v = norm(mesh.sheet(t).vorticity);
if (maxAmount > 0 && v > maxAmount)
mesh.sheet(t).vorticity *= maxAmount / v;
// stats
if (v > maxV)
maxV = v;
meanV += v;
}
cout << "vorticity: max " << maxV << " / mean " << meanV / mesh.numTris() << endl;
}
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, "vorticitySource", !noTiming);
PyObject *_retval = nullptr;
{
ArgLocker _lock;
VortexSheetMesh &mesh = *_args.getPtr<VortexSheetMesh>("mesh", 0, &_lock);
Vec3 gravity = _args.get<Vec3>("gravity", 1, &_lock);
const MACGrid *vel = _args.getPtrOpt<MACGrid>("vel", 2, nullptr, &_lock);
const MACGrid *velOld = _args.getPtrOpt<MACGrid>("velOld", 3, nullptr, &_lock);
Real scale = _args.getOpt<Real>("scale", 4, 0.1, &_lock);
Real maxAmount = _args.getOpt<Real>("maxAmount", 5, 0, &_lock);
Real mult = _args.getOpt<Real>("mult", 6, 1.0, &_lock);
_retval = getPyNone();
vorticitySource(mesh, gravity, vel, velOld, scale, maxAmount, mult);
_args.check();
}
pbFinalizePlugin(parent, "vorticitySource", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("vorticitySource", e.what());
return 0;
}
}
static const Pb::Register _RP_vorticitySource("", "vorticitySource", _W_3);
extern "C" {
void PbRegister_vorticitySource()
{
KEEP_UNUSED(_RP_vorticitySource);
}
}
void smoothVorticity(VortexSheetMesh &mesh, int iter = 1, Real sigma = 0.2, Real alpha = 0.8)
{
const Real mult = -0.5 / sigma / sigma;
// pre-calculate positions and weights
vector<Vec3> vort(mesh.numTris()), pos(mesh.numTris());
vector<Real> weights(3 * mesh.numTris());
vector<int> index(3 * mesh.numTris());
for (int i = 0; i < mesh.numTris(); i++) {
pos[i] = mesh.getFaceCenter(i);
mesh.sheet(i).vorticitySmoothed = mesh.sheet(i).vorticity;
}
for (int i = 0; i < mesh.numTris(); i++) {
for (int c = 0; c < 3; c++) {
int oc = mesh.corners(i, c).opposite;
if (oc >= 0) {
int t = mesh.corners(oc).tri;
weights[3 * i + c] = exp(normSquare(pos[t] - pos[i]) * mult);
index[3 * i + c] = t;
}
else {
weights[3 * i + c] = 0;
index[3 * i + c] = 0;
}
}
}
for (int it = 0; it < iter; ++it) {
// first, preload
for (int i = 0; i < mesh.numTris(); i++)
vort[i] = mesh.sheet(i).vorticitySmoothed;
for (int i = 0, idx = 0; i < mesh.numTris(); i++) {
// loop over adjacent tris
Real sum = 1.0f;
Vec3 v = vort[i];
for (int c = 0; c < 3; c++, idx++) {
Real w = weights[index[idx]];
v += w * vort[index[idx]];
sum += w;
}
mesh.sheet(i).vorticitySmoothed = v / sum;
}
}
for (int i = 0; i < mesh.numTris(); i++)
mesh.sheet(i).vorticitySmoothed *= alpha;
}
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, "smoothVorticity", !noTiming);
PyObject *_retval = nullptr;
{
ArgLocker _lock;
VortexSheetMesh &mesh = *_args.getPtr<VortexSheetMesh>("mesh", 0, &_lock);
int iter = _args.getOpt<int>("iter", 1, 1, &_lock);
Real sigma = _args.getOpt<Real>("sigma", 2, 0.2, &_lock);
Real alpha = _args.getOpt<Real>("alpha", 3, 0.8, &_lock);
_retval = getPyNone();
smoothVorticity(mesh, iter, sigma, alpha);
_args.check();
}
pbFinalizePlugin(parent, "smoothVorticity", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("smoothVorticity", e.what());
return 0;
}
}
static const Pb::Register _RP_smoothVorticity("", "smoothVorticity", _W_4);
extern "C" {
void PbRegister_smoothVorticity()
{
KEEP_UNUSED(_RP_smoothVorticity);
}
}
//! Seed Vortex Particles inside shape with K41 characteristics
void VPseedK41(VortexParticleSystem &system,
const Shape *shape,
Real strength = 0,
Real sigma0 = 0.2,
Real sigma1 = 1.0,
Real probability = 1.0,
Real N = 3.0)
{
Grid<Real> temp(system.getParent());
const Real dt = system.getParent()->getDt();
static RandomStream rand(3489572);
Real s0 = pow((Real)sigma0, (Real)(-N + 1.0));
Real s1 = pow((Real)sigma1, (Real)(-N + 1.0));
FOR_IJK(temp)
{
if (shape->isInsideGrid(i, j, k)) {
if (rand.getReal() < probability * dt) {
Real p = rand.getReal();
Real sigma = pow((1.0 - p) * s0 + p * s1, 1. / (-N + 1.0));
Vec3 randDir(rand.getReal(), rand.getReal(), rand.getReal());
Vec3 posUpd(i + rand.getReal(), j + rand.getReal(), k + rand.getReal());
normalize(randDir);
Vec3 vorticity = randDir * strength * pow((Real)sigma, (Real)(-10. / 6. + N / 2.0));
system.add(VortexParticleData(posUpd, vorticity, sigma));
}
}
}
}
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, "VPseedK41", !noTiming);
PyObject *_retval = nullptr;
{
ArgLocker _lock;
VortexParticleSystem &system = *_args.getPtr<VortexParticleSystem>("system", 0, &_lock);
const Shape *shape = _args.getPtr<Shape>("shape", 1, &_lock);
Real strength = _args.getOpt<Real>("strength", 2, 0, &_lock);
Real sigma0 = _args.getOpt<Real>("sigma0", 3, 0.2, &_lock);
Real sigma1 = _args.getOpt<Real>("sigma1", 4, 1.0, &_lock);
Real probability = _args.getOpt<Real>("probability", 5, 1.0, &_lock);
Real N = _args.getOpt<Real>("N", 6, 3.0, &_lock);
_retval = getPyNone();
VPseedK41(system, shape, strength, sigma0, sigma1, probability, N);
_args.check();
}
pbFinalizePlugin(parent, "VPseedK41", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("VPseedK41", e.what());
return 0;
}
}
static const Pb::Register _RP_VPseedK41("", "VPseedK41", _W_5);
extern "C" {
void PbRegister_VPseedK41()
{
KEEP_UNUSED(_RP_VPseedK41);
}
}
//! Vortex-in-cell integration
void VICintegration(VortexSheetMesh &mesh,
Real sigma,
Grid<Vec3> &vel,
const FlagGrid &flags,
Grid<Vec3> *vorticity = nullptr,
Real cgMaxIterFac = 1.5,
Real cgAccuracy = 1e-3,
Real scale = 0.01,
int precondition = 0)
{
MuTime t0;
const Real fac = 16.0; // experimental factor to balance out regularization
// if no vort grid is given, use a temporary one
Grid<Vec3> vortTemp(mesh.getParent());
Grid<Vec3> &vort = (vorticity) ? (*vorticity) : (vortTemp);
vort.clear();
// map vorticity to grid using Peskin kernel
int sgi = ceil(sigma);
Real pkfac = M_PI / sigma;
const int numTris = mesh.numTris();
for (int t = 0; t < numTris; t++) {
Vec3 pos = mesh.getFaceCenter(t);
Vec3 v = mesh.sheet(t).vorticity * mesh.getFaceArea(t) * fac;
// inner kernel
// first, summate
Real sum = 0;
for (int i = -sgi; i < sgi; i++) {
if (pos.x + i < 0 || (int)pos.x + i >= vort.getSizeX())
continue;
for (int j = -sgi; j < sgi; j++) {
if (pos.y + j < 0 || (int)pos.y + j >= vort.getSizeY())
continue;
for (int k = -sgi; k < sgi; k++) {
if (pos.z + k < 0 || (int)pos.z + k >= vort.getSizeZ())
continue;
Vec3i cell(pos.x + i, pos.y + j, pos.z + k);
if (!flags.isFluid(cell))
continue;
Vec3 d = pos -
Vec3(i + 0.5 + floor(pos.x), j + 0.5 + floor(pos.y), k + 0.5 + floor(pos.z));
Real dl = norm(d);
if (dl > sigma)
continue;
// precalc Peskin kernel
sum += 1.0 + cos(dl * pkfac);
}
}
}
// then, apply normalized kernel
Real wnorm = 1.0 / sum;
for (int i = -sgi; i < sgi; i++) {
if (pos.x + i < 0 || (int)pos.x + i >= vort.getSizeX())
continue;
for (int j = -sgi; j < sgi; j++) {
if (pos.y + j < 0 || (int)pos.y + j >= vort.getSizeY())
continue;
for (int k = -sgi; k < sgi; k++) {
if (pos.z + k < 0 || (int)pos.z + k >= vort.getSizeZ())
continue;
Vec3i cell(pos.x + i, pos.y + j, pos.z + k);
if (!flags.isFluid(cell))
continue;
Vec3 d = pos -
Vec3(i + 0.5 + floor(pos.x), j + 0.5 + floor(pos.y), k + 0.5 + floor(pos.z));
Real dl = norm(d);
if (dl > sigma)
continue;
Real w = (1.0 + cos(dl * pkfac)) * wnorm;
vort(cell) += v * w;
}
}
}
}
// Prepare grids for poisson solve
Grid<Vec3> vortexCurl(mesh.getParent());
Grid<Real> rhs(mesh.getParent());
Grid<Real> solution(mesh.getParent());
Grid<Real> residual(mesh.getParent());
Grid<Real> search(mesh.getParent());
Grid<Real> temp1(mesh.getParent());
Grid<Real> A0(mesh.getParent());
Grid<Real> Ai(mesh.getParent());
Grid<Real> Aj(mesh.getParent());
Grid<Real> Ak(mesh.getParent());
Grid<Real> pca0(mesh.getParent());
Grid<Real> pca1(mesh.getParent());
Grid<Real> pca2(mesh.getParent());
Grid<Real> pca3(mesh.getParent());
MakeLaplaceMatrix(flags, A0, Ai, Aj, Ak);
CurlOp(vort, vortexCurl);
// Solve vector poisson equation
for (int c = 0; c < 3; c++) {
// construct rhs
if (vel.getType() & GridBase::TypeMAC)
GetShiftedComponent(vortexCurl, rhs, c);
else
GetComponent(vortexCurl, rhs, c);
// prepare CG solver
const int maxIter = (int)(cgMaxIterFac * vel.getSize().max());
vector<Grid<Real> *> matA{&A0, &Ai, &Aj, &Ak};
GridCgInterface *gcg = new GridCg<ApplyMatrix>(
solution, rhs, residual, search, flags, temp1, matA);
gcg->setAccuracy(cgAccuracy);
gcg->setUseL2Norm(true);
gcg->setICPreconditioner(
(GridCgInterface::PreconditionType)precondition, &pca0, &pca1, &pca2, &pca3);
// iterations
for (int iter = 0; iter < maxIter; iter++) {
if (!gcg->iterate())
iter = maxIter;
}
debMsg("VICintegration CG iterations:" << gcg->getIterations() << ", res:" << gcg->getSigma(),
1);
delete gcg;
// copy back
solution *= scale;
SetComponent(vel, solution, c);
}
}
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, "VICintegration", !noTiming);
PyObject *_retval = nullptr;
{
ArgLocker _lock;
VortexSheetMesh &mesh = *_args.getPtr<VortexSheetMesh>("mesh", 0, &_lock);
Real sigma = _args.get<Real>("sigma", 1, &_lock);
Grid<Vec3> &vel = *_args.getPtr<Grid<Vec3>>("vel", 2, &_lock);
const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 3, &_lock);
Grid<Vec3> *vorticity = _args.getPtrOpt<Grid<Vec3>>("vorticity", 4, nullptr, &_lock);
Real cgMaxIterFac = _args.getOpt<Real>("cgMaxIterFac", 5, 1.5, &_lock);
Real cgAccuracy = _args.getOpt<Real>("cgAccuracy", 6, 1e-3, &_lock);
Real scale = _args.getOpt<Real>("scale", 7, 0.01, &_lock);
int precondition = _args.getOpt<int>("precondition", 8, 0, &_lock);
_retval = getPyNone();
VICintegration(
mesh, sigma, vel, flags, vorticity, cgMaxIterFac, cgAccuracy, scale, precondition);
_args.check();
}
pbFinalizePlugin(parent, "VICintegration", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("VICintegration", e.what());
return 0;
}
}
static const Pb::Register _RP_VICintegration("", "VICintegration", _W_6);
extern "C" {
void PbRegister_VICintegration()
{
KEEP_UNUSED(_RP_VICintegration);
}
}
//! Obtain density field from levelset with linear gradient of size sigma over the interface
void densityFromLevelset(const LevelsetGrid &phi,
Grid<Real> &density,
Real value = 1.0,
Real sigma = 1.0)
{
FOR_IJK(phi)
{
// remove boundary
if (i < 2 || j < 2 || k < 2 || i >= phi.getSizeX() - 2 || j >= phi.getSizeY() - 2 ||
k >= phi.getSizeZ() - 2)
density(i, j, k) = 0;
else if (phi(i, j, k) < -sigma)
density(i, j, k) = value;
else if (phi(i, j, k) > sigma)
density(i, j, k) = 0;
else
density(i, j, k) = clamp(
(Real)(0.5 * value / sigma * (1.0 - phi(i, j, k))), (Real)0.0, value);
}
}
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, "densityFromLevelset", !noTiming);
PyObject *_retval = nullptr;
{
ArgLocker _lock;
const LevelsetGrid &phi = *_args.getPtr<LevelsetGrid>("phi", 0, &_lock);
Grid<Real> &density = *_args.getPtr<Grid<Real>>("density", 1, &_lock);
Real value = _args.getOpt<Real>("value", 2, 1.0, &_lock);
Real sigma = _args.getOpt<Real>("sigma", 3, 1.0, &_lock);
_retval = getPyNone();
densityFromLevelset(phi, density, value, sigma);
_args.check();
}
pbFinalizePlugin(parent, "densityFromLevelset", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("densityFromLevelset", e.what());
return 0;
}
}
static const Pb::Register _RP_densityFromLevelset("", "densityFromLevelset", _W_7);
extern "C" {
void PbRegister_densityFromLevelset()
{
KEEP_UNUSED(_RP_densityFromLevelset);
}
}
} // namespace Manta

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,488 @@
// 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
*
* Wave equation
*
******************************************************************************/
#include "levelset.h"
#include "commonkernels.h"
#include "particle.h"
#include "conjugategrad.h"
#include <cmath>
using namespace std;
namespace Manta {
/******************************************************************************
*
* explicit integration
*
******************************************************************************/
struct knCalcSecDeriv2d : public KernelBase {
knCalcSecDeriv2d(const Grid<Real> &v, Grid<Real> &ret) : KernelBase(&v, 1), v(v), ret(ret)
{
runMessage();
run();
}
inline void op(int i, int j, int k, const Grid<Real> &v, Grid<Real> &ret) const
{
ret(i, j, k) = (-4. * v(i, j, k) + v(i - 1, j, k) + v(i + 1, j, k) + v(i, j - 1, k) +
v(i, j + 1, k));
}
inline const Grid<Real> &getArg0()
{
return v;
}
typedef Grid<Real> type0;
inline Grid<Real> &getArg1()
{
return ret;
}
typedef Grid<Real> type1;
void runMessage()
{
debMsg("Executing kernel knCalcSecDeriv2d ", 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, v, ret);
}
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, v, ret);
}
}
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<Real> &v;
Grid<Real> &ret;
};
;
//! calculate a second derivative for the wave equation
void calcSecDeriv2d(const Grid<Real> &v, Grid<Real> &curv)
{
knCalcSecDeriv2d(v, curv);
}
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, "calcSecDeriv2d", !noTiming);
PyObject *_retval = nullptr;
{
ArgLocker _lock;
const Grid<Real> &v = *_args.getPtr<Grid<Real>>("v", 0, &_lock);
Grid<Real> &curv = *_args.getPtr<Grid<Real>>("curv", 1, &_lock);
_retval = getPyNone();
calcSecDeriv2d(v, curv);
_args.check();
}
pbFinalizePlugin(parent, "calcSecDeriv2d", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("calcSecDeriv2d", e.what());
return 0;
}
}
static const Pb::Register _RP_calcSecDeriv2d("", "calcSecDeriv2d", _W_0);
extern "C" {
void PbRegister_calcSecDeriv2d()
{
KEEP_UNUSED(_RP_calcSecDeriv2d);
}
}
// mass conservation
struct knTotalSum : public KernelBase {
knTotalSum(Grid<Real> &h) : KernelBase(&h, 1), h(h), sum(0)
{
runMessage();
run();
}
inline void op(int i, int j, int k, Grid<Real> &h, double &sum)
{
sum += h(i, j, k);
}
inline operator double()
{
return sum;
}
inline double &getRet()
{
return sum;
}
inline Grid<Real> &getArg0()
{
return h;
}
typedef Grid<Real> type0;
void runMessage()
{
debMsg("Executing kernel knTotalSum ", 3);
debMsg("Kernel range"
<< " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
4);
};
void operator()(const tbb::blocked_range<IndexInt> &__r)
{
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, h, sum);
}
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, h, sum);
}
}
void run()
{
if (maxZ > 1)
tbb::parallel_reduce(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
else
tbb::parallel_reduce(tbb::blocked_range<IndexInt>(1, maxY), *this);
}
knTotalSum(knTotalSum &o, tbb::split) : KernelBase(o), h(o.h), sum(0)
{
}
void join(const knTotalSum &o)
{
sum += o.sum;
}
Grid<Real> &h;
double sum;
};
//! calculate the sum of all values in a grid (for wave equation solves)
Real totalSum(Grid<Real> &height)
{
knTotalSum ts(height);
return ts.sum;
}
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, "totalSum", !noTiming);
PyObject *_retval = nullptr;
{
ArgLocker _lock;
Grid<Real> &height = *_args.getPtr<Grid<Real>>("height", 0, &_lock);
_retval = toPy(totalSum(height));
_args.check();
}
pbFinalizePlugin(parent, "totalSum", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("totalSum", e.what());
return 0;
}
}
static const Pb::Register _RP_totalSum("", "totalSum", _W_1);
extern "C" {
void PbRegister_totalSum()
{
KEEP_UNUSED(_RP_totalSum);
}
}
//! normalize all values in a grid (for wave equation solves)
void normalizeSumTo(Grid<Real> &height, Real target)
{
knTotalSum ts(height);
Real factor = target / ts.sum;
height.multConst(factor);
}
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, "normalizeSumTo", !noTiming);
PyObject *_retval = nullptr;
{
ArgLocker _lock;
Grid<Real> &height = *_args.getPtr<Grid<Real>>("height", 0, &_lock);
Real target = _args.get<Real>("target", 1, &_lock);
_retval = getPyNone();
normalizeSumTo(height, target);
_args.check();
}
pbFinalizePlugin(parent, "normalizeSumTo", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("normalizeSumTo", e.what());
return 0;
}
}
static const Pb::Register _RP_normalizeSumTo("", "normalizeSumTo", _W_2);
extern "C" {
void PbRegister_normalizeSumTo()
{
KEEP_UNUSED(_RP_normalizeSumTo);
}
}
/******************************************************************************
*
* implicit time integration
*
******************************************************************************/
//! Kernel: Construct the right-hand side of the poisson equation
struct MakeRhsWE : public KernelBase {
MakeRhsWE(const FlagGrid &flags,
Grid<Real> &rhs,
const Grid<Real> &ut,
const Grid<Real> &utm1,
Real s,
bool crankNic = false)
: KernelBase(&flags, 1), flags(flags), rhs(rhs), ut(ut), utm1(utm1), s(s), crankNic(crankNic)
{
runMessage();
run();
}
inline void op(int i,
int j,
int k,
const FlagGrid &flags,
Grid<Real> &rhs,
const Grid<Real> &ut,
const Grid<Real> &utm1,
Real s,
bool crankNic = false) const
{
rhs(i, j, k) = (2. * ut(i, j, k) - utm1(i, j, k));
if (crankNic) {
rhs(i, j, k) += s * (-4. * ut(i, j, k) + 1. * ut(i - 1, j, k) + 1. * ut(i + 1, j, k) +
1. * ut(i, j - 1, k) + 1. * ut(i, j + 1, k));
}
}
inline const FlagGrid &getArg0()
{
return flags;
}
typedef FlagGrid type0;
inline Grid<Real> &getArg1()
{
return rhs;
}
typedef Grid<Real> type1;
inline const Grid<Real> &getArg2()
{
return ut;
}
typedef Grid<Real> type2;
inline const Grid<Real> &getArg3()
{
return utm1;
}
typedef Grid<Real> type3;
inline Real &getArg4()
{
return s;
}
typedef Real type4;
inline bool &getArg5()
{
return crankNic;
}
typedef bool type5;
void runMessage()
{
debMsg("Executing kernel MakeRhsWE ", 3);
debMsg("Kernel range"
<< " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
4);
};
void operator()(const tbb::blocked_range<IndexInt> &__r) const
{
const int _maxX = maxX;
const int _maxY = maxY;
if (maxZ > 1) {
for (int k = __r.begin(); k != (int)__r.end(); k++)
for (int j = 1; j < _maxY; j++)
for (int i = 1; i < _maxX; i++)
op(i, j, k, flags, rhs, ut, utm1, s, crankNic);
}
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, rhs, ut, utm1, s, crankNic);
}
}
void run()
{
if (maxZ > 1)
tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
else
tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
}
const FlagGrid &flags;
Grid<Real> &rhs;
const Grid<Real> &ut;
const Grid<Real> &utm1;
Real s;
bool crankNic;
};
//! do a CG solve for the wave equation (note, out grid only there for debugging... could be
//! removed)
void cgSolveWE(const FlagGrid &flags,
Grid<Real> &ut,
Grid<Real> &utm1,
Grid<Real> &out,
bool crankNic = false,
Real cSqr = 0.25,
Real cgMaxIterFac = 1.5,
Real cgAccuracy = 1e-5)
{
// reserve temp grids
FluidSolver *parent = flags.getParent();
Grid<Real> rhs(parent);
Grid<Real> residual(parent);
Grid<Real> search(parent);
Grid<Real> A0(parent);
Grid<Real> Ai(parent);
Grid<Real> Aj(parent);
Grid<Real> Ak(parent);
Grid<Real> tmp(parent);
// solution...
out.clear();
// setup matrix and boundaries
MakeLaplaceMatrix(flags, A0, Ai, Aj, Ak);
Real dt = parent->getDt();
Real s = dt * dt * cSqr * 0.5;
FOR_IJK(flags)
{
Ai(i, j, k) *= s;
Aj(i, j, k) *= s;
Ak(i, j, k) *= s;
A0(i, j, k) *= s;
A0(i, j, k) += 1.;
}
// compute divergence and init right hand side
rhs.clear();
// h=dt
// rhs: = 2 ut - ut-1
// A: (h2 c2/ dx)=s , (1+4s)uij + s ui-1j + ...
// Cr.Nic.
// rhs: cr nic = 2 ut - ut-1 + h^2c^2/2 b
// A: (h2 c2/2 dx)=s , (1+4s)uij + s ui-1j + ...
MakeRhsWE kernMakeRhs(flags, rhs, ut, utm1, s, crankNic);
const int maxIter = (int)(cgMaxIterFac * flags.getSize().max()) * (flags.is3D() ? 1 : 4);
GridCgInterface *gcg;
vector<Grid<Real> *> matA{&A0, &Ai, &Aj};
if (flags.is3D()) {
matA.push_back(&Ak);
gcg = new GridCg<ApplyMatrix>(out, rhs, residual, search, flags, tmp, matA);
}
else {
gcg = new GridCg<ApplyMatrix2D>(out, rhs, residual, search, flags, tmp, matA);
}
gcg->setAccuracy(cgAccuracy);
// no preconditioning for now...
for (int iter = 0; iter < maxIter; iter++) {
if (!gcg->iterate())
iter = maxIter;
}
debMsg("cgSolveWaveEq iterations:" << gcg->getIterations() << ", res:" << gcg->getSigma(), 1);
utm1.swap(ut);
ut.copyFrom(out);
delete gcg;
}
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, "cgSolveWE", !noTiming);
PyObject *_retval = nullptr;
{
ArgLocker _lock;
const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
Grid<Real> &ut = *_args.getPtr<Grid<Real>>("ut", 1, &_lock);
Grid<Real> &utm1 = *_args.getPtr<Grid<Real>>("utm1", 2, &_lock);
Grid<Real> &out = *_args.getPtr<Grid<Real>>("out", 3, &_lock);
bool crankNic = _args.getOpt<bool>("crankNic", 4, false, &_lock);
Real cSqr = _args.getOpt<Real>("cSqr", 5, 0.25, &_lock);
Real cgMaxIterFac = _args.getOpt<Real>("cgMaxIterFac", 6, 1.5, &_lock);
Real cgAccuracy = _args.getOpt<Real>("cgAccuracy", 7, 1e-5, &_lock);
_retval = getPyNone();
cgSolveWE(flags, ut, utm1, out, crankNic, cSqr, cgMaxIterFac, cgAccuracy);
_args.check();
}
pbFinalizePlugin(parent, "cgSolveWE", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("cgSolveWE", e.what());
return 0;
}
}
static const Pb::Register _RP_cgSolveWE("", "cgSolveWE", _W_3);
extern "C" {
void PbRegister_cgSolveWE()
{
KEEP_UNUSED(_RP_cgSolveWE);
}
}
} // namespace Manta