////////////////////////////////////////////////////////////////////// // handle texture coordinates (advection, reset, eigenvalues), // Beware -- uses big density maccormack as temporary arrays ////////////////////////////////////////////////////////////////////// void WTURBULENCE::advectTextureCoordinates (float dtOrg, float* xvel, float* yvel, float* zvel, float *tempBig1, float *tempBig2) { // advection SWAP_POINTERS(_tcTemp, _tcU); FLUID_3D::copyBorderX(_tcTemp, _resSm, 0 , _resSm[2]); FLUID_3D::copyBorderY(_tcTemp, _resSm, 0 , _resSm[2]); FLUID_3D::copyBorderZ(_tcTemp, _resSm, 0 , _resSm[2]); FLUID_3D::advectFieldMacCormack1(dtOrg, xvel, yvel, zvel, _tcTemp, tempBig1, _resSm, 0 , _resSm[2]); FLUID_3D::advectFieldMacCormack2(dtOrg, xvel, yvel, zvel, _tcTemp, _tcU, tempBig1, tempBig2, _resSm, NULL, 0 , _resSm[2]); SWAP_POINTERS(_tcTemp, _tcV); FLUID_3D::copyBorderX(_tcTemp, _resSm, 0 , _resSm[2]); FLUID_3D::copyBorderY(_tcTemp, _resSm, 0 , _resSm[2]); FLUID_3D::copyBorderZ(_tcTemp, _resSm, 0 , _resSm[2]); FLUID_3D::advectFieldMacCormack1(dtOrg, xvel, yvel, zvel, _tcTemp, tempBig1, _resSm, 0 , _resSm[2]); FLUID_3D::advectFieldMacCormack2(dtOrg, xvel, yvel, zvel, _tcTemp, _tcV, tempBig1, tempBig2, _resSm, NULL, 0 , _resSm[2]); SWAP_POINTERS(_tcTemp, _tcW); FLUID_3D::copyBorderX(_tcTemp, _resSm, 0 , _resSm[2]); FLUID_3D::copyBorderY(_tcTemp, _resSm, 0 , _resSm[2]); FLUID_3D::copyBorderZ(_tcTemp, _resSm, 0 , _resSm[2]); FLUID_3D::advectFieldMacCormack1(dtOrg, xvel, yvel, zvel, _tcTemp, tempBig1, _resSm, 0 , _resSm[2]); FLUID_3D::advectFieldMacCormack2(dtOrg, xvel, yvel, zvel, _tcTemp, _tcW, tempBig1, tempBig2, _resSm, NULL, 0 , _resSm[2]); }
////////////////////////////////////////////////////////////////////// // Advect using the MacCormack method from the Selle paper ////////////////////////////////////////////////////////////////////// void FLUID_3D::advectMacCormack() { Vec3Int res = Vec3Int(_xRes,_yRes,_zRes); if(DOMAIN_BC_LEFT == 0) copyBorderX(_xVelocity, res); else setZeroX(_xVelocity, res); if(DOMAIN_BC_TOP == 0) copyBorderY(_yVelocity, res); else setZeroY(_yVelocity, res); if(DOMAIN_BC_FRONT == 0) copyBorderZ(_zVelocity, res); else setZeroZ(_zVelocity, res); SWAP_POINTERS(_xVelocity, _xVelocityOld); SWAP_POINTERS(_yVelocity, _yVelocityOld); SWAP_POINTERS(_zVelocity, _zVelocityOld); SWAP_POINTERS(_density, _densityOld); SWAP_POINTERS(_heat, _heatOld); const float dt0 = _dt / _dx; // use force arrays as temp arrays for (int x = 0; x < _totalCells; x++) _xForce[x] = _yForce[x] = 0.0; float* t1 = _xForce; float* t2 = _yForce; advectFieldMacCormack(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _densityOld, _density, t1,t2, res, _obstacles); advectFieldMacCormack(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _heatOld, _heat, t1,t2, res, _obstacles); advectFieldMacCormack(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _xVelocityOld, _xVelocity, t1,t2, res, _obstacles); advectFieldMacCormack(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _yVelocityOld, _yVelocity, t1,t2, res, _obstacles); advectFieldMacCormack(dt0, _xVelocityOld, _yVelocityOld, _zVelocityOld, _zVelocityOld, _zVelocity, t1,t2, res, _obstacles); if(DOMAIN_BC_LEFT == 0) copyBorderX(_xVelocity, res); else setZeroX(_xVelocity, res); if(DOMAIN_BC_TOP == 0) copyBorderY(_yVelocity, res); else setZeroY(_yVelocity, res); if(DOMAIN_BC_FRONT == 0) copyBorderZ(_zVelocity, res); else setZeroZ(_zVelocity, res); setZeroBorder(_density, res); setZeroBorder(_heat, res); for (int x = 0; x < _totalCells; x++) t1[x] = t2[x] = 0.0; }
////////////////////////////////////////////////////////////////////// // diffuse heat ////////////////////////////////////////////////////////////////////// void FLUID_3D::diffuseHeat() { SWAP_POINTERS(_heat, _heatOld); copyBorderAll(_heatOld); solveHeat(_heat, _heatOld, _obstacles); // zero out inside obstacles for (int x = 0; x < _totalCells; x++) if (_obstacles[x]) _heat[x] = 0.0f; }
////////////////////////////////////////////////////////////////////// // step simulation once ////////////////////////////////////////////////////////////////////// void FLUID_3D::step(float dt) { // If border rules have been changed if (_colloPrev != *_borderColli) { setBorderCollisions(); } // set delta time by dt_factor _dt = (*_dtFactor) * dt; // set vorticity from RNA value _vorticityEps = (*_vorticityRNA)/_constantScaling; #if PARALLEL==1 int threadval = 1; threadval = omp_get_max_threads(); int stepParts = 1; float partSize = _zRes; stepParts = threadval*2; // Dividing parallelized sections into numOfThreads * 2 sections partSize = (float)_zRes/stepParts; // Size of one part; if (partSize < 4) {stepParts = threadval; // If the slice gets too low (might actually slow things down, change it to larger partSize = (float)_zRes/stepParts;} if (partSize < 4) {stepParts = (int)(ceil((float)_zRes/4.0f)); // If it's still too low (only possible on future systems with +24 cores), change it to 4 partSize = (float)_zRes/stepParts;} #else int zBegin=0; int zEnd=_zRes; #endif #if PARALLEL==1 #pragma omp parallel { #pragma omp for schedule(static,1) for (int i=0; i<stepParts; i++) { int zBegin = (int)((float)i*partSize + 0.5f); int zEnd = (int)((float)(i+1)*partSize + 0.5f); #endif wipeBoundariesSL(zBegin, zEnd); addVorticity(zBegin, zEnd); addBuoyancy(_heat, _density, zBegin, zEnd); addForce(zBegin, zEnd); #if PARALLEL==1 } // end of parallel #pragma omp barrier #pragma omp single { #endif /* * addForce() changed Temp values to preserve thread safety * (previous functions in per thread loop still needed * original velocity data) * * So swap temp values to velocity */ SWAP_POINTERS(_xVelocity, _xVelocityTemp); SWAP_POINTERS(_yVelocity, _yVelocityTemp); SWAP_POINTERS(_zVelocity, _zVelocityTemp); #if PARALLEL==1 } // end of single #pragma omp barrier #pragma omp for for (int i=0; i<2; i++) { if (i==0) { #endif project(); #if PARALLEL==1 } else { #endif diffuseHeat(); #if PARALLEL==1 } } #pragma omp barrier #pragma omp single { #endif /* * For thread safety use "Old" to read * "current" values but still allow changing values. */ SWAP_POINTERS(_xVelocity, _xVelocityOld); SWAP_POINTERS(_yVelocity, _yVelocityOld); SWAP_POINTERS(_zVelocity, _zVelocityOld); SWAP_POINTERS(_density, _densityOld); SWAP_POINTERS(_heat, _heatOld); advectMacCormackBegin(0, _zRes); #if PARALLEL==1 } // end of single #pragma omp barrier #pragma omp for schedule(static,1) for (int i=0; i<stepParts; i++) { int zBegin = (int)((float)i*partSize + 0.5f); int zEnd = (int)((float)(i+1)*partSize + 0.5f); #endif advectMacCormackEnd1(zBegin, zEnd); #if PARALLEL==1 } // end of parallel #pragma omp barrier #pragma omp for schedule(static,1) for (int i=0; i<stepParts; i++) { int zBegin = (int)((float)i*partSize + 0.5f); int zEnd = (int)((float)(i+1)*partSize + 0.5f); #endif advectMacCormackEnd2(zBegin, zEnd); artificialDampingSL(zBegin, zEnd); // Using forces as temp arrays #if PARALLEL==1 } } for (int i=1; i<stepParts; i++) { int zPos=(int)((float)i*partSize + 0.5f); artificialDampingExactSL(zPos); } #endif /* * swap final velocity back to Velocity array * from temp xForce storage */ SWAP_POINTERS(_xVelocity, _xForce); SWAP_POINTERS(_yVelocity, _yForce); SWAP_POINTERS(_zVelocity, _zForce); _totalTime += _dt; _totalSteps++; for (int i = 0; i < _totalCells; i++) { _xForce[i] = _yForce[i] = _zForce[i] = 0.0f; } }