libMesh
Loading...
Searching...
No Matches
Public Member Functions | Static Protected Member Functions | Protected Attributes | List of all members
FETest< order, family, elem_type, CaseName > Class Template Reference

#include <fe_test.h>

Inheritance diagram for FETest< order, family, elem_type, CaseName >:
[legend]

Public Member Functions

template<typename Functor >
void testLoop (Functor f)
 
void testPartitionOfUnity ()
 
void testFEInterface ()
 
void testU ()
 
void testDualDoesntScreamAndDie ()
 
void testGradU ()
 
void testGradUComp ()
 
void testHessU ()
 
void testHessUComp ()
 
void testCustomReinit ()
 
void setUp ()
 
void tearDown ()
 

Static Protected Member Functions

static RealGradient true_gradient (Point p)
 
static RealTensor true_hessian (Point p)
 

Protected Attributes

std::string libmesh_suite_name
 
std::string _case_name
 Name of the case, can be used in the test to switch cases.
 
unsigned int _dim
 
unsigned int _nx
 
unsigned int _ny
 
unsigned int _nz
 
Elem_elem
 
std::vector< dof_id_type_dof_indices
 
System_sys
 
std::unique_ptr< Mesh_mesh
 
std::unique_ptr< EquationSystems_es
 
std::unique_ptr< FEBase_fe
 
std::unique_ptr< QGauss_qrule
 
Real _value_tol
 
Real _grad_tol
 
Real _hess_tol
 

Detailed Description

template<Order order, FEFamily family, ElemType elem_type, typename CaseName>
class FETest< order, family, elem_type, CaseName >

Definition at line 627 of file fe_test.h.

Member Function Documentation

◆ setUp()

void FETestBase< order, family, elem_type, build_nx, CaseName >::setUp ( )
inlineinherited

Definition at line 356 of file fe_test.h.

