void SemiLagrangeMAC(FlagGrid& flags, MACGrid& vel, MACGrid& dst, MACGrid& src, Real dt) 
{
	if (flags.isObstacle(i,j,k)) {
		dst(i,j,k) = 0;
		return;
	}
//	std::cout << " Don't worry, I MADE IT till here " << std::endl ;
	if ( isNotFluidMAC(flags,i,j,k) ) {
		dst(i,j,k) = src(i,j,k);
		return;
	}
	
//	std::cout << " Don't worry, I REACHED till here " << std::endl ;

	// get currect velocity at MAC position
	// no need to shift xpos etc. as lookup field is also shifted
	Vec3 xpos = Vec3(i+0.5f,j+0.5f,k+0.5f) - vel.getAtMACX(i,j,k) * dt;
	Real vx = src.getInterpolatedComponent<0>(xpos);
	Vec3 ypos = Vec3(i+0.5f,j+0.5f,k+0.5f) - vel.getAtMACY(i,j,k) * dt;
	Real vy = src.getInterpolatedComponent<1>(ypos);
	Vec3 zpos = Vec3(i+0.5f,j+0.5f,k+0.5f) - vel.getAtMACZ(i,j,k) * dt;
	Real vz = src.getInterpolatedComponent<2>(zpos);
	
//	std::cout << " Don't worry, I CAN till here " << std::endl ;

	dst(i,j,k) = Vec3(vx,vy,vz);

//	std::cout << " Don't worry, I COULD till here " << std::endl ;

}
void fnAdvectSemiLagrange_time_fraction<MACGrid>(FluidSolver* parent, FlagGrid& flags, MACGrid& vel, MACGrid& orig, int order, Real strength, Real time_fraction) {
	Real dt = (time_fraction) * parent->getDt();
	std::cout << " time_fraction = " << time_fraction << std::endl ;
	std::cout << " dt = " << dt << std::endl ;

	// forward step
	MACGrid fwd(parent);    

	SemiLagrangeMAC (flags, vel, fwd, orig, dt);
	
	if (order == 1) {
		orig.swap(fwd);
	}
	else if (order == 2) { // MacCormack
		MACGrid bwd(parent);
		MACGrid newGrid(parent);
		
		// bwd <- backwards step
		SemiLagrangeMAC (flags, vel, bwd, fwd, -dt);

		// newGrid <- compute correction
		MacCormackCorrect<Vec3> (flags, newGrid, orig, fwd, bwd, strength, false, true);

		// clamp values
		MacCormackClampMAC (flags, vel, newGrid, orig, fwd, dt);

		orig.swap(newGrid);
	}
}
void MacCormackClamp(FlagGrid& flags, MACGrid& vel, Grid<T>& dst, Grid<T>& orig, Grid<T>& fwd, Real dt)
{
	if (flags.isObstacle(i,j,k))
		return;
	if ( isNotFluid(flags,i,j,k) ) {
		dst(i,j,k) = fwd(i,j,k);
		return;
	}

	T     dval       = dst(i,j,k);
	Vec3i upperClamp = flags.getSize() - 1;
	
	// lookup forward/backward
	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 );
	
	dval = doClampComponent<T>(upperClamp, orig, dval, posFwd );
	
	// 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) ) 
	{        
		dval = fwd(i,j,k);
	}
	dst(i,j,k) = dval;
}
//! add Buoyancy force based on smoke density
KERNEL(bnd=1) void KnAddBuoyancy(FlagGrid& flags, Grid<Real>& density, MACGrid& vel, Vec3 strength) {    
	if (!flags.isFluid(i,j,k)) return;
	if (flags.isFluid(i-1,j,k))
		vel(i,j,k).x += (0.5 * strength.x) * (density(i,j,k)+density(i-1,j,k));
	if (flags.isFluid(i,j-1,k))
		vel(i,j,k).y += (0.5 * strength.y) * (density(i,j,k)+density(i,j-1,k));
	if (vel.is3D() && flags.isFluid(i,j,k-1))
		vel(i,j,k).z += (0.5 * strength.z) * (density(i,j,k)+density(i,j,k-1));    
}
//! 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;
}
//! enforce a constant inflow/outflow at the grid boundaries
PYTHON void setInflowBcs(MACGrid& vel, string dire, Vec3 value) {
	for(size_t i=0; i<dire.size(); i++) {
		if (dire[i] >= 'x' && dire[i] <= 'z') { 
			int dim = dire[i]-'x';
			KnSetInflow(vel,dim,0,value);
		} else if (dire[i] >= 'X' && dire[i] <= 'Z') {
			int dim = dire[i]-'X';
			KnSetInflow(vel,dim,vel.getSize()[dim]-1,value);
		} else 
			errMsg("invalid character in direction string. Only [xyzXYZ] allowed.");
	}
}
Ejemplo n.º 7
0
//! Kernel: Set matrix stencils and velocities to enable open boundaries
KERNEL void SetOpenBound(Grid<Real>& A0, Grid<Real>& Ai, Grid<Real>& Aj, Grid<Real>& Ak, MACGrid& vel,
                         Vector3D<bool> lowerBound, Vector3D<bool> upperBound)
{    
    // set velocity boundary conditions
    if (lowerBound.x && i == 0) vel(0,j,k) = vel(1,j,k);
    if (lowerBound.y && j == 0) vel(i,0,k) = vel(i,1,k);
    if (lowerBound.z && k == 0) vel(i,j,0) = vel(i,j,1);
    if (upperBound.x && i == maxX-1) vel(maxX-1,j,k) = vel(maxX-2,j,k);
    if (upperBound.y && j == maxY-1) vel(i,maxY-1,k) = vel(i,maxY-2,k);
    if (upperBound.z && k == maxZ-1) vel(i,j,maxZ-1) = vel(i,j,maxZ-2);
    
    // set matrix stencils at boundary
    if ((lowerBound.x && i<=1) || (upperBound.x && i>=maxX-2) ||
        (lowerBound.y && j<=1) || (upperBound.y && j>=maxY-2) ||
        (lowerBound.z && k<=1) || (upperBound.z && k>=maxZ-2)) {
        A0(i,j,k) = vel.is3D() ? 6.0 : 4.0;
        Ai(i,j,k) = -1.0;
        Aj(i,j,k) = -1.0;
        if (vel.is3D()) Ak(i,j,k) = -1.0;
    }
}
inline Real doClampComponentMAC(const Vec3i& upperClamp, MACGrid& orig, Real dst, const Vec3i& posFwd) {
	// clamp forward lookup to grid
	const int i0 = clamp(posFwd.x, 0, upperClamp.x-1);
	const int j0 = clamp(posFwd.y, 0, upperClamp.y-1);
	const int k0 = clamp(posFwd.z, 0, (orig.is3D() ? (upperClamp.z-1) : 1) );
	const int i1 = i0+1, j1 = j0+1, k1= (orig.is3D() ? (k0+1) : k0);
	if (!orig.isInBounds(Vec3i(i0,j0,k0),1)) 
		return dst;
	
	// find min/max around fwd pos
	Real minv = orig(i0,j0,k0)[c], maxv = minv;
	getMinMax(minv, maxv, orig(i1,j0,k0)[c]);
	getMinMax(minv, maxv, orig(i0,j1,k0)[c]);
	getMinMax(minv, maxv, orig(i1,j1,k0)[c]);
	getMinMax(minv, maxv, orig(i0,j0,k1)[c]);
	getMinMax(minv, maxv, orig(i1,j0,k1)[c]);
	getMinMax(minv, maxv, orig(i0,j1,k1)[c]);
	getMinMax(minv, maxv, orig(i1,j1,k1)[c]);
	
	return clamp(dst, minv, maxv);    
}
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;
}
Ejemplo n.º 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);
    }    
}