/**************************************************************************** * Function definitions ****************************************************************************/ void BoundaryConditionsAndTreatments(const int tn, Space *space, const Model *model) { /* * Internal boundary treatment * * Should be performed first to ensure stencils for diffusive flux * discretization are treated correctly, especially for collapsed * dimensions. */ ImmersedBoundaryTreatment(tn, space, model); /* * External boundary treatment * * When no mixed derivatives are discretized, only cross-type stencils * are needed. Then, the corner ghost nodes do not need treatment. * However, corner ghost nodes are necessary for the computation of * mixed derivatives as in viscous fluxes, or for transfer operators * within multigrid. To treat the entire ghost region, the boundary * treatment should be performed one box layer by one box layer from * inside to outside. */ const Partition *restrict part = &(space->part); int box[DIMS][LIMIT] = {{0}}; /* range box of regions */ for (int r = 0; r <= part->ng; ++r) { /* process layer by layer */ for (int p = PWB; p < PWG; ++p) { const IntVec N = {part->N[p][X], part->N[p][Y], part->N[p][Z]}; for (int s = 0; s < DIMS; ++s) { /* compute range box of each layer */ box[s][MIN] = part->ns[p][s][MIN] + r * (N[s] - !N[s]); box[s][MAX] = part->ns[p][s][MAX] + r * (N[s] + !N[s]); } ApplyBoundaryConditions(p, r, box, tn, space, model); } } return; }
/* This program takes up to three arguments. The first is the Peclet number to * use in the calculation. The second is the number of elements to use when * solving the problem, and the third (optional) argument is the filename to * save the solution to. */ int main(int argc, char *argv[]) { double Pe, h; double left = 0; double right = 1; //double right = PI/2; int n; matrix *J, *F, *u, *Jinv, *mesh, *x; /* Parse arguments */ if(argc < 2) { fprintf(stderr, "Too few arguments: exiting.\n"); return 1; } Pe = atof(argv[1]); n = atoi(argv[2]); /* Create a uniform mesh */ mesh = GenerateUniformMesh(left, right, n); /* Use a mesh with these node spacings */ //mesh = ParseMatrix("[.75;.15;.0125;.0125;.0125;.0125;.0125;.0125;.0125;.0125]"); x = MeshXCoords(mesh, left, right); /* All the nodes are equally spaced. */ h = val(mesh, 0, 0); J = AssembleJ(&CreateElementMatrix, mesh, Pe); //J = AssembleJMesh(&testelem, mesh, Pe); F = AssembleF(&CreateElementLoad, mesh, Pe); //F = AssembleFMesh(&testload, mesh, Pe); ApplyBoundaryConditions(J, F, 0, 1); //ApplyBoundaryConditions(J, F, 2, 1); /* Invert the coefficient matrix and premultiply the load vector by it. */ Jinv = CalcInv(J); u = mtxmul(Jinv, F); /* Print out the result */ if(argc == 4) { mtxprntfile(u, argv[3]); } else { mtxprnt(x); puts(""); mtxprnt(u); } /* Clean up the allocated memory */ DestroyMatrix(J); DestroyMatrix(F); DestroyMatrix(u); DestroyMatrix(Jinv); DestroyMatrix(mesh); return 0; }
void FluidBase::SolvePoissonPressureEquation(unsigned int pressureID, unsigned int divergenceID, int numIterations, bool obstacles, unsigned int pressureOffsetID /* = 0 */) { static unsigned int lastPressure = 0; static unsigned int lastDivergence = 0; static unsigned int lastOffset = 0; if (lastPressure != pressureID) { _poissonSolver.SetOutputTexture(pressureID, _iWidth, _iHeight); _poissonSolver.SetTextureParameter("x", pressureID); _arbitraryPressureBC.SetTextureParameter("p", pressureID); _arbitraryPressureBC.SetOutputTexture(pressureID, _iWidth, _iHeight); lastPressure = pressureID; } if (lastDivergence != divergenceID) { _poissonSolver.SetTextureParameter("b", divergenceID); lastDivergence = divergenceID; } if (obstacles && lastOffset != pressureOffsetID) { _arbitraryPressureBC.SetTextureParameter("offsets", pressureOffsetID); lastOffset = pressureOffsetID; } float step = 1.0f / (float)numIterations; float z = 1 - step; for (int i = 0; i < numIterations; ++i) { // Apply pure neumann boundary conditions ApplyBoundaryConditions(pressureID, 1); // Apply pure neumann boundary conditions to arbitrary // interior boundaries if they are enabled. if (obstacles) { _arbitraryPressureBC.Compute(); } // for the zcull optimization _poissonSolver.SetStreamRect(1.0f / (float)_iWidth, 1.0f / (float)_iHeight, 1 - 1.0f / (float)_iWidth, 1 - 1.0f / (float)_iHeight, z); //*?* this might be something we want to change //_poissonSolver.SetStreamRect(1, 1, _iWidth - 1, _iHeight - 1, z); z -= step; _poissonSolver.Compute(); // perform one Jacobi iteration } }
void FluidBase::ComputeVorticityConfinement(unsigned int velocityID, unsigned int vorticityID, float timestep, float scale) { static unsigned int lastVelocity = 0; static unsigned int lastVorticity = 0; static float lastScale = 0; static float lastTimestep = 0; if (lastTimestep != timestep) { _vorticityForce.SetFragmentParameter1f("timestep", timestep); lastTimestep = timestep; } if (lastVelocity != velocityID) { _vorticityForce.SetTextureParameter("u", velocityID); _vorticityForce.SetOutputTexture(velocityID, _iWidth, _iHeight); lastVelocity = velocityID; } if (lastVorticity != vorticityID) { _vorticityForce.SetTextureParameter("vort", vorticityID); lastVorticity = vorticityID; } if (lastScale != scale) { _vorticityForce.SetFragmentParameter2f("dxscale", scale * _dx, scale * _dx); lastScale = scale; } ApplyBoundaryConditions(velocityID, -1); _vorticityForce.Compute(); }