libMesh
Functions | Variables
adaptivity_ex4.C File Reference

Go to the source code of this file.

Functions

void assemble_biharmonic (EquationSystems &es, const std::string &system_name)
 
Number exact_1D_solution (const Point &p, const Parameters &, const std::string &, const std::string &)
 
Number exact_2D_solution (const Point &p, const Parameters &, const std::string &, const std::string &)
 
Number exact_3D_solution (const Point &p, const Parameters &, const std::string &, const std::string &)
 
Gradient exact_1D_derivative (const Point &p, const Parameters &, const std::string &, const std::string &)
 
Gradient exact_2D_derivative (const Point &p, const Parameters &, const std::string &, const std::string &)
 
Gradient exact_3D_derivative (const Point &p, const Parameters &, const std::string &, const std::string &)
 
Tensor exact_1D_hessian (const Point &p, const Parameters &, const std::string &, const std::string &)
 
Tensor exact_2D_hessian (const Point &p, const Parameters &, const std::string &, const std::string &)
 
Tensor exact_3D_hessian (const Point &p, const Parameters &, const std::string &, const std::string &)
 
Number forcing_function_1D (const Point &p)
 
Number forcing_function_2D (const Point &p)
 
Number forcing_function_3D (const Point &p)
 
int main (int argc, char **argv)
 

Variables

bool penalty_dirichlet = true
 
Number(* exact_solution )(const Point &p, const Parameters &, const std::string &, const std::string &)
 
Gradient(* exact_derivative )(const Point &p, const Parameters &, const std::string &, const std::string &)
 
Tensor(* exact_hessian )(const Point &p, const Parameters &, const std::string &, const std::string &)
 
Number(* forcing_function )(const Point &p)
 

Function Documentation

◆ assemble_biharmonic()

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

Definition at line 705 of file adaptivity_ex4.C.

References libMesh::SparseMatrix< T >::add_matrix(), libMesh::NumericVector< T >::add_vector(), libMesh::FEGenericBase< OutputType >::build(), libMesh::FEType::default_quadrature_rule(), dim, exact_2D_derivative(), exact_solution, forcing_function, libMesh::System::get_dof_map(), libMesh::EquationSystems::get_mesh(), libMesh::EquationSystems::get_system(), libMesh::ImplicitSystem::get_system_matrix(), libMesh::libmesh_ignore(), mesh, libMesh::MeshBase::mesh_dimension(), libMesh::EquationSystems::parameters, penalty_dirichlet, libMesh::PerfLog::pop(), libMesh::PerfLog::push(), libMesh::Real, libMesh::DenseVector< T >::resize(), libMesh::DenseMatrix< T >::resize(), libMesh::ExplicitSystem::rhs, and value.

Referenced by main().

