6#include <libmesh/cell_c0polyhedron.h>
7#include <libmesh/dof_map.h>
8#include <libmesh/elem.h>
9#include <libmesh/equation_systems.h>
10#include <libmesh/face_c0polygon.h>
11#include <libmesh/fe.h>
12#include <libmesh/fe_base.h>
13#include <libmesh/fe_interface.h>
14#include <libmesh/function_base.h>
15#include <libmesh/mesh.h>
16#include <libmesh/mesh_generation.h>
17#include <libmesh/mesh_modification.h>
18#include <libmesh/numeric_vector.h>
19#include <libmesh/system.h>
20#include <libmesh/quadrature_gauss.h>
27 CPPUNIT_TEST( testFEInterface ); \
28 CPPUNIT_TEST( testU ); \
29 CPPUNIT_TEST( testPartitionOfUnity ); \
30 CPPUNIT_TEST( testGradU ); \
31 CPPUNIT_TEST( testGradUComp ); \
32 CPPUNIT_TEST( testHessU ); \
33 CPPUNIT_TEST( testHessUComp ); \
34 CPPUNIT_TEST( testDualDoesntScreamAndDie ); \
35 CPPUNIT_TEST( testCustomReinit );
42 std::unique_ptr<FunctionBase<Real>>
clone ()
const override
43 {
return std::make_unique<SkewFunc>(); }
46 const Real = 0.)
override
47 { libmesh_not_implemented(); }
74 const Real & x = p(0);
75 const Real & y = (LIBMESH_DIM > 1) ? p(1) : 0;
76 const Real & z = (LIBMESH_DIM > 2) ? p(2) : 0;
78 return x + 0.25*y + 0.0625*z;
103 const Real & x = p(0);
104 const Real & y = (LIBMESH_DIM > 1) ? p(1) : 0;
105 const Real & z = (LIBMESH_DIM > 2) ? p(2) : 0;
107 return x*x + 0.5*y*y + 0.25*z*z + 0.125*x*y + 0.0625*x*z + 0.03125*y*z;
116 const Real & x = p(0);
117 const Real & y = (LIBMESH_DIM > 1) ? p(1) : 0;
118 const Real & z = (LIBMESH_DIM > 2) ? p(2) : 0;
120 Gradient grad = 2*x + 0.125*y + 0.0625*z;
122 grad(1) = y + 0.125*x + 0.03125*z;
124 grad(2) = 0.5*z + 0.0625*x + 0.03125*y;
136 const Real & x = p(0);
137 const Real & y = (LIBMESH_DIM > 1) ? p(1) : 0;
138 const Real & z = (LIBMESH_DIM > 2) ? p(2) : 0;
140 return x*(1-x)*(1-x) + x*x*(1-y) + x*(1-y)*(1-z) + y*(1-y)*z + z*(1-z)*(1-z);
149 const Real & x = p(0);
150 const Real & y = (LIBMESH_DIM > 1) ? p(1) : 0;
151 const Real & z = (LIBMESH_DIM > 2) ? p(2) : 0;
153 Gradient grad = 3*x*x-4*x+1 + 2*x*(1-y) + (1-y)*(1-z);
155 grad(1) = -x*x - x*(1-z) + (1-2*y)*z;
157 grad(2) = -x*(1-y) + y*(1-y) + 3*z*z-4*z+1;
169 const Real & x = p(0);
170 const Real & y = (LIBMESH_DIM > 1) ? p(1) : 0;
171 const Real & z = (LIBMESH_DIM > 2) ? p(2) : 0;
173 return x*x*(1-x)*(1-x) + x*x*z*(1-y) + x*(1-x)*(1-y)*(1-z) + (1-x)*y*(1-y)*z + z*z*(1-z)*(1-z);
182 const Real & x = p(0);
183 const Real & y = (LIBMESH_DIM > 1) ? p(1) : 0;
184 const Real & z = (LIBMESH_DIM > 2) ? p(2) : 0;
186 Gradient grad = 4*x*x*x-6*x*x+2*x + 2*x*z*(1-y) + (1-2*x)*(1-y)*(1-z) - y*(1-y)*z;
188 grad(1) = -x*x*z - x*(1-x)*(1-z) + (1-x)*(1-2*y)*z;
190 grad(2) = x*x*(1-y) - x*(1-x)*(1-y) + (1-x)*y*(1-y) + 4*z*z*z-6*z*z+2*z;
208 const Real & x = p(0);
209 const Real & y = (LIBMESH_DIM > 1) ? p(1) : 0;
210 const Real & z = (LIBMESH_DIM > 2) ? p(2) : 0;
216 return (x + 0.25*y + 0.0625*z)/denom;
225 const Real & x = p(0);
226 const Real & y = (LIBMESH_DIM > 1) ? p(1) : 0;
227 const Real & z = (LIBMESH_DIM > 2) ? p(2) : 0;
236 const Real denom = xpoly * ypoly * zpoly;
238 const Real numer = (x + 0.25*y + 0.0625*z);
240 Gradient grad_n = 1, grad_d = xderiv * ypoly * zpoly;
244 grad_d(1) = xpoly * yderiv * zpoly;
249 grad_d(2) = xpoly * ypoly * zderiv;
252 Gradient grad = (grad_n - numer * grad_d / denom) / denom;
258#define FE_CAN_TEST_CUBIC \
259 (((family != LAGRANGE && family != L2_LAGRANGE) || \
260 (elem_type != TRI7 && elem_type != TET14 && \
261 elem_type != PRISM20 && elem_type != PRISM21 && \
262 elem_type != PYRAMID18)) && order > 2)
268template <Order order, FEFamily family, ElemType elem_type,
unsigned int build_nx,
typename CaseName = Default>
282 std::unique_ptr<EquationSystems>
_es;
283 std::unique_ptr<FEBase>
_fe;
300 else if (FE_CAN_TEST_CUBIC)
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;
308 true_grad =
Gradient(2*x+0.125*y+0.0625*z,
310 0.5*z+0.0625*x+0.03125*y);
313 true_grad =
Gradient(1.0, 0.25, 0.0625);
315 for (
unsigned int d=0; d != LIBMESH_DIM; ++d)
317 CPPUNIT_ASSERT(true_grad(d) ==
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;
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)
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 };
347 0.0625, 0.03125, 0.5 };
360 const unsigned int build_ny = (
_dim > 1) * build_nx;
361 const unsigned int build_nz = (
_dim > 2) * build_nx;
363 unsigned char weight_index = 0;
368 _mesh->add_node_integer(
"buffer integer");
372 const Real default_weight = 1.0;
373 weight_index = cast_int<unsigned char>
374 (
_mesh->add_node_datum<
Real>(
"rational_weight",
true,
376 libmesh_assert_not_equal_to(weight_index, 0);
381 _mesh->set_default_mapping_data(weight_index);
396 std::unique_ptr<Elem> polygon = std::make_unique<C0Polygon>(5);
398 polygon->set_node(i,
_mesh->node_ptr(i));
399 polygon->set_id() = 0;
401 _mesh->add_elem(std::move(polygon));
402 _mesh->prepare_for_use();
423 std::vector<std::vector<unsigned int>> nodes_on_side;
425 nodes_on_side = { {0, 1, 2, 3},
432 nodes_on_side = { {0, 1, 2, 3},
439 libmesh_error_msg(
"Unknown case name: " +
_case_name);
442 std::vector<std::shared_ptr<Polygon>> sides(nodes_on_side.size());
446 const auto & nodes_on_s = nodes_on_side[s];
447 sides[s] = std::make_shared<C0Polygon>(nodes_on_s.size());
449 sides[s]->set_node(i,
_mesh->node_ptr(nodes_on_s[i]));
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));
456 _mesh->add_node(std::move(mid_elem_node));
457 _mesh->prepare_for_use();
462 build_nx, build_ny, build_nz,
463 0., 1., 0., 1., 0., 1.,
474 if (elem && elem->
id())
475 _mesh->delete_elem(elem);
477 _mesh->prepare_for_use();
504 for (
auto elem :
_mesh->active_element_ptr_range())
510 const unsigned int nn = elem->n_nodes();
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);
520 for (
unsigned int i = 0; i != nv; ++i)
522 for (
unsigned int i = nv; i != nve; ++i)
525 for (
unsigned int i = nve; i != nvef; ++i)
528 for (
unsigned int i = nvef; i != nn; ++i)
533 _mesh->complete_preparation();
534 _es = std::make_unique<EquationSystems>(*
_mesh);
549 else if (FE_CAN_TEST_CUBIC)
567 _fe->attach_quadrature_rule(
_qrule.get());
569 auto rng =
_mesh->active_local_element_ptr_range();
570 this->_elem = rng.begin() == rng.end() ? nullptr : *(rng.begin());
600#if LIBMESH_ENABLE_SECOND_DERIVATIVES
609 _fe->get_d2phidxdy();
613 _fe->get_d2phidxdz();
614 _fe->get_d2phidydz();
626template <Order order, FEFamily family, ElemType elem_type,
typename CaseName>
631 template <
typename Functor>
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)
660 std::vector<Point> master_points
664 this->
_fe->reinit(this->
_elem, &master_points);
678 bool satisfies_partition_of_unity =
true;
682 for (std::size_t d = 0; d != this->
_dof_indices.size(); ++d)
683 phi_sum += this->
_fe->get_phi()[d][qp];
686 satisfies_partition_of_unity =
false;
691 switch (this->
_fe->get_family())
695 switch (this->
_fe->get_order())
698 CPPUNIT_ASSERT(satisfies_partition_of_unity);
702 CPPUNIT_ASSERT(!satisfies_partition_of_unity);
711 switch (this->
_fe->get_order())
714 CPPUNIT_ASSERT(satisfies_partition_of_unity);
718 CPPUNIT_ASSERT(!satisfies_partition_of_unity);
728 CPPUNIT_ASSERT(!satisfies_partition_of_unity);
737 CPPUNIT_ASSERT(satisfies_partition_of_unity);
742 CPPUNIT_FAIL(
"Uncovered FEFamily");
759 unsigned int my_n_dofs = 0;
779 CPPUNIT_ASSERT_EQUAL(
783 CPPUNIT_ASSERT_EQUAL(
785 this->
_fe->get_continuity());
787 CPPUNIT_ASSERT_EQUAL(
789 this->
_fe->is_hierarchic());
796 auto f = [
this](
Point p)
801 for (std::size_t d = 0; d != this->
_dof_indices.size(); ++d)
810 else if (FE_CAN_TEST_CUBIC)
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);
816 true_u = p(0) + 0.25*p(1) + 0.0625*p(2);
818 LIBMESH_ASSERT_NUMBERS_EQUAL (true_u, u, this->
_value_tol);
833 this->
_fe->get_dual_phi();
844 auto f = [
this](
Point p)
849 for (std::size_t d = 0; d != this->
_dof_indices.size(); ++d)
854 LIBMESH_ASSERT_NUMBERS_EQUAL
855 (grad_u(0), true_grad(0), this->
_grad_tol);
857 LIBMESH_ASSERT_NUMBERS_EQUAL
858 (grad_u(1), true_grad(1), this->
_grad_tol);
860 LIBMESH_ASSERT_NUMBERS_EQUAL
861 (grad_u(2), true_grad(2), this->
_grad_tol);
871 auto f = [
this](
Point p)
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)
889 LIBMESH_ASSERT_NUMBERS_EQUAL(grad_u_x,
892 LIBMESH_ASSERT_NUMBERS_EQUAL
893 (grad_u_y, true_grad(1), this->
_grad_tol);
895 LIBMESH_ASSERT_NUMBERS_EQUAL
896 (grad_u_z, true_grad(2), this->
_grad_tol);
911#ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
912 auto f = [
this](
Point p)
915 for (std::size_t d = 0; d != this->
_dof_indices.size(); ++d)
924 LIBMESH_ASSERT_NUMBERS_EQUAL
925 (true_hess(0,0), hess_u(0,0), this->
_hess_tol);
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);
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);
956#ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
963 auto f = [
this](
Point p)
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)
987 LIBMESH_ASSERT_NUMBERS_EQUAL
988 (true_hess(0,0), hess_u_xx, this->
_hess_tol);
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);
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);
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];
1024 const int extraorder = 3;
1026 fe->attach_quadrature_rule (qrule.get());
1028 const std::vector<Point> & q_pos = fe->get_xyz();
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));
1040#define INSTANTIATE_FETEST_CASE(order, family, elemtype, case_name) \
1041 class FETest_##order##_##family##_##elemtype##_##case_name : public FETest<order, family, elemtype, case_name> { \
1043 FETest_##order##_##family##_##elemtype##_##case_name() : \
1044 FETest<order,family,elemtype,case_name>() { \
1045 if (unitlog->summarized_logs_enabled()) \
1046 this->libmesh_suite_name = "FETest"; \
1048 this->libmesh_suite_name = "FETest_" #order "_" #family "_" #elemtype "_" #case_name; \
1049 this->_case_name = #case_name; \
1051 CPPUNIT_TEST_SUITE( FETest_##order##_##family##_##elemtype##_##case_name ); \
1053 CPPUNIT_TEST_SUITE_END(); \
1056 CPPUNIT_TEST_SUITE_REGISTRATION( FETest_##order##_##family##_##elemtype##_##case_name );
1058#define INSTANTIATE_FETEST(order, family, elemtype) \
1059 INSTANTIATE_FETEST_CASE(order, family, elemtype, Default)
std::string _case_name
Name of the case, can be used in the test to switch cases.
std::string libmesh_suite_name
std::unique_ptr< EquationSystems > _es
std::unique_ptr< FEBase > _fe
std::unique_ptr< Mesh > _mesh
std::vector< dof_id_type > _dof_indices
std::unique_ptr< QGauss > _qrule
static RealTensor true_hessian(Point p)
static RealGradient true_gradient(Point p)
void testPartitionOfUnity()
void testDualDoesntScreamAndDie()
Real operator()(const Point &, const Real=0.) override
std::unique_ptr< FunctionBase< Real > > clone() const override
Defines a dense vector for use in Finite Element-type computations.
void resize(const unsigned int n)
Resize the vector.
void dof_indices(const Elem *const elem, std::vector< dof_id_type > &di) const
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...
This is the base class from which all geometric element types are derived.
virtual unsigned int n_vertices() const =0
const Node & node_ref(const unsigned int i) const
virtual bool contains_point(const Point &p, Real tol=TOLERANCE) const
virtual unsigned short dim() 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...
virtual unsigned int local_singular_node(const Point &, const Real=TOLERANCE *TOLERANCE) const
static std::unique_ptr< FEGenericBase > build(const unsigned int dim, const FEType &type)
Builds a specific finite element type.
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 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)
class FEType hides (possibly multiple) FEFamily and approximation orders, thereby enabling specialize...
std::unique_ptr< QBase > default_quadrature_rule(const unsigned int dim, const int extraorder=0) const
Order default_quadrature_order() const
static unsigned int n_dofs(const ElemType t, const Order o)
Base class for functors that can be evaluated at a point and (optionally) time.
This class provides the ability to map between arbitrary, user-defined strings and several data types...
A Point defines a location in LIBMESH_DIM dimensional Real space.
Manages consistently variables, degrees of freedom, and coefficient vectors.
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.
std::unique_ptr< NumericVector< Number > > current_local_solution
All the values I need to compute my contribution to the simulation at hand.
const FEType & variable_type(const unsigned int i) const
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.
const DofMap & get_dof_map() const
This class defines a tensor in LIBMESH_DIM dimensional Real or Complex space.
This class defines a vector in LIBMESH_DIM dimensional Real or Complex space.
Communicator * TestCommWorld
static const Real rational_w
Number fe_cubic_test(const Point &p, const Parameters &, const std::string &, const std::string &)
Number rational_test(const Point &p, const Parameters &, const std::string &, const std::string &)
Gradient quadratic_test_grad(const Point &p, const Parameters &, const std::string &, const std::string &)
Number quadratic_test(const Point &p, const Parameters &, const std::string &, const std::string &)
Gradient fe_quartic_test_grad(const Point &p, const Parameters &, const std::string &, const std::string &)
Gradient linear_test_grad(const Point &, const Parameters &, const std::string &, const std::string &)
Number fe_quartic_test(const Point &p, const Parameters &, const std::string &, const std::string &)
Gradient rational_test_grad(const Point &p, const Parameters &, const std::string &, const std::string &)
Gradient fe_cubic_test_grad(const Point &p, const Parameters &, const std::string &, const std::string &)
Number linear_test(const Point &p, const Parameters &, const std::string &, const std::string &)
The libMesh namespace provides an interface to certain functionality in the library.
auto index_range(const T &sizable)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...
NumberVectorValue Gradient
const unsigned int invalid_uint
A number which is used quite often to represent an invalid or uninitialized value for an unsigned int...
static constexpr Real TOLERANCE
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...