357 {
358 _mesh = std::make_unique<Mesh>(*TestCommWorld);
359 _dim = Elem::type_to_dim_map[elem_type];
360 const unsigned int build_ny = (_dim > 1) * build_nx;
361 const unsigned int build_nz = (_dim > 2) * build_nx;
362
363 unsigned char weight_index = 0;
364
365 if (family == RATIONAL_BERNSTEIN)
366 {
367 // Make sure we can handle non-zero weight indices
368 _mesh->add_node_integer("buffer integer");
369
370 // Default weight to 1.0 so we don't get NaN from contains_point
371 // checks with a default GhostPointNeighbors ghosting
372 const Real default_weight = 1.0;
373 weight_index = cast_int<unsigned char>
374 (_mesh->add_node_datum<Real>("rational_weight", true,
375 &default_weight));
376 libmesh_assert_not_equal_to(weight_index, 0);
377
378 // Set mapping data but not type, since here we're testing
379 // rational basis functions in the FE space but testing then
380 // with Lagrange bases for the mapping space.
381 _mesh->set_default_mapping_data(weight_index);
382 }
383
384 if (elem_type == C0POLYGON)
385 {
386 // Build a pentagon by hand for testing purposes. Make this
387 // one non-skewed so a MONOMIAL basis will be able to exactly
388 // represent the polynomials we're projecting.
389
390 _mesh->add_point(Point(0, 0), 0);
391 _mesh->add_point(Point(1, 0), 1);
392 _mesh->add_point(Point(1+cos(2*libMesh::pi/5), sin(2*libMesh::pi/5)), 2);
393 _mesh->add_point(Point(0.5, sin(2*libMesh::pi/5)+sin(libMesh::pi/5)), 3);
394 _mesh->add_point(Point(-cos(2*libMesh::pi/5), sin(2*libMesh::pi/5)), 4);
395
396 std::unique_ptr<Elem> polygon = std::make_unique<C0Polygon>(5);
397 for (auto i : make_range(5))
398 polygon->set_node(i, _mesh->node_ptr(i));
399 polygon->set_id() = 0;
400
401 _mesh->add_elem(std::move(polygon));
402 _mesh->prepare_for_use();
403 }
404 else if (elem_type == C0POLYHEDRON)
405 {
406 // Build a plain cube by hand for testing purposes. We could
407 // upgrade this, but it should be to something non-skewed so a
408 // MONOMIAL basis will be able to exactly represent the
409 // polynomials we're projecting.
410 //
411 // See elem_test.h for the limitations here.
412
413 _mesh->add_point(Point(0, 0, 0), 0);
414 _mesh->add_point(Point(1, 0, 0), 1);
415 _mesh->add_point(Point(1, 1, 0), 2);
416 _mesh->add_point(Point(0, 1, 0), 3);
417 _mesh->add_point(Point(0, 0, 1), 4);
418 _mesh->add_point(Point(1, 0, 1), 5);
419 _mesh->add_point(Point(1, 1, 1), 6);
420 _mesh->add_point(Point(0, 1, 1), 7);
421
422 // Pick case
423 std::vector<std::vector<unsigned int>> nodes_on_side;
424 if (_case_name == "Default")
425 nodes_on_side = { {0, 1, 2, 3}, // min z
426 {0, 1, 5, 4}, // min y
427 {2, 6, 5, 1}, // max x
428 {2, 3, 7, 6}, // max y
429 {0, 4, 7, 3}, // min x
430 {5, 6, 7, 4} }; // max z
431 else if (_case_name == "MidNode")
432 nodes_on_side = { {0, 1, 2, 3}, // min z
433 {0, 1, 5, 4}, // min y
434 {1, 2, 6, 5}, // max x
435 {2, 3, 7, 6}, // max y
436 {3, 0, 4, 7}, // min x
437 {4, 5, 6, 7} }; // max z
438 else
439 libmesh_error_msg("Unknown case name: " + _case_name);
440
441 // Build all the sides.
442 std::vector<std::shared_ptr<Polygon>> sides(nodes_on_side.size());
443
444 for (auto s : index_range(nodes_on_side))
445 {
446 const auto & nodes_on_s = nodes_on_side[s];
447 sides[s] = std::make_shared<C0Polygon>(nodes_on_s.size());
448 for (auto i : index_range(nodes_on_s))
449 sides[s]->set_node(i, _mesh->node_ptr(nodes_on_s[i]));
450 }
451
452 std::unique_ptr<libMesh::Node> mid_elem_node;
453 std::unique_ptr<Elem> polyhedron = std::make_unique<C0Polyhedron>(sides, mid_elem_node);
454 _mesh->add_elem(std::move(polyhedron));
455 if (mid_elem_node)
456 _mesh->add_node(std::move(mid_elem_node));
457 _mesh->prepare_for_use();
458 }
459 else
460 {
462 build_nx, build_ny, build_nz,
463 0., 1., 0., 1., 0., 1.,
464 elem_type);
465 }
466
467 // For debugging purposes it can be helpful to only consider one
468 // element even when we're using an element type that requires
469 // more than one element to fill out a square or cube.
470#if 0
471 for (dof_id_type i = 0; i != _mesh->max_elem_id(); ++i)
472 {
473 Elem * elem = _mesh->query_elem_ptr(i);
474 if (elem && elem->id())
475 _mesh->delete_elem(elem);
476 }
477 _mesh->prepare_for_use();
478 CPPUNIT_ASSERT_EQUAL(_mesh->n_elem(), dof_id_type(1));
479#endif
480
481 // Permute our elements randomly and rotate and skew our mesh so
482 // we test all sorts of orientations ... except with Hermite
483 // elements, which are only designed to support meshes with a
484 // single orientation shared by all elements. We're also not
485 // rotating and/or skewing the rational elements, since our test
486 // solution was designed for a specific weighted mesh.
487 if (family != HERMITE &&
488 family != RATIONAL_BERNSTEIN)
489 {
491
492 // Not yet testing manifolds embedded in higher-D space
493 if (_dim > 1)
495 8*(_dim>2), 16*(_dim>2));
496
497 SkewFunc skew_func;
499 }
500
501 // Set rational weights so we can exactly match our test solution
502 if (family == RATIONAL_BERNSTEIN)
503 {
504 for (auto elem : _mesh->active_element_ptr_range())
505 {
506 // Workaround for nvc++ bug
507 Elem & e = *elem;
508
509 const unsigned int nv = elem->n_vertices();
510 const unsigned int nn = elem->n_nodes();
511 // We want interiors in lower dimensional elements treated
512 // like edges or faces as appropriate.
513 const unsigned int n_edges =
514 (elem->type() == EDGE3) ? 1 : elem->n_edges();
515 const unsigned int n_faces =
516 (elem->type() == QUAD9) ? 1 : elem->n_faces();
517 const unsigned int nve = std::min(nv + n_edges, nn);
518 const unsigned int nvef = std::min(nve + n_faces, nn);
519
520 for (unsigned int i = 0; i != nv; ++i)
521 e.node_ref(i).set_extra_datum<Real>(weight_index, 1.);
522 for (unsigned int i = nv; i != nve; ++i)
523 e.node_ref(i).set_extra_datum<Real>(weight_index, rational_w);
524 const Real w2 = rational_w * rational_w;
525 for (unsigned int i = nve; i != nvef; ++i)
526 e.node_ref(i).set_extra_datum<Real>(weight_index, w2);
527 const Real w3 = rational_w * w2;
528 for (unsigned int i = nvef; i != nn; ++i)
529 e.node_ref(i).set_extra_datum<Real>(weight_index, w3);
530 }
531 }
532
533 _mesh->complete_preparation();
534 _es = std::make_unique<EquationSystems>(*_mesh);
535 _sys = &(_es->add_system<System> ("SimpleSystem"));
536 _sys->add_variable("u", order, family);
537 _es->init();
538
539 if (family == RATIONAL_BERNSTEIN && order > 1)
540 {
542 }
543 else if (order > 3)
544 {
546 }
547 // Lagrange "cubic" on Tet7 only supports a bubble function, not
548 // all of P^3
549 else if (FE_CAN_TEST_CUBIC)
550 {
552 }
553 else if (order > 1)
554 {
556 }
557 else
558 {
560 }
561
562 FEType fe_type = _sys->variable_type(0);
563 _fe = FEBase::build(_dim, fe_type);
564
565 // Create quadrature rule for use in computing dual shape coefficients
566 _qrule = std::make_unique<QGauss>(_dim, fe_type.default_quadrature_order());
567 _fe->attach_quadrature_rule(_qrule.get());
568
569 auto rng = _mesh->active_local_element_ptr_range();
570 this->_elem = rng.begin() == rng.end() ? nullptr : *(rng.begin());
571
573
574 _nx = 10;
575 _ny = (_dim > 1) ? _nx : 1;
576 _nz = (_dim > 2) ? _nx : 1;
577
578 this->_value_tol = TOLERANCE * sqrt(TOLERANCE);
579
580 // We see 6.5*tol*sqrt(tol) errors on cubic Hermites with the fe_cubic
581 // hermite test function
582 // On Tri7 we see 10*tol*sqrt(tol) errors, even!
583 // On Tet14 Monomial gives us at least 13*tol*sqrt(tol) in some
584 // cases
585 this->_grad_tol = 15 * TOLERANCE * sqrt(TOLERANCE);
586
587 this->_hess_tol = sqrt(TOLERANCE); // FIXME: we see some ~1e-5 errors?!?
588
589 // Prerequest everything we'll want to calculate later.
590 _fe->get_phi();
591 _fe->get_dphi();
592 _fe->get_dphidx();
593#if LIBMESH_DIM > 1
594 _fe->get_dphidy();
595#endif
596#if LIBMESH_DIM > 2
597 _fe->get_dphidz();
598#endif
599
600#if LIBMESH_ENABLE_SECOND_DERIVATIVES
601
602 // Szabab elements don't have second derivatives yet
603 if (family == SZABAB)
604 return;
605
606 _fe->get_d2phi();
607 _fe->get_d2phidx2();
608#if LIBMESH_DIM > 1
609 _fe->get_d2phidxdy();
610 _fe->get_d2phidy2();
611#endif
612#if LIBMESH_DIM > 2
613 _fe->get_d2phidxdz();
614 _fe->get_d2phidydz();
615 _fe->get_d2phidz2();
616#endif
617
618#endif
619 }
std::string _case_name
Name of the case, can be used in the test to switch cases.
Definition fe_test.h:275
std::unique_ptr< EquationSystems > _es
Definition fe_test.h:282
void dof_indices(const Elem *const elem, std::vector< dof_id_type > &di) const
Definition dof_map.C:2201
void set_extra_datum(const unsigned int index, const T value)
Sets the value on this object of the extra datum associated with index, which should have been obtain...
dof_id_type id() const
Definition dof_object.h:819
This is the base class from which all geometric element types are derived.
Definition elem.h:96
virtual unsigned int n_vertices() const =0
const Node & node_ref(const unsigned int i) const
Definition elem.h:2538
virtual unsigned int n_nodes() const =0
static const unsigned int type_to_dim_map[INVALID_ELEM]
This array maps the integer representation of the ElemType enum to the geometric dimension of the ele...
Definition elem.h:628
virtual ElemType type() const =0
static std::unique_ptr< FEGenericBase > build(const unsigned int dim, const FEType &type)
Builds a specific finite element type.
class FEType hides (possibly multiple) FEFamily and approximation orders, thereby enabling specialize...
Definition fe_type.h:197
Order default_quadrature_order() const
Definition fe_type.h:415
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition point.h:40
Manages consistently variables, degrees of freedom, and coefficient vectors.
Definition system.h:100
void project_solution(FunctionBase< Number > *f, FunctionBase< Gradient > *g=nullptr, std::optional< ConstElemRange > active_local_range=std::nullopt, std::optional< std::vector< unsigned int > > variable_numbers=std::nullopt) const
Projects arbitrary functions onto the current solution.
const FEType & variable_type(const unsigned int i) const
Definition system.C:2721
unsigned int add_variable(std::string_view var, const FEType &type, const std::set< subdomain_id_type > *const active_subdomains=nullptr)
Adds the variable var to the list of variables for this system.
Definition system.C:1344
const DofMap & get_dof_map() const
Definition system.h:2417
static const Real rational_w
Definition fe_test.h:200
Number fe_cubic_test(const Point &p, const Parameters &, const std::string &, const std::string &)
Definition fe_test.h:131
Number rational_test(const Point &p, const Parameters &, const std::string &, const std::string &)
Definition fe_test.h:203
Gradient quadratic_test_grad(const Point &p, const Parameters &, const std::string &, const std::string &)
Definition fe_test.h:111
Number quadratic_test(const Point &p, const Parameters &, const std::string &, const std::string &)
Definition fe_test.h:98
Gradient fe_quartic_test_grad(const Point &p, const Parameters &, const std::string &, const std::string &)
Definition fe_test.h:177
Gradient linear_test_grad(const Point &, const Parameters &, const std::string &, const std::string &)
Definition fe_test.h:82
Number fe_quartic_test(const Point &p, const Parameters &, const std::string &, const std::string &)
Definition fe_test.h:164
Gradient rational_test_grad(const Point &p, const Parameters &, const std::string &, const std::string &)
Definition fe_test.h:220
Gradient fe_cubic_test_grad(const Point &p, const Parameters &, const std::string &, const std::string &)
Definition fe_test.h:144
Number linear_test(const Point &p, const Parameters &, const std::string &, const std::string &)
Definition fe_test.h:69
void build_cube(UnstructuredMesh &mesh, const unsigned int nx=0, const unsigned int ny=0, const unsigned int nz=0, const Real xmin=0., const Real xmax=1., const Real ymin=0., const Real ymax=1., const Real zmin=0., const Real zmax=1., const ElemType type=INVALID_ELEM, const bool gauss_lobatto_grid=false)
Builds a (elements) cube.
void redistribute(MeshBase &mesh, const FunctionBase< Real > &mapfunc)
Deterministically perturb the nodal locations.
RealTensorValue rotate(MeshBase &mesh, const Real phi, const Real theta=0., const Real psi=0.)
Rotates the mesh in 3D space.
void permute_elements(MeshBase &mesh)
Randomly permute the nodal ordering of each element (without twisting the element mapping).
auto index_range(const T &sizable)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...
Definition int_range.h:153
const Real pi
.
Definition libmesh.h:292
static constexpr Real TOLERANCE
uint8_t dof_id_type
Definition id_types.h:67
@ RATIONAL_BERNSTEIN
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
IntRange< T > make_range(T beg, T end)
The 2-parameter make_range() helper function returns an IntRange<T> when both input parameters are of...
Definition int_range.h:176

