libMesh
Functions
adaptivity_ex2.C File Reference

Go to the source code of this file.

Functions

void assemble_cd (EquationSystems &es, const std::string &system_name)
 
void init_cd (EquationSystems &es, const std::string &system_name)
 
Real exact_solution (const Real x, const Real y, const Real t)
 This is the exact solution that we are trying to obtain. More...
 
Number exact_value (const Point &p, const Parameters &parameters, const std::string &, const std::string &)
 
int main (int argc, char **argv)
 
void init_cd (EquationSystems &es, const std::string &libmesh_dbg_var(system_name))
 
void assemble_cd (EquationSystems &es, const std::string &libmesh_dbg_var(system_name))
 

Function Documentation

◆ assemble_cd() [1/2]

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

Definition at line 296 of file transient_ex1.C.

Referenced by main().

298 {
299  // Ignore unused parameter warnings when !LIBMESH_ENABLE_AMR.
300  libmesh_ignore(es, system_name);
301 
302 #ifdef LIBMESH_ENABLE_AMR
303  // It is a good idea to make sure we are assembling
304  // the proper system.
305  libmesh_assert_equal_to (system_name, "Convection-Diffusion");
306 
307  // Get a constant reference to the mesh object.
308  const MeshBase & mesh = es.get_mesh();
309 
310  // The dimension that we are running
311  const unsigned int dim = mesh.mesh_dimension();
312 
313  // Get a reference to the Convection-Diffusion system object.
315  es.get_system<TransientLinearImplicitSystem> ("Convection-Diffusion");
316 
317  // Get a constant reference to the Finite Element type
318  // for the first (and only) variable in the system.
319  FEType fe_type = system.variable_type(0);
320 
321  // Build a Finite Element object of the specified type. Since the
322  // FEBase::build() member dynamically creates memory we will
323  // store the object as a std::unique_ptr<FEBase>. This can be thought
324  // of as a pointer that will clean up after itself.
325  std::unique_ptr<FEBase> fe (FEBase::build(dim, fe_type));
326  std::unique_ptr<FEBase> fe_face (FEBase::build(dim, fe_type));
327 
328  // A Gauss quadrature rule for numerical integration.
329  // Let the FEType object decide what order rule is appropriate.
330  QGauss qrule (dim, fe_type.default_quadrature_order());
331  QGauss qface (dim-1, fe_type.default_quadrature_order());
332 
333  // Tell the finite element object to use our quadrature rule.
334  fe->attach_quadrature_rule (&qrule);
335  fe_face->attach_quadrature_rule (&qface);
336 
337  // Here we define some references to cell-specific data that
338  // will be used to assemble the linear system. We will start
339  // with the element Jacobian * quadrature weight at each integration point.
340  const std::vector<Real> & JxW = fe->get_JxW();
341  const std::vector<Real> & JxW_face = fe_face->get_JxW();
342 
343  // The element shape functions evaluated at the quadrature points.
344  const std::vector<std::vector<Real>> & phi = fe->get_phi();
345  const std::vector<std::vector<Real>> & psi = fe_face->get_phi();
346 
347  // The element shape function gradients evaluated at the quadrature
348  // points.
349  const std::vector<std::vector<RealGradient>> & dphi = fe->get_dphi();
350 
351  // The XY locations of the quadrature points used for face integration
352  const std::vector<Point> & qface_points = fe_face->get_xyz();
353 
354  // A reference to the DofMap object for this system. The DofMap
355  // object handles the index translation from node and element numbers
356  // to degree of freedom numbers. We will talk more about the DofMap
357  // in future examples.
358  const DofMap & dof_map = system.get_dof_map();
359 
360  // Define data structures to contain the element matrix
361  // and right-hand-side vector contribution. Following
362  // basic finite element terminology we will denote these
363  // "Ke" and "Fe".
366 
367  // This vector will hold the degree of freedom indices for
368  // the element. These define where in the global system
369  // the element degrees of freedom get mapped.
370  std::vector<dof_id_type> dof_indices;
371 
372  // Here we extract the velocity & parameters that we put in the
373  // EquationSystems object.
374  const RealVectorValue velocity =
375  es.parameters.get<RealVectorValue> ("velocity");
376 
377  const Real dt = es.parameters.get<Real> ("dt");
378 
379  SparseMatrix<Number> & matrix = system.get_system_matrix();
380 
381  // Now we will loop over all the elements in the mesh that
382  // live on the local processor. We will compute the element
383  // matrix and right-hand-side contribution. Since the mesh
384  // will be refined we want to only consider the ACTIVE elements,
385  // hence we use a variant of the active_elem_iterator.
386  for (const auto & elem : mesh.active_local_element_ptr_range())
387  {
388  // Get the degree of freedom indices for the
389  // current element. These define where in the global
390  // matrix and right-hand-side this element will
391  // contribute to.
392  dof_map.dof_indices (elem, dof_indices);
393 
394  // Compute the element-specific data for the current
395  // element. This involves computing the location of the
396  // quadrature points (q_point) and the shape functions
397  // (phi, dphi) for the current element.
398  fe->reinit (elem);
399 
400  // Zero the element matrix and right-hand side before
401  // summing them. We use the resize member here because
402  // the number of degrees of freedom might have changed from
403  // the last element. Note that this will be the case if the
404  // element type is different (i.e. the last element was a
405  // triangle, now we are on a quadrilateral).
406  Ke.resize (dof_indices.size(),
407  dof_indices.size());
408 
409  Fe.resize (dof_indices.size());
410 
411  // Now we will build the element matrix and right-hand-side.
412  // Constructing the RHS requires the solution and its
413  // gradient from the previous timestep. This myst be
414  // calculated at each quadrature point by summing the
415  // solution degree-of-freedom values by the appropriate
416  // weight functions.
417  for (unsigned int qp=0; qp<qrule.n_points(); qp++)
418  {
419  // Values to hold the old solution & its gradient.
420  Number u_old = 0.;
421  Gradient grad_u_old;
422 
423  // Compute the old solution & its gradient.
424  for (std::size_t l=0; l<phi.size(); l++)
425  {
426  u_old += phi[l][qp]*system.old_solution (dof_indices[l]);
427 
428  // This will work,
429  // grad_u_old += dphi[l][qp]*system.old_solution (dof_indices[l]);
430  // but we can do it without creating a temporary like this:
431  grad_u_old.add_scaled (dphi[l][qp], system.old_solution (dof_indices[l]));
432  }
433 
434  // Now compute the element matrix and RHS contributions.
435  for (std::size_t i=0; i<phi.size(); i++)
436  {
437  // The RHS contribution
438  Fe(i) += JxW[qp]*(
439  // Mass matrix term
440  u_old*phi[i][qp] +
441  -.5*dt*(
442  // Convection term
443  // (grad_u_old may be complex, so the
444  // order here is important!)
445  (grad_u_old*velocity)*phi[i][qp] +
446 
447  // Diffusion term
448  0.01*(grad_u_old*dphi[i][qp]))
449  );
450 
451  for (std::size_t j=0; j<phi.size(); j++)
452  {
453  // The matrix contribution
454  Ke(i,j) += JxW[qp]*(
455  // Mass-matrix
456  phi[i][qp]*phi[j][qp] +
457 
458  .5*dt*(
459  // Convection term
460  (velocity*dphi[j][qp])*phi[i][qp] +
461 
462  // Diffusion term
463  0.01*(dphi[i][qp]*dphi[j][qp]))
464  );
465  }
466  }
467  }
468 
469  // At this point the interior element integration has
470  // been completed. However, we have not yet addressed
471  // boundary conditions. For this example we will only
472  // consider simple Dirichlet boundary conditions imposed
473  // via the penalty method.
474  //
475  // The following loops over the sides of the element.
476  // If the element has no neighbor on a side then that
477  // side MUST live on a boundary of the domain.
478  {
479  // The penalty value.
480  const Real penalty = 1.e10;
481 
482  // The following loops over the sides of the element.
483  // If the element has no neighbor on a side then that
484  // side MUST live on a boundary of the domain.
485  for (auto s : elem->side_index_range())
486  if (elem->neighbor_ptr(s) == nullptr)
487  {
488  fe_face->reinit(elem, s);
489 
490  for (unsigned int qp=0; qp<qface.n_points(); qp++)
491  {
492  const Number value = exact_solution (qface_points[qp](0),
493  qface_points[qp](1),
494  system.time);
495 
496  // RHS contribution
497  for (std::size_t i=0; i<psi.size(); i++)
498  Fe(i) += penalty*JxW_face[qp]*value*psi[i][qp];
499 
500  // Matrix contribution
501  for (std::size_t i=0; i<psi.size(); i++)
502  for (std::size_t j=0; j<psi.size(); j++)
503  Ke(i,j) += penalty*JxW_face[qp]*psi[i][qp]*psi[j][qp];
504  }
505  }
506  }
507 
508  // If this assembly program were to be used on an adaptive mesh,
509  // we would have to apply any hanging node constraint equations
510  dof_map.constrain_element_matrix_and_vector (Ke, Fe, dof_indices);
511 
512  // The element matrix and right-hand-side are now built
513  // for this element. Add them to the global matrix and
514  // right-hand-side vector. The SparseMatrix::add_matrix()
515  // and NumericVector::add_vector() members do this for us.
516  matrix.add_matrix (Ke, dof_indices);
517  system.rhs->add_vector (Fe, dof_indices);
518  }
519 
520  // That concludes the system matrix assembly routine.
521 #endif // #ifdef LIBMESH_ENABLE_AMR
522 }
class FEType hides (possibly multiple) FEFamily and approximation orders, thereby enabling specialize...
Definition: fe_type.h:196
void add_scaled(const TypeVector< T2 > &, const T &)
Add a scaled value to this vector without creating a temporary.
Definition: type_vector.h:629
void constrain_element_matrix_and_vector(DenseMatrix< Number > &matrix, DenseVector< Number > &rhs, std::vector< dof_id_type > &elem_dofs, bool asymmetric_constraint_rows=true) const
Constrains the element matrix and vector.
Definition: dof_map.h:2498
void dof_indices(const Elem *const elem, std::vector< dof_id_type > &di) const
Definition: dof_map.C:2201
unsigned int dim
void resize(const unsigned int n)
Resize the vector.
Definition: dense_vector.h:396
MeshBase & mesh
Manages storage and variables for transient systems.
const T_sys & get_system(std::string_view name) const
This is the MeshBase class.
Definition: mesh_base.h:80
This class handles the numbering of degrees of freedom on a mesh.
Definition: dof_map.h:179
void libmesh_ignore(const Args &...)
const T & get(std::string_view) const
Definition: parameters.h:451
Real exact_solution(const Real x, const Real y, const Real t)
This is the exact solution that we are trying to obtain.
Number old_solution(const dof_id_type global_dof_number) const
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
const MeshBase & get_mesh() const
static const bool value
Definition: xdr_io.C:55
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
This class implements specific orders of Gauss quadrature.
unsigned int mesh_dimension() const
Definition: mesh_base.C:430
Parameters parameters
Data structure holding arbitrary parameters.

