libMesh
Loading...
Searching...
No Matches
Functions | Variables
adaptivity_ex5.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.
 
Number exact_value (const Point &p, const Parameters &parameters, const std::string &, const std::string &)
 
std::string exodus_filename (unsigned number)
 
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))
 

Variables

std::unique_ptr< FunctionBase< Number > > parsed_solution
 

Function Documentation

◆ assemble_cd() [1/2]

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

Definition at line 565 of file adaptivity_ex5.C.

567{
568 // It is a good idea to make sure we are assembling
569 // the proper system.
570 libmesh_assert_equal_to (system_name, "Convection-Diffusion");
571
572 // Get a constant reference to the mesh object.
573 const MeshBase & mesh = es.get_mesh();
574
575 // The dimension that we are running
576 const unsigned int dim = mesh.mesh_dimension();
577
578 // Get a reference to the Convection-Diffusion system object.
580 es.get_system<TransientLinearImplicitSystem> ("Convection-Diffusion");
581
582 // Get the Finite Element type for the first (and only)
583 // variable in the system.
584 FEType fe_type = system.variable_type(0);
585
586 // Build a Finite Element object of the specified type. Since the
587 // FEBase::build() member dynamically creates memory we will
588 // store the object as a std::unique_ptr<FEBase>. This can be thought
589 // of as a pointer that will clean up after itself.
590 std::unique_ptr<FEBase> fe (FEBase::build(dim, fe_type));
591 std::unique_ptr<FEBase> fe_face (FEBase::build(dim, fe_type));
592
593 // A Gauss quadrature rule for numerical integration.
594 // Let the FEType object decide what order rule is appropriate.
595 QGauss qrule (dim, fe_type.default_quadrature_order());
596 QGauss qface (dim-1, fe_type.default_quadrature_order());
597
598 // Tell the finite element object to use our quadrature rule.
599 fe->attach_quadrature_rule (&qrule);
600 fe_face->attach_quadrature_rule (&qface);
601
602 // Here we define some references to cell-specific data that
603 // will be used to assemble the linear system. We will start
604 // with the element Jacobian * quadrature weight at each integration point.
605 const std::vector<Real> & JxW = fe->get_JxW();
606
607 // The element shape functions evaluated at the quadrature points.
608 const std::vector<std::vector<Real>> & phi = fe->get_phi();
609
610 // The element shape function gradients evaluated at the quadrature
611 // points.
612 const std::vector<std::vector<RealGradient>> & dphi = fe->get_dphi();
613
614 // A reference to the DofMap object for this system. The DofMap
615 // object handles the index translation from node and element numbers
616 // to degree of freedom numbers. We will talk more about the DofMap
617 // in future examples.
618 const DofMap & dof_map = system.get_dof_map();
619
620 // Define data structures to contain the element matrix
621 // and right-hand-side vector contribution. Following
622 // basic finite element terminology we will denote these
623 // "Ke" and "Fe".
626
627 // This vector will hold the degree of freedom indices for
628 // the element. These define where in the global system
629 // the element degrees of freedom get mapped.
630 std::vector<dof_id_type> dof_indices;
631
632 // Here we extract the velocity & parameters that we put in the
633 // EquationSystems object.
634 const RealVectorValue velocity =
635 es.parameters.get<RealVectorValue> ("velocity");
636
637 const Real diffusivity =
638 es.parameters.get<Real> ("diffusivity");
639
640 const Real dt = es.parameters.get<Real> ("dt");
641
642 // The global system matrix
643 SparseMatrix<Number> & matrix = system.get_system_matrix();
644
645 // Now we will loop over all the elements in the mesh that
646 // live on the local processor. We will compute the element
647 // matrix and right-hand-side contribution. Since the mesh
648 // will be refined we want to only consider the ACTIVE elements,
649 // hence we use a variant of the active_elem_iterator.
650 for (const auto & elem : mesh.active_local_element_ptr_range())
651 {
652 // Get the degree of freedom indices for the
653 // current element. These define where in the global
654 // matrix and right-hand-side this element will
655 // contribute to.
656 dof_map.dof_indices (elem, dof_indices);
657
658 // Compute the element-specific data for the current
659 // element. This involves computing the location of the
660 // quadrature points (q_point) and the shape functions
661 // (phi, dphi) for the current element.
662 fe->reinit (elem);
663
664 const unsigned int n_dofs =
665 cast_int<unsigned int>(dof_indices.size());
666 libmesh_assert_equal_to (n_dofs, phi.size());
667
668 // Zero the element matrix and right-hand side before
669 // summing them. We use the resize member here because
670 // the number of degrees of freedom might have changed from
671 // the last element. Note that this will be the case if the
672 // element type is different (i.e. the last element was a
673 // triangle, now we are on a quadrilateral).
674 Ke.resize (n_dofs, n_dofs);
675
676 Fe.resize (n_dofs);
677
678 // Now we will build the element matrix and right-hand-side.
679 // Constructing the RHS requires the solution and its
680 // gradient from the previous timestep. This myst be
681 // calculated at each quadrature point by summing the
682 // solution degree-of-freedom values by the appropriate
683 // weight functions.
684 for (unsigned int qp=0; qp<qrule.n_points(); qp++)
685 {
686 // Values to hold the old solution & its gradient.
687 Number u_old = 0.;
688 Gradient grad_u_old;
689
690 // Compute the old solution & its gradient.
691 for (unsigned int l=0; l != n_dofs; l++)
692 {
693 u_old += phi[l][qp]*system.old_solution (dof_indices[l]);
694
695 // This will work,
696 // grad_u_old += dphi[l][qp]*system.old_solution (dof_indices[l]);
697 // but we can do it without creating a temporary like this:
698 grad_u_old.add_scaled (dphi[l][qp], system.old_solution (dof_indices[l]));
699 }
700
701 // Now compute the element matrix and RHS contributions.
702 for (unsigned int i=0; i != n_dofs; i++)
703 {
704 // The RHS contribution
705 Fe(i) += JxW[qp]*(
706 // Mass matrix term
707 u_old*phi[i][qp] +
708 -.5*dt*(
709 // Convection term
710 // (grad_u_old may be complex, so the
711 // order here is important!)
712 (grad_u_old*velocity)*phi[i][qp] +
713
714 // Diffusion term
715 diffusivity*(grad_u_old*dphi[i][qp]))
716 );
717
718 for (unsigned int j=0; j != n_dofs; j++)
719 {
720 // The matrix contribution
721 Ke(i,j) += JxW[qp]*(
722 // Mass-matrix
723 phi[i][qp]*phi[j][qp] +
724 .5*dt*(
725 // Convection term
726 (velocity*dphi[j][qp])*phi[i][qp] +
727 // Diffusion term
728 diffusivity*(dphi[i][qp]*dphi[j][qp]))
729 );
730 }
731 }
732 }
733
734 // We have now built the element matrix and RHS vector in terms
735 // of the element degrees of freedom. However, it is possible
736 // that some of the element DOFs are constrained to enforce
737 // solution continuity, i.e. they are not really "free". We need
738 // to constrain those DOFs in terms of non-constrained DOFs to
739 // ensure a continuous solution. The
740 // DofMap::constrain_element_matrix_and_vector() method does
741 // just that.
742 dof_map.constrain_element_matrix_and_vector (Ke, Fe, dof_indices);
743
744 // The element matrix and right-hand-side are now built
745 // for this element. Add them to the global matrix and
746 // right-hand-side vector. The SparseMatrix::add_matrix()
747 // and NumericVector::add_vector() members do this for us.
748 matrix.add_matrix (Ke, dof_indices);
749 system.rhs->add_vector (Fe, dof_indices);
750
751 }
752 // Finished computing the system matrix and right-hand side.
753}
unsigned int dim
Defines a dense matrix for use in Finite Element-type computations.
void resize(const unsigned int new_m, const unsigned int new_n)
Resizes the matrix to the specified size and calls zero().
Defines a dense vector for use in Finite Element-type computations.
void resize(const unsigned int n)
Resize the vector.
This class handles the numbering of degrees of freedom on a mesh.
Definition dof_map.h:181
void dof_indices(const Elem *const elem, std::vector< dof_id_type > &di) const
Definition dof_map.C:2201
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
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
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.
Manages storage and variables for transient systems.
Number old_solution(const dof_id_type global_dof_number) const
void add_scaled(const TypeVector< T2 > &, const T &)
Add a scaled value to this vector without creating a temporary.
MeshBase & mesh
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real

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