◆ tearDown()

void FETestBase< order, family, elem_type, build_nx, CaseName >::tearDown ( )
inlineinherited

Definition at line 621 of file fe_test.h.

621{}

◆ testCustomReinit()

template<Order order, FEFamily family, ElemType elem_type, typename CaseName >
void FETest< order, family, elem_type, CaseName >::testCustomReinit ( )
inline

Definition at line 1011 of file fe_test.h.

1012 {
1013 LOG_UNIT_TEST;
1014
1015 std::vector<Point> q_points;
1016 std::vector<Real> weights;
1017 q_points.resize(3); weights.resize(3);
1018 q_points[0](0) = 0.0; q_points[0](1) = 0.0; weights[0] = Real(1)/6;
1019 q_points[1](0) = 1.0; q_points[1](1) = 0.0; weights[1] = weights[0];
1020 q_points[2](0) = 0.0; q_points[2](1) = 1.0; weights[2] = weights[0];
1021
1022 FEType fe_type = this->_sys->variable_type(0);
1023 std::unique_ptr<FEBase> fe (FEBase::build(this->_dim, fe_type));
1024 const int extraorder = 3;
1025 std::unique_ptr<QBase> qrule (fe_type.default_quadrature_rule (this->_dim, extraorder));
1026 fe->attach_quadrature_rule (qrule.get());
1027
1028 const std::vector<Point> & q_pos = fe->get_xyz();
1029
1030 for (const auto & elem : this->_mesh->active_local_element_ptr_range()) {
1031 fe->reinit (elem, &q_points, &weights);
1032 CPPUNIT_ASSERT_EQUAL(q_points.size(), std::size_t(3));
1033 CPPUNIT_ASSERT_EQUAL(q_pos.size(), std::size_t(3)); // 6? bug?
1034 }
1035 }
std::unique_ptr< QBase > default_quadrature_rule(const unsigned int dim, const int extraorder=0) const
Definition fe_type.C:34