◆ assemble_cd() [2/2]

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

Definition at line 515 of file adaptivity_ex2.C.

References libMesh::TypeVector< T >::add_scaled(), libMesh::FEGenericBase< OutputType >::build(), libMesh::DofMap::constrain_element_matrix_and_vector(), libMesh::FEType::default_quadrature_order(), dim, libMesh::DofMap::dof_indices(), exact_solution(), libMesh::Parameters::get(), libMesh::EquationSystems::get_mesh(), libMesh::EquationSystems::get_system(), mesh, libMesh::MeshBase::mesh_dimension(), libMesh::TransientSystem< Base >::old_solution(), libMesh::EquationSystems::parameters, libMesh::Real, libMesh::DenseVector< T >::resize(), libMesh::DenseMatrix< T >::resize(), and value.

517 {
518  // It is a good idea to make sure we are assembling
519  // the proper system.
520  libmesh_assert_equal_to (system_name, "Convection-Diffusion");
521 
522  // Get a constant reference to the mesh object.
523  const MeshBase & mesh = es.get_mesh();
524 
525  // The dimension that we are running
526  const unsigned int dim = mesh.mesh_dimension();
527 
528  // Get a reference to the Convection-Diffusion system object.
530  es.get_system<TransientLinearImplicitSystem> ("Convection-Diffusion");
531 
532  // Get a pointer to the StaticCondensation class if it exists
533  StaticCondensation * sc = nullptr;
534  if (system.has_static_condensation())
535  sc = &system.get_static_condensation();
536 
537  // Get the Finite Element type for the first (and only)
538  // variable in the system.
539  FEType fe_type = system.variable_type(0);
540 
541  // Build a Finite Element object of the specified type. Since the
542  // FEBase::build() member dynamically creates memory we will
543  // store the object as a std::unique_ptr<FEBase>. This can be thought
544  // of as a pointer that will clean up after itself.
545  std::unique_ptr<FEBase> fe (FEBase::build(dim, fe_type));
546  std::unique_ptr<FEBase> fe_face (FEBase::build(dim, fe_type));
547 
548  // A Gauss quadrature rule for numerical integration.
549  // Let the FEType object decide what order rule is appropriate.
550  QGauss qrule (dim, fe_type.default_quadrature_order());
551  QGauss qface (dim-1, fe_type.default_quadrature_order());
552 
553  // Tell the finite element object to use our quadrature rule.
554  fe->attach_quadrature_rule (&qrule);
555  fe_face->attach_quadrature_rule (&qface);
556 
557  // Here we define some references to cell-specific data that
558  // will be used to assemble the linear system. We will start
559  // with the element Jacobian * quadrature weight at each integration point.
560  const std::vector<Real> & JxW = fe->get_JxW();
561  const std::vector<Real> & JxW_face = fe_face->get_JxW();
562 
563  // The element shape functions evaluated at the quadrature points.
564  const std::vector<std::vector<Real>> & phi = fe->get_phi();
565  const std::vector<std::vector<Real>> & psi = fe_face->get_phi();
566 
567  // The element shape function gradients evaluated at the quadrature
568  // points.
569  const std::vector<std::vector<RealGradient>> & dphi = fe->get_dphi();
570 
571  // The XY locations of the quadrature points used for face integration
572  const std::vector<Point> & qface_points = fe_face->get_xyz();
573 
574  // A reference to the DofMap object for this system. The DofMap
575  // object handles the index translation from node and element numbers
576  // to degree of freedom numbers. We will talk more about the DofMap
577  // in future examples.
578  const DofMap & dof_map = system.get_dof_map();
579 
580  // Define data structures to contain the element matrix
581  // and right-hand-side vector contribution. Following
582  // basic finite element terminology we will denote these
583  // "Ke" and "Fe".
586 
587  // This vector will hold the degree of freedom indices for
588  // the element. These define where in the global system
589  // the element degrees of freedom get mapped.
590  std::vector<dof_id_type> dof_indices;
591 
592  // Here we extract the velocity & parameters that we put in the
593  // EquationSystems object.
594  const RealVectorValue velocity =
595  es.parameters.get<RealVectorValue> ("velocity");
596 
597  const Real diffusivity =
598  es.parameters.get<Real> ("diffusivity");
599 
600  const Real dt = es.parameters.get<Real> ("dt");
601 
602  // The global system matrix
603  SparseMatrix<Number> & matrix = system.get_system_matrix();
604 
605  // Now we will loop over all the elements in the mesh that
606  // live on the local processor. We will compute the element
607  // matrix and right-hand-side contribution. Since the mesh
608  // will be refined we want to only consider the ACTIVE elements,
609  // hence we use a variant of the active_elem_iterator.
610  for (const auto & elem : mesh.active_local_element_ptr_range())
611  {
612  // Get the degree of freedom indices for the
613  // current element. These define where in the global
614  // matrix and right-hand-side this element will
615  // contribute to.
616  dof_map.dof_indices (elem, dof_indices);
617 
618  // Compute the element-specific data for the current
619  // element. This involves computing the location of the
620  // quadrature points (q_point) and the shape functions
621  // (phi, dphi) for the current element.
622  fe->reinit (elem);
623 
624  const unsigned int n_dofs =
625  cast_int<unsigned int>(dof_indices.size());
626  libmesh_assert_equal_to (n_dofs, phi.size());
627 
628  // Zero the element matrix and right-hand side before
629  // summing them. We use the resize member here because
630  // the number of degrees of freedom might have changed from
631  // the last element. Note that this will be the case if the
632  // element type is different (i.e. the last element was a
633  // triangle, now we are on a quadrilateral).
634  Ke.resize (n_dofs, n_dofs);
635 
636  Fe.resize (n_dofs);
637 
638  // Now we will build the element matrix and right-hand-side.
639  // Constructing the RHS requires the solution and its
640  // gradient from the previous timestep. This myst be
641  // calculated at each quadrature point by summing the
642  // solution degree-of-freedom values by the appropriate
643  // weight functions.
644  for (unsigned int qp=0; qp<qrule.n_points(); qp++)
645  {
646  // Values to hold the old solution & its gradient.
647  Number u_old = 0.;
648  Gradient grad_u_old;
649 
650  // Compute the old solution & its gradient.
651  for (unsigned int l=0; l != n_dofs; l++)
652  {
653  u_old += phi[l][qp]*system.old_solution (dof_indices[l]);
654 
655  // This will work,
656  // grad_u_old += dphi[l][qp]*system.old_solution (dof_indices[l]);
657  // but we can do it without creating a temporary like this:
658  grad_u_old.add_scaled (dphi[l][qp], system.old_solution (dof_indices[l]));
659  }
660 
661  // Now compute the element matrix and RHS contributions.
662  for (unsigned int i=0; i != n_dofs; i++)
663  {
664  // The RHS contribution
665  Fe(i) += JxW[qp]*(
666  // Mass matrix term
667  u_old*phi[i][qp] +
668  -.5*dt*(
669  // Convection term
670  // (grad_u_old may be complex, so the
671  // order here is important!)
672  (grad_u_old*velocity)*phi[i][qp] +
673 
674  // Diffusion term
675  diffusivity*(grad_u_old*dphi[i][qp]))
676  );
677 
678  for (unsigned int j=0; j != n_dofs; j++)
679  {
680  // The matrix contribution
681  Ke(i,j) += JxW[qp]*(
682  // Mass-matrix
683  phi[i][qp]*phi[j][qp] +
684  .5*dt*(
685  // Convection term
686  (velocity*dphi[j][qp])*phi[i][qp] +
687  // Diffusion term
688  diffusivity*(dphi[i][qp]*dphi[j][qp]))
689  );
690  }
691  }
692  }
693 
694  // At this point the interior element integration has
695  // been completed. However, we have not yet addressed
696  // boundary conditions. For this example we will only
697  // consider simple Dirichlet boundary conditions imposed
698  // via the penalty method.
699  //
700  // The following loops over the sides of the element.
701  // If the element has no neighbor on a side then that
702  // side MUST live on a boundary of the domain.
703  {
704  // The penalty value.
705  const Real penalty = 1.e10;
706 
707  // The following loops over the sides of the element.
708  // If the element has no neighbor on a side then that
709  // side MUST live on a boundary of the domain.
710  for (auto s : elem->side_index_range())
711  if (elem->neighbor_ptr(s) == nullptr)
712  {
713  fe_face->reinit(elem, s);
714 
715  libmesh_assert_equal_to (n_dofs, psi.size());
716 
717  for (unsigned int qp=0; qp<qface.n_points(); qp++)
718  {
719  const Number value = exact_solution (qface_points[qp](0),
720  qface_points[qp](1),
721  system.time);
722 
723  // RHS contribution
724  for (unsigned int i=0; i != n_dofs; i++)
725  Fe(i) += penalty*JxW_face[qp]*value*psi[i][qp];
726 
727  // Matrix contribution
728  for (unsigned int i=0; i != n_dofs; i++)
729  for (unsigned int j=0; j != n_dofs; j++)
730  Ke(i,j) += penalty*JxW_face[qp]*psi[i][qp]*psi[j][qp];
731  }
732  }
733  }
734 
735 
736  // We have now built the element matrix and RHS vector in terms
737  // of the element degrees of freedom. However, it is possible
738  // that some of the element DOFs are constrained to enforce
739  // solution continuity, i.e. they are not really "free". We need
740  // to constrain those DOFs in terms of non-constrained DOFs to
741  // ensure a continuous solution. The
742  // DofMap::constrain_element_matrix_and_vector() method does
743  // just that.
744  dof_map.constrain_element_matrix_and_vector (Ke, Fe, dof_indices);
745 
746  if (sc)
747  sc->set_current_elem(*elem);
748 
749  // The element matrix and right-hand-side are now built
750  // for this element. Add them to the global matrix and
751  // right-hand-side vector. The SparseMatrix::add_matrix()
752  // and NumericVector::add_vector() members do this for us.
753  matrix.add_matrix (Ke, dof_indices);
754  system.rhs->add_vector (Fe, dof_indices);
755 
756  }
757  // Finished computing the system matrix and right-hand side.
758 }
class FEType hides (possibly multiple) FEFamily and approximation orders, thereby enabling specialize...
Definition: fe_type.h:196
void add_scaled(const TypeVector< T2 > &, const T &)
Add a scaled value to this vector without creating a temporary.
Definition: type_vector.h:629
void constrain_element_matrix_and_vector(DenseMatrix< Number > &matrix, DenseVector< Number > &rhs, std::vector< dof_id_type > &elem_dofs, bool asymmetric_constraint_rows=true) const
Constrains the element matrix and vector.
Definition: dof_map.h:2498
void dof_indices(const Elem *const elem, std::vector< dof_id_type > &di) const
Definition: dof_map.C:2201
unsigned int dim
void resize(const unsigned int n)
Resize the vector.
Definition: dense_vector.h:396
MeshBase & mesh
Manages storage and variables for transient systems.
Order default_quadrature_order() const
Definition: fe_type.h:415
const T_sys & get_system(std::string_view name) const
This is the MeshBase class.
Definition: mesh_base.h:80
This class handles the numbering of degrees of freedom on a mesh.
Definition: dof_map.h:179
const T & get(std::string_view) const
Definition: parameters.h:451
Real exact_solution(const Real x, const Real y, const Real t)
This is the exact solution that we are trying to obtain.
Number old_solution(const dof_id_type global_dof_number) const
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
const MeshBase & get_mesh() const
static const bool value
Definition: xdr_io.C:55
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
This class implements specific orders of Gauss quadrature.
unsigned int mesh_dimension() const
Definition: mesh_base.C:430
Parameters parameters
Data structure holding arbitrary parameters.

