libMesh
Loading...
Searching...
No Matches
Typedefs | Functions
vector_fe_ex7.C File Reference

Go to the source code of this file.

Typedefs

typedef MatrixXcd EigenMatrix
 
typedef VectorXcd EigenVector
 

Functions

void fe_assembly (EquationSystems &es, bool global_solve)
 
void assemble_divgrad (EquationSystems &es, const std::string &system_name)
 
int main (int argc, char **argv)
 
void assemble_divgrad (EquationSystems &es, const std::string &libmesh_dbg_var(system_name))
 
int main ()
 

Typedef Documentation

◆ EigenMatrix

typedef MatrixXd EigenMatrix

Definition at line 149 of file vector_fe_ex7.C.

◆ EigenVector

typedef VectorXd EigenVector

Definition at line 150 of file vector_fe_ex7.C.

Function Documentation

◆ assemble_divgrad() [1/2]

void assemble_divgrad ( EquationSystems es,
const std::string &  libmesh_dbg_varsystem_name 
)

Definition at line 726 of file vector_fe_ex7.C.

727{
728 libmesh_assert_equal_to(system_name, "Lambda");
729 fe_assembly(es, /*global_solve=*/true);
730}
void fe_assembly(EquationSystems &es, bool global_solve)

References fe_assembly().

◆ assemble_divgrad() [2/2]

void assemble_divgrad ( EquationSystems es,
const std::string &  system_name 
)

Referenced by main().

◆ fe_assembly()

void fe_assembly ( EquationSystems es,
bool  global_solve 
)

The scalar solution at the quadrature points

Data structures for computing the enriched scalar solution

Definition at line 326 of file vector_fe_ex7.C.