References FETestBase< order, family, elem_type, 1, CaseName >::_dim, FETestBase< order, family, elem_type, 1, CaseName >::_mesh, FETestBase< order, family, elem_type, 1, CaseName >::_sys, libMesh::FEGenericBase< OutputType >::build(), libMesh::FEType::default_quadrature_rule(), libMesh::Real, and libMesh::System::variable_type().

◆ testDualDoesntScreamAndDie()

template<Order order, FEFamily family, ElemType elem_type, typename CaseName >
void FETest< order, family, elem_type, CaseName >::testDualDoesntScreamAndDie ( )
inline

Definition at line 824 of file fe_test.h.

825 {
826 LOG_UNIT_TEST;
827
828 // Handle the "more processors than elements" case
829 if (!this->_elem)
830 return;
831
832 // Request dual calculations
833 this->_fe->get_dual_phi();
834
835 // reinit using the default quadrature rule in order to calculate the dual coefficients
836 this->_fe->reinit(this->_elem);
837 }

References FETestBase< order, family, elem_type, 1, CaseName >::_elem, and FETestBase< order, family, elem_type, 1, CaseName >::_fe.

◆ testFEInterface()

template<Order order, FEFamily family, ElemType elem_type, typename CaseName >
void FETest< order, family, elem_type, CaseName >::testFEInterface ( )
inline

Definition at line 747 of file fe_test.h.

748 {
749 LOG_UNIT_TEST;
750
751 // Handle the "more processors than elements" case
752 if (!this->_elem)
753 return;
754
755 this->_fe->reinit(this->_elem);
756
757 const FEType fe_type = this->_sys->variable_type(0);
758
759 unsigned int my_n_dofs = 0;
760
761 switch (this->_elem->dim())
762 {
763 case 0:
764 my_n_dofs = FE<0,family>::n_dofs(this->_elem, order);
765 break;
766 case 1:
767 my_n_dofs = FE<1,family>::n_dofs(this->_elem, order);
768 break;
769 case 2:
770 my_n_dofs = FE<2,family>::n_dofs(this->_elem, order);
771 break;
772 case 3:
773 my_n_dofs = FE<3,family>::n_dofs(this->_elem, order);
774 break;
775 default:
776 libmesh_error();
777 }
778
779 CPPUNIT_ASSERT_EQUAL(
781 my_n_dofs);
782
783 CPPUNIT_ASSERT_EQUAL(
785 this->_fe->get_continuity());
786
787 CPPUNIT_ASSERT_EQUAL(
789 this->_fe->is_hierarchic());
790 }
virtual unsigned short dim() const =0
static bool is_hierarchic(const FEType &fe_type)
Returns whether or not the input FEType's higher-order shape functions are always hierarchic.
static FEContinuity get_continuity(const FEType &fe_type)
Returns the input FEType's FEContinuity based on the underlying FEFamily and potentially the Order,...
static unsigned int n_shape_functions(const unsigned int dim, const FEType &fe_t, const ElemType t)
static unsigned int n_dofs(const ElemType t, const Order o)

References FETestBase< order, family, elem_type, 1, CaseName >::_elem, FETestBase< order, family, elem_type, 1, CaseName >::_fe, FETestBase< order, family, elem_type, 1, CaseName >::_sys, libMesh::Elem::dim(), libMesh::FEInterface::get_continuity(), libMesh::FEInterface::is_hierarchic(), libMesh::FE< Dim, T >::n_dofs(), libMesh::FEInterface::n_shape_functions(), and libMesh::System::variable_type().

◆ testGradU()

template<Order order, FEFamily family, ElemType elem_type, typename CaseName >
void FETest< order, family, elem_type, CaseName >::testGradU ( )
inline

Definition at line 840 of file fe_test.h.

841 {
842 LOG_UNIT_TEST;
843
844 auto f = [this](Point p)
845 {
846 Parameters dummy;
847
848 Gradient grad_u = 0;
849 for (std::size_t d = 0; d != this->_dof_indices.size(); ++d)
850 grad_u += this->_fe->get_dphi()[d][0] * (*this->_sys->current_local_solution)(this->_dof_indices[d]);
851
852 RealGradient true_grad = this->true_gradient(p);
853
854 LIBMESH_ASSERT_NUMBERS_EQUAL
855 (grad_u(0), true_grad(0), this->_grad_tol);
856 if (this->_dim > 1)
857 LIBMESH_ASSERT_NUMBERS_EQUAL
858 (grad_u(1), true_grad(1), this->_grad_tol);
859 if (this->_dim > 2)
860 LIBMESH_ASSERT_NUMBERS_EQUAL
861 (grad_u(2), true_grad(2), this->_grad_tol);
862 };
863
864 testLoop(f);
865 }
static RealGradient true_gradient(Point p)
Definition fe_test.h:289
void testLoop(Functor f)
Definition fe_test.h:632
This class provides the ability to map between arbitrary, user-defined strings and several data types...
Definition parameters.h:75
std::unique_ptr< NumericVector< Number > > current_local_solution
All the values I need to compute my contribution to the simulation at hand.
Definition system.h:1667
This class defines a vector in LIBMESH_DIM dimensional Real or Complex space.

