Reference documentation for deal.II version 9.3.2
\(\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\}}\)
step-50.h
Go to the documentation of this file.
1 ,
480  * const unsigned int /*component*/ = 0) const override
481  * {
482  * return 1.0;
483  * }
484  *
485  *
486  * template <typename number>
488  * value(const Point<dim, VectorizedArray<number>> & /*p*/,
489  * const unsigned int /*component*/ = 0) const
490  * {
491  * return VectorizedArray<number>(1.0);
492  * }
493  * };
494  *
495  *
496  * @endcode
497  *
498  * This next class represents the diffusion coefficient. We use a variable
499  * coefficient which is 100.0 at any point where at least one coordinate is
500  * less than -0.5, and 1.0 at all other points. As above, a separate value()
501  * returning a VectorizedArray is used for the matrix-free code. An @p
502  * average() function computes the arithmetic average for a set of points.
503  *
504  * @code
505  * template <int dim>
506  * class Coefficient : public Function<dim>
507  * {
508  * public:
509  * virtual double value(const Point<dim> &p,
510  * const unsigned int /*component*/ = 0) const override;
511  *
512  * template <typename number>
514  * const unsigned int /*component*/ = 0) const;
515  *
516  * template <typename number>
517  * number average_value(const std::vector<Point<dim, number>> &points) const;
518  *
519  * @endcode
520  *
521  * When using a coefficient in the MatrixFree framework, we also
522  * need a function that creates a Table of coefficient values for a
523  * set of cells provided by the MatrixFree operator argument here.
524  *
525  * @code
526  * template <typename number>
527  * std::shared_ptr<Table<2, VectorizedArray<number>>> make_coefficient_table(
528  * const MatrixFree<dim, number, VectorizedArray<number>> &mf_storage) const;
529  * };
530  *
531  *
532  *
533  * template <int dim>
534  * double Coefficient<dim>::value(const Point<dim> &p, const unsigned int) const
535  * {
536  * for (int d = 0; d < dim; ++d)
537  * {
538  * if (p[d] < -0.5)
539  * return 100.0;
540  * }
541  * return 1.0;
542  * }
543  *
544  *
545  *
546  * template <int dim>
547  * template <typename number>
549  * Coefficient<dim>::value(const Point<dim, VectorizedArray<number>> &p,
550  * const unsigned int) const
551  * {
552  * VectorizedArray<number> return_value = VectorizedArray<number>(1.0);
553  * for (unsigned int i = 0; i < VectorizedArray<number>::size(); ++i)
554  * {
555  * for (int d = 0; d < dim; ++d)
556  * if (p[d][i] < -0.5)
557  * {
558  * return_value[i] = 100.0;
559  * break;
560  * }
561  * }
562  *
563  * return return_value;
564  * }
565  *
566  *
567  *
568  * template <int dim>
569  * template <typename number>
570  * number Coefficient<dim>::average_value(
571  * const std::vector<Point<dim, number>> &points) const
572  * {
573  * number average(0);
574  * for (unsigned int i = 0; i < points.size(); ++i)
575  * average += value(points[i]);
576  * average /= points.size();
577  *
578  * return average;
579  * }
580  *
581  *
582  *
583  * template <int dim>
584  * template <typename number>
585  * std::shared_ptr<Table<2, VectorizedArray<number>>>
586  * Coefficient<dim>::make_coefficient_table(
587  * const MatrixFree<dim, number, VectorizedArray<number>> &mf_storage) const
588  * {
589  * auto coefficient_table =
590  * std::make_shared<Table<2, VectorizedArray<number>>>();
591  *
592  * FEEvaluation<dim, -1, 0, 1, number> fe_eval(mf_storage);
593  *
594  * const unsigned int n_cells = mf_storage.n_cell_batches();
595  * const unsigned int n_q_points = fe_eval.n_q_points;
596  *
597  * coefficient_table->reinit(n_cells, 1);
598  *
599  * for (unsigned int cell = 0; cell < n_cells; ++cell)
600  * {
601  * fe_eval.reinit(cell);
602  *
603  * VectorizedArray<number> average_value = 0.;
604  * for (unsigned int q = 0; q < n_q_points; ++q)
605  * average_value += value(fe_eval.quadrature_point(q));
606  * average_value /= n_q_points;
607  *
608  * (*coefficient_table)(cell, 0) = average_value;
609  * }
610  *
611  * return coefficient_table;
612  * }
613  *
614  *
615  *
616  * @endcode
617  *
618  *
619  * <a name="Runtimeparameters"></a>
620  * <h3>Run time parameters</h3>
621  *
622 
623  *
624  * We will use ParameterHandler to pass in parameters at runtime. The
625  * structure @p Settings parses and stores these parameters to be queried
626  * throughout the program.
627  *
628  * @code
629  * struct Settings
630  * {
631  * bool try_parse(const std::string &prm_filename);
632  *
633  * enum SolverType
634  * {
635  * gmg_mb,
636  * gmg_mf,
637  * amg
638  * };
639  *
640  * SolverType solver;
641  *
642  * int dimension;
643  * double smoother_dampen;
644  * unsigned int smoother_steps;
645  * unsigned int n_steps;
646  * bool output;
647  * };
648  *
649  *
650  *
651  * bool Settings::try_parse(const std::string &prm_filename)
652  * {
653  * ParameterHandler prm;
654  * prm.declare_entry("dim", "2", Patterns::Integer(), "The problem dimension.");
655  * prm.declare_entry("n_steps",
656  * "10",
657  * Patterns::Integer(0),
658  * "Number of adaptive refinement steps.");
659  * prm.declare_entry("smoother dampen",
660  * "1.0",
661  * Patterns::Double(0.0),
662  * "Dampen factor for the smoother.");
663  * prm.declare_entry("smoother steps",
664  * "1",
665  * Patterns::Integer(1),
666  * "Number of smoother steps.");
667  * prm.declare_entry("solver",
668  * "MF",
669  * Patterns::Selection("MF|MB|AMG"),
670  * "Switch between matrix-free GMG, "
671  * "matrix-based GMG, and AMG.");
672  * prm.declare_entry("output",
673  * "false",
674  * Patterns::Bool(),
675  * "Output graphical results.");
676  *
677  * if (prm_filename.size() == 0)
678  * {
679  * std::cout << "**** Error: No input file provided!\n"
680  * << "**** Error: Call this program as './step-50 input.prm\n"
681  * << "\n"
682  * << "**** You may want to use one of the input files in this\n"
683  * << "**** directory, or use the following default values\n"
684  * << "**** to create an input file:\n";
685  * if (Utilities::MPI::this_mpi_process(MPI_COMM_WORLD) == 0)
686  * prm.print_parameters(std::cout, ParameterHandler::Text);
687  * return false;
688  * }
689  *
690  * try
691  * {
692  * prm.parse_input(prm_filename);
693  * }
694  * catch (std::exception &e)
695  * {
696  * if (Utilities::MPI::this_mpi_process(MPI_COMM_WORLD) == 0)
697  * std::cerr << e.what() << std::endl;
698  * return false;
699  * }
700  *
701  * if (prm.get("solver") == "MF")
702  * this->solver = gmg_mf;
703  * else if (prm.get("solver") == "MB")
704  * this->solver = gmg_mb;
705  * else if (prm.get("solver") == "AMG")
706  * this->solver = amg;
707  * else
708  * AssertThrow(false, ExcNotImplemented());
709  *
710  * this->dimension = prm.get_integer("dim");
711  * this->n_steps = prm.get_integer("n_steps");
712  * this->smoother_dampen = prm.get_double("smoother dampen");
713  * this->smoother_steps = prm.get_integer("smoother steps");
714  * this->output = prm.get_bool("output");
715  *
716  * return true;
717  * }
718  *
719  *
720  *
721  * @endcode
722  *
723  *
724  * <a name="LaplaceProblemclass"></a>
725  * <h3>LaplaceProblem class</h3>
726  *
727 
728  *
729  * This is the main class of the program. It looks very similar to
730  * @ref step_16 "step-16", @ref step_37 "step-37", and @ref step_40 "step-40". For the MatrixFree setup, we use the
731  * MatrixFreeOperators::LaplaceOperator class which defines `local_apply()`,
732  * `compute_diagonal()`, and `set_coefficient()` functions internally. Note that
733  * the polynomial degree is a template parameter of this class. This is
734  * necessary for the matrix-free code.
735  *
736  * @code
737  * template <int dim, int degree>
738  * class LaplaceProblem
739  * {
740  * public:
741  * LaplaceProblem(const Settings &settings);
742  * void run();
743  *
744  * private:
745  * @endcode
746  *
747  * We will use the following types throughout the program. First the
748  * matrix-based types, after that the matrix-free classes. For the
749  * matrix-free implementation, we use @p float for the level operators.
750  *
751  * @code
752  * using MatrixType = LA::MPI::SparseMatrix;
753  * using VectorType = LA::MPI::Vector;
756  *
757  * using MatrixFreeLevelMatrix = MatrixFreeOperators::LaplaceOperator<
758  * dim,
759  * degree,
760  * degree + 1,
761  * 1,
763  * using MatrixFreeActiveMatrix = MatrixFreeOperators::LaplaceOperator<
764  * dim,
765  * degree,
766  * degree + 1,
767  * 1,
769  *
770  * using MatrixFreeLevelVector = LinearAlgebra::distributed::Vector<float>;
771  * using MatrixFreeActiveVector = LinearAlgebra::distributed::Vector<double>;
772  *
773  * void setup_system();
774  * void setup_multigrid();
775  * void assemble_system();
776  * void assemble_multigrid();
777  * void assemble_rhs();
778  * void solve();
779  * void estimate();
780  * void refine_grid();
781  * void output_results(const unsigned int cycle);
782  *
783  * Settings settings;
784  *
785  * MPI_Comm mpi_communicator;
786  * ConditionalOStream pcout;
787  *
789  * const MappingQ1<dim> mapping;
790  * FE_Q<dim> fe;
791  *
792  * DoFHandler<dim> dof_handler;
793  *
794  * IndexSet locally_owned_dofs;
795  * IndexSet locally_relevant_dofs;
796  * AffineConstraints<double> constraints;
797  *
798  * MatrixType system_matrix;
799  * MatrixFreeActiveMatrix mf_system_matrix;
800  * VectorType solution;
801  * VectorType right_hand_side;
802  * Vector<double> estimated_error_square_per_cell;
803  *
804  * MGLevelObject<MatrixType> mg_matrix;
805  * MGLevelObject<MatrixType> mg_interface_in;
806  * MGConstrainedDoFs mg_constrained_dofs;
807  *
809  *
810  * TimerOutput computing_timer;
811  * };
812  *
813  *
814  * @endcode
815  *
816  * The only interesting part about the constructor is that we construct the
817  * multigrid hierarchy unless we use AMG. For that, we need to parse the
818  * run time parameters before this constructor completes.
819  *
820  * @code
821  * template <int dim, int degree>
822  * LaplaceProblem<dim, degree>::LaplaceProblem(const Settings &settings)
823  * : settings(settings)
824  * , mpi_communicator(MPI_COMM_WORLD)
825  * , pcout(std::cout, (Utilities::MPI::this_mpi_process(mpi_communicator) == 0))
826  * , triangulation(mpi_communicator,
828  * (settings.solver == Settings::amg) ?
832  * , mapping()
833  * , fe(degree)
834  * , dof_handler(triangulation)
835  * , computing_timer(pcout, TimerOutput::never, TimerOutput::wall_times)
836  * {
837  * GridGenerator::hyper_L(triangulation, -1., 1., /*colorize*/ false);
838  * triangulation.refine_global(1);
839  * }
840  *
841  *
842  *
843  * @endcode
844  *
845  *
846  * <a name="LaplaceProblemsetup_system"></a>
847  * <h4>LaplaceProblem::setup_system()</h4>
848  *
849 
850  *
851  * Unlike @ref step_16 "step-16" and @ref step_37 "step-37", we split the set up into two parts,
852  * setup_system() and setup_multigrid(). Here is the typical setup_system()
853  * function for the active mesh found in most tutorials. For matrix-free, the
854  * active mesh set up is similar to @ref step_37 "step-37"; for matrix-based (GMG and AMG
855  * solvers), the setup is similar to @ref step_40 "step-40".
856  *
857  * @code
858  * template <int dim, int degree>
859  * void LaplaceProblem<dim, degree>::setup_system()
860  * {
861  * TimerOutput::Scope timing(computing_timer, "Setup");
862  *
863  * dof_handler.distribute_dofs(fe);
864  *
865  * DoFTools::extract_locally_relevant_dofs(dof_handler, locally_relevant_dofs);
866  * locally_owned_dofs = dof_handler.locally_owned_dofs();
867  *
868  * solution.reinit(locally_owned_dofs, mpi_communicator);
869  * right_hand_side.reinit(locally_owned_dofs, mpi_communicator);
870  * constraints.reinit(locally_relevant_dofs);
871  * DoFTools::make_hanging_node_constraints(dof_handler, constraints);
872  *
874  * mapping, dof_handler, 0, Functions::ZeroFunction<dim>(), constraints);
875  * constraints.close();
876  *
877  * switch (settings.solver)
878  * {
879  * case Settings::gmg_mf:
880  * {
881  * typename MatrixFree<dim, double>::AdditionalData additional_data;
882  * additional_data.tasks_parallel_scheme =
884  * additional_data.mapping_update_flags =
886  * std::shared_ptr<MatrixFree<dim, double>> mf_storage =
887  * std::make_shared<MatrixFree<dim, double>>();
888  * mf_storage->reinit(mapping,
889  * dof_handler,
890  * constraints,
891  * QGauss<1>(degree + 1),
892  * additional_data);
893  *
894  * mf_system_matrix.initialize(mf_storage);
895  *
896  * const Coefficient<dim> coefficient;
897  * mf_system_matrix.set_coefficient(
898  * coefficient.make_coefficient_table(*mf_storage));
899  *
900  * break;
901  * }
902  *
903  * case Settings::gmg_mb:
904  * case Settings::amg:
905  * {
906  * #ifdef USE_PETSC_LA
907  * DynamicSparsityPattern dsp(locally_relevant_dofs);
908  * DoFTools::make_sparsity_pattern(dof_handler, dsp, constraints);
909  *
911  * locally_owned_dofs,
912  * mpi_communicator,
913  * locally_relevant_dofs);
914  *
915  * system_matrix.reinit(locally_owned_dofs,
916  * locally_owned_dofs,
917  * dsp,
918  * mpi_communicator);
919  * #else
920  * TrilinosWrappers::SparsityPattern dsp(locally_owned_dofs,
921  * locally_owned_dofs,
922  * locally_relevant_dofs,
923  * mpi_communicator);
924  * DoFTools::make_sparsity_pattern(dof_handler, dsp, constraints);
925  * dsp.compress();
926  * system_matrix.reinit(dsp);
927  * #endif
928  *
929  * break;
930  * }
931  *
932  * default:
933  * Assert(false, ExcNotImplemented());
934  * }
935  * }
936  *
937  * @endcode
938  *
939  *
940  * <a name="LaplaceProblemsetup_multigrid"></a>
941  * <h4>LaplaceProblem::setup_multigrid()</h4>
942  *
943 
944  *
945  * This function does the multilevel setup for both matrix-free and
946  * matrix-based GMG. The matrix-free setup is similar to that of @ref step_37 "step-37", and
947  * the matrix-based is similar to @ref step_16 "step-16", except we must use appropriate
948  * distributed sparsity patterns.
949  *
950 
951  *
952  * The function is not called for the AMG approach, but to err on the
953  * safe side, the main `switch` statement of this function
954  * nevertheless makes sure that the function only operates on known
955  * multigrid settings by throwing an assertion if the function were
956  * called for anything other than the two geometric multigrid methods.
957  *
958  * @code
959  * template <int dim, int degree>
960  * void LaplaceProblem<dim, degree>::setup_multigrid()
961  * {
962  * TimerOutput::Scope timing(computing_timer, "Setup multigrid");
963  *
964  * dof_handler.distribute_mg_dofs();
965  *
966  * mg_constrained_dofs.clear();
967  * mg_constrained_dofs.initialize(dof_handler);
968  *
969  * const std::set<types::boundary_id> boundary_ids = {types::boundary_id(0)};
970  * mg_constrained_dofs.make_zero_boundary_constraints(dof_handler, boundary_ids);
971  *
972  * const unsigned int n_levels = triangulation.n_global_levels();
973  *
974  * switch (settings.solver)
975  * {
976  * case Settings::gmg_mf:
977  * {
978  * mf_mg_matrix.resize(0, n_levels - 1);
979  *
980  * for (unsigned int level = 0; level < n_levels; ++level)
981  * {
982  * IndexSet relevant_dofs;
984  * level,
985  * relevant_dofs);
986  * AffineConstraints<double> level_constraints;
987  * level_constraints.reinit(relevant_dofs);
988  * level_constraints.add_lines(
989  * mg_constrained_dofs.get_boundary_indices(level));
990  * level_constraints.close();
991  *
992  * typename MatrixFree<dim, float>::AdditionalData additional_data;
993  * additional_data.tasks_parallel_scheme =
995  * additional_data.mapping_update_flags =
998  * additional_data.mg_level = level;
999  * std::shared_ptr<MatrixFree<dim, float>> mf_storage_level(
1000  * new MatrixFree<dim, float>());
1001  * mf_storage_level->reinit(mapping,
1002  * dof_handler,
1003  * level_constraints,
1004  * QGauss<1>(degree + 1),
1005  * additional_data);
1006  *
1007  * mf_mg_matrix[level].initialize(mf_storage_level,
1008  * mg_constrained_dofs,
1009  * level);
1010  *
1011  * const Coefficient<dim> coefficient;
1012  * mf_mg_matrix[level].set_coefficient(
1013  * coefficient.make_coefficient_table(*mf_storage_level));
1014  *
1015  * mf_mg_matrix[level].compute_diagonal();
1016  * }
1017  *
1018  * break;
1019  * }
1020  *
1021  * case Settings::gmg_mb:
1022  * {
1023  * mg_matrix.resize(0, n_levels - 1);
1024  * mg_matrix.clear_elements();
1025  * mg_interface_in.resize(0, n_levels - 1);
1026  * mg_interface_in.clear_elements();
1027  *
1028  * for (unsigned int level = 0; level < n_levels; ++level)
1029  * {
1030  * IndexSet dof_set;
1032  * level,
1033  * dof_set);
1034  *
1035  * {
1036  * #ifdef USE_PETSC_LA
1037  * DynamicSparsityPattern dsp(dof_set);
1038  * MGTools::make_sparsity_pattern(dof_handler, dsp, level);
1039  * dsp.compress();
1041  * dsp,
1042  * dof_handler.locally_owned_mg_dofs(level),
1043  * mpi_communicator,
1044  * dof_set);
1045  *
1046  * mg_matrix[level].reinit(
1047  * dof_handler.locally_owned_mg_dofs(level),
1048  * dof_handler.locally_owned_mg_dofs(level),
1049  * dsp,
1050  * mpi_communicator);
1051  * #else
1053  * dof_handler.locally_owned_mg_dofs(level),
1054  * dof_handler.locally_owned_mg_dofs(level),
1055  * dof_set,
1056  * mpi_communicator);
1057  * MGTools::make_sparsity_pattern(dof_handler, dsp, level);
1058  *
1059  * dsp.compress();
1060  * mg_matrix[level].reinit(dsp);
1061  * #endif
1062  * }
1063  *
1064  * {
1065  * #ifdef USE_PETSC_LA
1066  * DynamicSparsityPattern dsp(dof_set);
1068  * mg_constrained_dofs,
1069  * dsp,
1070  * level);
1071  * dsp.compress();
1073  * dsp,
1074  * dof_handler.locally_owned_mg_dofs(level),
1075  * mpi_communicator,
1076  * dof_set);
1077  *
1078  * mg_interface_in[level].reinit(
1079  * dof_handler.locally_owned_mg_dofs(level),
1080  * dof_handler.locally_owned_mg_dofs(level),
1081  * dsp,
1082  * mpi_communicator);
1083  * #else
1085  * dof_handler.locally_owned_mg_dofs(level),
1086  * dof_handler.locally_owned_mg_dofs(level),
1087  * dof_set,
1088  * mpi_communicator);
1089  *
1091  * mg_constrained_dofs,
1092  * dsp,
1093  * level);
1094  * dsp.compress();
1095  * mg_interface_in[level].reinit(dsp);
1096  * #endif
1097  * }
1098  * }
1099  * break;
1100  * }
1101  *
1102  * default:
1103  * Assert(false, ExcNotImplemented());
1104  * }
1105  * }
1106  *
1107  *
1108  * @endcode
1109  *
1110  *
1111  * <a name="LaplaceProblemassemble_system"></a>
1112  * <h4>LaplaceProblem::assemble_system()</h4>
1113  *
1114 
1115  *
1116  * The assembly is split into three parts: `assemble_system()`,
1117  * `assemble_multigrid()`, and `assemble_rhs()`. The
1118  * `assemble_system()` function here assembles and stores the (global)
1119  * system matrix and the right-hand side for the matrix-based
1120  * methods. It is similar to the assembly in @ref step_40 "step-40".
1121  *
1122 
1123  *
1124  * Note that the matrix-free method does not execute this function as it does
1125  * not need to assemble a matrix, and it will instead assemble the right-hand
1126  * side in assemble_rhs().
1127  *
1128  * @code
1129  * template <int dim, int degree>
1130  * void LaplaceProblem<dim, degree>::assemble_system()
1131  * {
1132  * TimerOutput::Scope timing(computing_timer, "Assemble");
1133  *
1134  * const QGauss<dim> quadrature_formula(degree + 1);
1135  *
1136  * FEValues<dim> fe_values(fe,
1137  * quadrature_formula,
1140  *
1141  * const unsigned int dofs_per_cell = fe.n_dofs_per_cell();
1142  * const unsigned int n_q_points = quadrature_formula.size();
1143  *
1144  * FullMatrix<double> cell_matrix(dofs_per_cell, dofs_per_cell);
1145  * Vector<double> cell_rhs(dofs_per_cell);
1146  *
1147  * std::vector<types::global_dof_index> local_dof_indices(dofs_per_cell);
1148  *
1149  * const Coefficient<dim> coefficient;
1150  * RightHandSide<dim> rhs;
1151  * std::vector<double> rhs_values(n_q_points);
1152  *
1153  * for (const auto &cell : dof_handler.active_cell_iterators())
1154  * if (cell->is_locally_owned())
1155  * {
1156  * cell_matrix = 0;
1157  * cell_rhs = 0;
1158  *
1159  * fe_values.reinit(cell);
1160  *
1161  * const double coefficient_value =
1162  * coefficient.average_value(fe_values.get_quadrature_points());
1163  * rhs.value_list(fe_values.get_quadrature_points(), rhs_values);
1164  *
1165  * for (unsigned int q_point = 0; q_point < n_q_points; ++q_point)
1166  * for (unsigned int i = 0; i < dofs_per_cell; ++i)
1167  * {
1168  * for (unsigned int j = 0; j < dofs_per_cell; ++j)
1169  * cell_matrix(i, j) +=
1170  * coefficient_value * // epsilon(x)
1171  * fe_values.shape_grad(i, q_point) * // * grad phi_i(x)
1172  * fe_values.shape_grad(j, q_point) * // * grad phi_j(x)
1173  * fe_values.JxW(q_point); // * dx
1174  *
1175  * cell_rhs(i) +=
1176  * fe_values.shape_value(i, q_point) * // grad phi_i(x)
1177  * rhs_values[q_point] * // * f(x)
1178  * fe_values.JxW(q_point); // * dx
1179  * }
1180  *
1181  * cell->get_dof_indices(local_dof_indices);
1182  * constraints.distribute_local_to_global(cell_matrix,
1183  * cell_rhs,
1184  * local_dof_indices,
1185  * system_matrix,
1186  * right_hand_side);
1187  * }
1188  *
1189  * system_matrix.compress(VectorOperation::add);
1190  * right_hand_side.compress(VectorOperation::add);
1191  * }
1192  *
1193  *
1194  * @endcode
1195  *
1196  *
1197  * <a name="LaplaceProblemassemble_multigrid"></a>
1198  * <h4>LaplaceProblem::assemble_multigrid()</h4>
1199  *
1200 
1201  *
1202  * The following function assembles and stores the multilevel matrices for the
1203  * matrix-based GMG method. This function is similar to the one found in
1204  * @ref step_16 "step-16", only here it works for distributed meshes. This difference amounts
1205  * to adding a condition that we only assemble on locally owned level cells and
1206  * a call to compress() for each matrix that is built.
1207  *
1208  * @code
1209  * template <int dim, int degree>
1210  * void LaplaceProblem<dim, degree>::assemble_multigrid()
1211  * {
1212  * TimerOutput::Scope timing(computing_timer, "Assemble multigrid");
1213  *
1214  * QGauss<dim> quadrature_formula(degree + 1);
1215  *
1216  * FEValues<dim> fe_values(fe,
1217  * quadrature_formula,
1220  *
1221  * const unsigned int dofs_per_cell = fe.n_dofs_per_cell();
1222  * const unsigned int n_q_points = quadrature_formula.size();
1223  *
1224  * FullMatrix<double> cell_matrix(dofs_per_cell, dofs_per_cell);
1225  *
1226  * std::vector<types::global_dof_index> local_dof_indices(dofs_per_cell);
1227  *
1228  * const Coefficient<dim> coefficient;
1229  *
1230  * std::vector<AffineConstraints<double>> boundary_constraints(
1231  * triangulation.n_global_levels());
1232  * for (unsigned int level = 0; level < triangulation.n_global_levels(); ++level)
1233  * {
1234  * IndexSet dof_set;
1236  * level,
1237  * dof_set);
1238  * boundary_constraints[level].reinit(dof_set);
1239  * boundary_constraints[level].add_lines(
1240  * mg_constrained_dofs.get_refinement_edge_indices(level));
1241  * boundary_constraints[level].add_lines(
1242  * mg_constrained_dofs.get_boundary_indices(level));
1243  *
1244  * boundary_constraints[level].close();
1245  * }
1246  *
1247  * for (const auto &cell : dof_handler.cell_iterators())
1248  * if (cell->level_subdomain_id() == triangulation.locally_owned_subdomain())
1249  * {
1250  * cell_matrix = 0;
1251  * fe_values.reinit(cell);
1252  *
1253  * const double coefficient_value =
1254  * coefficient.average_value(fe_values.get_quadrature_points());
1255  *
1256  * for (unsigned int q_point = 0; q_point < n_q_points; ++q_point)
1257  * for (unsigned int i = 0; i < dofs_per_cell; ++i)
1258  * for (unsigned int j = 0; j < dofs_per_cell; ++j)
1259  * cell_matrix(i, j) +=
1260  * coefficient_value * fe_values.shape_grad(i, q_point) *
1261  * fe_values.shape_grad(j, q_point) * fe_values.JxW(q_point);
1262  *
1263  * cell->get_mg_dof_indices(local_dof_indices);
1264  *
1265  * boundary_constraints[cell->level()].distribute_local_to_global(
1266  * cell_matrix, local_dof_indices, mg_matrix[cell->level()]);
1267  *
1268  * for (unsigned int i = 0; i < dofs_per_cell; ++i)
1269  * for (unsigned int j = 0; j < dofs_per_cell; ++j)
1270  * if (mg_constrained_dofs.is_interface_matrix_entry(
1271  * cell->level(), local_dof_indices[i], local_dof_indices[j]))
1272  * mg_interface_in[cell->level()].add(local_dof_indices[i],
1273  * local_dof_indices[j],
1274  * cell_matrix(i, j));
1275  * }
1276  *
1277  * for (unsigned int i = 0; i < triangulation.n_global_levels(); ++i)
1278  * {
1279  * mg_matrix[i].compress(VectorOperation::add);
1280  * mg_interface_in[i].compress(VectorOperation::add);
1281  * }
1282  * }
1283  *
1284  *
1285  *
1286  * @endcode
1287  *
1288  *
1289  * <a name="LaplaceProblemassemble_rhs"></a>
1290  * <h4>LaplaceProblem::assemble_rhs()</h4>
1291  *
1292 
1293  *
1294  * The final function in this triptych assembles the right-hand side
1295  * vector for the matrix-free method -- because in the matrix-free
1296  * framework, we don't have to assemble the matrix and can get away
1297  * with only assembling the right hand side. We could do this by extracting the
1298  * code from the `assemble_system()` function above that deals with the right
1299  * hand side, but we decide instead to go all in on the matrix-free approach and
1300  * do the assembly using that way as well.
1301  *
1302 
1303  *
1304  * The result is a function that is similar
1305  * to the one found in the "Use FEEvaluation::read_dof_values_plain()
1306  * to avoid resolving constraints" subsection in the "Possibilities
1307  * for extensions" section of @ref step_37 "step-37".
1308  *
1309 
1310  *
1311  * The reason for this function is that the MatrixFree operators do not take
1312  * into account non-homogeneous Dirichlet constraints, instead treating all
1313  * Dirichlet constraints as homogeneous. To account for this, the right-hand
1314  * side here is assembled as the residual @f$r_0 = f-Au_0@f$, where @f$u_0@f$ is a
1315  * zero vector except in the Dirichlet values. Then when solving, we have that
1316  * the solution is @f$u = u_0 + A^{-1}r_0@f$. This can be seen as a Newton
1317  * iteration on a linear system with initial guess @f$u_0@f$. The CG solve in the
1318  * `solve()` function below computes @f$A^{-1}r_0@f$ and the call to
1319  * `constraints.distribute()` (which directly follows) adds the @f$u_0@f$.
1320  *
1321 
1322  *
1323  * Obviously, since we are considering a problem with zero Dirichlet boundary,
1324  * we could have taken a similar approach to @ref step_37 "step-37" `assemble_rhs()`, but this
1325  * additional work allows us to change the problem declaration if we so
1326  * choose.
1327  *
1328 
1329  *
1330  * This function has two parts in the integration loop: applying the negative
1331  * of matrix @f$A@f$ to @f$u_0@f$ by submitting the negative of the gradient, and adding
1332  * the right-hand side contribution by submitting the value @f$f@f$. We must be sure
1333  * to use `read_dof_values_plain()` for evaluating @f$u_0@f$ as `read_dof_vaues()`
1334  * would set all Dirichlet values to zero.
1335  *
1336 
1337  *
1338  * Finally, the system_rhs vector is of type LA::MPI::Vector, but the
1339  * MatrixFree class only work for
1340  * ::LinearAlgebra::distributed::Vector. Therefore we must
1341  * compute the right-hand side using MatrixFree functionality and then
1342  * use the functions in the `ChangeVectorType` namespace to copy it to
1343  * the correct type.
1344  *
1345  * @code
1346  * template <int dim, int degree>
1347  * void LaplaceProblem<dim, degree>::assemble_rhs()
1348  * {
1349  * TimerOutput::Scope timing(computing_timer, "Assemble right-hand side");
1350  *
1351  * MatrixFreeActiveVector solution_copy;
1352  * MatrixFreeActiveVector right_hand_side_copy;
1353  * mf_system_matrix.initialize_dof_vector(solution_copy);
1354  * mf_system_matrix.initialize_dof_vector(right_hand_side_copy);
1355  *
1356  * solution_copy = 0.;
1357  * constraints.distribute(solution_copy);
1358  * solution_copy.update_ghost_values();
1359  * right_hand_side_copy = 0;
1360  * const Table<2, VectorizedArray<double>> &coefficient =
1361  * *(mf_system_matrix.get_coefficient());
1362  *
1363  * RightHandSide<dim> right_hand_side_function;
1364  *
1365  * FEEvaluation<dim, degree, degree + 1, 1, double> phi(
1366  * *mf_system_matrix.get_matrix_free());
1367  *
1368  * for (unsigned int cell = 0;
1369  * cell < mf_system_matrix.get_matrix_free()->n_cell_batches();
1370  * ++cell)
1371  * {
1372  * phi.reinit(cell);
1373  * phi.read_dof_values_plain(solution_copy);
1374  * phi.evaluate(EvaluationFlags::gradients);
1375  *
1376  * for (unsigned int q = 0; q < phi.n_q_points; ++q)
1377  * {
1378  * phi.submit_gradient(-1.0 *
1379  * (coefficient(cell, 0) * phi.get_gradient(q)),
1380  * q);
1381  * phi.submit_value(
1382  * right_hand_side_function.value(phi.quadrature_point(q)), q);
1383  * }
1384  *
1385  * phi.integrate_scatter(EvaluationFlags::values |
1386  * EvaluationFlags::gradients,
1387  * right_hand_side_copy);
1388  * }
1389  *
1390  * right_hand_side_copy.compress(VectorOperation::add);
1391  *
1392  * ChangeVectorTypes::copy(right_hand_side, right_hand_side_copy);
1393  * }
1394  *
1395  *
1396  *
1397  * @endcode
1398  *
1399  *
1400  * <a name="LaplaceProblemsolve"></a>
1401  * <h4>LaplaceProblem::solve()</h4>
1402  *
1403 
1404  *
1405  * Here we set up the multigrid preconditioner, test the timing of a single
1406  * V-cycle, and solve the linear system. Unsurprisingly, this is one of the
1407  * places where the three methods differ the most.
1408  *
1409  * @code
1410  * template <int dim, int degree>
1411  * void LaplaceProblem<dim, degree>::solve()
1412  * {
1413  * TimerOutput::Scope timing(computing_timer, "Solve");
1414  *
1415  * SolverControl solver_control(1000, 1.e-10 * right_hand_side.l2_norm());
1416  * solver_control.enable_history_data();
1417  *
1418  * solution = 0.;
1419  *
1420  * @endcode
1421  *
1422  * The solver for the matrix-free GMG method is similar to @ref step_37 "step-37", apart
1423  * from adding some interface matrices in complete analogy to @ref step_16 "step-16".
1424  *
1425  * @code
1426  * switch (settings.solver)
1427  * {
1428  * case Settings::gmg_mf:
1429  * {
1430  * computing_timer.enter_subsection("Solve: Preconditioner setup");
1431  *
1432  * MGTransferMatrixFree<dim, float> mg_transfer(mg_constrained_dofs);
1433  * mg_transfer.build(dof_handler);
1434  *
1435  * SolverControl coarse_solver_control(1000, 1e-12, false, false);
1436  * SolverCG<MatrixFreeLevelVector> coarse_solver(coarse_solver_control);
1437  * PreconditionIdentity identity;
1438  * MGCoarseGridIterativeSolver<MatrixFreeLevelVector,
1439  * SolverCG<MatrixFreeLevelVector>,
1440  * MatrixFreeLevelMatrix,
1441  * PreconditionIdentity>
1442  * coarse_grid_solver(coarse_solver, mf_mg_matrix[0], identity);
1443  *
1444  * using Smoother = ::PreconditionJacobi<MatrixFreeLevelMatrix>;
1445  * MGSmootherPrecondition<MatrixFreeLevelMatrix,
1446  * Smoother,
1447  * MatrixFreeLevelVector>
1448  * smoother;
1449  * smoother.initialize(mf_mg_matrix,
1450  * typename Smoother::AdditionalData(
1451  * settings.smoother_dampen));
1452  * smoother.set_steps(settings.smoother_steps);
1453  *
1454  * mg::Matrix<MatrixFreeLevelVector> mg_m(mf_mg_matrix);
1455  *
1456  * MGLevelObject<
1457  * MatrixFreeOperators::MGInterfaceOperator<MatrixFreeLevelMatrix>>
1458  * mg_interface_matrices;
1459  * mg_interface_matrices.resize(0, triangulation.n_global_levels() - 1);
1460  * for (unsigned int level = 0; level < triangulation.n_global_levels();
1461  * ++level)
1462  * mg_interface_matrices[level].initialize(mf_mg_matrix[level]);
1463  * mg::Matrix<MatrixFreeLevelVector> mg_interface(mg_interface_matrices);
1464  *
1465  * Multigrid<MatrixFreeLevelVector> mg(
1466  * mg_m, coarse_grid_solver, mg_transfer, smoother, smoother);
1467  * mg.set_edge_matrices(mg_interface, mg_interface);
1468  *
1469  * PreconditionMG<dim,
1470  * MatrixFreeLevelVector,
1471  * MGTransferMatrixFree<dim, float>>
1472  * preconditioner(dof_handler, mg, mg_transfer);
1473  *
1474  * @endcode
1475  *
1476  * Copy the solution vector and right-hand side from LA::MPI::Vector
1477  * to ::LinearAlgebra::distributed::Vector so that we can solve.
1478  *
1479  * @code
1480  * MatrixFreeActiveVector solution_copy;
1481  * MatrixFreeActiveVector right_hand_side_copy;
1482  * mf_system_matrix.initialize_dof_vector(solution_copy);
1483  * mf_system_matrix.initialize_dof_vector(right_hand_side_copy);
1484  *
1485  * ChangeVectorTypes::copy(solution_copy, solution);
1486  * ChangeVectorTypes::copy(right_hand_side_copy, right_hand_side);
1487  * computing_timer.leave_subsection("Solve: Preconditioner setup");
1488  *
1489  * @endcode
1490  *
1491  * Timing for 1 V-cycle.
1492  *
1493  * @code
1494  * {
1495  * TimerOutput::Scope timing(computing_timer,
1496  * "Solve: 1 multigrid V-cycle");
1497  * preconditioner.vmult(solution_copy, right_hand_side_copy);
1498  * }
1499  * solution_copy = 0.;
1500  *
1501  * @endcode
1502  *
1503  * Solve the linear system, update the ghost values of the solution,
1504  * copy back to LA::MPI::Vector and distribute constraints.
1505  *
1506  * @code
1507  * {
1508  * SolverCG<MatrixFreeActiveVector> solver(solver_control);
1509  *
1510  * TimerOutput::Scope timing(computing_timer, "Solve: CG");
1511  * solver.solve(mf_system_matrix,
1512  * solution_copy,
1513  * right_hand_side_copy,
1514  * preconditioner);
1515  * }
1516  *
1517  * solution_copy.update_ghost_values();
1518  * ChangeVectorTypes::copy(solution, solution_copy);
1519  * constraints.distribute(solution);
1520  *
1521  * break;
1522  * }
1523  *
1524  * @endcode
1525  *
1526  * Solver for the matrix-based GMG method, similar to @ref step_16 "step-16", only
1527  * using a Jacobi smoother instead of a SOR smoother (which is not
1528  * implemented in parallel).
1529  *
1530  * @code
1531  * case Settings::gmg_mb:
1532  * {
1533  * computing_timer.enter_subsection("Solve: Preconditioner setup");
1534  *
1535  * MGTransferPrebuilt<VectorType> mg_transfer(mg_constrained_dofs);
1536  * mg_transfer.build(dof_handler);
1537  *
1538  * SolverControl coarse_solver_control(1000, 1e-12, false, false);
1539  * SolverCG<VectorType> coarse_solver(coarse_solver_control);
1540  * PreconditionIdentity identity;
1541  * MGCoarseGridIterativeSolver<VectorType,
1542  * SolverCG<VectorType>,
1543  * MatrixType,
1544  * PreconditionIdentity>
1545  * coarse_grid_solver(coarse_solver, mg_matrix[0], identity);
1546  *
1547  * using Smoother = LA::MPI::PreconditionJacobi;
1548  * MGSmootherPrecondition<MatrixType, Smoother, VectorType> smoother;
1549  *
1550  * #ifdef USE_PETSC_LA
1551  * smoother.initialize(mg_matrix);
1552  * Assert(
1553  * settings.smoother_dampen == 1.0,
1554  * ExcNotImplemented(
1555  * "PETSc's PreconditionJacobi has no support for a damping parameter."));
1556  * #else
1557  * smoother.initialize(mg_matrix, settings.smoother_dampen);
1558  * #endif
1559  *
1560  * smoother.set_steps(settings.smoother_steps);
1561  *
1562  * mg::Matrix<VectorType> mg_m(mg_matrix);
1563  * mg::Matrix<VectorType> mg_in(mg_interface_in);
1564  * mg::Matrix<VectorType> mg_out(mg_interface_in);
1565  *
1566  * Multigrid<VectorType> mg(
1567  * mg_m, coarse_grid_solver, mg_transfer, smoother, smoother);
1568  * mg.set_edge_matrices(mg_out, mg_in);
1569  *
1570  *
1571  * PreconditionMG<dim, VectorType, MGTransferPrebuilt<VectorType>>
1572  * preconditioner(dof_handler, mg, mg_transfer);
1573  *
1574  * computing_timer.leave_subsection("Solve: Preconditioner setup");
1575  *
1576  * @endcode
1577  *
1578  * Timing for 1 V-cycle.
1579  *
1580  * @code
1581  * {
1582  * TimerOutput::Scope timing(computing_timer,
1583  * "Solve: 1 multigrid V-cycle");
1584  * preconditioner.vmult(solution, right_hand_side);
1585  * }
1586  * solution = 0.;
1587  *
1588  * @endcode
1589  *
1590  * Solve the linear system and distribute constraints.
1591  *
1592  * @code
1593  * {
1594  * SolverCG<VectorType> solver(solver_control);
1595  *
1596  * TimerOutput::Scope timing(computing_timer, "Solve: CG");
1597  * solver.solve(system_matrix,
1598  * solution,
1599  * right_hand_side,
1600  * preconditioner);
1601  * }
1602  *
1603  * constraints.distribute(solution);
1604  *
1605  * break;
1606  * }
1607  *
1608  * @endcode
1609  *
1610  * Solver for the AMG method, similar to @ref step_40 "step-40".
1611  *
1612  * @code
1613  * case Settings::amg:
1614  * {
1615  * computing_timer.enter_subsection("Solve: Preconditioner setup");
1616  *
1617  * PreconditionAMG preconditioner;
1618  * PreconditionAMG::AdditionalData Amg_data;
1619  *
1620  * #ifdef USE_PETSC_LA
1621  * Amg_data.symmetric_operator = true;
1622  * #else
1623  * Amg_data.elliptic = true;
1624  * Amg_data.smoother_type = "Jacobi";
1625  * Amg_data.higher_order_elements = true;
1626  * Amg_data.smoother_sweeps = settings.smoother_steps;
1627  * Amg_data.aggregation_threshold = 0.02;
1628  * #endif
1629  *
1630  * Amg_data.output_details = false;
1631  *
1632  * preconditioner.initialize(system_matrix, Amg_data);
1633  * computing_timer.leave_subsection("Solve: Preconditioner setup");
1634  *
1635  * @endcode
1636  *
1637  * Timing for 1 V-cycle.
1638  *
1639  * @code
1640  * {
1641  * TimerOutput::Scope timing(computing_timer,
1642  * "Solve: 1 multigrid V-cycle");
1643  * preconditioner.vmult(solution, right_hand_side);
1644  * }
1645  * solution = 0.;
1646  *
1647  * @endcode
1648  *
1649  * Solve the linear system and distribute constraints.
1650  *
1651  * @code
1652  * {
1653  * SolverCG<VectorType> solver(solver_control);
1654  *
1655  * TimerOutput::Scope timing(computing_timer, "Solve: CG");
1656  * solver.solve(system_matrix,
1657  * solution,
1658  * right_hand_side,
1659  * preconditioner);
1660  * }
1661  * constraints.distribute(solution);
1662  *
1663  * break;
1664  * }
1665  *
1666  * default:
1667  * Assert(false, ExcInternalError());
1668  * }
1669  *
1670  * pcout << " Number of CG iterations: " << solver_control.last_step()
1671  * << std::endl;
1672  * }
1673  *
1674  *
1675  * @endcode
1676  *
1677  *
1678  * <a name="Theerrorestimator"></a>
1679  * <h3>The error estimator</h3>
1680  *
1681 
1682  *
1683  * We use the FEInterfaceValues class to assemble an error estimator to decide
1684  * which cells to refine. See the exact definition of the cell and face
1685  * integrals in the introduction. To use the method, we define Scratch and
1686  * Copy objects for the MeshWorker::mesh_loop() with much of the following code
1687  * being in essence as was set up in @ref step_12 "step-12" already (or at least similar in
1688  * spirit).
1689  *
1690  * @code
1691  * template <int dim>
1692  * struct ScratchData
1693  * {
1694  * ScratchData(const Mapping<dim> & mapping,
1695  * const FiniteElement<dim> &fe,
1696  * const unsigned int quadrature_degree,
1697  * const UpdateFlags update_flags,
1698  * const UpdateFlags interface_update_flags)
1699  * : fe_values(mapping, fe, QGauss<dim>(quadrature_degree), update_flags)
1700  * , fe_interface_values(mapping,
1701  * fe,
1702  * QGauss<dim - 1>(quadrature_degree),
1703  * interface_update_flags)
1704  * {}
1705  *
1706  *
1707  * ScratchData(const ScratchData<dim> &scratch_data)
1708  * : fe_values(scratch_data.fe_values.get_mapping(),
1709  * scratch_data.fe_values.get_fe(),
1710  * scratch_data.fe_values.get_quadrature(),
1711  * scratch_data.fe_values.get_update_flags())
1712  * , fe_interface_values(scratch_data.fe_values.get_mapping(),
1713  * scratch_data.fe_values.get_fe(),
1714  * scratch_data.fe_interface_values.get_quadrature(),
1715  * scratch_data.fe_interface_values.get_update_flags())
1716  * {}
1717  *
1718  * FEValues<dim> fe_values;
1719  * FEInterfaceValues<dim> fe_interface_values;
1720  * };
1721  *
1722  *
1723  *
1724  * struct CopyData
1725  * {
1726  * CopyData()
1727  * : cell_index(numbers::invalid_unsigned_int)
1728  * , value(0.)
1729  * {}
1730  *
1731  * CopyData(const CopyData &) = default;
1732  *
1733  * struct FaceData
1734  * {
1735  * unsigned int cell_indices[2];
1736  * double values[2];
1737  * };
1738  *
1739  * unsigned int cell_index;
1740  * double value;
1741  * std::vector<FaceData> face_data;
1742  * };
1743  *
1744  *
1745  * template <int dim, int degree>
1746  * void LaplaceProblem<dim, degree>::estimate()
1747  * {
1748  * TimerOutput::Scope timing(computing_timer, "Estimate");
1749  *
1750  * VectorType temp_solution;
1751  * temp_solution.reinit(locally_owned_dofs,
1752  * locally_relevant_dofs,
1753  * mpi_communicator);
1754  * temp_solution = solution;
1755  *
1756  * const Coefficient<dim> coefficient;
1757  *
1758  * estimated_error_square_per_cell.reinit(triangulation.n_active_cells());
1759  *
1760  * using Iterator = typename DoFHandler<dim>::active_cell_iterator;
1761  *
1762  * @endcode
1763  *
1764  * Assembler for cell residual @f$h^2 \| f + \epsilon \triangle u \|_K^2@f$
1765  *
1766  * @code
1767  * auto cell_worker = [&](const Iterator & cell,
1768  * ScratchData<dim> &scratch_data,
1769  * CopyData & copy_data) {
1770  * FEValues<dim> &fe_values = scratch_data.fe_values;
1771  * fe_values.reinit(cell);
1772  *
1773  * RightHandSide<dim> rhs;
1774  * const double rhs_value = rhs.value(cell->center());
1775  *
1776  * const double nu = coefficient.value(cell->center());
1777  *
1778  * std::vector<Tensor<2, dim>> hessians(fe_values.n_quadrature_points);
1779  * fe_values.get_function_hessians(temp_solution, hessians);
1780  *
1781  * copy_data.cell_index = cell->active_cell_index();
1782  *
1783  * double residual_norm_square = 0.;
1784  * for (unsigned k = 0; k < fe_values.n_quadrature_points; ++k)
1785  * {
1786  * const double residual = (rhs_value + nu * trace(hessians[k]));
1787  * residual_norm_square += residual * residual * fe_values.JxW(k);
1788  * }
1789  *
1790  * copy_data.value =
1791  * cell->diameter() * cell->diameter() * residual_norm_square;
1792  * };
1793  *
1794  * @endcode
1795  *
1796  * Assembler for face term @f$\sum_F h_F \| \jump{\epsilon \nabla u \cdot n}
1797  * \|_F^2@f$
1798  *
1799  * @code
1800  * auto face_worker = [&](const Iterator & cell,
1801  * const unsigned int &f,
1802  * const unsigned int &sf,
1803  * const Iterator & ncell,
1804  * const unsigned int &nf,
1805  * const unsigned int &nsf,
1806  * ScratchData<dim> & scratch_data,
1807  * CopyData & copy_data) {
1808  * FEInterfaceValues<dim> &fe_interface_values =
1809  * scratch_data.fe_interface_values;
1810  * fe_interface_values.reinit(cell, f, sf, ncell, nf, nsf);
1811  *
1812  * copy_data.face_data.emplace_back();
1813  * CopyData::FaceData &copy_data_face = copy_data.face_data.back();
1814  *
1815  * copy_data_face.cell_indices[0] = cell->active_cell_index();
1816  * copy_data_face.cell_indices[1] = ncell->active_cell_index();
1817  *
1818  * const double coeff1 = coefficient.value(cell->center());
1819  * const double coeff2 = coefficient.value(ncell->center());
1820  *
1821  * std::vector<Tensor<1, dim>> grad_u[2];
1822  *
1823  * for (unsigned int i = 0; i < 2; ++i)
1824  * {
1825  * grad_u[i].resize(fe_interface_values.n_quadrature_points);
1826  * fe_interface_values.get_fe_face_values(i).get_function_gradients(
1827  * temp_solution, grad_u[i]);
1828  * }
1829  *
1830  * double jump_norm_square = 0.;
1831  *
1832  * for (unsigned int qpoint = 0;
1833  * qpoint < fe_interface_values.n_quadrature_points;
1834  * ++qpoint)
1835  * {
1836  * const double jump =
1837  * coeff1 * grad_u[0][qpoint] * fe_interface_values.normal(qpoint) -
1838  * coeff2 * grad_u[1][qpoint] * fe_interface_values.normal(qpoint);
1839  *
1840  * jump_norm_square += jump * jump * fe_interface_values.JxW(qpoint);
1841  * }
1842  *
1843  * const double h = cell->face(f)->measure();
1844  * copy_data_face.values[0] = 0.5 * h * jump_norm_square;
1845  * copy_data_face.values[1] = copy_data_face.values[0];
1846  * };
1847  *
1848  * auto copier = [&](const CopyData &copy_data) {
1849  * if (copy_data.cell_index != numbers::invalid_unsigned_int)
1850  * estimated_error_square_per_cell[copy_data.cell_index] += copy_data.value;
1851  *
1852  * for (auto &cdf : copy_data.face_data)
1853  * for (unsigned int j = 0; j < 2; ++j)
1854  * estimated_error_square_per_cell[cdf.cell_indices[j]] += cdf.values[j];
1855  * };
1856  *
1857  * const unsigned int n_gauss_points = degree + 1;
1858  * ScratchData<dim> scratch_data(mapping,
1859  * fe,
1860  * n_gauss_points,
1861  * update_hessians | update_quadrature_points |
1862  * update_JxW_values,
1863  * update_values | update_gradients |
1864  * update_JxW_values | update_normal_vectors);
1865  * CopyData copy_data;
1866  *
1867  * @endcode
1868  *
1869  * We need to assemble each interior face once but we need to make sure that
1870  * both processes assemble the face term between a locally owned and a ghost
1871  * cell. This is achieved by setting the
1872  * MeshWorker::assemble_ghost_faces_both flag. We need to do this, because
1873  * we do not communicate the error estimator contributions here.
1874  *
1875  * @code
1876  * MeshWorker::mesh_loop(dof_handler.begin_active(),
1877  * dof_handler.end(),
1878  * cell_worker,
1879  * copier,
1880  * scratch_data,
1881  * copy_data,
1882  * MeshWorker::assemble_own_cells |
1883  * MeshWorker::assemble_ghost_faces_both |
1884  * MeshWorker::assemble_own_interior_faces_once,
1885  * /*boundary_worker=*/nullptr,
1886  * face_worker);
1887  *
1888  * const double global_error_estimate =
1889  * std::sqrt(Utilities::MPI::sum(estimated_error_square_per_cell.l1_norm(),
1890  * mpi_communicator));
1891  * pcout << " Global error estimate: " << global_error_estimate
1892  * << std::endl;
1893  * }
1894  *
1895  *
1896  * @endcode
1897  *
1898  *
1899  * <a name="LaplaceProblemrefine_grid"></a>
1900  * <h4>LaplaceProblem::refine_grid()</h4>
1901  *
1902 
1903  *
1904  * We use the cell-wise estimator stored in the vector @p estimate_vector and
1905  * refine a fixed number of cells (chosen here to roughly double the number of
1906  * DoFs in each step).
1907  *
1908  * @code
1909  * template <int dim, int degree>
1910  * void LaplaceProblem<dim, degree>::refine_grid()
1911  * {
1912  * TimerOutput::Scope timing(computing_timer, "Refine grid");
1913  *
1914  * const double refinement_fraction = 1. / (std::pow(2.0, dim) - 1.);
1915  * parallel::distributed::GridRefinement::refine_and_coarsen_fixed_number(
1916  * triangulation, estimated_error_square_per_cell, refinement_fraction, 0.0);
1917  *
1918  * triangulation.execute_coarsening_and_refinement();
1919  * }
1920  *
1921  *
1922  * @endcode
1923  *
1924  *
1925  * <a name="LaplaceProblemoutput_results"></a>
1926  * <h4>LaplaceProblem::output_results()</h4>
1927  *
1928 
1929  *
1930  * The output_results() function is similar to the ones found in many of the
1931  * tutorials (see @ref step_40 "step-40" for example).
1932  *
1933  * @code
1934  * template <int dim, int degree>
1935  * void LaplaceProblem<dim, degree>::output_results(const unsigned int cycle)
1936  * {
1937  * TimerOutput::Scope timing(computing_timer, "Output results");
1938  *
1939  * VectorType temp_solution;
1940  * temp_solution.reinit(locally_owned_dofs,
1941  * locally_relevant_dofs,
1942  * mpi_communicator);
1943  * temp_solution = solution;
1944  *
1945  * DataOut<dim> data_out;
1946  * data_out.attach_dof_handler(dof_handler);
1947  * data_out.add_data_vector(temp_solution, "solution");
1948  *
1949  * Vector<float> subdomain(triangulation.n_active_cells());
1950  * for (unsigned int i = 0; i < subdomain.size(); ++i)
1951  * subdomain(i) = triangulation.locally_owned_subdomain();
1952  * data_out.add_data_vector(subdomain, "subdomain");
1953  *
1954  * Vector<float> level(triangulation.n_active_cells());
1955  * for (const auto &cell : triangulation.active_cell_iterators())
1956  * level(cell->active_cell_index()) = cell->level();
1957  * data_out.add_data_vector(level, "level");
1958  *
1959  * if (estimated_error_square_per_cell.size() > 0)
1960  * data_out.add_data_vector(estimated_error_square_per_cell,
1961  * "estimated_error_square_per_cell");
1962  *
1963  * data_out.build_patches();
1964  *
1965  * const std::string pvtu_filename = data_out.write_vtu_with_pvtu_record(
1966  * "", "solution", cycle, mpi_communicator, 2 /*n_digits*/, 1 /*n_groups*/);
1967  *
1968  * pcout << " Wrote " << pvtu_filename << std::endl;
1969  * }
1970  *
1971  *
1972  * @endcode
1973  *
1974  *
1975  * <a name="LaplaceProblemrun"></a>
1976  * <h4>LaplaceProblem::run()</h4>
1977  *
1978 
1979  *
1980  * As in most tutorials, this function calls the various functions defined
1981  * above to setup, assemble, solve, and output the results.
1982  *
1983  * @code
1984  * template <int dim, int degree>
1985  * void LaplaceProblem<dim, degree>::run()
1986  * {
1987  * for (unsigned int cycle = 0; cycle < settings.n_steps; ++cycle)
1988  * {
1989  * pcout << "Cycle " << cycle << ':' << std::endl;
1990  * if (cycle > 0)
1991  * refine_grid();
1992  *
1993  * pcout << " Number of active cells: "
1994  * << triangulation.n_global_active_cells();
1995  *
1996  * @endcode
1997  *
1998  * We only output level cell data for the GMG methods (same with DoF
1999  * data below). Note that the partition efficiency is irrelevant for AMG
2000  * since the level hierarchy is not distributed or used during the
2001  * computation.
2002  *
2003  * @code
2004  * if (settings.solver == Settings::gmg_mf ||
2005  * settings.solver == Settings::gmg_mb)
2006  * pcout << " (" << triangulation.n_global_levels() << " global levels)"
2007  * << std::endl
2008  * << " Partition efficiency: "
2009  * << 1.0 / MGTools::workload_imbalance(triangulation);
2010  * pcout << std::endl;
2011  *
2012  * setup_system();
2013  *
2014  * @endcode
2015  *
2016  * Only set up the multilevel hierarchy for GMG.
2017  *
2018  * @code
2019  * if (settings.solver == Settings::gmg_mf ||
2020  * settings.solver == Settings::gmg_mb)
2021  * setup_multigrid();
2022  *
2023  * pcout << " Number of degrees of freedom: " << dof_handler.n_dofs();
2024  * if (settings.solver == Settings::gmg_mf ||
2025  * settings.solver == Settings::gmg_mb)
2026  * {
2027  * pcout << " (by level: ";
2028  * for (unsigned int level = 0; level < triangulation.n_global_levels();
2029  * ++level)
2030  * pcout << dof_handler.n_dofs(level)
2031  * << (level == triangulation.n_global_levels() - 1 ? ")" :
2032  * ", ");
2033  * }
2034  * pcout << std::endl;
2035  *
2036  * @endcode
2037  *
2038  * For the matrix-free method, we only assemble the right-hand side.
2039  * For both matrix-based methods, we assemble both active matrix and
2040  * right-hand side, and only assemble the multigrid matrices for
2041  * matrix-based GMG.
2042  *
2043  * @code
2044  * if (settings.solver == Settings::gmg_mf)
2045  * assemble_rhs();
2046  * else /*gmg_mb or amg*/
2047  * {
2048  * assemble_system();
2049  * if (settings.solver == Settings::gmg_mb)
2050  * assemble_multigrid();
2051  * }
2052  *
2053  * solve();
2054  * estimate();
2055  *
2056  * if (settings.output)
2057  * output_results(cycle);
2058  *
2059  * computing_timer.print_summary();
2060  * computing_timer.reset();
2061  * }
2062  * }
2063  *
2064  *
2065  * @endcode
2066  *
2067  *
2068  * <a name="Themainfunction"></a>
2069  * <h3>The main() function</h3>
2070  *
2071 
2072  *
2073  * This is a similar main function to @ref step_40 "step-40", with the exception that
2074  * we require the user to pass a .prm file as a sole command line
2075  * argument (see @ref step_29 "step-29" and the documentation of the ParameterHandler
2076  * class for a complete discussion of parameter files).
2077  *
2078  * @code
2079  * int main(int argc, char *argv[])
2080  * {
2081  * using namespace dealii;
2082  * Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1);
2083  *
2084  * Settings settings;
2085  * if (!settings.try_parse((argc > 1) ? (argv[1]) : ""))
2086  * return 0;
2087  *
2088  * try
2089  * {
2090  * constexpr unsigned int fe_degree = 2;
2091  *
2092  * switch (settings.dimension)
2093  * {
2094  * case 2:
2095  * {
2096  * LaplaceProblem<2, fe_degree> test(settings);
2097  * test.run();
2098  *
2099  * break;
2100  * }
2101  *
2102  * case 3:
2103  * {
2104  * LaplaceProblem<3, fe_degree> test(settings);
2105  * test.run();
2106  *
2107  * break;
2108  * }
2109  *
2110  * default:
2111  * Assert(false, ExcMessage("This program only works in 2d and 3d."));
2112  * }
2113  * }
2114  * catch (std::exception &exc)
2115  * {
2116  * std::cerr << std::endl
2117  * << std::endl
2118  * << "----------------------------------------------------"
2119  * << std::endl;
2120  * std::cerr << "Exception on processing: " << std::endl
2121  * << exc.what() << std::endl
2122  * << "Aborting!" << std::endl
2123  * << "----------------------------------------------------"
2124  * << std::endl;
2125  * MPI_Abort(MPI_COMM_WORLD, 1);
2126  * return 1;
2127  * }
2128  * catch (...)
2129  * {
2130  * std::cerr << std::endl
2131  * << std::endl
2132  * << "----------------------------------------------------"
2133  * << std::endl;
2134  * std::cerr << "Unknown exception!" << std::endl
2135  * << "Aborting!" << std::endl
2136  * << "----------------------------------------------------"
2137  * << std::endl;
2138  * MPI_Abort(MPI_COMM_WORLD, 2);
2139  * return 1;
2140  * }
2141  *
2142  * return 0;
2143  * }
2144  * @endcode
2145 <a name="Results"></a><h1>Results</h1>
2146 
2147 
2148 When you run the program using the following command
2149 @code
2150 mpirun -np 16 ./step-50 gmg_mf_2d.prm
2151 @endcode
2152 the screen output should look like the following:
2153 @code
2154 Cycle 0:
2155  Number of active cells: 12 (2 global levels)
2156  Partition efficiency: 0.1875
2157  Number of degrees of freedom: 65 (by level: 21, 65)
2158  Number of CG iterations: 10
2159  Global error estimate: 0.355373
2160  Wrote solution_00.pvtu
2161 
2162 
2163 +---------------------------------------------+------------+------------+
2164 | Total wallclock time elapsed since start | 0.0163s | |
2165 | | | |
2166 | Section | no. calls | wall time | % of total |
2167 +---------------------------------+-----------+------------+------------+
2168 | Assemble right-hand side | 1 | 0.000374s | 2.3% |
2169 | Estimate | 1 | 0.000724s | 4.4% |
2170 | Output results | 1 | 0.00277s | 17% |
2171 | Setup | 1 | 0.00225s | 14% |
2172 | Setup multigrid | 1 | 0.00181s | 11% |
2173 | Solve | 1 | 0.00364s | 22% |
2174 | Solve: 1 multigrid V-cycle | 1 | 0.000354s | 2.2% |
2175 | Solve: CG | 1 | 0.00151s | 9.3% |
2176 | Solve: Preconditioner setup | 1 | 0.00125s | 7.7% |
2177 +---------------------------------+-----------+------------+------------+
2178 
2179 Cycle 1:
2180  Number of active cells: 24 (3 global levels)
2181  Partition efficiency: 0.276786
2182  Number of degrees of freedom: 139 (by level: 21, 65, 99)
2183  Number of CG iterations: 10
2184  Global error estimate: 0.216726
2185  Wrote solution_01.pvtu
2186 
2187 
2188 +---------------------------------------------+------------+------------+
2189 | Total wallclock time elapsed since start | 0.0169s | |
2190 | | | |
2191 | Section | no. calls | wall time | % of total |
2192 +---------------------------------+-----------+------------+------------+
2193 | Assemble right-hand side | 1 | 0.000309s | 1.8% |
2194 | Estimate | 1 | 0.00156s | 9.2% |
2195 | Output results | 1 | 0.00222s | 13% |
2196 | Refine grid | 1 | 0.00278s | 16% |
2197 | Setup | 1 | 0.00196s | 12% |
2198 | Setup multigrid | 1 | 0.0023s | 14% |
2199 | Solve | 1 | 0.00565s | 33% |
2200 | Solve: 1 multigrid V-cycle | 1 | 0.000349s | 2.1% |
2201 | Solve: CG | 1 | 0.00285s | 17% |
2202 | Solve: Preconditioner setup | 1 | 0.00195s | 12% |
2203 +---------------------------------+-----------+------------+------------+
2204 
2205 Cycle 2:
2206  Number of active cells: 51 (4 global levels)
2207  Partition efficiency: 0.41875
2208  Number of degrees of freedom: 245 (by level: 21, 65, 225, 25)
2209  Number of CG iterations: 11
2210  Global error estimate: 0.112098
2211  Wrote solution_02.pvtu
2212 
2213 
2214 +---------------------------------------------+------------+------------+
2215 | Total wallclock time elapsed since start | 0.0183s | |
2216 | | | |
2217 | Section | no. calls | wall time | % of total |
2218 +---------------------------------+-----------+------------+------------+
2219 | Assemble right-hand side | 1 | 0.000274s | 1.5% |
2220 | Estimate | 1 | 0.00127s | 6.9% |
2221 | Output results | 1 | 0.00227s | 12% |
2222 | Refine grid | 1 | 0.0024s | 13% |
2223 | Setup | 1 | 0.00191s | 10% |
2224 | Setup multigrid | 1 | 0.00295s | 16% |
2225 | Solve | 1 | 0.00702s | 38% |
2226 | Solve: 1 multigrid V-cycle | 1 | 0.000398s | 2.2% |
2227 | Solve: CG | 1 | 0.00376s | 21% |
2228 | Solve: Preconditioner setup | 1 | 0.00238s | 13% |
2229 +---------------------------------+-----------+------------+------------+
2230 .
2231 .
2232 .
2233 @endcode
2234 Here, the timing of the `solve()` function is split up in 3 parts: setting
2235 up the multigrid preconditioner, execution of a single multigrid V-cycle, and
2236 the CG solver. The V-cycle that is timed is unnecessary for the overall solve
2237 and only meant to give an insight at the different costs for AMG and GMG.
2238 Also it should be noted that when using the AMG solver, "Workload imbalance"
2239 is not included in the output since the hierarchy of coarse meshes is not
2240 required.
2241 
2242 All results in this section are gathered on Intel Xeon Platinum 8280 (Cascade
2243 Lake) nodes which have 56 cores and 192GB per node and support AVX-512 instructions,
2244 allowing for vectorization over 8 doubles (vectorization used only in the matrix-free
2245 computations). The code is compiled using gcc 7.1.0 with intel-mpi 17.0.3. Trilinos
2246 12.10.1 is used for the matrix-based GMG/AMG computations.
2247 
2248 We can then gather a variety of information by calling the program
2249 with the input files that are provided in the directory in which
2250 @ref step_50 "step-50" is located. Using these, and adjusting the number of mesh
2251 refinement steps, we can produce information about how well the
2252 program scales.
2253 
2254 The following table gives weak scaling timings for this program on up to 256M DoFs
2255 and 7,168 processors. (Recall that weak scaling keeps the number of
2256 degrees of freedom per processor constant while increasing the number of
2257 processors; i.e., it considers larger and larger problems.)
2258 Here, @f$\mathbb{E}@f$ is the partition efficiency from the
2259  introduction (also equal to 1.0/workload imbalance), "Setup" is a combination
2260 of setup, setup multigrid, assemble, and assemble multigrid from the timing blocks,
2261 and "Prec" is the preconditioner setup. Ideally all times would stay constant
2262 over each problem size for the individual solvers, but since the partition
2263 efficiency decreases from 0.371 to 0.161 from largest to smallest problem size,
2264 we expect to see an approximately @f$0.371/0.161=2.3@f$ times increase in timings
2265 for GMG. This is, in fact, pretty close to what we really get:
2266 
2267 <table align="center" class="doxtable">
2268 <tr>
2269  <th colspan="4"></th>
2270  <th></th>
2271  <th colspan="4">MF-GMG</th>
2272  <th></th>
2273  <th colspan="4">MB-GMG</th>
2274  <th></th>
2275  <th colspan="4">AMG</th>
2276 </tr>
2277 <tr>
2278  <th align="right">Procs</th>
2279  <th align="right">Cycle</th>
2280  <th align="right">DoFs</th>
2281  <th align="right">@f$\mathbb{E}@f$</th>
2282  <th></th>
2283  <th align="right">Setup</th>
2284  <th align="right">Prec</th>
2285  <th align="right">Solve</th>
2286  <th align="right">Total</th>
2287  <th></th>
2288  <th align="right">Setup</th>
2289  <th align="right">Prec</th>
2290  <th align="right">Solve</th>
2291  <th align="right">Total</th>
2292  <th></th>
2293  <th align="right">Setup</th>
2294  <th align="right">Prec</th>
2295  <th align="right">Solve</th>
2296  <th align="right">Total</th>
2297 </tr>
2298 <tr>
2299  <td align="right">112</th>
2300  <td align="right">13</th>
2301  <td align="right">4M</th>
2302  <td align="right">0.37</th>
2303  <td></td>
2304  <td align="right">0.742</th>
2305  <td align="right">0.393</th>
2306  <td align="right">0.200</th>
2307  <td align="right">1.335</th>
2308  <td></td>
2309  <td align="right">1.714</th>
2310  <td align="right">2.934</th>
2311  <td align="right">0.716</th>
2312  <td align="right">5.364</th>
2313  <td></td>
2314  <td align="right">1.544</th>
2315  <td align="right">0.456</th>
2316  <td align="right">1.150</th>
2317  <td align="right">3.150</th>
2318 </tr>
2319 <tr>
2320  <td align="right">448</th>
2321  <td align="right">15</th>
2322  <td align="right">16M</th>
2323  <td align="right">0.29</th>
2324  <td></td>
2325  <td align="right">0.884</th>
2326  <td align="right">0.535</th>
2327  <td align="right">0.253</th>
2328  <td align="right">1.672</th>
2329  <td></td>
2330  <td align="right">1.927</th>
2331  <td align="right">3.776</th>
2332  <td align="right">1.190</th>
2333  <td align="right">6.893</th>
2334  <td></td>
2335  <td align="right">1.544</th>
2336  <td align="right">0.456</th>
2337  <td align="right">1.150</th>
2338  <td align="right">3.150</th>
2339 </tr>
2340 <tr>
2341  <td align="right">1,792</th>
2342  <td align="right">17</th>
2343  <td align="right">65M</th>
2344  <td align="right">0.22</th>
2345  <td></td>
2346  <td align="right">1.122</th>
2347  <td align="right">0.686</th>
2348  <td align="right">0.309</th>
2349  <td align="right">2.117</th>
2350  <td></td>
2351  <td align="right">2.171</th>
2352  <td align="right">4.862</th>
2353  <td align="right">1.660</th>
2354  <td align="right">8.693</th>
2355  <td></td>
2356  <td align="right">1.654</th>
2357  <td align="right">0.546</th>
2358  <td align="right">1.460</th>
2359  <td align="right">3.660</th>
2360 </tr>
2361 <tr>
2362  <td align="right">7,168</th>
2363  <td align="right">19</th>
2364  <td align="right">256M</th>
2365  <td align="right">0.16</th>
2366  <td></td>
2367  <td align="right">1.214</th>
2368  <td align="right">0.893</th>
2369  <td align="right">0.521</th>
2370  <td align="right">2.628</th>
2371  <td></td>
2372  <td align="right">2.386</th>
2373  <td align="right">7.260</th>
2374  <td align="right">2.560</th>
2375  <td align="right">12.206</th>
2376  <td></td>
2377  <td align="right">1.844</th>
2378  <td align="right">1.010</th>
2379  <td align="right">1.890</th>
2380  <td align="right">4.744</th>
2381 </tr>
2382 </table>
2383 
2384 On the other hand, the algebraic multigrid in the last set of columns
2385 is relatively unaffected by the increasing imbalance of the mesh
2386 hierarchy (because it doesn't use the mesh hierarchy) and the growth
2387 in time is rather driven by other factors that are well documented in
2388 the literature (most notably that the algorithmic complexity of
2389 some parts of algebraic multigrid methods appears to be @f${\cal O}(N
2390 \log N)@f$ instead of @f${\cal O}(N)@f$ for geometric multigrid).
2391 
2392 The upshort of the table above is that the matrix-free geometric multigrid
2393 method appears to be the fastest approach to solving this equation if
2394 not by a huge margin. Matrix-based methods, on the other hand, are
2395 consistently the worst.
2396 
2397 The following figure provides strong scaling results for each method, i.e.,
2398 we solve the same problem on more and more processors. Specifically,
2399 we consider the problems after 16 mesh refinement cycles
2400 (32M DoFs) and 19 cycles (256M DoFs), on between 56 to 28,672 processors:
2401 
2402 <img width="600px" src="https://www.dealii.org/images/steps/developer/step-50-strong-scaling.png" alt="">
2403 
2404 While the matrix-based GMG solver and AMG scale similarly and have a
2405 similar time to solution (at least as long as there is a substantial
2406 number of unknowns per processor -- say, several 10,000), the
2407 matrix-free GMG solver scales much better and solves the finer problem
2408 in roughly the same time as the AMG solver for the coarser mesh with
2409 only an eighth of the number of processors. Conversely, it can solve the
2410 same problem on the same number of processors in about one eighth the
2411 time.
2412 
2413 
2414 <a name="Possibilitiesforextensions"></a><h3> Possibilities for extensions </h3>
2415 
2416 
2417 <a name="Testingconvergenceandhigherorderelements"></a><h4> Testing convergence and higher order elements </h4>
2418 
2419 
2420 The finite element degree is currently hard-coded as 2, see the template
2421 arguments of the main class. It is easy to change. To test, it would be
2422 interesting to switch to a test problem with a reference solution. This way,
2423 you can compare error rates.
2424 
2425 <a name="Coarsesolver"></a><h4> Coarse solver </h4>
2426 
2427 
2428 A more interesting example would involve a more complicated coarse mesh (see
2429 @ref step_49 "step-49" for inspiration). The issue in that case is that the coarsest
2430 level of the mesh hierarchy is actually quite large, and one would
2431 have to think about ways to solve the coarse level problem
2432 efficiently. (This is not an issue for algebraic multigrid methods
2433 because they would just continue to build coarser and coarser levels
2434 of the matrix, regardless of their geometric origin.)
2435 
2436 In the program here, we simply solve the coarse level problem with a
2437 Conjugate Gradient method without any preconditioner. That is acceptable
2438 if the coarse problem is really small -- for example, if the coarse
2439 mesh had a single cell, then the coarse mesh problems has a @f$9\times 9@f$
2440 matrix in 2d, and a @f$27\times 27@f$ matrix in 3d; for the coarse mesh we
2441 use on the @f$L@f$-shaped domain of the current program, these sizes are
2442 @f$21\times 21@f$ in 2d and @f$117\times 117@f$ in 3d. But if the coarse mesh
2443 consists of hundreds or thousands of cells, this approach will no
2444 longer work and might start to dominate the overall run-time of each V-cyle.
2445 A common approach is then to solve the coarse mesh problem using an
2446 algebraic multigrid preconditioner; this would then, however, require
2447 assembling the coarse matrix (even for the matrix-free version) as
2448 input to the AMG implementation.
2449  *
2450  *
2451 <a name="PlainProg"></a>
2452 <h1> The plain program</h1>
2453 @include "step-50.cc"
2454 */
void reinit(const IndexSet &local_constraints=IndexSet())
void add_lines(const std::vector< bool > &lines)
Definition: fe_q.h:549
virtual void parse_input(std::istream &input, const std::string &filename="input file", const std::string &last_line="", const bool skip_undefined=false)
std::ostream & print_parameters(std::ostream &out, const OutputStyle style) const
long int get_integer(const std::string &entry_string) const
bool get_bool(const std::string &entry_name) const
void declare_entry(const std::string &entry, const std::string &default_value, const Patterns::PatternBase &pattern=Patterns::Anything(), const std::string &documentation="", const bool has_to_be_set=false)
std::string get(const std::string &entry_string) const
double get_double(const std::string &entry_name) const
Definition: point.h:111
@ wall_times
Definition: timer.h:653
Point< 3 > center
@ update_values
Shape function values.
@ update_JxW_values
Transformed quadrature weights.
@ update_gradients
Shape function gradients.
@ update_quadrature_points
Transformed quadrature points.
unsigned int level
Definition: grid_out.cc:4590
__global__ void set(Number *val, const Number s, const size_type N)
#define Assert(cond, exc)
Definition: exceptions.h:1465
static ::ExceptionBase & ExcNotImplemented()
#define AssertThrow(cond, exc)
Definition: exceptions.h:1575
void make_hanging_node_constraints(const DoFHandler< dim, spacedim > &dof_handler, AffineConstraints< number > &constraints)
void make_sparsity_pattern(const DoFHandler< dim, spacedim > &dof_handler, SparsityPatternType &sparsity_pattern, const AffineConstraints< number > &constraints=AffineConstraints< number >(), const bool keep_constrained_dofs=true, const types::subdomain_id subdomain_id=numbers::invalid_subdomain_id)
std::vector< value_type > split(const typename ::Triangulation< dim, spacedim >::cell_iterator &parent, const value_type parent_value)
void extract_locally_relevant_level_dofs(const DoFHandler< dim, spacedim > &dof_handler, const unsigned int level, IndexSet &dof_set)
Definition: dof_tools.cc:1252
void extract_locally_relevant_dofs(const DoFHandler< dim, spacedim > &dof_handler, IndexSet &dof_set)
Definition: dof_tools.cc:1210
void hyper_L(Triangulation< dim > &tria, const double left=-1., const double right=1., const bool colorize=false)
void scale(const double scaling_factor, Triangulation< dim, spacedim > &triangulation)
Definition: grid_tools.cc:2042
@ matrix
Contents is actually a matrix.
static const char A
static const types::blas_int one
static const char V
SparseMatrix< double > SparseMatrix
PETScWrappers::PreconditionBoomerAMG PreconditionAMG
PETScWrappers::PreconditionJacobi PreconditionJacobi
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
void make_sparsity_pattern(const DoFHandler< dim, spacedim > &dof_handler, SparsityPatternType &sparsity, const unsigned int level, const AffineConstraints< number > &constraints=AffineConstraints< number >(), const bool keep_constrained_dofs=true)
Definition: mg_tools.cc:593
void make_interface_sparsity_pattern(const DoFHandler< dim, spacedim > &dof_handler, const MGConstrainedDoFs &mg_constrained_dofs, SparsityPatternType &sparsity, const unsigned int level)
Definition: mg_tools.cc:1052
void compute_diagonal(const MatrixFree< dim, Number, VectorizedArrayType > &matrix_free, LinearAlgebra::distributed::Vector< Number > &diagonal_global, const std::function< void(FEEvaluation< dim, fe_degree, n_q_points_1d, n_components, Number, VectorizedArrayType > &)> &local_vmult, const unsigned int dof_no=0, const unsigned int quad_no=0, const unsigned int first_selected_component=0)
Point< spacedim > point(const gp_Pnt &p, const double tolerance=1e-10)
Definition: utilities.cc:188
SymmetricTensor< 2, dim, Number > d(const Tensor< 2, dim, Number > &F, const Tensor< 2, dim, Number > &dF_dt)
SymmetricTensor< 2, dim, Number > e(const Tensor< 2, dim, Number > &F)
void distribute_sparsity_pattern(DynamicSparsityPattern &dsp, const IndexSet &locally_owned_rows, const MPI_Comm &mpi_comm, const IndexSet &locally_relevant_rows)
void call(const std::function< RT()> &function, internal::return_value< RT > &ret_val)
void free(T *&pointer)
Definition: cuda.h:97
unsigned int this_mpi_process(const MPI_Comm &mpi_communicator)
Definition: mpi.cc:128
std::string compress(const std::string &input)
Definition: utilities.cc:392
void interpolate_boundary_values(const Mapping< dim, spacedim > &mapping, const DoFHandler< dim, spacedim > &dof, const std::map< types::boundary_id, const Function< spacedim, number > * > &function_map, std::map< types::global_dof_index, number > &boundary_values, const ComponentMask &component_mask=ComponentMask())
void run(const Iterator &begin, const typename identity< Iterator >::type &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)
Definition: work_stream.h:691
unsigned int n_cells(const internal::TriangulationImplementation::NumberCache< 1 > &c)
Definition: tria.cc:12587
int(&) functions(const void *v1, const void *v2)
void assemble(const MeshWorker::DoFInfoBox< dim, DOFINFO > &dinfo, A *assembler)
Definition: loop.h:71
Definition: types.h:32
unsigned int boundary_id
Definition: types.h:129
const ::parallel::distributed::Triangulation< dim, spacedim > * triangulation
TasksParallelScheme tasks_parallel_scheme
Definition: matrix_free.h:344
UpdateFlags mapping_update_flags
Definition: matrix_free.h:368