// 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 using namespace std; namespace Manta { /****************************************************************************** * * explicit integration * ******************************************************************************/ struct knCalcSecDeriv2d : public KernelBase { knCalcSecDeriv2d(const Grid &v, Grid &ret) : KernelBase(&v, 1), v(v), ret(ret) { runMessage(); run(); } inline void op(int i, int j, int k, const Grid &v, Grid &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 &getArg0() { return v; } typedef Grid type0; inline Grid &getArg1() { return ret; } typedef Grid 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 &__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(minZ, maxZ), *this); else tbb::parallel_for(tbb::blocked_range(1, maxY), *this); } const Grid &v; Grid &ret; }; ; //! calculate a second derivative for the wave equation void calcSecDeriv2d(const Grid &v, Grid &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("notiming", -1, 0); pbPreparePlugin(parent, "calcSecDeriv2d", !noTiming); PyObject *_retval = 0; { ArgLocker _lock; const Grid &v = *_args.getPtr>("v", 0, &_lock); Grid &curv = *_args.getPtr>("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 &h) : KernelBase(&h, 1), h(h), sum(0) { runMessage(); run(); } inline void op(int i, int j, int k, Grid &h, double &sum) { sum += h(i, j, k); } inline operator double() { return sum; } inline double &getRet() { return sum; } inline Grid &getArg0() { return h; } typedef Grid 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 &__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(minZ, maxZ), *this); else tbb::parallel_reduce(tbb::blocked_range(1, maxY), *this); } knTotalSum(knTotalSum &o, tbb::split) : KernelBase(o), h(o.h), sum(0) { } void join(const knTotalSum &o) { sum += o.sum; } Grid &h; double sum; }; //! calculate the sum of all values in a grid (for wave equation solves) Real totalSum(Grid &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("notiming", -1, 0); pbPreparePlugin(parent, "totalSum", !noTiming); PyObject *_retval = 0; { ArgLocker _lock; Grid &height = *_args.getPtr>("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 &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("notiming", -1, 0); pbPreparePlugin(parent, "normalizeSumTo", !noTiming); PyObject *_retval = 0; { ArgLocker _lock; Grid &height = *_args.getPtr>("height", 0, &_lock); Real target = _args.get("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 &rhs, const Grid &ut, const Grid &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 &rhs, const Grid &ut, const Grid &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 &getArg1() { return rhs; } typedef Grid type1; inline const Grid &getArg2() { return ut; } typedef Grid type2; inline const Grid &getArg3() { return utm1; } typedef Grid 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 &__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(minZ, maxZ), *this); else tbb::parallel_for(tbb::blocked_range(1, maxY), *this); } const FlagGrid &flags; Grid &rhs; const Grid &ut; const Grid &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 &ut, Grid &utm1, Grid &out, bool crankNic = false, Real cSqr = 0.25, Real cgMaxIterFac = 1.5, Real cgAccuracy = 1e-5) { // reserve temp grids FluidSolver *parent = flags.getParent(); Grid rhs(parent); Grid residual(parent); Grid search(parent); Grid A0(parent); Grid Ai(parent); Grid Aj(parent); Grid Ak(parent); Grid 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; if (flags.is3D()) gcg = new GridCg(out, rhs, residual, search, flags, tmp, &A0, &Ai, &Aj, &Ak); else gcg = new GridCg(out, rhs, residual, search, flags, tmp, &A0, &Ai, &Aj, &Ak); 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("notiming", -1, 0); pbPreparePlugin(parent, "cgSolveWE", !noTiming); PyObject *_retval = 0; { ArgLocker _lock; const FlagGrid &flags = *_args.getPtr("flags", 0, &_lock); Grid &ut = *_args.getPtr>("ut", 1, &_lock); Grid &utm1 = *_args.getPtr>("utm1", 2, &_lock); Grid &out = *_args.getPtr>("out", 3, &_lock); bool crankNic = _args.getOpt("crankNic", 4, false, &_lock); Real cSqr = _args.getOpt("cSqr", 5, 0.25, &_lock); Real cgMaxIterFac = _args.getOpt("cgMaxIterFac", 6, 1.5, &_lock); Real cgAccuracy = _args.getOpt("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