References FETestBase< order, family, elem_type, 1, CaseName >::_dim, FETestBase< order, family, elem_type, 1, CaseName >::_dof_indices, FETestBase< order, family, elem_type, 1, CaseName >::_fe, FETestBase< order, family, elem_type, 1, CaseName >::_grad_tol, FETestBase< order, family, elem_type, 1, CaseName >::_sys, libMesh::System::current_local_solution, FETest< order, family, elem_type, CaseName >::testLoop(), and FETestBase< order, family, elem_type, 1, CaseName >::true_gradient().

◆ testGradUComp()

template<Order order, FEFamily family, ElemType elem_type, typename CaseName >
void FETest< order, family, elem_type, CaseName >::testGradUComp ( )
inline

Definition at line 867 of file fe_test.h.

868 {
869 LOG_UNIT_TEST;
870
871 auto f = [this](Point p)
872 {
873 Parameters dummy;
874
875 Number grad_u_x = 0, grad_u_y = 0, grad_u_z = 0;
876 for (std::size_t d = 0; d != this->_dof_indices.size(); ++d)
877 {
878 grad_u_x += this->_fe->get_dphidx()[d][0] * (*this->_sys->current_local_solution)(this->_dof_indices[d]);
879#if LIBMESH_DIM > 1
880 grad_u_y += this->_fe->get_dphidy()[d][0] * (*this->_sys->current_local_solution)(this->_dof_indices[d]);
881#endif
882#if LIBMESH_DIM > 2
883 grad_u_z += this->_fe->get_dphidz()[d][0] * (*this->_sys->current_local_solution)(this->_dof_indices[d]);
884#endif
885 }
886
887 RealGradient true_grad = this->true_gradient(p);
888
889 LIBMESH_ASSERT_NUMBERS_EQUAL(grad_u_x,
890 true_grad(0), this->_grad_tol);
891 if (this->_dim > 1)
892 LIBMESH_ASSERT_NUMBERS_EQUAL
893 (grad_u_y, true_grad(1), this->_grad_tol);
894 if (this->_dim > 2)
895 LIBMESH_ASSERT_NUMBERS_EQUAL
896 (grad_u_z, true_grad(2), this->_grad_tol);
897 };
898
899 testLoop(f);
900 }

References FETestBase< order, family, elem_type, 1, CaseName >::_dim, FETestBase< order, family, elem_type, 1, CaseName >::_dof_indices, FETestBase< order, family, elem_type, 1, CaseName >::_fe, FETestBase< order, family, elem_type, 1, CaseName >::_grad_tol, FETestBase< order, family, elem_type, 1, CaseName >::_sys, libMesh::System::current_local_solution, FETest< order, family, elem_type, CaseName >::testLoop(), and FETestBase< order, family, elem_type, 1, CaseName >::true_gradient().

◆ testHessU()

template<Order order, FEFamily family, ElemType elem_type, typename CaseName >
void FETest< order, family, elem_type, CaseName >::testHessU ( )
inline

Definition at line 903 of file fe_test.h.

904 {
905 LOG_UNIT_TEST;
906
907 // Szabab elements don't have second derivatives yet
908 if (family == SZABAB)
909 return;
910
911#ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
912 auto f = [this](Point p)
913 {
914 Tensor hess_u;
915 for (std::size_t d = 0; d != this->_dof_indices.size(); ++d)
916 hess_u += this->_fe->get_d2phi()[d][0] * (*this->_sys->current_local_solution)(this->_dof_indices[d]);
917
918 // TODO: Yeah we'll test the ugly expressions later.
919 if (family == RATIONAL_BERNSTEIN && order > 1)
920 return;
921
922 RealTensor true_hess = this->true_hessian(p);
923
924 LIBMESH_ASSERT_NUMBERS_EQUAL
925 (true_hess(0,0), hess_u(0,0), this->_hess_tol);
926 if (this->_dim > 1)
927 {
928 LIBMESH_ASSERT_NUMBERS_EQUAL
929 (hess_u(0,1), hess_u(1,0), this->_hess_tol);
930 LIBMESH_ASSERT_NUMBERS_EQUAL
931 (true_hess(0,1), hess_u(0,1), this->_hess_tol);
932 LIBMESH_ASSERT_NUMBERS_EQUAL
933 (true_hess(1,1), hess_u(1,1), this->_hess_tol);
934 }
935 if (this->_dim > 2)
936 {
937 LIBMESH_ASSERT_NUMBERS_EQUAL
938 (hess_u(0,2), hess_u(2,0), this->_hess_tol);
939 LIBMESH_ASSERT_NUMBERS_EQUAL
940 (hess_u(1,2), hess_u(2,1), this->_hess_tol);
941 LIBMESH_ASSERT_NUMBERS_EQUAL
942 (true_hess(0,2), hess_u(0,2), this->_hess_tol);
943 LIBMESH_ASSERT_NUMBERS_EQUAL
944 (true_hess(1,2), hess_u(1,2), this->_hess_tol);
945 LIBMESH_ASSERT_NUMBERS_EQUAL
946 (true_hess(2,2), hess_u(2,2), this->_hess_tol);
947 }
948 };
949
950 testLoop(f);
951#endif // LIBMESH_ENABLE_SECOND_DERIVATIVES
952 }
This class defines a tensor in LIBMESH_DIM dimensional Real or Complex space.

References FETestBase< order, family, elem_type, 1, CaseName >::_dim, FETestBase< order, family, elem_type, 1, CaseName >::_dof_indices, FETestBase< order, family, elem_type, 1, CaseName >::_fe, FETestBase< order, family, elem_type, 1, CaseName >::_hess_tol, FETestBase< order, family, elem_type, 1, CaseName >::_sys, libMesh::System::current_local_solution, libMesh::RATIONAL_BERNSTEIN, libMesh::SZABAB, FETest< order, family, elem_type, CaseName >::testLoop(), and FETestBase< order, family, elem_type, 1, CaseName >::true_hessian().

◆ testHessUComp()

template<Order order, FEFamily family, ElemType elem_type, typename CaseName >
void FETest< order, family, elem_type, CaseName >::testHessUComp ( )
inline

