libMesh
dof_map_test.C
Go to the documentation of this file.
1 #include <libmesh/equation_systems.h>
2 #include <libmesh/mesh.h>
3 #include <libmesh/mesh_generation.h>
4 #include <libmesh/elem.h>
5 #include <libmesh/dof_map.h>
6 
8 
9 #include "test_comm.h"
10 #include "libmesh_cppunit.h"
11 
12 #include <regex>
13 #include <string>
14 
15 using namespace libMesh;
16 
17 #ifdef LIBMESH_ENABLE_CONSTRAINTS
18 // This class is used by testConstraintLoopDetection
20 {
21 private:
22 
24 
25 public:
26 
27  MyConstraint( System & sys ) : Constraint(), _sys(sys) {}
28 
29  virtual ~MyConstraint() {}
30 
31  void constrain()
32  {
33  {
34  const dof_id_type constrained_dof_index = 0;
35  DofConstraintRow constraint_row;
36  constraint_row[1] = 1.0;
37  _sys.get_dof_map().add_constraint_row( constrained_dof_index, constraint_row, 0., true);
38  }
39  {
40  const dof_id_type constrained_dof_index = 1;
41  DofConstraintRow constraint_row;
42  constraint_row[0] = 1.0;
43  _sys.get_dof_map().add_constraint_row( constrained_dof_index, constraint_row, 0., true);
44  }
45  }
46 };
47 #endif
48 
49 
50 class DofMapTest : public CppUnit::TestCase {
51 public:
52  LIBMESH_CPPUNIT_TEST_SUITE( DofMapTest );
53 
54  CPPUNIT_TEST( testDofOwnerOnEdge3 );
55 #if LIBMESH_DIM > 1
56  CPPUNIT_TEST( testDofOwnerOnQuad9 );
57  CPPUNIT_TEST( testDofOwnerOnTri6 );
58 #endif
59 #if LIBMESH_DIM > 2
60  CPPUNIT_TEST( testDofOwnerOnHex27 );
61 #endif
62 
63 #if defined(LIBMESH_ENABLE_EXCEPTIONS)
64  CPPUNIT_TEST( testBadElemFECombo );
65 #endif
66 
67 #if defined(LIBMESH_ENABLE_CONSTRAINTS) && defined(LIBMESH_ENABLE_EXCEPTIONS) && LIBMESH_DIM > 1
68  CPPUNIT_TEST( testConstraintLoopDetection );
69 #endif
70 
71  CPPUNIT_TEST( testArrayDofIndices );
72 
73  CPPUNIT_TEST_SUITE_END();
74 
75 private:
76 
77 public:
78  void setUp()
79  {}
80 
81  void tearDown()
82  {}
83 
84  void testDofOwner(const ElemType elem_type)
85  {
87 
89  System &sys = es.add_system<System> ("SimpleSystem");
90  sys.add_variable("u", THIRD, HIERARCHIC);
91 
92  const unsigned int n_elem_per_side = 3;
93  const std::unique_ptr<Elem> test_elem = Elem::build(elem_type);
94  const unsigned int ymax = test_elem->dim() > 1;
95  const unsigned int zmax = test_elem->dim() > 2;
96  const unsigned int ny = ymax * n_elem_per_side;
97  const unsigned int nz = zmax * n_elem_per_side;
98 
100  n_elem_per_side,
101  ny,
102  nz,
103  0., 1.,
104  0., ymax,
105  0., zmax,
106  elem_type);
107 
108  es.init();
109 
110  DofMap & dof_map = sys.get_dof_map();
111  for (dof_id_type id = 0; id != dof_map.n_dofs(); ++id)
112  {
113  const processor_id_type pid = dof_map.dof_owner(id);
114  CPPUNIT_ASSERT(dof_map.first_dof(pid) <= id);
115  CPPUNIT_ASSERT(id < dof_map.end_dof(pid));
116  }
117  }
118 
119 
120 
121  void testDofOwnerOnEdge3() { LOG_UNIT_TEST; testDofOwner(EDGE3); }
122  void testDofOwnerOnQuad9() { LOG_UNIT_TEST; testDofOwner(QUAD9); }
123  void testDofOwnerOnTri6() { LOG_UNIT_TEST; testDofOwner(TRI6); }
124  void testDofOwnerOnHex27() { LOG_UNIT_TEST; testDofOwner(HEX27); }
125 
126 #if defined(LIBMESH_ENABLE_EXCEPTIONS)
128  {
129  LOG_UNIT_TEST;
130 
132 
133  EquationSystems es(mesh);
134  System & sys = es.add_system<System> ("SimpleSystem");
135  sys.add_variable("u", SECOND);
136 
137  MeshTools::Generation::build_square (mesh,4,4,-1., 1.,-1., 1., QUAD4);
138 
139  // We need at least one element per processor to make sure
140  // everyone throws and we don't get out of sync before going on to
141  // future tests.
142  dof_id_type min_local_elem = mesh.n_local_elem();
143  mesh.comm().min(min_local_elem);
144 
145  if (!min_local_elem)
146  return;
147 
148  // We can't just CPPUNIT_ASSERT_THROW, because we want to make
149  // sure we were thrown from the right place with the right error
150  // message!
151  bool threw_desired_exception = false;
152  try {
153  es.init();
154  }
155  catch (libMesh::LogicError & e) {
156  std::regex msg_regex("only supports FEInterface::max_order");
157  CPPUNIT_ASSERT(std::regex_search(e.what(), msg_regex));
158  threw_desired_exception = true;
159  }
160  catch (...) {
161  CPPUNIT_ASSERT_MESSAGE("Unexpected exception type thrown", false);
162  }
163 
164  // If we have more than 4*4 processors, or a poor partitioner, we
165  // might not get an exception on every processor
166  mesh.comm().max(threw_desired_exception);
167 
168  CPPUNIT_ASSERT(threw_desired_exception);
169  }
170 #endif
171 
172 #if defined(LIBMESH_ENABLE_CONSTRAINTS) && defined(LIBMESH_ENABLE_EXCEPTIONS)
174  {
175  LOG_UNIT_TEST;
177 
178  EquationSystems es(mesh);
179  System & sys = es.add_system<System> ("SimpleSystem");
180  sys.add_variable("u", FIRST);
181 
182  MyConstraint my_constraint(sys);
183  sys.attach_constraint_object(my_constraint);
184 
185  MeshTools::Generation::build_square (mesh,4,4,-1., 1.,-1., 1., QUAD4);
186 
187  // Tell the dof_map to check for constraint loops
188  DofMap & dof_map = sys.get_dof_map();
189  dof_map.set_error_on_constraint_loop(true);
190 
191  CPPUNIT_ASSERT_THROW_MESSAGE("Constraint loop not detected", es.init(), libMesh::LogicError);
192  }
193 #endif
194 
195  void testArrayDofIndicesWithType(const FEType & fe_type)
196  {
198  EquationSystems es(mesh);
199  auto & sys = es.add_system<System>("SimpleSystem");
200  const auto last_var = sys.add_variable_array({"u0", "u1"}, fe_type);
201  MeshTools::Generation::build_square (mesh,1,1,-1., 1.,-1., 1., QUAD9);
202  es.init();
203  auto & dof_map = sys.get_dof_map();
204  const auto * const elem = mesh.query_elem_ptr(0);
205  if (elem)
206  {
207  std::vector<dof_id_type> array_dofs, work_dofs, dofs;
208  dof_map.array_dof_indices(elem, array_dofs, last_var);
209  // Make sure there are no duplicates
210  std::sort(array_dofs.begin(), array_dofs.end());
211  auto it = std::unique(array_dofs.begin(), array_dofs.end());
212  array_dofs.erase(it, array_dofs.end());
213  CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(dof_map.n_dofs()), array_dofs.size());
214  dof_map.dof_indices(elem, work_dofs, last_var);
215  dofs = work_dofs;
216  dof_map.dof_indices(elem, work_dofs, last_var - 1);
217  dofs.insert(dofs.end(), work_dofs.begin(), work_dofs.end());
218  std::sort(dofs.begin(), dofs.end());
219  CPPUNIT_ASSERT(array_dofs == dofs);
220  }
221  }
222 
224  {
225  LOG_UNIT_TEST;
226  for (int i = 1; i < 3; ++i)
227  {
228  testArrayDofIndicesWithType({i, LAGRANGE});
229  testArrayDofIndicesWithType({i, HIERARCHIC});
230  testArrayDofIndicesWithType({i, MONOMIAL});
231  testArrayDofIndicesWithType({i, L2_LAGRANGE});
232  }
233  }
234 
235 };
236 
class FEType hides (possibly multiple) FEFamily and approximation orders, thereby enabling specialize...
Definition: fe_type.h:196
ElemType
Defines an enum for geometric element types.
dof_id_type end_dof(const processor_id_type proc) const
Definition: dof_map_base.h:191
This is the EquationSystems class.
void testDofOwnerOnQuad9()
Definition: dof_map_test.C:122
processor_id_type dof_owner(const dof_id_type dof) const
Definition: dof_map.h:815
void testConstraintLoopDetection()
Definition: dof_map_test.C:173
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:171
unsigned int add_variable_array(const std::vector< std::string > &vars, const FEType &type, const std::set< subdomain_id_type > *const active_subdomains=nullptr)
Adds variables vars to the list of variables for this system.
Definition: system.C:1382
MeshBase & mesh
const Parallel::Communicator & comm() const
void build_square(UnstructuredMesh &mesh, const unsigned int nx, const unsigned int ny, const Real xmin=0., const Real xmax=1., const Real ymin=0., const Real ymax=1., const ElemType type=INVALID_ELEM, const bool gauss_lobatto_grid=false)
A specialized build_cube() for 2D meshes.
dof_id_type n_dofs(const unsigned int vn) const
Definition: dof_map.h:776
The libMesh namespace provides an interface to certain functionality in the library.
void set_error_on_constraint_loop(bool error_on_constraint_loop)
Definition: dof_map.C:234
dof_id_type n_local_elem() const
Definition: mesh_base.h:548
void testDofOwnerOnEdge3()
Definition: dof_map_test.C:121
void attach_constraint_object(Constraint &constrain)
Register a user object for imposing constraints.
Definition: system.C:1987
void testDofOwner(const ElemType elem_type)
Definition: dof_map_test.C:84
This class handles the numbering of degrees of freedom on a mesh.
Definition: dof_map.h:179
uint8_t processor_id_type
void testDofOwnerOnTri6()
Definition: dof_map_test.C:123
void min(const T &r, T &o, Request &req) const
void add_constraint_row(const dof_id_type dof_number, const DofConstraintRow &constraint_row, const Number constraint_rhs, const bool forbid_constraint_overwrite)
Adds a copy of the user-defined row to the constraint matrix, using an inhomogeneous right-hand-side ...
Manages consistently variables, degrees of freedom, and coefficient vectors.
Definition: system.h:97
static std::unique_ptr< Elem > build(const ElemType type, Elem *p=nullptr)
Definition: elem.C:442
void testArrayDofIndices()
Definition: dof_map_test.C:223
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:1342
System & _sys
Definition: dof_map_test.C:23
virtual const Elem * query_elem_ptr(const dof_id_type i) const =0
void tearDown()
Definition: dof_map_test.C:81
void max(const T &r, T &o, Request &req) const
A class to represent the internal "this should never happen" errors, to be thrown by "libmesh_error()...
std::map< dof_id_type, Real, std::less< dof_id_type >, Threads::scalable_allocator< std::pair< const dof_id_type, Real > > > DofConstraintRow
A row of the Dof constraint matrix.
Definition: dof_map.h:100
void constrain()
Constraint function.
Definition: dof_map_test.C:31
Abstract base class to be used for system constraints.
Definition: system.h:180
void testBadElemFECombo()
Definition: dof_map_test.C:127
virtual void init()
Initialize all the systems.
dof_id_type first_dof(const processor_id_type proc) const
Definition: dof_map_base.h:185
virtual System & add_system(std::string_view system_type, std::string_view name)
Add the system of type system_type named name to the systems array.
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition: mesh.h:50
void testDofOwnerOnHex27()
Definition: dof_map_test.C:124
void setUp()
Definition: dof_map_test.C:78
const DofMap & get_dof_map() const
Definition: system.h:2375
CPPUNIT_TEST_SUITE_REGISTRATION(DofMapTest)
void testArrayDofIndicesWithType(const FEType &fe_type)
Definition: dof_map_test.C:195
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.
MyConstraint(System &sys)
Definition: dof_map_test.C:27
uint8_t dof_id_type
Definition: id_types.h:67
virtual ~MyConstraint()
Definition: dof_map_test.C:29