◆ exact_solution()

Real exact_solution ( const Real  x,
const Real  y,
const Real  z = 0. 
)

This is the exact solution that we are trying to obtain.

We will solve

  • (u_xx + u_yy) = f

and take a finite difference approximation using this function to get f. This is the well-known "method of manufactured solutions".

Definition at line 43 of file exact_solution.C.

Referenced by assemble_cd(), and exact_value().

46 {
47  static const Real pi = acos(-1.);
48 
49  return cos(.5*pi*x)*sin(.5*pi*y)*cos(.5*pi*z);
50 }
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
const Real pi
.
Definition: libmesh.h:292

◆ exact_value()

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

Definition at line 105 of file adaptivity_ex2.C.

References exact_solution(), libMesh::Parameters::get(), and libMesh::Real.

Referenced by init_cd(), and libMesh::DofMap::max_constraint_error().

109 {
110  return exact_solution(p(0), p(1), parameters.get<Real> ("time"));
111 }
const T & get(std::string_view) const
Definition: parameters.h:451
Real exact_solution(const Real x, const Real y, const Real t)
This is the exact solution that we are trying to obtain.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real

◆ init_cd() [1/2]

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

Referenced by main().

◆ init_cd() [2/2]

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

Definition at line 491 of file adaptivity_ex2.C.