◆ assemble_cd() [2/2]

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

Definition at line 296 of file transient_ex1.C.

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}
Number(* exact_solution)(const Point &p, const Parameters &, const std::string &, const std::string &)
void libmesh_ignore(const Args &...)
static const bool value
Definition xdr_io.C:55

Referenced by main().

◆ exact_solution()

Real exact_solution ( const Real  x,
const Real  y,
const Real  t 
)

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.

46{
47 static const Real pi = acos(-1.);
48
49 return cos(.5*pi*x)*sin(.5*pi*y)*cos(.5*pi*z);
50}
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 106 of file adaptivity_ex5.C.

110{
111 return exact_solution(p(0), p(1), parameters.get<Real> ("time"));
112}

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

Referenced by init_cd().

◆ exodus_filename()

std::string exodus_filename ( unsigned  number)

Definition at line 759 of file adaptivity_ex5.C.

760{
761 std::ostringstream oss;
762
763 oss << "out_";
764 oss << std::setw(3) << std::setfill('0') << number;
765 oss << ".e";
766
767 return oss.str();
768}

Referenced by main().

◆ init_cd() [1/2]

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

Definition at line 538 of file adaptivity_ex5.C.

540{
541 // It is a good idea to make sure we are initializing
542 // the proper system.
543 libmesh_assert_equal_to (system_name, "Convection-Diffusion");
544
545 // Get a reference to the Convection-Diffusion system object.
547 es.get_system<TransientLinearImplicitSystem>("Convection-Diffusion");
548
549 // Project initial conditions at time 0
550 es.parameters.set<Real> ("time") = system.time = 0;
551
552 if (parsed_solution.get())
553 system.project_solution(parsed_solution.get(), nullptr);
554 else
555 system.project_solution(exact_value, nullptr, es.parameters);
556}
std::unique_ptr< FunctionBase< Number > > parsed_solution
Number exact_value(const Point &p, const Parameters &parameters, const std::string &, const std::string &)
T & set(const std::string &)
Definition parameters.h:494

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

