bool checkLTSumConsistency(LinearTermPtr a, LinearTermPtr b, DofOrderingPtr dofOrdering, BasisCachePtr basisCache) { double tol = 1e-14; int numCells = basisCache->cellIDs().size(); int numDofs = dofOrdering->totalDofs(); bool forceBoundaryTerm = false; FieldContainer<double> aValues(numCells,numDofs), bValues(numCells,numDofs), sumValues(numCells,numDofs); a->integrate(aValues,dofOrdering,basisCache,forceBoundaryTerm); b->integrate(bValues,dofOrdering,basisCache,forceBoundaryTerm); (a+b)->integrate(sumValues, dofOrdering, basisCache, forceBoundaryTerm); int size = aValues.size(); for (int i=0; i<size; i++) { double expectedValue = aValues[i] + bValues[i]; double diff = abs( expectedValue - sumValues[i] ); if (diff > tol) { return false; } } return true; }
double integralOverMesh(LinearTermPtr testTerm, VarPtr testVar, FunctionPtr fxnToSubstitute) { map<int, FunctionPtr > varAsFunction; varAsFunction[testVar->ID()] = fxnToSubstitute; FunctionPtr substituteOnBoundary = testTerm->evaluate(varAsFunction, true); FunctionPtr substituteOnInterior = testTerm->evaluate(varAsFunction, false); double integral = substituteOnBoundary->integrate(mesh); integral += substituteOnInterior->integrate(mesh); return integral; }
PreviousSolutionFunction::PreviousSolutionFunction(SolutionPtr soln, LinearTermPtr solnExpression, bool multiplyFluxesByCellParity) : Function(solnExpression->rank()) { _soln = soln; _solnExpression = solnExpression; _overrideMeshCheck = false; if ((solnExpression->termType() == FLUX) && multiplyFluxesByCellParity) { FunctionPtr parity = Teuchos::rcp( new SideParityFunction ); _solnExpression = parity * solnExpression; } }
PreviousSolutionFunction<Scalar>::PreviousSolutionFunction(TSolutionPtr<Scalar> soln, LinearTermPtr solnExpression, bool multiplyFluxesByCellParity) : TFunction<Scalar>(solnExpression->rank()) { _soln = soln; _solnExpression = solnExpression; _overrideMeshCheck = false; if ((solnExpression->termType() == FLUX) && multiplyFluxesByCellParity) { TFunctionPtr<double> parity = TFunction<double>::sideParity(); _solnExpression = parity * solnExpression; } }
void LagrangeConstraints::getCoefficients(FieldContainer<double> &lhs, FieldContainer<double> &rhs, int elemConstraintIndex, DofOrderingPtr trialOrdering, BasisCachePtr basisCache) { LinearTermPtr lt = _constraints[elemConstraintIndex].linearTerm(); TFunctionPtr<double> f = _constraints[elemConstraintIndex].f(); lt->integrate(lhs, trialOrdering, basisCache); bool onBoundary = f->boundaryValueOnly(); if ( !onBoundary ) { f->integrate(rhs, basisCache); } else { int numSides = basisCache->cellTopology()->getSideCount(); rhs.initialize(0); for (int sideIndex=0; sideIndex<numSides; sideIndex++) { f->integrate(rhs, basisCache->getSideBasisCache(sideIndex), true); // true: sumInto } } }
bool LinearTermTests::testLinearTermEvaluation() { bool success = true; double eps = .1; FunctionPtr one = Function::constant(1.0); vector<double> e1,e2; e1.push_back(1.0); e1.push_back(0.0); e2.push_back(0.0); e2.push_back(1.0); // define test variables VarFactoryPtr varFactory = VarFactory::varFactory(); VarPtr tau = varFactory->testVar("\\tau", HDIV); VarPtr v = varFactory->testVar("v", HGRAD); // define a couple LinearTerms LinearTermPtr vVecLT = Teuchos::rcp(new LinearTerm); LinearTermPtr tauVecLT = Teuchos::rcp(new LinearTerm); vVecLT->addTerm(sqrt(eps)*v->grad()); tauVecLT->addTerm((1/sqrt(eps))*tau); //////////////////// evaluate LinearTerms ///////////////// map<int,FunctionPtr> errRepMap; errRepMap[v->ID()] = one; errRepMap[tau->ID()] = one*e1+one*e2; // vector valued fxn (1,1) FunctionPtr errTau = tauVecLT->evaluate(errRepMap,false); FunctionPtr errV = vVecLT->evaluate(errRepMap,false); try { bool xTauZero = errTau->x()->isZero(); bool yTauZero = errTau->y()->isZero(); bool xVZero = errV->dx()->isZero(); bool yVZero = errV->dy()->isZero(); } catch (...) { cout << "testLinearTermEvaluation: Caught exception.\n"; success = false; } /* FunctionPtr xErr = (errTau->x())*(errTau->x()) + (errV->dx())*(errV->dx()); FunctionPtr yErr = (errTau->y())*(errTau->y()) + (errV->dy())*(errV->dy()); double xErrVal = xErr->integrate(mesh,15,true); */ // if we don't crash, return success return success; }
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 rank = Teuchos::GlobalMPISession::getRank(); int numProcs = Teuchos::GlobalMPISession::getNProc(); int nCells = args.Input<int>("--nCells", "num cells",2); int numSteps = args.Input<int>("--numSteps", "num NR steps",20); int polyOrder = 0; // define our manufactured solution or problem bilinear form: bool useTriangles = false; int pToAdd = 1; args.Process(); int H1Order = polyOrder + 1; //////////////////////////////////////////////////////////////////// // 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 = MeshUtilities::buildUnitQuadMesh(nCells , 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),e2(2); e1[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 = Function::constant(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() ); // omitting term to make IP non-dependent on u //////////////////////////////////////////////////////////////////// // 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 ); //////////////////////////////////////////////////////////////////// // 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<NullFilter> nullFilter = Teuchos::rcp(new NullFilter); // Teuchos::RCP<HessianFilter> hessianFilter = Teuchos::rcp(new HessianFilter(hessianBF)); Teuchos::RCP< LineSearchStep > LS_Step = Teuchos::rcp(new LineSearchStep(riesz)); double NL_residual = 9e99; for (int i = 0;i<numSteps;i++){ // write matrix to file and then resollve without hessian /* solution->setFilter(hessianFilter); stringstream oss; oss << "hessianMatrix" << i << ".dat"; solution->setWriteMatrixToFile(true,oss.str()); solution->solve(false); solution->setFilter(nullFilter); oss.str(""); // clear oss << "stiffnessMatrix" << i << ".dat"; solution->setWriteMatrixToFile(false,oss.str()); */ solution->solve(false); // do one solve to initialize things... double stepLength = 1.0; stepLength = LS_Step->stepSize(backgroundFlow,solution, NL_residual); // solution->setWriteMatrixToFile(true,"stiffness.dat"); backgroundFlow->addSolution(solution,stepLength); NL_residual = LS_Step->getNLResidual(); if (rank==0){ cout << "NL residual after adding = " << NL_residual << " with step size " << stepLength << endl; } double fd_gradient; for (int dofIndex = 0;dofIndex<mesh->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; } } } VTKExporter exporter(solution, mesh, varFactory); if (rank==0){ exporter.exportSolution("qopt"); cout << endl; } return 0; }
// tests residual computation on simple convection bool ScratchPadTests::testLTResidualSimple() { double tol = 1e-11; int rank = Teuchos::GlobalMPISession::getRank(); bool success = true; int nCells = 2; //////////////////// DECLARE VARIABLES /////////////////////// // define test variables VarFactoryPtr varFactory = VarFactory::varFactory(); VarPtr v = varFactory->testVar("v", HGRAD); // define trial variables VarPtr beta_n_u = varFactory->fluxVar("\\widehat{\\beta \\cdot n u - \\sigma_{n}}"); VarPtr u = varFactory->fieldVar("u"); vector<double> beta; beta.push_back(1.0); beta.push_back(1.0); //////////////////// DEFINE BILINEAR FORM /////////////////////// BFPtr confusionBF = Teuchos::rcp( new BF(varFactory) ); // v terms: confusionBF->addTerm( -u, beta * v->grad() ); confusionBF->addTerm( beta_n_u, v); //////////////////// DEFINE INNER PRODUCT(S) /////////////////////// // robust test norm IPPtr ip = Teuchos::rcp(new IP); // choose the mesh-independent norm even though it may have BLs ip->addTerm(v->grad()); ip->addTerm(v); //////////////////// SPECIFY RHS AND HELPFUL FUNCTIONS /////////////////////// FunctionPtr n = Function::normal(); vector<double> e1,e2; e1.push_back(1.0); e1.push_back(0.0); e2.push_back(0.0); e2.push_back(1.0); FunctionPtr one = Function::constant(1.0); FunctionPtr zero = Function::constant(0.0); RHSPtr rhs = RHS::rhs(); FunctionPtr f = one; rhs->addTerm( f * v ); //////////////////// CREATE BCs /////////////////////// BCPtr bc = BC::bc(); SpatialFilterPtr boundary = Teuchos::rcp( new InflowSquareBoundary ); FunctionPtr u_in = Teuchos::rcp(new Uinflow); bc->addDirichlet(beta_n_u, boundary, beta*n*u_in); //////////////////// BUILD MESH /////////////////////// // define nodes for mesh int order = 2; int H1Order = order+1; int pToAdd = 2; // create a pointer to a new mesh: Teuchos::RCP<Mesh> mesh = MeshUtilities::buildUnitQuadMesh(nCells,confusionBF, H1Order, H1Order+pToAdd); //////////////////// SOLVE & REFINE /////////////////////// int cubEnrich = 0; Teuchos::RCP<Solution> solution; solution = Teuchos::rcp( new Solution(mesh, bc, rhs, ip) ); solution->solve(false); double energyError = solution->energyErrorTotal(); LinearTermPtr residual = rhs->linearTermCopy(); residual->addTerm(-confusionBF->testFunctional(solution),true); Teuchos::RCP<RieszRep> rieszResidual = Teuchos::rcp(new RieszRep(mesh, ip, residual)); rieszResidual->computeRieszRep(cubEnrich); double energyErrorLT = rieszResidual->getNorm(); bool testVsTest = true; FunctionPtr e_v = RieszRep::repFunction(v,rieszResidual); map<int,FunctionPtr> errFxns; errFxns[v->ID()] = e_v; FunctionPtr err = (ip->evaluate(errFxns,false))->evaluate(errFxns,false); // don't need boundary terms unless they're in IP double energyErrorIntegrated = sqrt(err->integrate(mesh,cubEnrich,testVsTest)); // check that energy error computed thru Solution and through rieszRep are the same success = abs(energyError-energyErrorLT) < tol; if (success==false) { if (rank==0) cout << "Failed testLTResidualSimple; energy error = " << energyError << ", while linearTerm error is computed to be " << energyErrorLT << endl; return success; } // checks that matrix-computed and integrated errors are the same success = abs(energyErrorLT-energyErrorIntegrated)<tol; if (success==false) { if (rank==0) cout << "Failed testLTResidualSimple; energy error = " << energyError << ", while error computed via integration is " << energyErrorIntegrated << endl; return success; } return success; }
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 rank = Teuchos::GlobalMPISession::getRank(); int numProcs = Teuchos::GlobalMPISession::getNProc(); int nCells = args.Input<int>("--nCells", "num cells",2); int numRefs = args.Input<int>("--numRefs","num adaptive refinements",0); int numPreRefs = args.Input<int>("--numPreRefs","num preemptive adaptive refinements",0); int order = args.Input<int>("--order","order of approximation",2); double eps = args.Input<double>("--epsilon","diffusion parameter",1e-2); double energyThreshold = args.Input<double>("-energyThreshold","energy thresh for adaptivity", .5); double rampHeight = args.Input<double>("--rampHeight","ramp height at x = 2", 0.0); double ipSwitch = args.Input<double>("--ipSwitch","point at which to switch to graph norm", 0.0); // default to 0 to remain on robust norm bool useAnisotropy = args.Input<bool>("--useAnisotropy","aniso flag ", false); int H1Order = order+1; int pToAdd = args.Input<int>("--pToAdd","test space enrichment", 2); FunctionPtr zero = Function::constant(0.0); FunctionPtr one = Function::constant(1.0); FunctionPtr n = Teuchos::rcp( new UnitNormalFunction ); vector<double> e1,e2; e1.push_back(1.0);e1.push_back(0.0); e2.push_back(0.0);e2.push_back(1.0); //////////////////// 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("\\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"); vector<double> beta; beta.push_back(1.0); beta.push_back(0.0); //////////////////// DEFINE BILINEAR FORM /////////////////////// BFPtr confusionBF = Teuchos::rcp( new BF(varFactory) ); // tau terms: confusionBF->addTerm(sigma1 / eps, tau->x()); confusionBF->addTerm(sigma2 / eps, 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( -u, beta * v->grad() ); confusionBF->addTerm( beta_n_u_minus_sigma_n, v); // first order term with magnitude alpha double alpha = 0.0; // confusionBF->addTerm(alpha * u, v); //////////////////// BUILD MESH /////////////////////// // create a pointer to a new mesh: Teuchos::RCP<Mesh> mesh = MeshUtilities::buildUnitQuadMesh(nCells,confusionBF, H1Order, H1Order+pToAdd); mesh->setPartitionPolicy(Teuchos::rcp(new ZoltanMeshPartitionPolicy("HSFC"))); MeshInfo meshInfo(mesh); // gets info like cell measure, etc //////////////////// DEFINE INNER PRODUCT(S) /////////////////////// IPPtr ip = Teuchos::rcp(new IP); /* // robust test norm FunctionPtr C_h = Teuchos::rcp( new EpsilonScaling(eps) ); FunctionPtr invH = Teuchos::rcp(new InvHScaling); FunctionPtr invSqrtH = Teuchos::rcp(new InvSqrtHScaling); FunctionPtr sqrtH = Teuchos::rcp(new SqrtHScaling); FunctionPtr hSwitch = Teuchos::rcp(new HSwitch(ipSwitch,mesh)); ip->addTerm(hSwitch*sqrt(eps) * v->grad() ); ip->addTerm(hSwitch*beta * v->grad() ); ip->addTerm(hSwitch*tau->div() ); // graph norm ip->addTerm( (one-hSwitch)*((1.0/eps) * tau + v->grad())); ip->addTerm( (one-hSwitch)*(beta * v->grad() - tau->div())); // regularizing terms ip->addTerm(C_h/sqrt(eps) * tau ); ip->addTerm(invSqrtH*v); */ // robust test norm IPPtr robIP = Teuchos::rcp(new IP); FunctionPtr C_h = Teuchos::rcp( new EpsilonScaling(eps) ); FunctionPtr invH = Teuchos::rcp(new InvHScaling); FunctionPtr invSqrtH = Teuchos::rcp(new InvSqrtHScaling); FunctionPtr sqrtH = Teuchos::rcp(new SqrtHScaling); FunctionPtr hSwitch = Teuchos::rcp(new HSwitch(ipSwitch,mesh)); robIP->addTerm(sqrt(eps) * v->grad() ); robIP->addTerm(beta * v->grad() ); robIP->addTerm(tau->div() ); // regularizing terms robIP->addTerm(C_h/sqrt(eps) * tau ); robIP->addTerm(invSqrtH*v); IPPtr graphIP = confusionBF->graphNorm(); graphIP->addTerm(invSqrtH*v); // graphIP->addTerm(C_h/sqrt(eps) * tau ); IPPtr switchIP = Teuchos::rcp(new IPSwitcher(robIP,graphIP,ipSwitch)); // rob IP for h>ipSwitch mesh size, graph norm o/w ip = switchIP; LinearTermPtr vVecLT = Teuchos::rcp(new LinearTerm); LinearTermPtr tauVecLT = Teuchos::rcp(new LinearTerm); vVecLT->addTerm(sqrt(eps)*v->grad()); tauVecLT->addTerm(C_h/sqrt(eps)*tau); LinearTermPtr restLT = Teuchos::rcp(new LinearTerm); restLT->addTerm(alpha*v); restLT->addTerm(invSqrtH*v); restLT = restLT + beta * v->grad(); restLT = restLT + tau->div(); //////////////////// SPECIFY RHS /////////////////////// Teuchos::RCP<RHSEasy> rhs = Teuchos::rcp( new RHSEasy ); FunctionPtr f = zero; // f = one; 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 Inflow = Teuchos::rcp(new LeftInflow); SpatialFilterPtr wallBoundary = Teuchos::rcp(new WallBoundary);//MeshUtilities::rampBoundary(rampHeight); SpatialFilterPtr freeStream = Teuchos::rcp(new FreeStreamBoundary); bc->addDirichlet(uhat, wallBoundary, one); // bc->addDirichlet(uhat, wallBoundary, Teuchos::rcp(new WallSmoothBC(eps))); bc->addDirichlet(beta_n_u_minus_sigma_n, Inflow, zero); bc->addDirichlet(beta_n_u_minus_sigma_n, freeStream, zero); //////////////////// SOLVE & REFINE /////////////////////// Teuchos::RCP<Solution> solution; solution = Teuchos::rcp( new Solution(mesh, bc, rhs, ip) ); 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) ); mesh->registerSolution(backgroundFlow); // to trigger issue with p-refinements map<int, Teuchos::RCP<Function> > functionMap; functionMap[u->ID()] = Function::constant(3.14); backgroundFlow->projectOntoMesh(functionMap); // lower p to p = 1 at SINGULARITY only vector<int> ids; /* for (int i = 0;i<mesh->numActiveElements();i++){ bool cellIDset = false; int cellID = mesh->activeElements()[i]->cellID(); int elemOrder = mesh->cellPolyOrder(cellID)-1; FieldContainer<double> vv(4,2); mesh->verticesForCell(vv, cellID); bool vertexOnWall = false; bool vertexAtSingularity = false; for (int j = 0;j<4;j++){ if ((abs(vv(j,0)-.5) + abs(vv(j,1)))<1e-10){ vertexAtSingularity = true; cellIDset = true; } } if (!vertexAtSingularity && elemOrder<2 && !cellIDset ){ ids.push_back(cellID); cout << "celliD = " << cellID << endl; } } */ ids.push_back(1); ids.push_back(3); mesh->pRefine(ids); // to put order = 1 return 0; LinearTermPtr residual = rhs->linearTermCopy(); residual->addTerm(-confusionBF->testFunctional(solution)); RieszRepPtr rieszResidual = Teuchos::rcp(new RieszRep(mesh, ip, residual)); rieszResidual->computeRieszRep(); FunctionPtr e_v = Teuchos::rcp(new RepFunction(v,rieszResidual)); FunctionPtr e_tau = Teuchos::rcp(new RepFunction(tau,rieszResidual)); map<int,FunctionPtr> errRepMap; errRepMap[v->ID()] = e_v; errRepMap[tau->ID()] = e_tau; FunctionPtr errTau = tauVecLT->evaluate(errRepMap,false); FunctionPtr errV = vVecLT->evaluate(errRepMap,false); FunctionPtr errRest = restLT->evaluate(errRepMap,false); FunctionPtr xErr = (errTau->x())*(errTau->x()) + (errV->dx())*(errV->dx()); FunctionPtr yErr = (errTau->y())*(errTau->y()) + (errV->dy())*(errV->dy()); FunctionPtr restErr = errRest*errRest; RefinementStrategy refinementStrategy( solution, energyThreshold ); //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // PRE REFINEMENTS //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// if (rank==0){ cout << "Number of pre-refinements = " << numPreRefs << endl; } for (int i =0;i<=numPreRefs;i++){ vector<ElementPtr> elems = mesh->activeElements(); vector<ElementPtr>::iterator elemIt; vector<int> wallCells; for (elemIt=elems.begin();elemIt != elems.end();elemIt++){ int cellID = (*elemIt)->cellID(); int numSides = mesh->getElement(cellID)->numSides(); FieldContainer<double> vertices(numSides,2); //for quads mesh->verticesForCell(vertices, cellID); bool cellIDset = false; for (int j = 0;j<numSides;j++){ if ((abs(vertices(j,0)-.5)<1e-7) && (abs(vertices(j,1))<1e-7) && !cellIDset){ // if at singularity, i.e. if a vertex is (1,0) wallCells.push_back(cellID); cellIDset = true; } } } if (i<numPreRefs){ refinementStrategy.refineCells(wallCells); } } double minSideLength = meshInfo.getMinCellSideLength() ; double minCellMeasure = meshInfo.getMinCellMeasure() ; if (rank==0){ cout << "after prerefs, sqrt min cell measure = " << sqrt(minCellMeasure) << ", min side length = " << minSideLength << endl; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// VTKExporter exporter(solution, mesh, varFactory); for (int refIndex=0;refIndex<numRefs;refIndex++){ if (rank==0){ cout << "on ref index " << refIndex << endl; } rieszResidual->computeRieszRep(); // in preparation to get anisotropy vector<int> cellIDs; refinementStrategy.getCellsAboveErrorThreshhold(cellIDs); map<int,double> energyError = solution->energyError(); map<int,double> xErrMap = xErr->cellIntegrals(cellIDs,mesh,5,true); map<int,double> yErrMap = yErr->cellIntegrals(cellIDs,mesh,5,true); map<int,double> restErrMap = restErr->cellIntegrals(cellIDs,mesh,5,true); for (vector<ElementPtr>::iterator elemIt = mesh->activeElements().begin();elemIt!=mesh->activeElements().end();elemIt++){ int cellID = (*elemIt)->cellID(); double err = xErrMap[cellID]+ yErrMap[cellID] + restErrMap[cellID]; // if (rank==0) // cout << "err thru LT = " << sqrt(err) << ", while energy err = " << energyError[cellID] << endl; } /* map<int,double> ratio,xErr,yErr; vector<ElementPtr> elems = mesh->activeElements(); for (vector<ElementPtr>::iterator elemIt = elems.begin();elemIt!=elems.end();elemIt++){ int cellID = (*elemIt)->cellID(); ratio[cellID] = 0.0; xErr[cellID] = 0.0; yErr[cellID] = 0.0; if (std::find(cellIDs.begin(),cellIDs.end(),cellID)!=cellIDs.end()){ // if this cell is above energy thresh ratio[cellID] = yErrMap[cellID]/xErrMap[cellID]; xErr[cellID] = xErrMap[cellID]; yErr[cellID] = yErrMap[cellID]; } } FunctionPtr ratioFxn = Teuchos::rcp(new EnergyErrorFunction(ratio)); FunctionPtr xErrFxn = Teuchos::rcp(new EnergyErrorFunction(xErr)); FunctionPtr yErrFxn = Teuchos::rcp(new EnergyErrorFunction(yErr)); exporter.exportFunction(ratioFxn, string("ratio")+oss.str()); exporter.exportFunction(xErrFxn, string("xErr")+oss.str()); exporter.exportFunction(yErrFxn, string("yErr")+oss.str()); */ if (useAnisotropy){ refinementStrategy.refine(rank==0,xErrMap,yErrMap); //anisotropic refinements }else{ refinementStrategy.refine(rank==0); // no anisotropy } // lower p to p = 1 at SINGULARITY only vector<int> ids; for (int i = 0;i<mesh->numActiveElements();i++){ int cellID = mesh->activeElements()[i]->cellID(); int elemOrder = mesh->cellPolyOrder(cellID)-1; FieldContainer<double> vv(4,2); mesh->verticesForCell(vv, cellID); bool vertexOnWall = false; bool vertexAtSingularity = false; for (int j = 0;j<4;j++){ if ((abs(vv(j,0)-.5) + abs(vv(j,1)))<1e-10) vertexAtSingularity = true; } if (!vertexAtSingularity && elemOrder<2){ ids.push_back(cellID); } } mesh->pRefine(ids); // to put order = 1 /* if (elemOrder>1){ if (vertexAtSingularity){ vector<int> ids; ids.push_back(cellID); mesh->pRefine(ids,1-(elemOrder-1)); // to put order = 1 // mesh->pRefine(ids); // to put order = 1 if (rank==0) cout << "p unrefining elem with elemOrder = " << elemOrder << endl; } }else{ if (!vertexAtSingularity){ vector<int> ids; ids.push_back(cellID); mesh->pRefine(ids,2-elemOrder); } } */ double minSideLength = meshInfo.getMinCellSideLength() ; if (rank==0) cout << "minSideLength is " << minSideLength << endl; solution->condensedSolve(); std::ostringstream oss; oss << refIndex; } // final solve on final mesh solution->setWriteMatrixToFile(true,"K.mat"); solution->condensedSolve(); //////////////////////////////////////////////////////////////////////////////////////////////////////////// // CHECK CONDITIONING //////////////////////////////////////////////////////////////////////////////////////////////////////////// bool checkConditioning = true; if (checkConditioning){ double minSideLength = meshInfo.getMinCellSideLength() ; StandardAssembler assembler(solution); double maxCond = 0.0; int maxCellID = 0; for (int i = 0;i<mesh->numActiveElements();i++){ int cellID = mesh->getActiveElement(i)->cellID(); FieldContainer<double> ipMat = assembler.getIPMatrix(mesh->getElement(cellID)); double cond = SerialDenseWrapper::getMatrixConditionNumber(ipMat); if (cond>maxCond){ maxCond = cond; maxCellID = cellID; } } if (rank==0){ cout << "cell ID " << maxCellID << " has minCellLength " << minSideLength << " and condition estimate " << maxCond << endl; } string ipMatName = string("ipMat.mat"); ElementPtr maxCondElem = mesh->getElement(maxCellID); FieldContainer<double> ipMat = assembler.getIPMatrix(maxCondElem); SerialDenseWrapper::writeMatrixToMatlabFile(ipMatName,ipMat); } //////////////////// print to file /////////////////////// if (rank==0){ exporter.exportSolution(string("robustIP")); cout << endl; } return 0; }
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 = 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; }
bool ScratchPadTests::testResidualMemoryError() { int rank = Teuchos::GlobalMPISession::getRank(); double tol = 1e-11; bool success = true; int nCells = 2; double eps = 1e-2; //////////////////// DECLARE VARIABLES /////////////////////// // define test variables VarFactoryPtr varFactory = VarFactory::varFactory(); VarPtr tau = varFactory->testVar("\\tau", HDIV); VarPtr v = varFactory->testVar("v", HGRAD); // define 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"); vector<double> beta; beta.push_back(1.0); beta.push_back(0.0); //////////////////// DEFINE BILINEAR FORM /////////////////////// BFPtr confusionBF = Teuchos::rcp( new BF(varFactory) ); // tau terms: confusionBF->addTerm(sigma1 / eps, tau->x()); confusionBF->addTerm(sigma2 / eps, 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( -u, beta * v->grad() ); confusionBF->addTerm( beta_n_u_minus_sigma_n, v); //////////////////// DEFINE INNER PRODUCT(S) /////////////////////// // robust test norm IPPtr robIP = Teuchos::rcp(new IP); robIP->addTerm(tau); robIP->addTerm(tau->div()); robIP->addTerm(v->grad()); robIP->addTerm(v); //////////////////// SPECIFY RHS /////////////////////// FunctionPtr zero = Function::constant(0.0); FunctionPtr one = Function::constant(1.0); RHSPtr rhs = RHS::rhs(); FunctionPtr f = zero; // FunctionPtr f = one; rhs->addTerm( f * v ); // obviously, with f = 0 adding this term is not necessary! //////////////////// CREATE BCs /////////////////////// BCPtr bc = BC::bc(); SpatialFilterPtr inflowBoundary = Teuchos::rcp( new LRInflowSquareBoundary ); SpatialFilterPtr outflowBoundary = Teuchos::rcp( new LROutflowSquareBoundary); FunctionPtr n = Function::normal(); vector<double> e1,e2; e1.push_back(1.0); e1.push_back(0.0); e2.push_back(0.0); e2.push_back(1.0); bc->addDirichlet(beta_n_u_minus_sigma_n, inflowBoundary, beta*n*one); bc->addDirichlet(uhat, outflowBoundary, zero); //////////////////// BUILD MESH /////////////////////// // define nodes for mesh int order = 2; int H1Order = order+1; int pToAdd = 2; // create a pointer to a new mesh: Teuchos::RCP<Mesh> mesh = MeshUtilities::buildUnitQuadMesh(nCells,confusionBF, H1Order, H1Order+pToAdd); // mesh->setPartitionPolicy(Teuchos::rcp(new ZoltanMeshPartitionPolicy("HSFC"))); //////////////////// SOLVE & REFINE /////////////////////// Teuchos::RCP<Solution> solution; solution = Teuchos::rcp( new Solution(mesh, bc, rhs, robIP) ); solution->solve(false); mesh->registerSolution(solution); double energyErr1 = solution->energyErrorTotal(); LinearTermPtr residual = rhs->linearTermCopy(); residual->addTerm(-confusionBF->testFunctional(solution)); RieszRepPtr rieszResidual = Teuchos::rcp(new RieszRep(mesh, robIP, residual)); rieszResidual->computeRieszRep(); FunctionPtr e_v = RieszRep::repFunction(v,rieszResidual); FunctionPtr e_tau = RieszRep::repFunction(tau,rieszResidual); double energyThreshold = 0.2; // for mesh refinements RefinementStrategy refinementStrategy( solution, energyThreshold ); refinementStrategy.refine(); solution->solve(false); double energyErr2 = solution->energyErrorTotal(); // if energy error rises if (energyErr1 < energyErr2) { if (rank==0) cout << "energy error increased from " << energyErr1 << " to " << energyErr2 << " after refinement.\n"; success = false; } return success; }
bool LinearTermTests::testBoundaryPlusVolumeTerms() { bool success = true; // notion is integration by parts: // (div f, v) = < f * n, v > - (f, grad v) // We perform two subtests for each test: first we try with a particular // function substituted for the variable. Second, we integrate over the // basis for the mesh (i.e. we test a whole bunch of functions, whose // precise definition is a bit complicated). // A third test is against the two-term LinearTerm::integrate() method. // This doesn't do integration by parts, but rather tests that // (u + u->dot_normal(), v) = (u,v) + (u->dot_normal(), v) ///////////// FIRST TEST //////////////// // start simply: define f to be (x, 0) // (div f, v) = (1, v) // < f * n, v > - (f, grad v) = < x n1, v > - ( x, v->dx() ) FunctionPtr x = Function::xn(1); FunctionPtr y = Function::yn(1); FunctionPtr x2 = Function::xn(2); FunctionPtr y2 = Function::yn(2); FunctionPtr x3 = Function::xn(3); FunctionPtr y3 = Function::yn(3); vector< FunctionPtr > f_fxns; f_fxns.push_back( Function::vectorize( x, Function::zero() ) ); // div of this = 1 f_fxns.push_back( Function::vectorize( x2 / 6.0, x2 * y / 2.0 ) ); // div of this = x / 3 + x^2 / 2 for ( vector< FunctionPtr >::iterator fIt = f_fxns.begin(); fIt != f_fxns.end(); fIt++) { FunctionPtr vector_fxn = *fIt; LinearTermPtr lt_v = vector_fxn->div()*v1; // part a: substitute v1 = x*y^2 FunctionPtr v1_value = x*y2; map< int, FunctionPtr > var_values; var_values[v1->ID()] = v1_value; double expectedValue = lt_v->evaluate(var_values, false)->integrate(mesh); FunctionPtr n = Function::normal(); LinearTermPtr ibp = vector_fxn * n * v1 - vector_fxn * v1->grad(); int numCells = basisCache->getPhysicalCubaturePoints().dimension(0); int numPoints = basisCache->getPhysicalCubaturePoints().dimension(1); int spaceDim = basisCache->getSpaceDim(); FieldContainer<double> vector_fxn_values(numCells,numPoints,spaceDim); vector_fxn->values(vector_fxn_values,basisCache); // cout << "vector_fxn values: \n" << vector_fxn_values; double boundaryIntegralSum = ibp->evaluate(var_values,true)->integrate(mesh); double volumeIntegralSum = ibp->evaluate(var_values,false)->integrate(mesh); double actualValue = boundaryIntegralSum + volumeIntegralSum; double tol = 1e-14; if (abs(expectedValue - actualValue)>tol) { success = false; } // part b: integrate the bases over each of the cells: int num_dofs = testOrder->totalDofs(); FieldContainer<double> integrals_expected( mesh->numActiveElements(), num_dofs ); FieldContainer<double> integrals_actual( mesh->numActiveElements(), num_dofs ); lt_v->integrate(integrals_expected,testOrder,basisCache); ibp->integrate(integrals_actual,testOrder,basisCache); double maxDiff = 0; if (! fcsAgree(integrals_actual, integrals_expected, tol, maxDiff) ) { cout << "LT integrated by parts does not agree with the original; maxDiff: " << maxDiff << endl; success = false; } // just on the odd chance that ordering makes a difference, repeat this test with the opposite order in ibp: ibp = - vector_fxn * v1->grad() + vector_fxn * n * v1; ibp->integrate(integrals_actual,testOrder,basisCache, false, false); maxDiff = 0; if (! fcsAgree(integrals_actual, integrals_expected, tol, maxDiff) ) { cout << "LT integrated by parts does not agree with the original; maxDiff: " << maxDiff << endl; success = false; } // part c: two-term integrals FieldContainer<double> integrals_expected_two_term( mesh->numActiveElements(), num_dofs, num_dofs); FieldContainer<double> integrals_actual_two_term( mesh->numActiveElements(), num_dofs, num_dofs ); LinearTermPtr ibp1 = vector_fxn * n * v1; LinearTermPtr ibp2 = - vector_fxn * v1->grad(); lt_v->integrate(integrals_expected_two_term, testOrder, ibp1 + ibp2, testOrder, basisCache, false, false); lt_v->integrate(integrals_actual_two_term, testOrder, ibp1, testOrder, basisCache, false, false); // don't forceBoundary, don't sumInto lt_v->integrate(integrals_actual_two_term, testOrder, ibp2, testOrder, basisCache, false, true); // DO sumInto maxDiff = 0; if (! fcsAgree(integrals_actual_two_term, integrals_expected_two_term, tol, maxDiff) ) { cout << "two-term integration is not bilinear; maxDiff: " << maxDiff << endl; success = false; } // now, same thing but with the roles of ibp{1|2} and lt_v reversed: (ibp1 + ibp2)->integrate(integrals_expected_two_term, testOrder, lt_v, testOrder, basisCache, false, false); ibp1->integrate(integrals_actual_two_term, testOrder, lt_v, testOrder, basisCache, false, false); // don't forceBoundary, don't sumInto ibp2->integrate(integrals_actual_two_term, testOrder, lt_v, testOrder, basisCache, false, true); // DO sumInto maxDiff = 0; if (! fcsAgree(integrals_actual_two_term, integrals_expected_two_term, tol, maxDiff) ) { cout << "two-term integration is not bilinear; maxDiff: " << maxDiff << endl; success = false; } // now, test that two-term integration commutes in the two terms: ibp1->integrate(integrals_expected_two_term, testOrder, lt_v, testOrder, basisCache, false, false); lt_v->integrate(integrals_actual_two_term, testOrder, ibp1, testOrder, basisCache, false, false); // we expect the integrals to commute up to a transpose, so let's transpose one of the containers: transposeFieldContainer(integrals_expected_two_term); maxDiff = 0; if (! fcsAgree(integrals_actual_two_term, integrals_expected_two_term, tol, maxDiff) ) { cout << "two-term integration does not commute for boundary value (ibp1); maxDiff: " << maxDiff << endl; success = false; } ibp2->integrate(integrals_expected_two_term, testOrder, lt_v, testOrder, basisCache, false, false); lt_v->integrate(integrals_actual_two_term, testOrder, ibp2, testOrder, basisCache, false, false); // we expect the integrals to commute up to a transpose, so let's transpose one of the containers: transposeFieldContainer(integrals_expected_two_term); maxDiff = 0; if (! fcsAgree(integrals_actual_two_term, integrals_expected_two_term, tol, maxDiff) ) { cout << "two-term integration does not commute for volume value (ibp2); maxDiff: " << maxDiff << endl; success = false; } // part d: to suss out where the integration failure happens in the non-commuting case: // 1. Substitute v1 = 1 in ibp2; get a function ibp2_at_v1_equals_one back. // 2. Substitute v1 = 1 in lt_v; get a function lt_v_at_v1_equals_one back. // 3. Integrate ibp2_at_v1_equals_one * lt_v_at_v1_equals_one over the mesh. Get a double result. // 4. Because basis is nodal, the representation for v1 = 1 is just all 1s for coefficients. // Therefore, the sum of the entries in the integrals_*_two_term matrices will should match // the function integral. Whichever doesn't match is wrong. // first, let's confirm that the v1 basis *is* nodal: BasisPtr v1Basis = testOrder->getBasis(v1->ID()); if (! v1Basis->isNodal()) { cout << "testBoundaryPlusVolumeTerms: final part of test relies on a nodal basis, but the basis is not nodal."; cout << " Exiting test early (with whatever success value we have thus far).\n"; return success; } map< int, FunctionPtr > v1_equals_one; v1_equals_one[v1->ID()] = Function::constant(1.0); FunctionPtr ibp1_at_v1_equals_one = ibp1->evaluate(v1_equals_one,true); // ibp1 has only a boundary term, so we just ask for this FunctionPtr ibp2_at_v1_equals_one = ibp2->evaluate(v1_equals_one,false); // ibp2 has no boundary terms, so we don't ask for these FunctionPtr lt_v_at_v1_equals_one = lt_v->evaluate(v1_equals_one,false); // lt_v also has no boundary terms if (ibp1_at_v1_equals_one->isZero()) { cout << "ibp1_at_v1_equals_one->isZero() = true.\n"; } if (lt_v_at_v1_equals_one->isZero()) { cout << "lt_v_at_v1_equals_one->isZero() = true.\n"; } FieldContainer<double> integrals_lt_v_first( mesh->numActiveElements(), num_dofs, num_dofs ); FieldContainer<double> integrals_ibp1_first( mesh->numActiveElements(), num_dofs, num_dofs ); FieldContainer<double> integrals_ibp2_first( mesh->numActiveElements(), num_dofs, num_dofs ); double lt_v_first_integral = 0.0, ibp1_first_integral = 0.0, ibp2_first_integral = 0.0; double integral = (ibp1_at_v1_equals_one * lt_v_at_v1_equals_one)->integrate(mesh); ibp1->integrate(integrals_ibp1_first, testOrder, lt_v, testOrder, basisCache, false, false); lt_v->integrate(integrals_lt_v_first, testOrder, ibp1, testOrder, basisCache, false, false); for (int i=0; i<integrals_lt_v_first.size(); i++) { lt_v_first_integral += integrals_lt_v_first[i]; ibp1_first_integral += integrals_ibp1_first[i]; } if (abs(lt_v_first_integral - integral) > tol) { double diff = abs(lt_v_first_integral - integral); success = false; cout << "Integral with v1=1 substituted does not match two-term integration of (lt_v,ibp1) with lt_v as this. diff = " << diff << "\n"; cout << "lt_v_first_integral = " << lt_v_first_integral << endl; cout << " (true) integral = " << integral << endl; } if (abs(ibp1_first_integral - integral) > tol) { double diff = abs(ibp1_first_integral - integral); success = false; cout << "Integral with v1=1 substituted does not match two-term integration of (lt_v,ibp1) with ibp1 as this. diff = " << diff << "\n"; cout << "ibp1_first_integral = " << ibp1_first_integral << endl; cout << " (true) integral = " << integral << endl; } // now, do the same but for ibp2 integral = (ibp2_at_v1_equals_one * lt_v_at_v1_equals_one)->integrate(mesh); ibp2->integrate(integrals_ibp2_first, testOrder, lt_v, testOrder, basisCache, false, false); lt_v->integrate(integrals_lt_v_first, testOrder, ibp2, testOrder, basisCache, false, false); // reset the sums: lt_v_first_integral = 0.0; ibp1_first_integral = 0.0; ibp2_first_integral = 0.0; for (int i=0; i<integrals_lt_v_first.size(); i++) { lt_v_first_integral += integrals_lt_v_first[i]; ibp2_first_integral += integrals_ibp2_first[i]; } if (abs(lt_v_first_integral - integral) > tol) { double diff = abs(lt_v_first_integral - integral); success = false; cout << "Integral with v1=1 substituted does not match two-term integration of (lt_v,ibp2) with lt_v as this. diff = " << diff << "\n"; cout << "lt_v_first_integral = " << lt_v_first_integral << endl; cout << " (true) integral = " << integral << endl; } if (abs(ibp2_first_integral - integral) > tol) { double diff = abs(ibp2_first_integral - integral); success = false; cout << "Integral with v1=1 substituted does not match two-term integration of (lt_v,ibp2) with ibp2 as this. diff = " << diff << "\n"; cout << "ibp1_first_integral = " << ibp1_first_integral << endl; cout << " (true) integral = " << integral << endl; } } return success; }
bool LinearTermTests::testSums() { bool success = true; LinearTermPtr sum = v1 + v2; if (sum->summands().size() != 2) { success = false; cout << "sum has the wrong number of summands\n"; return success; } LinearSummand first_summand = sum->summands()[0]; LinearSummand second_summand = sum->summands()[1]; VarPtr first_var = first_summand.second; Camellia::EOperator first_op = first_var->op(); VarPtr second_var = second_summand.second; Camellia::EOperator second_op = second_var->op(); if (first_var->ID() != v1->ID()) { success = false; cout << "first summand isn't v1.\n"; } if (first_var->op() != OP_VALUE) { success = false; cout << "first op isn't VALUE.\n"; } if (second_var->ID() != v2->ID()) { success = false; cout << "second summand isn't v2 (is named " << second_var->name() << ").\n"; } if (second_var->op() != OP_VALUE) { success = false; cout << "second op isn't VALUE.\n"; } // check that sum reports having both varIDs if (sum->varIDs().find(v1->ID()) == sum->varIDs().end()) { cout << "sum->varIDs() doesn't include v1.\n"; success = false; } if (sum->varIDs().find(v2->ID()) == sum->varIDs().end()) { cout << "sum->varIDs() doesn't include v2.\n"; success = false; } if (sum->varIDs().size() != 2) { cout << "sum->varIDs() doesn't have the expected size (expected 2; is " << sum->varIDs().size() << ").\n"; success = false; } // TODO: check that the sum is correct return success; }
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; }
// tests to make sure that the rieszNorm computed via matrices is the same as the one computed thru direct integration bool ScratchPadTests::testRieszIntegration() { double tol = 1e-11; bool success = true; int nCells = 2; double eps = .25; //////////////////// DECLARE VARIABLES /////////////////////// // define test variables VarFactoryPtr varFactory = VarFactory::varFactory(); VarPtr tau = varFactory->testVar("\\tau", HDIV); VarPtr v = varFactory->testVar("v", HGRAD); // define 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"); vector<double> beta; beta.push_back(1.0); beta.push_back(0.0); //////////////////// DEFINE BILINEAR FORM /////////////////////// BFPtr confusionBF = Teuchos::rcp( new BF(varFactory) ); // tau terms: confusionBF->addTerm(sigma1 / eps, tau->x()); confusionBF->addTerm(sigma2 / eps, 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( -u, beta * v->grad() ); confusionBF->addTerm( beta_n_u_minus_sigma_n, v); //////////////////// DEFINE INNER PRODUCT(S) /////////////////////// // robust test norm IPPtr ip = Teuchos::rcp(new IP); // just H1 projection ip->addTerm(v->grad()); ip->addTerm(v); ip->addTerm(tau); ip->addTerm(tau->div()); //////////////////// SPECIFY RHS AND HELPFUL FUNCTIONS /////////////////////// FunctionPtr n = Function::normal(); vector<double> e1,e2; e1.push_back(1.0); e1.push_back(0.0); e2.push_back(0.0); e2.push_back(1.0); FunctionPtr one = Function::constant(1.0); FunctionPtr zero = Function::constant(0.0); RHSPtr rhs = RHS::rhs(); FunctionPtr f = one; rhs->addTerm( f * v ); // obviously, with f = 0 adding this term is not necessary! //////////////////// CREATE BCs /////////////////////// BCPtr bc = BC::bc(); SpatialFilterPtr squareBoundary = Teuchos::rcp( new SquareBoundary ); bc->addDirichlet(uhat, squareBoundary, zero); //////////////////// BUILD MESH /////////////////////// // define nodes for mesh int order = 2; int H1Order = order+1; int pToAdd = 2; // create a pointer to a new mesh: Teuchos::RCP<Mesh> mesh = MeshUtilities::buildUnitQuadMesh(nCells,confusionBF, H1Order, H1Order+pToAdd); //////////////////// SOLVE & REFINE /////////////////////// LinearTermPtr lt = Teuchos::rcp(new LinearTerm); FunctionPtr fxn = Function::xn(1); // fxn = x lt->addTerm(fxn*v + fxn->grad()*v->grad()); lt->addTerm(fxn*tau->x() + fxn*tau->y() + (fxn->dx() + fxn->dy())*tau->div()); Teuchos::RCP<RieszRep> rieszLT = Teuchos::rcp(new RieszRep(mesh, ip, lt)); rieszLT->computeRieszRep(); double rieszNorm = rieszLT->getNorm(); FunctionPtr e_v = RieszRep::repFunction(v,rieszLT); FunctionPtr e_tau = RieszRep::repFunction(tau,rieszLT); map<int,FunctionPtr> repFxns; repFxns[v->ID()] = e_v; repFxns[tau->ID()] = e_tau; double integratedNorm = sqrt((lt->evaluate(repFxns,false))->integrate(mesh,5,true)); success = abs(rieszNorm-integratedNorm)<tol; if (success==false) { cout << "Failed testRieszIntegration; riesz norm is computed to be = " << rieszNorm << ", while using integration it's computed to be " << integratedNorm << endl; return success; } return success; }
bool ScratchPadTests::testGalerkinOrthogonality() { double tol = 1e-11; bool success = true; //////////////////// DECLARE VARIABLES /////////////////////// // define test variables VarFactoryPtr varFactory = VarFactory::varFactory(); VarPtr v = varFactory->testVar("v", HGRAD); vector<double> beta; beta.push_back(1.0); beta.push_back(1.0); //////////////////// DEFINE INNER PRODUCT(S) /////////////////////// // robust test norm IPPtr ip = Teuchos::rcp(new IP); ip->addTerm(v); ip->addTerm(beta*v->grad()); // define trial variables VarPtr beta_n_u = varFactory->fluxVar("\\widehat{\\beta \\cdot n }"); VarPtr u = varFactory->fieldVar("u"); //////////////////// BUILD MESH /////////////////////// BFPtr convectionBF = Teuchos::rcp( new BF(varFactory) ); FunctionPtr n = Function::normal(); // v terms: convectionBF->addTerm( -u, beta * v->grad() ); convectionBF->addTerm( beta_n_u, v); // define nodes for mesh int order = 2; int H1Order = order+1; int pToAdd = 1; // create a pointer to a new mesh: Teuchos::RCP<Mesh> mesh = MeshUtilities::buildUnitQuadMesh(4, convectionBF, H1Order, H1Order+pToAdd); //////////////////// SOLVE /////////////////////// RHSPtr rhs = RHS::rhs(); BCPtr bc = BC::bc(); SpatialFilterPtr inflowBoundary = Teuchos::rcp( new InflowSquareBoundary ); SpatialFilterPtr outflowBoundary = Teuchos::rcp( new NegatedSpatialFilter(inflowBoundary) ); FunctionPtr uIn; uIn = Teuchos::rcp(new Uinflow); // uses a discontinuous piecewise-constant basis function on left and bottom sides of square bc->addDirichlet(beta_n_u, inflowBoundary, beta*n*uIn); Teuchos::RCP<Solution> solution; solution = Teuchos::rcp( new Solution(mesh, bc, rhs, ip) ); solution->solve(false); FunctionPtr uFxn = Function::solution(u, solution); FunctionPtr fnhatFxn = Function::solution(beta_n_u,solution); // make residual for riesz representation function LinearTermPtr residual = Teuchos::rcp(new LinearTerm);// residual FunctionPtr parity = Function::sideParity(); residual->addTerm(-fnhatFxn*v + (beta*uFxn)*v->grad()); Teuchos::RCP<RieszRep> riesz = Teuchos::rcp(new RieszRep(mesh, ip, residual)); riesz->computeRieszRep(); map<int,FunctionPtr> err_rep_map; err_rep_map[v->ID()] = RieszRep::repFunction(v,riesz); //////////////////// GET BOUNDARY CONDITION DATA /////////////////////// FieldContainer<GlobalIndexType> bcGlobalIndices; FieldContainer<double> bcGlobalValues; mesh->boundary().bcsToImpose(bcGlobalIndices,bcGlobalValues,*(solution->bc()), NULL); set<int> bcInds; for (int i=0; i<bcGlobalIndices.dimension(0); i++) { bcInds.insert(bcGlobalIndices(i)); } //////////////////// CHECK GALERKIN ORTHOGONALITY /////////////////////// BCPtr nullBC; RHSPtr nullRHS; IPPtr nullIP; SolutionPtr solnPerturbation = Teuchos::rcp(new Solution(mesh, nullBC, nullRHS, nullIP) ); map< int, vector<DofInfo> > infoMap = constructGlobalDofToLocalDofInfoMap(mesh); for (map< int, vector<DofInfo> >::iterator mapIt = infoMap.begin(); mapIt != infoMap.end(); mapIt++) { int dofIndex = mapIt->first; vector< DofInfo > dofInfoVector = mapIt->second; // all the local dofs that map to dofIndex // create perturbation in direction du solnPerturbation->clear(); // clear all solns // set each corresponding local dof to 1.0 for (vector< DofInfo >::iterator dofInfoIt = dofInfoVector.begin(); dofInfoIt != dofInfoVector.end(); dofInfoIt++) { DofInfo info = *dofInfoIt; FieldContainer<double> solnCoeffs(info.basisCardinality); solnCoeffs(info.basisOrdinal) = 1.0; solnPerturbation->setSolnCoeffsForCellID(solnCoeffs, info.cellID, info.trialID, info.sideIndex); } // solnPerturbation->setSolnCoeffForGlobalDofIndex(1.0,dofIndex); LinearTermPtr b_du = convectionBF->testFunctional(solnPerturbation); FunctionPtr gradient = b_du->evaluate(err_rep_map, TestingUtilities::isFluxOrTraceDof(mesh,dofIndex)); // use boundary part only if flux double grad = gradient->integrate(mesh,10); if (!TestingUtilities::isFluxOrTraceDof(mesh,dofIndex) && abs(grad)>tol) // if we're not single-precision zero FOR FIELDS { // int cellID = mesh->getGlobalToLocalMap()[dofIndex].first; cout << "Failed testGalerkinOrthogonality() for fields with diff " << abs(grad) << " at dof " << dofIndex << "; info:" << endl; cout << dofInfoString(infoMap[dofIndex]); success = false; } } FieldContainer<double> errorJumps(mesh->numGlobalDofs()); //initialized to zero // just test fluxes ON INTERNAL SKELETON here set<GlobalIndexType> activeCellIDs = mesh->getActiveCellIDsGlobal(); for (GlobalIndexType activeCellID : activeCellIDs) { ElementPtr elem = mesh->getElement(activeCellID); for (int sideIndex = 0; sideIndex < 4; sideIndex++) { ElementTypePtr elemType = elem->elementType(); vector<int> localDofIndices = elemType->trialOrderPtr->getDofIndices(beta_n_u->ID(), sideIndex); for (int i = 0; i<localDofIndices.size(); i++) { int globalDofIndex = mesh->globalDofIndex(elem->cellID(), localDofIndices[i]); vector< DofInfo > dofInfoVector = infoMap[globalDofIndex]; solnPerturbation->clear(); TestingUtilities::setSolnCoeffForGlobalDofIndex(solnPerturbation,1.0,globalDofIndex); // also add in BCs for (int i = 0; i<bcGlobalIndices.dimension(0); i++) { TestingUtilities::setSolnCoeffForGlobalDofIndex(solnPerturbation,bcGlobalValues(i),bcGlobalIndices(i)); } LinearTermPtr b_du = convectionBF->testFunctional(solnPerturbation); FunctionPtr gradient = b_du->evaluate(err_rep_map, TestingUtilities::isFluxOrTraceDof(mesh,globalDofIndex)); // use boundary part only if flux double jump = gradient->integrate(mesh,10); errorJumps(globalDofIndex) += jump; } } } for (int i = 0; i<mesh->numGlobalDofs(); i++) { if (abs(errorJumps(i))>tol) { cout << "Failing Galerkin orthogonality test for fluxes with diff " << errorJumps(i) << " at dof " << i << endl; cout << dofInfoString(infoMap[i]); success = false; } } return success; }
// tests whether a mixed type LT bool ScratchPadTests::testIntegrateDiscontinuousFunction() { bool success = true; //////////////////// DECLARE VARIABLES /////////////////////// // define test variables VarFactoryPtr varFactory = VarFactory::varFactory(); VarPtr v = varFactory->testVar("v", HGRAD); vector<double> beta; beta.push_back(1.0); beta.push_back(1.0); //////////////////// DEFINE INNER PRODUCT(S) /////////////////////// // robust test norm IPPtr ip = Teuchos::rcp(new IP); ip->addTerm(v); ip->addTerm(beta*v->grad()); // for projections IPPtr ipL2 = Teuchos::rcp(new IP); ipL2->addTerm(v); // define trial variables VarPtr beta_n_u = varFactory->fluxVar("\\widehat{\\beta \\cdot n }"); VarPtr u = varFactory->fieldVar("u"); //////////////////// BUILD MESH /////////////////////// BFPtr convectionBF = Teuchos::rcp( new BF(varFactory) ); // v terms: convectionBF->addTerm( -u, beta * v->grad() ); convectionBF->addTerm( beta_n_u, v); // define nodes for mesh int order = 1; int H1Order = order+1; int pToAdd = 1; // create a pointer to a new mesh: Teuchos::RCP<Mesh> mesh = MeshUtilities::buildUnitQuadMesh(2, 1, convectionBF, H1Order, H1Order+pToAdd); //////////////////// integrate discontinuous function - cellIDFunction /////////////////////// // FunctionPtr cellIDFxn = Teuchos::rcp(new CellIDFunction); // should be 0 on cellID 0, 1 on cellID 1 set<int> cellIDs; cellIDs.insert(1); // 0 on cell 0, 1 on cell 1 FunctionPtr indicator = Teuchos::rcp(new IndicatorFunction(cellIDs)); // should be 0 on cellID 0, 1 on cellID 1 double jumpWeight = 13.3; // some random number FunctionPtr edgeRestrictionFxn = Teuchos::rcp(new EdgeFunction); FunctionPtr X = Function::xn(1); LinearTermPtr integrandLT = Function::constant(1.0)*v + Function::constant(jumpWeight)*X*edgeRestrictionFxn*v; // make riesz representation function to more closely emulate the error rep LinearTermPtr indicatorLT = Teuchos::rcp(new LinearTerm);// residual indicatorLT->addTerm(indicator*v); Teuchos::RCP<RieszRep> riesz = Teuchos::rcp(new RieszRep(mesh, ipL2, indicatorLT)); riesz->computeRieszRep(); map<int,FunctionPtr> vmap; vmap[v->ID()] = RieszRep::repFunction(v,riesz); // SHOULD BE L2 projection = same thing!!! FunctionPtr volumeIntegrand = integrandLT->evaluate(vmap,false); FunctionPtr edgeRestrictedIntegrand = integrandLT->evaluate(vmap,true); double edgeRestrictedValue = volumeIntegrand->integrate(mesh,10) + edgeRestrictedIntegrand->integrate(mesh,10); double expectedValue = .5 + .5*jumpWeight; double diff = abs(expectedValue-edgeRestrictedValue); if (abs(diff)>1e-11) { success = false; cout << "Failed testIntegrateDiscontinuousFunction() with expectedValue = " << expectedValue << " and actual value = " << edgeRestrictedValue << endl; } return success; }
// tests whether a mixed type LT bool ScratchPadTests::testLinearTermEvaluationConsistency() { bool success = true; //////////////////// DECLARE VARIABLES /////////////////////// // define test variables VarFactoryPtr varFactory = VarFactory::varFactory(); VarPtr v = varFactory->testVar("v", HGRAD); vector<double> beta; beta.push_back(1.0); beta.push_back(1.0); //////////////////// DEFINE INNER PRODUCT(S) /////////////////////// // robust test norm IPPtr ip = Teuchos::rcp(new IP); ip->addTerm(v); ip->addTerm(beta*v->grad()); // define trial variables VarPtr beta_n_u = varFactory->fluxVar("\\widehat{\\beta \\cdot n }"); VarPtr u = varFactory->fieldVar("u"); //////////////////// BUILD MESH /////////////////////// BFPtr convectionBF = Teuchos::rcp( new BF(varFactory) ); // v terms: convectionBF->addTerm( -u, beta * v->grad() ); convectionBF->addTerm( beta_n_u, v); // define nodes for mesh int order = 1; int H1Order = order+1; int pToAdd = 1; // create a pointer to a new mesh: Teuchos::RCP<Mesh> mesh = MeshUtilities::buildUnitQuadMesh(1, convectionBF, H1Order, H1Order+pToAdd); //////////////////// get fake residual /////////////////////// LinearTermPtr lt = Teuchos::rcp(new LinearTerm); FunctionPtr edgeFxn = Teuchos::rcp(new EdgeFunction); FunctionPtr Xsq = Function::xn(2); FunctionPtr Ysq = Function::yn(2); FunctionPtr XYsq = Xsq*Ysq; lt->addTerm(edgeFxn*v + (beta*XYsq)*v->grad()); Teuchos::RCP<RieszRep> ltRiesz = Teuchos::rcp(new RieszRep(mesh, ip, lt)); ltRiesz->computeRieszRep(); FunctionPtr repFxn = RieszRep::repFunction(v,ltRiesz); map<int,FunctionPtr> rep_map; rep_map[v->ID()] = repFxn; FunctionPtr edgeLt = lt->evaluate(rep_map, true) ; FunctionPtr elemLt = lt->evaluate(rep_map, false); double edgeVal = edgeLt->integrate(mesh,10); double elemVal = elemLt->integrate(mesh,10); LinearTermPtr edgeOnlyLt = Teuchos::rcp(new LinearTerm);// residual edgeOnlyLt->addTerm(edgeFxn*v); FunctionPtr edgeOnly = edgeOnlyLt->evaluate(rep_map,true); double edgeOnlyVal = edgeOnly->integrate(mesh,10); double diff = edgeOnlyVal-edgeVal; if (abs(diff)>1e-11) { success = false; cout << "Failed testLinearTermEvaluationConsistency() with diff = " << diff << endl; } return success; }
bool LinearTermTests::testIntegrateMixedBasis() { bool success = true; //////////////////// DECLARE VARIABLES /////////////////////// // define test variables VarFactoryPtr varFactory = 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(1.0); //////////////////// DEFINE BILINEAR FORM/Mesh /////////////////////// BFPtr convectionBF = Teuchos::rcp( new BF(varFactory) ); // v terms: convectionBF->addTerm( -u, beta * v->grad() ); convectionBF->addTerm( beta_n_u_hat, v); convectionBF->addTerm( u, v); // build CONSTANT SINGLE ELEMENT MESH int order = 0; int H1Order = order+1; int pToAdd = 1; int nCells = 2; // along a side // create a pointer to a new mesh: Teuchos::RCP<Mesh> mesh = MeshUtilities::buildUnitQuadMesh(nCells,convectionBF, H1Order, H1Order+pToAdd); ElementTypePtr elemType = mesh->getElement(0)->elementType(); BasisCachePtr basisCache = Teuchos::rcp(new BasisCache(elemType, mesh)); vector<GlobalIndexType> cellIDs; vector< ElementPtr > allElems = mesh->activeElements(); vector< ElementPtr >::iterator elemIt; for (elemIt=allElems.begin(); elemIt!=allElems.end(); elemIt++) { cellIDs.push_back((*elemIt)->cellID()); } bool createSideCacheToo = true; basisCache->setPhysicalCellNodes(mesh->physicalCellNodesGlobal(elemType), cellIDs, createSideCacheToo); int numTrialDofs = elemType->trialOrderPtr->totalDofs(); int numCells = mesh->numActiveElements(); double areaPerCell = 1.0 / numCells; FieldContainer<double> integrals(numCells,numTrialDofs); FieldContainer<double> expectedIntegrals(numCells,numTrialDofs); double sidelengthOfCell = 1.0 / nCells; DofOrderingPtr trialOrdering = elemType->trialOrderPtr; int dofForField = trialOrdering->getDofIndex(u->ID(), 0); vector<int> dofsForFlux; const vector<int>* sidesForFlux = &trialOrdering->getSidesForVarID(beta_n_u_hat->ID()); for (vector<int>::const_iterator sideIt = sidesForFlux->begin(); sideIt != sidesForFlux->end(); sideIt++) { int sideIndex = *sideIt; dofsForFlux.push_back(trialOrdering->getDofIndex(beta_n_u_hat->ID(), 0, sideIndex)); } for (int cellIndex = 0; cellIndex < numCells; cellIndex++) { expectedIntegrals(cellIndex, dofForField) = areaPerCell; for (vector<int>::iterator dofIt = dofsForFlux.begin(); dofIt != dofsForFlux.end(); dofIt++) { int fluxDofIndex = *dofIt; expectedIntegrals(cellIndex, fluxDofIndex) = sidelengthOfCell; } } // cout << "expectedIntegrals:\n" << expectedIntegrals; // setup: with constant degrees of freedom, we expect that the integral of int_dK (flux) + int_K (field) will be ones for each degree of freedom, assuming the basis functions for these constants field/flux variables are just C = 1.0. // //On a unit square, int_K (constant) = 1.0, and int_dK (u_i) = 1, for i = 0,...,3. LinearTermPtr lt = 1.0 * beta_n_u_hat; LinearTermPtr field = 1.0 * u; lt->addTerm(field,true); lt->integrate(integrals, elemType->trialOrderPtr, basisCache); double tol = 1e-12; double maxDiff; success = TestSuite::fcsAgree(integrals,expectedIntegrals,tol,maxDiff); if (success==false) { cout << "Failed testIntegrateMixedBasis with maxDiff = " << maxDiff << endl; } return success; }
bool LinearTermTests::testMixedTermConsistency() { bool success = true; //////////////////// DECLARE VARIABLES /////////////////////// // define test variables VarFactoryPtr varFactory = VarFactory::varFactory(); VarPtr tau = varFactory->testVar("\\tau", HDIV); VarPtr v = varFactory->testVar("v", HGRAD); // define 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"); vector<double> beta; beta.push_back(1.0); beta.push_back(0.0); double eps = .01; //////////////////// DEFINE BILINEAR FORM /////////////////////// BFPtr confusionBF = Teuchos::rcp( new BF(varFactory) ); // tau terms: confusionBF->addTerm(sigma1 / eps, tau->x()); confusionBF->addTerm(sigma2 / eps, 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( -u, beta * v->grad() ); confusionBF->addTerm( beta_n_u_minus_sigma_n, v); //////////////////// BUILD MESH /////////////////////// // define nodes for mesh int H1Order = 1; int pToAdd = 1; 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; int nCells = 1; int horizontalCells = nCells, verticalCells = nCells; // create a pointer to a new mesh: Teuchos::RCP<Mesh> myMesh = MeshFactory::buildQuadMesh(quadPoints, horizontalCells, verticalCells, confusionBF, H1Order, H1Order+pToAdd); ElementTypePtr elemType = myMesh->getElement(0)->elementType(); // DofOrderingPtr testOrder = elemType->testOrderPtr; BasisCachePtr basisCache = Teuchos::rcp(new BasisCache(elemType, myMesh, true)); LinearTermPtr integrandIBP = Teuchos::rcp(new LinearTerm);// residual vector<double> e1(2); // (1,0) vector<double> e2(2); // (0,1) e1[0] = 1; e2[1] = 1; FunctionPtr n = Function::normal(); FunctionPtr X = Function::xn(1); FunctionPtr Y = Function::yn(1); FunctionPtr testFxn1 = X; FunctionPtr testFxn2 = Y; FunctionPtr divTestFxn = testFxn1->dx() + testFxn2->dy(); FunctionPtr vectorTest = testFxn1*e1 + testFxn2*e2; integrandIBP->addTerm(vectorTest*n*v + -vectorTest*v->grad()); // boundary term // define dummy IP to initialize riesz rep class, but just integrate RHS IPPtr dummyIP = Teuchos::rcp(new IP); dummyIP->addTerm(v); Teuchos::RCP<RieszRep> riesz = Teuchos::rcp(new RieszRep(myMesh, dummyIP, integrandIBP)); map<GlobalIndexType,FieldContainer<double> > rieszRHS = riesz->integrateFunctional(); set<GlobalIndexType> cellIDs = myMesh->cellIDsInPartition(); for (set<GlobalIndexType>::iterator cellIDIt=cellIDs.begin(); cellIDIt !=cellIDs.end(); cellIDIt++) { GlobalIndexType cellID = *cellIDIt; ElementTypePtr elemTypePtr = myMesh->getElementType(cellID); DofOrderingPtr testOrderingPtr = elemTypePtr->testOrderPtr; int numTestDofs = testOrderingPtr->totalDofs(); BasisCachePtr basisCache = BasisCache::basisCacheForCell(myMesh, cellID, true); FieldContainer<double> rhsIBPValues(1,numTestDofs); integrandIBP->integrate(rhsIBPValues, testOrderingPtr, basisCache); FieldContainer<double> rieszValues(1,numTestDofs); (riesz->getFunctional())->integrate(rieszValues, testOrderingPtr, basisCache); double maxDiff; double tol = 1e-13; FieldContainer<double> rhsIBPVals(numTestDofs); for (int i = 0; i< numTestDofs; i++) { rhsIBPVals(i) = rhsIBPValues(0,i); // cout << "riesz rhs values = " << rieszRHS[cellID](i) << ", rhsIBPValues = " << rhsIBPVals(i) << ", riesz returned values = " << rieszValues(0,i) << endl; } bool fcsAgree = TestSuite::fcsAgree(rieszRHS[cellID],rhsIBPVals,tol,maxDiff); if (!fcsAgree) { success=false; cout << "Failed mixed term consistency test with maxDiff = " << maxDiff << " on cellID " << cellID<< endl; } } return allSuccess(success); }
// tests to make sure the energy error calculated thru direct integration works for vector valued test functions too bool ScratchPadTests::testLTResidual() { double tol = 1e-11; int rank = Teuchos::GlobalMPISession::getRank(); bool success = true; int nCells = 2; double eps = .1; //////////////////// DECLARE VARIABLES /////////////////////// // define test variables VarFactoryPtr varFactory = VarFactory::varFactory(); VarPtr tau = varFactory->testVar("\\tau", HDIV); VarPtr v = varFactory->testVar("v", HGRAD); // define 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"); vector<double> beta; beta.push_back(1.0); beta.push_back(0.0); //////////////////// DEFINE BILINEAR FORM /////////////////////// BFPtr confusionBF = Teuchos::rcp( new BF(varFactory) ); // tau terms: confusionBF->addTerm(sigma1 / eps, tau->x()); confusionBF->addTerm(sigma2 / eps, 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( -u, beta * v->grad() ); confusionBF->addTerm( beta_n_u_minus_sigma_n, v); //////////////////// DEFINE INNER PRODUCT(S) /////////////////////// // robust test norm IPPtr ip = Teuchos::rcp(new IP); // choose the mesh-independent norm even though it may have boundary layers ip->addTerm(v->grad()); ip->addTerm(v); ip->addTerm(tau); ip->addTerm(tau->div()); //////////////////// SPECIFY RHS AND HELPFUL FUNCTIONS /////////////////////// FunctionPtr n = Function::normal(); vector<double> e1,e2; e1.push_back(1.0); e1.push_back(0.0); e2.push_back(0.0); e2.push_back(1.0); FunctionPtr one = Function::constant(1.0); FunctionPtr zero = Function::constant(0.0); RHSPtr rhs = RHS::rhs(); FunctionPtr f = one; // if this is set to zero instead, we pass the test (a clue?) rhs->addTerm( f * v ); //////////////////// CREATE BCs /////////////////////// BCPtr bc = BC::bc(); SpatialFilterPtr squareBoundary = Teuchos::rcp( new SquareBoundary ); bc->addDirichlet(uhat, squareBoundary, one); //////////////////// BUILD MESH /////////////////////// // define nodes for mesh int order = 2; int H1Order = order+1; int pToAdd = 2; // create a pointer to a new mesh: Teuchos::RCP<Mesh> mesh = MeshUtilities::buildUnitQuadMesh(nCells,confusionBF, H1Order, H1Order+pToAdd); //////////////////// SOLVE & REFINE /////////////////////// Teuchos::RCP<Solution> solution; solution = Teuchos::rcp( new Solution(mesh, bc, rhs, ip) ); solution->solve(false); double energyError = solution->energyErrorTotal(); LinearTermPtr residual = rhs->linearTermCopy(); residual->addTerm(-confusionBF->testFunctional(solution),true); // FunctionPtr uh = Function::solution(uhat,solution); // FunctionPtr fn = Function::solution(beta_n_u_minus_sigma_n,solution); // FunctionPtr uF = Function::solution(u,solution); // FunctionPtr sigma = e1*Function::solution(sigma1,solution)+e2*Function::solution(sigma2,solution); // residual->addTerm(- (fn*v - uh*tau->dot_normal())); // residual->addTerm(- (uF*(tau->div() - beta*v->grad()) + sigma*((1/eps)*tau + v->grad()))); // residual->addTerm(-(fn*v - uF*beta*v->grad() + sigma*v->grad())); // just v portion // residual->addTerm(uh*tau->dot_normal() - uF*tau->div() - sigma*((1/eps)*tau)); // just tau portion Teuchos::RCP<RieszRep> rieszResidual = Teuchos::rcp(new RieszRep(mesh, ip, residual)); rieszResidual->computeRieszRep(); double energyErrorLT = rieszResidual->getNorm(); int cubEnrich = 0; bool testVsTest = true; FunctionPtr e_v = RieszRep::repFunction(v,rieszResidual); FunctionPtr e_tau = RieszRep::repFunction(tau,rieszResidual); // experiment by Nate: manually specify the error (this appears to produce identical results, as it should) // FunctionPtr err = e_v * e_v + e_tau * e_tau + e_v->grad() * e_v->grad() + e_tau->div() * e_tau->div(); map<int,FunctionPtr> errFxns; errFxns[v->ID()] = e_v; errFxns[tau->ID()] = e_tau; LinearTermPtr ipAtErrFxns = ip->evaluate(errFxns); FunctionPtr err = ip->evaluate(errFxns)->evaluate(errFxns); double energyErrorIntegrated = sqrt(err->integrate(mesh,cubEnrich,testVsTest)); // check that energy error computed thru Solution and through rieszRep are the same bool success1 = abs(energyError-energyErrorLT)<tol; // checks that matrix-computed and integrated errors are the same bool success2 = abs(energyErrorLT-energyErrorIntegrated)<tol; success = success1==true && success2==true; if (!success) { if (rank==0) cout << "Failed testLTResidual; energy error = " << energyError << ", while linearTerm error is computed to be " << energyErrorLT << ", and when computing through integration of the Riesz rep function, error = " << energyErrorIntegrated << endl; } // VTKExporter exporter(solution, mesh, varFactory); // exporter.exportSolution("testLTRes"); // cout << endl; return success; }
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; }
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 rank = Teuchos::GlobalMPISession::getRank(); int numProcs = Teuchos::GlobalMPISession::getNProc(); int nCells = args.Input<int>("--nCells", "num cells",2); int numRefs = args.Input<int>("--numRefs","num adaptive refinements",0); int numPreRefs = args.Input<int>("--numPreRefs","num preemptive adaptive refinements",0); int order = args.Input<int>("--order","order of approximation",2); double eps = args.Input<double>("--epsilon","diffusion parameter",1e-2); double energyThreshold = args.Input<double>("-energyThreshold","energy thresh for adaptivity", .5); double rampHeight = args.Input<double>("--rampHeight","ramp height at x = 2", 0.0); bool useAnisotropy = args.Input<bool>("--useAnisotropy","aniso flag ", false); FunctionPtr zero = Function::constant(0.0); FunctionPtr one = Function::constant(1.0); FunctionPtr n = Teuchos::rcp( new UnitNormalFunction ); vector<double> e1,e2; e1.push_back(1.0); e1.push_back(0.0); e2.push_back(0.0); e2.push_back(1.0); //////////////////// 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("\\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"); vector<double> beta; beta.push_back(1.0); beta.push_back(0.0); //////////////////// DEFINE BILINEAR FORM /////////////////////// BFPtr confusionBF = Teuchos::rcp( new BF(varFactory) ); // tau terms: confusionBF->addTerm(sigma1 / eps, tau->x()); confusionBF->addTerm(sigma2 / eps, 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( -u, beta * v->grad() ); confusionBF->addTerm( beta_n_u_minus_sigma_n, v); // first order term with magnitude alpha double alpha = 0.0; confusionBF->addTerm(alpha * u, v); //////////////////// DEFINE INNER PRODUCT(S) /////////////////////// // robust test norm IPPtr robIP = Teuchos::rcp(new IP); FunctionPtr C_h = Teuchos::rcp( new EpsilonScaling(eps) ); FunctionPtr invH = Teuchos::rcp(new InvHScaling); FunctionPtr invSqrtH = Teuchos::rcp(new InvSqrtHScaling); FunctionPtr sqrtH = Teuchos::rcp(new SqrtHScaling); robIP->addTerm(v*alpha); robIP->addTerm(invSqrtH*v); // robIP->addTerm(v); robIP->addTerm(sqrt(eps) * v->grad() ); robIP->addTerm(beta * v->grad() ); robIP->addTerm(tau->div() ); robIP->addTerm(C_h/sqrt(eps) * tau ); LinearTermPtr vVecLT = Teuchos::rcp(new LinearTerm); LinearTermPtr tauVecLT = Teuchos::rcp(new LinearTerm); vVecLT->addTerm(sqrt(eps)*v->grad()); tauVecLT->addTerm(C_h/sqrt(eps)*tau); LinearTermPtr restLT = Teuchos::rcp(new LinearTerm); restLT->addTerm(alpha*v); restLT->addTerm(invSqrtH*v); restLT = restLT + beta * v->grad(); restLT = restLT + tau->div(); //////////////////// SPECIFY RHS /////////////////////// Teuchos::RCP<RHSEasy> rhs = Teuchos::rcp( new RHSEasy ); FunctionPtr f = zero; // f = one; 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 InflowSquareBoundary ); // SpatialFilterPtr outflowBoundary = Teuchos::rcp( new OutflowSquareBoundary); // bc->addDirichlet(beta_n_u_minus_sigma_n, inflowBoundary, zero); // bc->addDirichlet(uhat, outflowBoundary, zero); SpatialFilterPtr rampInflow = Teuchos::rcp(new LeftInflow); SpatialFilterPtr rampBoundary = MeshUtilities::rampBoundary(rampHeight); SpatialFilterPtr freeStream = Teuchos::rcp(new FreeStreamBoundary); SpatialFilterPtr outflowBoundary = Teuchos::rcp(new OutflowBoundary); bc->addDirichlet(uhat, rampBoundary, one); // bc->addDirichlet(uhat, outflowBoundary, one); bc->addDirichlet(beta_n_u_minus_sigma_n, rampInflow, zero); bc->addDirichlet(beta_n_u_minus_sigma_n, freeStream, zero); //////////////////// BUILD MESH /////////////////////// // define nodes for mesh int H1Order = order+1; int pToAdd = 2; // create a pointer to a new mesh: // Teuchos::RCP<Mesh> mesh = MeshUtilities::buildUnitQuadMesh(nCells,confusionBF, H1Order, H1Order+pToAdd); Teuchos::RCP<Mesh> mesh = MeshUtilities::buildRampMesh(rampHeight,confusionBF, H1Order, H1Order+pToAdd); mesh->setPartitionPolicy(Teuchos::rcp(new ZoltanMeshPartitionPolicy("HSFC"))); //////////////////// SOLVE & REFINE /////////////////////// Teuchos::RCP<Solution> solution; solution = Teuchos::rcp( new Solution(mesh, bc, rhs, robIP) ); // solution->solve(false); solution->condensedSolve(); LinearTermPtr residual = rhs->linearTermCopy(); residual->addTerm(-confusionBF->testFunctional(solution)); RieszRepPtr rieszResidual = Teuchos::rcp(new RieszRep(mesh, robIP, residual)); rieszResidual->computeRieszRep(); FunctionPtr e_v = Teuchos::rcp(new RepFunction(v,rieszResidual)); FunctionPtr e_tau = Teuchos::rcp(new RepFunction(tau,rieszResidual)); map<int,FunctionPtr> errRepMap; errRepMap[v->ID()] = e_v; errRepMap[tau->ID()] = e_tau; FunctionPtr errTau = tauVecLT->evaluate(errRepMap,false); FunctionPtr errV = vVecLT->evaluate(errRepMap,false); FunctionPtr errRest = restLT->evaluate(errRepMap,false); FunctionPtr xErr = (errTau->x())*(errTau->x()) + (errV->dx())*(errV->dx()); FunctionPtr yErr = (errTau->y())*(errTau->y()) + (errV->dy())*(errV->dy()); FunctionPtr restErr = errRest*errRest; RefinementStrategy refinementStrategy( solution, energyThreshold ); //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // PRE REFINEMENTS //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// if (rank==0) { cout << "Number of pre-refinements = " << numPreRefs << endl; } for (int i =0; i<=numPreRefs; i++) { vector<ElementPtr> elems = mesh->activeElements(); vector<ElementPtr>::iterator elemIt; vector<int> wallCells; for (elemIt=elems.begin(); elemIt != elems.end(); elemIt++) { int cellID = (*elemIt)->cellID(); int numSides = mesh->getElement(cellID)->numSides(); FieldContainer<double> vertices(numSides,2); //for quads mesh->verticesForCell(vertices, cellID); bool cellIDset = false; for (int j = 0; j<numSides; j++) { if ((abs(vertices(j,0)-1.0)<1e-7) && (abs(vertices(j,1))<1e-7) && !cellIDset) // if at singularity, i.e. if a vertex is (1,0) { wallCells.push_back(cellID); cellIDset = true; } } } if (i<numPreRefs) { refinementStrategy.refineCells(wallCells); } } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// VTKExporter exporter(solution, mesh, varFactory); for (int refIndex=0; refIndex<numRefs; refIndex++) { if (rank==0) { cout << "on ref index " << refIndex << endl; } rieszResidual->computeRieszRep(); // in preparation to get anisotropy vector<int> cellIDs; refinementStrategy.getCellsAboveErrorThreshhold(cellIDs); map<int,double> energyError = solution->energyError(); map<int,double> xErrMap = xErr->cellIntegrals(cellIDs,mesh,5,true); map<int,double> yErrMap = yErr->cellIntegrals(cellIDs,mesh,5,true); map<int,double> restErrMap = restErr->cellIntegrals(cellIDs,mesh,5,true); for (vector<ElementPtr>::iterator elemIt = mesh->activeElements().begin(); elemIt!=mesh->activeElements().end(); elemIt++) { int cellID = (*elemIt)->cellID(); double err = xErrMap[cellID]+ yErrMap[cellID] + restErrMap[cellID]; if (rank==0) cout << "err thru LT = " << sqrt(err) << ", while energy err = " << energyError[cellID] << endl; } map<int,double> ratio,xErr,yErr; vector<ElementPtr> elems = mesh->activeElements(); for (vector<ElementPtr>::iterator elemIt = elems.begin(); elemIt!=elems.end(); elemIt++) { int cellID = (*elemIt)->cellID(); ratio[cellID] = 0.0; xErr[cellID] = 0.0; yErr[cellID] = 0.0; if (std::find(cellIDs.begin(),cellIDs.end(),cellID)!=cellIDs.end()) // if this cell is above energy thresh { ratio[cellID] = yErrMap[cellID]/xErrMap[cellID]; xErr[cellID] = xErrMap[cellID]; yErr[cellID] = yErrMap[cellID]; } } FunctionPtr ratioFxn = Teuchos::rcp(new EnergyErrorFunction(ratio)); FunctionPtr xErrFxn = Teuchos::rcp(new EnergyErrorFunction(xErr)); FunctionPtr yErrFxn = Teuchos::rcp(new EnergyErrorFunction(yErr)); std::ostringstream oss; oss << refIndex; exporter.exportFunction(ratioFxn, string("ratio")+oss.str()); exporter.exportFunction(xErrFxn, string("xErr")+oss.str()); exporter.exportFunction(yErrFxn, string("yErr")+oss.str()); if (useAnisotropy) { refinementStrategy.refine(rank==0,xErrMap,yErrMap); //anisotropic refinements } else { refinementStrategy.refine(rank==0); // no anisotropy } solution->condensedSolve(); } // final solve on final mesh solution->condensedSolve(); //////////////////// print to file /////////////////////// FunctionPtr orderFxn = Teuchos::rcp(new MeshPolyOrderFunction(mesh)); std::ostringstream oss; oss << nCells; if (rank==0) { exporter.exportSolution(string("robustIP")+oss.str()); exporter.exportFunction(orderFxn, "meshOrder"); cout << endl; } return 0; }
bool LinearTermTests::testRieszInversionAsProjection() { bool success = true; //////////////////// DECLARE VARIABLES /////////////////////// // define test variables VarFactoryPtr varFactory = VarFactory::varFactory(); VarPtr tau = varFactory->testVar("\\tau", HDIV); VarPtr v = varFactory->testVar("v", HGRAD); // define 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"); vector<double> beta; beta.push_back(1.0); beta.push_back(0.0); double eps = .01; //////////////////// DEFINE BILINEAR FORM /////////////////////// BFPtr confusionBF = Teuchos::rcp( new BF(varFactory) ); // tau terms: confusionBF->addTerm(sigma1 / eps, tau->x()); confusionBF->addTerm(sigma2 / eps, 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( -u, beta * v->grad() ); confusionBF->addTerm( beta_n_u_minus_sigma_n, v); //////////////////// BUILD MESH /////////////////////// // define nodes for mesh int H1Order = 2; int pToAdd = 2; 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; int nCells = 2; int horizontalCells = nCells, verticalCells = nCells; // create a new mesh: MeshPtr myMesh = MeshFactory::buildQuadMesh(quadPoints, horizontalCells, verticalCells, confusionBF, H1Order, H1Order+pToAdd); ElementTypePtr elemType = myMesh->getElement(0)->elementType(); BasisCachePtr basisCache = Teuchos::rcp(new BasisCache(elemType, myMesh)); vector<GlobalIndexType> cellIDs = myMesh->cellIDsOfTypeGlobal(elemType); bool createSideCacheToo = true; basisCache->setPhysicalCellNodes(myMesh->physicalCellNodesGlobal(elemType), cellIDs, createSideCacheToo); LinearTermPtr integrand = Teuchos::rcp(new LinearTerm); // residual FunctionPtr x = Function::xn(1); FunctionPtr y = Function::yn(1); FunctionPtr testFxn1 = x; FunctionPtr testFxn2 = y; FunctionPtr fxnToProject = x * y + 1.0; integrand->addTerm(fxnToProject * v); IPPtr ip_L2 = Teuchos::rcp(new IP); ip_L2->addTerm(v); ip_L2->addTerm(tau); Teuchos::RCP<RieszRep> riesz = Teuchos::rcp(new RieszRep(myMesh, ip_L2, integrand)); riesz->computeRieszRep(); FunctionPtr rieszFxn = RieszRep::repFunction(v,riesz); int numCells = basisCache->getPhysicalCubaturePoints().dimension(0); int numPts = basisCache->getPhysicalCubaturePoints().dimension(1); FieldContainer<double> valProject( numCells, numPts ); FieldContainer<double> valExpected( numCells, numPts ); rieszFxn->values(valProject,basisCache); fxnToProject->values(valExpected,basisCache); // int rank = Teuchos::GlobalMPISession::getRank(); // if (rank==0) cout << "physicalCubaturePoints:\n" << basisCache->getPhysicalCubaturePoints(); double maxDiff; double tol = 1e-12; success = TestSuite::fcsAgree(valProject,valExpected,tol,maxDiff); if (success==false) { cout << "Failed Riesz Inversion Projection test with maxDiff = " << maxDiff << endl; serializeOutput("valExpected", valExpected); serializeOutput("valProject", valProject); serializeOutput("physicalPoints", basisCache->getPhysicalCubaturePoints()); } return allSuccess(success); }
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; }
// tests Riesz inversion by integration by parts bool LinearTermTests::testRieszInversion() { bool success = true; //////////////////// DECLARE VARIABLES /////////////////////// // define test variables VarFactoryPtr varFactory = VarFactory::varFactory(); VarPtr tau = varFactory->testVar("\\tau", HDIV); VarPtr v = varFactory->testVar("v", HGRAD); // define 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"); vector<double> beta; beta.push_back(1.0); beta.push_back(0.0); double eps = .01; //////////////////// DEFINE BILINEAR FORM /////////////////////// BFPtr confusionBF = Teuchos::rcp( new BF(varFactory) ); // tau terms: confusionBF->addTerm(sigma1 / eps, tau->x()); confusionBF->addTerm(sigma2 / eps, 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( -u, beta * v->grad() ); confusionBF->addTerm( beta_n_u_minus_sigma_n, v); //////////////////// BUILD MESH /////////////////////// // define nodes for mesh int H1Order = 1; int pToAdd = 1; 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; int nCells = 1; int horizontalCells = nCells, verticalCells = nCells; // create a pointer to a new mesh: Teuchos::RCP<Mesh> myMesh = MeshFactory::buildQuadMesh(quadPoints, horizontalCells, verticalCells, confusionBF, H1Order, H1Order+pToAdd); ElementTypePtr elemType = myMesh->getElement(0)->elementType(); BasisCachePtr basisCache = Teuchos::rcp(new BasisCache(elemType, myMesh)); vector<GlobalIndexType> cellIDs; vector<ElementPtr> elems = myMesh->activeElements(); vector<ElementPtr>::iterator elemIt; for (elemIt=elems.begin(); elemIt!=elems.end(); elemIt++) { int cellID = (*elemIt)->cellID(); cellIDs.push_back(cellID); } bool createSideCacheToo = true; basisCache->setPhysicalCellNodes(myMesh->physicalCellNodesGlobal(elemType), cellIDs, createSideCacheToo); LinearTermPtr integrand = Teuchos::rcp(new LinearTerm);// residual LinearTermPtr integrandIBP = Teuchos::rcp(new LinearTerm);// residual vector<double> e1(2); // (1,0) vector<double> e2(2); // (0,1) e1[0] = 1; e2[1] = 1; FunctionPtr n = Function::normal(); FunctionPtr X = Function::xn(1); FunctionPtr Y = Function::yn(1); FunctionPtr testFxn1 = X; FunctionPtr testFxn2 = Y; FunctionPtr divTestFxn = testFxn1->dx() + testFxn2->dy(); FunctionPtr vectorTest = testFxn1*e1 + testFxn2*e2; integrand->addTerm(divTestFxn*v); integrandIBP->addTerm(vectorTest*n*v - vectorTest*v->grad()); // boundary term IPPtr sobolevIP = Teuchos::rcp(new IP); sobolevIP->addTerm(v); sobolevIP->addTerm(tau); Teuchos::RCP<RieszRep> riesz = Teuchos::rcp(new RieszRep(myMesh, sobolevIP, integrand)); // riesz->setPrintOption(true); riesz->computeRieszRep(); Teuchos::RCP<RieszRep> rieszIBP = Teuchos::rcp(new RieszRep(myMesh, sobolevIP, integrandIBP)); riesz->setFunctional(integrandIBP); // rieszIBP->setPrintOption(true); rieszIBP->computeRieszRep(); FunctionPtr rieszOrigFxn = RieszRep::repFunction(v,riesz); FunctionPtr rieszIBPFxn = RieszRep::repFunction(v,rieszIBP); int numCells = basisCache->getPhysicalCubaturePoints().dimension(0); int numPts = basisCache->getPhysicalCubaturePoints().dimension(1); FieldContainer<double> valOriginal( numCells, numPts); FieldContainer<double> valIBP( numCells, numPts); rieszOrigFxn->values(valOriginal,basisCache); rieszIBPFxn->values(valIBP,basisCache); double maxDiff; double tol = 1e-14; success = TestSuite::fcsAgree(valOriginal,valIBP,tol,maxDiff); if (success==false) { cout << "Failed TestRieszInversion with maxDiff = " << maxDiff << endl; } return success; }
virtual void localStiffnessMatrixAndRHS(FieldContainer<double> &localStiffness, FieldContainer<double> &rhsVector, IPPtr ip, BasisCachePtr ipBasisCache, RHSPtr rhs, BasisCachePtr basisCache) { double testMatrixAssemblyTime = 0, testMatrixInversionTime = 0, localStiffnessDeterminationFromTestsTime = 0; #ifdef HAVE_MPI Epetra_MpiComm Comm(MPI_COMM_WORLD); //cout << "rank: " << rank << " of " << numProcs << endl; #else Epetra_SerialComm Comm; #endif Epetra_Time timer(Comm); // localStiffness should have dim. (numCells, numTrialFields, numTrialFields) MeshPtr mesh = basisCache->mesh(); if (mesh.get() == NULL) { cout << "localStiffnessMatrix requires BasisCache to have mesh set.\n"; TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "localStiffnessMatrix requires BasisCache to have mesh set."); } const vector<GlobalIndexType>* cellIDs = &basisCache->cellIDs(); int numCells = cellIDs->size(); if (numCells != localStiffness.dimension(0)) { cout << "localStiffnessMatrix requires basisCache->cellIDs() to have the same # of cells as the first dimension of localStiffness\n"; TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "localStiffnessMatrix requires basisCache->cellIDs() to have the same # of cells as the first dimension of localStiffness"); } ElementTypePtr elemType = mesh->getElementType((*cellIDs)[0]); // we assume all cells provided are of the same type DofOrderingPtr trialOrder = elemType->trialOrderPtr; DofOrderingPtr fieldOrder = mesh->getDofOrderingFactory().getFieldOrdering(trialOrder); DofOrderingPtr traceOrder = mesh->getDofOrderingFactory().getTraceOrdering(trialOrder); map<int, int> stiffnessIndexForTraceIndex; map<int, int> stiffnessIndexForFieldIndex; set<int> varIDs = trialOrder->getVarIDs(); for (set<int>::iterator varIt = varIDs.begin(); varIt != varIDs.end(); varIt++) { int varID = *varIt; const vector<int>* sidesForVar = &trialOrder->getSidesForVarID(varID); bool isTrace = (sidesForVar->size() > 1); for (vector<int>::const_iterator sideIt = sidesForVar->begin(); sideIt != sidesForVar->end(); sideIt++) { int sideOrdinal = *sideIt; vector<int> dofIndices = trialOrder->getDofIndices(varID,sideOrdinal); if (isTrace) { vector<int> traceDofIndices = traceOrder->getDofIndices(varID,sideOrdinal); for (int i=0; i<traceDofIndices.size(); i++) { stiffnessIndexForTraceIndex[traceDofIndices[i]] = dofIndices[i]; } } else { vector<int> fieldDofIndices = fieldOrder->getDofIndices(varID); for (int i=0; i<fieldDofIndices.size(); i++) { stiffnessIndexForFieldIndex[fieldDofIndices[i]] = dofIndices[i]; } } } } int numTrialDofs = trialOrder->totalDofs(); if ((numTrialDofs != localStiffness.dimension(1)) || (numTrialDofs != localStiffness.dimension(2))) { cout << "localStiffness should have dimensions (C,numTrialFields,numTrialFields).\n"; TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "localStiffness should have dimensions (C,numTrialFields,numTrialFields)."); } map<int,int> traceTestMap, fieldTestMap; int numEquations = _virtualTerms.getFieldTestVars().size(); for (int eqn=0; eqn<numEquations; eqn++) { VarPtr testVar = _virtualTerms.getFieldTestVars()[eqn]; VarPtr traceVar = _virtualTerms.getAssociatedTrace(testVar); VarPtr fieldVar = _virtualTerms.getAssociatedField(testVar); traceTestMap[traceVar->ID()] = testVar->ID(); fieldTestMap[fieldVar->ID()] = testVar->ID(); } int maxDegreeField = fieldOrder->maxBasisDegree(); int testDegreeInterior = maxDegreeField + _virtualTerms.getTestEnrichment(); int testDegreeTrace = testDegreeInterior + 2; cout << "ERROR in Virtual: getRelabeledDofOrdering() is commented out in DofOrderingFactory. Need to rewrite for the new caching scheme.\n"; DofOrderingPtr testOrderInterior; // = mesh->getDofOrderingFactory().getRelabeledDofOrdering(fieldOrder, fieldTestMap); testOrderInterior = mesh->getDofOrderingFactory().setBasisDegree(testOrderInterior, testDegreeInterior, false); DofOrderingPtr testOrderTrace = mesh->getDofOrderingFactory().setBasisDegree(testOrderInterior, testDegreeTrace, true); // this has a bunch of extra dofs (interior guys) map<int, int> remappedTraceIndices; // go from the index that includes the interior dofs to one that doesn't set<int> testIDs = testOrderTrace->getVarIDs(); int testTraceIndex = 0; for (set<int>::iterator testIDIt = testIDs.begin(); testIDIt != testIDs.end(); testIDIt++) { int testID = *testIDIt; BasisPtr basis = testOrderTrace->getBasis(testID); vector<int> interiorDofs = basis->dofOrdinalsForInterior(); for (int basisOrdinal=0; basisOrdinal<basis->getCardinality(); basisOrdinal++) { if (std::find(interiorDofs.begin(),interiorDofs.end(),basisOrdinal) == interiorDofs.end()) { int dofIndex = testOrderTrace->getDofIndex(testID, basisOrdinal); remappedTraceIndices[dofIndex] = testTraceIndex; testTraceIndex++; } } } // DofOrderingPtr testOrderTrace = mesh->getDofOrderingFactory().getRelabeledDofOrdering(traceOrder, traceTestMap); // testOrderTrace = mesh->getDofOrderingFactory().setBasisDegree(testOrderTrace, testDegreeTrace); int numTestInteriorDofs = testOrderInterior->totalDofs(); int numTestTraceDofsIncludingInterior = testOrderTrace->totalDofs(); int numTestTraceDofs = testTraceIndex; int numTestDofs = numTestTraceDofs + numTestInteriorDofs; timer.ResetStartTime(); bool printTimings = true; if (printTimings) { cout << "numCells: " << numCells << endl; cout << "numTestDofs: " << numTestDofs << endl; } FieldContainer<double> rhsVectorTest(numCells,testOrderInterior->totalDofs()); // rhsVector is zero for the "trace" test dofs { // project the load f onto the space of interior test dofs. LinearTermPtr f = rhs->linearTerm(); set<int> testIDs = f->varIDs(); for (int eqn=0; eqn<numEquations; eqn++) { VarPtr v = _virtualTerms.getFieldTestVars()[eqn]; if (testIDs.find(v->ID()) != testIDs.end()) { BasisPtr testInteriorBasis = testOrderInterior->getBasis(v->ID()); FieldContainer<double> fValues(numCells,testInteriorBasis->getCardinality()); // DofOrderingPtr oneVarOrderingTest = Teuchos::rcp(new DofOrdering(testInteriorBasis->domainTopology())); DofOrderingPtr oneVarOrderingTest = Teuchos::rcp(new DofOrdering); oneVarOrderingTest->addEntry(v->ID(), testInteriorBasis, testInteriorBasis->rangeRank()); LinearTermPtr f_v = Teuchos::rcp( new LinearTerm ); typedef pair< FunctionPtr, VarPtr > LinearSummand; vector<LinearSummand> summands = f->summands(); for (int i=0; i<summands.size(); i++) { FunctionPtr f = summands[i].first; if (v->ID() == summands[i].second->ID()) { f_v->addTerm(f * v); f_v->integrate(fValues, oneVarOrderingTest, basisCache); } } LinearTermPtr v_lt = 1.0 * v; FieldContainer<double> l2(numCells,testInteriorBasis->getCardinality(),testInteriorBasis->getCardinality()); v_lt->integrate(l2,oneVarOrderingTest,v_lt,oneVarOrderingTest,basisCache,basisCache->isSideCache()); Teuchos::Array<int> testTestDim(2), testOneDim(2); testTestDim[0] = testInteriorBasis->getCardinality(); testTestDim[1] = testInteriorBasis->getCardinality(); testOneDim[0] = testInteriorBasis->getCardinality(); testOneDim[1] = 1; FieldContainer<double> projection(testOneDim); for (int cellOrdinal=0; cellOrdinal<numCells; cellOrdinal++) { FieldContainer<double> l2cell(testTestDim,&l2(cellOrdinal,0,0)); FieldContainer<double> f_cell(testOneDim,&fValues(cellOrdinal,0)); SerialDenseWrapper::solveSystemUsingQR(projection, l2cell, f_cell); // rows in projection correspond to Ae_i, columns to the e_j. I.e. projection coefficients for e_i are found in the ith row for (int basisOrdinal_j=0; basisOrdinal_j<projection.dimension(0); basisOrdinal_j++) { int testIndex = testOrderInterior->getDofIndex(v->ID(), basisOrdinal_j); rhsVectorTest(cellOrdinal,testIndex) = projection(basisOrdinal_j,0); } } } } } // project strong operator applied to field terms, and use this to populate the top left portion of stiffness matrix: { FieldContainer<double> trialFieldTestInterior(numCells, fieldOrder->totalDofs(), testOrderInterior->totalDofs()); for (int eqn=0; eqn<numEquations; eqn++) { LinearTermPtr Au = _virtualTerms.getFieldOperators()[eqn]; VarPtr v = _virtualTerms.getFieldTestVars()[eqn]; set<int> fieldIDs = Au->varIDs(); for (set<int>::iterator fieldIt = fieldIDs.begin(); fieldIt != fieldIDs.end(); fieldIt++) { int fieldID = *fieldIt; // int testID = fieldTestMap[fieldID]; // // LinearTermPtr testInteriorVar = 1.0 * this->varFactory().test(testID); BasisPtr vBasis = testOrderInterior->getBasis(v->ID()); BasisPtr fieldTrialBasis = fieldOrder->getBasis(fieldID); // DofOrderingPtr oneVarOrderingTest = Teuchos::rcp(new DofOrdering(vBasis->domainTopology())); DofOrderingPtr oneVarOrderingTest = Teuchos::rcp(new DofOrdering()); oneVarOrderingTest->addEntry(v->ID(), vBasis, vBasis->rangeRank()); FieldContainer<double> Au_values(numCells,vBasis->getCardinality(),fieldTrialBasis->getCardinality()); FieldContainer<double> l2(numCells,vBasis->getCardinality(),vBasis->getCardinality()); DofOrderingPtr oneVarOrderingTrial = Teuchos::rcp(new DofOrdering()); // DofOrderingPtr oneVarOrderingTrial = Teuchos::rcp(new DofOrdering(fieldTrialBasis->domainTopology())); oneVarOrderingTrial->addEntry(fieldID, fieldTrialBasis, fieldTrialBasis->rangeRank()); LinearTermPtr Au_restricted_to_field = Teuchos::rcp( new LinearTerm ); typedef pair< FunctionPtr, VarPtr > LinearSummand; vector<LinearSummand> summands = Au->summands(); for (int i=0; i<summands.size(); i++) { FunctionPtr f = summands[i].first; VarPtr v = summands[i].second; if (v->ID() == fieldID) { Au_restricted_to_field->addTerm(f * v); } } LinearTermPtr v_lt = 1.0 * v; Au_restricted_to_field->integrate(Au_values,oneVarOrderingTrial,v_lt,oneVarOrderingTest,basisCache,basisCache->isSideCache()); v_lt->integrate(l2,oneVarOrderingTest,v_lt,oneVarOrderingTest,basisCache,basisCache->isSideCache()); double maxValue = 0; for (int i=0; i<l2.size(); i++) { maxValue = max(abs(l2[i]),maxValue); } cout << "maxValue in l2 is " << maxValue << endl; Teuchos::Array<int> testTestDim(2), trialTestDim(2); testTestDim[0] = vBasis->getCardinality(); testTestDim[1] = vBasis->getCardinality(); trialTestDim[0] = vBasis->getCardinality(); trialTestDim[1] = fieldTrialBasis->getCardinality(); FieldContainer<double> projection(trialTestDim); for (int cellOrdinal=0; cellOrdinal<numCells; cellOrdinal++) { FieldContainer<double> l2cell(testTestDim,&l2(cellOrdinal,0,0)); FieldContainer<double> AuCell(trialTestDim,&Au_values(cellOrdinal,0,0)); // TODO: confirm that I'm doing the right projection here. I could be missing a key point, but it seems to me that we must // project onto an *orthonormal* basis here, to achieve the required identity structure of the (field,field) part of the // Gram matrix. OTOH, it looks to me like the computation here achieves exactly that, even though I didn't initially // have that in mind... // SerialDenseWrapper::solveSystemUsingQR(projection, l2cell, AuCell); SerialDenseWrapper::solveSystemMultipleRHS(projection, l2cell, AuCell); // rows in projection correspond to Ae_i, columns to the e_j. I.e. projection coefficients for e_i are found in the ith row for (int basisOrdinal_i=0; basisOrdinal_i<projection.dimension(0); basisOrdinal_i++) { int testIndex = testOrderInterior->getDofIndex(v->ID(), basisOrdinal_i); for (int basisOrdinal_j=0; basisOrdinal_j<projection.dimension(1); basisOrdinal_j++) { int trialIndex = fieldOrder->getDofIndex(fieldID, basisOrdinal_j); // in the *trial* space trialFieldTestInterior(cellOrdinal,trialIndex,testIndex) = projection(basisOrdinal_i,basisOrdinal_j); } } } } } Teuchos::Array<int> trialTestDim(2); trialTestDim[0] = fieldOrder->totalDofs(); trialTestDim[1] = testOrderInterior->totalDofs(); for (int cellOrdinal=0; cellOrdinal<numCells; cellOrdinal++) { FieldContainer<double> trialFieldTrialField(fieldOrder->totalDofs(), fieldOrder->totalDofs()); FieldContainer<double> trialTestCell(trialTestDim, &trialFieldTestInterior(cellOrdinal,0,0)); SerialDenseWrapper::multiply(trialFieldTrialField, trialTestCell, trialTestCell, 'N', 'T'); // transpose the second one // now, accumulate into localStiffness for (int i=0; i<trialFieldTrialField.dimension(0); i++) { int stiff_i = stiffnessIndexForFieldIndex[i]; for (int j=0; j<trialFieldTrialField.dimension(1); j++) { int stiff_j = stiffnessIndexForFieldIndex[j]; localStiffness(cellOrdinal,stiff_i,stiff_j) = trialFieldTrialField(i,j); } } } // multiply RHS integrated against the interior test space by the trialFieldTestInterior for (int cellOrdinal=0; cellOrdinal<numCells; cellOrdinal++) { Teuchos::Array<int> trialTestDim(2), oneTestDim(2); trialTestDim[0] = fieldOrder->totalDofs(); trialTestDim[1] = testOrderInterior->totalDofs(); oneTestDim[0] = 1; oneTestDim[1] = testOrderInterior->totalDofs(); FieldContainer<double> trialTestCell(trialTestDim, &trialFieldTestInterior(cellOrdinal,0,0)); FieldContainer<double> rhsTestCell(oneTestDim, &rhsVectorTest(cellOrdinal,0)); FieldContainer<double> rhsTrialCell(1, fieldOrder->totalDofs()); SerialDenseWrapper::multiply(rhsTrialCell, rhsTestCell, trialTestCell, 'N', 'T'); for (int fieldIndex=0; fieldIndex<fieldOrder->totalDofs(); fieldIndex++) { int stiffIndex = stiffnessIndexForFieldIndex[fieldIndex]; rhsVector(cellOrdinal,stiffIndex) = rhsTrialCell(0, fieldIndex); } } } FieldContainer<double> ipMatrixTraceIncludingInterior(numCells,numTestTraceDofsIncludingInterior,numTestTraceDofsIncludingInterior); int numTestTerms = _virtualTerms.getTestNormOperators().size(); for (int i=0; i<numTestTerms; i++) { LinearTermPtr testTerm = _virtualTerms.getTestNormOperators()[i]; LinearTermPtr boundaryTerm = _virtualTerms.getTestNormBoundaryOperators()[i]; testTerm->integrate(ipMatrixTraceIncludingInterior,testOrderTrace,boundaryTerm,testOrderTrace,ipBasisCache,ipBasisCache->isSideCache()); } FieldContainer<double> ipMatrixTrace(numCells,numTestTraceDofs,numTestTraceDofs); for (int cellOrdinal=0; cellOrdinal<numCells; cellOrdinal++) { for (int i_dofIndex=0; i_dofIndex<numTestTraceDofsIncludingInterior; i_dofIndex++) { if (remappedTraceIndices.find(i_dofIndex) == remappedTraceIndices.end()) { continue; } int i_remapped = remappedTraceIndices[i_dofIndex]; for (int j_dofIndex=0; j_dofIndex<numTestTraceDofsIncludingInterior; j_dofIndex++) { if (remappedTraceIndices.find(j_dofIndex) == remappedTraceIndices.end()) { continue; } int j_remapped = remappedTraceIndices[j_dofIndex]; ipMatrixTrace(cellOrdinal,i_remapped,j_remapped) = ipMatrixTraceIncludingInterior(cellOrdinal,i_dofIndex,j_dofIndex); } } } testMatrixAssemblyTime += timer.ElapsedTime(); // cout << "ipMatrix:\n" << ipMatrix; timer.ResetStartTime(); cout << "NOTE: we do not yet enforce continuity on the trace test space.\n"; // I *think* this is fine, but I'm not dead certain -- we do of course in the end enforce continuity in GDAMinimumRule // now, determine the trace part of the bilinear form matrix FieldContainer<double> bfMatrixTraceTraceIncludingTestInterior(numCells,testOrderTrace->totalDofs(),traceOrder->totalDofs()); FieldContainer<double> bfMatrixFieldTraceIncludingTestInterior(numCells,testOrderTrace->totalDofs(),fieldOrder->totalDofs()); for (int eqn=0; eqn<numEquations; eqn++) { VarPtr traceVar = _virtualTerms.getTraceVars()[eqn]; LinearTermPtr termTraced = traceVar->termTraced(); LinearTermPtr strongOperator = _virtualTerms.getFieldOperators()[eqn]; VarPtr testVar = _virtualTerms.getFieldTestVars()[eqn]; // want to determine \hat{C}(\hat{e}_i, \phi_j) for \phi_j with support on the boundary // the \phi_j's with support on the boundary are the ones associated with the trace LinearTermPtr trialTerm = 1.0 * traceVar; LinearTermPtr testTerm; if (traceVar->varType() == TRACE) { testTerm = Function::normal() * testVar; } else { testTerm = 1.0 * testVar; } // trialTerm->integrate(bfMatrixTrace,traceOrder,testTerm,testOrderTrace,basisCache,basisCache->isSideCache()); trialTerm->integrate(bfMatrixTraceTraceIncludingTestInterior,traceOrder,testTerm,testOrderTrace,basisCache,basisCache->isSideCache()); termTraced->integrate(bfMatrixFieldTraceIncludingTestInterior,fieldOrder,-testTerm,testOrderTrace,basisCache,basisCache->isSideCache()); } FieldContainer<double> bfMatrixFieldTrace(numCells,numTestTraceDofs,bfMatrixFieldTraceIncludingTestInterior.dimension(2)); FieldContainer<double> bfMatrixTraceTrace(numCells,numTestTraceDofs,bfMatrixTraceTraceIncludingTestInterior.dimension(2)); for (int cellOrdinal=0; cellOrdinal<numCells; cellOrdinal++) { for (int i_dofIndex=0; i_dofIndex<numTestTraceDofsIncludingInterior; i_dofIndex++) { if (remappedTraceIndices.find(i_dofIndex) == remappedTraceIndices.end()) { continue; } int i_remapped = remappedTraceIndices[i_dofIndex]; for (int j_dofIndex=0; j_dofIndex<bfMatrixFieldTrace.dimension(2); j_dofIndex++) { bfMatrixFieldTrace(cellOrdinal,i_remapped,j_dofIndex) = bfMatrixFieldTraceIncludingTestInterior(cellOrdinal,i_dofIndex,j_dofIndex); } for (int j_dofIndex=0; j_dofIndex<bfMatrixTraceTrace.dimension(2); j_dofIndex++) { bfMatrixTraceTrace(cellOrdinal,i_remapped,j_dofIndex) = bfMatrixTraceTraceIncludingTestInterior(cellOrdinal,i_dofIndex,j_dofIndex); } } } Teuchos::Array<int> ipMatrixDim(2), bfMatrixTraceTraceDim(2), bfMatrixFieldTraceDim(2); Teuchos::Array<int> traceTraceStiffDim(2), fieldTraceStiffDim(2), fieldFieldStiffDim(2); ipMatrixDim[0] = ipMatrixTrace.dimension(1); ipMatrixDim[1] = ipMatrixTrace.dimension(2); bfMatrixTraceTraceDim[0] = bfMatrixTraceTrace.dimension(1); bfMatrixTraceTraceDim[1] = bfMatrixTraceTrace.dimension(2); bfMatrixFieldTraceDim[0] = bfMatrixFieldTrace.dimension(1); bfMatrixFieldTraceDim[1] = bfMatrixFieldTrace.dimension(2); traceTraceStiffDim[0] = traceOrder->totalDofs(); traceTraceStiffDim[1] = traceTraceStiffDim[0]; fieldTraceStiffDim[0] = fieldOrder->totalDofs(); fieldTraceStiffDim[1] = traceOrder->totalDofs(); // rectangular fieldFieldStiffDim[0] = fieldOrder->totalDofs(); fieldFieldStiffDim[1] = fieldOrder->totalDofs(); FieldContainer<double> traceTraceStiffCell(traceTraceStiffDim); FieldContainer<double> fieldTraceStiffCell(fieldTraceStiffDim); FieldContainer<double> fieldFieldStiffCell(fieldFieldStiffDim); for (int cellOrdinal=0; cellOrdinal<numCells; cellOrdinal++) { FieldContainer<double> ipMatrixCell(ipMatrixDim,&ipMatrixTrace(cellOrdinal,0,0)); FieldContainer<double> optTestCoeffsTraceTrace(numTestTraceDofs,traceOrder->totalDofs()); FieldContainer<double> bfMatrixTraceTraceCell(bfMatrixTraceTraceDim,&bfMatrixTraceTrace(cellOrdinal,0,0)); int result = SerialDenseWrapper::solveSystemUsingQR(optTestCoeffsTraceTrace, ipMatrixCell, bfMatrixTraceTraceCell); SerialDenseWrapper::multiply(traceTraceStiffCell, bfMatrixTraceTraceCell, optTestCoeffsTraceTrace, 'T', 'N'); // copy into the appropriate spot in localStiffness: for (int i=0; i<traceTraceStiffDim[0]; i++) { int i_stiff = stiffnessIndexForTraceIndex[i]; for (int j=0; j<traceTraceStiffDim[1]; j++) { int j_stiff = stiffnessIndexForTraceIndex[j]; localStiffness(cellOrdinal,i_stiff,j_stiff) = traceTraceStiffCell(i,j); } } // because of the way the matrix blocks line up, we actually don't have to do a second inversion of ipMatrixCell for this part FieldContainer<double> bfMatrixFieldTraceCell(bfMatrixFieldTraceDim,&bfMatrixFieldTrace(cellOrdinal,0,0)); SerialDenseWrapper::multiply(fieldTraceStiffCell, bfMatrixFieldTraceCell, optTestCoeffsTraceTrace, 'T', 'N'); // copy into the appropriate spots in localStiffness (taking advantage of symmetry): for (int i=0; i<fieldTraceStiffDim[0]; i++) { int i_stiff = stiffnessIndexForFieldIndex[i]; for (int j=0; j<fieldTraceStiffDim[1]; j++) { int j_stiff = stiffnessIndexForTraceIndex[j]; localStiffness(cellOrdinal,i_stiff,j_stiff) = fieldTraceStiffCell(i,j); localStiffness(cellOrdinal,j_stiff,i_stiff) = fieldTraceStiffCell(i,j); } } // because of the way the matrix blocks line up, we do have some trace contributions in the (field, field) portion of the matrix // these get added to the field contributions (hence the +=) FieldContainer<double> optTestCoeffsFieldTrace(numTestTraceDofs,fieldOrder->totalDofs()); result = SerialDenseWrapper::solveSystemUsingQR(optTestCoeffsFieldTrace, ipMatrixCell, bfMatrixFieldTraceCell); SerialDenseWrapper::multiply(fieldFieldStiffCell, bfMatrixFieldTraceCell, optTestCoeffsFieldTrace, 'T', 'N'); for (int i=0; i<fieldFieldStiffDim[0]; i++) { int i_stiff = stiffnessIndexForFieldIndex[i]; for (int j=0; j<fieldFieldStiffDim[1]; j++) { int j_stiff = stiffnessIndexForFieldIndex[j]; localStiffness(cellOrdinal,i_stiff,j_stiff) += fieldFieldStiffCell(i,j); } } } testMatrixInversionTime += timer.ElapsedTime(); // cout << "optTestCoeffs:\n" << optTestCoeffs; if (printTimings) { cout << "testMatrixAssemblyTime: " << testMatrixAssemblyTime << " seconds.\n"; cout << "testMatrixInversionTime: " << testMatrixInversionTime << " seconds.\n"; cout << "localStiffnessDeterminationFromTestsTime: " << localStiffnessDeterminationFromTestsTime << " seconds.\n"; } }