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-76.h
Go to the documentation of this file.
1true);
282 FEFaceEvaluation<dim, degree, degree + 1, 1, Number> phi_p(data, /*is_interior_face=*/false);
283
284 for (unsigned int face = range.first; face < range.second; ++face)
285 {
286 phi_m.reinit(face);
287 phi_m.gather_evaluate(src, face_evaluation_flags);
288 phi_p.reinit(face);
289 phi_p.gather_evaluate(src, face_evaluation_flags);
290
291 // some operations on the face quadrature points
292
293 phi_m.integrate_scatter(face_evaluation_flags, dst);
294 phi_p.integrate_scatter(face_evaluation_flags, dst);
295 }
296 },
297 [&](const auto &data, auto &dst, const auto &src, const auto range) {
298 // operation performed boundary faces
299
300 FEFaceEvaluation<dim, degree, degree + 1, 1, Number> phi_m(data, /*is_interior_face=*/true);
301
302 for (unsigned int face = range.first; face < range.second; ++face)
303 {
304 phi_m.reinit(face);
305 phi_m.gather_evaluate(src, face_evaluation_flags);
306
307 // some operations on the face quadrature points
308
309 phi_m.integrate_scatter(face_evaluation_flags, dst);
310 }
311 },
312 dst,
313 src);
314@endcode
315
316in the following way:
317
318@code
320 [&](const auto &data, auto &dst, const auto &src, const auto range) {
322 FEFaceEvaluation<dim, degree, degree + 1, 1, Number> phi_m(data, /*is_interior_face=*/true);
323 FEFaceEvaluation<dim, degree, degree + 1, 1, Number> phi_p(data, /*is_interior_face=*/false);
324
325 for (unsigned int cell = range.first; cell < range.second; ++cell)
326 {
327 phi.reinit(cell);
328 phi.gather_evaluate(src, cell_evaluation_flags);
329
330 // some operations on the cell quadrature points
331
332 phi.integrate_scatter(cell_evaluation_flags, dst);
333
334 // loop over all faces of cell
335 for (unsigned int face = 0; face < GeometryInfo<dim>::faces_per_cell; ++face)
336 {
337 if (data.get_faces_by_cells_boundary_id(cell, face)[0] ==
339 {
340 // internal face
341 phi_m.reinit(cell, face);
342 phi_m.gather_evaluate(src, face_evaluation_flags);
343 phi_p.reinit(cell, face);
344 phi_p.gather_evaluate(src, face_evaluation_flags);
345
346 // some operations on the face quadrature points
347
348 phi_m.integrate_scatter(face_evaluation_flags, dst);
349 }
350 else
351 {
352 // boundary face
353 phi_m.reinit(cell, face);
354 phi_m.gather_evaluate(src, face_evaluation_flags);
355
356 // some operations on the face quadrature points
357
358 phi_m.integrate_scatter(face_evaluation_flags, dst);
359 }
360 }
361 }
362 },
363 dst,
364 src);
365@endcode
366
368the cell number and the local face number. The given example only
373
376
377@code
378typename MatrixFree<dim, Number>::AdditionalData additional_data;
379
380// set flags as usual (not shown)
381
382additional_data.hold_all_faces_to_owned_cells = true;
383additional_data.mapping_update_flags_faces_by_cells =
384 additional_data.mapping_update_flags_inner_faces |
385 additional_data.mapping_update_flags_boundary_faces;
386
387data.reinit(mapping, dof_handler, constraint, quadrature, additional_data);
388@endcode
389
391for all faces of the cells.
392
393Currently, cell-centric loops in deal.II only work for uniformly refined meshes
394and if no constraints are applied (which is the standard case DG is normally
395used).
396
397
398<a name="ProvidinglambdastoMatrixFreeloops"></a><h3>Providing lambdas to MatrixFree loops</h3>
399
400
403a version where a class and a pointer to one of its methods are used and a
404variant where lambdas are utilized.
405
408
409@code
410void
411local_apply_cell(const MatrixFree<dim, Number> & data,
412 VectorType & dst,
413 const VectorType & src,
414 const std::pair<unsigned int, unsigned int> &range) const
415{
417 for (unsigned int cell = range.first; cell < range.second; ++cell)
418 {
419 phi.reinit(cell);
420 phi.gather_evaluate(src, cell_evaluation_flags);
421
422 // some operations on the quadrature points
423
424 phi.integrate_scatter(cell_evaluation_flags, dst);
425 }
426}
427@endcode
428
429@code
430matrix_free.cell_loop(&Operator::local_apply_cell, this, dst, src);
431@endcode
432
433However, it is also possible to pass an anonymous function via a lambda function
435
436@code
437matrix_free.template cell_loop<VectorType, VectorType>(
438 [&](const auto &data, auto &dst, const auto &src, const auto range) {
440 for (unsigned int cell = range.first; cell < range.second; ++cell)
441 {
442 phi.reinit(cell);
443 phi.gather_evaluate(src, cell_evaluation_flags);
444
445 // some operations on the quadrature points
446
447 phi.integrate_scatter(cell_evaluation_flags, dst);
448 }
449 },
450 dst,
451 src);
452@endcode
453
454<a name="VectorizedArrayType"></a><h3>VectorizedArrayType</h3>
455
456
457The class VectorizedArray<Number> is a key component to achieve the high
459It is a wrapper class around a short vector of @f$n@f$ entries of type Number and
461(SIMD) concepts by intrinsic functions. The length of the vector can be
464
465In the default case (<code>VectorizedArray<Number></code>), the vector length is
466set at compile time of the library to
469specified as <code>VectorizedArray<Number, size></code>, where <code>size</code> explicitly
471set. A full list of supported vector lengths is presented in the following table:
472
473<table align="center" class="doxtable">
474 <tr>
475 <th>double</th>
476 <th>float</th>
477 <th>ISA</th>
478 </tr>
479 <tr>
480 <td><code>VectorizedArray<double, 1></code></td>
481 <td><code>VectorizedArray<float, 1></code></td>
482 <td>(auto-vectorization)</td>
483 </tr>
484 <tr>
485 <td><code>VectorizedArray<double, 2></code></td>
486 <td><code>VectorizedArray<float, 4></code></td>
487 <td>SSE2/AltiVec</td>
488 </tr>
489 <tr>
490 <td><code>VectorizedArray<double, 4></code></td>
491 <td><code>VectorizedArray<float, 8></code></td>
492 <td>AVX/AVX2</td>
493 </tr>
494 <tr>
495 <td><code>VectorizedArray<double, 8></code></td>
496 <td><code>VectorizedArray<float, 16></code></td>
497 <td>AVX-512</td>
498 </tr>
499</table>
500
501This allows users to select the vector length/ISA and, as a consequence, the
502number of cells to be processed at once in matrix-free operator evaluations,
504degrees (and dimensions).
505
506A possible further reason to reduce the number of filled lanes
508cells, one can concentrate on a single cell.
509
511a matching interface. Specifically, this prepares deal.II for the <code>std::simd</code>
514
515
516<table align="center" class="doxtable">
517 <tr>
518 <th>VectorizedArray (deal.II)</th>
519 <th>std::simd (C++23)</th>
520 </tr>
521 <tr>
522 <td><code>VectorizedArray<Number></code></td>
523 <td><code>std::experimental::native_simd<Number></code></td>
524 </tr>
525 <tr>
526 <td><code>VectorizedArray<Number, size></code></td>
527 <td><code>std::experimental::fixed_size_simd<Number, size></code></td>
528 </tr>
529</table>
530 *
531 *
532 * <a name="CommProg"></a>
533 * <h1> The commented program</h1>
534 *
535 *
536 * <a name="Parametersandutilityfunctions"></a>
538 *
539
540 *
541 * The same includes as in @ref step_67 "step-67":
542 *
543 * @code
544 *   #include <deal.II/base/conditional_ostream.h>
545 *   #include <deal.II/base/function.h>
546 *   #include <deal.II/base/logstream.h>
547 *   #include <deal.II/base/time_stepping.h>
548 *   #include <deal.II/base/timer.h>
549 *   #include <deal.II/base/utilities.h>
550 *   #include <deal.II/base/vectorization.h>
551 *  
552 *   #include <deal.II/distributed/tria.h>
553 *  
554 *   #include <deal.II/dofs/dof_handler.h>
555 *  
556 *   #include <deal.II/fe/fe_dgq.h>
557 *   #include <deal.II/fe/fe_system.h>
558 *  
559 *   #include <deal.II/grid/grid_generator.h>
560 *   #include <deal.II/grid/tria.h>
561 *   #include <deal.II/grid/tria_accessor.h>
562 *   #include <deal.II/grid/tria_iterator.h>
563 *  
564 *   #include <deal.II/lac/affine_constraints.h>
565 *   #include <deal.II/lac/la_parallel_vector.h>
566 *  
567 *   #include <deal.II/matrix_free/fe_evaluation.h>
568 *   #include <deal.II/matrix_free/matrix_free.h>
569 *   #include <deal.II/matrix_free/operators.h>
570 *  
571 *   #include <deal.II/numerics/data_out.h>
572 *  
573 *   #include <fstream>
574 *   #include <iomanip>
575 *   #include <iostream>
576 *  
577 * @endcode
578 *
579 * A new include for categorizing of cells according to their boundary IDs:
580 *
581 * @code
582 *   #include <deal.II/matrix_free/tools.h>
583 *  
584 *  
585 *  
587 *   {
588 *   using namespace dealii;
589 *  
590 * @endcode
591 *
592 * The same input parameters as in @ref step_67 "step-67":
593 *
594 * @code
595 *   constexpr unsigned int testcase = 1;
596 *   constexpr unsigned int dimension = 2;
597 *   constexpr unsigned int n_global_refinements = 2;
598 *   constexpr unsigned int fe_degree = 5;
599 *   constexpr unsigned int n_q_points_1d = fe_degree + 2;
600 *  
601 * @endcode
602 *
603 * This parameter specifies the size of the shared-memory group. Currently,
606 * having access to the same shared-memory domain are grouped together.
607 *
608 * @code
609 *   constexpr unsigned int group_size = numbers::invalid_unsigned_int;
610 *  
611 *   using Number = double;
612 *  
613 * @endcode
614 *
615 * Here, the type of the data structure is chosen for vectorization. In the
616 * default case, VectorizedArray<Number> is used, i.e., the highest
618 * the maximum number of vector lanes is used. However, one might reduce
619 * the number of filled lanes, e.g., by writing
620 * <code>using VectorizedArrayType = VectorizedArray<Number, 4></code> to only
621 * process 4 cells.
622 *
623 * @code
624 *   using VectorizedArrayType = VectorizedArray<Number>;
625 *  
626 * @endcode
627 *
628 * The following parameters have not changed:
629 *
630 * @code
631 *   constexpr double gamma = 1.4;
632 *   constexpr double final_time = testcase == 0 ? 10 : 2.0;
633 *   constexpr double output_tick = testcase == 0 ? 1 : 0.05;
634 *  
635 *   const double courant_number = 0.15 / std::pow(fe_degree, 1.5);
636 *  
637 * @endcode
638 *
639 * Specify max number of time steps useful for performance studies.
640 *
641 * @code
642 *   constexpr unsigned int max_time_steps = numbers::invalid_unsigned_int;
643 *  
644 * @endcode
645 *
647 * with the purpose to minimize global vector access:
648 *
649 * @code
651 *   {
656 *   };
658 *  
659 *  
660 *  
662 *   {
663 *   public:
665 *   {
667 *   switch (scheme)
668 *   {
669 *   case stage_3_order_3:
671 *   break;
672 *   case stage_5_order_4:
674 *   break;
675 *   case stage_7_order_4:
677 *   break;
678 *   case stage_9_order_5:
680 *   break;
681 *  
682 *   default:
683 *   AssertThrow(false, ExcNotImplemented());
684 *   }
688 *   std::vector<double> ci; // not used
689 *   rk_integrator.get_coefficients(ai, bi, ci);
690 *   }
691 *  
692 *   unsigned int n_stages() const
693 *   {
694 *   return bi.size();
695 *   }
696 *  
697 *   template <typename VectorType, typename Operator>
699 *   const double current_time,
700 *   const double time_step,
701 *   VectorType & solution,
702 *   VectorType & vec_ri,
703 *   VectorType & vec_ki) const
704 *   {
705 *   AssertDimension(ai.size() + 1, bi.size());
706 *  
707 *   vec_ki.swap(solution);
708 *  
709 *   double sum_previous_bi = 0;
710 *   for (unsigned int stage = 0; stage < bi.size(); ++stage)
711 *   {
712 *   const double c_i = stage == 0 ? 0 : sum_previous_bi + ai[stage - 1];
713 *  
714 *   pde_operator.perform_stage(stage,
715 *   current_time + c_i * time_step,
716 *   bi[stage] * time_step,
717 *   (stage == bi.size() - 1 ?
718 *   0 :
719 *   ai[stage] * time_step),
720 *   (stage % 2 == 0 ? vec_ki : vec_ri),
721 *   (stage % 2 == 0 ? vec_ri : vec_ki),
722 *   solution);
723 *  
724 *   if (stage > 0)
725 *   sum_previous_bi += bi[stage - 1];
726 *   }
727 *   }
728 *  
729 *   private:
730 *   std::vector<double> bi;
731 *   std::vector<double> ai;
732 *   };
733 *  
734 *  
735 * @endcode
736 *
737 * Euler-specific utility functions from @ref step_67 "step-67":
738 *
739 * @code
741 *   {
744 *   };
746 *  
747 *  
748 *  
749 *   template <int dim>
750 *   class ExactSolution : public Function<dim>
751 *   {
752 *   public:
753 *   ExactSolution(const double time)
754 *   : Function<dim>(dim + 2, time)
755 *   {}
756 *  
757 *   virtual double value(const Point<dim> & p,
758 *   const unsigned int component = 0) const override;
759 *   };
760 *  
761 *  
762 *  
763 *   template <int dim>
765 *   const unsigned int component) const
766 *   {
767 *   const double t = this->get_time();
768 *  
769 *   switch (testcase)
770 *   {
771 *   case 0:
772 *   {
773 *   Assert(dim == 2, ExcNotImplemented());
774 *   const double beta = 5;
775 *  
777 *   x0[0] = 5.;
778 *   const double radius_sqr =
779 *   (x - x0).norm_square() - 2. * (x[0] - x0[0]) * t + t * t;
780 *   const double factor =
781 *   beta / (numbers::PI * 2) * std::exp(1. - radius_sqr);
782 *   const double density_log = std::log2(
783 *   std::abs(1. - (gamma - 1.) / gamma * 0.25 * factor * factor));
784 *   const double density = std::exp2(density_log * (1. / (gamma - 1.)));
785 *   const double u = 1. - factor * (x[1] - x0[1]);
786 *   const double v = factor * (x[0] - t - x0[0]);
787 *  
788 *   if (component == 0)
789 *   return density;
790 *   else if (component == 1)
791 *   return density * u;
792 *   else if (component == 2)
793 *   return density * v;
794 *   else
795 *   {
796 *   const double pressure =
797 *   std::exp2(density_log * (gamma / (gamma - 1.)));
798 *   return pressure / (gamma - 1.) +
799 *   0.5 * (density * u * u + density * v * v);
800 *   }
801 *   }
802 *  
803 *   case 1:
804 *   {
805 *   if (component == 0)
806 *   return 1.;
807 *   else if (component == 1)
808 *   return 0.4;
809 *   else if (component == dim + 1)
810 *   return 3.097857142857143;
811 *   else
812 *   return 0.;
813 *   }
814 *  
815 *   default:
816 *   Assert(false, ExcNotImplemented());
817 *   return 0.;
818 *   }
819 *   }
820 *  
821 *  
822 *  
823 *   template <int dim, typename Number>
827 *   {
828 *   const Number inverse_density = Number(1.) / conserved_variables[0];
829 *  
831 *   for (unsigned int d = 0; d < dim; ++d)
833 *  
834 *   return velocity;
835 *   }
836 *  
837 *   template <int dim, typename Number>
839 *   Number
841 *   {
844 *  
845 *   Number rho_u_dot_u = conserved_variables[1] * velocity[0];
846 *   for (unsigned int d = 1; d < dim; ++d)
848 *  
849 *   return (gamma - 1.) * (conserved_variables[dim + 1] - 0.5 * rho_u_dot_u);
850 *   }
851 *  
852 *   template <int dim, typename Number>
856 *   {
860 *  
862 *   for (unsigned int d = 0; d < dim; ++d)
863 *   {
864 *   flux[0][d] = conserved_variables[1 + d];
865 *   for (unsigned int e = 0; e < dim; ++e)
866 *   flux[e + 1][d] = conserved_variables[e + 1] * velocity[d];
867 *   flux[d + 1][d] += pressure;
868 *   flux[dim + 1][d] =
869 *   velocity[d] * (conserved_variables[dim + 1] + pressure);
870 *   }
871 *  
872 *   return flux;
873 *   }
874 *  
875 *   template <int n_components, int dim, typename Number>
878 *   operator*(const Tensor<1, n_components, Tensor<1, dim, Number>> &matrix,
879 *   const Tensor<1, dim, Number> & vector)
880 *   {
882 *   for (unsigned int d = 0; d < n_components; ++d)
883 *   result[d] = matrix[d] * vector;
884 *   return result;
885 *   }
886 *  
887 *   template <int dim, typename Number>
892 *   const Tensor<1, dim, Number> & normal)
893 *   {
894 *   const auto velocity_m = euler_velocity<dim>(u_m);
895 *   const auto velocity_p = euler_velocity<dim>(u_p);
896 *  
897 *   const auto pressure_m = euler_pressure<dim>(u_m);
898 *   const auto pressure_p = euler_pressure<dim>(u_p);
899 *  
900 *   const auto flux_m = euler_flux<dim>(u_m);
901 *   const auto flux_p = euler_flux<dim>(u_p);
902 *  
903 *   switch (numerical_flux_type)
904 *   {
906 *   {
907 *   const auto lambda =
908 *   0.5 * std::sqrt(std::max(velocity_p.norm_square() +
909 *   gamma * pressure_p * (1. / u_p[0]),
910 *   velocity_m.norm_square() +
911 *   gamma * pressure_m * (1. / u_m[0])));
912 *  
913 *   return 0.5 * (flux_m * normal + flux_p * normal) +
914 *   0.5 * lambda * (u_m - u_p);
915 *   }
916 *  
918 *   {
919 *   const auto avg_velocity_normal =
920 *   0.5 * ((velocity_m + velocity_p) * normal);
921 *   const auto avg_c = std::sqrt(std::abs(
922 *   0.5 * gamma *
923 *   (pressure_p * (1. / u_p[0]) + pressure_m * (1. / u_m[0]))));
924 *   const Number s_pos =
925 *   std::max(Number(), avg_velocity_normal + avg_c);
926 *   const Number s_neg =
927 *   std::min(Number(), avg_velocity_normal - avg_c);
928 *   const Number inverse_s = Number(1.) / (s_pos - s_neg);
929 *  
930 *   return inverse_s *
931 *   ((s_pos * (flux_m * normal) - s_neg * (flux_p * normal)) -
932 *   s_pos * s_neg * (u_m - u_p));
933 *   }
934 *  
935 *   default:
936 *   {
937 *   Assert(false, ExcNotImplemented());
938 *   return {};
939 *   }
940 *   }
941 *   }
942 *  
943 *  
944 *  
945 * @endcode
946 *
947 * General-purpose utility functions from @ref step_67 "step-67":
948 *
949 * @code
950 *   template <int dim, typename VectorizedArrayType>
951 *   VectorizedArrayType
952 *   evaluate_function(const Function<dim> & function,
954 *   const unsigned int component)
955 *   {
956 *   VectorizedArrayType result;
957 *   for (unsigned int v = 0; v < VectorizedArrayType::size(); ++v)
958 *   {
959 *   Point<dim> p;
960 *   for (unsigned int d = 0; d < dim; ++d)
961 *   p[d] = p_vectorized[d][v];
962 *   result[v] = function.value(p, component);
963 *   }
964 *   return result;
965 *   }
966 *  
967 *  
968 *   template <int dim, typename VectorizedArrayType, int n_components = dim + 2>
970 *   evaluate_function(const Function<dim> & function,
972 *   {
973 *   AssertDimension(function.n_components, n_components);
975 *   for (unsigned int v = 0; v < VectorizedArrayType::size(); ++v)
976 *   {
977 *   Point<dim> p;
978 *   for (unsigned int d = 0; d < dim; ++d)
979 *   p[d] = p_vectorized[d][v];
980 *   for (unsigned int d = 0; d < n_components; ++d)
981 *   result[d][v] = function.value(p, d);
982 *   }
983 *   return result;
984 *   }
985 *  
986 *  
987 * @endcode
988 *
989 *
990 * <a name="EuleroperatorusingacellcentricloopandMPI30sharedmemory"></a>
991 * <h3>Euler operator using a cell-centric loop and MPI-3.0 shared memory</h3>
992 *
993
994 *
995 * Euler operator from @ref step_67 "step-67" with some changes as detailed below:
996 *
997 * @code
998 *   template <int dim, int degree, int n_points_1d>
999 *   class EulerOperator
1000 *   {
1001 *   public:
1002 *   static constexpr unsigned int n_quadrature_points_1d = n_points_1d;
1003 *  
1005 *  
1006 *   ~EulerOperator();
1007 *  
1008 *   void reinit(const Mapping<dim> & mapping,
1009 *   const DoFHandler<dim> &dof_handler);
1010 *  
1011 *   void set_inflow_boundary(const types::boundary_id boundary_id,
1012 *   std::unique_ptr<Function<dim>> inflow_function);
1013 *  
1015 *   const types::boundary_id boundary_id,
1016 *   std::unique_ptr<Function<dim>> outflow_energy);
1017 *  
1018 *   void set_wall_boundary(const types::boundary_id boundary_id);
1019 *  
1020 *   void set_body_force(std::unique_ptr<Function<dim>> body_force);
1021 *  
1022 *   void
1023 *   perform_stage(const unsigned int stage,
1024 *   const Number cur_time,
1025 *   const Number bi,
1026 *   const Number ai,
1030 *  
1031 *   void project(const Function<dim> & function,
1033 *  
1034 *   std::array<double, 3> compute_errors(
1035 *   const Function<dim> & function,
1036 *   const LinearAlgebra::distributed::Vector<Number> &solution) const;
1037 *  
1039 *   const LinearAlgebra::distributed::Vector<Number> &solution) const;
1040 *  
1041 *   void
1043 *  
1044 *   private:
1045 * @endcode
1046 *
1049 * shared-memory capabilities:
1050 *
1051 * @code
1053 *  
1054 *   MatrixFree<dim, Number, VectorizedArrayType> data;
1055 *  
1056 *   TimerOutput &timer;
1057 *  
1058 *   std::map<types::boundary_id, std::unique_ptr<Function<dim>>>
1060 *   std::map<types::boundary_id, std::unique_ptr<Function<dim>>>
1062 *   std::set<types::boundary_id> wall_boundaries;
1063 *   std::unique_ptr<Function<dim>> body_force;
1064 *   };
1065 *  
1066 *  
1067 *  
1068 * @endcode
1069 *
1070 * New constructor, which creates a sub-communicator. The user can specify
1071 * the size of the sub-communicator via the global parameter group_size. If
1072 * the size is set to -1, all MPI processes of a
1073 * shared-memory domain are combined to a group. The specified size is
1075 * and, therefore, setting the <code>size</code> to <code>-1</code> is a
1077 * disable the MPI-3.0 shared-memory features of MatrixFree and rely
1079 * <code>MPI_Irecv</code>.
1080 *
1081 * @code
1082 *   template <int dim, int degree, int n_points_1d>
1083 *   EulerOperator<dim, degree, n_points_1d>::EulerOperator(TimerOutput &timer)
1084 *   : timer(timer)
1085 *   {
1087 *   if (group_size == 1)
1088 *   {
1089 *   this->subcommunicator = MPI_COMM_SELF;
1090 *   }
1092 *   {
1094 *  
1097 *   rank,
1100 *   }
1101 *   else
1102 *   {
1103 *   Assert(false, ExcNotImplemented());
1104 *   }
1105 *   #else
1106 *   (void)subcommunicator;
1107 *   (void)group_size;
1108 *   this->subcommunicator = MPI_COMM_SELF;
1109 *   #endif
1110 *   }
1111 *  
1112 *  
1113 * @endcode
1114 *
1115 * New destructor responsible for freeing of the sub-communicator.
1116 *
1117 * @code
1118 *   template <int dim, int degree, int n_points_1d>
1120 *   {
1122 *   if (this->subcommunicator != MPI_COMM_SELF)
1124 *   #endif
1125 *   }
1126 *  
1127 *  
1128 * @endcode
1129 *
1130 * Modified reinit() function to set up the internal data structures in
1132 * the MPI-3.0 shared-memory capabilities are used:
1133 *
1134 * @code
1135 *   template <int dim, int degree, int n_points_1d>
1136 *   void EulerOperator<dim, degree, n_points_1d>::reinit(
1137 *   const Mapping<dim> & mapping,
1138 *   const DoFHandler<dim> &dof_handler)
1139 *   {
1140 *   const std::vector<const DoFHandler<dim> *> dof_handlers = {&dof_handler};
1142 *   const std::vector<const AffineConstraints<double> *> constraints = {&dummy};
1143 *   const std::vector<Quadrature<1>> quadratures = {QGauss<1>(n_q_points_1d),
1144 *   QGauss<1>(fe_degree + 1)};
1145 *  
1147 *   additional_data;
1148 *   additional_data.mapping_update_flags =
1151 *   additional_data.mapping_update_flags_inner_faces =
1154 *   additional_data.mapping_update_flags_boundary_faces =
1157 *   additional_data.tasks_parallel_scheme =
1159 *  
1160 * @endcode
1161 *
1162 * Categorize cells so that all lanes have the same boundary IDs for each
1166 * have to perform exactly the same operation also on the faces.
1167 *
1168 * @code
1169 *   MatrixFreeTools::categorize_by_boundary_ids(dof_handler.get_triangulation(),
1170 *   additional_data);
1171 *  
1172 * @endcode
1173 *
1174 * Enable MPI-3.0 shared-memory capabilities within MatrixFree by providing
1175 * the sub-communicator:
1176 *
1177 * @code
1178 *   additional_data.communicator_sm = subcommunicator;
1179 *  
1180 *   data.reinit(
1181 *   mapping, dof_handlers, constraints, quadratures, additional_data);
1182 *   }
1183 *  
1184 *  
1185 * @endcode
1186 *
1189 * compared to @ref step_67 "step-67".
1190 *
1191
1192 *
1193 * In contrast to @ref step_67 "step-67", we are not executing the advection step
1194 * (using MatrixFree::loop()) and the inverse mass-matrix step
1195 * (using MatrixFree::cell_loop()) in sequence, but evaluate everything in
1196 * one go inside of MatrixFree::loop_cell_centric(). This function expects
1197 * a single function that is executed on each locally-owned (macro) cell as
1198 * parameter so that we need to loop over all faces of that cell and perform
1199 * needed integration steps on our own.
1200 *
1201
1202 *
1204 * functions from @ref step_67 "step-67" so that comments related the evaluation of the weak
1205 * form are skipped here:
1206 * - <code>EulerDG::EulerOperator::local_apply_cell</code>
1210 *
1211 * @code
1212 *   template <int dim, int degree, int n_points_1d>
1213 *   void EulerOperator<dim, degree, n_points_1d>::perform_stage(
1214 *   const unsigned int stage,
1215 *   const Number current_time,
1216 *   const Number bi,
1217 *   const Number ai,
1218 *   const LinearAlgebra::distributed::Vector<Number> &current_ri,
1219 *   LinearAlgebra::distributed::Vector<Number> & vec_ki,
1220 *   LinearAlgebra::distributed::Vector<Number> & solution) const
1221 *   {
1222 *   for (auto &i : inflow_boundaries)
1223 *   i.second->set_time(current_time);
1224 *   for (auto &i : subsonic_outflow_boundaries)
1225 *   i.second->set_time(current_time);
1226 *  
1227 * @endcode
1228 *
1230 * providing a lambda containing the effects of the cell, face and
1231 * boundary-face integrals:
1232 *
1233 * @code
1234 *   data.template loop_cell_centric<LinearAlgebra::distributed::Vector<Number>,
1235 *   LinearAlgebra::distributed::Vector<Number>>(
1236 *   [&](const auto &data, auto &dst, const auto &src, const auto cell_range) {
1237 *   using FECellIntegral = FEEvaluation<dim,
1238 *   degree,
1239 *   n_points_1d,
1240 *   dim + 2,
1241 *   Number,
1242 *   VectorizedArrayType>;
1243 *   using FEFaceIntegral = FEFaceEvaluation<dim,
1244 *   degree,
1245 *   n_points_1d,
1246 *   dim + 2,
1247 *   Number,
1248 *   VectorizedArrayType>;
1249 *  
1250 *   FECellIntegral phi(data);
1252 *   FEFaceIntegral phi_m(data, true);
1253 *   FEFaceIntegral phi_p(data, false);
1254 *  
1257 *   dynamic_cast<Functions::ConstantFunction<dim> *>(body_force.get());
1258 *  
1259 *   if (constant_function)
1263 *  
1266 *   dim,
1267 *   n_points_1d,
1268 *   n_points_1d,
1269 *   VectorizedArrayType>
1271 *   data.get_shape_info().data[0].shape_gradients_collocation_eo,
1273 *  
1275 *   phi.n_components);
1276 *  
1277 * @endcode
1278 *
1279 * Loop over all cell batches:
1280 *
1281 * @code
1282 *   for (unsigned int cell = cell_range.first; cell < cell_range.second;
1283 *   ++cell)
1284 *   {
1285 *   phi.reinit(cell);
1286 *  
1287 *   if (ai != Number())
1288 *   phi_temp.reinit(cell);
1289 *  
1290 * @endcode
1291 *
1292 * Read values from global vector and compute the values at the
1293 * quadrature points:
1294 *
1295 * @code
1296 *   if (ai != Number() && stage == 0)
1297 *   {
1298 *   phi.read_dof_values(src);
1299 *  
1300 *   for (unsigned int i = 0;
1301 *   i < phi.static_dofs_per_component * (dim + 2);
1302 *   ++i)
1303 *   phi_temp.begin_dof_values()[i] = phi.begin_dof_values()[i];
1304 *  
1305 *   phi.evaluate(EvaluationFlags::values);
1306 *   }
1307 *   else
1308 *   {
1309 *   phi.gather_evaluate(src, EvaluationFlags::values);
1310 *   }
1311 *  
1312 * @endcode
1313 *
1314 * Buffer the computed values at the quadrature points, since
1316 * step, however, are needed later on for the face integrals:
1317 *
1318 * @code
1319 *   for (unsigned int i = 0; i < phi.static_n_q_points * (dim + 2); ++i)
1320 *   buffer[i] = phi.begin_values()[i];
1321 *  
1322 * @endcode
1323 *
1324 * Apply the cell integral at the cell quadrature points. See also
1325 * the function <code>EulerOperator::local_apply_cell()</code> from
1326 * @ref step_67 "step-67":
1327 *
1328 * @code
1329 *   for (unsigned int q = 0; q < phi.n_q_points; ++q)
1330 *   {
1331 *   const auto w_q = phi.get_value(q);
1332 *   phi.submit_gradient(euler_flux<dim>(w_q), q);
1333 *   if (body_force.get() != nullptr)
1334 *   {
1339 *   *body_force, phi.quadrature_point(q));
1340 *  
1342 *   for (unsigned int d = 0; d < dim; ++d)
1343 *   forcing[d + 1] = w_q[0] * force[d];
1344 *   for (unsigned int d = 0; d < dim; ++d)
1345 *   forcing[dim + 1] += force[d] * w_q[d + 1];
1346 *  
1347 *   phi.submit_value(forcing, q);
1348 *   }
1349 *   }
1350 *  
1351 * @endcode
1352 *
1353 * Test with the gradient of the test functions in the quadrature
1354 * points. We skip the interpolation back to the support points
1355 * of the element, since we first collect all contributions in the
1356 * cell quadrature points and only perform the interpolation back
1357 * as the final step.
1358 *
1359 * @code
1360 *   {
1361 *   auto *values_ptr = phi.begin_values();
1362 *   auto *gradient_ptr = phi.begin_gradients();
1363 *  
1364 *   for (unsigned int c = 0; c < dim + 2; ++c)
1365 *   {
1366 *   if (dim >= 1 && body_force.get() == nullptr)
1368 *   gradient_ptr + phi.static_n_q_points * 0, values_ptr);
1369 *   else if (dim >= 1)
1371 *   gradient_ptr + phi.static_n_q_points * 0, values_ptr);
1372 *   if (dim >= 2)
1374 *   gradient_ptr + phi.static_n_q_points * 1, values_ptr);
1375 *   if (dim >= 3)
1377 *   gradient_ptr + phi.static_n_q_points * 2, values_ptr);
1378 *  
1379 *   values_ptr += phi.static_n_q_points;
1380 *   gradient_ptr += phi.static_n_q_points * dim;
1381 *   }
1382 *   }
1383 *  
1384 * @endcode
1385 *
1386 * Loop over all faces of the current cell:
1387 *
1388 * @code
1389 *   for (unsigned int face = 0;
1391 *   ++face)
1392 *   {
1393 * @endcode
1394 *
1395 * Determine the boundary ID of the current face. Since we have
1397 * guaranteed the same boundary ID, we can select the
1398 * boundary ID of the first lane.
1399 *
1400 * @code
1401 *   const auto boundary_ids =
1402 *   data.get_faces_by_cells_boundary_id(cell, face);
1403 *  
1404 *   Assert(std::equal(boundary_ids.begin(),
1405 *   boundary_ids.begin() +
1406 *   data.n_active_entries_per_cell_batch(cell),
1407 *   boundary_ids.begin()),
1408 *   ExcMessage("Boundary IDs of lanes differ."));
1409 *  
1410 *   const auto boundary_id = boundary_ids[0];
1411 *  
1412 *   phi_m.reinit(cell, face);
1413 *  
1414 * @endcode
1415 *
1416 * Interpolate the values from the cell quadrature points to the
1417 * quadrature points of the current face via a simple 1d
1418 * interpolation:
1419 *
1420 * @code
1422 *   n_points_1d - 1,
1423 *   VectorizedArrayType>::
1425 *   dim + 2,
1427 *   data.get_shape_info(),
1428 *   buffer.data(),
1429 *   phi_m.begin_values(),
1430 *   face);
1431 *  
1432 * @endcode
1433 *
1434 * Check if the face is an internal or a boundary face and
1435 * select a different code path based on this information:
1436 *
1437 * @code
1438 *   if (boundary_id == numbers::internal_face_boundary_id)
1439 *   {
1440 * @endcode
1441 *
1442 * Process and internal face. The following lines of code
1443 * are a copy of the function
1444 * <code>EulerDG::EulerOperator::local_apply_face</code>
1445 * from @ref step_67 "step-67":
1446 *
1447 * @code
1448 *   phi_p.reinit(cell, face);
1449 *   phi_p.gather_evaluate(src, EvaluationFlags::values);
1450 *  
1451 *   for (unsigned int q = 0; q < phi_m.n_q_points; ++q)
1452 *   {
1453 *   const auto numerical_flux =
1455 *   phi_p.get_value(q),
1456 *   phi_m.normal_vector(q));
1457 *   phi_m.submit_value(-numerical_flux, q);
1458 *   }
1459 *   }
1460 *   else
1461 *   {
1462 * @endcode
1463 *
1464 * Process a boundary face. These following lines of code
1465 * are a copy of the function
1466 * <code>EulerDG::EulerOperator::local_apply_boundary_face</code>
1467 * from @ref step_67 "step-67":
1468 *
1469 * @code
1470 *   for (unsigned int q = 0; q < phi_m.n_q_points; ++q)
1471 *   {
1472 *   const auto w_m = phi_m.get_value(q);
1473 *   const auto normal = phi_m.normal_vector(q);
1474 *  
1475 *   auto rho_u_dot_n = w_m[1] * normal[0];
1476 *   for (unsigned int d = 1; d < dim; ++d)
1477 *   rho_u_dot_n += w_m[1 + d] * normal[d];
1478 *  
1479 *   bool at_outflow = false;
1480 *  
1482 *  
1483 *   if (wall_boundaries.find(boundary_id) !=
1485 *   {
1486 *   w_p[0] = w_m[0];
1487 *   for (unsigned int d = 0; d < dim; ++d)
1488 *   w_p[d + 1] =
1489 *   w_m[d + 1] - 2. * rho_u_dot_n * normal[d];
1490 *   w_p[dim + 1] = w_m[dim + 1];
1491 *   }
1492 *   else if (inflow_boundaries.find(boundary_id) !=
1495 *   *inflow_boundaries.find(boundary_id)->second,
1496 *   phi_m.quadrature_point(q));
1497 *   else if (subsonic_outflow_boundaries.find(
1498 *   boundary_id) !=
1500 *   {
1501 *   w_p = w_m;
1502 *   w_p[dim + 1] =
1504 *   .find(boundary_id)
1505 *   ->second,
1506 *   phi_m.quadrature_point(q),
1507 *   dim + 1);
1508 *   at_outflow = true;
1509 *   }
1510 *   else
1511 *   AssertThrow(false,
1512 *   ExcMessage(
1513 *   "Unknown boundary id, did "
1514 *   "you set a boundary condition for "
1515 *   "this part of the domain boundary?"));
1516 *  
1517 *   auto flux = euler_numerical_flux<dim>(w_m, w_p, normal);
1518 *  
1519 *   if (at_outflow)
1520 *   for (unsigned int v = 0;
1521 *   v < VectorizedArrayType::size();
1522 *   ++v)
1523 *   {
1524 *   if (rho_u_dot_n[v] < -1e-12)
1525 *   for (unsigned int d = 0; d < dim; ++d)
1526 *   flux[d + 1][v] = 0.;
1527 *   }
1528 *  
1529 *   phi_m.submit_value(-flux, q);
1530 *   }
1531 *   }
1532 *  
1533 * @endcode
1534 *
1535 * Evaluate local integrals related to cell by quadrature and
1536 * add into cell contribution via a simple 1d interpolation:
1537 *
1538 * @code
1540 *   n_points_1d - 1,
1541 *   VectorizedArrayType>::
1543 *   dim + 2,
1545 *   data.get_shape_info(),
1546 *   phi_m.begin_values(),
1547 *   phi.begin_values(),
1548 *   face);
1549 *   }
1550 *  
1551 * @endcode
1552 *
1553 * Apply inverse mass matrix in the cell quadrature points. See
1554 * also the function
1555 * <code>EulerDG::EulerOperator::local_apply_inverse_mass_matrix()</code>
1556 * from @ref step_67 "step-67":
1557 *
1558 * @code
1559 *   for (unsigned int q = 0; q < phi.static_n_q_points; ++q)
1560 *   {
1561 *   const auto factor = VectorizedArrayType(1.0) / phi.JxW(q);
1562 *   for (unsigned int c = 0; c < dim + 2; ++c)
1563 *   phi.begin_values()[c * phi.static_n_q_points + q] =
1564 *   phi.begin_values()[c * phi.static_n_q_points + q] * factor;
1565 *   }
1566 *  
1567 * @endcode
1568 *
1570 * Gauss-Lobatto space:
1571 *
1572 * @code
1576 *   dim,
1577 *   degree + 1,
1578 *   n_points_1d>::do_backward(dim + 2,
1579 *   data.get_shape_info()
1580 *   .data[0]
1581 *   .inverse_shape_values_eo,
1582 *   false,
1583 *   phi.begin_values(),
1584 *   phi.begin_dof_values());
1585 *  
1586 * @endcode
1587 *
1588 * Perform Runge-Kutta update and write results back to global
1589 * vectors:
1590 *
1591 * @code
1592 *   if (ai == Number())
1593 *   {
1594 *   for (unsigned int q = 0; q < phi.static_dofs_per_cell; ++q)
1595 *   phi.begin_dof_values()[q] = bi * phi.begin_dof_values()[q];
1596 *   phi.distribute_local_to_global(solution);
1597 *   }
1598 *   else
1599 *   {
1600 *   if (stage != 0)
1601 *   phi_temp.read_dof_values(solution);
1602 *  
1603 *   for (unsigned int q = 0; q < phi.static_dofs_per_cell; ++q)
1604 *   {
1605 *   const auto K_i = phi.begin_dof_values()[q];
1606 *  
1607 *   phi.begin_dof_values()[q] =
1608 *   phi_temp.begin_dof_values()[q] + (ai * K_i);
1609 *  
1610 *   phi_temp.begin_dof_values()[q] += bi * K_i;
1611 *   }
1612 *   phi.set_dof_values(dst);
1613 *   phi_temp.set_dof_values(solution);
1614 *   }
1615 *   }
1616 *   },
1617 *   vec_ki,
1618 *   current_ri,
1619 *   true,
1621 *   }
1622 *  
1623 *  
1624 *  
1625 * @endcode
1626 *
1627 * From here, the code of @ref step_67 "step-67" has not changed.
1628 *
1629 * @code
1630 *   template <int dim, int degree, int n_points_1d>
1633 *   {
1634 *   data.initialize_dof_vector(vector);
1635 *   }
1636 *  
1637 *  
1638 *  
1639 *   template <int dim, int degree, int n_points_1d>
1641 *   const types::boundary_id boundary_id,
1642 *   std::unique_ptr<Function<dim>> inflow_function)
1643 *   {
1644 *   AssertThrow(subsonic_outflow_boundaries.find(boundary_id) ==
1646 *   wall_boundaries.find(boundary_id) == wall_boundaries.end(),
1647 *   ExcMessage("You already set the boundary with id " +
1648 *   std::to_string(static_cast<int>(boundary_id)) +
1649 *   " to another type of boundary before now setting " +
1650 *   "it as inflow"));
1651 *   AssertThrow(inflow_function->n_components == dim + 2,
1652 *   ExcMessage("Expected function with dim+2 components"));
1653 *  
1655 *   }
1656 *  
1657 *  
1658 *  
1659 *   template <int dim, int degree, int n_points_1d>
1661 *   const types::boundary_id boundary_id,
1662 *   std::unique_ptr<Function<dim>> outflow_function)
1663 *   {
1664 *   AssertThrow(inflow_boundaries.find(boundary_id) ==
1666 *   wall_boundaries.find(boundary_id) == wall_boundaries.end(),
1667 *   ExcMessage("You already set the boundary with id " +
1668 *   std::to_string(static_cast<int>(boundary_id)) +
1669 *   " to another type of boundary before now setting " +
1670 *   "it as subsonic outflow"));
1671 *   AssertThrow(outflow_function->n_components == dim + 2,
1672 *   ExcMessage("Expected function with dim+2 components"));
1673 *  
1675 *   }
1676 *  
1677 *  
1678 *  
1679 *   template <int dim, int degree, int n_points_1d>
1681 *   const types::boundary_id boundary_id)
1682 *   {
1683 *   AssertThrow(inflow_boundaries.find(boundary_id) ==
1685 *   subsonic_outflow_boundaries.find(boundary_id) ==
1687 *   ExcMessage("You already set the boundary with id " +
1688 *   std::to_string(static_cast<int>(boundary_id)) +
1689 *   " to another type of boundary before now setting " +
1690 *   "it as wall boundary"));
1691 *  
1692 *   wall_boundaries.insert(boundary_id);
1693 *   }
1694 *  
1695 *  
1696 *  
1697 *   template <int dim, int degree, int n_points_1d>
1699 *   std::unique_ptr<Function<dim>> body_force)
1700 *   {
1701 *   AssertDimension(body_force->n_components, dim);
1702 *  
1703 *   this->body_force = std::move(body_force);
1704 *   }
1705 *  
1706 *  
1707 *  
1708 *   template <int dim, int degree, int n_points_1d>
1710 *   const Function<dim> & function,
1712 *   {
1714 *   phi(data, 0, 1);
1716 *   degree,
1717 *   dim + 2,
1718 *   Number,
1719 *   VectorizedArrayType>
1720 *   inverse(phi);
1721 *   solution.zero_out_ghost_values();
1722 *   for (unsigned int cell = 0; cell < data.n_cell_batches(); ++cell)
1723 *   {
1724 *   phi.reinit(cell);
1725 *   for (unsigned int q = 0; q < phi.n_q_points; ++q)
1726 *   phi.submit_dof_value(evaluate_function(function,
1727 *   phi.quadrature_point(q)),
1728 *   q);
1729 *   inverse.transform_from_q_points_to_basis(dim + 2,
1730 *   phi.begin_dof_values(),
1731 *   phi.begin_dof_values());
1732 *   phi.set_dof_values(solution);
1733 *   }
1734 *   }
1735 *  
1736 *  
1737 *  
1738 *   template <int dim, int degree, int n_points_1d>
1740 *   const Function<dim> & function,
1741 *   const LinearAlgebra::distributed::Vector<Number> &solution) const
1742 *   {
1743 *   TimerOutput::Scope t(timer, "compute errors");
1744 *   double errors_squared[3] = {};
1746 *   phi(data, 0, 0);
1747 *  
1748 *   for (unsigned int cell = 0; cell < data.n_cell_batches(); ++cell)
1749 *   {
1750 *   phi.reinit(cell);
1751 *   phi.gather_evaluate(solution, EvaluationFlags::values);
1752 *   VectorizedArrayType local_errors_squared[3] = {};
1753 *   for (unsigned int q = 0; q < phi.n_q_points; ++q)
1754 *   {
1755 *   const auto error =
1756 *   evaluate_function(function, phi.quadrature_point(q)) -
1757 *   phi.get_value(q);
1758 *   const auto JxW = phi.JxW(q);
1759 *  
1760 *   local_errors_squared[0] += error[0] * error[0] * JxW;
1761 *   for (unsigned int d = 0; d < dim; ++d)
1762 *   local_errors_squared[1] += (error[d + 1] * error[d + 1]) * JxW;
1763 *   local_errors_squared[2] += (error[dim + 1] * error[dim + 1]) * JxW;
1764 *   }
1765 *   for (unsigned int v = 0; v < data.n_active_entries_per_cell_batch(cell);
1766 *   ++v)
1767 *   for (unsigned int d = 0; d < 3; ++d)
1769 *   }
1770 *  
1772 *  
1773 *   std::array<double, 3> errors;
1774 *   for (unsigned int d = 0; d < 3; ++d)
1776 *  
1777 *   return errors;
1778 *   }
1779 *  
1780 *  
1781 *  
1782 *   template <int dim, int degree, int n_points_1d>
1784 *   const LinearAlgebra::distributed::Vector<Number> &solution) const
1785 *   {
1786 *   TimerOutput::Scope t(timer, "compute transport speed");
1787 *   Number max_transport = 0;
1789 *   phi(data, 0, 1);
1790 *  
1791 *   for (unsigned int cell = 0; cell < data.n_cell_batches(); ++cell)
1792 *   {
1793 *   phi.reinit(cell);
1794 *   phi.gather_evaluate(solution, EvaluationFlags::values);
1795 *   VectorizedArrayType local_max = 0.;
1796 *   for (unsigned int q = 0; q < phi.n_q_points; ++q)
1797 *   {
1798 *   const auto solution = phi.get_value(q);
1799 *   const auto velocity = euler_velocity<dim>(solution);
1800 *   const auto pressure = euler_pressure<dim>(solution);
1801 *  
1802 *   const auto inverse_jacobian = phi.inverse_jacobian(q);
1803 *   const auto convective_speed = inverse_jacobian * velocity;
1804 *   VectorizedArrayType convective_limit = 0.;
1805 *   for (unsigned int d = 0; d < dim; ++d)
1808 *  
1809 *   const auto speed_of_sound =
1810 *   std::sqrt(gamma * pressure * (1. / solution[0]));
1811 *  
1813 *   for (unsigned int d = 0; d < dim; ++d)
1814 *   eigenvector[d] = 1.;
1815 *   for (unsigned int i = 0; i < 5; ++i)
1816 *   {
1817 *   eigenvector = transpose(inverse_jacobian) *
1818 *   (inverse_jacobian * eigenvector);
1819 *   VectorizedArrayType eigenvector_norm = 0.;
1820 *   for (unsigned int d = 0; d < dim; ++d)
1824 *   }
1825 *   const auto jac_times_ev = inverse_jacobian * eigenvector;
1826 *   const auto max_eigenvalue = std::sqrt(
1828 *   local_max =
1830 *   max_eigenvalue * speed_of_sound + convective_limit);
1831 *   }
1832 *  
1833 *   for (unsigned int v = 0; v < data.n_active_entries_per_cell_batch(cell);
1834 *   ++v)
1835 *   for (unsigned int d = 0; d < 3; ++d)
1837 *   }
1838 *  
1840 *  
1841 *   return max_transport;
1842 *   }
1843 *  
1844 *  
1845 *  
1846 *   template <int dim>
1847 *   class EulerProblem
1848 *   {
1849 *   public:
1850 *   EulerProblem();
1851 *  
1852 *   void run();
1853 *  
1854 *   private:
1855 *   void make_grid_and_dofs();
1856 *  
1857 *   void output_results(const unsigned int result_number);
1858 *  
1860 *  
1862 *  
1865 *   #else
1867 *   #endif
1868 *  
1869 *   FESystem<dim> fe;
1870 *   MappingQ<dim> mapping;
1871 *   DoFHandler<dim> dof_handler;
1872 *  
1873 *   TimerOutput timer;
1874 *  
1876 *  
1877 *   double time, time_step;
1878 *  
1879 *   class Postprocessor : public DataPostprocessor<dim>
1880 *   {
1881 *   public:
1882 *   Postprocessor();
1883 *  
1884 *   virtual void evaluate_vector_field(
1886 *   std::vector<Vector<double>> &computed_quantities) const override;
1887 *  
1888 *   virtual std::vector<std::string> get_names() const override;
1889 *  
1890 *   virtual std::vector<
1892 *   get_data_component_interpretation() const override;
1893 *  
1894 *   virtual UpdateFlags get_needed_update_flags() const override;
1895 *  
1896 *   private:
1897 *   const bool do_schlieren_plot;
1898 *   };
1899 *   };
1900 *  
1901 *  
1902 *  
1903 *   template <int dim>
1905 *   : do_schlieren_plot(dim == 2)
1906 *   {}
1907 *  
1908 *  
1909 *  
1910 *   template <int dim>
1913 *   std::vector<Vector<double>> & computed_quantities) const
1914 *   {
1915 *   const unsigned int n_evaluation_points = inputs.solution_values.size();
1916 *  
1917 *   if (do_schlieren_plot == true)
1918 *   Assert(inputs.solution_gradients.size() == n_evaluation_points,
1919 *   ExcInternalError());
1920 *  
1922 *   ExcInternalError());
1923 *   Assert(inputs.solution_values[0].size() == dim + 2, ExcInternalError());
1924 *   Assert(computed_quantities[0].size() ==
1925 *   dim + 2 + (do_schlieren_plot == true ? 1 : 0),
1926 *   ExcInternalError());
1927 *  
1928 *   for (unsigned int p = 0; p < n_evaluation_points; ++p)
1929 *   {
1930 *   Tensor<1, dim + 2> solution;
1931 *   for (unsigned int d = 0; d < dim + 2; ++d)
1932 *   solution[d] = inputs.solution_values[p](d);
1933 *  
1934 *   const double density = solution[0];
1935 *   const Tensor<1, dim> velocity = euler_velocity<dim>(solution);
1936 *   const double pressure = euler_pressure<dim>(solution);
1937 *  
1938 *   for (unsigned int d = 0; d < dim; ++d)
1940 *   computed_quantities[p](dim) = pressure;
1941 *   computed_quantities[p](dim + 1) = std::sqrt(gamma * pressure / density);
1942 *  
1943 *   if (do_schlieren_plot == true)
1944 *   computed_quantities[p](dim + 2) =
1945 *   inputs.solution_gradients[p][0] * inputs.solution_gradients[p][0];
1946 *   }
1947 *   }
1948 *  
1949 *  
1950 *  
1951 *   template <int dim>
1952 *   std::vector<std::string> EulerProblem<dim>::Postprocessor::get_names() const
1953 *   {
1954 *   std::vector<std::string> names;
1955 *   for (unsigned int d = 0; d < dim; ++d)
1956 *   names.emplace_back("velocity");
1957 *   names.emplace_back("pressure");
1958 *   names.emplace_back("speed_of_sound");
1959 *  
1960 *   if (do_schlieren_plot == true)
1961 *   names.emplace_back("schlieren_plot");
1962 *  
1963 *   return names;
1964 *   }
1965 *  
1966 *  
1967 *  
1968 *   template <int dim>
1969 *   std::vector<DataComponentInterpretation::DataComponentInterpretation>
1971 *   {
1972 *   std::vector<DataComponentInterpretation::DataComponentInterpretation>
1974 *   for (unsigned int d = 0; d < dim; ++d)
1975 *   interpretation.push_back(
1979 *  
1980 *   if (do_schlieren_plot == true)
1981 *   interpretation.push_back(
1983 *  
1984 *   return interpretation;
1985 *   }
1986 *  
1987 *  
1988 *  
1989 *   template <int dim>
1991 *   {
1992 *   if (do_schlieren_plot == true)
1994 *   else
1995 *   return update_values;
1996 *   }
1997 *  
1998 *  
1999 *  
2000 *   template <int dim>
2005 *   #endif
2006 *   , fe(FE_DGQ<dim>(fe_degree), dim + 2)
2007 *   , mapping(fe_degree)
2008 *   , dof_handler(triangulation)
2010 *   , euler_operator(timer)
2011 *   , time(0)
2012 *   , time_step(0)
2013 *   {}
2014 *  
2015 *  
2016 *  
2017 *   template <int dim>
2019 *   {
2020 *   switch (testcase)
2021 *   {
2022 *   case 0:
2023 *   {
2025 *   for (unsigned int d = 1; d < dim; ++d)
2026 *   lower_left[d] = -5;
2027 *  
2029 *   upper_right[0] = 10;
2030 *   for (unsigned int d = 1; d < dim; ++d)
2031 *   upper_right[d] = 5;
2032 *  
2034 *   lower_left,
2035 *   upper_right);
2036 *   triangulation.refine_global(2);
2037 *  
2038 *   euler_operator.set_inflow_boundary(
2039 *   0, std::make_unique<ExactSolution<dim>>(0));
2040 *  
2041 *   break;
2042 *   }
2043 *  
2044 *   case 1:
2045 *   {
2047 *   triangulation, 0.03, 1, 0, true);
2048 *  
2049 *   euler_operator.set_inflow_boundary(
2050 *   0, std::make_unique<ExactSolution<dim>>(0));
2051 *   euler_operator.set_subsonic_outflow_boundary(
2052 *   1, std::make_unique<ExactSolution<dim>>(0));
2053 *  
2054 *   euler_operator.set_wall_boundary(2);
2055 *   euler_operator.set_wall_boundary(3);
2056 *  
2057 *   if (dim == 3)
2058 *   euler_operator.set_body_force(
2059 *   std::make_unique<Functions::ConstantFunction<dim>>(
2060 *   std::vector<double>({0., 0., -0.2})));
2061 *  
2062 *   break;
2063 *   }
2064 *  
2065 *   default:
2066 *   Assert(false, ExcNotImplemented());
2067 *   }
2068 *  
2069 *   triangulation.refine_global(n_global_refinements);
2070 *  
2071 *   dof_handler.distribute_dofs(fe);
2072 *  
2073 *   euler_operator.reinit(mapping, dof_handler);
2074 *   euler_operator.initialize_vector(solution);
2075 *  
2076 *   std::locale s = pcout.get_stream().getloc();
2077 *   pcout.get_stream().imbue(std::locale(""));
2078 *   pcout << "Number of degrees of freedom: " << dof_handler.n_dofs()
2079 *   << " ( = " << (dim + 2) << " [vars] x "
2080 *   << triangulation.n_global_active_cells() << " [cells] x "
2081 *   << Utilities::pow(fe_degree + 1, dim) << " [dofs/cell/var] )"
2082 *   << std::endl;
2083 *   pcout.get_stream().imbue(s);
2084 *   }
2085 *  
2086 *  
2087 *  
2088 *   template <int dim>
2089 *   void EulerProblem<dim>::output_results(const unsigned int result_number)
2090 *   {
2091 *   const std::array<double, 3> errors =
2092 *   euler_operator.compute_errors(ExactSolution<dim>(time), solution);
2093 *   const std::string quantity_name = testcase == 0 ? "error" : "norm";
2094 *  
2095 *   pcout << "Time:" << std::setw(8) << std::setprecision(3) << time
2096 *   << ", dt: " << std::setw(8) << std::setprecision(2) << time_step
2097 *   << ", " << quantity_name << " rho: " << std::setprecision(4)
2098 *   << std::setw(10) << errors[0] << ", rho * u: " << std::setprecision(4)
2099 *   << std::setw(10) << errors[1] << ", energy:" << std::setprecision(4)
2100 *   << std::setw(10) << errors[2] << std::endl;
2101 *  
2102 *   {
2103 *   TimerOutput::Scope t(timer, "output");
2104 *  
2105 *   Postprocessor postprocessor;
2106 *   DataOut<dim> data_out;
2107 *  
2109 *   flags.write_higher_order_cells = true;
2110 *   data_out.set_flags(flags);
2111 *  
2112 *   data_out.attach_dof_handler(dof_handler);
2113 *   {
2114 *   std::vector<std::string> names;
2115 *   names.emplace_back("density");
2116 *   for (unsigned int d = 0; d < dim; ++d)
2117 *   names.emplace_back("momentum");
2118 *   names.emplace_back("energy");
2119 *  
2120 *   std::vector<DataComponentInterpretation::DataComponentInterpretation>
2122 *   interpretation.push_back(
2124 *   for (unsigned int d = 0; d < dim; ++d)
2125 *   interpretation.push_back(
2127 *   interpretation.push_back(
2129 *  
2130 *   data_out.add_data_vector(dof_handler, solution, names, interpretation);
2131 *   }
2132 *   data_out.add_data_vector(solution, postprocessor);
2133 *  
2135 *   if (testcase == 0 && dim == 2)
2136 *   {
2137 *   reference.reinit(solution);
2138 *   euler_operator.project(ExactSolution<dim>(time), reference);
2139 *   reference.sadd(-1., 1, solution);
2140 *   std::vector<std::string> names;
2141 *   names.emplace_back("error_density");
2142 *   for (unsigned int d = 0; d < dim; ++d)
2143 *   names.emplace_back("error_momentum");
2144 *   names.emplace_back("error_energy");
2145 *  
2146 *   std::vector<DataComponentInterpretation::DataComponentInterpretation>
2148 *   interpretation.push_back(
2150 *   for (unsigned int d = 0; d < dim; ++d)
2151 *   interpretation.push_back(
2153 *   interpretation.push_back(
2155 *  
2156 *   data_out.add_data_vector(dof_handler,
2157 *   reference,
2158 *   names,
2160 *   }
2161 *  
2162 *   Vector<double> mpi_owner(triangulation.n_active_cells());
2164 *   data_out.add_data_vector(mpi_owner, "owner");
2165 *  
2166 *   data_out.build_patches(mapping,
2167 *   fe.degree,
2169 *  
2170 *   const std::string filename =
2171 *   "solution_" + Utilities::int_to_string(result_number, 3) + ".vtu";
2172 *   data_out.write_vtu_in_parallel(filename, MPI_COMM_WORLD);
2173 *   }
2174 *   }
2175 *  
2176 *  
2177 *  
2178 *   template <int dim>
2180 *   {
2181 *   {
2182 *   const unsigned int n_vect_number = VectorizedArrayType::size();
2183 *   const unsigned int n_vect_bits = 8 * sizeof(Number) * n_vect_number;
2184 *  
2185 *   pcout << "Running with "
2187 *   << " MPI processes" << std::endl;
2188 *   pcout << "Vectorization over " << n_vect_number << ' '
2189 *   << (std::is_same<Number, double>::value ? "doubles" : "floats")
2190 *   << " = " << n_vect_bits << " bits ("
2192 *   << std::endl;
2193 *   }
2194 *  
2196 *  
2198 *  
2201 *   rk_register_1.reinit(solution);
2202 *   rk_register_2.reinit(solution);
2203 *  
2204 *   euler_operator.project(ExactSolution<dim>(time), solution);
2205 *  
2206 *  
2207 *   double min_vertex_distance = std::numeric_limits<double>::max();
2208 *   for (const auto &cell : triangulation.active_cell_iterators())
2209 *   if (cell->is_locally_owned())
2211 *   std::min(min_vertex_distance, cell->minimum_vertex_distance());
2214 *  
2215 *   time_step = courant_number * integrator.n_stages() /
2216 *   euler_operator.compute_cell_transport_speed(solution);
2217 *   pcout << "Time step size: " << time_step
2218 *   << ", minimal h: " << min_vertex_distance
2219 *   << ", initial transport scaling: "
2220 *   << 1. / euler_operator.compute_cell_transport_speed(solution)
2221 *   << std::endl
2222 *   << std::endl;
2223 *  
2224 *   output_results(0);
2225 *  
2226 *   unsigned int timestep_number = 0;
2227 *  
2228 *   while (time < final_time - 1e-12 && timestep_number < max_time_steps)
2229 *   {
2231 *   if (timestep_number % 5 == 0)
2232 *   time_step =
2233 *   courant_number * integrator.n_stages() /
2235 *   euler_operator.compute_cell_transport_speed(solution), 3);
2236 *  
2237 *   {
2238 *   TimerOutput::Scope t(timer, "rk time stepping total");
2239 *   integrator.perform_time_step(euler_operator,
2240 *   time,
2241 *   time_step,
2242 *   solution,
2245 *   }
2246 *  
2247 *   time += time_step;
2248 *  
2249 *   if (static_cast<int>(time / output_tick) !=
2250 *   static_cast<int>((time - time_step) / output_tick) ||
2251 *   time >= final_time - 1e-12)
2253 *   static_cast<unsigned int>(std::round(time / output_tick)));
2254 *   }
2255 *  
2256 *   timer.print_wall_time_statistics(MPI_COMM_WORLD);
2257 *   pcout << std::endl;
2258 *   }
2259 *  
2260 *   } // namespace Euler_DG
2261 *  
2262 *  
2263 *   int main(int argc, char **argv)
2264 *   {
2265 *   using namespace Euler_DG;
2266 *   using namespace dealii;
2267 *  
2269 *  
2270 *   try
2271 *   {
2273 *  
2275 *   euler_problem.run();
2276 *   }
2277 *   catch (std::exception &exc)
2278 *   {
2279 *   std::cerr << std::endl
2280 *   << std::endl
2281 *   << "----------------------------------------------------"
2282 *   << std::endl;
2283 *   std::cerr << "Exception on processing: " << std::endl
2284 *   << exc.what() << std::endl
2285 *   << "Aborting!" << std::endl
2286 *   << "----------------------------------------------------"
2287 *   << std::endl;
2288 *  
2289 *   return 1;
2290 *   }
2291 *   catch (...)
2292 *   {
2293 *   std::cerr << std::endl
2294 *   << std::endl
2295 *   << "----------------------------------------------------"
2296 *   << std::endl;
2297 *   std::cerr << "Unknown exception!" << std::endl
2298 *   << "Aborting!" << std::endl
2299 *   << "----------------------------------------------------"
2300 *   << std::endl;
2301 *   return 1;
2302 *   }
2303 *  
2304 *   return 0;
2305 *   }
2306 * @endcode
2307<a name="Results"></a><h1>Results</h1>
2308
2309
2311produces the following output:
2312
2313@code
2314Running with 40 MPI processes
2316Number of degrees of freedom: 27.648.000 ( = 5 [vars] x 25.600 [cells] x 216 [dofs/cell/var] )
2317Time step size: 0.000295952, minimal h: 0.0075, initial transport scaling: 0.00441179
2318Time: 0, dt: 0.0003, norm rho: 5.385e-16, rho * u: 1.916e-16, energy: 1.547e-15
2319+--------------------------------------+------------------+------------+------------------+
2320| Total wallclock time elapsed | 17.52s 10 | 17.52s | 17.52s 11 |
2321| | | |
2322| Section | no. calls | min time rank | avg time | max time rank |
2323+--------------------------------------+------------------+------------+------------------+
2324| compute errors | 1 | 0.009594s 16 | 0.009705s | 0.009819s 8 |
2325| compute transport speed | 22 | 0.1366s 0 | 0.1367s | 0.1368s 18 |
2326| output | 1 | 1.233s 0 | 1.233s | 1.233s 32 |
2327| rk time stepping total | 100 | 8.746s 35 | 8.746s | 8.746s 0 |
2328| rk_stage - integrals L_h | 500 | 8.742s 36 | 8.742s | 8.743s 2 |
2329+--------------------------------------+------------------+------------+------------------+
2330@endcode
2331
2332and the following visual output:
2333
2334<table align="center" class="doxtable" style="width:85%">
2335 <tr>
2336 <td>
2337 <img src="https://www.dealii.org/images/steps/developer/step-67.pressure_010.png" alt="" width="100%">
2338 </td>
2339 <td>
2340 <img src="https://www.dealii.org/images/steps/developer/step-67.pressure_025.png" alt="" width="100%">
2341 </td>
2342 </tr>
2343 <tr>
2344 <td>
2345 <img src="https://www.dealii.org/images/steps/developer/step-67.pressure_050.png" alt="" width="100%">
2346 </td>
2347 <td>
2348 <img src="https://www.dealii.org/images/steps/developer/step-67.pressure_100.png" alt="" width="100%">
2349 </td>
2350 </tr>
2351</table>
2352
2353As a reference, the results of @ref step_67 "step-67" using FCL are:
2354
2355@code
2356Running with 40 MPI processes
2358Number of degrees of freedom: 27.648.000 ( = 5 [vars] x 25.600 [cells] x 216 [dofs/cell/var] )
2359Time step size: 0.000295952, minimal h: 0.0075, initial transport scaling: 0.00441179
2360Time: 0, dt: 0.0003, norm rho: 5.385e-16, rho * u: 1.916e-16, energy: 1.547e-15
2361+-------------------------------------------+------------------+------------+------------------+
2362| Total wallclock time elapsed | 13.33s 0 | 13.34s | 13.35s 34 |
2363| | | |
2364| Section | no. calls | min time rank | avg time | max time rank |
2365+-------------------------------------------+------------------+------------+------------------+
2366| compute errors | 1 | 0.007977s 10 | 0.008053s | 0.008161s 30 |
2367| compute transport speed | 22 | 0.1228s 34 | 0.2227s | 0.3845s 0 |
2368| output | 1 | 1.255s 3 | 1.257s | 1.259s 27 |
2369| rk time stepping total | 100 | 11.15s 0 | 11.32s | 11.42s 34 |
2370| rk_stage - integrals L_h | 500 | 8.719s 10 | 8.932s | 9.196s 0 |
2371| rk_stage - inv mass + vec upd | 500 | 1.944s 0 | 2.377s | 2.55s 10 |
2372+-------------------------------------------+------------------+------------+------------------+
2373@endcode
2374
2377
2378<a name="Possibilitiesforextensions"></a><h3>Possibilities for extensions</h3>
2379
2380
2382<a href="https://github.com/hyperdeal/hyperdeal/blob/a9e67b4e625ff1dde2fed93ad91cdfacfaa3acdf/include/hyper.deal/operators/advection/advection_operation.h#L219-L569">advection operator based on cell-centric loops</a>
2385
2386<a name="ExtensiontothecompressibleNavierStokesequations"></a><h4>Extension to the compressible Navier-Stokes equations</h4>
2387
2388
2392the additional cost of elliptic terms, e.g. via an interior penalty method, that
2394the @ref step_59 "step-59" tutorial program. The reasoning behind this switch is that in the
2395case of FE_DGQ all values of neighboring cells (i.e., @f$k+1@f$ layers) are needed,
2402
2403<a name="BlockGaussSeidellikepreconditioners"></a><h4>Block Gauss-Seidel-like preconditioners</h4>
2404
2405
2406Cell-centric loops could be used to create block Gauss-Seidel preconditioners
2411
2412@code
2413// vector monitor if cells have been updated or not
2414Vector<Number> visit_flags(data.n_cell_batches () + data.n_ghost_cell_batches ());
2415
2416// element centric loop with a modified kernel
2418 [&](const auto &data, auto &dst, const auto &src, const auto cell_range) {
2419
2420 for (unsigned int cell = cell_range.first; cell < cell_range.second; ++cell)
2421 {
2422 // cell integral as usual (not shown)
2423
2424 for (unsigned int face = 0; face < GeometryInfo<dim>::faces_per_cell; ++face)
2425 {
2426 const auto boundary_id = data.get_faces_by_cells_boundary_id(cell, face)[0];
2427
2428 if (boundary_id == numbers::internal_face_boundary_id)
2429 {
2430 phi_p.reinit(cell, face);
2431
2432 const auto flags = phi_p.read_cell_data(visit_flags);
2434 std::min(flags.begin(),
2435 flags().begin() + data.n_active_entries_per_cell_batch(cell) == 1;
2436
2438 phi_p.gather_evaluate(dst, EvaluationFlags::values);
2439 else
2440 phi_p.gather_evaluate(src, EvaluationFlags::values);
2441
2442 // continue as usual (not shown)
2443 }
2444 else
2445 {
2446 // boundary integral as usual (not shown)
2447 }
2448 }
2449
2450 // continue as above and apply your favorite algorithm to invert
2451 // the cell-local operator (not shown)
2452
2453 // make cells as updated
2454 phi.set_cell_data(visit_flags, VectorizedArrayType(1.0));
2455 }
2456 },
2457 dst,
2458 src,
2459 true,
2461@endcode
2462
2463For this purpose, one can exploit the cell-data vector capabilities of
2465
2466Please note that in the given example we process <code>VectorizedArrayType::size()</code>
2467number of blocks, since each lane corresponds to one block. We consider blocks
2468as updated if all blocks processed by a vector register have been updated. In
2471efficiency of the preconditioner. A reduction of cells processed in parallel
2472by explicitly reducing the number of lanes used by <code>VectorizedArrayType</code>
2475"possibility for extension": vectorization within an element.
2476 *
2477 *
2478<a name="PlainProg"></a>
2479<h1> The plain program</h1>
2480@include "step-76.cc"
2481*/
iterator begin() const
Definition array_view.h:594
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
void submit_value(const value_type val_in, const unsigned int q_point)
unsigned int depth_console(const unsigned int n)
Definition logstream.cc:350
Abstract base class for mapping classes.
Definition mapping.h:317
void loop_cell_centric(void(CLASS::*cell_operation)(const MatrixFree &, OutVector &, const InVector &, const std::pair< unsigned int, unsigned int > &) const, const CLASS *owning_class, OutVector &dst, const InVector &src, const bool zero_dst_vector=false, const DataAccessOnFaces src_vector_face_access=DataAccessOnFaces::unspecified) const
void reinit(const MappingType &mapping, const DoFHandler< dim > &dof_handler, const AffineConstraints< number2 > &constraint, const QuadratureType &quad, const AdditionalData &additional_data=AdditionalData())
@ wall_times
Definition timer.h:652
std::enable_if_t< std::is_floating_point< T >::value &&std::is_floating_point< U >::value, typename ProductType< std::complex< T >, std::complex< U > >::type > operator*(const std::complex< T > &left, const std::complex< U > &right)
#define DEAL_II_ALWAYS_INLINE
Definition config.h:106
#define DEAL_II_WITH_P4EST
Definition config.h:60
#define DEAL_II_WITH_MPI
Definition config.h:56
DerivativeForm< 1, spacedim, dim, Number > transpose(const DerivativeForm< 1, dim, spacedim, Number > &DF)
Point< 2 > second
Definition grid_out.cc:4616
Point< 2 > first
Definition grid_out.cc:4615
unsigned int level
Definition grid_out.cc:4618
__global__ void reduction(Number *result, const Number *v, const size_type N)
__global__ void set(Number *val, const Number s, const size_type N)
#define Assert(cond, exc)
#define AssertDimension(dim1, dim2)
#define AssertThrow(cond, exc)
void loop(ITERATOR begin, std_cxx20::type_identity_t< ITERATOR > end, DOFINFO &dinfo, INFOBOX &info, const std::function< void(DOFINFO &, typename INFOBOX::CellInfo &)> &cell_worker, const std::function< void(DOFINFO &, typename INFOBOX::CellInfo &)> &boundary_worker, const std::function< void(DOFINFO &, DOFINFO &, typename INFOBOX::CellInfo &, typename INFOBOX::CellInfo &)> &face_worker, ASSEMBLER &assembler, const LoopControl &lctrl=LoopControl())
Definition loop.h:439
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:37
const Event initial
Definition event.cc:65
void hyper_rectangle(Triangulation< dim, spacedim > &tria, const Point< dim > &p1, const Point< dim > &p2, const bool colorize=false)
void channel_with_cylinder(Triangulation< dim > &tria, const double shell_region_width=0.03, const unsigned int n_shells=2, const double skewness=2.0, const bool colorize=false)
@ matrix
Contents is actually a matrix.
@ general
No special properties.
double norm(const FEValuesBase< dim > &fe, const ArrayView< const std::vector< Tensor< 1, dim > > > &Du)
Definition divergence.h:472
Point< spacedim > point(const gp_Pnt &p, const double tolerance=1e-10)
Definition utilities.cc:189
SymmetricTensor< 2, dim, Number > C(const Tensor< 2, dim, Number > &F)
SymmetricTensor< 2, dim, Number > e(const Tensor< 2, dim, Number > &F)
SymmetricTensor< 2, dim, Number > d(const Tensor< 2, dim, Number > &F, const Tensor< 2, dim, Number > &dF_dt)
@ LOW_STORAGE_RK_STAGE9_ORDER5
@ LOW_STORAGE_RK_STAGE3_ORDER3
@ LOW_STORAGE_RK_STAGE7_ORDER4
@ LOW_STORAGE_RK_STAGE5_ORDER4
VectorType::value_type * begin(VectorType &V)
void free(T *&pointer)
Definition cuda.h:97
T sum(const T &t, const MPI_Comm mpi_communicator)
unsigned int n_mpi_processes(const MPI_Comm mpi_communicator)
Definition mpi.cc:150
T max(const T &t, const MPI_Comm mpi_communicator)
T min(const T &t, const MPI_Comm mpi_communicator)
unsigned int this_mpi_process(const MPI_Comm mpi_communicator)
Definition mpi.cc:161
T reduce(const T &local_value, const MPI_Comm comm, const std::function< T(const T &, const T &)> &combiner, const unsigned int root_process=0)
std::string get_time()
const std::string get_current_vectorization_level()
Definition utilities.cc:939
constexpr T pow(const T base, const int iexp)
Definition utilities.h:447
Number truncate_to_n_digits(const Number number, const unsigned int n_digits)
Definition utilities.cc:579
std::string int_to_string(const unsigned int value, const unsigned int digits=numbers::invalid_unsigned_int)
Definition utilities.cc:471
void project(const Mapping< dim, spacedim > &mapping, const DoFHandler< dim, spacedim > &dof, const AffineConstraints< typename VectorType::value_type > &constraints, const Quadrature< dim > &quadrature, const Function< spacedim, typename VectorType::value_type > &function, VectorType &vec, const bool enforce_zero_boundary=false, const Quadrature< dim - 1 > &q_boundary=(dim > 1 ? QGauss< dim - 1 >(2) :Quadrature< dim - 1 >(0)), const bool project_to_boundary_first=false)
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)
long double gamma(const unsigned int n)
void copy(const T *begin, const T *end, U *dest)
int(&) functions(const void *v1, const void *v2)
void reinit(MatrixBlock< MatrixType > &v, const BlockSparsityPattern &p)
static constexpr double PI
Definition numbers.h:259
const types::boundary_id internal_face_boundary_id
Definition types.h:277
static const unsigned int invalid_unsigned_int
Definition types.h:213
void transform(const InputIterator &begin_in, const InputIterator &end_in, OutputIterator out, const Function &function, const unsigned int grainsize)
Definition parallel.h:148
STL namespace.
::VectorizedArray< Number, width > exp(const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > min(const ::VectorizedArray< Number, width > &, const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > max(const ::VectorizedArray< Number, width > &, const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > sqrt(const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > pow(const ::VectorizedArray< Number, width > &, const Number p)
::VectorizedArray< Number, width > abs(const ::VectorizedArray< Number, width > &)
Definition types.h:33
unsigned int boundary_id
Definition types.h:141
const ::parallel::distributed::Triangulation< dim, spacedim > * triangulation
const TriangulationDescription::Settings settings