This repository has been archived on 2023-10-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
blender-archive/extern/mantaflow/preprocessed/plugin/pressure.cpp
Sebastián Barschkis 635694c0ff Fluid: Added new viscosity solver
Mainly updated the Mantaflow version. It includes the new viscosity solver plugin based on the method from 'Accurate Viscous Free Surfaces for Buckling, Coiling, and Rotating Liquids' (Batty & Bridson).

In the UI, this update adds a new 'Viscosity' section to the fluid modifier UI (liquid domains only). For now, there is a single 'strength' value to control the viscosity of liquids.
2020-12-23 15:48:38 +01:00

1517 lines
49 KiB
C++

// DO NOT EDIT !
// This file is generated using the MantaFlow preprocessor (prep generate).
/******************************************************************************
*
* MantaFlow fluid solver framework
* Copyright 2011 Tobias Pfaff, Nils Thuerey
*
* This program is free software, distributed under the terms of the
* Apache License, Version 2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Plugins for pressure correction: solve_pressure, and ghost fluid helpers
*
******************************************************************************/
#include "vectorbase.h"
#include "kernel.h"
#include "conjugategrad.h"
#include "multigrid.h"
using namespace std;
namespace Manta {
//! Preconditioner for CG solver
// - None: Use standard CG
// - MIC: Modified incomplete Cholesky preconditioner
// - MGDynamic: Multigrid preconditioner, rebuilt for each solve
// - MGStatic: Multigrid preconditioner, built only once (faster than
// MGDynamic, but works only if Poisson equation does not change)
enum Preconditioner { PcNone = 0, PcMIC = 1, PcMGDynamic = 2, PcMGStatic = 3 };
inline static Real surfTensHelper(const IndexInt idx,
const int offset,
const Grid<Real> &phi,
const Grid<Real> &curv,
const Real surfTens,
const Real gfClamp);
//! Kernel: Construct the right-hand side of the poisson equation
struct MakeRhs : public KernelBase {
MakeRhs(const FlagGrid &flags,
Grid<Real> &rhs,
const MACGrid &vel,
const Grid<Real> *perCellCorr,
const MACGrid *fractions,
const MACGrid *obvel,
const Grid<Real> *phi,
const Grid<Real> *curv,
const Real surfTens,
const Real gfClamp)
: KernelBase(&flags, 1),
flags(flags),
rhs(rhs),
vel(vel),
perCellCorr(perCellCorr),
fractions(fractions),
obvel(obvel),
phi(phi),
curv(curv),
surfTens(surfTens),
gfClamp(gfClamp),
cnt(0),
sum(0)
{
runMessage();
run();
}
inline void op(int i,
int j,
int k,
const FlagGrid &flags,
Grid<Real> &rhs,
const MACGrid &vel,
const Grid<Real> *perCellCorr,
const MACGrid *fractions,
const MACGrid *obvel,
const Grid<Real> *phi,
const Grid<Real> *curv,
const Real surfTens,
const Real gfClamp,
int &cnt,
double &sum)
{
if (!flags.isFluid(i, j, k)) {
rhs(i, j, k) = 0;
return;
}
// compute negative divergence
// no flag checks: assumes vel at obstacle interfaces is set to zero
Real set(0);
if (!fractions) {
set = vel(i, j, k).x - vel(i + 1, j, k).x + vel(i, j, k).y - vel(i, j + 1, k).y;
if (vel.is3D())
set += vel(i, j, k).z - vel(i, j, k + 1).z;
}
else {
set = (*fractions)(i, j, k).x * vel(i, j, k).x -
(*fractions)(i + 1, j, k).x * vel(i + 1, j, k).x +
(*fractions)(i, j, k).y * vel(i, j, k).y -
(*fractions)(i, j + 1, k).y * vel(i, j + 1, k).y;
if (vel.is3D())
set += (*fractions)(i, j, k).z * vel(i, j, k).z -
(*fractions)(i, j, k + 1).z * vel(i, j, k + 1).z;
// compute divergence from obstacle by using obstacle velocity (optional)
if (obvel) {
set += (1 - (*fractions)(i, j, k).x) * (*obvel)(i, j, k).x -
(1 - (*fractions)(i + 1, j, k).x) * (*obvel)(i + 1, j, k).x +
(1 - (*fractions)(i, j, k).y) * (*obvel)(i, j, k).y -
(1 - (*fractions)(i, j + 1, k).y) * (*obvel)(i, j + 1, k).y;
if (obvel->is3D())
set += (1 - (*fractions)(i, j, k).z) * (*obvel)(i, j, k).z -
(1 - (*fractions)(i, j, k + 1).z) * (*obvel)(i, j, k + 1).z;
}
}
// compute surface tension effect (optional)
if (phi && curv) {
const IndexInt idx = flags.index(i, j, k);
const int X = flags.getStrideX(), Y = flags.getStrideY(), Z = flags.getStrideZ();
if (flags.isEmpty(i - 1, j, k))
set += surfTensHelper(idx, -X, *phi, *curv, surfTens, gfClamp);
if (flags.isEmpty(i + 1, j, k))
set += surfTensHelper(idx, +X, *phi, *curv, surfTens, gfClamp);
if (flags.isEmpty(i, j - 1, k))
set += surfTensHelper(idx, -Y, *phi, *curv, surfTens, gfClamp);
if (flags.isEmpty(i, j + 1, k))
set += surfTensHelper(idx, +Y, *phi, *curv, surfTens, gfClamp);
if (vel.is3D()) {
if (flags.isEmpty(i, j, k - 1))
set += surfTensHelper(idx, -Z, *phi, *curv, surfTens, gfClamp);
if (flags.isEmpty(i, j, k + 1))
set += surfTensHelper(idx, +Z, *phi, *curv, surfTens, gfClamp);
}
}
// per cell divergence correction (optional)
if (perCellCorr)
set += perCellCorr->get(i, j, k);
// obtain sum, cell count
sum += set;
cnt++;
rhs(i, j, k) = set;
}
inline const FlagGrid &getArg0()
{
return flags;
}
typedef FlagGrid type0;
inline Grid<Real> &getArg1()
{
return rhs;
}
typedef Grid<Real> type1;
inline const MACGrid &getArg2()
{
return vel;
}
typedef MACGrid type2;
inline const Grid<Real> *getArg3()
{
return perCellCorr;
}
typedef Grid<Real> type3;
inline const MACGrid *getArg4()
{
return fractions;
}
typedef MACGrid type4;
inline const MACGrid *getArg5()
{
return obvel;
}
typedef MACGrid type5;
inline const Grid<Real> *getArg6()
{
return phi;
}
typedef Grid<Real> type6;
inline const Grid<Real> *getArg7()
{
return curv;
}
typedef Grid<Real> type7;
inline const Real &getArg8()
{
return surfTens;
}
typedef Real type8;
inline const Real &getArg9()
{
return gfClamp;
}
typedef Real type9;
void runMessage()
{
debMsg("Executing kernel MakeRhs ", 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,
flags,
rhs,
vel,
perCellCorr,
fractions,
obvel,
phi,
curv,
surfTens,
gfClamp,
cnt,
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,
flags,
rhs,
vel,
perCellCorr,
fractions,
obvel,
phi,
curv,
surfTens,
gfClamp,
cnt,
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);
}
MakeRhs(MakeRhs &o, tbb::split)
: KernelBase(o),
flags(o.flags),
rhs(o.rhs),
vel(o.vel),
perCellCorr(o.perCellCorr),
fractions(o.fractions),
obvel(o.obvel),
phi(o.phi),
curv(o.curv),
surfTens(o.surfTens),
gfClamp(o.gfClamp),
cnt(0),
sum(0)
{
}
void join(const MakeRhs &o)
{
cnt += o.cnt;
sum += o.sum;
}
const FlagGrid &flags;
Grid<Real> &rhs;
const MACGrid &vel;
const Grid<Real> *perCellCorr;
const MACGrid *fractions;
const MACGrid *obvel;
const Grid<Real> *phi;
const Grid<Real> *curv;
const Real surfTens;
const Real gfClamp;
int cnt;
double sum;
};
//! Kernel: make velocity divergence free by subtracting pressure gradient
struct knCorrectVelocity : public KernelBase {
knCorrectVelocity(const FlagGrid &flags, MACGrid &vel, const Grid<Real> &pressure)
: KernelBase(&flags, 1), flags(flags), vel(vel), pressure(pressure)
{
runMessage();
run();
}
inline void op(
int i, int j, int k, const FlagGrid &flags, MACGrid &vel, const Grid<Real> &pressure) const
{
const IndexInt idx = flags.index(i, j, k);
if (flags.isFluid(idx)) {
if (flags.isFluid(i - 1, j, k))
vel[idx].x -= (pressure[idx] - pressure(i - 1, j, k));
if (flags.isFluid(i, j - 1, k))
vel[idx].y -= (pressure[idx] - pressure(i, j - 1, k));
if (flags.is3D() && flags.isFluid(i, j, k - 1))
vel[idx].z -= (pressure[idx] - pressure(i, j, k - 1));
if (flags.isEmpty(i - 1, j, k))
vel[idx].x -= pressure[idx];
if (flags.isEmpty(i, j - 1, k))
vel[idx].y -= pressure[idx];
if (flags.is3D() && flags.isEmpty(i, j, k - 1))
vel[idx].z -= pressure[idx];
}
else if (flags.isEmpty(idx) &&
!flags.isOutflow(idx)) { // don't change velocities in outflow cells
if (flags.isFluid(i - 1, j, k))
vel[idx].x += pressure(i - 1, j, k);
else
vel[idx].x = 0.f;
if (flags.isFluid(i, j - 1, k))
vel[idx].y += pressure(i, j - 1, k);
else
vel[idx].y = 0.f;
if (flags.is3D()) {
if (flags.isFluid(i, j, k - 1))
vel[idx].z += pressure(i, j, k - 1);
else
vel[idx].z = 0.f;
}
}
}
inline const FlagGrid &getArg0()
{
return flags;
}
typedef FlagGrid type0;
inline MACGrid &getArg1()
{
return vel;
}
typedef MACGrid type1;
inline const Grid<Real> &getArg2()
{
return pressure;
}
typedef Grid<Real> type2;
void runMessage()
{
debMsg("Executing kernel knCorrectVelocity ", 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, vel, pressure);
}
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, vel, pressure);
}
}
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;
MACGrid &vel;
const Grid<Real> &pressure;
};
// *****************************************************************************
// Ghost fluid helpers
// calculate fraction filled with liquid (note, assumes inside value is < outside!)
inline static Real thetaHelper(const Real inside, const Real outside)
{
const Real denom = inside - outside;
if (denom > -1e-04)
return 0.5; // should always be neg, and large enough...
return std::max(Real(0), std::min(Real(1), inside / denom));
}
// calculate ghost fluid factor, cell at idx should be a fluid cell
inline static Real ghostFluidHelper(const IndexInt idx,
const int offset,
const Grid<Real> &phi,
const Real gfClamp)
{
Real alpha = thetaHelper(phi[idx], phi[idx + offset]);
if (alpha < gfClamp)
return alpha = gfClamp;
return (1. - (1. / alpha));
}
inline static Real surfTensHelper(const IndexInt idx,
const int offset,
const Grid<Real> &phi,
const Grid<Real> &curv,
const Real surfTens,
const Real gfClamp)
{
return surfTens * (curv[idx + offset] - ghostFluidHelper(idx, offset, phi, gfClamp) * curv[idx]);
}
//! Kernel: Adapt A0 for ghost fluid
struct ApplyGhostFluidDiagonal : public KernelBase {
ApplyGhostFluidDiagonal(Grid<Real> &A0,
const FlagGrid &flags,
const Grid<Real> &phi,
const Real gfClamp)
: KernelBase(&A0, 1), A0(A0), flags(flags), phi(phi), gfClamp(gfClamp)
{
runMessage();
run();
}
inline void op(int i,
int j,
int k,
Grid<Real> &A0,
const FlagGrid &flags,
const Grid<Real> &phi,
const Real gfClamp) const
{
const int X = flags.getStrideX(), Y = flags.getStrideY(), Z = flags.getStrideZ();
const IndexInt idx = flags.index(i, j, k);
if (!flags.isFluid(idx))
return;
if (flags.isEmpty(i - 1, j, k))
A0[idx] -= ghostFluidHelper(idx, -X, phi, gfClamp);
if (flags.isEmpty(i + 1, j, k))
A0[idx] -= ghostFluidHelper(idx, +X, phi, gfClamp);
if (flags.isEmpty(i, j - 1, k))
A0[idx] -= ghostFluidHelper(idx, -Y, phi, gfClamp);
if (flags.isEmpty(i, j + 1, k))
A0[idx] -= ghostFluidHelper(idx, +Y, phi, gfClamp);
if (flags.is3D()) {
if (flags.isEmpty(i, j, k - 1))
A0[idx] -= ghostFluidHelper(idx, -Z, phi, gfClamp);
if (flags.isEmpty(i, j, k + 1))
A0[idx] -= ghostFluidHelper(idx, +Z, phi, gfClamp);
}
}
inline Grid<Real> &getArg0()
{
return A0;
}
typedef Grid<Real> type0;
inline const FlagGrid &getArg1()
{
return flags;
}
typedef FlagGrid type1;
inline const Grid<Real> &getArg2()
{
return phi;
}
typedef Grid<Real> type2;
inline const Real &getArg3()
{
return gfClamp;
}
typedef Real type3;
void runMessage()
{
debMsg("Executing kernel ApplyGhostFluidDiagonal ", 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, A0, flags, phi, gfClamp);
}
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, A0, flags, phi, gfClamp);
}
}
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> &A0;
const FlagGrid &flags;
const Grid<Real> &phi;
const Real gfClamp;
};
//! Kernel: Apply velocity update: ghost fluid contribution
struct knCorrectVelocityGhostFluid : public KernelBase {
knCorrectVelocityGhostFluid(MACGrid &vel,
const FlagGrid &flags,
const Grid<Real> &pressure,
const Grid<Real> &phi,
Real gfClamp,
const Grid<Real> *curv,
const Real surfTens)
: KernelBase(&vel, 1),
vel(vel),
flags(flags),
pressure(pressure),
phi(phi),
gfClamp(gfClamp),
curv(curv),
surfTens(surfTens)
{
runMessage();
run();
}
inline void op(int i,
int j,
int k,
MACGrid &vel,
const FlagGrid &flags,
const Grid<Real> &pressure,
const Grid<Real> &phi,
Real gfClamp,
const Grid<Real> *curv,
const Real surfTens) const
{
const IndexInt X = flags.getStrideX(), Y = flags.getStrideY(), Z = flags.getStrideZ();
const IndexInt idx = flags.index(i, j, k);
if (flags.isFluid(idx)) {
if (flags.isEmpty(i - 1, j, k))
vel[idx][0] += pressure[idx] * ghostFluidHelper(idx, -X, phi, gfClamp);
if (flags.isEmpty(i, j - 1, k))
vel[idx][1] += pressure[idx] * ghostFluidHelper(idx, -Y, phi, gfClamp);
if (flags.is3D() && flags.isEmpty(i, j, k - 1))
vel[idx][2] += pressure[idx] * ghostFluidHelper(idx, -Z, phi, gfClamp);
}
else if (flags.isEmpty(idx) &&
!flags.isOutflow(idx)) { // do not change velocities in outflow cells
if (flags.isFluid(i - 1, j, k))
vel[idx][0] -= pressure(i - 1, j, k) * ghostFluidHelper(idx - X, +X, phi, gfClamp);
else
vel[idx].x = 0.f;
if (flags.isFluid(i, j - 1, k))
vel[idx][1] -= pressure(i, j - 1, k) * ghostFluidHelper(idx - Y, +Y, phi, gfClamp);
else
vel[idx].y = 0.f;
if (flags.is3D()) {
if (flags.isFluid(i, j, k - 1))
vel[idx][2] -= pressure(i, j, k - 1) * ghostFluidHelper(idx - Z, +Z, phi, gfClamp);
else
vel[idx].z = 0.f;
}
}
if (curv) {
if (flags.isFluid(idx)) {
if (flags.isEmpty(i - 1, j, k))
vel[idx].x += surfTensHelper(idx, -X, phi, *curv, surfTens, gfClamp);
if (flags.isEmpty(i, j - 1, k))
vel[idx].y += surfTensHelper(idx, -Y, phi, *curv, surfTens, gfClamp);
if (flags.is3D() && flags.isEmpty(i, j, k - 1))
vel[idx].z += surfTensHelper(idx, -Z, phi, *curv, surfTens, gfClamp);
}
else if (flags.isEmpty(idx) &&
!flags.isOutflow(idx)) { // do not change velocities in outflow cells
vel[idx].x -= (flags.isFluid(i - 1, j, k)) ?
surfTensHelper(idx - X, +X, phi, *curv, surfTens, gfClamp) :
0.f;
vel[idx].y -= (flags.isFluid(i, j - 1, k)) ?
surfTensHelper(idx - Y, +Y, phi, *curv, surfTens, gfClamp) :
0.f;
if (flags.is3D())
vel[idx].z -= (flags.isFluid(i, j, k - 1)) ?
surfTensHelper(idx - Z, +Z, phi, *curv, surfTens, gfClamp) :
0.f;
}
}
}
inline MACGrid &getArg0()
{
return vel;
}
typedef MACGrid type0;
inline const FlagGrid &getArg1()
{
return flags;
}
typedef FlagGrid type1;
inline const Grid<Real> &getArg2()
{
return pressure;
}
typedef Grid<Real> type2;
inline const Grid<Real> &getArg3()
{
return phi;
}
typedef Grid<Real> type3;
inline Real &getArg4()
{
return gfClamp;
}
typedef Real type4;
inline const Grid<Real> *getArg5()
{
return curv;
}
typedef Grid<Real> type5;
inline const Real &getArg6()
{
return surfTens;
}
typedef Real type6;
void runMessage()
{
debMsg("Executing kernel knCorrectVelocityGhostFluid ", 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, flags, pressure, phi, gfClamp, curv, surfTens);
}
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, flags, pressure, phi, gfClamp, curv, surfTens);
}
}
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);
}
MACGrid &vel;
const FlagGrid &flags;
const Grid<Real> &pressure;
const Grid<Real> &phi;
Real gfClamp;
const Grid<Real> *curv;
const Real surfTens;
};
// improve behavior of clamping for large time steps:
inline static Real ghostFluidWasClamped(const IndexInt idx,
const int offset,
const Grid<Real> &phi,
const Real gfClamp)
{
const Real alpha = thetaHelper(phi[idx], phi[idx + offset]);
if (alpha < gfClamp)
return true;
return false;
}
struct knReplaceClampedGhostFluidVels : public KernelBase {
knReplaceClampedGhostFluidVels(MACGrid &vel,
const FlagGrid &flags,
const Grid<Real> &pressure,
const Grid<Real> &phi,
Real gfClamp)
: KernelBase(&vel, 1), vel(vel), flags(flags), pressure(pressure), phi(phi), gfClamp(gfClamp)
{
runMessage();
run();
}
inline void op(int i,
int j,
int k,
MACGrid &vel,
const FlagGrid &flags,
const Grid<Real> &pressure,
const Grid<Real> &phi,
Real gfClamp) const
{
const IndexInt idx = flags.index(i, j, k);
const IndexInt X = flags.getStrideX(), Y = flags.getStrideY(), Z = flags.getStrideZ();
if (!flags.isEmpty(idx))
return;
if (flags.isFluid(i - 1, j, k) && ghostFluidWasClamped(idx - X, +X, phi, gfClamp))
vel[idx][0] = vel[idx - X][0];
if (flags.isFluid(i, j - 1, k) && ghostFluidWasClamped(idx - Y, +Y, phi, gfClamp))
vel[idx][1] = vel[idx - Y][1];
if (flags.is3D() && flags.isFluid(i, j, k - 1) &&
ghostFluidWasClamped(idx - Z, +Z, phi, gfClamp))
vel[idx][2] = vel[idx - Z][2];
if (flags.isFluid(i + 1, j, k) && ghostFluidWasClamped(idx + X, -X, phi, gfClamp))
vel[idx][0] = vel[idx + X][0];
if (flags.isFluid(i, j + 1, k) && ghostFluidWasClamped(idx + Y, -Y, phi, gfClamp))
vel[idx][1] = vel[idx + Y][1];
if (flags.is3D() && flags.isFluid(i, j, k + 1) &&
ghostFluidWasClamped(idx + Z, -Z, phi, gfClamp))
vel[idx][2] = vel[idx + Z][2];
}
inline MACGrid &getArg0()
{
return vel;
}
typedef MACGrid type0;
inline const FlagGrid &getArg1()
{
return flags;
}
typedef FlagGrid type1;
inline const Grid<Real> &getArg2()
{
return pressure;
}
typedef Grid<Real> type2;
inline const Grid<Real> &getArg3()
{
return phi;
}
typedef Grid<Real> type3;
inline Real &getArg4()
{
return gfClamp;
}
typedef Real type4;
void runMessage()
{
debMsg("Executing kernel knReplaceClampedGhostFluidVels ", 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, flags, pressure, phi, gfClamp);
}
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, flags, pressure, phi, gfClamp);
}
}
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);
}
MACGrid &vel;
const FlagGrid &flags;
const Grid<Real> &pressure;
const Grid<Real> &phi;
Real gfClamp;
};
//! Kernel: Compute min value of Real grid
struct CountEmptyCells : public KernelBase {
CountEmptyCells(const FlagGrid &flags) : KernelBase(&flags, 0), flags(flags), numEmpty(0)
{
runMessage();
run();
}
inline void op(IndexInt idx, const FlagGrid &flags, int &numEmpty)
{
if (flags.isEmpty(idx))
numEmpty++;
}
inline operator int()
{
return numEmpty;
}
inline int &getRet()
{
return numEmpty;
}
inline const FlagGrid &getArg0()
{
return flags;
}
typedef FlagGrid type0;
void runMessage()
{
debMsg("Executing kernel CountEmptyCells ", 3);
debMsg("Kernel range"
<< " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
4);
};
void operator()(const tbb::blocked_range<IndexInt> &__r)
{
for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
op(idx, flags, numEmpty);
}
void run()
{
tbb::parallel_reduce(tbb::blocked_range<IndexInt>(0, size), *this);
}
CountEmptyCells(CountEmptyCells &o, tbb::split) : KernelBase(o), flags(o.flags), numEmpty(0)
{
}
void join(const CountEmptyCells &o)
{
numEmpty += o.numEmpty;
}
const FlagGrid &flags;
int numEmpty;
};
// *****************************************************************************
// Misc helpers
//! Change 'A' and 'rhs' such that pressure at 'fixPidx' is fixed to 'value'
void fixPressure(int fixPidx,
Real value,
Grid<Real> &rhs,
Grid<Real> &A0,
Grid<Real> &Ai,
Grid<Real> &Aj,
Grid<Real> &Ak)
{
// Bring to rhs at neighbors
rhs[fixPidx + Ai.getStrideX()] -= Ai[fixPidx] * value;
rhs[fixPidx + Aj.getStrideY()] -= Aj[fixPidx] * value;
rhs[fixPidx - Ai.getStrideX()] -= Ai[fixPidx - Ai.getStrideX()] * value;
rhs[fixPidx - Aj.getStrideY()] -= Aj[fixPidx - Aj.getStrideY()] * value;
if (rhs.is3D()) {
rhs[fixPidx + Ak.getStrideZ()] -= Ak[fixPidx] * value;
rhs[fixPidx - Ak.getStrideZ()] -= Ak[fixPidx - Ak.getStrideZ()] * value;
}
// Trivialize equation at 'fixPidx' to: pressure[fixPidx] = value
rhs[fixPidx] = value;
A0[fixPidx] = Real(1);
Ai[fixPidx] = Aj[fixPidx] = Ak[fixPidx] = Real(0);
Ai[fixPidx - Ai.getStrideX()] = Real(0);
Aj[fixPidx - Aj.getStrideY()] = Real(0);
if (rhs.is3D()) {
Ak[fixPidx - Ak.getStrideZ()] = Real(0);
}
}
// for "static" MG mode, keep one MG data structure per fluid solver
// leave cleanup to OS/user if nonzero at program termination (PcMGStatic mode)
// alternatively, manually release in scene file with releaseMG
static std::map<FluidSolver *, GridMg *> gMapMG;
void releaseMG(FluidSolver *solver = nullptr)
{
// release all?
if (!solver) {
for (std::map<FluidSolver *, GridMg *>::iterator it = gMapMG.begin(); it != gMapMG.end();
it++) {
if (it->first != nullptr)
releaseMG(it->first);
}
return;
}
GridMg *mg = gMapMG[solver];
if (mg) {
delete mg;
gMapMG[solver] = nullptr;
}
}
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, "releaseMG", !noTiming);
PyObject *_retval = nullptr;
{
ArgLocker _lock;
FluidSolver *solver = _args.getPtrOpt<FluidSolver>("solver", 0, nullptr, &_lock);
_retval = getPyNone();
releaseMG(solver);
_args.check();
}
pbFinalizePlugin(parent, "releaseMG", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("releaseMG", e.what());
return 0;
}
}
static const Pb::Register _RP_releaseMG("", "releaseMG", _W_0);
extern "C" {
void PbRegister_releaseMG()
{
KEEP_UNUSED(_RP_releaseMG);
}
}
// *****************************************************************************
// Main pressure solve
// Note , all three pressure solve helper functions take
// identical parameters, apart from the RHS grid (and different const values)
//! Compute rhs for pressure solve
void computePressureRhs(Grid<Real> &rhs,
const MACGrid &vel,
const 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 = PcMIC,
bool enforceCompatibility = false,
bool useL2Norm = false,
bool zeroPressureFixing = false,
const Grid<Real> *curv = nullptr,
const Real surfTens = 0.)
{
// compute divergence and init right hand side
MakeRhs kernMakeRhs(
flags, rhs, vel, perCellCorr, fractions, obvel, phi, curv, surfTens, gfClamp);
if (enforceCompatibility)
rhs += (Real)(-kernMakeRhs.sum / (Real)kernMakeRhs.cnt);
}
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, "computePressureRhs", !noTiming);
PyObject *_retval = nullptr;
{
ArgLocker _lock;
Grid<Real> &rhs = *_args.getPtr<Grid<Real>>("rhs", 0, &_lock);
const MACGrid &vel = *_args.getPtr<MACGrid>("vel", 1, &_lock);
const Grid<Real> &pressure = *_args.getPtr<Grid<Real>>("pressure", 2, &_lock);
const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 3, &_lock);
Real cgAccuracy = _args.getOpt<Real>("cgAccuracy", 4, 1e-3, &_lock);
const Grid<Real> *phi = _args.getPtrOpt<Grid<Real>>("phi", 5, nullptr, &_lock);
const Grid<Real> *perCellCorr = _args.getPtrOpt<Grid<Real>>(
"perCellCorr", 6, nullptr, &_lock);
const MACGrid *fractions = _args.getPtrOpt<MACGrid>("fractions", 7, nullptr, &_lock);
const MACGrid *obvel = _args.getPtrOpt<MACGrid>("obvel", 8, nullptr, &_lock);
Real gfClamp = _args.getOpt<Real>("gfClamp", 9, 1e-04, &_lock);
Real cgMaxIterFac = _args.getOpt<Real>("cgMaxIterFac", 10, 1.5, &_lock);
bool precondition = _args.getOpt<bool>("precondition", 11, true, &_lock);
int preconditioner = _args.getOpt<int>("preconditioner", 12, PcMIC, &_lock);
bool enforceCompatibility = _args.getOpt<bool>("enforceCompatibility", 13, false, &_lock);
bool useL2Norm = _args.getOpt<bool>("useL2Norm", 14, false, &_lock);
bool zeroPressureFixing = _args.getOpt<bool>("zeroPressureFixing", 15, false, &_lock);
const Grid<Real> *curv = _args.getPtrOpt<Grid<Real>>("curv", 16, nullptr, &_lock);
const Real surfTens = _args.getOpt<Real>("surfTens", 17, 0., &_lock);
_retval = getPyNone();
computePressureRhs(rhs,
vel,
pressure,
flags,
cgAccuracy,
phi,
perCellCorr,
fractions,
obvel,
gfClamp,
cgMaxIterFac,
precondition,
preconditioner,
enforceCompatibility,
useL2Norm,
zeroPressureFixing,
curv,
surfTens);
_args.check();
}
pbFinalizePlugin(parent, "computePressureRhs", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("computePressureRhs", e.what());
return 0;
}
}
static const Pb::Register _RP_computePressureRhs("", "computePressureRhs", _W_1);
extern "C" {
void PbRegister_computePressureRhs()
{
KEEP_UNUSED(_RP_computePressureRhs);
}
}
//! Build and solve pressure system of equations
//! perCellCorr: a divergence correction for each cell, optional
//! fractions: for 2nd order obstacle boundaries, optional
//! gfClamp: clamping threshold for ghost fluid method
//! cgMaxIterFac: heuristic to determine maximal number of CG iteations, increase for more accurate
//! solutions preconditioner: MIC, or MG (see Preconditioner enum) useL2Norm: use max norm by
//! default, can be turned to L2 here zeroPressureFixing: remove null space by fixing a single
//! pressure value, needed for MG curv: curvature for surface tension effects surfTens: surface
//! tension coefficient retRhs: return RHS divergence, e.g., for debugging; optional
void solvePressureSystem(Grid<Real> &rhs,
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,
Real gfClamp = 1e-04,
Real cgMaxIterFac = 1.5,
bool precondition = true,
int preconditioner = PcMIC,
const bool enforceCompatibility = false,
const bool useL2Norm = false,
const bool zeroPressureFixing = false,
const Grid<Real> *curv = nullptr,
const Real surfTens = 0.)
{
if (precondition == false)
preconditioner = PcNone; // for backwards compatibility
// reserve temp grids
FluidSolver *parent = flags.getParent();
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);
// setup matrix and boundaries
MakeLaplaceMatrix(flags, A0, Ai, Aj, Ak, fractions);
if (phi) {
ApplyGhostFluidDiagonal(A0, flags, *phi, gfClamp);
}
// check whether we need to fix some pressure value...
// (manually enable, or automatically for high accuracy, can cause asymmetries otherwise)
if (zeroPressureFixing || cgAccuracy < 1e-07) {
if (FLOATINGPOINT_PRECISION == 1)
debMsg(
"Warning - high CG accuracy with single-precision floating point accuracy might not "
"converge...",
2);
int numEmpty = CountEmptyCells(flags);
IndexInt fixPidx = -1;
if (numEmpty == 0) {
// Determine appropriate fluid cell for pressure fixing
// 1) First check some preferred positions for approx. symmetric zeroPressureFixing
Vec3i topCenter(
flags.getSizeX() / 2, flags.getSizeY() - 1, flags.is3D() ? flags.getSizeZ() / 2 : 0);
Vec3i preferredPos[] = {topCenter, topCenter - Vec3i(0, 1, 0), topCenter - Vec3i(0, 2, 0)};
for (Vec3i pos : preferredPos) {
if (flags.isFluid(pos)) {
fixPidx = flags.index(pos);
break;
}
}
// 2) Then search whole domain
if (fixPidx == -1) {
FOR_IJK_BND(flags, 1)
{
if (flags.isFluid(i, j, k)) {
fixPidx = flags.index(i, j, k);
// break FOR_IJK_BND loop
i = flags.getSizeX() - 1;
j = flags.getSizeY() - 1;
k = __kmax;
}
}
}
// debMsg("No empty cells! Fixing pressure of cell "<<fixPidx<<" to zero",1);
}
if (fixPidx >= 0) {
fixPressure(fixPidx, Real(0), rhs, A0, Ai, Aj, Ak);
static bool msgOnce = false;
if (!msgOnce) {
debMsg("Pinning pressure of cell " << fixPidx << " to zero", 2);
msgOnce = true;
}
}
}
// CG setup
// note: the last factor increases the max iterations for 2d, which right now can't use a
// preconditioner
GridCgInterface *gcg;
vector<Grid<Real> *> matA{&A0, &Ai, &Aj};
if (vel.is3D()) {
matA.push_back(&Ak);
gcg = new GridCg<ApplyMatrix>(pressure, rhs, residual, search, flags, tmp, matA);
}
else {
gcg = new GridCg<ApplyMatrix2D>(pressure, rhs, residual, search, flags, tmp, matA);
}
gcg->setAccuracy(cgAccuracy);
gcg->setUseL2Norm(useL2Norm);
int maxIter = (int)(cgMaxIterFac * flags.getSize().max()) * (flags.is3D() ? 1 : 4);
Grid<Real> *pca0 = nullptr, *pca1 = nullptr, *pca2 = nullptr, *pca3 = nullptr;
GridMg *pmg = nullptr;
// optional preconditioning
if (preconditioner == PcMIC) {
pca0 = new Grid<Real>(parent);
pca1 = new Grid<Real>(parent);
pca2 = new Grid<Real>(parent);
pca3 = new Grid<Real>(parent);
gcg->setICPreconditioner(GridCgInterface::PC_mICP, pca0, pca1, pca2, pca3);
}
else if (preconditioner == PcMGDynamic || preconditioner == PcMGStatic) {
maxIter = 100;
pmg = gMapMG[parent];
// Release MG from previous step if present (e.g. if previous solve was with MGStatic)
if (pmg && preconditioner == PcMGDynamic) {
releaseMG(parent);
pmg = nullptr;
}
if (!pmg) {
pmg = new GridMg(pressure.getSize());
gMapMG[parent] = pmg;
}
gcg->setMGPreconditioner(GridCgInterface::PC_MGP, pmg);
}
// CG solve
for (int iter = 0; iter < maxIter; iter++) {
if (!gcg->iterate())
iter = maxIter;
if (iter < maxIter)
debMsg("FluidSolver::solvePressure iteration " << iter
<< ", residual: " << gcg->getResNorm(),
9);
}
debMsg("FluidSolver::solvePressure done. Iterations:" << gcg->getIterations()
<< ", residual:" << gcg->getResNorm(),
2);
// Cleanup
if (gcg)
delete gcg;
if (pca0)
delete pca0;
if (pca1)
delete pca1;
if (pca2)
delete pca2;
if (pca3)
delete pca3;
// PcMGDynamic: always delete multigrid solver after use
// PcMGStatic: keep multigrid solver for next solve
if (pmg && preconditioner == PcMGDynamic)
releaseMG(parent);
}
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, "solvePressureSystem", !noTiming);
PyObject *_retval = nullptr;
{
ArgLocker _lock;
Grid<Real> &rhs = *_args.getPtr<Grid<Real>>("rhs", 0, &_lock);
MACGrid &vel = *_args.getPtr<MACGrid>("vel", 1, &_lock);
Grid<Real> &pressure = *_args.getPtr<Grid<Real>>("pressure", 2, &_lock);
const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 3, &_lock);
Real cgAccuracy = _args.getOpt<Real>("cgAccuracy", 4, 1e-3, &_lock);
const Grid<Real> *phi = _args.getPtrOpt<Grid<Real>>("phi", 5, nullptr, &_lock);
const Grid<Real> *perCellCorr = _args.getPtrOpt<Grid<Real>>(
"perCellCorr", 6, nullptr, &_lock);
const MACGrid *fractions = _args.getPtrOpt<MACGrid>("fractions", 7, nullptr, &_lock);
Real gfClamp = _args.getOpt<Real>("gfClamp", 8, 1e-04, &_lock);
Real cgMaxIterFac = _args.getOpt<Real>("cgMaxIterFac", 9, 1.5, &_lock);
bool precondition = _args.getOpt<bool>("precondition", 10, true, &_lock);
int preconditioner = _args.getOpt<int>("preconditioner", 11, PcMIC, &_lock);
const bool enforceCompatibility = _args.getOpt<bool>(
"enforceCompatibility", 12, false, &_lock);
const bool useL2Norm = _args.getOpt<bool>("useL2Norm", 13, false, &_lock);
const bool zeroPressureFixing = _args.getOpt<bool>("zeroPressureFixing", 14, false, &_lock);
const Grid<Real> *curv = _args.getPtrOpt<Grid<Real>>("curv", 15, nullptr, &_lock);
const Real surfTens = _args.getOpt<Real>("surfTens", 16, 0., &_lock);
_retval = getPyNone();
solvePressureSystem(rhs,
vel,
pressure,
flags,
cgAccuracy,
phi,
perCellCorr,
fractions,
gfClamp,
cgMaxIterFac,
precondition,
preconditioner,
enforceCompatibility,
useL2Norm,
zeroPressureFixing,
curv,
surfTens);
_args.check();
}
pbFinalizePlugin(parent, "solvePressureSystem", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("solvePressureSystem", e.what());
return 0;
}
}
static const Pb::Register _RP_solvePressureSystem("", "solvePressureSystem", _W_2);
extern "C" {
void PbRegister_solvePressureSystem()
{
KEEP_UNUSED(_RP_solvePressureSystem);
}
}
//! Apply pressure gradient to make velocity field divergence free
void correctVelocity(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,
Real gfClamp = 1e-04,
Real cgMaxIterFac = 1.5,
bool precondition = true,
int preconditioner = PcMIC,
bool enforceCompatibility = false,
bool useL2Norm = false,
bool zeroPressureFixing = false,
const Grid<Real> *curv = nullptr,
const Real surfTens = 0.)
{
knCorrectVelocity(flags, vel, pressure);
if (phi) {
knCorrectVelocityGhostFluid(vel, flags, pressure, *phi, gfClamp, curv, surfTens);
// improve behavior of clamping for large time steps:
knReplaceClampedGhostFluidVels(vel, flags, pressure, *phi, gfClamp);
}
}
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, "correctVelocity", !noTiming);
PyObject *_retval = nullptr;
{
ArgLocker _lock;
MACGrid &vel = *_args.getPtr<MACGrid>("vel", 0, &_lock);
Grid<Real> &pressure = *_args.getPtr<Grid<Real>>("pressure", 1, &_lock);
const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 2, &_lock);
Real cgAccuracy = _args.getOpt<Real>("cgAccuracy", 3, 1e-3, &_lock);
const Grid<Real> *phi = _args.getPtrOpt<Grid<Real>>("phi", 4, nullptr, &_lock);
const Grid<Real> *perCellCorr = _args.getPtrOpt<Grid<Real>>(
"perCellCorr", 5, nullptr, &_lock);
const MACGrid *fractions = _args.getPtrOpt<MACGrid>("fractions", 6, nullptr, &_lock);
Real gfClamp = _args.getOpt<Real>("gfClamp", 7, 1e-04, &_lock);
Real cgMaxIterFac = _args.getOpt<Real>("cgMaxIterFac", 8, 1.5, &_lock);
bool precondition = _args.getOpt<bool>("precondition", 9, true, &_lock);
int preconditioner = _args.getOpt<int>("preconditioner", 10, PcMIC, &_lock);
bool enforceCompatibility = _args.getOpt<bool>("enforceCompatibility", 11, false, &_lock);
bool useL2Norm = _args.getOpt<bool>("useL2Norm", 12, false, &_lock);
bool zeroPressureFixing = _args.getOpt<bool>("zeroPressureFixing", 13, false, &_lock);
const Grid<Real> *curv = _args.getPtrOpt<Grid<Real>>("curv", 14, nullptr, &_lock);
const Real surfTens = _args.getOpt<Real>("surfTens", 15, 0., &_lock);
_retval = getPyNone();
correctVelocity(vel,
pressure,
flags,
cgAccuracy,
phi,
perCellCorr,
fractions,
gfClamp,
cgMaxIterFac,
precondition,
preconditioner,
enforceCompatibility,
useL2Norm,
zeroPressureFixing,
curv,
surfTens);
_args.check();
}
pbFinalizePlugin(parent, "correctVelocity", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("correctVelocity", e.what());
return 0;
}
}
static const Pb::Register _RP_correctVelocity("", "correctVelocity", _W_3);
extern "C" {
void PbRegister_correctVelocity()
{
KEEP_UNUSED(_RP_correctVelocity);
}
}
//! Perform pressure projection of the velocity grid, calls
//! all three pressure helper functions in a row.
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 = PcMIC,
bool enforceCompatibility = false,
bool useL2Norm = false,
bool zeroPressureFixing = false,
const Grid<Real> *curv = nullptr,
const Real surfTens = 0.,
Grid<Real> *retRhs = nullptr)
{
Grid<Real> rhs(vel.getParent());
computePressureRhs(rhs,
vel,
pressure,
flags,
cgAccuracy,
phi,
perCellCorr,
fractions,
obvel,
gfClamp,
cgMaxIterFac,
precondition,
preconditioner,
enforceCompatibility,
useL2Norm,
zeroPressureFixing,
curv,
surfTens);
solvePressureSystem(rhs,
vel,
pressure,
flags,
cgAccuracy,
phi,
perCellCorr,
fractions,
gfClamp,
cgMaxIterFac,
precondition,
preconditioner,
enforceCompatibility,
useL2Norm,
zeroPressureFixing,
curv,
surfTens);
correctVelocity(vel,
pressure,
flags,
cgAccuracy,
phi,
perCellCorr,
fractions,
gfClamp,
cgMaxIterFac,
precondition,
preconditioner,
enforceCompatibility,
useL2Norm,
zeroPressureFixing,
curv,
surfTens);
// optionally , return RHS
if (retRhs) {
retRhs->copyFrom(rhs);
}
}
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, "solvePressure", !noTiming);
PyObject *_retval = nullptr;
{
ArgLocker _lock;
MACGrid &vel = *_args.getPtr<MACGrid>("vel", 0, &_lock);
Grid<Real> &pressure = *_args.getPtr<Grid<Real>>("pressure", 1, &_lock);
const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 2, &_lock);
Real cgAccuracy = _args.getOpt<Real>("cgAccuracy", 3, 1e-3, &_lock);
const Grid<Real> *phi = _args.getPtrOpt<Grid<Real>>("phi", 4, nullptr, &_lock);
const Grid<Real> *perCellCorr = _args.getPtrOpt<Grid<Real>>(
"perCellCorr", 5, nullptr, &_lock);
const MACGrid *fractions = _args.getPtrOpt<MACGrid>("fractions", 6, nullptr, &_lock);
const MACGrid *obvel = _args.getPtrOpt<MACGrid>("obvel", 7, nullptr, &_lock);
Real gfClamp = _args.getOpt<Real>("gfClamp", 8, 1e-04, &_lock);
Real cgMaxIterFac = _args.getOpt<Real>("cgMaxIterFac", 9, 1.5, &_lock);
bool precondition = _args.getOpt<bool>("precondition", 10, true, &_lock);
int preconditioner = _args.getOpt<int>("preconditioner", 11, PcMIC, &_lock);
bool enforceCompatibility = _args.getOpt<bool>("enforceCompatibility", 12, false, &_lock);
bool useL2Norm = _args.getOpt<bool>("useL2Norm", 13, false, &_lock);
bool zeroPressureFixing = _args.getOpt<bool>("zeroPressureFixing", 14, false, &_lock);
const Grid<Real> *curv = _args.getPtrOpt<Grid<Real>>("curv", 15, nullptr, &_lock);
const Real surfTens = _args.getOpt<Real>("surfTens", 16, 0., &_lock);
Grid<Real> *retRhs = _args.getPtrOpt<Grid<Real>>("retRhs", 17, nullptr, &_lock);
_retval = getPyNone();
solvePressure(vel,
pressure,
flags,
cgAccuracy,
phi,
perCellCorr,
fractions,
obvel,
gfClamp,
cgMaxIterFac,
precondition,
preconditioner,
enforceCompatibility,
useL2Norm,
zeroPressureFixing,
curv,
surfTens,
retRhs);
_args.check();
}
pbFinalizePlugin(parent, "solvePressure", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("solvePressure", e.what());
return 0;
}
}
static const Pb::Register _RP_solvePressure("", "solvePressure", _W_4);
extern "C" {
void PbRegister_solvePressure()
{
KEEP_UNUSED(_RP_solvePressure);
}
}
} // namespace Manta