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.
The ReplicatedMesh class is derived from the MeshBase class, and is used to store identical copies of...
bool is_prepared() const
Definition: mesh_base.C:1057
Order
defines an enum for polynomial orders.
Definition: enum_order.h:40
virtual void read(const std::string &name, void *mesh_data=nullptr, bool skip_renumber_nodes_and_elements=false, bool skip_find_neighbors=false, bool skip_detect_interior_parents=false)=0
Interfaces for reading/writing a mesh to/from a file.
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:1345
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:218
The definition of the const_element_iterator struct.
Definition: mesh_base.h:2521
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:1256
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 created (or read) mesh for use.
Definition: mesh_base.C:824
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:2450
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:80
void assemble_matrix_and_rhs(EquationSystems &es, const std::string &)
Definition: systems_test.C:128
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:1655
Real calculate_norm(const NumericVector< Number > &v, unsigned int var, FEMNormType norm_type, std::set< unsigned int > *skip_dimensions=nullptr) const
Definition: system.C:1511
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:1344
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:1959
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:176
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:430
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:2417
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.