707 {
708  // Ignore unused parameter warnings when libmesh is configured without certain options.
709  libmesh_ignore(es, system_name);
710 
711 #ifdef LIBMESH_ENABLE_AMR
712 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
713 
714  // It is a good idea to make sure we are assembling
715  // the proper system.
716  libmesh_assert_equal_to (system_name, "Biharmonic");
717 
718  // Declare a performance log. Give it a descriptive
719  // string to identify what part of the code we are
720  // logging, since there may be many PerfLogs in an
721  // application.
722  PerfLog perf_log ("Matrix Assembly", false);
723 
724  // Get a constant reference to the mesh object.
725  const MeshBase & mesh = es.get_mesh();
726 
727  // The dimension that we are running
728  const unsigned int dim = mesh.mesh_dimension();
729 
730  // Get a reference to the LinearImplicitSystem we are solving
731  LinearImplicitSystem & system = es.get_system<LinearImplicitSystem>("Biharmonic");
732 
733  // A reference to the DofMap object for this system. The DofMap
734  // object handles the index translation from node and element numbers
735  // to degree of freedom numbers. We will talk more about the DofMap
736  // in future examples.
737  const DofMap & dof_map = system.get_dof_map();
738 
739  // Get a constant reference to the Finite Element type
740  // for the first (and only) variable in the system.
741  FEType fe_type = dof_map.variable_type(0);
742 
743  // Build a Finite Element object of the specified type. Since the
744  // FEBase::build() member dynamically creates memory we will
745  // store the object as a std::unique_ptr<FEBase>. This can be thought
746  // of as a pointer that will clean up after itself.
747  std::unique_ptr<FEBase> fe (FEBase::build(dim, fe_type));
748 
749  // Quadrature rule for numerical integration.
750  // With 2D triangles, the Clough quadrature rule puts a Gaussian
751  // quadrature rule on each of the 3 subelements
752  std::unique_ptr<QBase> qrule(fe_type.default_quadrature_rule(dim));
753 
754  // Tell the finite element object to use our quadrature rule.
755  fe->attach_quadrature_rule (qrule.get());
756 
757  // Declare a special finite element object for
758  // boundary integration.
759  std::unique_ptr<FEBase> fe_face (FEBase::build(dim, fe_type));
760 
761  // Boundary integration requires another quadrature rule,
762  // with dimensionality one less than the dimensionality
763  // of the element.
764  // In 1D, the Clough and Gauss quadrature rules are identical.
765  std::unique_ptr<QBase> qface(fe_type.default_quadrature_rule(dim-1));
766 
767  // Tell the finite element object to use our
768  // quadrature rule.
769  fe_face->attach_quadrature_rule (qface.get());
770 
771  // Here we define some references to cell-specific data that
772  // will be used to assemble the linear system.
773  // We begin with the element Jacobian * quadrature weight at each
774  // integration point.
775  const std::vector<Real> & JxW = fe->get_JxW();
776 
777  // The physical XY locations of the quadrature points on the element.
778  // These might be useful for evaluating spatially varying material
779  // properties at the quadrature points.
780  const std::vector<Point> & q_point = fe->get_xyz();
781 
782  // The element shape functions evaluated at the quadrature points.
783  const std::vector<std::vector<Real>> & phi = fe->get_phi();
784 
785  // The element shape function second derivatives evaluated at the
786  // quadrature points. Note that for the simple biharmonic, shape
787  // function first derivatives are unnecessary.
788  const std::vector<std::vector<RealTensor>> & d2phi = fe->get_d2phi();
789 
790  // For efficiency we will compute shape function laplacians n times,
791  // not n^2
792  std::vector<Real> shape_laplacian;
793 
794  // Define data structures to contain the element matrix
795  // and right-hand-side vector contribution. Following
796  // basic finite element terminology we will denote these
797  // "Ke" and "Fe". More detail is in example 3.
800 
801  // This vector will hold the degree of freedom indices for
802  // the element. These define where in the global system
803  // the element degrees of freedom get mapped.
804  std::vector<dof_id_type> dof_indices;
805 
806  // The global system matrix
807  SparseMatrix<Number> & matrix = system.get_system_matrix();
808 
809  // Now we will loop over all the elements in the mesh. We will
810  // compute the element matrix and right-hand-side contribution. See
811  // example 3 for a discussion of the element iterators.
812  for (const auto & elem : mesh.active_local_element_ptr_range())
813  {
814  // Start logging the shape function initialization.
815  // This is done through a simple function call with
816  // the name of the event to log.
817  perf_log.push("elem init");
818 
819  // Get the degree of freedom indices for the
820  // current element. These define where in the global
821  // matrix and right-hand-side this element will
822  // contribute to.
823  dof_map.dof_indices (elem, dof_indices);
824 
825  // Compute the element-specific data for the current
826  // element. This involves computing the location of the
827  // quadrature points (q_point) and the shape functions
828  // (phi, dphi) for the current element.
829  fe->reinit (elem);
830 
831  const unsigned int n_dofs =
832  cast_int<unsigned int>(dof_indices.size());
833  libmesh_assert_equal_to (n_dofs, phi.size());
834 
835  // Zero the element matrix and right-hand side before
836  // summing them.
837  Ke.resize (n_dofs, n_dofs);
838 
839  Fe.resize (n_dofs);
840 
841  // Make sure there is enough room in this cache
842  shape_laplacian.resize(n_dofs);
843 
844  // Stop logging the shape function initialization.
845  // If you forget to stop logging an event the PerfLog
846  // object will probably catch the error and abort.
847  perf_log.pop("elem init");
848 
849  // Now we will build the element matrix. This involves
850  // a double loop to integrate laplacians of the test functions
851  // (i) against laplacians of the trial functions (j).
852  //
853  // This step is why we need the Clough-Tocher elements -
854  // these C1 differentiable elements have square-integrable
855  // second derivatives.
856  //
857  // Now start logging the element matrix computation
858  perf_log.push ("Ke");
859 
860  for (unsigned int qp=0; qp<qrule->n_points(); qp++)
861  {
862  for (unsigned int i=0; i != n_dofs; i++)
863  {
864  shape_laplacian[i] = d2phi[i][qp](0,0);
865  if (dim > 1)
866  shape_laplacian[i] += d2phi[i][qp](1,1);
867  if (dim == 3)
868  shape_laplacian[i] += d2phi[i][qp](2,2);
869  }
870  for (unsigned int i=0; i != n_dofs; i++)
871  for (unsigned int j=0; j != n_dofs; j++)
872  Ke(i,j) += JxW[qp]*
873  shape_laplacian[i]*shape_laplacian[j];
874  }
875 
876  // Stop logging the matrix computation
877  perf_log.pop ("Ke");
878 
879 
880  // At this point the interior element integration has
881  // been completed. However, we may have not yet addressed
882  // boundary conditions, if we didn't add a DirichletBoundary to
883  // our system earlier. In that case, we will demonstrate the
884  // imposition of simple Dirichlet boundary conditions imposed
885  // via the penalty method. Note that this is a fourth-order
886  // problem: Dirichlet boundary conditions include *both*
887  // boundary values and boundary normal fluxes.
888  if (penalty_dirichlet)
889  {
890  // Start logging the boundary condition computation. We use a
891  // macro to log everything in this scope.
892  LOG_SCOPE_WITH("BCs", "", perf_log);
893 
894  // The penalty values, for solution boundary trace and flux.
895  const Real penalty = 1e10;
896  const Real penalty2 = 1e10;
897 
898  // The following loops over the sides of the element.
899  // If the element has no neighbor on a side then that
900  // side MUST live on a boundary of the domain.
901  for (auto s : elem->side_index_range())
902  if (elem->neighbor_ptr(s) == nullptr)
903  {
904  // The value of the shape functions at the quadrature
905  // points.
906  const std::vector<std::vector<Real>> & phi_face =
907  fe_face->get_phi();
908 
909  // The value of the shape function derivatives at the
910  // quadrature points.
911  const std::vector<std::vector<RealGradient>> & dphi_face =
912  fe_face->get_dphi();
913 
914  // The Jacobian * Quadrature Weight at the quadrature
915  // points on the face.
916  const std::vector<Real> & JxW_face = fe_face->get_JxW();
917 
918  // The XYZ locations (in physical space) of the
919  // quadrature points on the face. This is where
920  // we will interpolate the boundary value function.
921  const std::vector<Point> & qface_point = fe_face->get_xyz();
922  const std::vector<Point> & face_normals = fe_face->get_normals();
923 
924  // Compute the shape function values on the element
925  // face.
926  fe_face->reinit(elem, s);
927 
928  libmesh_assert_equal_to (n_dofs, phi_face.size());
929 
930  // Loop over the face quadrature points for integration.
931  for (unsigned int qp=0; qp<qface->n_points(); qp++)
932  {
933  // The boundary value.
934  Number value = exact_solution(qface_point[qp],
935  es.parameters, "null",
936  "void");
937  Gradient flux = exact_2D_derivative(qface_point[qp],
938  es.parameters,
939  "null", "void");
940 
941  // Matrix contribution of the L2 projection.
942  // Note that the basis function values are
943  // integrated against test function values while
944  // basis fluxes are integrated against test function
945  // fluxes.
946  for (unsigned int i=0; i != n_dofs; i++)
947  for (unsigned int j=0; j != n_dofs; j++)
948  Ke(i,j) += JxW_face[qp] *
949  (penalty * phi_face[i][qp] *
950  phi_face[j][qp] + penalty2
951  * (dphi_face[i][qp] *
952  face_normals[qp]) *
953  (dphi_face[j][qp] *
954  face_normals[qp]));
955 
956  // Right-hand-side contribution of the L2
957  // projection.
958  for (unsigned int i=0; i != n_dofs; i++)
959  Fe(i) += JxW_face[qp] *
960  (penalty * value * phi_face[i][qp]
961  + penalty2 *
962  (flux * face_normals[qp])
963  * (dphi_face[i][qp]
964  * face_normals[qp]));
965 
966  }
967  }
968  }
969 
970  for (unsigned int qp=0; qp<qrule->n_points(); qp++)
971  for (unsigned int i=0; i != n_dofs; i++)
972  Fe(i) += JxW[qp]*phi[i][qp]*forcing_function(q_point[qp]);
973 
974  // The element matrix and right-hand-side are now built
975  // for this element. Add them to the global matrix and
976  // right-hand-side vector. The SparseMatrix::add_matrix()
977  // and NumericVector::add_vector() members do this for us.
978  // Start logging the insertion of the local (element)
979  // matrix and vector into the global matrix and vector
980  LOG_SCOPE_WITH("matrix insertion", "", perf_log);
981 
982  dof_map.constrain_element_matrix_and_vector(Ke, Fe, dof_indices);
983  matrix.add_matrix (Ke, dof_indices);
984  system.rhs->add_vector (Fe, dof_indices);
985  }
986 
987  // That's it. We don't need to do anything else to the
988  // PerfLog. When it goes out of scope (at this function return)
989  // it will print its log to the screen. Pretty easy, huh?
990 
991 #else
992 
993 #endif // #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
994 #endif // #ifdef LIBMESH_ENABLE_AMR
995 }
class FEType hides (possibly multiple) FEFamily and approximation orders, thereby enabling specialize...
Definition: fe_type.h:182
Number(* exact_solution)(const Point &p, const Parameters &, const std::string &, const std::string &)
unsigned int dim
Manages consistently variables, degrees of freedom, coefficient vectors, matrices and linear solvers ...
void resize(const unsigned int n)
Resize the vector.
Definition: dense_vector.h:374
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]...
Gradient exact_2D_derivative(const Point &p, const Parameters &, const std::string &, const std::string &)
MeshBase & mesh
NumericVector< Number > * rhs
The system matrix.
This class defines a vector in LIBMESH_DIM dimensional Real or Complex space.
const T_sys & get_system(std::string_view name) const
This is the MeshBase class.
Definition: mesh_base.h:74
The PerfLog class allows monitoring of specific events.
Definition: perf_log.h:145
This class handles the numbering of degrees of freedom on a mesh.
Definition: dof_map.h:169
std::unique_ptr< QBase > default_quadrature_rule(const unsigned int dim, const int extraorder=0) const
Definition: fe_type.C:34
void libmesh_ignore(const Args &...)
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.
Number(* forcing_function)(const Point &p)
bool penalty_dirichlet
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
const MeshBase & get_mesh() const
static const bool value
Definition: xdr_io.C:54
void resize(const unsigned int new_m, const unsigned int new_n)
Resizes the matrix to the specified size and calls zero().
Definition: dense_matrix.h:895
unsigned int mesh_dimension() const
Definition: mesh_base.C:324
Parameters parameters
Data structure holding arbitrary parameters.
const DofMap & get_dof_map() const
Definition: system.h:2293
const SparseMatrix< Number > & get_system_matrix() const

