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;

}
Exemple #2
0
void Boundary::bcsToImpose( map<  GlobalIndexType, Scalar > &globalDofIndicesAndValues, TBC<Scalar> &bc,
                            GlobalIndexType cellID, DofInterpreter* dofInterpreter)
{
  // this is where we actually compute the BCs; the other bcsToImpose variants call this one.
  CellPtr cell = _mesh->getTopology()->getCell(cellID);

  // define a couple of important inner products:
  TIPPtr<Scalar> ipL2 = Teuchos::rcp( new TIP<Scalar> );
  TIPPtr<Scalar> ipH1 = Teuchos::rcp( new TIP<Scalar> );
  VarFactoryPtr varFactory = VarFactory::varFactory();
  VarPtr trace = varFactory->traceVar("trace");
  VarPtr flux = varFactory->traceVar("flux");
  ipL2->addTerm(flux);
  ipH1->addTerm(trace);
  ipH1->addTerm(trace->grad());
  ElementTypePtr elemType = _mesh->getElementType(cellID);
  DofOrderingPtr trialOrderingPtr = elemType->trialOrderPtr;
  vector< int > trialIDs = _mesh->bilinearForm()->trialIDs();

  vector<unsigned> boundarySides = cell->boundarySides();
  if (boundarySides.size() > 0)
  {
    BasisCachePtr basisCache = BasisCache::basisCacheForCell(_mesh, cellID);
    for (vector< int >::iterator trialIt = trialIDs.begin(); trialIt != trialIDs.end(); trialIt++)
    {
      int trialID = *(trialIt);
      if ( bc.bcsImposed(trialID) )
      {
//        // DEBUGGING: keep track of which sides we impose BCs on:
//        set<unsigned> bcImposedSides;
//
        // Determine global dof indices and values, in one pass per side
        for (int i=0; i<boundarySides.size(); i++)
        {
          unsigned sideOrdinal = boundarySides[i];
          // TODO: here, we need to treat the volume basis case.
          /*
           To do this:
           1. (Determine which dofs in the basis have support on the side.)
           2. (Probably should resize dirichletValues to match number of dofs with support on the side.)
           3. (Within coefficientsForBC, and the projection method it calls, when it's a side cache, check whether the basis being projected has a higher dimension.  If so, do the same determination regarding the support of basis on the side as #1.)
           4. DofInterpreter::interpretLocalBasisCoefficients() needs to handle the case that trialID has volume support, and in this case interpret the provided data appropriately.
           */
          
          BasisPtr basis;
          int numDofsSide;
          if (trialOrderingPtr->getSidesForVarID(trialID).size() == 1)
          {
            // volume basis
            basis = trialOrderingPtr->getBasis(trialID);
            // get the dof ordinals for the side (interpreted as a "continuous" basis)
            numDofsSide = basis->dofOrdinalsForSide(sideOrdinal).size();
          }
          else if (! trialOrderingPtr->hasBasisEntry(trialID, sideOrdinal))
          {
            continue;
          }
          else
          {
            basis = trialOrderingPtr->getBasis(trialID,sideOrdinal);
            numDofsSide = basis->getCardinality();
          }
          
          GlobalIndexType numCells = 1;
          if (numCells > 0)
          {
            FieldContainer<double> dirichletValues(numCells,numDofsSide);
            // project bc function onto side basis:
            BCPtr bcPtr = Teuchos::rcp(&bc, false);
            Teuchos::RCP<BCFunction<double>> bcFunction = BCFunction<double>::bcFunction(bcPtr, trialID);
            bcPtr->coefficientsForBC(dirichletValues, bcFunction, basis, basisCache->getSideBasisCache(sideOrdinal));
            dirichletValues.resize(numDofsSide);
            if (bcFunction->imposeOnCell(0))
            {
              FieldContainer<double> globalData;
              FieldContainer<GlobalIndexType> globalDofIndices;

              dofInterpreter->interpretLocalBasisCoefficients(cellID, trialID, sideOrdinal, dirichletValues, globalData, globalDofIndices);
              for (int globalDofOrdinal=0; globalDofOrdinal<globalDofIndices.size(); globalDofOrdinal++)
              {
                GlobalIndexType globalDofIndex = globalDofIndices(globalDofOrdinal);
                Scalar value = globalData(globalDofOrdinal);
                
                // sanity check: if this has been previously set, do the two values roughly agree?
                if (globalDofIndicesAndValues.find(globalDofIndex) != globalDofIndicesAndValues.end())
                {
                  double tol = 1e-10;
                  Scalar prevValue = globalDofIndicesAndValues[globalDofIndex];
                  double absDiff = abs(prevValue - value);
                  if (absDiff > tol)
                  {
                    double relativeDiff = absDiff / max(abs(prevValue),abs(value));
                    int rank = _mesh->Comm()->MyPID();
                    if (relativeDiff > tol)
                    {
                      cout << "WARNING: in Boundary::bcsToImpose(), inconsistent values for BC: " << prevValue << " and ";
                      cout << value << " prescribed for global dof index " << globalDofIndex;
                      cout << " on rank " << rank << endl;
                    }
                  }
                }
                globalDofIndicesAndValues[globalDofIndex] = value;
              }
            }
          }
        }
      }
    }
  }
}
// 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;
}
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);
}
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;
}
int main(int argc, char *argv[])
{
  // Process command line arguments
#ifdef HAVE_MPI
  Teuchos::GlobalMPISession mpiSession(&argc, &argv,0);
  int rank=mpiSession.getRank();
  int numProcs=mpiSession.getNProc();
#else
  int rank = 0;
  int numProcs = 1;
#endif

  ////////////////////   DECLARE VARIABLES   ///////////////////////
  // define test variables
  VarFactory varFactory;
  VarPtr v = varFactory.testVar("v", HGRAD);

  // define trial variables
  VarPtr beta_n_u_hat = varFactory.fluxVar("\\widehat{\\beta \\cdot n }");
  VarPtr u = varFactory.fieldVar("u");

  FunctionPtr beta = Teuchos::rcp(new Beta());

  ////////////////////   BUILD MESH   ///////////////////////
  BFPtr confusionBF = Teuchos::rcp( new BF(varFactory) );
  // define nodes for mesh
  FieldContainer<double> meshBoundary(4,2);

  meshBoundary(0,0) = -1.0; // x1
  meshBoundary(0,1) = -1.0; // y1
  meshBoundary(1,0) =  1.0;
  meshBoundary(1,1) = -1.0;
  meshBoundary(2,0) =  1.0;
  meshBoundary(2,1) =  1.0;
  meshBoundary(3,0) = -1.0;
  meshBoundary(3,1) =  1.0;

  int horizontalCells = 32, verticalCells = 32;

  // create a pointer to a new mesh:
  Teuchos::RCP<Mesh> mesh = Mesh::buildQuadMesh(meshBoundary, horizontalCells, verticalCells,
                            confusionBF, H1Order, H1Order+pToAdd);

  ////////////////////////////////////////////////////////////////////
  // INITIALIZE FLOW FUNCTIONS
  ////////////////////////////////////////////////////////////////////

  BCPtr nullBC = Teuchos::rcp((BC*)NULL);
  RHSPtr nullRHS = Teuchos::rcp((RHS*)NULL);
  IPPtr nullIP = Teuchos::rcp((IP*)NULL);
  SolutionPtr prevTimeFlow = Teuchos::rcp(new Solution(mesh, nullBC, nullRHS, nullIP) );
  SolutionPtr flowResidual = Teuchos::rcp(new Solution(mesh, nullBC, nullRHS, nullIP) );

  FunctionPtr u_prev_time = Teuchos::rcp( new PreviousSolutionFunction(prevTimeFlow, u) );

  ////////////////////   DEFINE BILINEAR FORM   ///////////////////////
  Teuchos::RCP<RHSEasy> rhs = Teuchos::rcp( new RHSEasy );
  FunctionPtr invDt = Teuchos::rcp(new ScalarParamFunction(1.0/dt));

  // v terms:
  confusionBF->addTerm( beta * u, - v->grad() );
  confusionBF->addTerm( beta_n_u_hat, v);

  confusionBF->addTerm( u, invDt*v );
  rhs->addTerm( u_prev_time * invDt * v );

  ////////////////////   SPECIFY RHS   ///////////////////////
  FunctionPtr f = Teuchos::rcp( new ConstantScalarFunction(0.0) );
  rhs->addTerm( f * v ); // obviously, with f = 0 adding this term is not necessary!

  ////////////////////   DEFINE INNER PRODUCT(S)   ///////////////////////
  // robust test norm
  IPPtr ip = confusionBF->graphNorm();
  // IPPtr ip = Teuchos::rcp(new IP);
  // ip->addTerm(v);
  // ip->addTerm(invDt*v - beta*v->grad());

  ////////////////////   CREATE BCs   ///////////////////////
  Teuchos::RCP<BCEasy> bc = Teuchos::rcp( new BCEasy );
  SpatialFilterPtr inflowBoundary = Teuchos::rcp( new InflowSquareBoundary(beta) );
  FunctionPtr u0 = Teuchos::rcp( new ConstantScalarFunction(0) );
  FunctionPtr n = Teuchos::rcp( new UnitNormalFunction );

  bc->addDirichlet(beta_n_u_hat, inflowBoundary, beta*n*u0);

  Teuchos::RCP<Solution> solution = Teuchos::rcp( new Solution(mesh, bc, rhs, ip) );

  // ==================== Register Solutions ==========================
  mesh->registerSolution(solution);
  mesh->registerSolution(prevTimeFlow);
  mesh->registerSolution(flowResidual);

  // ==================== SET INITIAL GUESS ==========================
  FunctionPtr u_init = Teuchos::rcp(new InitialCondition());
  map<int, Teuchos::RCP<Function> > functionMap;
  functionMap[u->ID()]      = u_init;

  prevTimeFlow->projectOntoMesh(functionMap);

  ////////////////////   SOLVE & REFINE   ///////////////////////
  // if (enforceLocalConservation) {
  //   // FunctionPtr parity = Teuchos::rcp<Function>( new SideParityFunction );
  //   // LinearTermPtr conservedQuantity = Teuchos::rcp<LinearTerm>( new LinearTerm(parity, beta_n_u_minus_sigma_n) );
  //   LinearTermPtr conservedQuantity = Teuchos::rcp<LinearTerm>( new LinearTerm(1.0, beta_n_u_minus_sigma_n) );
  //   LinearTermPtr sourcePart = Teuchos::rcp<LinearTerm>( new LinearTerm(invDt, u) );
  //   conservedQuantity->addTerm(sourcePart, true);
  //   solution->lagrangeConstraints()->addConstraint(conservedQuantity == u_prev_time * invDt);
  // }

  int timestepCount = 0;
  double time_tol = 1e-8;
  double L2_time_residual = 1e9;
  while((L2_time_residual > time_tol) && (timestepCount < numTimeSteps))
  {
    solution->solve(false);
    // Subtract solutions to get residual
    flowResidual->setSolution(solution);
    flowResidual->addSolution(prevTimeFlow, -1.0);
    L2_time_residual = flowResidual->L2NormOfSolutionGlobal(u->ID());

    if (rank == 0)
    {
      cout << endl << "Timestep: " << timestepCount << ", dt = " << dt << ", Time residual = " << L2_time_residual << endl;

      stringstream outfile;
      outfile << "rotatingCylinder_" << timestepCount;
      solution->writeToVTK(outfile.str(), 5);

      // Check local conservation
      FunctionPtr flux = Teuchos::rcp( new PreviousSolutionFunction(solution, beta_n_u_hat) );
      FunctionPtr source = Teuchos::rcp( new PreviousSolutionFunction(flowResidual, u) );
      source = invDt * source;
      Teuchos::Tuple<double, 3> fluxImbalances = checkConservation(flux, source, varFactory, mesh);
      cout << "Mass flux: Largest Local = " << fluxImbalances[0]
           << ", Global = " << fluxImbalances[1] << ", Sum Abs = " << fluxImbalances[2] << endl;
    }

    prevTimeFlow->setSolution(solution); // reset previous time solution to current time sol
    timestepCount++;
  }

  return 0;
}
Exemple #7
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);
  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[])
{
  Teuchos::GlobalMPISession mpiSession(&argc, &argv, 0);
  
  int spaceDim = 2;
  int meshWidth = 2;
  bool conformingTraces = true;
  int H1Order = 2, delta_k = 3;
  double domainWidth = 1.0e-3;
  bool diagScaling = false;
  double h = domainWidth / meshWidth;
  double weight = h / 4.0; // ratio of area of square with sidelength h to its perimeter
  
  double sigma_weight = 1.0; // h / 4.0; // sigma = sigma_weight * u->grad()

  Space uHatSpace = conformingTraces ? HGRAD : L2;
  
  VarFactoryPtr vf = VarFactory::varFactory();
  
  // fields
  VarPtr u = vf->fieldVar("u");
  VarPtr sigma = vf->fieldVar("sigma", VECTOR_L2);
  
  // traces
  VarPtr u_hat = vf->traceVar("u_hat", uHatSpace);
  VarPtr sigma_n = vf->fluxVar("sigma_n");
  
  // tests
  VarPtr v = vf->testVar("v", HGRAD);
  VarPtr tau = vf->testVar("tau", HDIV);
  
  BFPtr bf = BF::bf(vf);
  
// standard BF:
//  bf->addTerm(sigma, v->grad());
//  bf->addTerm(sigma_n, v);
//  
//  bf->addTerm(sigma, tau);
//  bf->addTerm(u, tau->div());
//  bf->addTerm(-u_hat, tau->dot_normal());
  
  // weighted BF:
  bf->addTerm(sigma, v->grad());
  bf->addTerm(weight * sigma_n, v);
  
  bf->addTerm(sigma, tau);
  bf->addTerm(sigma_weight * u, tau->div());
  bf->addTerm(- sigma_weight * weight * u_hat, tau->dot_normal());
  
  IPPtr ip = IP::ip();
// standard IP:
  ip->addTerm(tau + v->grad());
  ip->addTerm(tau->div());
  ip->addTerm(v);
  ip->addTerm(tau);
  
  // weighted IP:
//  ip->addTerm(tau + v->grad());
//  ip->addTerm(sigma_weight * tau->div());
//  ip->addTerm(max(sigma_weight,1e-3) * v);
//  ip->addTerm(sigma_weight * weight * tau);
  
  BCPtr bc = BC::bc();
  bc->addDirichlet(u_hat, SpatialFilter::allSpace(), Function::zero());
  
  RHSPtr rhs = RHS::rhs();
  rhs->addTerm(1.0 * sigma_weight * v);
  
  vector<double> dimensions(spaceDim,domainWidth);
  vector<int> elementCounts(spaceDim,meshWidth);
  
  MeshPtr mesh = MeshFactory::rectilinearMesh(bf, dimensions, elementCounts, H1Order, delta_k);
  
  SolutionPtr soln = Solution::solution(mesh, bc, rhs, ip);
  
  soln->setUseCondensedSolve(true);
  soln->initializeLHSVector();
  soln->initializeStiffnessAndLoad();
  soln->populateStiffnessAndLoad();
  
  Teuchos::RCP<Epetra_RowMatrix> stiffness = soln->getStiffnessMatrix();
  
  double condNumber = conditionNumberLAPACK(*stiffness, diagScaling);
  
  cout << "condest (1-norm): " << condNumber << endl;
  
  return 0;
}
int main(int argc, char *argv[])
{
#ifdef HAVE_MPI
  Teuchos::GlobalMPISession mpiSession(&argc, &argv,0);
  choice::MpiArgs args( argc, argv );
#else
  choice::Args args( argc, argv );
#endif
  int commRank = Teuchos::GlobalMPISession::getRank();
  int numProcs = Teuchos::GlobalMPISession::getNProc();

  // Required arguments
  int numRefs = args.Input<int>("--numRefs", "number of refinement steps");
  bool enforceLocalConservation = args.Input<bool>("--conserve", "enforce local conservation");
  bool steady = args.Input<bool>("--steady", "run steady rather than transient");

  // Optional arguments (have defaults)
  double dt = args.Input("--dt", "time step", 0.25);
  int numTimeSteps = args.Input("--nt", "number of time steps", 20);
  halfWidth = args.Input("--halfWidth", "half width of inlet profile", 1.0);
  args.Process();

  ////////////////////   DECLARE VARIABLES   ///////////////////////
  // define test variables
  VarFactory varFactory;
  VarPtr v = varFactory.testVar("v", HGRAD);

  // define trial variables
  VarPtr beta_n_u_hat = varFactory.fluxVar("\\widehat{\\beta \\cdot n }");
  VarPtr u = varFactory.fieldVar("u");

  vector<double> beta;
  beta.push_back(1.0);
  beta.push_back(0.0);

  ////////////////////   BUILD MESH   ///////////////////////
  BFPtr bf = Teuchos::rcp( new BF(varFactory) );
  // define nodes for mesh
  FieldContainer<double> meshBoundary(4,2);

  meshBoundary(0,0) =  0.0; // x1
  meshBoundary(0,1) = -2.0; // y1
  meshBoundary(1,0) =  4.0;
  meshBoundary(1,1) = -2.0;
  meshBoundary(2,0) =  4.0;
  meshBoundary(2,1) =  2.0;
  meshBoundary(3,0) =  0.0;
  meshBoundary(3,1) =  2.0;

  int horizontalCells = 8, verticalCells = 8;

  // create a pointer to a new mesh:
  Teuchos::RCP<Mesh> mesh = Mesh::buildQuadMesh(meshBoundary, horizontalCells, verticalCells,
                            bf, H1Order, H1Order+pToAdd);

  ////////////////////////////////////////////////////////////////////
  // INITIALIZE FLOW FUNCTIONS
  ////////////////////////////////////////////////////////////////////

  BCPtr nullBC = Teuchos::rcp((BC*)NULL);
  RHSPtr nullRHS = Teuchos::rcp((RHS*)NULL);
  IPPtr nullIP = Teuchos::rcp((IP*)NULL);
  SolutionPtr prevTimeFlow = Teuchos::rcp(new Solution(mesh, nullBC, nullRHS, nullIP) );
  SolutionPtr flowResidual = Teuchos::rcp(new Solution(mesh, nullBC, nullRHS, nullIP) );

  FunctionPtr u_prev_time = Teuchos::rcp( new PreviousSolutionFunction(prevTimeFlow, u) );

  ////////////////////   DEFINE BILINEAR FORM   ///////////////////////
  Teuchos::RCP<RHSEasy> rhs = Teuchos::rcp( new RHSEasy );
  FunctionPtr invDt = Teuchos::rcp(new ScalarParamFunction(1.0/dt));

  // v terms:
  bf->addTerm( beta * u, - v->grad() );
  bf->addTerm( beta_n_u_hat, v);

  if (!steady)
  {
    bf->addTerm( u, invDt*v );
    rhs->addTerm( u_prev_time * invDt * v );
  }

  ////////////////////   SPECIFY RHS   ///////////////////////
  FunctionPtr f = Teuchos::rcp( new ConstantScalarFunction(0.0) );
  rhs->addTerm( f * v ); // obviously, with f = 0 adding this term is not necessary!

  ////////////////////   DEFINE INNER PRODUCT(S)   ///////////////////////
  IPPtr ip = bf->graphNorm();
  // ip->addTerm(v);
  // ip->addTerm(beta*v->grad());

  ////////////////////   CREATE BCs   ///////////////////////
  Teuchos::RCP<BCEasy> bc = Teuchos::rcp( new BCEasy );
  SpatialFilterPtr lBoundary = Teuchos::rcp( new LeftBoundary );
  FunctionPtr u1 = Teuchos::rcp( new InletBC );
  bc->addDirichlet(beta_n_u_hat, lBoundary, -u1);

  Teuchos::RCP<Solution> solution = Teuchos::rcp( new Solution(mesh, bc, rhs, ip) );

  // ==================== Register Solutions ==========================
  mesh->registerSolution(solution);
  mesh->registerSolution(prevTimeFlow);
  mesh->registerSolution(flowResidual);

  // ==================== SET INITIAL GUESS ==========================
  double u_free = 0.0;
  map<int, Teuchos::RCP<Function> > functionMap;
  // functionMap[u->ID()]      = Teuchos::rcp( new ConInletBC
  functionMap[u->ID()]      = Teuchos::rcp( new InletBC );

  prevTimeFlow->projectOntoMesh(functionMap);

  ////////////////////   SOLVE & REFINE   ///////////////////////
  if (enforceLocalConservation)
  {
    if (steady)
    {
      FunctionPtr zero = Teuchos::rcp( new ConstantScalarFunction(0.0) );
      solution->lagrangeConstraints()->addConstraint(beta_n_u_hat == zero);
    }
    else
    {
      // FunctionPtr parity = Teuchos::rcp<Function>( new SideParityFunction );
      // LinearTermPtr conservedQuantity = Teuchos::rcp<LinearTerm>( new LinearTerm(parity, beta_n_u_minus_sigma_n) );
      LinearTermPtr conservedQuantity = Teuchos::rcp<LinearTerm>( new LinearTerm(1.0, beta_n_u_hat) );
      LinearTermPtr sourcePart = Teuchos::rcp<LinearTerm>( new LinearTerm(invDt, u) );
      conservedQuantity->addTerm(sourcePart, true);
      solution->lagrangeConstraints()->addConstraint(conservedQuantity == u_prev_time * invDt);
    }
  }

  double energyThreshold = 0.2; // for mesh refinements
  RefinementStrategy refinementStrategy( solution, energyThreshold );
  VTKExporter exporter(solution, mesh, varFactory);

  for (int refIndex=0; refIndex<=numRefs; refIndex++)
  {
    if (steady)
    {
      solution->solve(false);

      if (commRank == 0)
      {
        stringstream outfile;
        outfile << "Convection_" << refIndex;
        exporter.exportSolution(outfile.str());

        // Check local conservation
        FunctionPtr flux = Teuchos::rcp( new PreviousSolutionFunction(solution, beta_n_u_hat) );
        FunctionPtr zero = Teuchos::rcp( new ConstantScalarFunction(0.0) );
        Teuchos::Tuple<double, 3> fluxImbalances = checkConservation(flux, zero, varFactory, mesh);
        cout << "Mass flux: Largest Local = " << fluxImbalances[0]
             << ", Global = " << fluxImbalances[1] << ", Sum Abs = " << fluxImbalances[2] << endl;
      }
    }
    else
    {
      int timestepCount = 0;
      double time_tol = 1e-8;
      double L2_time_residual = 1e9;
      // cout << L2_time_residual <<" "<< time_tol << timestepCount << numTimeSteps << endl;
      while((L2_time_residual > time_tol) && (timestepCount < numTimeSteps))
      {
        solution->solve(false);
        // Subtract solutions to get residual
        flowResidual->setSolution(solution);
        flowResidual->addSolution(prevTimeFlow, -1.0);
        L2_time_residual = flowResidual->L2NormOfSolutionGlobal(u->ID());

        if (commRank == 0)
        {
          cout << endl << "Timestep: " << timestepCount << ", dt = " << dt << ", Time residual = " << L2_time_residual << endl;

          stringstream outfile;
          outfile << "TransientConvection_" << refIndex << "-" << timestepCount;
          exporter.exportSolution(outfile.str());

          // Check local conservation
          FunctionPtr flux = Teuchos::rcp( new PreviousSolutionFunction(solution, beta_n_u_hat) );
          FunctionPtr source = Teuchos::rcp( new PreviousSolutionFunction(flowResidual, u) );
          source = -invDt * source;
          Teuchos::Tuple<double, 3> fluxImbalances = checkConservation(flux, source, varFactory, mesh);
          cout << "Mass flux: Largest Local = " << fluxImbalances[0]
               << ", Global = " << fluxImbalances[1] << ", Sum Abs = " << fluxImbalances[2] << endl;
        }

        prevTimeFlow->setSolution(solution); // reset previous time solution to current time sol
        timestepCount++;
      }
    }

    if (refIndex < numRefs)
      refinementStrategy.refine(commRank==0); // print to console on commRank 0
  }

  return 0;
}
bool VectorizedBasisTestSuite::testPoisson()
{
  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 sigma_n = varFactory->fluxVar("\\widehat{\\sigma_{n}}");
  VarPtr u = varFactory->fieldVar("u");
  VarPtr sigma = varFactory->fieldVar("\\sigma", VECTOR_L2);

  ////////////////////   DEFINE BILINEAR FORM   ///////////////////////
  BFPtr bf = Teuchos::rcp( new BF(varFactory) );
  // tau terms:
  bf->addTerm(sigma, tau);
  bf->addTerm(u, tau->div());
  bf->addTerm(-uhat, tau->dot_normal());

  // v terms:
  bf->addTerm( sigma, v->grad() );
  bf->addTerm( -sigma_n, v);

  ////////////////////   DEFINE INNER PRODUCT(S)   ///////////////////////
  IPPtr ip = bf->graphNorm();

  ////////////////////   SPECIFY RHS   ///////////////////////
  RHSPtr rhs = RHS::rhs();
  FunctionPtr f = Function::constant(1.0);
  rhs->addTerm( f * v );

  ////////////////////   CREATE BCs   ///////////////////////
  BCPtr bc = BC::bc();
  SpatialFilterPtr boundary = SpatialFilter::allSpace();
  FunctionPtr zero = Function::zero();
  bc->addDirichlet(uhat, boundary, zero);

  ////////////////////   BUILD MESH   ///////////////////////
  int H1Order = 3, pToAdd = 2;
  // define nodes for mesh
  FieldContainer<double> meshBoundary(4,2);

  meshBoundary(0,0) = 0.0; // x1
  meshBoundary(0,1) = 0.0; // y1
  meshBoundary(1,0) = 1.0;
  meshBoundary(1,1) = 0.0;
  meshBoundary(2,0) = 1.0;
  meshBoundary(2,1) = 1.0;
  meshBoundary(3,0) = 0.0;
  meshBoundary(3,1) = 1.0;

  int horizontalCells = 1, verticalCells = 1;

  // create a pointer to a new mesh:
  Teuchos::RCP<Mesh> mesh = MeshFactory::buildQuadMesh(meshBoundary, horizontalCells, verticalCells,
                            bf, H1Order, H1Order+pToAdd, false);

  ////////////////////   SOLVE & REFINE   ///////////////////////
  Teuchos::RCP<Solution> solution = Teuchos::rcp( new Solution(mesh, bc, rhs, ip) );
  double energyThreshold = 0.2; // for mesh refinements
  RefinementStrategy refinementStrategy( solution, energyThreshold );
#ifdef USE_VTK
  VTKExporter exporter(solution, mesh, varFactory);
#endif

  for (int refIndex=0; refIndex<=4; refIndex++)
  {
    solution->solve(false);
#ifdef USE_VTK
    // output commented out because it's not properly part of the test.
//    stringstream outfile;
//    outfile << "test_" << refIndex;
//    exporter.exportSolution(outfile.str());
#endif

    if (refIndex < 4)
      refinementStrategy.refine(false); // don't print to console
  }
  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
  ////////////////////   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_const;
  beta_const.push_back(1.0);
  beta_const.push_back(0.0);
//  FunctionPtr beta = Teuchos::rcp(new Beta());

  double eps = 1e-2;

  ////////////////////   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( beta_const * u, - v->grad() );
  confusionBF->addTerm( beta_n_u_minus_sigma_n, v);

  ////////////////////   DEFINE INNER PRODUCT(S)   ///////////////////////
  // 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 / eps + v->grad() );
  qoptIP->addTerm( beta_const * v->grad() - tau->div() );

  // robust test norm
  IPPtr robIP = Teuchos::rcp(new IP);
  FunctionPtr ip_scaling = Teuchos::rcp( new EpsilonScaling(eps) );
  if (enforceLocalConservation)
  {
    robIP->addZeroMeanTerm( v );
  }
  else
  {
    robIP->addTerm( ip_scaling * v );
  }

  robIP->addTerm( sqrt(eps) * v->grad() );
  robIP->addTerm( beta_const * v->grad() );
  robIP->addTerm( tau->div() );
  robIP->addTerm( ip_scaling/sqrt(eps) * tau );

  ////////////////////   SPECIFY RHS   ///////////////////////
  FunctionPtr zero = Teuchos::rcp( new ConstantScalarFunction(0.0) );
  Teuchos::RCP<RHSEasy> rhs = Teuchos::rcp( new RHSEasy );
  FunctionPtr f = zero;
  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 );

  SpatialFilterPtr inflowTop = Teuchos::rcp(new InflowLshapeTop);
  SpatialFilterPtr inflowBot = Teuchos::rcp(new InflowLshapeBottom);
  SpatialFilterPtr LshapeBot1 = Teuchos::rcp(new LshapeBottom1);
  SpatialFilterPtr LshapeBot2 = Teuchos::rcp(new LshapeBottom2);
  SpatialFilterPtr Top = Teuchos::rcp(new LshapeTop);
  SpatialFilterPtr Out = Teuchos::rcp(new LshapeOutflow);

  FunctionPtr u0 = Teuchos::rcp( new U0 );
  bc->addDirichlet(uhat, LshapeBot1, u0);
  bc->addDirichlet(uhat, LshapeBot2, u0);
  bc->addDirichlet(uhat, Top, u0);
  bc->addDirichlet(uhat, Out, u0);

  FunctionPtr n = Teuchos::rcp( new UnitNormalFunction );
  //  bc->addDirichlet(uhat, inflowBot, u0);
  FunctionPtr u0Top = Teuchos::rcp(new ParabolicProfile);
  FunctionPtr u0Bot = Teuchos::rcp(new LinearProfile);
  bc->addDirichlet(beta_n_u_minus_sigma_n, inflowTop, beta_const*n*u0Top);
  //  bc->addDirichlet(beta_n_u_minus_sigma_n, inflowBot, beta_const*n*u0Bot);
  bc->addDirichlet(beta_n_u_minus_sigma_n, inflowBot, beta_const*n*zero);

  ////////////////////   BUILD MESH   ///////////////////////
  // define nodes for mesh
  int H1Order = 2, 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 horizontalCells = 1, verticalCells = 1;

  // create a pointer to a new mesh:
  Teuchos::RCP<Mesh> mesh = Mesh::buildQuadMesh(quadPoints, horizontalCells, verticalCells,
                                                confusionBF, H1Order, H1Order+pToAdd);
  */

  Teuchos::RCP<Mesh> mesh;
  // L-shaped domain for double ramp problem
  FieldContainer<double> A(2), B(2), C(2), D(2), E(2), F(2), G(2), H(2);
  A(0) = 0.0;
  A(1) = 0.5;
  B(0) = 0.0;
  B(1) = 1.0;
  C(0) = 0.5;
  C(1) = 1.0;
  D(0) = 1.0;
  D(1) = 1.0;
  E(0) = 1.0;
  E(1) = 0.5;
  F(0) = 1.0;
  F(1) = 0.0;
  G(0) = 0.5;
  G(1) = 0.0;
  H(0) = 0.5;
  H(1) = 0.5;
  vector<FieldContainer<double> > vertices;
  vertices.push_back(A);
  int A_index = 0;
  vertices.push_back(B);
  int B_index = 1;
  vertices.push_back(C);
  int C_index = 2;
  vertices.push_back(D);
  int D_index = 3;
  vertices.push_back(E);
  int E_index = 4;
  vertices.push_back(F);
  int F_index = 5;
  vertices.push_back(G);
  int G_index = 6;
  vertices.push_back(H);
  int H_index = 7;
  vector< vector<int> > elementVertices;
  vector<int> el1, el2, el3, el4, el5;
  // left patch:
  el1.push_back(A_index);
  el1.push_back(H_index);
  el1.push_back(C_index);
  el1.push_back(B_index);
  // top right:
  el2.push_back(H_index);
  el2.push_back(E_index);
  el2.push_back(D_index);
  el2.push_back(C_index);
  // bottom right:
  el3.push_back(G_index);
  el3.push_back(F_index);
  el3.push_back(E_index);
  el3.push_back(H_index);

  elementVertices.push_back(el1);
  elementVertices.push_back(el2);
  elementVertices.push_back(el3);

  mesh = Teuchos::rcp( new Mesh(vertices, elementVertices, confusionBF, H1Order, pToAdd) );

  ////////////////////   SOLVE & REFINE   ///////////////////////
  // Teuchos::RCP<Solution> solution = Teuchos::rcp( new Solution(mesh, bc, rhs, qoptIP) );
  Teuchos::RCP<Solution> solution = Teuchos::rcp( new Solution(mesh, bc, rhs, robIP) );
  // solution->setFilter(pc);

  if (enforceLocalConservation)
  {
    FunctionPtr zero = Teuchos::rcp( new ConstantScalarFunction(0.0) );
    solution->lagrangeConstraints()->addConstraint(beta_n_u_minus_sigma_n == zero);
  }

  double energyThreshold = 0.2; // for mesh refinements
  RefinementStrategy refinementStrategy( solution, energyThreshold );

  int numRefs = 8;

  for (int refIndex=0; refIndex<numRefs; refIndex++)
  {
    solution->solve(false);
    refinementStrategy.refine(rank==0); // print to console on rank 0
  }
  // one more solve on the final refined mesh:
  solution->solve(false);

  if (rank==0)
  {
    solution->writeToVTK("step.vtu",min(H1Order+1,4));
    solution->writeFluxesToFile(uhat->ID(), "uhat.dat");

    cout << "wrote files: u.m, uhat.dat\n";
  }

  return 0;
}
int main(int argc, char *argv[])
{
#ifdef HAVE_MPI
    Teuchos::GlobalMPISession mpiSession(&argc, &argv,0);
    int rank=mpiSession.getRank();
    int numProcs=mpiSession.getNProc();
#else
    int rank = 0;
    int numProcs = 1;
#endif
    int polyOrder = 2;

    // define our manufactured solution or problem bilinear form:
    double epsilon = 1e-3;
    bool useTriangles = false;

    int pToAdd = 2;
    int nCells = 2;
    if ( argc > 1)
    {
        nCells = atoi(argv[1]);
        if (rank==0)
        {
            cout << "numCells = " << nCells << endl;
        }
    }
    int numSteps = 20;
    if ( argc > 2)
    {
        numSteps = atoi(argv[2]);
        if (rank==0)
        {
            cout << "num NR steps = " << numSteps << endl;
        }
    }
    int useHessian = 0; // defaults to "not use"
    if ( argc > 3)
    {
        useHessian = atoi(argv[3]);
        if (rank==0)
        {
            cout << "useHessian = " << useHessian << endl;
        }
    }

    int thresh = numSteps; // threshhold for when to apply linesearch/hessian
    if ( argc > 4)
    {
        thresh = atoi(argv[4]);
        if (rank==0)
        {
            cout << "thresh = " << thresh << endl;
        }
    }

    int H1Order = polyOrder + 1;

    double energyThreshold = 0.2; // for mesh refinements
    double nonlinearStepSize = 0.5;
    double nonlinearRelativeEnergyTolerance = 1e-8; // used to determine convergence of the nonlinear solution

    ////////////////////////////////////////////////////////////////////
    // DEFINE VARIABLES
    ////////////////////////////////////////////////////////////////////

    // new-style bilinear form definition
    VarFactory varFactory;
    VarPtr uhat = varFactory.traceVar("\\widehat{u}");
    VarPtr beta_n_u_minus_sigma_hat = varFactory.fluxVar("\\widehat{\\beta_n u - \\sigma_n}");
    VarPtr u = varFactory.fieldVar("u");
    VarPtr sigma1 = varFactory.fieldVar("\\sigma_1");
    VarPtr sigma2 = varFactory.fieldVar("\\sigma_2");

    VarPtr tau = varFactory.testVar("\\tau",HDIV);
    VarPtr v = varFactory.testVar("v",HGRAD);
    BFPtr bf = Teuchos::rcp( new BF(varFactory) ); // initialize bilinear form

    ////////////////////////////////////////////////////////////////////
    // CREATE MESH
    ////////////////////////////////////////////////////////////////////

    // create a pointer to a new mesh:
    Teuchos::RCP<Mesh> mesh = MeshUtilities::buildUnitQuadMesh(nCells, bf, H1Order, H1Order+pToAdd);
    mesh->setPartitionPolicy(Teuchos::rcp(new ZoltanMeshPartitionPolicy("HSFC")));

    ////////////////////////////////////////////////////////////////////
    // INITIALIZE BACKGROUND FLOW FUNCTIONS
    ////////////////////////////////////////////////////////////////////
    BCPtr nullBC = Teuchos::rcp((BC*)NULL);
    RHSPtr nullRHS = Teuchos::rcp((RHS*)NULL);
    IPPtr nullIP = Teuchos::rcp((IP*)NULL);
    SolutionPtr backgroundFlow = Teuchos::rcp(new Solution(mesh, nullBC,
                                 nullRHS, nullIP) );

    vector<double> e1(2); // (1,0)
    e1[0] = 1;
    vector<double> e2(2); // (0,1)
    e2[1] = 1;

    FunctionPtr u_prev = Teuchos::rcp( new PreviousSolutionFunction(backgroundFlow, u) );
    FunctionPtr beta = e1 * u_prev + Teuchos::rcp( new ConstantVectorFunction( e2 ) );

    ////////////////////////////////////////////////////////////////////
    // DEFINE BILINEAR FORM
    ////////////////////////////////////////////////////////////////////

    // tau parts:
    // 1/eps (sigma, tau)_K + (u, div tau)_K - (u_hat, tau_n)_dK
    bf->addTerm(sigma1 / epsilon, tau->x());
    bf->addTerm(sigma2 / epsilon, tau->y());
    bf->addTerm(u, tau->div());
    bf->addTerm( - uhat, tau->dot_normal() );

    // v:
    // (sigma, grad v)_K - (sigma_hat_n, v)_dK - (u, beta dot grad v) + (u_hat * n dot beta, v)_dK
    bf->addTerm( sigma1, v->dx() );
    bf->addTerm( sigma2, v->dy() );
    bf->addTerm( -u, beta * v->grad());
    bf->addTerm( beta_n_u_minus_sigma_hat, v);

    // ==================== SET INITIAL GUESS ==========================
    mesh->registerSolution(backgroundFlow);
    FunctionPtr zero = Teuchos::rcp( new ConstantScalarFunction(0.0) );
    FunctionPtr u0 = Teuchos::rcp( new U0 );

    map<int, Teuchos::RCP<Function> > functionMap;
    functionMap[u->ID()] = u0;
    functionMap[sigma1->ID()] = zero;
    functionMap[sigma2->ID()] = zero;

    backgroundFlow->projectOntoMesh(functionMap);
    // ==================== END SET INITIAL GUESS ==========================

    ////////////////////////////////////////////////////////////////////
    // DEFINE INNER PRODUCT
    ////////////////////////////////////////////////////////////////////
    // function to scale the squared guy by epsilon/h
    FunctionPtr epsilonOverHScaling = Teuchos::rcp( new EpsilonScaling(epsilon) );
    IPPtr ip = Teuchos::rcp( new IP );
    ip->addTerm( epsilonOverHScaling * (1.0/sqrt(epsilon))* tau);
    ip->addTerm( tau->div());
    //  ip->addTerm( epsilonOverHScaling * v );
    ip->addTerm( v );
    ip->addTerm( sqrt(epsilon) * v->grad() );
    ip->addTerm(v->grad());
    //  ip->addTerm( beta * v->grad() );

    ////////////////////////////////////////////////////////////////////
    // DEFINE RHS
    ////////////////////////////////////////////////////////////////////
    RHSPtr rhs = RHS::rhs();
    FunctionPtr u_prev_squared_div2 = 0.5 * u_prev * u_prev;

    rhs->addTerm((e1 * u_prev_squared_div2 + e2 * u_prev) * v->grad() - u_prev * tau->div());

    ////////////////////////////////////////////////////////////////////
    // DEFINE DIRICHLET BC
    ////////////////////////////////////////////////////////////////////
    FunctionPtr n = Teuchos::rcp( new UnitNormalFunction );
    SpatialFilterPtr outflowBoundary = Teuchos::rcp( new TopBoundary);
    SpatialFilterPtr inflowBoundary = Teuchos::rcp( new NegatedSpatialFilter(outflowBoundary) );
    BCPtr inflowBC = BC::bc();
    FunctionPtr u0_squared_div_2 = 0.5 * u0 * u0;
    inflowBC->addDirichlet(beta_n_u_minus_sigma_hat,inflowBoundary,
                           ( e1 * u0_squared_div_2 + e2 * u0) * n );

    ////////////////////////////////////////////////////////////////////
    // CREATE SOLUTION OBJECT
    ////////////////////////////////////////////////////////////////////
    Teuchos::RCP<Solution> solution = Teuchos::rcp(new Solution(mesh, inflowBC, rhs, ip));
    mesh->registerSolution(solution);

    ////////////////////////////////////////////////////////////////////
    // WARNING: UNFINISHED HESSIAN BIT
    ////////////////////////////////////////////////////////////////////
    VarFactory hessianVars = varFactory.getBubnovFactory(VarFactory::BUBNOV_TRIAL);
    VarPtr du = hessianVars.test(u->ID());
    BFPtr hessianBF = Teuchos::rcp( new BF(hessianVars) ); // initialize bilinear form
    //  FunctionPtr e_v = Function::constant(1.0); // dummy error rep function for now - should do nothing

    FunctionPtr u_current  = Teuchos::rcp( new PreviousSolutionFunction(solution, u) );

    FunctionPtr sig1_prev = Teuchos::rcp( new PreviousSolutionFunction(solution, sigma1) );
    FunctionPtr sig2_prev = Teuchos::rcp( new PreviousSolutionFunction(solution, sigma2) );
    FunctionPtr sig_prev = (e1*sig1_prev + e2*sig2_prev);
    FunctionPtr fnhat = Teuchos::rcp(new PreviousSolutionFunction(solution,beta_n_u_minus_sigma_hat));
    FunctionPtr uhat_prev = Teuchos::rcp(new PreviousSolutionFunction(solution,uhat));
    LinearTermPtr residual = Teuchos::rcp(new LinearTerm);// residual
    residual->addTerm(fnhat*v - (e1 * (u_prev_squared_div2 - sig1_prev) + e2 * (u_prev - sig2_prev)) * v->grad());
    residual->addTerm((1/epsilon)*sig_prev * tau + u_prev * tau->div() - uhat_prev*tau->dot_normal());

    LinearTermPtr Bdu = Teuchos::rcp(new LinearTerm);// residual
    Bdu->addTerm( u_current*tau->div() - u_current*(beta*v->grad()));

    Teuchos::RCP<RieszRep> riesz = Teuchos::rcp(new RieszRep(mesh, ip, residual));
    Teuchos::RCP<RieszRep> duRiesz = Teuchos::rcp(new RieszRep(mesh, ip, Bdu));
    riesz->computeRieszRep();
    FunctionPtr e_v = Teuchos::rcp(new RepFunction(v,riesz));
    e_v->writeValuesToMATLABFile(mesh, "e_v.m");
    FunctionPtr posErrPart = Teuchos::rcp(new PositivePart(e_v->dx()));
    hessianBF->addTerm(e_v->dx()*u,du);
    //  hessianBF->addTerm(posErrPart*u,du);
    Teuchos::RCP<HessianFilter> hessianFilter = Teuchos::rcp(new HessianFilter(hessianBF));

    if (useHessian)
    {
        solution->setWriteMatrixToFile(true,"hessianStiffness.dat");
    }
    else
    {
        solution->setWriteMatrixToFile(true,"stiffness.dat");
    }

    Teuchos::RCP< LineSearchStep > LS_Step = Teuchos::rcp(new LineSearchStep(riesz));
    ofstream out;
    out.open("Burgers.txt");
    double NL_residual = 9e99;
    for (int i = 0; i<numSteps; i++)
    {
        solution->solve(false); // do one solve to initialize things...
        double stepLength = 1.0;
        stepLength = LS_Step->stepSize(backgroundFlow,solution, NL_residual);
        if (useHessian)
        {
            solution->setFilter(hessianFilter);
        }
        backgroundFlow->addSolution(solution,stepLength);
        NL_residual = LS_Step->getNLResidual();
        if (rank==0)
        {
            cout << "NL residual after adding = " << NL_residual << " with step size " << stepLength << endl;
            out << NL_residual << endl; // saves initial NL error
        }
    }
    out.close();


    ////////////////////////////////////////////////////////////////////
    // DEFINE REFINEMENT STRATEGY
    ////////////////////////////////////////////////////////////////////
    Teuchos::RCP<RefinementStrategy> refinementStrategy;
    refinementStrategy = Teuchos::rcp(new RefinementStrategy(solution,energyThreshold));

    int numRefs = 0;

    Teuchos::RCP<NonlinearStepSize> stepSize = Teuchos::rcp(new NonlinearStepSize(nonlinearStepSize));
    Teuchos::RCP<NonlinearSolveStrategy> solveStrategy;
    solveStrategy = Teuchos::rcp( new NonlinearSolveStrategy(backgroundFlow, solution, stepSize,
                                  nonlinearRelativeEnergyTolerance));

    ////////////////////////////////////////////////////////////////////
    // SOLVE
    ////////////////////////////////////////////////////////////////////

    for (int refIndex=0; refIndex<numRefs; refIndex++)
    {
        solveStrategy->solve(rank==0);       // print to console on rank 0
        refinementStrategy->refine(rank==0); // print to console on rank 0
    }
    //  solveStrategy->solve(rank==0);

    if (rank==0)
    {
        backgroundFlow->writeToVTK("Burgers.vtu",min(H1Order+1,4));
        solution->writeFluxesToFile(uhat->ID(), "burgers.dat");
        cout << "wrote solution files" << endl;
    }

    return 0;
}
void FunctionTests::setup()
{
  ////////////////////   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_const;
  beta_const.push_back(2.0);
  beta_const.push_back(1.0);

  double eps = 1e-2;

  // standard confusion bilinear form
  _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( beta_const * u, - v->grad() );
  _confusionBF->addTerm( beta_n_u_minus_sigma_n, v);

  ////////////////////   BUILD MESH   ///////////////////////
  // define nodes for mesh
  FieldContainer<double> quadPoints(4,2);

  quadPoints(0,0) = -1.0; // x1
  quadPoints(0,1) = -1.0; // y1
  quadPoints(1,0) = 1.0;
  quadPoints(1,1) = -1.0;
  quadPoints(2,0) = 1.0;
  quadPoints(2,1) = 1.0;
  quadPoints(3,0) = -1.0;
  quadPoints(3,1) = 1.0;

  int H1Order = 1, pToAdd = 0;
  int horizontalCells = 1, verticalCells = 1;

  // create a pointer to a new mesh:
  _spectralConfusionMesh = MeshFactory::buildQuadMesh(quadPoints, horizontalCells, verticalCells,
                           _confusionBF, H1Order, H1Order+pToAdd);

  // some 2D test points:
  // setup test points:
  static const int NUM_POINTS_1D = 10;
  double x[NUM_POINTS_1D] = {-1.0,-0.8,-0.6,-.4,-.2,0,0.2,0.4,0.6,0.8};
  double y[NUM_POINTS_1D] = {-0.8,-0.6,-.4,-.2,0,0.2,0.4,0.6,0.8,1.0};

  _testPoints = FieldContainer<double>(NUM_POINTS_1D*NUM_POINTS_1D,2);
  for (int i=0; i<NUM_POINTS_1D; i++)
  {
    for (int j=0; j<NUM_POINTS_1D; j++)
    {
      _testPoints(i*NUM_POINTS_1D + j, 0) = x[i];
      _testPoints(i*NUM_POINTS_1D + j, 1) = y[j];
    }
  }

  _elemType = _spectralConfusionMesh->getElementType(0);
  vector<GlobalIndexType> cellIDs;
  GlobalIndexType cellID = 0;
  cellIDs.push_back(cellID);
  _basisCache = Teuchos::rcp( new BasisCache( _elemType, _spectralConfusionMesh ) );
  _basisCache->setRefCellPoints(_testPoints);

  _basisCache->setPhysicalCellNodes( _spectralConfusionMesh->physicalCellNodesForCell(cellID), cellIDs, true );
}
SpaceTimeIncompressibleFormulation::SpaceTimeIncompressibleFormulation(Teuchos::RCP<IncompressibleProblem> problem, Teuchos::ParameterList &parameters)
{
  int spaceDim = parameters.get<int>("spaceDim", 2);
  bool steady = parameters.get<bool>("steady", true);
  double mu = parameters.get<double>("mu", 1e-2);
  bool useConformingTraces = parameters.get<bool>("useConformingTraces", false);
  int fieldPolyOrder = parameters.get<int>("fieldPolyOrder", 2);
  int delta_p = parameters.get<int>("delta_p", 2);
  int numTElems = parameters.get<int>("numTElems", 2);
  string norm = parameters.get<string>("norm", "Graph");
  string savedSolutionAndMeshPrefix = parameters.get<string>("savedSolutionAndMeshPrefix", "");

  _spaceDim = spaceDim;
  _steady = steady;
  _mu = mu;
  _useConformingTraces = useConformingTraces;
  MeshTopologyPtr meshTopo = problem->meshTopology(numTElems);
  MeshGeometryPtr meshGeometry = problem->meshGeometry();

  if (!steady)
  {
    TEUCHOS_TEST_FOR_EXCEPTION(meshTopo->getDimension() != _spaceDim + 1, std::invalid_argument, "MeshTopo must be space-time mesh for transient");
  }
  else
  {
    TEUCHOS_TEST_FOR_EXCEPTION(meshTopo->getDimension() != _spaceDim, std::invalid_argument, "MeshTopo must be spatial mesh for steady");
  }
  TEUCHOS_TEST_FOR_EXCEPTION(mu==0, std::invalid_argument, "mu may not be 0!");
  TEUCHOS_TEST_FOR_EXCEPTION(spaceDim==1, std::invalid_argument, "Incompressible Navier-Stokes is trivial for spaceDim=1");
  TEUCHOS_TEST_FOR_EXCEPTION((spaceDim != 2) && (spaceDim != 3), std::invalid_argument, "spaceDim must be 2 or 3");


  Space uHatSpace = useConformingTraces ? HGRAD : L2;

  FunctionPtr zero = Function::constant(1);
  FunctionPtr one = Function::constant(1);
  FunctionPtr n_x = TFunction<double>::normal(); // spatial normal
  // FunctionPtr n_x_parity = n_x * TFunction<double>::sideParity();
  FunctionPtr n_xt = TFunction<double>::normalSpaceTime();
  // FunctionPtr n_xt_parity = n_xt * TFunction<double>::sideParity();

  // declare all possible variables -- will only create the ones we need for spaceDim
  // fields
  VarPtr u1, u2, u3;
  VarPtr sigma11, sigma12, sigma13;
  VarPtr sigma21, sigma22, sigma23;
  VarPtr sigma31, sigma32, sigma33;
  VarPtr p;

  // traces
  VarPtr u1hat, u2hat, u3hat;
  VarPtr tm1hat, tm2hat, tm3hat;

  // tests
  VarPtr v1, v2, v3;
  VarPtr tau1, tau2, tau3;
  VarPtr q;

  _vf = VarFactory::varFactory();


  if (spaceDim == 1)
  {
    u1 = _vf->fieldVar(s_u1);
    sigma11 = _vf->fieldVar(s_sigma11);
    p = _vf->fieldVar(s_p);
    u1hat = _vf->traceVarSpaceOnly(s_u1hat, 1.0 * u1, uHatSpace);
    tm1hat = _vf->fluxVar(s_tm1hat);
    v1 = _vf->testVar(s_v1, HGRAD);
    tau1 = _vf->testVar(s_tau1, HGRAD); // scalar
    q = _vf->testVar(s_q, HGRAD);
  }
  if (spaceDim == 2)
  {
    u1 = _vf->fieldVar(s_u1);
    u2 = _vf->fieldVar(s_u2);
    sigma11 = _vf->fieldVar(s_sigma11);
    sigma12 = _vf->fieldVar(s_sigma12);
    sigma21 = _vf->fieldVar(s_sigma21);
    sigma22 = _vf->fieldVar(s_sigma22);
    p = _vf->fieldVar(s_p);
    u1hat = _vf->traceVarSpaceOnly(s_u1hat, 1.0 * u1, uHatSpace);
    u2hat = _vf->traceVarSpaceOnly(s_u2hat, 1.0 * u2, uHatSpace);

    // LinearTermPtr tm1_lt, tm2_lt;
    // tm1_lt = p * n_x->x() - sigma11 * n_x->x() - sigma12 * n_x->y();
    // tm2_lt = p * n_x->y() - sigma21 * n_x->x() - sigma22 * n_x->y();
    // tm1hat = _vf->fluxVar(s_tm1hat, tm1_lt);
    // tm2hat = _vf->fluxVar(s_tm2hat, tm2_lt);
    tm1hat = _vf->fluxVar(s_tm1hat);
    tm2hat = _vf->fluxVar(s_tm2hat);

    v1 = _vf->testVar(s_v1, HGRAD);
    v2 = _vf->testVar(s_v2, HGRAD);
    tau1 = _vf->testVar(s_tau1, HDIV); // vector
    tau2 = _vf->testVar(s_tau2, HDIV); // vector
    q = _vf->testVar(s_q, HGRAD);
  }
  if (spaceDim == 3)
  {
    u1 = _vf->fieldVar(s_u1);
    u2 = _vf->fieldVar(s_u2);
    u3 = _vf->fieldVar(s_u3);
    sigma11 = _vf->fieldVar(s_sigma11);
    sigma12 = _vf->fieldVar(s_sigma12);
    sigma13 = _vf->fieldVar(s_sigma13);
    sigma21 = _vf->fieldVar(s_sigma21);
    sigma22 = _vf->fieldVar(s_sigma22);
    sigma23 = _vf->fieldVar(s_sigma23);
    sigma31 = _vf->fieldVar(s_sigma31);
    sigma32 = _vf->fieldVar(s_sigma32);
    sigma33 = _vf->fieldVar(s_sigma33);
    p = _vf->fieldVar(s_p);
    u1hat = _vf->traceVarSpaceOnly(s_u1hat, 1.0 * u1, uHatSpace);
    u2hat = _vf->traceVarSpaceOnly(s_u2hat, 1.0 * u2, uHatSpace);
    u3hat = _vf->traceVarSpaceOnly(s_u3hat, 1.0 * u3, uHatSpace);
    tm1hat = _vf->fluxVar(s_tm1hat);
    tm2hat = _vf->fluxVar(s_tm2hat);
    tm3hat = _vf->fluxVar(s_tm3hat);
    v1 = _vf->testVar(s_v1, HGRAD);
    v2 = _vf->testVar(s_v2, HGRAD);
    v3 = _vf->testVar(s_v3, HGRAD);
    tau1 = _vf->testVar(s_tau1, HDIV); // vector
    tau2 = _vf->testVar(s_tau2, HDIV); // vector
    tau3 = _vf->testVar(s_tau3, HDIV); // vector
    q = _vf->testVar(s_q, HGRAD);
  }

  // LinearTermPtr tc_lt;
  // if (spaceDim == 1)
  // {
  //   tc_lt = beta->x()*n_x_parity->x()*u
  //     -sigma1 * n_x_parity->x()
  //     + u*n_xt_parity->t();
  // }
  // else if (spaceDim == 2)
  // {
  //   tc_lt = beta->x()*n_x_parity->x()*u
  //     + beta->y()*n_x_parity->y()*u
  //     - sigma1 * n_x_parity->x()
  //     - sigma2 * n_x_parity->y()
  //     + u*n_xt_parity->t();
  // }
  // else if (spaceDim == 3)
  // {
  //   tc_lt = beta->x()*n_x_parity->x()*u
  //     + beta->y()*n_x_parity->y()*u
  //     + beta->z()*n_x_parity->z()*u
  //     - sigma1 * n_x_parity->x()
  //     - sigma2 * n_x_parity->y()
  //     - sigma3 * n_x_parity->z()
  //     + u*n_xt_parity->t();
  // }
  // tc = _vf->fluxVar(s_tc, tc_lt);

  _bf = Teuchos::rcp( new BF(_vf) );




  // Define mesh
  BCPtr bc = BC::bc();

  vector<int> H1Order(2);
  H1Order[0] = fieldPolyOrder + 1;
  H1Order[1] = fieldPolyOrder + 1; // for now, use same poly. degree for temporal bases...
  if (savedSolutionAndMeshPrefix == "")
  {
    map<int,int> trialOrderEnhancements;
    // trialOrderEnhancements[tm1hat->ID()] = fieldPolyOrder;
    // trialOrderEnhancements[tm2hat->ID()] = fieldPolyOrder;
    // trialOrderEnhancements[u1hat->ID()] = fieldPolyOrder;
    // trialOrderEnhancements[u2hat->ID()] = fieldPolyOrder;
    // MeshPtr proxyMesh = Teuchos::rcp( new Mesh(meshTopo->deepCopy(), _bf, H1Order, delta_p) ) ;
    _mesh = Teuchos::rcp( new Mesh(meshTopo, _bf, H1Order, delta_p, trialOrderEnhancements) ) ;
    if (meshGeometry != Teuchos::null)
      _mesh->setEdgeToCurveMap(meshGeometry->edgeToCurveMap());
    // problem->preprocessMesh(_mesh);
    // proxyMesh->registerObserver(_mesh);
    // problem->preprocessMesh(proxyMesh);
    // _mesh->enforceOneIrregularity();

    _solutionUpdate = Solution::solution(_bf, _mesh, bc);
    _solutionBackground = Solution::solution(_bf, _mesh, bc);
    map<int, FunctionPtr> initialGuess;
    initialGuess[u(1)->ID()] = problem->u1_exact();
    initialGuess[u(2)->ID()] = problem->u2_exact();
    initialGuess[sigma(1,1)->ID()] = problem->sigma1_exact()->x();
    initialGuess[sigma(1,2)->ID()] = problem->sigma1_exact()->y();
    initialGuess[sigma(2,1)->ID()] = problem->sigma2_exact()->x();
    initialGuess[sigma(2,2)->ID()] = problem->sigma2_exact()->y();
    // initialGuess[p()->ID()] = problem->p_exact();
    initialGuess[uhat(1)->ID()] = problem->u1_exact();
    initialGuess[uhat(2)->ID()] = problem->u2_exact();
    // initialGuess[tmhat(1)->ID()] =
    //   (problem->u1_exact()*problem->u1_exact()-problem->sigma1_exact()->x()+problem->p_exact())*n_x->x()
    //   + (problem->u1_exact()*problem->u2_exact()-problem->sigma1_exact()->y())*n_x->y();
    // initialGuess[tmhat(2)->ID()] =
    //   (problem->u1_exact()*problem->u2_exact()-problem->sigma2_exact()->x())*n_x->x()
    //   + (problem->u2_exact()*problem->u2_exact()-problem->sigma2_exact()->y()+problem->p_exact())*n_x->y();

    _solutionBackground->projectOntoMesh(initialGuess);
  }
  else
  {
    // // BFPTR version should be deprecated
    _mesh = MeshFactory::loadFromHDF5(_bf, savedSolutionAndMeshPrefix+".mesh");
    _solutionBackground = Solution::solution(_bf, _mesh, bc);
    _solutionBackground->loadFromHDF5(savedSolutionAndMeshPrefix+".soln");
    _solutionUpdate = Solution::solution(_bf, _mesh, bc);
    // _solutionUpdate->loadFromHDF5(savedSolutionAndMeshPrefix+"_update.soln");
  }
  // _solutionUpdate->setFilter(problem->pc());
  // _solutionBackground->setFilter(problem->pc());

  FunctionPtr u1_prev = Function::solution(u1, _solutionBackground);
  FunctionPtr u2_prev = Function::solution(u2, _solutionBackground);
  FunctionPtr u_prev = Function::vectorize(u1_prev, u2_prev);


  if (spaceDim == 2)
  {
    // stress equation
    _bf->addTerm((1.0 / _mu) * sigma11, tau1->x());
    _bf->addTerm((1.0 / _mu) * sigma12, tau1->y());
    _bf->addTerm((1.0 / _mu) * sigma21, tau2->x());
    _bf->addTerm((1.0 / _mu) * sigma22, tau2->y());
    _bf->addTerm(u1, tau1->div());
    _bf->addTerm(u2, tau2->div());
    _bf->addTerm(-u1hat, tau1 * n_x);
    _bf->addTerm(-u2hat, tau2 * n_x);

    // momentum equation
    if (!steady)
    {
      _bf->addTerm(-u1, v1->dt());
      _bf->addTerm(-u2, v2->dt());
    }
    _bf->addTerm(-u1_prev*u1, v1->dx());
    _bf->addTerm(-u1_prev*u1, v1->dx());
    _bf->addTerm(-u2_prev*u1, v1->dy());
    _bf->addTerm(-u1_prev*u2, v1->dy());
    _bf->addTerm(-u2_prev*u1, v2->dx());
    _bf->addTerm(-u1_prev*u2, v2->dx());
    _bf->addTerm(-u2_prev*u2, v2->dy());
    _bf->addTerm(-u2_prev*u2, v2->dy());

    _bf->addTerm(sigma11, v1->dx());
    _bf->addTerm(sigma12, v1->dy());
    _bf->addTerm(sigma21, v2->dx());
    _bf->addTerm(sigma22, v2->dy());

    _bf->addTerm(-p, v1->dx());
    _bf->addTerm(-p, v2->dy());

    _bf->addTerm(tm1hat, v1);
    _bf->addTerm(tm2hat, v2);
    // _bf->addTerm(2*u1_prev*u1hat*n_x->x(), v1);
    // _bf->addTerm((u2_prev*u1hat+u1_prev*u2hat)*n_x->y(), v1);
    // _bf->addTerm((u2_prev*u1hat+u1_prev*u2hat)*n_x->x(), v2);
    // _bf->addTerm(2*u2_prev*u2hat*n_x->y(), v2);

    // continuity equation
    _bf->addTerm(-u1, q->dx());
    _bf->addTerm(-u2, q->dy());

    // _bf->addTerm(u1hat, q->times_normal_x());
    // _bf->addTerm(u2hat, q->times_normal_y());
    _bf->addTerm(u1hat*n_x->x(), q);
    _bf->addTerm(u2hat*n_x->y(), q);
  }

  // Add residual to RHS
  _rhs = RHS::rhs();
  // stress equation
  _rhs->addTerm( -u1_prev * tau1->div() );
  _rhs->addTerm( -u2_prev * tau2->div() );

  // momentum equation
  if (!steady)
  {
    _rhs->addTerm( u1_prev * v1->dt());
    _rhs->addTerm( u2_prev * v2->dt());
  }
  _rhs->addTerm( u1_prev * u1_prev*v1->dx() );
  _rhs->addTerm( u1_prev * u2_prev*v1->dy() );
  _rhs->addTerm( u2_prev * u1_prev*v2->dx() );
  _rhs->addTerm( u2_prev * u2_prev*v2->dy() );

  // _rhs->addTerm( -u1_prev*u1_prev*n_x->x() * v1 );
  // _rhs->addTerm( -u2_prev*u1_prev*n_x->y() * v1 );
  // _rhs->addTerm( -u2_prev*u1_prev*n_x->x() * v2 );
  // _rhs->addTerm( -u2_prev*u2_prev*n_x->y() * v2 );

  // continuity equation
  _rhs->addTerm( u1_prev*q->dx());
  _rhs->addTerm( u2_prev*q->dy());

  _ips["Graph"] = _bf->graphNorm();

  _ips["CoupledRobust"] = Teuchos::rcp(new IP);
  // _ips["CoupledRobust"]->addTerm(_beta*v->grad());
  _ips["CoupledRobust"]->addTerm(u_prev*v1->grad());
  _ips["CoupledRobust"]->addTerm(u_prev*v2->grad());
  _ips["CoupledRobust"]->addTerm(u1_prev*v1->dx() + u2_prev*v2->dx());
  _ips["CoupledRobust"]->addTerm(u1_prev*v1->dy() + u2_prev*v2->dy());
  // _ips["CoupledRobust"]->addTerm(Function::min(one/Function::h(),Function::constant(1./sqrt(_mu)))*tau);
  _ips["CoupledRobust"]->addTerm(Function::min(one/Function::h(),Function::constant(1./sqrt(_mu)))*tau1);
  _ips["CoupledRobust"]->addTerm(Function::min(one/Function::h(),Function::constant(1./sqrt(_mu)))*tau2);
  // _ips["CoupledRobust"]->addTerm(sqrt(_mu)*v->grad());
  _ips["CoupledRobust"]->addTerm(sqrt(_mu)*v1->grad());
  _ips["CoupledRobust"]->addTerm(sqrt(_mu)*v2->grad());
  // _ips["CoupledRobust"]->addTerm(Function::min(sqrt(_mu)*one/Function::h(),one)*v);
  _ips["CoupledRobust"]->addTerm(Function::min(sqrt(_mu)*one/Function::h(),one)*v1);
  _ips["CoupledRobust"]->addTerm(Function::min(sqrt(_mu)*one/Function::h(),one)*v2);
  // _ips["CoupledRobust"]->addTerm(tau->div() - v->dt() - beta*v->grad());
  if (!steady)
  {
    _ips["CoupledRobust"]->addTerm(tau1->div() -v1->dt() - u_prev*v1->grad() - u1_prev*v1->dx() - u2_prev*v2->dx());
    _ips["CoupledRobust"]->addTerm(tau2->div() -v2->dt() - u_prev*v2->grad() - u1_prev*v1->dy() - u2_prev*v2->dy());
  }
  else
  {
    _ips["CoupledRobust"]->addTerm(tau1->div() - u_prev*v1->grad() - u1_prev*v1->dx() - u2_prev*v2->dx());
    _ips["CoupledRobust"]->addTerm(tau2->div() - u_prev*v2->grad() - u1_prev*v1->dy() - u2_prev*v2->dy());
  }
  // _ips["CoupledRobust"]->addTerm(v1->dx() + v2->dy());
  _ips["CoupledRobust"]->addTerm(q->grad());
  _ips["CoupledRobust"]->addTerm(q);


  _ips["NSDecoupledH1"] = Teuchos::rcp(new IP);
  // _ips["NSDecoupledH1"]->addTerm(one/Function::h()*tau);
  _ips["NSDecoupledH1"]->addTerm(one/Function::h()*tau1);
  _ips["NSDecoupledH1"]->addTerm(one/Function::h()*tau2);
  // _ips["NSDecoupledH1"]->addTerm(v->grad());
  _ips["NSDecoupledH1"]->addTerm(v1->grad());
  _ips["NSDecoupledH1"]->addTerm(v2->grad());
  // _ips["NSDecoupledH1"]->addTerm(_beta*v->grad()+v->dt());
  if (!steady)
  {
    _ips["NSDecoupledH1"]->addTerm(v1->dt() + u_prev*v1->grad() + u1_prev*v1->dx() + u2_prev*v2->dx());
    _ips["NSDecoupledH1"]->addTerm(v2->dt() + u_prev*v2->grad() + u1_prev*v1->dy() + u2_prev*v2->dy());
  }
  else
  {
    _ips["NSDecoupledH1"]->addTerm(u_prev*v1->grad() + u1_prev*v1->dx() + u2_prev*v2->dx());
    _ips["NSDecoupledH1"]->addTerm(u_prev*v2->grad() + u1_prev*v1->dy() + u2_prev*v2->dy());
  }
  // _ips["NSDecoupledH1"]->addTerm(tau->div());
  _ips["NSDecoupledH1"]->addTerm(tau1->div());
  _ips["NSDecoupledH1"]->addTerm(tau2->div());
  // _ips["NSDecoupledH1"]->addTerm(v);
  _ips["NSDecoupledH1"]->addTerm(v1);
  _ips["NSDecoupledH1"]->addTerm(v2);
  // _ips["CoupledRobust"]->addTerm(v1->dx() + v2->dy());
  _ips["NSDecoupledH1"]->addTerm(q->grad());
  _ips["NSDecoupledH1"]->addTerm(q);

  IPPtr ip = _ips.at(norm);
  if (problem->forcingFunction != Teuchos::null)
  {
    _rhs->addTerm(problem->forcingFunction->x() * v1);
    _rhs->addTerm(problem->forcingFunction->y() * v2);
  }

  _solutionUpdate->setRHS(_rhs);
  _solutionUpdate->setIP(ip);

  // impose zero mean constraint
  // if (problem->imposeZeroMeanPressure())
  //   _solutionUpdate->bc()->shouldImposeZeroMeanConstraint(p->ID());
  // _solutionUpdate->bc()->singlePointBC(p->ID());

  _mesh->registerSolution(_solutionBackground);
  _mesh->registerSolution(_solutionUpdate);

  LinearTermPtr residual = _rhs->linearTerm() - _bf->testFunctional(_solutionUpdate, false); // false: don't exclude boundary terms

  // double energyThreshold = 0.2;
  double energyThreshold = 0;
  _refinementStrategy = Teuchos::rcp( new RefinementStrategy( _mesh, residual, ip, energyThreshold ) );
}
Exemple #15
0
int main(int argc, char *argv[])
{
#ifdef HAVE_MPI
  Teuchos::GlobalMPISession mpiSession(&argc, &argv,0);
#endif

  {
    // 1D tests
    CellTopoPtr line_2 = Teuchos::rcp( new shards::CellTopology(shards::getCellTopologyData<shards::Line<2> >() ) );

    // let's draw a line
    vector<double> v0 = makeVertex(0);
    vector<double> v1 = makeVertex(1);
    vector<double> v2 = makeVertex(2);

    vector< vector<double> > vertices;
    vertices.push_back(v0);
    vertices.push_back(v1);
    vertices.push_back(v2);

    vector<unsigned> line1VertexList;
    vector<unsigned> line2VertexList;
    line1VertexList.push_back(0);
    line1VertexList.push_back(1);
    line2VertexList.push_back(1);
    line2VertexList.push_back(2);

    vector< vector<unsigned> > elementVertices;
    elementVertices.push_back(line1VertexList);
    elementVertices.push_back(line2VertexList);

    vector< CellTopoPtr > cellTopos;
    cellTopos.push_back(line_2);
    cellTopos.push_back(line_2);
    MeshGeometryPtr meshGeometry = Teuchos::rcp( new MeshGeometry(vertices, elementVertices, cellTopos) );

    MeshTopologyPtr meshTopology = Teuchos::rcp( new MeshTopology(meshGeometry) );

    FunctionPtr x = Function::xn(1);
    FunctionPtr function = x;
    FunctionPtr fbdr = Function::restrictToCellBoundary(function);
    vector<FunctionPtr> functions;
    functions.push_back(function);
    functions.push_back(function);
    vector<string> functionNames;
    functionNames.push_back("function1");
    functionNames.push_back("function2");

    {
      XDMFExporter exporter(meshTopology, "function1", false);
      exporter.exportFunction(function, "function1");
    }
    {
      XDMFExporter exporter(meshTopology, "boundary1", false);
      exporter.exportFunction(fbdr, "boundary1");
    }
    {
      XDMFExporter exporter(meshTopology, "functions1", false);
      exporter.exportFunction(functions, functionNames);
    }
  }
  {
    // 2D tests
    CellTopoPtr quad_4 = Teuchos::rcp( new shards::CellTopology(shards::getCellTopologyData<shards::Quadrilateral<4> >() ) );
    CellTopoPtr tri_3 = Teuchos::rcp( new shards::CellTopology(shards::getCellTopologyData<shards::Triangle<3> >() ) );

    // let's draw a little house
    vector<double> v0 = makeVertex(-1,0);
    vector<double> v1 = makeVertex(1,0);
    vector<double> v2 = makeVertex(1,2);
    vector<double> v3 = makeVertex(-1,2);
    vector<double> v4 = makeVertex(0.0,3);

    vector< vector<double> > vertices;
    vertices.push_back(v0);
    vertices.push_back(v1);
    vertices.push_back(v2);
    vertices.push_back(v3);
    vertices.push_back(v4);

    vector<unsigned> quadVertexList;
    quadVertexList.push_back(0);
    quadVertexList.push_back(1);
    quadVertexList.push_back(2);
    quadVertexList.push_back(3);

    vector<unsigned> triVertexList;
    triVertexList.push_back(3);
    triVertexList.push_back(2);
    triVertexList.push_back(4);

    vector< vector<unsigned> > elementVertices;
    elementVertices.push_back(quadVertexList);
    elementVertices.push_back(triVertexList);

    vector< CellTopoPtr > cellTopos;
    cellTopos.push_back(quad_4);
    cellTopos.push_back(tri_3);
    MeshGeometryPtr meshGeometry = Teuchos::rcp( new MeshGeometry(vertices, elementVertices, cellTopos) );

    MeshTopologyPtr meshTopology = Teuchos::rcp( new MeshTopology(meshGeometry) );

    FunctionPtr x2 = Function::xn(2);
    FunctionPtr y2 = Function::yn(2);
    FunctionPtr function = x2 + y2;
    FunctionPtr vect = Function::vectorize(x2, y2);
    FunctionPtr fbdr = Function::restrictToCellBoundary(function);
    vector<FunctionPtr> functions;
    functions.push_back(function);
    functions.push_back(vect);
    vector<string> functionNames;
    functionNames.push_back("function");
    functionNames.push_back("vect");
    vector<FunctionPtr> bdrfunctions;
    bdrfunctions.push_back(fbdr);
    bdrfunctions.push_back(fbdr);
    vector<string> bdrfunctionNames;
    bdrfunctionNames.push_back("bdr1");
    bdrfunctionNames.push_back("bdr2");

    map<int, int> cellIDToNum1DPts;
    cellIDToNum1DPts[1] = 4;

    {
      XDMFExporter exporter(meshTopology, "Grid2D", false);
      // exporter.exportFunction(function, "function2", 0, 10);
      // exporter.exportFunction(vect, "vect2", 1, 10, cellIDToNum1DPts);
      // exporter.exportFunction(fbdr, "boundary2", 0);
      exporter.exportFunction(functions, functionNames, 1, 10);
    }
    {
      XDMFExporter exporter(meshTopology, "BdrGrid2D", false);
      // exporter.exportFunction(function, "function2", 0, 10);
      // exporter.exportFunction(vect, "vect2", 1, 10, cellIDToNum1DPts);
      // exporter.exportFunction(fbdr, "boundary2", 0);
      exporter.exportFunction(bdrfunctions, bdrfunctionNames, 1, 10);
    }

    ////////////////////   DECLARE VARIABLES   ///////////////////////
    // define test variables
    VarFactory varFactory;
    VarPtr tau = varFactory.testVar("tau", HDIV);
    VarPtr v = varFactory.testVar("v", HGRAD);

    // define trial variables
    VarPtr uhat = varFactory.traceVar("uhat");
    VarPtr fhat = varFactory.fluxVar("fhat");
    VarPtr u = varFactory.fieldVar("u");
    VarPtr sigma = varFactory.fieldVar("sigma", VECTOR_L2);

    ////////////////////   DEFINE BILINEAR FORM   ///////////////////////
    BFPtr bf = Teuchos::rcp( new BF(varFactory) );
    // tau terms:
    bf->addTerm(sigma, tau);
    bf->addTerm(u, tau->div());
    bf->addTerm(-uhat, tau->dot_normal());

    // v terms:
    bf->addTerm( sigma, v->grad() );
    bf->addTerm( fhat, v);

    ////////////////////   BUILD MESH   ///////////////////////
    int H1Order = 4, pToAdd = 2;
    Teuchos::RCP<Mesh> mesh = Teuchos::rcp( new Mesh (meshTopology, bf, H1Order, pToAdd) );

    ////////////////////   DEFINE INNER PRODUCT(S)   ///////////////////////
    IPPtr ip = bf->graphNorm();

    ////////////////////   SPECIFY RHS   ///////////////////////
    RHSPtr rhs = RHS::rhs();
    // Teuchos::RCP<RHS> rhs = Teuchos::rcp( new RHS );
    FunctionPtr one = Function::constant(1.0);
    rhs->addTerm( one * v );

    ////////////////////   CREATE BCs   ///////////////////////
    // Teuchos::RCP<BC> bc = Teuchos::rcp( new BCEasy );
    BCPtr bc = BC::bc();
    FunctionPtr zero = Function::zero();
    SpatialFilterPtr entireBoundary = Teuchos::rcp( new EntireBoundary );
    bc->addDirichlet(uhat, entireBoundary, zero);

    ////////////////////   SOLVE & REFINE   ///////////////////////
    Teuchos::RCP<Solution> solution = Teuchos::rcp( new Solution(mesh, bc, rhs, ip) );
    solution->solve(false);
    RefinementStrategy refinementStrategy( solution, 0.2);

    // Output solution
    FunctionPtr uSoln = Function::solution(u, solution);
    FunctionPtr sigmaSoln = Function::solution(sigma, solution);
    FunctionPtr uhatSoln = Function::solution(uhat, solution);
    FunctionPtr fhatSoln = Function::solution(fhat, solution);
    {
      XDMFExporter exporter(meshTopology, "Poisson", false);
      exporter.exportFunction(uSoln, "u", 0, 4);
      exporter.exportFunction(uSoln, "u", 1, 5);
      exporter.exportFunction(uhatSoln, "uhat", 0, 4);
      exporter.exportFunction(uhatSoln, "uhat", 1, 5);
      // exporter.exportFunction(fhatSoln, "fhat", 0, 4);
      // exporter.exportFunction(fhatSoln, "fhat", 1, 5);
    }
    {
      XDMFExporter exporter(meshTopology, "PoissonSolution", false);
      exporter.exportSolution(solution, mesh, varFactory, 0, 2, cellIDToSubdivision(mesh, 10));
      refinementStrategy.refine(true);
      solution->solve(false);
      exporter.exportSolution(solution, mesh, varFactory, 1, 2, cellIDToSubdivision(mesh, 10));
    }
    // exporter.exportFunction(sigmaSoln, "Poisson-s", "sigma", 0, 5);
    // exporter.exportFunction(uhatSoln, "Poisson-uhat", "uhat", 1, 6);
  }

  {
    // 3D tests
    CellTopoPtr hex = Teuchos::rcp(new shards::CellTopology(shards::getCellTopologyData<shards::Hexahedron<8> >() ));

    // let's draw a little box
    vector<double> v0 = makeVertex(0,0,0);
    vector<double> v1 = makeVertex(1,0,0);
    vector<double> v2 = makeVertex(1,1,0);
    vector<double> v3 = makeVertex(0,1,0);
    vector<double> v4 = makeVertex(0,0,1);
    vector<double> v5 = makeVertex(1,0,1);
    vector<double> v6 = makeVertex(1,1,1);
    vector<double> v7 = makeVertex(0,1,1);

    vector< vector<double> > vertices;
    vertices.push_back(v0);
    vertices.push_back(v1);
    vertices.push_back(v2);
    vertices.push_back(v3);
    vertices.push_back(v4);
    vertices.push_back(v5);
    vertices.push_back(v6);
    vertices.push_back(v7);

    vector<unsigned> hexVertexList;
    hexVertexList.push_back(0);
    hexVertexList.push_back(1);
    hexVertexList.push_back(2);
    hexVertexList.push_back(3);
    hexVertexList.push_back(4);
    hexVertexList.push_back(5);
    hexVertexList.push_back(6);
    hexVertexList.push_back(7);

    // vector<unsigned> triVertexList;
    // triVertexList.push_back(2);
    // triVertexList.push_back(3);
    // triVertexList.push_back(4);

    vector< vector<unsigned> > elementVertices;
    elementVertices.push_back(hexVertexList);
    // elementVertices.push_back(triVertexList);

    vector< CellTopoPtr > cellTopos;
    cellTopos.push_back(hex);
    // cellTopos.push_back(tri_3);
    MeshGeometryPtr meshGeometry = Teuchos::rcp( new MeshGeometry(vertices, elementVertices, cellTopos) );

    MeshTopologyPtr meshTopology = Teuchos::rcp( new MeshTopology(meshGeometry) );

    FunctionPtr x = Function::xn(1);
    FunctionPtr y = Function::yn(1);
    FunctionPtr z = Function::zn(1);
    FunctionPtr function = x + y + z;
    FunctionPtr fbdr = Function::restrictToCellBoundary(function);
    FunctionPtr vect = Function::vectorize(x, y, z);
    vector<FunctionPtr> functions;
    functions.push_back(function);
    functions.push_back(vect);
    vector<string> functionNames;
    functionNames.push_back("function");
    functionNames.push_back("vect");

    {
      XDMFExporter exporter(meshTopology, "function3", false);
      exporter.exportFunction(function, "function3");
    }
    {
      XDMFExporter exporter(meshTopology, "boundary3", false);
      exporter.exportFunction(fbdr, "boundary3");
    }
    {
      XDMFExporter exporter(meshTopology, "vect3", false);
      exporter.exportFunction(vect, "vect3");
    }
    {
      XDMFExporter exporter(meshTopology, "functions3", false);
      exporter.exportFunction(functions, functionNames);
    }
  }
}
Exemple #16
0
bool LobattoBasisTests::testSimpleStiffnessMatrix() {
  bool success = true;
  
  int rank = Teuchos::GlobalMPISession::getRank();
  
  VarFactory varFactory;
  VarPtr u = varFactory.fieldVar("u");
  VarPtr un = varFactory.fluxVar("un_hat");
  VarPtr v = varFactory.testVar("v", HGRAD);
  
  BFPtr bf = Teuchos::rcp( new BF(varFactory) );
  vector<double> beta;
  beta.push_back(1);
  beta.push_back(1);
  bf->addTerm(beta * u, v->grad());
  bf->addTerm(un, v);
  
  DofOrderingPtr trialSpace = Teuchos::rcp( new DofOrdering );
  DofOrderingPtr testSpace = Teuchos::rcp( new DofOrdering );
  
  const int numSides = 4;
  const int spaceDim = 2;
  
  int fieldOrder = 3;
  int testOrder = fieldOrder+2;
  BasisPtr fieldBasis = Camellia::intrepidQuadHGRAD(fieldOrder);
  BasisPtr fluxBasis = Camellia::intrepidLineHGRAD(fieldOrder);
  trialSpace->addEntry(u->ID(), fieldBasis, fieldBasis->rangeRank());
  for (int i=0; i<numSides; i++) {
    trialSpace->addEntry(un->ID(), fluxBasis, fluxBasis->rangeRank(), i);
  }
  
  BasisPtr testBasis = Camellia::lobattoQuadHGRAD(testOrder+1,false); // +1 because it lives in HGRAD
  testSpace->addEntry(v->ID(), testBasis, testBasis->rangeRank());
  
  int numTrialDofs = trialSpace->totalDofs();
  int numTestDofs = testSpace->totalDofs();
  int numCells = 1;
  
  FieldContainer<double> cellNodes(numCells,numSides,spaceDim);
  cellNodes(0,0,0) = 0;
  cellNodes(0,0,1) = 0;
  cellNodes(0,1,0) = 1;
  cellNodes(0,1,1) = 0;
  cellNodes(0,2,0) = 1;
  cellNodes(0,2,1) = 1;
  cellNodes(0,3,0) = 0;
  cellNodes(0,3,1) = 1;
  
  FieldContainer<double> stiffness(numCells,numTestDofs,numTrialDofs);
  
  FieldContainer<double> cellSideParities(numCells,numSides);
  cellSideParities.initialize(1.0);
  
  Teuchos::RCP<shards::CellTopology> quad_4 = Teuchos::rcp( new shards::CellTopology(shards::getCellTopologyData<shards::Quadrilateral<4> >() ) );
  Teuchos::RCP<ElementType> elemType = Teuchos::rcp( new ElementType(trialSpace, testSpace, quad_4));
  
  BasisCachePtr basisCache = Teuchos::rcp( new BasisCache(elemType) );
  vector<GlobalIndexType> cellIDs;
  cellIDs.push_back(0);
  basisCache->setPhysicalCellNodes(cellNodes, cellIDs, true);
  bf->stiffnessMatrix(stiffness, elemType, cellSideParities, basisCache);

  // TODO: finish this test
  
//  cout << stiffness;
  if (rank==0)
    cout << "Warning: testSimpleStiffnessMatrix() unfinished.\n";
  
  return 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;
}
Exemple #18
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;
}
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:
  double epsilon = 1e-2;
  bool useTriangles = false;

  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 H1Order = polyOrder + 1;
  int horizontalCells = 1, verticalCells = 1;

  double energyThreshold = 0.2; // for mesh refinements
  double nonlinearStepSize = 0.5;
  double nonlinearRelativeEnergyTolerance = 0.015; // used to determine convergence of the nonlinear solution

  ////////////////////////////////////////////////////////////////////
  // SET UP PROBLEM
  ////////////////////////////////////////////////////////////////////

  Teuchos::RCP<BurgersBilinearForm> oldBurgersBF = Teuchos::rcp(new BurgersBilinearForm(epsilon));

  // 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) );

  // create a pointer to a new mesh:
  Teuchos::RCP<Mesh> mesh = Mesh::buildQuadMesh(quadPoints, horizontalCells, verticalCells, bf, H1Order, H1Order+pToAdd, useTriangles);
  mesh->setPartitionPolicy(Teuchos::rcp(new ZoltanMeshPartitionPolicy("HSFC")));

  Teuchos::RCP<Solution> backgroundFlow = Teuchos::rcp(new Solution(mesh, Teuchos::rcp((BC*)NULL) , Teuchos::rcp((RHS*)NULL), Teuchos::rcp((DPGInnerProduct*)NULL))); // create null solution
  oldBurgersBF->setBackgroundFlow(backgroundFlow);

  // 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() );

  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 ) );

  // 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);

  map<int, Teuchos::RCP<AbstractFunction> > functionMap;
  functionMap[BurgersBilinearForm::U] = Teuchos::rcp(new InitialGuess());
  functionMap[BurgersBilinearForm::SIGMA_1] = Teuchos::rcp(new ZeroFunction());
  functionMap[BurgersBilinearForm::SIGMA_2] = Teuchos::rcp(new ZeroFunction());

  backgroundFlow->projectOntoMesh(functionMap);

  // ==================== END SET INITIAL GUESS ==========================
  // compare stiffness matrices for first linear step:
  int trialOrder = 1;
  pToAdd = 0;
  int testOrder = trialOrder + pToAdd;
  CellTopoPtr quadTopoPtr = Teuchos::rcp(new shards::CellTopology(shards::getCellTopologyData<shards::Quadrilateral<4> >() ));
  DofOrderingFactory dofOrderingFactory(bf);
  DofOrderingPtr testOrdering = dofOrderingFactory.testOrdering(testOrder, *quadTopoPtr);
  DofOrderingPtr trialOrdering = dofOrderingFactory.trialOrdering(trialOrder, *quadTopoPtr);

  int numCells = 1;
  // just use testOrdering for both trial and test spaces (we only use to define BasisCache)
  ElementTypePtr elemType  = Teuchos::rcp( new ElementType(trialOrdering, testOrdering, quadTopoPtr) );
  BasisCachePtr basisCache = Teuchos::rcp( new BasisCache(elemType) );
  quadPoints.resize(1,quadPoints.dimension(0),quadPoints.dimension(1));
  basisCache->setPhysicalCellNodes(quadPoints,vector<int>(1),true); // true: do create side cache
  FieldContainer<double> cellSideParities(numCells,quadTopoPtr->getSideCount());
  cellSideParities.initialize(1.0); // not worried here about neighbors actually having opposite parity -- just want the two BF implementations to agree...
  FieldContainer<double> expectedValues(numCells, testOrdering->totalDofs(), trialOrdering->totalDofs() );
  FieldContainer<double> actualValues(numCells, testOrdering->totalDofs(), trialOrdering->totalDofs() );
  oldBurgersBF->stiffnessMatrix(expectedValues, elemType, cellSideParities, basisCache);
  bf->stiffnessMatrix(actualValues, elemType, cellSideParities, basisCache);

  // compare beta's as well
  FieldContainer<double> expectedBeta = oldBurgersBF->getBeta(basisCache);
  Teuchos::Array<int> dim;
  expectedBeta.dimensions(dim);
  FieldContainer<double> actualBeta(dim);
  beta->values(actualBeta,basisCache);

  double tol = 1e-14;
  double maxDiff;
  if (rank == 0)
  {
    if ( ! TestSuite::fcsAgree(expectedBeta,actualBeta,tol,maxDiff) )
    {
      cout << "Test failed: old Burgers beta differs from new; maxDiff " << maxDiff << ".\n";
      cout << "Old beta: \n" << expectedBeta;
      cout << "New beta: \n" << actualBeta;
    }
    else
    {
      cout << "Old and new Burgers beta agree!!\n";
    }

    if ( ! TestSuite::fcsAgree(expectedValues,actualValues,tol,maxDiff) )
    {
      cout << "Test failed: old Burgers stiffness differs from new; maxDiff " << maxDiff << ".\n";
      cout << "Old: \n" << expectedValues;
      cout << "New: \n" << actualValues;
      cout << "TrialDofOrdering: \n" << *trialOrdering;
      cout << "TestDofOrdering:\n" << *testOrdering;
    }
    else
    {
      cout << "Old and new Burgers stiffness agree!!\n";
    }
  }

  // define our inner product:
  // Teuchos::RCP<BurgersInnerProduct> ip = Teuchos::rcp( new BurgersInnerProduct( bf, mesh ) );

  // function to scale the squared guy by epsilon/h
  FunctionPtr epsilonOverHScaling = Teuchos::rcp( new EpsilonScaling(epsilon) );
  IPPtr ip = Teuchos::rcp( new IP );
  ip->addTerm(tau);
  ip->addTerm(tau->div());
  ip->addTerm( epsilonOverHScaling * v );
  ip->addTerm( sqrt(sqrt(epsilon)) * v->grad() );
  ip->addTerm( beta * v->grad() );

  // use old IP instead, for now...
  Teuchos::RCP<BurgersInnerProduct> oldIP = Teuchos::rcp( new BurgersInnerProduct( oldBurgersBF, mesh ) );

  expectedValues.resize(numCells, testOrdering->totalDofs(), testOrdering->totalDofs() );
  actualValues.resize  (numCells, testOrdering->totalDofs(), testOrdering->totalDofs() );

  BasisCachePtr ipBasisCache = Teuchos::rcp( new BasisCache(elemType, true) ); // true: test vs. test
  ipBasisCache->setPhysicalCellNodes(quadPoints,vector<int>(1),false); // false: don't create side cache

  oldIP->computeInnerProductMatrix(expectedValues,testOrdering,ipBasisCache);
  ip->computeInnerProductMatrix(actualValues,testOrdering,ipBasisCache);

  tol = 1e-14;
  maxDiff = 0.0;
  if (rank==0)
  {
    if ( ! TestSuite::fcsAgree(expectedValues,actualValues,tol,maxDiff) )
    {
      cout << "Test failed: old inner product differs from new IP; maxDiff " << maxDiff << ".\n";
      cout << "Old: \n" << expectedValues;
      cout << "New IP: \n" << actualValues;
      cout << "testOrdering: \n" << *testOrdering;
    }
    else
    {
      cout << "Old inner product and new IP agree!!\n";
    }
  }

  Teuchos::RCP<RHSEasy> rhs = Teuchos::rcp( new RHSEasy );
  // the RHS as implemented by BurgersProblem divides the first component of beta by 2.0
  // so we follow that.  I've not done the math; just imitating the code...
  Teuchos::RCP<RHSEasy> otherRHS = Teuchos::rcp( new RHSEasy );
  vector<double> e1_div2 = e1;
  e1_div2[0] /= 2.0;
  FunctionPtr rhsBeta = (e1_div2 * beta * e1 + Teuchos::rcp( new ConstantVectorFunction( e2 ) )) * u_prev;
  otherRHS->addTerm( rhsBeta * v->grad() - u_prev * tau->div() );

  Teuchos::RCP<BurgersProblem> problem = Teuchos::rcp( new BurgersProblem(oldBurgersBF) );

  expectedValues.resize(numCells, testOrdering->totalDofs() );
  actualValues.resize  (numCells, testOrdering->totalDofs() );

  problem->integrateAgainstStandardBasis(expectedValues,testOrdering,basisCache);
  otherRHS->integrateAgainstStandardBasis(actualValues,testOrdering,basisCache);

  tol = 1e-14;
  maxDiff = 0.0;
  if (rank==0)
  {
    if ( ! TestSuite::fcsAgree(expectedValues,actualValues,tol,maxDiff) )
    {
      cout << "Test failed: old RHS differs from new (\"otherRHS\"); maxDiff " << maxDiff << ".\n";
      cout << "Old: \n" << expectedValues;
      cout << "New: \n" << actualValues;
      cout << "testOrdering: \n" << *testOrdering;
    }
    else
    {
      cout << "Old and new RHS (\"otherRHS\") agree!!\n";
    }
  }

  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());

  if (! functionsAgree(e2 * u_prev,
                       Teuchos::rcp( new ConstantVectorFunction( e2 ) ) * u_prev,
                       basisCache) )
  {
    cout << "two like functions differ...\n";
  }

  FunctionPtr e1_f = Teuchos::rcp( new ConstantVectorFunction( e1 ) );
  FunctionPtr e2_f = Teuchos::rcp( new ConstantVectorFunction( e2 ) );
  FunctionPtr one  = Teuchos::rcp( new ConstantScalarFunction( 1.0 ) );
  if (! functionsAgree( Teuchos::rcp( new ProductFunction(e1_f, (e1_f + e2_f)) ), // e1_f * (e1_f + e2_f)
                        one,
                        basisCache) )
  {
    cout << "two like functions differ...\n";
  }

  if (! functionsAgree(u_prev_squared_div2,
                       (e1_div2 * beta) * u_prev,
                       basisCache) )
  {
    cout << "two like functions differ...\n";
  }

  if (! functionsAgree(e1 * u_prev_squared_div2,
                       (e1_div2 * beta * e1) * u_prev,
                       basisCache) )
  {
    cout << "two like functions differ...\n";
  }

  if (! functionsAgree(e1 * u_prev_squared_div2 + e2 * u_prev,
                       (e1_div2 * beta * e1 + Teuchos::rcp( new ConstantVectorFunction( e2 ) )) * u_prev,
                       basisCache) )
  {
    cout << "two like functions differ...\n";
  }

  problem->integrateAgainstStandardBasis(expectedValues,testOrdering,basisCache);
  rhs->integrateAgainstStandardBasis(actualValues,testOrdering,basisCache);

  tol = 1e-14;
  maxDiff = 0.0;
  if (rank==0)
  {
    if ( ! TestSuite::fcsAgree(expectedValues,actualValues,tol,maxDiff) )
    {
      cout << "Test failed: old RHS differs from new (\"rhs\"); maxDiff " << maxDiff << ".\n";
      cout << "Old: \n" << expectedValues;
      cout << "New: \n" << actualValues;
      cout << "testOrdering: \n" << *testOrdering;
    }
    else
    {
      cout << "Old and new RHS (\"rhs\") agree!!\n";
    }
  }

  SpatialFilterPtr outflowBoundary = Teuchos::rcp( new TopBoundary );
  SpatialFilterPtr inflowBoundary = Teuchos::rcp( new NegatedSpatialFilter(outflowBoundary) );
  Teuchos::RCP<PenaltyConstraints> pc = Teuchos::rcp(new PenaltyConstraints);
  LinearTermPtr sigma_hat = beta * uhat->times_normal() - beta_n_u_minus_sigma_hat;
  FunctionPtr zero = Teuchos::rcp( new ConstantScalarFunction(0.0) );
  pc->addConstraint(sigma_hat==zero,outflowBoundary);

  FunctionPtr u0 = Teuchos::rcp( new U0 );
  FunctionPtr n = Teuchos::rcp( new UnitNormalFunction );
  Teuchos::RCP<BCEasy> inflowBC = Teuchos::rcp( new BCEasy );
  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 a solution object
  Teuchos::RCP<Solution> solution = Teuchos::rcp(new Solution(mesh, inflowBC, rhs, ip));
  mesh->registerSolution(solution);

  solution->setFilter(pc);

  // old penalty filter:
  Teuchos::RCP<LocalStiffnessMatrixFilter> penaltyBC = Teuchos::rcp(new PenaltyMethodFilter(problem));
