deal.II version GIT relicensing-2173-gae8fc9d14b 2024-11-24 06:40:00+00:00
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
Loading...
Searching...
No Matches
advection_reaction_estimator.h
Go to the documentation of this file.
1
213 *  
214 *   #ifndef INCLUDE_DG_UPWIND_H_
215 *   #define INCLUDE_DG_UPWIND_H_
216 *  
217 *  
218 *   #include <deal.II/base/function.h>
219 *   #include <deal.II/base/quadrature_lib.h>
220 *  
221 *   #include <deal.II/dofs/dof_handler.h>
222 *   #include <deal.II/dofs/dof_tools.h>
223 *  
224 *   #include <deal.II/fe/fe_dgq.h>
225 *   #include <deal.II/fe/fe_q.h>
226 *   #include <deal.II/fe/fe_values.h>
227 *   #include <deal.II/fe/mapping_q1.h>
228 *  
229 *   #include <deal.II/grid/grid_generator.h>
230 *   #include <deal.II/grid/grid_out.h>
231 *   #include <deal.II/grid/grid_refinement.h>
232 *   #include <deal.II/grid/tria.h>
233 *  
234 *   #include <deal.II/lac/dynamic_sparsity_pattern.h>
235 *   #include <deal.II/lac/full_matrix.h>
236 *   #include <deal.II/lac/sparse_matrix.h>
237 *   #include <deal.II/lac/vector.h>
238 *  
239 *   #include <deal.II/numerics/data_out.h>
240 *   #include <deal.II/numerics/vector_tools.h>
241 * @endcode
242 *
243 * This header is needed for FEInterfaceValues to compute integrals on
244 * interfaces:
245 *
246 * @code
247 *   #include <deal.II/fe/fe_interface_values.h>
248 * @endcode
249 *
250 * Solver
251 *
252 * @code
253 *   #include <deal.II/lac/precondition_block.h>
254 *   #include <deal.II/lac/solver_richardson.h>
255 *   #include <deal.II/lac/sparse_direct.h>
256 * @endcode
257 *
258 * We are going to use gradients as refinement indicator.
259 *
260 * @code
261 *   #include <deal.II/numerics/derivative_approximation.h>
262 * @endcode
263 *
264 * Using using the mesh_loop from the MeshWorker framework
265 *
266 * @code
267 *   #include <deal.II/base/convergence_table.h>
268 *  
269 *   #include <deal.II/meshworker/mesh_loop.h>
270 *  
271 * @endcode
272 *
273 * To enable parameter handling
274 *
275 * @code
276 *   #include <deal.II/base/function_parser.h>
277 *   #include <deal.II/base/parameter_acceptor.h>
278 *   #include <deal.II/base/parameter_handler.h>
279 *   #include <deal.II/base/parsed_convergence_table.h>
280 *   #include <deal.II/base/symbolic_function.h>
281 *  
282 *   #include <deal.II/meshworker/copy_data.h>
283 *   #include <deal.II/meshworker/mesh_loop.h>
284 *   #include <deal.II/meshworker/scratch_data.h>
285 *  
286 *   #include <fstream>
287 *   #include <iostream>
288 *   using namespace dealii;
289 *  
290 * @endcode
291 *
292 * This is a struct used only for throwing an exception when theta parameter is
293 * not okay.
294 *
295 * @code
296 *   struct theta_exc
297 *   {
298 *   std::string message;
299 *   theta_exc(std::string &&s)
300 *   : message{std::move(s)} {};
301 *   const char *
302 *   what() const
303 *   {
304 *   return message.c_str();
305 *   }
306 *   };
307 *  
308 *  
309 *   template <int dim>
310 *   class AdvectionReaction : ParameterAcceptor
311 *   {
312 *   public:
313 *   AdvectionReaction();
314 *   void
315 *   initialize_params(const std::string &filename);
316 *   void
317 *   run();
318 *  
319 *   private:
320 *   using Iterator = typename DoFHandler<dim>::active_cell_iterator;
321 *   void
322 *   parse_string(const std::string &parameters);
323 *   void
324 *   setup_system();
325 *   void
326 *   assemble_system();
327 *   void
328 *   solve();
329 *   void
330 *   refine_grid();
331 *   void
332 *   output_results(const unsigned int cycle) const;
333 *   void
334 *   compute_error();
335 *   double
336 *   compute_energy_norm();
337 *   void
338 *   compute_local_projection_and_estimate();
339 *  
341 *   const MappingQ1<dim> mapping;
342 *  
343 * @endcode
344 *
345 * Furthermore we want to use DG elements.
346 *
347 * @code
348 *   std::unique_ptr<FE_DGQ<dim>> fe;
349 *   DoFHandler<dim> dof_handler;
350 *  
351 *   SparsityPattern sparsity_pattern;
352 *   SparseMatrix<double> system_matrix;
353 *  
354 *   Vector<double> solution;
355 *   Vector<double> right_hand_side;
356 *   Vector<double> energy_norm_square_per_cell;
357 *   Vector<double> error_indicator_per_cell;
358 *  
359 * @endcode
360 *
361 * So far we declared the usual objects. Hereafter we declare
362 * `FunctionParser<dim>` objects
363 *
364 * @code
365 *   FunctionParser<dim> exact_solution;
366 *   FunctionParser<dim> boundary_conditions;
367 *   FunctionParser<dim> rhs;
368 *   FunctionParser<dim> advection_coeff;
369 *  
370 *   unsigned int fe_degree = 1;
371 *  
372 * @endcode
373 *
374 * and then we define default values that will be parsed from the following
375 * strings
376 *
377 * @code
378 *   std::string exact_solution_expression =
379 *   "tanh(100*(x+y-0.5))"; // internal layer solution
380 *   std::string rhs_expression =
381 *   "-200*tanh(100*x + 100*y - 50.0)^2 + tanh(100*x + 100*y - 50.0) + 200";
382 *   std::string advection_coefficient_expression = "1.0";
383 *   std::string boundary_conditions_expression = "tanh(100*x + 100*y - 50.0)";
384 *   std::string refinement = "residual";
385 *   std::string output_filename = "DG_advection_reaction_estimator";
386 *   std::map<std::string, double> constants;
387 *   ParsedConvergenceTable error_table;
388 *  
389 *   bool use_direct_solver = true;
390 *   unsigned int n_refinement_cycles = 8;
391 *   unsigned int n_global_refinements = 3;
392 *   double theta = 0.5; // default is 0.5 so that I have classical upwind flux
393 *   };
394 *  
395 *   #endif /* INCLUDE_DG_UPWIND_H_ */
396 * @endcode
397
398
399<a name="ann-main.cc"></a>
400<h1>Annotated version of main.cc</h1>
401 *
402 *
403 *
404 *
405 * @code
406 *   /* -----------------------------------------------------------------------------
407 *   *
408 *   * SPDX-License-Identifier: LGPL-2.1-or-later
409 *   * Copyright (C) 2015 by Marco Feder
410 *   *
411 *   * This file is part of the deal.II code gallery.
412 *   *
413 *   * -----------------------------------------------------------------------------
414 *   */
415 *  
416 *   #include "include/DG_advection_reaction.h"
417 *  
418 *   int
419 *   main(int argc, char **argv)
420 *   {
421 *   try
422 *   {
423 *   std::string par_name = "";
424 *   if (argc > 1)
425 *   {
426 *   par_name = argv[1];
427 *   }
428 *   else
429 *   {
430 *   par_name = "parameters.prm";
431 *   }
432 *   deallog.depth_console(2);
433 *   AdvectionReaction<2> problem;
434 *   problem.initialize_params(par_name);
435 *   problem.run();
436 *   }
437 *   catch (std::exception &exc)
438 *   {
439 *   std::cerr << std::endl
440 *   << std::endl
441 *   << "----------------------------------------------------"
442 *   << std::endl;
443 *   std::cerr << "Exception on processing: " << std::endl
444 *   << exc.what() << std::endl
445 *   << "Aborting!" << std::endl
446 *   << "----------------------------------------------------"
447 *   << std::endl;
448 *   return 1;
449 *   }
450 *   catch (const theta_exc &theta_range)
451 *   {
452 *   std::cerr << std::endl
453 *   << std::endl
454 *   << "----------------------------------------------------"
455 *   << std::endl;
456 *   std::cerr << "Exception on processing: " << std::endl
457 *   << theta_range.what() << std::endl
458 *   << "Aborting!" << std::endl
459 *   << "----------------------------------------------------"
460 *   << std::endl;
461 *   return 1;
462 *   }
463 *   catch (...)
464 *   {
465 *   std::cerr << std::endl
466 *   << std::endl
467 *   << "----------------------------------------------------"
468 *   << std::endl;
469 *   std::cerr << "Unknown exception!" << std::endl
470 *   << "Aborting!" << std::endl
471 *   << "----------------------------------------------------"
472 *   << std::endl;
473 *   return 1;
474 *   }
475 *  
476 *   return 0;
477 *   }
478 * @endcode
479
480
481<a name="ann-source/DG_advection_reaction.cc"></a>
482<h1>Annotated version of source/DG_advection_reaction.cc</h1>
483 *
484 *
485 *
486 *
487 * @code
488 *   /* -----------------------------------------------------------------------------
489 *   *
490 *   * SPDX-License-Identifier: LGPL-2.1-or-later
491 *   * Copyright (C) 2015 by Marco Feder
492 *   *
493 *   * This file is part of the deal.II code gallery.
494 *   *
495 *   * -----------------------------------------------------------------------------
496 *   */
497 *  
498 *   #include "../include/DG_advection_reaction.h"
499 *  
500 * @endcode
501 *
502 * Compute and returns the wind field b
503 *
504 * @code
505 *   template <int dim>
506 *   Tensor<1, dim>
507 *   beta(const Point<dim> &p)
508 *   {
509 *   Assert(dim > 1, ExcNotImplemented());
510 *   (void)p; // suppress warnings from p
511 *   Tensor<1, dim> wind_field;
512 *   wind_field[0] = 1.0;
513 *   wind_field[1] = 1.0;
514 *  
515 *   return wind_field;
516 *   }
517 *  
518 * @endcode
519 *
520 *
521 * <a name="source/DG_advection_reaction.cc-TheScratchDataandCopyDataclasses"></a>
522 * <h3>The ScratchData and CopyData classes</h3>
523 *
524
525 *
526 * The following objects are the scratch and copy objects we use in the call
527 * to MeshWorker::mesh_loop(). The new object is the FEInterfaceValues object,
528 * that works similar to FEValues or FEFacesValues, except that it acts on
529 * an interface between two cells and allows us to assemble the interface
530 * terms in our weak form.
531 *
532 * @code
533 *   template <int dim>
534 *   struct ScratchData
535 *   {
536 *   ScratchData(const Mapping<dim> &mapping,
537 *   const FiniteElement<dim> &fe,
538 *   const Quadrature<dim> &quadrature,
539 *   const Quadrature<dim - 1> &quadrature_face,
540 *   const UpdateFlags update_flags = update_values |
541 *   update_gradients |
544 *   const UpdateFlags interface_update_flags =
547 *   : fe_values(mapping, fe, quadrature, update_flags)
548 *   , fe_interface_values(mapping, fe, quadrature_face, interface_update_flags)
549 *   {}
550 *  
551 *   ScratchData(const ScratchData<dim> &scratch_data)
552 *   : fe_values(scratch_data.fe_values.get_mapping(),
553 *   scratch_data.fe_values.get_fe(),
554 *   scratch_data.fe_values.get_quadrature(),
555 *   scratch_data.fe_values.get_update_flags())
556 *   , fe_interface_values(scratch_data.fe_interface_values.get_mapping(),
557 *   scratch_data.fe_interface_values.get_fe(),
558 *   scratch_data.fe_interface_values.get_quadrature(),
559 *   scratch_data.fe_interface_values.get_update_flags())
560 *   {}
561 *  
562 *   FEValues<dim> fe_values;
563 *   FEInterfaceValues<dim> fe_interface_values;
564 *   };
565 *  
566 *  
567 *  
568 *   struct CopyDataFace
569 *   {
571 *   std::vector<types::global_dof_index> joint_dof_indices;
572 *   std::array<double, 2> values;
573 *   std::array<unsigned int, 2> cell_indices;
574 *   };
575 *  
576 *  
577 *  
578 *   struct CopyData
579 *   {
581 *   Vector<double> cell_rhs;
582 *   std::vector<types::global_dof_index> local_dof_indices;
583 *   std::vector<CopyDataFace> face_data;
584 *  
585 *   double value;
586 *   double value_estimator;
587 *   unsigned int cell_index;
588 *  
589 *   FullMatrix<double> cell_mass_matrix;
590 *   Vector<double> cell_mass_rhs;
591 *  
592 *   template <class Iterator>
593 *   void
594 *   reinit(const Iterator &cell, unsigned int dofs_per_cell)
595 *   {
596 *   cell_matrix.reinit(dofs_per_cell, dofs_per_cell);
597 *   cell_mass_matrix.reinit(dofs_per_cell, dofs_per_cell);
598 *  
599 *   cell_rhs.reinit(dofs_per_cell);
600 *   cell_mass_rhs.reinit(dofs_per_cell);
601 *  
602 *   local_dof_indices.resize(dofs_per_cell);
603 *   cell->get_dof_indices(local_dof_indices);
604 *   }
605 *   };
606 *  
607 *  
608 *  
609 * @endcode
610 *
611 *
612 * <a name="source/DG_advection_reaction.cc-Auxiliaryfunction"></a>
613 * <h3>Auxiliary function</h3>
614 * This auxiliary function is taken from @ref step_74 "step-74" and it's used to
615 * compute the jump of the finite element function @f$u_h@f$ on a face.
616 *
617 * @code
618 *   template <int dim>
619 *   void
620 *   get_function_jump(const FEInterfaceValues<dim> &fe_iv,
621 *   const Vector<double> &solution,
622 *   std::vector<double> &jump)
623 *   {
624 *   const unsigned int n_q = fe_iv.n_quadrature_points;
625 *   std::array<std::vector<double>, 2> face_values;
626 *   jump.resize(n_q);
627 *   for (unsigned int i = 0; i < 2; ++i)
628 *   {
629 *   face_values[i].resize(n_q);
630 *   fe_iv.get_fe_face_values(i).get_function_values(solution, face_values[i]);
631 *   }
632 *   for (unsigned int q = 0; q < n_q; ++q)
633 *   jump[q] = face_values[0][q] - face_values[1][q];
634 *   }
635 *  
636 *  
637 *  
638 *   template <int dim>
639 *   AdvectionReaction<dim>::AdvectionReaction()
640 *   : mapping()
641 *   , dof_handler(triangulation)
642 *   {
643 *   Assert(dim > 1, ExcMessage("Not implemented in 1D."));
644 *   add_parameter("Finite element degree", fe_degree);
645 *   add_parameter("Problem constants", constants);
646 *   add_parameter("Output filename", output_filename);
647 *   add_parameter("Use direct solver", use_direct_solver);
648 *   add_parameter("Number of refinement cycles", n_refinement_cycles);
649 *   add_parameter("Number of global refinement", n_global_refinements);
650 *   add_parameter("Refinement", refinement);
651 *   add_parameter("Exact solution expression", exact_solution_expression);
652 *   add_parameter("Boundary conditions expression",
653 *   boundary_conditions_expression);
654 *   add_parameter("Theta", theta);
655 *   add_parameter("Advection coefficient expression",
656 *   advection_coefficient_expression);
657 *   add_parameter("Right hand side expression", rhs_expression);
658 *  
659 *   this->prm.enter_subsection("Error table");
660 *   error_table.add_parameters(this->prm);
661 *   this->prm.leave_subsection();
662 *   }
663 *  
664 *  
665 *  
666 *   template <int dim>
667 *   void
668 *   AdvectionReaction<dim>::initialize_params(const std::string &filename)
669 *   {
670 *   ParameterAcceptor::initialize(filename,
671 *   "last_used_parameters.prm",
672 *   ParameterHandler::Short);
673 *   if (theta < 0.0 || theta > 10.0 || std::abs(theta) < 1e-12)
674 *   {
675 *   throw(
676 *   theta_exc("Theta parameter is not in a suitable range: see paper by "
677 *   "Brezzi, Marini, Suli for an extended discussion"));
678 *   }
679 *   }
680 *  
681 *  
682 *  
683 *   template <int dim>
684 *   void
685 *   AdvectionReaction<dim>::parse_string(const std::string &parameters)
686 *   {
687 *   ParameterAcceptor::prm.parse_input_from_string(parameters);
688 *   ParameterAcceptor::parse_all_parameters();
689 *   }
690 *  
691 *  
692 *  
693 *   template <int dim>
694 *   void
695 *   AdvectionReaction<dim>::setup_system()
696 *   {
697 * @endcode
698 *
699 * first need to distribute the DoFs.
700 *
701 * @code
702 *   if (!fe)
703 *   {
704 *   fe = std::make_unique<FE_DGQ<dim>>(fe_degree);
705 *   const auto vars = dim == 2 ? "x,y" : "x,y,z";
706 *   exact_solution.initialize(vars, exact_solution_expression, constants);
707 *   rhs.initialize(vars, rhs_expression, constants);
708 *   advection_coeff.initialize(vars,
709 *   advection_coefficient_expression,
710 *   constants);
711 *   boundary_conditions.initialize(vars,
712 *   boundary_conditions_expression,
713 *   constants);
714 *   }
715 *   dof_handler.distribute_dofs(*fe);
716 *  
717 * @endcode
718 *
719 * To build the sparsity pattern for DG discretizations, we can call the
720 * function analogue to DoFTools::make_sparsity_pattern, which is called
721 * DoFTools::make_flux_sparsity_pattern:
722 *
723 * @code
724 *   DynamicSparsityPattern dsp(dof_handler.n_dofs());
725 *   DoFTools::make_flux_sparsity_pattern(dof_handler,
726 *   dsp); // DG sparsity pattern generator
727 *   sparsity_pattern.copy_from(dsp);
728 *  
729 * @endcode
730 *
731 * Finally, we set up the structure of all components of the linear system.
732 *
733 * @code
734 *   system_matrix.reinit(sparsity_pattern);
735 *   solution.reinit(dof_handler.n_dofs());
736 *   right_hand_side.reinit(dof_handler.n_dofs());
737 *   }
738 *  
739 *  
740 *  
741 * @endcode
742 *
743 * in the call to MeshWorker::mesh_loop() we only need to specify what should
744 * happen on
745 * each cell, each boundary face, and each interior face. These three tasks
746 * are handled by the lambda functions inside the function below.
747 *
748
749 *
750 *
751 * @code
752 *   template <int dim>
753 *   void
754 *   AdvectionReaction<dim>::assemble_system()
755 *   {
756 *   using Iterator = typename DoFHandler<dim>::active_cell_iterator;
757 *  
758 *   const QGauss<dim> quadrature = fe->tensor_degree() + 1;
759 *   const QGauss<dim - 1> quadrature_face = fe->tensor_degree() + 1;
760 *  
761 * @endcode
762 *
763 * This is the function that will be executed for each cell.
764 *
765 * @code
766 *   const auto cell_worker = [&](const Iterator &cell,
767 *   ScratchData<dim> &scratch_data,
768 *   CopyData &copy_data) {
769 *   FEValues<dim> fe_values_continuous(*fe,
770 *   quadrature,
771 *   update_values | update_gradients |
772 *   update_quadrature_points |
773 *   update_JxW_values);
774 *  
775 *   const unsigned int n_dofs =
776 *   scratch_data.fe_values.get_fe().n_dofs_per_cell();
777 *   copy_data.reinit(cell, n_dofs);
778 *   scratch_data.fe_values.reinit(cell);
779 *  
780 *   const auto &q_points = scratch_data.fe_values.get_quadrature_points();
781 *  
782 *   const FEValues<dim> &fe_v = scratch_data.fe_values;
783 *   const std::vector<double> &JxW = fe_v.get_JxW_values();
784 *  
785 *   for (unsigned int point = 0; point < fe_v.n_quadrature_points; ++point)
786 *   {
787 *   auto beta_q = beta(q_points[point]);
788 *   for (unsigned int i = 0; i < n_dofs; ++i)
789 *   {
790 *   for (unsigned int j = 0; j < n_dofs; ++j)
791 *   {
792 *   copy_data.cell_matrix(i, j) +=
793 *   (-beta_q // -\beta
794 *   * fe_v.shape_grad(i, point) // \nabla \phi_i
795 *   * fe_v.shape_value(j, point) // \phi_j
796 *   + advection_coeff.value(q_points[point]) * // gamma
797 *   fe_v.shape_value(i, point) // phi_i
798 *   * fe_v.shape_value(j, point) // phi_j
799 *   ) *
800 *   JxW[point]; // dx
801 *   }
802 *   copy_data.cell_rhs(i) += rhs.value(q_points[point]) // f(x_q)
803 *   * fe_v.shape_value(i, point) // phi_i(x_q)
804 *   * JxW[point]; // dx
805 *   }
806 *   }
807 *   };
808 *  
809 * @endcode
810 *
811 * This is the function called for boundary faces and consists of a normal
812 * integration using FEFaceValues. New is the logic to decide if the term
813 * goes into the system matrix (outflow) or the right-hand side (inflow).
814 *
815 * @code
816 *   const auto boundary_worker = [&](const Iterator &cell,
817 *   const unsigned int &face_no,
818 *   ScratchData<dim> &scratch_data,
819 *   CopyData &copy_data) {
820 *   scratch_data.fe_interface_values.reinit(cell, face_no);
821 *   const FEFaceValuesBase<dim> &fe_face =
822 *   scratch_data.fe_interface_values.get_fe_face_values(0);
823 *  
824 *   const auto &q_points = fe_face.get_quadrature_points();
825 *  
826 *   const unsigned int n_facet_dofs = fe_face.get_fe().n_dofs_per_cell();
827 *   const std::vector<double> &JxW = fe_face.get_JxW_values();
828 *   const std::vector<Tensor<1, dim>> &normals = fe_face.get_normal_vectors();
829 *  
830 *   std::vector<double> g(q_points.size());
831 *   exact_solution.value_list(q_points, g);
832 *  
833 *   for (unsigned int point = 0; point < q_points.size(); ++point)
834 *   {
835 *   const double beta_dot_n = beta(q_points[point]) * normals[point];
836 *  
837 *   if (beta_dot_n > 0)
838 *   {
839 *   for (unsigned int i = 0; i < n_facet_dofs; ++i)
840 *   for (unsigned int j = 0; j < n_facet_dofs; ++j)
841 *   copy_data.cell_matrix(i, j) +=
842 *   fe_face.shape_value(i,
843 *   point) // \phi_i
844 *   * fe_face.shape_value(j, point) // \phi_j
845 *   * beta_dot_n // \beta . n
846 *   * JxW[point]; // dx
847 *   }
848 *   else
849 *   for (unsigned int i = 0; i < n_facet_dofs; ++i)
850 *   copy_data.cell_rhs(i) += -fe_face.shape_value(i, point) // \phi_i
851 *   * g[point] // g*/
852 *   * beta_dot_n // \beta . n
853 *   * JxW[point]; // dx
854 *   }
855 *   };
856 *  
857 * @endcode
858 *
859 * This is the function called on interior faces. The arguments specify
860 * cells, face and subface indices (for adaptive refinement). We just pass
861 * them along to the reinit() function of FEInterfaceValues.
862 *
863 * @code
864 *   const auto face_worker = [&](const Iterator &cell,
865 *   const unsigned int &f,
866 *   const unsigned int &sf,
867 *   const Iterator &ncell,
868 *   const unsigned int &nf,
869 *   const unsigned int &nsf,
870 *   ScratchData<dim> &scratch_data,
871 *   CopyData &copy_data) {
872 *   FEInterfaceValues<dim> &fe_iv = scratch_data.fe_interface_values;
873 *   fe_iv.reinit(cell, f, sf, ncell, nf, nsf);
874 *   const auto &q_points = fe_iv.get_quadrature_points();
875 *  
876 *   copy_data.face_data.emplace_back();
877 *   CopyDataFace &copy_data_face = copy_data.face_data.back();
878 *  
879 *   const unsigned int n_dofs = fe_iv.n_current_interface_dofs();
880 *   copy_data_face.joint_dof_indices = fe_iv.get_interface_dof_indices();
881 *  
882 *   copy_data_face.cell_matrix.reinit(n_dofs, n_dofs);
883 *  
884 *   const std::vector<double> &JxW = fe_iv.get_JxW_values();
885 *   const std::vector<Tensor<1, dim>> &normals = fe_iv.get_normal_vectors();
886 *  
887 *   for (unsigned int qpoint = 0; qpoint < q_points.size(); ++qpoint)
888 *   {
889 *   const double beta_dot_n = beta(q_points[qpoint]) * normals[qpoint];
890 *   for (unsigned int i = 0; i < n_dofs; ++i)
891 *   {
892 *   for (unsigned int j = 0; j < n_dofs; ++j)
893 *   {
894 *   copy_data_face.cell_matrix(i, j) +=
895 *   (beta(q_points[qpoint]) * normals[qpoint] *
896 *   fe_iv.average_of_shape_values(j, qpoint) *
897 *   fe_iv.jump_in_shape_values(i, qpoint) +
898 *   theta * std::abs(beta_dot_n) *
899 *   fe_iv.jump_in_shape_values(j, qpoint) *
900 *   fe_iv.jump_in_shape_values(i, qpoint)) *
901 *   JxW[qpoint];
902 *   }
903 *   }
904 *   }
905 *   };
906 *  
907 * @endcode
908 *
909 * The following lambda function will handle copying the data from the
910 * cell and face assembly into the global matrix and right-hand side.
911 *
912
913 *
914 * While we would not need an AffineConstraints object, because there are
915 * no hanging node constraints in DG discretizations, we use an empty
916 * object here as this allows us to use its `copy_local_to_global`
917 * functionality.
918 *
919 * @code
920 *   const AffineConstraints<double> constraints;
921 *  
922 *   const auto copier = [&](const CopyData &c) {
923 *   constraints.distribute_local_to_global(c.cell_matrix,
924 *   c.cell_rhs,
925 *   c.local_dof_indices,
926 *   system_matrix,
927 *   right_hand_side);
928 *  
929 *   for (auto &cdf : c.face_data)
930 *   {
931 *   constraints.distribute_local_to_global(cdf.cell_matrix,
932 *   cdf.joint_dof_indices,
933 *   system_matrix);
934 *   }
935 *   };
936 *  
937 *   ScratchData<dim> scratch_data(mapping, *fe, quadrature, quadrature_face);
938 *   CopyData copy_data;
939 *  
940 * @endcode
941 *
942 * Here, we finally handle the assembly. We pass in ScratchData and
943 * CopyData objects, the lambda functions from above, an specify that we
944 * want to assemble interior faces once.
945 *
946 * @code
947 *   MeshWorker::mesh_loop(dof_handler.begin_active(),
948 *   dof_handler.end(),
949 *   cell_worker,
950 *   copier,
951 *   scratch_data,
952 *   copy_data,
953 *   MeshWorker::assemble_own_cells |
954 *   MeshWorker::assemble_boundary_faces |
955 *   MeshWorker::assemble_own_interior_faces_once,
956 *   boundary_worker,
957 *   face_worker);
958 *   }
959 *  
960 *  
961 *  
962 *   template <int dim>
963 *   void
964 *   AdvectionReaction<dim>::solve()
965 *   {
966 *   if (use_direct_solver)
967 *   {
968 *   SparseDirectUMFPACK system_matrix_inverse;
969 *   system_matrix_inverse.initialize(system_matrix);
970 *   system_matrix_inverse.vmult(solution, right_hand_side);
971 *   }
972 *   else
973 *   {
974 * @endcode
975 *
976 * Here we have a classic iterative solver, as done in many tutorials:
977 *
978 * @code
979 *   SolverControl solver_control(1000, 1e-15);
980 *   SolverRichardson<Vector<double>> solver(solver_control);
981 *   PreconditionBlockSSOR<SparseMatrix<double>> preconditioner;
982 *   preconditioner.initialize(system_matrix, fe->n_dofs_per_cell());
983 *   solver.solve(system_matrix, solution, right_hand_side, preconditioner);
984 *   std::cout << " Solver converged in " << solver_control.last_step()
985 *   << " iterations." << std::endl;
986 *   }
987 *   }
988 *  
989 *  
990 *  
991 * @endcode
992 *
993 *
994 * <a name="source/DG_advection_reaction.cc-Meshrefinement"></a>
995 * <h3>Mesh refinement</h3>
996 * We refine the grid according the proposed estimator or with an approximation
997 * to the gradient of the solution. The first option is the default one (you can
998 * see it in the header file)
999 *
1000 * @code
1001 *   template <int dim>
1002 *   void
1003 *   AdvectionReaction<dim>::refine_grid()
1004 *   {
1005 *   if (refinement == "residual")
1006 *   {
1007 * @endcode
1008 *
1009 * If the `refinement` string is `"residual"`, then we first compute the
1010 * local projection
1011 *
1012 * @code
1013 *   compute_local_projection_and_estimate();
1014 * @endcode
1015 *
1016 * We then set the refinement fraction and as usual we execute the
1017 * refinement.
1018 *
1019 * @code
1020 *   const double refinement_fraction = 0.6;
1021 *   GridRefinement::refine_and_coarsen_fixed_fraction(
1022 *   triangulation, error_indicator_per_cell, refinement_fraction, 0.0);
1023 *   triangulation.execute_coarsening_and_refinement();
1024 *   }
1025 *   else if (refinement == "gradient")
1026 *   {
1027 *   Vector<float> gradient_indicator(triangulation.n_active_cells());
1028 *  
1029 * @endcode
1030 *
1031 * Now the approximate gradients are computed
1032 *
1033 * @code
1034 *   DerivativeApproximation::approximate_gradient(mapping,
1035 *   dof_handler,
1036 *   solution,
1037 *   gradient_indicator);
1038 *  
1039 * @endcode
1040 *
1041 * and they are cell-wise scaled by the factor @f$h^{1+d/2}@f$
1042 *
1043 * @code
1044 *   unsigned int cell_no = 0;
1045 *   for (const auto &cell : dof_handler.active_cell_iterators())
1046 *   gradient_indicator(cell_no++) *=
1047 *   std::pow(cell->diameter(), 1 + 1.0 * dim / 2);
1048 *  
1049 * @endcode
1050 *
1051 * Finally they serve as refinement indicator.
1052 *
1053 * @code
1054 *   GridRefinement::refine_and_coarsen_fixed_fraction(triangulation,
1055 *   gradient_indicator,
1056 *   0.25,
1057 *   0.0);
1058 *  
1059 *   triangulation.execute_coarsening_and_refinement();
1060 *   std::cout << gradient_indicator.l2_norm() << '\n';
1061 *   }
1062 *   else if (refinement == "global")
1063 *   {
1064 *   triangulation.refine_global(
1065 *   1); // just for testing on uniformly refined meshes
1066 *   }
1067 *   else
1068 *   {
1069 *   Assert(false, ExcInternalError());
1070 *   }
1071 *   }
1072 *  
1073 *  
1074 *  
1075 * @endcode
1076 *
1077 * The output of this program consists of a vtk file of the adaptively
1078 * refined grids and the numerical solutions.
1079 *
1080 * @code
1081 *   template <int dim>
1082 *   void
1083 *   AdvectionReaction<dim>::output_results(const unsigned int cycle) const
1084 *   {
1085 *   const std::string filename = "solution-" + std::to_string(cycle) + ".vtk";
1086 *   std::cout << " Writing solution to <" << filename << ">" << std::endl;
1087 *   std::ofstream output(filename);
1088 *  
1089 *   DataOut<dim> data_out;
1090 *   data_out.attach_dof_handler(dof_handler);
1091 *   data_out.add_data_vector(solution, "u", DataOut<dim>::type_dof_data);
1092 *   data_out.build_patches(mapping);
1093 *   data_out.write_vtk(output);
1094 *   }
1095 *  
1096 *   template <int dim>
1097 *   void
1098 *   AdvectionReaction<dim>::compute_error()
1099 *   {
1100 *   error_table.error_from_exact(
1101 *   mapping,
1102 *   dof_handler,
1103 *   solution,
1104 *   exact_solution); // be careful: a FD approximation of the gradient is used
1105 * @endcode
1106 *
1107 * to compute the H^1 norm if Solution<dim> doesn't
1108 * implements the Gradient function
1109 *
1110 * @code
1111 *   }
1112 *  
1113 *  
1114 *  
1115 * @endcode
1116 *
1117 *
1118 * <a name="source/DG_advection_reaction.cc-Computetheenergynorm"></a>
1119 * <h3>Compute the energy norm</h3>
1120 * The energy norm is defined as @f$ |||\cdot ||| = \Bigl(||\cdot||_{0,\Omega}^2 +
1121 * \sum_{F \in \mathbb{F}}||c_F^{\frac{1}{2}}[\cdot] ||_{0,F}^2
1122 * \Bigr)^{\frac{1}{2}}@f$ Notice that in the current case we have @f$c_f = \frac{|b
1123 * \cdot n|}{2}@f$ Like in the assembly, all the contributions are handled
1124 * separately by using ScratchData and CopyData objects.
1125 *
1126 * @code
1127 *   template <int dim>
1128 *   double
1129 *   AdvectionReaction<dim>::compute_energy_norm()
1130 *   {
1131 *   energy_norm_square_per_cell.reinit(triangulation.n_active_cells());
1132 *  
1133 *   using Iterator = typename DoFHandler<dim>::active_cell_iterator;
1134 *  
1135 * @endcode
1136 *
1137 * We start off by adding cell contributions
1138 *
1139 * @code
1140 *   const auto cell_worker = [&](const Iterator &cell,
1141 *   ScratchData<dim> &scratch_data,
1142 *   CopyData &copy_data) {
1143 *   const unsigned int n_dofs =
1144 *   scratch_data.fe_values.get_fe().n_dofs_per_cell();
1145 *   copy_data.reinit(cell, n_dofs);
1146 *   scratch_data.fe_values.reinit(cell);
1147 *  
1148 *   copy_data.cell_index = cell->active_cell_index();
1149 *  
1150 *   const auto &q_points = scratch_data.fe_values.get_quadrature_points();
1151 *   const FEValues<dim> &fe_v = scratch_data.fe_values;
1152 *   const std::vector<double> &JxW = fe_v.get_JxW_values();
1153 *  
1154 *   double error_square_norm{0.0};
1155 *   std::vector<double> sol_u(fe_v.n_quadrature_points);
1156 *   fe_v.get_function_values(solution, sol_u);
1157 *  
1158 *   for (unsigned int point = 0; point < fe_v.n_quadrature_points; ++point)
1159 *   {
1160 *   const double diff =
1161 *   (sol_u[point] - exact_solution.value(q_points[point]));
1162 *   error_square_norm += diff * diff * JxW[point];
1163 *   }
1164 *   copy_data.value = error_square_norm;
1165 *   };
1166 *  
1167 * @endcode
1168 *
1169 * Here we add contributions coming from the internal faces
1170 *
1171 * @code
1172 *   const auto face_worker = [&](const Iterator &cell,
1173 *   const unsigned int &f,
1174 *   const unsigned int &sf,
1175 *   const Iterator &ncell,
1176 *   const unsigned int &nf,
1177 *   const unsigned int &nsf,
1178 *   ScratchData<dim> &scratch_data,
1179 *   CopyData &copy_data) {
1180 *   FEInterfaceValues<dim> &fe_iv = scratch_data.fe_interface_values;
1181 *   fe_iv.reinit(cell, f, sf, ncell, nf, nsf);
1182 *  
1183 *   copy_data.face_data.emplace_back();
1184 *   CopyDataFace &copy_data_face = copy_data.face_data.back();
1185 *   copy_data_face.cell_indices[0] = cell->active_cell_index();
1186 *   copy_data_face.cell_indices[1] = ncell->active_cell_index();
1187 *  
1188 *   const auto &q_points = fe_iv.get_quadrature_points();
1189 *   const unsigned n_q_points = q_points.size();
1190 *   const std::vector<double> &JxW = fe_iv.get_JxW_values();
1191 *   std::vector<double> g(n_q_points);
1192 *  
1193 *   std::vector<double> jump(n_q_points);
1194 *   get_function_jump(fe_iv, solution, jump);
1195 *  
1196 *   const std::vector<Tensor<1, dim>> &normals = fe_iv.get_normal_vectors();
1197 *  
1198 *   double error_jump_square{0.0};
1199 *   for (unsigned int point = 0; point < n_q_points; ++point)
1200 *   {
1201 *   const double beta_dot_n =
1202 *   theta * std::abs(beta(q_points[point]) * normals[point]);
1203 *   error_jump_square +=
1204 *   beta_dot_n * jump[point] * jump[point] * JxW[point];
1205 *   }
1206 *  
1207 *   copy_data.value = error_jump_square;
1208 *   };
1209 *  
1210 * @endcode
1211 *
1212 * Finally, we add the boundary contributions
1213 *
1214 * @code
1215 *   const auto boundary_worker = [&](const Iterator &cell,
1216 *   const unsigned int &face_no,
1217 *   ScratchData<dim> &scratch_data,
1218 *   CopyData &copy_data) {
1219 *   scratch_data.fe_interface_values.reinit(cell, face_no);
1220 *   const FEFaceValuesBase<dim> &fe_fv =
1221 *   scratch_data.fe_interface_values.get_fe_face_values(0);
1222 *   const auto &q_points = fe_fv.get_quadrature_points();
1223 *   const unsigned n_q_points = q_points.size();
1224 *   const std::vector<double> &JxW = fe_fv.get_JxW_values();
1225 *  
1226 *   std::vector<double> g(n_q_points);
1227 *  
1228 *   std::vector<double> sol_u(n_q_points);
1229 *   fe_fv.get_function_values(solution, sol_u);
1230 *  
1231 *   const std::vector<Tensor<1, dim>> &normals = fe_fv.get_normal_vectors();
1232 *  
1233 *   double difference_norm_square = 0.;
1234 *   for (unsigned int point = 0; point < q_points.size(); ++point)
1235 *   {
1236 *   const double beta_dot_n =
1237 *   theta * std::abs(beta(q_points[point]) * normals[point]);
1238 *   const double diff =
1239 *   (boundary_conditions.value(q_points[point]) - sol_u[point]);
1240 *   difference_norm_square += beta_dot_n * diff * diff * JxW[point];
1241 *   }
1242 *   copy_data.value = difference_norm_square;
1243 *   };
1244 *  
1245 *   const auto copier = [&](const auto &copy_data) {
1246 *   if (copy_data.cell_index != numbers::invalid_unsigned_int)
1247 *   {
1248 *   energy_norm_square_per_cell[copy_data.cell_index] += copy_data.value;
1249 *   }
1250 *   for (auto &cdf : copy_data.face_data)
1251 *   for (unsigned int j = 0; j < 2; ++j)
1252 *   energy_norm_square_per_cell[cdf.cell_indices[j]] += cdf.values[j];
1253 *   };
1254 *  
1255 *   ScratchData<dim> scratch_data(mapping,
1256 *   *fe,
1257 *   QGauss<dim>{fe->tensor_degree() + 1},
1258 *   QGauss<dim - 1>{fe->tensor_degree() + 1});
1259 *  
1260 *   CopyData copy_data;
1261 *  
1262 *   MeshWorker::mesh_loop(dof_handler.begin_active(),
1263 *   dof_handler.end(),
1264 *   cell_worker,
1265 *   copier,
1266 *   scratch_data,
1267 *   copy_data,
1271 *   boundary_worker,
1272 *   face_worker);
1273 *  
1274 *   const double energy_error = std::sqrt(energy_norm_square_per_cell.l1_norm());
1275 *   return energy_error;
1276 *   }
1277 *  
1278 *  
1279 *  
1280 * @endcode
1281 *
1282 *
1283 * <a name="source/DG_advection_reaction.cc-Computingtheestimator"></a>
1284 * <h3>Computing the estimator</h3>
1285 * In the estimator, we have to compute the term @f$||f- c u_h - \Pi(f- c
1286 * u_h)||_{T}^{2}@f$ over a generic cell @f$T@f$. To achieve this, we first need to
1287 * compute the projection involving the finite element function @f$u_h@f$. Using the
1288 * definition of orthogonal projection, we're required to solve cellwise
1289 * @f$(v_h,f-c u_h)_T = (v_h,\Pi)_T \qquad \forall v_h \in V_h@f$ for @f$\Pi@f$, which
1290 * means that we have to build a mass-matrix on each cell. Once we have the
1291 * projection, which is a finite element function, we can add its contribution
1292 * in the <code>cell_worker</code> lambda. As done in @ref step_74 "step-74", the square of the
1293 * error indicator is computed.
1294 *
1295
1296 *
1297 *
1298 * @code
1299 *   template <int dim>
1300 *   void
1301 *   AdvectionReaction<dim>::compute_local_projection_and_estimate()
1302 *   {
1303 * @endcode
1304 *
1305 * Compute the term @f$||f-c u_h - \Pi(f- cu_h)||_T^2@f$
1306 *
1307 * @code
1308 *   using Iterator = typename DoFHandler<dim>::active_cell_iterator;
1309 *   error_indicator_per_cell.reinit(triangulation.n_active_cells());
1310 *  
1311 *   const auto cell_worker = [&](const Iterator &cell,
1312 *   ScratchData<dim> &scratch_data,
1313 *   CopyData &copy_data) {
1314 *   const unsigned int n_dofs =
1315 *   scratch_data.fe_values.get_fe().n_dofs_per_cell();
1316 *  
1317 *   copy_data.reinit(cell, n_dofs);
1318 *   scratch_data.fe_values.reinit(cell);
1319 *   copy_data.cell_index = cell->active_cell_index();
1320 *  
1321 *   const auto &q_points = scratch_data.fe_values.get_quadrature_points();
1322 *   const unsigned n_q_points = q_points.size();
1323 *  
1324 *   const FEValues<dim> &fe_v = scratch_data.fe_values;
1325 *   const std::vector<double> &JxW = fe_v.get_JxW_values();
1326 *  
1327 *   std::vector<double> sol_u_at_quadrature_points(fe_v.n_quadrature_points);
1328 *   fe_v.get_function_values(solution, sol_u_at_quadrature_points);
1329 *  
1330 * @endcode
1331 *
1332 * Compute local L^2 projection of @f$f- c u_h@f$ over the local finite element
1333 * space
1334 *
1335 * @code
1336 *   for (unsigned int point = 0; point < n_q_points; ++point)
1337 *   {
1338 *   for (unsigned int i = 0; i < n_dofs; ++i)
1339 *   {
1340 *   for (unsigned int j = 0; j < n_dofs; ++j)
1341 *   {
1342 *   copy_data.cell_mass_matrix(i, j) +=
1343 *   fe_v.shape_value(i, point) * // phi_i(x_q)
1344 *   fe_v.shape_value(j, point) * // phi_j(x_q)
1345 *   JxW[point]; // dx(x_q)
1346 *   }
1347 *   copy_data.cell_mass_rhs(i) +=
1348 *   (rhs.value(q_points[point]) * // f(x_q)
1349 *   fe_v.shape_value(i, point) // phi_i(x_q)
1350 *   - advection_coeff.value(q_points[point]) *
1351 *   fe_v.shape_value(i, point) * // c*phi_i(x_q)
1352 *   sol_u_at_quadrature_points[point]) * // u_h(x_q)
1353 *   JxW[point]; // dx
1354 *   }
1355 *   }
1356 *  
1357 *   FullMatrix<double> inverse(fe_v.n_quadrature_points,
1358 *   fe_v.n_quadrature_points);
1359 *   inverse.invert(copy_data.cell_mass_matrix);
1360 *   Vector<double> proj(fe_v.n_quadrature_points); // projection of (f-c*U_h) on
1361 * @endcode
1362 *
1363 * the local fe_space
1364 *
1365 * @code
1366 *   inverse.vmult(proj, copy_data.cell_mass_rhs); // M^{-1}*rhs = proj
1367 *  
1368 *   double square_norm_over_cell = 0.0;
1369 *   for (unsigned int point = 0; point < n_q_points; ++point)
1370 *   {
1371 *   const double diff = rhs.value(q_points[point]) -
1372 *   sol_u_at_quadrature_points[point] - proj[point];
1373 *   square_norm_over_cell += diff * diff * JxW[point];
1374 *   }
1375 *   copy_data.value_estimator = square_norm_over_cell;
1376 *   };
1377 *  
1378 * @endcode
1379 *
1380 * Finally we have the boundary term with @f$||\beta (g-u_h^+)||^2@f$
1381 *
1382 * @code
1383 *   const auto boundary_worker = [&](const Iterator &cell,
1384 *   const unsigned int &face_no,
1385 *   ScratchData<dim> &scratch_data,
1386 *   CopyData &copy_data) {
1387 *   scratch_data.fe_interface_values.reinit(cell, face_no);
1388 *   const FEFaceValuesBase<dim> &fe_fv =
1389 *   scratch_data.fe_interface_values.get_fe_face_values(0);
1390 *   const auto &q_points = fe_fv.get_quadrature_points();
1391 *   const unsigned n_q_points = q_points.size();
1392 *   const std::vector<double> &JxW = fe_fv.get_JxW_values();
1393 *  
1394 *   std::vector<double> g(n_q_points);
1395 *   exact_solution.value_list(q_points, g);
1396 *  
1397 *   std::vector<double> sol_u(n_q_points);
1398 *   fe_fv.get_function_values(solution, sol_u);
1399 *  
1400 *   const std::vector<Tensor<1, dim>> &normals = fe_fv.get_normal_vectors();
1401 *  
1402 *   double square_norm_over_bdary_face = 0.;
1403 *   for (unsigned int point = 0; point < q_points.size(); ++point)
1404 *   {
1405 *   const double beta_dot_n = beta(q_points[point]) * normals[point];
1406 *  
1407 *   if (beta_dot_n < 0) //\partial_{-T} \cap \partial_{- \Omega}
1408 *   {
1409 *   const double diff =
1410 *   std::abs(beta_dot_n) * (g[point] - sol_u[point]);
1411 *   square_norm_over_bdary_face += diff * diff * JxW[point];
1412 *   }
1413 *   }
1414 *   copy_data.value_estimator += square_norm_over_bdary_face;
1415 *   };
1416 *  
1417 * @endcode
1418 *
1419 * Then compute the interior face terms with @f$|| \sqrt{b \cdot n}[u_h]||^2@f$
1420 *
1421 * @code
1422 *   const auto face_worker = [&](const Iterator &cell,
1423 *   const unsigned int &f,
1424 *   const unsigned int &sf,
1425 *   const Iterator &ncell,
1426 *   const unsigned int &nf,
1427 *   const unsigned int &nsf,
1428 *   ScratchData<dim> &scratch_data,
1429 *   CopyData &copy_data) {
1430 *   FEInterfaceValues<dim> &fe_iv = scratch_data.fe_interface_values;
1431 *   fe_iv.reinit(cell, f, sf, ncell, nf, nsf);
1432 *  
1433 *   copy_data.face_data.emplace_back();
1434 *   CopyDataFace &copy_data_face = copy_data.face_data.back();
1435 *   copy_data_face.cell_indices[0] = cell->active_cell_index();
1436 *   copy_data_face.cell_indices[1] = ncell->active_cell_index();
1437 *  
1438 *   const auto &q_points = fe_iv.get_quadrature_points();
1439 *   const unsigned n_q_points = q_points.size();
1440 *  
1441 *   const std::vector<double> &JxW = fe_iv.get_JxW_values();
1442 *   std::vector<double> g(n_q_points);
1443 *  
1444 *   std::vector<double> jump(n_q_points);
1445 *   get_function_jump(fe_iv, solution, jump);
1446 *  
1447 *   const std::vector<Tensor<1, dim>> &normals = fe_iv.get_normal_vectors();
1448 *  
1449 *   double error_jump_square{0.0};
1450 *   for (unsigned int point = 0; point < n_q_points; ++point)
1451 *   {
1452 *   const double beta_dot_n = beta(q_points[point]) * normals[point];
1453 *   if (beta_dot_n < 0)
1454 *   {
1455 *   error_jump_square +=
1456 *   std::abs(beta_dot_n) * jump[point] * jump[point] * JxW[point];
1457 *   }
1458 *   }
1459 *  
1460 *   copy_data_face.values[0] = error_jump_square;
1461 *   copy_data_face.values[1] = copy_data_face.values[0];
1462 *   };
1463 *  
1464 *   ScratchData<dim> scratch_data(mapping,
1465 *   *fe,
1466 *   QGauss<dim>{fe->tensor_degree() + 1},
1467 *   QGauss<dim - 1>{fe->tensor_degree() + 1});
1468 *  
1469 *   const auto copier = [&](const auto &copy_data) {
1470 *   if (copy_data.cell_index != numbers::invalid_unsigned_int)
1471 *   {
1472 *   error_indicator_per_cell[copy_data.cell_index] +=
1473 *   copy_data.value_estimator;
1474 *   }
1475 *   for (auto &cdf : copy_data.face_data)
1476 *   {
1477 *   for (unsigned int j = 0; j < 2; ++j)
1478 *   {
1479 *   error_indicator_per_cell[cdf.cell_indices[j]] += cdf.values[j];
1480 *   }
1481 *   }
1482 *   };
1483 *  
1484 * @endcode
1485 *
1486 * Here, we finally handle the assembly of the Mass matrix (M)_{ij} = (\phi_j,
1487 * \phi_i)_T. We pass in ScratchData and CopyData objects
1488 *
1489 * @code
1490 *   CopyData copy_data;
1491 *   MeshWorker::mesh_loop(dof_handler.begin_active(),
1492 *   dof_handler.end(),
1493 *   cell_worker,
1494 *   copier,
1495 *   scratch_data,
1496 *   copy_data,
1497 *   MeshWorker::assemble_own_cells |
1498 *   MeshWorker::assemble_boundary_faces |
1499 *   MeshWorker::assemble_own_interior_faces_once,
1500 *   boundary_worker,
1501 *   face_worker);
1502 *   }
1503 *  
1504 *  
1505 *  
1506 * @endcode
1507 *
1508 * Usual <code>run</code> function, which runs over several refinement cycles
1509 *
1510 * @code
1511 *   template <int dim>
1512 *   void
1513 *   AdvectionReaction<dim>::run()
1514 *   {
1515 *   std::vector<double> energy_errors;
1516 *   std::vector<int> dofs_hist;
1517 *   for (unsigned int cycle = 0; cycle < n_refinement_cycles; ++cycle)
1518 *   {
1519 *   std::cout << "Cycle " << cycle << std::endl;
1520 *  
1521 *   if (cycle == 0)
1522 *   {
1523 *   GridGenerator::hyper_cube(triangulation);
1524 *   triangulation.refine_global(n_global_refinements);
1525 *   }
1526 *   else
1527 *   {
1528 *   refine_grid();
1529 *   }
1530 *   std::cout << " Number of active cells: "
1531 *   << triangulation.n_active_cells() << std::endl;
1532 *   std::cout << " Number of degrees of freedom: " << dof_handler.n_dofs()
1533 *   << std::endl;
1534 *  
1535 *   setup_system();
1536 *   assemble_system();
1537 *   solve();
1538 *   compute_error();
1539 *   output_results(cycle);
1540 *  
1541 *   energy_errors.emplace_back(compute_energy_norm());
1542 *   dofs_hist.emplace_back(triangulation.n_active_cells());
1543 *   }
1544 *   error_table.output_table(std::cout);
1545 *  
1546 *   for (unsigned int i = 0; i < n_refinement_cycles; ++i)
1547 *   std::cout << "Cycle " << i << "\t" << energy_errors[i] << std::endl;
1548 *   }
1549 * @endcode
1550 *
1551 * Explicit instantiation
1552 *
1553 * @code
1554 *   template class AdvectionReaction<1>;
1555 *   template class AdvectionReaction<2>;
1556 *   template class AdvectionReaction<3>;
1557 * @endcode
1558
1559
1560*/
void reinit(const CellIteratorType &cell, const unsigned int face_no, const unsigned int sub_face_no, const CellNeighborIteratorType &cell_neighbor, const unsigned int face_no_neighbor, const unsigned int sub_face_no_neighbor, const unsigned int q_index=numbers::invalid_unsigned_int, const unsigned int mapping_index=numbers::invalid_unsigned_int, const unsigned int fe_index=numbers::invalid_unsigned_int, const unsigned int fe_index_neighbor=numbers::invalid_unsigned_int)
const std::vector< double > & get_JxW_values() const
const std::vector< Point< spacedim > > & get_quadrature_points() const
unsigned int depth_console(const unsigned int n)
Definition logstream.cc:349
Abstract base class for mapping classes.
Definition mapping.h:318
The ParsedConvergenceTable class.
Definition point.h:111
Point< 2 > first
Definition grid_out.cc:4623
unsigned int cell_index
#define Assert(cond, exc)
typename ActiveSelector::active_cell_iterator active_cell_iterator
void mesh_loop(const CellIteratorType &begin, const CellIteratorType &end, const CellWorkerFunctionType &cell_worker, const CopierType &copier, const ScratchData &sample_scratch_data, const CopyData &sample_copy_data, const AssembleFlags flags=assemble_own_cells, const BoundaryWorkerFunctionType &boundary_worker=BoundaryWorkerFunctionType(), const FaceWorkerFunctionType &face_worker=FaceWorkerFunctionType(), const unsigned int queue_length=2 *MultithreadInfo::n_threads(), const unsigned int chunk_size=8)
Definition mesh_loop.h:281
UpdateFlags
@ update_values
Shape function values.
@ update_normal_vectors
Normal vectors.
@ update_JxW_values
Transformed quadrature weights.
@ update_gradients
Shape function gradients.
@ update_quadrature_points
Transformed quadrature points.
LogStream deallog
Definition logstream.cc:36
void cell_matrix(FullMatrix< double > &M, const FEValuesBase< dim > &fe, const FEValuesBase< dim > &fetest, const ArrayView< const std::vector< double > > &velocity, const double factor=1.)
Definition advection.h:74
double norm(const FEValuesBase< dim > &fe, const ArrayView< const std::vector< Tensor< 1, dim > > > &Du)
Definition divergence.h:471
@ assemble_boundary_faces
@ assemble_own_interior_faces_once
Point< spacedim > point(const gp_Pnt &p, const double tolerance=1e-10)
Definition utilities.cc:191
SymmetricTensor< 2, dim, Number > b(const Tensor< 2, dim, Number > &F)
Tensor< 2, dim, Number > F(const Tensor< 2, dim, Number > &Grad_u)
void run(const Iterator &begin, const std_cxx20::type_identity_t< Iterator > &end, Worker worker, Copier copier, const ScratchData &sample_scratch_data, const CopyData &sample_copy_data, const unsigned int queue_length, const unsigned int chunk_size)
void copy(const T *begin, const T *end, U *dest)
void assemble(const MeshWorker::DoFInfoBox< dim, DOFINFO > &dinfo, A *assembler)
Definition loop.h:70
void reinit(MatrixBlock< MatrixType > &v, const BlockSparsityPattern &p)
static const unsigned int invalid_unsigned_int
Definition types.h:220
::VectorizedArray< Number, width > sqrt(const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > abs(const ::VectorizedArray< Number, width > &)
const ::parallel::distributed::Triangulation< dim, spacedim > * triangulation