forked from bartvdbraak/blender
311031ecd0
Switched from NULL to nullptr.
398 lines
11 KiB
C++
398 lines
11 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
|
|
*
|
|
* Main class for the fluid solver
|
|
*
|
|
******************************************************************************/
|
|
|
|
#include "fluidsolver.h"
|
|
#include "grid.h"
|
|
#include <sstream>
|
|
#include <fstream>
|
|
|
|
using namespace std;
|
|
namespace Manta {
|
|
|
|
//******************************************************************************
|
|
// Gridstorage-related members
|
|
|
|
template<class T> void FluidSolver::GridStorage<T>::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<class T> T *FluidSolver::GridStorage<T>::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<class T> void FluidSolver::GridStorage<T>::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<int>()
|
|
{
|
|
return mGridsInt.get(mGridSize);
|
|
}
|
|
template<> Real *FluidSolver::getGridPointer<Real>()
|
|
{
|
|
return mGridsReal.get(mGridSize);
|
|
}
|
|
template<> Vec3 *FluidSolver::getGridPointer<Vec3>()
|
|
{
|
|
return mGridsVec.get(mGridSize);
|
|
}
|
|
template<> Vec4 *FluidSolver::getGridPointer<Vec4>()
|
|
{
|
|
return mGridsVec4.get(mGridSize);
|
|
}
|
|
template<> void FluidSolver::freeGridPointer<int>(int *ptr)
|
|
{
|
|
mGridsInt.release(ptr);
|
|
}
|
|
template<> void FluidSolver::freeGridPointer<Real>(Real *ptr)
|
|
{
|
|
mGridsReal.release(ptr);
|
|
}
|
|
template<> void FluidSolver::freeGridPointer<Vec3>(Vec3 *ptr)
|
|
{
|
|
mGridsVec.release(ptr);
|
|
}
|
|
template<> void FluidSolver::freeGridPointer<Vec4>(Vec4 *ptr)
|
|
{
|
|
mGridsVec4.release(ptr);
|
|
}
|
|
|
|
// 4d data (work around for now, convert to 1d length)
|
|
|
|
template<> int *FluidSolver::getGrid4dPointer<int>()
|
|
{
|
|
return mGrids4dInt.get(Vec3i(mGridSize[0] * mGridSize[1], mGridSize[2], mFourthDim));
|
|
}
|
|
template<> Real *FluidSolver::getGrid4dPointer<Real>()
|
|
{
|
|
return mGrids4dReal.get(Vec3i(mGridSize[0] * mGridSize[1], mGridSize[2], mFourthDim));
|
|
}
|
|
template<> Vec3 *FluidSolver::getGrid4dPointer<Vec3>()
|
|
{
|
|
return mGrids4dVec.get(Vec3i(mGridSize[0] * mGridSize[1], mGridSize[2], mFourthDim));
|
|
}
|
|
template<> Vec4 *FluidSolver::getGrid4dPointer<Vec4>()
|
|
{
|
|
return mGrids4dVec4.get(Vec3i(mGridSize[0] * mGridSize[1], mGridSize[2], mFourthDim));
|
|
}
|
|
template<> void FluidSolver::freeGrid4dPointer<int>(int *ptr)
|
|
{
|
|
mGrids4dInt.release(ptr);
|
|
}
|
|
template<> void FluidSolver::freeGrid4dPointer<Real>(Real *ptr)
|
|
{
|
|
mGrids4dReal.release(ptr);
|
|
}
|
|
template<> void FluidSolver::freeGrid4dPointer<Vec3>(Vec3 *ptr)
|
|
{
|
|
mGrids4dVec.release(ptr);
|
|
}
|
|
template<> void FluidSolver::freeGrid4dPointer<Vec4>(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 = nullptr;
|
|
#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<bool>("notiming", -1, 0);
|
|
pbPreparePlugin(parent, "mantaMsg", !noTiming);
|
|
PyObject *_retval = nullptr;
|
|
{
|
|
ArgLocker _lock;
|
|
const std::string &out = _args.get<std::string>("out", 0, &_lock);
|
|
int level = _args.getOpt<int>("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<bool>("notiming", -1, 0);
|
|
pbPreparePlugin(parent, "printBuildInfo", !noTiming);
|
|
PyObject *_retval = nullptr;
|
|
{
|
|
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<bool>("notiming", -1, 0);
|
|
pbPreparePlugin(parent, "setDebugLevel", !noTiming);
|
|
PyObject *_retval = nullptr;
|
|
{
|
|
ArgLocker _lock;
|
|
int level = _args.getOpt<int>("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<bool>("notiming", -1, 0);
|
|
pbPreparePlugin(parent, "assertNumpy", !noTiming);
|
|
PyObject *_retval = nullptr;
|
|
{
|
|
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
|