327{
328 const MeshBase & mesh = es.get_mesh();
329 const unsigned int dim = mesh.mesh_dimension();
330 // Are our elements simplicial?
331 const bool simplicial = es.parameters.get<bool>("simplicial");
332
333 // The div-grad, e.g. vector-scalar system
334 auto & system = es.get_system<System>("DivGrad");
335 // Our implicit Lagrange multiplier system
336 auto & lambda_system = es.get_system<LinearImplicitSystem>("Lambda");
337
338 const auto & dof_map = system.get_dof_map();
339 const auto & lambda_dof_map = lambda_system.get_dof_map();
340
341 const FEType vector_fe_type = dof_map.variable_type(system.variable_number("u"));
342 const FEType scalar_fe_type = dof_map.variable_type(system.variable_number("p"));
343 const FEType enriched_scalar_fe_type =
344 dof_map.variable_type(system.variable_number("p_enriched"));
345 const FEType lambda_fe_type =
346 lambda_dof_map.variable_type(lambda_system.variable_number("lambda"));
347
348 // Volumetric FE objects
349 std::unique_ptr<FEVectorBase> vector_fe(FEVectorBase::build(dim, vector_fe_type));
350 std::unique_ptr<FEBase> scalar_fe(FEBase::build(dim, scalar_fe_type));
351 std::unique_ptr<FEBase> enriched_scalar_fe(FEBase::build(dim, enriched_scalar_fe_type));
352
353 // Volumetric quadrature rule
354 QGauss qrule(dim, FIFTH);
355
356 // Attach quadrature rules for the FE objects that we will reinit within the element "volume"
357 vector_fe->attach_quadrature_rule(&qrule);
358 scalar_fe->attach_quadrature_rule(&qrule);
359 enriched_scalar_fe->attach_quadrature_rule(&qrule);
360
361 // Declare finite element objects for boundary integration
362 std::unique_ptr<FEVectorBase> vector_fe_face(FEVectorBase::build(dim, vector_fe_type));
363 std::unique_ptr<FEBase> enriched_scalar_fe_face(FEBase::build(dim, enriched_scalar_fe_type));
364 std::unique_ptr<FEBase> lambda_fe_face(FEBase::build(dim, lambda_fe_type));
365
366 // Boundary integration requires one quadrature rule with dimensionality one
367 // less than the dimensionality of the element.
368 QGauss qface(dim - 1, FIFTH);
369
370 // Attach quadrature rules for the FE objects that we will reinit on the element faces
371 vector_fe_face->attach_quadrature_rule(&qface);
372 enriched_scalar_fe_face->attach_quadrature_rule(&qface);
373 lambda_fe_face->attach_quadrature_rule(&qface);
374
375 // pre-request our required volumetric data
376 const auto & JxW = vector_fe->get_JxW();
377 const auto & q_point = vector_fe->get_xyz();
378 const auto & vector_phi = vector_fe->get_phi();
379 const auto & scalar_phi = scalar_fe->get_phi();
380 const auto & enriched_scalar_phi = enriched_scalar_fe->get_phi();
381 const auto & div_vector_phi = vector_fe->get_div_phi();
382
383 // pre-request our required element face data
384 const auto & vector_phi_face = vector_fe_face->get_phi();
385 const auto & enriched_scalar_phi_face = enriched_scalar_fe_face->get_phi();
386 const auto & lambda_phi_face = lambda_fe_face->get_phi();
387 const auto & JxW_face = vector_fe_face->get_JxW();
388 const auto & qface_point = vector_fe_face->get_xyz();
389 const auto & normals = vector_fe_face->get_normals();
390
391 //
392 // We follow the notation of Cockburn in "A Charactrization of Hybridized
393 // Mixed methods for Second Order Elliptic problems"for the element
394 // matrices/vectors. We will need "Eigen" versions of many of the
395 // matrices/vectors because the libMesh DenseMatrix doesn't have an inverse
396 // API
397 //
398
399 // LM matrix and RHS after eliminating vector and scalar dofs
400 DenseMatrix<Number> E_libmesh;
401 DenseVector<Number> H_libmesh;
402 EigenMatrix E;
403 EigenMatrix H;
404 // Auxiliary matrices and RHS. A is vector-vector. B is vector-scalar. C is
405 // vector-LM. Sinv is the inverse of the Schur complement S which is given by
406 // S = Bt * A^{-1} * B. G is the RHS of the vector equation (e.g. the
407 // Dirichlet condition). F is the RHS of the scalar equation (resulting from
408 // the body force or MMS force in this case). Hg is the post-elimination
409 // version of G, and Hf is the post-elimination version of F
410 EigenMatrix A, Ainv, B, Bt, C, Ct, Sinv;
411 EigenVector G, F, Hg, Hf;
412 // element matrix for boundary LM dofs. We have to have this because our
413 // SIDE_HIERARCHIC variables live on *all* element faces, not just interior
414 // ones.
415 EigenMatrix L;
416
417 // Lambda eigen vector for constructing vector and scalar solutions
418 EigenVector Lambda;
419 // The lambda solution at the quadrature points
420 std::vector<Number> lambda_qps;
422 std::vector<Number> scalar_qps;
423
425 DenseMatrix<Number> K_enriched_scalar;
426 DenseVector<Number> F_enriched_scalar, U_enriched_scalar;
427
428 // Containers for dof indices
429 std::vector<dof_id_type> vector_dof_indices;
430 std::vector<dof_id_type> scalar_dof_indices;
431 std::vector<dof_id_type> enriched_scalar_dof_indices;
432 std::vector<dof_id_type> lambda_dof_indices;
433 std::vector<Number> lambda_solution_std_vec;
434
435 // The global system matrix
436 SparseMatrix<Number> & matrix = lambda_system.get_system_matrix();
437
438 for (const auto & elem : mesh.active_local_element_ptr_range())
439 {
440 // Retrive our dof indices for all fields
441 dof_map.dof_indices(elem, vector_dof_indices, system.variable_number("u"));
442 dof_map.dof_indices(elem, scalar_dof_indices, system.variable_number("p"));
443 lambda_dof_map.dof_indices(elem, lambda_dof_indices, lambda_system.variable_number("lambda"));
444
445 const auto vector_n_dofs = vector_dof_indices.size();
446 const auto scalar_n_dofs = scalar_dof_indices.size();
447 const auto lambda_n_dofs = lambda_dof_indices.size();
448
449 // Reinit our volume FE objects
450 vector_fe->reinit(elem);
451 scalar_fe->reinit(elem);
452
453 libmesh_assert_equal_to(vector_n_dofs, vector_phi.size());
454 libmesh_assert_equal_to(scalar_n_dofs, scalar_phi.size());
455
456 // prepare our matrix/vector data structures for the vector equation
457 A.setZero(vector_n_dofs, vector_n_dofs);
458 B.setZero(vector_n_dofs, scalar_n_dofs);
459 C.setZero(vector_n_dofs, lambda_n_dofs);
460 G.setZero(vector_n_dofs);
461 // and for the scalar equation
462 Bt.setZero(scalar_n_dofs, vector_n_dofs);
463 F.setZero(scalar_n_dofs);
464 // and for the LM equation
465 Ct.setZero(lambda_n_dofs, vector_n_dofs);
466 L.setZero(lambda_n_dofs, lambda_n_dofs);
467
468 for (const auto qp : make_range(qrule.n_points()))
469 {
470 // Vector equation dependence on vector dofs
471 for (const auto i : make_range(vector_n_dofs))
472 for (const auto j : make_range(vector_n_dofs))
473 A(i, j) += JxW[qp] * (vector_phi[i][qp] * vector_phi[j][qp]);
474
475 // Vector equation dependence on scalar dofs
476 for (const auto i : make_range(vector_n_dofs))
477 for (const auto j : make_range(scalar_n_dofs))
478 B(i, j) -= JxW[qp] * (div_vector_phi[i][qp] * scalar_phi[j][qp]);
479
480 // Scalar equation dependence on vector dofs
481 for (const auto i : make_range(scalar_n_dofs))
482 for (const auto j : make_range(vector_n_dofs))
483 Bt(i, j) -= JxW[qp] * (scalar_phi[i][qp] * div_vector_phi[j][qp]);
484
485 // This is the end of the matrix summation loop
486 // Now we build the element right-hand-side contribution.
487 // This involves a single loop in which we integrate the "forcing
488 // function" in the PDE against the scalar test functions (k).
489 {
490 const Real x = q_point[qp](0);
491 const Real y = q_point[qp](1);
492 const Real z = q_point[qp](2);
493
494 // "f" is the forcing function for the Poisson equation, which is
495 // just the divergence of the exact solution for the vector field.
496 // This is the well-known "method of manufactured solutions".
497 Real f = 0;
498 if (dim == 2)
499 f = DivGradExactSolution().forcing(x, y);
500 else if (dim == 3)
501 f = DivGradExactSolution().forcing(x, y, z);
502
503 // Scalar equation RHS
504 for (const auto i : make_range(scalar_n_dofs))
505 F(i) -= JxW[qp] * scalar_phi[i][qp] * f;
506 }
507 }
508
509 {
510 for (auto side : elem->side_index_range())
511 {
512 // Reinit our face FE objects
513 vector_fe_face->reinit(elem, side);
514 libmesh_assert_equal_to(vector_n_dofs, vector_phi_face.size());
515 lambda_fe_face->reinit(elem, side);
516
517 if (elem->neighbor_ptr(side) == nullptr)
518 for (const auto qp : make_range(qface.n_points()))
519 {
520 const Real xf = qface_point[qp](0);
521 const Real yf = qface_point[qp](1);
522 const Real zf = qface_point[qp](2);
523
524 // The boundary value for scalar field.
525 Real scalar_value = 0;
526 if (dim == 2)
527 scalar_value = DivGradExactSolution().scalar(xf, yf);
528 else if (dim == 3)
529 scalar_value = DivGradExactSolution().scalar(xf, yf, zf);
530
531 // External boundary -> Dirichlet faces -> Vector equaton RHS
532 for (const auto i : make_range(vector_n_dofs))
533 G(i) -= JxW_face[qp] * (vector_phi_face[i][qp] * normals[qp]) * scalar_value;
534
535 // Need to do something with the external boundary LM dofs to prevent the matrix from
536 // being singular
537 for (const auto i : make_range(lambda_n_dofs))
538 for (const auto j : make_range(lambda_n_dofs))
539 L(i, j) += JxW_face[qp] * lambda_phi_face[i][qp] * lambda_phi_face[j][qp];
540 }
541 else
542 for (const auto qp : make_range(qface.n_points()))
543 {
544 // Vector equation dependence on LM dofs
545 for (const auto i : make_range(vector_n_dofs))
546 for (const auto j : make_range(lambda_n_dofs))
547 C(i, j) +=
548 JxW_face[qp] * (vector_phi_face[i][qp] * normals[qp]) * lambda_phi_face[j][qp];
549
550 // LM equation dependence on vector dofs
551 for (const auto i : make_range(lambda_n_dofs))
552 for (const auto j : make_range(vector_n_dofs))
553 Ct(i, j) +=
554 JxW_face[qp] * lambda_phi_face[i][qp] * (vector_phi_face[j][qp] * normals[qp]);
555 }
556 }
557 }
558
559 Ainv = A.inverse();
560 // Compute the Schur complement inverse
561 Sinv = (Bt * Ainv * B).inverse();
562 // These equations can be derived at by eliminating the u and p dofs from the system
563 // (A B C)(u) (G)
564 // (Bt 0 0)(p) = (F)
565 // (Ct 0 0)(lambda) (0)
566 E = Ct * Ainv * (A - B * Sinv * Bt) * Ainv * C;
567 E = E + L;
568 Hg = Ct * Ainv * (A - B * Sinv * Bt) * Ainv * G;
569 Hf = Ct * Ainv * B * Sinv * F;
570 H = Hg + Hf;
571
572 // Build our libMesh data structures from the Eigen ones
573 E_libmesh.resize(E.rows(), E.cols());
574 H_libmesh.resize(H.size());
575 libmesh_assert((E.rows() == E.cols()) && (E.rows() == H.size()));
576 for (const auto i : make_range(E.rows()))
577 {
578 H_libmesh(i) = H(i);
579 for (const auto j : make_range(E.cols()))
580 E_libmesh(i, j) = E(i, j);
581 }
582
583 if (global_solve)
584 {
585 // We were performing our finite element assembly for the implicit solve step of our
586 // example. Add our local element vectors/matrices into the global system
587 dof_map.constrain_element_matrix_and_vector(E_libmesh, H_libmesh, lambda_dof_indices);
588 matrix.add_matrix(E_libmesh, lambda_dof_indices);
589 lambda_system.rhs->add_vector(H_libmesh, lambda_dof_indices);
590 }
591 else
592 {
593 //
594 // We are doing our finite element assembly for the second time. We now know the Lagrange
595 // multiplier solution. With that and the local element matrices and vectors we can compute
596 // the vector and scalar solutions
597 //
598
599 Lambda.resize(lambda_n_dofs);
600 lambda_system.current_local_solution->get(lambda_dof_indices, lambda_solution_std_vec);
601 for (const auto i : make_range(lambda_n_dofs))
602 Lambda(i) = lambda_solution_std_vec[i];
603 const auto scalar_soln = Sinv * Bt * Ainv * G - Sinv * F - Sinv * Bt * Ainv * C * Lambda;
604 const auto vector_soln = Ainv * (G - B * scalar_soln - C * Lambda);
605 for (const auto i : make_range(vector_n_dofs))
606 system.solution->set(vector_dof_indices[i], vector_soln(i));
607 for (const auto i : make_range(scalar_n_dofs))
608 system.solution->set(scalar_dof_indices[i], scalar_soln(i));
609
610#if !defined(LIBMESH_HAVE_PETSC) || !defined(LIBMESH_USE_REAL_NUMBERS)
611 if (!simplicial)
612 // We don't support SVD solves in this configuration
613 continue;
614#endif
615
616 //
617 // Now solve for the enriched scalar solution using our Lagrange multiplier solution and, for
618 // non-simplexes, the lower-order scalar solution. Note that the Lagrange multiplier
619 // represents the trace of p so it is a logical choice to leverage in this postprocessing
620 // stage!
621 //
622
623 dof_map.dof_indices(elem, enriched_scalar_dof_indices, system.variable_number("p_enriched"));
624 const auto enriched_scalar_n_dofs = enriched_scalar_dof_indices.size();
625 const auto m = simplicial ? lambda_n_dofs : lambda_n_dofs + 1;
626 const auto n = enriched_scalar_n_dofs;
627
628 K_enriched_scalar.resize(m, n);
629 F_enriched_scalar.resize(m);
630 U_enriched_scalar.resize(n);
631
632 // L2 projection of the enriched scalar into the LM space
633 for (const auto side : elem->side_index_range())
634 {
635 vector_fe_face->reinit(elem, side); // for JxW_face and qface_point
636 enriched_scalar_fe_face->reinit(elem, side);
637 lambda_fe_face->reinit(elem, side);
638 if (elem->neighbor_ptr(side) == nullptr)
639 for (const auto qp : make_range(qface.n_points()))
640 {
641 const Real xf = qface_point[qp](0);
642 const Real yf = qface_point[qp](1);
643 const Real zf = qface_point[qp](2);
644
645 // The boundary value for scalar field.
646 Real scalar_value = 0;
647 if (dim == 2)
648 scalar_value = DivGradExactSolution().scalar(xf, yf);
649 else if (dim == 3)
650 scalar_value = DivGradExactSolution().scalar(xf, yf, zf);
651
652 for (const auto i : make_range(lambda_n_dofs))
653 {
654 F_enriched_scalar(i) += JxW_face[qp] * lambda_phi_face[i][qp] * scalar_value;
655 for (const auto j : make_range(enriched_scalar_n_dofs))
656 K_enriched_scalar(i, j) +=
657 JxW_face[qp] * lambda_phi_face[i][qp] * enriched_scalar_phi_face[j][qp];
658 }
659 }
660 else
661 {
662 // compute local face lambda solution
663 lambda_qps.resize(qface.n_points());
664 for (auto & lambda_qp : lambda_qps)
665 lambda_qp = 0;
666 for (const auto qp : make_range(qface.n_points()))
667 for (const auto i : index_range(lambda_solution_std_vec))
668 lambda_qps[qp] += lambda_solution_std_vec[i] * lambda_phi_face[i][qp];
669
670 for (const auto qp : make_range(qface.n_points()))
671 for (const auto i : make_range(lambda_n_dofs))
672 {
673 F_enriched_scalar(i) += JxW_face[qp] * lambda_phi_face[i][qp] * lambda_qps[qp];
674 for (const auto j : make_range(enriched_scalar_n_dofs))
675 K_enriched_scalar(i, j) +=
676 JxW_face[qp] * lambda_phi_face[i][qp] * enriched_scalar_phi_face[j][qp];
677 }
678 }
679 }
680
681 if (simplicial)
682 K_enriched_scalar.lu_solve(F_enriched_scalar, U_enriched_scalar);
683 else
684 {
685 //
686 // For tensor product elements, the system of equations coming from the L2 projection into
687 // the Lagrange multiplier space is singular. To make the system nonsingular, we add an L2
688 // projection into the low-order scalar solution space.
689 //
690
691 enriched_scalar_fe->reinit(elem);
692 libmesh_assert(scalar_n_dofs == 1);
693 libmesh_assert(scalar_soln.size() == 1);
694 libmesh_assert(scalar_phi.size() == 1);
695
696 scalar_qps.resize(qrule.n_points());
697 for (auto & scalar_qp : scalar_qps)
698 scalar_qp = 0;
699 for (const auto qp : make_range(qrule.n_points()))
700 scalar_qps[qp] += scalar_soln(0) * scalar_phi[0][qp];
701 for (const auto qp : make_range(qrule.n_points()))
702 {
703 F_enriched_scalar(n) += JxW[qp] * scalar_phi[0][qp] * scalar_qps[qp];
704 for (const auto j : make_range(n))
705 K_enriched_scalar(n, j) += JxW[qp] * scalar_phi[0][qp] * enriched_scalar_phi[j][qp];
706 }
707 // We have more rows than columns so an LU solve isn't an option
708 K_enriched_scalar.svd_solve(F_enriched_scalar, U_enriched_scalar);
709 }
710
711 // Our solution for the local enriched scalar dofs is complete. Insert into the global vector
712 system.solution->insert(U_enriched_scalar, enriched_scalar_dof_indices);
713 }
714 }
715
716 if (!global_solve)
717 {
718 system.solution->close();
719 // Scatter solution into the current_solution which is used in error computation
720 system.update();
721 }
722}
unsigned int dim
Real forcing(Real x, Real y)
Real scalar(Real x, Real y)
Defines a dense matrix for use in Finite Element-type computations.
void svd_solve(const DenseVector< T > &rhs, DenseVector< T > &x, Real rcond=std::numeric_limits< Real >::epsilon()) const
Solve the system of equations for in the least-squares sense.
void resize(const unsigned int new_m, const unsigned int new_n)
Resizes the matrix to the specified size and calls zero().
void lu_solve(const DenseVector< T > &b, DenseVector< T > &x)
Solve the system Ax=b given the input vector b.
Defines a dense vector for use in Finite Element-type computations.
void resize(const unsigned int n)
Resize the vector.
const MeshBase & get_mesh() const
Parameters parameters
Data structure holding arbitrary parameters.
const T_sys & get_system(std::string_view name) const
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
Manages consistently variables, degrees of freedom, coefficient vectors, matrices and linear solvers ...
virtual void reinit() override
Reinitializes the member data fields associated with the system, so that, e.g., assemble() may be use...
This is the MeshBase class.
Definition mesh_base.h:81
unsigned int mesh_dimension() const
Definition mesh_base.C:430
const T & get(std::string_view) const
Definition parameters.h:451
This class implements specific orders of Gauss quadrature.
Generic sparse matrix.
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.
Manages consistently variables, degrees of freedom, and coefficient vectors.
Definition system.h:100
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
const FEType & variable_type(const unsigned int i) const
Definition system.C:2721
NumericVector< Number > & add_vector(std::string_view vec_name, const bool projections=true, const ParallelType type=PARALLEL)
Adds the additional vector vec_name to this system.
Definition system.C:756
unsigned int variable_number(std::string_view var) const
Definition system.C:1398
const DofMap & get_dof_map() const
Definition system.h:2417
MeshBase & mesh
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
libmesh_assert(ctx)
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
Definition assembly.h:39
VectorXcd EigenVector
MatrixXcd EigenMatrix

