MxDimMatrix<T, DIM> MxDimMatrix<T, DIM>::inv() const { MxDimMatrix<T, DIM> thisT = this->transpose(); MxDimMatrix<T, DIM> solnT(MxDimVector<T, DIM>(1)); int info; int ipiv[DIM]; Teuchos::LAPACK<int, T> lapack; lapack.GESV(DIM, DIM, &thisT(0, 0), DIM, ipiv, &solnT(0, 0), DIM, &info); if (info != 0) std::cout << "MxDimMatrix::inv(): error in lapack routine. Return code: " << info << ".\n"; return solnT.transpose(); }
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_TET_Cn_FEM) |\n" \ << "| |\n" \ << "| 1) Patch test involving mass and stiffness matrices, |\n" \ << "| for the Neumann problem on a tetrahedral 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 = 5; // max total order of polynomial solution DefaultCubatureFactory<double> cubFactory; // create factory shards::CellTopology cell(shards::getCellTopologyData< shards::Tetrahedron<> >()); // create parent cell topology shards::CellTopology side(shards::getCellTopologyData< shards::Triangle<> >()); // create relevant subcell (side) topology int cellDim = cell.getDimension(); int sideDim = side.getDimension(); // Define array containing points at which the solution is evaluated, on the reference tet. int numIntervals = 10; int numInterpPoints = ((numIntervals + 1)*(numIntervals + 2)*(numIntervals + 3))/6; FieldContainer<double> interp_points_ref(numInterpPoints, 3); int counter = 0; for (int k=0; k<=numIntervals; k++) { for (int j=0; j<=numIntervals; j++) { for (int i=0; i<=numIntervals; i++) { if (i+j+k <= numIntervals) { 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++; } } } } /* Definition of parent cell. */ FieldContainer<double> cell_nodes(1, 4, cellDim); // funky tet cell_nodes(0, 0, 0) = -1.0; cell_nodes(0, 0, 1) = -2.0; cell_nodes(0, 0, 2) = 0.0; cell_nodes(0, 1, 0) = 6.0; cell_nodes(0, 1, 1) = 2.0; cell_nodes(0, 1, 2) = 0.0; cell_nodes(0, 2, 0) = -5.0; cell_nodes(0, 2, 1) = 1.0; cell_nodes(0, 2, 2) = 0.0; cell_nodes(0, 3, 0) = -4.0; cell_nodes(0, 3, 1) = -1.0; cell_nodes(0, 3, 2) = 3.0; // perturbed reference tet /*cell_nodes(0, 0, 0) = 0.1; cell_nodes(0, 0, 1) = -0.1; cell_nodes(0, 0, 2) = 0.2; cell_nodes(0, 1, 0) = 1.2; cell_nodes(0, 1, 1) = -0.1; cell_nodes(0, 1, 2) = 0.05; cell_nodes(0, 2, 0) = 0.0; cell_nodes(0, 2, 1) = 0.9; cell_nodes(0, 2, 2) = 0.1; cell_nodes(0, 3, 0) = 0.1; cell_nodes(0, 3, 1) = -0.1; cell_nodes(0, 3, 2) = 1.1;*/ // reference tet /*cell_nodes(0, 0, 0) = 0.0; cell_nodes(0, 0, 1) = 0.0; cell_nodes(0, 0, 2) = 0.0; cell_nodes(0, 1, 0) = 1.0; cell_nodes(0, 1, 1) = 0.0; cell_nodes(0, 1, 2) = 0.0; cell_nodes(0, 2, 0) = 0.0; cell_nodes(0, 2, 1) = 1.0; cell_nodes(0, 2, 2) = 0.0; cell_nodes(0, 3, 0) = 0.0; cell_nodes(0, 3, 1) = 0.0; cell_nodes(0, 3, 2) = 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); // we test two types of bases EPointType pointtype[] = {POINTTYPE_EQUISPACED, POINTTYPE_WARPBLEND}; for (int ptype=0; ptype < 2; ptype++) { *outStream << "\nTesting bases with " << EPointTypeToString(pointtype[ptype]) << ":\n"; for (int x_order=0; x_order <= max_order; x_order++) { for (int y_order=0; y_order <= max_order-x_order; y_order++) { for (int z_order=0; z_order <= max_order-x_order-y_order; z_order++) { // evaluate exact solution FieldContainer<double> exact_solution(1, numInterpPoints); u_exact(exact_solution, interp_points, x_order, y_order, z_order); int total_order = std::max(x_order + y_order + z_order, 1); for (int basis_order=total_order; basis_order <= max_order; basis_order++) { // set test tolerance; double zero = basis_order*basis_order*basis_order*100*INTREPID_TOL; //create basis Teuchos::RCP<Basis<double,FieldContainer<double> > > basis = Teuchos::rcp(new Basis_HGRAD_TET_Cn_FEM<double,FieldContainer<double> >(basis_order, pointtype[ptype]) ); 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 = 4; 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_ref(numFields, numInterpPoints); FieldContainer<double> transformed_value_of_basis_at_interp_points_ref(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, z_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 face measure FunctionSpaceTools::computeFaceMeasure<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, z_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_ref, interp_points_ref, OPERATOR_VALUE); // transform values of basis functions FunctionSpaceTools::HGRADtransformVALUE<double>(transformed_value_of_basis_at_interp_points_ref, value_of_basis_at_interp_points_ref); FunctionSpaceTools::evaluate<double>(interpolant, rhs_and_soln_vector, transformed_value_of_basis_at_interp_points_ref); //////////////////////// /******************* END COMPUTATION ***********************/ RealSpaceTools<double>::subtract(interpolant, exact_solution); *outStream << "\nRelative norm-2 error between exact solution polynomial of order (" << x_order << ", " << y_order << ", " << z_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 << ", " << z_order << ") and basis order " << basis_order << "\n\n"; errorFlag++; } } // end for basis_order } // end for z_order } // end for y_order } // end for x_order } // end for ptype } // 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; }
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; }
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; }
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_QUAD_C2_FEM) |\n" \ << "| |\n" \ << "| 1) Patch test involving mass and stiffness matrices, |\n" \ << "| for the Neumann problem on a physical parallelogram |\n" \ << "| AND a reference quad Omega with boundary Gamma. |\n" \ << "| |\n" \ << "| - div (grad u) + u = f in Omega, (grad u) . n = g on Gamma |\n" \ << "| |\n" \ << "| For a generic parallelogram, the basis recovers a complete |\n" \ << "| polynomial space of order 2. On a (scaled and/or translated) |\n" \ << "| reference quad, the basis recovers a complete tensor product |\n" \ << "| space of order 2 (i.e. incl. the x^2*y, x*y^2, x^2*y^2 terms). |\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 = 2; // max total order of polynomial solution DefaultCubatureFactory<double> cubFactory; // create cubature factory shards::CellTopology cell(shards::getCellTopologyData< shards::Quadrilateral<> >()); // 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 + 1); FieldContainer<double> interp_points_ref(numInterpPoints, 2); int counter = 0; for (int j=0; j<=numIntervals; j++) { for (int i=0; i<=numIntervals; i++) { interp_points_ref(counter,0) = i*(2.0/numIntervals)-1.0; interp_points_ref(counter,1) = j*(2.0/numIntervals)-1.0; counter++; } } /* Parent cell definition. */ FieldContainer<double> cell_nodes[2]; cell_nodes[0].resize(1, 4, cellDim); cell_nodes[1].resize(1, 4, cellDim); // Generic parallelogram. cell_nodes[0](0, 0, 0) = -5.0; cell_nodes[0](0, 0, 1) = -1.0; cell_nodes[0](0, 1, 0) = 4.0; cell_nodes[0](0, 1, 1) = 1.0; cell_nodes[0](0, 2, 0) = 8.0; cell_nodes[0](0, 2, 1) = 3.0; cell_nodes[0](0, 3, 0) = -1.0; cell_nodes[0](0, 3, 1) = 1.0; // Reference quad. cell_nodes[1](0, 0, 0) = -1.0; cell_nodes[1](0, 0, 1) = -1.0; cell_nodes[1](0, 1, 0) = 1.0; cell_nodes[1](0, 1, 1) = -1.0; cell_nodes[1](0, 2, 0) = 1.0; cell_nodes[1](0, 2, 1) = 1.0; cell_nodes[1](0, 3, 0) = -1.0; cell_nodes[1](0, 3, 1) = 1.0; std::stringstream mystream[2]; mystream[0].str("\n>> Now testing basis on a generic parallelogram ...\n"); mystream[1].str("\n>> Now testing basis on the reference quad ...\n"); for (int pcell = 0; pcell < 2; pcell++) { *outStream << mystream[pcell].str(); FieldContainer<double> interp_points(1, numInterpPoints, cellDim); CellTools<double>::mapToPhysicalFrame(interp_points, interp_points_ref, cell_nodes[pcell], cell); interp_points.resize(numInterpPoints, cellDim); for (int x_order=0; x_order <= max_order; x_order++) { int max_y_order = max_order; if (pcell == 0) { max_y_order -= x_order; } for (int y_order=0; y_order <= max_y_order; y_order++) { // evaluate exact solution FieldContainer<double> exact_solution(1, numInterpPoints); u_exact(exact_solution, interp_points, x_order, y_order); int basis_order = 2; // 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_QUAD_C2_FEM<double,FieldContainer<double> >() ); 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 = 4; 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[pcell], 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[pcell], 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[pcell], 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[pcell], 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 y_order } // end for x_order } // end for pcell } // 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; }
// ---------------------------------------------------------------------- // Main // // 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; for (int i=0;i<argc;++i) { if ((strcmp(argv[i],"--nelement") == 0)) { nelement = atoi(argv[++i]); continue;} if ((strcmp(argv[i],"--apply-orientation") == 0)) { apply_orientation = atoi(argv[++i]); continue;} if ((strcmp(argv[i],"--verbose") == 0)) { verbose = atoi(argv[++i]); continue;} if ((strcmp(argv[i],"--maxp") == 0)) { maxp = atoi(argv[++i]); continue;} } 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 << std::scientific; *outStream \ << "===============================================================================\n" \ << "| |\n" \ << "| Unit Test (Basis_HGRAD_TRI_Cn_FEM) |\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" \ << "| Kyungjoo Kim ([email protected]). |\n" \ << "| |\n" \ << "| Intrepid's website: http://trilinos.sandia.gov/packages/intrepid |\n" \ << "| Trilinos website: http://trilinos.sandia.gov |\n" \ << "| |\n" \ << "===============================================================================\n" \ << "| TEST 4: Patch test for high order assembly |\n" \ << "===============================================================================\n"; int r_val = 0; // precision control outStream->precision(3); #if defined( INTREPID_USING_EXPERIMENTAL_HIGH_ORDER ) try { // test setup const int ndim = 2; FieldContainer<value_type> base_nodes(1, 4, ndim); base_nodes(0, 0, 0) = 0.0; base_nodes(0, 0, 1) = 0.0; base_nodes(0, 1, 0) = 1.0; base_nodes(0, 1, 1) = 0.0; base_nodes(0, 2, 0) = 0.0; base_nodes(0, 2, 1) = 1.0; base_nodes(0, 3, 0) = 1.0; base_nodes(0, 3, 1) = 1.0; // element 0 has globally permuted edge node const int elt_0[2][3] = { { 0, 1, 2 }, { 0, 2, 1 } }; // element 1 is locally permuted int elt_1[3] = { 1, 2, 3 }; DefaultCubatureFactory<value_type> cubature_factory; // for all test orders for (int nx=0;nx<=maxp;++nx) { for (int ny=0;ny<=maxp-nx;++ny) { // polynomial order of approximation const int minp = std::max(nx+ny, 1); // test for all basis above order p const EPointType pointtype[] = { POINTTYPE_EQUISPACED, POINTTYPE_WARPBLEND }; for (int ptype=0;ptype<2;++ptype) { for (int p=minp;p<=maxp;++p) { *outStream << "\n" \ << "===============================================================================\n" \ << " Order (nx,ny,p) = " << nx << ", " << ny << ", " << p << " , PointType = " << EPointTypeToString(pointtype[ptype]) << "\n" \ << "===============================================================================\n"; BasisSet_HGRAD_TRI_Cn_FEM<value_type,FieldContainer<value_type> > basis_set(p, pointtype[ptype]); const auto& basis = basis_set.getCellBasis(); const shards::CellTopology cell = basis.getBaseCellTopology(); const int nbf = basis.getCardinality(); const int nvert = cell.getVertexCount(); const int nedge = cell.getEdgeCount(); FieldContainer<value_type> nodes(1, 4, ndim); FieldContainer<value_type> cell_nodes(1, nvert, ndim); // ignore the subdimension; the matrix is always considered as 1D array FieldContainer<value_type> A(1, nbf, nbf), b(1, nbf); // ***** Test for different orientations ***** for (int conf0=0;conf0<2;++conf0) { for (int ino=0;ino<3;++ino) { nodes(0, elt_0[conf0][ino], 0) = base_nodes(0, ino, 0); nodes(0, elt_0[conf0][ino], 1) = base_nodes(0, ino, 1); } nodes(0, 3, 0) = base_nodes(0, 3, 0); nodes(0, 3, 1) = base_nodes(0, 3, 1); // reset element connectivity elt_1[0] = 1; elt_1[1] = 2; elt_1[2] = 3; // for all permuations of element 1 for (int conf1=0;conf1<6;++conf1) { // filter out left handed element fill_cell_nodes(cell_nodes, nodes, elt_1, nvert, ndim); if (OrientationTools<value_type>::isLeftHandedCell(cell_nodes)) { // skip left handed } else { const int *element[2] = { elt_0[conf0], elt_1 }; *outStream << "\n" \ << " Element 0 is configured " << conf0 << " " << "(" << element[0][0] << ","<< element[0][1] << "," << element[0][2] << ")" << " Element 1 is configured " << conf1 << " " << "(" << element[1][0] << ","<< element[1][1] << "," << element[1][2] << ")" << "\n"; if (verbose) { *outStream << " - Element nodal connectivity - \n"; for (int iel=0;iel<nelement;++iel) *outStream << " iel = " << std::setw(4) << iel << ", nodes = " << std::setw(4) << element[iel][0] << std::setw(4) << element[iel][1] << std::setw(4) << element[iel][2] << "\n"; } // Step 0: count one-to-one mapping between high order nodes and dofs Example::ToyMesh mesh; int local2global[2][8][2], boundary[2][3], off_global = 0; const int nnodes_per_element = cell.getVertexCount() + cell.getEdgeCount() + 1; for (int iel=0;iel<nelement;++iel) mesh.getLocalToGlobalMap(local2global[iel], off_global, basis, element[iel]); for (int iel=0;iel<nelement;++iel) mesh.getBoundaryFlags(boundary[iel], cell, element[iel]); if (verbose) { *outStream << " - Element one-to-one local2global map -\n"; for (int iel=0;iel<nelement;++iel) { *outStream << " iel = " << std::setw(4) << iel << "\n"; for (int i=0;i<(nnodes_per_element+1);++i) { *outStream << " local = " << std::setw(4) << local2global[iel][i][0] << " global = " << std::setw(4) << local2global[iel][i][1] << "\n"; } } *outStream << " - Element boundary flags -\n"; const int nside = cell.getSideCount(); for (int iel=0;iel<nelement;++iel) { *outStream << " iel = " << std::setw(4) << iel << "\n"; for (int i=0;i<nside;++i) { *outStream << " side = " << std::setw(4) << i << " boundary = " << std::setw(4) << boundary[iel][i] << "\n"; } } } // Step 1: assembly const int ndofs = off_global; FieldContainer<value_type> A_asm(1, ndofs, ndofs), b_asm(1, ndofs); for (int iel=0;iel<nelement;++iel) { // Step 1.1: create element matrices Orientation ort = Orientation::getOrientation(cell, element[iel]); // set element nodal coordinates fill_cell_nodes(cell_nodes, nodes, element[iel], nvert, ndim); build_element_matrix_and_rhs(A, b, cubature_factory, basis_set, element[iel], boundary[iel], cell_nodes, ort, nx, ny); // if p is bigger than 4, not worth to look at the matrix if (verbose && p < 5) { *outStream << " - Element matrix and rhs, iel = " << iel << "\n"; *outStream << std::showpos; for (int i=0;i<nbf;++i) { for (int j=0;j<nbf;++j) *outStream << MatVal(A, i, j) << " "; *outStream << ":: " << MatVal(b, i, 0) << "\n"; } *outStream << std::noshowpos; } // Step 1.2: assemble high order elements assemble_element_matrix_and_rhs(A_asm, b_asm, A, b, local2global[iel], nnodes_per_element); } if (verbose && p < 5) { *outStream << " - Assembled element matrix and rhs -\n"; *outStream << std::showpos; for (int i=0;i<ndofs;++i) { for (int j=0;j<ndofs;++j) *outStream << MatVal(A_asm, i, j) << " "; *outStream << ":: " << MatVal(b_asm, i, 0) << "\n"; } *outStream << std::noshowpos; } // Step 2: solve the system of equations int info = 0; Teuchos::LAPACK<int,value_type> lapack; FieldContainer<int> ipiv(ndofs); lapack.GESV(ndofs, 1, &A_asm(0,0,0), ndofs, &ipiv(0,0), &b_asm(0,0), ndofs, &info); TEUCHOS_TEST_FOR_EXCEPTION( info != 0, std::runtime_error, ">>> ERROR (Intrepid::HGRAD_TRI_Cn::Test 04): " \ "LAPACK solve fails"); // Step 3: construct interpolant and check solutions magnitude_type interpolation_error = 0, solution_norm =0; for (int iel=0;iel<nelement;++iel) { retrieve_element_solution(b, b_asm, local2global[iel], nnodes_per_element); if (verbose && p < 5) { *outStream << " - Element solution, iel = " << iel << "\n"; *outStream << std::showpos; for (int i=0;i<nbf;++i) { *outStream << MatVal(b, i, 0) << "\n"; } *outStream << std::noshowpos; } magnitude_type element_interpolation_error = 0, element_solution_norm = 0; Orientation ort = Orientation::getOrientation(cell, element[iel]); // set element nodal coordinates fill_cell_nodes(cell_nodes, nodes, element[iel], nvert, ndim); compute_element_error(element_interpolation_error, element_solution_norm, element[iel], cell_nodes, basis_set, b, ort, nx, ny); interpolation_error += element_interpolation_error; solution_norm += element_solution_norm; { int edge_orts[3]; ort.getEdgeOrientation(edge_orts, nedge); *outStream << " iel = " << std::setw(4) << iel << ", orientation = " << edge_orts[0] << edge_orts[1] << edge_orts[2] << " , error = " << element_interpolation_error << " , solution norm = " << element_solution_norm << " , relative error = " << (element_interpolation_error/element_solution_norm) << "\n"; } const magnitude_type relative_error = interpolation_error/solution_norm; const magnitude_type tol = p*p*100*INTREPID_TOL; if (relative_error > tol) { ++r_val; *outStream << "\n\nPatch test failed: \n" << " exact polynomial (nx, ny) = " << std::setw(4) << nx << ", " << std::setw(4) << ny << "\n" << " basis order = " << std::setw(4) << p << "\n" << " orientation configuration = " << std::setw(4) << conf0 << std::setw(4) << conf1 << "\n" << " relative error = " << std::setw(4) << relative_error << "\n" << " tolerance = " << std::setw(4) << tol << "\n"; } } } // for next iteration std::next_permutation(elt_1, elt_1+3); } // end of conf1 } // end of conf0 } // end of p } // end of point type } // end of ny } // end of nx } catch (std::logic_error err) { *outStream << err.what() << "\n\n"; r_val = -1000; }; #else *outStream << "\t This test is for high order element assembly. \n" << "\t Use -D INTREPID_USING_EXPERIMENTAL_HIGH_ORDER in CMAKE_CXX_FLAGS \n"; #endif if (r_val != 0) std::cout << "End Result: TEST FAILED :: r_val = " << r_val << "\n"; else std::cout << "End Result: TEST PASSED\n"; // reset format state of std::cout std::cout.copyfmt(oldFormatState); Kokkos::finalize(); return r_val; }
// Solves turning point equations via classic Salinger bordering // The first m columns of input_x and input_null store the RHS while // the last column stores df/dp, d(Jn)/dp respectively. Note however // input_param has only m columns (not m+1). result_x, result_null, // are result_param have the same dimensions as their input counterparts NOX::Abstract::Group::ReturnType LOCA::TurningPoint::MooreSpence::PhippsBordering::solveTransposeContiguous( Teuchos::ParameterList& params, const NOX::Abstract::MultiVector& input_x, const NOX::Abstract::MultiVector& input_null, const NOX::Abstract::MultiVector::DenseMatrix& input_param, NOX::Abstract::MultiVector& result_x, NOX::Abstract::MultiVector& result_null, NOX::Abstract::MultiVector::DenseMatrix& result_param) const { std::string callingFunction = "LOCA::TurningPoint::MooreSpence::PhippsBordering::solveTransposeContiguous()"; NOX::Abstract::Group::ReturnType finalStatus = NOX::Abstract::Group::Ok; NOX::Abstract::Group::ReturnType status; int m = input_x.numVectors()-2; std::vector<int> index_input(m); std::vector<int> index_input_dp(m+1); std::vector<int> index_null(1); std::vector<int> index_dp(1); for (int i=0; i<m; i++) { index_input[i] = i; index_input_dp[i] = i; } index_input_dp[m] = m; index_dp[0] = m; index_null[0] = m+1; NOX::Abstract::MultiVector::DenseMatrix tmp_mat_1(1, m+1); NOX::Abstract::MultiVector::DenseMatrix tmp_mat_2(1, m+2); // Create view of first m+1 columns of input_null, result_null Teuchos::RCP<NOX::Abstract::MultiVector> input_null_view = input_null.subView(index_input_dp); Teuchos::RCP<NOX::Abstract::MultiVector> result_null_view = result_null.subView(index_input_dp); // verify underlying Jacobian is valid if (!group->isJacobian()) { status = group->computeJacobian(); finalStatus = globalData->locaErrorCheck->combineAndCheckReturnTypes(status, finalStatus, callingFunction); } // Solve |J^T v||A B| = |G -phi| // |u^T 0||a b| |0 0 | status = transposeBorderedSolver->applyInverseTranspose(params, input_null_view.get(), NULL, *result_null_view, tmp_mat_1); finalStatus = globalData->locaErrorCheck->combineAndCheckReturnTypes(status, finalStatus, callingFunction); Teuchos::RCP<NOX::Abstract::MultiVector> A = result_null.subView(index_input); Teuchos::RCP<NOX::Abstract::MultiVector> B = result_null.subView(index_dp); double b = tmp_mat_1(0,m); // compute (Jv)_x^T[A B u] result_null[m+1] = *uVector; Teuchos::RCP<NOX::Abstract::MultiVector> tmp = result_null.clone(NOX::ShapeCopy); status = group->computeDwtJnDxMulti(result_null, *nullVector, *tmp); finalStatus = globalData->locaErrorCheck->combineAndCheckReturnTypes(status, finalStatus, callingFunction); // compute [F 0 0] - (Jv)_x^T[A B u] tmp->update(1.0, input_x, -1.0); // verify underlying Jacobian is valid if (!group->isJacobian()) { status = group->computeJacobian(); finalStatus = globalData->locaErrorCheck->combineAndCheckReturnTypes(status, finalStatus, callingFunction); } // Solve |J^T v||C D E| = |F - (Jv)_x^T A -(Jv)_x^T B -(Jv)_x^T u| // |u^T 0||c d e| | 0 0 0 | status = transposeBorderedSolver->applyInverseTranspose(params, tmp.get(), NULL, result_x, tmp_mat_2); finalStatus = globalData->locaErrorCheck->combineAndCheckReturnTypes(status, finalStatus, callingFunction); Teuchos::RCP<NOX::Abstract::MultiVector> C = result_x.subView(index_input); Teuchos::RCP<NOX::Abstract::MultiVector> D = result_x.subView(index_dp); Teuchos::RCP<NOX::Abstract::MultiVector> E = result_x.subView(index_null); double d = tmp_mat_2(0, m); double e = tmp_mat_2(0, m+1); // compute (Jv)_p^T*[A B u] NOX::Abstract::MultiVector::DenseMatrix t1(1,m+2); result_null.multiply(1.0, *dJndp, t1); // compute f_p^T*[C D E] NOX::Abstract::MultiVector::DenseMatrix t2(1,m+2); result_x.multiply(1.0, *dfdp, t2); // compute f_p^T*u double fptu = uVector->innerProduct((*dfdp)[0]); // Fill coefficient arrays double M[9]; M[0] = st; M[1] = -e; M[2] = t1(0,m+1) + t2(0,m+1); M[3] = 0.0; M[4] = st; M[5] = fptu; M[6] = -b; M[7] = -d; M[8] = t1(0,m) + t2(0,m); // Compute RHS double *R = new double[3*m]; for (int i=0; i<m; i++) { R[3*i] = tmp_mat_1(0,i); R[3*i+1] = tmp_mat_2(0,i); R[3*i+2] = result_param(0,i) - t1(0,i) - t2(0,i); } // Solve M*P = R int three = 3; int piv[3]; int info; Teuchos::LAPACK<int,double> L; L.GESV(three, m, M, three, piv, R, three, &info); if (info != 0) { globalData->locaErrorCheck->throwError( callingFunction, "Solve of 3x3 coefficient matrix failed!"); return NOX::Abstract::Group::Failed; } NOX::Abstract::MultiVector::DenseMatrix alpha(1,m); NOX::Abstract::MultiVector::DenseMatrix beta(1,m); for (int i=0; i<m; i++) { alpha(0,i) = R[3*i]; beta(0,i) = R[3*i+1]; result_param(0,i) = R[3*i+2]; } // compute A = A + B*z + alpha*u (remember A is a sub-view of result_null) A->update(Teuchos::NO_TRANS, 1.0, *B, result_param, 1.0); A->update(Teuchos::NO_TRANS, 1.0, *uMultiVector, alpha, 1.0); // compute C = C + D*z + alpha*E + beta*u // (remember C is a sub-view of result_x) C->update(Teuchos::NO_TRANS, 1.0, *D, result_param, 1.0); C->update(Teuchos::NO_TRANS, 1.0, *E, alpha, 1.0); C->update(Teuchos::NO_TRANS, 1.0, *uMultiVector, beta, 1.0); delete [] R; return finalStatus; }
// Solves turning point equations via Phipps modified bordering // The first m columns of input_x and input_null store the RHS while // the last column stores df/dp, d(Jn)/dp respectively. Note however // input_param has only m columns (not m+1). result_x, result_null, // are result_param have the same dimensions as their input counterparts NOX::Abstract::Group::ReturnType LOCA::TurningPoint::MooreSpence::PhippsBordering::solveContiguous( Teuchos::ParameterList& params, const NOX::Abstract::MultiVector& input_x, const NOX::Abstract::MultiVector& input_null, const NOX::Abstract::MultiVector::DenseMatrix& input_param, NOX::Abstract::MultiVector& result_x, NOX::Abstract::MultiVector& result_null, NOX::Abstract::MultiVector::DenseMatrix& result_param) const { std::string callingFunction = "LOCA::TurningPoint::MooreSpence::PhippsBordering::solveContiguous()"; NOX::Abstract::Group::ReturnType finalStatus = NOX::Abstract::Group::Ok; NOX::Abstract::Group::ReturnType status; int m = input_x.numVectors()-2; std::vector<int> index_input(m); std::vector<int> index_input_dp(m+1); std::vector<int> index_null(1); std::vector<int> index_dp(1); for (int i=0; i<m; i++) { index_input[i] = i; index_input_dp[i] = i; } index_input_dp[m] = m; index_dp[0] = m; index_null[0] = m+1; NOX::Abstract::MultiVector::DenseMatrix tmp_mat_1(1, m+1); NOX::Abstract::MultiVector::DenseMatrix tmp_mat_2(1, m+2); // Create view of first m+1 columns of input_x, result_x Teuchos::RCP<NOX::Abstract::MultiVector> input_x_view = input_x.subView(index_input_dp); Teuchos::RCP<NOX::Abstract::MultiVector> result_x_view = result_x.subView(index_input_dp); // verify underlying Jacobian is valid if (!group->isJacobian()) { status = group->computeJacobian(); finalStatus = globalData->locaErrorCheck->combineAndCheckReturnTypes(status, finalStatus, callingFunction); } // Solve |J u||A B| = |F df/dp| // |v^T 0||a b| |0 0 | status = borderedSolver->applyInverse(params, input_x_view.get(), NULL, *result_x_view, tmp_mat_1); finalStatus = globalData->locaErrorCheck->combineAndCheckReturnTypes(status, finalStatus, callingFunction); Teuchos::RCP<NOX::Abstract::MultiVector> A = result_x.subView(index_input); Teuchos::RCP<NOX::Abstract::MultiVector> B = result_x.subView(index_dp); double b = tmp_mat_1(0,m); // compute (Jv)_x[A B v] result_x[m+1] = *nullVector; Teuchos::RCP<NOX::Abstract::MultiVector> tmp = result_x.clone(NOX::ShapeCopy); status = group->computeDJnDxaMulti(*nullVector, *JnVector, result_x, *tmp); finalStatus = globalData->locaErrorCheck->combineAndCheckReturnTypes(status, finalStatus, callingFunction); // compute (Jv)_x[A B v] - [G d(Jn)/dp 0] tmp->update(-1.0, input_null, 1.0); // verify underlying Jacobian is valid if (!group->isJacobian()) { status = group->computeJacobian(); finalStatus = globalData->locaErrorCheck->combineAndCheckReturnTypes(status, finalStatus, callingFunction); } // Solve |J u||C D E| = |(Jv)_x A - G (Jv)_x B - d(Jv)/dp (Jv)_x v| // |v^T 0||c d e| | 0 0 0 | status = borderedSolver->applyInverse(params, tmp.get(), NULL, result_null, tmp_mat_2); finalStatus = globalData->locaErrorCheck->combineAndCheckReturnTypes(status, finalStatus, callingFunction); Teuchos::RCP<NOX::Abstract::MultiVector> C = result_null.subView(index_input); Teuchos::RCP<NOX::Abstract::MultiVector> D = result_null.subView(index_dp); Teuchos::RCP<NOX::Abstract::MultiVector> E = result_null.subView(index_null); double d = tmp_mat_2(0, m); double e = tmp_mat_2(0, m+1); // Fill coefficient arrays double M[9]; M[0] = s; M[1] = e; M[2] = -tpGroup->lTransNorm((*E)[0]); M[3] = 0.0; M[4] = s; M[5] = tpGroup->lTransNorm(*nullVector); M[6] = b; M[7] = -d; M[8] = tpGroup->lTransNorm((*D)[0]); // compute h + phi^T C tpGroup->lTransNorm(*C, result_param); result_param += input_param; double *R = new double[3*m]; for (int i=0; i<m; i++) { R[3*i] = tmp_mat_1(0,i); R[3*i+1] = -tmp_mat_2(0,i); R[3*i+2] = result_param(0,i); } // Solve M*P = R int three = 3; int piv[3]; int info; Teuchos::LAPACK<int,double> L; L.GESV(three, m, M, three, piv, R, three, &info); if (info != 0) { globalData->locaErrorCheck->throwError( callingFunction, "Solve of 3x3 coefficient matrix failed!"); return NOX::Abstract::Group::Failed; } NOX::Abstract::MultiVector::DenseMatrix alpha(1,m); NOX::Abstract::MultiVector::DenseMatrix beta(1,m); for (int i=0; i<m; i++) { alpha(0,i) = R[3*i]; beta(0,i) = R[3*i+1]; result_param(0,i) = R[3*i+2]; } // compute A = A - B*z + v*alpha (remember A is a sub-view of result_x) A->update(Teuchos::NO_TRANS, -1.0, *B, result_param, 1.0); A->update(Teuchos::NO_TRANS, 1.0, *nullMultiVector, alpha, 1.0); // compute C = -C + d*z - E*alpha + v*beta // (remember C is a sub-view of result_null) C->update(Teuchos::NO_TRANS, 1.0, *D, result_param, -1.0); C->update(Teuchos::NO_TRANS, -1.0, *E, alpha, 1.0); C->update(Teuchos::NO_TRANS, 1.0, *nullMultiVector, beta, 1.0); delete [] R; return finalStatus; }
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_HCURL_HEX_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 { shards::CellTopology cell(shards::getCellTopologyData< shards::Hexahedron<8> >()); // create parent cell topology int cellDim = cell.getDimension(); int min_order = 1; int max_order = 3; int numIntervals = max_order; 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 basis Teuchos::RCP<Basis<double,FieldContainer<double> > > basis = Teuchos::rcp(new Basis_HCURL_HEX_In_FEM<double,FieldContainer<double> >(basis_order,POINTTYPE_SPECTRAL) ); int numFields = basis->getCardinality(); // create cubatures DefaultCubatureFactory<double> cubFactory; Teuchos::RCP<Cubature<double> > cellCub = cubFactory.create( cell , 2* basis_order ); 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 ); 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++) { 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,0,0), numFields, &ipiv(0), &rhs_and_soln_vec(0,0), numFields, &info); // solver.POTRF('L',numFields,&fe_matrix(0,0,0),numFields,&info); // solver.POTRS('L',numFields,1,&fe_matrix(0,0,0),numFields,&rhs_and_soln_vec(0,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); // let's compute the L2 norm interpolant.resize(1,numInterpPoints,cellDim); FieldContainer<double> l2norm(1); FunctionSpaceTools::dataIntegral<double>( l2norm , interpolant , interpolant , COMP_BLAS ); const double nrm = sqrtl(l2norm(0)); *outStream << "\nFunction space L^2 Norm-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); Kokkos::finalize(); return errorFlag; }
// Solves pitchfork equations via Phipps modified bordering // The first m columns of input_x and input_null store the RHS, // column m+1 stores df/dp, d(Jn)/dp, column m+2 stores psi and 0, // and the last column provides space for solving (Jv_x) v. Note however // input_param has only m columns. result_x, result_null, // are result_param have the same dimensions as their input counterparts NOX::Abstract::Group::ReturnType LOCA::Pitchfork::MooreSpence::PhippsBordering::solveContiguous( Teuchos::ParameterList& params, const NOX::Abstract::MultiVector& input_x, const NOX::Abstract::MultiVector& input_null, const NOX::Abstract::MultiVector::DenseMatrix& input_slack, const NOX::Abstract::MultiVector::DenseMatrix& input_param, NOX::Abstract::MultiVector& result_x, NOX::Abstract::MultiVector& result_null, NOX::Abstract::MultiVector::DenseMatrix& result_slack, NOX::Abstract::MultiVector::DenseMatrix& result_param) const { string callingFunction = "LOCA::Pitchfork::MooreSpence::PhippsBordering::solveContiguous()"; NOX::Abstract::Group::ReturnType finalStatus = NOX::Abstract::Group::Ok; NOX::Abstract::Group::ReturnType status; int m = input_x.numVectors()-3; vector<int> index_input(m); vector<int> index_input_dp(m+2); vector<int> index_null(1); vector<int> index_dp(1); vector<int> index_s(1); for (int i=0; i<m; i++) { index_input[i] = i; index_input_dp[i] = i; } index_input_dp[m] = m; index_input_dp[m+1] = m+1; index_dp[0] = m; index_s[0] = m+1; index_null[0] = m+2; NOX::Abstract::MultiVector::DenseMatrix tmp_mat_1(1, m+2); NOX::Abstract::MultiVector::DenseMatrix tmp_mat_2(1, m+3); // Create view of first m+2 columns of input_x, result_x Teuchos::RCP<NOX::Abstract::MultiVector> input_x_view = input_x.subView(index_input_dp); Teuchos::RCP<NOX::Abstract::MultiVector> result_x_view = result_x.subView(index_input_dp); // verify underlying Jacobian is valid if (!group->isJacobian()) { status = group->computeJacobian(); finalStatus = globalData->locaErrorCheck->combineAndCheckReturnTypes(status, finalStatus, callingFunction); } // Solve |J u||A B C| = |F df/dp psi| // |v^T 0||a b c| |0 0 0 | status = borderedSolver->applyInverse(params, input_x_view.get(), NULL, *result_x_view, tmp_mat_1); finalStatus = globalData->locaErrorCheck->combineAndCheckReturnTypes(status, finalStatus, callingFunction); Teuchos::RCP<NOX::Abstract::MultiVector> A = result_x.subView(index_input); Teuchos::RCP<NOX::Abstract::MultiVector> B = result_x.subView(index_dp); Teuchos::RCP<NOX::Abstract::MultiVector> C = result_x.subView(index_s); double b = tmp_mat_1(0,m); double c = tmp_mat_1(0,m+1); // compute (Jv)_x[A B C v] result_x[m+2] = *nullVector; Teuchos::RCP<NOX::Abstract::MultiVector> tmp = result_x.clone(NOX::ShapeCopy); status = group->computeDJnDxaMulti(*nullVector, *JnVector, result_x, *tmp); finalStatus = globalData->locaErrorCheck->combineAndCheckReturnTypes(status, finalStatus, callingFunction); // compute [G d(Jn)/dp 0 0] - (Jv)_x[A B C v] tmp->update(1.0, input_null, -1.0); // verify underlying Jacobian is valid if (!group->isJacobian()) { status = group->computeJacobian(); finalStatus = globalData->locaErrorCheck->combineAndCheckReturnTypes(status, finalStatus, callingFunction); } // Solve |J u||D E K L| = |G-(Jv)_xA d(Jv)/dp-(Jv)_xB -(Jv)_xC -(Jv)_xv| // |v^T 0||d e k l| | 0 0 0 0 | status = borderedSolver->applyInverse(params, tmp.get(), NULL, result_null, tmp_mat_2); finalStatus = globalData->locaErrorCheck->combineAndCheckReturnTypes(status, finalStatus, callingFunction); Teuchos::RCP<NOX::Abstract::MultiVector> D = result_null.subView(index_input); Teuchos::RCP<NOX::Abstract::MultiVector> E = result_null.subView(index_dp); Teuchos::RCP<NOX::Abstract::MultiVector> K = result_null.subView(index_s); Teuchos::RCP<NOX::Abstract::MultiVector> L = result_null.subView(index_null); double e = tmp_mat_2(0, m); double k = tmp_mat_2(0, m+1); double l = tmp_mat_2(0, m+2); double ltE = pfGroup->lTransNorm((*E)[0]); double ltK = pfGroup->lTransNorm((*K)[0]); double ltL = pfGroup->lTransNorm((*L)[0]); double ltv = pfGroup->lTransNorm(*nullVector); double ipv = group->innerProduct(*nullVector, *asymVector); double ipB = group->innerProduct((*B)[0], *asymVector); double ipC = group->innerProduct((*C)[0], *asymVector); // Fill coefficient arrays double M[16]; M[0] = sigma; M[1] = -l; M[2] = ipv; M[3] = ltL; M[4] = 0.0; M[5] = sigma; M[6] = 0.0; M[7] = ltv; M[8] = b; M[9] = e; M[10] = -ipB; M[11] = -ltE; M[12] = c; M[13] = k; M[14] = -ipC; M[15] = -ltK; // compute s - <A,psi> NOX::Abstract::MultiVector::DenseMatrix tmp_mat_3(1, m); group->innerProduct(*asymMultiVector, *A, tmp_mat_3); tmp_mat_3 -= input_slack; tmp_mat_3.scale(-1.0); // compute h - phi^T D NOX::Abstract::MultiVector::DenseMatrix tmp_mat_4(1, m); pfGroup->lTransNorm(*D, tmp_mat_4); tmp_mat_4 -= input_param; tmp_mat_4.scale(-1.0); double *R = new double[4*m]; for (int i=0; i<m; i++) { R[4*i] = tmp_mat_1(0,i); R[4*i+1] = tmp_mat_2(0,i); R[4*i+2] = tmp_mat_3(0,i); R[4*i+3] = tmp_mat_4(0,i); } // Solve M*P = R int piv[4]; int info; Teuchos::LAPACK<int,double> dlapack; dlapack.GESV(4, m, M, 4, piv, R, 4, &info); if (info != 0) { globalData->locaErrorCheck->throwError( callingFunction, "Solve of 4x4 coefficient matrix failed!"); return NOX::Abstract::Group::Failed; } NOX::Abstract::MultiVector::DenseMatrix alpha(1,m); NOX::Abstract::MultiVector::DenseMatrix beta(1,m); for (int i=0; i<m; i++) { alpha(0,i) = R[4*i]; beta(0,i) = R[4*i+1]; result_param(0,i) = R[4*i+2]; result_slack(0,i) = R[4*i+3]; } // compute A = A - B*z -C*w + v*alpha (remember A is a sub-view of result_x) A->update(Teuchos::NO_TRANS, -1.0, *B, result_param, 1.0); A->update(Teuchos::NO_TRANS, -1.0, *C, result_slack, 1.0); A->update(Teuchos::NO_TRANS, 1.0, *nullMultiVector, alpha, 1.0); // compute D = D - E*z - K*w + L*alpha + v*beta // (remember D is a sub-view of result_null) D->update(Teuchos::NO_TRANS, -1.0, *E, result_param, 1.0); D->update(Teuchos::NO_TRANS, -1.0, *K, result_slack, 1.0); D->update(Teuchos::NO_TRANS, 1.0, *L, alpha, 1.0); D->update(Teuchos::NO_TRANS, 1.0, *nullMultiVector, beta, 1.0); delete [] R; return finalStatus; }