◆ exact_1D_derivative()

Gradient exact_1D_derivative ( const Point p,
const Parameters ,
const std::string &  ,
const std::string &   
)

Definition at line 501 of file adaptivity_ex4.C.

References libMesh::Real.

Referenced by main().

505 {
506  // x coordinate in space
507  const Real x = p(0);
508 
509  // First derivatives to be returned.
510  Gradient gradu;
511 
512  gradu(0) = 256.*2.*(x-x*x)*(1-2*x);
513 
514  return gradu;
515 }
This class defines a vector in LIBMESH_DIM dimensional Real or Complex space.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real

◆ exact_1D_hessian()

Tensor exact_1D_hessian ( const Point p,
const Parameters ,
const std::string &  ,
const std::string &   
)

Definition at line 519 of file adaptivity_ex4.C.

References libMesh::Real.

Referenced by main().

523 {
524  // Second derivatives to be returned.
525  Tensor hessu;
526 
527  // x coordinate in space
528  const Real x = p(0);
529 
530  hessu(0,0) = 256.*2.*(1-6.*x+6.*x*x);
531 
532  return hessu;
533 }
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
This class defines a tensor in LIBMESH_DIM dimensional Real or Complex space.

◆ exact_1D_solution()

Number exact_1D_solution ( const Point p,
const Parameters ,
const std::string &  ,
const std::string &   
)

