Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'extern/mantaflow/preprocessed/plugin/fluidguiding.cpp')
-rw-r--r--extern/mantaflow/preprocessed/plugin/fluidguiding.cpp802
1 files changed, 802 insertions, 0 deletions
diff --git a/extern/mantaflow/preprocessed/plugin/fluidguiding.cpp b/extern/mantaflow/preprocessed/plugin/fluidguiding.cpp
new file mode 100644
index 00000000000..13383581123
--- /dev/null
+++ b/extern/mantaflow/preprocessed/plugin/fluidguiding.cpp
@@ -0,0 +1,802 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Plugins for pressure correction: solve_pressure, and ghost fluid helpers
+ *
+ ******************************************************************************/
+#include "vectorbase.h"
+#include "grid.h"
+#include "kernel.h"
+#include "conjugategrad.h"
+#include "rcmatrix.h"
+
+using namespace std;
+namespace Manta {
+
+// only supports a single blur size for now, globals stored here
+bool gBlurPrecomputed = false;
+int gBlurKernelRadius = -1;
+Matrix gBlurKernel;
+
+// *****************************************************************************
+// Helper functions for fluid guiding
+
+//! creates a 1D (horizontal) Gaussian blur kernel of size n and standard deviation sigma
+Matrix get1DGaussianBlurKernel(const int n, const int sigma)
+{
+ Matrix x(n), y(n);
+ for (int j = 0; j < n; j++) {
+ x.add_to_element(0, j, -(n - 1) * 0.5);
+ y.add_to_element(0, j, j - (n - 1) * 0.5);
+ }
+ Matrix G(n);
+ Real sumG = 0;
+ for (int j = 0; j < n; j++) {
+ G.add_to_element(0,
+ j,
+ 1 / (2 * M_PI * sigma * sigma) *
+ exp(-(x(0, j) * x(0, j) + y(0, j) * y(0, j)) / (2 * sigma * sigma)));
+ sumG += G(0, j);
+ }
+ G = G * (1.0 / sumG);
+ return G;
+}
+
+//! convolves in with 1D kernel (centred at the kernel's midpoint) in the x-direction
+//! (out must be a grid of zeros)
+struct apply1DKernelDirX : public KernelBase {
+ apply1DKernelDirX(const MACGrid &in, MACGrid &out, const Matrix &kernel)
+ : KernelBase(&in, 0), in(in), out(out), kernel(kernel)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i, int j, int k, const MACGrid &in, MACGrid &out, const Matrix &kernel) const
+ {
+ int nx = in.getSizeX();
+ int kn = kernel.n;
+ int kCentre = kn / 2;
+ for (int m = 0, ind = kn - 1, ii = i - kCentre; m < kn; m++, ind--, ii++) {
+ if (ii < 0)
+ continue;
+ else if (ii >= nx)
+ break;
+ else
+ out(i, j, k) += in(ii, j, k) * kernel(0, ind);
+ }
+ }
+ inline const MACGrid &getArg0()
+ {
+ return in;
+ }
+ typedef MACGrid type0;
+ inline MACGrid &getArg1()
+ {
+ return out;
+ }
+ typedef MACGrid type1;
+ inline const Matrix &getArg2()
+ {
+ return kernel;
+ }
+ typedef Matrix type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel apply1DKernelDirX ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, in, out, kernel);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, in, out, kernel);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ const MACGrid &in;
+ MACGrid &out;
+ const Matrix &kernel;
+};
+
+//! convolves in with 1D kernel (centred at the kernel's midpoint) in the y-direction
+//! (out must be a grid of zeros)
+struct apply1DKernelDirY : public KernelBase {
+ apply1DKernelDirY(const MACGrid &in, MACGrid &out, const Matrix &kernel)
+ : KernelBase(&in, 0), in(in), out(out), kernel(kernel)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i, int j, int k, const MACGrid &in, MACGrid &out, const Matrix &kernel) const
+ {
+ int ny = in.getSizeY();
+ int kn = kernel.n;
+ int kCentre = kn / 2;
+ for (int m = 0, ind = kn - 1, jj = j - kCentre; m < kn; m++, ind--, jj++) {
+ if (jj < 0)
+ continue;
+ else if (jj >= ny)
+ break;
+ else
+ out(i, j, k) += in(i, jj, k) * kernel(0, ind);
+ }
+ }
+ inline const MACGrid &getArg0()
+ {
+ return in;
+ }
+ typedef MACGrid type0;
+ inline MACGrid &getArg1()
+ {
+ return out;
+ }
+ typedef MACGrid type1;
+ inline const Matrix &getArg2()
+ {
+ return kernel;
+ }
+ typedef Matrix type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel apply1DKernelDirY ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, in, out, kernel);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, in, out, kernel);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ const MACGrid &in;
+ MACGrid &out;
+ const Matrix &kernel;
+};
+
+//! convolves in with 1D kernel (centred at the kernel's midpoint) in the z-direction
+//! (out must be a grid of zeros)
+struct apply1DKernelDirZ : public KernelBase {
+ apply1DKernelDirZ(const MACGrid &in, MACGrid &out, const Matrix &kernel)
+ : KernelBase(&in, 0), in(in), out(out), kernel(kernel)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i, int j, int k, const MACGrid &in, MACGrid &out, const Matrix &kernel) const
+ {
+ int nz = in.getSizeZ();
+ int kn = kernel.n;
+ int kCentre = kn / 2;
+ for (int m = 0, ind = kn - 1, kk = k - kCentre; m < kn; m++, ind--, kk++) {
+ if (kk < 0)
+ continue;
+ else if (kk >= nz)
+ break;
+ else
+ out(i, j, k) += in(i, j, kk) * kernel(0, ind);
+ }
+ }
+ inline const MACGrid &getArg0()
+ {
+ return in;
+ }
+ typedef MACGrid type0;
+ inline MACGrid &getArg1()
+ {
+ return out;
+ }
+ typedef MACGrid type1;
+ inline const Matrix &getArg2()
+ {
+ return kernel;
+ }
+ typedef Matrix type2;
+ void runMessage()
+ {
+ debMsg("Executing kernel apply1DKernelDirZ ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 0; j < _maxY; j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, in, out, kernel);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 0; i < _maxX; i++)
+ op(i, j, k, in, out, kernel);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
+ }
+ const MACGrid &in;
+ MACGrid &out;
+ const Matrix &kernel;
+};
+
+//! Apply separable Gaussian blur in 2D
+void applySeparableKernel2D(MACGrid &grid, const FlagGrid &flags, const Matrix &kernel)
+{
+ // int nx = grid.getSizeX(), ny = grid.getSizeY();
+ // int kn = kernel.n;
+ // int kCentre = kn / 2;
+ FluidSolver *parent = grid.getParent();
+ MACGrid orig = MACGrid(parent);
+ orig.copyFrom(grid);
+ MACGrid gridX = MACGrid(parent);
+ apply1DKernelDirX(grid, gridX, kernel);
+ MACGrid gridXY = MACGrid(parent);
+ apply1DKernelDirY(gridX, gridXY, kernel);
+ grid.copyFrom(gridXY);
+ FOR_IJK(grid)
+ {
+ if ((i > 0 && flags.isObstacle(i - 1, j, k)) || (j > 0 && flags.isObstacle(i, j - 1, k)) ||
+ flags.isObstacle(i, j, k)) {
+ grid(i, j, k).x = orig(i, j, k).x;
+ grid(i, j, k).y = orig(i, j, k).y;
+ grid(i, j, k).z = orig(i, j, k).z;
+ }
+ }
+}
+
+//! Apply separable Gaussian blur in 3D
+void applySeparableKernel3D(MACGrid &grid, const FlagGrid &flags, const Matrix &kernel)
+{
+ // int nx = grid.getSizeX(), ny = grid.getSizeY(), nz = grid.getSizeZ();
+ // int kn = kernel.n;
+ // int kCentre = kn / 2;
+ FluidSolver *parent = grid.getParent();
+ MACGrid orig = MACGrid(parent);
+ orig.copyFrom(grid);
+ MACGrid gridX = MACGrid(parent);
+ apply1DKernelDirX(grid, gridX, kernel);
+ MACGrid gridXY = MACGrid(parent);
+ apply1DKernelDirY(gridX, gridXY, kernel);
+ MACGrid gridXYZ = MACGrid(parent);
+ apply1DKernelDirZ(gridXY, gridXYZ, kernel);
+ grid.copyFrom(gridXYZ);
+ FOR_IJK(grid)
+ {
+ if ((i > 0 && flags.isObstacle(i - 1, j, k)) || (j > 0 && flags.isObstacle(i, j - 1, k)) ||
+ (k > 0 && flags.isObstacle(i, j, k - 1)) || flags.isObstacle(i, j, k)) {
+ grid(i, j, k).x = orig(i, j, k).x;
+ grid(i, j, k).y = orig(i, j, k).y;
+ grid(i, j, k).z = orig(i, j, k).z;
+ }
+ }
+}
+
+//! Apply separable Gaussian blur in 2D or 3D depending on input dimensions
+void applySeparableKernel(MACGrid &grid, const FlagGrid &flags, const Matrix &kernel)
+{
+ if (!grid.is3D())
+ applySeparableKernel2D(grid, flags, kernel);
+ else
+ applySeparableKernel3D(grid, flags, kernel);
+}
+
+//! Compute r-norm for the stopping criterion
+Real getRNorm(const MACGrid &x, const MACGrid &z)
+{
+ MACGrid r = MACGrid(x.getParent());
+ r.copyFrom(x);
+ r.sub(z);
+ return r.getMaxAbs();
+}
+
+//! Compute s-norm for the stopping criterion
+Real getSNorm(const Real rho, const MACGrid &z, const MACGrid &z_prev)
+{
+ MACGrid s = MACGrid(z_prev.getParent());
+ s.copyFrom(z_prev);
+ s.sub(z);
+ s.multConst(rho);
+ return s.getMaxAbs();
+}
+
+//! Compute primal eps for the stopping criterion
+Real getEpsPri(const Real eps_abs, const Real eps_rel, const MACGrid &x, const MACGrid &z)
+{
+ Real max_norm = max(x.getMaxAbs(), z.getMaxAbs());
+ Real eps_pri = sqrt(x.is3D() ? 3.0 : 2.0) * eps_abs + eps_rel * max_norm;
+ return eps_pri;
+}
+
+//! Compute dual eps for the stopping criterion
+Real getEpsDual(const Real eps_abs, const Real eps_rel, const MACGrid &y)
+{
+ Real eps_dual = sqrt(y.is3D() ? 3.0 : 2.0) * eps_abs + eps_rel * y.getMaxAbs();
+ return eps_dual;
+}
+
+//! Create a spiral velocity field in 2D as a test scene (optionally in 3D)
+void getSpiralVelocity(const FlagGrid &flags,
+ MACGrid &vel,
+ Real strength = 1.0,
+ bool with3D = false)
+{
+ int nx = flags.getSizeX(), ny = flags.getSizeY(), nz = 1;
+ if (with3D)
+ nz = flags.getSizeZ();
+ Real midX = 0.5 * (Real)(nx - 1);
+ Real midY = 0.5 * (Real)(ny - 1);
+ Real midZ = 0.5 * (Real)(nz - 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 = 0;
+ {
+ 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 = 0;
+ {
+ 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 = 0,
+ const Grid<Real> *perCellCorr = 0,
+ const MACGrid *fractions = 0,
+ const MACGrid *obvel = 0,
+ 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 = NULL,
+ const Real surfTens = 0.0,
+ Grid<Real> *retRhs = NULL);
+
+//! 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 = 0,
+ Grid<Real> *perCellCorr = 0,
+ MACGrid *fractions = 0,
+ MACGrid *obvel = 0,
+ Real gfClamp = 1e-04,
+ Real cgMaxIterFac = 1.5,
+ Real cgAccuracy = 1e-3,
+ int preconditioner = 1,
+ bool zeroPressureFixing = false,
+ const Grid<Real> *curv = NULL,
+ 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 = 0;
+ {
+ 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, 0, &_lock);
+ Grid<Real> *perCellCorr = _args.getPtrOpt<Grid<Real>>("perCellCorr", 13, 0, &_lock);
+ MACGrid *fractions = _args.getPtrOpt<MACGrid>("fractions", 14, 0, &_lock);
+ MACGrid *obvel = _args.getPtrOpt<MACGrid>("obvel", 15, 0, &_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, NULL, &_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 = 0;
+ {
+ 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