diff options
Diffstat (limited to 'extern/mantaflow/preprocessed/grid.cpp')
-rw-r--r-- | extern/mantaflow/preprocessed/grid.cpp | 2939 |
1 files changed, 2939 insertions, 0 deletions
diff --git a/extern/mantaflow/preprocessed/grid.cpp b/extern/mantaflow/preprocessed/grid.cpp new file mode 100644 index 00000000000..c21d56d8879 --- /dev/null +++ b/extern/mantaflow/preprocessed/grid.cpp @@ -0,0 +1,2939 @@ + + +// 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 + * + * Grid representation + * + ******************************************************************************/ + +#include "grid.h" +#include "levelset.h" +#include "kernel.h" +#include "mantaio.h" +#include <limits> +#include <sstream> +#include <cstring> + +#include "commonkernels.h" + +using namespace std; +namespace Manta { + +//****************************************************************************** +// GridBase members + +GridBase::GridBase(FluidSolver *parent) : PbClass(parent), mType(TypeNone) +{ + checkParent(); + m3D = getParent()->is3D(); +} + +//****************************************************************************** +// Grid<T> members + +// helpers to set type +template<class T> inline GridBase::GridType typeList() +{ + return GridBase::TypeNone; +} +template<> inline GridBase::GridType typeList<Real>() +{ + return GridBase::TypeReal; +} +template<> inline GridBase::GridType typeList<int>() +{ + return GridBase::TypeInt; +} +template<> inline GridBase::GridType typeList<Vec3>() +{ + return GridBase::TypeVec3; +} + +template<class T> +Grid<T>::Grid(FluidSolver *parent, bool show) : GridBase(parent), externalData(false) +{ + mType = typeList<T>(); + mSize = parent->getGridSize(); + mData = parent->getGridPointer<T>(); + + mStrideZ = parent->is2D() ? 0 : (mSize.x * mSize.y); + mDx = 1.0 / mSize.max(); + clear(); + setHidden(!show); +} + +template<class T> +Grid<T>::Grid(FluidSolver *parent, T *data, bool show) + : GridBase(parent), mData(data), externalData(true) +{ + mType = typeList<T>(); + mSize = parent->getGridSize(); + + mStrideZ = parent->is2D() ? 0 : (mSize.x * mSize.y); + mDx = 1.0 / mSize.max(); + + setHidden(!show); +} + +template<class T> Grid<T>::Grid(const Grid<T> &a) : GridBase(a.getParent()), externalData(false) +{ + mSize = a.mSize; + mType = a.mType; + mStrideZ = a.mStrideZ; + mDx = a.mDx; + FluidSolver *gp = a.getParent(); + mData = gp->getGridPointer<T>(); + memcpy(mData, a.mData, sizeof(T) * a.mSize.x * a.mSize.y * a.mSize.z); +} + +template<class T> Grid<T>::~Grid() +{ + if (!externalData) { + mParent->freeGridPointer<T>(mData); + } +} + +template<class T> void Grid<T>::clear() +{ + memset(mData, 0, sizeof(T) * mSize.x * mSize.y * mSize.z); +} + +template<class T> void Grid<T>::swap(Grid<T> &other) +{ + if (other.getSizeX() != getSizeX() || other.getSizeY() != getSizeY() || + other.getSizeZ() != getSizeZ()) + errMsg("Grid::swap(): Grid dimensions mismatch."); + + if (externalData || other.externalData) + errMsg("Grid::swap(): Cannot swap if one grid stores externalData."); + + T *dswap = other.mData; + other.mData = mData; + mData = dswap; +} + +template<class T> void Grid<T>::load(string name) +{ + if (name.find_last_of('.') == string::npos) + errMsg("file '" + name + "' does not have an extension"); + string ext = name.substr(name.find_last_of('.')); + if (ext == ".raw") + readGridRaw(name, this); + else if (ext == ".uni") + readGridUni(name, this); + else if (ext == ".vol") + readGridVol(name, this); + else if (ext == ".npz") + readGridNumpy(name, this); +#if OPENVDB == 1 + else if (ext == ".vdb") + readGridVDB(name, this); +#endif // OPENVDB==1 + else + errMsg("file '" + name + "' filetype not supported"); +} + +template<class T> void Grid<T>::save(string name) +{ + if (name.find_last_of('.') == string::npos) + errMsg("file '" + name + "' does not have an extension"); + string ext = name.substr(name.find_last_of('.')); + if (ext == ".raw") + writeGridRaw(name, this); + else if (ext == ".uni") + writeGridUni(name, this); + else if (ext == ".vol") + writeGridVol(name, this); +#if OPENVDB == 1 + else if (ext == ".vdb") + writeGridVDB(name, this); +#endif // OPENVDB==1 + else if (ext == ".npz") + writeGridNumpy(name, this); + else if (ext == ".txt") + writeGridTxt(name, this); + else + errMsg("file '" + name + "' filetype not supported"); +} + +//****************************************************************************** +// Grid<T> operators + +//! Kernel: Compute min value of Real grid + +struct CompMinReal : public KernelBase { + CompMinReal(const Grid<Real> &val) + : KernelBase(&val, 0), val(val), minVal(std::numeric_limits<Real>::max()) + { + runMessage(); + run(); + } + inline void op(IndexInt idx, const Grid<Real> &val, Real &minVal) + { + if (val[idx] < minVal) + minVal = val[idx]; + } + inline operator Real() + { + return minVal; + } + inline Real &getRet() + { + return minVal; + } + inline const Grid<Real> &getArg0() + { + return val; + } + typedef Grid<Real> type0; + void runMessage() + { + debMsg("Executing kernel CompMinReal ", 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, val, minVal); + } + void run() + { + tbb::parallel_reduce(tbb::blocked_range<IndexInt>(0, size), *this); + } + CompMinReal(CompMinReal &o, tbb::split) + : KernelBase(o), val(o.val), minVal(std::numeric_limits<Real>::max()) + { + } + void join(const CompMinReal &o) + { + minVal = min(minVal, o.minVal); + } + const Grid<Real> &val; + Real minVal; +}; + +//! Kernel: Compute max value of Real grid + +struct CompMaxReal : public KernelBase { + CompMaxReal(const Grid<Real> &val) + : KernelBase(&val, 0), val(val), maxVal(-std::numeric_limits<Real>::max()) + { + runMessage(); + run(); + } + inline void op(IndexInt idx, const Grid<Real> &val, Real &maxVal) + { + if (val[idx] > maxVal) + maxVal = val[idx]; + } + inline operator Real() + { + return maxVal; + } + inline Real &getRet() + { + return maxVal; + } + inline const Grid<Real> &getArg0() + { + return val; + } + typedef Grid<Real> type0; + void runMessage() + { + debMsg("Executing kernel CompMaxReal ", 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, val, maxVal); + } + void run() + { + tbb::parallel_reduce(tbb::blocked_range<IndexInt>(0, size), *this); + } + CompMaxReal(CompMaxReal &o, tbb::split) + : KernelBase(o), val(o.val), maxVal(-std::numeric_limits<Real>::max()) + { + } + void join(const CompMaxReal &o) + { + maxVal = max(maxVal, o.maxVal); + } + const Grid<Real> &val; + Real maxVal; +}; + +//! Kernel: Compute min value of int grid + +struct CompMinInt : public KernelBase { + CompMinInt(const Grid<int> &val) + : KernelBase(&val, 0), val(val), minVal(std::numeric_limits<int>::max()) + { + runMessage(); + run(); + } + inline void op(IndexInt idx, const Grid<int> &val, int &minVal) + { + if (val[idx] < minVal) + minVal = val[idx]; + } + inline operator int() + { + return minVal; + } + inline int &getRet() + { + return minVal; + } + inline const Grid<int> &getArg0() + { + return val; + } + typedef Grid<int> type0; + void runMessage() + { + debMsg("Executing kernel CompMinInt ", 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, val, minVal); + } + void run() + { + tbb::parallel_reduce(tbb::blocked_range<IndexInt>(0, size), *this); + } + CompMinInt(CompMinInt &o, tbb::split) + : KernelBase(o), val(o.val), minVal(std::numeric_limits<int>::max()) + { + } + void join(const CompMinInt &o) + { + minVal = min(minVal, o.minVal); + } + const Grid<int> &val; + int minVal; +}; + +//! Kernel: Compute max value of int grid + +struct CompMaxInt : public KernelBase { + CompMaxInt(const Grid<int> &val) + : KernelBase(&val, 0), val(val), maxVal(-std::numeric_limits<int>::max()) + { + runMessage(); + run(); + } + inline void op(IndexInt idx, const Grid<int> &val, int &maxVal) + { + if (val[idx] > maxVal) + maxVal = val[idx]; + } + inline operator int() + { + return maxVal; + } + inline int &getRet() + { + return maxVal; + } + inline const Grid<int> &getArg0() + { + return val; + } + typedef Grid<int> type0; + void runMessage() + { + debMsg("Executing kernel CompMaxInt ", 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, val, maxVal); + } + void run() + { + tbb::parallel_reduce(tbb::blocked_range<IndexInt>(0, size), *this); + } + CompMaxInt(CompMaxInt &o, tbb::split) + : KernelBase(o), val(o.val), maxVal(-std::numeric_limits<int>::max()) + { + } + void join(const CompMaxInt &o) + { + maxVal = max(maxVal, o.maxVal); + } + const Grid<int> &val; + int maxVal; +}; + +//! Kernel: Compute min norm of vec grid + +struct CompMinVec : public KernelBase { + CompMinVec(const Grid<Vec3> &val) + : KernelBase(&val, 0), val(val), minVal(std::numeric_limits<Real>::max()) + { + runMessage(); + run(); + } + inline void op(IndexInt idx, const Grid<Vec3> &val, Real &minVal) + { + const Real s = normSquare(val[idx]); + if (s < minVal) + minVal = s; + } + inline operator Real() + { + return minVal; + } + inline Real &getRet() + { + return minVal; + } + inline const Grid<Vec3> &getArg0() + { + return val; + } + typedef Grid<Vec3> type0; + void runMessage() + { + debMsg("Executing kernel CompMinVec ", 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, val, minVal); + } + void run() + { + tbb::parallel_reduce(tbb::blocked_range<IndexInt>(0, size), *this); + } + CompMinVec(CompMinVec &o, tbb::split) + : KernelBase(o), val(o.val), minVal(std::numeric_limits<Real>::max()) + { + } + void join(const CompMinVec &o) + { + minVal = min(minVal, o.minVal); + } + const Grid<Vec3> &val; + Real minVal; +}; + +//! Kernel: Compute max norm of vec grid + +struct CompMaxVec : public KernelBase { + CompMaxVec(const Grid<Vec3> &val) + : KernelBase(&val, 0), val(val), maxVal(-std::numeric_limits<Real>::max()) + { + runMessage(); + run(); + } + inline void op(IndexInt idx, const Grid<Vec3> &val, Real &maxVal) + { + const Real s = normSquare(val[idx]); + if (s > maxVal) + maxVal = s; + } + inline operator Real() + { + return maxVal; + } + inline Real &getRet() + { + return maxVal; + } + inline const Grid<Vec3> &getArg0() + { + return val; + } + typedef Grid<Vec3> type0; + void runMessage() + { + debMsg("Executing kernel CompMaxVec ", 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, val, maxVal); + } + void run() + { + tbb::parallel_reduce(tbb::blocked_range<IndexInt>(0, size), *this); + } + CompMaxVec(CompMaxVec &o, tbb::split) + : KernelBase(o), val(o.val), maxVal(-std::numeric_limits<Real>::max()) + { + } + void join(const CompMaxVec &o) + { + maxVal = max(maxVal, o.maxVal); + } + const Grid<Vec3> &val; + Real maxVal; +}; + +template<class T> Grid<T> &Grid<T>::copyFrom(const Grid<T> &a, bool copyType) +{ + assertMsg(a.mSize.x == mSize.x && a.mSize.y == mSize.y && a.mSize.z == mSize.z, + "different grid resolutions " << a.mSize << " vs " << this->mSize); + memcpy(mData, a.mData, sizeof(T) * mSize.x * mSize.y * mSize.z); + if (copyType) + mType = a.mType; // copy type marker + return *this; +} +/*template<class T> Grid<T>& Grid<T>::operator= (const Grid<T>& a) { + note: do not use , use copyFrom instead +}*/ + +template<class T> struct knGridSetConstReal : public KernelBase { + knGridSetConstReal(Grid<T> &me, T val) : KernelBase(&me, 0), me(me), val(val) + { + runMessage(); + run(); + } + inline void op(IndexInt idx, Grid<T> &me, T val) const + { + me[idx] = val; + } + inline Grid<T> &getArg0() + { + return me; + } + typedef Grid<T> type0; + inline T &getArg1() + { + return val; + } + typedef T type1; + void runMessage() + { + debMsg("Executing kernel knGridSetConstReal ", 3); + debMsg("Kernel range" + << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ", + 4); + }; + void operator()(const tbb::blocked_range<IndexInt> &__r) const + { + for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++) + op(idx, me, val); + } + void run() + { + tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this); + } + Grid<T> &me; + T val; +}; +template<class T> struct knGridAddConstReal : public KernelBase { + knGridAddConstReal(Grid<T> &me, T val) : KernelBase(&me, 0), me(me), val(val) + { + runMessage(); + run(); + } + inline void op(IndexInt idx, Grid<T> &me, T val) const + { + me[idx] += val; + } + inline Grid<T> &getArg0() + { + return me; + } + typedef Grid<T> type0; + inline T &getArg1() + { + return val; + } + typedef T type1; + void runMessage() + { + debMsg("Executing kernel knGridAddConstReal ", 3); + debMsg("Kernel range" + << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ", + 4); + }; + void operator()(const tbb::blocked_range<IndexInt> &__r) const + { + for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++) + op(idx, me, val); + } + void run() + { + tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this); + } + Grid<T> &me; + T val; +}; +template<class T> struct knGridMultConst : public KernelBase { + knGridMultConst(Grid<T> &me, T val) : KernelBase(&me, 0), me(me), val(val) + { + runMessage(); + run(); + } + inline void op(IndexInt idx, Grid<T> &me, T val) const + { + me[idx] *= val; + } + inline Grid<T> &getArg0() + { + return me; + } + typedef Grid<T> type0; + inline T &getArg1() + { + return val; + } + typedef T type1; + void runMessage() + { + debMsg("Executing kernel knGridMultConst ", 3); + debMsg("Kernel range" + << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ", + 4); + }; + void operator()(const tbb::blocked_range<IndexInt> &__r) const + { + for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++) + op(idx, me, val); + } + void run() + { + tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this); + } + Grid<T> &me; + T val; +}; + +template<class T> struct knGridSafeDiv : public KernelBase { + knGridSafeDiv(Grid<T> &me, const Grid<T> &other) : KernelBase(&me, 0), me(me), other(other) + { + runMessage(); + run(); + } + inline void op(IndexInt idx, Grid<T> &me, const Grid<T> &other) const + { + me[idx] = safeDivide(me[idx], other[idx]); + } + inline Grid<T> &getArg0() + { + return me; + } + typedef Grid<T> type0; + inline const Grid<T> &getArg1() + { + return other; + } + typedef Grid<T> type1; + void runMessage() + { + debMsg("Executing kernel knGridSafeDiv ", 3); + debMsg("Kernel range" + << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ", + 4); + }; + void operator()(const tbb::blocked_range<IndexInt> &__r) const + { + for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++) + op(idx, me, other); + } + void run() + { + tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this); + } + Grid<T> &me; + const Grid<T> &other; +}; +// KERNEL(idx) template<class T> void gridSafeDiv (Grid<T>& me, const Grid<T>& other) { me[idx] = +// safeDivide(me[idx], other[idx]); } + +template<class T> struct knGridClamp : public KernelBase { + knGridClamp(Grid<T> &me, const T &min, const T &max) + : KernelBase(&me, 0), me(me), min(min), max(max) + { + runMessage(); + run(); + } + inline void op(IndexInt idx, Grid<T> &me, const T &min, const T &max) const + { + me[idx] = clamp(me[idx], min, max); + } + inline Grid<T> &getArg0() + { + return me; + } + typedef Grid<T> type0; + inline const T &getArg1() + { + return min; + } + typedef T type1; + inline const T &getArg2() + { + return max; + } + typedef T type2; + void runMessage() + { + debMsg("Executing kernel knGridClamp ", 3); + debMsg("Kernel range" + << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ", + 4); + }; + void operator()(const tbb::blocked_range<IndexInt> &__r) const + { + for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++) + op(idx, me, min, max); + } + void run() + { + tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this); + } + Grid<T> &me; + const T &min; + const T &max; +}; + +template<typename T> inline void stomp(T &v, const T &th) +{ + if (v < th) + v = 0; +} +template<> inline void stomp<Vec3>(Vec3 &v, const Vec3 &th) +{ + if (v[0] < th[0]) + v[0] = 0; + if (v[1] < th[1]) + v[1] = 0; + if (v[2] < th[2]) + v[2] = 0; +} +template<class T> struct knGridStomp : public KernelBase { + knGridStomp(Grid<T> &me, const T &threshold) : KernelBase(&me, 0), me(me), threshold(threshold) + { + runMessage(); + run(); + } + inline void op(IndexInt idx, Grid<T> &me, const T &threshold) const + { + stomp(me[idx], threshold); + } + inline Grid<T> &getArg0() + { + return me; + } + typedef Grid<T> type0; + inline const T &getArg1() + { + return threshold; + } + typedef T type1; + void runMessage() + { + debMsg("Executing kernel knGridStomp ", 3); + debMsg("Kernel range" + << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ", + 4); + }; + void operator()(const tbb::blocked_range<IndexInt> &__r) const + { + for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++) + op(idx, me, threshold); + } + void run() + { + tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this); + } + Grid<T> &me; + const T &threshold; +}; + +template<class T> struct knPermuteAxes : public KernelBase { + knPermuteAxes(Grid<T> &self, Grid<T> &target, int axis0, int axis1, int axis2) + : KernelBase(&self, 0), self(self), target(target), axis0(axis0), axis1(axis1), axis2(axis2) + { + runMessage(); + run(); + } + inline void op( + int i, int j, int k, Grid<T> &self, Grid<T> &target, int axis0, int axis1, int axis2) const + { + int i0 = axis0 == 0 ? i : (axis0 == 1 ? j : k); + int i1 = axis1 == 0 ? i : (axis1 == 1 ? j : k); + int i2 = axis2 == 0 ? i : (axis2 == 1 ? j : k); + target(i0, i1, i2) = self(i, j, k); + } + inline Grid<T> &getArg0() + { + return self; + } + typedef Grid<T> type0; + inline Grid<T> &getArg1() + { + return target; + } + typedef Grid<T> type1; + inline int &getArg2() + { + return axis0; + } + typedef int type2; + inline int &getArg3() + { + return axis1; + } + typedef int type3; + inline int &getArg4() + { + return axis2; + } + typedef int type4; + void runMessage() + { + debMsg("Executing kernel knPermuteAxes ", 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, self, target, axis0, axis1, axis2); + } + 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, self, target, axis0, axis1, axis2); + } + } + 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); + } + Grid<T> &self; + Grid<T> ⌖ + int axis0; + int axis1; + int axis2; +}; + +template<class T> Grid<T> &Grid<T>::safeDivide(const Grid<T> &a) +{ + knGridSafeDiv<T>(*this, a); + return *this; +} + +template<class T> int Grid<T>::getGridType() +{ + return static_cast<int>(mType); +} + +template<class T> void Grid<T>::add(const Grid<T> &a) +{ + gridAdd<T, T>(*this, a); +} +template<class T> void Grid<T>::sub(const Grid<T> &a) +{ + gridSub<T, T>(*this, a); +} +template<class T> void Grid<T>::addScaled(const Grid<T> &a, const T &factor) +{ + gridScaledAdd<T, T>(*this, a, factor); +} +template<class T> void Grid<T>::setConst(T a) +{ + knGridSetConstReal<T>(*this, T(a)); +} +template<class T> void Grid<T>::addConst(T a) +{ + knGridAddConstReal<T>(*this, T(a)); +} +template<class T> void Grid<T>::multConst(T a) +{ + knGridMultConst<T>(*this, a); +} + +template<class T> void Grid<T>::mult(const Grid<T> &a) +{ + gridMult<T, T>(*this, a); +} + +template<class T> void Grid<T>::clamp(Real min, Real max) +{ + knGridClamp<T>(*this, T(min), T(max)); +} +template<class T> void Grid<T>::stomp(const T &threshold) +{ + knGridStomp<T>(*this, threshold); +} +template<class T> void Grid<T>::permuteAxes(int axis0, int axis1, int axis2) +{ + if (axis0 == axis1 || axis0 == axis2 || axis1 == axis2 || axis0 > 2 || axis1 > 2 || axis2 > 2 || + axis0 < 0 || axis1 < 0 || axis2 < 0) + return; + Vec3i size = mParent->getGridSize(); + assertMsg(mParent->is2D() ? size.x == size.y : size.x == size.y && size.y == size.z, + "Grid must be cubic!"); + Grid<T> tmp(mParent); + knPermuteAxes<T>(*this, tmp, axis0, axis1, axis2); + this->swap(tmp); +} +template<class T> +void Grid<T>::permuteAxesCopyToGrid(int axis0, int axis1, int axis2, Grid<T> &out) +{ + if (axis0 == axis1 || axis0 == axis2 || axis1 == axis2 || axis0 > 2 || axis1 > 2 || axis2 > 2 || + axis0 < 0 || axis1 < 0 || axis2 < 0) + return; + assertMsg(this->getGridType() == out.getGridType(), "Grids must have same data type!"); + Vec3i size = mParent->getGridSize(); + Vec3i sizeTarget = out.getParent()->getGridSize(); + assertMsg(sizeTarget[axis0] == size[0] && sizeTarget[axis1] == size[1] && + sizeTarget[axis2] == size[2], + "Permuted grids must have the same dimensions!"); + knPermuteAxes<T>(*this, out, axis0, axis1, axis2); +} + +template<> Real Grid<Real>::getMax() const +{ + return CompMaxReal(*this); +} +template<> Real Grid<Real>::getMin() const +{ + return CompMinReal(*this); +} +template<> Real Grid<Real>::getMaxAbs() const +{ + Real amin = CompMinReal(*this); + Real amax = CompMaxReal(*this); + return max(fabs(amin), fabs(amax)); +} +template<> Real Grid<Vec3>::getMax() const +{ + return sqrt(CompMaxVec(*this)); +} +template<> Real Grid<Vec3>::getMin() const +{ + return sqrt(CompMinVec(*this)); +} +template<> Real Grid<Vec3>::getMaxAbs() const +{ + return sqrt(CompMaxVec(*this)); +} +template<> Real Grid<int>::getMax() const +{ + return (Real)CompMaxInt(*this); +} +template<> Real Grid<int>::getMin() const +{ + return (Real)CompMinInt(*this); +} +template<> Real Grid<int>::getMaxAbs() const +{ + int amin = CompMinInt(*this); + int amax = CompMaxInt(*this); + return max(fabs((Real)amin), fabs((Real)amax)); +} +template<class T> std::string Grid<T>::getDataPointer() +{ + std::ostringstream out; + out << mData; + return out.str(); +} + +// L1 / L2 functions + +//! calculate L1 norm for whole grid with non-parallelized loop +template<class GRID> Real loop_calcL1Grid(const GRID &grid, int bnd) +{ + double accu = 0.; + FOR_IJKT_BND(grid, bnd) + { + accu += norm(grid(i, j, k, t)); + } + return (Real)accu; +} + +//! calculate L2 norm for whole grid with non-parallelized loop +// note - kernels "could" be used here, but they can't be templated at the moment (also, that would +// mean the bnd parameter is fixed) +template<class GRID> Real loop_calcL2Grid(const GRID &grid, int bnd) +{ + double accu = 0.; + FOR_IJKT_BND(grid, bnd) + { + accu += normSquare(grid(i, j, k, t)); // supported for real and vec3,4 types + } + return (Real)sqrt(accu); +} + +//! compute L1 norm of whole grid content (note, not parallel at the moment) +template<class T> Real Grid<T>::getL1(int bnd) +{ + return loop_calcL1Grid<Grid<T>>(*this, bnd); +} +//! compute L2 norm of whole grid content (note, not parallel at the moment) +template<class T> Real Grid<T>::getL2(int bnd) +{ + return loop_calcL2Grid<Grid<T>>(*this, bnd); +} + +struct knCountCells : public KernelBase { + knCountCells(const FlagGrid &flags, int flag, int bnd, Grid<Real> *mask) + : KernelBase(&flags, 0), flags(flags), flag(flag), bnd(bnd), mask(mask), cnt(0) + { + runMessage(); + run(); + } + inline void op( + int i, int j, int k, const FlagGrid &flags, int flag, int bnd, Grid<Real> *mask, int &cnt) + { + if (mask) + (*mask)(i, j, k) = 0.; + if (bnd > 0 && (!flags.isInBounds(Vec3i(i, j, k), bnd))) + return; + if (flags(i, j, k) & flag) { + cnt++; + if (mask) + (*mask)(i, j, k) = 1.; + } + } + inline operator int() + { + return cnt; + } + inline int &getRet() + { + return cnt; + } + inline const FlagGrid &getArg0() + { + return flags; + } + typedef FlagGrid type0; + inline int &getArg1() + { + return flag; + } + typedef int type1; + inline int &getArg2() + { + return bnd; + } + typedef int type2; + inline Grid<Real> *getArg3() + { + return mask; + } + typedef Grid<Real> type3; + void runMessage() + { + debMsg("Executing kernel knCountCells ", 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 = 0; j < _maxY; j++) + for (int i = 0; i < _maxX; i++) + op(i, j, k, flags, flag, bnd, mask, cnt); + } + 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, flags, flag, bnd, mask, cnt); + } + } + void run() + { + if (maxZ > 1) + tbb::parallel_reduce(tbb::blocked_range<IndexInt>(minZ, maxZ), *this); + else + tbb::parallel_reduce(tbb::blocked_range<IndexInt>(0, maxY), *this); + } + knCountCells(knCountCells &o, tbb::split) + : KernelBase(o), flags(o.flags), flag(o.flag), bnd(o.bnd), mask(o.mask), cnt(0) + { + } + void join(const knCountCells &o) + { + cnt += o.cnt; + } + const FlagGrid &flags; + int flag; + int bnd; + Grid<Real> *mask; + int cnt; +}; + +//! count number of cells of a certain type flag (can contain multiple bits, checks if any one of +//! them is set - not all!) +int FlagGrid::countCells(int flag, int bnd, Grid<Real> *mask) +{ + return knCountCells(*this, flag, bnd, mask); +} + +// compute maximal diference of two cells in the grid +// used for testing system + +Real gridMaxDiff(Grid<Real> &g1, Grid<Real> &g2) +{ + double maxVal = 0.; + FOR_IJK(g1) + { + maxVal = std::max(maxVal, (double)fabs(g1(i, j, k) - g2(i, j, k))); + } + return maxVal; +} +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, "gridMaxDiff", !noTiming); + PyObject *_retval = 0; + { + ArgLocker _lock; + Grid<Real> &g1 = *_args.getPtr<Grid<Real>>("g1", 0, &_lock); + Grid<Real> &g2 = *_args.getPtr<Grid<Real>>("g2", 1, &_lock); + _retval = toPy(gridMaxDiff(g1, g2)); + _args.check(); + } + pbFinalizePlugin(parent, "gridMaxDiff", !noTiming); + return _retval; + } + catch (std::exception &e) { + pbSetError("gridMaxDiff", e.what()); + return 0; + } +} +static const Pb::Register _RP_gridMaxDiff("", "gridMaxDiff", _W_0); +extern "C" { +void PbRegister_gridMaxDiff() +{ + KEEP_UNUSED(_RP_gridMaxDiff); +} +} + +Real gridMaxDiffInt(Grid<int> &g1, Grid<int> &g2) +{ + double maxVal = 0.; + FOR_IJK(g1) + { + maxVal = std::max(maxVal, (double)fabs((double)g1(i, j, k) - g2(i, j, k))); + } + return maxVal; +} +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, "gridMaxDiffInt", !noTiming); + PyObject *_retval = 0; + { + ArgLocker _lock; + Grid<int> &g1 = *_args.getPtr<Grid<int>>("g1", 0, &_lock); + Grid<int> &g2 = *_args.getPtr<Grid<int>>("g2", 1, &_lock); + _retval = toPy(gridMaxDiffInt(g1, g2)); + _args.check(); + } + pbFinalizePlugin(parent, "gridMaxDiffInt", !noTiming); + return _retval; + } + catch (std::exception &e) { + pbSetError("gridMaxDiffInt", e.what()); + return 0; + } +} +static const Pb::Register _RP_gridMaxDiffInt("", "gridMaxDiffInt", _W_1); +extern "C" { +void PbRegister_gridMaxDiffInt() +{ + KEEP_UNUSED(_RP_gridMaxDiffInt); +} +} + +Real gridMaxDiffVec3(Grid<Vec3> &g1, Grid<Vec3> &g2) +{ + double maxVal = 0.; + FOR_IJK(g1) + { + // accumulate differences with double precision + // note - don't use norm here! should be as precise as possible... + double d = 0.; + for (int c = 0; c < 3; ++c) { + d += fabs((double)g1(i, j, k)[c] - (double)g2(i, j, k)[c]); + } + maxVal = std::max(maxVal, d); + // maxVal = std::max(maxVal, (double)fabs( norm(g1(i,j,k)-g2(i,j,k)) )); + } + return maxVal; +} +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, "gridMaxDiffVec3", !noTiming); + PyObject *_retval = 0; + { + ArgLocker _lock; + Grid<Vec3> &g1 = *_args.getPtr<Grid<Vec3>>("g1", 0, &_lock); + Grid<Vec3> &g2 = *_args.getPtr<Grid<Vec3>>("g2", 1, &_lock); + _retval = toPy(gridMaxDiffVec3(g1, g2)); + _args.check(); + } + pbFinalizePlugin(parent, "gridMaxDiffVec3", !noTiming); + return _retval; + } + catch (std::exception &e) { + pbSetError("gridMaxDiffVec3", e.what()); + return 0; + } +} +static const Pb::Register _RP_gridMaxDiffVec3("", "gridMaxDiffVec3", _W_2); +extern "C" { +void PbRegister_gridMaxDiffVec3() +{ + KEEP_UNUSED(_RP_gridMaxDiffVec3); +} +} + +// simple helper functions to copy (convert) mac to vec3 , and levelset to real grids +// (are assumed to be the same for running the test cases - in general they're not!) + +void copyMacToVec3(MACGrid &source, Grid<Vec3> &target) +{ + FOR_IJK(target) + { + target(i, j, k) = source(i, j, k); + } +} +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, "copyMacToVec3", !noTiming); + PyObject *_retval = 0; + { + ArgLocker _lock; + MACGrid &source = *_args.getPtr<MACGrid>("source", 0, &_lock); + Grid<Vec3> &target = *_args.getPtr<Grid<Vec3>>("target", 1, &_lock); + _retval = getPyNone(); + copyMacToVec3(source, target); + _args.check(); + } + pbFinalizePlugin(parent, "copyMacToVec3", !noTiming); + return _retval; + } + catch (std::exception &e) { + pbSetError("copyMacToVec3", e.what()); + return 0; + } +} +static const Pb::Register _RP_copyMacToVec3("", "copyMacToVec3", _W_3); +extern "C" { +void PbRegister_copyMacToVec3() +{ + KEEP_UNUSED(_RP_copyMacToVec3); +} +} + +void convertMacToVec3(MACGrid &source, Grid<Vec3> &target) +{ + debMsg("Deprecated - do not use convertMacToVec3... use copyMacToVec3 instead", 1); + copyMacToVec3(source, target); +} +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, "convertMacToVec3", !noTiming); + PyObject *_retval = 0; + { + ArgLocker _lock; + MACGrid &source = *_args.getPtr<MACGrid>("source", 0, &_lock); + Grid<Vec3> &target = *_args.getPtr<Grid<Vec3>>("target", 1, &_lock); + _retval = getPyNone(); + convertMacToVec3(source, target); + _args.check(); + } + pbFinalizePlugin(parent, "convertMacToVec3", !noTiming); + return _retval; + } + catch (std::exception &e) { + pbSetError("convertMacToVec3", e.what()); + return 0; + } +} +static const Pb::Register _RP_convertMacToVec3("", "convertMacToVec3", _W_4); +extern "C" { +void PbRegister_convertMacToVec3() +{ + KEEP_UNUSED(_RP_convertMacToVec3); +} +} + +//! vec3->mac grid conversion , but with full resampling +void resampleVec3ToMac(Grid<Vec3> &source, MACGrid &target) +{ + FOR_IJK_BND(target, 1) + { + target(i, j, k)[0] = 0.5 * (source(i - 1, j, k)[0] + source(i, j, k))[0]; + target(i, j, k)[1] = 0.5 * (source(i, j - 1, k)[1] + source(i, j, k))[1]; + if (target.is3D()) { + target(i, j, k)[2] = 0.5 * (source(i, j, k - 1)[2] + source(i, j, k))[2]; + } + } +} +static PyObject *_W_5(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, "resampleVec3ToMac", !noTiming); + PyObject *_retval = 0; + { + ArgLocker _lock; + Grid<Vec3> &source = *_args.getPtr<Grid<Vec3>>("source", 0, &_lock); + MACGrid &target = *_args.getPtr<MACGrid>("target", 1, &_lock); + _retval = getPyNone(); + resampleVec3ToMac(source, target); + _args.check(); + } + pbFinalizePlugin(parent, "resampleVec3ToMac", !noTiming); + return _retval; + } + catch (std::exception &e) { + pbSetError("resampleVec3ToMac", e.what()); + return 0; + } +} +static const Pb::Register _RP_resampleVec3ToMac("", "resampleVec3ToMac", _W_5); +extern "C" { +void PbRegister_resampleVec3ToMac() +{ + KEEP_UNUSED(_RP_resampleVec3ToMac); +} +} + +//! mac->vec3 grid conversion , with full resampling +void resampleMacToVec3(MACGrid &source, Grid<Vec3> &target) +{ + FOR_IJK_BND(target, 1) + { + target(i, j, k) = source.getCentered(i, j, k); + } +} +static PyObject *_W_6(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, "resampleMacToVec3", !noTiming); + PyObject *_retval = 0; + { + ArgLocker _lock; + MACGrid &source = *_args.getPtr<MACGrid>("source", 0, &_lock); + Grid<Vec3> &target = *_args.getPtr<Grid<Vec3>>("target", 1, &_lock); + _retval = getPyNone(); + resampleMacToVec3(source, target); + _args.check(); + } + pbFinalizePlugin(parent, "resampleMacToVec3", !noTiming); + return _retval; + } + catch (std::exception &e) { + pbSetError("resampleMacToVec3", e.what()); + return 0; + } +} +static const Pb::Register _RP_resampleMacToVec3("", "resampleMacToVec3", _W_6); +extern "C" { +void PbRegister_resampleMacToVec3() +{ + KEEP_UNUSED(_RP_resampleMacToVec3); +} +} + +void copyLevelsetToReal(LevelsetGrid &source, Grid<Real> &target) +{ + FOR_IJK(target) + { + target(i, j, k) = source(i, j, k); + } +} +static PyObject *_W_7(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, "copyLevelsetToReal", !noTiming); + PyObject *_retval = 0; + { + ArgLocker _lock; + LevelsetGrid &source = *_args.getPtr<LevelsetGrid>("source", 0, &_lock); + Grid<Real> &target = *_args.getPtr<Grid<Real>>("target", 1, &_lock); + _retval = getPyNone(); + copyLevelsetToReal(source, target); + _args.check(); + } + pbFinalizePlugin(parent, "copyLevelsetToReal", !noTiming); + return _retval; + } + catch (std::exception &e) { + pbSetError("copyLevelsetToReal", e.what()); + return 0; + } +} +static const Pb::Register _RP_copyLevelsetToReal("", "copyLevelsetToReal", _W_7); +extern "C" { +void PbRegister_copyLevelsetToReal() +{ + KEEP_UNUSED(_RP_copyLevelsetToReal); +} +} + +void copyVec3ToReal(Grid<Vec3> &source, + Grid<Real> &targetX, + Grid<Real> &targetY, + Grid<Real> &targetZ) +{ + FOR_IJK(source) + { + targetX(i, j, k) = source(i, j, k).x; + targetY(i, j, k) = source(i, j, k).y; + targetZ(i, j, k) = source(i, j, k).z; + } +} +static PyObject *_W_8(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, "copyVec3ToReal", !noTiming); + PyObject *_retval = 0; + { + ArgLocker _lock; + Grid<Vec3> &source = *_args.getPtr<Grid<Vec3>>("source", 0, &_lock); + Grid<Real> &targetX = *_args.getPtr<Grid<Real>>("targetX", 1, &_lock); + Grid<Real> &targetY = *_args.getPtr<Grid<Real>>("targetY", 2, &_lock); + Grid<Real> &targetZ = *_args.getPtr<Grid<Real>>("targetZ", 3, &_lock); + _retval = getPyNone(); + copyVec3ToReal(source, targetX, targetY, targetZ); + _args.check(); + } + pbFinalizePlugin(parent, "copyVec3ToReal", !noTiming); + return _retval; + } + catch (std::exception &e) { + pbSetError("copyVec3ToReal", e.what()); + return 0; + } +} +static const Pb::Register _RP_copyVec3ToReal("", "copyVec3ToReal", _W_8); +extern "C" { +void PbRegister_copyVec3ToReal() +{ + KEEP_UNUSED(_RP_copyVec3ToReal); +} +} + +void copyRealToVec3(Grid<Real> &sourceX, + Grid<Real> &sourceY, + Grid<Real> &sourceZ, + Grid<Vec3> &target) +{ + FOR_IJK(target) + { + target(i, j, k).x = sourceX(i, j, k); + target(i, j, k).y = sourceY(i, j, k); + target(i, j, k).z = sourceZ(i, j, k); + } +} +static PyObject *_W_9(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, "copyRealToVec3", !noTiming); + PyObject *_retval = 0; + { + ArgLocker _lock; + Grid<Real> &sourceX = *_args.getPtr<Grid<Real>>("sourceX", 0, &_lock); + Grid<Real> &sourceY = *_args.getPtr<Grid<Real>>("sourceY", 1, &_lock); + Grid<Real> &sourceZ = *_args.getPtr<Grid<Real>>("sourceZ", 2, &_lock); + Grid<Vec3> &target = *_args.getPtr<Grid<Vec3>>("target", 3, &_lock); + _retval = getPyNone(); + copyRealToVec3(sourceX, sourceY, sourceZ, target); + _args.check(); + } + pbFinalizePlugin(parent, "copyRealToVec3", !noTiming); + return _retval; + } + catch (std::exception &e) { + pbSetError("copyRealToVec3", e.what()); + return 0; + } +} +static const Pb::Register _RP_copyRealToVec3("", "copyRealToVec3", _W_9); +extern "C" { +void PbRegister_copyRealToVec3() +{ + KEEP_UNUSED(_RP_copyRealToVec3); +} +} + +void convertLevelsetToReal(LevelsetGrid &source, Grid<Real> &target) +{ + debMsg("Deprecated - do not use convertLevelsetToReal... use copyLevelsetToReal instead", 1); + copyLevelsetToReal(source, target); +} +static PyObject *_W_10(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, "convertLevelsetToReal", !noTiming); + PyObject *_retval = 0; + { + ArgLocker _lock; + LevelsetGrid &source = *_args.getPtr<LevelsetGrid>("source", 0, &_lock); + Grid<Real> &target = *_args.getPtr<Grid<Real>>("target", 1, &_lock); + _retval = getPyNone(); + convertLevelsetToReal(source, target); + _args.check(); + } + pbFinalizePlugin(parent, "convertLevelsetToReal", !noTiming); + return _retval; + } + catch (std::exception &e) { + pbSetError("convertLevelsetToReal", e.what()); + return 0; + } +} +static const Pb::Register _RP_convertLevelsetToReal("", "convertLevelsetToReal", _W_10); +extern "C" { +void PbRegister_convertLevelsetToReal() +{ + KEEP_UNUSED(_RP_convertLevelsetToReal); +} +} + +template<class T> void Grid<T>::printGrid(int zSlice, bool printIndex, int bnd) +{ + std::ostringstream out; + out << std::endl; + FOR_IJK_BND(*this, bnd) + { + IndexInt idx = (*this).index(i, j, k); + if ((zSlice >= 0 && k == zSlice) || (zSlice < 0)) { + out << " "; + if (printIndex && this->is3D()) + out << " " << i << "," << j << "," << k << ":"; + if (printIndex && !this->is3D()) + out << " " << i << "," << j << ":"; + out << (*this)[idx]; + if (i == (*this).getSizeX() - 1 - bnd) + out << std::endl; + } + } + out << endl; + debMsg("Printing " << this->getName() << out.str().c_str(), 1); +} + +//! helper to swap components of a grid (eg for data import) +void swapComponents(Grid<Vec3> &vel, int c1 = 0, int c2 = 1, int c3 = 2) +{ + FOR_IJK(vel) + { + Vec3 v = vel(i, j, k); + vel(i, j, k)[0] = v[c1]; + vel(i, j, k)[1] = v[c2]; + vel(i, j, k)[2] = v[c3]; + } +} +static PyObject *_W_11(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, "swapComponents", !noTiming); + PyObject *_retval = 0; + { + ArgLocker _lock; + Grid<Vec3> &vel = *_args.getPtr<Grid<Vec3>>("vel", 0, &_lock); + int c1 = _args.getOpt<int>("c1", 1, 0, &_lock); + int c2 = _args.getOpt<int>("c2", 2, 1, &_lock); + int c3 = _args.getOpt<int>("c3", 3, 2, &_lock); + _retval = getPyNone(); + swapComponents(vel, c1, c2, c3); + _args.check(); + } + pbFinalizePlugin(parent, "swapComponents", !noTiming); + return _retval; + } + catch (std::exception &e) { + pbSetError("swapComponents", e.what()); + return 0; + } +} +static const Pb::Register _RP_swapComponents("", "swapComponents", _W_11); +extern "C" { +void PbRegister_swapComponents() +{ + KEEP_UNUSED(_RP_swapComponents); +} +} + +// helper functions for UV grid data (stored grid coordinates as Vec3 values, and uv weight in +// entry zero) + +// make uv weight accesible in python +Real getUvWeight(Grid<Vec3> &uv) +{ + return uv[0][0]; +} +static PyObject *_W_12(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, "getUvWeight", !noTiming); + PyObject *_retval = 0; + { + ArgLocker _lock; + Grid<Vec3> &uv = *_args.getPtr<Grid<Vec3>>("uv", 0, &_lock); + _retval = toPy(getUvWeight(uv)); + _args.check(); + } + pbFinalizePlugin(parent, "getUvWeight", !noTiming); + return _retval; + } + catch (std::exception &e) { + pbSetError("getUvWeight", e.what()); + return 0; + } +} +static const Pb::Register _RP_getUvWeight("", "getUvWeight", _W_12); +extern "C" { +void PbRegister_getUvWeight() +{ + KEEP_UNUSED(_RP_getUvWeight); +} +} + +// note - right now the UV grids have 0 values at the border after advection... could be fixed with +// an extrapolation step... + +// compute normalized modulo interval +static inline Real computeUvGridTime(Real t, Real resetTime) +{ + return fmod((t / resetTime), (Real)1.); +} +// create ramp function in 0..1 range with half frequency +static inline Real computeUvRamp(Real t) +{ + Real uvWeight = 2. * t; + if (uvWeight > 1.) + uvWeight = 2. - uvWeight; + return uvWeight; +} + +struct knResetUvGrid : public KernelBase { + knResetUvGrid(Grid<Vec3> &target, const Vec3 *offset) + : KernelBase(&target, 0), target(target), offset(offset) + { + runMessage(); + run(); + } + inline void op(int i, int j, int k, Grid<Vec3> &target, const Vec3 *offset) const + { + Vec3 coord = Vec3((Real)i, (Real)j, (Real)k); + if (offset) + coord += (*offset); + target(i, j, k) = coord; + } + inline Grid<Vec3> &getArg0() + { + return target; + } + typedef Grid<Vec3> type0; + inline const Vec3 *getArg1() + { + return offset; + } + typedef Vec3 type1; + void runMessage() + { + debMsg("Executing kernel knResetUvGrid ", 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, target, offset); + } + 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, target, offset); + } + } + 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); + } + Grid<Vec3> ⌖ + const Vec3 *offset; +}; + +void resetUvGrid(Grid<Vec3> &target, const Vec3 *offset = NULL) +{ + knResetUvGrid reset(target, + offset); // note, llvm complains about anonymous declaration here... ? +} +static PyObject *_W_13(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, "resetUvGrid", !noTiming); + PyObject *_retval = 0; + { + ArgLocker _lock; + Grid<Vec3> &target = *_args.getPtr<Grid<Vec3>>("target", 0, &_lock); + const Vec3 *offset = _args.getPtrOpt<Vec3>("offset", 1, NULL, &_lock); + _retval = getPyNone(); + resetUvGrid(target, offset); + _args.check(); + } + pbFinalizePlugin(parent, "resetUvGrid", !noTiming); + return _retval; + } + catch (std::exception &e) { + pbSetError("resetUvGrid", e.what()); + return 0; + } +} +static const Pb::Register _RP_resetUvGrid("", "resetUvGrid", _W_13); +extern "C" { +void PbRegister_resetUvGrid() +{ + KEEP_UNUSED(_RP_resetUvGrid); +} +} + +void updateUvWeight( + Real resetTime, int index, int numUvs, Grid<Vec3> &uv, const Vec3 *offset = NULL) +{ + const Real t = uv.getParent()->getTime(); + Real timeOff = resetTime / (Real)numUvs; + + Real lastt = computeUvGridTime(t + (Real)index * timeOff - uv.getParent()->getDt(), resetTime); + Real currt = computeUvGridTime(t + (Real)index * timeOff, resetTime); + Real uvWeight = computeUvRamp(currt); + + // normalize the uvw weights , note: this is a bit wasteful... + Real uvWTotal = 0.; + for (int i = 0; i < numUvs; ++i) { + uvWTotal += computeUvRamp(computeUvGridTime(t + (Real)i * timeOff, resetTime)); + } + if (uvWTotal <= VECTOR_EPSILON) { + uvWeight = uvWTotal = 1.; + } + else + uvWeight /= uvWTotal; + + // check for reset + if (currt < lastt) + knResetUvGrid reset(uv, offset); + + // write new weight value to grid + uv[0] = Vec3(uvWeight, 0., 0.); + + // print info about uv weights? + debMsg("Uv grid " << index << "/" << numUvs << " t=" << currt << " w=" << uvWeight + << ", reset:" << (int)(currt < lastt), + 2); +} +static PyObject *_W_14(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, "updateUvWeight", !noTiming); + PyObject *_retval = 0; + { + ArgLocker _lock; + Real resetTime = _args.get<Real>("resetTime", 0, &_lock); + int index = _args.get<int>("index", 1, &_lock); + int numUvs = _args.get<int>("numUvs", 2, &_lock); + Grid<Vec3> &uv = *_args.getPtr<Grid<Vec3>>("uv", 3, &_lock); + const Vec3 *offset = _args.getPtrOpt<Vec3>("offset", 4, NULL, &_lock); + _retval = getPyNone(); + updateUvWeight(resetTime, index, numUvs, uv, offset); + _args.check(); + } + pbFinalizePlugin(parent, "updateUvWeight", !noTiming); + return _retval; + } + catch (std::exception &e) { + pbSetError("updateUvWeight", e.what()); + return 0; + } +} +static const Pb::Register _RP_updateUvWeight("", "updateUvWeight", _W_14); +extern "C" { +void PbRegister_updateUvWeight() +{ + KEEP_UNUSED(_RP_updateUvWeight); +} +} + +template<class T> struct knSetBoundary : public KernelBase { + knSetBoundary(Grid<T> &grid, T value, int w) + : KernelBase(&grid, 0), grid(grid), value(value), w(w) + { + runMessage(); + run(); + } + inline void op(int i, int j, int k, Grid<T> &grid, T value, int w) const + { + bool bnd = (i <= w || i >= grid.getSizeX() - 1 - w || j <= w || j >= grid.getSizeY() - 1 - w || + (grid.is3D() && (k <= w || k >= grid.getSizeZ() - 1 - w))); + if (bnd) + grid(i, j, k) = value; + } + inline Grid<T> &getArg0() + { + return grid; + } + typedef Grid<T> type0; + inline T &getArg1() + { + return value; + } + typedef T type1; + inline int &getArg2() + { + return w; + } + typedef int type2; + void runMessage() + { + debMsg("Executing kernel knSetBoundary ", 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, grid, value, w); + } + 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, grid, value, w); + } + } + 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); + } + Grid<T> &grid; + T value; + int w; +}; + +template<class T> void Grid<T>::setBound(T value, int boundaryWidth) +{ + knSetBoundary<T>(*this, value, boundaryWidth); +} + +template<class T> struct knSetBoundaryNeumann : public KernelBase { + knSetBoundaryNeumann(Grid<T> &grid, int w) : KernelBase(&grid, 0), grid(grid), w(w) + { + runMessage(); + run(); + } + inline void op(int i, int j, int k, Grid<T> &grid, int w) const + { + bool set = false; + int si = i, sj = j, sk = k; + if (i <= w) { + si = w + 1; + set = true; + } + if (i >= grid.getSizeX() - 1 - w) { + si = grid.getSizeX() - 1 - w - 1; + set = true; + } + if (j <= w) { + sj = w + 1; + set = true; + } + if (j >= grid.getSizeY() - 1 - w) { + sj = grid.getSizeY() - 1 - w - 1; + set = true; + } + if (grid.is3D()) { + if (k <= w) { + sk = w + 1; + set = true; + } + if (k >= grid.getSizeZ() - 1 - w) { + sk = grid.getSizeZ() - 1 - w - 1; + set = true; + } + } + if (set) + grid(i, j, k) = grid(si, sj, sk); + } + inline Grid<T> &getArg0() + { + return grid; + } + typedef Grid<T> type0; + inline int &getArg1() + { + return w; + } + typedef int type1; + void runMessage() + { + debMsg("Executing kernel knSetBoundaryNeumann ", 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, grid, w); + } + 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, grid, w); + } + } + 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); + } + Grid<T> &grid; + int w; +}; + +template<class T> void Grid<T>::setBoundNeumann(int boundaryWidth) +{ + knSetBoundaryNeumann<T>(*this, boundaryWidth); +} + +//! kernel to set velocity components of mac grid to value for a boundary of w cells +struct knSetBoundaryMAC : public KernelBase { + knSetBoundaryMAC(Grid<Vec3> &grid, Vec3 value, int w) + : KernelBase(&grid, 0), grid(grid), value(value), w(w) + { + runMessage(); + run(); + } + inline void op(int i, int j, int k, Grid<Vec3> &grid, Vec3 value, int w) const + { + if (i <= w || i >= grid.getSizeX() - w || j <= w - 1 || j >= grid.getSizeY() - 1 - w || + (grid.is3D() && (k <= w - 1 || k >= grid.getSizeZ() - 1 - w))) + grid(i, j, k).x = value.x; + if (i <= w - 1 || i >= grid.getSizeX() - 1 - w || j <= w || j >= grid.getSizeY() - w || + (grid.is3D() && (k <= w - 1 || k >= grid.getSizeZ() - 1 - w))) + grid(i, j, k).y = value.y; + if (i <= w - 1 || i >= grid.getSizeX() - 1 - w || j <= w - 1 || j >= grid.getSizeY() - 1 - w || + (grid.is3D() && (k <= w || k >= grid.getSizeZ() - w))) + grid(i, j, k).z = value.z; + } + inline Grid<Vec3> &getArg0() + { + return grid; + } + typedef Grid<Vec3> type0; + inline Vec3 &getArg1() + { + return value; + } + typedef Vec3 type1; + inline int &getArg2() + { + return w; + } + typedef int type2; + void runMessage() + { + debMsg("Executing kernel knSetBoundaryMAC ", 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, grid, value, w); + } + 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, grid, value, w); + } + } + 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); + } + Grid<Vec3> &grid; + Vec3 value; + int w; +}; + +//! only set normal velocity components of mac grid to value for a boundary of w cells +struct knSetBoundaryMACNorm : public KernelBase { + knSetBoundaryMACNorm(Grid<Vec3> &grid, Vec3 value, int w) + : KernelBase(&grid, 0), grid(grid), value(value), w(w) + { + runMessage(); + run(); + } + inline void op(int i, int j, int k, Grid<Vec3> &grid, Vec3 value, int w) const + { + if (i <= w || i >= grid.getSizeX() - w) + grid(i, j, k).x = value.x; + if (j <= w || j >= grid.getSizeY() - w) + grid(i, j, k).y = value.y; + if ((grid.is3D() && (k <= w || k >= grid.getSizeZ() - w))) + grid(i, j, k).z = value.z; + } + inline Grid<Vec3> &getArg0() + { + return grid; + } + typedef Grid<Vec3> type0; + inline Vec3 &getArg1() + { + return value; + } + typedef Vec3 type1; + inline int &getArg2() + { + return w; + } + typedef int type2; + void runMessage() + { + debMsg("Executing kernel knSetBoundaryMACNorm ", 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, grid, value, w); + } + 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, grid, value, w); + } + } + 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); + } + Grid<Vec3> &grid; + Vec3 value; + int w; +}; + +//! set velocity components of mac grid to value for a boundary of w cells (optionally only normal +//! values) +void MACGrid::setBoundMAC(Vec3 value, int boundaryWidth, bool normalOnly) +{ + if (!normalOnly) + knSetBoundaryMAC(*this, value, boundaryWidth); + else + knSetBoundaryMACNorm(*this, value, boundaryWidth); +} + +//! helper kernels for getGridAvg + +struct knGridTotalSum : public KernelBase { + knGridTotalSum(const Grid<Real> &a, FlagGrid *flags) + : KernelBase(&a, 0), a(a), flags(flags), result(0.0) + { + runMessage(); + run(); + } + inline void op(IndexInt idx, const Grid<Real> &a, FlagGrid *flags, double &result) + { + if (flags) { + if (flags->isFluid(idx)) + result += a[idx]; + } + else { + result += a[idx]; + } + } + inline operator double() + { + return result; + } + inline double &getRet() + { + return result; + } + inline const Grid<Real> &getArg0() + { + return a; + } + typedef Grid<Real> type0; + inline FlagGrid *getArg1() + { + return flags; + } + typedef FlagGrid type1; + void runMessage() + { + debMsg("Executing kernel knGridTotalSum ", 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, a, flags, result); + } + void run() + { + tbb::parallel_reduce(tbb::blocked_range<IndexInt>(0, size), *this); + } + knGridTotalSum(knGridTotalSum &o, tbb::split) + : KernelBase(o), a(o.a), flags(o.flags), result(0.0) + { + } + void join(const knGridTotalSum &o) + { + result += o.result; + } + const Grid<Real> &a; + FlagGrid *flags; + double result; +}; + +struct knCountFluidCells : public KernelBase { + knCountFluidCells(FlagGrid &flags) : KernelBase(&flags, 0), flags(flags), numEmpty(0) + { + runMessage(); + run(); + } + inline void op(IndexInt idx, FlagGrid &flags, int &numEmpty) + { + if (flags.isFluid(idx)) + numEmpty++; + } + inline operator int() + { + return numEmpty; + } + inline int &getRet() + { + return numEmpty; + } + inline FlagGrid &getArg0() + { + return flags; + } + typedef FlagGrid type0; + void runMessage() + { + debMsg("Executing kernel knCountFluidCells ", 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); + } + knCountFluidCells(knCountFluidCells &o, tbb::split) : KernelBase(o), flags(o.flags), numEmpty(0) + { + } + void join(const knCountFluidCells &o) + { + numEmpty += o.numEmpty; + } + FlagGrid &flags; + int numEmpty; +}; + +//! averaged value for all cells (if flags are given, only for fluid cells) + +Real getGridAvg(Grid<Real> &source, FlagGrid *flags = NULL) +{ + double sum = knGridTotalSum(source, flags); + + double cells; + if (flags) { + cells = knCountFluidCells(*flags); + } + else { + cells = source.getSizeX() * source.getSizeY() * source.getSizeZ(); + } + + if (cells > 0.) + sum *= 1. / cells; + else + sum = -1.; + return sum; +} +static PyObject *_W_15(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, "getGridAvg", !noTiming); + PyObject *_retval = 0; + { + ArgLocker _lock; + Grid<Real> &source = *_args.getPtr<Grid<Real>>("source", 0, &_lock); + FlagGrid *flags = _args.getPtrOpt<FlagGrid>("flags", 1, NULL, &_lock); + _retval = toPy(getGridAvg(source, flags)); + _args.check(); + } + pbFinalizePlugin(parent, "getGridAvg", !noTiming); + return _retval; + } + catch (std::exception &e) { + pbSetError("getGridAvg", e.what()); + return 0; + } +} +static const Pb::Register _RP_getGridAvg("", "getGridAvg", _W_15); +extern "C" { +void PbRegister_getGridAvg() +{ + KEEP_UNUSED(_RP_getGridAvg); +} +} + +//! transfer data between real and vec3 grids + +struct knGetComponent : public KernelBase { + knGetComponent(const Grid<Vec3> &source, Grid<Real> &target, int component) + : KernelBase(&source, 0), source(source), target(target), component(component) + { + runMessage(); + run(); + } + inline void op(IndexInt idx, const Grid<Vec3> &source, Grid<Real> &target, int component) const + { + target[idx] = source[idx][component]; + } + inline const Grid<Vec3> &getArg0() + { + return source; + } + typedef Grid<Vec3> type0; + inline Grid<Real> &getArg1() + { + return target; + } + typedef Grid<Real> type1; + inline int &getArg2() + { + return component; + } + typedef int type2; + void runMessage() + { + debMsg("Executing kernel knGetComponent ", 3); + debMsg("Kernel range" + << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ", + 4); + }; + void operator()(const tbb::blocked_range<IndexInt> &__r) const + { + for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++) + op(idx, source, target, component); + } + void run() + { + tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this); + } + const Grid<Vec3> &source; + Grid<Real> ⌖ + int component; +}; +void getComponent(const Grid<Vec3> &source, Grid<Real> &target, int component) +{ + knGetComponent(source, target, component); +} +static PyObject *_W_16(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, "getComponent", !noTiming); + PyObject *_retval = 0; + { + ArgLocker _lock; + const Grid<Vec3> &source = *_args.getPtr<Grid<Vec3>>("source", 0, &_lock); + Grid<Real> &target = *_args.getPtr<Grid<Real>>("target", 1, &_lock); + int component = _args.get<int>("component", 2, &_lock); + _retval = getPyNone(); + getComponent(source, target, component); + _args.check(); + } + pbFinalizePlugin(parent, "getComponent", !noTiming); + return _retval; + } + catch (std::exception &e) { + pbSetError("getComponent", e.what()); + return 0; + } +} +static const Pb::Register _RP_getComponent("", "getComponent", _W_16); +extern "C" { +void PbRegister_getComponent() +{ + KEEP_UNUSED(_RP_getComponent); +} +} + +struct knSetComponent : public KernelBase { + knSetComponent(const Grid<Real> &source, Grid<Vec3> &target, int component) + : KernelBase(&source, 0), source(source), target(target), component(component) + { + runMessage(); + run(); + } + inline void op(IndexInt idx, const Grid<Real> &source, Grid<Vec3> &target, int component) const + { + target[idx][component] = source[idx]; + } + inline const Grid<Real> &getArg0() + { + return source; + } + typedef Grid<Real> type0; + inline Grid<Vec3> &getArg1() + { + return target; + } + typedef Grid<Vec3> type1; + inline int &getArg2() + { + return component; + } + typedef int type2; + void runMessage() + { + debMsg("Executing kernel knSetComponent ", 3); + debMsg("Kernel range" + << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ", + 4); + }; + void operator()(const tbb::blocked_range<IndexInt> &__r) const + { + for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++) + op(idx, source, target, component); + } + void run() + { + tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this); + } + const Grid<Real> &source; + Grid<Vec3> ⌖ + int component; +}; +void setComponent(const Grid<Real> &source, Grid<Vec3> &target, int component) +{ + knSetComponent(source, target, component); +} +static PyObject *_W_17(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, "setComponent", !noTiming); + PyObject *_retval = 0; + { + ArgLocker _lock; + const Grid<Real> &source = *_args.getPtr<Grid<Real>>("source", 0, &_lock); + Grid<Vec3> &target = *_args.getPtr<Grid<Vec3>>("target", 1, &_lock); + int component = _args.get<int>("component", 2, &_lock); + _retval = getPyNone(); + setComponent(source, target, component); + _args.check(); + } + pbFinalizePlugin(parent, "setComponent", !noTiming); + return _retval; + } + catch (std::exception &e) { + pbSetError("setComponent", e.what()); + return 0; + } +} +static const Pb::Register _RP_setComponent("", "setComponent", _W_17); +extern "C" { +void PbRegister_setComponent() +{ + KEEP_UNUSED(_RP_setComponent); +} +} + +//****************************************************************************** +// Specialization classes + +void FlagGrid::InitMinXWall(const int &boundaryWidth, Grid<Real> &phiWalls) +{ + const int w = boundaryWidth; + FOR_IJK(phiWalls) + { + phiWalls(i, j, k) = std::min(i - w - .5, (double)phiWalls(i, j, k)); + } +} + +void FlagGrid::InitMaxXWall(const int &boundaryWidth, Grid<Real> &phiWalls) +{ + const int w = boundaryWidth; + FOR_IJK(phiWalls) + { + phiWalls(i, j, k) = std::min(mSize.x - i - 1.5 - w, (double)phiWalls(i, j, k)); + } +} + +void FlagGrid::InitMinYWall(const int &boundaryWidth, Grid<Real> &phiWalls) +{ + const int w = boundaryWidth; + FOR_IJK(phiWalls) + { + phiWalls(i, j, k) = std::min(j - w - .5, (double)phiWalls(i, j, k)); + } +} + +void FlagGrid::InitMaxYWall(const int &boundaryWidth, Grid<Real> &phiWalls) +{ + const int w = boundaryWidth; + FOR_IJK(phiWalls) + { + phiWalls(i, j, k) = std::min(mSize.y - j - 1.5 - w, (double)phiWalls(i, j, k)); + } +} + +void FlagGrid::InitMinZWall(const int &boundaryWidth, Grid<Real> &phiWalls) +{ + const int w = boundaryWidth; + FOR_IJK(phiWalls) + { + phiWalls(i, j, k) = std::min(k - w - .5, (double)phiWalls(i, j, k)); + } +} + +void FlagGrid::InitMaxZWall(const int &boundaryWidth, Grid<Real> &phiWalls) +{ + const int w = boundaryWidth; + FOR_IJK(phiWalls) + { + phiWalls(i, j, k) = std::min(mSize.z - k - 1.5 - w, (double)phiWalls(i, j, k)); + } +} + +void FlagGrid::initDomain(const int &boundaryWidth, + const string &wallIn, + const string &openIn, + const string &inflowIn, + const string &outflowIn, + Grid<Real> *phiWalls) +{ + + int types[6] = {0}; + bool set[6] = {false}; + // make sure we have at least 6 entries + string wall = wallIn; + wall.append(" "); + string open = openIn; + open.append(" "); + string inflow = inflowIn; + inflow.append(" "); + string outflow = outflowIn; + outflow.append(" "); + + if (phiWalls) + phiWalls->setConst(1000000000); + + for (int i = 0; i < 6; ++i) { + // min x-direction + if (!set[0]) { + if (open[i] == 'x') { + types[0] = TypeOpen; + set[0] = true; + } + else if (inflow[i] == 'x') { + types[0] = TypeInflow; + set[0] = true; + } + else if (outflow[i] == 'x') { + types[0] = TypeOutflow; + set[0] = true; + } + else if (wall[i] == 'x') { + types[0] = TypeObstacle; + if (phiWalls) + InitMinXWall(boundaryWidth, *phiWalls); + set[0] = true; + } + } + // max x-direction + if (!set[1]) { + if (open[i] == 'X') { + types[1] = TypeOpen; + set[1] = true; + } + else if (inflow[i] == 'X') { + types[1] = TypeInflow; + set[1] = true; + } + else if (outflow[i] == 'X') { + types[1] = TypeOutflow; + set[1] = true; + } + else if (wall[i] == 'X') { + types[1] = TypeObstacle; + if (phiWalls) + InitMaxXWall(boundaryWidth, *phiWalls); + set[1] = true; + } + } + // min y-direction + if (!set[2]) { + if (open[i] == 'y') { + types[2] = TypeOpen; + set[2] = true; + } + else if (inflow[i] == 'y') { + types[2] = TypeInflow; + set[2] = true; + } + else if (outflow[i] == 'y') { + types[2] = TypeOutflow; + set[2] = true; + } + else if (wall[i] == 'y') { + types[2] = TypeObstacle; + if (phiWalls) + InitMinYWall(boundaryWidth, *phiWalls); + set[2] = true; + } + } + // max y-direction + if (!set[3]) { + if (open[i] == 'Y') { + types[3] = TypeOpen; + set[3] = true; + } + else if (inflow[i] == 'Y') { + types[3] = TypeInflow; + set[3] = true; + } + else if (outflow[i] == 'Y') { + types[3] = TypeOutflow; + set[3] = true; + } + else if (wall[i] == 'Y') { + types[3] = TypeObstacle; + if (phiWalls) + InitMaxYWall(boundaryWidth, *phiWalls); + set[3] = true; + } + } + if (this->is3D()) { + // min z-direction + if (!set[4]) { + if (open[i] == 'z') { + types[4] = TypeOpen; + set[4] = true; + } + else if (inflow[i] == 'z') { + types[4] = TypeInflow; + set[4] = true; + } + else if (outflow[i] == 'z') { + types[4] = TypeOutflow; + set[4] = true; + } + else if (wall[i] == 'z') { + types[4] = TypeObstacle; + if (phiWalls) + InitMinZWall(boundaryWidth, *phiWalls); + set[4] = true; + } + } + // max z-direction + if (!set[5]) { + if (open[i] == 'Z') { + types[5] = TypeOpen; + set[5] = true; + } + else if (inflow[i] == 'Z') { + types[5] = TypeInflow; + set[5] = true; + } + else if (outflow[i] == 'Z') { + types[5] = TypeOutflow; + set[5] = true; + } + else if (wall[i] == 'Z') { + types[5] = TypeObstacle; + if (phiWalls) + InitMaxZWall(boundaryWidth, *phiWalls); + set[5] = true; + } + } + } + } + + setConst(TypeEmpty); + initBoundaries(boundaryWidth, types); +} + +void FlagGrid::initBoundaries(const int &boundaryWidth, const int *types) +{ + const int w = boundaryWidth; + FOR_IJK(*this) + { + bool bnd = (i <= w); + if (bnd) + mData[index(i, j, k)] = types[0]; + bnd = (i >= mSize.x - 1 - w); + if (bnd) + mData[index(i, j, k)] = types[1]; + bnd = (j <= w); + if (bnd) + mData[index(i, j, k)] = types[2]; + bnd = (j >= mSize.y - 1 - w); + if (bnd) + mData[index(i, j, k)] = types[3]; + if (is3D()) { + bnd = (k <= w); + if (bnd) + mData[index(i, j, k)] = types[4]; + bnd = (k >= mSize.z - 1 - w); + if (bnd) + mData[index(i, j, k)] = types[5]; + } + } +} + +void FlagGrid::updateFromLevelset(LevelsetGrid &levelset) +{ + FOR_IDX(*this) + { + if (!isObstacle(idx) && !isOutflow(idx)) { + const Real phi = levelset[idx]; + if (phi <= levelset.invalidTimeValue()) + continue; + + mData[idx] &= ~(TypeEmpty | TypeFluid); // clear empty/fluid flags + mData[idx] |= (phi <= 0) ? TypeFluid : TypeEmpty; // set resepctive flag + } + } +} + +void FlagGrid::fillGrid(int type) +{ + FOR_IDX(*this) + { + if ((mData[idx] & TypeObstacle) == 0 && (mData[idx] & TypeInflow) == 0 && + (mData[idx] & TypeOutflow) == 0 && (mData[idx] & TypeOpen) == 0) + mData[idx] = (mData[idx] & ~(TypeEmpty | TypeFluid)) | type; + } +} + +// flag grid helper + +bool isIsolatedFluidCell(const IndexInt idx, const FlagGrid &flags) +{ + if (!flags.isFluid(idx)) + return false; + if (flags.isFluid(idx - flags.getStrideX())) + return false; + if (flags.isFluid(idx + flags.getStrideX())) + return false; + if (flags.isFluid(idx - flags.getStrideY())) + return false; + if (flags.isFluid(idx + flags.getStrideY())) + return false; + if (!flags.is3D()) + return true; + if (flags.isFluid(idx - flags.getStrideZ())) + return false; + if (flags.isFluid(idx + flags.getStrideZ())) + return false; + return true; +} + +struct knMarkIsolatedFluidCell : public KernelBase { + knMarkIsolatedFluidCell(FlagGrid &flags, const int mark) + : KernelBase(&flags, 0), flags(flags), mark(mark) + { + runMessage(); + run(); + } + inline void op(IndexInt idx, FlagGrid &flags, const int mark) const + { + if (isIsolatedFluidCell(idx, flags)) + flags[idx] = mark; + } + inline FlagGrid &getArg0() + { + return flags; + } + typedef FlagGrid type0; + inline const int &getArg1() + { + return mark; + } + typedef int type1; + void runMessage() + { + debMsg("Executing kernel knMarkIsolatedFluidCell ", 3); + debMsg("Kernel range" + << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ", + 4); + }; + void operator()(const tbb::blocked_range<IndexInt> &__r) const + { + for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++) + op(idx, flags, mark); + } + void run() + { + tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this); + } + FlagGrid &flags; + const int mark; +}; + +void markIsolatedFluidCell(FlagGrid &flags, const int mark) +{ + knMarkIsolatedFluidCell(flags, mark); +} +static PyObject *_W_18(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, "markIsolatedFluidCell", !noTiming); + PyObject *_retval = 0; + { + ArgLocker _lock; + FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock); + const int mark = _args.get<int>("mark", 1, &_lock); + _retval = getPyNone(); + markIsolatedFluidCell(flags, mark); + _args.check(); + } + pbFinalizePlugin(parent, "markIsolatedFluidCell", !noTiming); + return _retval; + } + catch (std::exception &e) { + pbSetError("markIsolatedFluidCell", e.what()); + return 0; + } +} +static const Pb::Register _RP_markIsolatedFluidCell("", "markIsolatedFluidCell", _W_18); +extern "C" { +void PbRegister_markIsolatedFluidCell() +{ + KEEP_UNUSED(_RP_markIsolatedFluidCell); +} +} + +void copyMACData( + const MACGrid &source, MACGrid &target, const FlagGrid &flags, const int flag, const int bnd) +{ + assertMsg(source.getSize().x == target.getSize().x && source.getSize().y == target.getSize().y && + source.getSize().z == target.getSize().z, + "different grid resolutions " << source.getSize() << " vs " << target.getSize()); + + // Grid<Real> divGrid(target.getParent()); + // DivergenceOpMAC(divGrid, target); + // Real fDivOrig = GridSumSqr(divGrid); + + FOR_IJK_BND(target, bnd) + { + if (flags.get(i, j, k) & flag) { + target(i, j, k) = source(i, j, k); + } + } + + // DivergenceOpMAC(divGrid, target); + // Real fDivTransfer = GridSumSqr(divGrid); + // std::cout << "Divergence: " << fDivOrig << " -> " << fDivTransfer << std::endl; +} +static PyObject *_W_19(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, "copyMACData", !noTiming); + PyObject *_retval = 0; + { + ArgLocker _lock; + const MACGrid &source = *_args.getPtr<MACGrid>("source", 0, &_lock); + MACGrid &target = *_args.getPtr<MACGrid>("target", 1, &_lock); + const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 2, &_lock); + const int flag = _args.get<int>("flag", 3, &_lock); + const int bnd = _args.get<int>("bnd", 4, &_lock); + _retval = getPyNone(); + copyMACData(source, target, flags, flag, bnd); + _args.check(); + } + pbFinalizePlugin(parent, "copyMACData", !noTiming); + return _retval; + } + catch (std::exception &e) { + pbSetError("copyMACData", e.what()); + return 0; + } +} +static const Pb::Register _RP_copyMACData("", "copyMACData", _W_19); +extern "C" { +void PbRegister_copyMACData() +{ + KEEP_UNUSED(_RP_copyMACData); +} +} + +// explicit instantiation +template class Grid<int>; +template class Grid<Real>; +template class Grid<Vec3>; + +} // namespace Manta |