Definition at line 487 of file adaptivity_ex4.C.

References libMesh::Real.

Referenced by main().

491 {
492  // x coordinate in space
493  const Real x = p(0);
494 
495  // analytic solution value
496  return 256.*(x-x*x)*(x-x*x);
497 }
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real

◆ exact_2D_derivative()

Gradient exact_2D_derivative ( const Point p,
const Parameters ,
const std::string &  ,
const std::string &   
)

Definition at line 559 of file adaptivity_ex4.C.

References libMesh::Real.

Referenced by assemble_biharmonic(), and main().

563 {
564  // x and y coordinates in space
565  const Real x = p(0);
566  const Real y = p(1);
567 
568  // First derivatives to be returned.
569  Gradient gradu;
570 
571  gradu(0) = 256.*2.*(x-x*x)*(1-2*x)*(y-y*y)*(y-y*y);
572  gradu(1) = 256.*2.*(x-x*x)*(x-x*x)*(y-y*y)*(1-2*y);
573 
574  return gradu;
575 }
This class defines a vector in LIBMESH_DIM dimensional Real or Complex space.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real

◆ exact_2D_hessian()

Tensor exact_2D_hessian ( const Point p,
const Parameters ,
const std::string &  ,
const std::string &   
)

Definition at line 579 of file adaptivity_ex4.C.

References libMesh::Real.

Referenced by main().

583 {
584  // Second derivatives to be returned.
585  Tensor hessu;
586 
587  // x and y coordinates in space
588  const Real x = p(0);
589  const Real y = p(1);
590 
591  hessu(0,0) = 256.*2.*(1-6.*x+6.*x*x)*(y-y*y)*(y-y*y);
592  hessu(0,1) = 256.*4.*(x-x*x)*(1.-2.*x)*(y-y*y)*(1.-2.*y);
593  hessu(1,1) = 256.*2.*(x-x*x)*(x-x*x)*(1.-6.*y+6.*y*y);
594 
595  // Hessians are always symmetric
596  hessu(1,0) = hessu(0,1);
597  return hessu;
598 }
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
This class defines a tensor in LIBMESH_DIM dimensional Real or Complex space.

◆ exact_2D_solution()

Number exact_2D_solution ( const Point p,
const Parameters ,
const std::string &  ,
const std::string &   
)

Definition at line 544 of file adaptivity_ex4.C.

References libMesh::Real.

Referenced by main().

548 {
549  // x and y coordinates in space
550  const Real x = p(0);
551  const Real y = p(1);
552 
553  // analytic solution value
554  return 256.*(x-x*x)*(x-x*x)*(y-y*y)*(y-y*y);
555 }
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real

◆ exact_3D_derivative()

Gradient exact_3D_derivative ( const Point p,
const Parameters ,
const std::string &  ,
const std::string &   
)

Definition at line 630 of file adaptivity_ex4.C.

References libMesh::Real.

Referenced by main().

634 {
635  // First derivatives to be returned.
636  Gradient gradu;
637 
638  // xyz coordinates in space
639  const Real x = p(0);
640  const Real y = p(1);
641  const Real z = p(2);
642 
643  gradu(0) = 4096.*2.*(x-x*x)*(1.-2.*x)*(y-y*y)*(y-y*y)*(z-z*z)*(z-z*z);
644  gradu(1) = 4096.*2.*(x-x*x)*(x-x*x)*(y-y*y)*(1.-2.*y)*(z-z*z)*(z-z*z);
645  gradu(2) = 4096.*2.*(x-x*x)*(x-x*x)*(y-y*y)*(y-y*y)*(z-z*z)*(1.-2.*z);
646 
647  return gradu;
648 }
This class defines a vector in LIBMESH_DIM dimensional Real or Complex space.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real

◆ exact_3D_hessian()

Tensor exact_3D_hessian ( const Point p,
const Parameters ,
const std::string &  ,
const std::string &   
)

Definition at line 652 of file adaptivity_ex4.C.

References libMesh::Real.

Referenced by main().

656 {
657  // Second derivatives to be returned.
658  Tensor hessu;
659 
660  // xyz coordinates in space
661  const Real x = p(0);
662  const Real y = p(1);
663  const Real z = p(2);
664 
665  hessu(0,0) = 4096.*(2.-12.*x+12.*x*x)*(y-y*y)*(y-y*y)*(z-z*z)*(z-z*z);
666  hessu(0,1) = 4096.*4.*(x-x*x)*(1.-2.*x)*(y-y*y)*(1.-2.*y)*(z-z*z)*(z-z*z);
667  hessu(0,2) = 4096.*4.*(x-x*x)*(1.-2.*x)*(y-y*y)*(y-y*y)*(z-z*z)*(1.-2.*z);
668  hessu(1,1) = 4096.*(x-x*x)*(x-x*x)*(2.-12.*y+12.*y*y)*(z-z*z)*(z-z*z);
669  hessu(1,2) = 4096.*4.*(x-x*x)*(x-x*x)*(y-y*y)*(1.-2.*y)*(z-z*z)*(1.-2.*z);
670  hessu(2,2) = 4096.*(x-x*x)*(x-x*x)*(y-y*y)*(y-y*y)*(2.-12.*z+12.*z*z);
671 
672  // Hessians are always symmetric
673  hessu(1,0) = hessu(0,1);
674  hessu(2,0) = hessu(0,2);
675  hessu(2,1) = hessu(1,2);
676 
677  return hessu;
678 }
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
This class defines a tensor in LIBMESH_DIM dimensional Real or Complex space.

◆ exact_3D_solution()

Number exact_3D_solution ( const Point p,
const Parameters ,
const std::string &  ,
const std::string &   
)

