Example #1
0
int main(int argc, char *argv[]) {
  Teuchos::GlobalMPISession mpiSession(&argc, &argv);
  Kokkos::initialize();
  // This little trick lets us print to std::cout only if
  // a (dummy) command-line argument is provided.
  int iprint = argc - 1;
  Teuchos::RCP<std::ostream> outStream;
  Teuchos::oblackholestream bhs; // outputs nothing
  if (iprint > 0)
    outStream = Teuchos::rcp(&std::cout, false);
  else
    outStream = Teuchos::rcp(&bhs, false);
  
  // Save the format state of the original std::cout.
  Teuchos::oblackholestream oldFormatState;
  oldFormatState.copyfmt(std::cout);
  
  *outStream \
    << "===============================================================================\n" \
    << "|                                                                             |\n" \
    << "|                  Unit Test (Basis_HGRAD_HEX_In_FEM)                         |\n" \
    << "|                                                                             |\n" \
    << "| 1) Patch test involving H(div) matrices                                     |\n" \
    << "|    for the Dirichlet problem on a hexahedron                                |\n" \
    << "|    Omega with boundary Gamma.                                               |\n" \
    << "|                                                                             |\n" \
    << "|   Questions? Contact Pavel Bochev ([email protected]),                     |\n" \
    << "|                      Robert Kirby ([email protected]),                 |\n" \
    << "|                      Denis Ridzal ([email protected]),                     |\n" \
    << "|                      Kara Peterson ([email protected]).                    |\n" \
    << "|                                                                             |\n" \
    << "|  Intrepid's website: http://trilinos.sandia.gov/packages/intrepid           |\n" \
    << "|  Trilinos website:   http://trilinos.sandia.gov                             |\n" \
    << "|                                                                             |\n" \
    << "===============================================================================\n" \
    << "| TEST 1: Patch test                                                          |\n" \
    << "===============================================================================\n";
  
  
  int errorFlag = 0;
  
  outStream -> precision(16);
  
  try {
    DefaultCubatureFactory<double> cubFactory;                                           // create cubature factory
    shards::CellTopology cell(shards::getCellTopologyData< shards::Hexahedron<> >());    // create parent cell topology
    shards::CellTopology side(shards::getCellTopologyData< shards::Quadrilateral<> >()); // create relevant subcell (side) topology
    shards::CellTopology line(shards::getCellTopologyData< shards::Line<> >() );         // for getting points to construct the basis
    
    int cellDim = cell.getDimension();
    int sideDim = side.getDimension();
    
    int min_order = 0;
    int max_order = 3;
    
    int numIntervals = 2;
    int numInterpPoints = (numIntervals + 1)*(numIntervals + 1)*(numIntervals+1);
    FieldContainer<double> interp_points_ref(numInterpPoints, cellDim);
    int counter = 0;
    for (int k=0;k<numIntervals;k++) {
      for (int j=0; j<=numIntervals; j++) {
	for (int i=0; i<=numIntervals; i++) {
          interp_points_ref(counter,0) = i*(1.0/numIntervals);
          interp_points_ref(counter,1) = j*(1.0/numIntervals);
          interp_points_ref(counter,2) = k*(1.0/numIntervals);
          counter++;
        }
      }
    }
    
    for (int basis_order=min_order;basis_order<=max_order;basis_order++) {
      // create bases
      // get the points for the vector basis
      Teuchos::RCP<Basis<double,FieldContainer<double> > > vectorBasis =
        Teuchos::rcp(new Basis_HDIV_HEX_In_FEM<double,FieldContainer<double> >(basis_order+1,POINTTYPE_SPECTRAL) );

      Teuchos::RCP<Basis<double,FieldContainer<double> > > scalarBasis =
	Teuchos::rcp(new Basis_HGRAD_HEX_Cn_FEM<double,FieldContainer<double> >(basis_order,POINTTYPE_SPECTRAL) );
      
      int numVectorFields = vectorBasis->getCardinality();
      int numScalarFields = scalarBasis->getCardinality();
      int numTotalFields = numVectorFields + numScalarFields;
      
      // create cubatures
      Teuchos::RCP<Cubature<double> > cellCub = cubFactory.create(cell, 2*(basis_order+1));
      Teuchos::RCP<Cubature<double> > sideCub = cubFactory.create(side, 2*(basis_order+1));
      
      int numCubPointsCell = cellCub->getNumPoints();
      int numCubPointsSide = sideCub->getNumPoints();
      
      // hold cubature information
      FieldContainer<double> cub_points_cell(numCubPointsCell, cellDim);
      FieldContainer<double> cub_weights_cell(numCubPointsCell);
      FieldContainer<double> cub_points_side( numCubPointsSide, sideDim );
      FieldContainer<double> cub_weights_side( numCubPointsSide );
      FieldContainer<double> cub_points_side_refcell( numCubPointsSide , cellDim );
      
      // hold basis function information on refcell
      FieldContainer<double> value_of_v_basis_at_cub_points_cell(numVectorFields, numCubPointsCell, cellDim );
      FieldContainer<double> w_value_of_v_basis_at_cub_points_cell(1, numVectorFields, numCubPointsCell, cellDim);
      FieldContainer<double> div_of_v_basis_at_cub_points_cell( numVectorFields, numCubPointsCell );
      FieldContainer<double> w_div_of_v_basis_at_cub_points_cell( 1, numVectorFields , numCubPointsCell );
      FieldContainer<double> value_of_s_basis_at_cub_points_cell(numScalarFields,numCubPointsCell);
      FieldContainer<double> w_value_of_s_basis_at_cub_points_cell(1,numScalarFields,numCubPointsCell);
      
      // containers for side integration:
      // I just need the normal component of the vector basis
      // and the exact solution at the cub points
      FieldContainer<double> value_of_v_basis_at_cub_points_side(numVectorFields,numCubPointsSide,cellDim);
      FieldContainer<double> n_of_v_basis_at_cub_points_side(numVectorFields,numCubPointsSide);
      FieldContainer<double> w_n_of_v_basis_at_cub_points_side(1,numVectorFields,numCubPointsSide);
      FieldContainer<double> diri_data_at_cub_points_side(1,numCubPointsSide);
      FieldContainer<double> side_normal(cellDim);
      
      // holds rhs data
      FieldContainer<double> rhs_at_cub_points_cell(1,numCubPointsCell);
      
      // FEM matrices and vectors
      FieldContainer<double> fe_matrix_M(1,numVectorFields,numVectorFields);
      FieldContainer<double> fe_matrix_B(1,numVectorFields,numScalarFields);
      FieldContainer<double> fe_matrix(1,numTotalFields,numTotalFields);
      
      FieldContainer<double> rhs_vector_vec(1,numVectorFields);
      FieldContainer<double> rhs_vector_scal(1,numScalarFields);
      FieldContainer<double> rhs_and_soln_vec(1,numTotalFields);
      
      FieldContainer<int> ipiv(numTotalFields);
      FieldContainer<double> value_of_s_basis_at_interp_points( numScalarFields , numInterpPoints);
      FieldContainer<double> interpolant( 1 , numInterpPoints );
      
      // set test tolerance
      double zero = (basis_order+1)*(basis_order+1)*1000.0*INTREPID_TOL;
      
      // build matrices outside the loop, and then just do the rhs
      // for each iteration
      
      cellCub->getCubature(cub_points_cell, cub_weights_cell);
      sideCub->getCubature(cub_points_side, cub_weights_side);
      
      // need the vector basis & its divergences
      vectorBasis->getValues(value_of_v_basis_at_cub_points_cell,
                             cub_points_cell,
                             OPERATOR_VALUE);
      vectorBasis->getValues(div_of_v_basis_at_cub_points_cell,
                             cub_points_cell,
                             OPERATOR_DIV);
      
      // need the scalar basis as well
      scalarBasis->getValues(value_of_s_basis_at_cub_points_cell,
                             cub_points_cell,
                             OPERATOR_VALUE);
      
      // construct mass matrix
      cub_weights_cell.resize(1,numCubPointsCell);
      FunctionSpaceTools::multiplyMeasure<double>(w_value_of_v_basis_at_cub_points_cell ,
                                                  cub_weights_cell ,
                                                  value_of_v_basis_at_cub_points_cell ); 
      cub_weights_cell.resize(numCubPointsCell);
      
      
      value_of_v_basis_at_cub_points_cell.resize( 1 , numVectorFields , numCubPointsCell , cellDim );
      FunctionSpaceTools::integrate<double>(fe_matrix_M,
                                            w_value_of_v_basis_at_cub_points_cell ,
                                            value_of_v_basis_at_cub_points_cell ,
                                            COMP_BLAS );
      value_of_v_basis_at_cub_points_cell.resize( numVectorFields , numCubPointsCell , cellDim );
      
      // div matrix
      cub_weights_cell.resize(1,numCubPointsCell);
      FunctionSpaceTools::multiplyMeasure<double>(w_div_of_v_basis_at_cub_points_cell,
                                                  cub_weights_cell,
                                                  div_of_v_basis_at_cub_points_cell);
      cub_weights_cell.resize(numCubPointsCell);
      
      value_of_s_basis_at_cub_points_cell.resize(1,numScalarFields,numCubPointsCell);
      FunctionSpaceTools::integrate<double>(fe_matrix_B,
                                            w_div_of_v_basis_at_cub_points_cell ,
                                            value_of_s_basis_at_cub_points_cell ,
                                            COMP_BLAS );
      value_of_s_basis_at_cub_points_cell.resize(numScalarFields,numCubPointsCell);
      
      for (int x_order=0;x_order<=basis_order;x_order++) {
        for (int y_order=0;y_order<=basis_order;y_order++) {
          for (int z_order=0;z_order<=basis_order;z_order++) {
            
            
            // reset global matrix since I destroyed it in LU factorization.
            fe_matrix.initialize();
            // insert mass matrix into global matrix
            for (int i=0;i<numVectorFields;i++) {
              for (int j=0;j<numVectorFields;j++) {
                fe_matrix(0,i,j) = fe_matrix_M(0,i,j);
              }
            }
            
            // insert div matrix into global matrix
            for (int i=0;i<numVectorFields;i++) {
              for (int j=0;j<numScalarFields;j++) {
                fe_matrix(0,i,numVectorFields+j)=-fe_matrix_B(0,i,j);
                fe_matrix(0,j+numVectorFields,i)=fe_matrix_B(0,i,j);
              }
            }
            
            // clear old vector data
            rhs_vector_vec.initialize();
            rhs_vector_scal.initialize();
            rhs_and_soln_vec.initialize();
            
            // now get rhs vector
            // rhs_vector_scal is just (rhs,w) for w in the scalar basis
            // I already have the scalar basis tabulated.
            cub_points_cell.resize(1,numCubPointsCell,cellDim);
            rhsFunc(rhs_at_cub_points_cell,
                    cub_points_cell,
                    x_order,
                    y_order,
                    z_order);
            
            cub_points_cell.resize(numCubPointsCell,cellDim);
            
            cub_weights_cell.resize(1,numCubPointsCell);
            FunctionSpaceTools::multiplyMeasure<double>(w_value_of_s_basis_at_cub_points_cell,
                                                        cub_weights_cell,
                                                        value_of_s_basis_at_cub_points_cell);
            cub_weights_cell.resize(numCubPointsCell);
            FunctionSpaceTools::integrate<double>(rhs_vector_scal,
                                                  rhs_at_cub_points_cell,
                                                  w_value_of_s_basis_at_cub_points_cell,
                                                  COMP_BLAS);

            for (int i=0;i<numScalarFields;i++) {
              rhs_and_soln_vec(0,numVectorFields+i) = rhs_vector_scal(0,i);
            }
            
            
            // now get <u,v.n> on boundary
            for (unsigned side_cur=0;side_cur<6;side_cur++) {
              // map side cubature to current side
              CellTools<double>::mapToReferenceSubcell( cub_points_side_refcell ,
                                                        cub_points_side ,
                                                        sideDim ,
                                                        (int)side_cur ,
                                                        cell );
              // Evaluate dirichlet data
              cub_points_side_refcell.resize(1,numCubPointsSide,cellDim);
              u_exact(diri_data_at_cub_points_side,
                      cub_points_side_refcell,x_order,y_order,z_order);

              cub_points_side_refcell.resize(numCubPointsSide,cellDim);
              
              // get normal direction, this has the edge weight factored into it already
              CellTools<double>::getReferenceSideNormal(side_normal , 
                                                        (int)side_cur,cell );

              // v.n at cub points on side
              vectorBasis->getValues(value_of_v_basis_at_cub_points_side ,
                                    cub_points_side_refcell ,
                                    OPERATOR_VALUE );

              for (int i=0;i<numVectorFields;i++) {
                for (int j=0;j<numCubPointsSide;j++) {
                  n_of_v_basis_at_cub_points_side(i,j) = 0.0;
                  for (int k=0;k<cellDim;k++) {
                    n_of_v_basis_at_cub_points_side(i,j) += side_normal(k) * 
                      value_of_v_basis_at_cub_points_side(i,j,k);
                  }
                } 
              }
              
              cub_weights_side.resize(1,numCubPointsSide);
              FunctionSpaceTools::multiplyMeasure<double>(w_n_of_v_basis_at_cub_points_side,
                                                          cub_weights_side,
                                                          n_of_v_basis_at_cub_points_side);
              cub_weights_side.resize(numCubPointsSide);
              
              FunctionSpaceTools::integrate<double>(rhs_vector_vec,
                                                    diri_data_at_cub_points_side,
                                                    w_n_of_v_basis_at_cub_points_side,
                                                    COMP_BLAS,
                                                    false);

              for (int i=0;i<numVectorFields;i++) {
                rhs_and_soln_vec(0,i) -= rhs_vector_vec(0,i);
              }
              
            }
            
            // solve linear system
            int info = 0;
            Teuchos::LAPACK<int, double> solver;
            solver.GESV(numTotalFields, 1, &fe_matrix(0,0,0), numTotalFields, &ipiv(0), &rhs_and_soln_vec(0,0), 
                        numTotalFields, &info);
            
            // compute interpolant; the scalar entries are last
            scalarBasis->getValues(value_of_s_basis_at_interp_points,
                                  interp_points_ref,
                                  OPERATOR_VALUE);
            for (int pt=0;pt<numInterpPoints;pt++) {
              interpolant(0,pt)=0.0;
              for (int i=0;i<numScalarFields;i++) {
                interpolant(0,pt) += rhs_and_soln_vec(0,numVectorFields+i)
                  * value_of_s_basis_at_interp_points(i,pt);
              }
            }
            
            interp_points_ref.resize(1,numInterpPoints,cellDim);
            // get exact solution for comparison
            FieldContainer<double> exact_solution(1,numInterpPoints);
            u_exact( exact_solution , interp_points_ref , x_order, y_order, z_order);
            interp_points_ref.resize(numInterpPoints,cellDim);

            RealSpaceTools<double>::add(interpolant,exact_solution);
            
            double nrm= RealSpaceTools<double>::vectorNorm(&interpolant(0,0),interpolant.dimension(1), NORM_TWO);

            *outStream << "\nNorm-2 error between scalar components of exact solution of order ("
                       << x_order << ", " << y_order << ", " << z_order
                       << ") and finite element interpolant of order " << basis_order << ": "
                       << nrm << "\n";

            if (nrm > zero) {
              *outStream << "\n\nPatch test failed for solution polynomial order ("
                         << x_order << ", " << y_order << ", " << z_order << ") and basis order (scalar, vector)  ("
                         << basis_order << ", " << basis_order+1 << ")\n\n";
              errorFlag++;
            }
            
          }
        }
      }
    }
    
  }
  
  catch (std::logic_error err) {
    *outStream << err.what() << "\n\n";
    errorFlag = -1000;
  };
  
  if (errorFlag != 0)
    std::cout << "End Result: TEST FAILED\n";
  else
    std::cout << "End Result: TEST PASSED\n";
  
  // reset format state of std::cout
  std::cout.copyfmt(oldFormatState);
  Kokkos::finalize();
  return errorFlag;
}
Example #2
0
int main(int argc, char *argv[]) {
Kokkos::initialize();
  //Check number of arguments
   if (argc < 4) {
      std::cout <<"\n>>> ERROR: Invalid number of arguments.\n\n";
      std::cout <<"Usage:\n\n";
      std::cout <<"  ./Intrepid_example_Drivers_Example_06.exe deg NX NY verbose\n\n";
      std::cout <<" where \n";
      std::cout <<"   int deg             - polynomial degree to be used (assumed > 1) \n";
      std::cout <<"   int NX              - num intervals in x direction (assumed box domain, 0,1) \n";
      std::cout <<"   int NY              - num intervals in y direction (assumed box domain, 0,1) \n";
      std::cout <<"   verbose (optional)  - any character, indicates verbose output \n\n";
      exit(1);
   }
  
  // This little trick lets us print to std::cout only if
  // a (dummy) command-line argument is provided.
  int iprint     = argc - 1;
  Teuchos::RCP<std::ostream> outStream;
  Teuchos::oblackholestream bhs; // outputs nothing
  if (iprint > 2)
    outStream = Teuchos::rcp(&std::cout, false);
  else
    outStream = Teuchos::rcp(&bhs, false);
  
  // Save the format state of the original std::cout.
  Teuchos::oblackholestream oldFormatState;
  oldFormatState.copyfmt(std::cout);
  
  *outStream \
    << "===============================================================================\n" \
    << "|                                                                             |\n" \
    << "|  Example: Apply Stiffness Matrix for                                        |\n" \
    << "|                   Poisson Equation on Quadrilateral Mesh                    |\n" \
    << "|                                                                             |\n" \
    << "|  Questions? Contact  Pavel Bochev  ([email protected]),                    |\n" \
    << "|                      Denis Ridzal  ([email protected]),                    |\n" \
    << "|                      Kara Peterson ([email protected]).                    |\n" \
    << "|                                                                             |\n" \
    << "|  Intrepid's website: http://trilinos.sandia.gov/packages/intrepid           |\n" \
    << "|  Trilinos website:   http://trilinos.sandia.gov                             |\n" \
    << "|                                                                             |\n" \
    << "===============================================================================\n";

  
  // ************************************ GET INPUTS **************************************
  
  int deg          = atoi(argv[1]);  // polynomial degree to use
  int NX            = atoi(argv[2]);  // num intervals in x direction (assumed box domain, 0,1)
  int NY            = atoi(argv[3]);  // num intervals in y direction (assumed box domain, 0,1)
  

  // *********************************** CELL TOPOLOGY **********************************
  
  // Get cell topology for base hexahedron
  typedef shards::CellTopology    CellTopology;
  CellTopology quad_4(shards::getCellTopologyData<shards::Quadrilateral<4> >() );
  
  // Get dimensions 
  int numNodesPerElem = quad_4.getNodeCount();
  int spaceDim = quad_4.getDimension();
  
  // *********************************** GENERATE MESH ************************************
  
  *outStream << "Generating mesh ... \n\n";
  
  *outStream << "   NX" << "   NY\n";
  *outStream << std::setw(5) << NX <<
    std::setw(5) << NY << "\n\n";
  
  // Print mesh information
  int numElems = NX*NY;
  int numNodes = (NX+1)*(NY+1);
  *outStream << " Number of Elements: " << numElems << " \n";
  *outStream << "    Number of Nodes: " << numNodes << " \n\n";
  
  // Square
  double leftX = 0.0, rightX = 1.0;
  double leftY = 0.0, rightY = 1.0;

  // Mesh spacing
  double hx = (rightX-leftX)/((double)NX);
  double hy = (rightY-leftY)/((double)NY);

  // Get nodal coordinates
  FieldContainer<double> nodeCoord(numNodes, spaceDim);
  FieldContainer<int> nodeOnBoundary(numNodes);
  int inode = 0;
  for (int j=0; j<NY+1; j++) {
    for (int i=0; i<NX+1; i++) {
      nodeCoord(inode,0) = leftX + (double)i*hx;
      nodeCoord(inode,1) = leftY + (double)j*hy;
      if (j==0 || i==0 || j==NY || i==NX){
	nodeOnBoundary(inode)=1;
      }
      else {
	nodeOnBoundary(inode)=0;
      }
      inode++;
    }
  }
#define DUMP_DATA
#ifdef DUMP_DATA
  // Print nodal coords
  ofstream fcoordout("coords.dat");
  for (int i=0; i<numNodes; i++) {
    fcoordout << nodeCoord(i,0) <<" ";
    fcoordout << nodeCoord(i,1) <<"\n";
  }
  fcoordout.close();
#endif
  
  
  // Element to Node map
  // We'll keep it around, but this is only the DOFMap if you are in the lowest order case.
  FieldContainer<int> elemToNode(numElems, numNodesPerElem);
  int ielem = 0;
  for (int j=0; j<NY; j++) {
    for (int i=0; i<NX; i++) {
      elemToNode(ielem,0) = (NX + 1)*j + i;
      elemToNode(ielem,1) = (NX + 1)*j + i + 1;
      elemToNode(ielem,2) = (NX + 1)*(j + 1) + i + 1;
      elemToNode(ielem,3) = (NX + 1)*(j + 1) + i;
      ielem++;
    }
  }
#ifdef DUMP_DATA
  // Output connectivity
  ofstream fe2nout("elem2node.dat");
  for (int j=0; j<NY; j++) {
    for (int i=0; i<NX; i++) {
      int ielem = i + j * NX;
      for (int m=0; m<numNodesPerElem; m++){
	fe2nout << elemToNode(ielem,m) <<"  ";
      }
      fe2nout <<"\n";
    }
  }
  fe2nout.close();
#endif
  
  // ************************************ CUBATURE ************************************** 
  *outStream << "Getting cubature ... \n\n";
  
  // Get numerical integration points and weights
  DefaultCubatureFactory<double>  cubFactory;                                   
  int cubDegree = 2*deg;
  Teuchos::RCP<Cubature<double> > quadCub = cubFactory.create(quad_4, cubDegree); 
  
  int cubDim       = quadCub->getDimension();
  int numCubPoints = quadCub->getNumPoints();
  
  FieldContainer<double> cubPoints(numCubPoints, cubDim);
  FieldContainer<double> cubWeights(numCubPoints);
  
  quadCub->getCubature(cubPoints, cubWeights);
  

  // ************************************** BASIS ***************************************
  
  *outStream << "Getting basis ... \n\n";
  
  // Define basis 
  Basis_HGRAD_QUAD_Cn_FEM<double, FieldContainer<double> > quadHGradBasis(deg,POINTTYPE_SPECTRAL);
  int numFieldsG = quadHGradBasis.getCardinality();
  FieldContainer<double> quadGVals(numFieldsG, numCubPoints); 
  FieldContainer<double> quadGrads(numFieldsG, numCubPoints, spaceDim); 
  
  // Evaluate basis values and gradients at cubature points
  quadHGradBasis.getValues(quadGVals, cubPoints, OPERATOR_VALUE);
  quadHGradBasis.getValues(quadGrads, cubPoints, OPERATOR_GRAD);

  // create the local-global mapping for higher order elements
  FieldContainer<int> ltgMapping(numElems,numFieldsG);
  const int numDOF = (NX*deg+1)*(NY*deg+1);
  ielem=0;
  for (int j=0;j<NY;j++) {
    for (int i=0;i<NX;i++) {
      const int start = deg * j * ( NX * deg + 1 ) + i * deg;
      // loop over local dof on this cell
      int local_dof_cur=0;
      for (int vertical=0;vertical<=deg;vertical++) {
	for (int horizontal=0;horizontal<=deg;horizontal++) {
	  ltgMapping(ielem,local_dof_cur) = start + vertical*(NX*deg+1)+horizontal;
	  local_dof_cur++;
	}
      }
      ielem++;
    }
  }
#ifdef DUMP_DATA
  // Output ltg mapping
//   ofstream ltgout("ltg.dat");
//   for (int j=0; j<NY; j++) {
//     for (int i=0; i<NX; i++) {
//       int ielem = i + j * NX;
//       for (int m=0; m<numFieldsG; m++){
// 	ltgout << ltgMapping(ielem,m) <<"  ";
//       }
//       ltgout <<"\n";
//     }
//   }
//   ltgout.close();
#endif
  
  // ******** CREATE A SINGLE STIFFNESS MATRIX, WHICH IS REPLICATED ON ALL ELEMENTS *********
  *outStream << "Applying stiffness matrix and right hand side ... \n\n";

  // Settings and data structures for mass and stiffness matrices
  typedef CellTools<double>  CellTools;
  typedef FunctionSpaceTools fst;
  int numCells = 1; 

  // Container for nodes
  FieldContainer<double> refQuadNodes(numCells, numNodesPerElem, spaceDim);
  // Containers for Jacobian
  FieldContainer<double> refQuadJacobian(numCells, numCubPoints, spaceDim, spaceDim);
  FieldContainer<double> refQuadJacobInv(numCells, numCubPoints, spaceDim, spaceDim);
  FieldContainer<double> refQuadJacobDet(numCells, numCubPoints);
  // Containers for element HGRAD stiffness matrix
  FieldContainer<double> localStiffMatrix(numCells, numFieldsG, numFieldsG);
  FieldContainer<double> weightedMeasure(numCells, numCubPoints);
  FieldContainer<double> quadGradsTransformed(numCells, numFieldsG, numCubPoints, spaceDim);
  FieldContainer<double> quadGradsTransformedWeighted(numCells, numFieldsG, numCubPoints, spaceDim);
  // Containers for right hand side vectors
  FieldContainer<double> rhsData(numCells, numCubPoints);
  FieldContainer<double> localRHS(numCells, numFieldsG);
  FieldContainer<double> quadGValsTransformed(numCells, numFieldsG, numCubPoints);
  FieldContainer<double> quadGValsTransformedWeighted(numCells, numFieldsG, numCubPoints);
  // Container for cubature points in physical space
  FieldContainer<double> physCubPoints(numCells, numCubPoints, cubDim);
  
  // Global arrays in Epetra format 
  Epetra_SerialComm Comm;
  Epetra_Map globalMapG(numDOF, 0, Comm);
  Epetra_FEVector u(globalMapG);
  Epetra_FEVector Ku(globalMapG);
  u.Random();

  std::cout << "About to start ref element matrix\n";

  // ************************** Compute element HGrad stiffness matrices *******************************  
  refQuadNodes(0,0,0) = 0.0;
  refQuadNodes(0,0,1) = 0.0;
  refQuadNodes(0,1,0) = hx;
  refQuadNodes(0,1,1) = 0.0;
  refQuadNodes(0,2,0) = hx;
  refQuadNodes(0,2,1) = hy;
  refQuadNodes(0,3,0) = 0.0;
  refQuadNodes(0,3,1) = hy;

  // Compute cell Jacobians, their inverses and their determinants
  CellTools::setJacobian(refQuadJacobian, cubPoints, refQuadNodes, quad_4);
  CellTools::setJacobianInv(refQuadJacobInv, refQuadJacobian );
  CellTools::setJacobianDet(refQuadJacobDet, refQuadJacobian );
  
  // transform from [-1,1]^2 to [0,hx]x[0,hy]
  fst::HGRADtransformGRAD<double>(quadGradsTransformed, refQuadJacobInv, quadGrads);
      
  // compute weighted measure
  fst::computeCellMeasure<double>(weightedMeasure, refQuadJacobDet, cubWeights);

  // multiply values with weighted measure
  fst::multiplyMeasure<double>(quadGradsTransformedWeighted,
			       weightedMeasure, quadGradsTransformed);

  // integrate to compute element stiffness matrix
  fst::integrate<double>(localStiffMatrix,
			 quadGradsTransformed, quadGradsTransformedWeighted, COMP_BLAS);

  std::cout << "Finished with reference element matrix\n";

  
  // now we will scatter global degrees of freedom, apply the local stiffness matrix 
  // with BLAS, and then gather the results
  FieldContainer<double> uScattered(numElems,numFieldsG);
  FieldContainer<double> KuScattered(numElems,numFieldsG);

  // to extract info from u

  u.GlobalAssemble();

  Epetra_Time multTimer(Comm);

  Ku.PutScalar(0.0);
  Ku.GlobalAssemble();

  double *uVals = u[0];
  double *KuVals = Ku[0];

  Teuchos::BLAS<int,double> blas;
  Epetra_Time scatterTime(Comm);
  std::cout << "Scattering\n";
  // Scatter
  for (int k=0; k<numElems; k++) 
    {
      for (int i=0;i<numFieldsG;i++) 
	{
	  uScattered(k,i) = uVals[ltgMapping(k,i)];
	}
    }
  const double scatTime = scatterTime.ElapsedTime();
  std::cout << "Scattered in time " << scatTime << "\n";

  Epetra_Time blasTimer(Comm);
  blas.GEMM(Teuchos::NO_TRANS , Teuchos::NO_TRANS , 
	    numFieldsG , numElems, numFieldsG  , 
	    1.0 , 
	    &localStiffMatrix(0,0,0) , 
	    numFieldsG ,
	    &uScattered(0,0) , 
	    numFieldsG , 
	    0.0 , 
	     &KuScattered(0,0) , 
	    numFieldsG );
  const double blasTime = blasTimer.ElapsedTime();
  std::cout << "Element matrices applied in " << blasTime << "\n";

  Epetra_Time gatherTimer(Comm);
  // Gather
  for (int k=0;k<numElems;k++)
    {
      for (int i=0;i<numFieldsG;i++)
	{
	  KuVals[ltgMapping(k,i)] += KuScattered(k,i);
	}
    }

  const double gatherTime = gatherTimer.ElapsedTime();
  std::cout << "Gathered in " << gatherTime << "\n";
  

  const double applyTime = gatherTime + blasTime + scatTime;
  std::cout << "Time to do matrix-free product: " << applyTime << std::endl;
  
  
  std::cout << "End Result: TEST PASSED\n";
  
  // reset format state of std::cout
  std::cout.copyfmt(oldFormatState);
 Kokkos::finalize(); 
  return 0;
}
Example #3
0
int main(int argc, char *argv[]) {

  Teuchos::GlobalMPISession mpiSession(&argc, &argv);

  // This little trick lets us print to std::cout only if
  // a (dummy) command-line argument is provided.
  int iprint     = argc - 1;
  Teuchos::RCP<std::ostream> outStream;
  Teuchos::oblackholestream bhs; // outputs nothing
  if (iprint > 0)
    outStream = Teuchos::rcp(&std::cout, false);
  else
    outStream = Teuchos::rcp(&bhs, false);

  // Save the format state of the original std::cout.
  Teuchos::oblackholestream oldFormatState;
  oldFormatState.copyfmt(std::cout);

  *outStream \
    << "===============================================================================\n" \
    << "|                                                                             |\n" \
    << "|               Unit Test (Basis_HGRAD_LINE_Cn_FEM_JACOBI)                    |\n" \
    << "|                                                                             |\n" \
    << "|     1) Conversion of Dof tags into Dof ordinals and back                    |\n" \
    << "|     2) Basis values for VALUE, GRAD, CURL, and Dk operators                 |\n" \
    << "|                                                                             |\n" \
    << "|  Questions? Contact  Pavel Bochev  ([email protected]),                    |\n" \
    << "|                      Denis Ridzal  ([email protected]),                    |\n" \
    << "|                      Kara Peterson ([email protected]).                    |\n" \
    << "|                                                                             |\n" \
    << "|  Intrepid's website: http://trilinos.sandia.gov/packages/intrepid           |\n" \
    << "|  Trilinos website:   http://trilinos.sandia.gov                             |\n" \
    << "|                                                                             |\n" \
    << "===============================================================================\n"\
    << "| TEST 1: Basis creation, exception testing                                   |\n"\
    << "===============================================================================\n";

  
  // Define basis and error flag
  double alpha = 0.0, beta = 0.0;
  Basis_HGRAD_LINE_Cn_FEM_JACOBI<double, FieldContainer<double> > lineBasis(5, alpha, beta);
  int errorFlag = 0;

  // Initialize throw counter for exception testing
  int nException     = 0;
  int throwCounter   = 0;
  
  // Define array containing vertices of the reference Line and a few other points   
  int numIntervals = 100;
  FieldContainer<double> lineNodes(numIntervals+1, 1);
  for (int i=0; i<numIntervals+1; i++) {
    lineNodes(i,0) = -1.0+(2.0*(double)i)/(double)numIntervals;
  }

  // Generic array for the output values; needs to be properly resized depending on the operator type
  FieldContainer<double> vals;

  try{
    // Exceptions 1-5: all bf tags/bf Ids below are wrong and should cause getDofOrdinal() and
    // getDofTag() to access invalid array elements thereby causing bounds check exception
    // exception #1
    INTREPID_TEST_COMMAND( lineBasis.getDofOrdinal(2,0,0), throwCounter, nException );
    // exception #2
    INTREPID_TEST_COMMAND( lineBasis.getDofOrdinal(1,1,1), throwCounter, nException );
    // exception #3
    INTREPID_TEST_COMMAND( lineBasis.getDofOrdinal(1,0,7), throwCounter, nException );
    // not an exception
    INTREPID_TEST_COMMAND( lineBasis.getDofOrdinal(1,0,5), throwCounter, nException ); --nException;
    // exception #4
    INTREPID_TEST_COMMAND( lineBasis.getDofTag(6), throwCounter, nException );
    // exception #5
    INTREPID_TEST_COMMAND( lineBasis.getDofTag(-1), throwCounter, nException );
    // not an exception
    INTREPID_TEST_COMMAND( lineBasis.getDofTag(5), throwCounter, nException ); --nException;
#ifdef HAVE_INTREPID_DEBUG
    // Exceptions 6-16 test exception handling with incorrectly dimensioned input/output arrays
    // exception #6: input points array must be of rank-2
    FieldContainer<double> badPoints1(4, 5, 3);
    INTREPID_TEST_COMMAND( lineBasis.getValues(vals, badPoints1, OPERATOR_VALUE), throwCounter, nException );

    // exception #7: dimension 1 in the input point array must equal space dimension of the cell
    FieldContainer<double> badPoints2(4, 3);
    INTREPID_TEST_COMMAND( lineBasis.getValues(vals, badPoints2, OPERATOR_VALUE), throwCounter, nException );

    // exception #8: output values must be of rank-2 for OPERATOR_VALUE
    FieldContainer<double> badVals1(4, 3, 1);
    INTREPID_TEST_COMMAND( lineBasis.getValues(badVals1, lineNodes, OPERATOR_VALUE), throwCounter, nException );

    // exception #9: output values must be of rank-3 for OPERATOR_GRAD
    FieldContainer<double> badVals2(4, 3);
    INTREPID_TEST_COMMAND( lineBasis.getValues(badVals2, lineNodes, OPERATOR_GRAD), throwCounter, nException );

    // exception #10: output values must be of rank-3 for OPERATOR_CURL
    INTREPID_TEST_COMMAND( lineBasis.getValues(badVals2, lineNodes, OPERATOR_CURL), throwCounter, nException );

    // exception #11: output values must be of rank-2 for OPERATOR_DIV
    INTREPID_TEST_COMMAND( lineBasis.getValues(badVals2, lineNodes, OPERATOR_DIV), throwCounter, nException );

    // exception #12: output values must be of rank-2 for OPERATOR_D1
    INTREPID_TEST_COMMAND( lineBasis.getValues(badVals2, lineNodes, OPERATOR_D1), throwCounter, nException );

    // exception #13: incorrect 0th dimension of output array (must equal number of basis functions)
    FieldContainer<double> badVals3(lineBasis.getCardinality() + 1, lineNodes.dimension(0));
    INTREPID_TEST_COMMAND( lineBasis.getValues(badVals3, lineNodes, OPERATOR_VALUE), throwCounter, nException );

    // exception #14: incorrect 1st dimension of output array (must equal number of points)
    FieldContainer<double> badVals4(lineBasis.getCardinality(), lineNodes.dimension(0) + 1);
    INTREPID_TEST_COMMAND( lineBasis.getValues(badVals4, lineNodes, OPERATOR_VALUE), throwCounter, nException );

    // exception #15: incorrect 2nd dimension of output array (must equal spatial dimension)
    FieldContainer<double> badVals5(lineBasis.getCardinality(), lineNodes.dimension(0), 2);
    INTREPID_TEST_COMMAND( lineBasis.getValues(badVals5, lineNodes, OPERATOR_GRAD), throwCounter, nException );

    // not an exception
    FieldContainer<double> goodVals2(lineBasis.getCardinality(), lineNodes.dimension(0));
    INTREPID_TEST_COMMAND( lineBasis.getValues(goodVals2, lineNodes, OPERATOR_VALUE), throwCounter, nException ); --nException;
#endif

  }
  catch (std::logic_error err) {
    *outStream << "UNEXPECTED ERROR !!! ----------------------------------------------------------\n";
    *outStream << err.what() << '\n';
    *outStream << "-------------------------------------------------------------------------------" << "\n\n";
    errorFlag = -1000;
  };

  // Check if number of thrown exceptions matches the one we expect
  if (throwCounter != nException) {
    errorFlag++;
    *outStream << std::setw(70) << "FAILURE! Incorrect number of exceptions." << "\n";
  }


  *outStream \
    << "\n"
    << "===============================================================================\n"\
    << "| TEST 3: orthogonality of basis functions                                    |\n"\
    << "===============================================================================\n";

  outStream -> precision(20);

  try {

    // Check orthogonality property for Legendre polynomials.
    int maxorder = 10;

    DefaultCubatureFactory<double>  cubFactory;                                   // create factory
    shards::CellTopology line(shards::getCellTopologyData< shards::Line<> >());   // create cell topology
    for (int ordi=0; ordi < maxorder; ordi++) {
      //create left basis
      Teuchos::RCP<Basis<double,FieldContainer<double> > > lineBasisLeft =
        Teuchos::rcp(new Basis_HGRAD_LINE_Cn_FEM_JACOBI<double,FieldContainer<double> >(ordi) );

      for (int ordj=0; ordj < maxorder; ordj++) {

        //create right basis
        Teuchos::RCP<Basis<double,FieldContainer<double> > > lineBasisRight =
          Teuchos::rcp(new Basis_HGRAD_LINE_Cn_FEM_JACOBI<double,FieldContainer<double> >(ordj) );

        // get cubature points and weights
        Teuchos::RCP<Cubature<double> > lineCub = cubFactory.create(line, ordi+ordj);
        int numPoints = lineCub->getNumPoints();
        FieldContainer<double> cubPoints (numPoints, lineCub->getDimension());
        FieldContainer<double> cubWeights(numPoints);
        FieldContainer<double> cubWeightsC(1, numPoints);
        lineCub->getCubature(cubPoints, cubWeights);
        // "reshape" weights
        for (int i=0; i<numPoints; i++) { cubWeightsC(0,i) = cubWeights(i); }
        

        // get basis values
        int numFieldsLeft  = lineBasisLeft ->getCardinality();
        int numFieldsRight = lineBasisRight->getCardinality();
        FieldContainer<double> valsLeft(numFieldsLeft,numPoints),
                               valsRight(numFieldsRight,numPoints);
        lineBasisLeft ->getValues(valsLeft,  cubPoints, OPERATOR_VALUE);
        lineBasisRight->getValues(valsRight, cubPoints, OPERATOR_VALUE);

        // reshape by cloning and integrate
        FieldContainer<double> valsLeftC(1, numFieldsLeft,numPoints),
                               valsRightC(1, numFieldsRight,numPoints),
                               massMatrix(1, numFieldsLeft, numFieldsRight);
        ArrayTools::cloneFields<double>(valsLeftC, valsLeft);
        ArrayTools::cloneFields<double>(valsRightC, valsRight);
        ArrayTools::scalarMultiplyDataField<double>(valsRightC, cubWeightsC, valsRightC);
        FunctionSpaceTools::integrate<double>(massMatrix, valsLeftC, valsRightC, COMP_CPP);

        // check orthogonality property
        for (int i=0; i<numFieldsLeft; i++) {
          for (int j=0; j<numFieldsRight; j++) {

            if (i==j) {
              if ( std::abs(massMatrix(0,i,j)-(double)(2.0/(2.0*j+1.0))) > INTREPID_TOL ) {
                *outStream << "Incorrect ii (\"diagonal\") value for i=" << i << ", j=" << j << ": "
                           << massMatrix(0,i,j) << " != " << "2/(2*" << j << "+1)\n\n";
                errorFlag++;
              }
            }
            else {
              if ( std::abs(massMatrix(0,i,j)) > INTREPID_TOL ) {
                *outStream << "Incorrect ij (\"off-diagonal\") value for i=" << i << ", j=" << j << ": "
                           << massMatrix(0,i,j) << " != " << "0\n\n";
                errorFlag++;
              }
            }
          }
        }

      }
    }

  }
  // Catch unexpected errors
  catch (std::logic_error err) {
    *outStream << err.what() << "\n\n";
    errorFlag = -1000;
  };

  *outStream \
    << "\n"
    << "===============================================================================\n"\
    << "| TEST 4: correctness of basis function derivatives                           |\n"\
    << "===============================================================================\n";

  outStream -> precision(20);

  // function values stored by bf, then pt
  double basisValues[] = {
    1.000000000000000, 1.000000000000000, 1.000000000000000,	\
    1.000000000000000, -1.000000000000000, -0.3333333333333333, \
    0.3333333333333333, 1.000000000000000, 1.000000000000000,	\
    -0.3333333333333333, -0.3333333333333333, 1.000000000000000,	\
    -1.000000000000000, 0.4074074074074074, -0.4074074074074074,	\
    1.000000000000000};

  double basisD1Values[] = 
    {0, 0, 0, 0, 1.000000000000000, 1.000000000000000, 1.000000000000000, \
     1.000000000000000, -3.000000000000000, -1.000000000000000,		\
     1.000000000000000, 3.000000000000000, 6.000000000000000,		\
     -0.6666666666666667, -0.6666666666666667, 6.000000000000000};

  double basisD2Values[] = 
    {0, 0, 0, 0, 0, 0, 0, 0, 3.000000000000000, 3.000000000000000,	\
     3.000000000000000, 3.000000000000000, -15.00000000000000,		\
     -5.000000000000000, 5.000000000000000, 15.00000000000000};

  double basisD3Values[] = 
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15.00000000000000,		\
     15.00000000000000, 15.00000000000000, 15.00000000000000};
  


  try {
    Basis_HGRAD_LINE_Cn_FEM_JACOBI<double, FieldContainer<double> > lineBasis3(3, alpha, beta);
    int numIntervals = 3;
    FieldContainer<double> lineNodes3(numIntervals+1, 1);
    FieldContainer<double> vals;
    for (int i=0; i<numIntervals+1; i++) {
      lineNodes3(i,0) = -1.0+(2.0*(double)i)/(double)numIntervals;
    }
    int numFields = lineBasis3.getCardinality();
    int numPoints = lineNodes3.dimension(0);

    // test basis values
    vals.resize(numFields, numPoints);
    lineBasis3.getValues(vals,lineNodes3,OPERATOR_VALUE);
    for (int i = 0; i < numFields; i++) {
      for (int j = 0; j < numPoints; j++) {
        
        // Compute offset for (F,P) container
        int l =  j + i * numPoints;
	if (std::abs(vals(i,j) - basisValues[l]) > INTREPID_TOL) {
	  errorFlag++;
	  *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
	  
	  // Output the multi-index of the value where the error is:
	  *outStream << " At multi-index { ";
	  *outStream << i << " ";*outStream << j << " ";
	  *outStream << "}  computed value: " << vals(i,j)
		     << " but reference value: " << basisValues[l] << "\n";
	}
      }
    }

    // test basis derivatives
    vals.resize(numFields, numPoints,1);
    lineBasis3.getValues(vals,lineNodes3,OPERATOR_D1);
    for (int i = 0; i < numFields; i++) {
      for (int j = 0; j < numPoints; j++) {
        
        // Compute offset for (F,P) container
        int l =  j + i * numPoints;
	if (std::abs(vals(i,j,0) - basisD1Values[l]) > INTREPID_TOL) {
	  errorFlag++;
	  *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
	  
	  // Output the multi-index of the value where the error is:
	  *outStream << " At multi-index { ";
	  *outStream << i << " ";*outStream << j << " ";
	  *outStream << "}  computed value: " << vals(i,j,0)
		     << " but reference value: " << basisD1Values[l] << "\n";
	}
      }
    }

    vals.resize(numFields, numPoints,1);
    lineBasis3.getValues(vals,lineNodes3,OPERATOR_D2);
    for (int i = 0; i < numFields; i++) {
      for (int j = 0; j < numPoints; j++) {
        
        // Compute offset for (F,P) container
        int l =  j + i * numPoints;
	if (std::abs(vals(i,j,0) - basisD2Values[l]) > INTREPID_TOL) {
	  errorFlag++;
	  *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
	  
	  // Output the multi-index of the value where the error is:
	  *outStream << " At multi-index { ";
	  *outStream << i << " ";*outStream << j << " ";
	  *outStream << "}  computed value: " << vals(i,j,0)
		     << " but reference value: " << basisD2Values[l] << "\n";
	}
      }
    }

    vals.resize(numFields, numPoints,1);
    lineBasis3.getValues(vals,lineNodes3,OPERATOR_D3);
    for (int i = 0; i < numFields; i++) {
      for (int j = 0; j < numPoints; j++) {
        
        // Compute offset for (F,P) container
        int l =  j + i * numPoints;
	if (std::abs(vals(i,j,0) - basisD3Values[l]) > INTREPID_TOL) {
	  errorFlag++;
	  *outStream << std::setw(70) << "^^^^----FAILURE!" << "\n";
	  
	  // Output the multi-index of the value where the error is:
	  *outStream << " At multi-index { ";
	  *outStream << i << " ";*outStream << j << " ";
	  *outStream << "}  computed value: " << vals(i,j,0)
		     << " but reference value: " << basisD3Values[l] << "\n";
	}
      }
    }
  }
  // Catch unexpected errors
  catch (std::logic_error err) {
    *outStream << err.what() << "\n\n";
    errorFlag = -1000;
  };


  if (errorFlag != 0)
    std::cout << "End Result: TEST FAILED\n";
  else
    std::cout << "End Result: TEST PASSED\n";

  // reset format state of std::cout
  std::cout.copyfmt(oldFormatState);

  return errorFlag;
}
Example #4
0
int main(int argc, char *argv[]) {
Kokkos::initialize();
  //Check number of arguments
   if (argc < 4) {
      std::cout <<"\n>>> ERROR: Invalid number of arguments.\n\n";
      std::cout <<"Usage:\n\n";
      std::cout <<"  ./Intrepid_example_Drivers_Example_03.exe NX NY NZ verbose\n\n";
      std::cout <<" where \n";
      std::cout <<"   int NX              - num intervals in x direction (assumed box domain, 0,1) \n";
      std::cout <<"   int NY              - num intervals in y direction (assumed box domain, 0,1) \n";
      std::cout <<"   int NZ              - num intervals in z direction (assumed box domain, 0,1) \n";
      std::cout <<"   verbose (optional)  - any character, indicates verbose output \n\n";
      exit(1);
   }
  
  // This little trick lets us print to std::cout only if
  // a (dummy) command-line argument is provided.
  int iprint     = argc - 1;
  Teuchos::RCP<std::ostream> outStream;
  Teuchos::oblackholestream bhs; // outputs nothing
  if (iprint > 3)
    outStream = Teuchos::rcp(&std::cout, false);
  else
    outStream = Teuchos::rcp(&bhs, false);
  
  // Save the format state of the original std::cout.
  Teuchos::oblackholestream oldFormatState;
  oldFormatState.copyfmt(std::cout);
  
  *outStream \
    << "===============================================================================\n" \
    << "|                                                                             |\n" \
    << "|  Example: Generate Stiffness Matrix and Right Hand Side Vector for          |\n" \
    << "|                   Poisson Equation on Hexahedral Mesh                       |\n" \
    << "|                                                                             |\n" \
    << "|  Questions? Contact  Pavel Bochev  ([email protected]),                    |\n" \
    << "|                      Denis Ridzal  ([email protected]),                    |\n" \
    << "|                      Kara Peterson ([email protected]).                    |\n" \
    << "|                                                                             |\n" \
    << "|  Intrepid's website: http://trilinos.sandia.gov/packages/intrepid           |\n" \
    << "|  Trilinos website:   http://trilinos.sandia.gov                             |\n" \
    << "|                                                                             |\n" \
    << "===============================================================================\n";


// ************************************ GET INPUTS **************************************

    int NX            = atoi(argv[1]);  // num intervals in x direction (assumed box domain, 0,1)
    int NY            = atoi(argv[2]);  // num intervals in y direction (assumed box domain, 0,1)
    int NZ            = atoi(argv[3]);  // num intervals in z direction (assumed box domain, 0,1)

// *********************************** CELL TOPOLOGY **********************************

   // Get cell topology for base hexahedron
    typedef shards::CellTopology    CellTopology;
    CellTopology hex_8(shards::getCellTopologyData<shards::Hexahedron<8> >() );

   // Get dimensions 
    int numNodesPerElem = hex_8.getNodeCount();
    int spaceDim = hex_8.getDimension();

// *********************************** GENERATE MESH ************************************

    *outStream << "Generating mesh ... \n\n";

    *outStream << "   NX" << "   NY" << "   NZ\n";
    *outStream << std::setw(5) << NX <<
                 std::setw(5) << NY <<
                 std::setw(5) << NZ << "\n\n";

   // Print mesh information
    int numElems = NX*NY*NZ;
    int numNodes = (NX+1)*(NY+1)*(NZ+1);
    *outStream << " Number of Elements: " << numElems << " \n";
    *outStream << "    Number of Nodes: " << numNodes << " \n\n";

   // Cube
    double leftX = 0.0, rightX = 1.0;
    double leftY = 0.0, rightY = 1.0;
    double leftZ = 0.0, rightZ = 1.0;

   // Mesh spacing
    double hx = (rightX-leftX)/((double)NX);
    double hy = (rightY-leftY)/((double)NY);
    double hz = (rightZ-leftZ)/((double)NZ);

   // Get nodal coordinates
    FieldContainer<double> nodeCoord(numNodes, spaceDim);
    FieldContainer<int> nodeOnBoundary(numNodes);
    int inode = 0;
    for (int k=0; k<NZ+1; k++) {
      for (int j=0; j<NY+1; j++) {
        for (int i=0; i<NX+1; i++) {
          nodeCoord(inode,0) = leftX + (double)i*hx;
          nodeCoord(inode,1) = leftY + (double)j*hy;
          nodeCoord(inode,2) = leftZ + (double)k*hz;
          if (k==0 || j==0 || i==0 || k==NZ || j==NY || i==NX){
             nodeOnBoundary(inode)=1;
          }
          else {
             nodeOnBoundary(inode)=0;
          }
          inode++;
        }
      }
    }
#define DUMP_DATA
#ifdef DUMP_DATA
   // Print nodal coords
    ofstream fcoordout("coords.dat");
    for (int i=0; i<numNodes; i++) {
       fcoordout << nodeCoord(i,0) <<" ";
       fcoordout << nodeCoord(i,1) <<" ";
       fcoordout << nodeCoord(i,2) <<"\n";
    }
    fcoordout.close();
#endif


  // Element to Node map
    FieldContainer<int> elemToNode(numElems, numNodesPerElem);
    int ielem = 0;
    for (int k=0; k<NZ; k++) {
      for (int j=0; j<NY; j++) {
        for (int i=0; i<NX; i++) {
          elemToNode(ielem,0) = (NY + 1)*(NX + 1)*k + (NX + 1)*j + i;
          elemToNode(ielem,1) = (NY + 1)*(NX + 1)*k + (NX + 1)*j + i + 1;
          elemToNode(ielem,2) = (NY + 1)*(NX + 1)*k + (NX + 1)*(j + 1) + i + 1;
          elemToNode(ielem,3) = (NY + 1)*(NX + 1)*k + (NX + 1)*(j + 1) + i;
          elemToNode(ielem,4) = (NY + 1)*(NX + 1)*(k + 1) + (NX + 1)*j + i;
          elemToNode(ielem,5) = (NY + 1)*(NX + 1)*(k + 1) + (NX + 1)*j + i + 1;
          elemToNode(ielem,6) = (NY + 1)*(NX + 1)*(k + 1) + (NX + 1)*(j + 1) + i + 1;
          elemToNode(ielem,7) = (NY + 1)*(NX + 1)*(k + 1) + (NX + 1)*(j + 1) + i;
          ielem++;
        }
      }
    }
#ifdef DUMP_DATA
   // Output connectivity
    ofstream fe2nout("elem2node.dat");
    for (int k=0; k<NZ; k++) {
      for (int j=0; j<NY; j++) {
        for (int i=0; i<NX; i++) {
          int ielem = i + j * NX + k * NX * NY;
          for (int m=0; m<numNodesPerElem; m++){
              fe2nout << elemToNode(ielem,m) <<"  ";
           }
          fe2nout <<"\n";
        }
      }
    }
    fe2nout.close();
#endif


// ************************************ CUBATURE **************************************

    *outStream << "Getting cubature ... \n\n";

   // Get numerical integration points and weights
    DefaultCubatureFactory<double>  cubFactory;                                   
    int cubDegree = 2;
    Teuchos::RCP<Cubature<double> > hexCub = cubFactory.create(hex_8, cubDegree); 

    int cubDim       = hexCub->getDimension();
    int numCubPoints = hexCub->getNumPoints();

    FieldContainer<double> cubPoints(numCubPoints, cubDim);
    FieldContainer<double> cubWeights(numCubPoints);

    hexCub->getCubature(cubPoints, cubWeights);


// ************************************** BASIS ***************************************

     *outStream << "Getting basis ... \n\n";

   // Define basis 
     Basis_HGRAD_HEX_C1_FEM<double, FieldContainer<double> > hexHGradBasis;
     int numFieldsG = hexHGradBasis.getCardinality();
     FieldContainer<double> hexGVals(numFieldsG, numCubPoints); 
     FieldContainer<double> hexGrads(numFieldsG, numCubPoints, spaceDim); 

  // Evaluate basis values and gradients at cubature points
     hexHGradBasis.getValues(hexGVals, cubPoints, OPERATOR_VALUE);
     hexHGradBasis.getValues(hexGrads, cubPoints, OPERATOR_GRAD);


// ******** LOOP OVER ELEMENTS TO CREATE LOCAL STIFFNESS MATRIX *************

    *outStream << "Building stiffness matrix and right hand side ... \n\n";

 // Settings and data structures for mass and stiffness matrices
    typedef CellTools<double>  CellTools;
    typedef FunctionSpaceTools fst;
    int numCells = 1; 

   // Container for nodes
    FieldContainer<double> hexNodes(numCells, numNodesPerElem, spaceDim);
   // Containers for Jacobian
    FieldContainer<double> hexJacobian(numCells, numCubPoints, spaceDim, spaceDim);
    FieldContainer<double> hexJacobInv(numCells, numCubPoints, spaceDim, spaceDim);
    FieldContainer<double> hexJacobDet(numCells, numCubPoints);
   // Containers for element HGRAD stiffness matrix
    FieldContainer<double> localStiffMatrix(numCells, numFieldsG, numFieldsG);
    FieldContainer<double> weightedMeasure(numCells, numCubPoints);
    FieldContainer<double> hexGradsTransformed(numCells, numFieldsG, numCubPoints, spaceDim);
    FieldContainer<double> hexGradsTransformedWeighted(numCells, numFieldsG, numCubPoints, spaceDim);
   // Containers for right hand side vectors
    FieldContainer<double> rhsData(numCells, numCubPoints);
    FieldContainer<double> localRHS(numCells, numFieldsG);
    FieldContainer<double> hexGValsTransformed(numCells, numFieldsG, numCubPoints);
    FieldContainer<double> hexGValsTransformedWeighted(numCells, numFieldsG, numCubPoints);
   // Container for cubature points in physical space
    FieldContainer<double> physCubPoints(numCells, numCubPoints, cubDim);

   // Global arrays in Epetra format 
    Epetra_SerialComm Comm;
    Epetra_Map globalMapG(numNodes, 0, Comm);
    Epetra_FECrsMatrix StiffMatrix(Copy, globalMapG, numFieldsG);
    Epetra_FEVector rhs(globalMapG);

 // *** Element loop ***
    for (int k=0; k<numElems; k++) {

     // Physical cell coordinates
      for (int i=0; i<numNodesPerElem; i++) {
         hexNodes(0,i,0) = nodeCoord(elemToNode(k,i),0);
         hexNodes(0,i,1) = nodeCoord(elemToNode(k,i),1);
         hexNodes(0,i,2) = nodeCoord(elemToNode(k,i),2);
      }

    // Compute cell Jacobians, their inverses and their determinants
       CellTools::setJacobian(hexJacobian, cubPoints, hexNodes, hex_8);
       CellTools::setJacobianInv(hexJacobInv, hexJacobian );
       CellTools::setJacobianDet(hexJacobDet, hexJacobian );

// ************************** Compute element HGrad stiffness matrices *******************************
  
     // transform to physical coordinates 
      fst::HGRADtransformGRAD<double>(hexGradsTransformed, hexJacobInv, hexGrads);
      
     // compute weighted measure
      fst::computeCellMeasure<double>(weightedMeasure, hexJacobDet, cubWeights);

     // multiply values with weighted measure
      fst::multiplyMeasure<double>(hexGradsTransformedWeighted,
                                   weightedMeasure, hexGradsTransformed);

     // integrate to compute element stiffness matrix
      fst::integrate<double>(localStiffMatrix,
                             hexGradsTransformed, hexGradsTransformedWeighted, COMP_BLAS);

      // assemble into global matrix
      for (int row = 0; row < numFieldsG; row++){
        for (int col = 0; col < numFieldsG; col++){
            int rowIndex = elemToNode(k,row);
            int colIndex = elemToNode(k,col);
            double val = localStiffMatrix(0,row,col);
            StiffMatrix.InsertGlobalValues(1, &rowIndex, 1, &colIndex, &val);
         }
      }

// ******************************* Build right hand side ************************************

      // transform integration points to physical points
       CellTools::mapToPhysicalFrame(physCubPoints, cubPoints, hexNodes, hex_8);

      // evaluate right hand side function at physical points
       for (int nPt = 0; nPt < numCubPoints; nPt++){

          double x = physCubPoints(0,nPt,0);
          double y = physCubPoints(0,nPt,1);
          double z = physCubPoints(0,nPt,2);

          rhsData(0,nPt) = evalDivGradu(x, y, z);
       }

     // transform basis values to physical coordinates 
      fst::HGRADtransformVALUE<double>(hexGValsTransformed, hexGVals);

     // multiply values with weighted measure
      fst::multiplyMeasure<double>(hexGValsTransformedWeighted,
                                   weightedMeasure, hexGValsTransformed);

     // integrate rhs term
      fst::integrate<double>(localRHS, rhsData, hexGValsTransformedWeighted, 
                             COMP_BLAS);

    // assemble into global vector
     for (int row = 0; row < numFieldsG; row++){
           int rowIndex = elemToNode(k,row);
           double val = -localRHS(0,row);
           rhs.SumIntoGlobalValues(1, &rowIndex, &val);
      }
     
 } // *** end element loop ***


  // Assemble global matrices
   StiffMatrix.GlobalAssemble(); StiffMatrix.FillComplete();
   rhs.GlobalAssemble();

 
  // Adjust stiffness matrix and rhs based on boundary conditions
   for (int row = 0; row<numNodes; row++){
       if (nodeOnBoundary(row)) {
          int rowindex = row;
          for (int col=0; col<numNodes; col++){
              double val = 0.0;
              int colindex = col;
              StiffMatrix.ReplaceGlobalValues(1, &rowindex, 1, &colindex, &val);
          }
          double val = 1.0;
          StiffMatrix.ReplaceGlobalValues(1, &rowindex, 1, &rowindex, &val);
          val = 0.0;
          rhs.ReplaceGlobalValues(1, &rowindex, &val);
       }
    }

#ifdef DUMP_DATA
   // Dump matrices to disk
     EpetraExt::RowMatrixToMatlabFile("stiff_matrix.dat",StiffMatrix);
     EpetraExt::MultiVectorToMatrixMarketFile("rhs_vector.dat",rhs,0,0,false);
#endif

   std::cout << "End Result: TEST PASSED\n";
   
   // reset format state of std::cout
   std::cout.copyfmt(oldFormatState);
   Kokkos::finalize();
   return 0;
}
Example #5
0
int main(int argc, char *argv[]) {
Kokkos::initialize();
    // Check number of arguments
    if (argc < 4) {
      std::cout <<"\n>>> ERROR: Invalid number of arguments.\n\n";
      std::cout <<"Usage:\n\n";
      std::cout <<"  ./Intrepid_example_Drivers_Example_03NL.exe NX NY NZ verbose\n\n";
      std::cout <<" where \n";
      std::cout <<"   int NX              - num intervals in x direction (assumed box domain, 0,1) \n";
      std::cout <<"   int NY              - num intervals in y direction (assumed box domain, 0,1) \n";
      std::cout <<"   int NZ              - num intervals in z direction (assumed box domain, 0,1) \n";
      std::cout <<"   verbose (optional)  - any character, indicates verbose output \n\n";
      exit(1);
    }
  
    // This little trick lets us print to std::cout only if
    // a (dummy) command-line argument is provided.
    int iprint     = argc - 1;
    Teuchos::RCP<std::ostream> outStream;
    Teuchos::oblackholestream bhs; // outputs nothing
    if (iprint > 3)
      outStream = Teuchos::rcp(&std::cout, false);
    else
      outStream = Teuchos::rcp(&bhs, false);
  
    // Save the format state of the original std::cout.
    Teuchos::oblackholestream oldFormatState;
    oldFormatState.copyfmt(std::cout);
  
    *outStream \
    << "===============================================================================\n" \
    << "|                                                                             |\n" \
    << "|  Example: Generate PDE Jacobian for a Nonlinear Reaction-Diffusion          |\n" \
    << "|                   Equation on Hexahedral Mesh                               |\n" \
    << "|                                                                             |\n" \
    << "|  Questions? Contact  Pavel Bochev  ([email protected]),                    |\n" \
    << "|                      Denis Ridzal  ([email protected]),                    |\n" \
    << "|                      Kara Peterson ([email protected]).                    |\n" \
    << "|                                                                             |\n" \
    << "|  Intrepid's website: http://trilinos.sandia.gov/packages/intrepid           |\n" \
    << "|  Trilinos website:   http://trilinos.sandia.gov                             |\n" \
    << "|                                                                             |\n" \
    << "===============================================================================\n";


    // ************************************ GET INPUTS **************************************

    int NX = atoi(argv[1]);  // num intervals in x direction (assumed box domain, 0,1)
    int NY = atoi(argv[2]);  // num intervals in y direction (assumed box domain, 0,1)
    int NZ = atoi(argv[3]);  // num intervals in z direction (assumed box domain, 0,1)

    // *********************************** CELL TOPOLOGY **********************************

    // Get cell topology for base hexahedron
    typedef shards::CellTopology CellTopology;
    CellTopology hex_8(shards::getCellTopologyData<shards::Hexahedron<8> >() );

    // Get dimensions 
    int numNodesPerElem = hex_8.getNodeCount();
    int spaceDim = hex_8.getDimension();

    // *********************************** GENERATE MESH ************************************

    *outStream << "Generating mesh ... \n\n";

    *outStream << "   NX" << "   NY" << "   NZ\n";
    *outStream << std::setw(5) << NX <<
                  std::setw(5) << NY <<
                  std::setw(5) << NZ << "\n\n";

    // Print mesh information
    int numElems = NX*NY*NZ;
    int numNodes = (NX+1)*(NY+1)*(NZ+1);
    *outStream << " Number of Elements: " << numElems << " \n";
    *outStream << "    Number of Nodes: " << numNodes << " \n\n";

    // Cube
    double leftX = 0.0, rightX = 1.0;
    double leftY = 0.0, rightY = 1.0;
    double leftZ = 0.0, rightZ = 1.0;

    // Mesh spacing
    double hx = (rightX-leftX)/((double)NX);
    double hy = (rightY-leftY)/((double)NY);
    double hz = (rightZ-leftZ)/((double)NZ);

    // Get nodal coordinates
    FieldContainer<double> nodeCoord(numNodes, spaceDim);
    FieldContainer<int> nodeOnBoundary(numNodes);
    int inode = 0;
    for (int k=0; k<NZ+1; k++) {
      for (int j=0; j<NY+1; j++) {
        for (int i=0; i<NX+1; i++) {
          nodeCoord(inode,0) = leftX + (double)i*hx;
          nodeCoord(inode,1) = leftY + (double)j*hy;
          nodeCoord(inode,2) = leftZ + (double)k*hz;
          if (k==0 || j==0 || i==0 || k==NZ || j==NY || i==NX){
             nodeOnBoundary(inode)=1;
          }
          else {
             nodeOnBoundary(inode)=0;
          }
          inode++;
        }
      }
    }

#ifdef DUMP_DATA
    // Print nodal coords
    ofstream fcoordout("coords.dat");
    for (int i=0; i<numNodes; i++) {
       fcoordout << nodeCoord(i,0) <<" ";
       fcoordout << nodeCoord(i,1) <<" ";
       fcoordout << nodeCoord(i,2) <<"\n";
    }
    fcoordout.close();
#endif


    // Element to Node map
    FieldContainer<int> elemToNode(numElems, numNodesPerElem);
    int ielem = 0;
    for (int k=0; k<NZ; k++) {
      for (int j=0; j<NY; j++) {
        for (int i=0; i<NX; i++) {
          elemToNode(ielem,0) = (NY + 1)*(NX + 1)*k + (NX + 1)*j + i;
          elemToNode(ielem,1) = (NY + 1)*(NX + 1)*k + (NX + 1)*j + i + 1;
          elemToNode(ielem,2) = (NY + 1)*(NX + 1)*k + (NX + 1)*(j + 1) + i + 1;
          elemToNode(ielem,3) = (NY + 1)*(NX + 1)*k + (NX + 1)*(j + 1) + i;
          elemToNode(ielem,4) = (NY + 1)*(NX + 1)*(k + 1) + (NX + 1)*j + i;
          elemToNode(ielem,5) = (NY + 1)*(NX + 1)*(k + 1) + (NX + 1)*j + i + 1;
          elemToNode(ielem,6) = (NY + 1)*(NX + 1)*(k + 1) + (NX + 1)*(j + 1) + i + 1;
          elemToNode(ielem,7) = (NY + 1)*(NX + 1)*(k + 1) + (NX + 1)*(j + 1) + i;
          ielem++;
        }
      }
    }
#ifdef DUMP_DATA
    // Output connectivity
    ofstream fe2nout("elem2node.dat");
    for (int k=0; k<NZ; k++) {
      for (int j=0; j<NY; j++) {
        for (int i=0; i<NX; i++) {
          int ielem = i + j * NX + k * NX * NY;
          for (int m=0; m<numNodesPerElem; m++){
              fe2nout << elemToNode(ielem,m) <<"  ";
           }
          fe2nout <<"\n";
        }
      }
    }
    fe2nout.close();
#endif


    // ************************************ CUBATURE **************************************

    *outStream << "Getting cubature ... \n\n";

    // Get numerical integration points and weights
    DefaultCubatureFactory<double>  cubFactory;                                   
    int cubDegree = 2;
    Teuchos::RCP<Cubature<double> > hexCub = cubFactory.create(hex_8, cubDegree); 

    int cubDim       = hexCub->getDimension();
    int numCubPoints = hexCub->getNumPoints();

    FieldContainer<double> cubPoints(numCubPoints, cubDim);
    FieldContainer<double> cubWeights(numCubPoints);

    hexCub->getCubature(cubPoints, cubWeights);


    // ************************************** BASIS ***************************************

    *outStream << "Getting basis ... \n\n";

    // Define basis 
    Basis_HGRAD_HEX_C1_FEM<double, FieldContainer<double> > hexHGradBasis;
    int numFieldsG = hexHGradBasis.getCardinality();
    FieldContainer<double> hexGVals(numFieldsG, numCubPoints); 
    FieldContainer<double> hexGrads(numFieldsG, numCubPoints, spaceDim); 

    // Evaluate basis values and gradients at cubature points
    hexHGradBasis.getValues(hexGVals, cubPoints, OPERATOR_VALUE);
    hexHGradBasis.getValues(hexGrads, cubPoints, OPERATOR_GRAD);


    // ******** FEM ASSEMBLY *************

    *outStream << "Building PDE Jacobian ... \n\n";

    // Settings and data structures for mass and stiffness matrices
    typedef CellTools<double>  CellTools;
    typedef FunctionSpaceTools fst;
    int numCells = BATCH_SIZE; 
    int numBatches = numElems/numCells; 

    // Container for nodes
    FieldContainer<double> hexNodes(numCells, numNodesPerElem, spaceDim);
    // Containers for Jacobian
    FieldContainer<double> hexJacobian(numCells, numCubPoints, spaceDim, spaceDim);
    FieldContainer<double> hexJacobInv(numCells, numCubPoints, spaceDim, spaceDim);
    FieldContainer<double> hexJacobDet(numCells, numCubPoints);
    // Containers for HGRAD bases
    FieldContainer<double> localPDEjacobian(numCells, numFieldsG, numFieldsG);
    FieldContainer<double> weightedMeasure(numCells, numCubPoints);
    FieldContainer<double> hexGValsTransformed(numCells, numFieldsG, numCubPoints);
    FieldContainer<double> hexGValsTransformedWeighted(numCells, numFieldsG, numCubPoints);
    FieldContainer<double> hexGradsTransformed(numCells, numFieldsG, numCubPoints, spaceDim);
    FieldContainer<double> hexGradsTransformedWeighted(numCells, numFieldsG, numCubPoints, spaceDim);

    // Global arrays in Epetra format 
    Epetra_SerialComm Comm;
    Epetra_Map globalMapG(numNodes, 0, Comm);
    Epetra_FECrsMatrix StiffMatrix(Copy, globalMapG, 64);

    // Additional arrays used in analytic assembly
    FieldContainer<double> u_coeffs(numCells, numFieldsG);
    FieldContainer<double> u_FE_val(numCells, numCubPoints);
    FieldContainer<double> df_of_u(numCells, numCubPoints);
    FieldContainer<double> df_of_u_times_basis(numCells, numFieldsG, numCubPoints);


    // Additional arrays used in AD-based assembly.
    FieldContainer<FadType> u_coeffsAD(numCells, numFieldsG);  
    FieldContainer<FadType> u_FE_gradAD(numCells, numCubPoints, spaceDim);
    FieldContainer<FadType> u_FE_valAD(numCells, numCubPoints);
    FieldContainer<FadType> f_of_u_AD(numCells, numCubPoints);
    FieldContainer<FadType> cellResidualAD(numCells, numFieldsG);
    for (int c=0; c<numCells; c++) {
      for(int f=0; f<numFieldsG; f++) {
          u_coeffsAD(c,f) = FadType(numFieldsG, f, 1.3);
      }
    }

    Teuchos::Time timer_jac_analytic("Time to compute element PDE Jacobians analytically: ");
    Teuchos::Time timer_jac_fad     ("Time to compute element PDE Jacobians using AD:     ");
    Teuchos::Time timer_jac_insert  ("Time for global insert,  w/o graph: ");
    Teuchos::Time timer_jac_insert_g("Time for global insert,  w/  graph: ");
    Teuchos::Time timer_jac_ga      ("Time for GlobalAssemble, w/o graph: ");
    Teuchos::Time timer_jac_ga_g    ("Time for GlobalAssemble, w/  graph: ");
    Teuchos::Time timer_jac_fc      ("Time for FillComplete,   w/o graph: ");
    Teuchos::Time timer_jac_fc_g    ("Time for FillComplete,   w/  graph: ");




    // *** Analytic element loop ***
    for (int bi=0; bi<numBatches; bi++) {

      // Physical cell coordinates
      for (int ci=0; ci<numCells; ci++) {
        int k = bi*numCells+ci;
        for (int i=0; i<numNodesPerElem; i++) {
            hexNodes(ci,i,0) = nodeCoord(elemToNode(k,i),0);
            hexNodes(ci,i,1) = nodeCoord(elemToNode(k,i),1);
            hexNodes(ci,i,2) = nodeCoord(elemToNode(k,i),2);
        }
      }

      // Compute cell Jacobians, their inverses and their determinants
      CellTools::setJacobian(hexJacobian, cubPoints, hexNodes, hex_8);
      CellTools::setJacobianInv(hexJacobInv, hexJacobian );
      CellTools::setJacobianDet(hexJacobDet, hexJacobian );

      // ******************** COMPUTE ELEMENT HGrad STIFFNESS MATRICES WITHOUT AD *******************

      // transform to physical coordinates 
      fst::HGRADtransformGRAD<double>(hexGradsTransformed, hexJacobInv, hexGrads);
      
      // compute weighted measure
      fst::computeCellMeasure<double>(weightedMeasure, hexJacobDet, cubWeights);

      // multiply values with weighted measure
      fst::multiplyMeasure<double>(hexGradsTransformedWeighted,
                                   weightedMeasure, hexGradsTransformed);

      // u_coeffs equals the value of u_coeffsAD
      for(int i=0; i<numFieldsG; i++){
        u_coeffs(0,i) = u_coeffsAD(0,i).val();
      }

      timer_jac_analytic.start(); // START TIMER
      // integrate to account for linear stiffness term
      fst::integrate<double>(localPDEjacobian, hexGradsTransformed, hexGradsTransformedWeighted, INTREPID_INTEGRATE_COMP_ENGINE);

      // represent value of the current state (iterate) as a linear combination of the basis functions
      u_FE_val.initialize();
      fst::evaluate<double>(u_FE_val, u_coeffs, hexGValsTransformed);
     
      // evaluate derivative of the nonlinear term and multiply by basis function
      dfunc_u(df_of_u, u_FE_val);
      fst::scalarMultiplyDataField<double>(df_of_u_times_basis, df_of_u, hexGValsTransformed);

      // integrate to account for nonlinear reaction term
      fst::integrate<double>(localPDEjacobian, df_of_u_times_basis, hexGValsTransformedWeighted, INTREPID_INTEGRATE_COMP_ENGINE, true);
      timer_jac_analytic.stop(); // STOP TIMER

      // assemble into global matrix
      for (int ci=0; ci<numCells; ci++) {
        int k = bi*numCells+ci;
        std::vector<int> rowIndex(numFieldsG);
        std::vector<int> colIndex(numFieldsG);
        for (int row = 0; row < numFieldsG; row++){
          rowIndex[row] = elemToNode(k,row);
        }
        for (int col = 0; col < numFieldsG; col++){
          colIndex[col] = elemToNode(k,col);
        }
        // We can insert an entire matrix at a time, but we opt for rows only.
        //timer_jac_insert.start();
        //StiffMatrix.InsertGlobalValues(numFieldsG, &rowIndex[0], numFieldsG, &colIndex[0], &localPDEjacobian(ci,0,0));
        //timer_jac_insert.stop();
        for (int row = 0; row < numFieldsG; row++){
          timer_jac_insert.start();
          StiffMatrix.InsertGlobalValues(1, &rowIndex[row], numFieldsG, &colIndex[0], &localPDEjacobian(ci,row,0));
          timer_jac_insert.stop();
        }
      }

    } // *** end analytic element loop ***
     
    // Assemble global objects
    timer_jac_ga.start(); StiffMatrix.GlobalAssemble(); timer_jac_ga.stop();
    timer_jac_fc.start(); StiffMatrix.FillComplete(); timer_jac_fc.stop();




    // *** AD element loop ***

    Epetra_CrsGraph mgraph = StiffMatrix.Graph();
    Epetra_FECrsMatrix StiffMatrixViaAD(Copy, mgraph);

    for (int bi=0; bi<numBatches; bi++) {

      // ******************** COMPUTE ELEMENT HGrad STIFFNESS MATRICES AND RIGHT-HAND SIDE WITH AD ********************

      // Physical cell coordinates
      for (int ci=0; ci<numCells; ci++) {
        int k = bi*numCells+ci;
        for (int i=0; i<numNodesPerElem; i++) {
            hexNodes(ci,i,0) = nodeCoord(elemToNode(k,i),0);
            hexNodes(ci,i,1) = nodeCoord(elemToNode(k,i),1);
            hexNodes(ci,i,2) = nodeCoord(elemToNode(k,i),2);
        }
      }

      // Compute cell Jacobians, their inverses and their determinants
      CellTools::setJacobian(hexJacobian, cubPoints, hexNodes, hex_8);
      CellTools::setJacobianInv(hexJacobInv, hexJacobian );
      CellTools::setJacobianDet(hexJacobDet, hexJacobian );

      // transform to physical coordinates
      fst::HGRADtransformGRAD<double>(hexGradsTransformed, hexJacobInv, hexGrads);
    
      // compute weighted measure
      fst::computeCellMeasure<double>(weightedMeasure, hexJacobDet, cubWeights);
    
      // multiply values with weighted measure
      fst::multiplyMeasure<double>(hexGradsTransformedWeighted, weightedMeasure, hexGradsTransformed);

      // transform basis values to physical coordinates 
      fst::HGRADtransformVALUE<double>(hexGValsTransformed, hexGVals);

      // multiply values with weighted measure
      fst::multiplyMeasure<double>(hexGValsTransformedWeighted,
                                   weightedMeasure, hexGValsTransformed);

      timer_jac_fad.start(); // START TIMER
      // represent gradient of the current state (iterate) as a linear combination of the gradients of basis functions
      // use AD arrays !
      u_FE_gradAD.initialize();
      fst::evaluate<FadType>(u_FE_gradAD, u_coeffsAD, hexGradsTransformed);

      // represent value of the current state (iterate) as a linear combination of the basis functions
      // use AD arrays !
      u_FE_valAD.initialize();
      fst::evaluate<FadType>(u_FE_valAD, u_coeffsAD, hexGValsTransformed);
      // compute nonlinear term
      func_u(f_of_u_AD, u_FE_valAD);

      // integrate to compute element residual   
      fst::integrate<FadType>(cellResidualAD, u_FE_gradAD,  hexGradsTransformedWeighted, INTREPID_INTEGRATE_COMP_ENGINE);
      fst::integrate<FadType>(cellResidualAD, f_of_u_AD, hexGValsTransformedWeighted, INTREPID_INTEGRATE_COMP_ENGINE, true);
      timer_jac_fad.stop(); // STOP TIMER

      // assemble into global matrix
      for (int ci=0; ci<numCells; ci++) {
        int k = bi*numCells+ci;
        std::vector<int> rowIndex(numFieldsG);
        std::vector<int> colIndex(numFieldsG);
        for (int row = 0; row < numFieldsG; row++){
          rowIndex[row] = elemToNode(k,row);
        }
        for (int col = 0; col < numFieldsG; col++){
          colIndex[col] = elemToNode(k,col);
	}
        for (int row = 0; row < numFieldsG; row++){
	  timer_jac_insert_g.start();
          StiffMatrixViaAD.SumIntoGlobalValues(1, &rowIndex[row], numFieldsG, &colIndex[0], cellResidualAD(ci,row).dx());
          timer_jac_insert_g.stop();
        }
      }
 
    } // *** end AD element loop ***

    // Assemble global objects
    timer_jac_ga_g.start(); StiffMatrixViaAD.GlobalAssemble(); timer_jac_ga_g.stop();
    timer_jac_fc_g.start(); StiffMatrixViaAD.FillComplete(); timer_jac_fc_g.stop();



    /****** Output *******/

#ifdef DUMP_DATA
    // Dump matrices to disk
    EpetraExt::RowMatrixToMatlabFile("stiff_matrix.dat",StiffMatrix);
    EpetraExt::RowMatrixToMatlabFile("stiff_matrixAD.dat",StiffMatrixViaAD);
#endif

    // take the infinity norm of the difference between StiffMatrix and StiffMatrixViaAD to see that 
    // the two matrices are the same
    EpetraExt::MatrixMatrix::Add(StiffMatrix, false, 1.0, StiffMatrixViaAD, -1.0);
    double normMat = StiffMatrixViaAD.NormInf();
    *outStream << "Infinity norm of difference between stiffness matrices = " << normMat << "\n";


    *outStream << "\n\nNumber of global nonzeros: " << StiffMatrix.NumGlobalNonzeros() << "\n\n";

    *outStream << timer_jac_analytic.name() << " " << timer_jac_analytic.totalElapsedTime() << " sec\n";
    *outStream << timer_jac_fad.name()      << " " << timer_jac_fad.totalElapsedTime()      << " sec\n\n";
    *outStream << timer_jac_insert.name()   << " " << timer_jac_insert.totalElapsedTime()   << " sec\n";
    *outStream << timer_jac_insert_g.name() << " " << timer_jac_insert_g.totalElapsedTime() << " sec\n\n";
    *outStream << timer_jac_ga.name()       << " " << timer_jac_ga.totalElapsedTime()       << " sec\n";
    *outStream << timer_jac_ga_g.name()     << " " << timer_jac_ga_g.totalElapsedTime()     << " sec\n\n";
    *outStream << timer_jac_fc.name()       << " " << timer_jac_fc.totalElapsedTime()       << " sec\n";
    *outStream << timer_jac_fc_g.name()     << " " << timer_jac_fc_g.totalElapsedTime()     << " sec\n\n";

    if ((normMat < 1.0e4*INTREPID_TOL)) {
      std::cout << "End Result: TEST PASSED\n";
    }
    else {
      std::cout << "End Result: TEST FAILED\n";
    }
   
    // reset format state of std::cout
    std::cout.copyfmt(oldFormatState);
   Kokkos::finalize();
    return 0;
}
Example #6
0
int main(int argc, char *argv[]) {

  Teuchos::GlobalMPISession mpiSession(&argc, &argv);

  // This little trick lets us print to std::cout only if
  // a (dummy) command-line argument is provided.
  int iprint     = argc - 1;
  Teuchos::RCP<std::ostream> outStream;
  Teuchos::oblackholestream bhs; // outputs nothing
  if (iprint > 0)
    outStream = Teuchos::rcp(&std::cout, false);
  else
    outStream = Teuchos::rcp(&bhs, false);

  // Save the format state of the original std::cout.
  Teuchos::oblackholestream oldFormatState;
  oldFormatState.copyfmt(std::cout);

  *outStream \
  << "===============================================================================\n" \
  << "|                                                                             |\n" \
  << "|                      Unit Test (FunctionSpaceTools)                         |\n" \
  << "|                                                                             |\n" \
  << "|     1) basic operator transformations and integration in HGRAD              |\n" \
  << "|                                                                             |\n" \
  << "|  Questions? Contact  Pavel Bochev ([email protected]) or                   |\n" \
  << "|                      Denis Ridzal ([email protected]).                     |\n" \
  << "|                                                                             |\n" \
  << "|  Intrepid's website: http://trilinos.sandia.gov/packages/intrepid           |\n" \
  << "|  Trilinos website:   http://trilinos.sandia.gov                             |\n" \
  << "|                                                                             |\n" \
  << "===============================================================================\n";


  int errorFlag = 0;
#ifdef HAVE_INTREPID_DEBUG
  int beginThrowNumber = Teuchos::TestForException_getThrowNumber();
  int endThrowNumber = beginThrowNumber + 28;
#endif

  typedef FunctionSpaceTools fst; 

  *outStream \
  << "\n"
  << "===============================================================================\n"\
  << "| TEST 1: exceptions                                                          |\n"\
  << "===============================================================================\n";

  try{
#ifdef HAVE_INTREPID_DEBUG
    FieldContainer<double,  1> a_2(2);
    FieldContainer<double,  2> a_2_2(2, 2);
    FieldContainer<double,  3> a_2_3(2, 3);
    FieldContainer<double,  4> a_3_2(3, 2);
    FieldContainer<double,  5> a_2_2_3(2, 2, 3);
    FieldContainer<double,  6> a_2_2_3_3(2, 2, 3, 3);
    FieldContainer<double,  7> a_2_2_2(2, 2, 2);
    FieldContainer<double,  8> a_2_2_2_3_3(2, 2, 2, 3, 3);
    FieldContainer<double,  9> a_2_2_2_2_2(2, 2, 2, 2, 2);
    FieldContainer<double, 10> a_2_2_2_2(2, 2, 2, 2);
    FieldContainer<double, 11> a_3_2_2_2(3, 2, 2, 2);
    FieldContainer<double, 12> a_2_3_2_2(2, 3, 2, 2);
    FieldContainer<double, 13> a_2_2_3_2(2, 2, 3, 2);
    FieldContainer<double, 14> a_2_2_2_3(2, 2, 2, 3);

    *outStream << "\n >>>>> TESTING computeCellMeasure:\n";
    INTREPID_TEST_COMMAND( fst::computeCellMeasure<double>(a_2_2, a_2, a_2) );
    INTREPID_TEST_COMMAND( fst::computeCellMeasure<double>(a_2_2, a_2_2, a_2) );

    *outStream << "\n >>>>> TESTING computeFaceMeasure:\n";
    INTREPID_TEST_COMMAND( fst::computeFaceMeasure<double>(a_2_2, a_2, a_2, 0, shards::getCellTopologyData< shards::Tetrahedron<> >()) );
    INTREPID_TEST_COMMAND( fst::computeFaceMeasure<double>(a_2_2, a_2_2_3_3, a_2, 0, shards::getCellTopologyData< shards::Tetrahedron<> >()) );

    *outStream << "\n >>>>> TESTING computeEdgeMeasure:\n";
    INTREPID_TEST_COMMAND( fst::computeEdgeMeasure<double>(a_2_2, a_2, a_2, 0, shards::getCellTopologyData< shards::Triangle<> >()) );
    INTREPID_TEST_COMMAND( fst::computeEdgeMeasure<double>(a_2_2, a_2_2_2_2, a_2, 0, shards::getCellTopologyData< shards::Triangle<> >()) );

    *outStream << "\n >>>>> TESTING integrate:\n";
    INTREPID_TEST_COMMAND( fst::integrate<double>(a_2_2_2_2, a_2_2_2, a_2_2_2, COMP_CPP) );
    INTREPID_TEST_COMMAND( fst::integrate<double>(a_2, a_2_2, a_2_2, COMP_CPP) );
    INTREPID_TEST_COMMAND( fst::integrate<double>(a_2, a_2_2_3, a_2_2_3, COMP_CPP) );
    INTREPID_TEST_COMMAND( fst::integrate<double>(a_2, a_2_2_3_3, a_2_2_3_3, COMP_CPP) );
    INTREPID_TEST_COMMAND( fst::integrate<double>(a_2_2, a_2_2, a_2_2_2, COMP_CPP) );
    INTREPID_TEST_COMMAND( fst::integrate<double>(a_2_2, a_2_2_3, a_2_2_2_3, COMP_CPP) );
    INTREPID_TEST_COMMAND( fst::integrate<double>(a_2_2, a_2_2_3_3, a_2_2_2_3_3, COMP_CPP) );
    INTREPID_TEST_COMMAND( fst::integrate<double>(a_2_2_2, a_2_2_2, a_2_2_2, COMP_CPP) );
    INTREPID_TEST_COMMAND( fst::integrate<double>(a_2_2_2, a_2_2_2_3, a_2_2_2_3, COMP_CPP) );
    INTREPID_TEST_COMMAND( fst::integrate<double>(a_2_2_2, a_2_2_2_3_3, a_2_2_2_3_3, COMP_CPP) );

    *outStream << "\n >>>>> TESTING operatorIntegral:\n";
    INTREPID_TEST_COMMAND( fst::operatorIntegral<double>(a_2_2_2, a_2_2, a_2_2_2, COMP_CPP) );
    INTREPID_TEST_COMMAND( fst::operatorIntegral<double>(a_2_2_2, a_2_2_2, a_2_2_2, COMP_CPP) );
    INTREPID_TEST_COMMAND( fst::operatorIntegral<double>(a_2_2_2, a_2_2_2_3, a_2_2_2_3, COMP_CPP) );
    INTREPID_TEST_COMMAND( fst::operatorIntegral<double>(a_2_2_2, a_2_2_2_3_3, a_2_2_2_3_3, COMP_CPP) );

    *outStream << "\n >>>>> TESTING functionalIntegral:\n";
    INTREPID_TEST_COMMAND( fst::functionalIntegral<double>(a_2_2, a_2_2_2_3_3, a_2_2_2, COMP_CPP) );
    INTREPID_TEST_COMMAND( fst::functionalIntegral<double>(a_2_2, a_2_2, a_2_2_2, COMP_CPP) );
    INTREPID_TEST_COMMAND( fst::functionalIntegral<double>(a_2_2, a_2_2_3, a_2_2_2_3, COMP_CPP) );
    INTREPID_TEST_COMMAND( fst::functionalIntegral<double>(a_2_2, a_2_2_3_3, a_2_2_2_3_3, COMP_CPP) );

    *outStream << "\n >>>>> TESTING dataIntegral:\n";
    INTREPID_TEST_COMMAND( fst::dataIntegral<double>(a_2, a_2, a_2_2_2, COMP_CPP) );
    INTREPID_TEST_COMMAND( fst::dataIntegral<double>(a_2, a_2_2, a_2_2, COMP_CPP) );
    INTREPID_TEST_COMMAND( fst::dataIntegral<double>(a_2, a_2_2_3, a_2_2_3, COMP_CPP) );
    INTREPID_TEST_COMMAND( fst::dataIntegral<double>(a_2, a_2_2_3_3, a_2_2_3_3, COMP_CPP) );

    *outStream << "\n >>>>> TESTING applyLeftFieldSigns:\n";
    INTREPID_TEST_COMMAND( fst::applyLeftFieldSigns<double>(a_2, a_2) );
    INTREPID_TEST_COMMAND( fst::applyLeftFieldSigns<double>(a_2_2_2, a_2) );
    INTREPID_TEST_COMMAND( fst::applyLeftFieldSigns<double>(a_2_2_2, a_3_2) );
    INTREPID_TEST_COMMAND( fst::applyLeftFieldSigns<double>(a_2_2_2, a_2_3) );
    INTREPID_TEST_COMMAND( fst::applyLeftFieldSigns<double>(a_2_2_2, a_2_2) );

    *outStream << "\n >>>>> TESTING applyRightFieldSigns:\n";
    INTREPID_TEST_COMMAND( fst::applyRightFieldSigns<double>(a_2, a_2) );
    INTREPID_TEST_COMMAND( fst::applyRightFieldSigns<double>(a_2_2_2, a_2) );
    INTREPID_TEST_COMMAND( fst::applyRightFieldSigns<double>(a_2_2_2, a_3_2) );
    INTREPID_TEST_COMMAND( fst::applyRightFieldSigns<double>(a_2_2_2, a_2_3) );
    INTREPID_TEST_COMMAND( fst::applyRightFieldSigns<double>(a_2_2_2, a_2_2) );

    *outStream << "\n >>>>> TESTING applyFieldSigns:\n";
    INTREPID_TEST_COMMAND( fst::applyFieldSigns<double>(a_2, a_2) );
    INTREPID_TEST_COMMAND( fst::applyFieldSigns<double>(a_2_2, a_2) );
    INTREPID_TEST_COMMAND( fst::applyFieldSigns<double>(a_2_2, a_3_2) );
    INTREPID_TEST_COMMAND( fst::applyFieldSigns<double>(a_2_2, a_2_3) );
    INTREPID_TEST_COMMAND( fst::applyFieldSigns<double>(a_2_2_2_3_3, a_2_2) );

    *outStream << "\n >>>>> TESTING evaluate:\n";
    INTREPID_TEST_COMMAND( fst::evaluate<double>(a_2, a_2, a_2_2) );
    INTREPID_TEST_COMMAND( fst::evaluate<double>(a_2, a_2, a_2_2_2_3_3) );
    INTREPID_TEST_COMMAND( fst::evaluate<double>(a_2, a_2_2, a_2_2_2_3_3) );
    INTREPID_TEST_COMMAND( fst::evaluate<double>(a_2_2_3_3, a_3_2, a_2_2_2_3_3) );
    INTREPID_TEST_COMMAND( fst::evaluate<double>(a_2_2_3_3, a_2_3, a_2_2_2_3_3) );
    INTREPID_TEST_COMMAND( fst::evaluate<double>(a_3_2_2_2, a_2_2, a_2_2_2_2_2) );
    INTREPID_TEST_COMMAND( fst::evaluate<double>(a_2_3_2_2, a_2_2, a_2_2_2_2_2) );
    INTREPID_TEST_COMMAND( fst::evaluate<double>(a_2_2_3_2, a_2_2, a_2_2_2_2_2) );
    INTREPID_TEST_COMMAND( fst::evaluate<double>(a_2_2_2_3, a_2_2, a_2_2_2_2_2) );
    INTREPID_TEST_COMMAND( fst::evaluate<double>(a_2_2_2_2, a_2_2, a_2_2_2_2_2) );
#endif
  }
  catch (std::logic_error err) {
    *outStream << "UNEXPECTED ERROR !!! ----------------------------------------------------------\n";
    *outStream << err.what() << '\n';
    *outStream << "-------------------------------------------------------------------------------" << "\n\n";
    errorFlag = -1000;
  };

#ifdef HAVE_INTREPID_DEBUG
  if (Teuchos::TestForException_getThrowNumber() != endThrowNumber)
    errorFlag++;
#endif

  *outStream \
  << "\n"
  << "===============================================================================\n"\
  << "| TEST 2: correctness of math operations                                      |\n"\
  << "===============================================================================\n";

  outStream->precision(20);

  try {
      // cell type: tet
      shards::CellTopology cellType = shards::getCellTopologyData< shards::Tetrahedron<> >();

      /* Related to cubature. */
      // create cubature factory
      DefaultCubatureFactory<double, FieldContainer<double, 1>, FieldContainer<double, 2> > cubFactory;
      // cubature degree
      int cubDegree = 2;
      // create default cubature
      Teuchos::RCP<Cubature<double, FieldContainer<double, 1>, FieldContainer<double, 2> > > myCub = cubFactory.create(cellType, cubDegree);
      // get spatial dimension 
      int spaceDim = myCub->getDimension();
      // get number of cubature points
      int numCubPoints = myCub->getNumPoints();

      /* Related to basis. */
      // create tet basis
      Basis_HGRAD_TET_C1_FEM<double, FieldContainer<double, 1> > tetBasis;
      // get basis cardinality
      int numFields = tetBasis.getCardinality();
 
      /* Cell geometries. */
      int numCells    = 4;
      int numNodes    = 4;
      int numCellData = numCells*numNodes*spaceDim;
      double tetnodes[] = {
        // tet 0
        0.0, 0.0, 0.0,
        1.0, 0.0, 0.0,
        0.0, 1.0, 0.0,
        0.0, 0.0, 1.0,
        // tet 1
        4.0, 5.0, 1.0,
       -6.0, 2.0, 0.0,
        4.0, -3.0, -1.0,
        0.0, 2.0, 5.0,
        // tet 2
        -6.0, -3.0, 1.0,
        9.0, 2.0, 1.0,
        8.9, 2.1, 0.9,
        8.9, 2.1, 1.1,
        // tet 3
        -6.0, -3.0, 1.0,
        12.0, 3.0, 1.0,
        2.9, 0.1, 0.9,
        2.9, 0.1, 1.1
      };

      /* Computational arrays. */
      FieldContainer<double,  1> cub_points(numCubPoints, spaceDim);
      FieldContainer<double,  2> cub_weights(numCubPoints);
      FieldContainer<double,  3> cell_nodes(numCells, numNodes, spaceDim);
      FieldContainer<double,  4> jacobian(numCells, numCubPoints, spaceDim, spaceDim);
      FieldContainer<double,  5> jacobian_inv(numCells, numCubPoints, spaceDim, spaceDim);
      FieldContainer<double,  6> jacobian_det(numCells, numCubPoints);
      FieldContainer<double,  7> weighted_measure(numCells, numCubPoints);

      FieldContainer<double,  1> grad_of_basis_at_cub_points(numFields, numCubPoints, spaceDim);
      FieldContainer<double,  9> transformed_grad_of_basis_at_cub_points(numCells, numFields, numCubPoints, spaceDim);
      FieldContainer<double, 10> weighted_transformed_grad_of_basis_at_cub_points(numCells, numFields, numCubPoints, spaceDim);
      FieldContainer<double, 11> stiffness_matrices(numCells, numFields, numFields);

      FieldContainer<double,  1> value_of_basis_at_cub_points(numFields, numCubPoints);
      FieldContainer<double, 13> transformed_value_of_basis_at_cub_points(numCells, numFields, numCubPoints);
      FieldContainer<double, 14> weighted_transformed_value_of_basis_at_cub_points(numCells, numFields, numCubPoints);
      FieldContainer<double, 15> mass_matrices(numCells, numFields, numFields);

      /******************* START COMPUTATION ***********************/

      // get cubature points and weights
      myCub->getCubature(cub_points, cub_weights);

      // fill cell vertex array
      cell_nodes.setValues(tetnodes, numCellData);

      // compute geometric cell information
      CellTools<double>::setJacobian(jacobian, cub_points, cell_nodes, cellType);
      CellTools<double>::setJacobianInv(jacobian_inv, jacobian);
      CellTools<double>::setJacobianDet(jacobian_det, jacobian);

      // compute weighted measure
      fst::computeCellMeasure<double>(weighted_measure, jacobian_det, cub_weights);

      // Computing stiffness matrices:
      // tabulate gradients of basis functions at (reference) cubature points
      tetBasis.getValues(grad_of_basis_at_cub_points, cub_points, OPERATOR_GRAD);

      // transform gradients of basis functions
      fst::HGRADtransformGRAD<double>(transformed_grad_of_basis_at_cub_points,
                                      jacobian_inv,
                                      grad_of_basis_at_cub_points);

      // multiply with weighted measure
      fst::multiplyMeasure<double>(weighted_transformed_grad_of_basis_at_cub_points,
                                   weighted_measure,
                                   transformed_grad_of_basis_at_cub_points);

      // compute stiffness matrices
      fst::integrate<double>(stiffness_matrices,
                             transformed_grad_of_basis_at_cub_points,
                             weighted_transformed_grad_of_basis_at_cub_points,
                             COMP_CPP);


      // Computing mass matrices:
      // tabulate values of basis functions at (reference) cubature points
      tetBasis.getValues(value_of_basis_at_cub_points, cub_points, OPERATOR_VALUE);

      // transform values of basis functions
      fst::HGRADtransformVALUE<double>(transformed_value_of_basis_at_cub_points,
                                       value_of_basis_at_cub_points);

      // multiply with weighted measure
      fst::multiplyMeasure<double>(weighted_transformed_value_of_basis_at_cub_points,
                                   weighted_measure,
                                   transformed_value_of_basis_at_cub_points);

      // compute mass matrices
      fst::integrate<double>(mass_matrices,
                             transformed_value_of_basis_at_cub_points,
                             weighted_transformed_value_of_basis_at_cub_points,
                             COMP_CPP);

      /*******************  STOP COMPUTATION ***********************/


      /******************* START COMPARISON ***********************/
      string basedir = "./testdata";
      for (int cell_id = 0; cell_id < numCells; cell_id++) {

        stringstream namestream;
        string filename;
        namestream <<  basedir << "/mass_TET_FEM_P1" << "_" << "0" << cell_id+1 << ".dat";
        namestream >> filename;

        ifstream massfile(&filename[0]);
        if (massfile.is_open()) {
          if (compareToAnalytic<double>(&mass_matrices(cell_id, 0, 0), massfile, 1e-10, 0) > 0)
            errorFlag++;
          massfile.close();
        }
        else {
          errorFlag = -1;
          std::cout << "End Result: TEST FAILED\n";
          return errorFlag;
        }

        namestream.clear();
        namestream << basedir << "/stiff_TET_FEM_P1" << "_" << "0" << cell_id+1 << ".dat";
        namestream >> filename;

        ifstream stifffile(&filename[0]);
        if (stifffile.is_open())
        {
          if (compareToAnalytic<double>(&stiffness_matrices(cell_id, 0, 0), stifffile, 1e-10, 0) > 0)
            errorFlag++;
          stifffile.close();
        }
        else {
          errorFlag = -1;
          std::cout << "End Result: TEST FAILED\n";
          return errorFlag;
        }

      }

      /******************* STOP COMPARISON ***********************/

      *outStream << "\n";
  }
  catch (std::logic_error err) {
    *outStream << "UNEXPECTED ERROR !!! ----------------------------------------------------------\n";
    *outStream << err.what() << '\n';
    *outStream << "-------------------------------------------------------------------------------" << "\n\n";
    errorFlag = -1000;
  };


  if (errorFlag != 0)
    std::cout << "End Result: TEST FAILED\n";
  else
    std::cout << "End Result: TEST PASSED\n";

  // reset format state of std::cout
  std::cout.copyfmt(oldFormatState);

  return errorFlag;
}
Example #7
0
int main(int argc, char *argv[]) {

  Teuchos::GlobalMPISession mpiSession(&argc, &argv);
 Kokkos::initialize();
  // This little trick lets us print to std::cout only if
  // a (dummy) command-line argument is provided.
  int iprint     = argc - 1;
  Teuchos::RCP<std::ostream> outStream;
  Teuchos::oblackholestream bhs; // outputs nothing
  if (iprint > 0)
    outStream = Teuchos::rcp(&std::cout, false);
  else
    outStream = Teuchos::rcp(&bhs, false);

  // Save the format state of the original std::cout.
  Teuchos::oblackholestream oldFormatState;
  oldFormatState.copyfmt(std::cout);

  *outStream \
  << "===============================================================================\n" \
  << "|                                                                             |\n" \
  << "|                      Unit Test (FunctionSpaceTools)                         |\n" \
  << "|                                                                             |\n" \
  << "|     1) volume integration on tetrahedra, testing dataIntegral               |\n" \
  << "|                                                                             |\n" \
  << "|  Questions? Contact  Pavel Bochev ([email protected]) or                   |\n" \
  << "|                      Denis Ridzal ([email protected]).                     |\n" \
  << "|                                                                             |\n" \
  << "|  Intrepid's website: http://trilinos.sandia.gov/packages/intrepid           |\n" \
  << "|  Trilinos website:   http://trilinos.sandia.gov                             |\n" \
  << "|                                                                             |\n" \
  << "===============================================================================\n";


  int errorFlag = 0;

  typedef FunctionSpaceTools fst; 

  *outStream \
  << "\n"
  << "===============================================================================\n"\
  << "| TEST 1: correctness of cell volumes                                         |\n"\
  << "===============================================================================\n";

  outStream->precision(20);

  try {
      shards::CellTopology cellType = shards::getCellTopologyData< shards::Tetrahedron<> >();   // cell type: tet

      /* Related to cubature. */
      DefaultCubatureFactory<double> cubFactory;                                                // create cubature factory
      int cubDegree = 0;                                                                        // cubature degree
      Teuchos::RCP<Cubature<double> > myCub = cubFactory.create(cellType, cubDegree);           // create default cubature
      int spaceDim = myCub->getDimension();                                                     // get spatial dimension 
      int numCubPoints = myCub->getNumPoints();                                                 // get number of cubature points

      /* Cell geometries. */
      int numCells    = 4;
      int numNodes    = 4;
      int numCellData = numCells*numNodes*spaceDim;
      double tetnodes[] = {
        // tet 0
        0.0, 0.0, 0.0,
        1.0, 0.0, 0.0,
        0.0, 1.0, 0.0,
        0.0, 0.0, 1.0,
        // tet 1
        4.0, 5.0, 1.0,
       -6.0, 2.0, 0.0,
        4.0, -3.0, -1.0,
        0.0, 2.0, 5.0,
        // tet 2
        -6.0, -3.0, 1.0,
        9.0, 2.0, 1.0,
        8.9, 2.1, 0.9,
        8.9, 2.1, 1.1,
        // tet 3
        -6.0, -3.0, 1.0,
        12.0, 3.0, 1.0,
        2.9, 0.1, 0.9,
        2.9, 0.1, 1.1
      };

      /* Analytic volumes. */
      double tetvols[] = {1.0/6.0, 194.0/3.0, 1.0/15.0, 2.0/25.0};

      /* Computational arrays. */
      FieldContainer<double> cub_points(numCubPoints, spaceDim);
      FieldContainer<double> cub_weights(numCubPoints);
      FieldContainer<double> cell_nodes(numCells, numNodes, spaceDim);
      FieldContainer<double> jacobian(numCells, numCubPoints, spaceDim, spaceDim);
      FieldContainer<double> jacobian_det(numCells, numCubPoints);
      FieldContainer<double> weighted_measure(numCells, numCubPoints);
      FieldContainer<double> data_one(numCells, numCubPoints);
      FieldContainer<double> volumes(numCells);

      /******************* START COMPUTATION ***********************/

      // get cubature points and weights
      myCub->getCubature(cub_points, cub_weights);

      // fill cell vertex array
      cell_nodes.setValues(tetnodes, numCellData);

      // compute geometric cell information
      CellTools<double>::setJacobian(jacobian, cub_points, cell_nodes, cellType);
      CellTools<double>::setJacobianDet(jacobian_det, jacobian);

      // compute weighted measure
      fst::computeCellMeasure<double>(weighted_measure, jacobian_det, cub_weights);

      // set data to 1.0
      for (int cell=0; cell<data_one.dimension(0); cell++) { 
        for (int qp=0; qp<data_one.dimension(1); qp++) {
          data_one(cell,qp) = 1.0;
        }
      } 

      // compute volumes
      fst::integrate<double>(volumes, data_one, weighted_measure, COMP_CPP);

      /******************* STOP COMPUTATION ***********************/


      /******************* START COMPARISON ***********************/
      for (int cell_id = 0; cell_id < numCells; cell_id++) {
        *outStream << "Volume of cell " << cell_id << " = " << volumes(cell_id) << "    vs.    Analytic value =  " << tetvols[cell_id] << "\n";
        if (std::fabs(volumes(cell_id)-tetvols[cell_id]) > INTREPID_TOL) {
          errorFlag++;
        }
      }
      /******************* STOP COMPARISON ***********************/

      *outStream << "\n";
  }
  catch (std::logic_error err) {
    *outStream << "UNEXPECTED ERROR !!! ----------------------------------------------------------\n";
    *outStream << err.what() << '\n';
    *outStream << "-------------------------------------------------------------------------------" << "\n\n";
    errorFlag = -1000;
  };


  if (errorFlag != 0)
    std::cout << "End Result: TEST FAILED\n";
  else
    std::cout << "End Result: TEST PASSED\n";

  // reset format state of std::cout
  std::cout.copyfmt(oldFormatState);
 Kokkos::finalize();
  return errorFlag;
}
Example #8
0
int main(int argc, char *argv[]) {
 
  Teuchos::GlobalMPISession mpiSession(&argc, &argv);
Kokkos::initialize();
  typedef CellTools<double>       CellTools;
  typedef shards::CellTopology    CellTopology;
  
  // This little trick lets us print to std::cout only if a (dummy) command-line argument is provided.
  int iprint     = argc - 1;
  
  Teuchos::RCP<std::ostream> outStream;
  Teuchos::oblackholestream bhs; // outputs nothing
  
  if (iprint > 0)
    outStream = Teuchos::rcp(&std::cout, false);
  else
    outStream = Teuchos::rcp(&bhs, false);
  
  // Save the format state of the original std::cout.
  Teuchos::oblackholestream oldFormatState;
  oldFormatState.copyfmt(std::cout);
  
  *outStream \
    << "===============================================================================\n" \
    << "|                                                                             |\n" \
    << "|                              Unit Test CellTools                            |\n" \
    << "|                                                                             |\n" \
    << "|     1) Edge parametrizations                                                |\n" \
    << "|     2) Face parametrizations                                                |\n" \
    << "|     3) Edge tangents                                                        |\n" \
    << "|     4) Face tangents and normals                                            |\n" \
    << "|                                                                             |\n" \
    << "|  Questions? Contact  Pavel Bochev ([email protected])                      |\n" \
    << "|                      Denis Ridzal ([email protected]), or                  |\n" \
    << "|                      Kara Peterson ([email protected])                     |\n" \
    << "|                                                                             |\n" \
    << "|  Intrepid's website: http://trilinos.sandia.gov/packages/intrepid           |\n" \
    << "|  Trilinos website:   http://trilinos.sandia.gov                             |\n" \
    << "|                                                                             |\n" \
    << "===============================================================================\n";
  
  int errorFlag  = 0;

    
  // Vertices of the parametrization domain for 1-subcells: standard 1-cube [-1,1]
  FieldContainer<double> cube_1(2, 1);
  cube_1(0,0) = -1.0; 
  cube_1(1,0) = 1.0;

  
  // Vertices of the parametrization domain for triangular faces: the standard 2-simplex
  FieldContainer<double> simplex_2(3, 2);
  simplex_2(0, 0) = 0.0;   simplex_2(0, 1) = 0.0;
  simplex_2(1, 0) = 1.0;   simplex_2(1, 1) = 0.0;
  simplex_2(2, 0) = 0.0;   simplex_2(2, 1) = 1.0;
  
  
  // Vertices of the parametrization domain for quadrilateral faces: the standard 2-cube
  FieldContainer<double> cube_2(4, 2);
  cube_2(0, 0) =  -1.0;    cube_2(0, 1) =  -1.0;
  cube_2(1, 0) =   1.0;    cube_2(1, 1) =  -1.0;
  cube_2(2, 0) =   1.0;    cube_2(2, 1) =   1.0;
  cube_2(3, 0) =  -1.0;    cube_2(3, 1) =   1.0;

  
  // Pull all available topologies from Shards
  std::vector<shards::CellTopology> allTopologies;
  shards::getTopologies(allTopologies);
  
  
  // Set to 1 for edge and 2 for face tests
  int subcDim;

  try{
    
    *outStream \
    << "\n"
    << "===============================================================================\n"\
    << "| Test 1: edge parametrizations:                                              |\n"\
    << "===============================================================================\n\n";
    
    subcDim      = 1;
        
    // Loop over the cell topologies
    for(int topoOrd = 0; topoOrd < (int)allTopologies.size(); topoOrd++){
            
      // Test only 2D and 3D topologies that have reference cells, e.g., exclude Line, Pentagon, etc.
      if(allTopologies[topoOrd].getDimension() > 1 && CellTools::hasReferenceCell(allTopologies[topoOrd]) ){
        *outStream << " Testing edge parametrization for " <<  allTopologies[topoOrd].getName() <<"\n";
        testSubcellParametrizations(errorFlag,
                                    allTopologies[topoOrd],
                                    cube_1,
                                    cube_1,
                                    subcDim,
                                    outStream);
      }
    }

    
    *outStream \
      << "\n"
      << "===============================================================================\n"\
      << "| Test 2: face parametrizations:                                              |\n"\
      << "===============================================================================\n\n";
    
    subcDim      = 2;
    
    // Loop over the cell topologies
    for(int topoOrd = 0; topoOrd < (int)allTopologies.size(); topoOrd++){
      
      // Test only 3D topologies that have reference cells
      if(allTopologies[topoOrd].getDimension() > 2 && CellTools::hasReferenceCell(allTopologies[topoOrd]) ){
        *outStream << " Testing face parametrization for cell topology " <<  allTopologies[topoOrd].getName() <<"\n";
        testSubcellParametrizations(errorFlag,
                                    allTopologies[topoOrd],
                                    simplex_2,
                                    cube_2,
                                    subcDim,
                                    outStream);
      }
    }
    
    
    /***********************************************************************************************
      *
      * Common for test 3 and 4: edge tangents and face normals for standard cells with base topo
      *
      **********************************************************************************************/
    
    // Allocate storage and extract all standard cells with base topologies
    std::vector<shards::CellTopology> standardBaseTopologies;    
    shards::getTopologies(standardBaseTopologies, 4, shards::STANDARD_CELL, shards::BASE_TOPOLOGY);

    // Define topologies for the edge and face parametrization domains. (faces are Tri or Quad)
    CellTopology paramEdge    (shards::getCellTopologyData<shards::Line<2> >() );
    CellTopology paramTriFace (shards::getCellTopologyData<shards::Triangle<3> >() );
    CellTopology paramQuadFace(shards::getCellTopologyData<shards::Quadrilateral<4> >() );
    
    // Define CubatureFactory:
    DefaultCubatureFactory<double>  cubFactory;   
    
    *outStream \
      << "\n"
      << "===============================================================================\n"\
      << "| Test 3: edge tangents/normals for stand. cells with base topologies:        |\n"\
      << "===============================================================================\n\n";
    // This test loops over standard cells with base topologies, creates a set of nodes and tests tangents/normals 
    std::vector<shards::CellTopology>::iterator cti;
    
    // Define cubature on the edge parametrization domain:
    Teuchos::RCP<Cubature<double> > edgeCubature = cubFactory.create(paramEdge, 6); 
    int cubDim       = edgeCubature -> getDimension();
    int numCubPoints = edgeCubature -> getNumPoints();

    // Allocate storage for cubature points and weights on edge parameter domain and fill with points:
    FieldContainer<double> paramEdgePoints(numCubPoints, cubDim);
    FieldContainer<double> paramEdgeWeights(numCubPoints);
    edgeCubature -> getCubature(paramEdgePoints, paramEdgeWeights);
    

    // Loop over admissible topologies 
    for(cti = standardBaseTopologies.begin(); cti !=standardBaseTopologies.end(); ++cti){
      
      // Exclude 0D (node), 1D (Line) and Pyramid<5> cells
      if( ( (*cti).getDimension() >= 2) && ( (*cti).getKey() != shards::Pyramid<5>::key) ){ 
        
        int cellDim = (*cti).getDimension();
        int vCount  = (*cti).getVertexCount();
        FieldContainer<double> refCellVertices(vCount, cellDim);
        CellTools::getReferenceSubcellVertices(refCellVertices, cellDim, 0, (*cti) );
        
        *outStream << " Testing edge tangents";
          if(cellDim == 2) { *outStream << " and normals"; }          
        *outStream <<" for cell topology " <<  (*cti).getName() <<"\n";
        
        
        // Array for physical cell vertices ( must have rank 3 for setJacobians)
        FieldContainer<double> physCellVertices(1, vCount, cellDim);

        // Randomize reference cell vertices by moving them up to +/- (1/8) units along their
        // coordinate axis. Guaranteed to be non-degenerate for standard cells with base topology 
        for(int v = 0; v < vCount; v++){
          for(int d = 0; d < cellDim; d++){
            double delta = Teuchos::ScalarTraits<double>::random()/8.0;
            physCellVertices(0, v, d) = refCellVertices(v, d) + delta;
          } //for d
        }// for v     
        
        // Allocate storage for cub. points on a ref. edge; Jacobians, phys. edge tangents/normals
        FieldContainer<double> refEdgePoints(numCubPoints, cellDim);        
        FieldContainer<double> edgePointsJacobians(1, numCubPoints, cellDim, cellDim);
        FieldContainer<double> edgePointTangents(1, numCubPoints, cellDim);
        FieldContainer<double> edgePointNormals(1, numCubPoints, cellDim);        

        // Loop over edges:
        for(int edgeOrd = 0; edgeOrd < (int)(*cti).getEdgeCount(); edgeOrd++){
          /* 
           * Compute tangents on the specified physical edge using CellTools:
           *    1. Map points from edge parametrization domain to ref. edge with specified ordinal
           *    2. Compute parent cell Jacobians at ref. edge points
           *    3. Compute physical edge tangents
           */
          CellTools::mapToReferenceSubcell(refEdgePoints, paramEdgePoints, 1, edgeOrd, (*cti) );
          CellTools::setJacobian(edgePointsJacobians, refEdgePoints, physCellVertices, (*cti) );
          CellTools::getPhysicalEdgeTangents(edgePointTangents, edgePointsJacobians, edgeOrd, (*cti)); 
          /*
           * Compute tangents directly using parametrization of phys. edge and compare with CellTools tangents.
           *    1. Get edge vertices
           *    2. For affine edges tangent coordinates are given by F'(t) = (V1-V0)/2
           *       (for now we only test affine edges, but later we will test edges for cells 
           *        with extended topologies.)
           */
          int v0ord = (*cti).getNodeMap(1, edgeOrd, 0);
          int v1ord = (*cti).getNodeMap(1, edgeOrd, 1);
          
          for(int pt = 0; pt < numCubPoints; pt++){

            // Temp storage for directly computed edge tangents
            FieldContainer<double> edgeBenchmarkTangents(3);
            
            for(int d = 0; d < cellDim; d++){
              edgeBenchmarkTangents(d) = (physCellVertices(0, v1ord, d) - physCellVertices(0, v0ord, d))/2.0;
              
              // Compare with d-component of edge tangent by CellTools
              if( abs(edgeBenchmarkTangents(d) - edgePointTangents(0, pt, d)) > INTREPID2_THRESHOLD ){
                errorFlag++;
                *outStream
                  << std::setw(70) << "^^^^----FAILURE!" << "\n"
                  << " Edge tangent computation by CellTools failed for: \n"
                  << "       Cell Topology = " << (*cti).getName() << "\n"
                  << "        Edge ordinal = " << edgeOrd << "\n"
                  << "   Edge point number = " << pt << "\n"
                  << "  Tangent coordinate = " << d << "\n"
                  << "     CellTools value = " <<  edgePointTangents(0, pt, d) << "\n"
                  << "     Benchmark value = " <<  edgeBenchmarkTangents(d) << "\n\n";
              }
            } // for d
            
            // Test side normals for 2D cells only: edge normal has coordinates (t1, -t0)
            if(cellDim == 2) {
              CellTools::getPhysicalSideNormals(edgePointNormals, edgePointsJacobians, edgeOrd, (*cti));
              if( abs(edgeBenchmarkTangents(1) - edgePointNormals(0, pt, 0)) > INTREPID2_THRESHOLD ){
                errorFlag++;
                *outStream
                  << std::setw(70) << "^^^^----FAILURE!" << "\n"
                  << " Edge Normal computation by CellTools failed for: \n"
                  << "       Cell Topology = " << (*cti).getName() << "\n"
                  << "        Edge ordinal = " << edgeOrd << "\n"
                  << "   Edge point number = " << pt << "\n"
                  << "   Normal coordinate = " << 0 << "\n"
                  << "     CellTools value = " <<  edgePointNormals(0, pt, 0) << "\n"
                  << "     Benchmark value = " <<  edgeBenchmarkTangents(1) << "\n\n";
              }
              if( abs(edgeBenchmarkTangents(0) + edgePointNormals(0, pt, 1)) > INTREPID2_THRESHOLD ){
                errorFlag++;
                *outStream
                  << std::setw(70) << "^^^^----FAILURE!" << "\n"
                  << " Edge Normal computation by CellTools failed for: \n"
                  << "       Cell Topology = " << (*cti).getName() << "\n"
                  << "        Edge ordinal = " << edgeOrd << "\n"
                  << "   Edge point number = " << pt << "\n"
                  << "   Normal coordinate = " << 1  << "\n"
                  << "     CellTools value = " <<  edgePointNormals(0, pt, 1) << "\n"
                  << "     Benchmark value = " << -edgeBenchmarkTangents(0) << "\n\n";
              }
            } // edge normals            
          } // for pt
        }// for edgeOrd
      }// if admissible cell
    }// for cti
    
    
    
    *outStream \
      << "\n"
      << "===============================================================================\n"\
      << "| Test 4: face/side normals for stand. 3D cells with base topologies:         |                                                      |\n"\
      << "===============================================================================\n\n";
    // This test loops over standard 3D cells with base topologies, creates a set of nodes and tests normals 

    // Define cubature on the edge parametrization domain:
    Teuchos::RCP<Cubature<double> > triFaceCubature  = cubFactory.create(paramTriFace, 6); 
    Teuchos::RCP<Cubature<double> > quadFaceCubature = cubFactory.create(paramQuadFace, 6); 
    
    int faceCubDim           = triFaceCubature -> getDimension();
    int numTriFaceCubPoints  = triFaceCubature -> getNumPoints();
    int numQuadFaceCubPoints = quadFaceCubature -> getNumPoints();    
        
    // Allocate storage for cubature points and weights on face parameter domain and fill with points:
    FieldContainer<double> paramTriFacePoints(numTriFaceCubPoints, faceCubDim);
    FieldContainer<double> paramTriFaceWeights(numTriFaceCubPoints);
    FieldContainer<double> paramQuadFacePoints(numQuadFaceCubPoints, faceCubDim);
    FieldContainer<double> paramQuadFaceWeights(numQuadFaceCubPoints);
    
    triFaceCubature -> getCubature(paramTriFacePoints, paramTriFaceWeights);
    quadFaceCubature -> getCubature(paramQuadFacePoints, paramQuadFaceWeights);
    
    
    // Loop over admissible topologies 
    for(cti = standardBaseTopologies.begin(); cti !=standardBaseTopologies.end(); ++cti){
      
      // Exclude 2D and Pyramid<5> cells
      if( ( (*cti).getDimension() == 3) && ( (*cti).getKey() != shards::Pyramid<5>::key) ){ 
        
        int cellDim = (*cti).getDimension();
        int vCount  = (*cti).getVertexCount();
        FieldContainer<double> refCellVertices(vCount, cellDim);
        CellTools::getReferenceSubcellVertices(refCellVertices, cellDim, 0, (*cti) );
        
        *outStream << " Testing face/side normals for cell topology " <<  (*cti).getName() <<"\n";
        
        // Array for physical cell vertices ( must have rank 3 for setJacobians)
        FieldContainer<double> physCellVertices(1, vCount, cellDim);
        
        // Randomize reference cell vertices by moving them up to +/- (1/8) units along their
        // coordinate axis. Guaranteed to be non-degenerate for standard cells with base topology 
        for(int v = 0; v < vCount; v++){
          for(int d = 0; d < cellDim; d++){
            double delta = Teuchos::ScalarTraits<double>::random()/8.0;
            physCellVertices(0, v, d) = refCellVertices(v, d) + delta;
          } //for d
        }// for v     
        
        // Allocate storage for cub. points on a ref. face; Jacobians, phys. face normals and 
        // benchmark normals.
        FieldContainer<double> refTriFacePoints(numTriFaceCubPoints, cellDim);        
        FieldContainer<double> refQuadFacePoints(numQuadFaceCubPoints, cellDim);        
        FieldContainer<double> triFacePointsJacobians(1, numTriFaceCubPoints, cellDim, cellDim);
        FieldContainer<double> quadFacePointsJacobians(1, numQuadFaceCubPoints, cellDim, cellDim);
        FieldContainer<double> triFacePointNormals(1, numTriFaceCubPoints, cellDim);
        FieldContainer<double> triSidePointNormals(1, numTriFaceCubPoints, cellDim);
        FieldContainer<double> quadFacePointNormals(1, numQuadFaceCubPoints, cellDim);
        FieldContainer<double> quadSidePointNormals(1, numQuadFaceCubPoints, cellDim);
        
        
        // Loop over faces:
        for(int faceOrd = 0; faceOrd < (int)(*cti).getSideCount(); faceOrd++){
          
          // This test presently includes only Triangle<3> and Quadrilateral<4> faces. Once we support
          // cells with extended topologies we will add their faces as well.
          switch( (*cti).getCellTopologyData(2, faceOrd) -> key ) {
            
            case shards::Triangle<3>::key: 
              {
                // Compute face normals using CellTools
                CellTools::mapToReferenceSubcell(refTriFacePoints, paramTriFacePoints, 2, faceOrd, (*cti) );
                CellTools::setJacobian(triFacePointsJacobians, refTriFacePoints, physCellVertices, (*cti) );
                CellTools::getPhysicalFaceNormals(triFacePointNormals, triFacePointsJacobians, faceOrd, (*cti));               
                CellTools::getPhysicalSideNormals(triSidePointNormals, triFacePointsJacobians, faceOrd, (*cti));               
                /* 
                 * Compute face normals using direct linear parametrization of the face: the map from
                 * standard 2-simplex to physical Triangle<3> face in 3D is 
                 * F(x,y) = V0 + (V1-V0)x + (V2-V0)*y 
                 * Face normal is vector product Tx X Ty where Tx = (V1-V0); Ty = (V2-V0)
                 */
                int v0ord = (*cti).getNodeMap(2, faceOrd, 0);
                int v1ord = (*cti).getNodeMap(2, faceOrd, 1);
                int v2ord = (*cti).getNodeMap(2, faceOrd, 2);
                
                // Loop over face points: redundant for affine faces, but CellTools gives one vector 
                // per point so need to check all points anyways.
                for(int pt = 0; pt < numTriFaceCubPoints; pt++){
                  FieldContainer<double> tanX(3), tanY(3), faceNormal(3);
                  for(int d = 0; d < cellDim; d++){
                    tanX(d) = (physCellVertices(0, v1ord, d) - physCellVertices(0, v0ord, d));
                    tanY(d) = (physCellVertices(0, v2ord, d) - physCellVertices(0, v0ord, d));
                  }// for d
                  
                  RealSpaceTools<double>::vecprod(faceNormal, tanX, tanY); 
                  
                  // Compare direct normal with d-component of the face/side normal by CellTools
                  for(int d = 0; d < cellDim; d++){
                    
                    // face normal method
                    if( abs(faceNormal(d) - triFacePointNormals(0, pt, d)) > INTREPID2_THRESHOLD ){
                      errorFlag++;
                      *outStream
                        << std::setw(70) << "^^^^----FAILURE!" << "\n"
                        << " Face normal computation by CellTools failed for: \n"
                        << "       Cell Topology = " << (*cti).getName() << "\n"
                        << "       Face Topology = " << (*cti).getCellTopologyData(2, faceOrd) -> name << "\n"
                        << "        Face ordinal = " << faceOrd << "\n"
                        << "   Face point number = " << pt << "\n"
                        << "   Normal coordinate = " << d  << "\n"
                        << "     CellTools value = " <<  triFacePointNormals(0, pt, d)
                        << "     Benchmark value = " <<  faceNormal(d) << "\n\n";
                    }
                    //side normal method
                    if( abs(faceNormal(d) - triSidePointNormals(0, pt, d)) > INTREPID2_THRESHOLD ){
                      errorFlag++;
                      *outStream
                        << std::setw(70) << "^^^^----FAILURE!" << "\n"
                        << " Side normal computation by CellTools failed for: \n"
                        << "       Cell Topology = " << (*cti).getName() << "\n"
                        << "       Side Topology = " << (*cti).getCellTopologyData(2, faceOrd) -> name << "\n"
                        << "        Side ordinal = " << faceOrd << "\n"
                        << "   Side point number = " << pt << "\n"
                        << "   Normal coordinate = " << d  << "\n"
                        << "     CellTools value = " <<  triSidePointNormals(0, pt, d)
                        << "     Benchmark value = " <<  faceNormal(d) << "\n\n";
                    }
                  } // for d
                } // for pt
              }
              break;
              
            case shards::Quadrilateral<4>::key:
              {
                // Compute face normals using CellTools
                CellTools::mapToReferenceSubcell(refQuadFacePoints, paramQuadFacePoints, 2, faceOrd, (*cti) );
                CellTools::setJacobian(quadFacePointsJacobians, refQuadFacePoints, physCellVertices, (*cti) );
                CellTools::getPhysicalFaceNormals(quadFacePointNormals, quadFacePointsJacobians, faceOrd, (*cti));               
                CellTools::getPhysicalSideNormals(quadSidePointNormals, quadFacePointsJacobians, faceOrd, (*cti)); 
                /*
                 * Compute face normals using direct bilinear parametrization of the face: the map from
                 * [-1,1]^2 to physical Quadrilateral<4> face in 3D is 
                 * F(x,y) = ((V0+V1+V2+V3) + (-V0+V1+V2-V3)*X + (-V0-V1+V2+V3)*Y + (V0-V1+V2-V3)*X*Y)/4 
                 * Face normal is vector product Tx X Ty where
                 *          Tx = ((-V0+V1+V2-V3) + (V0-V1+V2-V3)*Y)/4
                 *          Ty = ((-V0-V1+V2+V3) + (V0-V1+V2-V3)*X)/4
                 */
                int v0ord = (*cti).getNodeMap(2, faceOrd, 0);
                int v1ord = (*cti).getNodeMap(2, faceOrd, 1);
                int v2ord = (*cti).getNodeMap(2, faceOrd, 2);
                int v3ord = (*cti).getNodeMap(2, faceOrd, 3);
                
                // Loop over face points (redundant for affine faces, but needed for later when we handle non-affine ones)
                for(int pt = 0; pt < numTriFaceCubPoints; pt++){
                  FieldContainer<double> tanX(3), tanY(3), faceNormal(3);
                  for(int d = 0; d < cellDim; d++){
                    tanX(d) = (physCellVertices(0, v0ord, d)*(-1.0 + paramQuadFacePoints(pt,1) )  +
                               physCellVertices(0, v1ord, d)*( 1.0 - paramQuadFacePoints(pt,1) ) + 
                               physCellVertices(0, v2ord, d)*( 1.0 + paramQuadFacePoints(pt,1) ) + 
                               physCellVertices(0, v3ord, d)*(-1.0 - paramQuadFacePoints(pt,1) ) )/4.0;
                    
                    tanY(d) = (physCellVertices(0, v0ord, d)*(-1.0 + paramQuadFacePoints(pt,0) ) +
                               physCellVertices(0, v1ord, d)*(-1.0 - paramQuadFacePoints(pt,0) ) + 
                               physCellVertices(0, v2ord, d)*( 1.0 + paramQuadFacePoints(pt,0) ) + 
                               physCellVertices(0, v3ord, d)*( 1.0 - paramQuadFacePoints(pt,0) ) )/4.0;
                  }// for d
                  
                  RealSpaceTools<double>::vecprod(faceNormal, tanX, tanY); 
                  // Compare direct normal with d-component of the face/side normal by CellTools
                  for(int d = 0; d < cellDim; d++){
                    
                    // face normal method
                    if( abs(faceNormal(d) - quadFacePointNormals(0, pt, d)) > INTREPID2_THRESHOLD ){
                      errorFlag++;
                      *outStream
                        << std::setw(70) << "^^^^----FAILURE!" << "\n"
                        << " Face normal computation by CellTools failed for: \n"
                        << "       Cell Topology = " << (*cti).getName() << "\n"
                        << "       Face Topology = " << (*cti).getCellTopologyData(2, faceOrd) -> name << "\n"
                        << "        Face ordinal = " << faceOrd << "\n"
                        << "   Face point number = " << pt << "\n"
                        << "   Normal coordinate = " << d  << "\n"
                        << "     CellTools value = " <<  quadFacePointNormals(0, pt, d)
                        << "     Benchmark value = " <<  faceNormal(d) << "\n\n";
                    }
                    //side normal method
                    if( abs(faceNormal(d) - quadSidePointNormals(0, pt, d)) > INTREPID2_THRESHOLD ){
                      errorFlag++;
                      *outStream
                        << std::setw(70) << "^^^^----FAILURE!" << "\n"
                        << " Side normal computation by CellTools failed for: \n"
                        << "       Cell Topology = " << (*cti).getName() << "\n"
                        << "       Side Topology = " << (*cti).getCellTopologyData(2, faceOrd) -> name << "\n"
                        << "        Side ordinal = " << faceOrd << "\n"
                        << "   Side point number = " << pt << "\n"
                        << "   Normal coordinate = " << d  << "\n"
                        << "     CellTools value = " <<  quadSidePointNormals(0, pt, d)
                        << "     Benchmark value = " <<  faceNormal(d) << "\n\n";
                    }
                  } // for d
                }// for pt
              }// case Quad
              break;
            default:
              errorFlag++;
              *outStream << " Face normals test failure: face topology not supported \n\n";
          } // switch 
        }// for faceOrd
      }// if admissible
      }// for cti
  }// try
  
  //============================================================================================//
  // Wrap up test: check if the test broke down unexpectedly due to an exception                //
  //============================================================================================//
  catch (std::logic_error err) {
    *outStream << err.what() << "\n";
    errorFlag = -1000;
  };
  
  
  if (errorFlag != 0)
    std::cout << "End Result: TEST FAILED\n";
  else
    std::cout << "End Result: TEST PASSED\n";
  
  // reset format state of std::cout
  std::cout.copyfmt(oldFormatState);
Kokkos::finalize();  
  return errorFlag;
}
Example #9
0
int main(int argc, char *argv[]) {
  Teuchos::GlobalMPISession mpiSession(&argc, &argv);
  
  // This little trick lets us print to std::cout only if
  // a (dummy) command-line argument is provided.
  int iprint = argc - 1;
  Teuchos::RCP<std::ostream> outStream;
  Teuchos::oblackholestream bhs; // outputs nothing
  if (iprint > 0)
    outStream = Teuchos::rcp(&std::cout, false);
  else
    outStream = Teuchos::rcp(&bhs, false);
  
  // Save the format state of the original std::cout.
  Teuchos::oblackholestream oldFormatState;
  oldFormatState.copyfmt(std::cout);
  
  *outStream \
    << "===============================================================================\n" \
    << "|                                                                             |\n" \
    << "|                  Unit Test (Basis_HCURL_TET_In_FEM)                         |\n" \
    << "|                                                                             |\n" \
    << "| 1) Patch test involving H(curl) matrices                                    |\n" \
    << "|                                                                             |\n" \
    << "|   Questions? Contact Pavel Bochev ([email protected]),                     |\n" \
    << "|                      Robert Kirby ([email protected]),                 |\n" \
    << "|                      Denis Ridzal ([email protected]),                     |\n" \
    << "|                      Kara Peterson ([email protected]).                    |\n" \
    << "|                                                                             |\n" \
    << "|  Intrepid's website: http://trilinos.sandia.gov/packages/intrepid           |\n" \
    << "|  Trilinos website:   http://trilinos.sandia.gov                             |\n" \
    << "|                                                                             |\n" \
    << "===============================================================================\n" \
    << "| TEST 2: Patch test for mass matrices                                        |\n" \
    << "===============================================================================\n";
  
  
  int errorFlag = 0;
  
  outStream -> precision(16);
  
  try {
    DefaultCubatureFactory<double> cubFactory;                                          // create cubature factory
    shards::CellTopology cell(shards::getCellTopologyData< shards::Tetrahedron<> >());  // create parent cell topology
    
    int cellDim = cell.getDimension();
    
    int min_order = 1;
    int max_order = 5;
    
    int numIntervals = max_order;
    int numInterpPoints = ((numIntervals + 1)*(numIntervals + 2)*(numIntervals+3))/6;
    FieldContainer<double> interp_points_ref(numInterpPoints, cellDim);
    int counter = 0;
    for (int j=0; j<=numIntervals; j++) {
      for (int i=0; i<=numIntervals-j; i++) {
        for (int k=0;k<numIntervals-j-i;k++) {
          interp_points_ref(counter,0) = i*(1.0/numIntervals);
          interp_points_ref(counter,1) = j*(1.0/numIntervals);
          interp_points_ref(counter,2) = k*(1.0/numIntervals);
          counter++;
        }
      }
    }
    
    for (int basis_order=min_order;basis_order<=max_order;basis_order++) {
      // create basis
      Teuchos::RCP<Basis<double,FieldContainer<double> > > basis =
        Teuchos::rcp(new Basis_HCURL_TET_In_FEM<double,FieldContainer<double> >(basis_order,POINTTYPE_EQUISPACED) );
      
      int numFields = basis->getCardinality();
      
      // create cubatures
      Teuchos::RCP<Cubature<double> > cellCub = cubFactory.create(cell, 2*(basis_order+1));
      
      int numCubPointsCell = cellCub->getNumPoints();
      
      // hold cubature information
      FieldContainer<double> cub_points_cell(numCubPointsCell, cellDim);
      FieldContainer<double> cub_weights_cell(numCubPointsCell);
      
      // hold basis function information on refcell
      FieldContainer<double> value_of_basis_at_cub_points_cell(numFields, numCubPointsCell, cellDim );
      FieldContainer<double> w_value_of_basis_at_cub_points_cell(1, numFields, numCubPointsCell, cellDim);

      // holds rhs data
      FieldContainer<double> rhs_at_cub_points_cell(1,numCubPointsCell,cellDim);
      
      // FEM mass matrix
      FieldContainer<double> fe_matrix_bak(1,numFields,numFields);
      FieldContainer<double> fe_matrix(1,numFields,numFields);
      FieldContainer<double> rhs_and_soln_vec(1,numFields);
      
      FieldContainer<int> ipiv(numFields);
      FieldContainer<double> value_of_basis_at_interp_points( numFields , numInterpPoints , cellDim);
      FieldContainer<double> interpolant( 1, numInterpPoints , cellDim );

      int info = 0;
      Teuchos::LAPACK<int, double> solver;
      
      // set test tolerance
      double zero = (basis_order+1)*(basis_order+1)*1000*INTREPID_TOL;
      
      // build matrices outside the loop, and then just do the rhs
      // for each iteration
      cellCub->getCubature(cub_points_cell, cub_weights_cell);
      
      // need the vector basis
      basis->getValues(value_of_basis_at_cub_points_cell,
		       cub_points_cell,
		       OPERATOR_VALUE);
      basis->getValues( value_of_basis_at_interp_points ,
			interp_points_ref ,
			OPERATOR_VALUE );
			
			


      // construct mass matrix
      cub_weights_cell.resize(1,numCubPointsCell);
      FunctionSpaceTools::multiplyMeasure<double>(w_value_of_basis_at_cub_points_cell ,
                                                  cub_weights_cell ,
                                                  value_of_basis_at_cub_points_cell ); 
      cub_weights_cell.resize(numCubPointsCell);
      
      
      value_of_basis_at_cub_points_cell.resize( 1 , numFields , numCubPointsCell , cellDim );
      FunctionSpaceTools::integrate<double>(fe_matrix_bak,
                                            w_value_of_basis_at_cub_points_cell ,
                                            value_of_basis_at_cub_points_cell ,
                                            COMP_BLAS );
      value_of_basis_at_cub_points_cell.resize( numFields , numCubPointsCell , cellDim );
      

      //std::cout << fe_matrix_bak << std::endl;

      for (int x_order=0;x_order<basis_order;x_order++) {
        for (int y_order=0;y_order<basis_order-x_order;y_order++) {
          for (int z_order=0;z_order<basis_order-x_order-y_order;z_order++) {
	    for (int comp=0;comp<cellDim;comp++) {
	      fe_matrix.initialize();
	      // copy mass matrix 
	      for (int i=0;i<numFields;i++) {
		for (int j=0;j<numFields;j++) {
		  fe_matrix(0,i,j) = fe_matrix_bak(0,i,j);
		}
	      }
	      
	      // clear old vector data
	      rhs_and_soln_vec.initialize();
	      
	      // now get rhs vector
	      
	      cub_points_cell.resize(1,numCubPointsCell,cellDim);
	     
	      rhs_at_cub_points_cell.initialize();
	      rhsFunc(rhs_at_cub_points_cell,
		      cub_points_cell,
		      comp, 
		      x_order,
		      y_order,
		      z_order);
            
	      cub_points_cell.resize(numCubPointsCell,cellDim);

	      cub_weights_cell.resize(numCubPointsCell);

	      FunctionSpaceTools::integrate<double>(rhs_and_soln_vec,
						    rhs_at_cub_points_cell,
						    w_value_of_basis_at_cub_points_cell,
						    COMP_BLAS);
	      
	      // solve linear system

// 	      solver.GESV(numFields, 1, &fe_matrix[0], numFields, &ipiv(0), &rhs_and_soln_vec[0], 
// 			  numFields, &info);
	      solver.POTRF('L',numFields,&fe_matrix[0],numFields,&info);
	      solver.POTRS('L',numFields,1,&fe_matrix[0],numFields,&rhs_and_soln_vec[0],numFields,&info);
	      
	      interp_points_ref.resize(1,numInterpPoints,cellDim);
	      // get exact solution for comparison
	      FieldContainer<double> exact_solution(1,numInterpPoints,cellDim);
	      exact_solution.initialize();
	      u_exact( exact_solution , interp_points_ref , comp , x_order, y_order, z_order);
	      interp_points_ref.resize(numInterpPoints,cellDim);

	      // compute interpolant
	      // first evaluate basis at interpolation points
	      value_of_basis_at_interp_points.resize(1,numFields,numInterpPoints,cellDim);
	      FunctionSpaceTools::evaluate<double>( interpolant , 
						    rhs_and_soln_vec ,
						    value_of_basis_at_interp_points );
	      value_of_basis_at_interp_points.resize(numFields,numInterpPoints,cellDim);
	      
	      RealSpaceTools<double>::subtract(interpolant,exact_solution);
	      
	      double nrm= RealSpaceTools<double>::vectorNorm(&interpolant[0],interpolant.dimension(1), NORM_TWO);
	      
	      *outStream << "\nNorm-2 error between scalar components of exact solution of order ("
			 << x_order << ", " << y_order << ", " << z_order
			 << ") in component " << comp 
			 << " and finite element interpolant of order " << basis_order << ": "
			 << nrm << "\n";
	      
	      if (nrm > zero) {
		*outStream << "\n\nPatch test failed for solution polynomial order ("
			   << x_order << ", " << y_order << ", " << z_order << ") and basis order (scalar, vector)  ("
			   << basis_order << ", " << basis_order+1 << ")\n\n";
		errorFlag++;
	      }
            }
          }
        }
      }
    }
    
  }
  
  catch (std::logic_error err) {
    *outStream << err.what() << "\n\n";
    errorFlag = -1000;
  };
  
  if (errorFlag != 0)
    std::cout << "End Result: TEST FAILED\n";
  else
    std::cout << "End Result: TEST PASSED\n";
  
  // reset format state of std::cout
  std::cout.copyfmt(oldFormatState);
  
  return errorFlag;
}
Example #10
0
void build_element_matrix_and_rhs(FieldContainer<value_type> & A,
                                  FieldContainer<value_type> & b,
                                  DefaultCubatureFactory<value_type> & cubature_factory,
                                  const BasisSet_HGRAD_TRI_Cn_FEM<value_type,FieldContainer<value_type> > &basis_set,
                                  const int *element,
                                  const int *boundary,
                                  const FieldContainer<value_type> & cell_nodes,
                                  const Orientation ort,
                                  const int nx,
                                  const int ny) {

  // Step 0: initilization
  const auto &cell_basis = basis_set.getCellBasis();
  const auto &side_basis = basis_set.getLineBasis();

  const shards::CellTopology cell_topo = cell_basis.getBaseCellTopology();
  const shards::CellTopology side_topo = side_basis.getBaseCellTopology();

  const int nbf_cell = cell_basis.getCardinality();
  //const int nbf_side = side_basis.getCardinality();

  const int ndim_cell = cell_topo.getDimension();
  const int ndim_side = side_topo.getDimension();

  //const int nside = cell_topo.getEdgeCount();

  const int p = cell_basis.getDegree();

  // Step 1: create cubature data for integration
  Teuchos::RCP<Cubature<value_type> > cell_cub = cubature_factory.create(cell_topo, 2*p);
  Teuchos::RCP<Cubature<value_type> > side_cub = cubature_factory.create(side_topo, 2*p);

  const int npts_cell_cub = cell_cub->getNumPoints();
  const int npts_side_cub = side_cub->getNumPoints();

  // - cell related containers
  FieldContainer<value_type> cub_points_cell(npts_cell_cub, ndim_cell);
  FieldContainer<value_type> cub_points_cell_physical(1, npts_cell_cub, ndim_cell);
  FieldContainer<value_type> cub_weights_cell(npts_cell_cub);

  FieldContainer<value_type> jacobian_cell(1, npts_cell_cub, ndim_cell, ndim_cell);
  FieldContainer<value_type> jacobian_inv_cell(1, npts_cell_cub, ndim_cell, ndim_cell);
  FieldContainer<value_type> jacobian_det_cell(1, npts_cell_cub);

  FieldContainer<value_type> weighted_measure_cell(1, npts_cell_cub);

  FieldContainer<value_type> value_of_basis_at_cub_points_cell(nbf_cell, npts_cell_cub);
  FieldContainer<value_type> value_of_reordered_basis_at_cub_points_cell(nbf_cell, npts_cell_cub);

  FieldContainer<value_type> transformed_value_of_basis_at_cub_points_cell(1, nbf_cell, npts_cell_cub);
  FieldContainer<value_type> weighted_transformed_value_of_basis_at_cub_points_cell(1, nbf_cell, npts_cell_cub);

  FieldContainer<value_type> grad_of_basis_at_cub_points_cell(nbf_cell, npts_cell_cub, ndim_cell);
  FieldContainer<value_type> grad_of_reordered_basis_at_cub_points_cell(nbf_cell, npts_cell_cub, ndim_cell);

  FieldContainer<value_type> transformed_grad_of_basis_at_cub_points_cell(1, nbf_cell, npts_cell_cub, ndim_cell);
  FieldContainer<value_type> weighted_transformed_grad_of_basis_at_cub_points_cell(1, nbf_cell, npts_cell_cub, ndim_cell);

  FieldContainer<value_type> rhs_at_cub_points_cell_physical(1, npts_cell_cub);
  FieldContainer<value_type> rhs_and_soln_vector(1, nbf_cell);

  // - subcell related containders
  FieldContainer<value_type> cub_points_side(npts_side_cub, ndim_side);
  FieldContainer<value_type> cub_weights_side(npts_side_cub);
  FieldContainer<value_type> cub_points_side_refcell(npts_side_cub, ndim_cell);
  FieldContainer<value_type> cub_points_side_physical(1, npts_side_cub, ndim_cell);

  FieldContainer<value_type> jacobian_side_refcell(1, npts_side_cub, ndim_cell, ndim_cell);
  FieldContainer<value_type> jacobian_det_side_refcell(1, npts_side_cub);

  FieldContainer<value_type> weighted_measure_side_refcell(1, npts_side_cub);

  FieldContainer<value_type> value_of_basis_at_cub_points_side_refcell(nbf_cell, npts_side_cub);
  FieldContainer<value_type> value_of_reordered_basis_at_cub_points_side_refcell(nbf_cell, npts_side_cub);

  FieldContainer<value_type> transformed_value_of_basis_at_cub_points_side_refcell(1, nbf_cell, npts_side_cub);
  FieldContainer<value_type> weighted_transformed_value_of_basis_at_cub_points_side_refcell(1, nbf_cell, npts_side_cub);

  FieldContainer<value_type> neumann_data_at_cub_points_side_physical(1, npts_side_cub);
  FieldContainer<value_type> neumann_fields_per_side(1, nbf_cell);

  // get cubature points and weights
  cell_cub->getCubature(cub_points_cell, cub_weights_cell);

  CellTools<value_type>::setJacobian   (jacobian_cell, cub_points_cell, cell_nodes, cell_topo);
  CellTools<value_type>::setJacobianInv(jacobian_inv_cell, jacobian_cell);
  CellTools<value_type>::setJacobianDet(jacobian_det_cell, jacobian_cell);

  // compute weighted measure
  FunctionSpaceTools::computeCellMeasure<value_type>(weighted_measure_cell,
                                                     jacobian_det_cell, cub_weights_cell);

  // Step 1: mass matrix: tabulate values of basis functions at cubature points
  cell_basis.getValues(value_of_basis_at_cub_points_cell, cub_points_cell, OPERATOR_VALUE);
  if (apply_orientation) {
    OrientationTools<value_type>::verbose = false;
    OrientationTools<value_type>::getBasisFunctionsByTopology(value_of_reordered_basis_at_cub_points_cell,
                                                              value_of_basis_at_cub_points_cell,
                                                              cell_basis);
    OrientationTools<value_type>::getModifiedBasisFunctions(value_of_basis_at_cub_points_cell,
                                                            value_of_reordered_basis_at_cub_points_cell,
                                                            basis_set,
                                                            ort);
    OrientationTools<value_type>::verbose = false;
  }

  // transform values of basis functions
  FunctionSpaceTools::HGRADtransformVALUE<value_type>(transformed_value_of_basis_at_cub_points_cell,
                                                      value_of_basis_at_cub_points_cell);

  // multiply with weighted measure
  FunctionSpaceTools::multiplyMeasure<value_type>(weighted_transformed_value_of_basis_at_cub_points_cell,
                                                  weighted_measure_cell,
                                                  transformed_value_of_basis_at_cub_points_cell);

  // integrate
  FunctionSpaceTools::integrate<value_type>(A,
                                            transformed_value_of_basis_at_cub_points_cell,
                                            weighted_transformed_value_of_basis_at_cub_points_cell,
                                            COMP_BLAS);

  // Step 2: stiffness matrix: tabulate grad values of basis functions at cubature points
  cell_basis.getValues(grad_of_basis_at_cub_points_cell, cub_points_cell, OPERATOR_GRAD);
  if (apply_orientation) {
    OrientationTools<value_type>::getBasisFunctionsByTopology(grad_of_reordered_basis_at_cub_points_cell,
                                                              grad_of_basis_at_cub_points_cell,
                                                              cell_basis);
    OrientationTools<value_type>::getModifiedBasisFunctions(grad_of_basis_at_cub_points_cell,
                                                            grad_of_reordered_basis_at_cub_points_cell,
                                                            basis_set,
                                                            ort);
  }

  // transform gradients of basis functions
  FunctionSpaceTools::HGRADtransformGRAD<value_type>(transformed_grad_of_basis_at_cub_points_cell,
                                                     jacobian_inv_cell,
                                                     grad_of_basis_at_cub_points_cell);

  // multiply with weighted measure
  FunctionSpaceTools::multiplyMeasure<value_type>(weighted_transformed_grad_of_basis_at_cub_points_cell,
                                                  weighted_measure_cell,
                                                  transformed_grad_of_basis_at_cub_points_cell);

  // compute stiffness matrices and sum into fe_matrix
  FunctionSpaceTools::integrate<value_type>(A,
                                            transformed_grad_of_basis_at_cub_points_cell,
                                            weighted_transformed_grad_of_basis_at_cub_points_cell,
                                            COMP_BLAS,
                                            true);

  // Step 3: compute rhs function
  CellTools<value_type>::mapToPhysicalFrame(cub_points_cell_physical, cub_points_cell, cell_nodes, cell_topo);

  // evaluate rhs function
  eval_rhs(rhs_at_cub_points_cell_physical,
           cub_points_cell_physical,
           nx, ny);

  // compute rhs
  FunctionSpaceTools::integrate<value_type>(b,
                                            rhs_at_cub_points_cell_physical,
                                            weighted_transformed_value_of_basis_at_cub_points_cell,
                                            COMP_BLAS);

  // Step 4: compute boundary condition
  side_cub->getCubature(cub_points_side, cub_weights_side);
  const int nside = cell_topo.getSideCount();
  for (int i=0;i<nside;++i) {
    if (boundary[i]) {
      // compute geometric cell information
      CellTools<value_type>::mapToReferenceSubcell(cub_points_side_refcell, cub_points_side, ndim_side, i, cell_topo);
      CellTools<value_type>::setJacobian   (jacobian_side_refcell, cub_points_side_refcell, cell_nodes, cell_topo);
      CellTools<value_type>::setJacobianDet(jacobian_det_side_refcell, jacobian_side_refcell);

      // compute weighted edge measure
      FunctionSpaceTools::computeEdgeMeasure<value_type>(weighted_measure_side_refcell,
                                                         jacobian_side_refcell,
                                                         cub_weights_side,
                                                         i,
                                                         cell_topo);

      // tabulate values of basis functions at side cubature points, in the reference parent cell domain
      cell_basis.getValues(value_of_basis_at_cub_points_side_refcell, cub_points_side_refcell, OPERATOR_VALUE);
      if (apply_orientation) {
        OrientationTools<value_type>::getBasisFunctionsByTopology(value_of_reordered_basis_at_cub_points_side_refcell,
                                                                  value_of_basis_at_cub_points_side_refcell,
                                                                  cell_basis);
        OrientationTools<value_type>::getModifiedBasisFunctions(value_of_basis_at_cub_points_side_refcell,
                                                                value_of_reordered_basis_at_cub_points_side_refcell,
                                                                basis_set,
                                                                ort);
      }

      // transform
      FunctionSpaceTools::HGRADtransformVALUE<value_type>(transformed_value_of_basis_at_cub_points_side_refcell,
                                                          value_of_basis_at_cub_points_side_refcell);

      // multiply with weighted measure
      FunctionSpaceTools::multiplyMeasure<value_type>(weighted_transformed_value_of_basis_at_cub_points_side_refcell,
                                                      weighted_measure_side_refcell,
                                                      transformed_value_of_basis_at_cub_points_side_refcell);

      // compute neumann boundary

      // map side cubature points in reference parent cell domain to physical space
      CellTools<value_type>::mapToPhysicalFrame(cub_points_side_physical, cub_points_side_refcell, cell_nodes, cell_topo);

      // now compute data
      eval_neumann(neumann_data_at_cub_points_side_physical,
                   cub_points_side_physical,
                   jacobian_side_refcell,
                   cell_topo,
                   i,
                   nx, ny);

      FunctionSpaceTools::integrate<value_type>(neumann_fields_per_side,
                                                neumann_data_at_cub_points_side_physical,
                                                weighted_transformed_value_of_basis_at_cub_points_side_refcell,
                                                COMP_BLAS);

      // adjust rhs
      RealSpaceTools<value_type>::add(b, neumann_fields_per_side);;
    }
  }
}
Example #11
0
    /**
     * Check for nonpositive Jacobian
     */
    bool GeometryVerifier::isGeometryBad(stk::mesh::BulkData& bulk, bool printTable) //, stk::mesh::Part& mesh_part )
    {
      const stk::mesh::fem::FEMMetaData& meta = stk::mesh::fem::FEMMetaData::get(bulk);
      const unsigned p_rank = bulk.parallel_rank();

      unsigned foundBad=0;
      jac_data_map jac_data;

      stk::mesh::Field<double, stk::mesh::Cartesian> *coord_field =
        meta.get_field<stk::mesh::Field<double, stk::mesh::Cartesian> >("coordinates");

      mesh::Selector select_owned( meta.locally_owned_part() );
      const std::vector<mesh::Bucket*> & buckets = bulk.buckets( meta.element_rank() );

      //for ( std::vector<mesh::Bucket *>::const_iterator ik = buckets.begin() ; ik != buckets.end() ; ++ik )
      const stk::mesh::PartVector & all_parts = meta.get_parts();
      for ( stk::mesh::PartVector::const_iterator ip = all_parts.begin(); ip != all_parts.end(); ++ip ) 
        {
          stk::mesh::Part * part = *ip;

          if ( stk::mesh::is_auto_declared_part(*part) )
            continue;

          const CellTopologyData * const part_cell_topo_data = stk::percept::PerceptMesh::get_cell_topology(*part);
          //std::cout << "P[" << p_rank << "] part = " << part->name() << " part_cell_topo_data= " << part_cell_topo_data << " topo-name= "
          //          << (part_cell_topo_data ? part_cell_topo_data->name : "null") << std::endl;

          if (part_cell_topo_data)
            jac_data[part_cell_topo_data->name] = jacData();
        }

      for (unsigned ipass = 0; ipass < 1; ipass++)
        {
          for ( std::vector<mesh::Bucket *>::const_iterator ik = buckets.begin() ; ik != buckets.end() ; ++ik )
            {
              if ( select_owned( **ik ) ) {

              const mesh::Bucket & bucket = **ik ;

              // Number of elems in this bucket of elems and elem field data
              const unsigned number_elems = bucket.size();

              double * elem_node_data = field_data( *coord_field , bucket.begin() );
              //double * elem_centroid_data = field_data( elem_centroid_field , bucket.begin() );
              //double * const coord = field_data( m_coordinates_field , *node );

              // FIXME
              if (0) { elem_node_data[0]++;}

#if 1
              const CellTopologyData * const bucket_cell_topo_data = stk::percept::PerceptMesh::get_cell_topology(bucket);
              int bucket_shardsId = ShardsInterfaceTable::s_singleton.lookupShardsId(bucket_cell_topo_data->name);
#endif

              //if (0) { std::cout << bucket_cell_topo_data->name; }
              if (0) { std::cout << "bucket_shardsId= " << bucket_shardsId << " name= " << bucket_cell_topo_data->name <<  std::endl; }

              if (0) { std::cout << "number_elems= " << number_elems << std::endl;}

              CellTopology cell_topo(bucket_cell_topo_data);
              double volEqui = getEquiVol(cell_topo);
              unsigned numCells = number_elems;
              unsigned numNodes = cell_topo.getNodeCount();
              unsigned spaceDim = cell_topo.getDimension();
              //unsigned spatialDimMeta = stk::mesh::fem::FEMMetaData::get(bulk).spatial_dimension();

              // Rank-3 array with dimensions (C,N,D) for the node coordinates of 3 traingle cells
              FieldContainer<double> cellNodes(numCells, numNodes, spaceDim);
              PerceptMesh::fillCellNodes(bucket,  coord_field, cellNodes, spaceDim);

              FieldContainer<double> volume(numCells);

              // get min/max edge length
              FieldContainer<double> elem_min_edge_length(number_elems);
              FieldContainer<double> elem_max_edge_length(number_elems);
              PerceptMesh::findMinMaxEdgeLength(bucket, *coord_field, elem_min_edge_length, elem_max_edge_length);

              /// note: we're using cubature here instead of explicitly specifying some reference points
              ///  the idea is that we'll get a good estimate of the Jacobian's sign by testing it at all the
              ///  cubature points

              DefaultCubatureFactory<double> cubFactory;                                              // create cubature factory
              unsigned cubDegree = 2;                                                                      // set cubature degree, e.g. 2
              Teuchos::RCP<Cubature<double> > myCub;
              bool hasGoodTopo = true;
              try {
                myCub = cubFactory.create(cell_topo, cubDegree);         // create default cubature
              }
              catch(...)
                {
                  if (!p_rank)
                    std::cout << "WARNING: mesh contains elements that Intrepid doesn't support for quadrature, cell_topo= " << cell_topo.getName() << std::endl;
                  //continue;
                  hasGoodTopo = false;
                }

              FieldContainer<double> jacobian_det(numCells, 1);
              unsigned numCubPoints = 1;
              FieldContainer<double> jacobian(numCells, numCubPoints, spaceDim, spaceDim);

              if (hasGoodTopo)
                {
                  numCubPoints = myCub->getNumPoints();                                               // retrieve number of cubature points

                  FieldContainer<double> cub_points(numCubPoints, spaceDim);
                  FieldContainer<double> cub_weights(numCubPoints);

                  // Rank-4 array (C,P,D,D) for the Jacobian and its inverse and Rank-2 array (C,P) for its determinant
                  //FieldContainer<double> jacobian(numCells, numCubPoints, spaceDim, spaceDim);
                  jacobian.resize(numCells, numCubPoints, spaceDim, spaceDim);
                  FieldContainer<double> jacobian_inv(numCells, numCubPoints, spaceDim, spaceDim);
                  //FieldContainer<double> jacobian_det(numCells, numCubPoints);
                  jacobian_det.resize(numCells, numCubPoints);

                  myCub->getCubature(cub_points, cub_weights);                                          // retrieve cubature points and weights

                  // Methods to compute cell Jacobians, their inverses and their determinants

                  CellTools<double>::setJacobian(jacobian, cub_points, cellNodes, cell_topo);           // compute cell Jacobians
                  CellTools<double>::setJacobianInv(jacobian_inv, jacobian);                            // compute inverses of cell Jacobians
                  CellTools<double>::setJacobianDet(jacobian_det, jacobian);                            // compute determinants of cell Jacobians

                  FieldContainer<double> weightedMeasure(numCells, numCubPoints);

                  FieldContainer<double> onesLeft(numCells,  numCubPoints);
                  onesLeft.initialize(1.0);

                  // compute weighted measure
                  FunctionSpaceTools::computeCellMeasure<double>(weightedMeasure, jacobian_det, cub_weights);

                  // integrate to get volume
                  FunctionSpaceTools::integrate<double>(volume, onesLeft, weightedMeasure,  COMP_BLAS);
                }

              jacData& jdata = jac_data[cell_topo.getName()];
              jdata.numEle += numCells;

              for (unsigned iCell = 0; iCell < numCells; iCell++)
                {
                  mesh::Entity & elem = bucket[iCell];
                  double min_edge_length = elem_min_edge_length[iCell];
                  double max_edge_length = elem_max_edge_length[iCell];
                  double max_edge_lengthNotZero = (fabs(max_edge_length) < 1.e-20? 1.e-20 : max_edge_length);

                  double cellVolActual = volume(iCell);
                  double cellVol = cellVolActual/volEqui; // scaled so that equilateral cell has vol=1.0

                  for (unsigned iCubPt = 0; iCubPt < numCubPoints; iCubPt++)
                    {
                      double jacDet = jacobian_det(iCell, iCubPt);
                      if (hasGoodTopo && jacDet < m_badJacobian)
                        {
                          ++foundBad;
                        }

                      double cellVolNotZero = fabs(cellVol) < 1.e-20? 1.e-20 : cellVol;
                      double quality_measure_1 = (cellVolNotZero < 0? -1.0 : 1.0) * min_edge_length / pow(fabs(cellVolNotZero), 1./(double(spaceDim)));
                      if (0 && iCubPt==0)
                        {
                          std::cout << "quality_measure_1= " << quality_measure_1 << " cellVolNotZero= " << cellVolNotZero << " cellVolActual= "
                                    << cellVolActual << " volEqui= " << volEqui << " min_edge_length= " << min_edge_length
                                    << " max_edge_length= " << max_edge_length << std::endl;
                        }

                      double quality_measure_2 = min_edge_length / max_edge_lengthNotZero;

                      if (ipass == 0)
                        {
                          jdata.jac.registerValue(elem.identifier(), jacDet);
                          jdata.QM_1.registerValue(elem.identifier(),  quality_measure_1);
                          jdata.QM_2.registerValue(elem.identifier(),  quality_measure_2);
                        }
                    }
                }

              if (m_dump)
                {
                  for (unsigned iCell = 0; iCell < numCells; iCell++)
                    {
                      for (unsigned iCubPt = 0; iCubPt < numCubPoints; iCubPt++)
                        {
                          stk::PrintTable table;
                          std::ostringstream msg; msg << "Jacobian"<<" iCell= "<<iCell<<" iCubPt= "<<iCubPt << " Det= " << jacobian_det(iCell, iCubPt);
                          table.setTitle(msg.str());

                          for (unsigned id = 0; id < spaceDim; id++)
                            {
                              for (unsigned jd = 0; jd < spaceDim; jd++)
                                {
                                  table << jacobian(iCell, iCubPt, id, jd);
                                }
                              table << stk::end_row;
                            }
                          std::cout << "P["<< bulk.parallel_rank() << "] " << cell_topo.getName() << "\n" << table;
                        }
                    }
                }
              }

            } // buckets

          // setup the histogram ranges and counts

        } // ipass

      for (jac_data_map::iterator itMap = jac_data.begin(); itMap != jac_data.end(); itMap++)
        {
          itMap->second.jac.finish(bulk);
          itMap->second.QM_1.finish(bulk);
          itMap->second.QM_2.finish(bulk);
        }

      //  all_reduce( mesh.parallel() , ReduceMax<1>( & error_flag ) );

      stk::PrintTable table;
      if (0)
        {
          const unsigned rank = bulk.parallel_rank();
          std::string title = "Jacobian and Quality Table P["+toString(rank)+"]\n";
          table.setTitle(title.c_str());
        }
      table.setTitle("Jacobian and Quality Table\n");

      table << "|" << "Element Type" << "|"
            << "Min JacDet" << "|" << "Id" << "|"
            << "Max JacDet" << "|" << "Id" << "|"
            << "Ave JacDet" << "|"
            << "Sum JacDet" << "|"
            << "Min QM1" << "|" << "Id" << "|"
            << "Max QM1" << "|" << "Id" << "|"
            << "Ave QM1" << "|"
            << "Min QM2" << "|" << "Id" << "|"
            << "Max QM2" << "|" << "Id" << "|"
            << "Ave QM2" << "|"
            << stk::end_header;

      for (jac_data_map::iterator itMap = jac_data.begin(); itMap != jac_data.end(); itMap++)
        {
          if (1)
            {
              std::cout << "P[" << p_rank << "] nele = " << itMap->second.numEle << std::endl;
            }

          table << "|" << itMap->first << "|"
                << itMap->second.jac.min << "|"
                << itMap->second.jac.min_i << "|"
                << itMap->second.jac.max << "|"
                << itMap->second.jac.max_i << "|"
                << itMap->second.jac.ave << "|"
                << itMap->second.jac.sum << "|"
                << itMap->second.QM_1.min << "|"
                << itMap->second.QM_1.min_i << "|"
                << itMap->second.QM_1.max << "|"
                << itMap->second.QM_1.max_i << "|"
                << itMap->second.QM_1.ave << "|"
                << itMap->second.QM_2.min << "|"
                << itMap->second.QM_2.min_i << "|"
                << itMap->second.QM_2.max << "|"
                << itMap->second.QM_2.max_i << "|"
                << itMap->second.QM_2.ave << "|"
                << stk::end_row;
        }

      if (!p_rank && printTable)
        //if (printTable)
        {
          std::cout << "P[" << p_rank << "] Explanation: JacDet=det(element jacobian), QM1=min(element edge length)/(elemement vol)^(1/dim), QM2=min(element edge length)/max(element edge length)\n" 
                    << " NOTE: QM1 is normalized to 1 for ideally shaped elements, < 1 or > 1 values signify badly shaped elements\n"
                    << " NOTE: QM2 is small for badly shaped elements, normalized to 1 for ideally shaped elements\n"
                    << std::endl;
          std::cout << table;
        }

      return (foundBad > 0);
    }
