/****************************************************************************** * * 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 * * Helper functions for interpolation * ******************************************************************************/ #ifndef _INTERPOL_H #define _INTERPOL_H #include "vectorbase.h" // Grid values are stored at i+0.5, j+0.5, k+0.5 // MAC grid values are stored at i,j+0.5,k+0.5 (for x) ... namespace Manta { inline Vec3 fdTangent(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2) { return 0.5 * (getNormalized(p2 - p1) + getNormalized(p1 - p0)); } inline Vec3 crTangent(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2) { return 0.5 * (p2 - p0); } inline Vec3 hermiteSpline(const Vec3 &p0, const Vec3 &p1, const Vec3 &m0, const Vec3 &m1, Real t) { const Real t2 = t * t, t3 = t2 * t; return (2.0 * t3 - 3.0 * t2 + 1.0) * p0 + (t3 - 2.0 * t2 + t) * m0 + (-2.0 * t3 + 3.0 * t2) * p1 + (t3 - t2) * m1; } static inline void checkIndexInterpol(const Vec3i &size, IndexInt idx) { if (idx < 0 || idx > (IndexInt)size.x * size.y * size.z) { std::ostringstream s; s << "Grid interpol dim " << size << " : index " << idx << " out of bound "; errMsg(s.str()); } } // ---------------------------------------------------------------------- // Grid interpolators // ---------------------------------------------------------------------- #define BUILD_INDEX \ Real px = pos.x - 0.5f, py = pos.y - 0.5f, pz = pos.z - 0.5f; \ int xi = (int)px; \ int yi = (int)py; \ int zi = (int)pz; \ Real s1 = px - (Real)xi, s0 = 1. - s1; \ Real t1 = py - (Real)yi, t0 = 1. - t1; \ Real f1 = pz - (Real)zi, f0 = 1. - f1; \ /* clamp to border */ \ if (px < 0.) { \ xi = 0; \ s0 = 1.0; \ s1 = 0.0; \ } \ if (py < 0.) { \ yi = 0; \ t0 = 1.0; \ t1 = 0.0; \ } \ if (pz < 0.) { \ zi = 0; \ f0 = 1.0; \ f1 = 0.0; \ } \ if (xi >= size.x - 1) { \ xi = size.x - 2; \ s0 = 0.0; \ s1 = 1.0; \ } \ if (yi >= size.y - 1) { \ yi = size.y - 2; \ t0 = 0.0; \ t1 = 1.0; \ } \ if (size.z > 1) { \ if (zi >= size.z - 1) { \ zi = size.z - 2; \ f0 = 0.0; \ f1 = 1.0; \ } \ } \ const int X = 1; \ const int Y = size.x; template inline T interpol(const T *data, const Vec3i &size, const int Z, const Vec3 &pos) { BUILD_INDEX IndexInt idx = (IndexInt)xi + (IndexInt)Y * yi + (IndexInt)Z * zi; DEBUG_ONLY(checkIndexInterpol(size, idx)); DEBUG_ONLY(checkIndexInterpol(size, idx + X + Y + Z)); return ((data[idx] * t0 + data[idx + Y] * t1) * s0 + (data[idx + X] * t0 + data[idx + X + Y] * t1) * s1) * f0 + ((data[idx + Z] * t0 + data[idx + Y + Z] * t1) * s0 + (data[idx + X + Z] * t0 + data[idx + X + Y + Z] * t1) * s1) * f1; } template inline Real interpolComponent(const Vec3 *data, const Vec3i &size, const int Z, const Vec3 &pos) { BUILD_INDEX IndexInt idx = (IndexInt)xi + (IndexInt)Y * yi + (IndexInt)Z * zi; DEBUG_ONLY(checkIndexInterpol(size, idx)); DEBUG_ONLY(checkIndexInterpol(size, idx + X + Y + Z)); return ((data[idx][c] * t0 + data[idx + Y][c] * t1) * s0 + (data[idx + X][c] * t0 + data[idx + X + Y][c] * t1) * s1) * f0 + ((data[idx + Z][c] * t0 + data[idx + Y + Z][c] * t1) * s0 + (data[idx + X + Z][c] * t0 + data[idx + X + Y + Z][c] * t1) * s1) * f1; } template inline void setInterpol( T *data, const Vec3i &size, const int Z, const Vec3 &pos, const T &v, Real *sumBuffer) { BUILD_INDEX IndexInt idx = (IndexInt)xi + (IndexInt)Y * yi + (IndexInt)Z * zi; DEBUG_ONLY(checkIndexInterpol(size, idx)); DEBUG_ONLY(checkIndexInterpol(size, idx + X + Y + Z)); T *ref = &data[idx]; Real *sum = &sumBuffer[idx]; Real s0f0 = s0 * f0, s1f0 = s1 * f0, s0f1 = s0 * f1, s1f1 = s1 * f1; Real w0 = t0 * s0f0, wx = t0 * s1f0, wy = t1 * s0f0, wxy = t1 * s1f0; Real wz = t0 * s0f1, wxz = t0 * s1f1, wyz = t1 * s0f1, wxyz = t1 * s1f1; sum[Z] += wz; sum[X + Z] += wxz; sum[Y + Z] += wyz; sum[X + Y + Z] += wxyz; ref[Z] += wz * v; ref[X + Z] += wxz * v; ref[Y + Z] += wyz * v; ref[X + Y + Z] += wxyz * v; sum[0] += w0; sum[X] += wx; sum[Y] += wy; sum[X + Y] += wxy; ref[0] += w0 * v; ref[X] += wx * v; ref[Y] += wy * v; ref[X + Y] += wxy * v; } #define BUILD_INDEX_SHIFT \ BUILD_INDEX \ /* shifted coords */ \ int s_xi = (int)pos.x, s_yi = (int)pos.y, s_zi = (int)pos.z; \ Real s_s1 = pos.x - (Real)s_xi, s_s0 = 1. - s_s1; \ Real s_t1 = pos.y - (Real)s_yi, s_t0 = 1. - s_t1; \ Real s_f1 = pos.z - (Real)s_zi, s_f0 = 1. - s_f1; \ /* clamp to border */ \ if (pos.x < 0) { \ s_xi = 0; \ s_s0 = 1.0; \ s_s1 = 0.0; \ } \ if (pos.y < 0) { \ s_yi = 0; \ s_t0 = 1.0; \ s_t1 = 0.0; \ } \ if (pos.z < 0) { \ s_zi = 0; \ s_f0 = 1.0; \ s_f1 = 0.0; \ } \ if (s_xi >= size.x - 1) { \ s_xi = size.x - 2; \ s_s0 = 0.0; \ s_s1 = 1.0; \ } \ if (s_yi >= size.y - 1) { \ s_yi = size.y - 2; \ s_t0 = 0.0; \ s_t1 = 1.0; \ } \ if (size.z > 1) { \ if (s_zi >= size.z - 1) { \ s_zi = size.z - 2; \ s_f0 = 0.0; \ s_f1 = 1.0; \ } \ } inline Vec3 interpolMAC(const Vec3 *data, const Vec3i &size, const int Z, const Vec3 &pos) { BUILD_INDEX_SHIFT; DEBUG_ONLY(checkIndexInterpol(size, (zi * (IndexInt)size.y + yi) * (IndexInt)size.x + xi)); DEBUG_ONLY(checkIndexInterpol( size, (s_zi * (IndexInt)size.y + s_yi) * (IndexInt)size.x + s_xi + X + Y + Z)); // process individual components Vec3 ret(0.); { // X const Vec3 *ref = &data[((zi * size.y + yi) * size.x + s_xi)]; ret.x = f0 * ((ref[0].x * t0 + ref[Y].x * t1) * s_s0 + (ref[X].x * t0 + ref[X + Y].x * t1) * s_s1) + f1 * ((ref[Z].x * t0 + ref[Z + Y].x * t1) * s_s0 + (ref[X + Z].x * t0 + ref[X + Y + Z].x * t1) * s_s1); } { // Y const Vec3 *ref = &data[((zi * size.y + s_yi) * size.x + xi)]; ret.y = f0 * ((ref[0].y * s_t0 + ref[Y].y * s_t1) * s0 + (ref[X].y * s_t0 + ref[X + Y].y * s_t1) * s1) + f1 * ((ref[Z].y * s_t0 + ref[Z + Y].y * s_t1) * s0 + (ref[X + Z].y * s_t0 + ref[X + Y + Z].y * s_t1) * s1); } { // Z const Vec3 *ref = &data[((s_zi * size.y + yi) * size.x + xi)]; ret.z = s_f0 * ((ref[0].z * t0 + ref[Y].z * t1) * s0 + (ref[X].z * t0 + ref[X + Y].z * t1) * s1) + s_f1 * ((ref[Z].z * t0 + ref[Z + Y].z * t1) * s0 + (ref[X + Z].z * t0 + ref[X + Y + Z].z * t1) * s1); } return ret; } inline void setInterpolMAC( Vec3 *data, const Vec3i &size, const int Z, const Vec3 &pos, const Vec3 &val, Vec3 *sumBuffer) { BUILD_INDEX_SHIFT; DEBUG_ONLY(checkIndexInterpol(size, (zi * (IndexInt)size.y + yi) * (IndexInt)size.x + xi)); DEBUG_ONLY(checkIndexInterpol( size, (s_zi * (IndexInt)size.y + s_yi) * (IndexInt)size.x + s_xi + X + Y + Z)); // process individual components { // X const IndexInt idx = (IndexInt)(zi * size.y + yi) * size.x + s_xi; Vec3 *ref = &data[idx], *sum = &sumBuffer[idx]; Real s0f0 = s_s0 * f0, s1f0 = s_s1 * f0, s0f1 = s_s0 * f1, s1f1 = s_s1 * f1; Real w0 = t0 * s0f0, wx = t0 * s1f0, wy = t1 * s0f0, wxy = t1 * s1f0; Real wz = t0 * s0f1, wxz = t0 * s1f1, wyz = t1 * s0f1, wxyz = t1 * s1f1; sum[Z].x += wz; sum[X + Z].x += wxz; sum[Y + Z].x += wyz; sum[X + Y + Z].x += wxyz; ref[Z].x += wz * val.x; ref[X + Z].x += wxz * val.x; ref[Y + Z].x += wyz * val.x; ref[X + Y + Z].x += wxyz * val.x; sum[0].x += w0; sum[X].x += wx; sum[Y].x += wy; sum[X + Y].x += wxy; ref[0].x += w0 * val.x; ref[X].x += wx * val.x; ref[Y].x += wy * val.x; ref[X + Y].x += wxy * val.x; } { // Y const IndexInt idx = (IndexInt)(zi * size.y + s_yi) * size.x + xi; Vec3 *ref = &data[idx], *sum = &sumBuffer[idx]; Real s0f0 = s0 * f0, s1f0 = s1 * f0, s0f1 = s0 * f1, s1f1 = s1 * f1; Real w0 = s_t0 * s0f0, wx = s_t0 * s1f0, wy = s_t1 * s0f0, wxy = s_t1 * s1f0; Real wz = s_t0 * s0f1, wxz = s_t0 * s1f1, wyz = s_t1 * s0f1, wxyz = s_t1 * s1f1; sum[Z].y += wz; sum[X + Z].y += wxz; sum[Y + Z].y += wyz; sum[X + Y + Z].y += wxyz; ref[Z].y += wz * val.y; ref[X + Z].y += wxz * val.y; ref[Y + Z].y += wyz * val.y; ref[X + Y + Z].y += wxyz * val.y; sum[0].y += w0; sum[X].y += wx; sum[Y].y += wy; sum[X + Y].y += wxy; ref[0].y += w0 * val.y; ref[X].y += wx * val.y; ref[Y].y += wy * val.y; ref[X + Y].y += wxy * val.y; } { // Z const IndexInt idx = (IndexInt)(s_zi * size.y + yi) * size.x + xi; Vec3 *ref = &data[idx], *sum = &sumBuffer[idx]; Real s0f0 = s0 * s_f0, s1f0 = s1 * s_f0, s0f1 = s0 * s_f1, s1f1 = s1 * s_f1; Real w0 = t0 * s0f0, wx = t0 * s1f0, wy = t1 * s0f0, wxy = t1 * s1f0; Real wz = t0 * s0f1, wxz = t0 * s1f1, wyz = t1 * s0f1, wxyz = t1 * s1f1; sum[0].z += w0; sum[X].z += wx; sum[Y].z += wy; sum[X + Y].z += wxy; sum[Z].z += wz; sum[X + Z].z += wxz; sum[Y + Z].z += wyz; sum[X + Y + Z].z += wxyz; ref[0].z += w0 * val.z; ref[X].z += wx * val.z; ref[Y].z += wy * val.z; ref[X + Y].z += wxy * val.z; ref[Z].z += wz * val.z; ref[X + Z].z += wxz * val.z; ref[Y + Z].z += wyz * val.z; ref[X + Y + Z].z += wxyz * val.z; } } #undef BUILD_INDEX #undef BUILD_INDEX_SHIFT } // namespace Manta #endif