References libMesh::SparseMatrix< T >::add_matrix(), libMesh::System::add_vector(), libMesh::FEGenericBase< OutputType >::build(), libMesh::System::current_local_solution, dim, libMesh::FIFTH, DivGradExactSolution::forcing(), libMesh::Parameters::get(), libMesh::System::get_dof_map(), libMesh::EquationSystems::get_mesh(), libMesh::EquationSystems::get_system(), libMesh::index_range(), libMesh::libmesh_assert(), libMesh::DenseMatrix< T >::lu_solve(), libMesh::make_range(), mesh, libMesh::MeshBase::mesh_dimension(), libMesh::QBase::n_points(), libMesh::EquationSystems::parameters, libMesh::Real, libMesh::LinearImplicitSystem::reinit(), libMesh::DenseVector< T >::resize(), libMesh::DenseMatrix< T >::resize(), DivGradExactSolution::scalar(), libMesh::DenseMatrix< T >::svd_solve(), libMesh::System::variable_number(), and libMesh::System::variable_type().

Referenced by assemble_divgrad(), and main().

◆ main() [1/2]

int main ( )

Definition at line 735 of file vector_fe_ex7.C.

736{
737 return 0;
738}

◆ main() [2/2]

int main ( int  argc,
char **  argv 
)

Definition at line 160 of file vector_fe_ex7.C.

