libMesh
constraint_operator_test.C
Go to the documentation of this file.
1 #include <libmesh/dof_map.h>
2 #include <libmesh/elem.h>
3 #include <libmesh/enum_norm_type.h>
4 #include <libmesh/equation_systems.h>
5 #include <libmesh/exact_solution.h>
6 #include <libmesh/int_range.h>
7 #include <libmesh/linear_implicit_system.h>
8 #include <libmesh/mesh.h>
9 #include <libmesh/mesh_generation.h>
10 #include <libmesh/mesh_function.h>
11 #include <libmesh/mesh_tools.h>
12 #include <libmesh/numeric_vector.h>
13 #include <libmesh/parallel.h>
14 #include <libmesh/quadrature.h>
15 #include <libmesh/replicated_mesh.h>
16 #include <libmesh/sparse_matrix.h>
17 #include <libmesh/petsc_macro.h>
18 
19 #include "test_comm.h"
20 #include "libmesh_cppunit.h"
21 
22 #include <string>
23 
24 using namespace libMesh;
25 
26 namespace {
27 
28 // A simple u"+u=f
30  const std::string&)
31 {
32  const MeshBase& mesh = es.get_mesh();
34  const DofMap& dof_map = system.get_dof_map();
35  SparseMatrix<Number> & matrix = system.get_system_matrix();
36 
37  FEMContext c(system);
38 
39  const unsigned short dim = mesh.mesh_dimension();
40  FEBase * fe = nullptr;
41  c.get_element_fe(0, fe, dim);
42 
43  const std::vector<Real> & JxW = fe->get_JxW();
44  const std::vector<Point> & xyz = fe->get_xyz();
45  const std::vector<std::vector<Real>> & phi = fe->get_phi();
46  const std::vector<std::vector<RealGradient>> & dphi = fe->get_dphi();
47 
48  std::vector<dof_id_type> & dof_indices = c.get_dof_indices();
49 
50  // The subvectors and submatrices we need to fill:
51  DenseMatrix<Number> & K = c.get_elem_jacobian();
52  DenseVector<Number> & F = c.get_elem_residual();
53 
54  MeshBase::const_element_iterator el = mesh.active_local_elements_begin();
55  const MeshBase::const_element_iterator end_el = mesh.active_local_elements_end();
56 
57  for ( ; el != end_el; ++el)
58  {
59  const Elem* elem = *el;
60 
61  if(elem->type() == NODEELEM)
62  continue;
63 
64  c.pre_fe_reinit(system, elem);
65  c.elem_fe_reinit();
66 
67  unsigned int n_dofs = dof_indices.size();
68  unsigned int n_qpoints = c.get_element_qrule().n_points();
69 
70  for (unsigned int qp=0; qp != n_qpoints; qp++)
71  {
72  const Gradient grad_u = c.interior_gradient(0, qp);
73  const Number u = c.interior_value(0, qp);
74  const Point p = xyz[qp];
75 
76  const Number forcing = p(0);
77 
78  for (unsigned int i=0; i != n_dofs; i++)
79  {
80  F(i) += JxW[qp] * (grad_u * dphi[i][qp] + (forcing-u) * phi[i][qp]);
81  for (unsigned int j=0; j != n_dofs; ++j)
82  K(i,j) += JxW[qp] * (dphi[i][qp] * dphi[j][qp] - phi[i][qp]*phi[j][qp]);
83  }
84  }
85 
86  dof_map.constrain_element_matrix_and_vector (K, F, dof_indices);
87 
88  matrix.add_matrix (K, dof_indices);
89  system.rhs->add_vector (F, dof_indices);
90  }
91 
92  system.rhs->close();
93  matrix.close();
94 }
95 }
96 
97 
98 
99 class ConstraintOperatorTest : public CppUnit::TestCase {
100 public:
101  LIBMESH_CPPUNIT_TEST_SUITE( ConstraintOperatorTest );
102 
103 #ifdef LIBMESH_HAVE_SOLVER
104  CPPUNIT_TEST( test1DCoarseningOperator );
105  CPPUNIT_TEST( test1DCoarseningNewNodes );
106 
107 #ifdef LIBMESH_HAVE_EXODUS_API
108  // These tests seem to fail on older PETScs with the following error:
109  // [0]PETSC ERROR: Nonconforming object sizes
110  // [0]PETSC ERROR: Square matrix only for in-place
111  // [0]PETSC ERROR: See http://www.mcs.anl.gov/petsc/documentation/faq.html for trouble shooting.
112  // [0]PETSC ERROR: Petsc Release Version 3.8.0, unknown
113  // So we only run them if you have new enough PETSc. We
114  // don't know exactly how new of a PETSc is required, though,
115  // so for now it's anything greater than 3.8. See also:
116  // libMesh/libmesh#3803.
117 #if PETSC_RELEASE_GREATER_THAN(3,8,0)
118  CPPUNIT_TEST( testCoreformGeom2 );
119  CPPUNIT_TEST( testCoreformGeom4 );
120  CPPUNIT_TEST( testCoreformGeom8 );
121 #endif
122 
123 #endif
124 #endif
125 
126  CPPUNIT_TEST_SUITE_END();
127 
128 public:
129  void setUp()
130  {}
131 
132  void tearDown()
133  {}
134 
135 
137  {
138  LOG_UNIT_TEST;
139 
141  EquationSystems es(mesh);
142 
143  ExplicitSystem &sys =
144  es.add_system<LinearImplicitSystem> ("test");
145 
146  sys.add_variable("u", FIRST);
148 
149  // Make sure numbering matches our constraint operator matrix
150  mesh.allow_renumbering(false);
151 
153  10,
154  0., 1.,
155  EDGE2);
156 
157  // We should be prepared at this point
158  CPPUNIT_ASSERT(mesh.is_prepared());
159  CPPUNIT_ASSERT(MeshTools::valid_is_prepared(mesh));
160 
161  auto matrix = SparseMatrix<Number>::build (mesh.comm());
162 
163  // Create a projection matrix from 10 elements to 5. We might as
164  // well just make it on processor 0.
165  processor_id_type my_rank = mesh.comm().rank();
166  matrix->init(11, 6,
167  (my_rank ? 0 : 11),
168  (my_rank ? 0 : 6),
169  (my_rank ? 0 : 6),
170  0);
171 
172  if (!my_rank)
173  {
174  for (auto i : make_range(5))
175  {
176  matrix->set(i*2, i, 1);
177  matrix->set(i*2+1, i, 0.5);
178  matrix->set(i*2+1, i+1, 0.5);
179  }
180  matrix->set(10, 5, 1);
181  }
182  matrix->close();
183 
184  mesh.copy_constraint_rows(*matrix);
185 
186  // We should still be prepared at this point
187  CPPUNIT_ASSERT(mesh.is_prepared());
188  CPPUNIT_ASSERT(MeshTools::valid_is_prepared(mesh));
189 
190  // Do a redundant prepare-for-use to catch any issues there
192 
193  es.init ();
194  sys.solve();
195 
196  const DofMap & dof_map = sys.get_dof_map();
197 
198  CPPUNIT_ASSERT_EQUAL(dof_id_type(5), dof_map.n_constrained_dofs());
199 
200  // Now compare the results to just solving on 5 elements.
201 
202  // Matching up partitioning is hard, so just replicate+serialize
204  EquationSystems es2(mesh);
205 
206  ExplicitSystem &sys2 =
207  es2.add_system<LinearImplicitSystem> ("test");
208 
209  sys2.add_variable("u", FIRST);
211 
213  5,
214  0., 1.,
215  EDGE2);
216 
217  es2.init ();
218  sys2.solve();
219 
220  // Integrate any differences on the fine grid
221  ExactSolution exact(es);
222 
223  // Serialize rather than figure out proper ghosting for an
224  // arbitrary partitioning mix
225  auto serialized_solution2 =
227  serialized_solution2->init(sys2.solution->size(), false, SERIAL);
228  sys2.solution->localize(*serialized_solution2);
229 
230  MeshFunction coarse_solution
231  (es2, *serialized_solution2, sys2.get_dof_map(), 0);
232 
233  exact.attach_exact_value(0, &coarse_solution);
234  exact.compute_error("test", "u");
235  Real err = exact.l2_error("test", "u");
236  CPPUNIT_ASSERT_LESS(Real(TOLERANCE*TOLERANCE), err);
237  }
238 
239 
240  void testCoreform(const std::string & meshfile,
241  const std::string & matrixfile,
242  Real expected_norm,
243  Order order=FIRST)
244  {
246  EquationSystems es(mesh);
247 
248  ExplicitSystem &sys =
249  es.add_system<LinearImplicitSystem> ("test");
250 
251  sys.add_variable("u", order);
253 
254  // Make sure numbering matches our constraint operator matrix
255  mesh.allow_renumbering(false);
256 
257  mesh.read(meshfile);
258 
259  CPPUNIT_ASSERT(mesh.is_prepared());
260 
261  // For these matrices Coreform has been experimenting with PETSc
262  // solvers which take the transpose of what we expect, so we'll
263  // un-transpose here.
264  auto matrix = SparseMatrix<Number>::build (mesh.comm());
265  matrix->read_matlab(matrixfile);
266  matrix->get_transpose(*matrix);
267 
268  mesh.copy_constraint_rows(*matrix);
269 
270  // We should be prepared at this point
271  CPPUNIT_ASSERT(mesh.is_prepared());
272  CPPUNIT_ASSERT(MeshTools::valid_is_prepared(mesh));
273 
274  // Do a redundant prepare-for-use to catch any issues there
276 
277  es.init ();
278  sys.solve();
279 
280  // Skip norm calculations on NodeElems
281  std::set<unsigned int> skip_dimensions {0};
282  Real h1_norm = sys.calculate_norm(*sys.solution, 0, H1,
283  &skip_dimensions);
284 
285  LIBMESH_ASSERT_FP_EQUAL(h1_norm, expected_norm, TOLERANCE*std::sqrt(TOLERANCE));
286  }
287 
288 
290  {
291  LOG_UNIT_TEST;
292  testCoreform("meshes/geom_2.exo",
293  "matrices/geom_2_extraction_op.m",
294  0.09598270393980124874069039295234223854_R);
295  }
296 
297 
299  {
300  LOG_UNIT_TEST;
301  testCoreform("meshes/geom_4.exo",
302  "matrices/geom_4_extraction_op.m",
303  0.1040405127939275102143852084416339522_R);
304  }
305 
306 
308  {
309  LOG_UNIT_TEST;
310  testCoreform("meshes/geom_8.exo",
311  "matrices/geom_8_extraction_op.m",
312  0.103252835327032837145271735988790535_R);
313  }
314 
315 
317  {
318  LOG_UNIT_TEST;
319 
321  EquationSystems es(mesh);
322 
323  ExplicitSystem &sys =
324  es.add_system<LinearImplicitSystem> ("test");
325 
326  sys.add_variable("u", FIRST);
328 
329  // Make sure numbering matches our constraint operator matrix
330  mesh.allow_renumbering(false);
331 
333  10,
334  0., 1.,
335  EDGE2);
336 
337  // We should be prepared at this point
338  CPPUNIT_ASSERT(mesh.is_prepared());
339  CPPUNIT_ASSERT(MeshTools::valid_is_prepared(mesh));
340 
341  auto matrix = SparseMatrix<Number>::build (mesh.comm());
342 
343  // Create a projection matrix from 10 elements to 4. We'll only
344  // be leaving the end nodes and one central node unconstrained, so
345  // we should see two new unconstrained NodeElem added.
346  matrix->read_matlab("meshes/constrain10to4.m");
347 
348  mesh.copy_constraint_rows(*matrix);
349 
350  // We should still be prepared at this point
351  CPPUNIT_ASSERT(mesh.is_prepared());
352  CPPUNIT_ASSERT(MeshTools::valid_is_prepared(mesh));
353 
354  // Do a redundant prepare-for-use to catch any issues there
356 
357  es.init ();
358  sys.solve();
359 
360  const DofMap & dof_map = sys.get_dof_map();
361 
362  CPPUNIT_ASSERT_EQUAL(dof_id_type(11+2), mesh.n_nodes());
363  CPPUNIT_ASSERT_EQUAL(dof_id_type(10+2), mesh.n_elem());
364  CPPUNIT_ASSERT_EQUAL(dof_id_type(8), dof_map.n_constrained_dofs());
365  }
366 };
367 
OStreamProxy err
This class handles the computation of the L2 and/or H1 error for the Systems in the EquationSystems o...
This is the EquationSystems class.
virtual void read(const std::string &name, void *mesh_data=nullptr, bool skip_renumber_nodes_and_elements=false, bool skip_find_neighbors=false)=0
Interfaces for reading/writing a mesh to/from a file.
The ReplicatedMesh class is derived from the MeshBase class, and is used to store identical copies of...
bool is_prepared() const
Definition: mesh_base.h:198
Order
defines an enum for polynomial orders.
Definition: enum_order.h:40
virtual void solve() override
For explicit systems, just assemble the system which should directly compute A*x. ...
void allow_renumbering(bool allow)
If false is passed in then this mesh will no longer be renumbered when being prepared for use...
Definition: mesh_base.h:1196
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:171
The definition of the const_element_iterator struct.
Definition: mesh_base.h:2216
static constexpr Real TOLERANCE
bool valid_is_prepared(const MeshBase &mesh)
A function for testing whether a mesh&#39;s cached is_prepared() setting is not a false positive...
Definition: mesh_tools.C:1182
unsigned int dim
Manages consistently variables, degrees of freedom, coefficient vectors, matrices and linear solvers ...
virtual void add_vector(const T *v, const std::vector< numeric_index_type > &dof_indices)
Computes , where v is a pointer and each dof_indices[i] specifies where to add value v[i]...
void prepare_for_use(const bool skip_renumber_nodes_and_elements, const bool skip_find_neighbors)
Prepare a newly ecreated (or read) mesh for use.
Definition: mesh_base.C:759
This is the base class from which all geometric element types are derived.
Definition: elem.h:94
MeshBase & mesh
processor_id_type rank() const
NumericVector< Number > * rhs
The system matrix.
void copy_constraint_rows(const MeshBase &other_mesh)
Copy the constraints from the other mesh to this mesh.
Definition: mesh_base.C:2063
const Parallel::Communicator & comm() const
This class defines a vector in LIBMESH_DIM dimensional Real or Complex space.
The libMesh namespace provides an interface to certain functionality in the library.
const T_sys & get_system(std::string_view name) const
static std::unique_ptr< SparseMatrix< T > > build(const Parallel::Communicator &comm, const SolverPackage solver_package=libMesh::default_solver_package(), const MatrixBuildType matrix_build_type=MatrixBuildType::AUTOMATIC)
Builds a SparseMatrix<T> using the linear solver package specified by solver_package.
This is the MeshBase class.
Definition: mesh_base.h:75
void assemble_matrix_and_rhs(EquationSystems &es, const std::string &)
Definition: systems_test.C:123
virtual void set(const numeric_index_type i, const numeric_index_type j, const T value)=0
Set the element (i,j) to value.
virtual void read_matlab(const std::string &filename)
Read the contents of the matrix from the Matlab-script sparse matrix format used by PETSc...
This class handles the numbering of degrees of freedom on a mesh.
Definition: dof_map.h:179
CPPUNIT_TEST_SUITE_REGISTRATION(ConstraintOperatorTest)
const std::vector< std::vector< OutputGradient > > & get_dphi() const
Definition: fe_base.h:230
uint8_t processor_id_type
virtual void add_matrix(const DenseMatrix< T > &dm, const std::vector< numeric_index_type > &rows, const std::vector< numeric_index_type > &cols)=0
Add the full matrix dm to the SparseMatrix.
void compute_error(std::string_view sys_name, std::string_view unknown_name)
Computes and stores the error in the solution value e = u-u_h, the gradient grad(e) = grad(u) - grad(...
std::unique_ptr< NumericVector< Number > > solution
Data structure to hold solution values.
Definition: system.h:1593
Real calculate_norm(const NumericVector< Number > &v, unsigned int var, FEMNormType norm_type, std::set< unsigned int > *skip_dimensions=nullptr) const
Definition: system.C:1724
virtual_for_inffe const std::vector< Real > & get_JxW() const
Definition: fe_abstract.h:303
This class provides all data required for a physics package (e.g.
Definition: fem_context.h:62
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:1357
void testCoreform(const std::string &meshfile, const std::string &matrixfile, Real expected_norm, Order order=FIRST)
virtual_for_inffe const std::vector< Point > & get_xyz() const
Definition: fe_abstract.h:280
void attach_assemble_function(void fptr(EquationSystems &es, const std::string &name))
Register a user function to use in assembling the system matrix and RHS.
Definition: system.C:2161
Real l2_error(std::string_view sys_name, std::string_view unknown_name)
virtual void close()=0
Calls the NumericVector&#39;s internal assembly routines, ensuring that the values are consistent across ...
virtual void close()=0
Calls the SparseMatrix&#39;s internal assembly routines, ensuring that the values are consistent across p...
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
dof_id_type n_constrained_dofs() const
const MeshBase & get_mesh() const
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:140
static std::unique_ptr< NumericVector< T > > build(const Parallel::Communicator &comm, SolverPackage solver_package=libMesh::default_solver_package(), ParallelType parallel_type=AUTOMATIC)
Builds a NumericVector on the processors in communicator comm using the linear solver package specifi...
unsigned int mesh_dimension() const
Definition: mesh_base.C:372
void build_line(UnstructuredMesh &mesh, const unsigned int nx, const Real xmin=0., const Real xmax=1., const ElemType type=INVALID_ELEM, const bool gauss_lobatto_grid=false)
A specialized build_cube() for 1D meshes.
void attach_exact_value(unsigned int sys_num, FunctionBase< Number > *f)
Clone and attach an arbitrary functor which computes the exact value of the system sys_num solution a...
virtual void init()
Initialize all the systems.
This class provides function-like objects for data distributed over a mesh.
Definition: mesh_function.h:54
virtual dof_id_type n_elem() const =0
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
const DofMap & get_dof_map() const
Definition: system.h:2374
virtual ElemType type() const =0
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:39
const SparseMatrix< Number > & get_system_matrix() const
virtual dof_id_type n_nodes() const =0
This class forms the foundation from which generic finite elements may be derived.
Manages consistently variables, degrees of freedom, and coefficient vectors for explicit systems...
uint8_t dof_id_type
Definition: id_types.h:67
const std::vector< std::vector< OutputShape > > & get_phi() const
Definition: fe_base.h:207
virtual void init(const numeric_index_type m, const numeric_index_type n, const numeric_index_type m_l, const numeric_index_type n_l, const numeric_index_type nnz=30, const numeric_index_type noz=10, const numeric_index_type blocksize=1)=0
Initialize SparseMatrix with the specified sizes.