◆ init_cd() [2/2]

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

Referenced by main().

◆ main()

int main ( int  argc,
char **  argv 
)

Definition at line 129 of file adaptivity_ex5.C.

130{
131 // Initialize libMesh.
132 LibMeshInit init (argc, argv);
133
134 // This example requires a linear solver package.
135 libmesh_example_requires(libMesh::default_solver_package() != INVALID_SOLVER_PACKAGE,
136 "--enable-petsc, --enable-trilinos, or --enable-eigen");
137
138 // Skip this 2D example if libMesh was compiled as 1D-only.
139 libmesh_example_requires(2 <= LIBMESH_DIM, "2D support");
140
141#if !defined(LIBMESH_ENABLE_AMR)
142 libmesh_example_requires(false, "--enable-amr");
143#elif !defined(LIBMESH_HAVE_XDR)
144 // We use XDR support in our output here
145 libmesh_example_requires(false, "--enable-xdr");
146#elif !defined(LIBMESH_ENABLE_PERIODIC)
147 libmesh_example_requires(false, "--enable-periodic");
148#elif (LIBMESH_DOF_ID_BYTES == 8)
149 libmesh_example_requires(false, "--with-dof-id-bytes=4");
150#else
151
152 // Our Trilinos interface does not yet support adaptive transient
153 // problems
154 libmesh_example_requires(libMesh::default_solver_package() != TRILINOS_SOLVERS, "--enable-petsc");
155
156 // Brief message to the user regarding the program name
157 // and command line arguments.
158
159 // Use commandline parameter to specify if we are to
160 // read in an initial solution or generate it ourself
161 libMesh::out << "Usage:\n"
162 <<"\t " << argv[0] << " -init_timestep 0\n"
163 << "OR\n"
164 <<"\t " << argv[0] << " -read_solution -init_timestep 26\n"
165 << std::endl;
166
167 libMesh::out << "Running: " << argv[0];
168
169 for (int i=1; i<argc; i++)
170 libMesh::out << " " << argv[i];
171
172 libMesh::out << std::endl << std::endl;
173
174 // This boolean value is obtained from the command line, it is true
175 // if the flag "-read_solution" is present, false otherwise.
176 // It indicates whether we are going to read in
177 // the mesh and solution files "saved_mesh.xda" and "saved_solution.xda"
178 // or whether we are going to start from scratch by just reading
179 // "mesh.xda"
180 const bool read_solution = libMesh::on_command_line("-read_solution");
181
182 // This value is also obtained from the commandline and it specifies the
183 // initial value for the t_step looping variable. We must
184 // distinguish between the two cases here, whether we read in the
185 // solution or we started from scratch, so that we do not overwrite the
186 // gmv output files.
187 const unsigned int init_timestep =
188 libMesh::command_line_next("-init_timestep",
190
191 if (init_timestep == libMesh::invalid_uint)
192 {
193 // This handy function will print the file name, line number,
194 // specified message, and then throw an exception.
195 libmesh_error_msg("ERROR: Initial timestep not specified!");
196 }
197
198 // This value is also obtained from the command line, and specifies
199 // the number of time steps to take.
200 const unsigned int n_timesteps =
201 libMesh::command_line_next("-n_timesteps",
203
204 if (n_timesteps == libMesh::invalid_uint)
205 libmesh_error_msg("ERROR: Number of timesteps not specified");
206
207 // The user can specify a different exact solution on the command
208 // line, if we have an expression parser compiled in
209#ifdef LIBMESH_HAVE_FPARSER
210 const bool have_expression = libMesh::on_command_line("-exact_solution");
211#else
212 const bool have_expression = false;
213#endif
214 if (have_expression)
215 parsed_solution = std::make_unique<ParsedFunction<Number>>
216 (libMesh::command_line_next("-exact_solution", std::string()));
217
218 // Skip this 2D example if libMesh was compiled as 1D-only.
219 libmesh_example_requires(2 <= LIBMESH_DIM, "2D support");
220
221 // Create a new mesh on the default MPI communicator.
222 // There seems to be a DistributedMesh bug triggered here.
223 ReplicatedMesh mesh(init.comm());
224
225 // Create an equation systems object.
226 EquationSystems equation_systems (mesh);
227 MeshRefinement mesh_refinement (mesh);
228
229 // Declare the system and its variables.
230 // Begin by creating a transient system
231 // named "Convection-Diffusion".
233 equation_systems.add_system<TransientLinearImplicitSystem>
234 ("Convection-Diffusion");
235
236 // Give the system a pointer to the assembly function.
237 system.attach_assemble_function (assemble_cd);
238
239 // Creating and attaching Periodic Boundaries
240 DofMap & dof_map = system.get_dof_map();
241
242 // Create a boundary periodic with one displaced 2.0 in the x
243 // direction
244 PeriodicBoundary horz(RealVectorValue(2.0, 0., 0.));
245
246 // Connect boundary ids 3 and 1 with it
247 horz.myboundary = 3;
248 horz.pairedboundary = 1;
249
250 // Add it to the PeriodicBoundaries
251 dof_map.add_periodic_boundary(horz);
252
253 // Create a boundary periodic with one displaced 2.0 in the y
254 // direction
255 PeriodicBoundary vert(RealVectorValue(0., 2.0, 0.));
256
257 // Connect boundary ids 0 and 2 with it
258 vert.myboundary = 0;
259 vert.pairedboundary = 2;
260
261 // Add it to the PeriodicBoundaries
262 dof_map.add_periodic_boundary(vert);
263
264 // Next build or read the mesh. We do this only *after* generating
265 // periodic boundaries; otherwise a DistributedMesh won't know to
266 // retain periodic neighbor elements.
267
268 // First we process the case where we do not read in the solution
269 if (!read_solution)
270 {
271 MeshTools::Generation::build_square(mesh, 2, 2, 0., 2., 0., 2., QUAD4);
272
273 // Again do a search on the command line for an argument
274 const unsigned int n_refinements =
275 libMesh::command_line_next("-n_refinements", 5);
276
277 // Uniformly refine the mesh 5 times
278 if (!read_solution)
279 mesh_refinement.uniformly_refine (n_refinements);
280
281 // Print information about the mesh to the screen.
283
284 // Adds the variable "u" to "Convection-Diffusion". "u"
285 // will be approximated using first-order approximation.
286 system.add_variable ("u", FIRST);
287
288 // Give the system a pointer to the initialization function.
289 system.attach_init_function (init_cd);
290 }
291 // Otherwise we read in the solution and mesh
292 else
293 {
294 // Read in the mesh stored in "saved_mesh.xda"
295 mesh.read("saved_mesh.xdr");
296
297 // Print information about the mesh to the screen.
299
300 // Read in the solution stored in "saved_solution.xda"
301 equation_systems.read("saved_solution.xdr", DECODE);
302 }
303
304 // Initialize the data structures for the equation system.
305 if (!read_solution)
306 equation_systems.init ();
307 else
308 equation_systems.reinit ();
309
310 // Print out the H1 norm of the initialized or saved solution, for
311 // verification purposes:
312 Real H1norm = system.calculate_norm(*system.solution, SystemNorm(H1));
313
314 libMesh::out << "Initial H1 norm = " << H1norm << std::endl << std::endl;
315
316 // Prints information about the system to the screen.
317 equation_systems.print_info();
318
319 equation_systems.parameters.set<unsigned int>
320 ("linear solver maximum iterations") = 250;
321 equation_systems.parameters.set<Real>
322 ("linear solver tolerance") = TOLERANCE;
323
324 if (!read_solution)
325 {
326 // Write out the initial condition
327#ifdef LIBMESH_HAVE_GMV
328 GMVIO(mesh).write_equation_systems ("out.gmv.000",
329 equation_systems);
330#endif
331#ifdef LIBMESH_HAVE_EXODUS_API
333 equation_systems);
334#endif
335 }
336 else
337 {
338 // Write out the solution that was read in
339#ifdef LIBMESH_HAVE_GMV
340 GMVIO(mesh).write_equation_systems ("solution_read_in.gmv",
341 equation_systems);
342#endif
343#ifdef LIBMESH_HAVE_EXODUS_API
344 ExodusII_IO(mesh).write_equation_systems ("solution_read_in.e",
345 equation_systems);
346#endif
347 }
348
349
350 // The Convection-Diffusion system requires that we specify
351 // the flow velocity. We will specify it as a RealVectorValue
352 // data type and then use the Parameters object to pass it to
353 // the assemble function.
354 equation_systems.parameters.set<RealVectorValue>("velocity") =
355 RealVectorValue (0.8, 0.8);
356
357 // The Convection-Diffusion system also requires a specified
358 // diffusivity. We use an isotropic (hence Real) value.
359 equation_systems.parameters.set<Real>("diffusivity") = 0.01;
360
361 // Solve the system "Convection-Diffusion". This will be done by
362 // looping over the specified time interval and calling the
363 // solve() member at each time step. This will assemble the
364 // system and call the linear solver.
365 const Real dt = 0.025;
366 system.time = init_timestep*dt;
367
368 // Tell the MeshRefinement object about the periodic boundaries so
369 // that it can get heuristics like level-one conformity and
370 // unrefined island elimination right.
371 mesh_refinement.set_periodic_boundaries_ptr(dof_map.get_periodic_boundaries());
372
373 // We do 25 timesteps both before and after writing out the
374 // intermediate solution
375 for (unsigned int t_step=init_timestep; t_step<(init_timestep+n_timesteps); t_step++)
376 {
377 // Increment the time counter, set the time and the
378 // time step size as parameters in the EquationSystem.
379 system.time += dt;
380
381 equation_systems.parameters.set<Real> ("time") = system.time;
382 equation_systems.parameters.set<Real> ("dt") = dt;
383
384 // A pretty update message
385 libMesh::out << " Solving time step ";
386
387 {
388 // Save flags to avoid polluting cout with custom precision values, etc.
389 std::ios_base::fmtflags os_flags = libMesh::out.flags();
390
391 libMesh::out << t_step
392 << ", time="
393 << std::setw(6)
394 << std::setprecision(3)
395 << std::setfill('0')
396 << std::left
397 << system.time
398 << "..."
399 << std::endl;
400
401 // Restore flags
402 libMesh::out.flags(os_flags);
403 }
404
405 // At this point we need to update the old
406 // solution vector. The old solution vector
407 // will be the current solution vector from the
408 // previous time step. We will do this by extracting the
409 // system from the EquationSystems object and using
410 // vector assignment. Since only TransientLinearImplicitSystems
411 // (and systems derived from them) contain old solutions
412 // we need to specify the system type when we ask for it.
413 *system.old_local_solution = *system.current_local_solution;
414
415 // The number of refinement steps per time step.
416 const unsigned int max_r_steps =
417 libMesh::command_line_next("-max_r_steps", 1);
418
419 // A refinement loop.
420 for (unsigned int r_step=0; r_step<max_r_steps+1; r_step++)
421 {
422 // Assemble & solve the linear system
423 system.solve();
424
425 // Print out the H1 norm, for verification purposes:
426 H1norm = system.calculate_norm(*system.solution, SystemNorm(H1));
427 libMesh::out << "H1 norm = " << H1norm << std::endl;
428
429 // Possibly refine the mesh
430 if (r_step+1 <= max_r_steps)
431 {
432 libMesh::out << " Refining the mesh..." << std::endl;
433
434 // The ErrorVector is a particular StatisticsVector
435 // for computing error information on a finite element mesh.
436 ErrorVector error;
437
438 // The ErrorEstimator class interrogates a finite element
439 // solution and assigns to each element a positive error value.
440 // This value is used for deciding which elements to refine
441 // and which to coarsen.
442 KellyErrorEstimator error_estimator;
443
444 // This is a subclass of JumpErrorEstimator, based
445 // on measuring discontinuities across sides between
446 // elements, and we can tell it to use a cheaper
447 // "unweighted" quadrature rule when numerically
448 // integrating those discontinuities.
449 error_estimator.use_unweighted_quadrature_rules = true;
450
451 // Compute the error for each active element using the provided
452 // flux_jump indicator. Note in general you will need to
453 // provide an error estimator specifically designed for your
454 // application.
455 error_estimator.estimate_error (system,
456 error);
457
458 // This takes the error in error and decides which elements
459 // will be coarsened or refined. Any element within 20% of the
460 // maximum error on any element will be refined, and any
461 // element within 7% of the minimum error on any element might
462 // be coarsened. Note that the elements flagged for refinement
463 // will be refined, but those flagged for coarsening _might_ be
464 // coarsened.
465 mesh_refinement.refine_fraction() = 0.80;
466 mesh_refinement.coarsen_fraction() = 0.07;
467 mesh_refinement.max_h_level() = 5;
468 mesh_refinement.flag_elements_by_error_fraction (error);
469
470 // This call actually refines and coarsens the flagged
471 // elements.
472 mesh_refinement.refine_and_coarsen_elements();
473
474 // This call reinitializes the EquationSystems object for
475 // the newly refined mesh. One of the steps in the
476 // reinitialization is projecting the solution,
477 // old_solution, etc... vectors from the old mesh to
478 // the current one.
479 equation_systems.reinit ();
480 }
481 }
482
483 // Again do a search on the command line for an argument
484 const unsigned int output_freq =
485 libMesh::command_line_next("-output_freq", 10);
486
487 // Output every 10 timesteps to file.
488 if ((t_step+1)%output_freq == 0)
489 {
490#ifdef LIBMESH_HAVE_GMV
491 // std::ostringstream file_name;
492 // out << "out.gmv."
493 // << std::setw(3)
494 // << std::setfill('0')
495 // << std::right
496 // << t_step+1;
497 // GMVIO(mesh).write_equation_systems (file_name.str(),
498 // equation_systems);
499#endif
500#ifdef LIBMESH_HAVE_EXODUS_API
501 // So... if paraview is told to open a file called out.e.{N}, it automatically tries to
502 // open out.e.{N-1}, out.e.{N-2}, etc. If we name the file something else, we can work
503 // around that issue, but the right thing to do (for adaptive meshes) is to write a filename
504 // with the adaptation step into a separate file.
506 equation_systems);
507#endif
508 }
509 }
510
511 if (!read_solution)
512 {
513 // Print out the H1 norm of the saved solution, for verification purposes:
514 H1norm = system.calculate_norm(*system.solution, SystemNorm(H1));
515
516 libMesh::out << "Final H1 norm = " << H1norm << std::endl << std::endl;
517
518 mesh.write("saved_mesh.xdr");
519 equation_systems.write("saved_solution.xdr", ENCODE);
520#ifdef LIBMESH_HAVE_GMV
521 GMVIO(mesh).write_equation_systems ("saved_solution.gmv",
522 equation_systems);
523#endif
524#ifdef LIBMESH_HAVE_EXODUS_API
525 ExodusII_IO(mesh).write_equation_systems ("saved_solution.e",
526 equation_systems);
527#endif
528 }
529#endif // #ifndef LIBMESH_ENABLE_AMR
530
531 return 0;
532}
std::string exodus_filename(unsigned number)
void assemble_cd(EquationSystems &es, const std::string &system_name)
void init_cd(EquationSystems &es, const std::string &system_name)
std::ios_base::fmtflags flags() const
Get the associated format flags.
PeriodicBoundaries * get_periodic_boundaries()
Definition dof_map.h:1583
void add_periodic_boundary(const PeriodicBoundaryBase &periodic_boundary)
Adds a copy of the specified periodic boundary to the system.
This is the EquationSystems class.
The ErrorVector is a specialization of the StatisticsVector for error data computed on a finite eleme...
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.
This class implements writing meshes in the GMV format.
Definition gmv_io.h:48
bool use_unweighted_quadrature_rules
This boolean flag allows you to use "unweighted" quadrature rules (sized to exactly integrate unweigh...
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's jump error estimate formula to estimate the error on each cell...
This class implements the Kelly error indicator which is based on the flux jumps between elements.
The LibMeshInit class, when constructed, initializes the dependent libraries (e.g.
Definition libmesh.h:92
virtual void write(const std::string &name) const =0
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.
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:1755
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
Implements (adaptive) mesh refinement algorithms for a MeshBase.
The definition of a periodic boundary.
The ReplicatedMesh class is derived from the MeshBase class, and is used to store identical copies of...
This class defines a norm/seminorm to be applied to a NumericVector which contains coefficients in a ...
Definition system_norm.h:50
NumericVector< Number > * old_local_solution
All the values I need to compute my contribution to the simulation at hand.
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 init(triangulateio &t)
Initializes the fields of t to nullptr/0 as necessary.
SolverPackage default_solver_package()
Definition libmesh.C:1064
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
OStreamProxy out
VectorValue< Real > RealVectorValue
Useful typedefs to allow transparent switching between Real and Complex data types.
T command_line_next(std::string name, T default_value)
Use GetPot's search()/next() functions to get following arguments from the command line.
Definition libmesh.C:1025
static constexpr Real TOLERANCE
bool on_command_line(std::string arg)
Definition libmesh.C:934

References libMesh::DofMap::add_periodic_boundary(), libMesh::EquationSystems::add_system(), assemble_cd(), libMesh::MeshTools::Generation::build_square(), libMesh::MeshRefinement::coarsen_fraction(), libMesh::command_line_next(), libMesh::DECODE, libMesh::default_solver_package(), libMesh::ENCODE, libMesh::JumpErrorEstimator::estimate_error(), exodus_filename(), libMesh::FIRST, libMesh::MeshRefinement::flag_elements_by_error_fraction(), libMesh::BasicOStreamProxy< charT, traits >::flags(), libMesh::DofMap::get_periodic_boundaries(), libMesh::H1, libMesh::EquationSystems::init(), init_cd(), libMesh::INVALID_SOLVER_PACKAGE, libMesh::invalid_uint, main(), libMesh::MeshRefinement::max_h_level(), mesh, libMesh::PeriodicBoundaryBase::myboundary, libMesh::TransientSystem< Base >::old_local_solution, libMesh::on_command_line(), libMesh::out, libMesh::PeriodicBoundaryBase::pairedboundary, libMesh::EquationSystems::parameters, parsed_solution, libMesh::EquationSystems::print_info(), libMesh::MeshBase::print_info(), libMesh::QUAD4, libMesh::MeshBase::read(), libMesh::EquationSystems::read(), libMesh::Real, libMesh::MeshRefinement::refine_and_coarsen_elements(), libMesh::MeshRefinement::refine_fraction(), libMesh::EquationSystems::reinit(), libMesh::Parameters::set(), libMesh::MeshRefinement::set_periodic_boundaries_ptr(), libMesh::TOLERANCE, libMesh::TRILINOS_SOLVERS, libMesh::MeshRefinement::uniformly_refine(), libMesh::JumpErrorEstimator::use_unweighted_quadrature_rules, libMesh::MeshBase::write(), libMesh::EquationSystems::write(), libMesh::MeshOutput< MT >::write_equation_systems(), and libMesh::ExodusII_IO::write_equation_systems().

Variable Documentation

◆ parsed_solution

std::unique_ptr<FunctionBase<Number> > parsed_solution

Definition at line 116 of file adaptivity_ex5.C.

Referenced by init_cd(), and main().