Definition at line 954 of file fe_test.h.

955 {
956#ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
957 LOG_UNIT_TEST;
958
959 // Szabab elements don't have second derivatives yet
960 if (family == SZABAB)
961 return;
962
963 auto f = [this](Point p)
964 {
965 Number hess_u_xx = 0, hess_u_xy = 0, hess_u_yy = 0,
966 hess_u_xz = 0, hess_u_yz = 0, hess_u_zz = 0;
967 for (std::size_t d = 0; d != this->_dof_indices.size(); ++d)
968 {
969 hess_u_xx += this->_fe->get_d2phidx2()[d][0] * (*this->_sys->current_local_solution)(this->_dof_indices[d]);
970#if LIBMESH_DIM > 1
971 hess_u_xy += this->_fe->get_d2phidxdy()[d][0] * (*this->_sys->current_local_solution)(this->_dof_indices[d]);
972 hess_u_yy += this->_fe->get_d2phidy2()[d][0] * (*this->_sys->current_local_solution)(this->_dof_indices[d]);
973#endif
974#if LIBMESH_DIM > 2
975 hess_u_xz += this->_fe->get_d2phidxdz()[d][0] * (*this->_sys->current_local_solution)(this->_dof_indices[d]);
976 hess_u_yz += this->_fe->get_d2phidydz()[d][0] * (*this->_sys->current_local_solution)(this->_dof_indices[d]);
977 hess_u_zz += this->_fe->get_d2phidz2()[d][0] * (*this->_sys->current_local_solution)(this->_dof_indices[d]);
978#endif
979 }
980
981 // TODO: Yeah we'll test the ugly expressions later.
982 if (family == RATIONAL_BERNSTEIN && order > 1)
983 return;
984
985 RealTensor true_hess = this->true_hessian(p);
986
987 LIBMESH_ASSERT_NUMBERS_EQUAL
988 (true_hess(0,0), hess_u_xx, this->_hess_tol);
989 if (this->_dim > 1)
990 {
991 LIBMESH_ASSERT_NUMBERS_EQUAL
992 (true_hess(0,1), hess_u_xy, this->_hess_tol);
993 LIBMESH_ASSERT_NUMBERS_EQUAL
994 (true_hess(1,1), hess_u_yy, this->_hess_tol);
995 }
996 if (this->_dim > 2)
997 {
998 LIBMESH_ASSERT_NUMBERS_EQUAL
999 (true_hess(0,2), hess_u_xz, this->_hess_tol);
1000 LIBMESH_ASSERT_NUMBERS_EQUAL
1001 (true_hess(1,2), hess_u_yz, this->_hess_tol);
1002 LIBMESH_ASSERT_NUMBERS_EQUAL
1003 (true_hess(2,2), hess_u_zz, this->_hess_tol);
1004 }
1005 };
1006
1007 testLoop(f);
1008#endif // LIBMESH_ENABLE_SECOND_DERIVATIVES
1009 }

References FETestBase< order, family, elem_type, 1, CaseName >::_dim, FETestBase< order, family, elem_type, 1, CaseName >::_dof_indices, FETestBase< order, family, elem_type, 1, CaseName >::_fe, FETestBase< order, family, elem_type, 1, CaseName >::_hess_tol, FETestBase< order, family, elem_type, 1, CaseName >::_sys, libMesh::System::current_local_solution, libMesh::RATIONAL_BERNSTEIN, libMesh::SZABAB, FETest< order, family, elem_type, CaseName >::testLoop(), and FETestBase< order, family, elem_type, 1, CaseName >::true_hessian().

◆ testLoop()

template<Order order, FEFamily family, ElemType elem_type, typename CaseName >
template<typename Functor >
void FETest< order, family, elem_type, CaseName >::testLoop ( Functor  f)
inline

Definition at line 632 of file fe_test.h.

633 {
634 // Handle the "more processors than elements" case
635 if (!this->_elem)
636 return;
637
638 // These tests require exceptions to be enabled because a
639 // TypeTensor::solve() call down in Elem::contains_point()
640 // actually throws a non-fatal exception for a certain Point which
641 // is not in the Elem. When exceptions are not enabled, this test
642 // simply aborts.
643#ifdef LIBMESH_ENABLE_EXCEPTIONS
644 for (unsigned int i=0; i != this->_nx; ++i)
645 for (unsigned int j=0; j != this->_ny; ++j)
646 for (unsigned int k=0; k != this->_nz; ++k)
647 {
648 Point p = Real(i)/this->_nx;
649 if (j > 0)
650 p(1) = Real(j)/this->_ny;
651 if (k > 0)
652 p(2) = Real(k)/this->_nz;
653 if (!this->_elem->contains_point(p))
654 continue;
655
656 // If at a singular node, cannot use FEMap::map
657 if (this->_elem->local_singular_node(p) != invalid_uint)
658 continue;
659
660 std::vector<Point> master_points
661 (1, FEMap::inverse_map(this->_dim, this->_elem, p));
662
663 // Reinit at point to test against analytic solution
664 this->_fe->reinit(this->_elem, &master_points);
665
666 f(p);
667 }
668#endif // LIBMESH_ENABLE_EXCEPTIONS
669 }
virtual bool contains_point(const Point &p, Real tol=TOLERANCE) const
Definition elem.C:2784
virtual unsigned int local_singular_node(const Point &, const Real=TOLERANCE *TOLERANCE) const
Definition elem.h:1840
static Point inverse_map(const unsigned int dim, const Elem *elem, const Point &p, const Real tolerance=TOLERANCE, const bool secure=true, const bool extra_checks=true)
Definition fe_map.C:1512
const unsigned int invalid_uint
A number which is used quite often to represent an invalid or uninitialized value for an unsigned int...
Definition libmesh.h:303

