16#include <deal.II/dofs/dof_tools.h>
17#include <deal.II/lac/linear_operator.h>
18#include <deal.II/lac/precondition.h>
19#include <deal.II/lac/solver_cg.h>
20#include <deal.II/matrix_free/fe_evaluation.h>
21#include <deal.II/numerics/vector_tools.h>
22#include <deal.II/numerics/vector_tools.templates.h>
27 namespace EulerPoisson
29 using namespace dealii;
31 template <
typename Description,
int dim,
typename Number>
38 const std::string &subsection)
39 : ParameterAcceptor(subsection)
40 , mpi_ensemble_(mpi_ensemble)
41 , hyperbolic_system_(&hyperbolic_system)
42 , parabolic_system_(¶bolic_system)
43 , offline_data_(&offline_data)
44 , initial_values_(&initial_values)
47 , n_iterations_gauss_(0)
48 , n_iterations_step_(0)
52 , potential_initialized_(false)
53 , t_background_density_(std::numeric_limits<Number>::lowest())
54 , t_magnetic_field_(std::numeric_limits<Number>::lowest())
57 add_parameter(
"gauss law restart strategy",
58 gauss_law_restart_strategy_,
59 "Strategy used when restarting the gauss law. Options are "
60 "\'no restart\', \'full restart\', \'correction\', "
61 "\'static no restart\', and \'static full restart\'.");
64 add_parameter(
"multigrid - max iter",
66 "Maximal number of CG iterations with GMG smoother");
68 gmg_smoother_range_ = 8.;
69 add_parameter(
"multigrid - chebyshev range",
71 "Chebyshev smoother: eigenvalue range parameter");
73 gmg_smoother_max_eig_ = 2.0;
74 add_parameter(
"multigrid - chebyshev max eig",
75 gmg_smoother_max_eig_,
76 "Chebyshev smoother: maximal eigenvalue");
78 gmg_smoother_degree_ = 3;
79 add_parameter(
"multigrid - chebyshev degree",
81 "Chebyshev smoother: degree");
83 gmg_smoother_n_cg_iter_ = 10;
85 "multigrid - chebyshev cg iter",
86 gmg_smoother_n_cg_iter_,
87 "Chebyshev smoother: number of CG iterations to approximate "
92 "multigrid - min level",
94 "Minimal mesh level to be visited in the geometric multigrid "
95 "cycle where the coarse grid solver (Chebyshev) is called");
97 tolerance_ = Number(1.0e-12);
98 add_parameter(
"tolerance", tolerance_,
"Tolerance for linear solvers");
100 tolerance_linfty_norm_ =
false;
101 add_parameter(
"tolerance linfty norm",
102 tolerance_linfty_norm_,
103 "Use the l_infty norm instead of the l_2 norm for the "
104 "stopping criterion");
106 ElectrostaticConfigurationLibrary::
107 populate_electrostatic_configuration_list<dim, Number>(
108 electrostatic_configuration_list_,
109 parabolic_system_->subsection());
111 const auto populate = [
this]() {
112 bool initialized =
false;
113 for (
auto &it : electrostatic_configuration_list_)
115 if (it->name() == parabolic_system_->electrostatic_configuration()) {
116 selected_electrostatic_configuration_ = it;
121 AssertThrow(initialized,
123 "Could not find an electrostatic configuration "
124 "description with name \"" +
125 parabolic_system_->electrostatic_configuration() +
129 ParameterAcceptor::parse_parameters_call_back.connect(populate);
134 template <
typename Description,
int dim,
typename Number>
138 std::cout <<
"ParabolicModule<dim, Number>::prepare()" << std::endl;
146 const auto &discretization = offline_data_->discretization();
149 dealii::ExcMessage(
"The Euler-Poisson module currently only "
150 "supports cG/dg Q1 finite elements."));
152 AssertThrow(!offline_data_->dof_handler().has_hp_capabilities(),
154 "The Euler-Poisson module currently does not support "
155 "DoFHandlers set up with hp capabilities."));
157 potential_initialized_ =
false;
163 typename MatrixFree<dim, Number>::AdditionalData additional_data;
164 additional_data.tasks_parallel_scheme =
165 MatrixFree<dim, Number>::AdditionalData::none;
168 std::vector<const dealii::DoFHandler<dim> *> dof_handlers = {
169 &offline_data_->dof_handler_cg(), &offline_data_->dof_handler()};
171 create_constraints();
172 std::vector<const dealii::AffineConstraints<Number> *>
173 affine_constraints = {&affine_constraints_potential_,
174 &offline_data_->affine_constraints()};
177 std::vector<dealii::Quadrature<1>> quadratures = {
178 discretization.quadrature_1d()[0],
179 discretization.nodal_quadrature_1d()[0]};
181 matrix_free_.reinit(discretization.mapping(),
191 laplace_operator_.initialize(matrix_free_);
192 laplace_operator_.compute_diagonal(diagonal_preconditioner_);
193 update_operator_.initialize(matrix_free_, density_, magnetic_field_);
195 typename decltype(multigrid_preconditioner_)::MultigridParameters
196 parameters{gmg_max_iter_,
198 gmg_smoother_max_eig_,
199 gmg_smoother_degree_,
200 gmg_smoother_n_cg_iter_,
204 multigrid_preconditioner_.initialize(
206 selected_electrostatic_configuration_->dirichlet_boundaries(),
213 const auto &potential_partitioner =
214 matrix_free_.get_dof_info(0).vector_partitioner;
215 potential_rhs_.reinit(potential_partitioner);
217 const auto &scalar_partitioner =
218 matrix_free_.get_dof_info(1).vector_partitioner;
219 density_.reinit(scalar_partitioner);
220 background_density_.reinit(scalar_partitioner);
222 magnetic_field_.reinit(dim == 2 ? 1 : dim);
223 for (
unsigned int i = 0; i < magnetic_field_.n_blocks(); ++i)
224 magnetic_field_.block(i).reinit(scalar_partitioner);
226 velocity_rhs_.reinit(dim);
227 for (
unsigned int i = 0; i < dim; ++i)
228 velocity_rhs_.block(i).reinit(scalar_partitioner);
234 if (!selected_electrostatic_configuration_->is_time_dependent()) {
235 update_background_density(Number(0.));
236 update_magnetic_field(Number(0.));
241 template <
typename Description,
int dim,
typename Number>
246 std::cout <<
"ParabolicModule<dim, Number>::reinit_state_vector()"
250 auto &[U, precomputed, V] = state_vector;
253 const auto &partitioner = matrix_free_.get_dof_info(0).vector_partitioner;
254 V[0].reinit_with_scalar_partitioner(partitioner);
255 V[0].deal_ii_vector() = 0.;
259 template <
typename Description,
int dim,
typename Number>
264 std::cout <<
"ParabolicModule<dim, Number>::prepare_state_vector()"
273 AssertThrow(gauss_law_restart_strategy_ !=
275 dealii::ExcNotImplemented());
277 if (!potential_initialized_ ||
278 (gauss_law_restart_strategy_ ==
280 (gauss_law_restart_strategy_ ==
283 compute_potential(t, state_vector);
285 if (!potential_initialized_ &&
286 parabolic_system_->magnetic_drift_limit())
287 enforce_magnetic_drift_velocity(state_vector);
288 potential_initialized_ =
true;
293 template <
typename Description,
int dim,
typename Number>
294 template <
int stages>
298 std::array<std::reference_wrapper<const StateVector>,
300 const std::array<Number, stages> ,
304 step(old_state_vector,
312 template <
typename Description,
int dim,
typename Number>
322 step(old_state_vector,
338 step(old_state_vector,
347 template <
typename Description,
int dim,
typename Number>
349 std::ostream &output)
const
351 output <<
" [ " << std::setprecision(2) << std::fixed
352 << n_iterations_gauss_ <<
" GMG gauss -- "
353 << n_iterations_step_ <<
" GMG step ]" << std::endl;
357 template <
typename Description,
int dim,
typename Number>
361 std::cout <<
"ParabolicModule<dim, Number>::create_constraints()"
365 const auto &discretization = offline_data_->discretization();
366 const auto &dof_handler = offline_data_->dof_handler_cg();
368 affine_constraints_potential_.clear();
370 const auto locally_relevant =
371 DoFTools::extract_locally_relevant_dofs(dof_handler);
373 const IndexSet &locally_owned = dof_handler.locally_owned_dofs();
374 affine_constraints_potential_.reinit(locally_owned, locally_relevant);
376 DoFTools::make_hanging_node_constraints(offline_data_->dof_handler_cg(),
377 affine_constraints_potential_);
384 const auto &periodic_faces =
385 discretization.triangulation().get_periodic_face_map();
387 for (
const auto &[left, value] : periodic_faces) {
388 const auto &[right, orientation] = value;
390 typename DoFHandler<dim>::cell_iterator dof_cell_left(
391 &left.first->get_triangulation(),
396 typename DoFHandler<dim>::cell_iterator dof_cell_right(
397 &right.first->get_triangulation(),
398 right.first->level(),
399 right.first->index(),
402 if constexpr (std::is_same_v<Number, double>) {
403 DoFTools::make_periodicity_constraints(
404 dof_cell_left->face(left.second),
405 dof_cell_right->face(right.second),
406 affine_constraints_potential_,
410 AssertThrow(
false, dealii::ExcNotImplemented());
415 for (
const auto &it :
416 selected_electrostatic_configuration_->dirichlet_boundaries())
417 DoFTools::make_zero_boundary_constraints(
418 offline_data_->dof_handler_cg(), it, affine_constraints_potential_);
420 affine_constraints_potential_.close();
424 template <
typename Description,
int dim,
typename Number>
425 void ParabolicModule<Description, dim, Number>::update_background_density(
426 const Number t)
const
429 std::cout <<
"ParabolicModule<dim, Number>::update_background_density()"
437 if (!selected_electrostatic_configuration_->is_time_dependent() &&
445 if (std::abs(t_background_density_ - t) < 1.e-12)
449 std::cout <<
" updating to t = " << t << std::endl;
452 ComputingTimer::Scope scope(
"time step [X] - interpolate data vectors");
454 const auto &discretization = offline_data_->discretization();
455 background_density_.zero_out_ghost_values();
456 dealii::VectorTools::interpolate(
457 discretization.mapping(),
458 offline_data_->dof_handler(),
459 dealii::ScalarFunctionFromFunctionObject<dim, Number>(
460 [&](
const dealii::Point<dim> &p) {
461 return selected_electrostatic_configuration_
462 ->background_density(p, t);
464 background_density_);
465 background_density_.update_ghost_values();
467 t_background_density_ = t;
471 template <
typename Description,
int dim,
typename Number>
472 void ParabolicModule<Description, dim, Number>::update_magnetic_field(
473 const Number t)
const
476 std::cout <<
"ParabolicModule<dim, Number>::update_magnetic_field()"
484 if (!selected_electrostatic_configuration_->is_time_dependent() &&
492 if (std::abs(t_magnetic_field_ - t) < 1.e-12)
496 std::cout <<
" updating to t = " << t << std::endl;
499 ComputingTimer::Scope scope(
"time step [X] - interpolate data vectors");
501 const auto &discretization = offline_data_->discretization();
502 for (
unsigned int k = 0; k < (dim == 2 ? 1 : dim); ++k) {
503 magnetic_field_.block(k).zero_out_ghost_values();
504 dealii::VectorTools::interpolate(
505 discretization.mapping(),
506 offline_data_->dof_handler(),
507 to_function<dim, Number>(
508 [&](
const dealii::Point<dim> &p) {
509 return selected_electrostatic_configuration_->magnetic_field(
513 magnetic_field_.block(k));
515 magnetic_field_.update_ghost_values();
517 t_magnetic_field_ = t;
521 template <
typename Description,
int dim,
typename Number>
522 void ParabolicModule<Description, dim, Number>::compute_potential(
523 const Number t, StateVector &state_vector)
const
526 std::cout <<
"ParabolicModule<dim, Number>::compute_potential()"
529 const auto U_view = std::get<0>(state_vector).view();
530 auto &V = std::get<2>(state_vector);
531 auto &potential = V[0].deal_ii_vector();
533 const unsigned int n_owned = offline_data_->n_locally_owned();
535 constexpr unsigned int order_fe = 1;
536 constexpr unsigned int order_quad = 2;
544 ComputingTimer::Scope scope(
"time step [P] 1 - enforce Gauss law");
546 update_background_density(t);
548 const auto body_copy = [&](
auto sentinel,
unsigned int i) {
549 using T =
decltype(sentinel);
550 const auto view = hyperbolic_system_->template view<dim, T>();
551 const auto U_i = U_view.template read_tensor<T>(i);
552 const auto rho_i = view.density(U_i);
553 write_entry<T>(density_, rho_i, i);
556 cpu_simd_loop<Number>(
557 "time_step_parabolic_1a", body_copy, 0, n_owned, n_owned);
559 density_.update_ghost_values();
561 const auto body_matrix_free = [
this](
const auto &data,
565 FEEvaluation<dim, order_fe, order_quad, 1, Number>
566 fee_potential(data, 0, 1);
567 FEEvaluation<dim, order_fe, order_quad, 1, Number>
568 fee_density(data, 1, 1);
569 FEEvaluation<dim, order_fe, order_quad, 1, Number>
570 fee_background(data, 1, 1);
573 const Number alpha = parabolic_system_->alpha();
575 for (
unsigned int cell = range.first; cell < range.second; ++cell) {
576 fee_potential.reinit(cell);
577 fee_density.reinit(cell);
578 fee_background.reinit(cell);
580 fee_density.gather_evaluate(src, dealii::EvaluationFlags::values);
581 fee_background.gather_evaluate(background_density_,
582 dealii::EvaluationFlags::values);
584 for (
unsigned int q = 0; q < fee_potential.n_q_points; ++q) {
585 const auto density_q = fee_density.get_value(q);
586 const auto background_q = fee_background.get_value(q);
588 const auto value = alpha * (density_q + background_q);
589 fee_potential.submit_value(value, q);
591 fee_potential.integrate_scatter(dealii::EvaluationFlags::values, dst);
595 matrix_free_.template cell_loop<ScalarHostVector, ScalarHostVector>(
607 matrix_free_.get_affine_constraints(0).distribute(potential);
608 matrix_free_.get_affine_constraints(0).set_zero(potential_rhs_);
610 const auto tolerance =
611 (tolerance_linfty_norm_ ? potential_rhs_.linfty_norm()
612 : potential_rhs_.l2_norm()) *
615 typename dealii::SolverCG<ScalarHostVector>::AdditionalData solver_data;
618 SolverControl solver_control(gmg_max_iter_, tolerance);
619 dealii::SolverCG<ScalarHostVector> solver(solver_control, solver_data);
620 solver.solve(laplace_operator_,
623 multigrid_preconditioner_);
626 if (potential_initialized_) {
628 n_iterations_gauss_ =
629 0.9 * n_iterations_gauss_ + 0.1 * solver_control.last_step();
631 n_iterations_gauss_ = solver_control.last_step();
634 }
catch (SolverControl::NoConvergence &) {
635 SolverControl solver_control(1000, tolerance);
636 dealii::SolverCG<ScalarHostVector> solver(solver_control, solver_data);
638 solver.solve(laplace_operator_,
641 diagonal_preconditioner_);
643 if (potential_initialized_) {
645 n_iterations_gauss_ *= 0.9;
646 n_iterations_gauss_ +=
647 0.1 * gmg_max_iter_ + 0.1 * solver_control.last_step();
649 n_iterations_gauss_ = gmg_max_iter_ + solver_control.last_step();
655 matrix_free_.get_affine_constraints(0).distribute(potential);
659 template <
typename Description,
int dim,
typename Number>
661 ParabolicModule<Description, dim, Number>::enforce_magnetic_drift_velocity(
662 StateVector &state_vector)
const
666 <<
"ParabolicModule<dim, Number>::enforce_magnetic_drift_velocity()"
670 const auto U_view = std::get<0>(state_vector).view();
671 auto &V = std::get<2>(state_vector);
672 auto &potential = V[0].deal_ii_vector();
674 const unsigned int n_owned = offline_data_->n_locally_owned();
676 const auto lumped_mass_matrix_inverse_view =
677 offline_data_->lumped_mass_matrix_inverse().view();
679 constexpr unsigned int order_fe = 1;
680 constexpr unsigned int order_quad = 2;
688 update_magnetic_field(Number(0.));
692 const auto body_velocity =
693 [](
const auto &data,
auto &dst,
const auto &src,
const auto range) {
694 FEEvaluation<dim, order_fe, order_quad, 1, Number>
696 FEEvaluation<dim, order_fe, order_quad, dim, Number>
699 for (
unsigned int cell = range.first; cell < range.second; ++cell) {
700 fee_pot.reinit(cell);
701 fee_vel.reinit(cell);
703 fee_pot.gather_evaluate(src, dealii::EvaluationFlags::gradients);
704 for (
unsigned int q = 0; q < fee_pot.n_q_points; ++q) {
705 fee_vel.submit_value(fee_pot.get_gradient(q), q);
707 fee_vel.integrate_scatter(dealii::EvaluationFlags::values, dst);
711 matrix_free_.template cell_loop<BlockHostVector, ScalarHostVector>(
717 const auto body = [&](
auto sentinel,
unsigned int i) {
718 using T =
decltype(sentinel);
719 const auto view = hyperbolic_system_->template view<dim, T>();
722 lumped_mass_matrix_inverse_view.template read_entry<T>(i);
724 auto U_i = U_view.template read_tensor<T>(i);
725 const auto rho_i = view.density(U_i);
726 const auto m_i = view.momentum(U_i);
727 const auto v_i = m_i / rho_i;
729 dealii::Tensor<1, (dim == 2 ? 1 : dim), T> magnetic_field;
730 for (
unsigned int d = 0; d < (dim == 2 ? 1 : dim); ++d)
731 magnetic_field[d] = read_entry<T>(magnetic_field_.block(d), i);
733 dealii::Tensor<1, dim, T> grad_phi;
734 for (
unsigned int d = 0; d < dim; ++d)
735 grad_phi[d] = m_i_inv * read_entry<T>(velocity_rhs_.block(d), i);
739 if constexpr (dim == 2) {
740 new_v_i = -magnetic_field[0] * cross_product_2d(grad_phi) /
741 magnetic_field.norm_square();
743 }
else if constexpr (dim == 3) {
744 new_v_i = -cross_product_3d(grad_phi, magnetic_field) /
745 magnetic_field.norm_square();
748 for (
unsigned int d = 0; d < dim; ++d)
749 U_i[1 + d] = rho_i * new_v_i[d];
752 if constexpr (view.have_energy_equation)
754 Number(0.5) * rho_i * (new_v_i.norm_square() - v_i.norm_square());
756 U_view.template write_tensor<T>(U_i, i);
759 cpu_simd_loop<Number>(
760 "time_step_parabolic_1c", body, 0, n_owned, n_owned);
764 template <
typename Description,
int dim,
typename Number>
765 void ParabolicModule<Description, dim, Number>::step(
766 const StateVector &old_state_vector,
768 StateVector &new_state_vector,
769 Number tau [[maybe_unused]],
770 const bool crank_nicolson_extrapolation [[maybe_unused]])
const
773 std::cout <<
"ParabolicModule<dim, Number>::step()" << std::endl;
774 std::cout <<
" perform time-step with tau = " << tau << std::endl;
775 if (crank_nicolson_extrapolation)
776 std::cout <<
" and extrapolate to t + 2 * tau" << std::endl;
779 const Number alpha = parabolic_system_->alpha();
781 const auto &old_U = std::get<0>(old_state_vector);
782 const auto old_U_view = old_U.view();
783 const auto &old_V = std::get<2>(old_state_vector);
784 const auto &old_potential = old_V[0].deal_ii_vector();
786 auto &new_U = std::get<0>(new_state_vector);
787 auto &new_V = std::get<2>(new_state_vector);
788 auto &new_potential = new_V[0].deal_ii_vector();
790 const unsigned int n_owned = offline_data_->n_locally_owned();
792 const auto lumped_mass_matrix_inverse_view =
793 offline_data_->lumped_mass_matrix_inverse().view();
795 constexpr unsigned int order_fe = 1;
796 constexpr unsigned int order_quad = 2;
802 new_potential = old_potential;
808 if ((gauss_law_restart_strategy_ !=
810 (gauss_law_restart_strategy_ !=
830 ComputingTimer::Scope scope(
"time step [P] 2 - update potential");
833 update_magnetic_field(t + tau);
840 const auto body_copy = [&](
auto sentinel,
unsigned int i) {
841 using T =
decltype(sentinel);
842 const auto view = hyperbolic_system_->template view<dim, T>();
844 const auto U_i = old_U_view.template read_tensor<T>(i);
845 const auto rho_i = view.density(U_i);
846 const auto m_i = view.momentum(U_i);
848 dealii::Tensor<1, (dim == 2 ? 1 : dim), T> magnetic_field;
849 for (
unsigned int d = 0; d < (dim == 2 ? 1 : dim); ++d)
850 magnetic_field[d] = read_entry<T>(magnetic_field_.block(d), i);
852 const auto velocity_rhs =
853 tau * alpha * rho_i *
856 write_entry<T>(density_, rho_i, i);
857 for (
unsigned int d = 0; d < dim; ++d)
858 write_entry<T>(velocity_rhs_.block(d), velocity_rhs[d], i);
861 cpu_simd_loop<Number>(
862 "time_step_parabolic_2a", body_copy, 0, n_owned, n_owned);
864 density_.update_ghost_values();
868 const auto body_laplace = [](
const auto &data,
872 FEEvaluation<dim, order_fe, order_quad, 1, Number> fee(
875 for (
unsigned int cell = range.first; cell < range.second; ++cell) {
877 fee.gather_evaluate(src, dealii::EvaluationFlags::gradients);
879 for (
unsigned int q = 0; q < fee.n_q_points; ++q) {
880 const auto grad_potential = fee.get_gradient(q);
881 fee.submit_gradient(grad_potential, q);
883 fee.integrate_scatter(dealii::EvaluationFlags::gradients, dst);
887 matrix_free_.template cell_loop<ScalarHostVector, ScalarHostVector>(
895 const auto body_velocity = [](
const auto &data,
899 FEEvaluation<dim, order_fe, order_quad, 1, Number>
901 FEEvaluation<dim, order_fe, order_quad, dim, Number>
904 for (
unsigned int cell = range.first; cell < range.second; ++cell) {
905 fee_pot.reinit(cell);
906 fee_vel.reinit(cell);
908 fee_vel.gather_evaluate(src, dealii::EvaluationFlags::values);
910 for (
unsigned int q = 0; q < fee_pot.n_q_points; ++q) {
911 if constexpr (dim == 1) {
912 decltype(fee_pot.get_gradient(q)) velocity_rhs;
913 velocity_rhs[0] = fee_vel.get_value(q);
914 fee_pot.submit_gradient(velocity_rhs, q);
916 fee_pot.submit_gradient(fee_vel.get_value(q), q);
919 fee_pot.integrate_scatter(dealii::EvaluationFlags::gradients, dst);
923 matrix_free_.template cell_loop<ScalarHostVector, BlockHostVector>(
931 if (selected_electrostatic_configuration_->is_time_dependent()) {
937 update_background_density(t);
939 Number factor = (crank_nicolson_extrapolation ? -0.5 : -1.0) * alpha;
941 const auto body = [&factor](
const auto &data,
945 FEEvaluation<dim, order_fe, order_quad, 1, Number>
946 fee_potential(data, 0, 1);
947 FEEvaluation<dim, order_fe, order_quad, 1, Number>
948 fee_background(data, 1, 1);
950 for (
unsigned int cell = range.first; cell < range.second; ++cell) {
951 fee_potential.reinit(cell);
952 fee_background.reinit(cell);
953 fee_background.gather_evaluate(src, EvaluationFlags::values);
955 for (
unsigned int q = 0; q < fee_potential.n_q_points; ++q) {
956 const auto background_q = fee_background.get_value(q);
957 fee_potential.submit_value(factor * background_q, q);
959 fee_potential.integrate_scatter(EvaluationFlags::values, dst);
963 matrix_free_.template cell_loop<ScalarHostVector, ScalarHostVector>(
973 update_background_density(
974 t + (crank_nicolson_extrapolation ? 2. : 1.) * tau);
978 matrix_free_.template cell_loop<ScalarHostVector, ScalarHostVector>(
991 update_operator_.set_alpha(alpha);
992 update_operator_.set_theta_tau(tau);
994 matrix_free_.get_affine_constraints(0).distribute(new_potential);
995 matrix_free_.get_affine_constraints(0).set_zero(potential_rhs_);
997 const auto tolerance =
998 (tolerance_linfty_norm_ ? potential_rhs_.linfty_norm()
999 : potential_rhs_.l2_norm()) *
1002 typename dealii::SolverCG<ScalarHostVector>::AdditionalData solver_data;
1005 SolverControl solver_control(gmg_max_iter_, tolerance);
1006 dealii::SolverCG<ScalarHostVector> solver(solver_control,
1008 solver.solve(update_operator_,
1011 multigrid_preconditioner_);
1014 n_iterations_step_ =
1015 0.9 * n_iterations_step_ + 0.1 * solver_control.last_step();
1017 }
catch (SolverControl::NoConvergence &) {
1018 SolverControl solver_control(1000, tolerance);
1019 dealii::SolverCG<ScalarHostVector> solver(solver_control,
1022 solver.solve(update_operator_,
1025 diagonal_preconditioner_);
1028 n_iterations_step_ *= 0.9;
1029 n_iterations_step_ +=
1030 0.1 * gmg_max_iter_ + 0.1 * solver_control.last_step();
1033 matrix_free_.get_affine_constraints(0).distribute(new_potential);
1044 const auto body_velocity =
1045 [](
const auto &data,
auto &dst,
const auto &src,
const auto range) {
1046 FEEvaluation<dim, order_fe, order_quad, 1, Number>
1047 fee_pot(data, 0, 1);
1048 FEEvaluation<dim, order_fe, order_quad, dim, Number>
1049 fee_vel(data, 1, 1);
1051 for (
unsigned int cell = range.first; cell < range.second; ++cell) {
1052 fee_pot.reinit(cell);
1053 fee_vel.reinit(cell);
1055 fee_pot.gather_evaluate(src, dealii::EvaluationFlags::gradients);
1056 for (
unsigned int q = 0; q < fee_pot.n_q_points; ++q) {
1057 fee_vel.submit_value(fee_pot.get_gradient(q), q);
1059 fee_vel.integrate_scatter(dealii::EvaluationFlags::values, dst);
1063 matrix_free_.template cell_loop<BlockHostVector, ScalarHostVector>(
1076 const auto new_U_view = new_U.view();
1078 if (crank_nicolson_extrapolation) {
1079 new_potential *= Number(2.);
1080 new_potential -= old_potential;
1087 const auto body = [&](
auto sentinel,
unsigned int i) {
1088 using T =
decltype(sentinel);
1089 const auto view = hyperbolic_system_->template view<dim, T>();
1091 const auto m_i_inv =
1092 lumped_mass_matrix_inverse_view.template read_entry<T>(i);
1094 const auto old_U_i = old_U_view.template read_tensor<T>(i);
1095 const auto rho_i = view.density(old_U_i);
1096 const auto old_m_i = view.momentum(old_U_i);
1097 const auto old_v_i = old_m_i / rho_i;
1099 dealii::Tensor<1, (dim == 2 ? 1 : dim), T> magnetic_field;
1100 for (
unsigned int d = 0; d < (dim == 2 ? 1 : dim); ++d)
1101 magnetic_field[d] = read_entry<T>(magnetic_field_.block(d), i);
1103 dealii::Tensor<1, dim, T> grad_phi;
1104 for (
unsigned int d = 0; d < dim; ++d)
1105 grad_phi[d] = m_i_inv * read_entry<T>(velocity_rhs_.block(d), i);
1111 if (crank_nicolson_extrapolation)
1112 new_v_i = Number(2.) * new_v_i - old_v_i;
1114 auto new_U_i = old_U_i;
1115 for (
unsigned int d = 0; d < dim; ++d)
1116 new_U_i[1 + d] = rho_i * new_v_i[d];
1119 if constexpr (view.have_energy_equation)
1120 new_U_i[1 + dim] += Number(0.5) * rho_i *
1121 (new_v_i.norm_square() - old_v_i.norm_square());
1123 new_U_view.template write_tensor<T>(new_U_i, i);
1126 cpu_simd_loop<Number>(
1127 "time_step_parabolic_2c", body, 0, n_owned, n_owned);
typename Description::HyperbolicSystem HyperbolicSystem
typename Description::ParabolicSystem ParabolicSystem
typename View::StateVector StateVector
DEAL_II_ALWAYS_INLINE dealii::Tensor< 1, dim, Number > apply_B_n_inverse(const dealii::Tensor< 1,(dim==2 ? 1 :dim), Number > &magnetic_field, const Number2 &theta_tau, const dealii::Tensor< 1, dim, Number > &velocity)