161{
162 // Initialize libMesh.
163 LibMeshInit init(argc, argv);
164
165 // This example requires a linear solver package.
166 libmesh_example_requires(libMesh::default_solver_package() != INVALID_SOLVER_PACKAGE,
167 "--enable-petsc, --enable-trilinos, or --enable-eigen");
168
169 // Parse the input file.
170 GetPot infile("vector_fe_ex7.in");
171
172 // But allow the command line to override it.
173 infile.parse_command_line(argc, argv);
174
175 // Read in parameters from the command line and the input file.
176 const unsigned int dimension = infile("dim", 2);
177 const unsigned int grid_size = infile("grid_size", 15);
178
179 // Skip higher-dimensional examples on a lower-dimensional libMesh build.
180 libmesh_example_requires(dimension <= LIBMESH_DIM, dimension << "D support");
181
182 // Create a mesh, with dimension to be overridden later, distributed
183 // across the default MPI communicator.
184 Mesh mesh(init.comm());
185
186 // Use the MeshTools::Generation mesh generator to create a uniform
187 // grid on the cube [-1,1]^D. To accomodate Raviart-Thomas elements, we must
188 // use TRI6/7 or QUAD8/9 elements in 2d, or TET14 or HEX27 in 3d.
189 const std::string elem_str = infile("element_type", std::string("TRI6"));
190
191 libmesh_error_msg_if((dimension == 2 && elem_str != "TRI6" && elem_str != "TRI7" &&
192 elem_str != "QUAD8" && elem_str != "QUAD9") ||
193 (dimension == 3 && elem_str != "TET14" && elem_str != "HEX27"),
194 "You selected "
195 << elem_str
196 << " but this example must be run with TRI6, TRI7, QUAD8, or QUAD9 in 2d"
197 << " or with TET14, or HEX27 in 3d.");
198
199 if (dimension == 2)
201 mesh, grid_size, grid_size, -1., 1., -1., 1., Utility::string_to_enum<ElemType>(elem_str));
202 else if (dimension == 3)
204 grid_size,
205 grid_size,
206 grid_size,
207 -1.,
208 1.,
209 -1.,
210 1.,
211 -1.,
212 1.,
213 Utility::string_to_enum<ElemType>(elem_str));
214
215 // Make sure the code is robust against nodal reorderings.
217
218 // Create an equation systems object.
219 EquationSystems equation_systems(mesh);
220 const bool simplicial = (elem_str == "TRI6") || (elem_str == "TRI7") || (elem_str == "TET14");
221 equation_systems.parameters.set<bool>("simplicial") = simplicial;
222
223
224 // Declare the system "DivGrad" and its variables.
225 auto & system = equation_systems.add_system<System>("DivGrad");
226
227 // Add the LM system
228 auto & lm_system = equation_systems.add_system<LinearImplicitSystem>("Lambda");
229
230 // Adds the variable "u" and "p" to "DivGrad". "u" will be our vector field
231 // whereas "p" will be the scalar field.
233 system.add_variable("p", CONSTANT, MONOMIAL);
234 // We also add a higher order version of our 'p' variable whose solution we
235 // will compute using the Lagrange multiplier field and, for non-simplexes,
236 // the low order 'p' solution
237 system.add_variable("p_enriched", FIRST, MONOMIAL);
238
239 // Add our Lagrange multiplier to the implicit system
240 lm_system.add_variable("lambda", CONSTANT, SIDE_HIERARCHIC);
241
242 // Give the system a pointer to the matrix assembly
243 // function. This will be called when needed by the library.
245
246 // Initialize the data structures for the equation system.
247 equation_systems.init();
248
249 // Solve the implicit system for the Lagrange multiplier
250 lm_system.solve();
251
252 // Armed with our Lagrange multiplier solution, we can now compute the vector and scalar solutions
253 fe_assembly(equation_systems, /*global_solve=*/false);
254
255 //
256 // Now we will compute our solution approximation errors
257 //
258
259 ExactSolution exact_sol(equation_systems);
260
261 if (dimension == 2)
262 {
263 SolutionFunction<2> soln_func;
264 SolutionGradient<2> soln_grad;
265
266 // Build FunctionBase* containers to attach to the ExactSolution object.
267 std::vector<FunctionBase<Number> *> sols(1, &soln_func);
268 std::vector<FunctionBase<Gradient> *> grads(1, &soln_grad);
269
270 exact_sol.attach_exact_values(sols);
271 exact_sol.attach_exact_derivs(grads);
272 }
273 else if (dimension == 3)
274 {
275 SolutionFunction<3> soln_func;
276 SolutionGradient<3> soln_grad;
277
278 // Build FunctionBase* containers to attach to the ExactSolution object.
279 std::vector<FunctionBase<Number> *> sols(1, &soln_func);
280 std::vector<FunctionBase<Gradient> *> grads(1, &soln_grad);
281
282 exact_sol.attach_exact_values(sols);
283 exact_sol.attach_exact_derivs(grads);
284 }
285
286 // Use higher quadrature order for more accurate error results.
287 int extra_error_quadrature = infile("extra_error_quadrature", 2);
288 if (extra_error_quadrature)
289 exact_sol.extra_quadrature_order(extra_error_quadrature);
290
291 // Compute the error.
292 exact_sol.compute_error("DivGrad", "u");
293 exact_sol.compute_error("DivGrad", "p");
294#if !defined(LIBMESH_HAVE_PETSC) || !defined(LIBMESH_USE_REAL_NUMBERS)
295 if (simplicial)
296#endif
297 exact_sol.compute_error("DivGrad", "p_enriched");
298
299 // Print out the error values.
300 libMesh::out << "L2 error is: " << exact_sol.l2_error("DivGrad", "u") << std::endl;
301 libMesh::out << "HDiv semi-norm error is: " << exact_sol.error_norm("DivGrad", "u", HDIV_SEMINORM)
302 << std::endl;
303 libMesh::out << "HDiv error is: " << exact_sol.hdiv_error("DivGrad", "u") << std::endl;
304 libMesh::out << "L2 error for p is: " << exact_sol.l2_error("DivGrad", "p") << std::endl;
305#if !defined(LIBMESH_HAVE_PETSC) || !defined(LIBMESH_USE_REAL_NUMBERS)
306 if (simplicial)
307#endif
308 libMesh::out << "L2 error p_enriched is: " << exact_sol.l2_error("DivGrad", "p_enriched")
309 << std::endl;
310
311#ifdef LIBMESH_HAVE_EXODUS_API
312
313 // We write the file in the ExodusII format.
314 ExodusII_IO(mesh).write_equation_systems("out.e", equation_systems);
315
316#endif // #ifdef LIBMESH_HAVE_EXODUS_API
317
318 // All done.
319 return 0;
320}
This is the EquationSystems class.
This class handles the computation of the L2 and/or H1 error for the Systems in the EquationSystems o...
The ExodusII_IO class implements reading meshes in the ExodusII file format from Sandia National Labs...
Definition exodusII_io.h:53
virtual void write_equation_systems(const std::string &fname, const EquationSystems &es, const std::set< std::string > *system_names=nullptr) override
Writes out the solution for no specific time or timestep.
The LibMeshInit class, when constructed, initializes the dependent libraries (e.g.
Definition libmesh.h:92
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition mesh.h:51
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
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
virtual void solve()
Solves the system.
Definition system.h:349
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.
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 permute_elements(MeshBase &mesh)
Randomly permute the nodal ordering of each element (without twisting the element mapping).
void init(triangulateio &t)
Initializes the fields of t to nullptr/0 as necessary.
SolverPackage default_solver_package()
Definition libmesh.C:1064
OStreamProxy out
@ L2_RAVIART_THOMAS
void assemble_divgrad(EquationSystems &es, const std::string &system_name)

References libMesh::EquationSystems::add_system(), libMesh::System::add_variable(), assemble_divgrad(), libMesh::System::attach_assemble_function(), libMesh::ExactSolution::attach_exact_derivs(), libMesh::ExactSolution::attach_exact_values(), libMesh::MeshTools::Generation::build_cube(), libMesh::MeshTools::Generation::build_square(), libMesh::ExactSolution::compute_error(), libMesh::CONSTANT, libMesh::default_solver_package(), libMesh::ExactSolution::error_norm(), libMesh::ExactSolution::extra_quadrature_order(), fe_assembly(), libMesh::FIRST, libMesh::ExactSolution::hdiv_error(), libMesh::HDIV_SEMINORM, libMesh::EquationSystems::init(), libMesh::INVALID_SOLVER_PACKAGE, libMesh::ExactSolution::l2_error(), libMesh::L2_RAVIART_THOMAS, mesh, libMesh::MONOMIAL, libMesh::out, libMesh::EquationSystems::parameters, libMesh::MeshTools::Modification::permute_elements(), libMesh::Parameters::set(), libMesh::SIDE_HIERARCHIC, libMesh::System::solve(), and libMesh::ExodusII_IO::write_equation_systems().