//! add Forces between fl/fl and fl/em cells
KERNEL(bnd=1) void KnAddForce(FlagGrid& flags, MACGrid& vel, Vec3 force) {
	bool curFluid = flags.isFluid(i,j,k);
	bool curEmpty = flags.isEmpty(i,j,k);
	if (!curFluid && !curEmpty) return;
	
	if (flags.isFluid(i-1,j,k) || (curFluid && flags.isEmpty(i-1,j,k))) 
		vel(i,j,k).x += force.x;
	if (flags.isFluid(i,j-1,k) || (curFluid && flags.isEmpty(i,j-1,k))) 
		vel(i,j,k).y += force.y;
	if (vel.is3D() && (flags.isFluid(i,j,k-1) || (curFluid && flags.isEmpty(i,j,k-1))))
		vel(i,j,k).z += force.z;
}
void MacCormackCorrect(FlagGrid& flags, Grid<T>& dst, Grid<T>& old, Grid<T>& fwd,  Grid<T>& bwd, 
					   Real strength, bool isLevelSet, bool isMAC=false )
{
	// note, replacement for isNotFluidMAC and isNotFluid
	bool skip = false;

	if (!flags.isFluid(idx)) skip = true;
	if(!isMAC) {
	if( (idx>=flags.getStrideX()) && 	(!flags.isFluid(idx-flags.getStrideX()) )) skip = true; 
	if( (idx>=flags.getStrideY()) && 	(!flags.isFluid(idx-flags.getStrideY()) )) skip = true; 
	if ( flags.is3D() ) {
		if( (idx>=flags.getStrideZ()) &&(!flags.isFluid(idx-flags.getStrideZ()) )) skip = true;
	} }
	if ( skip ) {
		dst[idx] = isLevelSet ? fwd[idx] : (T)0.0;
		return;
	}
	
	// note, strenth of correction can be modified here
	dst[idx] = fwd[idx] + strength * 0.5 * (old[idx] - bwd[idx]);
}
void SemiLagrange (FlagGrid& flags, MACGrid& vel, Grid<T>& dst, Grid<T>& src, Real dt, bool isLevelset) 
{
	if (flags.isObstacle(i,j,k)) {
		dst(i,j,k) = 0;
		return;
	}
	if (!isLevelset && isNotFluid(flags,i,j,k) ) {
		dst(i,j,k) = src(i,j,k);
		return;
	}
	
	// SL traceback
	Vec3 pos = Vec3(i+0.5f,j+0.5f,k+0.5f) - vel.getCentered(i,j,k) * dt;
	dst(i,j,k) = src.getInterpolated(pos);
}
void MacCormackClampMAC (FlagGrid& flags, MACGrid& vel, MACGrid& dst, MACGrid& orig, MACGrid& fwd, Real dt)
{
	if (flags.isObstacle(i,j,k))
		return;
	if ( isNotFluidMAC(flags,i,j,k) ) {
		dst(i,j,k) = fwd(i,j,k);
		return;
	}
	
	Vec3  pos(i,j,k);
	Vec3  dval       = dst(i,j,k);
	Vec3i upperClamp = flags.getSize() - 1;
	
	// get total fwd lookup
	Vec3i posFwd = toVec3i( Vec3(i,j,k) - vel.getCentered(i,j,k) * dt );
	Vec3i posBwd = toVec3i( Vec3(i,j,k) + vel.getCentered(i,j,k) * dt );
	
	// clamp individual components
	dval.x = doClampComponentMAC<0>(upperClamp, orig, dval.x, toVec3i( pos - vel.getAtMACX(i,j,k) * dt) );
	dval.y = doClampComponentMAC<1>(upperClamp, orig, dval.y, toVec3i( pos - vel.getAtMACY(i,j,k) * dt) );
	dval.z = doClampComponentMAC<2>(upperClamp, orig, dval.z, toVec3i( pos - vel.getAtMACZ(i,j,k) * dt) );
	
	// test if lookups point out of grid or into obstacle
	if (posFwd.x < 0 || posFwd.y < 0 || posFwd.z < 0 ||
		posBwd.x < 0 || posBwd.y < 0 || posBwd.z < 0 ||
		posFwd.x > upperClamp.x || posFwd.y > upperClamp.y || ((posFwd.z > upperClamp.z)&&flags.is3D()) ||
		posBwd.x > upperClamp.x || posBwd.y > upperClamp.y || ((posBwd.z > upperClamp.z)&&flags.is3D()) 
		//|| flags.isObstacle(posFwd) || flags.isObstacle(posBwd)  // note - this unfortunately introduces asymmetry... TODO update
		) 
	{        
		dval = fwd(i,j,k);
	}
 
	// writeback
	dst(i,j,k) = dval;
}
//! set no-stick wall boundary condition between ob/fl and ob/ob cells
KERNEL void KnSetWallBcs(FlagGrid& flags, MACGrid& vel, Vector3D<bool> lo, Vector3D<bool> up, bool admm) {

	bool curFluid = flags.isFluid(i,j,k);
    bool curObstacle = flags.isObstacle(i,j,k);
	if (!curFluid && !curObstacle) return;

	// MLE 2014-07-04
	// if not admm, leave it as in orig
	// if openBound, don't correct anything (solid is as empty)
	// if admm, correct if vel is pointing outwards
	
	// if "inner" obstacle vel
	if(i>0 && curObstacle && !flags.isFluid(i-1,j,k)) vel(i,j,k).x = 0;
	if(j>0 && curObstacle && !flags.isFluid(i,j-1,k)) vel(i,j,k).y = 0;

	// check lo.x
	if(!lo.x && i>0 && curFluid && flags.isObstacle(i-1,j,k) && ((admm&&vel(i,j,k).x<0)||!admm)) vel(i,j,k).x = 0;
	// check up.x
	if(!up.x && i>0 && curObstacle && flags.isFluid(i-1,j,k) && ((admm&&vel(i,j,k).x>0)||!admm)) vel(i,j,k).x = 0;
	// check lo.y
	if(!lo.y && j>0 && curFluid && flags.isObstacle(i,j-1,k) && ((admm&&vel(i,j,k).y<0)||!admm)) vel(i,j,k).y = 0;
	// check up.y
	if(!up.y && j>0 && curObstacle && flags.isFluid(i,j-1,k) && ((admm&&vel(i,j,k).y>0)||!admm)) vel(i,j,k).y = 0;
	// check lo.z
	if(!lo.z && k>0 && curFluid && flags.isObstacle(i,j,k-1) && ((admm&&vel(i,j,k).z<0)||!admm)) vel(i,j,k).z = 0;
	// check up.z
	if(!up.z && k>0 && curObstacle && flags.isFluid(i,j,k-1) && ((admm&&vel(i,j,k).z>0)||!admm)) vel(i,j,k).z = 0;
	

	/* MLE consider later	
	if (curFluid) {
		if ((i>0 && flags.isStick(i-1,j,k)) || (i<flags.getSizeX()-1 && flags.isStick(i+1,j,k)))
			vel(i,j,k).y = vel(i,j,k).z = 0;
		if ((j>0 && flags.isStick(i,j-1,k)) || (j<flags.getSizeY()-1 && flags.isStick(i,j+1,k)))
			vel(i,j,k).x = vel(i,j,k).z = 0;
		if (vel.is3D() && ((k>0 && flags.isStick(i,j,k-1)) || (k<flags.getSizeZ()-1 && flags.isStick(i,j,k+1))))
			vel(i,j,k).x = vel(i,j,k).y = 0;
	}
	*/
}
예제 #6
0
void CorrectVelGhostFluid (FlagGrid& flags, MACGrid& vel, Grid<Real>& pressure) //, Grid<Real>& phi)
{
    bool curFluid = flags.isFluid(i,j,k);
    if (!curFluid && !flags.isEmpty(i,j,k))
        return;
    
    const Real curPress = pressure(i,j,k);

    //const Real curPhi = phi(i,j,k);
	// TODO - include ghost fluid factor  NT_DEBUG
    
    // in contrast to old implementation:
    // make sure to add gradient for all fluid-empty or fluid-fluid combinations
    // of neighbors...

    if (!flags.isObstacle(i-1,j,k) && (curFluid || flags.isFluid(i-1,j,k)))
        vel(i,j,k).x -= curPress - pressure(i-1,j,k);
    
    if (!flags.isObstacle(i,j-1,k) && (curFluid || flags.isFluid(i,j-1,k)))
        vel(i,j,k).y -= curPress - pressure(i,j-1,k);
    
    if (flags.is3D() && (!flags.isObstacle(i,j,k-1) && (curFluid || flags.isFluid(i,j,k-1))))
        vel(i,j,k).z -= curPress - pressure(i,j,k-1);
}
void TurbulenceParticleSystem::deleteInObstacle(FlagGrid& flags) {
	for (int i=0; i<size(); i++)
		if (flags.isObstacle(mData[i].pos))
			mData[i].flag |= PDELETE;
	compress();
}
//! add Buoyancy force based on smoke density
PYTHON void print_dt_dx(FlagGrid& flags, Grid<Real>& density, MACGrid& vel) {
//	Vec3 f = - gravity * flags.getParent()->getDt() / flags.getParent()->getDx();
	std::cout << " flags.getParent()->getDt() " << flags.getParent()->getDt() << std::endl ;
	std::cout << " flags.getParent()->getDx() " << flags.getParent()->getDx() << std::endl ;
}
//! add Buoyancy force based on smoke density
PYTHON void addBuoyancy(FlagGrid& flags, Grid<Real>& density, MACGrid& vel, Vec3 gravity) {
	Vec3 f = - gravity * flags.getParent()->getDt() / flags.getParent()->getDx();
	KnAddBuoyancy(flags,density, vel, f);
}
//! add gravity forces to all fluid cells
PYTHON void addGravity(FlagGrid& flags, MACGrid& vel, Vec3 gravity) {    
	Vec3 f = gravity * flags.getParent()->getDt() / flags.getDx();
	KnAddForce(flags, vel, f);
}
예제 #11
0
//! Perform pressure projection of the velocity grid
PYTHON void solvePressure(MACGrid& vel, Grid<Real>& pressure, FlagGrid& flags,
                     Grid<Real>* phi = 0, 
                     Grid<Real>* perCellCorr = 0, 
                     Real ghostAccuracy = 0, 
                     Real cgMaxIterFac = 1.5,
                     Real cgAccuracy = 1e-3,
                     string openBound = "",
                     string outflow = "",
                     int outflowHeight = 1,
                     int precondition = 0,
                     bool enforceCompatibility = false,
                     bool useResNorm = true )
{
    //assertMsg(vel.is3D(), "Only 3D grids supported so far");
    
    // parse strings
    Vector3D<bool> loOpenBound, upOpenBound, loOutflow, upOutflow;
    convertDescToVec(openBound, loOpenBound, upOpenBound);
    convertDescToVec(outflow, loOutflow, upOutflow);
    if (vel.is2D() && (loOpenBound.z || upOpenBound.z))
        errMsg("open boundaries for z specified for 2D grid");
    
    // reserve temp grids
    Grid<Real> rhs(parent);
    Grid<Real> residual(parent);
    Grid<Real> search(parent);
    Grid<Real> A0(parent);
    Grid<Real> Ai(parent);
    Grid<Real> Aj(parent);
    Grid<Real> Ak(parent);
    Grid<Real> tmp(parent);
    Grid<Real> pca0(parent);
    Grid<Real> pca1(parent);
    Grid<Real> pca2(parent);
    Grid<Real> pca3(parent);
        
    // setup matrix and boundaries
    MakeLaplaceMatrix (flags, A0, Ai, Aj, Ak);
    SetOpenBound (A0, Ai, Aj, Ak, vel, loOpenBound, upOpenBound);
    
    if (ghostAccuracy > 0) {
        if (!phi) errMsg("solve_pressure: if ghostAccuracy>0, need to specify levelset phi=xxx");
        ApplyGhostFluid (flags, A0, *phi, ghostAccuracy);
    }
    
    // compute divergence and init right hand side
    MakeRhs kernMakeRhs (flags, rhs, vel, perCellCorr);
    
    if (!outflow.empty())
        SetOutflow (rhs, loOutflow, upOutflow, outflowHeight);
    
    if (enforceCompatibility)
        rhs += (Real)(-kernMakeRhs.sum / (Real)kernMakeRhs.cnt);
    
    // CG
    const int maxIter = (int)(cgMaxIterFac * flags.getSize().max());
    GridCgInterface *gcg;
    if (vel.is3D())
        gcg = new GridCg<ApplyMatrix>(pressure, rhs, residual, search, flags, tmp, &A0, &Ai, &Aj, &Ak );
    else
        gcg = new GridCg<ApplyMatrix2D>(pressure, rhs, residual, search, flags, tmp, &A0, &Ai, &Aj, &Ak );
    
    gcg->setAccuracy( cgAccuracy ); 
    gcg->setUseResNorm( useResNorm );

    // optional preconditioning
    gcg->setPreconditioner( (GridCgInterface::PreconditionType)precondition, &pca0, &pca1, &pca2, &pca3);

    for (int iter=0; iter<maxIter; iter++) {
        if (!gcg->iterate()) iter=maxIter;
    } 
    debMsg("FluidSolver::solvePressure iterations:"<<gcg->getIterations()<<", res:"<<gcg->getSigma(), 1);
    delete gcg;
    
    if(ghostAccuracy<=0.) {
        // ghost fluid off, normal correction
        CorrectVelocity (flags, vel, pressure );
    } else {        
        CorrectVelGhostFluid (flags, vel, pressure);
    }    
}
static inline bool isNotFluidMAC(FlagGrid& flags, int i, int j, int k)
{
	if ( flags.isFluid(i,j,k)   ) return false;
	return true;
}