15#include <deal.II/dofs/dof_tools.h>
16#include <deal.II/lac/linear_operator.h>
17#include <deal.II/lac/precondition.h>
18#include <deal.II/lac/solver_cg.h>
19#include <deal.II/matrix_free/fe_evaluation.h>
20#include <deal.II/numerics/vector_tools.h>
21#include <deal.II/numerics/vector_tools.templates.h>
26 namespace EulerPoisson
28 using namespace dealii;
30 template <
typename HyperbolicDescription,
int dim,
typename Number>
37 const std::string &subsection)
39 , mpi_ensemble_(mpi_ensemble)
40 , hyperbolic_system_(&hyperbolic_system)
41 , parabolic_system_(¶bolic_system)
42 , offline_data_(&offline_data)
43 , initial_values_(&initial_values)
45 , n_iterations_gauss_(0)
46 , n_iterations_step_(0)
47 , potential_initialized_(false)
48 , t_background_density_(std::numeric_limits<Number>::lowest())
49 , t_magnetic_field_(std::numeric_limits<Number>::lowest())
53 "gauss law restart strategy",
54 gauss_law_restart_strategy_,
55 "Strategy used when restarting the gauss law. Options are "
56 "\'no restart\', \'full restart\', \'correction\', "
57 "\'static no restart\', and \'static full restart\'.");
60 this->add_parameter(
"multigrid - max iter",
62 "Maximal number of CG iterations with GMG smoother");
64 gmg_smoother_range_ = 8.;
65 this->add_parameter(
"multigrid - chebyshev range",
67 "Chebyshev smoother: eigenvalue range parameter");
69 gmg_smoother_max_eig_ = 2.0;
70 this->add_parameter(
"multigrid - chebyshev max eig",
71 gmg_smoother_max_eig_,
72 "Chebyshev smoother: maximal eigenvalue");
74 gmg_smoother_degree_ = 3;
75 this->add_parameter(
"multigrid - chebyshev degree",
77 "Chebyshev smoother: degree");
79 gmg_smoother_n_cg_iter_ = 10;
81 "multigrid - chebyshev cg iter",
82 gmg_smoother_n_cg_iter_,
83 "Chebyshev smoother: number of CG iterations to approximate "
88 "multigrid - min level",
90 "Minimal mesh level to be visited in the geometric multigrid "
91 "cycle where the coarse grid solver (Chebyshev) is called");
93 tolerance_ = Number(1.0e-12);
95 "tolerance", tolerance_,
"Tolerance for linear solvers");
97 tolerance_linfty_norm_ =
false;
99 "tolerance linfty norm",
100 tolerance_linfty_norm_,
101 "Use the l_infty norm instead of the l_2 norm for the "
102 "stopping criterion");
104 electrostatic_configuration_list_ =
106 parabolic_system_->subsection());
108 const auto populate = [
this]() {
109 selected_electrostatic_configuration_ =
111 electrostatic_configuration_list_,
112 parabolic_system_->electrostatic_configuration());
115 this->parse_parameters_call_back.connect(populate);
120 template <
typename HyperbolicDescription,
int dim,
typename Number>
124 std::cout <<
"ParabolicModule<dim, Number>::prepare()" << std::endl;
132 const auto &discretization = offline_data_->discretization();
135 dealii::ExcMessage(
"The Euler-Poisson module currently only "
136 "supports cG/dg Q1 finite elements."));
138 AssertThrow(!offline_data_->dof_handler().has_hp_capabilities(),
140 "The Euler-Poisson module currently does not support "
141 "DoFHandlers set up with hp capabilities."));
143 potential_initialized_ =
false;
149 typename MatrixFree<dim, Number>::AdditionalData additional_data;
150 additional_data.tasks_parallel_scheme =
151 MatrixFree<dim, Number>::AdditionalData::none;
154 std::vector<const dealii::DoFHandler<dim> *> dof_handlers = {
155 &offline_data_->dof_handler_cg(), &offline_data_->dof_handler()};
157 create_constraints();
158 std::vector<const dealii::AffineConstraints<Number> *>
159 affine_constraints = {&affine_constraints_potential_,
160 &offline_data_->affine_constraints()};
163 std::vector<dealii::Quadrature<1>> quadratures = {
164 discretization.quadrature_1d()[0],
165 discretization.nodal_quadrature_1d()[0]};
167 matrix_free_.reinit(discretization.mapping(),
177 laplace_operator_.initialize(matrix_free_);
178 laplace_operator_.compute_diagonal(diagonal_preconditioner_);
179 update_operator_.initialize(matrix_free_, density_, magnetic_field_);
181 typename decltype(multigrid_preconditioner_)::MultigridParameters
182 parameters{gmg_max_iter_,
184 gmg_smoother_max_eig_,
185 gmg_smoother_degree_,
186 gmg_smoother_n_cg_iter_,
190 multigrid_preconditioner_.initialize(
192 selected_electrostatic_configuration_->dirichlet_boundaries(),
199 const auto &potential_partitioner =
200 matrix_free_.get_dof_info(0).vector_partitioner;
201 potential_rhs_.reinit(potential_partitioner);
203 const auto &scalar_partitioner =
204 matrix_free_.get_dof_info(1).vector_partitioner;
205 density_.reinit(scalar_partitioner);
206 background_density_.reinit(scalar_partitioner);
208 magnetic_field_.reinit(dim == 2 ? 1 : dim);
209 for (
unsigned int i = 0; i < magnetic_field_.n_blocks(); ++i)
210 magnetic_field_.block(i).reinit(scalar_partitioner);
212 velocity_rhs_.reinit(dim);
213 for (
unsigned int i = 0; i < dim; ++i)
214 velocity_rhs_.block(i).reinit(scalar_partitioner);
221 t_background_density_ = std::numeric_limits<Number>::lowest();
222 t_magnetic_field_ = std::numeric_limits<Number>::lowest();
224 if (!selected_electrostatic_configuration_->is_time_dependent()) {
225 update_background_density(Number(0.));
226 update_magnetic_field(Number(0.));
231 template <
typename HyperbolicDescription,
int dim,
typename Number>
237 std::cout <<
"ParabolicModule<dim, Number>::reinit_state_vector()"
241 auto &[U, Q, U_dynamic, Q_dynamic] = state_vector;
244 const auto &partitioner = matrix_free_.get_dof_info(0).vector_partitioner;
245 U_dynamic[0].reinit_with_scalar_partitioner(partitioner, 1);
246 U_dynamic[0].deal_ii_vector() = 0.;
250 template <
typename HyperbolicDescription,
int dim,
typename Number>
256 std::cout <<
"ParabolicModule<dim, Number>::prepare_state_vector()"
260 AssertThrow(gauss_law_restart_strategy_ !=
262 dealii::ExcNotImplemented());
268 if (!potential_initialized_) {
269 copy_to_memory_space<dealii::MemorySpace::Host>(
271 const auto &phi = std::as_const(state_vector).dynamic_state[0];
272 potential_initialized_ = !phi.deal_ii_vector().all_zero();
282 if (!potential_initialized_ ||
283 (gauss_law_restart_strategy_ ==
285 (gauss_law_restart_strategy_ ==
288 compute_potential(t, state_vector);
290 if (!potential_initialized_ &&
291 parabolic_system_->magnetic_drift_limit())
292 enforce_magnetic_drift_velocity(state_vector);
293 potential_initialized_ =
true;
298 template <
typename HyperbolicDescription,
int dim,
typename Number>
309 AssertThrow(tau != Number(0.),
310 dealii::ExcMessage(
"A parabolic module cannot choose the "
311 "time step size: tau must be nonzero."));
313 switch (stage_state_vectors.size()) {
315 backward_euler_step<0>(old_state_vector,
323 backward_euler_step<1>(old_state_vector,
331 backward_euler_step<2>(old_state_vector,
339 backward_euler_step<3>(old_state_vector,
347 backward_euler_step<4>(old_state_vector,
355 AssertThrow(
false, dealii::ExcMessage(
"Unsupported number of stages."));
362 template <
typename HyperbolicDescription,
int dim,
typename Number>
363 template <
int stages>
373 step(old_state_vector,
381 template <
typename HyperbolicDescription,
int dim,
typename Number>
390 AssertThrow(tau != Number(0.),
391 dealii::ExcMessage(
"A parabolic module cannot choose the "
392 "time step size: tau must be nonzero."));
397 step(old_state_vector,
413 step(old_state_vector,
424 template <
typename HyperbolicDescription,
int dim,
typename Number>
428 output <<
" [ " << std::setprecision(2) << std::fixed
429 << n_iterations_gauss_ <<
" GMG gauss -- "
430 << n_iterations_step_ <<
" GMG step ]" << std::endl;
434 template <
typename HyperbolicDescription,
int dim,
typename Number>
439 std::cout <<
"ParabolicModule<dim, Number>::create_constraints()"
443 const auto &discretization = offline_data_->discretization();
444 const auto &dof_handler = offline_data_->dof_handler_cg();
446 affine_constraints_potential_.clear();
448 const auto locally_relevant =
449 DoFTools::extract_locally_relevant_dofs(dof_handler);
451 const IndexSet &locally_owned = dof_handler.locally_owned_dofs();
452 affine_constraints_potential_.reinit(locally_owned, locally_relevant);
454 DoFTools::make_hanging_node_constraints(offline_data_->dof_handler_cg(),
455 affine_constraints_potential_);
462 const auto &periodic_faces =
463 discretization.triangulation().get_periodic_face_map();
465 for (
const auto &[left, value] : periodic_faces) {
466 const auto &[right, orientation] = value;
468 typename DoFHandler<dim>::cell_iterator dof_cell_left(
469 &left.first->get_triangulation(),
474 typename DoFHandler<dim>::cell_iterator dof_cell_right(
475 &right.first->get_triangulation(),
476 right.first->level(),
477 right.first->index(),
480 if constexpr (std::is_same_v<Number, double>) {
481 DoFTools::make_periodicity_constraints(
482 dof_cell_left->face(left.second),
483 dof_cell_right->face(right.second),
484 affine_constraints_potential_,
488 AssertThrow(
false, dealii::ExcNotImplemented());
493 for (
const auto &it :
494 selected_electrostatic_configuration_->dirichlet_boundaries())
495 DoFTools::make_zero_boundary_constraints(
496 offline_data_->dof_handler_cg(), it, affine_constraints_potential_);
498 affine_constraints_potential_.close();
502 template <
typename HyperbolicDescription,
int dim,
typename Number>
503 void ParabolicModule<HyperbolicDescription, dim, Number>::
504 update_background_density(
const Number t)
const
507 std::cout <<
"ParabolicModule<dim, Number>::update_background_density()"
515 if (!selected_electrostatic_configuration_->is_time_dependent() &&
523 if (std::abs(t_background_density_ - t) < 1.e-12)
527 std::cout <<
" updating to t = " << t << std::endl;
530 ComputingTimer::Scope scope(
"time step [X] - interpolate data vectors");
532 const auto &discretization = offline_data_->discretization();
533 background_density_.zero_out_ghost_values();
534 dealii::VectorTools::interpolate(
535 discretization.mapping(),
536 offline_data_->dof_handler(),
537 dealii::ScalarFunctionFromFunctionObject<dim, Number>(
538 [&](
const dealii::Point<dim> &p) {
539 return selected_electrostatic_configuration_
540 ->background_density(p, t);
542 background_density_);
543 background_density_.update_ghost_values();
545 t_background_density_ = t;
549 template <
typename HyperbolicDescription,
int dim,
typename Number>
551 ParabolicModule<HyperbolicDescription, dim, Number>::update_magnetic_field(
552 const Number t)
const
555 std::cout <<
"ParabolicModule<dim, Number>::update_magnetic_field()"
563 if (!selected_electrostatic_configuration_->is_time_dependent() &&
571 if (std::abs(t_magnetic_field_ - t) < 1.e-12)
575 std::cout <<
" updating to t = " << t << std::endl;
578 ComputingTimer::Scope scope(
"time step [X] - interpolate data vectors");
580 const auto &discretization = offline_data_->discretization();
581 for (
unsigned int k = 0; k < (dim == 2 ? 1 : dim); ++k) {
582 magnetic_field_.block(k).zero_out_ghost_values();
583 dealii::VectorTools::interpolate(
584 discretization.mapping(),
585 offline_data_->dof_handler(),
586 to_function<dim, Number>(
587 [&](
const dealii::Point<dim> &p) {
588 return selected_electrostatic_configuration_->magnetic_field(
592 magnetic_field_.block(k));
594 magnetic_field_.update_ghost_values();
596 t_magnetic_field_ = t;
600 template <
typename HyperbolicDescription,
int dim,
typename Number>
601 void ParabolicModule<HyperbolicDescription, dim, Number>::compute_potential(
602 const Number t, StateVector<Number> &state_vector)
const
605 std::cout <<
"ParabolicModule<dim, Number>::compute_potential()"
608 using HostSpace = dealii::MemorySpace::Host;
610 copy_to_memory_space<HostSpace>(std::as_const(state_vector),
612 move_to_memory_space<HostSpace>(state_vector,
616 std::as_const(state_vector).state.template view<problem_dimension>();
617 auto &U_dynamic = state_vector.dynamic_state;
618 auto &potential = U_dynamic[0].deal_ii_vector();
620 const unsigned int n_owned = offline_data_->n_locally_owned();
622 constexpr unsigned int order_fe = 1;
623 constexpr unsigned int order_quad = 2;
631 ComputingTimer::Scope scope(
"time step [P] 1 - enforce Gauss law");
633 update_background_density(t);
635 const auto body_copy = [&](
auto sentinel,
unsigned int i) {
636 using T =
decltype(sentinel);
637 const auto view = hyperbolic_system_->template view<dim, T>();
638 const auto U_i = U_view.template read_tensor<T>(i);
639 const auto rho_i = view.density(U_i);
640 write_entry<T>(density_, rho_i, i);
643 cpu_simd_loop<Number>(
644 "time_step_parabolic_1a", body_copy, 0, n_owned, n_owned);
646 density_.update_ghost_values();
648 const auto body_matrix_free = [
this](
const auto &data,
652 FEEvaluation<dim, order_fe, order_quad, 1, Number>
653 fee_potential(data, 0, 1);
654 FEEvaluation<dim, order_fe, order_quad, 1, Number>
655 fee_density(data, 1, 1);
656 FEEvaluation<dim, order_fe, order_quad, 1, Number>
657 fee_background(data, 1, 1);
660 const Number alpha = parabolic_system_->alpha();
662 for (
unsigned int cell = range.first; cell < range.second; ++cell) {
663 fee_potential.reinit(cell);
664 fee_density.reinit(cell);
665 fee_background.reinit(cell);
667 fee_density.gather_evaluate(src, dealii::EvaluationFlags::values);
668 fee_background.gather_evaluate(background_density_,
669 dealii::EvaluationFlags::values);
671 for (
unsigned int q = 0; q < fee_potential.n_q_points; ++q) {
672 const auto density_q = fee_density.get_value(q);
673 const auto background_q = fee_background.get_value(q);
675 const auto value = alpha * (density_q + background_q);
676 fee_potential.submit_value(value, q);
678 fee_potential.integrate_scatter(dealii::EvaluationFlags::values, dst);
682 matrix_free_.template cell_loop<ScalarHostVector<Number>,
683 ScalarHostVector<Number>>(
695 matrix_free_.get_affine_constraints(0).distribute(potential);
696 matrix_free_.get_affine_constraints(0).set_zero(potential_rhs_);
698 const auto tolerance =
699 (tolerance_linfty_norm_ ? potential_rhs_.linfty_norm()
700 : potential_rhs_.l2_norm()) *
703 typename dealii::SolverCG<ScalarHostVector<Number>>::AdditionalData
707 SolverControl solver_control(gmg_max_iter_, tolerance);
708 dealii::SolverCG<ScalarHostVector<Number>> solver(solver_control,
710 solver.solve(laplace_operator_,
713 multigrid_preconditioner_);
716 if (potential_initialized_) {
718 n_iterations_gauss_ =
719 0.9 * n_iterations_gauss_ + 0.1 * solver_control.last_step();
721 n_iterations_gauss_ = solver_control.last_step();
724 }
catch (SolverControl::NoConvergence &) {
725 SolverControl solver_control(1000, tolerance);
726 dealii::SolverCG<ScalarHostVector<Number>> solver(solver_control,
729 solver.solve(laplace_operator_,
732 diagonal_preconditioner_);
734 if (potential_initialized_) {
736 n_iterations_gauss_ *= 0.9;
737 n_iterations_gauss_ +=
738 0.1 * gmg_max_iter_ + 0.1 * solver_control.last_step();
740 n_iterations_gauss_ = gmg_max_iter_ + solver_control.last_step();
746 matrix_free_.get_affine_constraints(0).distribute(potential);
750 template <
typename HyperbolicDescription,
int dim,
typename Number>
751 void ParabolicModule<HyperbolicDescription, dim, Number>::
752 enforce_magnetic_drift_velocity(StateVector<Number> &state_vector)
const
756 <<
"ParabolicModule<dim, Number>::enforce_magnetic_drift_velocity()"
760 using HostSpace = dealii::MemorySpace::Host;
763 copy_to_memory_space<HostSpace>(std::as_const(state_vector),
766 const auto U_view = state_vector.state.template view<problem_dimension>();
767 const auto &U_dynamic = std::as_const(state_vector).dynamic_state;
768 const auto &potential = U_dynamic[0].deal_ii_vector();
770 const unsigned int n_owned = offline_data_->n_locally_owned();
772 const auto lumped_mass_matrix_inverse_view =
773 offline_data_->lumped_mass_matrix_inverse().template view<1>();
775 constexpr unsigned int order_fe = 1;
776 constexpr unsigned int order_quad = 2;
784 update_magnetic_field(Number(0.));
788 const auto body_velocity =
789 [](
const auto &data,
auto &dst,
const auto &src,
const auto range) {
790 FEEvaluation<dim, order_fe, order_quad, 1, Number>
792 FEEvaluation<dim, order_fe, order_quad, dim, Number>
795 for (
unsigned int cell = range.first; cell < range.second; ++cell) {
796 fee_pot.reinit(cell);
797 fee_vel.reinit(cell);
799 fee_pot.gather_evaluate(src, dealii::EvaluationFlags::gradients);
800 for (
unsigned int q = 0; q < fee_pot.n_q_points; ++q) {
801 fee_vel.submit_value(fee_pot.get_gradient(q), q);
803 fee_vel.integrate_scatter(dealii::EvaluationFlags::values, dst);
808 .template cell_loop<BlockHostVector, ScalarHostVector<Number>>(
814 const auto body = [&](
auto sentinel,
unsigned int i) {
815 using T =
decltype(sentinel);
816 const auto view = hyperbolic_system_->template view<dim, T>();
819 lumped_mass_matrix_inverse_view.template read_entry<T>(i);
821 auto U_i = U_view.template read_tensor<T>(i);
822 const auto rho_i = view.density(U_i);
823 const auto m_i = view.momentum(U_i);
824 const auto v_i = m_i / rho_i;
826 dealii::Tensor<1, (dim == 2 ? 1 : dim), T> magnetic_field;
827 for (
unsigned int d = 0; d < (dim == 2 ? 1 : dim); ++d)
828 magnetic_field[d] = read_entry<T>(magnetic_field_.block(d), i);
830 dealii::Tensor<1, dim, T> grad_phi;
831 for (
unsigned int d = 0; d < dim; ++d)
832 grad_phi[d] = m_i_inv * read_entry<T>(velocity_rhs_.block(d), i);
836 if constexpr (dim == 2) {
837 new_v_i = -magnetic_field[0] * cross_product_2d(grad_phi) /
838 magnetic_field.norm_square();
840 }
else if constexpr (dim == 3) {
841 new_v_i = -cross_product_3d(grad_phi, magnetic_field) /
842 magnetic_field.norm_square();
845 for (
unsigned int d = 0; d < dim; ++d)
846 U_i[1 + d] = rho_i * new_v_i[d];
849 if constexpr (view.have_energy_equation)
851 Number(0.5) * rho_i * (new_v_i.norm_square() - v_i.norm_square());
853 U_view.template write_tensor<T>(U_i, i);
856 cpu_simd_loop<Number>(
857 "time_step_parabolic_1c", body, 0, n_owned, n_owned);
861 template <
typename HyperbolicDescription,
int dim,
typename Number>
862 void ParabolicModule<HyperbolicDescription, dim, Number>::step(
863 const StateVector<Number> &old_state_vector,
864 StateVector<Number> &new_state_vector,
866 Number tau [[maybe_unused]],
867 const bool crank_nicolson_extrapolation [[maybe_unused]])
const
870 std::cout <<
"ParabolicModule<dim, Number>::step()" << std::endl;
871 std::cout <<
" perform time-step with tau = " << tau << std::endl;
872 if (crank_nicolson_extrapolation)
873 std::cout <<
" and extrapolate to t + 2 * tau" << std::endl;
876 const Number alpha = parabolic_system_->alpha();
878 using HostSpace = dealii::MemorySpace::Host;
880 copy_to_memory_space<HostSpace>(old_state_vector,
883 move_to_memory_space<HostSpace>(new_state_vector,
886 const auto &old_U = old_state_vector.state;
887 const auto old_U_view = old_U.template view<problem_dimension>();
888 const auto &old_U_dynamic = old_state_vector.dynamic_state;
889 const auto &old_potential = old_U_dynamic[0].deal_ii_vector();
891 auto &new_U = new_state_vector.state;
892 auto &new_U_dynamic = new_state_vector.dynamic_state;
893 auto &new_potential = new_U_dynamic[0].deal_ii_vector();
895 const unsigned int n_owned = offline_data_->n_locally_owned();
897 const auto lumped_mass_matrix_inverse_view =
898 offline_data_->lumped_mass_matrix_inverse().template view<1>();
900 constexpr unsigned int order_fe = 1;
901 constexpr unsigned int order_quad = 2;
907 new_potential = old_potential;
913 if ((gauss_law_restart_strategy_ !=
915 (gauss_law_restart_strategy_ !=
935 ComputingTimer::Scope scope(
"time step [P] 2 - update potential");
938 update_magnetic_field(t + tau);
945 const auto body_copy = [&](
auto sentinel,
unsigned int i) {
946 using T =
decltype(sentinel);
947 const auto view = hyperbolic_system_->template view<dim, T>();
949 const auto U_i = old_U_view.template read_tensor<T>(i);
950 const auto rho_i = view.density(U_i);
951 const auto m_i = view.momentum(U_i);
953 dealii::Tensor<1, (dim == 2 ? 1 : dim), T> magnetic_field;
954 for (
unsigned int d = 0; d < (dim == 2 ? 1 : dim); ++d)
955 magnetic_field[d] = read_entry<T>(magnetic_field_.block(d), i);
957 const auto velocity_rhs =
958 tau * alpha * rho_i *
961 write_entry<T>(density_, rho_i, i);
962 for (
unsigned int d = 0; d < dim; ++d)
963 write_entry<T>(velocity_rhs_.block(d), velocity_rhs[d], i);
966 cpu_simd_loop<Number>(
967 "time_step_parabolic_2a", body_copy, 0, n_owned, n_owned);
969 density_.update_ghost_values();
973 const auto body_laplace = [](
const auto &data,
977 FEEvaluation<dim, order_fe, order_quad, 1, Number> fee(
980 for (
unsigned int cell = range.first; cell < range.second; ++cell) {
982 fee.gather_evaluate(src, dealii::EvaluationFlags::gradients);
984 for (
unsigned int q = 0; q < fee.n_q_points; ++q) {
985 const auto grad_potential = fee.get_gradient(q);
986 fee.submit_gradient(grad_potential, q);
988 fee.integrate_scatter(dealii::EvaluationFlags::gradients, dst);
992 matrix_free_.template cell_loop<ScalarHostVector<Number>,
993 ScalarHostVector<Number>>(
1001 const auto body_velocity = [](
const auto &data,
1005 FEEvaluation<dim, order_fe, order_quad, 1, Number>
1006 fee_pot(data, 0, 1);
1007 FEEvaluation<dim, order_fe, order_quad, dim, Number>
1008 fee_vel(data, 1, 1);
1010 for (
unsigned int cell = range.first; cell < range.second; ++cell) {
1011 fee_pot.reinit(cell);
1012 fee_vel.reinit(cell);
1014 fee_vel.gather_evaluate(src, dealii::EvaluationFlags::values);
1016 for (
unsigned int q = 0; q < fee_pot.n_q_points; ++q) {
1017 if constexpr (dim == 1) {
1018 decltype(fee_pot.get_gradient(q)) velocity_rhs;
1019 velocity_rhs[0] = fee_vel.get_value(q);
1020 fee_pot.submit_gradient(velocity_rhs, q);
1022 fee_pot.submit_gradient(fee_vel.get_value(q), q);
1025 fee_pot.integrate_scatter(dealii::EvaluationFlags::gradients, dst);
1030 .template cell_loop<ScalarHostVector<Number>, BlockHostVector>(
1038 if (selected_electrostatic_configuration_->is_time_dependent()) {
1044 update_background_density(t);
1046 Number factor = (crank_nicolson_extrapolation ? -0.5 : -1.0) * alpha;
1048 const auto body = [&factor](
const auto &data,
1052 FEEvaluation<dim, order_fe, order_quad, 1, Number>
1053 fee_potential(data, 0, 1);
1054 FEEvaluation<dim, order_fe, order_quad, 1, Number>
1055 fee_background(data, 1, 1);
1057 for (
unsigned int cell = range.first; cell < range.second; ++cell) {
1058 fee_potential.reinit(cell);
1059 fee_background.reinit(cell);
1060 fee_background.gather_evaluate(src, EvaluationFlags::values);
1062 for (
unsigned int q = 0; q < fee_potential.n_q_points; ++q) {
1063 const auto background_q = fee_background.get_value(q);
1064 fee_potential.submit_value(factor * background_q, q);
1066 fee_potential.integrate_scatter(EvaluationFlags::values, dst);
1070 matrix_free_.template cell_loop<ScalarHostVector<Number>,
1071 ScalarHostVector<Number>>(
1074 background_density_,
1081 update_background_density(
1082 t + (crank_nicolson_extrapolation ? 2. : 1.) * tau);
1086 matrix_free_.template cell_loop<ScalarHostVector<Number>,
1087 ScalarHostVector<Number>>(
1090 background_density_,
1100 update_operator_.set_alpha(alpha);
1101 update_operator_.set_theta_tau(tau);
1103 matrix_free_.get_affine_constraints(0).distribute(new_potential);
1104 matrix_free_.get_affine_constraints(0).set_zero(potential_rhs_);
1106 const auto tolerance =
1107 (tolerance_linfty_norm_ ? potential_rhs_.linfty_norm()
1108 : potential_rhs_.l2_norm()) *
1111 typename dealii::SolverCG<ScalarHostVector<Number>>::AdditionalData
1115 SolverControl solver_control(gmg_max_iter_, tolerance);
1116 dealii::SolverCG<ScalarHostVector<Number>> solver(solver_control,
1118 solver.solve(update_operator_,
1121 multigrid_preconditioner_);
1124 n_iterations_step_ =
1125 0.9 * n_iterations_step_ + 0.1 * solver_control.last_step();
1127 }
catch (SolverControl::NoConvergence &) {
1128 SolverControl solver_control(1000, tolerance);
1129 dealii::SolverCG<ScalarHostVector<Number>> solver(solver_control,
1132 solver.solve(update_operator_,
1135 diagonal_preconditioner_);
1138 n_iterations_step_ *= 0.9;
1139 n_iterations_step_ +=
1140 0.1 * gmg_max_iter_ + 0.1 * solver_control.last_step();
1143 matrix_free_.get_affine_constraints(0).distribute(new_potential);
1154 const auto body_velocity =
1155 [](
const auto &data,
auto &dst,
const auto &src,
const auto range) {
1156 FEEvaluation<dim, order_fe, order_quad, 1, Number>
1157 fee_pot(data, 0, 1);
1158 FEEvaluation<dim, order_fe, order_quad, dim, Number>
1159 fee_vel(data, 1, 1);
1161 for (
unsigned int cell = range.first; cell < range.second; ++cell) {
1162 fee_pot.reinit(cell);
1163 fee_vel.reinit(cell);
1165 fee_pot.gather_evaluate(src, dealii::EvaluationFlags::gradients);
1166 for (
unsigned int q = 0; q < fee_pot.n_q_points; ++q) {
1167 fee_vel.submit_value(fee_pot.get_gradient(q), q);
1169 fee_vel.integrate_scatter(dealii::EvaluationFlags::values, dst);
1174 .template cell_loop<BlockHostVector, ScalarHostVector<Number>>(
1187 move_to_memory_space<HostSpace>(new_U);
1188 const auto new_U_view = new_U.template view<problem_dimension>();
1190 if (crank_nicolson_extrapolation) {
1191 new_potential *= Number(2.);
1192 new_potential -= old_potential;
1199 const auto body = [&](
auto sentinel,
unsigned int i) {
1200 using T =
decltype(sentinel);
1201 const auto view = hyperbolic_system_->template view<dim, T>();
1203 const auto m_i_inv =
1204 lumped_mass_matrix_inverse_view.template read_entry<T>(i);
1206 const auto old_U_i = old_U_view.template read_tensor<T>(i);
1207 const auto rho_i = view.density(old_U_i);
1208 const auto old_m_i = view.momentum(old_U_i);
1209 const auto old_v_i = old_m_i / rho_i;
1211 dealii::Tensor<1, (dim == 2 ? 1 : dim), T> magnetic_field;
1212 for (
unsigned int d = 0; d < (dim == 2 ? 1 : dim); ++d)
1213 magnetic_field[d] = read_entry<T>(magnetic_field_.block(d), i);
1215 dealii::Tensor<1, dim, T> grad_phi;
1216 for (
unsigned int d = 0; d < dim; ++d)
1217 grad_phi[d] = m_i_inv * read_entry<T>(velocity_rhs_.block(d), i);
1223 if (crank_nicolson_extrapolation)
1224 new_v_i = Number(2.) * new_v_i - old_v_i;
1226 auto new_U_i = old_U_i;
1227 for (
unsigned int d = 0; d < dim; ++d)
1228 new_U_i[1 + d] = rho_i * new_v_i[d];
1231 if constexpr (view.have_energy_equation)
1232 new_U_i[1 + dim] += Number(0.5) * rho_i *
1233 (new_v_i.norm_square() - old_v_i.norm_square());
1235 new_U_view.template write_tensor<T>(new_U_i, i);
1238 cpu_simd_loop<Number>(
1239 "time_step_parabolic_2c", body, 0, n_owned, n_owned);
typename Interface::ParabolicModule< dim, Number >::StageVectors StageVectors
ParabolicModule(const MPIEnsemble &mpi_ensemle, const OfflineData< dim, Number > &offline_data, const HyperbolicSystem &hyperbolic_system, const ParabolicSystem ¶bolic_system, const InitialValues< HyperbolicDescription, dim, Number > &initial_values, const std::string &subsection="/ParabolicModule")
typename Interface::ParabolicModule< dim, Number >::StageWeights StageWeights
typename HyperbolicDescription::HyperbolicSystem HyperbolicSystem
void print_solver_statistics(std::ostream &output) const override
Number crank_nicolson_step(const StateVector< Number > &old_state_vector, StateVector< Number > &new_state_vector, Number t, Number tau, Number tau_max=std::numeric_limits< Number >::max()) const override
void prepare_state_vector(StateVector< Number > &state_vector, Number t) const override
Number backward_euler_step(const StateVector< Number > &old_state_vector, StageVectors stage_state_vectors, StageWeights stage_weights, StateVector< Number > &new_state_vector, Number t, Number tau, Number tau_max=std::numeric_limits< Number >::max()) const override
void reinit_state_vector(StateVector< Number > &state_vector) const override
static Base & select(const std::vector< std::unique_ptr< Base > > &objects, const std::string &name)
static std::vector< std::unique_ptr< Base > > create(Args... args)
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)