References FETestBase< order, family, elem_type, 1, CaseName >::_dim, FETestBase< order, family, elem_type, 1, CaseName >::_elem, FETestBase< order, family, elem_type, 1, CaseName >::_fe, FETestBase< order, family, elem_type, 1, CaseName >::_nx, FETestBase< order, family, elem_type, 1, CaseName >::_ny, FETestBase< order, family, elem_type, 1, CaseName >::_nz, libMesh::Elem::contains_point(), libMesh::invalid_uint, libMesh::FEMap::inverse_map(), libMesh::Elem::local_singular_node(), and libMesh::Real.

Referenced by FETest< order, family, elem_type, CaseName >::testGradU(), FETest< order, family, elem_type, CaseName >::testGradUComp(), FETest< order, family, elem_type, CaseName >::testHessU(), FETest< order, family, elem_type, CaseName >::testHessUComp(), and FETest< order, family, elem_type, CaseName >::testU().

◆ testPartitionOfUnity()

template<Order order, FEFamily family, ElemType elem_type, typename CaseName >
void FETest< order, family, elem_type, CaseName >::testPartitionOfUnity ( )
inline

Definition at line 671 of file fe_test.h.

672 {
673 if (!this->_elem)
674 return;
675
676 this->_fe->reinit(this->_elem);
677
678 bool satisfies_partition_of_unity = true;
679 for (const auto qp : make_range(this->_qrule->n_points()))
680 {
681 Real phi_sum = 0;
682 for (std::size_t d = 0; d != this->_dof_indices.size(); ++d)
683 phi_sum += this->_fe->get_phi()[d][qp];
684 if (phi_sum < (1 - TOLERANCE) || phi_sum > (1 + TOLERANCE))
685 {
686 satisfies_partition_of_unity = false;
687 break;
688 }
689 }
690
691 switch (this->_fe->get_family())
692 {
693 case MONOMIAL:
694 {
695 switch (this->_fe->get_order())
696 {
697 case CONSTANT:
698 CPPUNIT_ASSERT(satisfies_partition_of_unity);
699 break;
700
701 default:
702 CPPUNIT_ASSERT(!satisfies_partition_of_unity);
703 break;
704 }
705 break;
706 }
707 case SZABAB:
708 case HIERARCHIC:
709 case L2_HIERARCHIC:
710 {
711 switch (this->_fe->get_order())
712 {
713 case FIRST:
714 CPPUNIT_ASSERT(satisfies_partition_of_unity);
715 break;
716
717 default:
718 CPPUNIT_ASSERT(!satisfies_partition_of_unity);
719 break;
720 }
721 break;
722 }
723
724 case XYZ:
725 case CLOUGH:
726 case HERMITE:
727 {
728 CPPUNIT_ASSERT(!satisfies_partition_of_unity);
729 break;
730 }
731
732 case LAGRANGE:
733 case L2_LAGRANGE:
734 case BERNSTEIN:
736 {
737 CPPUNIT_ASSERT(satisfies_partition_of_unity);
738 break;
739 }
740
741 default:
742 CPPUNIT_FAIL("Uncovered FEFamily");
743 }
744 }

References FETestBase< order, family, elem_type, 1, CaseName >::_dof_indices, FETestBase< order, family, elem_type, 1, CaseName >::_elem, FETestBase< order, family, elem_type, 1, CaseName >::_fe, FETestBase< order, family, elem_type, 1, CaseName >::_qrule, libMesh::BERNSTEIN, libMesh::CLOUGH, libMesh::CONSTANT, libMesh::FIRST, libMesh::HERMITE, libMesh::HIERARCHIC, libMesh::L2_HIERARCHIC, libMesh::L2_LAGRANGE, libMesh::LAGRANGE, libMesh::make_range(), libMesh::MONOMIAL, libMesh::RATIONAL_BERNSTEIN, libMesh::Real, libMesh::SZABAB, libMesh::TOLERANCE, and libMesh::XYZ.

◆ testU()

template<Order order, FEFamily family, ElemType elem_type, typename CaseName >
void FETest< order, family, elem_type, CaseName >::testU ( )
inline

Definition at line 792 of file fe_test.h.

793 {
794 LOG_UNIT_TEST;
795
796 auto f = [this](Point p)
797 {
798 Parameters dummy;
799
800 Number u = 0;
801 for (std::size_t d = 0; d != this->_dof_indices.size(); ++d)
802 u += this->_fe->get_phi()[d][0] * (*this->_sys->current_local_solution)(this->_dof_indices[d]);
803
804 Number true_u;
805
806 if (family == RATIONAL_BERNSTEIN && order > 1)
807 true_u = rational_test(p, dummy, "", "");
808 else if (order > 3)
809 true_u = fe_quartic_test(p, dummy, "", "");
810 else if (FE_CAN_TEST_CUBIC)
811 true_u = fe_cubic_test(p, dummy, "", "");
812 else if (order > 1)
813 true_u = p(0)*p(0) + 0.5*p(1)*p(1) + 0.25*p(2)*p(2) +
814 0.125*p(0)*p(1) + 0.0625*p(0)*p(2) + 0.03125*p(1)*p(2);
815 else
816 true_u = p(0) + 0.25*p(1) + 0.0625*p(2);
817
818 LIBMESH_ASSERT_NUMBERS_EQUAL (true_u, u, this->_value_tol);
819 };
820
821 testLoop(f);
822 }

References FETestBase< order, family, elem_type, 1, CaseName >::_dof_indices, FETestBase< order, family, elem_type, 1, CaseName >::_fe, FETestBase< order, family, elem_type, 1, CaseName >::_sys, FETestBase< order, family, elem_type, 1, CaseName >::_value_tol, libMesh::System::current_local_solution, fe_cubic_test(), fe_quartic_test(), libMesh::RATIONAL_BERNSTEIN, rational_test(), and FETest< order, family, elem_type, CaseName >::testLoop().

◆ true_gradient()

static RealGradient FETestBase< order, family, elem_type, build_nx, CaseName >::true_gradient ( Point  p)
inlinestaticprotectedinherited

Definition at line 289 of file fe_test.h.