References exact_value(), libMesh::EquationSystems::get_system(), libMesh::EquationSystems::parameters, libMesh::Real, and libMesh::Parameters::set().

493 {
494  // It is a good idea to make sure we are initializing
495  // the proper system.
496  libmesh_assert_equal_to (system_name, "Convection-Diffusion");
497 
498  // Get a reference to the Convection-Diffusion system object.
500  es.get_system<TransientLinearImplicitSystem>("Convection-Diffusion");
501 
502  // Project initial conditions at time 0
503  es.parameters.set<Real> ("time") = system.time = 0;
504 
505  system.project_solution(exact_value, nullptr, es.parameters);
506 }
Manages storage and variables for transient systems.
const T_sys & get_system(std::string_view name) const
Number exact_value(const Point &p, const Parameters &parameters, const std::string &, const std::string &)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
T & set(const std::string &)
Definition: parameters.h:494
Parameters parameters
Data structure holding arbitrary parameters.

◆ main()

int main ( int  argc,
char **  argv 
)

Definition at line 120 of file adaptivity_ex2.C.

References libMesh::MeshBase::all_second_order(), assemble_cd(), libMesh::MeshRefinement::coarsen_fraction(), libMesh::command_line_next(), libMesh::default_solver_package(), libMesh::JumpErrorEstimator::estimate_error(), libMesh::MeshRefinement::flag_elements_by_error_fraction(), libMesh::H1, libMesh::HIERARCHIC, libMesh::TriangleWrapper::init(), init_cd(), libMesh::INVALID_SOLVER_PACKAGE, libMesh::invalid_uint, libMesh::LAGRANGE, libMesh::MeshRefinement::max_h_level(), mesh, libMesh::on_command_line(), libMesh::out, libMesh::MeshBase::print_info(), libMesh::READ, libMesh::MeshBase::read(), libMesh::Real, libMesh::MeshRefinement::refine_and_coarsen_elements(), libMesh::MeshRefinement::refine_fraction(), libMesh::TOLERANCE, libMesh::TRILINOS_SOLVERS, libMesh::MeshRefinement::uniformly_refine(), libMesh::JumpErrorEstimator::use_unweighted_quadrature_rules, libMesh::WRITE, libMesh::MeshBase::write(), and libMesh::ExodusII_IO::write_equation_systems().