Definition at line 615 of file adaptivity_ex4.C.

References libMesh::Real.

Referenced by main().

619 {
620  // xyz coordinates in space
621  const Real x = p(0);
622  const Real y = p(1);
623  const Real z = p(2);
624 
625  // analytic solution value
626  return 4096.*(x-x*x)*(x-x*x)*(y-y*y)*(y-y*y)*(z-z*z)*(z-z*z);
627 }
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real

◆ forcing_function_1D()

Number forcing_function_1D ( const Point p)

Definition at line 537 of file adaptivity_ex4.C.

Referenced by main().

538 {
539  // Equals laplacian(laplacian(u)), u'''' in 1D
540  return 256. * 2. * 12.;
541 }

◆ forcing_function_2D()

Number forcing_function_2D ( const Point p)

Definition at line 602 of file adaptivity_ex4.C.

References libMesh::Real.

Referenced by main().

603 {
604  // x and y coordinates in space
605  const Real x = p(0);
606  const Real y = p(1);
607 
608  // Equals laplacian(laplacian(u))
609  return 256. * 8. * (3.*((y-y*y)*(y-y*y)+(x-x*x)*(x-x*x))
610  + (1.-6.*x+6.*x*x)*(1.-6.*y+6.*y*y));
611 }
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real

◆ forcing_function_3D()

Number forcing_function_3D ( const Point p)

Definition at line 682 of file adaptivity_ex4.C.

References libMesh::Real.

Referenced by main().

683 {
684  // xyz coordinates in space
685  const Real x = p(0);
686  const Real y = p(1);
687  const Real z = p(2);
688 
689  // Equals laplacian(laplacian(u))
690  return 4096. * 8. * (3.*((y-y*y)*(y-y*y)*(x-x*x)*(x-x*x) +
691  (z-z*z)*(z-z*z)*(x-x*x)*(x-x*x) +
692  (z-z*z)*(z-z*z)*(y-y*y)*(y-y*y)) +
693  (1.-6.*x+6.*x*x)*(1.-6.*y+6.*y*y)*(z-z*z)*(z-z*z) +
694  (1.-6.*x+6.*x*x)*(1.-6.*z+6.*z*z)*(y-y*y)*(y-y*y) +
695  (1.-6.*y+6.*y*y)*(1.-6.*z+6.*z*z)*(x-x*x)*(x-x*x));
696 }
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real

◆ main()

int main ( int  argc,
char **  argv 
)

Definition at line 156 of file adaptivity_ex4.C.

References libMesh::DofMap::add_dirichlet_boundary(), libMesh::EquationSystems::add_system(), libMesh::System::add_variable(), libMesh::MeshBase::all_second_order(), libMesh::MeshTools::Modification::all_tri(), assemble_biharmonic(), libMesh::System::attach_assemble_function(), libMesh::ExactSolution::attach_exact_deriv(), libMesh::ExactSolution::attach_exact_hessian(), libMesh::ExactSolution::attach_exact_value(), libMesh::MeshTools::Generation::build_cube(), libMesh::MeshTools::Generation::build_line(), libMesh::MeshTools::Generation::build_square(), libMesh::CLOUGH, libMesh::MeshRefinement::coarsen_fraction(), libMesh::ExactSolution::compute_error(), libMesh::default_solver_package(), dim, libMesh::JumpErrorEstimator::estimate_error(), exact_1D_derivative(), exact_1D_hessian(), exact_1D_solution(), exact_2D_derivative(), exact_2D_hessian(), exact_2D_solution(), exact_3D_derivative(), exact_3D_hessian(), exact_3D_solution(), exact_derivative, exact_grad(), exact_hessian, exact_solution, libMesh::LinearImplicitSystem::final_linear_residual(), libMesh::MeshRefinement::flag_elements_by_elem_fraction(), forcing_function, forcing_function_1D(), forcing_function_2D(), forcing_function_3D(), libMesh::System::get_dof_map(), libMesh::ExactSolution::h1_error(), libMesh::ExactSolution::h2_error(), libMesh::HERMITE, libMesh::TriangleWrapper::init(), libMesh::EquationSystems::init(), libMesh::INVALID_SOLVER_PACKAGE, libMesh::ExactSolution::l2_error(), libMesh::libmesh_assert(), libMesh::MeshRefinement::max_h_level(), libMesh::ErrorVector::mean(), mesh, libMesh::EquationSystems::n_active_dofs(), libMesh::System::n_dofs(), libMesh::LinearImplicitSystem::n_linear_iterations(), libMesh::out, libMesh::EquationSystems::parameters, penalty_dirichlet, libMesh::Utility::pow(), libMesh::EquationSystems::print_info(), libMesh::MeshBase::print_info(), libMesh::Real, libMesh::MeshRefinement::refine_and_coarsen_elements(), libMesh::MeshRefinement::refine_fraction(), libMesh::EquationSystems::reinit(), libMesh::SECOND, libMesh::Parameters::set(), libMesh::LinearImplicitSystem::solve(), libMesh::TOLERANCE, libMesh::MeshRefinement::uniformly_refine(), libMesh::JumpErrorEstimator::use_unweighted_quadrature_rules, libMesh::System::variable_number(), libMesh::ErrorVector::variance(), and libMesh::MeshOutput< MT >::write_equation_systems().

