libMesh
Loading...
Searching...
No Matches
adaptivity_ex2.C
Go to the documentation of this file.
1// The libMesh Finite Element Library.
2// Copyright (C) 2002-2026 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3
4// This library is free software; you can redistribute it and/or
5// modify it under the terms of the GNU Lesser General Public
6// License as published by the Free Software Foundation; either
7// version 2.1 of the License, or (at your option) any later version.
8
9// This library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12// Lesser General Public License for more details.
13
14// You should have received a copy of the GNU Lesser General Public
15// License along with this library; if not, write to the Free Software
16// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
18
19
20// <h1>Adaptivity Example 2 - Solving a Transient System with Adaptive Mesh Refinement</h1>
21// \author Benjamin S. Kirk
22// \date 2003
23//
24// This example shows how a simple, linear transient
25// system can be solved in parallel. The system is simple
26// scalar convection-diffusion with a specified external
27// velocity. The initial condition is given, and the
28// solution is advanced in time with a standard Crank-Nicolson
29// time-stepping strategy.
30//
31// Also, we use this example to demonstrate writing out and reading
32// in of solutions. We do 25 time steps, then save the solution
33// and do another 25 time steps starting from the saved solution.
34
35// C++ include files that we need
36#include <iostream>
37#include <algorithm>
38#include <cstdlib> // *must* precede <cmath> for proper std:abs() on PGI, Sun Studio CC
39#include <cmath>
40
41// Basic include file needed for the mesh functionality.
42#include "libmesh/libmesh.h"
43#include "libmesh/replicated_mesh.h"
44#include "libmesh/mesh_refinement.h"
45#include "libmesh/exodusII_io.h"
46#include "libmesh/equation_systems.h"
47#include "libmesh/fe.h"
48#include "libmesh/quadrature_gauss.h"
49#include "libmesh/dof_map.h"
50#include "libmesh/static_condensation.h"
51#include "libmesh/sparse_matrix.h"
52#include "libmesh/numeric_vector.h"
53#include "libmesh/dense_matrix.h"
54#include "libmesh/dense_vector.h"
55#include "libmesh/getpot.h"
56#include "libmesh/enum_solver_package.h"
57#include "libmesh/enum_xdr_mode.h"
58#include "libmesh/enum_norm_type.h"
59
60// This example will solve a linear transient system,
61// so we need to include the TransientLinearImplicitSystem definition.
62#include "libmesh/transient_system.h"
63#include "libmesh/linear_implicit_system.h"
64#include "libmesh/vector_value.h"
65
66// To refine the mesh we need an ErrorEstimator
67// object to figure out which elements to refine.
68#include "libmesh/error_vector.h"
69#include "libmesh/kelly_error_estimator.h"
70
71// The definition of a geometric element
72#include "libmesh/elem.h"
73
74// Bring in everything from the libMesh namespace
75using namespace libMesh;
76
77// Function prototype. This function will assemble the system
78// matrix and right-hand-side at each time step. Note that
79// since the system is linear we technically do not need to
80// assemble the matrix at each time step, but we will anyway.
81// In subsequent examples we will employ adaptive mesh refinement,
82// and with a changing mesh it will be necessary to rebuild the
83// system matrix.
84#ifdef LIBMESH_ENABLE_AMR
86 const std::string & system_name);
87#endif
88
89// Function prototype. This function will initialize the system.
90// Initialization functions are optional for systems. They allow
91// you to specify the initial values of the solution. If an
92// initialization function is not provided then the default (0)
93// solution is provided.
95 const std::string & system_name);
96
97// Exact solution function prototype. This gives the exact
98// solution as a function of space and time. In this case the
99// initial condition will be taken as the exact solution at time 0,
100// as will the Dirichlet boundary conditions at time t.
101Real exact_solution (const Real x,
102 const Real y,
103 const Real t);
104
106 const Parameters & parameters,
107 const std::string &,
108 const std::string &)
109{
110 return exact_solution(p(0), p(1), parameters.get<Real> ("time"));
111}
112
113
114
115// Begin the main program. Note that the first
116// statement in the program throws an error if
117// you are in complex number mode, since this
118// example is only intended to work with real
119// numbers.
120int main (int argc, char ** argv)
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.
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.
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}
486
487// Here we define the initialization routine for the
488// Convection-Diffusion system. This routine is
489// responsible for applying the initial conditions to
490// the system.
492 const std::string & libmesh_dbg_var(system_name))
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}
507
508
509
510// This function defines the assembly routine which
511// will be called at each time step. It is responsible
512// for computing the proper matrix entries for the
513// element stiffness matrices and right-hand sides.
514#ifdef LIBMESH_ENABLE_AMR
516 const std::string & libmesh_dbg_var(system_name))
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}
759#endif // #ifdef LIBMESH_ENABLE_AMR
Number exact_value(const Point &p, const Parameters &parameters, const std::string &, const std::string &)
void assemble_cd(EquationSystems &es, const std::string &system_name)
void init_cd(EquationSystems &es, const std::string &system_name)
unsigned int dim
Number(* exact_solution)(const Point &p, const Parameters &, const std::string &, const std::string &)
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
This is the EquationSystems class.
virtual void reinit()
Handle any mesh changes and reinitialize all the systems on the updated mesh.
void print_info(std::ostream &os=libMesh::out) const
Prints information about the equation systems, by default to libMesh::out.
void write(std::string_view name, const XdrMODE, const unsigned int write_flags=(WRITE_DATA), bool partition_agnostic=true) const
Write the systems to disk using the XDR data format.
void read(std::string_view name, const XdrMODE, const unsigned int read_flags=(READ_HEADER|READ_DATA), bool partition_agnostic=true)
Read & initialize the systems from disk using the XDR data format.
const MeshBase & get_mesh() const
Parameters parameters
Data structure holding arbitrary parameters.
virtual void init()
Initialize all the systems.
virtual System & add_system(std::string_view system_type, std::string_view name)
Add the system of type system_type named name to the systems array.
const T_sys & get_system(std::string_view name) const
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.
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
Order default_quadrature_order() const
Definition fe_type.h:415
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
This is the MeshBase class.
Definition mesh_base.h:81
unsigned int mesh_dimension() const
Definition mesh_base.C:430
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:1803
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
Implements (adaptive) mesh refinement algorithms for a MeshBase.
void uniformly_refine(unsigned int n=1)
Uniformly refines the mesh n times.
void flag_elements_by_error_fraction(const ErrorVector &error_per_cell, const Real refine_fraction=0.3, const Real coarsen_fraction=0.0, const unsigned int max_level=libMesh::invalid_uint)
Flags elements for coarsening and refinement based on the computed error passed in error_per_cell.
unsigned int & max_h_level()
The max_h_level is the greatest refinement level an element should reach.
bool refine_and_coarsen_elements()
Refines and coarsens user-requested elements.
Real & refine_fraction()
The refine_fraction sets either a desired target or a desired maximum number of elements to flag for ...
Real & coarsen_fraction()
The coarsen_fraction sets either a desired target or a desired maximum number of elements to flag for...
This class provides the ability to map between arbitrary, user-defined strings and several data types...
Definition parameters.h:75
T & set(const std::string &)
Definition parameters.h:494
const T & get(std::string_view) const
Definition parameters.h:451
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition point.h:40
unsigned int n_points() const
Definition quadrature.h:131
This class implements specific orders of Gauss quadrature.
The ReplicatedMesh class is derived from the MeshBase class, and is used to store identical copies of...
Generic sparse matrix.
This class defines a norm/seminorm to be applied to a NumericVector which contains coefficients in a ...
Definition system_norm.h:50
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
The libMesh namespace provides an interface to certain functionality in the library.
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
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
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
int main()
static const bool value
Definition xdr_io.C:55