// 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 * * Main class for the fluid solver * ******************************************************************************/ #include "fluidsolver.h" #include "grid.h" #include #include using namespace std; namespace Manta { //****************************************************************************** // Gridstorage-related members template void FluidSolver::GridStorage::free() { if (used != 0) errMsg("can't clean grid cache, some grids are still in use"); for (size_t i = 0; i < grids.size(); i++) delete[] grids[i]; grids.clear(); } template T *FluidSolver::GridStorage::get(Vec3i size) { if ((int)grids.size() <= used) { debMsg("FluidSolver::GridStorage::get Allocating new " << size.x << "," << size.y << "," << size.z << " ", 3); grids.push_back(new T[(long long)(size.x) * size.y * size.z]); } if (used > 200) errMsg("too many temp grids used -- are they released properly ?"); return grids[used++]; } template void FluidSolver::GridStorage::release(T *ptr) { // rewrite pointer, as it may have changed due to swap operations used--; if (used < 0) errMsg("temp grid inconsistency"); grids[used] = ptr; } template<> int *FluidSolver::getGridPointer() { return mGridsInt.get(mGridSize); } template<> Real *FluidSolver::getGridPointer() { return mGridsReal.get(mGridSize); } template<> Vec3 *FluidSolver::getGridPointer() { return mGridsVec.get(mGridSize); } template<> Vec4 *FluidSolver::getGridPointer() { return mGridsVec4.get(mGridSize); } template<> void FluidSolver::freeGridPointer(int *ptr) { mGridsInt.release(ptr); } template<> void FluidSolver::freeGridPointer(Real *ptr) { mGridsReal.release(ptr); } template<> void FluidSolver::freeGridPointer(Vec3 *ptr) { mGridsVec.release(ptr); } template<> void FluidSolver::freeGridPointer(Vec4 *ptr) { mGridsVec4.release(ptr); } // 4d data (work around for now, convert to 1d length) template<> int *FluidSolver::getGrid4dPointer() { return mGrids4dInt.get(Vec3i(mGridSize[0] * mGridSize[1], mGridSize[2], mFourthDim)); } template<> Real *FluidSolver::getGrid4dPointer() { return mGrids4dReal.get(Vec3i(mGridSize[0] * mGridSize[1], mGridSize[2], mFourthDim)); } template<> Vec3 *FluidSolver::getGrid4dPointer() { return mGrids4dVec.get(Vec3i(mGridSize[0] * mGridSize[1], mGridSize[2], mFourthDim)); } template<> Vec4 *FluidSolver::getGrid4dPointer() { return mGrids4dVec4.get(Vec3i(mGridSize[0] * mGridSize[1], mGridSize[2], mFourthDim)); } template<> void FluidSolver::freeGrid4dPointer(int *ptr) { mGrids4dInt.release(ptr); } template<> void FluidSolver::freeGrid4dPointer(Real *ptr) { mGrids4dReal.release(ptr); } template<> void FluidSolver::freeGrid4dPointer(Vec3 *ptr) { mGrids4dVec.release(ptr); } template<> void FluidSolver::freeGrid4dPointer(Vec4 *ptr) { mGrids4dVec4.release(ptr); } //****************************************************************************** // FluidSolver members FluidSolver::FluidSolver(Vec3i gridsize, int dim, int fourthDim) : PbClass(this), mDt(1.0), mTimeTotal(0.), mFrame(0), mCflCond(1000), mDtMin(1.), mDtMax(1.), mFrameLength(1.), mTimePerFrame(0.), mGridSize(gridsize), mDim(dim), mLockDt(false), mFourthDim(fourthDim) { if (dim == 4 && mFourthDim > 0) errMsg("Don't create 4D solvers, use 3D with fourth-dim parameter >0 instead."); assertMsg(dim == 2 || dim == 3, "Only 2D and 3D solvers allowed."); assertMsg(dim != 2 || gridsize.z == 1, "Trying to create 2D solver with size.z != 1"); } FluidSolver::~FluidSolver() { mGridsInt.free(); mGridsReal.free(); mGridsVec.free(); mGridsVec4.free(); mGrids4dInt.free(); mGrids4dReal.free(); mGrids4dVec.free(); mGrids4dVec4.free(); } PbClass *FluidSolver::create(PbType t, PbTypeVec T, const string &name) { #if NOPYTHON != 1 _args.add("nocheck", true); if (t.str() == "") errMsg( "Need to specify object type. Use e.g. Solver.create(FlagGrid, ...) or " "Solver.create(type=FlagGrid, ...)"); PbClass *ret = PbClass::createPyObject(t.str() + T.str(), name, _args, this); #else PbClass *ret = NULL; #endif return ret; } void FluidSolver::step() { // update simulation time with adaptive time stepping // (use eps value to prevent roundoff errors) mTimePerFrame += mDt; mTimeTotal += mDt; if ((mTimePerFrame + VECTOR_EPSILON) > mFrameLength) { mFrame++; // re-calc total time, prevent drift... mTimeTotal = (double)mFrame * mFrameLength; mTimePerFrame = 0.; mLockDt = false; } updateQtGui(true, mFrame, mTimeTotal, "FluidSolver::step"); } void FluidSolver::printMemInfo() { std::ostringstream msg; msg << "Allocated grids: int " << mGridsInt.used << "/" << mGridsInt.grids.size() << ", "; msg << " real " << mGridsReal.used << "/" << mGridsReal.grids.size() << ", "; msg << " vec3 " << mGridsVec.used << "/" << mGridsVec.grids.size() << ". "; msg << " vec4 " << mGridsVec4.used << "/" << mGridsVec4.grids.size() << ". "; if (supports4D()) { msg << "Allocated 4d grids: int " << mGrids4dInt.used << "/" << mGrids4dInt.grids.size() << ", "; msg << " real " << mGrids4dReal.used << "/" << mGrids4dReal.grids.size() << ", "; msg << " vec3 " << mGrids4dVec.used << "/" << mGrids4dVec.grids.size() << ". "; msg << " vec4 " << mGrids4dVec4.used << "/" << mGrids4dVec4.grids.size() << ". "; } printf("%s\n", msg.str().c_str()); } //! warning, uses 10^-4 epsilon values, thus only use around "regular" FPS time scales, e.g. 30 //! frames per time unit pass max magnitude of current velocity as maxvel, not yet scaled by dt! void FluidSolver::adaptTimestep(Real maxVel) { const Real mvt = maxVel * mDt; if (!mLockDt) { // calculate current timestep from maxvel, clamp range mDt = std::max(std::min(mDt * (Real)(mCflCond / (mvt + 1e-05)), mDtMax), mDtMin); if ((mTimePerFrame + mDt * 1.05) > mFrameLength) { // within 5% of full step? add epsilon to prevent roundoff errors... mDt = (mFrameLength - mTimePerFrame) + 1e-04; } else if ((mTimePerFrame + mDt + mDtMin) > mFrameLength || (mTimePerFrame + (mDt * 1.25)) > mFrameLength) { // avoid tiny timesteps and strongly varying ones, do 2 medium size ones if necessary... mDt = (mFrameLength - mTimePerFrame + 1e-04) * 0.5; mLockDt = true; } } debMsg("Frame " << mFrame << ", max vel per step: " << mvt << " , dt: " << mDt << ", frame time " << mTimePerFrame << "/" << mFrameLength << "; lock:" << mLockDt, 2); // sanity check assertMsg((mDt > (mDtMin / 2.)), "Invalid dt encountered! Shouldnt happen..."); } //****************************************************************************** // Generic helpers (no PYTHON funcs in general.cpp, thus they're here...) //! helper to unify printing from python scripts and printing internal messages (optionally pass //! debug level to control amount of output) void mantaMsg(const std::string &out, int level = 1) { debMsg(out, level); } 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, "mantaMsg", !noTiming); PyObject *_retval = 0; { ArgLocker _lock; const std::string &out = _args.get("out", 0, &_lock); int level = _args.getOpt("level", 1, 1, &_lock); _retval = getPyNone(); mantaMsg(out, level); _args.check(); } pbFinalizePlugin(parent, "mantaMsg", !noTiming); return _retval; } catch (std::exception &e) { pbSetError("mantaMsg", e.what()); return 0; } } static const Pb::Register _RP_mantaMsg("", "mantaMsg", _W_0); extern "C" { void PbRegister_mantaMsg() { KEEP_UNUSED(_RP_mantaMsg); } } std::string printBuildInfo() { string infoString = buildInfoString(); debMsg("Build info: " << infoString.c_str() << " ", 1); return infoString; } 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, "printBuildInfo", !noTiming); PyObject *_retval = 0; { ArgLocker _lock; _retval = toPy(printBuildInfo()); _args.check(); } pbFinalizePlugin(parent, "printBuildInfo", !noTiming); return _retval; } catch (std::exception &e) { pbSetError("printBuildInfo", e.what()); return 0; } } static const Pb::Register _RP_printBuildInfo("", "printBuildInfo", _W_1); extern "C" { void PbRegister_printBuildInfo() { KEEP_UNUSED(_RP_printBuildInfo); } } //! set debug level for messages (0 off, 1 regular, higher = more, up to 10) void setDebugLevel(int level = 1) { gDebugLevel = level; } 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, "setDebugLevel", !noTiming); PyObject *_retval = 0; { ArgLocker _lock; int level = _args.getOpt("level", 0, 1, &_lock); _retval = getPyNone(); setDebugLevel(level); _args.check(); } pbFinalizePlugin(parent, "setDebugLevel", !noTiming); return _retval; } catch (std::exception &e) { pbSetError("setDebugLevel", e.what()); return 0; } } static const Pb::Register _RP_setDebugLevel("", "setDebugLevel", _W_2); extern "C" { void PbRegister_setDebugLevel() { KEEP_UNUSED(_RP_setDebugLevel); } } //! helper function to check for numpy compilation void assertNumpy() { #if NUMPY == 1 // all good, nothing to do... #else errMsg("This scene requires numpy support. Enable compilation in cmake with \"-DNUMPY=1\" "); #endif } 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, "assertNumpy", !noTiming); PyObject *_retval = 0; { ArgLocker _lock; _retval = getPyNone(); assertNumpy(); _args.check(); } pbFinalizePlugin(parent, "assertNumpy", !noTiming); return _retval; } catch (std::exception &e) { pbSetError("assertNumpy", e.what()); return 0; } } static const Pb::Register _RP_assertNumpy("", "assertNumpy", _W_3); extern "C" { void PbRegister_assertNumpy() { KEEP_UNUSED(_RP_assertNumpy); } } } // namespace Manta