//  solution->setFilter(penaltyBC);

  // compare old and new filters
  elemType = mesh->getElement(0)->elementType();
  trialOrdering = elemType->trialOrderPtr;
  testOrdering = elemType->testOrderPtr;
  // stiffness
  expectedValues.resize(numCells, trialOrdering->totalDofs(), trialOrdering->totalDofs() );
  actualValues.resize  (numCells, trialOrdering->totalDofs(), trialOrdering->totalDofs() );
  expectedValues.initialize(0.0);
  actualValues.initialize(0.0);
  // load
  FieldContainer<double> expectedLoad(numCells, trialOrdering->totalDofs() );
  FieldContainer<double> actualLoad(numCells, trialOrdering->totalDofs() );

  penaltyBC->filter(expectedValues,expectedLoad,basisCache,mesh,problem);
  pc->filter(actualValues,actualLoad,basisCache,mesh,problem);

  maxDiff = 0.0;
  if (rank==0)
  {
    if ( ! TestSuite::fcsAgree(expectedValues,actualValues,tol,maxDiff) )
    {
      cout << "Test failed: old penalty stiffness differs from new; maxDiff " << maxDiff << ".\n";
      cout << "Old: \n" << expectedValues;
      cout << "New: \n" << actualValues;
      cout << "trialOrdering: \n" << *trialOrdering;
    }
    else
    {
      cout << "Old and new penalty stiffness agree!!\n";
    }
  }
  if (rank==0)
  {
    if ( ! TestSuite::fcsAgree(expectedLoad,actualLoad,tol,maxDiff) )
    {
      cout << "Test failed: old penalty load differs from new; maxDiff " << maxDiff << ".\n";
      cout << "Old: \n" << expectedValues;
      cout << "New: \n" << actualValues;
      cout << "trialOrdering: \n" << *trialOrdering;
    }
    else
    {
      cout << "Old and new penalty load agree!!\n";
    }
  }

  // define refinement strategy:
  Teuchos::RCP<RefinementStrategy> refinementStrategy = Teuchos::rcp(new RefinementStrategy(solution,energyThreshold));

  // =================== END INITIALIZATION CODE ==========================

  // refine the spectral mesh, for comparability with the original Burgers' driver
  mesh->hRefine(vector<int>(1),RefinementPattern::regularRefinementPatternQuad());

  int numRefs = 5;

  Teuchos::RCP<NonlinearStepSize> stepSize = Teuchos::rcp(new NonlinearStepSize(nonlinearStepSize));
  Teuchos::RCP<NonlinearSolveStrategy> solveStrategy = Teuchos::rcp(
        new NonlinearSolveStrategy(backgroundFlow, solution, stepSize, nonlinearRelativeEnergyTolerance)
      );

  for (int refIndex=0; refIndex<numRefs; refIndex++)
  {
    solveStrategy->solve(rank==0);
    refinementStrategy->refine(rank==0); // print to console on rank 0
  }

  // one more nonlinear solve on refined mesh
  int numNRSteps = 5;
  for (int i=0; i<numNRSteps; i++)
  {
    solution->solve(false);
    backgroundFlow->addSolution(solution,1.0);
  }

  if (rank==0)
  {
    backgroundFlow->writeFieldsToFile(BurgersBilinearForm::U, "u_ref.m");
    backgroundFlow->writeFieldsToFile(BurgersBilinearForm::SIGMA_1, "sigmax.m");
    backgroundFlow->writeFieldsToFile(BurgersBilinearForm::SIGMA_2, "sigmay.m");
    solution->writeFluxesToFile(BurgersBilinearForm::U_HAT, "du_hat_ref.dat");
  }

  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
  bool useCompliantGraphNorm = false;
  bool enforceOneIrregularity = true;
  bool writeStiffnessMatrices = false;
  bool writeWorstCaseGramMatrices = false;
  int numRefs = 10;
  
  // problem parameters:
  double eps = 1e-8;
  vector<double> beta_const;
  beta_const.push_back(2.0);
  beta_const.push_back(1.0);
  
  int k = 2, delta_k = 2;
  
  Teuchos::CommandLineProcessor cmdp(false,true); // false: don't throw exceptions; true: do return errors for unrecognized options
  
  cmdp.setOption("polyOrder",&k,"polynomial order for field variable u");
  cmdp.setOption("delta_k", &delta_k, "test space polynomial order enrichment");
  cmdp.setOption("numRefs",&numRefs,"number of refinements");
  cmdp.setOption("eps", &eps, "epsilon");
  
  if (cmdp.parse(argc,argv) != Teuchos::CommandLineProcessor::PARSE_SUCCESSFUL) {
#ifdef HAVE_MPI
    MPI_Finalize();
#endif
    return -1;
  }
  
  int H1Order = k + 1;
  
  if (rank==0) {
    string normChoice = useCompliantGraphNorm ? "unit-compliant graph norm" : "standard graph norm";
    cout << "Using " << normChoice << "." << endl;
    cout << "eps = " << eps << endl;
    cout << "numRefs = " << numRefs << endl;
    cout << "p = " << k << endl;
  }
  
  ////////////////////   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;
  if (useCompliantGraphNorm) {
    u = varFactory.fieldVar("u",HGRAD);
  } else {
    u = varFactory.fieldVar("u");
  }
  
  VarPtr sigma1 = varFactory.fieldVar("\\sigma_1");
  VarPtr sigma2 = varFactory.fieldVar("\\sigma_2");
  
  ////////////////////   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( beta_const * u, - v->grad() );
  confusionBF->addTerm( beta_n_u_minus_sigma_n, v);
  
  ////////////////////   DEFINE INNER PRODUCT(S)   ///////////////////////
  // 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);
  
  if (!useCompliantGraphNorm) {
    qoptIP->addTerm( tau / eps + v->grad() );
    qoptIP->addTerm( beta_const * v->grad() - tau->div() );
    
    qoptIP->addTerm( v );
  } else {
    FunctionPtr h = Teuchos::rcp( new hFunction );
    
    // here, we're aiming at optimality in 1/h^2 |u|^2 + 1/eps^2 |sigma|^2
    
    qoptIP->addTerm( tau + eps * v->grad() );
    qoptIP->addTerm( h * beta_const * v->grad() - tau->div() );
    qoptIP->addTerm(v);
    qoptIP->addTerm(tau);
  }
  
  ////////////////////   SPECIFY RHS   ///////////////////////
  RHSPtr rhs = RHS::rhs();
  FunctionPtr f = Teuchos::rcp( new ConstantScalarFunction(0.0) );
  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 InflowSquareBoundary );
  SpatialFilterPtr outflowBoundary = Teuchos::rcp( new OutflowSquareBoundary );
  FunctionPtr u0 = Teuchos::rcp( new U0 );
  bc->addDirichlet(uhat, outflowBoundary, u0);

  bc->addDirichlet(uhat, inflowBoundary, u0);
  
