int main(int argc, char *argv[]) { // Process command line arguments #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 //////////////////// DECLARE VARIABLES /////////////////////// // define test variables VarFactory varFactory; VarPtr v = varFactory.testVar("v", HGRAD); // define trial variables VarPtr beta_n_u_hat = varFactory.fluxVar("\\widehat{\\beta \\cdot n }"); VarPtr u = varFactory.fieldVar("u"); FunctionPtr beta = Teuchos::rcp(new Beta()); //////////////////// BUILD MESH /////////////////////// BFPtr confusionBF = Teuchos::rcp( new BF(varFactory) ); // define nodes for mesh FieldContainer<double> meshBoundary(4,2); meshBoundary(0,0) = -1.0; // x1 meshBoundary(0,1) = -1.0; // y1 meshBoundary(1,0) = 1.0; meshBoundary(1,1) = -1.0; meshBoundary(2,0) = 1.0; meshBoundary(2,1) = 1.0; meshBoundary(3,0) = -1.0; meshBoundary(3,1) = 1.0; int horizontalCells = 32, verticalCells = 32; // create a pointer to a new mesh: Teuchos::RCP<Mesh> mesh = Mesh::buildQuadMesh(meshBoundary, horizontalCells, verticalCells, confusionBF, H1Order, H1Order+pToAdd); //////////////////////////////////////////////////////////////////// // INITIALIZE FLOW FUNCTIONS //////////////////////////////////////////////////////////////////// BCPtr nullBC = Teuchos::rcp((BC*)NULL); RHSPtr nullRHS = Teuchos::rcp((RHS*)NULL); IPPtr nullIP = Teuchos::rcp((IP*)NULL); SolutionPtr prevTimeFlow = Teuchos::rcp(new Solution(mesh, nullBC, nullRHS, nullIP) ); SolutionPtr flowResidual = Teuchos::rcp(new Solution(mesh, nullBC, nullRHS, nullIP) ); FunctionPtr u_prev_time = Teuchos::rcp( new PreviousSolutionFunction(prevTimeFlow, u) ); //////////////////// DEFINE BILINEAR FORM /////////////////////// Teuchos::RCP<RHSEasy> rhs = Teuchos::rcp( new RHSEasy ); FunctionPtr invDt = Teuchos::rcp(new ScalarParamFunction(1.0/dt)); // v terms: confusionBF->addTerm( beta * u, - v->grad() ); confusionBF->addTerm( beta_n_u_hat, v); confusionBF->addTerm( u, invDt*v ); rhs->addTerm( u_prev_time * invDt * v ); //////////////////// SPECIFY RHS /////////////////////// FunctionPtr f = Teuchos::rcp( new ConstantScalarFunction(0.0) ); rhs->addTerm( f * v ); // obviously, with f = 0 adding this term is not necessary! //////////////////// DEFINE INNER PRODUCT(S) /////////////////////// // robust test norm IPPtr ip = confusionBF->graphNorm(); // IPPtr ip = Teuchos::rcp(new IP); // ip->addTerm(v); // ip->addTerm(invDt*v - beta*v->grad()); //////////////////// CREATE BCs /////////////////////// Teuchos::RCP<BCEasy> bc = Teuchos::rcp( new BCEasy ); SpatialFilterPtr inflowBoundary = Teuchos::rcp( new InflowSquareBoundary(beta) ); FunctionPtr u0 = Teuchos::rcp( new ConstantScalarFunction(0) ); FunctionPtr n = Teuchos::rcp( new UnitNormalFunction ); bc->addDirichlet(beta_n_u_hat, inflowBoundary, beta*n*u0); Teuchos::RCP<Solution> solution = Teuchos::rcp( new Solution(mesh, bc, rhs, ip) ); // ==================== Register Solutions ========================== mesh->registerSolution(solution); mesh->registerSolution(prevTimeFlow); mesh->registerSolution(flowResidual); // ==================== SET INITIAL GUESS ========================== FunctionPtr u_init = Teuchos::rcp(new InitialCondition()); map<int, Teuchos::RCP<Function> > functionMap; functionMap[u->ID()] = u_init; prevTimeFlow->projectOntoMesh(functionMap); //////////////////// SOLVE & REFINE /////////////////////// // if (enforceLocalConservation) { // // FunctionPtr parity = Teuchos::rcp<Function>( new SideParityFunction ); // // LinearTermPtr conservedQuantity = Teuchos::rcp<LinearTerm>( new LinearTerm(parity, beta_n_u_minus_sigma_n) ); // LinearTermPtr conservedQuantity = Teuchos::rcp<LinearTerm>( new LinearTerm(1.0, beta_n_u_minus_sigma_n) ); // LinearTermPtr sourcePart = Teuchos::rcp<LinearTerm>( new LinearTerm(invDt, u) ); // conservedQuantity->addTerm(sourcePart, true); // solution->lagrangeConstraints()->addConstraint(conservedQuantity == u_prev_time * invDt); // } int timestepCount = 0; double time_tol = 1e-8; double L2_time_residual = 1e9; while((L2_time_residual > time_tol) && (timestepCount < numTimeSteps)) { solution->solve(false); // Subtract solutions to get residual flowResidual->setSolution(solution); flowResidual->addSolution(prevTimeFlow, -1.0); L2_time_residual = flowResidual->L2NormOfSolutionGlobal(u->ID()); if (rank == 0) { cout << endl << "Timestep: " << timestepCount << ", dt = " << dt << ", Time residual = " << L2_time_residual << endl; stringstream outfile; outfile << "rotatingCylinder_" << timestepCount; solution->writeToVTK(outfile.str(), 5); // Check local conservation FunctionPtr flux = Teuchos::rcp( new PreviousSolutionFunction(solution, beta_n_u_hat) ); FunctionPtr source = Teuchos::rcp( new PreviousSolutionFunction(flowResidual, u) ); source = invDt * source; Teuchos::Tuple<double, 3> fluxImbalances = checkConservation(flux, source, varFactory, mesh); cout << "Mass flux: Largest Local = " << fluxImbalances[0] << ", Global = " << fluxImbalances[1] << ", Sum Abs = " << fluxImbalances[2] << endl; } prevTimeFlow->setSolution(solution); // reset previous time solution to current time sol timestepCount++; } return 0; }
int main(int argc, char *argv[]) { #ifdef HAVE_MPI Teuchos::GlobalMPISession mpiSession(&argc, &argv,0); choice::MpiArgs args( argc, argv ); #else choice::Args args( argc, argv ); #endif int commRank = Teuchos::GlobalMPISession::getRank(); int numProcs = Teuchos::GlobalMPISession::getNProc(); // Required arguments int numRefs = args.Input<int>("--numRefs", "number of refinement steps"); int norm = args.Input<int>("--norm", "0 = graph\n 1 = robust\n 2 = coupled robust"); // Optional arguments (have defaults) bool enforceLocalConservation = args.Input<bool>("--conserve", "enforce local conservation", false); double Re = args.Input("--Re", "Reynolds number", 40); double nu = 1./Re; double lambda = Re/2.-sqrt(Re*Re/4+4*pi*pi); int maxNewtonIterations = args.Input("--maxIterations", "maximum number of Newton iterations", 20); int polyOrder = args.Input("--polyOrder", "polynomial order for field variables", 2); int deltaP = args.Input("--deltaP", "how much to enrich test space", 2); // string saveFile = args.Input<string>("--meshSaveFile", "file to which to save refinement history", ""); // string replayFile = args.Input<string>("--meshLoadFile", "file with refinement history to replay", ""); args.Process(); // if (commRank==0) // { // cout << "saveFile is " << saveFile << endl; // cout << "loadFile is " << replayFile << endl; // } //////////////////// PROBLEM DEFINITIONS /////////////////////// int H1Order = polyOrder+1; //////////////////// DECLARE VARIABLES /////////////////////// // define test variables VarFactory varFactory; // VarPtr tau11 = varFactory.testVar("tau11", HGRAD); // VarPtr tau12 = varFactory.testVar("tau12", HGRAD); // VarPtr tau22 = varFactory.testVar("tau22", HGRAD); VarPtr tau1 = varFactory.testVar("tau1", HDIV); VarPtr tau2 = varFactory.testVar("tau2", HDIV); VarPtr v1 = varFactory.testVar("v1", HGRAD); VarPtr v2 = varFactory.testVar("v2", HGRAD); VarPtr q = varFactory.testVar("q", HGRAD); // define trial variables VarPtr u1 = varFactory.fieldVar("u1"); VarPtr u2 = varFactory.fieldVar("u2"); // VarPtr sigma11 = varFactory.fieldVar("sigma11"); // VarPtr sigma12 = varFactory.fieldVar("sigma12"); // VarPtr sigma22 = varFactory.fieldVar("sigma22"); VarPtr sigma1 = varFactory.fieldVar("sigma1", VECTOR_L2); VarPtr sigma2 = varFactory.fieldVar("sigma2", VECTOR_L2); VarPtr u1hat = varFactory.traceVar("u1hat"); VarPtr u2hat = varFactory.traceVar("u2hat"); VarPtr t1hat = varFactory.fluxVar("t1hat"); VarPtr t2hat = varFactory.fluxVar("t2hat"); VarPtr p = varFactory.fieldVar("p"); //////////////////// BUILD MESH /////////////////////// BFPtr bf = Teuchos::rcp( new BF(varFactory) ); // define nodes for mesh FieldContainer<double> meshBoundary(4,2); double xmin = -0.5; double xmax = 1.0; double ymin = -0.5; double ymax = 1.5; meshBoundary(0,0) = xmin; // x1 meshBoundary(0,1) = ymin; // y1 meshBoundary(1,0) = xmax; meshBoundary(1,1) = ymin; meshBoundary(2,0) = xmax; meshBoundary(2,1) = ymax; meshBoundary(3,0) = xmin; meshBoundary(3,1) = ymax; int horizontalCells = 6, verticalCells = 8; // create a pointer to a new mesh: Teuchos::RCP<Mesh> mesh = Mesh::buildQuadMesh(meshBoundary, horizontalCells, verticalCells, bf, H1Order, H1Order+deltaP); //////////////////////////////////////////////////////////////////// // 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 u1_prev = Function::solution(u1, backgroundFlow); FunctionPtr u2_prev = Function::solution(u2, backgroundFlow); FunctionPtr sigma1_prev = Function::solution(sigma1, backgroundFlow); FunctionPtr sigma2_prev = Function::solution(sigma2, backgroundFlow); FunctionPtr p_prev = Function::solution(p, backgroundFlow); // FunctionPtr sigma11_prev = Function::solution(sigma11, backgroundFlow); // FunctionPtr sigma12_prev = Function::solution(sigma12, backgroundFlow); // FunctionPtr sigma22_prev = Function::solution(sigma22, backgroundFlow); FunctionPtr zero = Teuchos::rcp( new ConstantScalarFunction(0.0) ); FunctionPtr one = Teuchos::rcp( new ConstantScalarFunction(1.0) ); FunctionPtr u1Exact = Teuchos::rcp( new ExactU1(lambda) ); FunctionPtr u2Exact = Teuchos::rcp( new ExactU2(lambda) ); // FunctionPtr beta = e1 * u1_prev + e2 * u2_prev; // ==================== SET INITIAL GUESS ========================== map<int, Teuchos::RCP<Function> > functionMap; functionMap[u1->ID()] = u1Exact; functionMap[u2->ID()] = u2Exact; // functionMap[sigma1->ID()] = Function::vectorize(zero,zero); // functionMap[sigma2->ID()] = Function::vectorize(zero,zero); // functionMap[p->ID()] = zero; backgroundFlow->projectOntoMesh(functionMap); //////////////////// DEFINE BILINEAR FORM /////////////////////// // // stress equation bf->addTerm( 1./nu*sigma1, tau1 ); bf->addTerm( 1./nu*sigma2, tau2 ); bf->addTerm( u1, tau1->div() ); bf->addTerm( u2, tau2->div() ); bf->addTerm( -u1hat, tau1->dot_normal() ); bf->addTerm( -u2hat, tau2->dot_normal() ); // bf->addTerm( 1./(2*nu)*sigma11, tau11 ); // bf->addTerm( 1./(2*nu)*sigma12, tau12 ); // bf->addTerm( 1./(2*nu)*sigma12, tau12 ); // bf->addTerm( 1./(2*nu)*sigma22, tau22 ); // bf->addTerm( u1, tau11->dx() ); // bf->addTerm( u1, tau12->dy() ); // bf->addTerm( u2, tau12->dx() ); // bf->addTerm( u2, tau22->dy() ); // bf->addTerm( -u1hat, tau11->times_normal_x() ); // bf->addTerm( -u1hat, tau12->times_normal_y() ); // bf->addTerm( -u2hat, tau12->times_normal_x() ); // bf->addTerm( -u2hat, tau22->times_normal_y() ); // momentum equation bf->addTerm( -2.*u1_prev*u1, v1->dx() ); bf->addTerm( -u2_prev*u1, v1->dy() ); bf->addTerm( -u1_prev*u2, v1->dy() ); bf->addTerm( -u2_prev*u1, v2->dx() ); bf->addTerm( -u1_prev*u2, v1->dy() ); bf->addTerm( -2.*u2_prev*u2, v2->dy() ); bf->addTerm( -p, v1->dx() ); bf->addTerm( -p, v2->dy() ); // bf->addTerm( sigma11, v1->dx() ); // bf->addTerm( sigma12, v1->dy() ); // bf->addTerm( sigma12, v2->dx() ); // bf->addTerm( sigma22, v2->dy() ); bf->addTerm( sigma1, v1->grad() ); bf->addTerm( sigma2, v2->grad() ); bf->addTerm( t1hat, v1); bf->addTerm( t2hat, v2); // continuity equation bf->addTerm( -u1, q->dx() ); bf->addTerm( -u2, q->dy() ); bf->addTerm( u1hat, q->times_normal_x() ); bf->addTerm( u2hat, q->times_normal_y() ); //////////////////// SPECIFY RHS /////////////////////// Teuchos::RCP<RHSEasy> rhs = Teuchos::rcp( new RHSEasy ); // stress equation rhs->addTerm( -u1_prev * tau1->div() ); rhs->addTerm( -u2_prev * tau2->div() ); // momentum equation rhs->addTerm( 2.*u1_prev*u1_prev * v1->dx() ); rhs->addTerm( u2_prev*u1_prev * v1->dy() ); rhs->addTerm( u1_prev*u2_prev * v1->dy() ); rhs->addTerm( u2_prev*u1_prev * v2->dx() ); rhs->addTerm( u1_prev*u2_prev * v1->dy() ); rhs->addTerm( 2.*u2_prev*u2_prev * v2->dy() ); // rhs->addTerm( p_prev * v1->dx() ); // rhs->addTerm( p_prev * v2->dy() ); // rhs->addTerm( -sigma1_prev * v1->grad() ); // rhs->addTerm( -sigma2_prev * v2->grad() ); // rhs->addTerm( -sigma11_prev * v1->dx() ); // rhs->addTerm( -sigma12_prev * v1->dy() ); // rhs->addTerm( -sigma12_prev * v2->dx() ); // rhs->addTerm( -sigma22_prev * v2->dy() ); // continuity equation rhs->addTerm( u1_prev * q->dx() ); rhs->addTerm( u2_prev * q->dy() ); //////////////////// DEFINE INNER PRODUCT(S) /////////////////////// IPPtr ip = Teuchos::rcp(new IP); if (norm == 0) { ip = bf->graphNorm(); } else if (norm == 1) { // ip = bf->l2Norm(); } //////////////////// CREATE BCs /////////////////////// Teuchos::RCP<BCEasy> bc = Teuchos::rcp( new BCEasy ); // Teuchos::RCP<PenaltyConstraints> pc = Teuchos::rcp( new PenaltyConstraints ); SpatialFilterPtr left = Teuchos::rcp( new ConstantXBoundary(-0.5) ); SpatialFilterPtr right = Teuchos::rcp( new ConstantXBoundary(1) ); SpatialFilterPtr top = Teuchos::rcp( new ConstantYBoundary(-0.5) ); SpatialFilterPtr bottom = Teuchos::rcp( new ConstantYBoundary(1.5) ); bc->addDirichlet(u1hat, left, u1Exact); bc->addDirichlet(u2hat, left, u2Exact); bc->addDirichlet(u1hat, right, u1Exact); bc->addDirichlet(u2hat, right, u2Exact); bc->addDirichlet(u1hat, top, u1Exact); bc->addDirichlet(u2hat, top, u2Exact); bc->addDirichlet(u1hat, bottom, u1Exact); bc->addDirichlet(u2hat, bottom, u2Exact); // zero mean constraint on pressure bc->addZeroMeanConstraint(p); // pc->addConstraint(u1hat*u2hat-t1hat == zero, top); // pc->addConstraint(u2hat*u2hat-t2hat == zero, top); Teuchos::RCP<Solution> solution = Teuchos::rcp( new Solution(mesh, bc, rhs, ip) ); // solution->setFilter(pc); // if (enforceLocalConservation) { // solution->lagrangeConstraints()->addConstraint(u1hat->times_normal_x() + u2hat->times_normal_y() == zero); // } // ==================== Register Solutions ========================== mesh->registerSolution(solution); mesh->registerSolution(backgroundFlow); // Teuchos::RCP< RefinementHistory > refHistory = Teuchos::rcp( new RefinementHistory ); // mesh->registerObserver(refHistory); //////////////////// SOLVE & REFINE /////////////////////// double energyThreshold = 0.2; // for mesh refinements RefinementStrategy refinementStrategy( solution, energyThreshold ); VTKExporter exporter(backgroundFlow, mesh, varFactory); stringstream outfile; outfile << "kovasznay" << "_" << 0; exporter.exportSolution(outfile.str()); double nonlinearRelativeEnergyTolerance = 1e-5; // used to determine convergence of the nonlinear solution for (int refIndex=0; refIndex<=numRefs; refIndex++) { double L2Update = 1e10; int iterCount = 0; while (L2Update > nonlinearRelativeEnergyTolerance && iterCount < maxNewtonIterations) { solution->solve(false); double u1L2Update = solution->L2NormOfSolutionGlobal(u1->ID()); double u2L2Update = solution->L2NormOfSolutionGlobal(u2->ID()); L2Update = sqrt(u1L2Update*u1L2Update + u2L2Update*u2L2Update); // Check local conservation if (commRank == 0) { cout << "L2 Norm of Update = " << L2Update << endl; // if (saveFile.length() > 0) { // std::ostringstream oss; // oss << string(saveFile) << refIndex ; // cout << "on refinement " << refIndex << " saving mesh file to " << oss.str() << endl; // refHistory->saveToFile(oss.str()); // } } // line search algorithm double alpha = 1.0; backgroundFlow->addSolution(solution, alpha); iterCount++; } if (commRank == 0) { stringstream outfile; outfile << "kovasznay" << "_" << refIndex+1; exporter.exportSolution(outfile.str()); } if (refIndex < numRefs) refinementStrategy.refine(commRank==0); // print to console on commRank 0 } return 0; }
void TransientTests::SetUp() { //////////////////// DECLARE VARIABLES /////////////////////// // define test variables VarPtr v = varFactory.testVar("v", HGRAD); // define trial variables beta_n_u_hat = varFactory.fluxVar("\\widehat{\\beta \\cdot n }"); u = varFactory.fieldVar("u"); vector<double> beta; beta.push_back(1.0); beta.push_back(0.0); //////////////////// BUILD MESH /////////////////////// bf = Teuchos::rcp( new BF(varFactory) ); // define nodes for mesh FieldContainer<double> meshBoundary(4,2); meshBoundary(0,0) = 0.0; // x1 meshBoundary(0,1) = -2.0; // y1 meshBoundary(1,0) = 4.0; meshBoundary(1,1) = -2.0; meshBoundary(2,0) = 4.0; meshBoundary(2,1) = 2.0; meshBoundary(3,0) = 0.0; meshBoundary(3,1) = 2.0; int horizontalCells = 4, verticalCells = 4; // create a pointer to a new mesh: mesh = MeshFactory::buildQuadMesh(meshBoundary, horizontalCells, verticalCells, bf, H1Order, H1Order+pToAdd); //////////////////////////////////////////////////////////////////// // INITIALIZE FLOW FUNCTIONS //////////////////////////////////////////////////////////////////// BCPtr nullBC = Teuchos::rcp((BC*)NULL); RHSPtr nullRHS = Teuchos::rcp((RHS*)NULL); IPPtr nullIP = Teuchos::rcp((IP*)NULL); prevTimeFlow = Teuchos::rcp(new Solution(mesh, nullBC, nullRHS, nullIP) ); flowResidual = Teuchos::rcp(new Solution(mesh, nullBC, nullRHS, nullIP) ); FunctionPtr u_prev_time = Teuchos::rcp( new PreviousSolutionFunction(prevTimeFlow, u) ); //////////////////// DEFINE BILINEAR FORM /////////////////////// RHSPtr rhs = RHS::rhs(); FunctionPtr invDt = Teuchos::rcp(new ScalarParamFunction(1.0/dt)); // v terms: bf->addTerm( beta * u, - v->grad() ); bf->addTerm( beta_n_u_hat, v); // transient terms bf->addTerm( u, invDt*v ); rhs->addTerm( u_prev_time * invDt * v ); //////////////////// SPECIFY RHS /////////////////////// FunctionPtr f = Teuchos::rcp( new ConstantScalarFunction(0.0) ); rhs->addTerm( f * v ); // obviously, with f = 0 adding this term is not necessary! //////////////////// DEFINE INNER PRODUCT(S) /////////////////////// IPPtr ip = bf->graphNorm(); //////////////////// CREATE BCs /////////////////////// BCPtr bc = BC::bc(); SpatialFilterPtr lBoundary = Teuchos::rcp( new LeftBoundary ); FunctionPtr u1 = Teuchos::rcp( new InletBC ); bc->addDirichlet(beta_n_u_hat, lBoundary, -u1); solution = Teuchos::rcp( new Solution(mesh, bc, rhs, ip) ); // ==================== Register Solutions ========================== mesh->registerSolution(solution); mesh->registerSolution(prevTimeFlow); mesh->registerSolution(flowResidual); // ==================== SET INITIAL GUESS ========================== double u_free = 0.0; map<int, Teuchos::RCP<Function> > functionMap; functionMap[u->ID()] = Teuchos::rcp( new ConstantScalarFunction(u_free) ); // prevTimeFlow->projectOntoMesh(functionMap); }
int main(int argc, char *argv[]) { // Process command line arguments if (argc > 1) numRefs = atof(argv[1]); #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 FunctionPtr beta = Teuchos::rcp(new Beta()); //////////////////////////////////////////////////////////////////// // DEFINE VARIABLES //////////////////////////////////////////////////////////////////// // test variables VarFactory varFactory; VarPtr tau = varFactory.testVar("\\tau", HDIV); VarPtr v = varFactory.testVar("v", HGRAD); // trial variables VarPtr uhat = varFactory.traceVar("\\widehat{u}"); VarPtr beta_n_u_minus_sigma_n = varFactory.fluxVar("\\widehat{\\beta \\cdot n u - \\sigma_{n}}"); VarPtr u = varFactory.fieldVar("u"); VarPtr sigma1 = varFactory.fieldVar("\\sigma_1"); VarPtr sigma2 = varFactory.fieldVar("\\sigma_2"); //////////////////////////////////////////////////////////////////// // CREATE MESH //////////////////////////////////////////////////////////////////// BFPtr confusionBF = Teuchos::rcp( new BF(varFactory) ); FieldContainer<double> meshBoundary(4,2); meshBoundary(0,0) = 0.0; // x1 meshBoundary(0,1) = -2.0; // y1 meshBoundary(1,0) = 4.0; meshBoundary(1,1) = -2.0; meshBoundary(2,0) = 4.0; meshBoundary(2,1) = 2.0; meshBoundary(3,0) = 0.0; meshBoundary(3,1) = 2.0; int horizontalCells = 4, verticalCells = 4; // create a pointer to a new mesh: Teuchos::RCP<Mesh> mesh = Mesh::buildQuadMesh(meshBoundary, horizontalCells, verticalCells, confusionBF, H1Order, H1Order+pToAdd, false); //////////////////////////////////////////////////////////////////// // INITIALIZE BACKGROUND FLOW FUNCTIONS //////////////////////////////////////////////////////////////////// BCPtr nullBC = Teuchos::rcp((BC*)NULL); RHSPtr nullRHS = Teuchos::rcp((RHS*)NULL); IPPtr nullIP = Teuchos::rcp((IP*)NULL); SolutionPtr prevTimeFlow = Teuchos::rcp(new Solution(mesh, nullBC, nullRHS, nullIP) ); SolutionPtr flowResidual = Teuchos::rcp(new Solution(mesh, nullBC, nullRHS, nullIP) ); FunctionPtr u_prev_time = Teuchos::rcp( new PreviousSolutionFunction(prevTimeFlow, u) ); // ==================== SET INITIAL GUESS ========================== double u_free = 0.0; double sigma1_free = 0.0; double sigma2_free = 0.0; map<int, Teuchos::RCP<Function> > functionMap; functionMap[u->ID()] = Teuchos::rcp( new ConstantScalarFunction(u_free) ); functionMap[sigma1->ID()] = Teuchos::rcp( new ConstantScalarFunction(sigma1_free) ); functionMap[sigma2->ID()] = Teuchos::rcp( new ConstantScalarFunction(sigma2_free) ); prevTimeFlow->projectOntoMesh(functionMap); // ==================== END SET INITIAL GUESS ========================== //////////////////////////////////////////////////////////////////// // DEFINE BILINEAR FORM //////////////////////////////////////////////////////////////////// // tau terms: confusionBF->addTerm(sigma1 / epsilon, tau->x()); confusionBF->addTerm(sigma2 / epsilon, tau->y()); confusionBF->addTerm(u, tau->div()); confusionBF->addTerm(-uhat, tau->dot_normal()); // v terms: confusionBF->addTerm( sigma1, v->dx() ); confusionBF->addTerm( sigma2, v->dy() ); confusionBF->addTerm( beta * u, - v->grad() ); confusionBF->addTerm( beta_n_u_minus_sigma_n, v); //////////////////////////////////////////////////////////////////// // TIMESTEPPING TERMS //////////////////////////////////////////////////////////////////// Teuchos::RCP<RHSEasy> rhs = Teuchos::rcp( new RHSEasy ); double dt = 0.25; FunctionPtr invDt = Teuchos::rcp(new ScalarParamFunction(1.0/dt)); if (rank==0){ cout << "Timestep dt = " << dt << endl; } if (transient) { confusionBF->addTerm( u, invDt*v ); rhs->addTerm( u_prev_time * invDt * v ); } //////////////////////////////////////////////////////////////////// // DEFINE INNER PRODUCT //////////////////////////////////////////////////////////////////// // mathematician's norm IPPtr mathIP = Teuchos::rcp(new IP()); mathIP->addTerm(tau); mathIP->addTerm(tau->div()); mathIP->addTerm(v); mathIP->addTerm(v->grad()); // quasi-optimal norm IPPtr qoptIP = Teuchos::rcp(new IP); qoptIP->addTerm( v ); qoptIP->addTerm( tau / epsilon + v->grad() ); qoptIP->addTerm( beta * v->grad() - tau->div() ); // robust test norm IPPtr robIP = Teuchos::rcp(new IP); FunctionPtr ip_scaling = Teuchos::rcp( new EpsilonScaling(epsilon) ); if (!enforceLocalConservation) { robIP->addTerm( ip_scaling * v ); if (transient) robIP->addTerm( invDt * v ); } robIP->addTerm( sqrt(epsilon) * v->grad() ); // Weight these two terms for inflow FunctionPtr ip_weight = Teuchos::rcp( new IPWeight() ); robIP->addTerm( ip_weight * beta * v->grad() ); robIP->addTerm( ip_weight * tau->div() ); robIP->addTerm( ip_scaling/sqrt(epsilon) * tau ); if (enforceLocalConservation) robIP->addZeroMeanTerm( v ); //////////////////////////////////////////////////////////////////// // DEFINE RHS //////////////////////////////////////////////////////////////////// FunctionPtr f = Teuchos::rcp( new ConstantScalarFunction(0.0) ); rhs->addTerm( f * v ); // obviously, with f = 0 adding this term is not necessary! //////////////////////////////////////////////////////////////////// // DEFINE BC //////////////////////////////////////////////////////////////////// Teuchos::RCP<BCEasy> bc = Teuchos::rcp( new BCEasy ); // Teuchos::RCP<PenaltyConstraints> pc = Teuchos::rcp( new PenaltyConstraints ); SpatialFilterPtr lBoundary = Teuchos::rcp( new LeftBoundary ); SpatialFilterPtr tbBoundary = Teuchos::rcp( new TopBottomBoundary ); SpatialFilterPtr rBoundary = Teuchos::rcp( new RightBoundary ); FunctionPtr u0 = Teuchos::rcp( new ZeroBC ); FunctionPtr u_inlet = Teuchos::rcp( new InletBC ); // FunctionPtr n = Teuchos::rcp( new UnitNormalFunction ); bc->addDirichlet(beta_n_u_minus_sigma_n, lBoundary, u_inlet); bc->addDirichlet(beta_n_u_minus_sigma_n, tbBoundary, u0); bc->addDirichlet(uhat, rBoundary, u0); // pc->addConstraint(beta_n_u_minus_sigma_n - uhat == u0, rBoundary); //////////////////////////////////////////////////////////////////// // CREATE SOLUTION OBJECT //////////////////////////////////////////////////////////////////// Teuchos::RCP<Solution> solution = Teuchos::rcp( new Solution(mesh, bc, rhs, robIP) ); // solution->setFilter(pc); // ==================== Enforce Local Conservation ================== if (enforceLocalConservation) { if (transient) { FunctionPtr conserved_rhs = u_prev_time * invDt; LinearTermPtr conserved_quantity = invDt * u; LinearTermPtr flux_part = Teuchos::rcp(new LinearTerm(-1.0, beta_n_u_minus_sigma_n)); conserved_quantity->addTerm(flux_part, true); // conserved_quantity = conserved_quantity - beta_n_u_minus_sigma_n; solution->lagrangeConstraints()->addConstraint(conserved_quantity == conserved_rhs); } else { FunctionPtr zero = Teuchos::rcp( new ConstantScalarFunction(0.0) ); solution->lagrangeConstraints()->addConstraint(beta_n_u_minus_sigma_n == zero); } } // ==================== Register Solutions ========================== mesh->registerSolution(solution); mesh->registerSolution(prevTimeFlow); // u_t(i-1) mesh->registerSolution(flowResidual); // u_t(i-1) double energyThreshold = 0.25; // for mesh refinements Teuchos::RCP<RefinementStrategy> refinementStrategy; refinementStrategy = Teuchos::rcp(new RefinementStrategy(solution,energyThreshold)); //////////////////////////////////////////////////////////////////// // PSEUDO-TIME SOLVE STRATEGY //////////////////////////////////////////////////////////////////// double time_tol = 1e-8; for (int refIndex=0; refIndex<=numRefs; refIndex++) { double L2_time_residual = 1e7; int timestepCount = 0; if (!transient) numTimeSteps = 1; while((L2_time_residual > time_tol) && (timestepCount < numTimeSteps)) { solution->solve(false); // subtract solutions to get residual flowResidual->setSolution(solution); // reset previous time solution to current time sol flowResidual->addSolution(prevTimeFlow, -1.0); double L2u = flowResidual->L2NormOfSolutionGlobal(u->ID()); double L2sigma1 = flowResidual->L2NormOfSolutionGlobal(sigma1->ID()); double L2sigma2 = flowResidual->L2NormOfSolutionGlobal(sigma2->ID()); L2_time_residual = sqrt(L2u*L2u + L2sigma1*L2sigma1 + L2sigma2*L2sigma2); cout << endl << "Timestep: " << timestepCount << ", dt = " << dt << ", Time residual = " << L2_time_residual << endl; if (rank == 0) { stringstream outfile; if (transient) outfile << "TransientConfusion_" << refIndex << "_" << timestepCount; else outfile << "TransientConfusion_" << refIndex; solution->writeToVTK(outfile.str(), 5); } ////////////////////////////////////////////////////////////////////////// // Check conservation by testing against one ////////////////////////////////////////////////////////////////////////// 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 flux_current_time = Teuchos::rcp( new PreviousSolutionFunction(solution, beta_n_u_minus_sigma_n) ); FunctionPtr delta_u = Teuchos::rcp( new PreviousSolutionFunction(flowResidual, u) ); LinearTermPtr surfaceFlux = -1.0 * flux_current_time * testOne; LinearTermPtr volumeChange = invDt * delta_u * testOne; LinearTermPtr massFluxTerm; if (transient) { massFluxTerm = volumeChange; // massFluxTerm->addTerm(surfaceFlux); } else { massFluxTerm = surfaceFlux; } // cout << "surface case = " << surfaceFlux->summands()[0].first->boundaryValueOnly() << " volume case = " << volumeChange->summands()[0].first->boundaryValueOnly() << endl; // FunctionPtr massFlux= Teuchos::rcp( new PreviousSolutionFunction(solution, beta_n_u_minus_sigma_n) ); // 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] ); } } // Print results from processor with rank 0 if (rank == 0) { cout << "largest mass flux: " << maxMassFluxIntegral << endl; cout << "total mass flux: " << totalMassFlux << endl; cout << "sum of mass flux absolute value: " << totalAbsMassFlux << endl; } prevTimeFlow->setSolution(solution); // reset previous time solution to current time sol timestepCount++; } if (refIndex < numRefs){ if (rank==0){ cout << "Performing refinement number " << refIndex << endl; } refinementStrategy->refine(rank==0); // RESET solution every refinement - make sure discretization error doesn't creep in // prevTimeFlow->projectOntoMesh(functionMap); } } return 0; }
int main(int argc, char *argv[]) { #ifdef HAVE_MPI Teuchos::GlobalMPISession mpiSession(&argc, &argv,0); choice::MpiArgs args( argc, argv ); #else choice::Args args( argc, argv ); #endif int commRank = Teuchos::GlobalMPISession::getRank(); int numProcs = Teuchos::GlobalMPISession::getNProc(); // Required arguments int numRefs = args.Input<int>("--numRefs", "number of refinement steps"); bool enforceLocalConservation = args.Input<bool>("--conserve", "enforce local conservation"); bool steady = args.Input<bool>("--steady", "run steady rather than transient"); // Optional arguments (have defaults) double dt = args.Input("--dt", "time step", 0.25); int numTimeSteps = args.Input("--nt", "number of time steps", 20); halfWidth = args.Input("--halfWidth", "half width of inlet profile", 1.0); args.Process(); //////////////////// DECLARE VARIABLES /////////////////////// // define test variables VarFactory varFactory; VarPtr v = varFactory.testVar("v", HGRAD); // define trial variables VarPtr beta_n_u_hat = varFactory.fluxVar("\\widehat{\\beta \\cdot n }"); VarPtr u = varFactory.fieldVar("u"); vector<double> beta; beta.push_back(1.0); beta.push_back(0.0); //////////////////// BUILD MESH /////////////////////// BFPtr bf = Teuchos::rcp( new BF(varFactory) ); // define nodes for mesh FieldContainer<double> meshBoundary(4,2); meshBoundary(0,0) = 0.0; // x1 meshBoundary(0,1) = -2.0; // y1 meshBoundary(1,0) = 4.0; meshBoundary(1,1) = -2.0; meshBoundary(2,0) = 4.0; meshBoundary(2,1) = 2.0; meshBoundary(3,0) = 0.0; meshBoundary(3,1) = 2.0; int horizontalCells = 8, verticalCells = 8; // create a pointer to a new mesh: Teuchos::RCP<Mesh> mesh = Mesh::buildQuadMesh(meshBoundary, horizontalCells, verticalCells, bf, H1Order, H1Order+pToAdd); //////////////////////////////////////////////////////////////////// // INITIALIZE FLOW FUNCTIONS //////////////////////////////////////////////////////////////////// BCPtr nullBC = Teuchos::rcp((BC*)NULL); RHSPtr nullRHS = Teuchos::rcp((RHS*)NULL); IPPtr nullIP = Teuchos::rcp((IP*)NULL); SolutionPtr prevTimeFlow = Teuchos::rcp(new Solution(mesh, nullBC, nullRHS, nullIP) ); SolutionPtr flowResidual = Teuchos::rcp(new Solution(mesh, nullBC, nullRHS, nullIP) ); FunctionPtr u_prev_time = Teuchos::rcp( new PreviousSolutionFunction(prevTimeFlow, u) ); //////////////////// DEFINE BILINEAR FORM /////////////////////// Teuchos::RCP<RHSEasy> rhs = Teuchos::rcp( new RHSEasy ); FunctionPtr invDt = Teuchos::rcp(new ScalarParamFunction(1.0/dt)); // v terms: bf->addTerm( beta * u, - v->grad() ); bf->addTerm( beta_n_u_hat, v); if (!steady) { bf->addTerm( u, invDt*v ); rhs->addTerm( u_prev_time * invDt * v ); } //////////////////// SPECIFY RHS /////////////////////// FunctionPtr f = Teuchos::rcp( new ConstantScalarFunction(0.0) ); rhs->addTerm( f * v ); // obviously, with f = 0 adding this term is not necessary! //////////////////// DEFINE INNER PRODUCT(S) /////////////////////// IPPtr ip = bf->graphNorm(); // ip->addTerm(v); // ip->addTerm(beta*v->grad()); //////////////////// CREATE BCs /////////////////////// Teuchos::RCP<BCEasy> bc = Teuchos::rcp( new BCEasy ); SpatialFilterPtr lBoundary = Teuchos::rcp( new LeftBoundary ); FunctionPtr u1 = Teuchos::rcp( new InletBC ); bc->addDirichlet(beta_n_u_hat, lBoundary, -u1); Teuchos::RCP<Solution> solution = Teuchos::rcp( new Solution(mesh, bc, rhs, ip) ); // ==================== Register Solutions ========================== mesh->registerSolution(solution); mesh->registerSolution(prevTimeFlow); mesh->registerSolution(flowResidual); // ==================== SET INITIAL GUESS ========================== double u_free = 0.0; map<int, Teuchos::RCP<Function> > functionMap; // functionMap[u->ID()] = Teuchos::rcp( new ConInletBC functionMap[u->ID()] = Teuchos::rcp( new InletBC ); prevTimeFlow->projectOntoMesh(functionMap); //////////////////// SOLVE & REFINE /////////////////////// if (enforceLocalConservation) { if (steady) { FunctionPtr zero = Teuchos::rcp( new ConstantScalarFunction(0.0) ); solution->lagrangeConstraints()->addConstraint(beta_n_u_hat == zero); } else { // FunctionPtr parity = Teuchos::rcp<Function>( new SideParityFunction ); // LinearTermPtr conservedQuantity = Teuchos::rcp<LinearTerm>( new LinearTerm(parity, beta_n_u_minus_sigma_n) ); LinearTermPtr conservedQuantity = Teuchos::rcp<LinearTerm>( new LinearTerm(1.0, beta_n_u_hat) ); LinearTermPtr sourcePart = Teuchos::rcp<LinearTerm>( new LinearTerm(invDt, u) ); conservedQuantity->addTerm(sourcePart, true); solution->lagrangeConstraints()->addConstraint(conservedQuantity == u_prev_time * invDt); } } double energyThreshold = 0.2; // for mesh refinements RefinementStrategy refinementStrategy( solution, energyThreshold ); VTKExporter exporter(solution, mesh, varFactory); for (int refIndex=0; refIndex<=numRefs; refIndex++) { if (steady) { solution->solve(false); if (commRank == 0) { stringstream outfile; outfile << "Convection_" << refIndex; exporter.exportSolution(outfile.str()); // Check local conservation FunctionPtr flux = Teuchos::rcp( new PreviousSolutionFunction(solution, beta_n_u_hat) ); FunctionPtr zero = Teuchos::rcp( new ConstantScalarFunction(0.0) ); Teuchos::Tuple<double, 3> fluxImbalances = checkConservation(flux, zero, varFactory, mesh); cout << "Mass flux: Largest Local = " << fluxImbalances[0] << ", Global = " << fluxImbalances[1] << ", Sum Abs = " << fluxImbalances[2] << endl; } } else { int timestepCount = 0; double time_tol = 1e-8; double L2_time_residual = 1e9; // cout << L2_time_residual <<" "<< time_tol << timestepCount << numTimeSteps << endl; while((L2_time_residual > time_tol) && (timestepCount < numTimeSteps)) { solution->solve(false); // Subtract solutions to get residual flowResidual->setSolution(solution); flowResidual->addSolution(prevTimeFlow, -1.0); L2_time_residual = flowResidual->L2NormOfSolutionGlobal(u->ID()); if (commRank == 0) { cout << endl << "Timestep: " << timestepCount << ", dt = " << dt << ", Time residual = " << L2_time_residual << endl; stringstream outfile; outfile << "TransientConvection_" << refIndex << "-" << timestepCount; exporter.exportSolution(outfile.str()); // Check local conservation FunctionPtr flux = Teuchos::rcp( new PreviousSolutionFunction(solution, beta_n_u_hat) ); FunctionPtr source = Teuchos::rcp( new PreviousSolutionFunction(flowResidual, u) ); source = -invDt * source; Teuchos::Tuple<double, 3> fluxImbalances = checkConservation(flux, source, varFactory, mesh); cout << "Mass flux: Largest Local = " << fluxImbalances[0] << ", Global = " << fluxImbalances[1] << ", Sum Abs = " << fluxImbalances[2] << endl; } prevTimeFlow->setSolution(solution); // reset previous time solution to current time sol timestepCount++; } } if (refIndex < numRefs) refinementStrategy.refine(commRank==0); // print to console on commRank 0 } return 0; }
//----------------------------------------------------------------------- //mesh square parameterize //----------------------------------------------------------------------- void OMPmodel::Param(const char *infile, const char *outfile, int solveType, int outType) { // read mesh from file if (!OpenMesh::IO::read_mesh(mesh, infile)) { std::cerr << "Error: Cannot read mesh from " << infile << std::endl; } // this vertex property stores the vertex id OpenMesh::VPropHandleT<uint> vertexID; mesh.add_property(vertexID); uint i = 0; for (MyMesh::VertexIter v_it = mesh.vertices_begin(); v_it != mesh.vertices_end(); ++v_it) { mesh.property(vertexID, *v_it) = i; ++i; } //find a boundary half edge MyMesh::HalfedgeHandle heh, heh_init; for (MyMesh::HalfedgeIter h_it = mesh.halfedges_begin(); h_it != mesh.halfedges_end(); ++h_it) { if (mesh.is_boundary(*h_it)) { heh_init = *h_it; heh = heh_init; break; } } //mesh.property(vertexID, mesh.from_vertex_handle(heh)); //mesh.point(mesh.from_vertex_handle(heh)); //push first boundary vertex meshBoundryStatus.push_back(meshBoundary(mesh.property(vertexID, mesh.from_vertex_handle(heh)), mesh.point(mesh.from_vertex_handle(heh)))); heh = mesh.next_halfedge_handle(heh); // push all boundary vertex while (heh != heh_init) { meshBoundryStatus.push_back(meshBoundary(mesh.property(vertexID, mesh.from_vertex_handle(heh)), mesh.point(mesh.from_vertex_handle(heh)))); heh = mesh.next_halfedge_handle(heh); } //caculate length OpenMesh::Vec3d vec; for (i = 0; i < meshBoundryStatus.size() - 1; ++i) { vec = meshBoundryStatus[i + 1].position - meshBoundryStatus[i].position; meshBoundryStatus[i].distanceToNext = vec.norm(); tLen += meshBoundryStatus[i].distanceToNext; } vec = meshBoundryStatus[0].position - meshBoundryStatus[i].position; meshBoundryStatus[i].distanceToNext = vec.norm(); tLen += meshBoundryStatus[i].distanceToNext; //get other information mesh.request_vertex_status(); meshVetexNum = mesh.n_vertices(); mesh.request_face_status(); meshFaceNum = mesh.n_faces(); mesh.release_face_status(); mesh.release_vertex_status(); cout << "#vertices: " << meshVetexNum << endl; cout << "#faces: " << meshFaceNum << endl; cout << "#boundary vertices: " << meshBoundryStatus.size() << endl; cout << "coner vertices: " << meshBoundryStatus[0].vertexID << " " << meshBoundryStatus[meshBoundryStatus.size()/3].vertexID<<" "; cout << meshBoundryStatus[meshBoundryStatus.size() * 2 / 3].vertexID <<" "<< meshBoundryStatus[meshBoundryStatus.size() - 1].vertexID << endl; cout << "Total length: " << tLen << endl; //map interior vertex //resize A and b A.resize(meshVetexNum, meshVetexNum); Bu.resize(meshVetexNum); Bv.resize(meshVetexNum); u.resize(meshVetexNum); v.resize(meshVetexNum); A.setZero(); Bu.setZero(); Bv.setZero(); vector<meshVertex> oneRing; typedef Eigen::Triplet<double> T; std::vector<T> tripletList; for (MyMesh::VertexIter v_it = mesh.vertices_begin(); v_it != mesh.vertices_end(); ++v_it) { oneRing.clear(); if (!mesh.is_boundary(*v_it)) { for (MyMesh::VertexVertexIter vv_it = mesh.vv_iter(*v_it); vv_it.is_valid(); ++vv_it) { oneRing.push_back(meshVertex(mesh.property(vertexID, *vv_it), mesh.point(*vv_it))); } double wij = 0; double sumWij = 0; double cotaij = 0; double cotbij = 0; OpenMesh::Vec3d vi_12vi, vi_12v, vi12vi, vi12v; for (int i = 0; i < oneRing.size(); ++i) { if (i == 0) { vi_12v = mesh.point(*v_it) - oneRing[oneRing.size() - 1].position; vi_12vi = oneRing[0].position - oneRing[oneRing.size() - 1].position; vi12v = mesh.point(*v_it) - oneRing[i + 1].position; vi12vi = oneRing[i].position - oneRing[i + 1].position; } else if (i == oneRing.size() - 1) { vi_12v = mesh.point(*v_it) - oneRing[i - 1].position; vi_12vi = oneRing[i].position - oneRing[i - 1].position; vi12v = mesh.point(*v_it) - oneRing[0].position; vi12vi = oneRing[i].position - oneRing[0].position; } else { vi_12v = mesh.point(*v_it) - oneRing[i - 1].position; vi_12vi = oneRing[i].position - oneRing[i - 1].position; vi12v = mesh.point(*v_it) - oneRing[i + 1].position; vi12vi = oneRing[i].position - oneRing[i + 1].position; } vi_12v.normalize(); vi_12vi.normalize(); vi12v.normalize(); vi12vi.normalize(); cotaij = cot(acos(dot(vi_12v, vi_12vi))); cotbij = cot(acos(dot(vi12v, vi12vi))); wij = 0.5 * (cotaij + cotbij); sumWij += wij; //insert tripletList.push_back(T(mesh.property(vertexID, *v_it), oneRing[i].vertexID, wij));//insert wij (i != j) } tripletList.push_back(T(mesh.property(vertexID, *v_it), mesh.property(vertexID, *v_it), - sumWij));//when i = j } else { tripletList.push_back(T(mesh.property(vertexID, *v_it), mesh.property(vertexID, *v_it), 1));// add boundary } } A.setFromTriplets(tripletList.begin(), tripletList.end()); //debug << A << endl; //map boundary to a unit square BoundaryMap(); Solve(solveType); //change the mesh and output if (outType == 1) { i = 0; for (MyMesh::VertexIter v_it = mesh.vertices_begin(); v_it != mesh.vertices_end(); ++v_it) { mesh.set_point(*v_it, MyMesh::Point(u[i], v[i], 0)); ++i; } // write mesh to output.* OpenMesh::IO::write_mesh(mesh, outfile); } else { mesh.request_vertex_texcoords2D(); i = 0; for (MyMesh::VertexIter v_it = mesh.vertices_begin(); v_it != mesh.vertices_end(); ++v_it) { mesh.set_texcoord2D(*v_it, MyMesh::TexCoord2D(u[i], v[i])); ++i; } // write mesh to output.* OpenMesh::IO::Options wopt; wopt += OpenMesh::IO::Options::VertexTexCoord; OpenMesh::IO::write_mesh(mesh, outfile, wopt); mesh.release_vertex_texcoords2D(); } }
int main(int argc, char *argv[]) { #ifdef HAVE_MPI Teuchos::GlobalMPISession mpiSession(&argc, &argv,0); choice::MpiArgs args( argc, argv ); #else choice::Args args( argc, argv ); #endif int commRank = Teuchos::GlobalMPISession::getRank(); int numProcs = Teuchos::GlobalMPISession::getNProc(); // Required arguments double epsilon = args.Input<double>("--epsilon", "diffusion parameter"); int numRefs = args.Input<int>("--numRefs", "number of refinement steps"); bool enforceLocalConservation = args.Input<bool>("--conserve", "enforce local conservation"); int norm = args.Input<int>("--norm", "0 = graph\n 1 = robust\n 2 = modified robust"); // Optional arguments (have defaults) bool zeroL2 = args.Input("--zeroL2", "take L2 term on v in robust norm to zero", true); args.Process(); //////////////////// DECLARE VARIABLES /////////////////////// // define test variables VarFactory varFactory; VarPtr tau = varFactory.testVar("tau", HDIV); VarPtr v = varFactory.testVar("v", HGRAD); // define trial variables VarPtr uhat = varFactory.traceVar("uhat"); VarPtr fhat = varFactory.fluxVar("fhat"); VarPtr u = varFactory.fieldVar("u"); VarPtr sigma = varFactory.fieldVar("sigma", VECTOR_L2); //////////////////// BUILD MESH /////////////////////// BFPtr bf = Teuchos::rcp( new BF(varFactory) ); int H1Order = 3, pToAdd = 2; // define nodes for mesh FieldContainer<double> meshBoundary(4,2); meshBoundary(0,0) = 0.0; // x1 meshBoundary(0,1) = 0.0; // y1 meshBoundary(1,0) = 1.0; meshBoundary(1,1) = 0.0; meshBoundary(2,0) = 1.0; meshBoundary(2,1) = 1.0; meshBoundary(3,0) = 0.0; meshBoundary(3,1) = 1.0; int horizontalCells = 4, verticalCells = 4; // create a pointer to a new mesh: Teuchos::RCP<Mesh> mesh = Mesh::buildQuadMesh(meshBoundary, horizontalCells, verticalCells, bf, H1Order, H1Order+pToAdd, false); vector<double> beta; beta.push_back(2.0); beta.push_back(1.0); //////////////////// DEFINE BILINEAR FORM /////////////////////// // tau terms: bf->addTerm(sigma / epsilon, tau); bf->addTerm(u, tau->div()); bf->addTerm(-uhat, tau->dot_normal()); // v terms: bf->addTerm( sigma, v->grad() ); bf->addTerm( beta * u, - v->grad() ); bf->addTerm( fhat, v); //////////////////// DEFINE INNER PRODUCT(S) /////////////////////// IPPtr ip = Teuchos::rcp(new IP); if (norm == 0) { ip = bf->graphNorm(); FunctionPtr h2_scaling = Teuchos::rcp( new ZeroMeanScaling ); ip->addZeroMeanTerm( h2_scaling*v ); } // Robust norm else if (norm == 1) { // robust test norm FunctionPtr ip_scaling = Teuchos::rcp( new EpsilonScaling(epsilon) ); FunctionPtr h2_scaling = Teuchos::rcp( new ZeroMeanScaling ); if (!zeroL2) ip->addTerm( v ); ip->addTerm( sqrt(epsilon) * v->grad() ); // Weight these two terms for inflow ip->addTerm( beta * v->grad() ); ip->addTerm( tau->div() ); ip->addTerm( ip_scaling/sqrt(epsilon) * tau ); if (zeroL2) ip->addZeroMeanTerm( h2_scaling*v ); } // Modified robust norm else if (norm == 2) { // robust test norm FunctionPtr ip_scaling = Teuchos::rcp( new EpsilonScaling(epsilon) ); FunctionPtr h2_scaling = Teuchos::rcp( new ZeroMeanScaling ); // FunctionPtr ip_weight = Teuchos::rcp( new IPWeight() ); if (!zeroL2) ip->addTerm( v ); ip->addTerm( sqrt(epsilon) * v->grad() ); ip->addTerm( beta * v->grad() ); ip->addTerm( tau->div() - beta*v->grad() ); ip->addTerm( ip_scaling/sqrt(epsilon) * tau ); if (zeroL2) ip->addZeroMeanTerm( h2_scaling*v ); } //////////////////// SPECIFY RHS /////////////////////// Teuchos::RCP<RHSEasy> rhs = Teuchos::rcp( new RHSEasy ); FunctionPtr f = Teuchos::rcp( new ConstantScalarFunction(0.0) ); rhs->addTerm( f * v ); // obviously, with f = 0 adding this term is not necessary! //////////////////// CREATE BCs /////////////////////// Teuchos::RCP<BCEasy> bc = Teuchos::rcp( new BCEasy ); SpatialFilterPtr inflowBoundary = Teuchos::rcp( new InflowBoundary ); SpatialFilterPtr outflowBoundary = Teuchos::rcp( new OutflowBoundary ); FunctionPtr u0 = Teuchos::rcp( new U0 ); bc->addDirichlet(uhat, outflowBoundary, u0); FunctionPtr n = Teuchos::rcp( new UnitNormalFunction ); bc->addDirichlet(fhat, inflowBoundary, beta*n*u0); // Teuchos::RCP<PenaltyConstraints> pc = Teuchos::rcp(new PenaltyConstraints); // pc->addConstraint(uhat==u0,inflowBoundary); //////////////////// SOLVE & REFINE /////////////////////// Teuchos::RCP<Solution> solution = Teuchos::rcp( new Solution(mesh, bc, rhs, ip) ); // solution->setFilter(pc); if (enforceLocalConservation) { FunctionPtr zero = Teuchos::rcp( new ConstantScalarFunction(0.0) ); solution->lagrangeConstraints()->addConstraint(fhat == zero); } double energyThreshold = 0.2; // for mesh refinements RefinementStrategy refinementStrategy( solution, energyThreshold ); VTKExporter exporter(solution, mesh, varFactory); ofstream errOut; if (commRank == 0) errOut.open("confusion_err.txt"); for (int refIndex=0; refIndex<=numRefs; refIndex++){ solution->solve(false); double energy_error = solution->energyErrorTotal(); if (commRank==0){ stringstream outfile; outfile << "confusion_" << refIndex; exporter.exportSolution(outfile.str()); // solution->writeToVTK(outfile.str()); // Check local conservation FunctionPtr flux = Function::solution(fhat, solution); FunctionPtr zero = Teuchos::rcp( new ConstantScalarFunction(0.0) ); Teuchos::Tuple<double, 3> fluxImbalances = checkConservation(flux, zero, varFactory, mesh); cout << "Mass flux: Largest Local = " << fluxImbalances[0] << ", Global = " << fluxImbalances[1] << ", Sum Abs = " << fluxImbalances[2] << endl; errOut << mesh->numGlobalDofs() << " " << energy_error << " " << fluxImbalances[0] << " " << fluxImbalances[1] << " " << fluxImbalances[2] << endl; } if (refIndex < numRefs) refinementStrategy.refine(commRank==0); // print to console on commRank 0 } if (commRank == 0) errOut.close(); return 0; }