Example #12
0
int main(int argc, char *argv[]) {

   //Check number of arguments
   if (argc < 13) {
      std::cout <<"\n>>> ERROR: Invalid number of arguments.\n\n";
      std::cout <<"Usage:\n\n";
      std::cout <<"  ./Intrepid_example_Drivers_Example_01.exe NX NY NZ randomMesh mu1 mu2 mu1LX mu1RX mu1LY mu1RY mu1LZ mu1RZ verbose\n\n";
      std::cout <<" where \n";
      std::cout <<"   int NX              - num intervals in x direction (assumed box domain, -1,1) \n";
      std::cout <<"   int NY              - num intervals in y direction (assumed box domain, -1,1) \n";
      std::cout <<"   int NZ              - num intervals in z direction (assumed box domain, -1,1) \n";
      std::cout <<"   int randomMesh      - 1 if mesh randomizer is to be used 0 if not \n";
      std::cout <<"   double mu1          - material property value for region 1 \n";
      std::cout <<"   double mu2          - material property value for region 2 \n";
      std::cout <<"   double mu1LX        - left X boundary for region 1 \n";
      std::cout <<"   double mu1RX        - right X boundary for region 1 \n";
      std::cout <<"   double mu1LY        - left Y boundary for region 1 \n";
      std::cout <<"   double mu1RY        - right Y boundary for region 1 \n";
      std::cout <<"   double mu1LZ        - bottom Z boundary for region 1 \n";
      std::cout <<"   double mu1RZ        - top Z boundary for region 1 \n";
      std::cout <<"   verbose (optional)  - any character, indicates verbose output \n\n";
      exit(1);
   }
  
  // This little trick lets us print to std::cout only if
  // a (dummy) command-line argument is provided.
  int iprint     = argc - 1;
  Teuchos::RCP<std::ostream> outStream;
  Teuchos::oblackholestream bhs; // outputs nothing
  if (iprint > 12)
    outStream = Teuchos::rcp(&std::cout, false);
  else
    outStream = Teuchos::rcp(&bhs, false);
  
  // Save the format state of the original std::cout.
  Teuchos::oblackholestream oldFormatState;
  oldFormatState.copyfmt(std::cout);
  
  *outStream \
    << "===============================================================================\n" \
    << "|                                                                             |\n" \
    << "|  Example: Generate Mass and Stiffness Matrices and Right-Hand Side Vector   |\n"
    << "|    for Div-Curl System on Hexahedral Mesh with Curl-Conforming Elements     |\n" \
    << "|                                                                             |\n" \
    << "|  Questions? Contact  Pavel Bochev  ([email protected]),                    |\n" \
    << "|                      Denis Ridzal  ([email protected]),                    |\n" \
    << "|                      Kara Peterson ([email protected]).                    |\n" \
    << "|                                                                             |\n" \
    << "|  Intrepid's website: http://trilinos.sandia.gov/packages/intrepid           |\n" \
    << "|  Trilinos website:   http://trilinos.sandia.gov                             |\n" \
    << "|                                                                             |\n" \
    << "===============================================================================\n";


// ************************************ GET INPUTS **************************************

  /* In the implementation for discontinuous material properties only the boundaries for
     region 1, associated with mu1, are input. The remainder of the grid is assumed to use mu2.
     Note that the material properties are assigned using the undeformed grid. */

    int NX            = atoi(argv[1]);  // num intervals in x direction (assumed box domain, -1,1)
    int NY            = atoi(argv[2]);  // num intervals in y direction (assumed box domain, -1,1)
    int NZ            = atoi(argv[3]);  // num intervals in z direction (assumed box domain, -1,1)
    int randomMesh    = atoi(argv[4]);  // 1 if mesh randomizer is to be used 0 if not
    double mu1        = atof(argv[5]);  // material property value for region 1
    double mu2        = atof(argv[6]);  // material property value for region 2
    double mu1LeftX   = atof(argv[7]);  // left X boundary for region 1
    double mu1RightX  = atof(argv[8]);  // right X boundary for region 1
    double mu1LeftY   = atof(argv[9]);  // left Y boundary for region 1
    double mu1RightY  = atof(argv[10]); // right Y boundary for region 1
    double mu1LeftZ   = atof(argv[11]); // left Z boundary for region 1
    double mu1RightZ  = atof(argv[12]); // right Z boundary for region 1

// *********************************** CELL TOPOLOGY **********************************

   // Get cell topology for base hexahedron
    typedef shards::CellTopology    CellTopology;
    CellTopology hex_8(shards::getCellTopologyData<shards::Hexahedron<8> >() );

   // Get dimensions 
    int numNodesPerElem = hex_8.getNodeCount();
    int numEdgesPerElem = hex_8.getEdgeCount();
    int numFacesPerElem = hex_8.getSideCount();
    int numNodesPerEdge = 2;
    int numNodesPerFace = 4;
    int numEdgesPerFace = 4;
    int spaceDim = hex_8.getDimension();

   // Build reference element edge to node map
    FieldContainer<int> refEdgeToNode(numEdgesPerElem,numNodesPerEdge);
    for (int i=0; i<numEdgesPerElem; i++){
        refEdgeToNode(i,0)=hex_8.getNodeMap(1, i, 0);
        refEdgeToNode(i,1)=hex_8.getNodeMap(1, i, 1);
    }

// *********************************** GENERATE MESH ************************************

    *outStream << "Generating mesh ... \n\n";

    *outStream << "    NX" << "   NY" << "   NZ\n";
    *outStream << std::setw(5) << NX <<
                 std::setw(5) << NY <<
                 std::setw(5) << NZ << "\n\n";

   // Print mesh information  
    int numElems = NX*NY*NZ;
    int numNodes = (NX+1)*(NY+1)*(NZ+1);
    int numEdges = (NX)*(NY + 1)*(NZ + 1) + (NX + 1)*(NY)*(NZ + 1) + (NX + 1)*(NY + 1)*(NZ);
    int numFaces = (NX)*(NY)*(NZ + 1) + (NX)*(NY + 1)*(NZ) + (NX + 1)*(NY)*(NZ);
    *outStream << " Number of Elements: " << numElems << " \n";
    *outStream << "    Number of Nodes: " << numNodes << " \n";
    *outStream << "    Number of Edges: " << numEdges << " \n";
    *outStream << "    Number of Faces: " << numFaces << " \n\n";

   // Cube
    double leftX = -1.0, rightX = 1.0;
    double leftY = -1.0, rightY = 1.0;
    double leftZ = -1.0, rightZ = 1.0;

   // Mesh spacing
    double hx = (rightX-leftX)/((double)NX);
    double hy = (rightY-leftY)/((double)NY);
    double hz = (rightZ-leftZ)/((double)NZ);

    // Get nodal coordinates
    FieldContainer<double> nodeCoord(numNodes, spaceDim);
    FieldContainer<int> nodeOnBoundary(numNodes);
    int inode = 0;
    for (int k=0; k<NZ+1; k++) {
      for (int j=0; j<NY+1; j++) {
        for (int i=0; i<NX+1; i++) {
          nodeCoord(inode,0) = leftX + (double)i*hx;
          nodeCoord(inode,1) = leftY + (double)j*hy;
          nodeCoord(inode,2) = leftZ + (double)k*hz;
          if (k==0 || j==0 || i==0 || k==NZ || j==NY || i==NX){
             nodeOnBoundary(inode)=1; 
          }
          inode++;
        }
      }
    }
    
   // Element to Node map
    FieldContainer<int> elemToNode(numElems, numNodesPerElem);
    int ielem = 0;
    for (int k=0; k<NZ; k++) {
      for (int j=0; j<NY; j++) {
        for (int i=0; i<NX; i++) {
          elemToNode(ielem,0) = (NY + 1)*(NX + 1)*k + (NX + 1)*j + i;
          elemToNode(ielem,1) = (NY + 1)*(NX + 1)*k + (NX + 1)*j + i + 1;
          elemToNode(ielem,2) = (NY + 1)*(NX + 1)*k + (NX + 1)*(j + 1) + i + 1;
          elemToNode(ielem,3) = (NY + 1)*(NX + 1)*k + (NX + 1)*(j + 1) + i;
          elemToNode(ielem,4) = (NY + 1)*(NX + 1)*(k + 1) + (NX + 1)*j + i;
          elemToNode(ielem,5) = (NY + 1)*(NX + 1)*(k + 1) + (NX + 1)*j + i + 1;
          elemToNode(ielem,6) = (NY + 1)*(NX + 1)*(k + 1) + (NX + 1)*(j + 1) + i + 1;
          elemToNode(ielem,7) = (NY + 1)*(NX + 1)*(k + 1) + (NX + 1)*(j + 1) + i;
          ielem++;
        }
      }
    }

  // Get edge connectivity
    FieldContainer<int> edgeToNode(numEdges, numNodesPerEdge);
    FieldContainer<int> elemToEdge(numElems, numEdgesPerElem);
    int iedge = 0;
    inode = 0;
    for (int k=0; k<NZ+1; k++) {
      for (int j=0; j<NY+1; j++) {
        for (int i=0; i<NX+1; i++) {
           if (i < NX){
               edgeToNode(iedge,0) = inode;
               edgeToNode(iedge,1) = inode + 1;
               if (j < NY && k < NZ){
                  ielem=i+j*NX+k*NX*NY;
                  elemToEdge(ielem,0) = iedge;
                  if (j > 0)
                     elemToEdge(ielem-NX,2) = iedge; 
                  if (k > 0)
                     elemToEdge(ielem-NX*NY,4) = iedge; 
                  if (j > 0 && k > 0)
                     elemToEdge(ielem-NX*NY-NX,6) = iedge; 
                }
               else if (j == NY && k == NZ){
                  ielem=i+(NY-1)*NX+(NZ-1)*NX*NY;
                  elemToEdge(ielem,6) = iedge;
                }
               else if (k == NZ && j < NY){
                  ielem=i+j*NX+(NZ-1)*NX*NY;
                  elemToEdge(ielem,4) = iedge;
                  if (j > 0)
                    elemToEdge(ielem-NX,6) = iedge;
                }
               else if (k < NZ && j == NY){
                  ielem=i+(NY-1)*NX+k*NX*NY;
                  elemToEdge(ielem,2) = iedge;
                  if (k > 0)
                     elemToEdge(ielem-NX*NY,6) = iedge;
                }
               iedge++;
            }
           if (j < NY){
               edgeToNode(iedge,0) = inode;
               edgeToNode(iedge,1) = inode + NX+1;
               if (i < NX && k < NZ){
                  ielem=i+j*NX+k*NX*NY;
                  elemToEdge(ielem,3) = iedge;
                  if (i > 0)
                     elemToEdge(ielem-1,1) = iedge; 
                  if (k > 0)
                     elemToEdge(ielem-NX*NY,7) = iedge; 
                  if (i > 0 && k > 0)
                     elemToEdge(ielem-NX*NY-1,5) = iedge; 
                }
               else if (i == NX && k == NZ){
                  ielem=NX-1+j*NX+(NZ-1)*NX*NY;
                  elemToEdge(ielem,5) = iedge;
                }
               else if (k == NZ && i < NX){
                  ielem=i+j*NX+(NZ-1)*NX*NY;
                  elemToEdge(ielem,7) = iedge;
                  if (i > 0)
                    elemToEdge(ielem-1,5) = iedge;
                }
               else if (k < NZ && i == NX){
                  ielem=NX-1+j*NX+k*NX*NY;
                  elemToEdge(ielem,1) = iedge;
                  if (k > 0)
                     elemToEdge(ielem-NX*NY,5) = iedge;
                }
               iedge++;
            }
           if (k < NZ){
               edgeToNode(iedge,0) = inode;
               edgeToNode(iedge,1) = inode + (NX+1)*(NY+1);
               if (i < NX && j < NY){
                  ielem=i+j*NX+k*NX*NY;
                  elemToEdge(ielem,8) = iedge;
                  if (i > 0)
                     elemToEdge(ielem-1,9) = iedge; 
                  if (j > 0)
                     elemToEdge(ielem-NX,11) = iedge; 
                  if (i > 0 && j > 0)
                     elemToEdge(ielem-NX-1,10) = iedge; 
                }
               else if (i == NX && j == NY){
                  ielem=NX-1+(NY-1)*NX+k*NX*NY;
                  elemToEdge(ielem,10) = iedge;
                }
               else if (j == NY && i < NX){
                  ielem=i+(NY-1)*NX+k*NX*NY;
                  elemToEdge(ielem,11) = iedge;
                  if (i > 0)
                    elemToEdge(ielem-1,10) = iedge;
                }
               else if (j < NY && i == NX){
                  ielem=NX-1+j*NX+k*NX*NY;
                  elemToEdge(ielem,9) = iedge;
                  if (j > 0)
                     elemToEdge(ielem-NX,10) = iedge;
                }
               iedge++;
            }
            inode++;
         }
      }
   }

   // Find boundary edges  
    FieldContainer<int> edgeOnBoundary(numEdges);
    for (int i=0; i<numEdges; i++){
       if (nodeOnBoundary(edgeToNode(i,0)) && nodeOnBoundary(edgeToNode(i,1))){
           edgeOnBoundary(i)=1;
       }
    }

   // Get face connectivity
    FieldContainer<int> faceToNode(numFaces, numNodesPerFace);
    FieldContainer<int> elemToFace(numElems, numFacesPerElem);
    FieldContainer<int> faceToEdge(numFaces, numEdgesPerFace);
    int iface = 0;
    inode = 0;
    for (int k=0; k<NZ+1; k++) {
      for (int j=0; j<NY+1; j++) {
        for (int i=0; i<NX+1; i++) {
           if (i < NX && k < NZ) {
              faceToNode(iface,0)=inode;
              faceToNode(iface,1)=inode + 1;
              faceToNode(iface,2)=inode + (NX+1)*(NY+1)+1;
              faceToNode(iface,3)=inode + (NX+1)*(NY+1);
              if (j < NY) {
                 ielem=i+j*NX+k*NX*NY;
                 faceToEdge(iface,0)=elemToEdge(ielem,0);
                 faceToEdge(iface,1)=elemToEdge(ielem,9);
                 faceToEdge(iface,2)=elemToEdge(ielem,4);
                 faceToEdge(iface,3)=elemToEdge(ielem,8);
                 elemToFace(ielem,0)=iface;
                 if (j > 0) {
                    elemToFace(ielem-NX,2)=iface;
                 }
              }
              else if (j == NY) {
                 ielem=i+(NY-1)*NX+k*NX*NY;
                 faceToEdge(iface,0)=elemToEdge(ielem,2);
                 faceToEdge(iface,1)=elemToEdge(ielem,10);
                 faceToEdge(iface,2)=elemToEdge(ielem,6);
                 faceToEdge(iface,3)=elemToEdge(ielem,11);
                 elemToFace(ielem,2)=iface;
              }
              iface++;
           }
           if (j < NY && k < NZ) {
              faceToNode(iface,0)=inode;
              faceToNode(iface,1)=inode + NX+1;
              faceToNode(iface,2)=inode + (NX+1)*(NY+1) + NX+1;
              faceToNode(iface,3)=inode + (NX+1)*(NY+1);
              if (i < NX) {
                 ielem=i+j*NX+k*NX*NY;
                 faceToEdge(iface,0)=elemToEdge(ielem,3);
                 faceToEdge(iface,1)=elemToEdge(ielem,11);
                 faceToEdge(iface,2)=elemToEdge(ielem,7);
                 faceToEdge(iface,3)=elemToEdge(ielem,8);
                 elemToFace(ielem,3)=iface;
                 if (i > 0) {
                    elemToFace(ielem-1,1)=iface;
                 }
              }
              else if (i == NX) {
                 ielem=NX-1+j*NX+k*NX*NY;
                 faceToEdge(iface,0)=elemToEdge(ielem,1);
                 faceToEdge(iface,1)=elemToEdge(ielem,10);
                 faceToEdge(iface,2)=elemToEdge(ielem,5);
                 faceToEdge(iface,3)=elemToEdge(ielem,9);
                 elemToFace(ielem,1)=iface;
              }
              iface++;
           }
           if (i < NX && j < NY) {
              faceToNode(iface,0)=inode;
              faceToNode(iface,1)=inode + 1;
              faceToNode(iface,2)=inode + NX+2;
              faceToNode(iface,3)=inode + NX+1;
              if (k < NZ) {
                 ielem=i+j*NX+k*NX*NY;
                 faceToEdge(iface,0)=elemToEdge(ielem,0);
                 faceToEdge(iface,1)=elemToEdge(ielem,1);
                 faceToEdge(iface,2)=elemToEdge(ielem,2);
                 faceToEdge(iface,3)=elemToEdge(ielem,3);
                 elemToFace(ielem,4)=iface;
                 if (k > 0) {
                    elemToFace(ielem-NX*NY,5)=iface;
                 }
              }
              else if (k == NZ) {
                 ielem=i+j*NX+(NZ-1)*NX*NY;
                 faceToEdge(iface,0)=elemToEdge(ielem,4);
                 faceToEdge(iface,1)=elemToEdge(ielem,5);
                 faceToEdge(iface,2)=elemToEdge(ielem,6);
                 faceToEdge(iface,3)=elemToEdge(ielem,7);
                 elemToFace(ielem,5)=iface;
              }
              iface++;
           }
          inode++;
         }
      }
   }

   // Find boundary faces  
    FieldContainer<int> faceOnBoundary(numFaces);
    for (int i=0; i<numFaces; i++){
       if (nodeOnBoundary(faceToNode(i,0)) && nodeOnBoundary(faceToNode(i,1))
          && nodeOnBoundary(faceToNode(i,2)) && nodeOnBoundary(faceToNode(i,3))){
           faceOnBoundary(i)=1;
       }
    }
        
 
#define DUMP_DATA
#ifdef DUMP_DATA
   // Output connectivity
    ofstream fe2nout("elem2node.dat");
    ofstream fe2eout("elem2edge.dat");
    for (int k=0; k<NZ; k++) {
      for (int j=0; j<NY; j++) {
        for (int i=0; i<NX; i++) {
          int ielem = i + j * NX + k * NX * NY;
          for (int m=0; m<numNodesPerElem; m++){
              fe2nout << elemToNode(ielem,m) <<"  ";
           }
          fe2nout <<"\n";
          for (int l=0; l<numEdgesPerElem; l++) {
             fe2eout << elemToEdge(ielem,l) << "  ";
          }
          fe2eout << "\n";
        }
      }
    }
    fe2nout.close();
    fe2eout.close();
#endif

#ifdef DUMP_DATA_EXTRA
    ofstream fed2nout("edge2node.dat");
    for (int i=0; i<numEdges; i++) {
       fed2nout << edgeToNode(i,0) <<" ";
       fed2nout << edgeToNode(i,1) <<"\n";
    }
    fed2nout.close();

    ofstream fBnodeout("nodeOnBndy.dat");
    ofstream fBedgeout("edgeOnBndy.dat");
    for (int i=0; i<numNodes; i++) {
        fBnodeout << nodeOnBoundary(i) <<"\n";
    }
    for (int i=0; i<numEdges; i++) {
        fBedgeout << edgeOnBoundary(i) <<"\n";
    }
    fBnodeout.close();
    fBedgeout.close();
#endif

   // Set material properties using undeformed grid assuming each element has only one value of mu
    FieldContainer<double> muVal(numElems);
    for (int k=0; k<NZ; k++) {
      for (int j=0; j<NY; j++) {
        for (int i=0; i<NX; i++) {
          int ielem = i + j * NX + k * NX * NY;
          double midElemX = nodeCoord(elemToNode(ielem,0),0) + hx/2.0;
          double midElemY = nodeCoord(elemToNode(ielem,0),1) + hy/2.0;
          double midElemZ = nodeCoord(elemToNode(ielem,0),2) + hz/2.0;
          if ( (midElemX > mu1LeftX) && (midElemY > mu1LeftY) && (midElemZ > mu1LeftZ) &&
               (midElemX <= mu1RightX) && (midElemY <= mu1RightY) && (midElemZ <= mu1RightZ) ){
             muVal(ielem) = mu1;
          }
           else {
             muVal(ielem) = mu2;
          }
        }
      }
    }

   // Perturb mesh coordinates (only interior nodes)
    if (randomMesh){
      for (int k=1; k<NZ; k++) {
        for (int j=1; j<NY; j++) {
          for (int i=1; i<NX; i++) {
            int inode = i + j * (NX + 1) + k * (NX + 1) * (NY + 1);
           // random numbers between -1.0 and 1.0
            double rx = 2.0 * (double)rand()/RAND_MAX - 1.0;
            double ry = 2.0 * (double)rand()/RAND_MAX - 1.0;
            double rz = 2.0 * (double)rand()/RAND_MAX - 1.0; 
           // limit variation to 1/4 edge length
            nodeCoord(inode,0) = nodeCoord(inode,0) + 0.125 * hx * rx;
            nodeCoord(inode,1) = nodeCoord(inode,1) + 0.125 * hy * ry;
            nodeCoord(inode,2) = nodeCoord(inode,2) + 0.125 * hz * rz;
          }
        }
      }
    }

#ifdef DUMP_DATA
   // Print nodal coords
    ofstream fcoordout("coords.dat");
    for (int i=0; i<numNodes; i++) {
       fcoordout << nodeCoord(i,0) <<" ";
       fcoordout << nodeCoord(i,1) <<" ";
       fcoordout << nodeCoord(i,2) <<"\n";
    }
    fcoordout.close();
#endif


// **************************** INCIDENCE MATRIX **************************************

   // Node to edge incidence matrix
    *outStream << "Building incidence matrix ... \n\n";

    Epetra_SerialComm Comm;
    Epetra_Map globalMapC(numEdges, 0, Comm);
    Epetra_Map globalMapG(numNodes, 0, Comm);
    Epetra_FECrsMatrix DGrad(Copy, globalMapC, globalMapG, 2);

    double vals[2];
    vals[0]=-1.0; vals[1]=1.0;
    for (int j=0; j<numEdges; j++){
        int rowNum = j;
        int colNum[2];
        colNum[0] = edgeToNode(j,0);
        colNum[1] = edgeToNode(j,1);
        DGrad.InsertGlobalValues(1, &rowNum, 2, colNum, vals);
    }


// ************************************ CUBATURE **************************************

   // Get numerical integration points and weights for element
    *outStream << "Getting cubature ... \n\n";

    DefaultCubatureFactory<double>  cubFactory;                                   
    int cubDegree = 2;
    Teuchos::RCP<Cubature<double> > hexCub = cubFactory.create(hex_8, cubDegree); 

    int cubDim       = hexCub->getDimension();
    int numCubPoints = hexCub->getNumPoints();

    FieldContainer<double> cubPoints(numCubPoints, cubDim);
    FieldContainer<double> cubWeights(numCubPoints);

    hexCub->getCubature(cubPoints, cubWeights);


   // Get numerical integration points and weights for hexahedron face
    //             (needed for rhs boundary term)

    // Define topology of the face parametrization domain as [-1,1]x[-1,1]
    CellTopology paramQuadFace(shards::getCellTopologyData<shards::Quadrilateral<4> >() );

    // Define cubature
    DefaultCubatureFactory<double>  cubFactoryFace;
    Teuchos::RCP<Cubature<double> > hexFaceCubature = cubFactoryFace.create(paramQuadFace, 3);
    int cubFaceDim    = hexFaceCubature -> getDimension();
    int numFacePoints = hexFaceCubature -> getNumPoints();

    // Define storage for cubature points and weights on [-1,1]x[-1,1]
    FieldContainer<double> paramGaussWeights(numFacePoints);
    FieldContainer<double> paramGaussPoints(numFacePoints,cubFaceDim);

    // Define storage for cubature points on workset faces
    hexFaceCubature -> getCubature(paramGaussPoints, paramGaussWeights);


// ************************************** BASIS ***************************************

   // Define basis 
    *outStream << "Getting basis ... \n\n";
    Basis_HCURL_HEX_I1_FEM<double, FieldContainer<double> > hexHCurlBasis;
    Basis_HGRAD_HEX_C1_FEM<double, FieldContainer<double> > hexHGradBasis;

    int numFieldsC = hexHCurlBasis.getCardinality();
    int numFieldsG = hexHGradBasis.getCardinality();

  // Evaluate basis at cubature points
     FieldContainer<double> hexGVals(numFieldsG, numCubPoints); 
     FieldContainer<double> hexCVals(numFieldsC, numCubPoints, spaceDim); 
     FieldContainer<double> hexCurls(numFieldsC, numCubPoints, spaceDim); 
     FieldContainer<double> worksetCVals(numFieldsC, numFacePoints, spaceDim);


     hexHCurlBasis.getValues(hexCVals, cubPoints, OPERATOR_VALUE);
     hexHCurlBasis.getValues(hexCurls, cubPoints, OPERATOR_CURL);
     hexHGradBasis.getValues(hexGVals, cubPoints, OPERATOR_VALUE);


// ******** LOOP OVER ELEMENTS TO CREATE LOCAL MASS and STIFFNESS MATRICES *************


    *outStream << "Building mass and stiffness matrices ... \n\n";

 // Settings and data structures for mass and stiffness matrices
    typedef CellTools<double>  CellTools;
    typedef FunctionSpaceTools fst;
    //typedef ArrayTools art;
    int numCells = 1; 

   // Containers for nodes and edge signs 
    FieldContainer<double> hexNodes(numCells, numNodesPerElem, spaceDim);
    FieldContainer<double> hexEdgeSigns(numCells, numFieldsC);
   // Containers for Jacobian
    FieldContainer<double> hexJacobian(numCells, numCubPoints, spaceDim, spaceDim);
    FieldContainer<double> hexJacobInv(numCells, numCubPoints, spaceDim, spaceDim);
    FieldContainer<double> hexJacobDet(numCells, numCubPoints);
   // Containers for element HGRAD mass matrix
    FieldContainer<double> massMatrixG(numCells, numFieldsG, numFieldsG);
    FieldContainer<double> weightedMeasure(numCells, numCubPoints);
    FieldContainer<double> weightedMeasureMuInv(numCells, numCubPoints);
    FieldContainer<double> hexGValsTransformed(numCells, numFieldsG, numCubPoints);
    FieldContainer<double> hexGValsTransformedWeighted(numCells, numFieldsG, numCubPoints);
   // Containers for element HCURL mass matrix
    FieldContainer<double> massMatrixC(numCells, numFieldsC, numFieldsC);
    FieldContainer<double> hexCValsTransformed(numCells, numFieldsC, numCubPoints, spaceDim);
    FieldContainer<double> hexCValsTransformedWeighted(numCells, numFieldsC, numCubPoints, spaceDim);
   // Containers for element HCURL stiffness matrix
    FieldContainer<double> stiffMatrixC(numCells, numFieldsC, numFieldsC);
    FieldContainer<double> weightedMeasureMu(numCells, numCubPoints);    
    FieldContainer<double> hexCurlsTransformed(numCells, numFieldsC, numCubPoints, spaceDim);
    FieldContainer<double> hexCurlsTransformedWeighted(numCells, numFieldsC, numCubPoints, spaceDim);
   // Containers for right hand side vectors
    FieldContainer<double> rhsDatag(numCells, numCubPoints, cubDim);
    FieldContainer<double> rhsDatah(numCells, numCubPoints, cubDim);
    FieldContainer<double> gC(numCells, numFieldsC);
    FieldContainer<double> hC(numCells, numFieldsC);
    FieldContainer<double> hCBoundary(numCells, numFieldsC);
    FieldContainer<double> refGaussPoints(numFacePoints,spaceDim);
    FieldContainer<double> worksetGaussPoints(numCells,numFacePoints,spaceDim);
    FieldContainer<double> worksetJacobians(numCells, numFacePoints, spaceDim, spaceDim);
    FieldContainer<double> worksetJacobInv(numCells, numFacePoints, spaceDim, spaceDim);
    FieldContainer<double> worksetFaceN(numCells, numFacePoints, spaceDim);
    FieldContainer<double> worksetFaceNweighted(numCells, numFacePoints, spaceDim);
    FieldContainer<double> worksetVFieldVals(numCells, numFacePoints, spaceDim);
    FieldContainer<double> worksetCValsTransformed(numCells, numFieldsC, numFacePoints, spaceDim);
    FieldContainer<double> divuFace(numCells, numFacePoints);
    FieldContainer<double> worksetFieldDotNormal(numCells, numFieldsC, numFacePoints);
   // Container for cubature points in physical space
    FieldContainer<double> physCubPoints(numCells,numCubPoints, cubDim);

    
   // Global arrays in Epetra format
    Epetra_FECrsMatrix MassG(Copy, globalMapG, numFieldsG);
    Epetra_FECrsMatrix MassC(Copy, globalMapC, numFieldsC);
    Epetra_FECrsMatrix StiffC(Copy, globalMapC, numFieldsC);
    Epetra_FEVector rhsC(globalMapC);

#ifdef DUMP_DATA
    ofstream fSignsout("edgeSigns.dat");
#endif

 // *** Element loop ***
    for (int k=0; k<numElems; k++) {

     // Physical cell coordinates
      for (int i=0; i<numNodesPerElem; i++) {
         hexNodes(0,i,0) = nodeCoord(elemToNode(k,i),0);
         hexNodes(0,i,1) = nodeCoord(elemToNode(k,i),1);
         hexNodes(0,i,2) = nodeCoord(elemToNode(k,i),2);
      }

     // Edge signs
      for (int j=0; j<numEdgesPerElem; j++) {
          if (elemToNode(k,refEdgeToNode(j,0))==edgeToNode(elemToEdge(k,j),0) &&
              elemToNode(k,refEdgeToNode(j,1))==edgeToNode(elemToEdge(k,j),1))
              hexEdgeSigns(0,j) = 1.0;
          else 
              hexEdgeSigns(0,j) = -1.0;
#ifdef DUMP_DATA
          fSignsout << hexEdgeSigns(0,j) << "  ";
#endif
      }
#ifdef DUMP_DATA
       fSignsout << "\n";
#endif

    // Compute cell Jacobians, their inverses and their determinants
       CellTools::setJacobian(hexJacobian, cubPoints, hexNodes, hex_8);
       CellTools::setJacobianInv(hexJacobInv, hexJacobian );
       CellTools::setJacobianDet(hexJacobDet, hexJacobian );

// ************************** Compute element HGrad mass matrices *******************************
  
     // transform to physical coordinates 
      fst::HGRADtransformVALUE<double>(hexGValsTransformed, hexGVals);
      
     // compute weighted measure
      fst::computeCellMeasure<double>(weightedMeasure, hexJacobDet, cubWeights);

      // combine mu value with weighted measure
      for (int nC = 0; nC < numCells; nC++){
        for (int nPt = 0; nPt < numCubPoints; nPt++){
          weightedMeasureMuInv(nC,nPt) = weightedMeasure(nC,nPt) / muVal(k);
        }
      }
      
     // multiply values with weighted measure
      fst::multiplyMeasure<double>(hexGValsTransformedWeighted,
                                   weightedMeasureMuInv, hexGValsTransformed);

     // integrate to compute element mass matrix
      fst::integrate<double>(massMatrixG,
                             hexGValsTransformed, hexGValsTransformedWeighted, COMP_CPP);

      // assemble into global matrix
    //  int err = 0;
      for (int row = 0; row < numFieldsG; row++){
        for (int col = 0; col < numFieldsG; col++){
            int rowIndex = elemToNode(k,row);
            int colIndex = elemToNode(k,col);
            double val = massMatrixG(0,row,col);
            MassG.InsertGlobalValues(1, &rowIndex, 1, &colIndex, &val);
         }
      }

// ************************** Compute element HCurl mass matrices *******************************

     // transform to physical coordinates 
      fst::HCURLtransformVALUE<double>(hexCValsTransformed, hexJacobInv, 
                                   hexCVals);

     // multiply by weighted measure
      fst::multiplyMeasure<double>(hexCValsTransformedWeighted,
                                   weightedMeasure, hexCValsTransformed);

     // integrate to compute element mass matrix
      fst::integrate<double>(massMatrixC,
                             hexCValsTransformed, hexCValsTransformedWeighted,
                             COMP_CPP);

     // apply edge signs
      fst::applyLeftFieldSigns<double>(massMatrixC, hexEdgeSigns);
      fst::applyRightFieldSigns<double>(massMatrixC, hexEdgeSigns);


     // assemble into global matrix
      //err = 0;
      for (int row = 0; row < numFieldsC; row++){
        for (int col = 0; col < numFieldsC; col++){
            int rowIndex = elemToEdge(k,row);
            int colIndex = elemToEdge(k,col);
            double val = massMatrixC(0,row,col);
            MassC.InsertGlobalValues(1, &rowIndex, 1, &colIndex, &val);
         }
      }

// ************************ Compute element HCurl stiffness matrices *****************************

      // transform to physical coordinates 
      fst::HCURLtransformCURL<double>(hexCurlsTransformed, hexJacobian, hexJacobDet, 
                                       hexCurls);

      // combine mu value with weighted measure
      for (int nC = 0; nC < numCells; nC++){
        for (int nPt = 0; nPt < numCubPoints; nPt++){
          weightedMeasureMu(nC,nPt) = weightedMeasure(nC,nPt) / muVal(k);
         }
      }

     // multiply by weighted measure
      fst::multiplyMeasure<double>(hexCurlsTransformedWeighted,
                                   weightedMeasureMu, hexCurlsTransformed);

     // integrate to compute element stiffness matrix
      fst::integrate<double>(stiffMatrixC,
                             hexCurlsTransformed, hexCurlsTransformedWeighted,
                             COMP_CPP);

     // apply edge signs
     fst::applyLeftFieldSigns<double>(stiffMatrixC, hexEdgeSigns);
     fst::applyRightFieldSigns<double>(stiffMatrixC, hexEdgeSigns);

     // assemble into global matrix
      //err = 0;
      for (int row = 0; row < numFieldsC; row++){
        for (int col = 0; col < numFieldsC; col++){
            int rowIndex = elemToEdge(k,row);
            int colIndex = elemToEdge(k,col);
            double val = stiffMatrixC(0,row,col);
            StiffC.InsertGlobalValues(1, &rowIndex, 1, &colIndex, &val);
         }
      }

// ******************************* Build right hand side ************************************

      // transform integration points to physical points
       FieldContainer<double> physCubPoints(numCells,numCubPoints, cubDim);
       CellTools::mapToPhysicalFrame(physCubPoints, cubPoints, hexNodes, hex_8);

      // evaluate right hand side functions at physical points
       FieldContainer<double> rhsDatag(numCells, numCubPoints, cubDim);
       FieldContainer<double> rhsDatah(numCells, numCubPoints, cubDim);
       for (int nPt = 0; nPt < numCubPoints; nPt++){

          double x = physCubPoints(0,nPt,0);
          double y = physCubPoints(0,nPt,1);
          double z = physCubPoints(0,nPt,2);
          double du1, du2, du3;

          evalCurlu(du1, du2, du3, x, y, z);
          rhsDatag(0,nPt,0) = du1;
          rhsDatag(0,nPt,1) = du2;
          rhsDatag(0,nPt,2) = du3;
         
          evalGradDivu(du1, du2, du3,  x, y, z);
          rhsDatah(0,nPt,0) = du1;
          rhsDatah(0,nPt,1) = du2;
          rhsDatah(0,nPt,2) = du3;
       }

     // integrate (g,curl w) term
      fst::integrate<double>(gC, rhsDatag, hexCurlsTransformedWeighted,
                             COMP_CPP);

     // integrate -(grad h, w)  
      fst::integrate<double>(hC, rhsDatah, hexCValsTransformedWeighted,
                             COMP_CPP);

     // apply signs
      fst::applyFieldSigns<double>(gC, hexEdgeSigns);
      fst::applyFieldSigns<double>(hC, hexEdgeSigns);


     // calculate boundary term, (h*w, n)_{\Gamma} 
      for (int i = 0; i < numFacesPerElem; i++){
        if (faceOnBoundary(elemToFace(k,i))){

         // Map Gauss points on quad to reference face: paramGaussPoints -> refGaussPoints
            CellTools::mapToReferenceSubcell(refGaussPoints,
                                   paramGaussPoints,
                                   2, i, hex_8);

         // Get basis values at points on reference cell
           hexHCurlBasis.getValues(worksetCVals, refGaussPoints, OPERATOR_VALUE);

         // Compute Jacobians at Gauss pts. on reference face for all parent cells
           CellTools::setJacobian(worksetJacobians,
                         refGaussPoints,
                         hexNodes, hex_8);
           CellTools::setJacobianInv(worksetJacobInv, worksetJacobians );

         // transform to physical coordinates
            fst::HCURLtransformVALUE<double>(worksetCValsTransformed, worksetJacobInv,
                                   worksetCVals);

         // Map Gauss points on quad from ref. face to face workset: refGaussPoints -> worksetGaussPoints
            CellTools::mapToPhysicalFrame(worksetGaussPoints,
                                refGaussPoints,
                                hexNodes, hex_8);

         // Compute face normals
            CellTools::getPhysicalFaceNormals(worksetFaceN,
                                              worksetJacobians,
                                              i, hex_8);

         // multiply with weights
            for(int nPt = 0; nPt < numFacePoints; nPt++){
                for (int dim = 0; dim < spaceDim; dim++){
                   worksetFaceNweighted(0,nPt,dim) = worksetFaceN(0,nPt,dim) * paramGaussWeights(nPt);
                } //dim
             } //nPt

            fst::dotMultiplyDataField<double>(worksetFieldDotNormal, worksetFaceNweighted, 
                                               worksetCValsTransformed);

         // Evaluate div u at face points
           for(int nPt = 0; nPt < numFacePoints; nPt++){

             double x = worksetGaussPoints(0, nPt, 0);
             double y = worksetGaussPoints(0, nPt, 1);
             double z = worksetGaussPoints(0, nPt, 2);

             divuFace(0,nPt)=evalDivu(x, y, z);
           }

          // Integrate
          fst::integrate<double>(hCBoundary, divuFace, worksetFieldDotNormal,
                             COMP_CPP);

          // apply signs
           fst::applyFieldSigns<double>(hCBoundary, hexEdgeSigns);

         // add into hC term
            for (int nF = 0; nF < numFieldsC; nF++){
                hC(0,nF) = hC(0,nF) - hCBoundary(0,nF);
            }

        } // if faceOnBoundary
      } // numFaces


    // assemble into global vector
     for (int row = 0; row < numFieldsC; row++){
           int rowIndex = elemToEdge(k,row);
           double val = gC(0,row)-hC(0,row);
           rhsC.SumIntoGlobalValues(1, &rowIndex, &val);
     }
 
     
 } // *** end element loop ***

#ifdef DUMP_DATA
   fSignsout.close();
#endif

  // Assemble over multiple processors, if necessary
   MassG.GlobalAssemble();  MassG.FillComplete();
   MassC.GlobalAssemble();  MassC.FillComplete();
   StiffC.GlobalAssemble(); StiffC.FillComplete();
   rhsC.GlobalAssemble();
   DGrad.GlobalAssemble(); DGrad.FillComplete(MassG.RowMap(),MassC.RowMap());


  // Build the inverse diagonal for MassG
   Epetra_CrsMatrix MassGinv(Copy,MassG.RowMap(),MassG.RowMap(),1);
   Epetra_Vector DiagG(MassG.RowMap());

   DiagG.PutScalar(1.0);
   MassG.Multiply(false,DiagG,DiagG);
   for(int i=0; i<DiagG.MyLength(); i++) {
     DiagG[i]=1.0/DiagG[i];
   }
   for(int i=0; i<DiagG.MyLength(); i++) {
     int CID=MassG.GCID(i);
     MassGinv.InsertGlobalValues(MassG.GRID(i),1,&(DiagG[i]),&CID);
   }
   MassGinv.FillComplete();

  // Set value to zero on diagonal that cooresponds to boundary node
   for(int i=0;i<numNodes;i++) {
     if (nodeOnBoundary(i)){
      double val=0.0;
      MassGinv.ReplaceGlobalValues(i,1,&val,&i);
     }
   }

    int numEntries;
    double *values;
    int *cols;
  
  // Adjust matrices and rhs due to boundary conditions
   for (int row = 0; row<numEdges; row++){
      MassC.ExtractMyRowView(row,numEntries,values,cols);
        for (int i=0; i<numEntries; i++){
           if (edgeOnBoundary(cols[i])) {
             values[i]=0;
          }
       }
      StiffC.ExtractMyRowView(row,numEntries,values,cols);
        for (int i=0; i<numEntries; i++){
           if (edgeOnBoundary(cols[i])) {
             values[i]=0;
          }
       }
    }
   for (int row = 0; row<numEdges; row++){
       if (edgeOnBoundary(row)) {
          int rowindex = row;
          StiffC.ExtractMyRowView(row,numEntries,values,cols);
          for (int i=0; i<numEntries; i++){
             values[i]=0;
          }
          MassC.ExtractMyRowView(row,numEntries,values,cols);
          for (int i=0; i<numEntries; i++){
             values[i]=0;
          }
         rhsC[0][row]=0;
         double val = 1.0;
         StiffC.ReplaceGlobalValues(1, &rowindex, 1, &rowindex, &val);
       }
    }


#ifdef DUMP_DATA
  // Dump matrices to disk
   EpetraExt::RowMatrixToMatlabFile("mag_m0inv_matrix.dat",MassGinv);
   EpetraExt::RowMatrixToMatlabFile("mag_m1_matrix.dat",MassC);
   EpetraExt::RowMatrixToMatlabFile("mag_k1_matrix.dat",StiffC);
   EpetraExt::RowMatrixToMatlabFile("mag_t0_matrix.dat",DGrad);
   EpetraExt::MultiVectorToMatrixMarketFile("mag_rhs1_vector.dat",rhsC,0,0,false);
   fSignsout.close();
#endif


   std::cout << "End Result: TEST PASSED\n";

 // reset format state of std::cout
 std::cout.copyfmt(oldFormatState);
 
 return 0;
}
Example #13
0
int main(int argc, char *argv[]) {

  Teuchos::GlobalMPISession mpiSession(&argc, &argv);

  typedef CellTools<double>       CellTools;
  typedef RealSpaceTools<double>  RealSpaceTools;
  typedef shards::CellTopology    CellTopology;

 std::cout \
  << "===============================================================================\n" \
  << "|                                                                             |\n" \
  << "|                   Example use of the CellTools class                        |\n" \
  << "|                                                                             |\n" \
  << "|  1) Computation of face flux, for a given vector field, on a face workset   |\n" \
  << "|  2) Computation of edge circulation, for a given vector field, on a face    |\n" \
  << "|     workset.                                                                |\n" \
  << "|                                                                             |\n" \
  << "|  Questions? Contact  Pavel Bochev ([email protected])                      |\n" \
  << "|                      Denis Ridzal ([email protected]), or                  |\n" \
  << "|                      Kara Peterson ([email protected])                     |\n" \
  << "|                                                                             |\n" \
  << "|  Intrepid's website: http://trilinos.sandia.gov/packages/intrepid           |\n" \
  << "|  Trilinos website:   http://trilinos.sandia.gov                             |\n" \
  << "|                                                                             |\n" \
  << "===============================================================================\n"\
  << "|  EXAMPLE 1: Computation of face flux on a face workset                      |\n"\
  << "===============================================================================\n";

  
  /**  Given a vector field u(x,y,z) and a face workset we want to compute the flux of u on every
    *  face in this workset. A face workset is a set of faces that are images of the same reference
    *  face. It is defined by the following items:
    *    1. cell topology of a parent cell
    *    2. a set of nodes in physical frame defining the parenct cells in the workset
    *    3. subcell dimension and ordinal, relative to the reference cell in 1)
    *
    *  Given a face workset, the key steps to accomplish the task, , are as follows:
    *    1. Obtain cubature points on workset faces, i.e., in physical frame;
    *    2. Obtain (non-normalized) face normals at cubature points on workset faces
    *    3. Evaluate the vector field u(x,y,z) at cubature points on workset faces
    *    4. Compute dot product of u(x,y,z) and the face normals, times the cubature weights
    */
  
  /*************************************************************************************************
    *
    *  Step 0. Face workset comprising of 1 face of a Hexahedron<8> cell
    *
    ************************************************************************************************/
  
  //   Step 0.a: Specify cell topology of the parent cell
  CellTopology hexahedron_8( shards::getCellTopologyData<shards::Hexahedron<8> >() );
  
  //   Step 0.b: Specify the vertices of the parent Hexahedron<8> cell
  int worksetSize    = 2;
  int pCellNodeCount = hexahedron_8.getVertexCount();
  int pCellDim       = hexahedron_8.getDimension();
  
  FieldContainer<double> hexNodes(worksetSize, pCellNodeCount, pCellDim);
  // cell 0 bottom face vertices:
  hexNodes(0, 0, 0) = 0.00;   hexNodes(0, 0, 1) = 0.00,   hexNodes(0, 0, 2) = 0.00;          
  hexNodes(0, 1, 0) = 1.00;   hexNodes(0, 1, 1) = 0.00,   hexNodes(0, 1, 2) = 0.00;
  hexNodes(0, 2, 0) = 1.00;   hexNodes(0, 2, 1) = 1.00,   hexNodes(0, 2, 2) = 0.00;
  hexNodes(0, 3, 0) = 0.00;   hexNodes(0, 3, 1) = 1.00,   hexNodes(0, 3, 2) = 0.00;
  // cell 0 top face vertices
  hexNodes(0, 4, 0) = 0.00;   hexNodes(0, 4, 1) = 0.00,   hexNodes(0, 4, 2) = 1.00;          
  hexNodes(0, 5, 0) = 1.00;   hexNodes(0, 5, 1) = 0.00,   hexNodes(0, 5, 2) = 1.00;
  hexNodes(0, 6, 0) = 1.00;   hexNodes(0, 6, 1) = 1.00,   hexNodes(0, 6, 2) = 1.00;
  hexNodes(0, 7, 0) = 0.00;   hexNodes(0, 7, 1) = 1.00,   hexNodes(0, 7, 2) = 1.00;
  
  // cell 1 bottom face vertices:
  hexNodes(1, 0, 0) = 0.00;   hexNodes(1, 0, 1) = 0.00,   hexNodes(1, 0, 2) = 0.00;          
  hexNodes(1, 1, 0) = 1.00;   hexNodes(1, 1, 1) = 0.00,   hexNodes(1, 1, 2) = 0.00;
  hexNodes(1, 2, 0) = 1.00;   hexNodes(1, 2, 1) = 1.00,   hexNodes(1, 2, 2) = 0.00;
  hexNodes(1, 3, 0) = 0.00;   hexNodes(1, 3, 1) = 1.00,   hexNodes(1, 3, 2) = 0.00;
  // cell 1 top face vertices
  hexNodes(1, 4, 0) = 0.00;   hexNodes(1, 4, 1) = 0.00,   hexNodes(1, 4, 2) = 1.00;          
  hexNodes(1, 5, 0) = 1.00;   hexNodes(1, 5, 1) = 0.00,   hexNodes(1, 5, 2) = 1.00;
  hexNodes(1, 6, 0) = 1.00;   hexNodes(1, 6, 1) = 1.00,   hexNodes(1, 6, 2) = 0.75;
  hexNodes(1, 7, 0) = 0.00;   hexNodes(1, 7, 1) = 1.00,   hexNodes(1, 7, 2) = 1.00;
  
  
  //   Step 0.c: Specify the face ordinal, relative to the reference cell, of the face workset
  int subcellDim = 2;
  int subcellOrd = 1;  
  
  
  
  /*************************************************************************************************
    *
    *  Step 1:    Obtain Gauss points on workset faces for Hexahedron<8> topology
    *       1.1   Define cubature factory, face parametrization domain and arrays for cubature points
    *       1.2   Select Gauss rule on D = [-1,1]x[-1,1] 
    *       1.3   Map Gauss points from D to reference face and workset faces
    *
    ************************************************************************************************/
  
  //   Step 1.1.a: Define CubatureFactory
  DefaultCubatureFactory<double>  cubFactory;   
  
  //   Step 1.1.b: Define topology of the face parametrization domain as [-1,1]x[-1,1]
  CellTopology paramQuadFace(shards::getCellTopologyData<shards::Quadrilateral<4> >() );
  
  //   Step 1.1.c: Define storage for cubature points and weights on [-1,1]x[-1,1]
  FieldContainer<double> paramGaussWeights;
  FieldContainer<double> paramGaussPoints;
  
  //   Step 1.1.d: Define storage for cubature points on a reference face
  FieldContainer<double> refGaussPoints;
  
  //   Step 1.1.f: Define storage for cubature points on workset faces
  FieldContainer<double> worksetGaussPoints;

  //----------------
  
  //   Step 1.2.a: selects Gauss rule of order 3 on [-1,1]x[-1,1]
  Teuchos::RCP<Cubature<double> > hexFaceCubature = cubFactory.create(paramQuadFace, 3); 
  
  //   Step 1.2.b allocate storage for cubature points on [-1,1]x[-1,1]
  int cubDim       = hexFaceCubature -> getDimension();
  int numCubPoints = hexFaceCubature -> getNumPoints();
  
  // Arrays must be properly sized for the specified set of Gauss points
  paramGaussPoints.resize(numCubPoints, cubDim);
  paramGaussWeights.resize(numCubPoints);
  hexFaceCubature -> getCubature(paramGaussPoints, paramGaussWeights);
  
  //----------------
  
  //   Step 1.3.a: Allocate storage for Gauss points on the reference face
  refGaussPoints.resize(numCubPoints, pCellDim);

  //   Step 1.3.b: Allocate storage for Gauss points on the face in the workset
  worksetGaussPoints.resize(worksetSize, numCubPoints, pCellDim);

  //   Step 1.3.c: Map Gauss points to reference face: paramGaussPoints -> refGaussPoints
  CellTools::mapToReferenceSubcell(refGaussPoints,
                                   paramGaussPoints,
                                   subcellDim,                      
                                   subcellOrd,
                                   hexahedron_8);

  //   Step 1.3.d: Map Gauss points from ref. face to face workset: refGaussPoints -> worksetGaussPoints
  CellTools::mapToPhysicalFrame(worksetGaussPoints,
                                refGaussPoints,
                                hexNodes,
                                hexahedron_8);
  
  
  
  /*************************************************************************************************
    *
    *  Step 2.   Obtain (non-normalized) face normals at cubature points on workset faces
    *       2.1  Compute parent cell Jacobians at Gauss points on workset faces
    *       2.2  Compute face tangents on workset faces and their vector product
    *
    ************************************************************************************************/
  
  //   Step 2.1.a: Define and allocate storage for workset Jacobians
  FieldContainer<double> worksetJacobians(worksetSize, numCubPoints, pCellDim, pCellDim);
  
  //   Step 2.1.b: Compute Jacobians at Gauss pts. on reference face for all parent cells:
  CellTools::setJacobian(worksetJacobians,
                         refGaussPoints,
                         hexNodes,
                         hexahedron_8);
  
  //----------------
  
  //   Step 2.2.a: Allocate storage for face tangents and face normals
  FieldContainer<double> worksetFaceTu(worksetSize, numCubPoints, pCellDim);
  FieldContainer<double> worksetFaceTv(worksetSize, numCubPoints, pCellDim);
  FieldContainer<double> worksetFaceN(worksetSize, numCubPoints, pCellDim);
  
  //   Step 2.2.b: Compute face tangents
  CellTools::getPhysicalFaceTangents(worksetFaceTu,
                                     worksetFaceTv,
                                     worksetJacobians,
                                     subcellOrd,
                                     hexahedron_8);
  
  //   Step 2.2.c: Face outer normals (relative to parent cell) are uTan x vTan:
  RealSpaceTools::vecprod(worksetFaceN, worksetFaceTu, worksetFaceTv);
  
  
  
  /*************************************************************************************************
    *
    *  Step 3.   Evaluate the vector field u(x,y,z) at cubature points on workset faces
    *
    ************************************************************************************************/
  
  //   Step 3.a:  Allocate storage for vector field values at Gauss points on workset faces
  FieldContainer<double> worksetVFieldVals(worksetSize, numCubPoints, pCellDim);
  
  //   Step 3.b:  Compute vector field at Gauss points: here we take u(x,y,z) = (x,y,z)
  for(int pCellOrd = 0; pCellOrd < worksetSize; pCellOrd++){
    for(int ptOrd = 0; ptOrd < numCubPoints; ptOrd++){
      
      double x = worksetGaussPoints(pCellOrd, ptOrd, 0);
      double y = worksetGaussPoints(pCellOrd, ptOrd, 1);
      double z = worksetGaussPoints(pCellOrd, ptOrd, 2);

      vField(worksetVFieldVals(pCellOrd, ptOrd, 0), 
             worksetVFieldVals(pCellOrd, ptOrd, 1), 
             worksetVFieldVals(pCellOrd, ptOrd, 2),  x, y, z);
      
    }// pt
  }//cell
  

  /*************************************************************************************************
    *
    *  Step 4.   Compute dot product of u(x,y,z) and the face normals, times the cubature weights
    *
    ************************************************************************************************/
  
  // Allocate storage for dot product of vector field and face normals at Gauss points
  FieldContainer<double> worksetFieldDotNormal(worksetSize, numCubPoints);
  
  // Compute the dot product
  RealSpaceTools::dot(worksetFieldDotNormal, worksetVFieldVals, worksetFaceN);
  
  // Allocate storage for face fluxes on the workset
  FieldContainer<double> worksetFluxes(worksetSize);
  
  //----------------
  
  // Integration loop (temporary)
  for(int pCellOrd = 0; pCellOrd < worksetSize; pCellOrd++){
    worksetFluxes(pCellOrd) = 0.0;
    for(int pt = 0; pt < numCubPoints; pt++ ){
      worksetFluxes(pCellOrd) += worksetFieldDotNormal(pCellOrd, pt)*paramGaussWeights(pt);
    }// pt
  }//cell
  
  std::cout << "Face fluxes on workset faces : \n\n";
  for(int pCellOrd = 0; pCellOrd < worksetSize; pCellOrd++){
    
    CellTools::printWorksetSubcell(hexNodes, hexahedron_8, pCellOrd, subcellDim, subcellOrd);
    std::cout << " Flux = " << worksetFluxes(pCellOrd) << "\n\n";
    
  }
  
  
  
  /*************************************************************************************************
    *
    *  Optional: print Gauss points and face normals at Gauss points
    *
    ************************************************************************************************/

  // Print Gauss points on [-1,1]x[-1,1] and their images on workset faces
  std::cout \
    << "===============================================================================\n" \
    << "|                        Gauss points on workset faces:                       |\n" \
    << "===============================================================================\n";
  for(int pCell = 0; pCell < worksetSize; pCell++){
    
    CellTools::printWorksetSubcell(hexNodes, hexahedron_8, pCell, subcellDim, subcellOrd);
    
    for(int pt = 0; pt < numCubPoints; pt++){
      std::cout << "\t 2D Gauss point (" 
      << std::setw(8) << std::right <<  paramGaussPoints(pt, 0) << ", "
      << std::setw(8) << std::right <<  paramGaussPoints(pt, 1) << ")  " 
      << std::setw(8) << " -->  " << "(" 
      << std::setw(8) << std::right << worksetGaussPoints(pCell, pt, 0) << ", " 
      << std::setw(8) << std::right << worksetGaussPoints(pCell, pt, 1) << ", " 
      << std::setw(8) << std::right << worksetGaussPoints(pCell, pt, 2) << ")\n";
    }    
    std::cout << "\n\n";      
  }//pCell
  
  
  // Print face normals at Gauss points on workset faces
  std::cout \
    << "===============================================================================\n" \
    << "|          Face normals (non-unit) at Gauss points on workset faces:          |\n" \
    << "===============================================================================\n";
  for(int pCell = 0; pCell < worksetSize; pCell++){
    
    CellTools::printWorksetSubcell(hexNodes, hexahedron_8, pCell, subcellDim, subcellOrd);
    
    for(int pt = 0; pt < numCubPoints; pt++){
      std::cout << "\t 3D Gauss point: (" 
      << std::setw(8) << std::right << worksetGaussPoints(pCell, pt, 0) << ", " 
      << std::setw(8) << std::right << worksetGaussPoints(pCell, pt, 1) << ", " 
      << std::setw(8) << std::right << worksetGaussPoints(pCell, pt, 2) << ")" 
      << std::setw(8) << " out. normal:  " << "(" 
      << std::setw(8) << std::right << worksetFaceN(pCell, pt, 0) << ", " 
      << std::setw(8) << std::right << worksetFaceN(pCell, pt, 1) << ", " 
      << std::setw(8) << std::right << worksetFaceN(pCell, pt, 2) << ")\n";
    }    
    std::cout << "\n";      
  }//pCell
  
  return 0;
}
Example #14
0
int main(int argc, char *argv[]) {

  Teuchos::GlobalMPISession mpiSession(&argc, &argv);

  typedef CellTools<double>       CellTools;
  typedef shards::CellTopology    CellTopology;
  
  cout \
  << "===============================================================================\n" \
  << "|                                                                             |\n" \
  << "|                   Example use of the CellTools class                        |\n" \
  << "|                                                                             |\n" \
  << "|  1) Reference edge parametrizations                                         |\n" \
  << "|  2) Reference face parametrizations                                         |\n" \
  << "|                                                                             |\n" \
  << "|  Questions? Contact  Pavel Bochev ([email protected])                      |\n" \
  << "|                      Denis Ridzal ([email protected]), or                  |\n" \
  << "|                      Kara Peterson ([email protected]).                    |\n" \
  << "|                                                                             |\n" \
  << "|  Intrepid's website: http://trilinos.sandia.gov/packages/intrepid           |\n" \
  << "|  Trilinos website:   http://trilinos.sandia.gov                             |\n" \
  << "|                                                                             |\n" \
  << "===============================================================================\n"\
  << "| Summary:                                                                    |\n"\
  << "| Reference edge parametrizations map [-1,1] to the edges of reference cells. |\n"\
  << "| They are used to define, e.g., integration points on the edges of 2D and 3D |\n"\
  << "| reference cells. Edge parametrizations for special 2D  cells such as Beam   |\n"\
  << "| and ShellLine, are also supported.                                          |\n"\
  << "===============================================================================\n";
 
  /* 
    Specification of integration points on 1-subcells (edges) of reference cells. Edges are 
    parametrized by [-1,1] and integration points on an edge are defined by mapping integration
    points from the parametrization domain [-1,1] to a specific edge on the reference cell.
   
   1. Common tasks: definition of integration points in the edge parametrization domain [-1,1]
      These steps are independent of parent cell topology:
   
      a. Instantiate a CubatureFactory object to create cubatures (needed for face maps too)
      b. Define parametrization domain for the edges as having Line<2> cell topology. This is 
         required by the CubatureFactory in order to select cubature points and weights from 
         the reference line [-1,1]
      c. Use CubatureFactory to select cubature of the desired degree for the Line<2> topology
      d. Allocate containers for the cubature points and weights.
   
   2. Parent cell topology specific tasks
   
      a. Select the parent cell topology
      b. Allocate containers for the images of the integration points on [-1,1] on the edges
      c. Apply the edge parametrization map to the pointss in [-1,1]
   */
  
  // Step 1.a (Define CubatureFactory)
  DefaultCubatureFactory<double>  cubFactory;   
  
  
  // Step 1.b (Define the topology of the parametrization domain)
  CellTopology edgeParam(shards::getCellTopologyData<shards::Line<2> >() );
  
  
  // Step 1.c (selects Gauss rule of order 6 on [-1,1]) 
  Teuchos::RCP<Cubature<double> > edgeParamCubature = cubFactory.create(edgeParam, 6); 
  
  
  // Step 1.d (allocate storage for cubature points)
  int cubDim       = edgeParamCubature -> getDimension();
  int numCubPoints = edgeParamCubature -> getNumPoints();
  
  FieldContainer<double> edgeParamCubPts(numCubPoints, cubDim);
  FieldContainer<double> edgeParamCubWts(numCubPoints);
  edgeParamCubature -> getCubature(edgeParamCubPts, edgeParamCubWts);
    
  
  
  std::cout \
  << "===============================================================================\n"\
  << "| EXAMPLE 1.1                                                                 |\n"
  << "| Edge parametrizations for standard 2D cells: Triangle                       |\n"\
  << "===============================================================================\n";
    
  // Step 2.a (select reference cell topology)
  CellTopology triangle_3(getCellTopologyData<Triangle<3> >() );
  
  
  // Step 2.b (allocate storage for points on an edge of the reference cell)
  FieldContainer<double> triEdgePoints(numCubPoints, triangle_3.getDimension() );
    
  
  // Step 2.c (same points are mapped to all edges, can also map different set to each edge) 
  for(int edgeOrd = 0; edgeOrd < (int)triangle_3.getEdgeCount(); edgeOrd++){
    
    CellTools::mapToReferenceSubcell(triEdgePoints, 
                                     edgeParamCubPts,
                                     1,
                                     edgeOrd,
                                     triangle_3);
    
    // Optional: print the vertices of the reference edge
    CellTools::printSubcellVertices(1, edgeOrd, triangle_3);
        
    for(int pt = 0; pt < numCubPoints; pt++){
      std::cout << "\t Parameter point " 
      << std::setw(12) << std::right << edgeParamCubPts(pt, 0) << std::setw(10) << "  -->  " << "(" 
      << std::setw(10) << std::right << triEdgePoints(pt, 0) << " , " 
      << std::setw(10) << std::right << triEdgePoints(pt, 1) << ")\n";
    }    
    std::cout << "\n";
  }
  
  
  
  std::cout \
    << "===============================================================================\n"\
    << "| EXAMPLE 1.2                                                                 |\n"
    << "| Edge parametrizations for standard 2D cells: Quadrilateral                  |\n"\
    << "===============================================================================\n";
  
  // Step 2.a (select reference cell topology)
  CellTopology quad_4(getCellTopologyData<Quadrilateral<4> >() );
  
  
  // Step 2.b (allocate storage for points on an edge of the reference cell)
  FieldContainer<double> quadEdgePoints(numCubPoints, quad_4.getDimension() );
  
  
  // Step 2.c (same points are mapped to all edges, can also map different set to each edge) 
  for(int edgeOrd = 0; edgeOrd < (int)quad_4.getEdgeCount(); edgeOrd++){
    
    CellTools::mapToReferenceSubcell(quadEdgePoints, 
                                     edgeParamCubPts,
                                     1,
                                     edgeOrd,
                                     quad_4);
    
    // Optional: print the vertices of the reference edge
    CellTools::printSubcellVertices(1, edgeOrd, quad_4);
    
    for(int pt = 0; pt < numCubPoints; pt++){
      std::cout << "\t Parameter point " 
      << std::setw(12) << std::right << edgeParamCubPts(pt, 0) << std::setw(10) << "  -->  " << "(" 
      << std::setw(10) << std::right << quadEdgePoints(pt, 0) << " , " 
      << std::setw(10) << std::right << quadEdgePoints(pt, 1) << ")\n";
    }    
    std::cout << "\n";
  }
  
  
  /* 
    Specification of integration points on 2-subcells (faces) of reference cells. Reference cells
    can have triangular, quadrilateral or a mixture of triangular and quadrilateral faces. Thus,
    parametrization domain of a face depends on that face's topology and is either the standard 
    2-simplex {(0,0), (1,0), (0,1)} for triangular faces or the standard 2-cube [-1,1]^2 for 
    quadrilateral faces. 
      
   1. Common tasks: definition of integration points in the standard 2-simplex and the standard
      2-cube. These steps are independent of parent cell topology:
   
      a. Instantiate a CubatureFactory object to create cubatures (already done!)
      b. Define parametrization domain for traingular faces as having Triangle<3> topology and for
         quadrilateral faces - as having Quadrilateral<4> topology. This is required by the 
         CubatureFactory in order to select cubature points and weights from the appropriate
         face parametrization domain. 
      c. Use CubatureFactory to select cubature of the desired degree for Triangle<3> and 
         Quadrilateral<4> topologies
      d. Allocate containers for the cubature points and weights on the parametrization domains.
   
   2. Parent cell topology specific tasks
   
      a. Select the parent cell topology
      b. Allocate containers for the images of the integration points from the parametrization
         domains on the reference faces
      c. Apply the face parametrization map to the points in the parametrization domain
   */
  
  // Step 1.b (Define the topology of the parametrization domain)
  CellTopology triFaceParam(shards::getCellTopologyData<shards::Triangle<3> >() );
  CellTopology quadFaceParam(shards::getCellTopologyData<shards::Quadrilateral<4> >() );
  
  
  // Step 1.c (selects Gauss rule of order 3 on [-1,1]^2 and a rule of order 3 on Triangle) 
  Teuchos::RCP<Cubature<double> > triFaceParamCubature = cubFactory.create(triFaceParam, 3); 
  Teuchos::RCP<Cubature<double> > quadFaceParamCubature = cubFactory.create(quadFaceParam, 3); 
  
  
  // Step 1.d - Triangle faces (allocate storage for cubature points)
  int triFaceCubDim    = triFaceParamCubature -> getDimension();
  int triFaceNumCubPts = triFaceParamCubature -> getNumPoints();
  
  FieldContainer<double> triFaceParamCubPts(triFaceNumCubPts, triFaceCubDim);
  FieldContainer<double> triFaceParamCubWts(triFaceNumCubPts);
  triFaceParamCubature -> getCubature(triFaceParamCubPts, triFaceParamCubWts);
  
  
  // Step 1.d - Quadrilateral faces (allocate storage for cubature points)
  int quadFaceCubDim    = quadFaceParamCubature -> getDimension();
  int quadFaceNumCubPts = quadFaceParamCubature -> getNumPoints();
  
  FieldContainer<double> quadFaceParamCubPts(quadFaceNumCubPts, quadFaceCubDim);
  FieldContainer<double> quadFaceParamCubWts(quadFaceNumCubPts);
  quadFaceParamCubature -> getCubature(quadFaceParamCubPts, quadFaceParamCubWts);
  
  
  
  std::cout \
    << "===============================================================================\n"\
    << "| EXAMPLE 2.1                                                                 |\n"
    << "| Face parametrizations for standard 3D cells: Tetrahedron                    |\n"\
    << "===============================================================================\n";
  
  // Step 2.a (select reference cell topology)
  CellTopology tet_4(getCellTopologyData<Tetrahedron<4> >() );
  
  
  // Step 2.b (allocate storage for points on a face of the reference cell)
  FieldContainer<double> tetFacePoints(triFaceNumCubPts, tet_4.getDimension() );
  
  
  // Step 2.c (same points are mapped to all faces, can also map different set to each face) 
  for(int faceOrd = 0; faceOrd < (int)tet_4.getSideCount(); faceOrd++){
    
    CellTools::mapToReferenceSubcell(tetFacePoints, 
                                     triFaceParamCubPts,
                                     2,
                                     faceOrd,
                                     tet_4);
    
    // Optional: print the vertices of the reference face 
    CellTools::printSubcellVertices(2, faceOrd, tet_4);
    
    for(int pt = 0; pt < triFaceNumCubPts; pt++){
      std::cout << "\t Parameter point (" 
      << std::setw(10) << std::right <<  triFaceParamCubPts(pt, 0) << " , "
      << std::setw(10) << std::right <<  triFaceParamCubPts(pt, 1) << ")  " 
      << std::setw(10) << " -->  " << "(" 
      << std::setw(10) << std::right << tetFacePoints(pt, 0) << " , " 
      << std::setw(10) << std::right << tetFacePoints(pt, 1) << " , " 
      << std::setw(10) << std::right << tetFacePoints(pt, 2) << ")\n";
    }    
    std::cout << "\n";
  }
  
  
  
  std::cout \
    << "===============================================================================\n"\
    << "| EXAMPLE 2.2                                                                 |\n"
    << "| Face parametrizations for standard 3D cells: Wedge                          |\n"\
    << "| Example of a reference cell that has two different kinds of faces           |\n"\
    << "===============================================================================\n";
  
  
  // Step 2.a (select reference cell topology)
  CellTopology wedge_6(getCellTopologyData<Wedge<6> >() );
  
  
  // Step 2.b (allocate storage for points on a face of the reference cell)
  //          Wedge<6> has Triangle<3> and Quadrilateral<4> faces. Two different arrays are needed
  //          to store the points on each face because different types integration rules are used
  //          on their respective parametrization domains and numbers of points defined by these
  //          rules do not necessarily match.
  FieldContainer<double> wedgeTriFacePoints(triFaceNumCubPts, wedge_6.getDimension() );
  FieldContainer<double> wedgeQuadFacePoints(quadFaceNumCubPts, wedge_6.getDimension() );

  
  // Step 2.c (for Wedge<6> need to distinguish Triangle<3> and Quadrilateral<4> faces) 
  for(int faceOrd = 0; faceOrd < (int)wedge_6.getSideCount(); faceOrd++){
    
    // Optional: print the vertices of the reference face 
    CellTools::printSubcellVertices(2, faceOrd, wedge_6);
    
    if( wedge_6.getKey(2, faceOrd) == shards::Triangle<3>::key ){
      CellTools::mapToReferenceSubcell(wedgeTriFacePoints, 
                                       triFaceParamCubPts,
                                       2,
                                       faceOrd,
                                       wedge_6);
      
      for(int pt = 0; pt < triFaceNumCubPts; pt++){
        std::cout << "\t Parameter point (" 
        << std::setw(10) << std::right <<  triFaceParamCubPts(pt, 0) << " , "
        << std::setw(10) << std::right <<  triFaceParamCubPts(pt, 1) << ")  "
        << std::setw(10) << "   -->    " << "(" 
        << std::setw(10) << std::right << wedgeTriFacePoints(pt, 0) << " , " 
        << std::setw(10) << std::right << wedgeTriFacePoints(pt, 1) << " , " 
        << std::setw(10) << std::right << wedgeTriFacePoints(pt, 2) << ")\n";
      }    
      std::cout << "\n";
    }
    else if(wedge_6.getKey(2, faceOrd) == shards::Quadrilateral<4>::key) {
      CellTools::mapToReferenceSubcell(wedgeQuadFacePoints, 
                                       quadFaceParamCubPts,
                                       2,
                                       faceOrd,
                                       wedge_6);
      
      for(int pt = 0; pt < quadFaceNumCubPts; pt++){
        std::cout << "\t Parameter point (" 
        << std::setw(10) << std::right <<  quadFaceParamCubPts(pt, 0) << " , "
        << std::setw(10) << std::right <<  quadFaceParamCubPts(pt, 1) << ")  "
        << std::setw(10) << "   -->    " << "(" 
        << std::setw(10) << std::right << wedgeQuadFacePoints(pt, 0) << " , " 
        << std::setw(10) << std::right << wedgeQuadFacePoints(pt, 1) << " , " 
        << std::setw(10) << std::right << wedgeQuadFacePoints(pt, 2) << ")\n";
      }    
      std::cout << "\n";
    }
    else {
      std::cout << " Invalid face encountered \n"; 
    }
  }
  
  return 0;
}
Example #15
0
int main(int argc, char *argv[]) {

  Teuchos::GlobalMPISession mpiSession(&argc, &argv);
 Kokkos::initialize();
  // This little trick lets us print to std::cout only if
  // a (dummy) command-line argument is provided.
  int iprint     = argc - 1;
  Teuchos::RCP<std::ostream> outStream;
  Teuchos::oblackholestream bhs; // outputs nothing
  if (iprint > 0)
    outStream = Teuchos::rcp(&std::cout, false);
  else
    outStream = Teuchos::rcp(&bhs, false);

  // Save the format state of the original std::cout.
  Teuchos::oblackholestream oldFormatState;
  oldFormatState.copyfmt(std::cout);

  *outStream \
  << "===============================================================================\n" \
  << "|                                                                             |\n" \
  << "|                      Unit Test (FunctionSpaceTools)                         |\n" \
  << "|                                                                             |\n" \
  << "|     1) basic operator transformations and integration in HCURL              |\n" \
  << "|                                                                             |\n" \
  << "|  Questions? Contact  Pavel Bochev ([email protected]) or                   |\n" \
  << "|                      Denis Ridzal ([email protected]).                     |\n" \
  << "|                                                                             |\n" \
  << "|  Intrepid's website: http://trilinos.sandia.gov/packages/intrepid           |\n" \
  << "|  Trilinos website:   http://trilinos.sandia.gov                             |\n" \
  << "|                                                                             |\n" \
  << "===============================================================================\n";


  int errorFlag = 0;

  typedef FunctionSpaceTools fst; 

  *outStream \
  << "\n"
  << "===============================================================================\n"\
  << "| TEST 1: correctness of math operations                                      |\n"\
  << "===============================================================================\n";

  outStream->precision(20);

  try {
      shards::CellTopology cellType = shards::getCellTopologyData< shards::Hexahedron<> >();    // cell type: hex

      /* Related to cubature. */
      DefaultCubatureFactory<double> cubFactory;                                                // create cubature factory
      int cubDegree = 20;                                                                       // cubature degree
      Teuchos::RCP<Cubature<double> > myCub = cubFactory.create(cellType, cubDegree);           // create default cubature
      int spaceDim = myCub->getDimension();                                                     // get spatial dimension 
      int numCubPoints = myCub->getNumPoints();                                                 // get number of cubature points
      /* Related to basis. */
      Basis_HCURL_HEX_I1_FEM<double, FieldContainer<double> > hexBasis;                         // create H-curl basis on a hex
      int numFields = hexBasis.getCardinality();                                                // get basis cardinality
 
      /* Cell geometries and orientations. */
      int numCells    = 4;
      int numNodes    = 8;
      int numCellData = numCells*numNodes*spaceDim;
      int numSignData = numCells*numFields;

      double hexnodes[] = {
        // hex 0  -- affine
        -1.0, -1.0, -1.0,
        1.0, -1.0, -1.0,
        1.0, 1.0, -1.0,
        -1.0, 1.0, -1.0,
        -1.0, -1.0, 1.0,
        1.0, -1.0, 1.0,
        1.0, 1.0, 1.0,
        -1.0, 1.0, 1.0,
        // hex 1  -- affine
        -3.0, -3.0, 1.0,
        6.0, 3.0, 1.0,
        7.0, 8.0, 0.0,
        -2.0, 2.0, 0.0,
        -3.0, -3.0, 4.0,
        6.0, 3.0, 4.0,
        7.0, 8.0, 3.0,
        -2.0, 2.0, 3.0,
        // hex 2  -- affine
        -3.0, -3.0, 0.0,
        9.0, 3.0, 0.0,
        15.0, 6.1, 0.0,
        3.0, 0.1, 0.0,
        9.0, 3.0, 0.1,
        21.0, 9.0, 0.1,
        27.0, 12.1, 0.1,
        15.0, 6.1, 0.1,
        // hex 3  -- nonaffine
        -2.0, -2.0, 0.0,
        2.0, -1.0, 0.0,
        1.0, 6.0, 0.0,
        -1.0, 1.0, 0.0,
        0.0, 0.0, 1.0,
        1.0, 0.0, 1.0,
        1.0, 1.0, 1.0,
        0.0, 1.0, 1.0
      };

      double edgesigns[] = {
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
        1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1,
        -1, -1, -1, 1, 1, 1, -1, -1, 1, 1, -1, 1,
        1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, 1
      };

      /* Computational arrays. */
      FieldContainer<double> cub_points(numCubPoints, spaceDim);
      FieldContainer<double> cub_weights(numCubPoints);
      FieldContainer<double> cell_nodes(numCells, numNodes, spaceDim);
      FieldContainer<double>  field_signs(numCells, numFields);
      FieldContainer<double> jacobian(numCells, numCubPoints, spaceDim, spaceDim);
      FieldContainer<double> jacobian_inv(numCells, numCubPoints, spaceDim, spaceDim);
      FieldContainer<double> jacobian_det(numCells, numCubPoints);
      FieldContainer<double> weighted_measure(numCells, numCubPoints);

      FieldContainer<double> curl_of_basis_at_cub_points(numFields, numCubPoints, spaceDim);
      FieldContainer<double> transformed_curl_of_basis_at_cub_points(numCells, numFields, numCubPoints, spaceDim);
      FieldContainer<double> weighted_transformed_curl_of_basis_at_cub_points(numCells, numFields, numCubPoints, spaceDim);
      FieldContainer<double> stiffness_matrices(numCells, numFields, numFields);

      FieldContainer<double> value_of_basis_at_cub_points(numFields, numCubPoints, spaceDim);
      FieldContainer<double> transformed_value_of_basis_at_cub_points(numCells, numFields, numCubPoints, spaceDim);
      FieldContainer<double> weighted_transformed_value_of_basis_at_cub_points(numCells, numFields, numCubPoints, spaceDim);
      FieldContainer<double> mass_matrices(numCells, numFields, numFields);

      /******************* START COMPUTATION ***********************/

      // get cubature points and weights
      myCub->getCubature(cub_points, cub_weights);

      // fill cell vertex array
      cell_nodes.setValues(hexnodes, numCellData);
      // set basis function signs, for each cell
      field_signs.setValues(edgesigns, numSignData);

      // compute geometric cell information
      CellTools<double>::setJacobian(jacobian, cub_points, cell_nodes, cellType);
      CellTools<double>::setJacobianInv(jacobian_inv, jacobian);
      CellTools<double>::setJacobianDet(jacobian_det, jacobian);
      // compute weighted measure
      fst::computeCellMeasure<double>(weighted_measure, jacobian_det, cub_weights);

      // Computing stiffness matrices:
      // tabulate curls of basis functions at (reference) cubature points
      hexBasis.getValues(curl_of_basis_at_cub_points, cub_points, OPERATOR_CURL);

      // transform curls of basis functions 
      fst::HCURLtransformCURL<double>(transformed_curl_of_basis_at_cub_points,
                                      jacobian,
                                      jacobian_det,
                                      curl_of_basis_at_cub_points);
      // multiply with weighted measure
      fst::multiplyMeasure<double>(weighted_transformed_curl_of_basis_at_cub_points,
                                   weighted_measure,
                                   transformed_curl_of_basis_at_cub_points);

      // we can apply the field signs to the basis function arrays, or after the fact, see below
      fst::applyFieldSigns<double>(transformed_curl_of_basis_at_cub_points, field_signs);
      fst::applyFieldSigns<double>(weighted_transformed_curl_of_basis_at_cub_points, field_signs);

      // compute stiffness matrices
      fst::integrate<double>(stiffness_matrices,
                             transformed_curl_of_basis_at_cub_points,
                             weighted_transformed_curl_of_basis_at_cub_points,
                             COMP_CPP);
      // Computing mass matrices:
      // tabulate values of basis functions at (reference) cubature points
      hexBasis.getValues(value_of_basis_at_cub_points, cub_points, OPERATOR_VALUE);

      // transform values of basis functions 
      fst::HCURLtransformVALUE<double>(transformed_value_of_basis_at_cub_points,
                                       jacobian_inv,
                                       value_of_basis_at_cub_points);

      // multiply with weighted measure
      fst::multiplyMeasure<double>(weighted_transformed_value_of_basis_at_cub_points,
                                   weighted_measure,
                                   transformed_value_of_basis_at_cub_points);

      // compute mass matrices
      fst::integrate<double>(mass_matrices,
                             transformed_value_of_basis_at_cub_points,
                             weighted_transformed_value_of_basis_at_cub_points,
                             COMP_CPP);

      // apply field signs (after the fact, as a post-processing step)
      fst::applyLeftFieldSigns<double>(mass_matrices, field_signs);
      fst::applyRightFieldSigns<double>(mass_matrices, field_signs);
      /*******************  STOP COMPUTATION ***********************/


      /******************* START COMPARISON ***********************/
      string basedir = "./testdata";
      for (int cell_id = 0; cell_id < numCells-1; cell_id++) {

        stringstream namestream;
        string filename;
        namestream <<  basedir << "/mass_HCURL_HEX_I1_FEM" << "_" << "0" << cell_id+1 << ".dat";
        namestream >> filename;

        ifstream massfile(&filename[0]);
        if (massfile.is_open()) {
          if (compareToAnalytic<double>(&mass_matrices(cell_id, 0, 0), massfile, 1e-10, iprint) > 0)
            errorFlag++;
          massfile.close();
        }
        else {
          errorFlag = -1;
          std::cout << "End Result: TEST FAILED\n";
          return errorFlag;
        }

        namestream.clear();
        namestream << basedir << "/stiff_HCURL_HEX_I1_FEM" << "_" << "0" << cell_id+1 << ".dat";
        namestream >> filename;

        ifstream stifffile(&filename[0]);
        if (stifffile.is_open())
        {
          if (compareToAnalytic<double>(&stiffness_matrices(cell_id, 0, 0), stifffile, 1e-10, iprint) > 0)
            errorFlag++;
          stifffile.close();
        }
        else {
          errorFlag = -1;
          std::cout << "End Result: TEST FAILED\n";
          return errorFlag;
        }

      }

      for (int cell_id = 3; cell_id < numCells; cell_id++) {

        stringstream namestream;
        string filename;
        namestream <<  basedir << "/mass_fp_HCURL_HEX_I1_FEM" << "_" << "0" << cell_id+1 << ".dat";
        namestream >> filename;

        ifstream massfile(&filename[0]);
        if (massfile.is_open()) {
          if (compareToAnalytic<double>(&mass_matrices(cell_id, 0, 0), massfile, 1e-4, iprint, INTREPID2_UTILS_SCALAR) > 0)
            errorFlag++;
          massfile.close();
        }
        else {
          errorFlag = -1;
          std::cout << "End Result: TEST FAILED\n";
          return errorFlag;
        }

        namestream.clear();
        namestream << basedir << "/stiff_fp_HCURL_HEX_I1_FEM" << "_" << "0" << cell_id+1 << ".dat";
        namestream >> filename;

        ifstream stifffile(&filename[0]);
        if (stifffile.is_open())
        {
          if (compareToAnalytic<double>(&stiffness_matrices(cell_id, 0, 0), stifffile, 1e-4, iprint, INTREPID2_UTILS_SCALAR) > 0)
            errorFlag++;
          stifffile.close();
        }
        else {
          errorFlag = -1;
          std::cout << "End Result: TEST FAILED\n";
          return errorFlag;
        }

      }

      /******************* STOP COMPARISON ***********************/

      *outStream << "\n";
  }
  catch (std::logic_error err) {
    *outStream << "UNEXPECTED ERROR !!! ----------------------------------------------------------\n";
    *outStream << err.what() << '\n';
    *outStream << "-------------------------------------------------------------------------------" << "\n\n";
    errorFlag = -1000;
  };

  if (errorFlag != 0)
    std::cout << "End Result: TEST FAILED\n";
  else
    std::cout << "End Result: TEST PASSED\n";

  // reset format state of std::cout
  std::cout.copyfmt(oldFormatState);
 Kokkos::finalize();
  return errorFlag;
}
Example #16
0
int main(int argc, char *argv[]) {

  Teuchos::GlobalMPISession mpiSession(&argc, &argv);
 Kokkos::initialize();
  // This little trick lets us print to std::cout only if
  // a (dummy) command-line argument is provided.
  int iprint     = argc - 1;
  Teuchos::RCP<std::ostream> outStream;
  Teuchos::oblackholestream bhs; // outputs nothing
  if (iprint > 0)
    outStream = Teuchos::rcp(&std::cout, false);
  else
    outStream = Teuchos::rcp(&bhs, false);

  // Save the format state of the original std::cout.
  Teuchos::oblackholestream oldFormatState;
  oldFormatState.copyfmt(std::cout);

  *outStream \
    << "===============================================================================\n" \
    << "|                                                                             |\n" \
    << "|               Unit Test (Basis_HGRAD_LINE_C1_FEM)                           |\n" \
    << "|                                                                             |\n" \
    << "|     1) Patch test involving mass and stiffness matrices,                    |\n" \
    << "|        for the Neumann problem on a REFERENCE line:                         |\n" \
    << "|                                                                             |\n" \
    << "|            - u'' + u = f  in (-1,1),  u' = g at -1,1                        |\n" \
    << "|                                                                             |\n" \
    << "|  Questions? Contact  Pavel Bochev  ([email protected]),                    |\n" \
    << "|                      Denis Ridzal  ([email protected]),                    |\n" \
    << "|                      Kara Peterson ([email protected]).                    |\n" \
    << "|                                                                             |\n" \
    << "|  Intrepid's website: http://trilinos.sandia.gov/packages/intrepid           |\n" \
    << "|  Trilinos website:   http://trilinos.sandia.gov                             |\n" \
    << "|                                                                             |\n" \
    << "===============================================================================\n"\
    << "| TEST 1: Patch test                                                          |\n"\
    << "===============================================================================\n";

  
  int errorFlag = 0;
  double zero = 100*INTREPID_TOL;
  outStream -> precision(20);


  try {

    int max_order = 1;  // max total order of polynomial solution

    // Define array containing points at which the solution is evaluated
    int numIntervals = 100;
    int numInterpPoints = numIntervals + 1;
    FieldContainer<double> interp_points(numInterpPoints, 1);
    for (int i=0; i<numInterpPoints; i++) {
      interp_points(i,0) = -1.0+(2.0*(double)i)/(double)numIntervals;
    }
    
    DefaultCubatureFactory<double>  cubFactory;                                   // create factory
    shards::CellTopology line(shards::getCellTopologyData< shards::Line<> >());   // create cell topology

    //create basis
    Teuchos::RCP<Basis<double,FieldContainer<double> > > lineBasis =
      Teuchos::rcp(new Basis_HGRAD_LINE_C1_FEM<double,FieldContainer<double> >() );
    int numFields = lineBasis->getCardinality();
    int basis_order = lineBasis->getDegree();

    // create cubature
    Teuchos::RCP<Cubature<double> > lineCub = cubFactory.create(line, 2);
    int numCubPoints = lineCub->getNumPoints();
    int spaceDim = lineCub->getDimension();

    for (int soln_order=0; soln_order <= max_order; soln_order++) {

      // evaluate exact solution
      FieldContainer<double> exact_solution(1, numInterpPoints);
      u_exact(exact_solution, interp_points, soln_order);

      /* Computational arrays. */
      FieldContainer<double> cub_points(numCubPoints, spaceDim);
      FieldContainer<double> cub_points_physical(1, numCubPoints, spaceDim);
      FieldContainer<double> cub_weights(numCubPoints);
      FieldContainer<double> cell_nodes(1, 2, spaceDim);
      FieldContainer<double> jacobian(1, numCubPoints, spaceDim, spaceDim);
      FieldContainer<double> jacobian_inv(1, numCubPoints, spaceDim, spaceDim);
      FieldContainer<double> jacobian_det(1, numCubPoints);
      FieldContainer<double> weighted_measure(1, numCubPoints);

      FieldContainer<double> value_of_basis_at_cub_points(numFields, numCubPoints);
      FieldContainer<double> transformed_value_of_basis_at_cub_points(1, numFields, numCubPoints);
      FieldContainer<double> weighted_transformed_value_of_basis_at_cub_points(1, numFields, numCubPoints);
      FieldContainer<double> grad_of_basis_at_cub_points(numFields, numCubPoints, spaceDim);
      FieldContainer<double> transformed_grad_of_basis_at_cub_points(1, numFields, numCubPoints, spaceDim);
      FieldContainer<double> weighted_transformed_grad_of_basis_at_cub_points(1, numFields, numCubPoints, spaceDim);
      FieldContainer<double> fe_matrix(1, numFields, numFields);

      FieldContainer<double> rhs_at_cub_points_physical(1, numCubPoints);
      FieldContainer<double> rhs_and_soln_vector(1, numFields);

      FieldContainer<double> one_point(1, 1);
      FieldContainer<double> value_of_basis_at_one(numFields, 1);
      FieldContainer<double> value_of_basis_at_minusone(numFields, 1);
      FieldContainer<double> bc_neumann(2, numFields);

      FieldContainer<double> value_of_basis_at_interp_points(numFields, numInterpPoints);
      FieldContainer<double> transformed_value_of_basis_at_interp_points(1, numFields, numInterpPoints);
      FieldContainer<double> interpolant(1, numInterpPoints);

      FieldContainer<int> ipiv(numFields);

      /******************* START COMPUTATION ***********************/

      // get cubature points and weights
      lineCub->getCubature(cub_points, cub_weights);

      // fill cell vertex array
      cell_nodes(0, 0, 0) = -1.0;
      cell_nodes(0, 1, 0) = 1.0;

      // compute geometric cell information
      CellTools<double>::setJacobian(jacobian, cub_points, cell_nodes, line);
      CellTools<double>::setJacobianInv(jacobian_inv, jacobian);
      CellTools<double>::setJacobianDet(jacobian_det, jacobian);

      // compute weighted measure
      FunctionSpaceTools::computeCellMeasure<double>(weighted_measure, jacobian_det, cub_weights);

      ///////////////////////////
      // Computing mass matrices:
      // tabulate values of basis functions at (reference) cubature points
      lineBasis->getValues(value_of_basis_at_cub_points, cub_points, OPERATOR_VALUE);

      // transform values of basis functions
      FunctionSpaceTools::HGRADtransformVALUE<double>(transformed_value_of_basis_at_cub_points,
                                                      value_of_basis_at_cub_points);

      // multiply with weighted measure
      FunctionSpaceTools::multiplyMeasure<double>(weighted_transformed_value_of_basis_at_cub_points,
                                                  weighted_measure,
                                                  transformed_value_of_basis_at_cub_points);

      // compute mass matrices
      FunctionSpaceTools::integrate<double>(fe_matrix,
                                            transformed_value_of_basis_at_cub_points,
                                            weighted_transformed_value_of_basis_at_cub_points,
                                            COMP_CPP);
      ///////////////////////////

      ////////////////////////////////
      // Computing stiffness matrices:
      // tabulate gradients of basis functions at (reference) cubature points
      lineBasis->getValues(grad_of_basis_at_cub_points, cub_points, OPERATOR_GRAD);

      // transform gradients of basis functions
      FunctionSpaceTools::HGRADtransformGRAD<double>(transformed_grad_of_basis_at_cub_points,
                                                     jacobian_inv,
                                                     grad_of_basis_at_cub_points);

      // multiply with weighted measure
      FunctionSpaceTools::multiplyMeasure<double>(weighted_transformed_grad_of_basis_at_cub_points,
                                                  weighted_measure,
                                                  transformed_grad_of_basis_at_cub_points);

      // compute stiffness matrices and sum into fe_matrix
      FunctionSpaceTools::integrate<double>(fe_matrix,
                                            transformed_grad_of_basis_at_cub_points,
                                            weighted_transformed_grad_of_basis_at_cub_points,
                                            COMP_CPP,
                                            true);
      ////////////////////////////////

      ///////////////////////////////
      // Computing RHS contributions:
      // map (reference) cubature points to physical space
      CellTools<double>::mapToPhysicalFrame(cub_points_physical, cub_points, cell_nodes, line);

      // evaluate rhs function
      rhsFunc(rhs_at_cub_points_physical, cub_points_physical, soln_order);

      // compute rhs
      FunctionSpaceTools::integrate<double>(rhs_and_soln_vector,
                                            rhs_at_cub_points_physical,
                                            weighted_transformed_value_of_basis_at_cub_points,
                                            COMP_CPP);

      // compute neumann b.c. contributions and adjust rhs
      one_point(0,0) = 1.0;   lineBasis->getValues(value_of_basis_at_one, one_point, OPERATOR_VALUE);
      one_point(0,0) = -1.0;  lineBasis->getValues(value_of_basis_at_minusone, one_point, OPERATOR_VALUE);
      neumann(bc_neumann, value_of_basis_at_minusone, value_of_basis_at_one, soln_order);
      for (int i=0; i<numFields; i++) {
        rhs_and_soln_vector(0, i) -= bc_neumann(0, i);
        rhs_and_soln_vector(0, i) += bc_neumann(1, i);
      }
      ///////////////////////////////

      /////////////////////////////
      // Solution of linear system:
      int info = 0;
      Teuchos::LAPACK<int, double> solver;
      //solver.GESV(numRows, 1, &fe_mat(0,0), numRows, &ipiv(0), &fe_vec(0), numRows, &info);
      solver.GESV(numFields, 1, &fe_matrix[0], numFields, &ipiv(0), &rhs_and_soln_vector[0], numFields, &info);
      /////////////////////////////

      ////////////////////////
      // Building interpolant:
      // evaluate basis at interpolation points
      lineBasis->getValues(value_of_basis_at_interp_points, interp_points, OPERATOR_VALUE);
      // transform values of basis functions
      FunctionSpaceTools::HGRADtransformVALUE<double>(transformed_value_of_basis_at_interp_points,
                                                      value_of_basis_at_interp_points);
      FunctionSpaceTools::evaluate<double>(interpolant, rhs_and_soln_vector, transformed_value_of_basis_at_interp_points);
      ////////////////////////

      /******************* END COMPUTATION ***********************/
    
      RealSpaceTools<double>::subtract(interpolant, exact_solution);

      *outStream << "\nNorm-2 difference between exact solution polynomial of order "
                 << soln_order << " and finite element interpolant of order " << basis_order << ": "
                 << RealSpaceTools<double>::vectorNorm(&interpolant[0], interpolant.dimension(1), NORM_TWO) << "\n";

      if (RealSpaceTools<double>::vectorNorm(&interpolant[0], interpolant.dimension(1), NORM_TWO) > zero) {
        *outStream << "\n\nPatch test failed for solution polynomial order "
                   << soln_order << " and basis order " << basis_order << "\n\n";
        errorFlag++;
      }

    } // end for soln_order

  }
  // Catch unexpected errors
  catch (std::logic_error err) {
    *outStream << err.what() << "\n\n";
    errorFlag = -1000;
  };

  if (errorFlag != 0)
    std::cout << "End Result: TEST FAILED\n";
  else
    std::cout << "End Result: TEST PASSED\n";

  // reset format state of std::cout
  std::cout.copyfmt(oldFormatState);
 Kokkos::finalize();
  return errorFlag;
}
Example #17
0
int main(int argc, char *argv[]) {

  //Check number of arguments
  if (argc < 4) {
    std::cout <<"\n>>> ERROR: Invalid number of arguments.\n\n";
    std::cout <<"Usage:\n\n";
    std::cout <<"  ./Intrepid_example_Drivers_Example_10.exe deg NX NY NZ verbose\n\n";
    std::cout <<" where \n";
    std::cout <<"   int deg             - polynomial degree to be used (assumed >= 1) \n";
    std::cout <<"   int NX              - num intervals in x direction (assumed box domain, 0,1) \n";
    std::cout <<"   int NY              - num intervals in y direction (assumed box domain, 0,1) \n";
    std::cout <<"   int NZ              - num intervals in y direction (assumed box domain, 0,1) \n";
    std::cout <<"   verbose (optional)  - any character, indicates verbose output \n\n";
    exit(1);
  }
  
  // This little trick lets us print to std::cout only if
  // a (dummy) command-line argument is provided.
  int iprint     = argc - 1;
  Teuchos::RCP<std::ostream> outStream;
  Teuchos::oblackholestream bhs; // outputs nothing
  if (iprint > 2)
    outStream = Teuchos::rcp(&std::cout, false);
  else
    outStream = Teuchos::rcp(&bhs, false);
  
  // Save the format state of the original std::cout.
  Teuchos::oblackholestream oldFormatState;
  oldFormatState.copyfmt(std::cout);
  
  *outStream								\
    << "===============================================================================\n" \
    << "|                                                                             |\n" \
    << "|  Example: Build Stiffness Matrix for                                        |\n" \
    << "|                   Poisson Equation on Hexahedral Mesh                       |\n" \
    << "|                                                                             |\n" \
    << "|  Questions? Contact  Pavel Bochev  ([email protected]),                    |\n" \
    << "|                      Denis Ridzal  ([email protected]),                    |\n" \
    << "|                      Kara Peterson ([email protected]).                    |\n" \
    << "|                                                                             |\n" \
    << "|  Intrepid's website: http://trilinos.sandia.gov/packages/intrepid           |\n" \
    << "|  Trilinos website:   http://trilinos.sandia.gov                             |\n" \
    << "|                                                                             |\n" \
    << "===============================================================================\n";

  
  // ************************************ GET INPUTS **************************************
  
  int deg          = atoi(argv[1]);  // polynomial degree to use
  int NX           = atoi(argv[2]);  // num intervals in x direction (assumed box domain, 0,1)
  int NY           = atoi(argv[3]);  // num intervals in y direction (assumed box domain, 0,1)
  int NZ           = atoi(argv[4]);  // num intervals in y direction (assumed box domain, 0,1)
  

  // *********************************** CELL TOPOLOGY **********************************
  
  // Get cell topology for base hexahedron
  typedef shards::CellTopology    CellTopology;
  CellTopology hex_8(shards::getCellTopologyData<shards::Hexahedron<8> >() );
  
  // Get dimensions 
  int numNodesPerElem = hex_8.getNodeCount();
  int spaceDim = hex_8.getDimension();
  
  // *********************************** GENERATE MESH ************************************
  
  *outStream << "Generating mesh ... \n\n";
  
  *outStream << "   NX" << "   NY" << "   NZ\n";
  *outStream << std::setw(5) << NX <<
    std::setw(5) << NY << std::setw(5) << NZ << "\n\n";
  
  // Print mesh information
  int numElems = NX*NY*NZ;
  int numNodes = (NX+1)*(NY+1)*(NZ+1);
  *outStream << " Number of Elements: " << numElems << " \n";
  *outStream << "    Number of Nodes: " << numNodes << " \n\n";
  
  // Cube
  double leftX = 0.0, rightX = 1.0;
  double leftY = 0.0, rightY = 1.0;
  double leftZ = 0.0, rightZ = 1.0;

  // Mesh spacing
  double hx = (rightX-leftX)/((double)NX);
  double hy = (rightY-leftY)/((double)NY);
  double hz = (rightZ-leftZ)/((double)NZ);

  // Get nodal coordinates
  FieldContainer<double> nodeCoord(numNodes, spaceDim);
  FieldContainer<int> nodeOnBoundary(numNodes);
  int inode = 0;
  for (int k=0; k<NZ+1; k++) 
    {
      for (int j=0; j<NY+1; j++) 
	{
	  for (int i=0; i<NX+1; i++) 
	    {
	      nodeCoord(inode,0) = leftX + (double)i*hx;
	      nodeCoord(inode,1) = leftY + (double)j*hy;
	      nodeCoord(inode,2) = leftZ + (double)k*hz;
	      if (k==0 || k==NZ || j==0 || i==0 || j==NY || i==NX)
		{
		  nodeOnBoundary(inode)=1;
		}
	      else 
		{
		  nodeOnBoundary(inode)=0;
		}
	      inode++;
	    }
	}
    }
#define DUMP_DATA
#ifdef DUMP_DATA
  // Print nodal coords
  ofstream fcoordout("coords.dat");
  for (int i=0; i<numNodes; i++) {
    fcoordout << nodeCoord(i,0) <<" ";
    fcoordout << nodeCoord(i,1) <<" ";
    fcoordout << nodeCoord(i,2) <<"\n";
  }
  fcoordout.close();
#endif
  
  
  // Element to Node map
  // We'll keep it around, but this is only the DOFMap if you are in the lowest order case.
  FieldContainer<int> elemToNode(numElems, numNodesPerElem);
  int ielem = 0;
  for (int k=0; k<NZ; k++) 
    {
      for (int j=0; j<NY; j++) 
	{
	  for (int i=0; i<NX; i++) 
	    {
 	      elemToNode(ielem,0) = k * ( NX + 1 ) * ( NY + 1 ) + j * ( NX + 1 ) + i;
 	      elemToNode(ielem,1) = k * ( NX + 1 ) * ( NY + 1 ) + j * ( NX + 1 ) + i + 1;
 	      elemToNode(ielem,2) = k * ( NX + 1 ) * ( NY + 1 ) + ( j + 1 ) * ( NX + 1 ) + i + 1;
 	      elemToNode(ielem,3) = k * ( NX + 1 ) * ( NY + 1 ) + ( j + 1 ) * ( NX + 1 ) + i;
 	      elemToNode(ielem,4) = ( k + 1 ) * ( NX + 1 ) * ( NY + 1 ) + j * ( NX + 1 ) + i;
 	      elemToNode(ielem,5) = ( k + 1 ) * ( NX + 1 ) * ( NY + 1 ) + j * ( NX + 1 ) + i + 1;
 	      elemToNode(ielem,6) = ( k + 1 ) * ( NX + 1 ) * ( NY + 1 ) + ( j + 1 ) * ( NX + 1 ) + i + 1;
 	      elemToNode(ielem,7) = ( k + 1 ) * ( NX + 1 ) * ( NY + 1 ) + ( j + 1 ) * ( NX + 1 ) + i;
	      ielem++;
	    }
	}
    }
#ifdef DUMP_DATA
  // Output connectivity
  ofstream fe2nout("elem2node.dat");
  for (int k=0;k<NZ;k++)
    {
      for (int j=0; j<NY; j++) 
	{
	  for (int i=0; i<NX; i++) 
	    {
	      int ielem = i + j * NX + k * NY * NY;
	      for (int m=0; m<numNodesPerElem; m++)
		{
		  fe2nout << elemToNode(ielem,m) <<"  ";
		}
	      fe2nout <<"\n";
	    }
	}
    }
  fe2nout.close();
#endif
  
  // ************************************ CUBATURE ************************************** 
  *outStream << "Getting cubature ... \n\n";
  
  // Get numerical integration points and weights
  DefaultCubatureFactory<double>  cubFactory;                                   
  int cubDegree = 2*deg;
  Teuchos::RCP<Cubature<double> > quadCub = cubFactory.create(hex_8, cubDegree); 
  
  int cubDim       = quadCub->getDimension();
  int numCubPoints = quadCub->getNumPoints();
  
  FieldContainer<double> cubPoints(numCubPoints, cubDim);
  FieldContainer<double> cubWeights(numCubPoints);
  
  quadCub->getCubature(cubPoints, cubWeights);
  

  // ************************************** BASIS ***************************************
  
  *outStream << "Getting basis ... \n\n";
  
  // Define basis 
  Basis_HGRAD_HEX_Cn_FEM<double, FieldContainer<double> > quadHGradBasis(deg,POINTTYPE_SPECTRAL);
  int numFieldsG = quadHGradBasis.getCardinality();
  FieldContainer<double> quadGVals(numFieldsG, numCubPoints); 
  FieldContainer<double> quadGrads(numFieldsG, numCubPoints, spaceDim); 
  
  // Evaluate basis values and gradients at cubature points
  quadHGradBasis.getValues(quadGVals, cubPoints, OPERATOR_VALUE);
  quadHGradBasis.getValues(quadGrads, cubPoints, OPERATOR_GRAD);

  // create the local-global mapping
  FieldContainer<int> ltgMapping(numElems,numFieldsG);
  const int numDOF = (NX*deg+1)*(NY*deg+1)*(NZ*deg+1);
  ielem=0;
  for (int k=0;k<NZ;k++) 
    {
      for (int j=0;j<NY;j++) 
	{
	  for (int i=0;i<NX;i++) 
	    {
	      const int start = k * ( NY * deg + 1 ) * ( NX * deg + 1 ) + j * ( NX * deg + 1 ) + i * deg;
	      // loop over local dof on this cell
	      int local_dof_cur=0;
	      for (int kloc=0;kloc<=deg;kloc++) 
		{
		  for (int jloc=0;jloc<=deg;jloc++) 
		    {
		      for (int iloc=0;iloc<=deg;iloc++)
			{
			  ltgMapping(ielem,local_dof_cur) = start 
			    + kloc * ( NX * deg + 1 ) * ( NY * deg + 1 )
			    + jloc * ( NX * deg + 1 )
			    + iloc;
			  local_dof_cur++;
			}
		    }
		}
	      ielem++;
	    }
	}
    }
#ifdef DUMP_DATA
  // Output ltg mapping 
  ielem = 0;
  ofstream ltgout("ltg.dat");
  for (int k=0;k<NZ;k++)  
    {
      for (int j=0; j<NY; j++) 
	{
	  for (int i=0; i<NX; i++) 
	    {
	      int ielem = i + j * NX + k * NX * NY;
	      for (int m=0; m<numFieldsG; m++)
		{
		  ltgout << ltgMapping(ielem,m) <<"  ";
		}
	      ltgout <<"\n";
	    }
	}
    }
  ltgout.close();
#endif

  // ********** DECLARE GLOBAL OBJECTS *************
  Epetra_SerialComm Comm;
  Epetra_Map globalMapG(numDOF, 0, Comm);
  Epetra_FEVector u(globalMapG);  u.Random();
  Epetra_FEVector Ku(globalMapG);

  // time the instantiation 
  Epetra_Time instantiateTimer(Comm);
  Epetra_FECrsMatrix StiffMatrix(Copy,globalMapG,8*numFieldsG); 
  const double instantiateTime = instantiateTimer.ElapsedTime();


  // ********** CONSTRUCT AND INSERT LOCAL STIFFNESS MATRICES ***********
  *outStream << "Building local stiffness matrices...\n\n";
  typedef CellTools<double>  CellTools;
  typedef FunctionSpaceTools fst;
  int numCells = numElems; 

  // vertices
  FieldContainer<double> cellVertices(numCells,numNodesPerElem,spaceDim);

  // jacobian information
  FieldContainer<double> cellJacobian(numCells,numCubPoints,spaceDim,spaceDim);
  FieldContainer<double> cellJacobInv(numCells,numCubPoints,spaceDim,spaceDim);
  FieldContainer<double> cellJacobDet(numCells,numCubPoints);

  // element stiffness matrices and supporting storage space
  FieldContainer<double> localStiffMatrices(numCells, numFieldsG, numFieldsG);
  FieldContainer<double> transformedBasisGradients(numCells,numFieldsG,numCubPoints,spaceDim);
  FieldContainer<double> weightedTransformedBasisGradients(numCells,numFieldsG,numCubPoints,spaceDim);
  FieldContainer<double> weightedMeasure(numCells, numCubPoints);


  // get vertices of cells (for computing Jacobians)
  for (int i=0;i<numElems;i++)
    {
      for (int j=0;j<numNodesPerElem;j++)
	{
	  const int nodeCur = elemToNode(i,j);
	  for (int k=0;k<spaceDim;k++) 
	    {
	      cellVertices(i,j,k) = nodeCoord(nodeCur,k);
	    }
	}
    }
   
  Epetra_Time localConstructTimer( Comm );

  // jacobian evaluation 
  CellTools::setJacobian(cellJacobian,cubPoints,cellVertices,hex_8);
  CellTools::setJacobianInv(cellJacobInv, cellJacobian );
  CellTools::setJacobianDet(cellJacobDet, cellJacobian );

  // transform reference element gradients to each cell
  fst::HGRADtransformGRAD<double>(transformedBasisGradients, cellJacobInv, quadGrads);
      
  // compute weighted measure
  fst::computeCellMeasure<double>(weightedMeasure, cellJacobDet, cubWeights);

  // multiply values with weighted measure
  fst::multiplyMeasure<double>(weightedTransformedBasisGradients,
                               weightedMeasure, transformedBasisGradients);

  // integrate to compute element stiffness matrix
  fst::integrate<double>(localStiffMatrices,
                         transformedBasisGradients, weightedTransformedBasisGradients , COMP_BLAS);

  const double localConstructTime = localConstructTimer.ElapsedTime();


  Epetra_Time insertionTimer(Comm);

  // *** Element loop ***
  for (int k=0; k<numElems; k++) 
    {
      // assemble into global matrix
      StiffMatrix.InsertGlobalValues(numFieldsG,&ltgMapping(k,0),numFieldsG,&ltgMapping(k,0),&localStiffMatrices(k,0,0));
      
    }
  StiffMatrix.GlobalAssemble(); StiffMatrix.FillComplete();
  const double insertionTime = insertionTimer.ElapsedTime( );
  
  *outStream << "Time to instantiate global stiffness matrix: " << instantiateTime << "\n";
  *outStream << "Time to build local matrices (including Jacobian computation): "<< localConstructTime << "\n";
  *outStream << "Time to assemble global matrix from local matrices: " << insertionTime << "\n";
  *outStream << "Total construction time: " << instantiateTime + localConstructTime + insertionTime << "\n";

  Epetra_Time applyTimer(Comm);
  StiffMatrix.Apply(u,Ku);
  const double multTime = applyTimer.ElapsedTime();
  *outStream << "Time to multiply onto a vector: " << multTime << "\n";

  *outStream << "End Result: TEST PASSED\n";
  
  // reset format state of std::cout
  std::cout.copyfmt(oldFormatState);
  
  return 0;
}
Example #18
0
int main(int argc, char *argv[]) {

  Teuchos::GlobalMPISession mpiSession(&argc, &argv);
 Kokkos::initialize();
  // This little trick lets us print to std::cout only if
  // a (dummy) command-line argument is provided.
  int iprint     = argc - 1;
  Teuchos::RCP<std::ostream> outStream;
  Teuchos::oblackholestream bhs; // outputs nothing
  if (iprint > 0)
    outStream = Teuchos::rcp(&std::cout, false);
  else
    outStream = Teuchos::rcp(&bhs, false);

  // Save the format state of the original std::cout.
  Teuchos::oblackholestream oldFormatState;
  oldFormatState.copyfmt(std::cout);

  *outStream \
    << "===============================================================================\n" \
    << "|                                                                             |\n" \
    << "|                Unit Test (Basis_HGRAD_TRI_Cn_FEM_ORTH)                      |\n" \
    << "|                                                                             |\n" \
    << "|     1) Patch test involving mass and stiffness matrices,                    |\n" \
    << "|        for the Neumann problem on a triangular patch                        |\n" \
    << "|        Omega with boundary Gamma.                                           |\n" \
    << "|                                                                             |\n" \
    << "|        - div (grad u) + u = f  in Omega,  (grad u) . n = g  on Gamma        |\n" \
    << "|                                                                             |\n" \
    << "|  Questions? Contact  Pavel Bochev  ([email protected]),                    |\n" \
    << "|                      Denis Ridzal  ([email protected]),                    |\n" \
    << "|                      Kara Peterson ([email protected]).                    |\n" \
    << "|                                                                             |\n" \
    << "|  Intrepid's website: http://trilinos.sandia.gov/packages/intrepid           |\n" \
    << "|  Trilinos website:   http://trilinos.sandia.gov                             |\n" \
    << "|                                                                             |\n" \
    << "===============================================================================\n"\
    << "| TEST 1: Patch test                                                          |\n"\
    << "===============================================================================\n";

  
  int errorFlag = 0;

  outStream -> precision(16);


  try {

    int max_order = 10;                                                              // max total order of polynomial solution
    DefaultCubatureFactory<double>  cubFactory;                                      // create cubature factory
    shards::CellTopology cell(shards::getCellTopologyData< shards::Triangle<> >());  // create parent cell topology
    shards::CellTopology side(shards::getCellTopologyData< shards::Line<> >());      // create relevant subcell (side) topology
    int cellDim = cell.getDimension();
    int sideDim = side.getDimension();

    // Define array containing points at which the solution is evaluated, in reference cell.
    int numIntervals = 10;
    int numInterpPoints = ((numIntervals + 1)*(numIntervals + 2))/2;
    FieldContainer<double> interp_points_ref(numInterpPoints, 2);
    int counter = 0;
    for (int j=0; j<=numIntervals; j++) {
      for (int i=0; i<=numIntervals; i++) {
        if (i <= numIntervals-j) {
          interp_points_ref(counter,0) = i*(1.0/numIntervals);
          interp_points_ref(counter,1) = j*(1.0/numIntervals);
          counter++;
        }
      }
    }

    /* Parent cell definition. */
    FieldContainer<double> cell_nodes(1, 3, cellDim);
    // Perturbed reference triangle.
    cell_nodes(0, 0, 0) = 0.1;
    cell_nodes(0, 0, 1) = -0.1;
    cell_nodes(0, 1, 0) = 1.1;
    cell_nodes(0, 1, 1) = -0.1;
    cell_nodes(0, 2, 0) = 0.1;
    cell_nodes(0, 2, 1) = 0.9;
    // Reference triangle. 
    /*cell_nodes(0, 0, 0) = 0.0;
    cell_nodes(0, 0, 1) = 0.0;
    cell_nodes(0, 1, 0) = 1.0;
    cell_nodes(0, 1, 1) = 0.0;
    cell_nodes(0, 2, 0) = 0.0;
    cell_nodes(0, 2, 1) = 1.0;*/

    FieldContainer<double> interp_points(1, numInterpPoints, cellDim);
    CellTools<double>::mapToPhysicalFrame(interp_points, interp_points_ref, cell_nodes, cell);
    interp_points.resize(numInterpPoints, cellDim);

    for (int x_order=0; x_order <= max_order; x_order++) {
      for (int y_order=0; y_order <= max_order-x_order; y_order++) {

        // evaluate exact solution
        FieldContainer<double> exact_solution(1, numInterpPoints);
        u_exact(exact_solution, interp_points, x_order, y_order);

        int total_order = std::max(x_order + y_order, 1);

        for (int basis_order=total_order; basis_order <= max_order; basis_order++) {

          // set test tolerance
          double zero = basis_order*basis_order*100*INTREPID_TOL;

          //create basis
          Teuchos::RCP<Basis<double,FieldContainer<double> > > basis =
            Teuchos::rcp(new Basis_HGRAD_TRI_Cn_FEM_ORTH<double,FieldContainer<double> >(basis_order) );
          int numFields = basis->getCardinality();

          // create cubatures
          Teuchos::RCP<Cubature<double> > cellCub = cubFactory.create(cell, 2*basis_order);
          Teuchos::RCP<Cubature<double> > sideCub = cubFactory.create(side, 2*basis_order);
          int numCubPointsCell = cellCub->getNumPoints();
          int numCubPointsSide = sideCub->getNumPoints();

          /* Computational arrays. */
          /* Section 1: Related to parent cell integration. */
          FieldContainer<double> cub_points_cell(numCubPointsCell, cellDim);
          FieldContainer<double> cub_points_cell_physical(1, numCubPointsCell, cellDim);
          FieldContainer<double> cub_weights_cell(numCubPointsCell);
          FieldContainer<double> jacobian_cell(1, numCubPointsCell, cellDim, cellDim);
          FieldContainer<double> jacobian_inv_cell(1, numCubPointsCell, cellDim, cellDim);
          FieldContainer<double> jacobian_det_cell(1, numCubPointsCell);
          FieldContainer<double> weighted_measure_cell(1, numCubPointsCell);

          FieldContainer<double> value_of_basis_at_cub_points_cell(numFields, numCubPointsCell);
          FieldContainer<double> transformed_value_of_basis_at_cub_points_cell(1, numFields, numCubPointsCell);
          FieldContainer<double> weighted_transformed_value_of_basis_at_cub_points_cell(1, numFields, numCubPointsCell);
          FieldContainer<double> grad_of_basis_at_cub_points_cell(numFields, numCubPointsCell, cellDim);
          FieldContainer<double> transformed_grad_of_basis_at_cub_points_cell(1, numFields, numCubPointsCell, cellDim);
          FieldContainer<double> weighted_transformed_grad_of_basis_at_cub_points_cell(1, numFields, numCubPointsCell, cellDim);
          FieldContainer<double> fe_matrix(1, numFields, numFields);

          FieldContainer<double> rhs_at_cub_points_cell_physical(1, numCubPointsCell);
          FieldContainer<double> rhs_and_soln_vector(1, numFields);

          /* Section 2: Related to subcell (side) integration. */
          unsigned numSides = 3;
          FieldContainer<double> cub_points_side(numCubPointsSide, sideDim);
          FieldContainer<double> cub_weights_side(numCubPointsSide);
          FieldContainer<double> cub_points_side_refcell(numCubPointsSide, cellDim);
          FieldContainer<double> cub_points_side_physical(1, numCubPointsSide, cellDim);
          FieldContainer<double> jacobian_side_refcell(1, numCubPointsSide, cellDim, cellDim);
          FieldContainer<double> jacobian_det_side_refcell(1, numCubPointsSide);
          FieldContainer<double> weighted_measure_side_refcell(1, numCubPointsSide);

          FieldContainer<double> value_of_basis_at_cub_points_side_refcell(numFields, numCubPointsSide);
          FieldContainer<double> transformed_value_of_basis_at_cub_points_side_refcell(1, numFields, numCubPointsSide);
          FieldContainer<double> weighted_transformed_value_of_basis_at_cub_points_side_refcell(1, numFields, numCubPointsSide);
          FieldContainer<double> neumann_data_at_cub_points_side_physical(1, numCubPointsSide);
          FieldContainer<double> neumann_fields_per_side(1, numFields);

          /* Section 3: Related to global interpolant. */
          FieldContainer<double> value_of_basis_at_interp_points(numFields, numInterpPoints);
          FieldContainer<double> transformed_value_of_basis_at_interp_points(1, numFields, numInterpPoints);
          FieldContainer<double> interpolant(1, numInterpPoints);

          FieldContainer<int> ipiv(numFields);



          /******************* START COMPUTATION ***********************/

          // get cubature points and weights
          cellCub->getCubature(cub_points_cell, cub_weights_cell);

          // compute geometric cell information
          CellTools<double>::setJacobian(jacobian_cell, cub_points_cell, cell_nodes, cell);
          CellTools<double>::setJacobianInv(jacobian_inv_cell, jacobian_cell);
          CellTools<double>::setJacobianDet(jacobian_det_cell, jacobian_cell);

          // compute weighted measure
          FunctionSpaceTools::computeCellMeasure<double>(weighted_measure_cell, jacobian_det_cell, cub_weights_cell);

          ///////////////////////////
          // Computing mass matrices:
          // tabulate values of basis functions at (reference) cubature points
          basis->getValues(value_of_basis_at_cub_points_cell, cub_points_cell, OPERATOR_VALUE);

          // transform values of basis functions
          FunctionSpaceTools::HGRADtransformVALUE<double>(transformed_value_of_basis_at_cub_points_cell,
                                                          value_of_basis_at_cub_points_cell);

          // multiply with weighted measure
          FunctionSpaceTools::multiplyMeasure<double>(weighted_transformed_value_of_basis_at_cub_points_cell,
                                                      weighted_measure_cell,
                                                      transformed_value_of_basis_at_cub_points_cell);

          // compute mass matrices
          FunctionSpaceTools::integrate<double>(fe_matrix,
                                                transformed_value_of_basis_at_cub_points_cell,
                                                weighted_transformed_value_of_basis_at_cub_points_cell,
                                                COMP_BLAS);
          ///////////////////////////

          ////////////////////////////////
          // Computing stiffness matrices:
          // tabulate gradients of basis functions at (reference) cubature points
          basis->getValues(grad_of_basis_at_cub_points_cell, cub_points_cell, OPERATOR_GRAD);

          // transform gradients of basis functions
          FunctionSpaceTools::HGRADtransformGRAD<double>(transformed_grad_of_basis_at_cub_points_cell,
                                                         jacobian_inv_cell,
                                                         grad_of_basis_at_cub_points_cell);

          // multiply with weighted measure
          FunctionSpaceTools::multiplyMeasure<double>(weighted_transformed_grad_of_basis_at_cub_points_cell,
                                                      weighted_measure_cell,
                                                      transformed_grad_of_basis_at_cub_points_cell);

          // compute stiffness matrices and sum into fe_matrix
          FunctionSpaceTools::integrate<double>(fe_matrix,
                                                transformed_grad_of_basis_at_cub_points_cell,
                                                weighted_transformed_grad_of_basis_at_cub_points_cell,
                                                COMP_BLAS,
                                                true);
          ////////////////////////////////

          ///////////////////////////////
          // Computing RHS contributions:
          // map cell (reference) cubature points to physical space
          CellTools<double>::mapToPhysicalFrame(cub_points_cell_physical, cub_points_cell, cell_nodes, cell);

          // evaluate rhs function
          rhsFunc(rhs_at_cub_points_cell_physical, cub_points_cell_physical, x_order, y_order);

          // compute rhs
          FunctionSpaceTools::integrate<double>(rhs_and_soln_vector,
                                                rhs_at_cub_points_cell_physical,
                                                weighted_transformed_value_of_basis_at_cub_points_cell,
                                                COMP_BLAS);

          // compute neumann b.c. contributions and adjust rhs
          sideCub->getCubature(cub_points_side, cub_weights_side);
          for (unsigned i=0; i<numSides; i++) {
            // compute geometric cell information
            CellTools<double>::mapToReferenceSubcell(cub_points_side_refcell, cub_points_side, sideDim, (int)i, cell);
            CellTools<double>::setJacobian(jacobian_side_refcell, cub_points_side_refcell, cell_nodes, cell);
            CellTools<double>::setJacobianDet(jacobian_det_side_refcell, jacobian_side_refcell);

            // compute weighted edge measure
            FunctionSpaceTools::computeEdgeMeasure<double>(weighted_measure_side_refcell,
                                                           jacobian_side_refcell,
                                                           cub_weights_side,
                                                           i,
                                                           cell);

            // tabulate values of basis functions at side cubature points, in the reference parent cell domain
            basis->getValues(value_of_basis_at_cub_points_side_refcell, cub_points_side_refcell, OPERATOR_VALUE);
            // transform
            FunctionSpaceTools::HGRADtransformVALUE<double>(transformed_value_of_basis_at_cub_points_side_refcell,
                                                            value_of_basis_at_cub_points_side_refcell);

            // multiply with weighted measure
            FunctionSpaceTools::multiplyMeasure<double>(weighted_transformed_value_of_basis_at_cub_points_side_refcell,
                                                        weighted_measure_side_refcell,
                                                        transformed_value_of_basis_at_cub_points_side_refcell);

            // compute Neumann data
            // map side cubature points in reference parent cell domain to physical space
            CellTools<double>::mapToPhysicalFrame(cub_points_side_physical, cub_points_side_refcell, cell_nodes, cell);
            // now compute data
            neumann(neumann_data_at_cub_points_side_physical, cub_points_side_physical, jacobian_side_refcell,
                    cell, (int)i, x_order, y_order);

            FunctionSpaceTools::integrate<double>(neumann_fields_per_side,
                                                  neumann_data_at_cub_points_side_physical,
                                                  weighted_transformed_value_of_basis_at_cub_points_side_refcell,
                                                  COMP_BLAS);

            // adjust RHS
            RealSpaceTools<double>::add(rhs_and_soln_vector, neumann_fields_per_side);;
          }
          ///////////////////////////////

          /////////////////////////////
          // Solution of linear system:
          int info = 0;
          Teuchos::LAPACK<int, double> solver;
          solver.GESV(numFields, 1, &fe_matrix[0], numFields, &ipiv(0), &rhs_and_soln_vector[0], numFields, &info);
          /////////////////////////////

          ////////////////////////
          // Building interpolant:
          // evaluate basis at interpolation points
          basis->getValues(value_of_basis_at_interp_points, interp_points_ref, OPERATOR_VALUE);
          // transform values of basis functions
          FunctionSpaceTools::HGRADtransformVALUE<double>(transformed_value_of_basis_at_interp_points,
                                                          value_of_basis_at_interp_points);
          FunctionSpaceTools::evaluate<double>(interpolant, rhs_and_soln_vector, transformed_value_of_basis_at_interp_points);
          ////////////////////////

          /******************* END COMPUTATION ***********************/
      
          RealSpaceTools<double>::subtract(interpolant, exact_solution);

          *outStream << "\nRelative norm-2 error between exact solution polynomial of order ("
                     << x_order << ", " << y_order << ") and finite element interpolant of order " << basis_order << ": "
                     << RealSpaceTools<double>::vectorNorm(&interpolant[0], interpolant.dimension(1), NORM_TWO) /
                        RealSpaceTools<double>::vectorNorm(&exact_solution[0], exact_solution.dimension(1), NORM_TWO) << "\n";

          if (RealSpaceTools<double>::vectorNorm(&interpolant[0], interpolant.dimension(1), NORM_TWO) /
              RealSpaceTools<double>::vectorNorm(&exact_solution[0], exact_solution.dimension(1), NORM_TWO) > zero) {
            *outStream << "\n\nPatch test failed for solution polynomial order ("
                       << x_order << ", " << y_order << ") and basis order " << basis_order << "\n\n";
            errorFlag++;
          }
        } // end for basis_order
      } // end for y_order
    } // end for x_order

  }
  // Catch unexpected errors
  catch (std::logic_error err) {
    *outStream << err.what() << "\n\n";
    errorFlag = -1000;
  };

  if (errorFlag != 0)
    std::cout << "End Result: TEST FAILED\n";
  else
    std::cout << "End Result: TEST PASSED\n";

  // reset format state of std::cout
  std::cout.copyfmt(oldFormatState);
 Kokkos::finalize();
  return errorFlag;
}
Example #19
0
int main(int argc, char *argv[]) {

  using FC  = FieldContainer<double>;
  using CT  = CellTools<double>;
  using FST = FunctionSpaceTools;
  using AT  = ArrayTools;

  using Teuchos::RCP;
  using Teuchos::rcpFromRef;
  using Vector = Teuchos::SerialDenseVector<int,double>;
  using Matrix = Teuchos::SerialDenseMatrix<int,double>;
  using Solver = Teuchos::SerialDenseSolver<int,double>;

  Teuchos::GlobalMPISession mpiSession(&argc, &argv);

  // This little trick lets us print to std::cout only if
  // a (dummy) command-line argument is provided.
  int iprint     = argc - 1;
  Teuchos::RCP<std::ostream> outStream;
  Teuchos::oblackholestream bhs; // outputs nothing
  if (iprint > 0)
    outStream = Teuchos::rcp(&std::cout, false);
  else
    outStream = Teuchos::rcp(&bhs, false);
  // Save the format state of the original std::cout.
  Teuchos::oblackholestream oldFormatState;
  oldFormatState.copyfmt(std::cout);

  *outStream \
    << "=============================================================================\n" \
    << "|                                                                           |\n" \
    << "|                Unit Test (Basis_HGRAD_LINE_Hermite_FEM)                   |\n" \
    << "|                                                                           |\n" \
    << "|   Solve the cantilevered Euler-Bernoulli static beam equation with unit   |\n" \
    << "|   second moment of area and verify using a manufactured solution.         |\n" \
    << "|                                                                           |\n" \
    << "|                          D^2[E(x) D^2 w(x) = q(x)                         |\n" \
    << "|                                                                           |\n" \
    << "|   with clamped boundary conditions    w(0) = 0,       w'(0) = 0           |\n" \
    << "|   stress boundary condition           E(1)w\"(1)=-6                        |\n" \
    << "|   and shear force boundary condition  [Ew\"]'(1)=-6                        |\n" \
    << "|                                                                           |\n" \
    << "|   The exact deflection is w(x) = 3x^2-2*x^3                               |\n" \
    << "|   The elastic modulus is  E(x) = 2-x                                      |\n" \
    << "|   The forcing term is     q(x) = 24                                       |\n" \
    << "|                                                                           |\n" \
    << "|   Questions? Contact  Pavel Bochev  ([email protected]),                 |\n" \
    << "|                       Denis Ridzal  ([email protected]),                 |\n" \
    << "|                       Kara Peterson ([email protected]).                 |\n" \
    << "|                                                                           |\n" \
    << "|   Intrepid's website: http://trilinos.sandia.gov/packages/intrepid        |\n" \
    << "|   Trilinos website:   http://trilinos.sandia.gov                          |\n" \
    << "|                                                                           |\n" \
    << "=============================================================================\n";

  int errorFlag = 0;


  try {
  
    shards::CellTopology line(shards::getCellTopologyData<shards::Line<2>>());

    DefaultCubatureFactory<double> cubFactory;

    int numCells  = 10;        // Number of cells
    int numVert   = 2;         // Number of vertices per cell
    int cubOrder  = 8;         // Highest order of polynomial to integrate exactly
    int numPts    = 3;         // Number of interpolation points per cell
    int numFields = 2*numPts;  // Number of basis functions per cell
    int spaceDim  = 1;         // Number of spatial dimensions

    double length = 1.0;                   // Computatonal domain length
    double cellLength = length/numCells;

    *outStream << "\n\nDiscretization Details"      << std::endl;
    *outStream << "-------------------------------" << std::endl; 
    *outStream << "Number of cells           = "    << numCells   << std::endl;
    *outStream << "Cubature order            = "    << cubOrder   << std::endl;
    *outStream << "Number of basis functions = "    << numFields  << std::endl;
    *outStream << "Physical cell length      = "    << cellLength << std::endl;

    // Total degrees of freedom 
    // Exclude 2 for the clamped boundary condition at x=0
    // Exclude 2 per cell for value and derivative node condensation
    int numDof = numCells*(numFields-2);

    *outStream << "Total degrees of freedom  = " << numDof << std::endl; 

    FC cellVert(numCells,numVert,spaceDim);  // Elemental end points
 
    // Set cell vertices
    for(int cell=0; cell<numCells; ++cell ) {
      cellVert(cell,0,0) = cell*cellLength;
      cellVert(cell,1,0) = (cell+1)*cellLength;   
    }   
 
   
    /*****************************************/
    /*   CREATE CELL AND PHYSICAL CUBATURE   */
    /*****************************************/

    RCP<Cubature<double>> cellCub = cubFactory.create(line,cubOrder);

    FC cubPts(cubOrder, spaceDim);               // Reference cell cubature points
    FC cubWts(cubOrder);                         // Reference cell cubature weights
    cellCub->getCubature(cubPts,cubWts);
 
    // Determine how many points are used and resize accordingly
    int numCubPts = cellCub->getNumPoints();

    *outStream << "Number of cubature points = " << numCubPts << std::endl; 

    cubPts.resize(numCubPts,spaceDim);
    cubWts.resize(numCubPts);

    FC physCubPts(numCells,numCubPts, spaceDim); // Physical cubature points
    FC wtdMeasure(numCells,numCubPts);          
    
    CellTools<double>::mapToPhysicalFrame(physCubPts,cubPts,cellVert,line);

    *outStream << std::setprecision(5) << std::endl;
    *outStream << "Cell Vertices:" << std::endl;;
    for(int cell=0; cell<numCells; ++cell) {
      *outStream << std::setw(5) << cellVert(cell,0,0); 
    }
    *outStream << std::setw(5) << cellVert(numCells-1,1,0) << std::endl; 
 
    *outStream << "\nReference cell cubature points:" << std::endl;
    for(int pt=0; pt<numCubPts; ++pt) {
      *outStream << std::setw(10) << cubPts(pt,0);
    }
    *outStream << std::endl;
   
    *outStream << "\nReference cell cubature weights:" << std::endl;
    for( int pt=0; pt<numCubPts; ++pt) {
      *outStream << std::setw(10) << cubWts(pt);
    }
    *outStream << std::endl;

    *outStream << "\nPhysical cubature points:\n" << std::endl;
    *outStream << std::setw(7) << "Cell\\Pt | ";
    for(int pt=0; pt<numCubPts; ++pt) {
      *outStream << std::setw(10) << pt;
    }  
    *outStream << std::endl;
    
    *outStream << std::string(10*(1+numCubPts),'-') << std::endl;
    for(int cell=0; cell<numCells; ++cell){
      *outStream << std::setw(7) << cell << " | ";
      for(int pt=0; pt<numCubPts; ++pt) {
        *outStream << std::setw(10) << physCubPts(cell,pt,0);   
      } 
      *outStream << std::endl;
    }


    /********************************************/
    /*   ELASTIC MODULUS AND FORCING FUNCTION   */
    /********************************************/

    FC elasmod(numCells,numCubPts); 
    FC qforce(numCells,numCubPts);

    for(int cell=0; cell<numCells; ++cell) {

      for(int pt=0; pt<numCubPts; ++pt) {
        double x = physCubPts(cell,pt,0);
        elasmod(cell,pt) = 2.0-x; //std::exp(-x);
        qforce(cell,pt)  = 24.0; // 4.0-3.0*x; //6*x;  // (x-2.0)*std::exp(-x);
      }
    }   

    /****************************************/
    /*   CREATE HERMITE INTERPOLANT BASIS   */
    /****************************************/


    FC pts(PointTools::getLatticeSize(line,numPts-1),1);
    PointTools::getLattice<double,FC>(pts,line,numPts-1);

    *outStream << "\nReference cell interpolation points:" << std::endl;
    for(int pt=0; pt<numPts; ++pt) {
      *outStream << std::setw(10) << pts(pt,0);
    }
    *outStream << std::endl;
    

    FC physPts(numCells, numPts, spaceDim);  // Physical interpolation points
    CellTools<double>::mapToPhysicalFrame(physPts,pts,cellVert,line);

    *outStream << "\nPhysical interpolation points:\n" << std::endl;
    *outStream << std::setw(7) << "Cell\\Pt | ";
    for(int pt=0; pt<numPts; ++pt) {
      *outStream << std::setw(10) << pt;
    }  
    *outStream << std::endl;
    
    *outStream << std::string(10*(1+numPts),'-') << std::endl;
    for(int cell=0; cell<numCells; ++cell){
      *outStream << std::setw(7) << cell << " | ";
      for(int pt=0; pt<numPts; ++pt) {
        *outStream << std::setw(10) << physPts(cell,pt,0);   
      } 
      *outStream << std::endl;
    }

    Basis_HGRAD_LINE_Hermite_FEM<double,FC> hermiteBasis(pts);

    FC valsCubPts(numFields,numCubPts);
    FC der2CubPts(numFields,numCubPts,spaceDim);
    
    hermiteBasis.getValues(valsCubPts,cubPts,OPERATOR_VALUE);
    hermiteBasis.getValues(der2CubPts,cubPts,OPERATOR_D2);

    FC jacobian(numCells,numCubPts,spaceDim,spaceDim);
    FC jacInv(numCells,numCubPts,spaceDim,spaceDim);
    FC jacDet(numCells,numCubPts);

    FC tranValsCubPts(numCells,numFields,numCubPts);
    FC tranDer2CubPts(numCells,numFields,numCubPts,spaceDim);
    FC wtdTranValsCubPts(numCells,numFields,numCubPts);
    FC wtdTranDer2CubPts(numCells,numFields,numCubPts,spaceDim);    

    CT::setJacobian(jacobian,cubPts,cellVert,line);
    CT::setJacobianInv(jacInv,jacobian);
    CT::setJacobianDet(jacDet,jacobian);

    FST::computeCellMeasure<double>(wtdMeasure,jacDet,cubWts);
    FST::HGRADtransformVALUE<double>(tranValsCubPts,valsCubPts); 

    // There is no predefined transform for second derivatives
    // Note that applying the Jacobian inverse twice is only valid because of the
    // affine mapping between reference and physical cells. For general nonlinear
    // mappings, second order terms would be needed. 

    // Apply once
    AT::matvecProductDataField<double>(tranDer2CubPts,jacInv,der2CubPts);
    FC temp_Der2CubPts(tranDer2CubPts);

    // Apply twice
    AT::matvecProductDataField<double>(tranDer2CubPts,jacInv,temp_Der2CubPts);


    // Scale derivative interpolants by cell length

    for( int cell=0; cell<numCells; ++cell ) {
      double scale = (cellVert(cell,1,0)-cellVert(cell,0,0))/2.0;
      for( int field=0; field<numFields/2; ++field ) {
        for( int pt=0; pt<numCubPts; ++pt ) { 
          tranValsCubPts(cell,2*field+1,pt)   *= scale;
          tranDer2CubPts(cell,2*field+1,pt,0) *= scale;
        }
      }
    }
 
    /********************************************/
    /*   EVALUATE FORCING AND STIFFNESS TERMS   */
    /********************************************/

    FST::multiplyMeasure<double>(wtdTranValsCubPts,wtdMeasure,tranValsCubPts);

    FST::multiplyMeasure<double>(wtdTranDer2CubPts,wtdMeasure,tranDer2CubPts);
    FC temp_wtdTranDer2CubPts(wtdTranDer2CubPts);
    FST::multiplyMeasure<double>(wtdTranDer2CubPts,elasmod,temp_wtdTranDer2CubPts);

    FC loadVectors(numCells,numFields);
    FC stiffnessMatrices(numCells,numFields,numFields);
    
    FST::integrate(loadVectors, qforce, wtdTranValsCubPts, COMP_CPP);
    FST::integrate(stiffnessMatrices, tranDer2CubPts, wtdTranDer2CubPts, COMP_CPP); 

    /***********************************************************/
    /*   ASSEMBLY OF GLOBAL STIFFNESS MATRIX AND LOAD VECTOR   */
    /***********************************************************/

    Vector q(numDof);           // Global Load Vector
    Vector w(numDof);           // Global Displacement Vector (solution)
    Matrix K(numDof,numDof);    // Global Stiffness Matrix
    
    // For the first cell, we exclude the first two fields to enforce the clamped
    // boundary condition at x=0

    for( int row=0; row<numFields-2; ++row ) {
      q(row) = loadVectors(0,row+2);
      for(int col=0; col<numFields-2; ++col ) {
        K(row,col) = stiffnessMatrices(0,row+2,col+2);
      }  
    }

    for( int cell=1; cell<numCells; ++cell ) {
      for( int rf=0; rf<numFields; ++rf ) {
        int row = rf + (numFields-2)*cell-2;
        q(row) += loadVectors(cell,rf);

        for( int cf=0; cf<numFields; ++cf ) {
          int col = cf + (numFields-2)*cell-2;
          K(row,col) += stiffnessMatrices(cell,rf,cf); 
        } 
      }
    } 

    // Boundary conditions
    q(numDof-2) += 6.0;  // Stress boundary condition
    q(numDof-1) -= 6.0;  // Shear force boundary condition

    Solver solver;
    solver.setMatrix(rcpFromRef(K));
    solver.factorWithEquilibration(true);
    solver.factor();
    solver.setVectors(rcpFromRef(w),rcpFromRef(q));
    solver.solve();
  
    int dim = 1+numDof/2;
    Vector w0( dim );
    Vector w1( dim );

    // Separate solution into value and derivative
    for(int i=1; i<dim; ++i) {
       w0(i) = w(2*i-2);   // Extract deflection values
       w1(i) = w(2*i-1);   // Extract deflection derivatives
    }

    // Create exact solution and its derivative
    Vector w0_exact( dim );
    Vector w1_exact( dim );

    int row=0;
    for( int cell=0; cell<numCells; ++cell ) {
      for( int pt=0; pt<numPts-1; ++pt ) {
        double x = physPts(cell,pt,0);
        w0_exact(row) = (3.0-2*x)*x*x;
        w1_exact(row) = 6.0*x*(1.0-x);
        row++;
      }
    }

    w0_exact(dim-1) = 1.0;

    double error0 = 0;
    double error1 = 0;

    for( int i=0; i<dim; ++i ) {
      error0 += std::pow(w0(i)-w0_exact(i),2);
      error1 += std::pow(w1(i)-w1_exact(i),2);
    }
 
    error0 = std::sqrt(error0);
    error1 = std::sqrt(error1);

    *outStream << "\n\n";
    *outStream << "|w-w_exact|   = " << error0 << std::endl;
    *outStream << "|w'-w'_exact| = " << error1 << std::endl;

    double tolerance = 2e-10;

    if( error0 > tolerance ) {
      *outStream << "Solution failed to converge within tolerance" << std::endl;
      errorFlag++;
    }

    if( error1 > tolerance ) {
      *outStream << "Derivative of solution failed to converge within tolerance" << std::endl;
      errorFlag++;
    }

  }

  // Catch unexpected errors
  catch (std::logic_error err) {
    *outStream << err.what() << "\n\n";
    errorFlag = -1000;
  };

  if (errorFlag != 0)
    std::cout << "End Result: TEST FAILED\n";
  else
    std::cout << "End Result: TEST PASSED\n";

  // reset format state of std::cout
  std::cout.copyfmt(oldFormatState);

  return errorFlag;
}