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 HyperbolicDescription,
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 HyperbolicDescription,
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 HyperbolicDescription,
int dim,
typename Number>
247 std::cout <<
"ParabolicModule<dim, Number>::reinit_state_vector()"
254 const auto &partitioner = matrix_free_.get_dof_info(0).vector_partitioner;
255 V[0].reinit_with_scalar_partitioner(partitioner, 1);
256 V[0].deal_ii_vector() = 0.;
260 template <
typename HyperbolicDescription,
int dim,
typename Number>
266 std::cout <<
"ParabolicModule<dim, Number>::prepare_state_vector()"
275 AssertThrow(gauss_law_restart_strategy_ !=
277 dealii::ExcNotImplemented());
279 if (!potential_initialized_ ||
280 (gauss_law_restart_strategy_ ==
282 (gauss_law_restart_strategy_ ==
285 compute_potential(t, state_vector);
287 if (!potential_initialized_ &&
288 parabolic_system_->magnetic_drift_limit())
289 enforce_magnetic_drift_velocity(state_vector);
290 potential_initialized_ =
true;
295 template <
typename HyperbolicDescription,
int dim,
typename Number>
296 template <
int stages>
303 const std::array<Number, stages> ,
307 step(old_state_vector,
315 template <
typename HyperbolicDescription,
int dim,
typename Number>
326 step(old_state_vector,
342 step(old_state_vector,
351 template <
typename HyperbolicDescription,
int dim,
typename Number>
355 output <<
" [ " << std::setprecision(2) << std::fixed
356 << n_iterations_gauss_ <<
" GMG gauss -- "
357 << n_iterations_step_ <<
" GMG step ]" << std::endl;
361 template <
typename HyperbolicDescription,
int dim,
typename Number>
366 std::cout <<
"ParabolicModule<dim, Number>::create_constraints()"
370 const auto &discretization = offline_data_->discretization();
371 const auto &dof_handler = offline_data_->dof_handler_cg();
373 affine_constraints_potential_.clear();
375 const auto locally_relevant =
376 DoFTools::extract_locally_relevant_dofs(dof_handler);
378 const IndexSet &locally_owned = dof_handler.locally_owned_dofs();
379 affine_constraints_potential_.reinit(locally_owned, locally_relevant);
381 DoFTools::make_hanging_node_constraints(offline_data_->dof_handler_cg(),
382 affine_constraints_potential_);
389 const auto &periodic_faces =
390 discretization.triangulation().get_periodic_face_map();
392 for (
const auto &[left, value] : periodic_faces) {
393 const auto &[right, orientation] = value;
395 typename DoFHandler<dim>::cell_iterator dof_cell_left(
396 &left.first->get_triangulation(),
401 typename DoFHandler<dim>::cell_iterator dof_cell_right(
402 &right.first->get_triangulation(),
403 right.first->level(),
404 right.first->index(),
407 if constexpr (std::is_same_v<Number, double>) {
408 DoFTools::make_periodicity_constraints(
409 dof_cell_left->face(left.second),
410 dof_cell_right->face(right.second),
411 affine_constraints_potential_,
415 AssertThrow(
false, dealii::ExcNotImplemented());
420 for (
const auto &it :
421 selected_electrostatic_configuration_->dirichlet_boundaries())
422 DoFTools::make_zero_boundary_constraints(
423 offline_data_->dof_handler_cg(), it, affine_constraints_potential_);
425 affine_constraints_potential_.close();
429 template <
typename HyperbolicDescription,
int dim,
typename Number>
430 void ParabolicModule<HyperbolicDescription, dim, Number>::
431 update_background_density(
const Number t)
const
434 std::cout <<
"ParabolicModule<dim, Number>::update_background_density()"
442 if (!selected_electrostatic_configuration_->is_time_dependent() &&
450 if (std::abs(t_background_density_ - t) < 1.e-12)
454 std::cout <<
" updating to t = " << t << std::endl;
457 ComputingTimer::Scope scope(
"time step [X] - interpolate data vectors");
459 const auto &discretization = offline_data_->discretization();
460 background_density_.zero_out_ghost_values();
461 dealii::VectorTools::interpolate(
462 discretization.mapping(),
463 offline_data_->dof_handler(),
464 dealii::ScalarFunctionFromFunctionObject<dim, Number>(
465 [&](
const dealii::Point<dim> &p) {
466 return selected_electrostatic_configuration_
467 ->background_density(p, t);
469 background_density_);
470 background_density_.update_ghost_values();
472 t_background_density_ = t;
476 template <
typename HyperbolicDescription,
int dim,
typename Number>
478 ParabolicModule<HyperbolicDescription, dim, Number>::update_magnetic_field(
479 const Number t)
const
482 std::cout <<
"ParabolicModule<dim, Number>::update_magnetic_field()"
490 if (!selected_electrostatic_configuration_->is_time_dependent() &&
498 if (std::abs(t_magnetic_field_ - t) < 1.e-12)
502 std::cout <<
" updating to t = " << t << std::endl;
505 ComputingTimer::Scope scope(
"time step [X] - interpolate data vectors");
507 const auto &discretization = offline_data_->discretization();
508 for (
unsigned int k = 0; k < (dim == 2 ? 1 : dim); ++k) {
509 magnetic_field_.block(k).zero_out_ghost_values();
510 dealii::VectorTools::interpolate(
511 discretization.mapping(),
512 offline_data_->dof_handler(),
513 to_function<dim, Number>(
514 [&](
const dealii::Point<dim> &p) {
515 return selected_electrostatic_configuration_->magnetic_field(
519 magnetic_field_.block(k));
521 magnetic_field_.update_ghost_values();
523 t_magnetic_field_ = t;
527 template <
typename HyperbolicDescription,
int dim,
typename Number>
528 void ParabolicModule<HyperbolicDescription, dim, Number>::compute_potential(
529 const Number t, StateVector<Number> &state_vector)
const
532 std::cout <<
"ParabolicModule<dim, Number>::compute_potential()"
535 using HostSpace = dealii::MemorySpace::Host;
537 copy_to_memory_space<HostSpace>(std::as_const(state_vector),
542 std::as_const(state_vector).U.template view<problem_dimension>();
543 auto &V = state_vector.V;
544 auto &potential = V[0].deal_ii_vector();
546 const unsigned int n_owned = offline_data_->n_locally_owned();
548 constexpr unsigned int order_fe = 1;
549 constexpr unsigned int order_quad = 2;
557 ComputingTimer::Scope scope(
"time step [P] 1 - enforce Gauss law");
559 update_background_density(t);
561 const auto body_copy = [&](
auto sentinel,
unsigned int i) {
562 using T =
decltype(sentinel);
563 const auto view = hyperbolic_system_->template view<dim, T>();
564 const auto U_i = U_view.template read_tensor<T>(i);
565 const auto rho_i = view.density(U_i);
566 write_entry<T>(density_, rho_i, i);
569 cpu_simd_loop<Number>(
570 "time_step_parabolic_1a", body_copy, 0, n_owned, n_owned);
572 density_.update_ghost_values();
574 const auto body_matrix_free = [
this](
const auto &data,
578 FEEvaluation<dim, order_fe, order_quad, 1, Number>
579 fee_potential(data, 0, 1);
580 FEEvaluation<dim, order_fe, order_quad, 1, Number>
581 fee_density(data, 1, 1);
582 FEEvaluation<dim, order_fe, order_quad, 1, Number>
583 fee_background(data, 1, 1);
586 const Number alpha = parabolic_system_->alpha();
588 for (
unsigned int cell = range.first; cell < range.second; ++cell) {
589 fee_potential.reinit(cell);
590 fee_density.reinit(cell);
591 fee_background.reinit(cell);
593 fee_density.gather_evaluate(src, dealii::EvaluationFlags::values);
594 fee_background.gather_evaluate(background_density_,
595 dealii::EvaluationFlags::values);
597 for (
unsigned int q = 0; q < fee_potential.n_q_points; ++q) {
598 const auto density_q = fee_density.get_value(q);
599 const auto background_q = fee_background.get_value(q);
601 const auto value = alpha * (density_q + background_q);
602 fee_potential.submit_value(value, q);
604 fee_potential.integrate_scatter(dealii::EvaluationFlags::values, dst);
608 matrix_free_.template cell_loop<ScalarHostVector<Number>,
609 ScalarHostVector<Number>>(
621 matrix_free_.get_affine_constraints(0).distribute(potential);
622 matrix_free_.get_affine_constraints(0).set_zero(potential_rhs_);
624 const auto tolerance =
625 (tolerance_linfty_norm_ ? potential_rhs_.linfty_norm()
626 : potential_rhs_.l2_norm()) *
629 typename dealii::SolverCG<ScalarHostVector<Number>>::AdditionalData
633 SolverControl solver_control(gmg_max_iter_, tolerance);
634 dealii::SolverCG<ScalarHostVector<Number>> solver(solver_control,
636 solver.solve(laplace_operator_,
639 multigrid_preconditioner_);
642 if (potential_initialized_) {
644 n_iterations_gauss_ =
645 0.9 * n_iterations_gauss_ + 0.1 * solver_control.last_step();
647 n_iterations_gauss_ = solver_control.last_step();
650 }
catch (SolverControl::NoConvergence &) {
651 SolverControl solver_control(1000, tolerance);
652 dealii::SolverCG<ScalarHostVector<Number>> solver(solver_control,
655 solver.solve(laplace_operator_,
658 diagonal_preconditioner_);
660 if (potential_initialized_) {
662 n_iterations_gauss_ *= 0.9;
663 n_iterations_gauss_ +=
664 0.1 * gmg_max_iter_ + 0.1 * solver_control.last_step();
666 n_iterations_gauss_ = gmg_max_iter_ + solver_control.last_step();
672 matrix_free_.get_affine_constraints(0).distribute(potential);
676 template <
typename HyperbolicDescription,
int dim,
typename Number>
677 void ParabolicModule<HyperbolicDescription, dim, Number>::
678 enforce_magnetic_drift_velocity(StateVector<Number> &state_vector)
const
682 <<
"ParabolicModule<dim, Number>::enforce_magnetic_drift_velocity()"
686 using HostSpace = dealii::MemorySpace::Host;
688 move_to_memory_space<HostSpace>(state_vector,
690 copy_to_memory_space<HostSpace>(std::as_const(state_vector),
693 const auto U_view = state_vector.U.template view<problem_dimension>();
694 const auto &V = std::as_const(state_vector).V;
695 const auto &potential = V[0].deal_ii_vector();
697 const unsigned int n_owned = offline_data_->n_locally_owned();
699 const auto lumped_mass_matrix_inverse_view =
700 offline_data_->lumped_mass_matrix_inverse().template view<1>();
702 constexpr unsigned int order_fe = 1;
703 constexpr unsigned int order_quad = 2;
711 update_magnetic_field(Number(0.));
715 const auto body_velocity =
716 [](
const auto &data,
auto &dst,
const auto &src,
const auto range) {
717 FEEvaluation<dim, order_fe, order_quad, 1, Number>
719 FEEvaluation<dim, order_fe, order_quad, dim, Number>
722 for (
unsigned int cell = range.first; cell < range.second; ++cell) {
723 fee_pot.reinit(cell);
724 fee_vel.reinit(cell);
726 fee_pot.gather_evaluate(src, dealii::EvaluationFlags::gradients);
727 for (
unsigned int q = 0; q < fee_pot.n_q_points; ++q) {
728 fee_vel.submit_value(fee_pot.get_gradient(q), q);
730 fee_vel.integrate_scatter(dealii::EvaluationFlags::values, dst);
735 .template cell_loop<BlockHostVector, ScalarHostVector<Number>>(
741 const auto body = [&](
auto sentinel,
unsigned int i) {
742 using T =
decltype(sentinel);
743 const auto view = hyperbolic_system_->template view<dim, T>();
746 lumped_mass_matrix_inverse_view.template read_entry<T>(i);
748 auto U_i = U_view.template read_tensor<T>(i);
749 const auto rho_i = view.density(U_i);
750 const auto m_i = view.momentum(U_i);
751 const auto v_i = m_i / rho_i;
753 dealii::Tensor<1, (dim == 2 ? 1 : dim), T> magnetic_field;
754 for (
unsigned int d = 0; d < (dim == 2 ? 1 : dim); ++d)
755 magnetic_field[d] = read_entry<T>(magnetic_field_.block(d), i);
757 dealii::Tensor<1, dim, T> grad_phi;
758 for (
unsigned int d = 0; d < dim; ++d)
759 grad_phi[d] = m_i_inv * read_entry<T>(velocity_rhs_.block(d), i);
763 if constexpr (dim == 2) {
764 new_v_i = -magnetic_field[0] * cross_product_2d(grad_phi) /
765 magnetic_field.norm_square();
767 }
else if constexpr (dim == 3) {
768 new_v_i = -cross_product_3d(grad_phi, magnetic_field) /
769 magnetic_field.norm_square();
772 for (
unsigned int d = 0; d < dim; ++d)
773 U_i[1 + d] = rho_i * new_v_i[d];
776 if constexpr (view.have_energy_equation)
778 Number(0.5) * rho_i * (new_v_i.norm_square() - v_i.norm_square());
780 U_view.template write_tensor<T>(U_i, i);
783 cpu_simd_loop<Number>(
784 "time_step_parabolic_1c", body, 0, n_owned, n_owned);
788 template <
typename HyperbolicDescription,
int dim,
typename Number>
789 void ParabolicModule<HyperbolicDescription, dim, Number>::step(
790 const StateVector<Number> &old_state_vector,
792 StateVector<Number> &new_state_vector,
793 Number tau [[maybe_unused]],
794 const bool crank_nicolson_extrapolation [[maybe_unused]])
const
797 std::cout <<
"ParabolicModule<dim, Number>::step()" << std::endl;
798 std::cout <<
" perform time-step with tau = " << tau << std::endl;
799 if (crank_nicolson_extrapolation)
800 std::cout <<
" and extrapolate to t + 2 * tau" << std::endl;
803 const Number alpha = parabolic_system_->alpha();
805 using HostSpace = dealii::MemorySpace::Host;
807 copy_to_memory_space<HostSpace>(old_state_vector,
810 move_to_memory_space<HostSpace>(new_state_vector,
813 const auto &old_U = old_state_vector.U;
814 const auto old_U_view = old_U.template view<problem_dimension>();
815 const auto &old_V = old_state_vector.V;
816 const auto &old_potential = old_V[0].deal_ii_vector();
818 auto &new_U = new_state_vector.U;
819 auto &new_V = new_state_vector.V;
820 auto &new_potential = new_V[0].deal_ii_vector();
822 const unsigned int n_owned = offline_data_->n_locally_owned();
824 const auto lumped_mass_matrix_inverse_view =
825 offline_data_->lumped_mass_matrix_inverse().template view<1>();
827 constexpr unsigned int order_fe = 1;
828 constexpr unsigned int order_quad = 2;
834 new_potential = old_potential;
840 if ((gauss_law_restart_strategy_ !=
842 (gauss_law_restart_strategy_ !=
862 ComputingTimer::Scope scope(
"time step [P] 2 - update potential");
865 update_magnetic_field(t + tau);
872 const auto body_copy = [&](
auto sentinel,
unsigned int i) {
873 using T =
decltype(sentinel);
874 const auto view = hyperbolic_system_->template view<dim, T>();
876 const auto U_i = old_U_view.template read_tensor<T>(i);
877 const auto rho_i = view.density(U_i);
878 const auto m_i = view.momentum(U_i);
880 dealii::Tensor<1, (dim == 2 ? 1 : dim), T> magnetic_field;
881 for (
unsigned int d = 0; d < (dim == 2 ? 1 : dim); ++d)
882 magnetic_field[d] = read_entry<T>(magnetic_field_.block(d), i);
884 const auto velocity_rhs =
885 tau * alpha * rho_i *
888 write_entry<T>(density_, rho_i, i);
889 for (
unsigned int d = 0; d < dim; ++d)
890 write_entry<T>(velocity_rhs_.block(d), velocity_rhs[d], i);
893 cpu_simd_loop<Number>(
894 "time_step_parabolic_2a", body_copy, 0, n_owned, n_owned);
896 density_.update_ghost_values();
900 const auto body_laplace = [](
const auto &data,
904 FEEvaluation<dim, order_fe, order_quad, 1, Number> fee(
907 for (
unsigned int cell = range.first; cell < range.second; ++cell) {
909 fee.gather_evaluate(src, dealii::EvaluationFlags::gradients);
911 for (
unsigned int q = 0; q < fee.n_q_points; ++q) {
912 const auto grad_potential = fee.get_gradient(q);
913 fee.submit_gradient(grad_potential, q);
915 fee.integrate_scatter(dealii::EvaluationFlags::gradients, dst);
919 matrix_free_.template cell_loop<ScalarHostVector<Number>,
920 ScalarHostVector<Number>>(
928 const auto body_velocity = [](
const auto &data,
932 FEEvaluation<dim, order_fe, order_quad, 1, Number>
934 FEEvaluation<dim, order_fe, order_quad, dim, Number>
937 for (
unsigned int cell = range.first; cell < range.second; ++cell) {
938 fee_pot.reinit(cell);
939 fee_vel.reinit(cell);
941 fee_vel.gather_evaluate(src, dealii::EvaluationFlags::values);
943 for (
unsigned int q = 0; q < fee_pot.n_q_points; ++q) {
944 if constexpr (dim == 1) {
945 decltype(fee_pot.get_gradient(q)) velocity_rhs;
946 velocity_rhs[0] = fee_vel.get_value(q);
947 fee_pot.submit_gradient(velocity_rhs, q);
949 fee_pot.submit_gradient(fee_vel.get_value(q), q);
952 fee_pot.integrate_scatter(dealii::EvaluationFlags::gradients, dst);
957 .template cell_loop<ScalarHostVector<Number>, BlockHostVector>(
965 if (selected_electrostatic_configuration_->is_time_dependent()) {
971 update_background_density(t);
973 Number factor = (crank_nicolson_extrapolation ? -0.5 : -1.0) * alpha;
975 const auto body = [&factor](
const auto &data,
979 FEEvaluation<dim, order_fe, order_quad, 1, Number>
980 fee_potential(data, 0, 1);
981 FEEvaluation<dim, order_fe, order_quad, 1, Number>
982 fee_background(data, 1, 1);
984 for (
unsigned int cell = range.first; cell < range.second; ++cell) {
985 fee_potential.reinit(cell);
986 fee_background.reinit(cell);
987 fee_background.gather_evaluate(src, EvaluationFlags::values);
989 for (
unsigned int q = 0; q < fee_potential.n_q_points; ++q) {
990 const auto background_q = fee_background.get_value(q);
991 fee_potential.submit_value(factor * background_q, q);
993 fee_potential.integrate_scatter(EvaluationFlags::values, dst);
997 matrix_free_.template cell_loop<ScalarHostVector<Number>,
998 ScalarHostVector<Number>>(
1001 background_density_,
1008 update_background_density(
1009 t + (crank_nicolson_extrapolation ? 2. : 1.) * tau);
1013 matrix_free_.template cell_loop<ScalarHostVector<Number>,
1014 ScalarHostVector<Number>>(
1017 background_density_,
1027 update_operator_.set_alpha(alpha);
1028 update_operator_.set_theta_tau(tau);
1030 matrix_free_.get_affine_constraints(0).distribute(new_potential);
1031 matrix_free_.get_affine_constraints(0).set_zero(potential_rhs_);
1033 const auto tolerance =
1034 (tolerance_linfty_norm_ ? potential_rhs_.linfty_norm()
1035 : potential_rhs_.l2_norm()) *
1038 typename dealii::SolverCG<ScalarHostVector<Number>>::AdditionalData
1042 SolverControl solver_control(gmg_max_iter_, tolerance);
1043 dealii::SolverCG<ScalarHostVector<Number>> solver(solver_control,
1045 solver.solve(update_operator_,
1048 multigrid_preconditioner_);
1051 n_iterations_step_ =
1052 0.9 * n_iterations_step_ + 0.1 * solver_control.last_step();
1054 }
catch (SolverControl::NoConvergence &) {
1055 SolverControl solver_control(1000, tolerance);
1056 dealii::SolverCG<ScalarHostVector<Number>> solver(solver_control,
1059 solver.solve(update_operator_,
1062 diagonal_preconditioner_);
1065 n_iterations_step_ *= 0.9;
1066 n_iterations_step_ +=
1067 0.1 * gmg_max_iter_ + 0.1 * solver_control.last_step();
1070 matrix_free_.get_affine_constraints(0).distribute(new_potential);
1081 const auto body_velocity =
1082 [](
const auto &data,
auto &dst,
const auto &src,
const auto range) {
1083 FEEvaluation<dim, order_fe, order_quad, 1, Number>
1084 fee_pot(data, 0, 1);
1085 FEEvaluation<dim, order_fe, order_quad, dim, Number>
1086 fee_vel(data, 1, 1);
1088 for (
unsigned int cell = range.first; cell < range.second; ++cell) {
1089 fee_pot.reinit(cell);
1090 fee_vel.reinit(cell);
1092 fee_pot.gather_evaluate(src, dealii::EvaluationFlags::gradients);
1093 for (
unsigned int q = 0; q < fee_pot.n_q_points; ++q) {
1094 fee_vel.submit_value(fee_pot.get_gradient(q), q);
1096 fee_vel.integrate_scatter(dealii::EvaluationFlags::values, dst);
1101 .template cell_loop<BlockHostVector, ScalarHostVector<Number>>(
1114 move_to_memory_space<HostSpace>(new_U);
1115 const auto new_U_view = new_U.template view<problem_dimension>();
1117 if (crank_nicolson_extrapolation) {
1118 new_potential *= Number(2.);
1119 new_potential -= old_potential;
1126 const auto body = [&](
auto sentinel,
unsigned int i) {
1127 using T =
decltype(sentinel);
1128 const auto view = hyperbolic_system_->template view<dim, T>();
1130 const auto m_i_inv =
1131 lumped_mass_matrix_inverse_view.template read_entry<T>(i);
1133 const auto old_U_i = old_U_view.template read_tensor<T>(i);
1134 const auto rho_i = view.density(old_U_i);
1135 const auto old_m_i = view.momentum(old_U_i);
1136 const auto old_v_i = old_m_i / rho_i;
1138 dealii::Tensor<1, (dim == 2 ? 1 : dim), T> magnetic_field;
1139 for (
unsigned int d = 0; d < (dim == 2 ? 1 : dim); ++d)
1140 magnetic_field[d] = read_entry<T>(magnetic_field_.block(d), i);
1142 dealii::Tensor<1, dim, T> grad_phi;
1143 for (
unsigned int d = 0; d < dim; ++d)
1144 grad_phi[d] = m_i_inv * read_entry<T>(velocity_rhs_.block(d), i);
1150 if (crank_nicolson_extrapolation)
1151 new_v_i = Number(2.) * new_v_i - old_v_i;
1153 auto new_U_i = old_U_i;
1154 for (
unsigned int d = 0; d < dim; ++d)
1155 new_U_i[1 + d] = rho_i * new_v_i[d];
1158 if constexpr (view.have_energy_equation)
1159 new_U_i[1 + dim] += Number(0.5) * rho_i *
1160 (new_v_i.norm_square() - old_v_i.norm_square());
1162 new_U_view.template write_tensor<T>(new_U_i, i);
1165 cpu_simd_loop<Number>(
1166 "time_step_parabolic_2c", body, 0, n_owned, n_owned);
typename HyperbolicDescription::HyperbolicSystem HyperbolicSystem
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)