121 {
122  // Initialize libMesh.
123  LibMeshInit init (argc, argv);
124 
125  // This example requires a linear solver package.
126  libmesh_example_requires(libMesh::default_solver_package() != INVALID_SOLVER_PACKAGE,
127  "--enable-petsc, --enable-trilinos, or --enable-eigen");
128 
129 #ifndef LIBMESH_ENABLE_AMR
130  libmesh_example_requires(false, "--enable-amr");
131 #else
132 
133  // Our Trilinos interface does not yet support adaptive transient
134  // problems
135  libmesh_example_requires(libMesh::default_solver_package() != TRILINOS_SOLVERS, "--enable-petsc");
136 
137  // Brief message to the user regarding the program name
138  // and command line arguments.
139 
140  // Use commandline parameter to specify if we are to
141  // read in an initial solution or generate it ourself
142  libMesh::out << "Usage:\n"
143  <<"\t " << argv[0] << " -init_timestep 0 -n_timesteps 25 [-n_refinements 5]\n"
144  << "OR\n"
145  <<"\t " << argv[0] << " -read_solution -init_timestep 26 -n_timesteps 25\n"
146  << std::endl;
147 
148  libMesh::out << "Running: " << argv[0];
149 
150  for (int i=1; i<argc; i++)
151  libMesh::out << " " << argv[i];
152 
153  libMesh::out << std::endl << std::endl;
154 
155  // This boolean value is obtained from the command line, it is true
156  // if the flag "-read_solution" is present, false otherwise.
157  // It indicates whether we are going to read in
158  // the mesh and solution files "saved_mesh.xda" and "saved_solution.xda"
159  // or whether we are going to start from scratch by just reading
160  // "mesh.xda"
161  const bool read_solution = libMesh::on_command_line("-read_solution");
162 
163  // This value is also obtained from the commandline and it specifies the
164  // initial value for the t_step looping variable. We must
165  // distinguish between the two cases here, whether we read in the
166  // solution or we started from scratch, so that we do not overwrite the
167  // gmv output files.
168  const unsigned int init_timestep =
169  libMesh::command_line_next("-init_timestep",
171 
172  if (init_timestep == libMesh::invalid_uint)
173  {
174  // This handy function will print the file name, line number,
175  // specified message, and then throw an exception.
176  libmesh_error_msg("ERROR: Initial timestep not specified!");
177  }
178 
179  // This command line value specifies how many time steps to take.
180  const unsigned int n_timesteps =
181  libMesh::command_line_next("-n_timesteps",
183 
184  if (n_timesteps == libMesh::invalid_uint)
185  libmesh_error_msg("ERROR: Number of timesteps not specified");
186 
187  // This command line value specifies how far to allow refinement
188  const unsigned int max_h_level =
189  libMesh::command_line_next("-max_h_level", 5);
190 
191  // Skip this 2D example if libMesh was compiled as 1D-only.
192  libmesh_example_requires(2 <= LIBMESH_DIM, "2D support");
193 
194  // Create a new mesh on the default MPI communicator.
195  // We still need some work on automatic parallel restarts with
196  // DistributedMesh
197  ReplicatedMesh mesh(init.comm());
198 
199  // Create an equation systems object.
200  EquationSystems equation_systems (mesh);
201  MeshRefinement mesh_refinement (mesh);
202 
203  // First we process the case where we do not read in the solution
204  if (!read_solution)
205  {
206  // Read the mesh from file.
207  mesh.read ("mesh.xda");
208 
209  // Again do a search on the command line for an argument
210  const int order =
211  libMesh::command_line_next("-order", 1);
212 
213  // If we need a higher-order variable, we'll need second-order
214  // geometric elements to store edge DoFs. In 2D every
215  // second-order geometric can support every polynomial degree
216  // (even higher-than-second), but we'll leave the 3D-compatible
217  // thing in comments here for didactic purposes.
218  //if (order > 2)
219  // mesh.all_complete_order();
220  //else
221  if (order > 1)
223 
224  const unsigned int n_refinements =
225  libMesh::command_line_next("-n_refinements", 5);
226 
227  // Uniformly refine the mesh n times
228  if (!read_solution)
229  mesh_refinement.uniformly_refine (n_refinements);
230 
231  // Print information about the mesh to the screen.
232  mesh.print_info();
233 
234  // Declare the system and its variables.
235  // Begin by creating a transient system
236  // named "Convection-Diffusion".
238  equation_systems.add_system<TransientLinearImplicitSystem>("Convection-Diffusion");
239 
240  // Adds the variable "u" to "Convection-Diffusion". "u"
241  // will be approximated using first- or second-order
242  // approximation. For higher than second-order FE we need a
243  // non-Lagrange type.
244  system.add_variable ("u", Order(order), order > 2 ? HIERARCHIC : LAGRANGE);
245 
246  // Give the system a pointer to the matrix assembly
247  // and initialization functions.
248  system.attach_assemble_function (assemble_cd);
249  system.attach_init_function (init_cd);
250 
251  // Initialize the data structures for the equation system.
252  equation_systems.init ();
253  }
254  // Otherwise we read in the solution and mesh
255  else
256  {
257  // Read in the mesh stored in "saved_mesh.xda"
258  mesh.read("saved_mesh.xda");
259 
260  // Print information about the mesh to the screen.
261  mesh.print_info();
262 
263  // Read in the solution stored in "saved_solution.xda"
264  equation_systems.read("saved_solution.xda", READ);
265 
266  // Get a reference to the system so that we can call update() on it
268  equation_systems.get_system<TransientLinearImplicitSystem>("Convection-Diffusion");
269 
270  // We need to call update to put system in a consistent state
271  // with the solution that was read in
272  system.update();
273 
274  // Attach the same matrix assembly function as above. Note, we do not
275  // have to attach an init() function since we are initializing the
276  // system by reading in "saved_solution.xda"
277  system.attach_assemble_function (assemble_cd);
278 
279  // Print out the H1 norm of the saved solution, for verification purposes:
280  Real H1norm = system.calculate_norm(*system.solution, SystemNorm(H1));
281 
282  libMesh::out << "Initial H1 norm = " << H1norm << std::endl << std::endl;
283  }
284 
285  // Prints information about the system to the screen.
286  equation_systems.print_info();
287 
288  equation_systems.parameters.set<unsigned int>("linear solver maximum iterations") = 250;
289  equation_systems.parameters.set<Real>("linear solver tolerance") = TOLERANCE;
290 
291  // Get some output to visualize
292 #ifdef LIBMESH_HAVE_EXODUS_API
293  if (!read_solution)
294  // Write out the initial condition
295  ExodusII_IO(mesh).write_equation_systems ("out.e.000", equation_systems);
296  else
297  // Write out the solution that was read in
298  ExodusII_IO(mesh).write_equation_systems ("solution_read_in.e", equation_systems);
299 #endif // LIBMESH_HAVE_EXODUS_API
300 
301  // The Convection-Diffusion system requires that we specify
302  // the flow velocity. We will specify it as a RealVectorValue
303  // data type and then use the Parameters object to pass it to
304  // the assemble function.
305  equation_systems.parameters.set<RealVectorValue>("velocity") =
306  RealVectorValue (0.8, 0.8);
307 
308  // The Convection-Diffusion system also requires a specified
309  // diffusivity. We use an isotropic (hence Real) value.
310  equation_systems.parameters.set<Real>("diffusivity") = 0.01;
311 
312  // Solve the system "Convection-Diffusion". This will be done by
313  // looping over the specified time interval and calling the
314  // solve() member at each time step. This will assemble the
315  // system and call the linear solver.
316 
317  // Since only TransientLinearImplicitSystems (and systems
318  // derived from them) contain old solutions, to use the
319  // old_local_solution later we now need to specify the system
320  // type when we ask for it.
322  equation_systems.get_system<TransientLinearImplicitSystem>("Convection-Diffusion");
323 
324  const Real dt = 0.025;
325  system.time = init_timestep*dt;
326 
327  // We're going to refine and coarsen based on some heuristics.
328  const Real refine_fraction =
329  libMesh::command_line_next("-refine_fraction", 0.80);
330 
331  const Real coarsen_fraction =
332  libMesh::command_line_next("-coarsen_fraction", 0.07);
333 
334  // We do 25 timesteps both before and after writing out the
335  // intermediate solution
336  for (unsigned int t_step=init_timestep; t_step<(init_timestep+n_timesteps); t_step++)
337  {
338  // Increment the time counter, set the time and the
339  // time step size as parameters in the EquationSystem.
340  system.time += dt;
341 
342  equation_systems.parameters.set<Real> ("time") = system.time;
343  equation_systems.parameters.set<Real> ("dt") = dt;
344 
345  // A pretty update message
346  libMesh::out << " Solving time step ";
347 
348  // Add a set of scope braces to enforce data locality.
349  {
350  std::ostringstream out;
351 
352  out << std::setw(2)
353  << std::right
354  << t_step
355  << ", time="
356  << std::fixed
357  << std::setw(6)
358  << std::setprecision(3)
359  << std::setfill('0')
360  << std::left
361  << system.time
362  << "...";
363 
364  libMesh::out << out.str() << std::endl;
365  }
366 
367  // At this point we need to update the old
368  // solution vector. The old solution vector
369  // will be the current solution vector from the
370  // previous time step.
371 
372  *system.old_local_solution = *system.current_local_solution;
373 
374  // The number of refinement steps per time step.
375  const unsigned int max_r_steps = 2;
376 
377  // A refinement loop.
378  for (unsigned int r_step=0; r_step<max_r_steps; r_step++)
379  {
380  // Assemble & solve the linear system
381  system.solve();
382 
383  // Print out the H1 norm, for verification purposes:
384  Real H1norm = system.calculate_norm(*system.solution, SystemNorm(H1));
385 
386  libMesh::out << "H1 norm = " << H1norm << std::endl;
387 
388  // Possibly refine the mesh
389  if (r_step+1 != max_r_steps)
390  {
391  libMesh::out << " Refining the mesh..." << std::endl;
392 
393  // The ErrorVector is a particular StatisticsVector
394  // for computing error information on a finite element mesh.
395  ErrorVector error;
396 
397  // The ErrorEstimator class interrogates a finite element
398  // solution and assigns to each element a positive error value.
399  // This value is used for deciding which elements to refine
400  // and which to coarsen.
401  KellyErrorEstimator error_estimator;
402 
403  // This is a subclass of JumpErrorEstimator, based on
404  // measuring discontinuities across sides between
405  // elements, and we can tell it to use a cheaper
406  // "unweighted" quadrature rule when numerically
407  // integrating those discontinuities.
408  error_estimator.use_unweighted_quadrature_rules = true;
409 
410  // Compute the error for each active element using the provided
411  // flux_jump indicator. Note in general you will need to
412  // provide an error estimator specifically designed for your
413  // application.
414  error_estimator.estimate_error (system,
415  error);
416 
417  // This takes the error in error and decides which elements
418  // will be coarsened or refined. Any element within 20% of the
419  // maximum error on any element will be refined, and any
420  // element within 7% of the minimum error on any element might
421  // be coarsened. Note that the elements flagged for refinement
422  // will be refined, but those flagged for coarsening _might_ be
423  // coarsened.
424  mesh_refinement.refine_fraction() = refine_fraction;
425  mesh_refinement.coarsen_fraction() = coarsen_fraction;
426  mesh_refinement.max_h_level() = max_h_level;
427  mesh_refinement.flag_elements_by_error_fraction (error);
428 
429  // This call actually refines and coarsens the flagged
430  // elements.
431  mesh_refinement.refine_and_coarsen_elements();
432 
433  // This call reinitializes the EquationSystems object for
434  // the newly refined mesh. One of the steps in the
435  // reinitialization is projecting the solution,
436  // old_solution, etc... vectors from the old mesh to
437  // the current one.
438  equation_systems.reinit ();
439  }
440  }
441 
442  // Again do a search on the command line for an argument
443  const unsigned int output_freq =
444  libMesh::command_line_next("-output_freq", 10);
445 
446  // Every N timesteps, output solutions to file and summaries to
447  // the console.
448  if ((t_step+1)%output_freq == 0)
449  {
450  equation_systems.print_info();
451 
452  std::ostringstream file_name;
453 
454  file_name << "out.e."
455  << std::setw(3)
456  << std::setfill('0')
457  << std::right
458  << t_step+1;
459 
460  // Get some output to visualize
461 #ifdef LIBMESH_HAVE_EXODUS_API
462  ExodusII_IO(mesh).write_equation_systems (file_name.str(),
463  equation_systems);
464 #endif // LIBMESH_HAVE_EXODUS_API
465  }
466  }
467 
468  if (!read_solution)
469  {
470  // Print out the H1 norm of the saved solution, for verification purposes:
471  Real H1norm = system.calculate_norm(*system.solution, SystemNorm(H1));
472 
473  libMesh::out << "Final H1 norm = " << H1norm << std::endl << std::endl;
474 
475  mesh.write("saved_mesh.xda");
476  equation_systems.write("saved_solution.xda", WRITE);
477 #ifdef LIBMESH_HAVE_EXODUS_API
478  ExodusII_IO(mesh).write_equation_systems ("saved_solution.e",
479  equation_systems);
480 #endif // LIBMESH_HAVE_EXODUS_API
481  }
482 #endif // #ifndef LIBMESH_ENABLE_AMR
483 
484  return 0;
485 }
T command_line_next(std::string name, T default_value)
Use GetPot&#39;s search()/next() functions to get following arguments from the command line...
Definition: libmesh.C:1025
This is the EquationSystems class.
The ReplicatedMesh class is derived from the MeshBase class, and is used to store identical copies of...
Order
defines an enum for polynomial orders.
Definition: enum_order.h:40
const unsigned int invalid_uint
A number which is used quite often to represent an invalid or uninitialized value for an unsigned int...
Definition: libmesh.h:303
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.
static constexpr Real TOLERANCE
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:50
MeshBase & mesh
Manages storage and variables for transient systems.
This class defines a norm/seminorm to be applied to a NumericVector which contains coefficients in a ...
Definition: system_norm.h:49
The LibMeshInit class, when constructed, initializes the dependent libraries (e.g.
Definition: libmesh.h:91
SolverPackage default_solver_package()
Definition: libmesh.C:1064
Implements (adaptive) mesh refinement algorithms for a MeshBase.
void assemble_cd(EquationSystems &es, const std::string &system_name)
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.
Definition: exodusII_io.C:2050
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:1748
void init(triangulateio &t)
Initializes the fields of t to nullptr/0 as necessary.
virtual void write(const std::string &name) const =0
This class implements the Kelly error indicator which is based on the flux jumps between elements...
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
void init_cd(EquationSystems &es, const std::string &system_name)
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:1796
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...
bool on_command_line(std::string arg)
Definition: libmesh.C:934