//  Teuchos::RCP<PenaltyConstraints> pc = Teuchos::rcp(new PenaltyConstraints);
//  pc->addConstraint(uhat==u0,inflowBoundary);

  ////////////////////   BUILD MESH   ///////////////////////
  // create a new mesh on a single-cell, unit square domain
  Teuchos::RCP<Mesh> mesh = MeshFactory::quadMeshMinRule(confusionBF, H1Order, delta_k);
  
  ////////////////////   SOLVE & REFINE   ///////////////////////
  Teuchos::RCP<Solution> solution = Teuchos::rcp( new Solution(mesh, bc, rhs, qoptIP) );
//  solution->setFilter(pc);
  
  double energyThreshold = 0.2; // for mesh refinements
  
  bool useRieszRepBasedRefStrategy = true;
  
  if (rank==0) {
    if (useRieszRepBasedRefStrategy) {
      cout << "using RieszRep-based refinement strategy.\n";
    } else {
      cout << "using solution-based refinement strategy.\n";
    }
  }
  Teuchos::RCP<RefinementStrategy> refinementStrategy;
  if (!useRieszRepBasedRefStrategy) {
    refinementStrategy = Teuchos::rcp( new RefinementStrategy( solution, energyThreshold ) );
  } else {
    LinearTermPtr residual = confusionBF->testFunctional(solution) - rhs->linearTerm();
    refinementStrategy = Teuchos::rcp( new RefinementStrategy( mesh, residual, qoptIP, energyThreshold ) );
  }
  
  refinementStrategy->setReportPerCellErrors(true);
  refinementStrategy->setEnforceOneIrregularity(enforceOneIrregularity);
  
  for (int refIndex=0; refIndex<numRefs; refIndex++){
    if (writeStiffnessMatrices) {
      string stiffnessFile = fileNameForRefinement("confusion_stiffness", refIndex);
      solution->setWriteMatrixToFile(true, stiffnessFile);
    }
    solution->solve();
    if (writeWorstCaseGramMatrices) {
      string gramFile = fileNameForRefinement("confusion_gram", refIndex);
      bool jacobiScaling = true;
      double condNum = MeshUtilities::computeMaxLocalConditionNumber(qoptIP, mesh, jacobiScaling, gramFile);
      if (rank==0) {
        cout << "estimated worst-case Gram matrix condition number: " << condNum << endl;
        cout << "putative worst-case Gram matrix written to file " << gramFile << endl;
      }
    }
    if (refIndex == numRefs-1) { // write out second-to-last mesh
      if (rank==0)
        GnuPlotUtil::writeComputationalMeshSkeleton("confusionMesh", mesh, true);
    }
    refinementStrategy->refine(rank==0); // print to console on rank 0
  }
  if (writeStiffnessMatrices) {
    string stiffnessFile = fileNameForRefinement("confusion_stiffness", numRefs);
    solution->setWriteMatrixToFile(true, stiffnessFile);
  }
  if (writeWorstCaseGramMatrices) {
    string gramFile = fileNameForRefinement("confusion_gram", numRefs);
    bool jacobiScaling = true;
    double condNum = MeshUtilities::computeMaxLocalConditionNumber(qoptIP, mesh, jacobiScaling, gramFile);
    if (rank==0) {
      cout << "estimated worst-case Gram matrix condition number: " << condNum << endl;
      cout << "putative worst-case Gram matrix written to file " << gramFile << endl;
    }
  }
  // one more solve on the final refined mesh:
  solution->solve();
  