290 {
291 Parameters dummy;
292
293 Gradient true_grad;
294 RealGradient returnval;
295
296 if (family == RATIONAL_BERNSTEIN && order > 1)
297 true_grad = rational_test_grad(p, dummy, "", "");
298 else if (order > 3)
299 true_grad = fe_quartic_test_grad(p, dummy, "", "");
300 else if (FE_CAN_TEST_CUBIC)
301 true_grad = fe_cubic_test_grad(p, dummy, "", "");
302 else if (order > 1)
303 {
304 const Real & x = p(0);
305 const Real & y = (LIBMESH_DIM > 1) ? p(1) : 0;
306 const Real & z = (LIBMESH_DIM > 2) ? p(2) : 0;
307
308 true_grad = Gradient(2*x+0.125*y+0.0625*z,
309 y+0.125*x+0.03125*z,
310 0.5*z+0.0625*x+0.03125*y);
311 }
312 else
313 true_grad = Gradient(1.0, 0.25, 0.0625);
314
315 for (unsigned int d=0; d != LIBMESH_DIM; ++d)
316 {
317 CPPUNIT_ASSERT(true_grad(d) ==
318 Number(libmesh_real(true_grad(d))));
319
320 returnval(d) = libmesh_real(true_grad(d));
321 }
322
323 return returnval;
324 }
NumberVectorValue Gradient
T libmesh_real(T a)

◆ true_hessian()

static RealTensor FETestBase< order, family, elem_type, build_nx, CaseName >::true_hessian ( Point  p)
inlinestaticprotectedinherited

Definition at line 327 of file fe_test.h.

328 {
329 const Real & x = p(0);
330 const Real & y = LIBMESH_DIM > 1 ? p(1) : 0;
331 const Real & z = LIBMESH_DIM > 2 ? p(2) : 0;
332
333 if (order > 3)
334 return RealTensor
335 { 12*x*x-12*x+2+2*z*(1-y)-2*(1-y)*(1-z), -2*x*z-(1-2*x)*(1-z)-(1-2*y)*z, 2*x*(1-y)-(1-2*x)*(1-y)-y*(1-y),
336 -2*x*z-(1-2*x)*(1-z)-(1-2*y)*z, -2*(1-x)*z, -x*x+x*(1-x)+(1-x)*(1-2*y),
337 2*x*(1-y)-(1-2*x)*(1-y)-y*(1-y), -x*x+x*(1-x)+(1-x)*(1-2*y), 12*z*z-12*z+2 };
338 else if (FE_CAN_TEST_CUBIC)
339 return RealTensor
340 { 6*x-4+2*(1-y), -2*x+z-1, y-1,
341 -2*x+z-1, -2*z, x+1-2*y,
342 y-1, x+1-2*y, 6*z-4 };
343 else if (order > 1)
344 return RealTensor
345 { 2, 0.125, 0.0625,
346 0.125, 1, 0.03125,
347 0.0625, 0.03125, 0.5 };
348
349 return RealTensor
350 { 0, 0, 0,
351 0, 0, 0,
352 0, 0, 0 };
353 }

Member Data Documentation

◆ _case_name

std::string FETestBase< order, family, elem_type, build_nx, CaseName >::_case_name
protectedinherited

Name of the case, can be used in the test to switch cases.

Definition at line 275 of file fe_test.h.

◆ _dim

unsigned int FETestBase< order, family, elem_type, build_nx, CaseName >::_dim
protectedinherited

Definition at line 277 of file fe_test.h.

◆ _dof_indices

std::vector<dof_id_type> FETestBase< order, family, elem_type, build_nx, CaseName >::_dof_indices
protectedinherited

Definition at line 279 of file fe_test.h.

◆ _elem

Elem* FETestBase< order, family, elem_type, build_nx, CaseName >::_elem
protectedinherited

Definition at line 278 of file fe_test.h.

◆ _es

std::unique_ptr<EquationSystems> FETestBase< order, family, elem_type, build_nx, CaseName >::_es
protectedinherited

Definition at line 282 of file fe_test.h.

◆ _fe

std::unique_ptr<FEBase> FETestBase< order, family, elem_type, build_nx, CaseName >::_fe
protectedinherited

Definition at line 283 of file fe_test.h.

◆ _grad_tol

Real FETestBase< order, family, elem_type, build_nx, CaseName >::_grad_tol
protectedinherited

Definition at line 286 of file fe_test.h.

◆ _hess_tol

Real FETestBase< order, family, elem_type, build_nx, CaseName >::_hess_tol
protectedinherited

Definition at line 286 of file fe_test.h.

◆ _mesh

std::unique_ptr<Mesh> FETestBase< order, family, elem_type, build_nx, CaseName >::_mesh
protectedinherited

Definition at line 281 of file fe_test.h.

◆ _nx

unsigned int FETestBase< order, family, elem_type, build_nx, CaseName >::_nx
protectedinherited

Definition at line 277 of file fe_test.h.

◆ _ny

unsigned int FETestBase< order, family, elem_type, build_nx, CaseName >::_ny
protectedinherited

Definition at line 277 of file fe_test.h.

◆ _nz

unsigned int FETestBase< order, family, elem_type, build_nx, CaseName >::_nz
protectedinherited

Definition at line 277 of file fe_test.h.

◆ _qrule

std::unique_ptr<QGauss> FETestBase< order, family, elem_type, build_nx, CaseName >::_qrule
protectedinherited

Definition at line 284 of file fe_test.h.

◆ _sys

System* FETestBase< order, family, elem_type, build_nx, CaseName >::_sys
protectedinherited

Definition at line 280 of file fe_test.h.

◆ _value_tol

Real FETestBase< order, family, elem_type, build_nx, CaseName >::_value_tol
protectedinherited

Definition at line 286 of file fe_test.h.

◆ libmesh_suite_name

std::string FETestBase< order, family, elem_type, build_nx, CaseName >::libmesh_suite_name
protectedinherited

Definition at line 272 of file fe_test.h.


The documentation for this class was generated from the following file: