Reference documentation for deal.II version 9.5.1
\(\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
step-74.h
Go to the documentation of this file.
1) const
275 *   {
276 *   using numbers::PI;
277 *   for (unsigned int i = 0; i < values.size(); ++i)
278 *   values[i] =
279 *   std::sin(2. * PI * points[i][0]) * std::sin(2. * PI * points[i][1]);
280 *   }
281 *  
282 *  
283 *  
284 *   template <int dim>
287 *   const unsigned int /*component*/) const
288 *   {
289 *   Tensor<1, dim> return_value;
290 *   using numbers::PI;
291 *   return_value[0] =
292 *   2. * PI * std::cos(2. * PI * point[0]) * std::sin(2. * PI * point[1]);
293 *   return_value[1] =
294 *   2. * PI * std::sin(2. * PI * point[0]) * std::cos(2. * PI * point[1]);
295 *   return return_value;
296 *   }
297 *  
298 *  
299 *  
300 * @endcode
301 *
302 * The corresponding right-hand side of the smooth function:
303 *
304 * @code
305 *   template <int dim>
306 *   class SmoothRightHandSide : public Function<dim>
307 *   {
308 *   public:
310 *   : Function<dim>()
311 *   {}
312 *  
313 *   virtual void value_list(const std::vector<Point<dim>> &points,
314 *   std::vector<double> & values,
315 *   const unsigned int /*component*/) const override;
316 *   };
317 *  
318 *  
319 *  
320 *   template <int dim>
321 *   void
322 *   SmoothRightHandSide<dim>::value_list(const std::vector<Point<dim>> &points,
323 *   std::vector<double> & values,
324 *   const unsigned int /*component*/) const
325 *   {
326 *   using numbers::PI;
327 *   for (unsigned int i = 0; i < values.size(); ++i)
328 *   values[i] = 8. * PI * PI * std::sin(2. * PI * points[i][0]) *
329 *   std::sin(2. * PI * points[i][1]);
330 *   }
331 *  
332 *  
333 *  
334 * @endcode
335 *
336 * The right-hand side that corresponds to the function
339 *
340 * @code
341 *   template <int dim>
342 *   class SingularRightHandSide : public Function<dim>
343 *   {
344 *   public:
346 *   : Function<dim>()
347 *   {}
348 *  
349 *   virtual void value_list(const std::vector<Point<dim>> &points,
350 *   std::vector<double> & values,
351 *   const unsigned int /*component*/) const override;
352 *  
353 *   private:
355 *   };
356 *  
357 *  
358 *  
359 *   template <int dim>
360 *   void
361 *   SingularRightHandSide<dim>::value_list(const std::vector<Point<dim>> &points,
362 *   std::vector<double> & values,
363 *   const unsigned int /*component*/) const
364 *   {
365 *   for (unsigned int i = 0; i < values.size(); ++i)
366 *   values[i] = -ref.laplacian(points[i]);
367 *   }
368 *  
369 *  
370 *  
371 * @endcode
372 *
373 *
374 * <a name="Auxiliaryfunctions"></a>
376 * This function computes the penalty @f$\sigma@f$.
377 *
378 * @code
379 *   double get_penalty_factor(const unsigned int fe_degree,
380 *   const double cell_extent_left,
381 *   const double cell_extent_right)
382 *   {
383 *   const unsigned int degree = std::max(1U, fe_degree);
384 *   return degree * (degree + 1.) * 0.5 *
385 *   (1. / cell_extent_left + 1. / cell_extent_right);
386 *   }
387 *  
388 *  
389 * @endcode
390 *
391 *
392 * <a name="TheCopyData"></a>
393 * <h3>The CopyData</h3>
394 * In the following, we define "Copy" objects for the MeshWorker::mesh_loop(),
395 * which is essentially the same as @ref step_12 "step-12". Note that the
396 * "Scratch" object is not defined here because we use
397 * MeshWorker::ScratchData<dim> instead. (The use of "Copy" and "Scratch"
398 * objects is extensively explained in the WorkStream namespace documentation.
399 *
400 * @code
401 *   struct CopyDataFace
402 *   {
404 *   std::vector<types::global_dof_index> joint_dof_indices;
405 *   std::array<double, 2> values;
406 *   std::array<unsigned int, 2> cell_indices;
407 *   };
408 *  
409 *  
410 *  
411 *   struct CopyData
412 *   {
415 *   std::vector<types::global_dof_index> local_dof_indices;
416 *   std::vector<CopyDataFace> face_data;
417 *   double value;
418 *   unsigned int cell_index;
419 *  
420 *  
421 *   template <class Iterator>
422 *   void reinit(const Iterator &cell, const unsigned int dofs_per_cell)
423 *   {
424 *   cell_matrix.reinit(dofs_per_cell, dofs_per_cell);
425 *   cell_rhs.reinit(dofs_per_cell);
426 *   local_dof_indices.resize(dofs_per_cell);
427 *   cell->get_dof_indices(local_dof_indices);
428 *   }
429 *   };
430 *  
431 *  
432 *  
433 * @endcode
434 *
435 *
436 * <a name="TheSIPGLaplaceclass"></a>
437 * <h3>The SIPGLaplace class</h3>
442 * assemble face terms.
443 *
444 * @code
445 *   template <int dim>
446 *   class SIPGLaplace
447 *   {
448 *   public:
450 *   void run();
451 *  
452 *   private:
453 *   void setup_system();
454 *   void assemble_system();
455 *   void solve();
456 *   void refine_grid();
457 *   void output_results(const unsigned int cycle) const;
458 *  
459 *   void compute_errors();
460 *   void compute_error_estimate();
461 *   double compute_energy_norm_error();
462 *  
464 *   const unsigned int degree;
465 *   const QGauss<dim> quadrature;
466 *   const QGauss<dim - 1> face_quadrature;
469 *   const MappingQ1<dim> mapping;
470 *  
471 *   using ScratchData = MeshWorker::ScratchData<dim>;
472 *  
473 *   const FE_DGQ<dim> fe;
474 *   DoFHandler<dim> dof_handler;
475 *  
476 *   SparsityPattern sparsity_pattern;
477 *   SparseMatrix<double> system_matrix;
478 *   Vector<double> solution;
480 *  
481 * @endcode
482 *
483 * The remainder of the class's members are used for the following:
484 * - Vectors to store error estimator square and energy norm square per
485 * cell.
486 * - Print convergence rate and errors on the screen.
487 * - The fiffusion coefficient @f$\nu@f$ is set to 1.
488 * - Members that store information about the test case to be computed.
489 *
490 * @code
491 *   Vector<double> estimated_error_square_per_cell;
492 *   Vector<double> energy_norm_square_per_cell;
493 *  
494 *   ConvergenceTable convergence_table;
495 *  
496 *   const double diffusion_coefficient = 1.;
497 *  
498 *   const TestCase test_case;
499 *   std::unique_ptr<const Function<dim>> exact_solution;
500 *   std::unique_ptr<const Function<dim>> rhs_function;
501 *   };
502 *  
503 * @endcode
504 *
505 * The constructor here takes the test case as input and then
506 * determines the correct solution and right-hand side classes. The
507 * remaining member variables are initialized in the obvious way.
508 *
509 * @code
510 *   template <int dim>
511 *   SIPGLaplace<dim>::SIPGLaplace(const TestCase &test_case)
512 *   : degree(3)
513 *   , quadrature(degree + 1)
514 *   , face_quadrature(degree + 1)
515 *   , quadrature_overintegration(degree + 2)
516 *   , face_quadrature_overintegration(degree + 2)
517 *   , mapping()
518 *   , fe(degree)
519 *   , dof_handler(triangulation)
520 *   , test_case(test_case)
521 *   {
522 *   if (test_case == TestCase::convergence_rate)
523 *   {
524 *   exact_solution = std::make_unique<const SmoothSolution<dim>>();
525 *   rhs_function = std::make_unique<const SmoothRightHandSide<dim>>();
526 *   }
527 *  
528 *   else if (test_case == TestCase::l_singularity)
529 *   {
530 *   exact_solution =
531 *   std::make_unique<const Functions::LSingularityFunction>();
532 *   rhs_function = std::make_unique<const SingularRightHandSide<dim>>();
533 *   }
534 *   else
535 *   AssertThrow(false, ExcNotImplemented());
536 *   }
537 *  
538 *  
539 *  
540 *   template <int dim>
541 *   void SIPGLaplace<dim>::setup_system()
542 *   {
543 *   dof_handler.distribute_dofs(fe);
544 *   DynamicSparsityPattern dsp(dof_handler.n_dofs());
545 *   DoFTools::make_flux_sparsity_pattern(dof_handler, dsp);
546 *   sparsity_pattern.copy_from(dsp);
547 *  
548 *   system_matrix.reinit(sparsity_pattern);
549 *   solution.reinit(dof_handler.n_dofs());
550 *   system_rhs.reinit(dof_handler.n_dofs());
551 *   }
552 *  
553 *  
554 *  
555 * @endcode
556 *
557 *
558 * <a name="Theassemble_systemfunction"></a>
559 * <h3>The assemble_system function</h3>
560 * The assemble function here is similar to that in @ref step_12 "step-12" and @ref step_47 "step-47".
561 * Different from assembling by hand, we just need to focus
562 * on assembling on each cell, each boundary face, and each
563 * interior face. The loops over cells and faces are handled
564 * automatically by MeshWorker::mesh_loop().
565 *
566
567 *
568 * The function starts by defining a local (lambda) function that is
569 * used to integrate the cell terms:
570 *
571 * @code
572 *   template <int dim>
573 *   void SIPGLaplace<dim>::assemble_system()
574 *   {
575 *   const auto cell_worker =
576 *   [&](const auto &cell, auto &scratch_data, auto &copy_data) {
577 *   const FEValues<dim> &fe_v = scratch_data.reinit(cell);
578 *   const unsigned int dofs_per_cell = fe_v.dofs_per_cell;
579 *   copy_data.reinit(cell, dofs_per_cell);
580 *  
581 *   const auto & q_points = scratch_data.get_quadrature_points();
582 *   const unsigned int n_q_points = q_points.size();
583 *   const std::vector<double> &JxW = scratch_data.get_JxW_values();
584 *  
585 *   std::vector<double> rhs(n_q_points);
586 *   rhs_function->value_list(q_points, rhs);
587 *  
588 *   for (unsigned int point = 0; point < n_q_points; ++point)
589 *   for (unsigned int i = 0; i < fe_v.dofs_per_cell; ++i)
590 *   {
591 *   for (unsigned int j = 0; j < fe_v.dofs_per_cell; ++j)
592 *   copy_data.cell_matrix(i, j) +=
593 *   diffusion_coefficient * // nu
594 *   fe_v.shape_grad(i, point) * // grad v_h
595 *   fe_v.shape_grad(j, point) * // grad u_h
596 *   JxW[point]; // dx
597 *  
598 *   copy_data.cell_rhs(i) += fe_v.shape_value(i, point) * // v_h
599 *   rhs[point] * // f
600 *   JxW[point]; // dx
601 *   }
602 *   };
603 *  
604 * @endcode
605 *
606 * Next, we need a function that assembles face integrals on the boundary:
607 *
608 * @code
609 *   const auto boundary_worker = [&](const auto & cell,
610 *   const unsigned int &face_no,
611 *   auto & scratch_data,
612 *   auto & copy_data) {
613 *   const FEFaceValuesBase<dim> &fe_fv = scratch_data.reinit(cell, face_no);
614 *  
615 *   const auto & q_points = scratch_data.get_quadrature_points();
616 *   const unsigned int n_q_points = q_points.size();
617 *   const unsigned int dofs_per_cell = fe_fv.dofs_per_cell;
618 *  
619 *   const std::vector<double> & JxW = scratch_data.get_JxW_values();
620 *   const std::vector<Tensor<1, dim>> &normals =
621 *   scratch_data.get_normal_vectors();
622 *  
623 *   std::vector<double> g(n_q_points);
624 *   exact_solution->value_list(q_points, g);
625 *  
626 *   const double extent1 = cell->measure() / cell->face(face_no)->measure();
627 *   const double penalty = get_penalty_factor(degree, extent1, extent1);
628 *  
629 *   for (unsigned int point = 0; point < n_q_points; ++point)
630 *   {
631 *   for (unsigned int i = 0; i < dofs_per_cell; ++i)
632 *   for (unsigned int j = 0; j < dofs_per_cell; ++j)
633 *   copy_data.cell_matrix(i, j) +=
634 *   (-diffusion_coefficient * // - nu
635 *   fe_fv.shape_value(i, point) * // v_h
636 *   (fe_fv.shape_grad(j, point) * // (grad u_h .
637 *   normals[point]) // n)
638 *  
639 *   - diffusion_coefficient * // - nu
640 *   (fe_fv.shape_grad(i, point) * // (grad v_h .
641 *   normals[point]) * // n)
642 *   fe_fv.shape_value(j, point) // u_h
643 *  
644 *   + diffusion_coefficient * penalty * // + nu sigma
645 *   fe_fv.shape_value(i, point) * // v_h
646 *   fe_fv.shape_value(j, point) // u_h
647 *  
648 *   ) *
649 *   JxW[point]; // dx
650 *  
651 *   for (unsigned int i = 0; i < dofs_per_cell; ++i)
652 *   copy_data.cell_rhs(i) +=
653 *   (-diffusion_coefficient * // - nu
654 *   (fe_fv.shape_grad(i, point) * // (grad v_h .
655 *   normals[point]) * // n)
656 *   g[point] // g
657 *  
658 *  
659 *   + diffusion_coefficient * penalty * // + nu sigma
660 *   fe_fv.shape_value(i, point) * g[point] // v_h g
661 *  
662 *   ) *
663 *   JxW[point]; // dx
664 *   }
665 *   };
666 *  
667 * @endcode
668 *
669 * Finally, a function that assembles face integrals on interior
670 * faces. To reinitialize FEInterfaceValues, we need to pass
671 * cells, face and subface indices (for adaptive refinement) to
672 * the reinit() function of FEInterfaceValues:
673 *
674 * @code
675 *   const auto face_worker = [&](const auto & cell,
676 *   const unsigned int &f,
677 *   const unsigned int &sf,
678 *   const auto & ncell,
679 *   const unsigned int &nf,
680 *   const unsigned int &nsf,
681 *   auto & scratch_data,
682 *   auto & copy_data) {
683 *   const FEInterfaceValues<dim> &fe_iv =
684 *   scratch_data.reinit(cell, f, sf, ncell, nf, nsf);
685 *  
686 *   copy_data.face_data.emplace_back();
687 *   CopyDataFace & copy_data_face = copy_data.face_data.back();
688 *   const unsigned int n_dofs_face = fe_iv.n_current_interface_dofs();
689 *   copy_data_face.joint_dof_indices = fe_iv.get_interface_dof_indices();
690 *   copy_data_face.cell_matrix.reinit(n_dofs_face, n_dofs_face);
691 *  
692 *   const std::vector<double> & JxW = fe_iv.get_JxW_values();
693 *   const std::vector<Tensor<1, dim>> &normals = fe_iv.get_normal_vectors();
694 *  
695 *   const double extent1 = cell->measure() / cell->face(f)->measure();
696 *   const double extent2 = ncell->measure() / ncell->face(nf)->measure();
697 *   const double penalty = get_penalty_factor(degree, extent1, extent2);
698 *  
699 *   for (const unsigned int point : fe_iv.quadrature_point_indices())
700 *   {
701 *   for (const unsigned int i : fe_iv.dof_indices())
702 *   for (const unsigned int j : fe_iv.dof_indices())
703 *   copy_data_face.cell_matrix(i, j) +=
704 *   (-diffusion_coefficient * // - nu
705 *   fe_iv.jump_in_shape_values(i, point) * // [v_h]
706 *   (fe_iv.average_of_shape_gradients(j,
707 *   point) * // ({grad u_h} .
708 *   normals[point]) // n)
709 *  
710 *   -
711 *   diffusion_coefficient * // - nu
712 *   (fe_iv.average_of_shape_gradients(i, point) * // (grad v_h .
713 *   normals[point]) * // n)
714 *   fe_iv.jump_in_shape_values(j, point) // [u_h]
715 *  
716 *   + diffusion_coefficient * penalty * // + nu sigma
717 *   fe_iv.jump_in_shape_values(i, point) * // [v_h]
718 *   fe_iv.jump_in_shape_values(j, point) // [u_h]
719 *  
720 *   ) *
721 *   JxW[point]; // dx
722 *   }
723 *   };
724 *  
725 * @endcode
726 *
727 * The following lambda function will then copy data into the
728 * global matrix and right-hand side. Though there are no hanging
729 * node constraints in DG discretization, we define an empty
730 * AffineConstraints object that allows us to use the
731 * AffineConstraints::distribute_local_to_global() functionality.
732 *
733 * @code
734 *   AffineConstraints<double> constraints;
735 *   constraints.close();
736 *   const auto copier = [&](const auto &c) {
737 *   constraints.distribute_local_to_global(c.cell_matrix,
738 *   c.cell_rhs,
739 *   c.local_dof_indices,
740 *   system_matrix,
741 *   system_rhs);
742 *  
743 * @endcode
744 *
745 * Copy data from interior face assembly to the global matrix.
746 *
747 * @code
748 *   for (auto &cdf : c.face_data)
749 *   {
750 *   constraints.distribute_local_to_global(cdf.cell_matrix,
751 *   cdf.joint_dof_indices,
752 *   system_matrix);
753 *   }
754 *   };
755 *  
756 *  
757 * @endcode
758 *
759 * With the assembly functions defined, we can now create
760 * ScratchData and CopyData objects, and pass them together with
761 * the lambda functions above to MeshWorker::mesh_loop(). In
762 * addition, we need to specify that we want to assemble on
763 * interior faces exactly once.
764 *
765 * @code
766 *   const UpdateFlags cell_flags = update_values | update_gradients |
767 *   update_quadrature_points | update_JxW_values;
768 *   const UpdateFlags face_flags = update_values | update_gradients |
769 *   update_quadrature_points |
770 *   update_normal_vectors | update_JxW_values;
771 *  
772 *   ScratchData scratch_data(
773 *   mapping, fe, quadrature, cell_flags, face_quadrature, face_flags);
774 *   CopyData copy_data;
775 *  
776 *   MeshWorker::mesh_loop(dof_handler.begin_active(),
777 *   dof_handler.end(),
778 *   cell_worker,
779 *   copier,
780 *   scratch_data,
781 *   copy_data,
782 *   MeshWorker::assemble_own_cells |
783 *   MeshWorker::assemble_boundary_faces |
784 *   MeshWorker::assemble_own_interior_faces_once,
785 *   boundary_worker,
786 *   face_worker);
787 *   }
788 *  
789 *  
790 *  
791 * @endcode
792 *
793 *
794 * <a name="Thesolveandoutput_resultsfunction"></a>
795 * <h3>The solve() and output_results() function</h3>
796 * The following two functions are entirely standard and without difficulty.
797 *
798 * @code
799 *   template <int dim>
800 *   void SIPGLaplace<dim>::solve()
801 *   {
802 *   SparseDirectUMFPACK A_direct;
803 *   A_direct.initialize(system_matrix);
804 *   A_direct.vmult(solution, system_rhs);
805 *   }
806 *  
807 *  
808 *  
809 *   template <int dim>
810 *   void SIPGLaplace<dim>::output_results(const unsigned int cycle) const
811 *   {
812 *   const std::string filename = "sol_Q" + Utilities::int_to_string(degree, 1) +
813 *   "-" + Utilities::int_to_string(cycle, 2) +
814 *   ".vtu";
815 *   std::ofstream output(filename);
816 *  
817 *   DataOut<dim> data_out;
818 *   data_out.attach_dof_handler(dof_handler);
819 *   data_out.add_data_vector(solution, "u", DataOut<dim>::type_dof_data);
820 *   data_out.build_patches(mapping);
821 *   data_out.write_vtu(output);
822 *   }
823 *  
824 *  
825 * @endcode
826 *
827 *
828 * <a name="Thecompute_error_estimatefunction"></a>
829 * <h3>The compute_error_estimate() function</h3>
830 * The assembly of the error estimator here is quite similar to
831 * that of the global matrix and right-had side and can be handled
832 * by the MeshWorker::mesh_loop() framework. To understand what
833 * each of the local (lambda) functions is doing, recall first that
834 * the local cell residual is defined as
835 * @f$h_K^2 \left\| f + \nu \Delta u_h \right\|_K^2@f$:
836 *
837 * @code
838 *   template <int dim>
839 *   void SIPGLaplace<dim>::compute_error_estimate()
840 *   {
841 *   const auto cell_worker =
842 *   [&](const auto &cell, auto &scratch_data, auto &copy_data) {
843 *   const FEValues<dim> &fe_v = scratch_data.reinit(cell);
844 *  
845 *   copy_data.cell_index = cell->active_cell_index();
846 *  
847 *   const auto & q_points = fe_v.get_quadrature_points();
848 *   const unsigned int n_q_points = q_points.size();
849 *   const std::vector<double> &JxW = fe_v.get_JxW_values();
850 *  
851 *   std::vector<Tensor<2, dim>> hessians(n_q_points);
852 *   fe_v.get_function_hessians(solution, hessians);
853 *  
854 *   std::vector<double> rhs(n_q_points);
855 *   rhs_function->value_list(q_points, rhs);
856 *  
857 *   const double hk = cell->diameter();
858 *   double residual_norm_square = 0;
859 *  
860 *   for (unsigned int point = 0; point < n_q_points; ++point)
861 *   {
862 *   const double residual =
863 *   rhs[point] + diffusion_coefficient * trace(hessians[point]);
864 *   residual_norm_square += residual * residual * JxW[point];
865 *   }
866 *   copy_data.value = hk * hk * residual_norm_square;
867 *   };
868 *  
869 * @endcode
870 *
871 * Next compute boundary terms @f$\sum_{f\in \partial K \cap \partial \Omega}
872 * \sigma \left\| [ u_h-g_D ] \right\|_f^2 @f$:
873 *
874 * @code
875 *   const auto boundary_worker = [&](const auto & cell,
876 *   const unsigned int &face_no,
877 *   auto & scratch_data,
878 *   auto & copy_data) {
879 *   const FEFaceValuesBase<dim> &fe_fv = scratch_data.reinit(cell, face_no);
880 *  
881 *   const auto & q_points = fe_fv.get_quadrature_points();
882 *   const unsigned n_q_points = q_points.size();
883 *  
884 *   const std::vector<double> &JxW = fe_fv.get_JxW_values();
885 *  
886 *   std::vector<double> g(n_q_points);
887 *   exact_solution->value_list(q_points, g);
888 *  
889 *   std::vector<double> sol_u(n_q_points);
890 *   fe_fv.get_function_values(solution, sol_u);
891 *  
892 *   const double extent1 = cell->measure() / cell->face(face_no)->measure();
893 *   const double penalty = get_penalty_factor(degree, extent1, extent1);
894 *  
895 *   double difference_norm_square = 0.;
896 *   for (unsigned int point = 0; point < q_points.size(); ++point)
897 *   {
898 *   const double diff = (g[point] - sol_u[point]);
899 *   difference_norm_square += diff * diff * JxW[point];
900 *   }
901 *   copy_data.value += penalty * difference_norm_square;
902 *   };
903 *  
904 * @endcode
905 *
906 * And finally interior face terms @f$\sum_{f\in \partial K}\lbrace \sigma
907 * \left\| [u_h] \right\|_f^2 + h_f \left\| [\nu \nabla u_h \cdot
908 * \mathbf n ] \right\|_f^2 \rbrace@f$:
909 *
910 * @code
911 *   const auto face_worker = [&](const auto & cell,
912 *   const unsigned int &f,
913 *   const unsigned int &sf,
914 *   const auto & ncell,
915 *   const unsigned int &nf,
916 *   const unsigned int &nsf,
917 *   auto & scratch_data,
918 *   auto & copy_data) {
919 *   const FEInterfaceValues<dim> &fe_iv =
920 *   scratch_data.reinit(cell, f, sf, ncell, nf, nsf);
921 *  
922 *   copy_data.face_data.emplace_back();
923 *   CopyDataFace &copy_data_face = copy_data.face_data.back();
924 *  
925 *   copy_data_face.cell_indices[0] = cell->active_cell_index();
926 *   copy_data_face.cell_indices[1] = ncell->active_cell_index();
927 *  
928 *   const std::vector<double> & JxW = fe_iv.get_JxW_values();
929 *   const std::vector<Tensor<1, dim>> &normals = fe_iv.get_normal_vectors();
930 *  
931 *   const auto & q_points = fe_iv.get_quadrature_points();
932 *   const unsigned int n_q_points = q_points.size();
933 *  
934 *   std::vector<double> jump(n_q_points);
935 *   fe_iv.get_jump_in_function_values(solution, jump);
936 *  
937 *   std::vector<Tensor<1, dim>> grad_jump(n_q_points);
938 *   fe_iv.get_jump_in_function_gradients(solution, grad_jump);
939 *  
940 *   const double h = cell->face(f)->diameter();
941 *  
942 *   const double extent1 = cell->measure() / cell->face(f)->measure();
943 *   const double extent2 = ncell->measure() / ncell->face(nf)->measure();
944 *   const double penalty = get_penalty_factor(degree, extent1, extent2);
945 *  
946 *   double flux_jump_square = 0;
947 *   double u_jump_square = 0;
948 *   for (unsigned int point = 0; point < n_q_points; ++point)
949 *   {
950 *   u_jump_square += jump[point] * jump[point] * JxW[point];
951 *   const double flux_jump = grad_jump[point] * normals[point];
952 *   flux_jump_square +=
953 *   diffusion_coefficient * flux_jump * flux_jump * JxW[point];
954 *   }
955 *   copy_data_face.values[0] =
956 *   0.5 * h * (flux_jump_square + penalty * u_jump_square);
957 *   copy_data_face.values[1] = copy_data_face.values[0];
958 *   };
959 *  
960 * @endcode
961 *
962 * Having computed local contributions for each cell, we still
963 * need a way to copy these into the global vector that will hold
964 * the error estimators for all cells:
965 *
966 * @code
967 *   const auto copier = [&](const auto &copy_data) {
968 *   if (copy_data.cell_index != numbers::invalid_unsigned_int)
969 *   estimated_error_square_per_cell[copy_data.cell_index] +=
970 *   copy_data.value;
971 *   for (auto &cdf : copy_data.face_data)
972 *   for (unsigned int j = 0; j < 2; ++j)
973 *   estimated_error_square_per_cell[cdf.cell_indices[j]] += cdf.values[j];
974 *   };
975 *  
976 * @endcode
977 *
978 * After all of this set-up, let's do the actual work: We resize
979 * the vector into which the results will be written, and then
980 * drive the whole process using the MeshWorker::mesh_loop()
981 * function.
982 *
983 * @code
985 *  
986 *   const UpdateFlags cell_flags =
988 *   const UpdateFlags face_flags = update_values | update_gradients |
991 *  
992 *   ScratchData scratch_data(
993 *   mapping, fe, quadrature, cell_flags, face_quadrature, face_flags);
994 *  
995 *   CopyData copy_data;
996 *   MeshWorker::mesh_loop(dof_handler.begin_active(),
997 *   dof_handler.end(),
998 *   cell_worker,
999 *   copier,
1000 *   scratch_data,
1001 *   copy_data,
1006 *   face_worker);
1007 *   }
1008 *  
1009 * @endcode
1010 *
1011 *
1012 * <a name="Thecompute_energy_norm_errorfunction"></a>
1013 * <h3>The compute_energy_norm_error() function</h3>
1014 * Next, we evaluate the accuracy in terms of the energy norm.
1016 * Here we compute the square of the energy norm defined by
1017 * @f[
1018 * \|u \|_{1,h}^2 = \sum_{K \in \Gamma_h} \nu\|\nabla u \|_K^2 +
1019 * \sum_{f \in F_i} \sigma \| [ u ] \|_f^2 +
1020 * \sum_{f \in F_b} \sigma \|u\|_f^2.
1021 * @f]
1023 * @f[
1024 * \|u -u_h \|_{1,h}^2 = \sum_{K \in \Gamma_h} \nu\|\nabla (u_h - u) \|_K^2
1025 * + \sum_{f \in F_i} \sigma \|[ u_h ] \|_f^2 + \sum_{f \in F_b}\sigma
1026 * \|u_h-g_D\|_f^2.
1027 * @f]
1028 *
1029 * @code
1030 *   template <int dim>
1032 *   {
1034 *  
1035 * @endcode
1036 *
1037 * Assemble @f$\sum_{K \in \Gamma_h} \nu\|\nabla (u_h - u) \|_K^2 @f$.
1038 *
1039 * @code
1040 *   const auto cell_worker =
1041 *   [&](const auto &cell, auto &scratch_data, auto &copy_data) {
1042 *   const FEValues<dim> &fe_v = scratch_data.reinit(cell);
1043 *  
1044 *   copy_data.cell_index = cell->active_cell_index();
1045 *  
1046 *   const auto & q_points = fe_v.get_quadrature_points();
1047 *   const unsigned int n_q_points = q_points.size();
1048 *   const std::vector<double> &JxW = fe_v.get_JxW_values();
1049 *  
1050 *   std::vector<Tensor<1, dim>> grad_u(n_q_points);
1051 *   fe_v.get_function_gradients(solution, grad_u);
1052 *  
1053 *   std::vector<Tensor<1, dim>> grad_exact(n_q_points);
1054 *   exact_solution->gradient_list(q_points, grad_exact);
1055 *  
1056 *   double norm_square = 0;
1057 *   for (unsigned int point = 0; point < n_q_points; ++point)
1058 *   {
1059 *   norm_square +=
1060 *   (grad_u[point] - grad_exact[point]).norm_square() * JxW[point];
1061 *   }
1062 *   copy_data.value = diffusion_coefficient * norm_square;
1063 *   };
1064 *  
1065 * @endcode
1066 *
1068 *
1069 * @code
1070 *   const auto boundary_worker = [&](const auto & cell,
1071 *   const unsigned int &face_no,
1072 *   auto & scratch_data,
1073 *   auto & copy_data) {
1074 *   const FEFaceValuesBase<dim> &fe_fv = scratch_data.reinit(cell, face_no);
1075 *  
1076 *   const auto & q_points = fe_fv.get_quadrature_points();
1077 *   const unsigned n_q_points = q_points.size();
1078 *  
1079 *   const std::vector<double> &JxW = fe_fv.get_JxW_values();
1080 *  
1081 *   std::vector<double> g(n_q_points);
1082 *   exact_solution->value_list(q_points, g);
1083 *  
1084 *   std::vector<double> sol_u(n_q_points);
1085 *   fe_fv.get_function_values(solution, sol_u);
1086 *  
1087 *   const double extent1 = cell->measure() / cell->face(face_no)->measure();
1088 *   const double penalty = get_penalty_factor(degree, extent1, extent1);
1089 *  
1090 *   double difference_norm_square = 0.;
1091 *   for (unsigned int point = 0; point < q_points.size(); ++point)
1092 *   {
1093 *   const double diff = (g[point] - sol_u[point]);
1094 *   difference_norm_square += diff * diff * JxW[point];
1095 *   }
1096 *   copy_data.value += penalty * difference_norm_square;
1097 *   };
1098 *  
1099 * @endcode
1100 *
1101 * Assemble @f$\sum_{f \in F_i} \sigma \| [ u_h ] \|_f^2@f$.
1102 *
1103 * @code
1104 *   const auto face_worker = [&](const auto & cell,
1105 *   const unsigned int &f,
1106 *   const unsigned int &sf,
1107 *   const auto & ncell,
1108 *   const unsigned int &nf,
1109 *   const unsigned int &nsf,
1110 *   auto & scratch_data,
1111 *   auto & copy_data) {
1113 *   scratch_data.reinit(cell, f, sf, ncell, nf, nsf);
1114 *  
1115 *   copy_data.face_data.emplace_back();
1116 *   CopyDataFace &copy_data_face = copy_data.face_data.back();
1117 *  
1118 *   copy_data_face.cell_indices[0] = cell->active_cell_index();
1119 *   copy_data_face.cell_indices[1] = ncell->active_cell_index();
1120 *  
1121 *   const std::vector<double> &JxW = fe_iv.get_JxW_values();
1122 *  
1123 *   const auto & q_points = fe_iv.get_quadrature_points();
1124 *   const unsigned int n_q_points = q_points.size();
1125 *  
1126 *   std::vector<double> jump(n_q_points);
1127 *   fe_iv.get_jump_in_function_values(solution, jump);
1128 *  
1129 *   const double extent1 = cell->measure() / cell->face(f)->measure();
1130 *   const double extent2 = ncell->measure() / ncell->face(nf)->measure();
1131 *   const double penalty = get_penalty_factor(degree, extent1, extent2);
1132 *  
1133 *   double u_jump_square = 0;
1134 *   for (unsigned int point = 0; point < n_q_points; ++point)
1135 *   {
1136 *   u_jump_square += jump[point] * jump[point] * JxW[point];
1137 *   }
1138 *   copy_data_face.values[0] = 0.5 * penalty * u_jump_square;
1139 *   copy_data_face.values[1] = copy_data_face.values[0];
1140 *   };
1141 *  
1142 *   const auto copier = [&](const auto &copy_data) {
1143 *   if (copy_data.cell_index != numbers::invalid_unsigned_int)
1144 *   energy_norm_square_per_cell[copy_data.cell_index] += copy_data.value;
1145 *   for (auto &cdf : copy_data.face_data)
1146 *   for (unsigned int j = 0; j < 2; ++j)
1147 *   energy_norm_square_per_cell[cdf.cell_indices[j]] += cdf.values[j];
1148 *   };
1149 *  
1150 *   const UpdateFlags cell_flags =
1152 *   UpdateFlags face_flags =
1154 *  
1155 *   const ScratchData scratch_data(mapping,
1156 *   fe,
1158 *   cell_flags,
1160 *   face_flags);
1161 *  
1162 *   CopyData copy_data;
1163 *   MeshWorker::mesh_loop(dof_handler.begin_active(),
1164 *   dof_handler.end(),
1165 *   cell_worker,
1166 *   copier,
1167 *   scratch_data,
1168 *   copy_data,
1173 *   face_worker);
1174 *   const double energy_error =
1176 *   return energy_error;
1177 *   }
1178 *  
1179 *  
1180 *  
1181 * @endcode
1182 *
1183 *
1184 * <a name="Therefine_gridfunction"></a>
1185 * <h3>The refine_grid() function</h3>
1186 *
1187 * @code
1188 *   template <int dim>
1189 *   void SIPGLaplace<dim>::refine_grid()
1190 *   {
1191 *   const double refinement_fraction = 0.1;
1192 *  
1195 *  
1196 *   triangulation.execute_coarsening_and_refinement();
1197 *   }
1198 *  
1199 *  
1200 *  
1201 * @endcode
1202 *
1203 *
1204 * <a name="Thecompute_errorsfunction"></a>
1205 * <h3>The compute_errors() function</h3>
1206 * We compute three errors in the @f$L_2@f$ norm, @f$H_1@f$ seminorm, and
1207 * the energy norm, respectively. These are then printed to screen,
1209 * with mesh refinement and which can be output in one step at the
1210 * end of the program.
1211 *
1212 * @code
1213 *   template <int dim>
1214 *   void SIPGLaplace<dim>::compute_errors()
1215 *   {
1216 *   double L2_error, H1_error, energy_error;
1217 *  
1218 *   {
1221 *   dof_handler,
1222 *   solution,
1223 *   *(exact_solution.get()),
1227 *  
1231 *   convergence_table.add_value("L2", L2_error);
1232 *   }
1233 *  
1234 *   {
1237 *   dof_handler,
1238 *   solution,
1239 *   *(exact_solution.get()),
1243 *  
1247 *   convergence_table.add_value("H1", H1_error);
1248 *   }
1249 *  
1250 *   {
1252 *   convergence_table.add_value("Energy", energy_error);
1253 *   }
1254 *  
1255 *   std::cout << " Error in the L2 norm : " << L2_error << std::endl
1256 *   << " Error in the H1 seminorm : " << H1_error << std::endl
1257 *   << " Error in the energy norm : " << energy_error
1258 *   << std::endl;
1259 *   }
1260 *  
1261 *  
1262 *  
1263 * @endcode
1264 *
1265 *
1266 * <a name="Therunfunction"></a>
1267 * <h3>The run() function</h3>
1268 *
1269 * @code
1270 *   template <int dim>
1271 *   void SIPGLaplace<dim>::run()
1272 *   {
1273 *   const unsigned int max_cycle =
1274 *   (test_case == TestCase::convergence_rate ? 6 : 20);
1275 *   for (unsigned int cycle = 0; cycle < max_cycle; ++cycle)
1276 *   {
1277 *   std::cout << "Cycle " << cycle << std::endl;
1278 *  
1279 *   switch (test_case)
1280 *   {
1282 *   {
1283 *   if (cycle == 0)
1284 *   {
1286 *  
1287 *   triangulation.refine_global(2);
1288 *   }
1289 *   else
1290 *   {
1291 *   triangulation.refine_global(1);
1292 *   }
1293 *   break;
1294 *   }
1295 *  
1297 *   {
1298 *   if (cycle == 0)
1299 *   {
1301 *   triangulation.refine_global(3);
1302 *   }
1303 *   else
1304 *   {
1305 *   refine_grid();
1306 *   }
1307 *   break;
1308 *   }
1309 *  
1310 *   default:
1311 *   {
1312 *   Assert(false, ExcNotImplemented());
1313 *   }
1314 *   }
1315 *  
1316 *   std::cout << " Number of active cells : "
1317 *   << triangulation.n_active_cells() << std::endl;
1318 *   setup_system();
1319 *  
1320 *   std::cout << " Number of degrees of freedom : " << dof_handler.n_dofs()
1321 *   << std::endl;
1322 *  
1323 *   assemble_system();
1324 *   solve();
1325 *   output_results(cycle);
1326 *   {
1327 *   convergence_table.add_value("cycle", cycle);
1328 *   convergence_table.add_value("cells", triangulation.n_active_cells());
1329 *   convergence_table.add_value("dofs", dof_handler.n_dofs());
1330 *   }
1331 *   compute_errors();
1332 *  
1334 *   {
1336 *   std::cout << " Estimated error : "
1338 *   << std::endl;
1339 *  
1340 *   convergence_table.add_value(
1341 *   "Estimator",
1343 *   }
1344 *   std::cout << std::endl;
1345 *   }
1346 *  
1347 * @endcode
1348 *
1350 * table how to format its data and output it to screen:
1351 *
1352 * @code
1353 *   convergence_table.set_precision("L2", 3);
1354 *   convergence_table.set_precision("H1", 3);
1355 *   convergence_table.set_precision("Energy", 3);
1356 *  
1357 *   convergence_table.set_scientific("L2", true);
1358 *   convergence_table.set_scientific("H1", true);
1359 *   convergence_table.set_scientific("Energy", true);
1360 *  
1362 *   {
1363 *   convergence_table.evaluate_convergence_rates(
1365 *   convergence_table.evaluate_convergence_rates(
1367 *   }
1369 *   {
1370 *   convergence_table.set_precision("Estimator", 3);
1371 *   convergence_table.set_scientific("Estimator", true);
1372 *   }
1373 *  
1374 *   std::cout << "degree = " << degree << std::endl;
1375 *   convergence_table.write_text(
1377 *   }
1378 *   } // namespace Step74
1379 *  
1380 *  
1381 *  
1382 * @endcode
1383 *
1384 *
1385 * <a name="Themainfunction"></a>
1386 * <h3>The main() function</h3>
1389 *
1390 * @code
1391 *   int main()
1392 *   {
1393 *   try
1394 *   {
1395 *   using namespace dealii;
1396 *   using namespace Step74;
1397 *  
1399 *  
1401 *   problem.run();
1402 *   }
1403 *   catch (std::exception &exc)
1404 *   {
1405 *   std::cerr << std::endl
1406 *   << std::endl
1407 *   << "----------------------------------------------------"
1408 *   << std::endl;
1409 *   std::cerr << "Exception on processing: " << std::endl
1410 *   << exc.what() << std::endl
1411 *   << "Aborting!" << std::endl
1412 *   << "----------------------------------------------------"
1413 *   << std::endl;
1414 *   return 1;
1415 *   }
1416 *   catch (...)
1417 *   {
1418 *   std::cerr << std::endl
1419 *   << std::endl
1420 *   << "----------------------------------------------------"
1421 *   << std::endl;
1422 *   std::cerr << "Unknown exception!" << std::endl
1423 *   << "Aborting!" << std::endl
1424 *   << "----------------------------------------------------"
1425 *   << std::endl;
1426 *   return 1;
1427 *   };
1428 *  
1429 *   return 0;
1430 *   }
1431 * @endcode
1432<a name="Results"></a><h1>Results</h1>
1433
1434
1435The output of this program consist of the console output and
1437
1439@code
1440Cycle 0
1441 Number of active cells : 16
1442 Number of degrees of freedom : 256
1443 Error in the L2 norm : 0.00193285
1444 Error in the H1 seminorm : 0.106087
1445 Error in the energy norm : 0.150625
1446
1447Cycle 1
1448 Number of active cells : 64
1449 Number of degrees of freedom : 1024
1450 Error in the L2 norm : 9.60497e-05
1451 Error in the H1 seminorm : 0.0089954
1452 Error in the energy norm : 0.0113265
1453
1454Cycle 2
1455.
1456.
1457.
1458@endcode
1459
1460When using the smooth case with polynomial degree 3, the convergence
1461table will look like this:
1462<table align="center" class="doxtable">
1463 <tr>
1464 <th>cycle</th>
1465 <th>n_cells</th>
1466 <th>n_dofs</th>
1467 <th>L2 </th>
1468 <th>rate</th>
1469 <th>H1</th>
1470 <th>rate</th>
1471 <th>Energy</th>
1472 </tr>
1473 <tr>
1474 <td align="center">0</td>
1475 <td align="right">16</td>
1476 <td align="right">256</td>
1477 <td align="center">1.933e-03</td>
1478 <td>&nbsp;</td>
1479 <td align="center">1.061e-01</td>
1480 <td>&nbsp;</td>
1481 <td align="center">1.506e-01</td>
1482 </tr>
1483 <tr>
1484 <td align="center">1</td>
1485 <td align="right">64</td>
1486 <td align="right">1024</td>
1487 <td align="center">9.605e-05</td>
1488 <td align="center">4.33</td>
1489 <td align="center">8.995e-03</td>
1490 <td align="center">3.56</td>
1491 <td align="center">1.133e-02</td>
1492 </tr>
1493 <tr>
1494 <td align="center">2</td>
1495 <td align="right">256</td>
1496 <td align="right">4096</td>
1497 <td align="center">5.606e-06</td>
1498 <td align="center">4.10</td>
1499 <td align="center">9.018e-04</td>
1500 <td align="center">3.32</td>
1501 <td align="center">9.736e-04</td>
1502 </tr>
1503 <tr>
1504 <td align="center">3</td>
1505 <td align="right">1024</td>
1506 <td align="right">16384</td>
1507 <td align="center">3.484e-07</td>
1508 <td align="center">4.01</td>
1509 <td align="center">1.071e-04</td>
1510 <td align="center">3.07</td>
1511 <td align="center">1.088e-04</td>
1512 </tr>
1513 <tr>
1514 <td align="center">4</td>
1515 <td align="right">4096</td>
1516 <td align="right">65536</td>
1517 <td align="center">2.179e-08</td>
1518 <td align="center">4.00</td>
1519 <td align="center">1.327e-05</td>
1520 <td align="center">3.01</td>
1521 <td align="center">1.331e-05</td>
1522 </tr>
1523 <tr>
1524 <td align="center">5</td>
1525 <td align="right">16384</td>
1526 <td align="right">262144</td>
1527 <td align="center">1.363e-09</td>
1528 <td align="center">4.00</td>
1529 <td align="center">1.656e-06</td>
1530 <td align="center">3.00</td>
1531 <td align="center">1.657e-06</td>
1532 </tr>
1533</table>
1534
1535Theoretically, for polynomial degree @f$p@f$, the order of convergence in @f$L_2@f$
1537results are in good agreement with theory.
1538
1540@code
1541Cycle 0
1542 Number of active cells : 192
1543 Number of degrees of freedom : 3072
1544 Error in the L2 norm : 0.000323585
1545 Error in the H1 seminorm : 0.0296202
1546 Error in the energy norm : 0.0420478
1547 Estimated error : 0.136067
1548
1549Cycle 1
1550 Number of active cells : 249
1551 Number of degrees of freedom : 3984
1552 Error in the L2 norm : 0.000114739
1553 Error in the H1 seminorm : 0.0186571
1554 Error in the energy norm : 0.0264879
1555 Estimated error : 0.0857186
1556
1557Cycle 2
1558.
1559.
1560.
1561@endcode
1562
1564the number of degrees of freedom for this test case on the L-shaped
1565domain. In order to interpret it, let @f$n@f$ be the number of degrees of
1567@f$1/\sqrt{n}@f$ in 2D. Combining the theoretical results in the previous case,
1568we see that if the solution is sufficiently smooth,
1569we can expect the error in the @f$L_2@f$ norm to be of order @f$O(n^{-\frac{p+1}{2}})@f$
1570and in @f$H^1@f$ seminorm to be @f$O(n^{-\frac{p}{2}})@f$. It is not a priori
1571clear that one would get the same kind of behavior as a function of
1573test case, but one can certainly hope. Indeed, from the figure, we see
1575the kinds of hoped-for results:
1576
1577<img width="600px" src="https://www.dealii.org/images/steps/developer/step-74.log-log-plot.png" alt="">
1578
1580at almost the same rate as the errors in the energy norm and @f$H^1@f$ seminorm,
1583
1585large-scale solver in terms of computing time with matrix-free solution techniques.
1587because the multigrid interface matrices are not as easily determined,
1589 *
1590 *
1591<a name="PlainProg"></a>
1592<h1> The plain program</h1>
1593@include "step-74.cc"
1594*/
iterator end() const
Definition array_view.h:603
value_type * data() const noexcept
Definition array_view.h:553
void reinit(value_type *starting_element, const std::size_t n_elements)
Definition array_view.h:413
std::size_t size() const
Definition array_view.h:576
Point< 2 > second
Definition grid_out.cc:4616
Point< 2 > first
Definition grid_out.cc:4615
unsigned int cell_index
static ::ExceptionBase & ExcNotImplemented()
#define Assert(cond, exc)
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:282
UpdateFlags
@ update_hessians
Second derivatives of shape functions.
@ 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.
void hyper_L(Triangulation< dim > &tria, const double left=-1., const double right=1., const bool colorize=false)
void hyper_cube(Triangulation< dim, spacedim > &tria, const double left=0., const double right=1., const bool colorize=false)
void refine_and_coarsen_fixed_number(Triangulation< dim, spacedim > &triangulation, const Vector< Number > &criteria, const double top_fraction_of_cells, const double bottom_fraction_of_cells, const unsigned int max_n_cells=std::numeric_limits< unsigned int >::max())
void scale(const double scaling_factor, Triangulation< dim, spacedim > &triangulation)
@ matrix
Contents is actually a matrix.
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:75
double norm(const FEValuesBase< dim > &fe, const ArrayView< const std::vector< Tensor< 1, dim > > > &Du)
Definition divergence.h:472
void L2(Vector< number > &result, const FEValuesBase< dim > &fe, const std::vector< double > &input, const double factor=1.)
Definition l2.h:160
@ assemble_boundary_faces
@ assemble_own_interior_faces_once
Point< spacedim > point(const gp_Pnt &p, const double tolerance=1e-10)
Definition utilities.cc:189
void free(T *&pointer)
Definition cuda.h:97
double compute_global_error(const Triangulation< dim, spacedim > &tria, const InVector &cellwise_error, const NormType &norm, const double exponent=2.)
void integrate_difference(const Mapping< dim, spacedim > &mapping, const DoFHandler< dim, spacedim > &dof, const InVector &fe_function, const Function< spacedim, typename InVector::value_type > &exact_solution, OutVector &difference, const Quadrature< dim > &q, const NormType &norm, const Function< spacedim, double > *weight=nullptr, const double exponent=2.)
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)
unsigned int n_cells(const internal::TriangulationImplementation::NumberCache< 1 > &c)
Definition tria.cc:13826
int(&) functions(const void *v1, const void *v2)
void assemble(const MeshWorker::DoFInfoBox< dim, DOFINFO > &dinfo, A *assembler)
Definition loop.h:71
void reinit(MatrixBlock< MatrixType > &v, const BlockSparsityPattern &p)
static constexpr double PI
Definition numbers.h:259
static const unsigned int invalid_unsigned_int
Definition types.h:213
::VectorizedArray< Number, width > log(const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > max(const ::VectorizedArray< Number, width > &, const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > cos(const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > sin(const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > sqrt(const ::VectorizedArray< Number, width > &)
const ::parallel::distributed::Triangulation< dim, spacedim > * triangulation