#ifdef HAVE_EPETRAEXT_HDF5
  ostringstream dir_name;
  dir_name << "confusion_eps" << eps;
  HDF5Exporter exporter(mesh,dir_name.str());
  exporter.exportSolution(solution, varFactory, 0);
  if (rank==0) cout << "wrote solution to " << dir_name.str() << endl;
#endif

  
  return 0;
}
Exemple #21
0
void TransientTests::SetUp()
{
  ////////////////////   DECLARE VARIABLES   ///////////////////////
  // define test variables
  VarPtr v = varFactory.testVar("v", HGRAD);
  
  // define trial variables
  beta_n_u_hat = varFactory.fluxVar("\\widehat{\\beta \\cdot n }");
  u = varFactory.fieldVar("u");

  vector<double> beta;
  beta.push_back(1.0);
  beta.push_back(0.0);
  
  ////////////////////   BUILD MESH   ///////////////////////
  bf = Teuchos::rcp( new BF(varFactory) );
  // define nodes for mesh
  FieldContainer<double> meshBoundary(4,2);
  
  meshBoundary(0,0) =  0.0; // x1
  meshBoundary(0,1) = -2.0; // y1
  meshBoundary(1,0) =  4.0;
  meshBoundary(1,1) = -2.0;
  meshBoundary(2,0) =  4.0;
  meshBoundary(2,1) =  2.0;
  meshBoundary(3,0) =  0.0;
  meshBoundary(3,1) =  2.0;

  int horizontalCells = 4, verticalCells = 4;
  
  // create a pointer to a new mesh:
  mesh = MeshFactory::buildQuadMesh(meshBoundary, horizontalCells, verticalCells,
                                                bf, H1Order, H1Order+pToAdd);

  ////////////////////////////////////////////////////////////////////
  // INITIALIZE FLOW FUNCTIONS
  ////////////////////////////////////////////////////////////////////

  BCPtr nullBC = Teuchos::rcp((BC*)NULL);
  RHSPtr nullRHS = Teuchos::rcp((RHS*)NULL);
  IPPtr nullIP = Teuchos::rcp((IP*)NULL);
  prevTimeFlow = Teuchos::rcp(new Solution(mesh, nullBC, nullRHS, nullIP) );  
  flowResidual = Teuchos::rcp(new Solution(mesh, nullBC, nullRHS, nullIP) );  

  FunctionPtr u_prev_time = Teuchos::rcp( new PreviousSolutionFunction(prevTimeFlow, u) );
  
  ////////////////////   DEFINE BILINEAR FORM   ///////////////////////
  RHSPtr rhs = RHS::rhs();
  FunctionPtr invDt = Teuchos::rcp(new ScalarParamFunction(1.0/dt));    
  
  // v terms:
  bf->addTerm( beta * u, - v->grad() );
  bf->addTerm( beta_n_u_hat, v);

  // transient terms
  bf->addTerm( u, invDt*v );
  rhs->addTerm( u_prev_time * invDt * v );
  
  ////////////////////   SPECIFY RHS   ///////////////////////
  FunctionPtr f = Teuchos::rcp( new ConstantScalarFunction(0.0) );
  rhs->addTerm( f * v ); // obviously, with f = 0 adding this term is not necessary!
  
  ////////////////////   DEFINE INNER PRODUCT(S)   ///////////////////////
  IPPtr ip = bf->graphNorm();

  ////////////////////   CREATE BCs   ///////////////////////
  BCPtr bc = BC::bc();

  SpatialFilterPtr lBoundary = Teuchos::rcp( new LeftBoundary );
  FunctionPtr u1 = Teuchos::rcp( new InletBC );
  bc->addDirichlet(beta_n_u_hat, lBoundary, -u1);

  solution = Teuchos::rcp( new Solution(mesh, bc, rhs, ip) );

  // ==================== Register Solutions ==========================
  mesh->registerSolution(solution);
  mesh->registerSolution(prevTimeFlow);
  mesh->registerSolution(flowResidual);

  // ==================== SET INITIAL GUESS ==========================
  double u_free = 0.0;
  map<int, Teuchos::RCP<Function> > functionMap;
  functionMap[u->ID()] = Teuchos::rcp( new ConstantScalarFunction(u_free) );

  // prevTimeFlow->projectOntoMesh(functionMap);
  
}
PoissonFormulation::PoissonFormulation(int spaceDim, bool useConformingTraces, PoissonFormulationChoice formulationChoice)
{
  _spaceDim = spaceDim;

  if (formulationChoice == ULTRAWEAK)
  {
    Space tauSpace = (spaceDim > 1) ? HDIV : HGRAD;
    Space phi_hat_space = useConformingTraces ? HGRAD : L2;
    Space psiSpace = (spaceDim > 1) ? VECTOR_L2 : L2;

    // fields
    VarPtr phi;
    VarPtr psi;

    // traces
    VarPtr phi_hat, psi_n_hat;

    // tests
    VarPtr q;
    VarPtr tau;

    VarFactoryPtr vf = VarFactory::varFactory();
    phi = vf->fieldVar(S_PHI);
    psi = vf->fieldVar(S_PSI, psiSpace);

    TFunctionPtr<double> parity = TFunction<double>::sideParity();
    
    if (spaceDim > 1)
      phi_hat = vf->traceVar(S_PHI_HAT, phi, phi_hat_space);
    else
      phi_hat = vf->fluxVar(S_PHI_HAT, phi * (Function::normal_1D() * parity), phi_hat_space); // for spaceDim==1, the "normal" component is in the flux-ness of phi_hat (it's a plus or minus 1)

    TFunctionPtr<double> n = TFunction<double>::normal();

    if (spaceDim > 1)
      psi_n_hat = vf->fluxVar(S_PSI_N_HAT, psi * (n * parity));
    else
      psi_n_hat = vf->fluxVar(S_PSI_N_HAT, psi * (Function::normal_1D() * parity));

    q = vf->testVar(S_Q, HGRAD);
    tau = vf->testVar(S_TAU, tauSpace);

    _poissonBF = Teuchos::rcp( new BF(vf) );

    if (spaceDim==1)
    {
      // for spaceDim==1, the "normal" component is in the flux-ness of phi_hat (it's a plus or minus 1)
      _poissonBF->addTerm(phi, tau->dx());
      _poissonBF->addTerm(psi, tau);
      _poissonBF->addTerm(-phi_hat, tau);

      _poissonBF->addTerm(-psi, q->dx());
      _poissonBF->addTerm(psi_n_hat, q);
    }
    else
    {
      _poissonBF->addTerm(phi, tau->div());
      _poissonBF->addTerm(psi, tau);
      _poissonBF->addTerm(-phi_hat, tau->dot_normal());

      _poissonBF->addTerm(-psi, q->grad());
      _poissonBF->addTerm(psi_n_hat, q);
    }
  }
  else if ((formulationChoice == PRIMAL) || (formulationChoice == CONTINUOUS_GALERKIN))
  {
    // field
    VarPtr phi;
    
    // flux
    VarPtr psi_n_hat;
    
    // tests
    VarPtr q;
    
    VarFactoryPtr vf = VarFactory::varFactory();
    phi = vf->fieldVar(S_PHI, HGRAD);
    
    TFunctionPtr<double> parity = TFunction<double>::sideParity();
    TFunctionPtr<double> n = TFunction<double>::normal();
    
    if (formulationChoice == PRIMAL)
    {
      if (spaceDim > 1)
        psi_n_hat = vf->fluxVar(S_PSI_N_HAT, phi->grad() * (n * parity));
      else
        psi_n_hat = vf->fluxVar(S_PSI_N_HAT, phi->dx() * (Function::normal_1D() * parity));
    }
    q = vf->testVar(S_Q, HGRAD);
    
    _poissonBF = BF::bf(vf);
    _poissonBF->addTerm(-phi->grad(), q->grad());

    if (formulationChoice == CONTINUOUS_GALERKIN)
    {
      FunctionPtr boundaryIndicator = Function::meshBoundaryCharacteristic();
      _poissonBF->addTerm(phi->grad() * n, boundaryIndicator * q);
    }
    else // primal
    {
      _poissonBF->addTerm(psi_n_hat, q);
    }
  }
  else
  {
    TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "Unsupported PoissonFormulationChoice");
  }
}
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;
}
int main(int argc, char *argv[])
{

#ifdef HAVE_MPI
  Teuchos::GlobalMPISession mpiSession(&argc, &argv,0);

  Epetra_MpiComm Comm(MPI_COMM_WORLD);
#else
  Epetra_SerialComm Comm;
#endif

  int commRank = Teuchos::GlobalMPISession::getRank();

  Comm.Barrier(); // set breakpoint here to allow debugger attachment to other MPI processes than the one you automatically attached to.

  Teuchos::CommandLineProcessor cmdp(false,true); // false: don't throw exceptions; true: do return errors for unrecognized options

  // problem parameters:
  double mu = 0.1;
  double permCoef = 1e4;
  int numRefs = 0;
  int k = 2, delta_k = 2;
  string norm = "Graph";
  cmdp.setOption("polyOrder",&k,"polynomial order for field variable u");
  cmdp.setOption("delta_k", &delta_k, "test space polynomial order enrichment");
  cmdp.setOption("numRefs",&numRefs,"number of refinements");
  cmdp.setOption("norm", &norm, "norm");
  cmdp.setOption("mu", &mu, "mu");
  cmdp.setOption("permCoef", &permCoef, "Permeability coefficient");

  if (cmdp.parse(argc,argv) != Teuchos::CommandLineProcessor::PARSE_SUCCESSFUL)
  {
#ifdef HAVE_MPI
    MPI_Finalize();
#endif
    return -1;
  }

  FunctionPtr zero = TFunction<double>::zero();
  FunctionPtr one = TFunction<double>::constant(1);
  FunctionPtr sin2pix = Teuchos::rcp( new Sin_ax(2*pi) );
  FunctionPtr cos2pix = Teuchos::rcp( new Cos_ax(2*pi) );
  FunctionPtr sin2piy = Teuchos::rcp( new Sin_ay(2*pi) );
  FunctionPtr cos2piy = Teuchos::rcp( new Cos_ay(2*pi) );
  FunctionPtr u1_exact = sin2pix*cos2piy;
  FunctionPtr u2_exact = -cos2pix*sin2piy;
  FunctionPtr x2 = TFunction<double>::xn(2);
  FunctionPtr y2 = TFunction<double>::yn(2);
  FunctionPtr p_exact = x2*y2 - 1./9;
  FunctionPtr permInv = permCoef*(sin2pix + 1.1);

  VarFactoryPtr vf = VarFactory::varFactory();
  //fields:
  VarPtr sigma1 = vf->fieldVar("sigma1", VECTOR_L2);
  VarPtr sigma2 = vf->fieldVar("sigma2", VECTOR_L2);
  VarPtr u1 = vf->fieldVar("u1", L2);
  VarPtr u2 = vf->fieldVar("u2", L2);
  VarPtr p = vf->fieldVar("p", L2);

  // traces:
  VarPtr u1hat = vf->traceVar("u1hat");
  VarPtr u2hat = vf->traceVar("u2hat");
  VarPtr t1c = vf->fluxVar("t1c");
  VarPtr t2c = vf->fluxVar("t2c");

  // test:
  VarPtr v1 = vf->testVar("v1", HGRAD);
  VarPtr v2 = vf->testVar("v2", HGRAD);
  VarPtr tau1 = vf->testVar("tau1", HDIV);
  VarPtr tau2 = vf->testVar("tau2", HDIV);
  VarPtr q = vf->testVar("q", HGRAD);

  BFPtr bf = Teuchos::rcp( new BF(vf) );

  bf->addTerm(1./mu*sigma1, tau1);
  bf->addTerm(1./mu*sigma2, tau2);
  bf->addTerm(u1, tau1->div());
  bf->addTerm(u2, tau2->div());
  bf->addTerm(-u1hat, tau1->dot_normal());
  bf->addTerm(-u2hat, tau2->dot_normal());

  bf->addTerm(sigma1, v1->grad());
  bf->addTerm(sigma2, v2->grad());
  bf->addTerm(-p, v1->dx());
  bf->addTerm(-p, v2->dy());
  bf->addTerm(t1c, v1);
  bf->addTerm(t2c, v2);
  bf->addTerm(mu*permInv*u1, v1);
  bf->addTerm(mu*permInv*u2, v2);

  bf->addTerm(-u1, q->dx());
  bf->addTerm(-u2, q->dy());
  bf->addTerm(u1hat, q->times_normal_x());
  bf->addTerm(u2hat, q->times_normal_y());

  RHSPtr rhs = RHS::rhs();

  BCPtr bc = BC::bc();

  SpatialFilterPtr y_equals_one = SpatialFilter::matchingY(1.0);
  SpatialFilterPtr y_equals_zero = SpatialFilter::matchingY(0);
  SpatialFilterPtr x_equals_one = SpatialFilter::matchingX(1.0);
  SpatialFilterPtr x_equals_zero = SpatialFilter::matchingX(0.0);
  bc->addDirichlet(u1hat, y_equals_zero, u1_exact);
  bc->addDirichlet(u2hat, y_equals_zero, u2_exact);
  bc->addDirichlet(u1hat, x_equals_zero, u1_exact);
  bc->addDirichlet(u2hat, x_equals_zero, u2_exact);
  bc->addDirichlet(u1hat, y_equals_one, u1_exact);
  bc->addDirichlet(u2hat, y_equals_one, u2_exact);
  bc->addDirichlet(u1hat, x_equals_one, u1_exact);
  bc->addDirichlet(u2hat, x_equals_one, u2_exact);
  bc->addZeroMeanConstraint(p);

  MeshPtr mesh = MeshFactory::quadMesh(bf, k+1, delta_k, 1, 1, 4, 4);

  map<string, IPPtr> brinkmanIPs;
  brinkmanIPs["Graph"] = bf->graphNorm();

  brinkmanIPs["Decoupled"] = Teuchos::rcp(new IP);
  brinkmanIPs["Decoupled"]->addTerm(tau1);
  brinkmanIPs["Decoupled"]->addTerm(tau2);
  brinkmanIPs["Decoupled"]->addTerm(tau1->div());
  brinkmanIPs["Decoupled"]->addTerm(tau2->div());
  brinkmanIPs["Decoupled"]->addTerm(permInv*v1);
  brinkmanIPs["Decoupled"]->addTerm(permInv*v2);
  brinkmanIPs["Decoupled"]->addTerm(v1->grad());
  brinkmanIPs["Decoupled"]->addTerm(v2->grad());
  brinkmanIPs["Decoupled"]->addTerm(q);
  brinkmanIPs["Decoupled"]->addTerm(q->grad());

  // brinkmanIPs["CoupledRobust"] = Teuchos::rcp(new IP);
  // brinkmanIPs["CoupledRobust"]->addTerm(tau->div()-beta*v->grad());
  // brinkmanIPs["CoupledRobust"]->addTerm(Function<double>::min(one/Function<double>::h(),Function<double>::constant(1./sqrt(epsilon)))*tau);
  // brinkmanIPs["CoupledRobust"]->addTerm(sqrt(epsilon)*v->grad());
  // brinkmanIPs["CoupledRobust"]->addTerm(beta*v->grad());
  // brinkmanIPs["CoupledRobust"]->addTerm(Function<double>::min(sqrt(epsilon)*one/Function<double>::h(),one)*v);

  IPPtr ip = brinkmanIPs[norm];

  SolutionPtr soln = TSolution<double>::solution(mesh, bc, rhs, ip);

  double threshold = 0.20;
  RefinementStrategy refStrategy(soln, threshold);

  ostringstream refName;
  refName << "brinkman";
  HDF5Exporter exporter(mesh,refName.str());

  for (int refIndex=0; refIndex <= numRefs; refIndex++)
  {
    soln->solve(false);

    double energyError = soln->energyErrorTotal();
    if (commRank == 0)
    {
      // if (refIndex > 0)
      // refStrategy.printRefinementStatistics(refIndex-1);
      cout << "Refinement:\t " << refIndex << " \tElements:\t " << mesh->numActiveElements()
           << " \tDOFs:\t " << mesh->numGlobalDofs() << " \tEnergy Error:\t " << energyError << endl;
    }

    exporter.exportSolution(soln, refIndex);

    if (refIndex != numRefs)
      refStrategy.refine();
  }

  return 0;
}
Exemple #25
0
int main(int argc, char *argv[])
{
#ifdef HAVE_MPI
  Teuchos::GlobalMPISession mpiSession(&argc, &argv,0);
#endif
  int commRank = Teuchos::GlobalMPISession::getRank();
  int numProcs = Teuchos::GlobalMPISession::getNProc();

  // {
  // // 1D tests
  //   CellTopoPtrLegacy line_2 = Teuchos::rcp( new shards::CellTopology(shards::getCellTopologyData<shards::Line<2> >() ) );

  // // let's draw a line
  //   vector<double> v0 = makeVertex(0);
  //   vector<double> v1 = makeVertex(1);
  //   vector<double> v2 = makeVertex(2);

  //   vector< vector<double> > vertices;
  //   vertices.push_back(v0);
  //   vertices.push_back(v1);
  //   vertices.push_back(v2);

  //   vector<unsigned> line1VertexList;
  //   vector<unsigned> line2VertexList;
  //   line1VertexList.push_back(0);
  //   line1VertexList.push_back(1);
  //   line2VertexList.push_back(1);
  //   line2VertexList.push_back(2);

  //   vector< vector<unsigned> > elementVertices;
  //   elementVertices.push_back(line1VertexList);
  //   elementVertices.push_back(line2VertexList);

  //   vector< CellTopoPtrLegacy > cellTopos;
  //   cellTopos.push_back(line_2);
  //   cellTopos.push_back(line_2);
  //   MeshGeometryPtr meshGeometry = Teuchos::rcp( new MeshGeometry(vertices, elementVertices, cellTopos) );

  //   MeshTopologyPtr meshTopology = Teuchos::rcp( new MeshTopology(meshGeometry) );

  //   FunctionPtr x = Function::xn(1);
  //   FunctionPtr function = x;
  //   FunctionPtr fbdr = Function::restrictToCellBoundary(function);
  //   vector<FunctionPtr> functions;
  //   functions.push_back(function);
  //   functions.push_back(function);
  //   vector<string> functionNames;
  //   functionNames.push_back("function1");
  //   functionNames.push_back("function2");

  //   // {
  //   //     HDF5Exporter exporter(mesh, "function1", false);
  //   //     exporter.exportFunction(function, "function1");
  //   // }
  //   // {
  //   //     HDF5Exporter exporter(mesh, "boundary1", false);
  //   //     exporter.exportFunction(fbdr, "boundary1");
  //   // }
  //   // {
  //   //     HDF5Exporter exporter(mesh, "functions1", false);
  //   //     exporter.exportFunction(functions, functionNames);
  //   // }
  // }
  {
    // 2D tests
    // CellTopoPtrLegacy quad_4 = Teuchos::rcp( new shards::CellTopology(shards::getCellTopologyData<shards::Quadrilateral<4> >() ) );
    // CellTopoPtrLegacy tri_3 = Teuchos::rcp( new shards::CellTopology(shards::getCellTopologyData<shards::Triangle<3> >() ) );
    CellTopoPtr quad_4 = CellTopology::quad();
    CellTopoPtr tri_3 = CellTopology::triangle();

    // let's draw a little house
    vector<double> v0 = makeVertex(-1,0);
    vector<double> v1 = makeVertex(1,0);
    vector<double> v2 = makeVertex(1,2);
    vector<double> v3 = makeVertex(-1,2);
    vector<double> v4 = makeVertex(0.0,3);

    vector< vector<double> > vertices;
    vertices.push_back(v0);
    vertices.push_back(v1);
    vertices.push_back(v2);
    vertices.push_back(v3);
    vertices.push_back(v4);

    vector<unsigned> quadVertexList;
    quadVertexList.push_back(0);
    quadVertexList.push_back(1);
    quadVertexList.push_back(2);
    quadVertexList.push_back(3);

    vector<unsigned> triVertexList;
    triVertexList.push_back(3);
    triVertexList.push_back(2);
    triVertexList.push_back(4);

    vector< vector<unsigned> > elementVertices;
    elementVertices.push_back(quadVertexList);
    elementVertices.push_back(triVertexList);

    // vector< CellTopoPtrLegacy > cellTopos;
    vector< CellTopoPtr> cellTopos;
    cellTopos.push_back(quad_4);
    cellTopos.push_back(tri_3);
    MeshGeometryPtr meshGeometry = Teuchos::rcp( new MeshGeometry(vertices, elementVertices, cellTopos) );

    MeshTopologyPtr meshTopology = Teuchos::rcp( new MeshTopology(meshGeometry) );

    ////////////////////   DECLARE VARIABLES   ///////////////////////
    // define test variables
    VarFactoryPtr vf = VarFactory::varFactory();
    VarPtr tau = vf->testVar("tau", HDIV);
    VarPtr v = vf->testVar("v", HGRAD);

    // define trial variables
    VarPtr uhat = vf->traceVar("uhat");
    VarPtr fhat = vf->fluxVar("fhat");
    VarPtr u = vf->fieldVar("u");
    VarPtr sigma = vf->fieldVar("sigma", VECTOR_L2);

    ////////////////////   DEFINE BILINEAR FORM   ///////////////////////
    BFPtr bf = Teuchos::rcp( new BF(vf) );
    // tau terms:
    bf->addTerm(sigma, tau);
    bf->addTerm(u, tau->div());
    bf->addTerm(-uhat, tau->dot_normal());

    // v terms:
    bf->addTerm( sigma, v->grad() );
    bf->addTerm( fhat, v);

    ////////////////////   DEFINE INNER PRODUCT(S)   ///////////////////////
    IPPtr ip = bf->graphNorm();

    ////////////////////   SPECIFY RHS   ///////////////////////
    RHSPtr rhs = RHS::rhs();
    FunctionPtr one = Function::constant(1.0);
    rhs->addTerm( one * v );

    ////////////////////   CREATE BCs   ///////////////////////
    BCPtr bc = BC::bc();
    FunctionPtr zero = Function::zero();
    SpatialFilterPtr entireBoundary = SpatialFilter::allSpace();
    bc->addDirichlet(uhat, entireBoundary, zero);

    ////////////////////   SOLVE & REFINE   ///////////////////////

    // Output solution
    Intrepid::FieldContainer<GlobalIndexType> savedCellPartition;
    Teuchos::RCP<Epetra_FEVector> savedLHSVector;

    {
      ////////////////////   BUILD MESH   ///////////////////////
      int H1Order = 4, pToAdd = 2;
      Teuchos::RCP<Mesh> mesh = Teuchos::rcp( new Mesh (meshTopology, bf, H1Order, pToAdd) );

      Teuchos::RCP<Solution> solution = Teuchos::rcp( new Solution(mesh, bc, rhs, ip) );
      solution->solve(false);
      RefinementStrategy refinementStrategy( solution, 0.2);
      HDF5Exporter exporter(mesh, "Poisson");
      // exporter.exportSolution(solution, vf, 0, 2, cellIDToSubdivision(mesh, 4));
      exporter.exportSolution(solution, 0, 2);
      mesh->saveToHDF5("MeshSave.h5");
      solution->saveToHDF5("SolnSave.h5");
      solution->save("PoissonProblem");
      // int numRefs = 1;
      // for (int ref = 1; ref <= numRefs; ref++)
      // {
      //   refinementStrategy.refine(commRank==0);
      //   solution->solve(false);
      //   mesh->saveToHDF5("MeshSave.h5");
      //   solution->saveToHDF5("SolnSave.h5");
      //   exporter.exportSolution(solution, vf, ref, 2, cellIDToSubdivision(mesh, 4));
      // }
      mesh->globalDofAssignment()->getPartitions(savedCellPartition);
      savedLHSVector = solution->getLHSVector();
    }
    {
      SolutionPtr loadedSolution = Solution::load(bf, "PoissonProblem");
      HDF5Exporter exporter(loadedSolution->mesh(), "ProblemLoaded");
      // exporter.exportSolution(loadedSolution, vf, 0, 2, cellIDToSubdivision(loadedSolution->mesh(), 4));
      exporter.exportSolution(loadedSolution, 0, 2);
    }
    // {
    //   MeshPtr loadedMesh = MeshFactory::loadFromHDF5(bf, "Test0.h5");
    //   Teuchos::RCP<Solution> loadedSolution = Teuchos::rcp( new Solution(loadedMesh, bc, rhs, ip) );
    //   loadedSolution->solve(false);
    //   HDF5Exporter exporter(loadedMesh, "MeshLoaded");
    //   exporter.exportSolution(loadedSolution, vf, 0, 2, cellIDToSubdivision(loadedMesh, 4));
    // }
    {
      MeshPtr loadedMesh = MeshFactory::loadFromHDF5(bf, "MeshSave.h5");
      Intrepid::FieldContainer<GlobalIndexType> loadedCellPartition;
      loadedMesh->globalDofAssignment()->getPartitions(loadedCellPartition);
      if (loadedCellPartition.size() != savedCellPartition.size())
      {
        cout << "Error: the loaded partition has different size/shape than the saved one.\n";
        cout << "loaded size: " << loadedCellPartition.size() << "; saved size: " << savedCellPartition.size() << endl;
      }
      else
      {
        bool partitionsMatch = true;
        for (int i=0; i<loadedCellPartition.size(); i++)
        {
          if (loadedCellPartition[i] != savedCellPartition[i])
          {
            partitionsMatch = false;
            break;
          }
        }
        if (partitionsMatch) cout << "Saved and loaded cell partitions match!\n";
        else
        {
          cout << "Saved and loaded cell partitions differ.\n";
          cout << "saved:\n" << savedCellPartition;
          cout << "loaded:\n" << loadedCellPartition;
        }
      }
      Teuchos::RCP<Solution> loadedSolution = Teuchos::rcp( new Solution(loadedMesh, bc, rhs, ip) );
      loadedSolution->loadFromHDF5("SolnSave.h5");

      Teuchos::RCP<Epetra_FEVector> loadedLHSVector = loadedSolution->getLHSVector();
      if (loadedLHSVector->Map().MinLID() != savedLHSVector->Map().MinLID())
      {
        cout << "On rank " << commRank << ", loaded min LID = " << loadedLHSVector->Map().MinLID();
        cout << ", but saved min LID = " << savedLHSVector->Map().MinLID() << endl;
      }
      else if (loadedLHSVector->Map().MaxLID() != savedLHSVector->Map().MaxLID())
      {
        cout << "On rank " << commRank << ", loaded max LID = " << loadedLHSVector->Map().MaxLID();
        cout << ", but saved max LID = " << savedLHSVector->Map().MaxLID() << endl;
      }
      else
      {
        bool globalIDsMatch = true;
        for (int lid = loadedLHSVector->Map().MinLID(); lid <= loadedLHSVector->Map().MaxLID(); lid++)
        {
          if (loadedLHSVector->Map().GID(lid) != savedLHSVector->Map().GID(lid))
          {
            globalIDsMatch = false;
          }
        }
        if (! globalIDsMatch)
        {
          cout << "On rank " << commRank << ", loaded and saved solution vector maps differ in their global IDs.\n";
        }
        else
        {
          cout << "On rank " << commRank << ", loaded and saved solution vector maps match in their global IDs.\n";
        }

        bool entriesMatch = true;
        double tol = 1e-16;
        if (loadedLHSVector->Map().MinLID() != loadedLHSVector->Map().MaxLID())
        {
          for (int lid = loadedLHSVector->Map().MinLID(); lid <= loadedLHSVector->Map().MaxLID(); lid++)
          {
            double loadedValue = (*loadedLHSVector)[0][lid];
            double savedValue = (*savedLHSVector)[0][lid];
            double diff = abs( loadedValue - savedValue );
            if (diff > tol)
            {
              entriesMatch = false;
              cout << "On rank " << commRank << ", loaded and saved solution vectors differ in entry with lid " << lid;
              cout << "; loaded value = " << loadedValue << "; saved value = " << savedValue << ".\n";
            }
          }
          if (entriesMatch)
          {
            cout << "On rank " << commRank << ", loaded and saved solution vectors match!\n";
          }
          else
          {
            cout << "On rank " << commRank << ", loaded and saved solution vectors do not match.\n";
          }
        }
      }

      HDF5Exporter exporter(loadedMesh, "SolutionLoaded");
      // exporter.exportSolution(loadedSolution, vf, 0, 2, cellIDToSubdivision(loadedMesh, 4));
      exporter.exportSolution(loadedSolution, 0, 2);
    }
  }

  // {
  // // 3D tests
  //   CellTopoPtrLegacy hex = Teuchos::rcp(new shards::CellTopology(shards::getCellTopologyData<shards::Hexahedron<8> >() ));

  // // let's draw a little box
  //   vector<double> v0 = makeVertex(0,0,0);
  //   vector<double> v1 = makeVertex(1,0,0);
  //   vector<double> v2 = makeVertex(1,1,0);
  //   vector<double> v3 = makeVertex(0,1,0);
  //   vector<double> v4 = makeVertex(0,0,1);
  //   vector<double> v5 = makeVertex(1,0,1);
  //   vector<double> v6 = makeVertex(1,1,1);
  //   vector<double> v7 = makeVertex(0,1,1);

  //   vector< vector<double> > vertices;
  //   vertices.push_back(v0);
  //   vertices.push_back(v1);
  //   vertices.push_back(v2);
  //   vertices.push_back(v3);
  //   vertices.push_back(v4);
  //   vertices.push_back(v5);
  //   vertices.push_back(v6);
  //   vertices.push_back(v7);

  //   vector<unsigned> hexVertexList;
  //   hexVertexList.push_back(0);
  //   hexVertexList.push_back(1);
  //   hexVertexList.push_back(2);
  //   hexVertexList.push_back(3);
  //   hexVertexList.push_back(4);
  //   hexVertexList.push_back(5);
  //   hexVertexList.push_back(6);
  //   hexVertexList.push_back(7);

  //   // vector<unsigned> triVertexList;
  //   // triVertexList.push_back(2);
  //   // triVertexList.push_back(3);
  //   // triVertexList.push_back(4);

  //   vector< vector<unsigned> > elementVertices;
  //   elementVertices.push_back(hexVertexList);
  //   // elementVertices.push_back(triVertexList);

  //   vector< CellTopoPtrLegacy > cellTopos;
  //   cellTopos.push_back(hex);
  //   // cellTopos.push_back(tri_3);
  //   MeshGeometryPtr meshGeometry = Teuchos::rcp( new MeshGeometry(vertices, elementVertices, cellTopos) );

  //   MeshTopologyPtr meshTopology = Teuchos::rcp( new MeshTopology(meshGeometry) );

  //   FunctionPtr x = Function::xn(1);
  //   FunctionPtr y = Function::yn(1);
  //   FunctionPtr z = Function::zn(1);
  //   FunctionPtr function = x + y + z;
  //   FunctionPtr fbdr = Function::restrictToCellBoundary(function);
  //   FunctionPtr vect = Function::vectorize(x, y, z);
  //   vector<FunctionPtr> functions;
  //   functions.push_back(function);
  //   functions.push_back(vect);
  //   vector<string> functionNames;
  //   functionNames.push_back("function");
  //   functionNames.push_back("vect");

  //   // {
  //   //     HDF5Exporter exporter(mesh, "function3", false);
  //   //     exporter.exportFunction(function, "function3");
  //   // }
  //   // {
  //   //     HDF5Exporter exporter(mesh, "boundary3", false);
  //   //     exporter.exportFunction(fbdr, "boundary3");
  //   // }
  //   // {
  //   //     HDF5Exporter exporter(mesh, "vect3", false);
  //   //     exporter.exportFunction(vect, "vect3");
  //   // }
  //   // {
  //   //     HDF5Exporter exporter(mesh, "functions3", false);
  //   //     exporter.exportFunction(functions, functionNames);
  //   // }
  // }
}
Exemple #26
0
int main(int argc, char *argv[]) {
#ifdef HAVE_MPI
  Teuchos::GlobalMPISession mpiSession(&argc, &argv,0);
  choice::MpiArgs args( argc, argv );
#else
  choice::Args args( argc, argv );
#endif
  int commRank = Teuchos::GlobalMPISession::getRank();
  int numProcs = Teuchos::GlobalMPISession::getNProc();

  // Required arguments
  double epsilon = args.Input<double>("--epsilon", "diffusion parameter");
  int numRefs = args.Input<int>("--numRefs", "number of refinement steps");
  bool enforceLocalConservation = args.Input<bool>("--conserve", "enforce local conservation");
  int norm = args.Input<int>("--norm", "0 = graph\n    1 = robust\n    2 = modified robust");

  // Optional arguments (have defaults)
  halfwidth = args.Input("--halfwidth", "half the width of the wedge", 0.5);
  bool allQuads = args.Input("--allQuads", "use only quads in mesh", false);
  bool zeroL2 = args.Input("--zeroL2", "take L2 term on v in robust norm to zero", enforceLocalConservation);
  args.Process();

  ////////////////////   DECLARE VARIABLES   ///////////////////////
  // define test variables
  VarFactory varFactory; 
  VarPtr tau = varFactory.testVar("tau", HDIV);
  VarPtr v = varFactory.testVar("v", HGRAD);
  
  // define trial variables
  VarPtr uhat = varFactory.traceVar("uhat");
  VarPtr beta_n_u_minus_sigma_n = varFactory.fluxVar("fhat");
  VarPtr u = varFactory.fieldVar("u");
  VarPtr sigma = varFactory.fieldVar("sigma", VECTOR_L2);

  vector<double> beta;
  beta.push_back(1.0);
  beta.push_back(0.0);
  
  ////////////////////   DEFINE BILINEAR FORM   ///////////////////////
  BFPtr bf = Teuchos::rcp( new BF(varFactory) );
  // tau terms:
  bf->addTerm(sigma / epsilon, tau);
  bf->addTerm(u, tau->div());
  bf->addTerm(-uhat, tau->dot_normal());
  
  // v terms:
  bf->addTerm( sigma, v->grad() );
  bf->addTerm( beta * u, - v->grad() );
  bf->addTerm( beta_n_u_minus_sigma_n, v);
  
  ////////////////////   DEFINE INNER PRODUCT(S)   ///////////////////////
  IPPtr ip = Teuchos::rcp(new IP);
  // Graph norm
  if (norm == 0)
  {
    ip = bf->graphNorm();
    FunctionPtr h2_scaling = Teuchos::rcp( new ZeroMeanScaling ); 
    ip->addZeroMeanTerm( h2_scaling*v );
  }
  // Robust norm
  else if (norm == 1)
  {
    // robust test norm
    FunctionPtr ip_scaling = Teuchos::rcp( new EpsilonScaling(epsilon) ); 
    FunctionPtr h2_scaling = Teuchos::rcp( new ZeroMeanScaling ); 
    if (!zeroL2)
      ip->addTerm( v );
    ip->addTerm( sqrt(epsilon) * v->grad() );
    // Weight these two terms for inflow
    ip->addTerm( beta * v->grad() );
    ip->addTerm( tau->div() );
    ip->addTerm( ip_scaling/sqrt(epsilon) * tau );
    if (zeroL2)
      ip->addZeroMeanTerm( h2_scaling*v );
  }
  // Modified robust norm
  else if (norm == 2)
  {
    // robust test norm
    FunctionPtr ip_scaling = Teuchos::rcp( new EpsilonScaling(epsilon) ); 
    FunctionPtr h2_scaling = Teuchos::rcp( new ZeroMeanScaling ); 
    if (!zeroL2)
      ip->addTerm( v );
    ip->addTerm( sqrt(epsilon) * v->grad() );
    ip->addTerm( tau->div() - beta*v->grad() );
    ip->addTerm( ip_scaling/sqrt(epsilon) * tau );
    if (zeroL2)
      ip->addZeroMeanTerm( h2_scaling*v );
  }
  
  ////////////////////   SPECIFY RHS   ///////////////////////
  Teuchos::RCP<RHSEasy> rhs = Teuchos::rcp( new RHSEasy );
  FunctionPtr f = Teuchos::rcp( new ConstantScalarFunction(0.0) );
  rhs->addTerm( f * v ); // obviously, with f = 0 adding this term is not necessary!

  ////////////////////   CREATE BCs   ///////////////////////
  Teuchos::RCP<BCEasy> bc = Teuchos::rcp( new BCEasy );
  Teuchos::RCP<PenaltyConstraints> pc = Teuchos::rcp( new PenaltyConstraints );
  FunctionPtr n = Teuchos::rcp( new UnitNormalFunction );

  SpatialFilterPtr inflow = Teuchos::rcp( new Inflow );
  FunctionPtr zero = Teuchos::rcp( new ConstantScalarFunction(0.0) );
  bc->addDirichlet(beta_n_u_minus_sigma_n, inflow, zero);

  SpatialFilterPtr leadingWedge = Teuchos::rcp( new LeadingWedge );
  FunctionPtr one = Teuchos::rcp( new ConstantScalarFunction(1.0) );
  bc->addDirichlet(uhat, leadingWedge, one);

  SpatialFilterPtr trailingWedge = Teuchos::rcp( new TrailingWedge );
  bc->addDirichlet(beta_n_u_minus_sigma_n, trailingWedge, beta*n*one);
  // bc->addDirichlet(uhat, trailingWedge, one);

  SpatialFilterPtr top = Teuchos::rcp( new Top );
  bc->addDirichlet(uhat, top, zero);
  // bc->addDirichlet(beta_n_u_minus_sigma_n, top, zero);

  SpatialFilterPtr outflow = Teuchos::rcp( new Outflow );
  pc->addConstraint(beta*uhat->times_normal() - beta_n_u_minus_sigma_n == zero, outflow);
  
  ////////////////////   BUILD MESH   ///////////////////////
  int H1Order = 3, pToAdd = 2;
  // define nodes for mesh
  vector< FieldContainer<double> > vertices;
  FieldContainer<double> pt(2);
  vector< vector<int> > elementIndices;
  vector<int> q(4);
  vector<int> t(3);

  if (allQuads)
  {
    pt(0) = -halfwidth; pt(1) = -1;
    vertices.push_back(pt);
    pt(0) =  0;         pt(1) =  0;
    vertices.push_back(pt);
    pt(0) =  halfwidth; pt(1) = -1;
    vertices.push_back(pt);
    pt(0) =  halfwidth; pt(1) =  halfwidth;
    vertices.push_back(pt);
    pt(0) =  0;         pt(1) =  halfwidth;
    vertices.push_back(pt);
    pt(0) = -halfwidth; pt(1) =  halfwidth;
    vertices.push_back(pt);

    q[0] = 0; q[1] = 1; q[2] = 4; q[3] = 5;
    elementIndices.push_back(q);
    q[0] = 1; q[1] = 2; q[2] = 3; q[3] = 4;
    elementIndices.push_back(q);
  }
  else
  {
    pt(0) = -halfwidth; pt(1) = -1;
    vertices.push_back(pt);
    pt(0) =  0;         pt(1) =  0;
    vertices.push_back(pt);
    pt(0) =  halfwidth; pt(1) = -1;
    vertices.push_back(pt);
    pt(0) =  halfwidth; pt(1) =  0;
    vertices.push_back(pt);
    pt(0) =  halfwidth; pt(1) =  halfwidth;
    vertices.push_back(pt);
    pt(0) =  0;         pt(1) =  halfwidth;
    vertices.push_back(pt);
    pt(0) = -halfwidth; pt(1) =  halfwidth;
    vertices.push_back(pt);
    pt(0) = -halfwidth; pt(1) =  0;
    vertices.push_back(pt);

    t[0] = 0; t[1] = 1; t[2] = 7;
    elementIndices.push_back(t);
    t[0] = 1; t[1] = 2; t[2] = 3;
    elementIndices.push_back(t);
    q[0] = 1; q[1] = 3; q[2] = 4; q[3] = 5;
    elementIndices.push_back(q);
    q[0] = 7; q[1] = 1; q[2] = 5; q[3] = 6;
    elementIndices.push_back(q);
  }

  Teuchos::RCP<Mesh> mesh = Teuchos::rcp( new Mesh(vertices, elementIndices, bf, H1Order, pToAdd) );  
  
  ////////////////////   SOLVE & REFINE   ///////////////////////
  Teuchos::RCP<Solution> solution = Teuchos::rcp( new Solution(mesh, bc, rhs, ip) );
  solution->setFilter(pc);

  if (enforceLocalConservation) {
    FunctionPtr zero = Teuchos::rcp( new ConstantScalarFunction(0.0) );
    solution->lagrangeConstraints()->addConstraint(beta_n_u_minus_sigma_n == zero);
  }
  
  double energyThreshold = 0.2; // for mesh refinements
  RefinementStrategy refinementStrategy( solution, energyThreshold );
  VTKExporter exporter(solution, mesh, varFactory);
  ofstream errOut;
  if (commRank == 0)
    errOut.open("singularwedge_err.txt");
  
  for (int refIndex=0; refIndex<=numRefs; refIndex++){    
    solution->solve(false);

    double energy_error = solution->energyErrorTotal();
    if (commRank==0){
      stringstream outfile;
      outfile << "singularwedge_" << refIndex;
      exporter.exportSolution(outfile.str());

      // Check local conservation
      FunctionPtr flux = Teuchos::rcp( new PreviousSolutionFunction(solution, beta_n_u_minus_sigma_n) );
      FunctionPtr zero = Teuchos::rcp( new ConstantScalarFunction(0.0) );
      Teuchos::Tuple<double, 3> fluxImbalances = checkConservation(flux, zero, varFactory, mesh);
      cout << "Mass flux: Largest Local = " << fluxImbalances[0] 
        << ", Global = " << fluxImbalances[1] << ", Sum Abs = " << fluxImbalances[2] << endl;

      errOut << mesh->numGlobalDofs() << " " << energy_error << " "
        << fluxImbalances[0] << " " << fluxImbalances[1] << " " << fluxImbalances[2] << endl;
    }

    if (refIndex < numRefs)
      refinementStrategy.refine(commRank==0); // print to console on commRank 0
  }
  if (commRank == 0)
    errOut.close();
  
  return 0;
}
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);

}
Exemple #28
0
int main(int argc, char *argv[])
{
#ifdef HAVE_MPI
  Teuchos::GlobalMPISession mpiSession(&argc, &argv,0);
  choice::MpiArgs args( argc, argv );
#else
  choice::Args args( argc, argv );
#endif
  int commRank = Teuchos::GlobalMPISession::getRank();
  int numProcs = Teuchos::GlobalMPISession::getNProc();

  // Required arguments
  double epsilon = args.Input<double>("--epsilon", "diffusion parameter");
  int numRefs = args.Input<int>("--numRefs", "number of refinement steps");
  bool enforceLocalConservation = args.Input<bool>("--conserve", "enforce local conservation");
  int norm = args.Input<int>("--norm", "0 = graph\n    1 = robust\n    2 = modified robust");

  // Optional arguments (have defaults)
  bool zeroL2 = args.Input("--zeroL2", "take L2 term on v in robust norm to zero", false);
  args.Process();

  ////////////////////   DECLARE VARIABLES   ///////////////////////
  // define test variables
  VarFactory varFactory;
  VarPtr tau = varFactory.testVar("\\tau", HDIV);
  VarPtr v = varFactory.testVar("v", HGRAD);

  // define trial variables
  VarPtr uhat = varFactory.traceVar("\\widehat{u}");
  VarPtr beta_n_u_minus_sigma_n = varFactory.fluxVar("\\widehat{\\beta \\cdot n u - \\sigma_{n}}");
  VarPtr u = varFactory.fieldVar("u");
  VarPtr sigma = varFactory.fieldVar("sigma", VECTOR_L2);

  vector<double> beta;
  beta.push_back(1.0);
  beta.push_back(0.0);

  ////////////////////   DEFINE BILINEAR FORM   ///////////////////////
  BFPtr bf = Teuchos::rcp( new BF(varFactory) );
  // tau terms:
  bf->addTerm(sigma / epsilon, tau);
  bf->addTerm(u, tau->div());
  bf->addTerm(-uhat, tau->dot_normal());

  // v terms:
  bf->addTerm( sigma, v->grad() );
  bf->addTerm( beta * u, - v->grad() );
  bf->addTerm( beta_n_u_minus_sigma_n, v);

  ////////////////////   DEFINE INNER PRODUCT(S)   ///////////////////////
  IPPtr ip = Teuchos::rcp(new IP);
  if (norm == 0)
  {
    ip = bf->graphNorm();
    FunctionPtr h2_scaling = Teuchos::rcp( new ZeroMeanScaling );
    ip->addZeroMeanTerm( h2_scaling*v );
  }
  // Robust norm
  else if (norm == 1)
  {
    // robust test norm
    FunctionPtr ip_scaling = Teuchos::rcp( new EpsilonScaling(epsilon) );
    FunctionPtr h2_scaling = Teuchos::rcp( new ZeroMeanScaling );
    if (!zeroL2)
      ip->addTerm( v );
    ip->addTerm( sqrt(epsilon) * v->grad() );
    // Weight these two terms for inflow
    ip->addTerm( beta * v->grad() );
    ip->addTerm( tau->div() );
    ip->addTerm( ip_scaling/sqrt(epsilon) * tau );
    if (zeroL2)
      ip->addZeroMeanTerm( h2_scaling*v );
  }
  // Modified robust norm
  else if (norm == 2)
  {
    // robust test norm
    FunctionPtr ip_scaling = Teuchos::rcp( new EpsilonScaling(epsilon) );
    FunctionPtr h2_scaling = Teuchos::rcp( new ZeroMeanScaling );
    // FunctionPtr ip_weight = Teuchos::rcp( new IPWeight() );
    if (!zeroL2)
      ip->addTerm( v );
    ip->addTerm( sqrt(epsilon) * v->grad() );
    ip->addTerm( beta * v->grad() );
    ip->addTerm( tau->div() - beta*v->grad() );
    ip->addTerm( ip_scaling/sqrt(epsilon) * tau );
    if (zeroL2)
      ip->addZeroMeanTerm( h2_scaling*v );
  }

  // // robust test norm
  // IPPtr robIP = Teuchos::rcp(new IP);
  // FunctionPtr ip_scaling = Teuchos::rcp( new EpsilonScaling(epsilon) );
  // if (!enforceLocalConservation)
  //   robIP->addTerm( ip_scaling * 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 );

  ////////////////////   SPECIFY RHS   ///////////////////////
  Teuchos::RCP<RHSEasy> rhs = Teuchos::rcp( new RHSEasy );
  FunctionPtr f = Teuchos::rcp( new ConstantScalarFunction(0.0) );
  rhs->addTerm( f * v ); // obviously, with f = 0 adding this term is not necessary!

  ////////////////////   CREATE BCs   ///////////////////////
  Teuchos::RCP<BCEasy> bc = Teuchos::rcp( new BCEasy );
  Teuchos::RCP<PenaltyConstraints> pc = Teuchos::rcp( new PenaltyConstraints );

  FunctionPtr zero = Teuchos::rcp( new ConstantScalarFunction(0.0) );
  FunctionPtr one = Teuchos::rcp( new ConstantScalarFunction(1.0) );
  FunctionPtr n = Teuchos::rcp( new UnitNormalFunction );

  SpatialFilterPtr lBoundary = Teuchos::rcp( new LeftBoundary );
  SpatialFilterPtr tbBoundary = Teuchos::rcp( new TopBottomBoundary );
  SpatialFilterPtr rBoundary = Teuchos::rcp( new RightBoundary );
  // SpatialFilterPtr leftCircleBoundary = Teuchos::rcp( new LeftCircleBoundary );
  // SpatialFilterPtr rightCircleBoundary = Teuchos::rcp( new RightCircleBoundary );
  SpatialFilterPtr circleBoundary = Teuchos::rcp( new CircleBoundary );

  bc->addDirichlet(beta_n_u_minus_sigma_n, lBoundary, zero);
  bc->addDirichlet(beta_n_u_minus_sigma_n, tbBoundary, zero);
  pc->addConstraint(beta*uhat->times_normal() - beta_n_u_minus_sigma_n == zero, rBoundary);
  // bc->addDirichlet(uhat, leftCircleBoundary, one);
  // bc->addDirichlet(beta_n_u_minus_sigma_n, rightCircleBoundary, beta*n*one);
  bc->addDirichlet(uhat, circleBoundary, one);


  ////////////////////   BUILD MESH   ///////////////////////
  // define nodes for mesh
  int H1Order = 3, pToAdd = 2;
  Teuchos::RCP<Mesh> mesh;
  mesh = MeshFactory::shiftedHemkerMesh(-3, 9, 6, 1, bf, H1Order, pToAdd);
  // mesh = BuildHemkerMesh(bf, nseg, circleMesh, triangulateMesh, H1Order, pToAdd);

  ////////////////////   SOLVE & REFINE   ///////////////////////
  Teuchos::RCP<Solution> solution = Teuchos::rcp( new Solution(mesh, bc, rhs, ip) );
  solution->setFilter(pc);

  if (enforceLocalConservation)
  {
    FunctionPtr zero = Teuchos::rcp( new ConstantScalarFunction(0.0) );
    solution->lagrangeConstraints()->addConstraint(beta_n_u_minus_sigma_n == zero);
  }

  double energyThreshold = 0.25; // for mesh refinements
  RefinementStrategy refinementStrategy( solution, energyThreshold );
  Teuchos::RCP<RefinementHistory> refHistory = Teuchos::rcp( new RefinementHistory );
  mesh->registerObserver(refHistory);
#ifdef saveVTK
  VTKExporter exporter(solution, mesh, varFactory);
#endif
  ofstream errOut;
  if (commRank == 0)
    errOut.open("hemker_err.txt");

  for (int refIndex=0; refIndex<=numRefs; refIndex++)
  {
    solution->solve(false);

    double energy_error = solution->energyErrorTotal();
    if (commRank==0)
    {
      stringstream outfile;
      outfile << "hemker_" << refIndex;
#ifdef saveVTK
      exporter.exportSolution(outfile.str());
#endif

      // Check local conservation
      FunctionPtr flux = Teuchos::rcp( new PreviousSolutionFunction(solution, beta_n_u_minus_sigma_n) );
      FunctionPtr zero = Teuchos::rcp( new ConstantScalarFunction(0.0) );
      Teuchos::Tuple<double, 3> fluxImbalances = checkConservation(flux, zero, varFactory, mesh);
      cout << "Mass flux: Largest Local = " << fluxImbalances[0]
           << ", Global = " << fluxImbalances[1] << ", Sum Abs = " << fluxImbalances[2] << endl;

      errOut << mesh->numGlobalDofs() << " " << energy_error << " "
             << fluxImbalances[0] << " " << fluxImbalances[1] << " " << fluxImbalances[2] << endl;
    }

    if (refIndex < numRefs)
      refinementStrategy.refine(commRank==0); // print to console on commRank 0
  }
  if (commRank == 0)
    errOut.close();

  return 0;
}
int main(int argc, char *argv[])
{
#ifdef ENABLE_INTEL_FLOATING_POINT_EXCEPTIONS
  cout << "NOTE: enabling floating point exceptions for divide by zero.\n";
  _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_INVALID);
