a) Enable the possibility to remove the "air bubble" around submerged collision object. This feature is enabled as standard for new files. The code was found in elbeem by nudelZ, coded and provided by Nils Thürey (thanks!) b) Old baked files gets deleted if a new bake gets started (were overwritten before and resulted in weird old bake + new bake mixture) (idea by nudelZ)
2383 lines
84 KiB
C++
2383 lines
84 KiB
C++
/** \file elbeem/intern/solver_init.cpp
|
|
* \ingroup elbeem
|
|
*/
|
|
/******************************************************************************
|
|
*
|
|
* El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
|
|
* Copyright 2003-2006 Nils Thuerey
|
|
*
|
|
* Standard LBM Factory implementation
|
|
*
|
|
*****************************************************************************/
|
|
|
|
|
|
#include "solver_class.h"
|
|
#include "solver_relax.h"
|
|
// for geo init FGI_ defines
|
|
#include "elbeem.h"
|
|
|
|
// helper for 2d init
|
|
#define SWAPYZ(vec) { \
|
|
const LbmFloat tmp = (vec)[2]; \
|
|
(vec)[2] = (vec)[1]; (vec)[1] = tmp; }
|
|
|
|
|
|
/*****************************************************************************/
|
|
//! common variables
|
|
|
|
/*****************************************************************************/
|
|
/*! 3D implementation D3Q19 */
|
|
#if LBMDIM==3
|
|
|
|
//! how many dimensions?
|
|
const int LbmFsgrSolver::cDimension = 3;
|
|
|
|
// Wi factors for collide step
|
|
const LbmFloat LbmFsgrSolver::cCollenZero = (1.0/3.0);
|
|
const LbmFloat LbmFsgrSolver::cCollenOne = (1.0/18.0);
|
|
const LbmFloat LbmFsgrSolver::cCollenSqrtTwo = (1.0/36.0);
|
|
|
|
//! threshold value for filled/emptied cells
|
|
const LbmFloat LbmFsgrSolver::cMagicNr2 = 1.0005;
|
|
const LbmFloat LbmFsgrSolver::cMagicNr2Neg = -0.0005;
|
|
const LbmFloat LbmFsgrSolver::cMagicNr = 1.010001;
|
|
const LbmFloat LbmFsgrSolver::cMagicNrNeg = -0.010001;
|
|
|
|
//! size of a single set of distribution functions
|
|
const int LbmFsgrSolver::cDfNum = 19;
|
|
//! direction vector contain vecs for all spatial dirs, even if not used for LBM model
|
|
const int LbmFsgrSolver::cDirNum = 27;
|
|
|
|
//const string LbmFsgrSolver::dfString[ cDfNum ] = {
|
|
const char* LbmFsgrSolver::dfString[ cDfNum ] = {
|
|
" C", " N"," S"," E"," W"," T"," B",
|
|
"NE","NW","SE","SW",
|
|
"NT","NB","ST","SB",
|
|
"ET","EB","WT","WB"
|
|
};
|
|
|
|
const int LbmFsgrSolver::dfNorm[ cDfNum ] = {
|
|
cDirC, cDirN, cDirS, cDirE, cDirW, cDirT, cDirB,
|
|
cDirNE, cDirNW, cDirSE, cDirSW,
|
|
cDirNT, cDirNB, cDirST, cDirSB,
|
|
cDirET, cDirEB, cDirWT, cDirWB
|
|
};
|
|
|
|
const int LbmFsgrSolver::dfInv[ cDfNum ] = {
|
|
cDirC, cDirS, cDirN, cDirW, cDirE, cDirB, cDirT,
|
|
cDirSW, cDirSE, cDirNW, cDirNE,
|
|
cDirSB, cDirST, cDirNB, cDirNT,
|
|
cDirWB, cDirWT, cDirEB, cDirET
|
|
};
|
|
|
|
const int LbmFsgrSolver::dfRefX[ cDfNum ] = {
|
|
0, 0, 0, 0, 0, 0, 0,
|
|
cDirSE, cDirSW, cDirNE, cDirNW,
|
|
0, 0, 0, 0,
|
|
cDirEB, cDirET, cDirWB, cDirWT
|
|
};
|
|
|
|
const int LbmFsgrSolver::dfRefY[ cDfNum ] = {
|
|
0, 0, 0, 0, 0, 0, 0,
|
|
cDirNW, cDirNE, cDirSW, cDirSE,
|
|
cDirNB, cDirNT, cDirSB, cDirST,
|
|
0, 0, 0, 0
|
|
};
|
|
|
|
const int LbmFsgrSolver::dfRefZ[ cDfNum ] = {
|
|
0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0,
|
|
cDirST, cDirSB, cDirNT, cDirNB,
|
|
cDirWT, cDirWB, cDirET, cDirEB
|
|
};
|
|
|
|
// Vector Order 3D:
|
|
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
|
|
// 0, 0, 0, 1,-1, 0, 0, 1,-1, 1,-1, 0, 0, 0, 0, 1, 1,-1,-1, 1,-1, 1,-1, 1,-1, 1,-1
|
|
// 0, 1,-1, 0, 0, 0, 0, 1, 1,-1,-1, 1, 1,-1,-1, 0, 0, 0, 0, 1, 1,-1,-1, 1, 1,-1,-1
|
|
// 0, 0, 0, 0, 0, 1,-1, 0, 0, 0, 0, 1,-1, 1,-1, 1,-1, 1,-1, 1, 1, 1, 1, -1,-1,-1,-1
|
|
|
|
const int LbmFsgrSolver::dfVecX[ cDirNum ] = {
|
|
0, 0,0, 1,-1, 0,0,
|
|
1,-1,1,-1,
|
|
0,0,0,0,
|
|
1,1,-1,-1,
|
|
1,-1, 1,-1,
|
|
1,-1, 1,-1,
|
|
};
|
|
const int LbmFsgrSolver::dfVecY[ cDirNum ] = {
|
|
0, 1,-1, 0,0,0,0,
|
|
1,1,-1,-1,
|
|
1,1,-1,-1,
|
|
0,0,0,0,
|
|
1, 1,-1,-1,
|
|
1, 1,-1,-1
|
|
};
|
|
const int LbmFsgrSolver::dfVecZ[ cDirNum ] = {
|
|
0, 0,0,0,0,1,-1,
|
|
0,0,0,0,
|
|
1,-1,1,-1,
|
|
1,-1,1,-1,
|
|
1, 1, 1, 1,
|
|
-1,-1,-1,-1
|
|
};
|
|
|
|
const LbmFloat LbmFsgrSolver::dfDvecX[ cDirNum ] = {
|
|
0, 0,0, 1,-1, 0,0,
|
|
1,-1,1,-1,
|
|
0,0,0,0,
|
|
1,1,-1,-1,
|
|
1,-1, 1,-1,
|
|
1,-1, 1,-1
|
|
};
|
|
const LbmFloat LbmFsgrSolver::dfDvecY[ cDirNum ] = {
|
|
0, 1,-1, 0,0,0,0,
|
|
1,1,-1,-1,
|
|
1,1,-1,-1,
|
|
0,0,0,0,
|
|
1, 1,-1,-1,
|
|
1, 1,-1,-1
|
|
};
|
|
const LbmFloat LbmFsgrSolver::dfDvecZ[ cDirNum ] = {
|
|
0, 0,0,0,0,1,-1,
|
|
0,0,0,0,
|
|
1,-1,1,-1,
|
|
1,-1,1,-1,
|
|
1, 1, 1, 1,
|
|
-1,-1,-1,-1
|
|
};
|
|
|
|
/* principal directions */
|
|
const int LbmFsgrSolver::princDirX[ 2*LbmFsgrSolver::cDimension ] = {
|
|
1,-1, 0,0, 0,0
|
|
};
|
|
const int LbmFsgrSolver::princDirY[ 2*LbmFsgrSolver::cDimension ] = {
|
|
0,0, 1,-1, 0,0
|
|
};
|
|
const int LbmFsgrSolver::princDirZ[ 2*LbmFsgrSolver::cDimension ] = {
|
|
0,0, 0,0, 1,-1
|
|
};
|
|
|
|
/*! arrays for les model coefficients, inited in lbmsolver constructor */
|
|
LbmFloat LbmFsgrSolver::lesCoeffDiag[ (cDimension-1)*(cDimension-1) ][ cDirNum ];
|
|
LbmFloat LbmFsgrSolver::lesCoeffOffdiag[ cDimension ][ cDirNum ];
|
|
|
|
|
|
const LbmFloat LbmFsgrSolver::dfLength[ cDfNum ]= {
|
|
cCollenZero,
|
|
cCollenOne, cCollenOne, cCollenOne,
|
|
cCollenOne, cCollenOne, cCollenOne,
|
|
cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo,
|
|
cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo,
|
|
cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo
|
|
};
|
|
|
|
/* precalculated equilibrium dfs, inited in lbmsolver constructor */
|
|
LbmFloat LbmFsgrSolver::dfEquil[ dTotalNum ];
|
|
|
|
#else // end LBMDIM==3 , LBMDIM==2
|
|
|
|
/*****************************************************************************/
|
|
/*! 2D implementation D2Q9 */
|
|
|
|
//! how many dimensions?
|
|
const int LbmFsgrSolver::cDimension = 2;
|
|
|
|
//! Wi factors for collide step
|
|
const LbmFloat LbmFsgrSolver::cCollenZero = (4.0/9.0);
|
|
const LbmFloat LbmFsgrSolver::cCollenOne = (1.0/9.0);
|
|
const LbmFloat LbmFsgrSolver::cCollenSqrtTwo = (1.0/36.0);
|
|
|
|
//! threshold value for filled/emptied cells
|
|
const LbmFloat LbmFsgrSolver::cMagicNr2 = 1.0005;
|
|
const LbmFloat LbmFsgrSolver::cMagicNr2Neg = -0.0005;
|
|
const LbmFloat LbmFsgrSolver::cMagicNr = 1.010001;
|
|
const LbmFloat LbmFsgrSolver::cMagicNrNeg = -0.010001;
|
|
|
|
//! size of a single set of distribution functions
|
|
const int LbmFsgrSolver::cDfNum = 9;
|
|
const int LbmFsgrSolver::cDirNum = 9;
|
|
|
|
//const string LbmFsgrSolver::dfString[ cDfNum ] = {
|
|
const char* LbmFsgrSolver::dfString[ cDfNum ] = {
|
|
" C",
|
|
" N", " S", " E", " W",
|
|
"NE", "NW", "SE","SW"
|
|
};
|
|
|
|
const int LbmFsgrSolver::dfNorm[ cDfNum ] = {
|
|
cDirC,
|
|
cDirN, cDirS, cDirE, cDirW,
|
|
cDirNE, cDirNW, cDirSE, cDirSW
|
|
};
|
|
|
|
const int LbmFsgrSolver::dfInv[ cDfNum ] = {
|
|
cDirC,
|
|
cDirS, cDirN, cDirW, cDirE,
|
|
cDirSW, cDirSE, cDirNW, cDirNE
|
|
};
|
|
|
|
const int LbmFsgrSolver::dfRefX[ cDfNum ] = {
|
|
0,
|
|
0, 0, 0, 0,
|
|
cDirSE, cDirSW, cDirNE, cDirNW
|
|
};
|
|
|
|
const int LbmFsgrSolver::dfRefY[ cDfNum ] = {
|
|
0,
|
|
0, 0, 0, 0,
|
|
cDirNW, cDirNE, cDirSW, cDirSE
|
|
};
|
|
|
|
const int LbmFsgrSolver::dfRefZ[ cDfNum ] = {
|
|
0, 0, 0, 0, 0,
|
|
0, 0, 0, 0
|
|
};
|
|
|
|
// Vector Order 2D:
|
|
// 0 1 2 3 4 5 6 7 8
|
|
// 0, 0,0, 1,-1, 1,-1,1,-1
|
|
// 0, 1,-1, 0,0, 1,1,-1,-1
|
|
|
|
const int LbmFsgrSolver::dfVecX[ cDirNum ] = {
|
|
0,
|
|
0,0, 1,-1,
|
|
1,-1,1,-1
|
|
};
|
|
const int LbmFsgrSolver::dfVecY[ cDirNum ] = {
|
|
0,
|
|
1,-1, 0,0,
|
|
1,1,-1,-1
|
|
};
|
|
const int LbmFsgrSolver::dfVecZ[ cDirNum ] = {
|
|
0, 0,0,0,0, 0,0,0,0
|
|
};
|
|
|
|
const LbmFloat LbmFsgrSolver::dfDvecX[ cDirNum ] = {
|
|
0,
|
|
0,0, 1,-1,
|
|
1,-1,1,-1
|
|
};
|
|
const LbmFloat LbmFsgrSolver::dfDvecY[ cDirNum ] = {
|
|
0,
|
|
1,-1, 0,0,
|
|
1,1,-1,-1
|
|
};
|
|
const LbmFloat LbmFsgrSolver::dfDvecZ[ cDirNum ] = {
|
|
0, 0,0,0,0, 0,0,0,0
|
|
};
|
|
|
|
const int LbmFsgrSolver::princDirX[ 2*LbmFsgrSolver::cDimension ] = {
|
|
1,-1, 0,0
|
|
};
|
|
const int LbmFsgrSolver::princDirY[ 2*LbmFsgrSolver::cDimension ] = {
|
|
0,0, 1,-1
|
|
};
|
|
const int LbmFsgrSolver::princDirZ[ 2*LbmFsgrSolver::cDimension ] = {
|
|
0,0, 0,0
|
|
};
|
|
|
|
|
|
/*! arrays for les model coefficients, inited in lbmsolver constructor */
|
|
LbmFloat LbmFsgrSolver::lesCoeffDiag[ (cDimension-1)*(cDimension-1) ][ cDirNum ];
|
|
LbmFloat LbmFsgrSolver::lesCoeffOffdiag[ cDimension ][ cDirNum ];
|
|
|
|
|
|
const LbmFloat LbmFsgrSolver::dfLength[ cDfNum ]= {
|
|
cCollenZero,
|
|
cCollenOne, cCollenOne, cCollenOne, cCollenOne,
|
|
cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo
|
|
};
|
|
|
|
/* precalculated equilibrium dfs, inited in lbmsolver constructor */
|
|
LbmFloat LbmFsgrSolver::dfEquil[ dTotalNum ];
|
|
|
|
// D2Q9 end
|
|
#endif // LBMDIM==2
|
|
|
|
|
|
// required globals
|
|
extern bool glob_mpactive;
|
|
extern int glob_mpnum, glob_mpindex;
|
|
|
|
|
|
/******************************************************************************
|
|
* Lbm Constructor
|
|
*****************************************************************************/
|
|
LbmFsgrSolver::LbmFsgrSolver() :
|
|
//D(),
|
|
mCurrentMass(0.0), mCurrentVolume(0.0),
|
|
mNumProblems(0),
|
|
mAvgMLSUPS(0.0), mAvgMLSUPSCnt(0.0),
|
|
mpPreviewSurface(NULL),
|
|
mTimeAdap(true), mForceTimeStepReduce(false),
|
|
mFVHeight(0.0), mFVArea(1.0), mUpdateFVHeight(false),
|
|
mInitSurfaceSmoothing(0), mFsSurfGenSetting(0),
|
|
mTimestepReduceLock(0),
|
|
mTimeSwitchCounts(0), mTimeMaxvelStepCnt(0),
|
|
mSimulationTime(0.0), mLastSimTime(0.0),
|
|
mMinTimestep(0.0), mMaxTimestep(0.0),
|
|
mMaxNoCells(0), mMinNoCells(0), mAvgNumUsedCells(0),
|
|
mObjectSpeeds(), mObjectPartslips(), mObjectMassMovnd(),
|
|
mMOIVertices(), mMOIVerticesOld(), mMOINormals(),
|
|
mIsoWeightMethod(1),
|
|
mMaxRefine(1),
|
|
mDfScaleUp(-1.0), mDfScaleDown(-1.0),
|
|
mInitialCsmago(0.02), // set to 0.02 for mMaxRefine==0 below and default for fine level, coarser ones are 0.03
|
|
mDebugOmegaRet(0.0),
|
|
mLastOmega(1e10), mLastGravity(1e10),
|
|
mNumInvIfTotal(0), mNumFsgrChanges(0),
|
|
mDisableStandingFluidInit(0),
|
|
mInit2dYZ(false),
|
|
mForceTadapRefine(-1), mCutoff(-1)
|
|
{
|
|
mpControl = new LbmControlData();
|
|
|
|
#if LBM_INCLUDE_TESTSOLVERS==1
|
|
mpTest = new LbmTestdata();
|
|
mMpNum = mMpIndex = 0;
|
|
mOrgSizeX = 0;
|
|
mOrgStartX = 0.;
|
|
mOrgEndX = 0.;
|
|
#endif // LBM_INCLUDE_TESTSOLVERS!=1
|
|
mpIso = new IsoSurface( mIsoValue );
|
|
|
|
// init equilibrium dist. func
|
|
LbmFloat rho=1.0;
|
|
FORDF0 {
|
|
dfEquil[l] = this->getCollideEq( l,rho, 0.0, 0.0, 0.0);
|
|
}
|
|
dfEquil[dMass] = 1.;
|
|
dfEquil[dFfrac] = 1.;
|
|
dfEquil[dFlux] = FLUX_INIT;
|
|
|
|
// init LES
|
|
int odm = 0;
|
|
for(int m=0; m<LBMDIM; m++) {
|
|
for(int l=0; l<cDfNum; l++) {
|
|
this->lesCoeffDiag[m][l] =
|
|
this->lesCoeffOffdiag[m][l] = 0.0;
|
|
}
|
|
}
|
|
for(int m=0; m<LBMDIM; m++) {
|
|
for(int n=0; n<LBMDIM; n++) {
|
|
for(int l=1; l<cDfNum; l++) {
|
|
LbmFloat em;
|
|
switch(m) {
|
|
case 0: em = dfDvecX[l]; break;
|
|
case 1: em = dfDvecY[l]; break;
|
|
case 2: em = dfDvecZ[l]; break;
|
|
default: em = -1.0; errFatal("SMAGO1","err m="<<m, SIMWORLD_GENERICERROR);
|
|
}
|
|
LbmFloat en;
|
|
switch(n) {
|
|
case 0: en = dfDvecX[l]; break;
|
|
case 1: en = dfDvecY[l]; break;
|
|
case 2: en = dfDvecZ[l]; break;
|
|
default: en = -1.0; errFatal("SMAGO2","err n="<<n, SIMWORLD_GENERICERROR);
|
|
}
|
|
const LbmFloat coeff = em*en;
|
|
if(m==n) {
|
|
this->lesCoeffDiag[m][l] = coeff;
|
|
} else {
|
|
if(m>n) {
|
|
this->lesCoeffOffdiag[odm][l] = coeff;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(m==n) {
|
|
} else {
|
|
if(m>n) odm++;
|
|
}
|
|
}
|
|
}
|
|
|
|
mDvecNrm[0] = LbmVec(0.0);
|
|
FORDF1 {
|
|
mDvecNrm[l] = getNormalized(
|
|
LbmVec(dfDvecX[dfInv[l]], dfDvecY[dfInv[l]], dfDvecZ[dfInv[l]] )
|
|
) * -1.0;
|
|
}
|
|
|
|
// calculate gauss weights for restriction
|
|
//LbmFloat mGaussw[27];
|
|
LbmFloat totGaussw = 0.0;
|
|
const LbmFloat alpha = 1.0;
|
|
const LbmFloat gw = sqrt(2.0*LBMDIM);
|
|
#if ELBEEM_PLUGIN!=1
|
|
errMsg("coarseRestrictFromFine", "TCRFF_DFDEBUG2 test df/dir num!");
|
|
#endif
|
|
for(int n=0;(n<cDirNum); n++) { mGaussw[n] = 0.0; }
|
|
//for(int n=0;(n<cDirNum); n++) {
|
|
for(int n=0;(n<cDfNum); n++) {
|
|
const LbmFloat d = norm(LbmVec(dfVecX[n], dfVecY[n], dfVecZ[n]));
|
|
LbmFloat w = expf( -alpha*d*d ) - expf( -alpha*gw*gw );
|
|
mGaussw[n] = w;
|
|
totGaussw += w;
|
|
}
|
|
for(int n=0;(n<cDirNum); n++) {
|
|
mGaussw[n] = mGaussw[n]/totGaussw;
|
|
}
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/* Destructor */
|
|
/*****************************************************************************/
|
|
LbmFsgrSolver::~LbmFsgrSolver()
|
|
{
|
|
if(!mInitDone){ debMsgStd("LbmFsgrSolver::LbmFsgrSolver",DM_MSG,"not inited...",0); return; }
|
|
#if COMPRESSGRIDS==1
|
|
delete [] mLevel[mMaxRefine].mprsCells[1];
|
|
mLevel[mMaxRefine].mprsCells[0] = mLevel[mMaxRefine].mprsCells[1] = NULL;
|
|
#endif // COMPRESSGRIDS==1
|
|
|
|
for(int i=0; i<=mMaxRefine; i++) {
|
|
for(int s=0; s<2; s++) {
|
|
if(mLevel[i].mprsCells[s]) delete [] mLevel[i].mprsCells[s];
|
|
if(mLevel[i].mprsFlags[s]) delete [] mLevel[i].mprsFlags[s];
|
|
}
|
|
}
|
|
delete mpIso;
|
|
if(mpPreviewSurface) delete mpPreviewSurface;
|
|
// cleanup done during scene deletion...
|
|
|
|
if(mpControl) delete mpControl;
|
|
|
|
// always output performance estimate
|
|
debMsgStd("LbmFsgrSolver::~LbmFsgrSolver",DM_MSG," Avg. MLSUPS:"<<(mAvgMLSUPS/mAvgMLSUPSCnt), 5);
|
|
if(!mSilent) debMsgStd("LbmFsgrSolver::~LbmFsgrSolver",DM_MSG,"Deleted...",10);
|
|
}
|
|
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
* initilize variables fom attribute list
|
|
*****************************************************************************/
|
|
void LbmFsgrSolver::parseAttrList()
|
|
{
|
|
LbmSolverInterface::parseStdAttrList();
|
|
|
|
string matIso("default");
|
|
matIso = mpSifAttrs->readString("material_surf", matIso, "SimulationLbm","mpIso->material", false );
|
|
mpIso->setMaterialName( matIso );
|
|
mOutputSurfacePreview = mpSifAttrs->readInt("surfacepreview", mOutputSurfacePreview, "SimulationLbm","mOutputSurfacePreview", false );
|
|
mTimeAdap = mpSifAttrs->readBool("timeadap", mTimeAdap, "SimulationLbm","mTimeAdap", false );
|
|
mDomainBound = mpSifAttrs->readString("domainbound", mDomainBound, "SimulationLbm","mDomainBound", false );
|
|
mDomainPartSlipValue = mpSifAttrs->readFloat("domainpartslip", mDomainPartSlipValue, "SimulationLbm","mDomainPartSlipValue", false );
|
|
|
|
mIsoWeightMethod= mpSifAttrs->readInt("isoweightmethod", mIsoWeightMethod, "SimulationLbm","mIsoWeightMethod", false );
|
|
mInitSurfaceSmoothing = mpSifAttrs->readInt("initsurfsmooth", mInitSurfaceSmoothing, "SimulationLbm","mInitSurfaceSmoothing", false );
|
|
mSmoothSurface = mpSifAttrs->readFloat("smoothsurface", mSmoothSurface, "SimulationLbm","mSmoothSurface", false );
|
|
mSmoothNormals = mpSifAttrs->readFloat("smoothnormals", mSmoothNormals, "SimulationLbm","mSmoothNormals", false );
|
|
mFsSurfGenSetting = mpSifAttrs->readInt("fssurfgen", mFsSurfGenSetting, "SimulationLbm","mFsSurfGenSetting", false );
|
|
|
|
// refinement
|
|
mMaxRefine = mRefinementDesired;
|
|
mMaxRefine = mpSifAttrs->readInt("maxrefine", mMaxRefine ,"LbmFsgrSolver", "mMaxRefine", false);
|
|
if(mMaxRefine<0) mMaxRefine=0;
|
|
if(mMaxRefine>FSGR_MAXNOOFLEVELS) mMaxRefine=FSGR_MAXNOOFLEVELS-1;
|
|
mDisableStandingFluidInit = mpSifAttrs->readInt("disable_stfluidinit", mDisableStandingFluidInit,"LbmFsgrSolver", "mDisableStandingFluidInit", false);
|
|
mInit2dYZ = mpSifAttrs->readBool("init2dyz", mInit2dYZ,"LbmFsgrSolver", "mInit2dYZ", false);
|
|
mForceTadapRefine = mpSifAttrs->readInt("forcetadaprefine", mForceTadapRefine,"LbmFsgrSolver", "mForceTadapRefine", false);
|
|
|
|
// demo mode settings
|
|
mFVHeight = mpSifAttrs->readFloat("fvolheight", mFVHeight, "LbmFsgrSolver","mFVHeight", false );
|
|
// FIXME check needed?
|
|
mFVArea = mpSifAttrs->readFloat("fvolarea", mFVArea, "LbmFsgrSolver","mFArea", false );
|
|
|
|
// debugging - skip some time...
|
|
double starttimeskip = 0.;
|
|
starttimeskip = mpSifAttrs->readFloat("forcestarttimeskip", starttimeskip, "LbmFsgrSolver","starttimeskip", false );
|
|
mSimulationTime += starttimeskip;
|
|
if(starttimeskip>0.) debMsgStd("LbmFsgrSolver::parseStdAttrList",DM_NOTIFY,"Used starttimeskip="<<starttimeskip<<", t="<<mSimulationTime, 1);
|
|
|
|
mpControl->parseControldataAttrList(mpSifAttrs);
|
|
|
|
#if LBM_INCLUDE_TESTSOLVERS==1
|
|
mUseTestdata = 0;
|
|
mUseTestdata = mpSifAttrs->readBool("use_testdata", mUseTestdata,"LbmFsgrSolver", "mUseTestdata", false);
|
|
mpTest->parseTestdataAttrList(mpSifAttrs);
|
|
#ifdef ELBEEM_PLUGIN
|
|
mUseTestdata=1; // DEBUG
|
|
#endif // ELBEEM_PLUGIN
|
|
|
|
mMpNum = mpSifAttrs->readInt("mpnum", mMpNum ,"LbmFsgrSolver", "mMpNum", false);
|
|
mMpIndex = mpSifAttrs->readInt("mpindex", mMpIndex ,"LbmFsgrSolver", "mMpIndex", false);
|
|
if(glob_mpactive) {
|
|
// used instead...
|
|
mMpNum = glob_mpnum;
|
|
mMpIndex = glob_mpindex;
|
|
} else {
|
|
glob_mpnum = mMpNum;
|
|
glob_mpindex = 0;
|
|
}
|
|
errMsg("LbmFsgrSolver::parseAttrList"," mpactive:"<<glob_mpactive<<", "<<glob_mpindex<<"/"<<glob_mpnum);
|
|
if(mMpNum>0) {
|
|
mUseTestdata=1; // needed in this case...
|
|
}
|
|
|
|
errMsg("LbmFsgrSolver::LBM_INCLUDE_TESTSOLVERS","Active, mUseTestdata:"<<mUseTestdata<<" ");
|
|
#else // LBM_INCLUDE_TESTSOLVERS!=1
|
|
// not testsolvers, off by default
|
|
mUseTestdata = 0;
|
|
if(mFarFieldSize>=2.) mUseTestdata=1; // equiv. to test solver check
|
|
#endif // LBM_INCLUDE_TESTSOLVERS!=1
|
|
|
|
mInitialCsmago = mpSifAttrs->readFloat("csmago", mInitialCsmago, "SimulationLbm","mInitialCsmago", false );
|
|
// deprecated!
|
|
float mInitialCsmagoCoarse = 0.0;
|
|
mInitialCsmagoCoarse = mpSifAttrs->readFloat("csmago_coarse", mInitialCsmagoCoarse, "SimulationLbm","mInitialCsmagoCoarse", false );
|
|
#if USE_LES==1
|
|
#else // USE_LES==1
|
|
debMsgStd("LbmFsgrSolver", DM_WARNING, "LES model switched off!",2);
|
|
mInitialCsmago = 0.0;
|
|
#endif // USE_LES==1
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
* (part of enabling chapter 6 of "Free Surface Flows with Moving and Deforming Objects for LBM")
|
|
*****************************************************************************/
|
|
void LbmFsgrSolver::setSurfGenSettings(short value)
|
|
{
|
|
mFsSurfGenSetting = value;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
* Initialize omegas and forces on all levels (for init/timestep change)
|
|
*****************************************************************************/
|
|
void LbmFsgrSolver::initLevelOmegas()
|
|
{
|
|
// no explicit settings
|
|
mOmega = mpParam->calculateOmega(mSimulationTime);
|
|
mGravity = vec2L( mpParam->calculateGravity(mSimulationTime) );
|
|
mSurfaceTension = 0.; //mpParam->calculateSurfaceTension(); // unused
|
|
if(mInit2dYZ) { SWAPYZ(mGravity); }
|
|
|
|
// check if last init was ok
|
|
LbmFloat gravDelta = norm(mGravity-mLastGravity);
|
|
//errMsg("ChannelAnimDebug","t:"<<mSimulationTime<<" om:"<<mOmega<<" - lom:"<<mLastOmega<<" gv:"<<mGravity<<" - "<<mLastGravity<<" , "<<gravDelta );
|
|
if((mOmega == mLastOmega) && (gravDelta<=0.0)) return;
|
|
|
|
if(mInitialCsmago<=0.0) {
|
|
if(OPT3D==1) {
|
|
errFatal("LbmFsgrSolver::initLevelOmegas","Csmago-LES = 0 not supported for optimized 3D version...",SIMWORLD_INITERROR);
|
|
return;
|
|
}
|
|
}
|
|
|
|
LbmFloat fineCsmago = mInitialCsmago;
|
|
LbmFloat coarseCsmago = mInitialCsmago;
|
|
LbmFloat maxFineCsmago1 = 0.026;
|
|
LbmFloat maxCoarseCsmago1 = 0.029; // try stabilizing
|
|
LbmFloat maxFineCsmago2 = 0.028;
|
|
LbmFloat maxCoarseCsmago2 = 0.032; // try stabilizing some more
|
|
if((mMaxRefine==1)&&(mInitialCsmago<maxFineCsmago1)) {
|
|
fineCsmago = maxFineCsmago1;
|
|
coarseCsmago = maxCoarseCsmago1;
|
|
}
|
|
if((mMaxRefine>1)&&(mInitialCsmago<maxFineCsmago2)) {
|
|
fineCsmago = maxFineCsmago2;
|
|
coarseCsmago = maxCoarseCsmago2;
|
|
}
|
|
|
|
|
|
// use Tau instead of Omega for calculations
|
|
{ // init base level
|
|
int i = mMaxRefine;
|
|
mLevel[i].omega = mOmega;
|
|
mLevel[i].timestep = mpParam->getTimestep();
|
|
mLevel[i].lcsmago = fineCsmago; //CSMAGO_INITIAL;
|
|
mLevel[i].lcsmago_sqr = mLevel[i].lcsmago*mLevel[i].lcsmago;
|
|
mLevel[i].lcnu = (2.0* (1.0/mLevel[i].omega)-1.0) * (1.0/6.0);
|
|
}
|
|
|
|
// init all sub levels
|
|
for(int i=mMaxRefine-1; i>=0; i--) {
|
|
//mLevel[i].omega = 2.0 * (mLevel[i+1].omega-0.5) + 0.5;
|
|
double nomega = 0.5 * ( (1.0/(double)mLevel[i+1].omega) -0.5) + 0.5;
|
|
nomega = 1.0/nomega;
|
|
mLevel[i].omega = (LbmFloat)nomega;
|
|
mLevel[i].timestep = 2.0 * mLevel[i+1].timestep;
|
|
mLevel[i].lcsmago = coarseCsmago;
|
|
mLevel[i].lcsmago_sqr = mLevel[i].lcsmago*mLevel[i].lcsmago;
|
|
mLevel[i].lcnu = (2.0* (1.0/mLevel[i].omega)-1.0) * (1.0/6.0);
|
|
}
|
|
|
|
// for lbgk
|
|
mLevel[ mMaxRefine ].gravity = mGravity / mLevel[ mMaxRefine ].omega;
|
|
for(int i=mMaxRefine-1; i>=0; i--) {
|
|
// should be the same on all levels...
|
|
// for lbgk
|
|
mLevel[i].gravity = (mLevel[i+1].gravity * mLevel[i+1].omega) * 2.0 / mLevel[i].omega;
|
|
}
|
|
|
|
mLastOmega = mOmega;
|
|
mLastGravity = mGravity;
|
|
// debug? invalidate old values...
|
|
mGravity = -100.0;
|
|
mOmega = -100.0;
|
|
|
|
for(int i=0; i<=mMaxRefine; i++) {
|
|
if(!mSilent) {
|
|
errMsg("LbmFsgrSolver", "Level init "<<i<<" - sizes:"<<mLevel[i].lSizex<<","<<mLevel[i].lSizey<<","<<mLevel[i].lSizez<<" offs:"<<mLevel[i].lOffsx<<","<<mLevel[i].lOffsy<<","<<mLevel[i].lOffsz
|
|
<<" omega:"<<mLevel[i].omega<<" grav:"<<mLevel[i].gravity<< ", "
|
|
<<" cmsagp:"<<mLevel[i].lcsmago<<", "
|
|
<< " ss"<<mLevel[i].timestep<<" ns"<<mLevel[i].nodeSize<<" cs"<<mLevel[i].simCellSize );
|
|
} else {
|
|
if(!mInitDone) {
|
|
debMsgStd("LbmFsgrSolver", DM_MSG, "Level init "<<i<<" - sizes:"<<mLevel[i].lSizex<<","<<mLevel[i].lSizey<<","<<mLevel[i].lSizez<<" "
|
|
<<"omega:"<<mLevel[i].omega<<" grav:"<<mLevel[i].gravity , 5);
|
|
}
|
|
}
|
|
}
|
|
if(mMaxRefine>0) {
|
|
mDfScaleUp = (mLevel[0 ].timestep/mLevel[0+1].timestep)* (1.0/mLevel[0 ].omega-1.0)/ (1.0/mLevel[0+1].omega-1.0); // yu
|
|
mDfScaleDown = (mLevel[0+1].timestep/mLevel[0 ].timestep)* (1.0/mLevel[0+1].omega-1.0)/ (1.0/mLevel[0 ].omega-1.0); // yu
|
|
}
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
* Init Solver (values should be read from config file)
|
|
*****************************************************************************/
|
|
|
|
/*! finish the init with config file values (allocate arrays...) */
|
|
bool LbmFsgrSolver::initializeSolverMemory()
|
|
{
|
|
debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Init start... "<<mInitDone<<" "<<(void*)this,1);
|
|
|
|
// init cppf stage
|
|
if(mCppfStage>0) {
|
|
mSizex *= mCppfStage;
|
|
mSizey *= mCppfStage;
|
|
mSizez *= mCppfStage;
|
|
}
|
|
if(mFsSurfGenSetting==-1) {
|
|
// all on
|
|
mFsSurfGenSetting =
|
|
fssgNormal | fssgNoNorth | fssgNoSouth | fssgNoEast |
|
|
fssgNoWest | fssgNoTop | fssgNoBottom | fssgNoObs ;
|
|
}
|
|
|
|
// size inits to force cubic cells and mult4 level dimensions
|
|
// and make sure we dont allocate too much...
|
|
bool memOk = false;
|
|
int orgSx = mSizex;
|
|
int orgSy = mSizey;
|
|
int orgSz = mSizez;
|
|
double sizeReduction = 1.0;
|
|
double memEstFromFunc = -1.0;
|
|
double memEstFine = -1.0;
|
|
string memreqStr("");
|
|
bool firstMInit = true;
|
|
int minitTries=0;
|
|
while(!memOk) {
|
|
minitTries++;
|
|
initGridSizes( mSizex, mSizey, mSizez,
|
|
mvGeoStart, mvGeoEnd, mMaxRefine, PARALLEL);
|
|
|
|
// MPT
|
|
#if LBM_INCLUDE_TESTSOLVERS==1
|
|
if(firstMInit) {
|
|
mrSetup();
|
|
}
|
|
#endif // LBM_INCLUDE_TESTSOLVERS==1
|
|
firstMInit=false;
|
|
|
|
calculateMemreqEstimate( mSizex, mSizey, mSizez,
|
|
mMaxRefine, mFarFieldSize, &memEstFromFunc, &memEstFine, &memreqStr );
|
|
|
|
double memLimit;
|
|
string memLimStr("-");
|
|
if(sizeof(void*)==4) {
|
|
// 32bit system, limit to 2GB
|
|
memLimit = 2.0* 1024.0*1024.0*1024.0;
|
|
memLimStr = string("2GB");
|
|
} else {
|
|
// 64bit, just take 16GB as limit for now...
|
|
memLimit = 16.0* 1024.0*1024.0*1024.0;
|
|
memLimStr = string("16GB");
|
|
}
|
|
|
|
// restrict max. chunk of 1 mem block to 1GB for windos
|
|
bool memBlockAllocProblem = false;
|
|
double maxDefaultMemChunk = 2.*1024.*1024.*1024.;
|
|
//std::cerr<<" memEstFine "<< memEstFine <<" maxWin:" <<maxWinMemChunk <<" maxMac:" <<maxMacMemChunk ; // DEBUG
|
|
#ifdef WIN32
|
|
double maxWinMemChunk = 1100.*1024.*1024.;
|
|
if(sizeof(void *)==4 && memEstFine>maxWinMemChunk) {
|
|
memBlockAllocProblem = true;
|
|
}
|
|
#endif // WIN32
|
|
#ifdef __APPLE__
|
|
double maxMacMemChunk = 1200.*1024.*1024.;
|
|
if(memEstFine> maxMacMemChunk) {
|
|
memBlockAllocProblem = true;
|
|
}
|
|
#endif // Mac
|
|
if(sizeof(void*)==4 && memEstFine>maxDefaultMemChunk) {
|
|
// max memory chunk for 32bit systems 2gig
|
|
memBlockAllocProblem = true;
|
|
}
|
|
|
|
if(memEstFromFunc>memLimit || memBlockAllocProblem) {
|
|
sizeReduction *= 0.9;
|
|
mSizex = (int)(orgSx * sizeReduction);
|
|
mSizey = (int)(orgSy * sizeReduction);
|
|
mSizez = (int)(orgSz * sizeReduction);
|
|
debMsgStd("LbmFsgrSolver::initialize",DM_WARNING,"initGridSizes: memory limit exceeded "<<
|
|
//memEstFromFunc<<"/"<<memLimit<<", "<<
|
|
//memEstFine<<"/"<<maxWinMemChunk<<", "<<
|
|
memreqStr<<"/"<<memLimStr<<", "<<
|
|
"retrying: "<<PRINT_VEC(mSizex,mSizey,mSizez)<<" org:"<<PRINT_VEC(orgSx,orgSy,orgSz)
|
|
, 3 );
|
|
} else {
|
|
memOk = true;
|
|
}
|
|
}
|
|
|
|
mPreviewFactor = (LbmFloat)mOutputSurfacePreview / (LbmFloat)mSizex;
|
|
debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"initGridSizes: Final domain size X:"<<mSizex<<" Y:"<<mSizey<<" Z:"<<mSizez<<
|
|
", Domain: "<<mvGeoStart<<":"<<mvGeoEnd<<", "<<(mvGeoEnd-mvGeoStart)<<
|
|
", PointerSize: "<< sizeof(void*) << ", IntSize: "<< sizeof(int) <<
|
|
", est. Mem.Req.: "<<memreqStr ,2);
|
|
mpParam->setSize(mSizex, mSizey, mSizez);
|
|
if((minitTries>1)&&(glob_mpnum)) { errMsg("LbmFsgrSolver::initialize","Warning!!!!!!!!!!!!!!! Original gridsize changed........."); }
|
|
|
|
debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Definitions: "
|
|
<<"LBM_EPSILON="<<LBM_EPSILON <<" "
|
|
<<"FSGR_STRICT_DEBUG="<<FSGR_STRICT_DEBUG <<" "
|
|
<<"OPT3D="<<OPT3D <<" "
|
|
<<"COMPRESSGRIDS="<<COMPRESSGRIDS<<" "
|
|
<<"MASS_INVALID="<<MASS_INVALID <<" "
|
|
<<"FSGR_LISTTRICK="<<FSGR_LISTTRICK <<" "
|
|
<<"FSGR_LISTTTHRESHEMPTY="<<FSGR_LISTTTHRESHEMPTY <<" "
|
|
<<"FSGR_LISTTTHRESHFULL="<<FSGR_LISTTTHRESHFULL <<" "
|
|
<<"FSGR_MAGICNR="<<FSGR_MAGICNR <<" "
|
|
<<"USE_LES="<<USE_LES <<" "
|
|
,10);
|
|
|
|
// perform 2D corrections...
|
|
if(LBMDIM == 2) mSizez = 1;
|
|
|
|
mpParam->setSimulationMaxSpeed(0.0);
|
|
if(mFVHeight>0.0) mpParam->setFluidVolumeHeight(mFVHeight);
|
|
mpParam->setTadapLevels( mMaxRefine+1 );
|
|
|
|
if(mForceTadapRefine>mMaxRefine) {
|
|
mpParam->setTadapLevels( mForceTadapRefine+1 );
|
|
debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Forcing a t-adap refine level of "<<mForceTadapRefine, 6);
|
|
}
|
|
|
|
if(!mpParam->calculateAllMissingValues(mSimulationTime, false)) {
|
|
errFatal("LbmFsgrSolver::initialize","Fatal: failed to init parameters! Aborting...",SIMWORLD_INITERROR);
|
|
return false;
|
|
}
|
|
|
|
|
|
// init vectors
|
|
for(int i=0; i<=mMaxRefine; i++) {
|
|
mLevel[i].id = i;
|
|
mLevel[i].nodeSize = 0.0;
|
|
mLevel[i].simCellSize = 0.0;
|
|
mLevel[i].omega = 0.0;
|
|
mLevel[i].time = 0.0;
|
|
mLevel[i].timestep = 1.0;
|
|
mLevel[i].gravity = LbmVec(0.0);
|
|
mLevel[i].mprsCells[0] = NULL;
|
|
mLevel[i].mprsCells[1] = NULL;
|
|
mLevel[i].mprsFlags[0] = NULL;
|
|
mLevel[i].mprsFlags[1] = NULL;
|
|
|
|
mLevel[i].avgOmega = 0.0;
|
|
mLevel[i].avgOmegaCnt = 0.0;
|
|
}
|
|
|
|
// init sizes
|
|
mLevel[mMaxRefine].lSizex = mSizex;
|
|
mLevel[mMaxRefine].lSizey = mSizey;
|
|
mLevel[mMaxRefine].lSizez = mSizez;
|
|
for(int i=mMaxRefine-1; i>=0; i--) {
|
|
mLevel[i].lSizex = mLevel[i+1].lSizex/2;
|
|
mLevel[i].lSizey = mLevel[i+1].lSizey/2;
|
|
mLevel[i].lSizez = mLevel[i+1].lSizez/2;
|
|
}
|
|
|
|
// safety check
|
|
if(sizeof(CellFlagType) != CellFlagTypeSize) {
|
|
errFatal("LbmFsgrSolver::initialize","Fatal Error: CellFlagType has wrong size! Is:"<<sizeof(CellFlagType)<<", should be:"<<CellFlagTypeSize, SIMWORLD_GENERICERROR);
|
|
return false;
|
|
}
|
|
|
|
double ownMemCheck = 0.0;
|
|
mLevel[ mMaxRefine ].nodeSize = ((mvGeoEnd[0]-mvGeoStart[0]) / (LbmFloat)(mSizex));
|
|
mLevel[ mMaxRefine ].simCellSize = mpParam->getCellSize();
|
|
mLevel[ mMaxRefine ].lcellfactor = 1.0;
|
|
LONGINT rcellSize = ((mLevel[mMaxRefine].lSizex*mLevel[mMaxRefine].lSizey*mLevel[mMaxRefine].lSizez) *dTotalNum);
|
|
|
|
#if COMPRESSGRIDS==0
|
|
mLevel[ mMaxRefine ].mprsCells[0] = new LbmFloat[ rcellSize +4 ];
|
|
mLevel[ mMaxRefine ].mprsCells[1] = new LbmFloat[ rcellSize +4 ];
|
|
ownMemCheck += 2 * sizeof(LbmFloat) * (rcellSize+4);
|
|
#else // COMPRESSGRIDS==0
|
|
LONGINT compressOffset = (mLevel[mMaxRefine].lSizex*mLevel[mMaxRefine].lSizey*dTotalNum*2);
|
|
// D int tmp = ( (rcellSize +compressOffset +4)/(1024*1024) )*4;
|
|
// D printf("Debug MEMMMM excee: %d\n", tmp);
|
|
mLevel[ mMaxRefine ].mprsCells[1] = new LbmFloat[ rcellSize +compressOffset +4 ];
|
|
mLevel[ mMaxRefine ].mprsCells[0] = mLevel[ mMaxRefine ].mprsCells[1]+compressOffset;
|
|
ownMemCheck += sizeof(LbmFloat) * (rcellSize +compressOffset +4);
|
|
#endif // COMPRESSGRIDS==0
|
|
|
|
if(!mLevel[ mMaxRefine ].mprsCells[1] || !mLevel[ mMaxRefine ].mprsCells[0]) {
|
|
errFatal("LbmFsgrSolver::initialize","Fatal: Couldnt allocate memory (1)! Aborting...",SIMWORLD_INITERROR);
|
|
return false;
|
|
}
|
|
|
|
// +4 for safety ?
|
|
mLevel[ mMaxRefine ].mprsFlags[0] = new CellFlagType[ rcellSize/dTotalNum +4 ];
|
|
mLevel[ mMaxRefine ].mprsFlags[1] = new CellFlagType[ rcellSize/dTotalNum +4 ];
|
|
ownMemCheck += 2 * sizeof(CellFlagType) * (rcellSize/dTotalNum +4);
|
|
if(!mLevel[ mMaxRefine ].mprsFlags[1] || !mLevel[ mMaxRefine ].mprsFlags[0]) {
|
|
errFatal("LbmFsgrSolver::initialize","Fatal: Couldnt allocate memory (2)! Aborting...",SIMWORLD_INITERROR);
|
|
|
|
#if COMPRESSGRIDS==0
|
|
delete[] mLevel[ mMaxRefine ].mprsCells[0];
|
|
delete[] mLevel[ mMaxRefine ].mprsCells[1];
|
|
#else // COMPRESSGRIDS==0
|
|
delete[] mLevel[ mMaxRefine ].mprsCells[1];
|
|
#endif // COMPRESSGRIDS==0
|
|
return false;
|
|
}
|
|
|
|
LbmFloat lcfdimFac = 8.0;
|
|
if(LBMDIM==2) lcfdimFac = 4.0;
|
|
for(int i=mMaxRefine-1; i>=0; i--) {
|
|
mLevel[i].nodeSize = 2.0 * mLevel[i+1].nodeSize;
|
|
mLevel[i].simCellSize = 2.0 * mLevel[i+1].simCellSize;
|
|
mLevel[i].lcellfactor = mLevel[i+1].lcellfactor * lcfdimFac;
|
|
|
|
if(LBMDIM==2){ mLevel[i].lSizez = 1; } // 2D
|
|
rcellSize = ((mLevel[i].lSizex*mLevel[i].lSizey*mLevel[i].lSizez) *dTotalNum);
|
|
mLevel[i].mprsFlags[0] = new CellFlagType[ rcellSize/dTotalNum +4 ];
|
|
mLevel[i].mprsFlags[1] = new CellFlagType[ rcellSize/dTotalNum +4 ];
|
|
ownMemCheck += 2 * sizeof(CellFlagType) * (rcellSize/dTotalNum +4);
|
|
mLevel[i].mprsCells[0] = new LbmFloat[ rcellSize +4 ];
|
|
mLevel[i].mprsCells[1] = new LbmFloat[ rcellSize +4 ];
|
|
ownMemCheck += 2 * sizeof(LbmFloat) * (rcellSize+4);
|
|
}
|
|
|
|
// isosurface memory, use orig res values
|
|
if(mFarFieldSize>0.) {
|
|
ownMemCheck += (double)( (3*sizeof(int)+sizeof(float)) * ((mSizex+2)*(mSizey+2)*(mSizez+2)) );
|
|
} else {
|
|
// ignore 3 int slices...
|
|
ownMemCheck += (double)( ( sizeof(float)) * ((mSizex+2)*(mSizey+2)*(mSizez+2)) );
|
|
}
|
|
|
|
// sanity check
|
|
#if ELBEEM_PLUGIN!=1
|
|
if(ABS(1.0-ownMemCheck/memEstFromFunc)>0.01) {
|
|
errMsg("LbmFsgrSolver::initialize","Sanity Error - memory estimate is off! real:"<<ownMemCheck<<" vs. estimate:"<<memEstFromFunc );
|
|
}
|
|
#endif // ELBEEM_PLUGIN!=1
|
|
|
|
// init sizes for _all_ levels
|
|
for(int i=mMaxRefine; i>=0; i--) {
|
|
mLevel[i].lOffsx = mLevel[i].lSizex;
|
|
mLevel[i].lOffsy = mLevel[i].lOffsx*mLevel[i].lSizey;
|
|
mLevel[i].lOffsz = mLevel[i].lOffsy*mLevel[i].lSizez;
|
|
mLevel[i].setCurr = 0;
|
|
mLevel[i].setOther = 1;
|
|
mLevel[i].lsteps = 0;
|
|
mLevel[i].lmass = 0.0;
|
|
mLevel[i].lvolume = 0.0;
|
|
}
|
|
|
|
// calc omega, force for all levels
|
|
initLevelOmegas();
|
|
mMinTimestep = mpParam->getTimestep();
|
|
mMaxTimestep = mpParam->getTimestep();
|
|
|
|
// init isosurf
|
|
mpIso->setIsolevel( mIsoValue );
|
|
#if LBM_INCLUDE_TESTSOLVERS==1
|
|
if(mUseTestdata) {
|
|
mpTest->setMaterialName( mpIso->getMaterialName() );
|
|
delete mpIso;
|
|
mpIso = mpTest;
|
|
if(mpTest->mFarfMode>0) { // 3d off
|
|
mpTest->setIsolevel(-100.0);
|
|
} else {
|
|
mpTest->setIsolevel( mIsoValue );
|
|
}
|
|
}
|
|
#endif // LBM_INCLUDE_TESTSOLVERS!=1
|
|
// approximate feature size with mesh resolution
|
|
float featureSize = mLevel[ mMaxRefine ].nodeSize*0.5;
|
|
// smooth vars defined in solver_interface, set by simulation object
|
|
// reset for invalid values...
|
|
if((mSmoothSurface<0.)||(mSmoothSurface>50.)) mSmoothSurface = 1.;
|
|
if((mSmoothNormals<0.)||(mSmoothNormals>50.)) mSmoothNormals = 1.;
|
|
mpIso->setSmoothSurface( mSmoothSurface * featureSize );
|
|
mpIso->setSmoothNormals( mSmoothNormals * featureSize );
|
|
|
|
// init iso weight values mIsoWeightMethod
|
|
int wcnt = 0;
|
|
float totw = 0.0;
|
|
for(int ak=-1;ak<=1;ak++)
|
|
for(int aj=-1;aj<=1;aj++)
|
|
for(int ai=-1;ai<=1;ai++) {
|
|
switch(mIsoWeightMethod) {
|
|
case 1: // light smoothing
|
|
mIsoWeight[wcnt] = sqrt(3.0) - sqrt( (LbmFloat)(ak*ak + aj*aj + ai*ai) );
|
|
break;
|
|
case 2: // very light smoothing
|
|
mIsoWeight[wcnt] = sqrt(3.0) - sqrt( (LbmFloat)(ak*ak + aj*aj + ai*ai) );
|
|
mIsoWeight[wcnt] *= mIsoWeight[wcnt];
|
|
break;
|
|
case 3: // no smoothing
|
|
if(ai==0 && aj==0 && ak==0) mIsoWeight[wcnt] = 1.0;
|
|
else mIsoWeight[wcnt] = 0.0;
|
|
break;
|
|
default: // strong smoothing (=0)
|
|
mIsoWeight[wcnt] = 1.0;
|
|
break;
|
|
}
|
|
totw += mIsoWeight[wcnt];
|
|
wcnt++;
|
|
}
|
|
for(int i=0; i<27; i++) mIsoWeight[i] /= totw;
|
|
|
|
LbmVec isostart = vec2L(mvGeoStart);
|
|
LbmVec isoend = vec2L(mvGeoEnd);
|
|
int twodOff = 0; // 2d slices
|
|
if(LBMDIM==2) {
|
|
LbmFloat sn,se;
|
|
sn = isostart[2]+(isoend[2]-isostart[2])*0.5 - ((isoend[0]-isostart[0]) / (LbmFloat)(mSizex+1.0))*0.5;
|
|
se = isostart[2]+(isoend[2]-isostart[2])*0.5 + ((isoend[0]-isostart[0]) / (LbmFloat)(mSizex+1.0))*0.5;
|
|
isostart[2] = sn;
|
|
isoend[2] = se;
|
|
twodOff = 2;
|
|
}
|
|
int isosx = mSizex+2;
|
|
int isosy = mSizey+2;
|
|
int isosz = mSizez+2+twodOff;
|
|
|
|
// MPT
|
|
#if LBM_INCLUDE_TESTSOLVERS==1
|
|
//if( strstr( this->getName().c_str(), "mpfluid1" ) != NULL) {
|
|
if( (mMpNum>0) && (mMpIndex==0) ) {
|
|
//? mpindex==0
|
|
// restore original value for node0
|
|
isosx = mOrgSizeX + 2;
|
|
isostart[0] = mOrgStartX;
|
|
isoend[0] = mOrgEndX;
|
|
}
|
|
errMsg("LbmFsgrSolver::initialize", "MPT: gcon "<<mMpNum<<","<<mMpIndex<<" src"<< PRINT_VEC(mpTest->mGCMin.mSrcx,mpTest->mGCMin.mSrcy,mpTest->mGCMin.mSrcz)<<" dst"
|
|
<< PRINT_VEC(mpTest->mGCMin.mDstx,mpTest->mGCMin.mDsty,mpTest->mGCMin.mDstz)<<" consize"
|
|
<< PRINT_VEC(mpTest->mGCMin.mConSizex,mpTest->mGCMin.mConSizey,mpTest->mGCMin.mConSizez)<<" ");
|
|
errMsg("LbmFsgrSolver::initialize", "MPT: gcon "<<mMpNum<<","<<mMpIndex<<" src"<< PRINT_VEC(mpTest->mGCMax.mSrcx,mpTest->mGCMax.mSrcy,mpTest->mGCMax.mSrcz)<<" dst"
|
|
<< PRINT_VEC(mpTest->mGCMax.mDstx,mpTest->mGCMax.mDsty,mpTest->mGCMax.mDstz)<<" consize"
|
|
<< PRINT_VEC(mpTest->mGCMax.mConSizex,mpTest->mGCMax.mConSizey,mpTest->mGCMax.mConSizez)<<" ");
|
|
#endif // LBM_INCLUDE_TESTSOLVERS==1
|
|
|
|
errMsg(" SETISO ", "iso "<<isostart<<" - "<<isoend<<" "<<(((isoend[0]-isostart[0]) / (LbmFloat)(mSizex+1.0))*0.5)<<" "<<(LbmFloat)(mSizex+1.0) );
|
|
errMsg("LbmFsgrSolver::initialize", "MPT: geo "<< mvGeoStart<<","<<mvGeoEnd<<
|
|
" grid:"<<PRINT_VEC(mSizex,mSizey,mSizez)<<",iso:"<< PRINT_VEC(isosx,isosy,isosz) );
|
|
mpIso->setStart( vec2G(isostart) );
|
|
mpIso->setEnd( vec2G(isoend) );
|
|
LbmVec isodist = isoend-isostart;
|
|
|
|
int isosubs = mIsoSubdivs;
|
|
if(mFarFieldSize>1.) {
|
|
errMsg("LbmFsgrSolver::initialize","Warning - resetting isosubdivs, using fulledge!");
|
|
isosubs = 1;
|
|
mpIso->setUseFulledgeArrays(true);
|
|
}
|
|
mpIso->setSubdivs(isosubs);
|
|
|
|
mpIso->initializeIsosurface( isosx,isosy,isosz, vec2G(isodist) );
|
|
|
|
// reset iso field
|
|
for(int ak=0;ak<isosz;ak++)
|
|
for(int aj=0;aj<isosy;aj++)
|
|
for(int ai=0;ai<isosx;ai++) { *mpIso->getData(ai,aj,ak) = 0.0; }
|
|
|
|
|
|
/* init array (set all invalid first) */
|
|
preinitGrids();
|
|
for(int lev=0; lev<=mMaxRefine; lev++) {
|
|
FSGR_FORIJK_BOUNDS(lev) {
|
|
RFLAG(lev,i,j,k,0) = 0, RFLAG(lev,i,j,k,0) = 0; // reset for changeFlag usage
|
|
if(!mAllfluid) {
|
|
initEmptyCell(lev, i,j,k, CFEmpty, -1.0, -1.0);
|
|
} else {
|
|
initEmptyCell(lev, i,j,k, CFFluid, 1.0, 1.0);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if(LBMDIM==2) {
|
|
if(mOutputSurfacePreview) {
|
|
errMsg("LbmFsgrSolver::init","No preview in 2D allowed!");
|
|
mOutputSurfacePreview = 0; }
|
|
}
|
|
if((glob_mpactive) && (glob_mpindex>0)) {
|
|
mOutputSurfacePreview = 0;
|
|
}
|
|
|
|
#if LBM_USE_GUI==1
|
|
if(mOutputSurfacePreview) {
|
|
errMsg("LbmFsgrSolver::init","No preview in GUI mode... mOutputSurfacePreview=0");
|
|
mOutputSurfacePreview = 0; }
|
|
#endif // LBM_USE_GUI==1
|
|
if(mOutputSurfacePreview) {
|
|
// same as normal one, but use reduced size
|
|
mpPreviewSurface = new IsoSurface( mIsoValue );
|
|
mpPreviewSurface->setMaterialName( mpPreviewSurface->getMaterialName() );
|
|
mpPreviewSurface->setIsolevel( mIsoValue );
|
|
// usually dont display for rendering
|
|
mpPreviewSurface->setVisible( false );
|
|
|
|
mpPreviewSurface->setStart( vec2G(isostart) );
|
|
mpPreviewSurface->setEnd( vec2G(isoend) );
|
|
LbmVec pisodist = isoend-isostart;
|
|
LbmFloat pfac = mPreviewFactor;
|
|
mpPreviewSurface->initializeIsosurface( (int)(pfac*mSizex)+2, (int)(pfac*mSizey)+2, (int)(pfac*mSizez)+2, vec2G(pisodist) );
|
|
//mpPreviewSurface->setName( getName() + "preview" );
|
|
mpPreviewSurface->setName( "preview" );
|
|
|
|
debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Preview with sizes "<<(pfac*mSizex)<<","<<(pfac*mSizey)<<","<<(pfac*mSizez)<<" enabled",10);
|
|
}
|
|
|
|
// init defaults
|
|
mAvgNumUsedCells = 0;
|
|
mFixMass= 0.0;
|
|
return true;
|
|
}
|
|
|
|
/*! init solver arrays */
|
|
bool LbmFsgrSolver::initializeSolverGrids() {
|
|
/* init boundaries */
|
|
debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Boundary init...",10);
|
|
// init obstacles, and reinit time step size
|
|
initGeometryFlags();
|
|
mLastSimTime = -1.0;
|
|
// TODO check for invalid cells? nitGenericTestCases();
|
|
|
|
// new - init noslip 1 everywhere...
|
|
// half fill boundary cells?
|
|
|
|
CellFlagType domainBoundType = CFInvalid;
|
|
// TODO use normal object types instad...
|
|
if(mDomainBound.find(string("free")) != string::npos) {
|
|
domainBoundType = CFBnd | CFBndFreeslip;
|
|
debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Domain Boundary Type: FreeSlip, value:"<<mDomainBound,10);
|
|
} else if(mDomainBound.find(string("part")) != string::npos) {
|
|
domainBoundType = CFBnd | CFBndPartslip; // part slip type
|
|
debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Domain Boundary Type: PartSlip ("<<mDomainPartSlipValue<<"), value:"<<mDomainBound,10);
|
|
} else {
|
|
domainBoundType = CFBnd | CFBndNoslip;
|
|
debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Domain Boundary Type: NoSlip, value:"<<mDomainBound,10);
|
|
}
|
|
|
|
// use ar[numobjs] as entry for domain (used e.g. for mDomainPartSlipValue in mObjectPartslips)
|
|
int domainobj = (int)(mpGiObjects->size());
|
|
domainBoundType |= (domainobj<<24);
|
|
//for(int i=0; i<(int)(domainobj+0); i++) {
|
|
//errMsg("GEOIN","i"<<i<<" "<<(*mpGiObjects)[i]->getName());
|
|
//if((*mpGiObjects)[i] == mpIso) { //check...
|
|
//}
|
|
//}
|
|
//errMsg("GEOIN"," dm "<<(domainBoundType>>24));
|
|
|
|
for(int k=0;k<mLevel[mMaxRefine].lSizez;k++)
|
|
for(int i=0;i<mLevel[mMaxRefine].lSizex;i++) {
|
|
initEmptyCell(mMaxRefine, i,0,k, domainBoundType, 0.0, BND_FILL);
|
|
initEmptyCell(mMaxRefine, i,mLevel[mMaxRefine].lSizey-1,k, domainBoundType, 0.0, BND_FILL);
|
|
}
|
|
|
|
for(int k=0;k<mLevel[mMaxRefine].lSizez;k++)
|
|
for(int j=0;j<mLevel[mMaxRefine].lSizey;j++) {
|
|
initEmptyCell(mMaxRefine, 0,j,k, domainBoundType, 0.0, BND_FILL);
|
|
initEmptyCell(mMaxRefine, mLevel[mMaxRefine].lSizex-1,j,k, domainBoundType, 0.0, BND_FILL);
|
|
// DEBUG BORDER!
|
|
//initEmptyCell(mMaxRefine, mLevel[mMaxRefine].lSizex-2,j,k, domainBoundType, 0.0, BND_FILL);
|
|
}
|
|
|
|
if(LBMDIM == 3) {
|
|
// only for 3D
|
|
for(int j=0;j<mLevel[mMaxRefine].lSizey;j++)
|
|
for(int i=0;i<mLevel[mMaxRefine].lSizex;i++) {
|
|
initEmptyCell(mMaxRefine, i,j,0, domainBoundType, 0.0, BND_FILL);
|
|
initEmptyCell(mMaxRefine, i,j,mLevel[mMaxRefine].lSizez-1, domainBoundType, 0.0, BND_FILL);
|
|
}
|
|
}
|
|
|
|
// TEST!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!11
|
|
/*for(int k=0;k<mLevel[mMaxRefine].lSizez;k++)
|
|
for(int j=0;j<mLevel[mMaxRefine].lSizey;j++) {
|
|
initEmptyCell(mMaxRefine, mLevel[mMaxRefine].lSizex-2,j,k, domainBoundType, 0.0, BND_FILL);
|
|
}
|
|
for(int k=0;k<mLevel[mMaxRefine].lSizez;k++)
|
|
for(int i=0;i<mLevel[mMaxRefine].lSizex;i++) {
|
|
initEmptyCell(mMaxRefine, i,1,k, domainBoundType, 0.0, BND_FILL);
|
|
}
|
|
// */
|
|
|
|
/*for(int ii=0; ii<(int)po w_change?(2.0,mMaxRefine)-1; ii++) {
|
|
errMsg("BNDTESTSYMM","set "<<mLevel[mMaxRefine].lSizex-2-ii );
|
|
for(int k=0;k<mLevel[mMaxRefine].lSizez;k++)
|
|
for(int j=0;j<mLevel[mMaxRefine].lSizey;j++) {
|
|
initEmptyCell(mMaxRefine, mLevel[mMaxRefine].lSizex-2-ii,j,k, domainBoundType, 0.0, BND_FILL); // SYMM!? 2D?
|
|
}
|
|
for(int j=0;j<mLevel[mMaxRefine].lSizey;j++)
|
|
for(int i=0;i<mLevel[mMaxRefine].lSizex;i++) {
|
|
initEmptyCell(mMaxRefine, i,j,mLevel[mMaxRefine].lSizez-2-ii, domainBoundType, 0.0, BND_FILL); // SYMM!? 3D?
|
|
}
|
|
}
|
|
// Symmetry tests */
|
|
// vortt
|
|
#if LBM_INCLUDE_TESTSOLVERS==1
|
|
if(( strstr( this->getName().c_str(), "vorttfluid" ) != NULL) && (LBMDIM==2)) {
|
|
errMsg("VORTT","init");
|
|
int level=mMaxRefine;
|
|
int cx = mLevel[level].lSizex/2;
|
|
int cyo = mLevel[level].lSizey/2;
|
|
int sx = mLevel[level].lSizex/8;
|
|
int sy = mLevel[level].lSizey/8;
|
|
LbmFloat rho = 1.;
|
|
LbmFloat rhomass = 1.;
|
|
LbmFloat uFactor = 0.15;
|
|
LbmFloat vdist = 1.0;
|
|
|
|
int cy1=cyo-(int)(vdist*sy);
|
|
int cy2=cyo+(int)(vdist*sy);
|
|
|
|
//for(int j=cy-sy;j<cy+sy;j++) for(int i=cx-sx;i<cx+sx;i++) {
|
|
for(int j=1;j<mLevel[level].lSizey-1;j++)
|
|
for(int i=1;i<mLevel[level].lSizex-1;i++) {
|
|
LbmFloat d1 = norm(LbmVec(cx,cy1,0.)-LbmVec(i,j,0));
|
|
LbmFloat d2 = norm(LbmVec(cx,cy2,0.)-LbmVec(i,j,0));
|
|
bool in1 = (d1<=(LbmFloat)(sx));
|
|
bool in2 = (d2<=(LbmFloat)(sx));
|
|
LbmVec uvec(0.);
|
|
LbmVec v1 = getNormalized( cross( LbmVec(cx,cy1,0.)-LbmVec(i,j,0), LbmVec(0.,0.,1.)) )* uFactor;
|
|
LbmVec v2 = getNormalized( cross( LbmVec(cx,cy2,0.)-LbmVec(i,j,0), LbmVec(0.,0.,1.)) )* uFactor;
|
|
LbmFloat w1=1., w2=1.;
|
|
if(!in1) w1=(LbmFloat)(sx)/(1.5*d1);
|
|
if(!in2) w2=(LbmFloat)(sx)/(1.5*d2);
|
|
if(!in1) w1=0.; if(!in2) w2=0.; // sharp falloff
|
|
uvec += v1*w1;
|
|
uvec += v2*w2;
|
|
initVelocityCell(level, i,j,0, CFFluid, rho, rhomass, uvec );
|
|
//errMsg("VORTT","init uvec"<<uvec);
|
|
}
|
|
|
|
}
|
|
#endif // LBM_INCLUDE_TESTSOLVERS==1
|
|
|
|
//if(getGlobalBakeState()<0) { CAUSE_PANIC; errMsg("LbmFsgrSolver::initialize","Got abort signal1, causing panic, aborting..."); return false; }
|
|
|
|
// prepare interface cells
|
|
initFreeSurfaces();
|
|
initStandingFluidGradient();
|
|
|
|
// perform first step to init initial mass
|
|
mInitialMass = 0.0;
|
|
int inmCellCnt = 0;
|
|
FSGR_FORIJK1(mMaxRefine) {
|
|
if( RFLAG(mMaxRefine, i,j,k, mLevel[mMaxRefine].setCurr)& CFFluid) {
|
|
LbmFloat fluidRho = QCELL(mMaxRefine, i,j,k, mLevel[mMaxRefine].setCurr, 0);
|
|
FORDF1 { fluidRho += QCELL(mMaxRefine, i,j,k, mLevel[mMaxRefine].setCurr, l); }
|
|
mInitialMass += fluidRho;
|
|
inmCellCnt ++;
|
|
} else if( RFLAG(mMaxRefine, i,j,k, mLevel[mMaxRefine].setCurr)& CFInter) {
|
|
mInitialMass += QCELL(mMaxRefine, i,j,k, mLevel[mMaxRefine].setCurr, dMass);
|
|
inmCellCnt ++;
|
|
}
|
|
}
|
|
mCurrentVolume = mCurrentMass = mInitialMass;
|
|
|
|
ParamVec cspv = mpParam->calculateCellSize();
|
|
if(LBMDIM==2) cspv[2] = 1.0;
|
|
inmCellCnt = 1;
|
|
double nrmMass = (double)mInitialMass / (double)(inmCellCnt) *cspv[0]*cspv[1]*cspv[2] * 1000.0;
|
|
debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Initial Mass:"<<mInitialMass<<" normalized:"<<nrmMass, 3);
|
|
mInitialMass = 0.0; // reset, and use actual value after first step
|
|
|
|
//mStartSymm = false;
|
|
#if ELBEEM_PLUGIN!=1
|
|
if((LBMDIM==2)&&(mSizex<200)) {
|
|
if(!checkSymmetry("init")) {
|
|
errMsg("LbmFsgrSolver::initialize","Unsymmetric init...");
|
|
} else {
|
|
errMsg("LbmFsgrSolver::initialize","Symmetric init!");
|
|
}
|
|
}
|
|
#endif // ELBEEM_PLUGIN!=1
|
|
return true;
|
|
}
|
|
|
|
|
|
/*! prepare actual simulation start, setup viz etc */
|
|
bool LbmFsgrSolver::initializeSolverPostinit() {
|
|
// coarsen region
|
|
myTime_t fsgrtstart = getTime();
|
|
for(int lev=mMaxRefine-1; lev>=0; lev--) {
|
|
debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Coarsening level "<<lev<<".",8);
|
|
adaptGrid(lev);
|
|
coarseRestrictFromFine(lev);
|
|
adaptGrid(lev);
|
|
coarseRestrictFromFine(lev);
|
|
}
|
|
markedClearList();
|
|
myTime_t fsgrtend = getTime();
|
|
if(!mSilent){ debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"FSGR init done ("<< getTimeString(fsgrtend-fsgrtstart)<<"), changes:"<<mNumFsgrChanges , 10 ); }
|
|
mNumFsgrChanges = 0;
|
|
|
|
for(int l=0; l<cDirNum; l++) {
|
|
LbmFloat area = 0.5 * 0.5 *0.5;
|
|
if(LBMDIM==2) area = 0.5 * 0.5;
|
|
|
|
if(dfVecX[l]!=0) area *= 0.5;
|
|
if(dfVecY[l]!=0) area *= 0.5;
|
|
if(dfVecZ[l]!=0) area *= 0.5;
|
|
mFsgrCellArea[l] = area;
|
|
} // l
|
|
|
|
// make sure both sets are ok
|
|
// copy from other to curr
|
|
for(int lev=0; lev<=mMaxRefine; lev++) {
|
|
FSGR_FORIJK_BOUNDS(lev) {
|
|
RFLAG(lev, i,j,k,mLevel[lev].setOther) = RFLAG(lev, i,j,k,mLevel[lev].setCurr);
|
|
} } // first copy flags */
|
|
|
|
|
|
// old mpPreviewSurface init
|
|
//if(getGlobalBakeState()<0) { CAUSE_PANIC; errMsg("LbmFsgrSolver::initialize","Got abort signal2, causing panic, aborting..."); return false; }
|
|
// make sure fill fracs are right for first surface generation
|
|
stepMain();
|
|
|
|
// prepare once...
|
|
mpIso->setParticles(mpParticles, mPartDropMassSub);
|
|
debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Iso Settings, subdivs="<<mpIso->getSubdivs()<<", partsize="<<mPartDropMassSub, 9);
|
|
prepareVisualization();
|
|
// copy again for stats counting
|
|
for(int lev=0; lev<=mMaxRefine; lev++) {
|
|
FSGR_FORIJK_BOUNDS(lev) {
|
|
RFLAG(lev, i,j,k,mLevel[lev].setOther) = RFLAG(lev, i,j,k,mLevel[lev].setCurr);
|
|
} } // first copy flags */
|
|
|
|
|
|
// now really done...
|
|
debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"SurfaceGen: SmsOrg("<<mSmoothSurface<<","<<mSmoothNormals<< /*","<<featureSize<<*/ "), Iso("<<mpIso->getSmoothSurface()<<","<<mpIso->getSmoothNormals()<<") ",10);
|
|
debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Init done ... ",10);
|
|
mInitDone = 1;
|
|
|
|
// init fluid control
|
|
initCpdata();
|
|
|
|
#if LBM_INCLUDE_TESTSOLVERS==1
|
|
initTestdata();
|
|
#endif // ELBEEM_PLUGIN!=1
|
|
// not inited? dont use...
|
|
if(mCutoff<0) mCutoff=0;
|
|
|
|
initParticles();
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
// macros for mov obj init
|
|
#if LBMDIM==2
|
|
|
|
#define POS2GRID_CHECK(vec,n) \
|
|
monTotal++;\
|
|
int k=(int)( ((vec)[n][2]-iniPos[2])/dvec[2] +0.0); \
|
|
if(k!=0) continue; \
|
|
const int i=(int)( ((vec)[n][0]-iniPos[0])/dvec[0] +0.0); \
|
|
if(i<=0) continue; \
|
|
if(i>=mLevel[level].lSizex-1) continue; \
|
|
const int j=(int)( ((vec)[n][1]-iniPos[1])/dvec[1] +0.0); \
|
|
if(j<=0) continue; \
|
|
if(j>=mLevel[level].lSizey-1) continue; \
|
|
|
|
#else // LBMDIM -> 3
|
|
#define POS2GRID_CHECK(vec,n) \
|
|
monTotal++;\
|
|
const int i=(int)( ((vec)[n][0]-iniPos[0])/dvec[0] +0.0); \
|
|
if(i<=0) continue; \
|
|
if(i>=mLevel[level].lSizex-1) continue; \
|
|
const int j=(int)( ((vec)[n][1]-iniPos[1])/dvec[1] +0.0); \
|
|
if(j<=0) continue; \
|
|
if(j>=mLevel[level].lSizey-1) continue; \
|
|
const int k=(int)( ((vec)[n][2]-iniPos[2])/dvec[2] +0.0); \
|
|
if(k<=0) continue; \
|
|
if(k>=mLevel[level].lSizez-1) continue; \
|
|
|
|
#endif // LBMDIM
|
|
|
|
// calculate object velocity from vert arrays in objvel vec
|
|
#define OBJVEL_CALC \
|
|
LbmVec objvel = vec2L((mMOIVertices[n]-mMOIVerticesOld[n]) /dvec); { \
|
|
const LbmFloat usqr = (objvel[0]*objvel[0]+objvel[1]*objvel[1]+objvel[2]*objvel[2])*1.5; \
|
|
USQRMAXCHECK(usqr, objvel[0],objvel[1],objvel[2], mMaxVlen, mMxvx,mMxvy,mMxvz); \
|
|
if(usqr>maxusqr) { \
|
|
/* cutoff at maxVelVal */ \
|
|
for(int jj=0; jj<3; jj++) { \
|
|
if(objvel[jj]>0.) objvel[jj] = maxVelVal; \
|
|
if(objvel[jj]<0.) objvel[jj] = -maxVelVal; \
|
|
} \
|
|
} } \
|
|
if(ntype&(CFBndFreeslip)) { \
|
|
const LbmFloat dp=dot(objvel, vec2L((*pNormals)[n]) ); \
|
|
const LbmVec oldov=objvel; /*DEBUG*/ \
|
|
objvel = vec2L((*pNormals)[n]) *dp; \
|
|
/* if((j==24)&&(n%5==2)) errMsg("FSBT","n"<<n<<" v"<<objvel<<" nn"<<(*pNormals)[n]<<" dp"<<dp<<" oldov"<<oldov ); */ \
|
|
} \
|
|
else if(ntype&(CFBndPartslip)) { \
|
|
const LbmFloat dp=dot(objvel, vec2L((*pNormals)[n]) ); \
|
|
const LbmVec oldov=objvel; /*DEBUG*/ \
|
|
/* if((j==24)&&(n%5==2)) errMsg("FSBT","n"<<n<<" v"<<objvel<<" nn"<<(*pNormals)[n]<<" dp"<<dp<<" oldov"<<oldov ); */ \
|
|
const LbmFloat partv = mObjectPartslips[OId]; \
|
|
/*errMsg("PARTSLIP_DEBUG","l="<<l<<" ccel="<<RAC(ccel, dfInv[l] )<<" partv="<<partv<<",id="<<(int)(mnbf>>24)<<" newval="<<newval ); / part slip debug */ \
|
|
/* m[l] = (RAC(ccel, dfInv[l] ) ) * partv + newval * (1.-partv); part slip */ \
|
|
objvel = objvel*partv + vec2L((*pNormals)[n]) *dp*(1.-partv); \
|
|
}
|
|
|
|
#define TTT \
|
|
|
|
|
|
/*****************************************************************************/
|
|
//! init moving obstacles for next sim step sim
|
|
/*****************************************************************************/
|
|
void LbmFsgrSolver::initMovingObstacles(bool staticInit) {
|
|
myTime_t monstart = getTime();
|
|
|
|
// movobj init
|
|
const int level = mMaxRefine;
|
|
const int workSet = mLevel[level].setCurr;
|
|
const int otherSet = mLevel[level].setOther;
|
|
LbmFloat sourceTime = mSimulationTime; // should be equal to mLastSimTime!
|
|
// for debugging - check targetTime check during DEFAULT STREAM
|
|
LbmFloat targetTime = mSimulationTime + mpParam->getTimestep();
|
|
if(mLastSimTime == targetTime) {
|
|
debMsgStd("LbmFsgrSolver::initMovingObstacles",DM_WARNING,"Called for same time! (t="<<mSimulationTime<<" , targett="<<targetTime<<")", 1);
|
|
return;
|
|
}
|
|
//debMsgStd("LbmFsgrSolver::initMovingObstacles",DM_WARNING,"time: "<<mSimulationTime<<" lasttt:"<<mLastSimTime,10);
|
|
//if(mSimulationTime!=mLastSimTime) errMsg("LbmFsgrSolver::initMovingObstacles","time: "<<mSimulationTime<<" lasttt:"<<mLastSimTime);
|
|
|
|
const LbmFloat maxVelVal = 0.1666;
|
|
const LbmFloat maxusqr = maxVelVal*maxVelVal*3. *1.5;
|
|
|
|
LbmFloat rhomass = 0.0;
|
|
CellFlagType otype = CFInvalid; // verify type of last step, might be non moving obs!
|
|
CellFlagType ntype = CFInvalid;
|
|
// WARNING - copied from geo init!
|
|
int numobjs = (int)(mpGiObjects->size());
|
|
ntlVec3Gfx dvec = ntlVec3Gfx(mLevel[level].nodeSize); //dvec*1.0;
|
|
// 2d display as rectangles
|
|
ntlVec3Gfx iniPos(0.0);
|
|
if(LBMDIM==2) {
|
|
dvec[2] = 1.0;
|
|
iniPos = (mvGeoStart + ntlVec3Gfx( 0.0, 0.0, (mvGeoEnd[2]-mvGeoStart[2])*0.5 ))-(dvec*0.0);
|
|
} else {
|
|
iniPos = (mvGeoStart + ntlVec3Gfx( 0.0 ))-(dvec*0.0);
|
|
}
|
|
|
|
if( (int)mObjectMassMovnd.size() < numobjs) {
|
|
for(int i=mObjectMassMovnd.size(); i<numobjs; i++) {
|
|
mObjectMassMovnd.push_back(0.);
|
|
}
|
|
}
|
|
|
|
// stats
|
|
int monPoints=0, monObsts=0, monFluids=0, monTotal=0, monTrafo=0;
|
|
int nbored;
|
|
for(int OId=0; OId<numobjs; OId++) {
|
|
ntlGeometryObject *obj = (*mpGiObjects)[OId];
|
|
bool skip = false;
|
|
if(obj->getGeoInitId() != mLbmInitId) skip=true;
|
|
if( (!staticInit) && (!obj->getIsAnimated()) ) skip=true;
|
|
if( ( staticInit) && ( obj->getIsAnimated()) ) skip=true;
|
|
if(skip) continue;
|
|
debMsgStd("LbmFsgrSolver::initMovingObstacles",DM_MSG," obj "<<obj->getName()<<" skip:"<<skip<<", static:"<<staticInit<<" anim:"<<obj->getIsAnimated()<<" gid:"<<obj->getGeoInitId()<<" simgid:"<<mLbmInitId, 10);
|
|
|
|
if( (obj->getGeoInitType()&FGI_ALLBOUNDS) ||
|
|
((obj->getGeoInitType()&FGI_FLUID) && staticInit) ) {
|
|
|
|
otype = ntype = CFInvalid;
|
|
switch(obj->getGeoInitType()) {
|
|
/* case FGI_BNDPART: // old, use noslip for moving part/free objs
|
|
case FGI_BNDFREE:
|
|
if(!staticInit) {
|
|
errMsg("LbmFsgrSolver::initMovingObstacles","Warning - moving free/part slip objects NYI "<<obj->getName() );
|
|
otype = ntype = CFBnd|CFBndNoslip;
|
|
} else {
|
|
if(obj->getGeoInitType()==FGI_BNDPART) otype = ntype = CFBnd|CFBndPartslip;
|
|
if(obj->getGeoInitType()==FGI_BNDFREE) otype = ntype = CFBnd|CFBndFreeslip;
|
|
}
|
|
break;
|
|
// off */
|
|
case FGI_BNDPART: rhomass = BND_FILL;
|
|
otype = ntype = CFBnd|CFBndPartslip|(OId<<24);
|
|
break;
|
|
case FGI_BNDFREE: rhomass = BND_FILL;
|
|
otype = ntype = CFBnd|CFBndFreeslip|(OId<<24);
|
|
break;
|
|
// off */
|
|
case FGI_BNDNO: rhomass = BND_FILL;
|
|
otype = ntype = CFBnd|CFBndNoslip|(OId<<24);
|
|
break;
|
|
case FGI_FLUID:
|
|
otype = ntype = CFFluid;
|
|
break;
|
|
case FGI_MBNDINFLOW:
|
|
otype = ntype = CFMbndInflow;
|
|
break;
|
|
case FGI_MBNDOUTFLOW:
|
|
otype = ntype = CFMbndOutflow;
|
|
break;
|
|
}
|
|
int wasActive = ((obj->getGeoActive(sourceTime)>0.)? 1:0);
|
|
int active = ((obj->getGeoActive(targetTime)>0.)? 1:0);
|
|
//errMsg("GEOACTT"," obj "<<obj->getName()<<" a:"<<active<<","<<wasActive<<" s"<<sourceTime<<" t"<<targetTime <<" v"<<mObjectSpeeds[OId] );
|
|
// skip inactive in/out flows
|
|
if(ntype==CFInvalid){ errMsg("LbmFsgrSolver::initMovingObstacles","Invalid obj type "<<obj->getGeoInitType()); continue; }
|
|
if((!active) && (otype&(CFMbndOutflow|CFMbndInflow)) ) continue;
|
|
|
|
// copied from recalculateObjectSpeeds
|
|
mObjectSpeeds[OId] = vec2L(mpParam->calculateLattVelocityFromRw( vec2P( (*mpGiObjects)[OId]->getInitialVelocity(mSimulationTime) )));
|
|
debMsgStd("LbmFsgrSolver::initMovingObstacles",DM_MSG,"id"<<OId<<" "<<obj->getName()<<" inivel set to "<< mObjectSpeeds[OId]<<", unscaled:"<< (*mpGiObjects)[OId]->getInitialVelocity(mSimulationTime) ,10 );
|
|
|
|
//vector<ntlVec3Gfx> tNormals;
|
|
vector<ntlVec3Gfx> *pNormals = NULL;
|
|
mMOINormals.clear();
|
|
if(ntype&(CFBndFreeslip|CFBndPartslip)) { pNormals = &mMOINormals; }
|
|
|
|
mMOIVertices.clear();
|
|
if(obj->getMeshAnimated()) {
|
|
// do two full update
|
|
// TODO tNormals handling!?
|
|
mMOIVerticesOld.clear();
|
|
obj->initMovingPointsAnim(sourceTime,mMOIVerticesOld, targetTime, mMOIVertices, pNormals, mLevel[mMaxRefine].nodeSize, mvGeoStart, mvGeoEnd);
|
|
monTrafo += mMOIVerticesOld.size();
|
|
obj->applyTransformation(sourceTime, &mMOIVerticesOld,pNormals, 0, mMOIVerticesOld.size(), false );
|
|
monTrafo += mMOIVertices.size();
|
|
obj->applyTransformation(targetTime, &mMOIVertices,NULL /* no old normals needed */, 0, mMOIVertices.size(), false );
|
|
} else {
|
|
// only do transform update
|
|
obj->getMovingPoints(mMOIVertices,pNormals); // mMOIVertices = mCachedMovPoints
|
|
mMOIVerticesOld = mMOIVertices;
|
|
// WARNING - assumes mSimulationTime is global!?
|
|
obj->applyTransformation(targetTime, &mMOIVertices,pNormals, 0, mMOIVertices.size(), false );
|
|
monTrafo += mMOIVertices.size();
|
|
|
|
// correct flags from last position, but extrapolate
|
|
// velocity to next timestep
|
|
obj->applyTransformation(sourceTime, &mMOIVerticesOld, NULL /* no old normals needed */, 0, mMOIVerticesOld.size(), false );
|
|
monTrafo += mMOIVerticesOld.size();
|
|
}
|
|
|
|
// object types
|
|
if(ntype&CFBnd){
|
|
|
|
// check if object is moving at all
|
|
if(obj->getIsAnimated()) {
|
|
ntlVec3Gfx objMaxVel = obj->calculateMaxVel(sourceTime,targetTime);
|
|
// FIXME?
|
|
if(normNoSqrt(objMaxVel)>0.0) { ntype |= CFBndMoving; }
|
|
// get old type - CHECK FIXME , timestep could have changed - cause trouble?
|
|
ntlVec3Gfx oldobjMaxVel = obj->calculateMaxVel(sourceTime - mpParam->getTimestep(),sourceTime);
|
|
if(normNoSqrt(oldobjMaxVel)>0.0) { otype |= CFBndMoving; }
|
|
}
|
|
if(obj->getMeshAnimated()) { ntype |= CFBndMoving; otype |= CFBndMoving; }
|
|
CellFlagType rflagnb[27];
|
|
LbmFloat massCheck = 0.;
|
|
int massReinits=0;
|
|
bool fillCells = (mObjectMassMovnd[OId]<=-1.);
|
|
LbmFloat impactCorrFactor = obj->getGeoImpactFactor(targetTime);
|
|
|
|
|
|
// first pass - set new obs. cells
|
|
if(active) {
|
|
for(size_t n=0; n<mMOIVertices.size(); n++) {
|
|
//errMsg("initMovingObstacles_Debug","OId"<<OId<<" n"<<n<<" -> "<<PRINT_IJK);
|
|
POS2GRID_CHECK(mMOIVertices,n);
|
|
//{ errMsg("initMovingObstacles_Debug","OId"<<OId<<" n"<<n<<" -> "<<PRINT_IJK<<", t="<<targetTime); }
|
|
if(QCELL(level, i,j,k, workSet, dFlux)==targetTime) continue;
|
|
monPoints++;
|
|
|
|
// check mass
|
|
if(RFLAG(level, i,j,k, workSet)&(CFFluid)) {
|
|
FORDF0 { massCheck -= QCELL(level, i,j,k, workSet, l); }
|
|
massReinits++;
|
|
}
|
|
else if(RFLAG(level, i,j,k, workSet)&(CFInter)) {
|
|
massCheck -= QCELL(level, i,j,k, workSet, dMass);
|
|
massReinits++;
|
|
}
|
|
|
|
RFLAG(level, i,j,k, workSet) = ntype;
|
|
FORDF1 {
|
|
//CellFlagType flag = RFLAG_NB(level, i,j,k,workSet,l);
|
|
rflagnb[l] = RFLAG_NB(level, i,j,k,workSet,l);
|
|
if(rflagnb[l]&(CFFluid|CFInter)) {
|
|
rflagnb[l] &= (~CFNoBndFluid); // remove CFNoBndFluid flag
|
|
RFLAG_NB(level, i,j,k,workSet,l) &= rflagnb[l];
|
|
}
|
|
}
|
|
LbmFloat *dstCell = RACPNT(level, i,j,k,workSet);
|
|
RAC(dstCell,0) = 0.0;
|
|
if(ntype&CFBndMoving) {
|
|
OBJVEL_CALC;
|
|
|
|
// compute fluid acceleration
|
|
FORDF1 {
|
|
if(rflagnb[l]&(CFFluid|CFInter)) {
|
|
const LbmFloat ux = dfDvecX[l]*objvel[0];
|
|
const LbmFloat uy = dfDvecY[l]*objvel[1];
|
|
const LbmFloat uz = dfDvecZ[l]*objvel[2];
|
|
|
|
LbmFloat factor = 2. * dfLength[l] * 3.0 * (ux+uy+uz); //
|
|
if(ntype&(CFBndFreeslip|CFBndPartslip)) {
|
|
// missing, diag mass checks...
|
|
//if(l<=LBMDIM*2) factor *= 1.4142;
|
|
factor *= 2.0; // TODO, optimize
|
|
} else {
|
|
factor *= 1.2; // TODO, optimize
|
|
}
|
|
factor *= impactCorrFactor; // use manual tweaking channel
|
|
RAC(dstCell,l) = factor;
|
|
massCheck += factor;
|
|
} else {
|
|
RAC(dstCell,l) = 0.;
|
|
}
|
|
}
|
|
|
|
#if NEWDIRVELMOTEST==1
|
|
FORDF1 { RAC(dstCell,l) = 0.; }
|
|
RAC(dstCell,dMass) = objvel[0];
|
|
RAC(dstCell,dFfrac) = objvel[1];
|
|
RAC(dstCell,dC) = objvel[2];
|
|
#endif // NEWDIRVELMOTEST==1
|
|
} else {
|
|
FORDF1 { RAC(dstCell,l) = 0.0; }
|
|
}
|
|
RAC(dstCell, dFlux) = targetTime;
|
|
//errMsg("initMovingObstacles_Debug","OId"<<OId<<" n"<<n<<" -> "<<PRINT_IJK" dflt="<<RAC(dstCell, dFlux) );
|
|
monObsts++;
|
|
} // points
|
|
} // bnd, is active?
|
|
|
|
// second pass, remove old ones
|
|
// warning - initEmptyCell et. al dont overwrite OId or persist flags...
|
|
if(wasActive) {
|
|
for(size_t n=0; n<mMOIVerticesOld.size(); n++) {
|
|
POS2GRID_CHECK(mMOIVerticesOld,n);
|
|
monPoints++;
|
|
if((RFLAG(level, i,j,k, workSet) == otype) &&
|
|
(QCELL(level, i,j,k, workSet, dFlux) != targetTime)) {
|
|
// from mainloop
|
|
nbored = 0;
|
|
// TODO: optimize for OPT3D==0
|
|
FORDF1 {
|
|
//rflagnb[l] = RFLAG_NB(level, i,j,k,workSet,l);
|
|
rflagnb[l] = RFLAG_NB(level, i,j,k,otherSet,l); // test use other set to not have loop dependance
|
|
nbored |= rflagnb[l];
|
|
}
|
|
CellFlagType settype = CFInvalid;
|
|
if(nbored&CFFluid) {
|
|
settype = CFInter|CFNoInterpolSrc;
|
|
rhomass = 1.5;
|
|
if(!fillCells) rhomass = 0.;
|
|
|
|
OBJVEL_CALC;
|
|
if(!(nbored&CFEmpty)) { settype=CFFluid|CFNoInterpolSrc; rhomass=1.; }
|
|
|
|
// new interpolate values
|
|
LbmFloat avgrho = 0.0;
|
|
LbmFloat avgux = 0.0, avguy = 0.0, avguz = 0.0;
|
|
interpolateCellValues(level,i,j,k,workSet, avgrho,avgux,avguy,avguz);
|
|
initVelocityCell(level, i,j,k, settype, avgrho, rhomass, LbmVec(avgux,avguy,avguz) );
|
|
//errMsg("NMOCIT"," at "<<PRINT_IJK<<" "<<avgrho<<" "<<norm(LbmVec(avgux,avguy,avguz))<<" "<<LbmVec(avgux,avguy,avguz) );
|
|
massCheck += rhomass;
|
|
} else {
|
|
settype = CFEmpty; rhomass = 0.0;
|
|
initEmptyCell(level, i,j,k, settype, 1., rhomass );
|
|
}
|
|
monFluids++;
|
|
massReinits++;
|
|
} // flag & simtime
|
|
}
|
|
} // wasactive
|
|
|
|
// only compute mass transfer when init is done
|
|
if(mInitDone) {
|
|
errMsg("initMov","dccd\n\nMassd test "<<obj->getName()<<" dccd massCheck="<<massCheck<<" massReinits"<<massReinits<<
|
|
" fillCells"<<fillCells<<" massmovbnd:"<<mObjectMassMovnd[OId]<<" inim:"<<mInitialMass );
|
|
mObjectMassMovnd[OId] += massCheck;
|
|
}
|
|
} // bnd, active
|
|
|
|
else if(ntype&CFFluid){
|
|
// second static init pass
|
|
if(staticInit) {
|
|
//debMsgStd("LbmFsgrSolver::initMovingObstacles",DM_MSG," obj "<<obj->getName()<<" verts"<<mMOIVertices.size() ,9);
|
|
CellFlagType setflflag = CFFluid; //|(OId<<24);
|
|
for(size_t n=0; n<mMOIVertices.size(); n++) {
|
|
POS2GRID_CHECK(mMOIVertices,n);
|
|
if(RFLAG(level, i,j,k, workSet)&(CFMbndInflow|CFMbndOutflow)){ continue; }
|
|
if(RFLAG(level, i,j,k, workSet)&(CFEmpty)) {
|
|
//changeFlag(level, i,j,k, workSet, setflflag);
|
|
initVelocityCell(level, i,j,k, setflflag, 1., 1., mObjectSpeeds[OId] );
|
|
}
|
|
//else if(RFLAG(level, i,j,k, workSet)&(CFFluid|CFInter)) { changeFlag(level, i,j,k, workSet, RFLAG(level, i,j,k, workSet)|set2Flag); }
|
|
}
|
|
} // second static inflow pass
|
|
} // fluid
|
|
|
|
else if(ntype&CFMbndInflow){
|
|
// inflow pass - add new fluid cells
|
|
// this is slightly different for standing inflows,
|
|
// as the fluid is forced to the desired velocity inside as
|
|
// well...
|
|
const LbmFloat iniRho = 1.0;
|
|
const LbmVec vel(mObjectSpeeds[OId]);
|
|
const LbmFloat usqr = (vel[0]*vel[0]+vel[1]*vel[1]+vel[2]*vel[2])*1.5;
|
|
USQRMAXCHECK(usqr,vel[0],vel[1],vel[2], mMaxVlen, mMxvx,mMxvy,mMxvz);
|
|
//errMsg("LbmFsgrSolver::initMovingObstacles","id"<<OId<<" "<<obj->getName()<<" inflow "<<staticInit<<" "<<mMOIVertices.size() );
|
|
|
|
for(size_t n=0; n<mMOIVertices.size(); n++) {
|
|
POS2GRID_CHECK(mMOIVertices,n);
|
|
// TODO - also reinit interface cells !?
|
|
if(RFLAG(level, i,j,k, workSet)!=CFEmpty) {
|
|
// test prevent particle gen for inflow inter cells
|
|
if(RFLAG(level, i,j,k, workSet)&(CFInter)) { RFLAG(level, i,j,k, workSet) &= (~CFNoBndFluid); } // remove CFNoBndFluid flag
|
|
continue; }
|
|
monFluids++;
|
|
|
|
// TODO add OPT3D treatment
|
|
LbmFloat *tcel = RACPNT(level, i,j,k,workSet);
|
|
FORDF0 { RAC(tcel, l) = this->getCollideEq(l, iniRho,vel[0],vel[1],vel[2]); }
|
|
RAC(tcel, dMass) = RAC(tcel, dFfrac) = iniRho;
|
|
RAC(tcel, dFlux) = FLUX_INIT;
|
|
CellFlagType setFlag = CFInter;
|
|
changeFlag(level, i,j,k, workSet, setFlag);
|
|
mInitialMass += iniRho;
|
|
}
|
|
// second static init pass
|
|
if(staticInit) {
|
|
CellFlagType set2Flag = CFMbndInflow|(OId<<24);
|
|
for(size_t n=0; n<mMOIVertices.size(); n++) {
|
|
POS2GRID_CHECK(mMOIVertices,n);
|
|
if(RFLAG(level, i,j,k, workSet)&(CFMbndInflow|CFMbndOutflow)){ continue; }
|
|
if(RFLAG(level, i,j,k, workSet)&(CFEmpty)) {
|
|
forceChangeFlag(level, i,j,k, workSet, set2Flag);
|
|
} else if(RFLAG(level, i,j,k, workSet)&(CFFluid|CFInter)) {
|
|
forceChangeFlag(level, i,j,k, workSet,
|
|
(RFLAG(level, i,j,k, workSet)&CFNoPersistMask)|set2Flag);
|
|
}
|
|
}
|
|
} // second static inflow pass
|
|
|
|
} // inflow
|
|
|
|
else if(ntype&CFMbndOutflow){
|
|
const LbmFloat iniRho = 0.0;
|
|
for(size_t n=0; n<mMOIVertices.size(); n++) {
|
|
POS2GRID_CHECK(mMOIVertices,n);
|
|
// FIXME check fluid/inter cells for non-static!?
|
|
if(!(RFLAG(level, i,j,k, workSet)&(CFFluid|CFInter))) {
|
|
if((staticInit)&&(RFLAG(level, i,j,k, workSet)==CFEmpty)) {
|
|
forceChangeFlag(level, i,j,k, workSet, CFMbndOutflow); }
|
|
continue;
|
|
}
|
|
monFluids++;
|
|
// interface cell - might be double empty? FIXME check?
|
|
|
|
// remove fluid cells, shouldnt be here anyway
|
|
LbmFloat *tcel = RACPNT(level, i,j,k,workSet);
|
|
LbmFloat fluidRho = RAC(tcel,0); FORDF1 { fluidRho += RAC(tcel,l); }
|
|
mInitialMass -= fluidRho;
|
|
RAC(tcel, dMass) = RAC(tcel, dFfrac) = iniRho;
|
|
RAC(tcel, dFlux) = FLUX_INIT;
|
|
CellFlagType setFlag = CFInter;
|
|
changeFlag(level, i,j,k, workSet, setFlag);
|
|
|
|
// same as ifemptied for if below
|
|
LbmPoint emptyp;
|
|
emptyp.x = i; emptyp.y = j; emptyp.z = k;
|
|
mListEmpty.push_back( emptyp );
|
|
//calcCellsEmptied++;
|
|
} // points
|
|
// second static init pass
|
|
if(staticInit) {
|
|
CellFlagType set2Flag = CFMbndOutflow|(OId<<24);
|
|
for(size_t n=0; n<mMOIVertices.size(); n++) {
|
|
POS2GRID_CHECK(mMOIVertices,n);
|
|
if(RFLAG(level, i,j,k, workSet)&(CFMbndInflow|CFMbndOutflow)){ continue; }
|
|
if(RFLAG(level, i,j,k, workSet)&(CFEmpty)) {
|
|
forceChangeFlag(level, i,j,k, workSet, set2Flag);
|
|
} else if(RFLAG(level, i,j,k, workSet)&(CFFluid|CFInter)) {
|
|
forceChangeFlag(level, i,j,k, workSet,
|
|
(RFLAG(level, i,j,k, workSet)&CFNoPersistMask)|set2Flag);
|
|
}
|
|
}
|
|
} // second static outflow pass
|
|
} // outflow
|
|
|
|
} // allbound check
|
|
} // OId
|
|
|
|
|
|
/* { // DEBUG check
|
|
int workSet = mLevel[level].setCurr;
|
|
FSGR_FORIJK1(level) {
|
|
if( (RFLAG(level,i,j,k, workSet) & CFBndMoving) ) {
|
|
if(QCELL(level, i,j,k, workSet, dFlux)!=targetTime) {
|
|
errMsg("lastt"," old val!? at "<<PRINT_IJK<<" t="<<QCELL(level, i,j,k, workSet, dFlux)<<" target="<<targetTime);
|
|
}
|
|
}
|
|
}
|
|
} // DEBUG */
|
|
|
|
#undef POS2GRID_CHECK
|
|
myTime_t monend = getTime();
|
|
if(monend-monstart>0) debMsgStd("LbmFsgrSolver::initMovingObstacles",DM_MSG,"Total: "<<monTotal<<" Points :"<<monPoints<<" ObstInits:"<<monObsts<<" FlInits:"<<monFluids<<" Trafos:"<<monTotal<<", took "<<getTimeString(monend-monstart), 7);
|
|
mLastSimTime = targetTime;
|
|
}
|
|
|
|
|
|
// geoinit position
|
|
|
|
#define GETPOS(i,j,k) \
|
|
ntlVec3Gfx ggpos = \
|
|
ntlVec3Gfx( iniPos[0]+ dvec[0]*(gfxReal)(i), \
|
|
iniPos[1]+ dvec[1]*(gfxReal)(j), \
|
|
iniPos[2]+ dvec[2]*(gfxReal)(k) ); \
|
|
if((LBMDIM==2)&&(mInit2dYZ)) { SWAPYZ(ggpos); }
|
|
|
|
/*****************************************************************************/
|
|
/*! perform geometry init (if switched on) */
|
|
/*****************************************************************************/
|
|
extern int globGeoInitDebug; //solver_interface
|
|
bool LbmFsgrSolver::initGeometryFlags() {
|
|
int level = mMaxRefine;
|
|
myTime_t geotimestart = getTime();
|
|
ntlGeometryObject *pObj;
|
|
ntlVec3Gfx dvec = ntlVec3Gfx(mLevel[level].nodeSize); //dvec*1.0;
|
|
debMsgStd("LbmFsgrSolver::initGeometryFlags",DM_MSG,"Performing geometry init ("<< mLbmInitId <<") v"<<dvec,3);
|
|
// WARNING - copied to movobj init!
|
|
|
|
/* init object velocities, this has always to be called for init */
|
|
initGeoTree();
|
|
if(mAllfluid) {
|
|
freeGeoTree();
|
|
return true; }
|
|
|
|
// make sure moving obstacles are inited correctly
|
|
// preinit moving obj points
|
|
int numobjs = (int)(mpGiObjects->size());
|
|
for(int o=0; o<numobjs; o++) {
|
|
ntlGeometryObject *obj = (*mpGiObjects)[o];
|
|
//debMsgStd("LbmFsgrSolver::initMovingObstacles",DM_MSG," obj "<<obj->getName()<<" type "<<obj->getGeoInitType()<<" anim"<<obj->getIsAnimated()<<" "<<obj->getVolumeInit() ,9);
|
|
if(
|
|
((obj->getGeoInitType()&FGI_ALLBOUNDS) && (obj->getIsAnimated())) ||
|
|
(obj->getVolumeInit()&VOLUMEINIT_SHELL) ) {
|
|
if(!obj->getMeshAnimated()) {
|
|
debMsgStd("LbmFsgrSolver::initMovingObstacles",DM_MSG," obj "<<obj->getName()<<" type "<<obj->getGeoInitType()<<" anim"<<obj->getIsAnimated()<<" "<<obj->getVolumeInit() ,9);
|
|
obj->initMovingPoints(mSimulationTime, mLevel[mMaxRefine].nodeSize);
|
|
}
|
|
}
|
|
}
|
|
|
|
// max speed init
|
|
ntlVec3Gfx maxMovobjVelRw = getGeoMaxMovementVelocity( mSimulationTime, mpParam->getTimestep() );
|
|
ntlVec3Gfx maxMovobjVel = vec2G( mpParam->calculateLattVelocityFromRw( vec2P( maxMovobjVelRw )) );
|
|
mpParam->setSimulationMaxSpeed( norm(maxMovobjVel) + norm(mLevel[level].gravity) );
|
|
LbmFloat allowMax = mpParam->getTadapMaxSpeed(); // maximum allowed velocity
|
|
debMsgStd("LbmFsgrSolver::initGeometryFlags",DM_MSG,"Maximum Velocity from geo init="<< maxMovobjVel <<" from mov. obj.="<<maxMovobjVelRw<<" , allowed Max="<<allowMax ,5);
|
|
if(mpParam->getSimulationMaxSpeed() > allowMax) {
|
|
// similar to adaptTimestep();
|
|
LbmFloat nextmax = mpParam->getSimulationMaxSpeed();
|
|
LbmFloat newdt = mpParam->getTimestep() * (allowMax / nextmax); // newtr
|
|
debMsgStd("LbmFsgrSolver::initGeometryFlags",DM_MSG,"Performing reparametrization, newdt="<< newdt<<" prevdt="<< mpParam->getTimestep() <<" ",5);
|
|
mpParam->setDesiredTimestep( newdt );
|
|
mpParam->calculateAllMissingValues( mSimulationTime, mSilent );
|
|
maxMovobjVel = vec2G( mpParam->calculateLattVelocityFromRw( vec2P(getGeoMaxMovementVelocity(
|
|
mSimulationTime, mpParam->getTimestep() )) ));
|
|
debMsgStd("LbmFsgrSolver::initGeometryFlags",DM_MSG,"New maximum Velocity from geo init="<< maxMovobjVel,5);
|
|
}
|
|
recalculateObjectSpeeds();
|
|
// */
|
|
|
|
// init obstacles for first time step (requires obj speeds)
|
|
initMovingObstacles(true);
|
|
|
|
/* set interface cells */
|
|
ntlVec3Gfx pos,iniPos; // position of current cell
|
|
LbmFloat rhomass = 0.0;
|
|
CellFlagType ntype = CFInvalid;
|
|
int savedNodes = 0;
|
|
int OId = -1;
|
|
gfxReal distance;
|
|
|
|
// 2d display as rectangles
|
|
if(LBMDIM==2) {
|
|
dvec[2] = 0.0;
|
|
iniPos =(mvGeoStart + ntlVec3Gfx( 0.0, 0.0, (mvGeoEnd[2]-mvGeoStart[2])*0.5 ))+(dvec*0.5);
|
|
//if(mInit2dYZ) { SWAPYZ(mGravity); for(int lev=0; lev<=mMaxRefine; lev++){ SWAPYZ( mLevel[lev].gravity ); } }
|
|
} else {
|
|
iniPos =(mvGeoStart + ntlVec3Gfx( 0.0 ))+(dvec*0.5);
|
|
}
|
|
|
|
|
|
// first init boundary conditions
|
|
// invalid cells are set to empty afterwards
|
|
// TODO use floop macros!?
|
|
for(int k= getForZMin1(); k< getForZMax1(level); ++k) {
|
|
for(int j=1;j<mLevel[level].lSizey-1;j++) {
|
|
for(int i=1;i<mLevel[level].lSizex-1;i++) {
|
|
ntype = CFInvalid;
|
|
|
|
GETPOS(i,j,k);
|
|
const bool inside = geoInitCheckPointInside( ggpos, FGI_ALLBOUNDS, OId, distance);
|
|
if(inside) {
|
|
pObj = (*mpGiObjects)[OId];
|
|
switch( pObj->getGeoInitType() ){
|
|
case FGI_MBNDINFLOW:
|
|
if(! pObj->getIsAnimated() ) {
|
|
rhomass = 1.0;
|
|
ntype = CFFluid | CFMbndInflow;
|
|
} else {
|
|
ntype = CFInvalid;
|
|
}
|
|
break;
|
|
case FGI_MBNDOUTFLOW:
|
|
if(! pObj->getIsAnimated() ) {
|
|
rhomass = 0.0;
|
|
ntype = CFEmpty|CFMbndOutflow;
|
|
} else {
|
|
ntype = CFInvalid;
|
|
}
|
|
break;
|
|
case FGI_BNDNO:
|
|
rhomass = BND_FILL;
|
|
ntype = CFBnd|CFBndNoslip;
|
|
break;
|
|
case FGI_BNDPART:
|
|
rhomass = BND_FILL;
|
|
ntype = CFBnd|CFBndPartslip; break;
|
|
case FGI_BNDFREE:
|
|
rhomass = BND_FILL;
|
|
ntype = CFBnd|CFBndFreeslip; break;
|
|
default: // warn here?
|
|
rhomass = BND_FILL;
|
|
ntype = CFBnd|CFBndNoslip; break;
|
|
}
|
|
}
|
|
if(ntype != CFInvalid) {
|
|
// initDefaultCell
|
|
if((ntype & CFMbndInflow) || (ntype & CFMbndOutflow) ) { }
|
|
ntype |= (OId<<24); // NEWTEST2
|
|
initVelocityCell(level, i,j,k, ntype, rhomass, rhomass, mObjectSpeeds[OId] );
|
|
}
|
|
|
|
// walk along x until hit for following inits
|
|
if(distance<=-1.0) { distance = 100.0; } // FIXME dangerous
|
|
if(distance>=0.0) {
|
|
gfxReal dcnt=dvec[0];
|
|
while(( dcnt< distance-dvec[0] )&&(i+1<mLevel[level].lSizex-1)) {
|
|
dcnt += dvec[0]; i++;
|
|
savedNodes++;
|
|
if(ntype != CFInvalid) {
|
|
// rho,mass,OId are still inited from above
|
|
initVelocityCell(level, i,j,k, ntype, rhomass, rhomass, mObjectSpeeds[OId] );
|
|
}
|
|
}
|
|
}
|
|
// */
|
|
|
|
}
|
|
}
|
|
} // zmax
|
|
// */
|
|
|
|
// now init fluid layer
|
|
for(int k= getForZMin1(); k< getForZMax1(level); ++k) {
|
|
for(int j=1;j<mLevel[level].lSizey-1;j++) {
|
|
for(int i=1;i<mLevel[level].lSizex-1;i++) {
|
|
if(!(RFLAG(level, i,j,k, mLevel[level].setCurr)==CFEmpty)) continue;
|
|
ntype = CFInvalid;
|
|
int inits = 0;
|
|
GETPOS(i,j,k);
|
|
const bool inside = geoInitCheckPointInside( ggpos, FGI_FLUID, OId, distance);
|
|
if(inside) {
|
|
ntype = CFFluid;
|
|
}
|
|
if(ntype != CFInvalid) {
|
|
// initDefaultCell
|
|
rhomass = 1.0;
|
|
initVelocityCell(level, i,j,k, ntype, rhomass, rhomass, mObjectSpeeds[OId] );
|
|
inits++;
|
|
}
|
|
|
|
// walk along x until hit for following inits
|
|
if(distance<=-1.0) { distance = 100.0; }
|
|
if(distance>=0.0) {
|
|
gfxReal dcnt=dvec[0];
|
|
while((dcnt< distance )&&(i+1<mLevel[level].lSizex-1)) {
|
|
dcnt += dvec[0]; i++;
|
|
savedNodes++;
|
|
if(!(RFLAG(level, i,j,k, mLevel[level].setCurr)==CFEmpty)) continue;
|
|
if(ntype != CFInvalid) {
|
|
// rhomass are still inited from above
|
|
initVelocityCell(level, i,j,k, ntype, rhomass, rhomass, mObjectSpeeds[OId] );
|
|
inits++;
|
|
}
|
|
}
|
|
} // distance>0
|
|
|
|
}
|
|
}
|
|
} // zmax
|
|
|
|
// reset invalid to empty again
|
|
for(int k= getForZMin1(); k< getForZMax1(level); ++k) {
|
|
for(int j=1;j<mLevel[level].lSizey-1;j++) {
|
|
for(int i=1;i<mLevel[level].lSizex-1;i++) {
|
|
if(RFLAG(level, i,j,k, mLevel[level].setCurr)==CFInvalid) {
|
|
RFLAG(level, i,j,k, mLevel[level].setOther) =
|
|
RFLAG(level, i,j,k, mLevel[level].setCurr) = CFEmpty;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
freeGeoTree();
|
|
myTime_t geotimeend = getTime();
|
|
debMsgStd("LbmFsgrSolver::initGeometryFlags",DM_MSG,"Geometry init done ("<< getTimeString(geotimeend-geotimestart)<<","<<savedNodes<<") " , 10 );
|
|
//errMsg(" SAVED "," "<<savedNodes<<" of "<<(mLevel[mMaxRefine].lSizex*mLevel[mMaxRefine].lSizey*mLevel[mMaxRefine].lSizez));
|
|
return true;
|
|
}
|
|
|
|
#undef GETPOS
|
|
|
|
/*****************************************************************************/
|
|
/* init part for all freesurface testcases */
|
|
void LbmFsgrSolver::initFreeSurfaces() {
|
|
double interfaceFill = 0.45; // filling level of interface cells
|
|
//interfaceFill = 1.0; // DEUG!! GEOMTEST!!!!!!!!!!!!
|
|
|
|
// set interface cells
|
|
FSGR_FORIJK1(mMaxRefine) {
|
|
if( ( RFLAG(mMaxRefine, i,j,k, mLevel[mMaxRefine].setCurr)& CFFluid )) {
|
|
FORDF1 {
|
|
int ni=i+dfVecX[l], nj=j+dfVecY[l], nk=k+dfVecZ[l];
|
|
if( ( RFLAG(mMaxRefine, ni, nj, nk, mLevel[mMaxRefine].setCurr)& CFEmpty ) ) {
|
|
LbmFloat arho=0., aux=0., auy=0., auz=0.;
|
|
interpolateCellValues(mMaxRefine, ni,nj,nk, mLevel[mMaxRefine].setCurr, arho,aux,auy,auz);
|
|
//errMsg("TINI"," "<<PRINT_VEC(ni,nj,nk)<<" v"<<LbmVec(aux,auy,auz) );
|
|
// unnecessary? initEmptyCell(mMaxRefine, ni,nj,nk, CFInter, arho, interfaceFill);
|
|
initVelocityCell(mMaxRefine, ni,nj,nk, CFInter, arho, interfaceFill, LbmVec(aux,auy,auz) );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// remove invalid interface cells
|
|
FSGR_FORIJK1(mMaxRefine) {
|
|
// remove invalid interface cells
|
|
if( ( RFLAG(mMaxRefine, i,j,k, mLevel[mMaxRefine].setCurr)& CFInter) ) {
|
|
int delit = 0;
|
|
int NBs = 0; // neighbor flags or'ed
|
|
int noEmptyNB = 1;
|
|
|
|
FORDF1 {
|
|
if( ( RFLAG_NBINV(mMaxRefine, i, j, k, mLevel[mMaxRefine].setCurr,l )& CFEmpty ) ) {
|
|
noEmptyNB = 0;
|
|
}
|
|
NBs |= RFLAG_NBINV(mMaxRefine, i, j, k, mLevel[mMaxRefine].setCurr, l);
|
|
}
|
|
// remove cells with no fluid or interface neighbors
|
|
if((NBs & CFFluid)==0) { delit = 1; }
|
|
if((NBs & CFInter)==0) { delit = 1; }
|
|
// remove cells with no empty neighbors
|
|
if(noEmptyNB) { delit = 2; }
|
|
|
|
// now we can remove the cell
|
|
if(delit==1) {
|
|
initEmptyCell(mMaxRefine, i,j,k, CFEmpty, 1.0, 0.0);
|
|
}
|
|
if(delit==2) {
|
|
//initEmptyCell(mMaxRefine, i,j,k, CFFluid, 1.0, 1.0);
|
|
LbmFloat arho=0., aux=0., auy=0., auz=0.;
|
|
interpolateCellValues(mMaxRefine, i,j,k, mLevel[mMaxRefine].setCurr, arho,aux,auy,auz);
|
|
initVelocityCell(mMaxRefine, i,j,k, CFFluid, arho,1., LbmVec(aux,auy,auz) );
|
|
}
|
|
} // interface
|
|
} // */
|
|
|
|
// another brute force init, make sure the fill values are right...
|
|
// and make sure both sets are equal
|
|
for(int lev=0; lev<=mMaxRefine; lev++) {
|
|
FSGR_FORIJK_BOUNDS(lev) {
|
|
if( (RFLAG(lev, i,j,k,0) & (CFBnd)) ) {
|
|
QCELL(lev, i,j,k,mLevel[mMaxRefine].setCurr, dFfrac) = BND_FILL;
|
|
continue;
|
|
}
|
|
if( (RFLAG(lev, i,j,k,0) & (CFEmpty)) ) {
|
|
QCELL(lev, i,j,k,mLevel[mMaxRefine].setCurr, dFfrac) = 0.0;
|
|
continue;
|
|
}
|
|
} }
|
|
|
|
// ----------------------------------------------------------------------
|
|
// smoother surface...
|
|
if(mInitSurfaceSmoothing>0) {
|
|
debMsgStd("Surface Smoothing init", DM_MSG, "Performing "<<(mInitSurfaceSmoothing)<<" smoothing timestep ",10);
|
|
#if COMPRESSGRIDS==1
|
|
//errFatal("NYI","COMPRESSGRIDS mInitSurfaceSmoothing",SIMWORLD_INITERROR); return;
|
|
#endif // COMPRESSGRIDS==0
|
|
}
|
|
for(int s=0; s<mInitSurfaceSmoothing; s++) {
|
|
//SGR_FORIJK1(mMaxRefine) {
|
|
|
|
int kstart=getForZMin1(), kend=getForZMax1(mMaxRefine);
|
|
int lev = mMaxRefine;
|
|
#if COMPRESSGRIDS==0
|
|
for(int k=kstart;k<kend;++k) {
|
|
#else // COMPRESSGRIDS==0
|
|
int kdir = 1; // COMPRT ON
|
|
if(mLevel[lev].setCurr==1) {
|
|
kdir = -1;
|
|
int temp = kend;
|
|
kend = kstart-1;
|
|
kstart = temp-1;
|
|
} // COMPRT
|
|
for(int k=kstart;k!=kend;k+=kdir) {
|
|
#endif // COMPRESSGRIDS==0
|
|
for(int j=1;j<mLevel[lev].lSizey-1;++j) {
|
|
for(int i=1;i<mLevel[lev].lSizex-1;++i) {
|
|
if( ( RFLAG(lev, i,j,k, mLevel[lev].setCurr)& CFInter) ) {
|
|
LbmFloat mass = 0.0;
|
|
//LbmFloat nbdiv;
|
|
//FORDF0 {
|
|
for(int l=0;(l<cDirNum); l++) {
|
|
int ni=i+dfVecX[l], nj=j+dfVecY[l], nk=k+dfVecZ[l];
|
|
if( RFLAG(lev, ni,nj,nk, mLevel[lev].setCurr) & CFFluid ){
|
|
mass += 1.0;
|
|
}
|
|
if( RFLAG(lev, ni,nj,nk, mLevel[lev].setCurr) & CFInter ){
|
|
mass += QCELL(lev, ni,nj,nk, mLevel[lev].setCurr, dMass);
|
|
}
|
|
//nbdiv+=1.0;
|
|
}
|
|
|
|
//errMsg(" I ", PRINT_IJK<<" m"<<mass );
|
|
QCELL(lev, i,j,k, mLevel[lev].setOther, dMass) = (mass/ ((LbmFloat)cDirNum) );
|
|
QCELL(lev, i,j,k, mLevel[lev].setOther, dFfrac) = QCELL(lev, i,j,k, mLevel[lev].setOther, dMass);
|
|
}
|
|
}}}
|
|
|
|
mLevel[lev].setOther = mLevel[lev].setCurr;
|
|
mLevel[lev].setCurr ^= 1;
|
|
}
|
|
// copy back...?
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/* init part for all freesurface testcases */
|
|
void LbmFsgrSolver::initStandingFluidGradient() {
|
|
// ----------------------------------------------------------------------
|
|
// standing fluid preinit
|
|
const int debugStandingPreinit = 0;
|
|
int haveStandingFluid = 0;
|
|
|
|
#define STANDFLAGCHECK(iindex) \
|
|
if( ( (RFLAG(mMaxRefine,i,j,k,mLevel[mMaxRefine].setCurr) & (CFInter)) ) || \
|
|
( (RFLAG(mMaxRefine,i,j,k,mLevel[mMaxRefine].setCurr) & (CFEmpty)) ) ){ \
|
|
if((iindex)>1) { haveStandingFluid=(iindex); } \
|
|
j = mLevel[mMaxRefine].lSizey; i=mLevel[mMaxRefine].lSizex; k=getForZMaxBnd(); \
|
|
continue; \
|
|
}
|
|
int gravIndex[3] = {0,0,0};
|
|
int gravDir[3] = {1,1,1};
|
|
int maxGravComp = 1; // by default y
|
|
int gravComp1 = 0; // by default y
|
|
int gravComp2 = 2; // by default y
|
|
if( ABS(mLevel[mMaxRefine].gravity[0]) > ABS(mLevel[mMaxRefine].gravity[1]) ){ maxGravComp = 0; gravComp1=1; gravComp2=2; }
|
|
if( ABS(mLevel[mMaxRefine].gravity[2]) > ABS(mLevel[mMaxRefine].gravity[0]) ){ maxGravComp = 2; gravComp1=0; gravComp2=1; }
|
|
|
|
int gravIMin[3] = { 0 , 0 , 0 };
|
|
int gravIMax[3] = {
|
|
mLevel[mMaxRefine].lSizex + 0,
|
|
mLevel[mMaxRefine].lSizey + 0,
|
|
mLevel[mMaxRefine].lSizez + 0 };
|
|
if(LBMDIM==2) gravIMax[2] = 1;
|
|
|
|
//int gravDir = 1;
|
|
if( mLevel[mMaxRefine].gravity[maxGravComp] > 0.0 ) {
|
|
// swap directions
|
|
int i=maxGravComp;
|
|
int tmp = gravIMin[i];
|
|
gravIMin[i] = gravIMax[i] - 1;
|
|
gravIMax[i] = tmp - 1;
|
|
gravDir[i] = -1;
|
|
}
|
|
#define PRINTGDIRS \
|
|
errMsg("Standing fp","X start="<<gravIMin[0]<<" end="<<gravIMax[0]<<" dir="<<gravDir[0] ); \
|
|
errMsg("Standing fp","Y start="<<gravIMin[1]<<" end="<<gravIMax[1]<<" dir="<<gravDir[1] ); \
|
|
errMsg("Standing fp","Z start="<<gravIMin[2]<<" end="<<gravIMax[2]<<" dir="<<gravDir[2] );
|
|
// _PRINTGDIRS;
|
|
|
|
bool gravAbort = false;
|
|
#define GRAVLOOP \
|
|
gravAbort=false; \
|
|
for(gravIndex[2]= gravIMin[2]; (gravIndex[2]!=gravIMax[2])&&(!gravAbort); gravIndex[2] += gravDir[2]) \
|
|
for(gravIndex[1]= gravIMin[1]; (gravIndex[1]!=gravIMax[1])&&(!gravAbort); gravIndex[1] += gravDir[1]) \
|
|
for(gravIndex[0]= gravIMin[0]; (gravIndex[0]!=gravIMax[0])&&(!gravAbort); gravIndex[0] += gravDir[0])
|
|
|
|
GRAVLOOP {
|
|
int i = gravIndex[0], j = gravIndex[1], k = gravIndex[2];
|
|
if( ( (RFLAG(mMaxRefine,i,j,k,mLevel[mMaxRefine].setCurr) & (CFInter)) ) ||
|
|
( (RFLAG(mMaxRefine,i,j,k,mLevel[mMaxRefine].setCurr) & (CFBndMoving)) ) ||
|
|
( (RFLAG(mMaxRefine,i,j,k,mLevel[mMaxRefine].setCurr) & (CFEmpty)) ) ) {
|
|
int fluidHeight = (ABS(gravIndex[maxGravComp] - gravIMin[maxGravComp]));
|
|
if(debugStandingPreinit) errMsg("Standing fp","fh="<<fluidHeight<<" gmax="<<gravIMax[maxGravComp]<<" gi="<<gravIndex[maxGravComp] );
|
|
if(fluidHeight>1) {
|
|
haveStandingFluid = fluidHeight; //gravIndex[maxGravComp];
|
|
gravIMax[maxGravComp] = gravIndex[maxGravComp] + gravDir[maxGravComp];
|
|
}
|
|
gravAbort = true; continue;
|
|
}
|
|
} // GRAVLOOP
|
|
// _PRINTGDIRS;
|
|
|
|
LbmFloat fluidHeight;
|
|
fluidHeight = (LbmFloat)(ABS(gravIMax[maxGravComp]-gravIMin[maxGravComp]));
|
|
#if LBM_INCLUDE_TESTSOLVERS==1
|
|
if(mUseTestdata) mpTest->mFluidHeight = (int)fluidHeight;
|
|
#endif // ELBEEM_PLUGIN!=1
|
|
if(debugStandingPreinit) debMsgStd("Standing fluid preinit", DM_MSG, "fheight="<<fluidHeight<<" min="<<PRINT_VEC(gravIMin[0],gravIMin[1], gravIMin[2])<<" max="<<PRINT_VEC(gravIMax[0], gravIMax[1],gravIMax[2])<<
|
|
" mgc="<<maxGravComp<<" mc1="<<gravComp1<<" mc2="<<gravComp2<<" dir="<<gravDir[maxGravComp]<<" have="<<haveStandingFluid ,10);
|
|
|
|
if(mDisableStandingFluidInit) {
|
|
debMsgStd("Standing fluid preinit", DM_MSG, "Should be performed - but skipped due to mDisableStandingFluidInit flag set!", 2);
|
|
haveStandingFluid=0;
|
|
}
|
|
|
|
// copy flags and init , as no flags will be changed during grav init
|
|
// also important for corasening later on
|
|
const int lev = mMaxRefine;
|
|
CellFlagType nbflag[LBM_DFNUM], nbored;
|
|
for(int k=getForZMinBnd();k<getForZMaxBnd(mMaxRefine);++k) {
|
|
for(int j=0;j<mLevel[lev].lSizey-0;++j) {
|
|
for(int i=0;i<mLevel[lev].lSizex-0;++i) {
|
|
if( (RFLAG(lev, i,j,k,SRCS(lev)) & (CFFluid)) ) {
|
|
nbored = 0;
|
|
FORDF1 {
|
|
nbflag[l] = RFLAG_NB(lev, i,j,k, SRCS(lev),l);
|
|
nbored |= nbflag[l];
|
|
}
|
|
if(nbored&CFBnd) {
|
|
RFLAG(lev, i,j,k,SRCS(lev)) &= (~CFNoBndFluid);
|
|
} else {
|
|
RFLAG(lev, i,j,k,SRCS(lev)) |= CFNoBndFluid;
|
|
}
|
|
}
|
|
RFLAG(lev, i,j,k,TSET(lev)) = RFLAG(lev, i,j,k,SRCS(lev));
|
|
} } }
|
|
|
|
if(haveStandingFluid) {
|
|
int rhoworkSet = mLevel[lev].setCurr;
|
|
myTime_t timestart = getTime(); // FIXME use user time here?
|
|
|
|
GRAVLOOP {
|
|
int i = gravIndex[0], j = gravIndex[1], k = gravIndex[2];
|
|
//debMsgStd("Standing fluid preinit", DM_MSG, " init check "<<PRINT_IJK<<" "<< haveStandingFluid, 1 );
|
|
if( ( (RFLAG(lev, i,j,k,rhoworkSet) & (CFInter)) ) ||
|
|
( (RFLAG(lev, i,j,k,rhoworkSet) & (CFEmpty)) ) ){
|
|
//gravAbort = true;
|
|
continue;
|
|
}
|
|
|
|
LbmFloat rho = 1.0;
|
|
// 1/6 velocity from denisty gradient, 1/2 for delta of two cells
|
|
rho += 1.0* (fluidHeight-gravIndex[maxGravComp]) *
|
|
(mLevel[lev].gravity[maxGravComp])* (-3.0/1.0)*(mLevel[lev].omega);
|
|
if(debugStandingPreinit)
|
|
if((gravIndex[gravComp1]==gravIMin[gravComp1]) && (gravIndex[gravComp2]==gravIMin[gravComp2])) {
|
|
errMsg("Standing fp","gi="<<gravIndex[maxGravComp]<<" rho="<<rho<<" at "<<PRINT_IJK);
|
|
}
|
|
|
|
if( (RFLAG(lev, i,j,k, rhoworkSet) & CFFluid) ||
|
|
(RFLAG(lev, i,j,k, rhoworkSet) & CFInter) ) {
|
|
FORDF0 { QCELL(lev, i,j,k, rhoworkSet, l) *= rho; }
|
|
QCELL(lev, i,j,k, rhoworkSet, dMass) *= rho;
|
|
}
|
|
|
|
} // GRAVLOOP
|
|
|
|
debMsgStd("Standing fluid preinit", DM_MSG, "Density gradient inited (max-rho:"<<
|
|
(1.0+ (fluidHeight) * (mLevel[lev].gravity[maxGravComp])* (-3.0/1.0)*(mLevel[lev].omega)) <<", h:"<< fluidHeight<<") ", 8);
|
|
|
|
int preinitSteps = (haveStandingFluid* ((mLevel[lev].lSizey+mLevel[lev].lSizez+mLevel[lev].lSizex)/3) );
|
|
preinitSteps = (haveStandingFluid>>2); // not much use...?
|
|
//preinitSteps = 0;
|
|
debMsgStd("Standing fluid preinit", DM_MSG, "Performing "<<preinitSteps<<" prerelaxations ",10);
|
|
for(int s=0; s<preinitSteps; s++) {
|
|
// in solver main cpp
|
|
standingFluidPreinit();
|
|
}
|
|
|
|
myTime_t timeend = getTime();
|
|
debMsgStd("Standing fluid preinit", DM_MSG, " done, "<<getTimeString(timeend-timestart), 9);
|
|
#undef NBFLAG
|
|
}
|
|
}
|
|
|
|
|
|
|
|
bool LbmFsgrSolver::checkSymmetry(string idstring)
|
|
{
|
|
bool erro = false;
|
|
bool symm = true;
|
|
int msgs = 0;
|
|
const int maxMsgs = 10;
|
|
const bool markCells = false;
|
|
|
|
//for(int lev=0; lev<=mMaxRefine; lev++) {
|
|
{ int lev = mMaxRefine;
|
|
|
|
// no point if not symm.
|
|
if( (mLevel[lev].lSizex==mLevel[lev].lSizey) && (mLevel[lev].lSizex==mLevel[lev].lSizez)) {
|
|
// ok
|
|
} else {
|
|
return false;
|
|
}
|
|
|
|
for(int s=0; s<2; s++) {
|
|
FSGR_FORIJK1(lev) {
|
|
if(i<(mLevel[lev].lSizex/2)) {
|
|
int inb = (mLevel[lev].lSizey-1-i);
|
|
|
|
if(lev==mMaxRefine) inb -= 1; // FSGR_SYMM_T
|
|
|
|
if( RFLAG(lev, i,j,k,s) != RFLAG(lev, inb,j,k,s) ) { erro = true;
|
|
if(LBMDIM==2) {
|
|
if(msgs<maxMsgs) { msgs++;
|
|
errMsg("EFLAG", PRINT_IJK<<"s"<<s<<" flag "<<RFLAG(lev, i,j,k,s)<<" , at "<<PRINT_VEC(inb,j,k)<<"s"<<s<<" flag "<<RFLAG(lev, inb,j,k,s) );
|
|
}
|
|
}
|
|
if(markCells){ debugMarkCell(lev, i,j,k); debugMarkCell(lev, inb,j,k); }
|
|
symm = false;
|
|
}
|
|
if( LBM_FLOATNEQ(QCELL(lev, i,j,k,s, dMass), QCELL(lev, inb,j,k,s, dMass)) ) { erro = true;
|
|
if(LBMDIM==2) {
|
|
if(msgs<maxMsgs) { msgs++;
|
|
//debMsgDirect(" mass1 "<<QCELL(lev, i,j,k,s, dMass)<<" mass2 "<<QCELL(lev, inb,j,k,s, dMass) <<std::endl);
|
|
errMsg("EMASS", PRINT_IJK<<"s"<<s<<" mass "<<QCELL(lev, i,j,k,s, dMass)<<" , at "<<PRINT_VEC(inb,j,k)<<"s"<<s<<" mass "<<QCELL(lev, inb,j,k,s, dMass) );
|
|
}
|
|
}
|
|
if(markCells){ debugMarkCell(lev, i,j,k); debugMarkCell(lev, inb,j,k); }
|
|
symm = false;
|
|
}
|
|
|
|
LbmFloat nbrho = QCELL(lev, i,j,k, s, dC);
|
|
FORDF1 { nbrho += QCELL(lev, i,j,k, s, l); }
|
|
LbmFloat otrho = QCELL(lev, inb,j,k, s, dC);
|
|
FORDF1 { otrho += QCELL(lev, inb,j,k, s, l); }
|
|
if( LBM_FLOATNEQ(nbrho, otrho) ) { erro = true;
|
|
if(LBMDIM==2) {
|
|
if(msgs<maxMsgs) { msgs++;
|
|
//debMsgDirect(" rho 1 "<<nbrho <<" rho 2 "<<otrho <<std::endl);
|
|
errMsg("ERHO ", PRINT_IJK<<"s"<<s<<" rho "<<nbrho <<" , at "<<PRINT_VEC(inb,j,k)<<"s"<<s<<" rho "<<otrho );
|
|
}
|
|
}
|
|
if(markCells){ debugMarkCell(lev, i,j,k); debugMarkCell(lev, inb,j,k); }
|
|
symm = false;
|
|
}
|
|
}
|
|
} }
|
|
} // lev
|
|
LbmFloat maxdiv =0.0;
|
|
if(erro) {
|
|
errMsg("SymCheck Failed!", idstring<<" rho maxdiv:"<< maxdiv );
|
|
//if(LBMDIM==2) mPanic = true;
|
|
//return false;
|
|
} else {
|
|
errMsg("SymCheck OK!", idstring<<" rho maxdiv:"<< maxdiv );
|
|
}
|
|
// all ok...
|
|
return symm;
|
|
}// */
|
|
|
|
|
|
void
|
|
LbmFsgrSolver::interpolateCellValues(
|
|
int level,int ei,int ej,int ek,int workSet,
|
|
LbmFloat &retrho, LbmFloat &retux, LbmFloat &retuy, LbmFloat &retuz)
|
|
{
|
|
LbmFloat avgrho = 0.0;
|
|
LbmFloat avgux = 0.0, avguy = 0.0, avguz = 0.0;
|
|
LbmFloat cellcnt = 0.0;
|
|
|
|
for(int nbl=1; nbl< cDfNum ; ++nbl) {
|
|
if(RFLAG_NB(level,ei,ej,ek,workSet,nbl) & CFNoInterpolSrc) continue;
|
|
if( (RFLAG_NB(level,ei,ej,ek,workSet,nbl) & (CFFluid|CFInter)) ){
|
|
//((!(RFLAG_NB(level,ei,ej,ek,workSet,nbl) & CFNoInterpolSrc) ) &&
|
|
//(RFLAG_NB(level,ei,ej,ek,workSet,nbl) & CFInter) ) {
|
|
cellcnt += 1.0;
|
|
for(int rl=0; rl< cDfNum ; ++rl) {
|
|
LbmFloat nbdf = QCELL_NB(level,ei,ej,ek, workSet,nbl, rl);
|
|
avgux += (dfDvecX[rl]*nbdf);
|
|
avguy += (dfDvecY[rl]*nbdf);
|
|
avguz += (dfDvecZ[rl]*nbdf);
|
|
avgrho += nbdf;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(cellcnt<=0.0) {
|
|
// no nbs? just use eq.
|
|
avgrho = 1.0;
|
|
avgux = avguy = avguz = 0.0;
|
|
//TTT mNumProblems++;
|
|
#if ELBEEM_PLUGIN!=1
|
|
//mPanic=1;
|
|
// this can happen for worst case moving obj scenarios...
|
|
errMsg("LbmFsgrSolver::interpolateCellValues","Cellcnt<=0.0 at "<<PRINT_VEC(ei,ej,ek));
|
|
#endif // ELBEEM_PLUGIN
|
|
} else {
|
|
// init speed
|
|
avgux /= cellcnt; avguy /= cellcnt; avguz /= cellcnt;
|
|
avgrho /= cellcnt;
|
|
}
|
|
|
|
retrho = avgrho;
|
|
retux = avgux;
|
|
retuy = avguy;
|
|
retuz = avguz;
|
|
} // interpolateCellValues
|
|
|
|
|
|
/******************************************************************************
|
|
* instantiation
|
|
*****************************************************************************/
|
|
|
|
//! lbm factory functions
|
|
LbmSolverInterface* createSolver() { return new LbmFsgrSolver(); }
|
|
|
|
|