157 {
158  // Initialize libMesh.
159  LibMeshInit init (argc, argv);
160 
161  // This example requires a linear solver package.
162  libmesh_example_requires(libMesh::default_solver_package() != INVALID_SOLVER_PACKAGE,
163  "--enable-petsc, --enable-trilinos, or --enable-eigen");
164 
165  // Adaptive constraint calculations for fine Hermite elements seems
166  // to require half-decent precision
167 #ifdef LIBMESH_DEFAULT_SINGLE_PRECISION
168  libmesh_example_requires(false, "double precision");
169 #endif
170 
171  // This example requires Adaptive Mesh Refinement support
172 #ifndef LIBMESH_ENABLE_AMR
173  libmesh_example_requires(false, "--enable-amr");
174 #else
175 
176  // This example requires second derivative calculation support
177 #ifndef LIBMESH_ENABLE_SECOND_DERIVATIVES
178  libmesh_example_requires(false, "--enable-second");
179 #else
180 
181  // Parse the input file
182  GetPot input_file("adaptivity_ex4.in");
183 
184  // But allow the command line to override it.
185  input_file.parse_command_line(argc, argv);
186 
187  // Read in parameters from the input file
188  const unsigned int max_r_level = input_file("max_r_level", 10);
189  const unsigned int max_r_steps = input_file("max_r_steps", 4);
190  const std::string approx_type = input_file("approx_type", "HERMITE");
191  const std::string approx_order_string = input_file("approx_order", "THIRD");
192  const unsigned int uniform_refine = input_file("uniform_refine", 0);
193  const Real refine_percentage = input_file("refine_percentage", 0.5);
194  const Real coarsen_percentage = input_file("coarsen_percentage", 0.5);
195  const unsigned int dim = input_file("dimension", 2);
196  const unsigned int max_linear_iterations = input_file("max_linear_iterations", 10000);
197  penalty_dirichlet = input_file("penalty_dirichlet", penalty_dirichlet);
198 
199  // Skip higher-dimensional examples on a lower-dimensional libMesh build
200  libmesh_example_requires(dim <= LIBMESH_DIM, "2D/3D support");
201 
202  // Currently only the Hermite cubics give a 1D or 3D C^1 basis
203  libmesh_assert (dim == 2 || approx_type == "HERMITE");
204 
205  // Create a mesh, with dimension to be overridden later, on the
206  // default MPI communicator.
207  Mesh mesh(init.comm());
208 
209  // Output file for plotting the error
210  std::string output_file = "";
211 
212  if (dim == 1)
213  output_file += "1D_";
214  else if (dim == 2)
215  output_file += "2D_";
216  else if (dim == 3)
217  output_file += "3D_";
218 
219  if (approx_type == "HERMITE")
220  output_file += "hermite_";
221  else if (approx_type == "SECOND")
222  output_file += "reducedclough_";
223  else
224  output_file += "clough_";
225 
226  output_file += approx_order_string;
227 
228  if (uniform_refine == 0)
229  output_file += "_adaptive";
230  else
231  output_file += "_uniform";
232 
233 #ifdef LIBMESH_HAVE_EXODUS_API
234  // If we have Exodus, use the same base output filename
235  std::string exd_file = output_file;
236  exd_file += ".e";
237 #endif // #ifdef LIBMESH_HAVE_EXODUS_API
238 
239  output_file += ".m";
240 
241  std::ofstream out (output_file.c_str());
242  out << "% dofs L2-error H1-error H2-error\n"
243  << "e = [\n";
244 
245  // Set up the dimension-dependent coarse mesh and solution
246  if (dim == 1)
247  {
253  }
254 
255  if (dim == 2)
256  {
262  }
263  else if (dim == 3)
264  {
270  }
271 
272  // Convert the mesh to second order: necessary for computing with
273  // Clough-Tocher elements, useful for getting slightly less
274  // broken visualization output with Hermite elements
276 
277  // Convert it to triangles if necessary
278  if (approx_type != "HERMITE")
280 
281  // Mesh Refinement object
282  MeshRefinement mesh_refinement(mesh);
283  mesh_refinement.refine_fraction() = refine_percentage;
284  mesh_refinement.coarsen_fraction() = coarsen_percentage;
285  mesh_refinement.max_h_level() = max_r_level;
286 
287  // Create an equation systems object.
288  EquationSystems equation_systems (mesh);
289 
290  // Declare the system and its variables.
291  // Create a system named "Biharmonic"
292  LinearImplicitSystem & system =
293  equation_systems.add_system<LinearImplicitSystem> ("Biharmonic");
294 
295  Order approx_order = approx_type == "SECOND" ? SECOND :
296  Utility::string_to_enum<Order>(approx_order_string);
297 
298  // Adds the variable "u" to "Biharmonic". "u" will be approximated
299  // using Hermite tensor product squares or Clough-Tocher triangles
300 
301  if (approx_type == "HERMITE")
302  system.add_variable("u", approx_order, HERMITE);
303  else if (approx_type == "SECOND")
304  system.add_variable("u", SECOND, CLOUGH);
305  else if (approx_type == "CLOUGH")
306  system.add_variable("u", approx_order, CLOUGH);
307  else
308  libmesh_error_msg("Invalid approx_type = " << approx_type);
309 
310  // Give the system a pointer to the matrix assembly
311  // function.
313 
314  // Give the system Dirichlet boundary conditions, if we want to
315  // enforce those strongly.
316  if (!penalty_dirichlet)
317  {
318  const std::vector<unsigned int>
319  all_vars(1, system.variable_number("u"));
320  std::set<boundary_id_type> all_bdys;
321  for (unsigned int i=0; i != dim; ++i)
322  {
323  all_bdys.insert(2*i);
324  all_bdys.insert(2*i+1);
325  }
326 
327  WrappedFunction<Number> exact_val(system, exact_solution);
329  DirichletBoundary exact_bc(all_bdys, all_vars, exact_val,
330  exact_grad);
331  system.get_dof_map().add_dirichlet_boundary(exact_bc);
332  }
333 
334  // Initialize the data structures for the equation system.
335  equation_systems.init();
336 
337  // Set linear solver max iterations
338  equation_systems.parameters.set<unsigned int>
339  ("linear solver maximum iterations") = max_linear_iterations;
340 
341  // Linear solver tolerance.
342  equation_systems.parameters.set<Real>
343  ("linear solver tolerance") = TOLERANCE * TOLERANCE;
344 
345  // Prints information about the system to the screen.
346  equation_systems.print_info();
347 
348  // Construct ExactSolution object and attach function to compute exact solution
349  ExactSolution exact_sol(equation_systems);
350  exact_sol.attach_exact_value(exact_solution);
351  exact_sol.attach_exact_deriv(exact_derivative);
352  exact_sol.attach_exact_hessian(exact_hessian);
353 
354  // Construct zero solution object, useful for computing solution norms
355  // Attaching "zero_solution" functions is unnecessary
356  ExactSolution zero_sol(equation_systems);
357 
358  // A refinement loop.
359  for (unsigned int r_step=0; r_step<max_r_steps; r_step++)
360  {
361  mesh.print_info();
362  equation_systems.print_info();
363 
364  libMesh::out << "Beginning Solve " << r_step << std::endl;
365 
366  // Solve the system "Biharmonic", just like example 2.
367  system.solve();
368 
369  libMesh::out << "Linear solver converged at step: "
370  << system.n_linear_iterations()
371  << ", final residual: "
372  << system.final_linear_residual()
373  << std::endl;
374 
375  // Compute the error.
376  exact_sol.compute_error("Biharmonic", "u");
377  // Compute the norm.
378  zero_sol.compute_error("Biharmonic", "u");
379 
380  // Print out the error values
381  libMesh::out << "L2-Norm is: "
382  << zero_sol.l2_error("Biharmonic", "u")
383  << std::endl;
384  libMesh::out << "H1-Norm is: "
385  << zero_sol.h1_error("Biharmonic", "u")
386  << std::endl;
387  libMesh::out << "H2-Norm is: "
388  << zero_sol.h2_error("Biharmonic", "u")
389  << std::endl
390  << std::endl;
391  libMesh::out << "L2-Error is: "
392  << exact_sol.l2_error("Biharmonic", "u")
393  << std::endl;
394  libMesh::out << "H1-Error is: "
395  << exact_sol.h1_error("Biharmonic", "u")
396  << std::endl;
397  libMesh::out << "H2-Error is: "
398  << exact_sol.h2_error("Biharmonic", "u")
399  << std::endl
400  << std::endl;
401 
402  // Print to output file
403  out << equation_systems.n_active_dofs() << " "
404  << exact_sol.l2_error("Biharmonic", "u") << " "
405  << exact_sol.h1_error("Biharmonic", "u") << " "
406  << exact_sol.h2_error("Biharmonic", "u") << std::endl;
407 
408  // Assert that we're not outright diverging here, for regression
409  // testing. These bounds just come from eyeballing some graphs
410  // and tacking on a huge tolerance.
411  const dof_id_type n_dofs = system.n_dofs();
412 
413  if (exact_sol.l2_error("Biharmonic", "u") > 200*std::pow(n_dofs,-4./3.))
414  libmesh_error_msg("Unacceptably high L2-error!");
415 
416  if (exact_sol.h1_error("Biharmonic", "u") > 200./n_dofs)
417  libmesh_error_msg("Unacceptably high H1-error!");
418 
419  if (exact_sol.h2_error("Biharmonic", "u") > 400*std::pow(n_dofs,-2./3.))
420  libmesh_error_msg("Unacceptably high H2-error!");
421 
422  // Possibly refine the mesh
423  if (r_step+1 != max_r_steps)
424  {
425  libMesh::out << " Refining the mesh..." << std::endl;
426 
427  if (uniform_refine == 0)
428  {
429  ErrorVector error;
430  LaplacianErrorEstimator error_estimator;
431 
432  // This is another subclass of JumpErrorEstimator, based
433  // on measuring discontinuities across sides between
434  // elements, and we can tell it to use a cheaper
435  // "unweighted" quadrature rule when numerically
436  // integrating those discontinuities.
437  error_estimator.use_unweighted_quadrature_rules = true;
438 
439  error_estimator.estimate_error(system, error);
440  mesh_refinement.flag_elements_by_elem_fraction (error);
441 
442  libMesh::out << "Mean Error: " << error.mean() << std::endl;
443  libMesh::out << "Error Variance: " << error.variance() << std::endl;
444 
445  mesh_refinement.refine_and_coarsen_elements();
446  }
447  else
448  {
449  mesh_refinement.uniformly_refine(1);
450  }
451 
452  // This call reinitializes the EquationSystems object for
453  // the newly refined mesh. One of the steps in the
454  // reinitialization is projecting the solution,
455  // old_solution, etc... vectors from the old mesh to
456  // the current one.
457  equation_systems.reinit ();
458  }
459  }
460 
461 #ifdef LIBMESH_HAVE_EXODUS_API
462  // After solving the system write the solution
463  // to a ExodusII-formatted plot file.
465  equation_systems);
466 #endif // #ifdef LIBMESH_HAVE_EXODUS_API
467 
468  // Close up the output file.
469  out << "];\n"
470  << "hold on\n"
471  << "loglog(e(:,1), e(:,2), 'bo-');\n"
472  << "loglog(e(:,1), e(:,3), 'ro-');\n"
473  << "loglog(e(:,1), e(:,4), 'go-');\n"
474  << "xlabel('log(dofs)');\n"
475  << "ylabel('log(error)');\n"
476  << "title('C1 " << approx_type << " elements');\n"
477  << "legend('L2-error', 'H1-error', 'H2-error');\n";
478 
479  // All done.
480  return 0;
481 #endif // #ifndef LIBMESH_ENABLE_SECOND_DERIVATIVES
482 #endif // #ifndef LIBMESH_ENABLE_AMR
483 }
This class handles the computation of the L2 and/or H1 error for the Systems in the EquationSystems o...
Wrap a libMesh-style function pointer into a FunctionBase object.
void assemble_biharmonic(EquationSystems &es, const std::string &system_name)
This is the EquationSystems class.
Order
defines an enum for polynomial orders.
Definition: enum_order.h:40
Gradient(* exact_derivative)(const Point &p, const Parameters &, const std::string &, const std::string &)
virtual void write_equation_systems(const std::string &, const EquationSystems &, const std::set< std::string > *system_names=nullptr)
This method implements writing a mesh with data to a specified file where the data is taken from the ...
Definition: mesh_output.C:31
Number(* exact_solution)(const Point &p, const Parameters &, const std::string &, const std::string &)
static constexpr Real TOLERANCE
unsigned int dim
The ErrorVector is a specialization of the StatisticsVector for error data computed on a finite eleme...
Definition: error_vector.h:50
The ExodusII_IO class implements reading meshes in the ExodusII file format from Sandia National Labs...
Definition: exodusII_io.h:52
Manages consistently variables, degrees of freedom, coefficient vectors, matrices and linear solvers ...
Gradient exact_1D_derivative(const Point &p, const Parameters &, const std::string &, const std::string &)
Gradient exact_2D_derivative(const Point &p, const Parameters &, const std::string &, const std::string &)
MeshBase & mesh
This class allows one to associate Dirichlet boundary values with a given set of mesh boundary ids an...
Tensor exact_1D_hessian(const Point &p, const Parameters &, const std::string &, const std::string &)
virtual Real variance() const override
Definition: error_vector.h:115
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.
The LibMeshInit class, when constructed, initializes the dependent libraries (e.g.
Definition: libmesh.h:90
virtual void solve() override
Assembles & solves the linear system A*x=b.
dof_id_type n_dofs() const
Definition: system.C:113
Gradient exact_grad(const Point &, const Parameters &, const std::string &, const std::string &)
Definition: mysystems.h:25
unsigned int variable_number(std::string_view var) const
Definition: system.C:1557
SolverPackage default_solver_package()
Definition: libmesh.C:1050
Number exact_1D_solution(const Point &p, const Parameters &, const std::string &, const std::string &)
void all_tri(MeshBase &mesh)
Converts the 2D quadrilateral elements of a Mesh into triangular elements.
T pow(const T &x)
Definition: utility.h:328
Implements (adaptive) mesh refinement algorithms for a MeshBase.
Tensor exact_3D_hessian(const Point &p, const Parameters &, const std::string &, const std::string &)
unsigned int n_linear_iterations() const
void print_info(std::ostream &os=libMesh::out, const unsigned int verbosity=0, const bool global=true) const
Prints relevant information about the mesh.
Definition: mesh_base.C:1489
void init(triangulateio &t)
Initializes the fields of t to nullptr/0 as necessary.
libmesh_assert(ctx)
Tensor(* exact_hessian)(const Point &p, const Parameters &, const std::string &, const std::string &)
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:1305
Tensor exact_2D_hessian(const Point &p, const Parameters &, const std::string &, const std::string &)
Gradient exact_3D_derivative(const Point &p, const Parameters &, const std::string &, const std::string &)
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:2109
Number forcing_function_2D(const Point &p)
Number(* forcing_function)(const Point &p)
bool penalty_dirichlet
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
OStreamProxy out
bool use_unweighted_quadrature_rules
This boolean flag allows you to use "unweighted" quadrature rules (sized to exactly integrate unweigh...
void all_second_order(const bool full_ordered=true)
Calls the range-based version of this function with a range consisting of all elements in the mesh...
Definition: mesh_base.C:1535
Number forcing_function_1D(const Point &p)
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 add_dirichlet_boundary(const DirichletBoundary &dirichlet_boundary)
Adds a copy of the specified Dirichlet boundary to the system.
Number exact_2D_solution(const Point &p, const Parameters &, const std::string &, const std::string &)
virtual void estimate_error(const System &system, ErrorVector &error_per_cell, const NumericVector< Number > *solution_vector=nullptr, bool estimate_parent_error=false) override
This function uses the derived class&#39;s jump error estimate formula to estimate the error on each cell...
Number exact_3D_solution(const Point &p, const Parameters &, const std::string &, const std::string &)
Number forcing_function_3D(const Point &p)
This class is an error indicator based on laplacian jumps between elements.
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:2293
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.
uint8_t dof_id_type
Definition: id_types.h:67
virtual Real mean() const override
Definition: error_vector.C:69

Variable Documentation

◆ exact_derivative

Gradient exact_derivative

Definition at line 142 of file adaptivity_ex4.C.

Referenced by main().

◆ exact_hessian

Tensor(* exact_hessian) (const Point &p, const Parameters &, const std::string &, const std::string &)

Definition at line 147 of file adaptivity_ex4.C.

Referenced by main().

◆ exact_solution

Number exact_solution

Definition at line 137 of file adaptivity_ex4.C.

Referenced by assemble_biharmonic(), main(), and LaplaceSystem::side_constraint().

◆ forcing_function

Number(* forcing_function) (const Point &p)

Definition at line 152 of file adaptivity_ex4.C.

Referenced by assemble_biharmonic(), and main().

◆ penalty_dirichlet

bool penalty_dirichlet = true

Definition at line 77 of file adaptivity_ex4.C.

Referenced by assemble_biharmonic(), and main().