#endif

  Teuchos::GlobalMPISession mpiSession(&argc, &argv);
  int rank = Teuchos::GlobalMPISession::getRank();

#ifdef HAVE_MPI
  Epetra_MpiComm Comm(MPI_COMM_WORLD);
  //cout << "rank: " << rank << " of " << numProcs << endl;
#else
  Epetra_SerialComm Comm;
#endif

  Comm.Barrier(); // set breakpoint here to allow debugger attachment to other MPI processes than the one you automatically attached to.

  Teuchos::CommandLineProcessor cmdp(false,true); // false: don't throw exceptions; true: do return errors for unrecognized options

  double minTol = 1e-8;

  bool use3D = false;
  int refCount = 10;

  int k = 4; // poly order for field variables
  int delta_k = use3D ? 3 : 2;   // test space enrichment
  int k_coarse = 0;

  bool useMumps = true;
  bool useGMGSolver = true;

  bool enforceOneIrregularity = true;
  bool useStaticCondensation = false;
  bool conformingTraces = false;
  bool useDiagonalScaling = false; // of the global stiffness matrix in GMGSolver

  bool printRefinementDetails = false;

  bool useWeightedGraphNorm = true; // graph norm scaled according to units, more or less

  int numCells = 2;

  int AztecOutputLevel = 1;
  int gmgMaxIterations = 10000;
  int smootherOverlap = 0;
  double relativeTol = 1e-6;
  double D = 1.0; // characteristic length scale

  cmdp.setOption("polyOrder",&k,"polynomial order for field variable u");
  cmdp.setOption("delta_k", &delta_k, "test space polynomial order enrichment");
  cmdp.setOption("k_coarse", &k_coarse, "polynomial order for field variables on coarse mesh");
  cmdp.setOption("numRefs",&refCount,"number of refinements");
  cmdp.setOption("D", &D, "domain dimension");
  cmdp.setOption("useConformingTraces", "useNonConformingTraces", &conformingTraces);
  cmdp.setOption("enforceOneIrregularity", "dontEnforceOneIrregularity", &enforceOneIrregularity);

  cmdp.setOption("smootherOverlap", &smootherOverlap, "overlap for smoother");

  cmdp.setOption("printRefinementDetails", "dontPrintRefinementDetails", &printRefinementDetails);
  cmdp.setOption("azOutput", &AztecOutputLevel, "Aztec output level");
  cmdp.setOption("numCells", &numCells, "number of cells in the initial mesh");
  cmdp.setOption("useScaledGraphNorm", "dontUseScaledGraphNorm", &useWeightedGraphNorm);
