Add Chromium-only Blender WebEngine parity work
This commit is contained in:
1521
blender-5.2.0/extern/mantaflow/preprocessed/plugin/advection.cpp
vendored
Normal file
1521
blender-5.2.0/extern/mantaflow/preprocessed/plugin/advection.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
597
blender-5.2.0/extern/mantaflow/preprocessed/plugin/apic.cpp
vendored
Normal file
597
blender-5.2.0/extern/mantaflow/preprocessed/plugin/apic.cpp
vendored
Normal 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
|
||||
1701
blender-5.2.0/extern/mantaflow/preprocessed/plugin/extforces.cpp
vendored
Normal file
1701
blender-5.2.0/extern/mantaflow/preprocessed/plugin/extforces.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
435
blender-5.2.0/extern/mantaflow/preprocessed/plugin/fire.cpp
vendored
Normal file
435
blender-5.2.0/extern/mantaflow/preprocessed/plugin/fire.cpp
vendored
Normal 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
|
||||
2812
blender-5.2.0/extern/mantaflow/preprocessed/plugin/flip.cpp
vendored
Normal file
2812
blender-5.2.0/extern/mantaflow/preprocessed/plugin/flip.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
801
blender-5.2.0/extern/mantaflow/preprocessed/plugin/fluidguiding.cpp
vendored
Normal file
801
blender-5.2.0/extern/mantaflow/preprocessed/plugin/fluidguiding.cpp
vendored
Normal 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 ∈
|
||||
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 ∈
|
||||
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 ∈
|
||||
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
|
||||
2582
blender-5.2.0/extern/mantaflow/preprocessed/plugin/initplugins.cpp
vendored
Normal file
2582
blender-5.2.0/extern/mantaflow/preprocessed/plugin/initplugins.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
578
blender-5.2.0/extern/mantaflow/preprocessed/plugin/kepsilon.cpp
vendored
Normal file
578
blender-5.2.0/extern/mantaflow/preprocessed/plugin/kepsilon.cpp
vendored
Normal 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> ∏
|
||||
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
|
||||
780
blender-5.2.0/extern/mantaflow/preprocessed/plugin/meshplugins.cpp
vendored
Normal file
780
blender-5.2.0/extern/mantaflow/preprocessed/plugin/meshplugins.cpp
vendored
Normal 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
|
||||
1526
blender-5.2.0/extern/mantaflow/preprocessed/plugin/pressure.cpp
vendored
Normal file
1526
blender-5.2.0/extern/mantaflow/preprocessed/plugin/pressure.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
502
blender-5.2.0/extern/mantaflow/preprocessed/plugin/ptsplugins.cpp
vendored
Normal file
502
blender-5.2.0/extern/mantaflow/preprocessed/plugin/ptsplugins.cpp
vendored
Normal 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 ∂
|
||||
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
|
||||
3099
blender-5.2.0/extern/mantaflow/preprocessed/plugin/secondaryparticles.cpp
vendored
Normal file
3099
blender-5.2.0/extern/mantaflow/preprocessed/plugin/secondaryparticles.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2188
blender-5.2.0/extern/mantaflow/preprocessed/plugin/surfaceturbulence.cpp
vendored
Normal file
2188
blender-5.2.0/extern/mantaflow/preprocessed/plugin/surfaceturbulence.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1428
blender-5.2.0/extern/mantaflow/preprocessed/plugin/viscosity.cpp
vendored
Normal file
1428
blender-5.2.0/extern/mantaflow/preprocessed/plugin/viscosity.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
697
blender-5.2.0/extern/mantaflow/preprocessed/plugin/vortexplugins.cpp
vendored
Normal file
697
blender-5.2.0/extern/mantaflow/preprocessed/plugin/vortexplugins.cpp
vendored
Normal 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
|
||||
1292
blender-5.2.0/extern/mantaflow/preprocessed/plugin/waveletturbulence.cpp
vendored
Normal file
1292
blender-5.2.0/extern/mantaflow/preprocessed/plugin/waveletturbulence.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
488
blender-5.2.0/extern/mantaflow/preprocessed/plugin/waves.cpp
vendored
Normal file
488
blender-5.2.0/extern/mantaflow/preprocessed/plugin/waves.cpp
vendored
Normal 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
|
||||
Reference in New Issue
Block a user