int main(int argc, char *argv[]) { int rank = 0; #ifdef HAVE_MPI // TODO: figure out the right thing to do here... // may want to modify argc and argv before we make the following call: Teuchos::GlobalMPISession mpiSession(&argc, &argv,0); rank=mpiSession.getRank(); #else #endif bool useLineSearch = false; int pToAdd = 2; // for optimal test function approximation int pToAddForStreamFunction = 2; double nonlinearStepSize = 1.0; double dt = 0.5; double nonlinearRelativeEnergyTolerance = 0.015; // used to determine convergence of the nonlinear solution // double nonlinearRelativeEnergyTolerance = 0.15; // used to determine convergence of the nonlinear solution double eps = 1.0/64.0; // width of ramp up to 1.0 for top BC; eps == 0 ==> soln not in H1 // epsilon above is chosen to match our initial 16x16 mesh, to avoid quadrature errors. // double eps = 0.0; // John Evans's problem: not in H^1 bool enforceLocalConservation = false; bool enforceOneIrregularity = true; bool reportPerCellErrors = true; bool useMumps = true; int horizontalCells, verticalCells; int maxIters = 50; // for nonlinear steps vector<double> ReValues; // usage: polyOrder [numRefinements] // parse args: if (argc < 6) { cout << "Usage: NavierStokesCavityFlowContinuationFixedMesh fieldPolyOrder hCells vCells energyErrorGoal Re0 [Re1 ...]\n"; return -1; } int polyOrder = atoi(argv[1]); horizontalCells = atoi(argv[2]); verticalCells = atoi(argv[3]); double energyErrorGoal = atof(argv[4]); for (int i=5; i<argc; i++) { ReValues.push_back(atof(argv[i])); } if (rank == 0) { cout << "L^2 order: " << polyOrder << endl; cout << "initial mesh size: " << horizontalCells << " x " << verticalCells << endl; cout << "energy error goal: " << energyErrorGoal << endl; cout << "Reynolds number values for continuation:\n"; for (int i=0; i<ReValues.size(); i++) { cout << ReValues[i] << ", "; } cout << endl; } FieldContainer<double> quadPoints(4,2); quadPoints(0,0) = 0.0; // x1 quadPoints(0,1) = 0.0; // y1 quadPoints(1,0) = 1.0; quadPoints(1,1) = 0.0; quadPoints(2,0) = 1.0; quadPoints(2,1) = 1.0; quadPoints(3,0) = 0.0; quadPoints(3,1) = 1.0; // define meshes: int H1Order = polyOrder + 1; bool useTriangles = false; bool meshHasTriangles = useTriangles; double minL2Increment = 1e-8; // get variable definitions: VarFactory varFactory = VGPStokesFormulation::vgpVarFactory(); u1 = varFactory.fieldVar(VGP_U1_S); u2 = varFactory.fieldVar(VGP_U2_S); sigma11 = varFactory.fieldVar(VGP_SIGMA11_S); sigma12 = varFactory.fieldVar(VGP_SIGMA12_S); sigma21 = varFactory.fieldVar(VGP_SIGMA21_S); sigma22 = varFactory.fieldVar(VGP_SIGMA22_S); p = varFactory.fieldVar(VGP_P_S); u1hat = varFactory.traceVar(VGP_U1HAT_S); u2hat = varFactory.traceVar(VGP_U2HAT_S); t1n = varFactory.fluxVar(VGP_T1HAT_S); t2n = varFactory.fluxVar(VGP_T2HAT_S); v1 = varFactory.testVar(VGP_V1_S, HGRAD); v2 = varFactory.testVar(VGP_V2_S, HGRAD); tau1 = varFactory.testVar(VGP_TAU1_S, HDIV); tau2 = varFactory.testVar(VGP_TAU2_S, HDIV); q = varFactory.testVar(VGP_Q_S, HGRAD); FunctionPtr u1_0 = Teuchos::rcp( new U1_0(eps) ); FunctionPtr u2_0 = Teuchos::rcp( new U2_0 ); FunctionPtr zero = Function::zero(); ParameterFunctionPtr Re_param = ParameterFunction::parameterFunction(1); VGPNavierStokesProblem problem = VGPNavierStokesProblem(Re_param,quadPoints, horizontalCells,verticalCells, H1Order, pToAdd, u1_0, u2_0, // BC for u zero, zero); // zero forcing function SolutionPtr solution = problem.backgroundFlow(); SolutionPtr solnIncrement = problem.solutionIncrement(); Teuchos::RCP<Mesh> mesh = problem.mesh(); mesh->registerSolution(solution); mesh->registerSolution(solnIncrement); /////////////////////////////////////////////////////////////////////////// // define bilinear form for stream function: VarFactory streamVarFactory; VarPtr phi_hat = streamVarFactory.traceVar("\\widehat{\\phi}"); VarPtr psin_hat = streamVarFactory.fluxVar("\\widehat{\\psi}_n"); VarPtr psi_1 = streamVarFactory.fieldVar("\\psi_1"); VarPtr psi_2 = streamVarFactory.fieldVar("\\psi_2"); VarPtr phi = streamVarFactory.fieldVar("\\phi"); VarPtr q_s = streamVarFactory.testVar("q_s", HGRAD); VarPtr v_s = streamVarFactory.testVar("v_s", HDIV); BFPtr streamBF = Teuchos::rcp( new BF(streamVarFactory) ); streamBF->addTerm(psi_1, q_s->dx()); streamBF->addTerm(psi_2, q_s->dy()); streamBF->addTerm(-psin_hat, q_s); streamBF->addTerm(psi_1, v_s->x()); streamBF->addTerm(psi_2, v_s->y()); streamBF->addTerm(phi, v_s->div()); streamBF->addTerm(-phi_hat, v_s->dot_normal()); Teuchos::RCP<Mesh> streamMesh, overkillMesh; streamMesh = MeshFactory::buildQuadMesh(quadPoints, horizontalCells, verticalCells, streamBF, H1Order+pToAddForStreamFunction, H1Order+pToAdd+pToAddForStreamFunction, useTriangles); mesh->registerObserver(streamMesh); // will refine streamMesh in the same way as mesh. map<int, double> dofsToL2error; // key: numGlobalDofs, value: total L2error compared with overkill vector< VarPtr > fields; fields.push_back(u1); fields.push_back(u2); fields.push_back(sigma11); fields.push_back(sigma12); fields.push_back(sigma21); fields.push_back(sigma22); fields.push_back(p); if (rank == 0) { cout << "Starting mesh has " << horizontalCells << " x " << verticalCells << " elements and "; cout << mesh->numGlobalDofs() << " total dofs.\n"; cout << "polyOrder = " << polyOrder << endl; cout << "pToAdd = " << pToAdd << endl; cout << "eps for top BC = " << eps << endl; if (useTriangles) { cout << "Using triangles.\n"; } if (enforceLocalConservation) { cout << "Enforcing local conservation.\n"; } else { cout << "NOT enforcing local conservation.\n"; } if (enforceOneIrregularity) { cout << "Enforcing 1-irregularity.\n"; } else { cout << "NOT enforcing 1-irregularity.\n"; } } //////////////////// CREATE BCs /////////////////////// SpatialFilterPtr entireBoundary = Teuchos::rcp( new SpatialFilterUnfiltered ); FunctionPtr u1_prev = Function::solution(u1,solution); FunctionPtr u2_prev = Function::solution(u2,solution); FunctionPtr u1hat_prev = Function::solution(u1hat,solution); FunctionPtr u2hat_prev = Function::solution(u2hat,solution); //////////////////// SOLVE & REFINE /////////////////////// FunctionPtr vorticity = Teuchos::rcp( new PreviousSolutionFunction(solution, - u1->dy() + u2->dx() ) ); // FunctionPtr vorticity = Teuchos::rcp( new PreviousSolutionFunction(solution,sigma12 - sigma21) ); RHSPtr streamRHS = RHS::rhs(); streamRHS->addTerm(vorticity * q_s); ((PreviousSolutionFunction*) vorticity.get())->setOverrideMeshCheck(true); ((PreviousSolutionFunction*) u1_prev.get())->setOverrideMeshCheck(true); ((PreviousSolutionFunction*) u2_prev.get())->setOverrideMeshCheck(true); BCPtr streamBC = BC::bc(); // streamBC->addDirichlet(psin_hat, entireBoundary, u0_cross_n); streamBC->addDirichlet(phi_hat, entireBoundary, zero); // streamBC->addZeroMeanConstraint(phi); IPPtr streamIP = Teuchos::rcp( new IP ); streamIP->addTerm(q_s); streamIP->addTerm(q_s->grad()); streamIP->addTerm(v_s); streamIP->addTerm(v_s->div()); SolutionPtr streamSolution = Teuchos::rcp( new Solution( streamMesh, streamBC, streamRHS, streamIP ) ); if (enforceLocalConservation) { FunctionPtr zero = Function::zero(); solution->lagrangeConstraints()->addConstraint(u1hat->times_normal_x() + u2hat->times_normal_y()==zero); solnIncrement->lagrangeConstraints()->addConstraint(u1hat->times_normal_x() + u2hat->times_normal_y()==zero); } if (true) { FunctionPtr u1_incr = Function::solution(u1, solnIncrement); FunctionPtr u2_incr = Function::solution(u2, solnIncrement); FunctionPtr sigma11_incr = Function::solution(sigma11, solnIncrement); FunctionPtr sigma12_incr = Function::solution(sigma12, solnIncrement); FunctionPtr sigma21_incr = Function::solution(sigma21, solnIncrement); FunctionPtr sigma22_incr = Function::solution(sigma22, solnIncrement); FunctionPtr p_incr = Function::solution(p, solnIncrement); FunctionPtr l2_incr = u1_incr * u1_incr + u2_incr * u2_incr + p_incr * p_incr + sigma11_incr * sigma11_incr + sigma12_incr * sigma12_incr + sigma21_incr * sigma21_incr + sigma22_incr * sigma22_incr; double energyThreshold = 0.20; Teuchos::RCP< RefinementStrategy > refinementStrategy = Teuchos::rcp( new RefinementStrategy( solnIncrement, energyThreshold )); for (int i=0; i<ReValues.size(); i++) { double Re = ReValues[i]; Re_param->setValue(Re); if (rank==0) cout << "Solving with Re = " << Re << ":\n"; double energyErrorTotal; do { double incr_norm; do { problem.iterate(useLineSearch); incr_norm = sqrt(l2_incr->integrate(problem.mesh())); if (rank==0) { cout << "\x1B[2K"; // Erase the entire current line. cout << "\x1B[0E"; // Move to the beginning of the current line. cout << "Iteration: " << problem.iterationCount() << "; L^2(incr) = " << incr_norm; flush(cout); } } while ((incr_norm > minL2Increment ) && (problem.iterationCount() < maxIters)); if (rank==0) cout << endl; problem.setIterationCount(1); // 1 means reuse background flow (which we must, given that we want continuation in Re...) energyErrorTotal = solnIncrement->energyErrorTotal(); //solution->energyErrorTotal(); if (energyErrorTotal > energyErrorGoal) { refinementStrategy->refine(false); } if (rank==0) { cout << "Energy error: " << energyErrorTotal << endl; } } while (energyErrorTotal > energyErrorGoal); } } double energyErrorTotal = solution->energyErrorTotal(); double incrementalEnergyErrorTotal = solnIncrement->energyErrorTotal(); if (rank == 0) { cout << "final mesh has " << mesh->numActiveElements() << " elements and " << mesh->numGlobalDofs() << " dofs.\n"; cout << "energy error: " << energyErrorTotal << endl; cout << " (Incremental solution's energy error is " << incrementalEnergyErrorTotal << ".)\n"; } FunctionPtr u1_sq = u1_prev * u1_prev; FunctionPtr u_dot_u = u1_sq + (u2_prev * u2_prev); FunctionPtr u_mag = Teuchos::rcp( new SqrtFunction( u_dot_u ) ); FunctionPtr u_div = Teuchos::rcp( new PreviousSolutionFunction(solution, u1->dx() + u2->dy() ) ); FunctionPtr massFlux = Teuchos::rcp( new PreviousSolutionFunction(solution, u1hat->times_normal_x() + u2hat->times_normal_y()) ); // check that the zero mean pressure is being correctly imposed: FunctionPtr p_prev = Teuchos::rcp( new PreviousSolutionFunction(solution,p) ); double p_avg = p_prev->integrate(mesh); if (rank==0) cout << "Integral of pressure: " << p_avg << endl; // integrate massFlux over each element (a test): // fake a new bilinear form so we can integrate against 1 VarPtr testOne = varFactory.testVar("1",CONSTANT_SCALAR); BFPtr fakeBF = Teuchos::rcp( new BF(varFactory) ); LinearTermPtr massFluxTerm = massFlux * testOne; CellTopoPtrLegacy quadTopoPtr = Teuchos::rcp(new shards::CellTopology(shards::getCellTopologyData<shards::Quadrilateral<4> >() )); DofOrderingFactory dofOrderingFactory(fakeBF); int fakeTestOrder = H1Order; DofOrderingPtr testOrdering = dofOrderingFactory.testOrdering(fakeTestOrder, *quadTopoPtr); int testOneIndex = testOrdering->getDofIndex(testOne->ID(),0); vector< ElementTypePtr > elemTypes = mesh->elementTypes(); // global element types map<int, double> massFluxIntegral; // cellID -> integral double maxMassFluxIntegral = 0.0; double totalMassFlux = 0.0; double totalAbsMassFlux = 0.0; double maxCellMeasure = 0; double minCellMeasure = 1; for (vector< ElementTypePtr >::iterator elemTypeIt = elemTypes.begin(); elemTypeIt != elemTypes.end(); elemTypeIt++) { ElementTypePtr elemType = *elemTypeIt; vector< ElementPtr > elems = mesh->elementsOfTypeGlobal(elemType); vector<GlobalIndexType> cellIDs; for (int i=0; i<elems.size(); i++) { cellIDs.push_back(elems[i]->cellID()); } FieldContainer<double> physicalCellNodes = mesh->physicalCellNodesGlobal(elemType); BasisCachePtr basisCache = Teuchos::rcp( new BasisCache(elemType,mesh,polyOrder) ); // enrich by trial space order basisCache->setPhysicalCellNodes(physicalCellNodes,cellIDs,true); // true: create side caches FieldContainer<double> cellMeasures = basisCache->getCellMeasures(); FieldContainer<double> fakeRHSIntegrals(elems.size(),testOrdering->totalDofs()); massFluxTerm->integrate(fakeRHSIntegrals,testOrdering,basisCache,true); // true: force side evaluation // cout << "fakeRHSIntegrals:\n" << fakeRHSIntegrals; for (int i=0; i<elems.size(); i++) { int cellID = cellIDs[i]; // pick out the ones for testOne: massFluxIntegral[cellID] = fakeRHSIntegrals(i,testOneIndex); } // find the largest: for (int i=0; i<elems.size(); i++) { int cellID = cellIDs[i]; maxMassFluxIntegral = max(abs(massFluxIntegral[cellID]), maxMassFluxIntegral); } for (int i=0; i<elems.size(); i++) { int cellID = cellIDs[i]; maxCellMeasure = max(maxCellMeasure,cellMeasures(i)); minCellMeasure = min(minCellMeasure,cellMeasures(i)); maxMassFluxIntegral = max(abs(massFluxIntegral[cellID]), maxMassFluxIntegral); totalMassFlux += massFluxIntegral[cellID]; totalAbsMassFlux += abs( massFluxIntegral[cellID] ); } } if (rank==0) { cout << "largest mass flux: " << maxMassFluxIntegral << endl; cout << "total mass flux: " << totalMassFlux << endl; cout << "sum of mass flux absolute value: " << totalAbsMassFlux << endl; cout << "largest h: " << sqrt(maxCellMeasure) << endl; cout << "smallest h: " << sqrt(minCellMeasure) << endl; cout << "ratio of largest / smallest h: " << sqrt(maxCellMeasure) / sqrt(minCellMeasure) << endl; } if (rank == 0) { cout << "phi ID: " << phi->ID() << endl; cout << "psi1 ID: " << psi_1->ID() << endl; cout << "psi2 ID: " << psi_2->ID() << endl; cout << "streamMesh has " << streamMesh->numActiveElements() << " elements.\n"; cout << "solving for approximate stream function...\n"; } streamSolution->solve(useMumps); energyErrorTotal = streamSolution->energyErrorTotal(); if (rank == 0) { cout << "...solved.\n"; cout << "Stream mesh has energy error: " << energyErrorTotal << endl; } if (rank==0) { solution->writeToVTK("nsCavitySoln.vtk"); if (! meshHasTriangles ) { massFlux->writeBoundaryValuesToMATLABFile(solution->mesh(), "massFlux.dat"); u_mag->writeValuesToMATLABFile(solution->mesh(), "u_mag.m"); u_div->writeValuesToMATLABFile(solution->mesh(), "u_div.m"); solution->writeFieldsToFile(u1->ID(), "u1.m"); solution->writeFluxesToFile(u1hat->ID(), "u1_hat.dat"); solution->writeFieldsToFile(u2->ID(), "u2.m"); solution->writeFluxesToFile(u2hat->ID(), "u2_hat.dat"); solution->writeFieldsToFile(p->ID(), "p.m"); streamSolution->writeFieldsToFile(phi->ID(), "phi.m"); streamSolution->writeFluxesToFile(phi_hat->ID(), "phi_hat.dat"); streamSolution->writeFieldsToFile(psi_1->ID(), "psi1.m"); streamSolution->writeFieldsToFile(psi_2->ID(), "psi2.m"); vorticity->writeValuesToMATLABFile(streamMesh, "vorticity.m"); FunctionPtr ten = Teuchos::rcp( new ConstantScalarFunction(10) ); ten->writeBoundaryValuesToMATLABFile(solution->mesh(), "skeleton.dat"); cout << "wrote files: u_mag.m, u_div.m, u1.m, u1_hat.dat, u2.m, u2_hat.dat, p.m, phi.m, vorticity.m.\n"; } else { solution->writeToFile(u1->ID(), "u1.dat"); solution->writeToFile(u2->ID(), "u2.dat"); solution->writeToFile(u2->ID(), "p.dat"); cout << "wrote files: u1.dat, u2.dat, p.dat\n"; } FieldContainer<double> points = pointGrid(0, 1, 0, 1, 100); FieldContainer<double> pointData = solutionData(points, streamSolution, phi); GnuPlotUtil::writeXYPoints("phi_patch_navierStokes_cavity.dat", pointData); set<double> patchContourLevels = diagonalContourLevels(pointData,1); vector<string> patchDataPath; patchDataPath.push_back("phi_patch_navierStokes_cavity.dat"); GnuPlotUtil::writeContourPlotScript(patchContourLevels, patchDataPath, "lidCavityNavierStokes.p"); GnuPlotUtil::writeExactMeshSkeleton("lid_navierStokes_continuation_adaptive", mesh, 2); writePatchValues(0, 1, 0, 1, streamSolution, phi, "phi_patch.m"); writePatchValues(0, .1, 0, .1, streamSolution, phi, "phi_patch_detail.m"); writePatchValues(0, .01, 0, .01, streamSolution, phi, "phi_patch_minute_detail.m"); writePatchValues(0, .001, 0, .001, streamSolution, phi, "phi_patch_minute_minute_detail.m"); } return 0; }
int main(int argc, char *argv[]) { #ifdef HAVE_MPI Teuchos::GlobalMPISession mpiSession(&argc, &argv,0); int rank=mpiSession.getRank(); int numProcs=mpiSession.getNProc(); #else int rank = 0; int numProcs = 1; #endif int polyOrder = 0; // define our manufactured solution or problem bilinear form: bool useTriangles = false; int pToAdd = 1; int nCells = 2; if ( argc > 1) { nCells = atoi(argv[1]); if (rank==0) { cout << "numCells = " << nCells << endl; } } int numSteps = 20; if ( argc > 2) { numSteps = atoi(argv[2]); if (rank==0) { cout << "num NR steps = " << numSteps << endl; } } int useHessian = 0; // defaults to "not use" if ( argc > 3) { useHessian = atoi(argv[3]); if (rank==0) { cout << "useHessian = " << useHessian << endl; } } int H1Order = polyOrder + 1; double energyThreshold = 0.2; // for mesh refinements double nonlinearStepSize = 0.5; double nonlinearRelativeEnergyTolerance = 1e-8; // used to determine convergence of the nonlinear solution //////////////////////////////////////////////////////////////////// // DEFINE VARIABLES //////////////////////////////////////////////////////////////////// // new-style bilinear form definition VarFactory varFactory; VarPtr fn = varFactory.fluxVar("\\widehat{\\beta_n_u}"); VarPtr u = varFactory.fieldVar("u"); VarPtr v = varFactory.testVar("v",HGRAD); BFPtr bf = Teuchos::rcp( new BF(varFactory) ); // initialize bilinear form //////////////////////////////////////////////////////////////////// // CREATE MESH //////////////////////////////////////////////////////////////////// // create a pointer to a new mesh: Teuchos::RCP<Mesh> mesh = Mesh::buildUnitQuadMesh(2,1 , bf, H1Order, H1Order+pToAdd); //////////////////////////////////////////////////////////////////// // INITIALIZE BACKGROUND FLOW FUNCTIONS //////////////////////////////////////////////////////////////////// BCPtr nullBC = Teuchos::rcp((BC*)NULL); RHSPtr nullRHS = Teuchos::rcp((RHS*)NULL); IPPtr nullIP = Teuchos::rcp((IP*)NULL); SolutionPtr backgroundFlow = Teuchos::rcp(new Solution(mesh, nullBC, nullRHS, nullIP) ); SolutionPtr solnPerturbation = Teuchos::rcp(new Solution(mesh, nullBC, nullRHS, nullIP) ); vector<double> e1(2); // (1,0) e1[0] = 1; vector<double> e2(2); // (0,1) e2[1] = 1; FunctionPtr u_prev = Teuchos::rcp( new PreviousSolutionFunction(backgroundFlow, u) ); FunctionPtr beta = e1 * u_prev + Teuchos::rcp( new ConstantVectorFunction( e2 ) ); //////////////////////////////////////////////////////////////////// // DEFINE BILINEAR FORM //////////////////////////////////////////////////////////////////// // v: bf->addTerm( -u, beta * v->grad()); bf->addTerm( fn, v); //////////////////////////////////////////////////////////////////// // DEFINE RHS //////////////////////////////////////////////////////////////////// Teuchos::RCP<RHSEasy> rhs = Teuchos::rcp( new RHSEasy ); FunctionPtr u_prev_squared_div2 = 0.5 * u_prev * u_prev; rhs->addTerm((e1 * u_prev_squared_div2 + e2 * u_prev) * v->grad()); // ==================== SET INITIAL GUESS ========================== mesh->registerSolution(backgroundFlow); FunctionPtr zero = Teuchos::rcp( new ConstantScalarFunction(0.0) ); FunctionPtr u0 = Teuchos::rcp( new U0 ); FunctionPtr n = Teuchos::rcp( new UnitNormalFunction ); FunctionPtr parity = Teuchos::rcp(new SideParityFunction); FunctionPtr u0_squared_div_2 = 0.5 * u0 * u0; map<int, Teuchos::RCP<Function> > functionMap; functionMap[u->ID()] = u0; // functionMap[fn->ID()] = -(e1 * u0_squared_div_2 + e2 * u0) * n * parity; backgroundFlow->projectOntoMesh(functionMap); // ==================== END SET INITIAL GUESS ========================== //////////////////////////////////////////////////////////////////// // DEFINE INNER PRODUCT //////////////////////////////////////////////////////////////////// IPPtr ip = Teuchos::rcp( new IP ); ip->addTerm( v ); ip->addTerm(v->grad()); // ip->addTerm( beta * v->grad() ); //////////////////////////////////////////////////////////////////// // DEFINE DIRICHLET BC //////////////////////////////////////////////////////////////////// SpatialFilterPtr outflowBoundary = Teuchos::rcp( new TopBoundary); SpatialFilterPtr inflowBoundary = Teuchos::rcp( new NegatedSpatialFilter(outflowBoundary) ); Teuchos::RCP<BCEasy> inflowBC = Teuchos::rcp( new BCEasy ); inflowBC->addDirichlet(fn,inflowBoundary, ( e1 * u0_squared_div_2 + e2 * u0) * n ); // inflowBC->addDirichlet(fn,inflowBoundary,zero); //////////////////////////////////////////////////////////////////// // CREATE SOLUTION OBJECT //////////////////////////////////////////////////////////////////// Teuchos::RCP<Solution> solution = Teuchos::rcp(new Solution(mesh, inflowBC, rhs, ip)); mesh->registerSolution(solution); solution->setCubatureEnrichmentDegree(10); //////////////////////////////////////////////////////////////////// // HESSIAN BIT + CHECKS ON GRADIENT + HESSIAN //////////////////////////////////////////////////////////////////// VarFactory hessianVars = varFactory.getBubnovFactory(VarFactory::BUBNOV_TRIAL); VarPtr du = hessianVars.test(u->ID()); BFPtr hessianBF = Teuchos::rcp( new BF(hessianVars) ); // initialize bilinear form FunctionPtr du_current = Teuchos::rcp( new PreviousSolutionFunction(solution, u) ); FunctionPtr fnhat = Teuchos::rcp(new PreviousSolutionFunction(solution,fn)); LinearTermPtr residual = Teuchos::rcp(new LinearTerm);// residual residual->addTerm(fnhat*v,true); residual->addTerm( - (e1 * (u_prev_squared_div2) + e2 * (u_prev)) * v->grad(),true); LinearTermPtr Bdu = Teuchos::rcp(new LinearTerm);// residual Bdu->addTerm( - du_current*(beta*v->grad())); Teuchos::RCP<RieszRep> riesz = Teuchos::rcp(new RieszRep(mesh, ip, residual)); Teuchos::RCP<RieszRep> duRiesz = Teuchos::rcp(new RieszRep(mesh, ip, Bdu)); riesz->computeRieszRep(); FunctionPtr e_v = Teuchos::rcp(new RepFunction(v,riesz)); e_v->writeValuesToMATLABFile(mesh, "e_v.m"); FunctionPtr posErrPart = Teuchos::rcp(new PositivePart(e_v->dx())); hessianBF->addTerm(e_v->dx()*u,du); // hessianBF->addTerm(posErrPart*u,du); Teuchos::RCP<HessianFilter> hessianFilter = Teuchos::rcp(new HessianFilter(hessianBF)); if (useHessian) { solution->setWriteMatrixToFile(true,"hessianStiffness.dat"); } else { solution->setWriteMatrixToFile(true,"stiffness.dat"); } Teuchos::RCP< LineSearchStep > LS_Step = Teuchos::rcp(new LineSearchStep(riesz)); double NL_residual = 9e99; for (int i = 0; i<numSteps; i++) { solution->solve(false); // do one solve to initialize things... double stepLength = 1.0; stepLength = LS_Step->stepSize(backgroundFlow,solution, NL_residual); if (useHessian) { solution->setFilter(hessianFilter); } backgroundFlow->addSolution(solution,stepLength); NL_residual = LS_Step->getNLResidual(); if (rank==0) { cout << "NL residual after adding = " << NL_residual << " with step size " << stepLength << endl; } int numGlobalDofs = mesh->numGlobalDofs(); double fd_gradient; for (int dofIndex = 0; dofIndex<numGlobalDofs; dofIndex++) { TestingUtilities::initializeSolnCoeffs(solnPerturbation); TestingUtilities::setSolnCoeffForGlobalDofIndex(solnPerturbation,1.0,dofIndex); fd_gradient = FiniteDifferenceUtilities::finiteDifferenceGradient(mesh, riesz, backgroundFlow, dofIndex); // CHECK GRADIENT LinearTermPtr b_u = bf->testFunctional(solnPerturbation); map<int,FunctionPtr> NL_err_rep_map; NL_err_rep_map[v->ID()] = Teuchos::rcp(new RepFunction(v,riesz)); FunctionPtr gradient = b_u->evaluate(NL_err_rep_map, TestingUtilities::isFluxOrTraceDof(mesh,dofIndex)); // use boundary part only if flux or trace double grad; if (TestingUtilities::isFluxOrTraceDof(mesh,dofIndex)) { grad = gradient->integralOfJump(mesh,10); } else { grad = gradient->integrate(mesh,10); } double fdgrad = fd_gradient; double diff = grad-fdgrad; if (abs(diff)>1e-6 && i>0) { cout << "Found difference of " << diff << ", " << " with fd val = " << fdgrad << " and gradient = " << grad << " in dof " << dofIndex << ", isTraceDof = " << TestingUtilities::isFluxOrTraceDof(mesh,dofIndex) << endl; } } } if (rank==0) { backgroundFlow->writeToVTK("BurgersTest.vtu",min(H1Order+1,4)); solution->writeFluxesToFile(fn->ID(),"fn.dat"); cout << "wrote solution files" << endl; } return 0; }
int main(int argc, char *argv[]) { #ifdef HAVE_MPI Teuchos::GlobalMPISession mpiSession(&argc, &argv,0); int rank=mpiSession.getRank(); int numProcs=mpiSession.getNProc(); #else int rank = 0; int numProcs = 1; #endif int polyOrder = 2; // define our manufactured solution or problem bilinear form: double epsilon = 1e-3; bool useTriangles = false; int pToAdd = 2; int nCells = 2; if ( argc > 1) { nCells = atoi(argv[1]); if (rank==0) { cout << "numCells = " << nCells << endl; } } int numSteps = 20; if ( argc > 2) { numSteps = atoi(argv[2]); if (rank==0) { cout << "num NR steps = " << numSteps << endl; } } int useHessian = 0; // defaults to "not use" if ( argc > 3) { useHessian = atoi(argv[3]); if (rank==0) { cout << "useHessian = " << useHessian << endl; } } int thresh = numSteps; // threshhold for when to apply linesearch/hessian if ( argc > 4) { thresh = atoi(argv[4]); if (rank==0) { cout << "thresh = " << thresh << endl; } } int H1Order = polyOrder + 1; double energyThreshold = 0.2; // for mesh refinements double nonlinearStepSize = 0.5; double nonlinearRelativeEnergyTolerance = 1e-8; // used to determine convergence of the nonlinear solution //////////////////////////////////////////////////////////////////// // DEFINE VARIABLES //////////////////////////////////////////////////////////////////// // new-style bilinear form definition VarFactory varFactory; VarPtr uhat = varFactory.traceVar("\\widehat{u}"); VarPtr beta_n_u_minus_sigma_hat = varFactory.fluxVar("\\widehat{\\beta_n u - \\sigma_n}"); VarPtr u = varFactory.fieldVar("u"); VarPtr sigma1 = varFactory.fieldVar("\\sigma_1"); VarPtr sigma2 = varFactory.fieldVar("\\sigma_2"); VarPtr tau = varFactory.testVar("\\tau",HDIV); VarPtr v = varFactory.testVar("v",HGRAD); BFPtr bf = Teuchos::rcp( new BF(varFactory) ); // initialize bilinear form //////////////////////////////////////////////////////////////////// // CREATE MESH //////////////////////////////////////////////////////////////////// // create a pointer to a new mesh: Teuchos::RCP<Mesh> mesh = MeshUtilities::buildUnitQuadMesh(nCells, bf, H1Order, H1Order+pToAdd); mesh->setPartitionPolicy(Teuchos::rcp(new ZoltanMeshPartitionPolicy("HSFC"))); //////////////////////////////////////////////////////////////////// // INITIALIZE BACKGROUND FLOW FUNCTIONS //////////////////////////////////////////////////////////////////// BCPtr nullBC = Teuchos::rcp((BC*)NULL); RHSPtr nullRHS = Teuchos::rcp((RHS*)NULL); IPPtr nullIP = Teuchos::rcp((IP*)NULL); SolutionPtr backgroundFlow = Teuchos::rcp(new Solution(mesh, nullBC, nullRHS, nullIP) ); vector<double> e1(2); // (1,0) e1[0] = 1; vector<double> e2(2); // (0,1) e2[1] = 1; FunctionPtr u_prev = Teuchos::rcp( new PreviousSolutionFunction(backgroundFlow, u) ); FunctionPtr beta = e1 * u_prev + Teuchos::rcp( new ConstantVectorFunction( e2 ) ); //////////////////////////////////////////////////////////////////// // DEFINE BILINEAR FORM //////////////////////////////////////////////////////////////////// // tau parts: // 1/eps (sigma, tau)_K + (u, div tau)_K - (u_hat, tau_n)_dK bf->addTerm(sigma1 / epsilon, tau->x()); bf->addTerm(sigma2 / epsilon, tau->y()); bf->addTerm(u, tau->div()); bf->addTerm( - uhat, tau->dot_normal() ); // v: // (sigma, grad v)_K - (sigma_hat_n, v)_dK - (u, beta dot grad v) + (u_hat * n dot beta, v)_dK bf->addTerm( sigma1, v->dx() ); bf->addTerm( sigma2, v->dy() ); bf->addTerm( -u, beta * v->grad()); bf->addTerm( beta_n_u_minus_sigma_hat, v); // ==================== SET INITIAL GUESS ========================== mesh->registerSolution(backgroundFlow); FunctionPtr zero = Teuchos::rcp( new ConstantScalarFunction(0.0) ); FunctionPtr u0 = Teuchos::rcp( new U0 ); map<int, Teuchos::RCP<Function> > functionMap; functionMap[u->ID()] = u0; functionMap[sigma1->ID()] = zero; functionMap[sigma2->ID()] = zero; backgroundFlow->projectOntoMesh(functionMap); // ==================== END SET INITIAL GUESS ========================== //////////////////////////////////////////////////////////////////// // DEFINE INNER PRODUCT //////////////////////////////////////////////////////////////////// // function to scale the squared guy by epsilon/h FunctionPtr epsilonOverHScaling = Teuchos::rcp( new EpsilonScaling(epsilon) ); IPPtr ip = Teuchos::rcp( new IP ); ip->addTerm( epsilonOverHScaling * (1.0/sqrt(epsilon))* tau); ip->addTerm( tau->div()); // ip->addTerm( epsilonOverHScaling * v ); ip->addTerm( v ); ip->addTerm( sqrt(epsilon) * v->grad() ); ip->addTerm(v->grad()); // ip->addTerm( beta * v->grad() ); //////////////////////////////////////////////////////////////////// // DEFINE RHS //////////////////////////////////////////////////////////////////// RHSPtr rhs = RHS::rhs(); FunctionPtr u_prev_squared_div2 = 0.5 * u_prev * u_prev; rhs->addTerm((e1 * u_prev_squared_div2 + e2 * u_prev) * v->grad() - u_prev * tau->div()); //////////////////////////////////////////////////////////////////// // DEFINE DIRICHLET BC //////////////////////////////////////////////////////////////////// FunctionPtr n = Teuchos::rcp( new UnitNormalFunction ); SpatialFilterPtr outflowBoundary = Teuchos::rcp( new TopBoundary); SpatialFilterPtr inflowBoundary = Teuchos::rcp( new NegatedSpatialFilter(outflowBoundary) ); BCPtr inflowBC = BC::bc(); FunctionPtr u0_squared_div_2 = 0.5 * u0 * u0; inflowBC->addDirichlet(beta_n_u_minus_sigma_hat,inflowBoundary, ( e1 * u0_squared_div_2 + e2 * u0) * n ); //////////////////////////////////////////////////////////////////// // CREATE SOLUTION OBJECT //////////////////////////////////////////////////////////////////// Teuchos::RCP<Solution> solution = Teuchos::rcp(new Solution(mesh, inflowBC, rhs, ip)); mesh->registerSolution(solution); //////////////////////////////////////////////////////////////////// // WARNING: UNFINISHED HESSIAN BIT //////////////////////////////////////////////////////////////////// VarFactory hessianVars = varFactory.getBubnovFactory(VarFactory::BUBNOV_TRIAL); VarPtr du = hessianVars.test(u->ID()); BFPtr hessianBF = Teuchos::rcp( new BF(hessianVars) ); // initialize bilinear form // FunctionPtr e_v = Function::constant(1.0); // dummy error rep function for now - should do nothing FunctionPtr u_current = Teuchos::rcp( new PreviousSolutionFunction(solution, u) ); FunctionPtr sig1_prev = Teuchos::rcp( new PreviousSolutionFunction(solution, sigma1) ); FunctionPtr sig2_prev = Teuchos::rcp( new PreviousSolutionFunction(solution, sigma2) ); FunctionPtr sig_prev = (e1*sig1_prev + e2*sig2_prev); FunctionPtr fnhat = Teuchos::rcp(new PreviousSolutionFunction(solution,beta_n_u_minus_sigma_hat)); FunctionPtr uhat_prev = Teuchos::rcp(new PreviousSolutionFunction(solution,uhat)); LinearTermPtr residual = Teuchos::rcp(new LinearTerm);// residual residual->addTerm(fnhat*v - (e1 * (u_prev_squared_div2 - sig1_prev) + e2 * (u_prev - sig2_prev)) * v->grad()); residual->addTerm((1/epsilon)*sig_prev * tau + u_prev * tau->div() - uhat_prev*tau->dot_normal()); LinearTermPtr Bdu = Teuchos::rcp(new LinearTerm);// residual Bdu->addTerm( u_current*tau->div() - u_current*(beta*v->grad())); Teuchos::RCP<RieszRep> riesz = Teuchos::rcp(new RieszRep(mesh, ip, residual)); Teuchos::RCP<RieszRep> duRiesz = Teuchos::rcp(new RieszRep(mesh, ip, Bdu)); riesz->computeRieszRep(); FunctionPtr e_v = Teuchos::rcp(new RepFunction(v,riesz)); e_v->writeValuesToMATLABFile(mesh, "e_v.m"); FunctionPtr posErrPart = Teuchos::rcp(new PositivePart(e_v->dx())); hessianBF->addTerm(e_v->dx()*u,du); // hessianBF->addTerm(posErrPart*u,du); Teuchos::RCP<HessianFilter> hessianFilter = Teuchos::rcp(new HessianFilter(hessianBF)); if (useHessian) { solution->setWriteMatrixToFile(true,"hessianStiffness.dat"); } else { solution->setWriteMatrixToFile(true,"stiffness.dat"); } Teuchos::RCP< LineSearchStep > LS_Step = Teuchos::rcp(new LineSearchStep(riesz)); ofstream out; out.open("Burgers.txt"); double NL_residual = 9e99; for (int i = 0; i<numSteps; i++) { solution->solve(false); // do one solve to initialize things... double stepLength = 1.0; stepLength = LS_Step->stepSize(backgroundFlow,solution, NL_residual); if (useHessian) { solution->setFilter(hessianFilter); } backgroundFlow->addSolution(solution,stepLength); NL_residual = LS_Step->getNLResidual(); if (rank==0) { cout << "NL residual after adding = " << NL_residual << " with step size " << stepLength << endl; out << NL_residual << endl; // saves initial NL error } } out.close(); //////////////////////////////////////////////////////////////////// // DEFINE REFINEMENT STRATEGY //////////////////////////////////////////////////////////////////// Teuchos::RCP<RefinementStrategy> refinementStrategy; refinementStrategy = Teuchos::rcp(new RefinementStrategy(solution,energyThreshold)); int numRefs = 0; Teuchos::RCP<NonlinearStepSize> stepSize = Teuchos::rcp(new NonlinearStepSize(nonlinearStepSize)); Teuchos::RCP<NonlinearSolveStrategy> solveStrategy; solveStrategy = Teuchos::rcp( new NonlinearSolveStrategy(backgroundFlow, solution, stepSize, nonlinearRelativeEnergyTolerance)); //////////////////////////////////////////////////////////////////// // SOLVE //////////////////////////////////////////////////////////////////// for (int refIndex=0; refIndex<numRefs; refIndex++) { solveStrategy->solve(rank==0); // print to console on rank 0 refinementStrategy->refine(rank==0); // print to console on rank 0 } // solveStrategy->solve(rank==0); if (rank==0) { backgroundFlow->writeToVTK("Burgers.vtu",min(H1Order+1,4)); solution->writeFluxesToFile(uhat->ID(), "burgers.dat"); cout << "wrote solution files" << endl; } return 0; }
int main(int argc, char *argv[]) { #ifdef HAVE_MPI Teuchos::GlobalMPISession mpiSession(&argc, &argv,0); int rank=mpiSession.getRank(); int numProcs=mpiSession.getNProc(); #else int rank = 0; int numProcs = 1; #endif int polyOrder = 3; int pToAdd = 2; // for tests // define our manufactured solution or problem bilinear form: bool useTriangles = false; FieldContainer<double> meshPoints(4,2); meshPoints(0,0) = 0.0; // x1 meshPoints(0,1) = 0.0; // y1 meshPoints(1,0) = 1.0; meshPoints(1,1) = 0.0; meshPoints(2,0) = 1.0; meshPoints(2,1) = 1.0; meshPoints(3,0) = 0.0; meshPoints(3,1) = 1.0; int H1Order = polyOrder + 1; int horizontalCells = 4, verticalCells = 4; double energyThreshold = 0.2; // for mesh refinements double nonlinearStepSize = 0.5; double nonlinearRelativeEnergyTolerance = 1e-8; // used to determine convergence of the nonlinear solution //////////////////////////////////////////////////////////////////// // DEFINE VARIABLES //////////////////////////////////////////////////////////////////// // new-style bilinear form definition VarFactory varFactory; VarPtr fhat = varFactory.fluxVar("\\widehat{f}"); VarPtr u = varFactory.fieldVar("u"); VarPtr v = varFactory.testVar("v",HGRAD); BFPtr bf = Teuchos::rcp( new BF(varFactory) ); // initialize bilinear form //////////////////////////////////////////////////////////////////// // CREATE MESH //////////////////////////////////////////////////////////////////// // create a pointer to a new mesh: Teuchos::RCP<Mesh> mesh = Mesh::buildQuadMesh(meshPoints, horizontalCells, verticalCells, bf, H1Order, H1Order+pToAdd, useTriangles); mesh->setPartitionPolicy(Teuchos::rcp(new ZoltanMeshPartitionPolicy("HSFC"))); //////////////////////////////////////////////////////////////////// // INITIALIZE BACKGROUND FLOW FUNCTIONS //////////////////////////////////////////////////////////////////// BCPtr nullBC = Teuchos::rcp((BC*)NULL); RHSPtr nullRHS = Teuchos::rcp((RHS*)NULL); IPPtr nullIP = Teuchos::rcp((IP*)NULL); SolutionPtr backgroundFlow = Teuchos::rcp(new Solution(mesh, nullBC, nullRHS, nullIP) ); vector<double> e1(2); // (1,0) e1[0] = 1; vector<double> e2(2); // (0,1) e2[1] = 1; FunctionPtr u_prev = Teuchos::rcp( new PreviousSolutionFunction(backgroundFlow, u) ); FunctionPtr beta = e1 * u_prev + Teuchos::rcp( new ConstantVectorFunction( e2 ) ); //////////////////////////////////////////////////////////////////// // DEFINE BILINEAR FORM //////////////////////////////////////////////////////////////////// // v: // (sigma, grad v)_K - (sigma_hat_n, v)_dK - (u, beta dot grad v) + (u_hat * n dot beta, v)_dK bf->addTerm( -u, beta * v->grad()); bf->addTerm( fhat, v); // ==================== SET INITIAL GUESS ========================== mesh->registerSolution(backgroundFlow); FunctionPtr zero = Teuchos::rcp( new ConstantScalarFunction(0.0) ); FunctionPtr u0 = Teuchos::rcp( new U0 ); map<int, Teuchos::RCP<Function> > functionMap; functionMap[u->ID()] = u0; backgroundFlow->projectOntoMesh(functionMap); // ==================== END SET INITIAL GUESS ========================== //////////////////////////////////////////////////////////////////// // DEFINE INNER PRODUCT //////////////////////////////////////////////////////////////////// IPPtr ip = Teuchos::rcp( new IP ); ip->addTerm( v ); ip->addTerm( beta * v->grad() ); //////////////////////////////////////////////////////////////////// // DEFINE RHS //////////////////////////////////////////////////////////////////// Teuchos::RCP<RHSEasy> rhs = Teuchos::rcp( new RHSEasy ); FunctionPtr u_prev_squared_div2 = 0.5 * u_prev * u_prev; rhs->addTerm( (e1 * u_prev_squared_div2 + e2 * u_prev) * v->grad()); //////////////////////////////////////////////////////////////////// // DEFINE DIRICHLET BC //////////////////////////////////////////////////////////////////// Teuchos::RCP<BCEasy> inflowBC = Teuchos::rcp( new BCEasy ); // Create spatial filters SpatialFilterPtr bottomBoundary = Teuchos::rcp( new BottomBoundary ); SpatialFilterPtr leftBoundary = Teuchos::rcp( new LeftBoundary ); SpatialFilterPtr rightBoundary = Teuchos::rcp( new LeftBoundary ); // Create BCs FunctionPtr n = Teuchos::rcp( new UnitNormalFunction ); FunctionPtr u0_squared_div_2 = 0.5 * u0 * u0; SimpleFunction* u0Ptr = static_cast<SimpleFunction *>(u0.get()); double u0Left = u0Ptr->value(0,0); double u0Right = u0Ptr->value(1.0,0); FunctionPtr leftVal = Teuchos::rcp( new ConstantScalarFunction( -0.5*u0Left*u0Left ) ); FunctionPtr rightVal = Teuchos::rcp( new ConstantScalarFunction( 0.5*u0Right*u0Right ) ); inflowBC->addDirichlet(fhat, bottomBoundary, -u0 ); inflowBC->addDirichlet(fhat, leftBoundary, leftVal ); inflowBC->addDirichlet(fhat, rightBoundary, rightVal ); //////////////////////////////////////////////////////////////////// // CREATE SOLUTION OBJECT //////////////////////////////////////////////////////////////////// Teuchos::RCP<Solution> solution = Teuchos::rcp(new Solution(mesh, inflowBC, rhs, ip)); mesh->registerSolution(solution); if (enforceLocalConservation) { FunctionPtr zero = Teuchos::rcp( new ConstantScalarFunction(0.0) ); solution->lagrangeConstraints()->addConstraint(fhat == zero); } //////////////////////////////////////////////////////////////////// // DEFINE REFINEMENT STRATEGY //////////////////////////////////////////////////////////////////// Teuchos::RCP<RefinementStrategy> refinementStrategy; refinementStrategy = Teuchos::rcp(new RefinementStrategy(solution,energyThreshold)); //////////////////////////////////////////////////////////////////// // SOLVE //////////////////////////////////////////////////////////////////// for (int refIndex=0; refIndex<=numRefs; refIndex++) { double L2Update = 1e7; int iterCount = 0; while (L2Update > nonlinearRelativeEnergyTolerance && iterCount < maxNewtonIterations) { solution->solve(); L2Update = solution->L2NormOfSolutionGlobal(u->ID()); cout << "L2 Norm of Update = " << L2Update << endl; // backgroundFlow->clear(); backgroundFlow->addSolution(solution, newtonStepSize); iterCount++; } cout << endl; // check conservation VarPtr testOne = varFactory.testVar("1", CONSTANT_SCALAR); // Create a fake bilinear form for the testing BFPtr fakeBF = Teuchos::rcp( new BF(varFactory) ); // Define our mass flux FunctionPtr massFlux = Teuchos::rcp( new PreviousSolutionFunction(solution, fhat) ); LinearTermPtr massFluxTerm = massFlux * testOne; Teuchos::RCP<shards::CellTopology> quadTopoPtr = Teuchos::rcp(new shards::CellTopology(shards::getCellTopologyData<shards::Quadrilateral<4> >() )); DofOrderingFactory dofOrderingFactory(fakeBF); int fakeTestOrder = H1Order; DofOrderingPtr testOrdering = dofOrderingFactory.testOrdering(fakeTestOrder, *quadTopoPtr); int testOneIndex = testOrdering->getDofIndex(testOne->ID(),0); vector< ElementTypePtr > elemTypes = mesh->elementTypes(); // global element types map<int, double> massFluxIntegral; // cellID -> integral double maxMassFluxIntegral = 0.0; double totalMassFlux = 0.0; double totalAbsMassFlux = 0.0; for (vector< ElementTypePtr >::iterator elemTypeIt = elemTypes.begin(); elemTypeIt != elemTypes.end(); elemTypeIt++) { ElementTypePtr elemType = *elemTypeIt; vector< ElementPtr > elems = mesh->elementsOfTypeGlobal(elemType); vector<int> cellIDs; for (int i=0; i<elems.size(); i++) { cellIDs.push_back(elems[i]->cellID()); } FieldContainer<double> physicalCellNodes = mesh->physicalCellNodesGlobal(elemType); BasisCachePtr basisCache = Teuchos::rcp( new BasisCache(elemType,mesh) ); basisCache->setPhysicalCellNodes(physicalCellNodes,cellIDs,true); // true: create side caches FieldContainer<double> cellMeasures = basisCache->getCellMeasures(); FieldContainer<double> fakeRHSIntegrals(elems.size(),testOrdering->totalDofs()); massFluxTerm->integrate(fakeRHSIntegrals,testOrdering,basisCache,true); // true: force side evaluation for (int i=0; i<elems.size(); i++) { int cellID = cellIDs[i]; // pick out the ones for testOne: massFluxIntegral[cellID] = fakeRHSIntegrals(i,testOneIndex); } // find the largest: for (int i=0; i<elems.size(); i++) { int cellID = cellIDs[i]; maxMassFluxIntegral = max(abs(massFluxIntegral[cellID]), maxMassFluxIntegral); } for (int i=0; i<elems.size(); i++) { int cellID = cellIDs[i]; maxMassFluxIntegral = max(abs(massFluxIntegral[cellID]), maxMassFluxIntegral); totalMassFlux += massFluxIntegral[cellID]; totalAbsMassFlux += abs( massFluxIntegral[cellID] ); } } if (rank==0) { cout << endl; cout << "largest mass flux: " << maxMassFluxIntegral << endl; cout << "total mass flux: " << totalMassFlux << endl; cout << "sum of mass flux absolute value: " << totalAbsMassFlux << endl; cout << endl; stringstream outfile; outfile << "burgers_" << refIndex; backgroundFlow->writeToVTK(outfile.str(), 5); } if (refIndex < numRefs) refinementStrategy->refine(rank==0); // print to console on rank 0 } return 0; }