//  cmdp.setOption("gmgTol", &gmgTolerance, "tolerance for GMG convergence");
  cmdp.setOption("relativeTol", &relativeTol, "Energy error-relative tolerance for iterative solver.");
  cmdp.setOption("gmgMaxIterations", &gmgMaxIterations, "tolerance for GMG convergence");

  bool enhanceUField = false;
  cmdp.setOption("enhanceUField", "dontEnhanceUField", &enhanceUField);
  cmdp.setOption("useStaticCondensation", "dontUseStaticCondensation", &useStaticCondensation);

  if (cmdp.parse(argc,argv) != Teuchos::CommandLineProcessor::PARSE_SUCCESSFUL)
  {
#ifdef HAVE_MPI
    MPI_Finalize();
#endif
    return -1;
  }

  double width = D, height = D, depth = D;

  VarFactory varFactory;
  // fields:
  VarPtr u = varFactory.fieldVar("u", L2);
  VarPtr sigma = varFactory.fieldVar("\\sigma", VECTOR_L2);

  FunctionPtr n = Function::normal();
  // traces:
  VarPtr u_hat;

  if (conformingTraces)
  {
    u_hat = varFactory.traceVar("\\widehat{u}", u);
  }
  else
  {
    cout << "Note: using non-conforming traces.\n";
    u_hat = varFactory.traceVar("\\widehat{u}", u, L2);
  }
  VarPtr sigma_n_hat = varFactory.fluxVar("\\widehat{\\sigma}_{n}", sigma * n);

  // test functions:
  VarPtr tau = varFactory.testVar("\\tau", HDIV);
  VarPtr v = varFactory.testVar("v", HGRAD);

  BFPtr poissonBF = Teuchos::rcp( new BF(varFactory) );
  FunctionPtr alpha = Function::constant(1); // viscosity

  // tau terms:
  poissonBF->addTerm(sigma / alpha, tau);
  poissonBF->addTerm(-u, tau->div()); // (sigma1, tau1)
  poissonBF->addTerm(u_hat, tau * n);

  // v terms:
  poissonBF->addTerm(- sigma, v->grad()); // (mu sigma1, grad v1)
  poissonBF->addTerm( sigma_n_hat, v);

  int horizontalCells = numCells, verticalCells = numCells, depthCells = numCells;

  vector<double> domainDimensions;
  domainDimensions.push_back(width);
  domainDimensions.push_back(height);

  vector<int> elementCounts;
  elementCounts.push_back(horizontalCells);
  elementCounts.push_back(verticalCells);

  if (use3D)
  {
    domainDimensions.push_back(depth);
    elementCounts.push_back(depthCells);
  }

  MeshPtr mesh, k0Mesh;

  int H1Order = k + 1;
  int H1Order_coarse = k_coarse + 1;
  if (!use3D)
  {
    Teuchos::ParameterList pl;

    map<int,int> trialOrderEnhancements;

    if (enhanceUField)
    {
      trialOrderEnhancements[u->ID()] = 1;
    }

    BFPtr poissonBilinearForm = poissonBF;

    pl.set("useMinRule", true);
    pl.set("bf",poissonBilinearForm);
    pl.set("H1Order", H1Order);
    pl.set("delta_k", delta_k);
    pl.set("horizontalElements", horizontalCells);
    pl.set("verticalElements", verticalCells);
    pl.set("divideIntoTriangles", false);
    pl.set("useConformingTraces", conformingTraces);
    pl.set("trialOrderEnhancements", &trialOrderEnhancements);
    pl.set("x0",(double)0);
    pl.set("y0",(double)0);
    pl.set("width", width);
    pl.set("height",height);

    mesh = MeshFactory::quadMesh(pl);

    pl.set("H1Order", H1Order_coarse);
    k0Mesh = MeshFactory::quadMesh(pl);

  }
  else
  {
    mesh = MeshFactory::rectilinearMesh(poissonBF, domainDimensions, elementCounts, H1Order, delta_k);
    k0Mesh = MeshFactory::rectilinearMesh(poissonBF, domainDimensions, elementCounts, H1Order_coarse, delta_k);
  }

  mesh->registerObserver(k0Mesh); // ensure that the k0 mesh refinements track those of the solution mesh

  RHSPtr rhs = RHS::rhs(); // zero
  FunctionPtr sin_pi_x = Teuchos::rcp( new Sin_ax(PI/D) );
  FunctionPtr sin_pi_y = Teuchos::rcp( new Sin_ay(PI/D) );
  FunctionPtr u_exact = sin_pi_x * sin_pi_y;
  FunctionPtr f = -(2.0 * PI * PI / (D * D)) * sin_pi_x * sin_pi_y;
  rhs->addTerm( f * v );

  BCPtr bc = BC::bc();
  SpatialFilterPtr boundary = SpatialFilter::allSpace();

  bc->addDirichlet(u_hat, boundary, u_exact);

  IPPtr graphNorm;

  FunctionPtr h = Teuchos::rcp( new hFunction() );

  if (useWeightedGraphNorm)
  {
    graphNorm = IP::ip();
    graphNorm->addTerm( tau->div() ); // u
    graphNorm->addTerm( (h / alpha) * tau - h * v->grad() ); // sigma
    graphNorm->addTerm( v ); // boundary term (adjoint to u)
    graphNorm->addTerm( h * tau );

//    // new effort, with the idea that the test norm should be considered in reference space, basically
//    graphNorm = IP::ip();
//    graphNorm->addTerm( tau->div() ); // u
//    graphNorm->addTerm( tau / h - v->grad() ); // sigma
//    graphNorm->addTerm( v / h ); // boundary term (adjoint to u)
//    graphNorm->addTerm( tau / h );
  }
  else
  {
    map<int, double> trialWeights; // on the squared terms in the trial space norm
    trialWeights[u->ID()] = 1.0 / (D * D);
    trialWeights[sigma->ID()] = 1.0;
    graphNorm = poissonBF->graphNorm(trialWeights, 1.0); // 1.0: weight on the L^2 terms
  }

  SolutionPtr solution = Solution::solution(mesh, bc, rhs, graphNorm);
  solution->setUseCondensedSolve(useStaticCondensation);

  mesh->registerSolution(solution); // sign up for projection of old solution onto refined cells.

  double energyThreshold = 0.2;
  RefinementStrategy refinementStrategy( solution, energyThreshold );

  refinementStrategy.setReportPerCellErrors(true);
  refinementStrategy.setEnforceOneIrregularity(enforceOneIrregularity);

  Teuchos::RCP<Solver> coarseSolver, fineSolver;
  if (useMumps)
  {
#ifdef HAVE_AMESOS_MUMPS
    coarseSolver = Teuchos::rcp( new MumpsSolver(512, true) );
#else
    cout << "useMumps=true, but MUMPS is not available!\n";
    exit(0);
#endif
  }
  else
  {
    coarseSolver = Teuchos::rcp( new KluSolver );
  }
  GMGSolver* gmgSolver;

  if (useGMGSolver)
  {
    double tol = relativeTol;
    int maxIters = gmgMaxIterations;
    BCPtr zeroBCs = bc->copyImposingZero();
    gmgSolver = new GMGSolver(zeroBCs, k0Mesh, graphNorm, mesh, solution->getDofInterpreter(),
                              solution->getPartitionMap(), maxIters, tol, coarseSolver,
                              useStaticCondensation);

    gmgSolver->setAztecOutput(AztecOutputLevel);
    gmgSolver->setUseConjugateGradient(true);
    gmgSolver->gmgOperator()->setSmootherType(GMGOperator::IFPACK_ADDITIVE_SCHWARZ);
    gmgSolver->gmgOperator()->setSmootherOverlap(smootherOverlap);

    fineSolver = Teuchos::rcp( gmgSolver );
  }
  else
  {
    fineSolver = coarseSolver;
  }

//  if (rank==0) cout << "experimentally starting by solving with MUMPS on the fine mesh.\n";
//  solution->solve( Teuchos::rcp( new MumpsSolver) );

  solution->solve(fineSolver);

#ifdef HAVE_EPETRAEXT_HDF5
  ostringstream dir_name;
  dir_name << "poissonCavityFlow_k" << k;
  HDF5Exporter exporter(mesh,dir_name.str());
  exporter.exportSolution(solution,varFactory,0);
#endif

#ifdef HAVE_AMESOS_MUMPS
  if (useMumps) coarseSolver = Teuchos::rcp( new MumpsSolver(512, true) );
#endif

  solution->reportTimings();
  if (useGMGSolver) gmgSolver->gmgOperator()->reportTimings();
  for (int refIndex=0; refIndex < refCount; refIndex++)
  {
    double energyError = solution->energyErrorTotal();
    GlobalIndexType numFluxDofs = mesh->numFluxDofs();
    if (rank==0)
    {
      cout << "Before refinement " << refIndex << ", energy error = " << energyError;
      cout << " (using " << numFluxDofs << " trace degrees of freedom)." << endl;
    }
    bool printToConsole = printRefinementDetails && (rank==0);
    refinementStrategy.refine(printToConsole);

    if (useStaticCondensation)
    {
      CondensedDofInterpreter* condensedDofInterpreter = dynamic_cast<CondensedDofInterpreter*>(solution->getDofInterpreter().get());
      if (condensedDofInterpreter != NULL)
      {
        condensedDofInterpreter->reinitialize();
      }
    }

    GlobalIndexType fineDofs = mesh->globalDofCount();
    GlobalIndexType coarseDofs = k0Mesh->globalDofCount();
    if (rank==0)
    {
      cout << "After refinement, coarse mesh has " << k0Mesh->numActiveElements() << " elements and " << coarseDofs << " dofs.\n";
      cout << "  Fine mesh has " << mesh->numActiveElements() << " elements and " << fineDofs << " dofs.\n";
    }

    if (!use3D)
    {
      ostringstream fineMeshLocation, coarseMeshLocation;
      fineMeshLocation << "poissonFineMesh_k" << k << "_ref" << refIndex;
      GnuPlotUtil::writeComputationalMeshSkeleton(fineMeshLocation.str(), mesh, true); // true: label cells
      coarseMeshLocation << "poissonCoarseMesh_k" << k << "_ref" << refIndex;
      GnuPlotUtil::writeComputationalMeshSkeleton(coarseMeshLocation.str(), k0Mesh, true); // true: label cells
    }

    if (useGMGSolver)   // create fresh fineSolver now that the meshes have changed:
    {
#ifdef HAVE_AMESOS_MUMPS
      if (useMumps) coarseSolver = Teuchos::rcp( new MumpsSolver(512, true) );
#endif
      double tol = max(relativeTol * energyError, minTol);
      int maxIters = gmgMaxIterations;
      BCPtr zeroBCs = bc->copyImposingZero();
      gmgSolver = new GMGSolver(zeroBCs, k0Mesh, graphNorm, mesh, solution->getDofInterpreter(),
                                solution->getPartitionMap(), maxIters, tol, coarseSolver, useStaticCondensation);
      gmgSolver->setAztecOutput(AztecOutputLevel);
      gmgSolver->setUseDiagonalScaling(useDiagonalScaling);
      fineSolver = Teuchos::rcp( gmgSolver );
    }

    solution->solve(fineSolver);
    solution->reportTimings();
    if (useGMGSolver) gmgSolver->gmgOperator()->reportTimings();

#ifdef HAVE_EPETRAEXT_HDF5
    exporter.exportSolution(solution,varFactory,refIndex+1);
#endif
  }
  double energyErrorTotal = solution->energyErrorTotal();

  GlobalIndexType numFluxDofs = mesh->numFluxDofs();
  GlobalIndexType numGlobalDofs = mesh->numGlobalDofs();
  if (rank==0)
  {
    cout << "Final mesh has " << mesh->numActiveElements() << " elements and " << numFluxDofs << " trace dofs (";
    cout << numGlobalDofs << " total dofs, including fields).\n";
    cout << "Final energy error: " << energyErrorTotal << endl;
  }

#ifdef HAVE_EPETRAEXT_HDF5
  exporter.exportSolution(solution,varFactory,0);
#endif

  if (!use3D)
  {
    GnuPlotUtil::writeComputationalMeshSkeleton("poissonRefinedMesh", mesh, true);
  }

  coarseSolver = Teuchos::rcp((Solver*) NULL); // without this when useMumps = true and running on one rank, we see a crash on exit, which may have to do with MPI being finalized before coarseSolver is deleted.

  return 0;
}
ConvectionDiffusionFormulation::ConvectionDiffusionFormulation(int spaceDim, bool useConformingTraces, FunctionPtr beta, double epsilon)
{
  _spaceDim = spaceDim;
  _epsilon = epsilon;
  _beta = beta;

  FunctionPtr zero = Function::constant(1);
  FunctionPtr one = Function::constant(1);

  Space tauSpace = (spaceDim > 1) ? HDIV : HGRAD;
  Space uhat_space = useConformingTraces ? HGRAD : L2;
  Space vSpace = (spaceDim > 1) ? VECTOR_L2 : L2;

  // fields
  VarPtr u;
  VarPtr sigma;

  // traces
  VarPtr uhat, tc;

  // tests
  VarPtr v;
  VarPtr tau;

  _vf = VarFactory::varFactory();
  u = _vf->fieldVar(s_u);
  sigma = _vf->fieldVar(s_sigma, vSpace);

  if (spaceDim > 1)
    uhat = _vf->traceVar(s_uhat, u, uhat_space);
  else
    uhat = _vf->fluxVar(s_uhat, u, uhat_space); // for spaceDim==1, the "normal" component is in the flux-ness of uhat (it's a plus or minus 1)

  TFunctionPtr<double> n = TFunction<double>::normal();
  TFunctionPtr<double> parity = TFunction<double>::sideParity();

  if (spaceDim > 1)
    tc = _vf->fluxVar(s_tc, (_beta*u-sigma) * (n * parity));
  else
    tc = _vf->fluxVar(s_tc, _beta*u-sigma);

  v = _vf->testVar(s_v, HGRAD);
  tau = _vf->testVar(s_tau, tauSpace);

  _bf = Teuchos::rcp( new BF(_vf) );

  if (spaceDim==1)
  {
    // for spaceDim==1, the "normal" component is in the flux-ness of uhat (it's a plus or minus 1)
    _bf->addTerm(sigma/_epsilon, tau);
    _bf->addTerm(u, tau->dx());
    _bf->addTerm(-uhat, tau);

    _bf->addTerm(-_beta*u + sigma, v->dx());
    _bf->addTerm(tc, v);
  }
  else
  {
    _bf->addTerm(sigma/_epsilon, tau);
    _bf->addTerm(u, tau->div());
    _bf->addTerm(-uhat, tau->dot_normal());

    _bf->addTerm(-_beta*u + sigma, v->grad());
    _bf->addTerm(tc, v);
  }

  _ips["Graph"] = _bf->graphNorm();

  if (spaceDim > 1)
  {
    _ips["Robust"] = Teuchos::rcp(new IP);
    _ips["Robust"]->addTerm(tau->div());
    _ips["Robust"]->addTerm(Function::min(one/Function::h(),Function::constant(1./sqrt(_epsilon)))*tau);
    _ips["Robust"]->addTerm(sqrt(_epsilon)*v->grad());
    _ips["Robust"]->addTerm(_beta*v->grad());
    _ips["Robust"]->addTerm(Function::min(sqrt(_epsilon)*one/Function::h(),one)*v);
  }
  else
  {
    _ips["Robust"] = Teuchos::rcp(new IP);
    _ips["Robust"]->addTerm(tau->dx());
    _ips["Robust"]->addTerm(Function::min(one/Function::h(),Function::constant(1./sqrt(_epsilon)))*tau);
    _ips["Robust"]->addTerm(sqrt(_epsilon)*v->dx());
    _ips["Robust"]->addTerm(_beta*v->dx());
    _ips["Robust"]->addTerm(Function::min(sqrt(_epsilon)*one/Function::h(),one)*v);
  }

  if (spaceDim > 1)
  {
    _ips["CoupledRobust"] = Teuchos::rcp(new IP);
    _ips["CoupledRobust"]->addTerm(tau->div()-_beta*v->grad());
    _ips["CoupledRobust"]->addTerm(Function::min(one/Function::h(),Function::constant(1./sqrt(_epsilon)))*tau);
    _ips["CoupledRobust"]->addTerm(sqrt(_epsilon)*v->grad());
    _ips["CoupledRobust"]->addTerm(_beta*v->grad());
    _ips["CoupledRobust"]->addTerm(Function::min(sqrt(_epsilon)*one/Function::h(),one)*v);
  }
  else
  {
    _ips["CoupledRobust"] = Teuchos::rcp(new IP);
    _ips["CoupledRobust"]->addTerm(tau->dx()-_beta*v->dx());
    _ips["CoupledRobust"]->addTerm(Function::min(one/Function::h(),Function::constant(1./sqrt(_epsilon)))*tau);
    _ips["CoupledRobust"]->addTerm(sqrt(_epsilon)*v->dx());
    _ips["CoupledRobust"]->addTerm(_beta*v->dx());
    _ips["CoupledRobust"]->addTerm(Function::min(sqrt(_epsilon)*one/Function::h(),one)*v);
  }
}