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 auto &potential = V.block(0);
254 const auto &partitioner = matrix_free_.get_dof_info(0).vector_partitioner;
255 potential.reinit(partitioner);
260 template <
typename Description,
int dim,
typename Number>
265 std::cout <<
"ParabolicModule<dim, Number>::prepare_state_vector()"
274 AssertThrow(gauss_law_restart_strategy_ !=
276 dealii::ExcNotImplemented());
278 if (!potential_initialized_ ||
279 (gauss_law_restart_strategy_ ==
281 (gauss_law_restart_strategy_ ==
284 compute_potential(t, state_vector);
286 if (!potential_initialized_ &&
287 parabolic_system_->magnetic_drift_limit())
288 enforce_magnetic_drift_velocity(state_vector);
289 potential_initialized_ =
true;
294 template <
typename Description,
int dim,
typename Number>
295 template <
int stages>
299 std::array<std::reference_wrapper<const StateVector>,
301 const std::array<Number, stages> ,
305 step(old_state_vector,
313 template <
typename Description,
int dim,
typename Number>
323 step(old_state_vector,
339 step(old_state_vector,
348 template <
typename Description,
int dim,
typename Number>
350 std::ostream &output)
const
352 output <<
" [ " << std::setprecision(2) << std::fixed
353 << n_iterations_gauss_ <<
" GMG gauss -- "
354 << n_iterations_step_ <<
" GMG step ]" << std::endl;
358 template <
typename Description,
int dim,
typename Number>
362 std::cout <<
"ParabolicModule<dim, Number>::create_constraints()"
366 const auto &discretization = offline_data_->discretization();
367 const auto &dof_handler = offline_data_->dof_handler_cg();
369 affine_constraints_potential_.clear();
371 const auto locally_relevant =
372 DoFTools::extract_locally_relevant_dofs(dof_handler);
374 const IndexSet &locally_owned = dof_handler.locally_owned_dofs();
375 affine_constraints_potential_.reinit(locally_owned, locally_relevant);
377 DoFTools::make_hanging_node_constraints(offline_data_->dof_handler_cg(),
378 affine_constraints_potential_);
385 const auto &periodic_faces =
386 discretization.triangulation().get_periodic_face_map();
388 for (
const auto &[left, value] : periodic_faces) {
389 const auto &[right, orientation] = value;
391 typename DoFHandler<dim>::cell_iterator dof_cell_left(
392 &left.first->get_triangulation(),
397 typename DoFHandler<dim>::cell_iterator dof_cell_right(
398 &right.first->get_triangulation(),
399 right.first->level(),
400 right.first->index(),
403 if constexpr (std::is_same_v<Number, double>) {
404 DoFTools::make_periodicity_constraints(
405 dof_cell_left->face(left.second),
406 dof_cell_right->face(right.second),
407 affine_constraints_potential_,
411 AssertThrow(
false, dealii::ExcNotImplemented());
416 for (
const auto &it :
417 selected_electrostatic_configuration_->dirichlet_boundaries())
418 DoFTools::make_zero_boundary_constraints(
419 offline_data_->dof_handler_cg(), it, affine_constraints_potential_);
421 affine_constraints_potential_.close();
425 template <
typename Description,
int dim,
typename Number>
426 void ParabolicModule<Description, dim, Number>::update_background_density(
427 const Number t)
const
430 std::cout <<
"ParabolicModule<dim, Number>::update_background_density()"
438 if (!selected_electrostatic_configuration_->is_time_dependent() &&
446 if (std::abs(t_background_density_ - t) < 1.e-12)
450 std::cout <<
" updating to t = " << t << std::endl;
453 ComputingTimer::Scope scope(
"time step [X] - interpolate data vectors");
455 const auto &discretization = offline_data_->discretization();
456 background_density_.zero_out_ghost_values();
457 dealii::VectorTools::interpolate(
458 discretization.mapping(),
459 offline_data_->dof_handler(),
460 dealii::ScalarFunctionFromFunctionObject<dim, Number>(
461 [&](
const dealii::Point<dim> &p) {
462 return selected_electrostatic_configuration_
463 ->background_density(p, t);
465 background_density_);
466 background_density_.update_ghost_values();
468 t_background_density_ = t;
472 template <
typename Description,
int dim,
typename Number>
473 void ParabolicModule<Description, dim, Number>::update_magnetic_field(
474 const Number t)
const
477 std::cout <<
"ParabolicModule<dim, Number>::update_magnetic_field()"
485 if (!selected_electrostatic_configuration_->is_time_dependent() &&
493 if (std::abs(t_magnetic_field_ - t) < 1.e-12)
497 std::cout <<
" updating to t = " << t << std::endl;
500 ComputingTimer::Scope scope(
"time step [X] - interpolate data vectors");
502 const auto &discretization = offline_data_->discretization();
503 for (
unsigned int k = 0; k < (dim == 2 ? 1 : dim); ++k) {
504 magnetic_field_.block(k).zero_out_ghost_values();
505 dealii::VectorTools::interpolate(
506 discretization.mapping(),
507 offline_data_->dof_handler(),
508 to_function<dim, Number>(
509 [&](
const dealii::Point<dim> &p) {
510 return selected_electrostatic_configuration_->magnetic_field(
514 magnetic_field_.block(k));
516 magnetic_field_.update_ghost_values();
518 t_magnetic_field_ = t;
522 template <
typename Description,
int dim,
typename Number>
523 void ParabolicModule<Description, dim, Number>::compute_potential(
524 const Number t, StateVector &state_vector)
const
527 std::cout <<
"ParabolicModule<dim, Number>::compute_potential()"
530 const auto U_view = std::get<0>(state_vector).view();
531 auto &V = std::get<2>(state_vector);
532 auto &potential = V.block(0);
534 const unsigned int n_owned = offline_data_->n_locally_owned();
536 constexpr unsigned int order_fe = 1;
537 constexpr unsigned int order_quad = 2;
545 ComputingTimer::Scope scope(
"time step [P] 1 - enforce Gauss law");
547 update_background_density(t);
549 const auto body_copy = [&](
auto sentinel,
unsigned int i) {
550 using T =
decltype(sentinel);
551 const auto view = hyperbolic_system_->template view<dim, T>();
552 const auto U_i = U_view.template read_tensor<T>(i);
553 const auto rho_i = view.density(U_i);
554 write_entry<T>(density_, rho_i, i);
557 cpu_simd_loop<Number>(
558 "time_step_parabolic_1a", body_copy, 0, n_owned, n_owned);
560 density_.update_ghost_values();
562 const auto body_matrix_free = [
this](
const auto &data,
566 FEEvaluation<dim, order_fe, order_quad, 1, Number>
567 fee_potential(data, 0, 1);
568 FEEvaluation<dim, order_fe, order_quad, 1, Number>
569 fee_density(data, 1, 1);
570 FEEvaluation<dim, order_fe, order_quad, 1, Number>
571 fee_background(data, 1, 1);
574 const Number alpha = parabolic_system_->alpha();
576 for (
unsigned int cell = range.first; cell < range.second; ++cell) {
577 fee_potential.reinit(cell);
578 fee_density.reinit(cell);
579 fee_background.reinit(cell);
581 fee_density.gather_evaluate(src, dealii::EvaluationFlags::values);
582 fee_background.gather_evaluate(background_density_,
583 dealii::EvaluationFlags::values);
585 for (
unsigned int q = 0; q < fee_potential.n_q_points; ++q) {
586 const auto density_q = fee_density.get_value(q);
587 const auto background_q = fee_background.get_value(q);
589 const auto value = alpha * (density_q + background_q);
590 fee_potential.submit_value(value, q);
592 fee_potential.integrate_scatter(dealii::EvaluationFlags::values, dst);
596 matrix_free_.template cell_loop<ScalarHostVector, ScalarHostVector>(
608 matrix_free_.get_affine_constraints(0).distribute(potential);
609 matrix_free_.get_affine_constraints(0).set_zero(potential_rhs_);
611 const auto tolerance =
612 (tolerance_linfty_norm_ ? potential_rhs_.linfty_norm()
613 : potential_rhs_.l2_norm()) *
616 typename dealii::SolverCG<ScalarHostVector>::AdditionalData solver_data;
619 SolverControl solver_control(gmg_max_iter_, tolerance);
620 dealii::SolverCG<ScalarHostVector> solver(solver_control, solver_data);
621 solver.solve(laplace_operator_,
624 multigrid_preconditioner_);
627 if (potential_initialized_) {
629 n_iterations_gauss_ =
630 0.9 * n_iterations_gauss_ + 0.1 * solver_control.last_step();
632 n_iterations_gauss_ = solver_control.last_step();
635 }
catch (SolverControl::NoConvergence &) {
636 SolverControl solver_control(1000, tolerance);
637 dealii::SolverCG<ScalarHostVector> solver(solver_control, solver_data);
639 solver.solve(laplace_operator_,
642 diagonal_preconditioner_);
644 if (potential_initialized_) {
646 n_iterations_gauss_ *= 0.9;
647 n_iterations_gauss_ +=
648 0.1 * gmg_max_iter_ + 0.1 * solver_control.last_step();
650 n_iterations_gauss_ = gmg_max_iter_ + solver_control.last_step();
656 matrix_free_.get_affine_constraints(0).distribute(potential);
660 template <
typename Description,
int dim,
typename Number>
662 ParabolicModule<Description, dim, Number>::enforce_magnetic_drift_velocity(
663 StateVector &state_vector)
const
667 <<
"ParabolicModule<dim, Number>::enforce_magnetic_drift_velocity()"
671 const auto U_view = std::get<0>(state_vector).view();
672 auto &V = std::get<2>(state_vector);
673 auto &potential = V.block(0);
675 const unsigned int n_owned = offline_data_->n_locally_owned();
677 const auto lumped_mass_matrix_inverse_view =
678 offline_data_->lumped_mass_matrix_inverse().view();
680 constexpr unsigned int order_fe = 1;
681 constexpr unsigned int order_quad = 2;
689 update_magnetic_field(Number(0.));
693 const auto body_velocity =
694 [](
const auto &data,
auto &dst,
const auto &src,
const auto range) {
695 FEEvaluation<dim, order_fe, order_quad, 1, Number>
697 FEEvaluation<dim, order_fe, order_quad, dim, Number>
700 for (
unsigned int cell = range.first; cell < range.second; ++cell) {
701 fee_pot.reinit(cell);
702 fee_vel.reinit(cell);
704 fee_pot.gather_evaluate(src, dealii::EvaluationFlags::gradients);
705 for (
unsigned int q = 0; q < fee_pot.n_q_points; ++q) {
706 fee_vel.submit_value(fee_pot.get_gradient(q), q);
708 fee_vel.integrate_scatter(dealii::EvaluationFlags::values, dst);
712 matrix_free_.template cell_loop<BlockHostVector, ScalarHostVector>(
718 const auto body = [&](
auto sentinel,
unsigned int i) {
719 using T =
decltype(sentinel);
720 const auto view = hyperbolic_system_->template view<dim, T>();
723 lumped_mass_matrix_inverse_view.template read_entry<T>(i);
725 auto U_i = U_view.template read_tensor<T>(i);
726 const auto rho_i = view.density(U_i);
727 const auto m_i = view.momentum(U_i);
728 const auto v_i = m_i / rho_i;
730 dealii::Tensor<1, (dim == 2 ? 1 : dim), T> magnetic_field;
731 for (
unsigned int d = 0; d < (dim == 2 ? 1 : dim); ++d)
732 magnetic_field[d] = read_entry<T>(magnetic_field_.block(d), i);
734 dealii::Tensor<1, dim, T> grad_phi;
735 for (
unsigned int d = 0; d < dim; ++d)
736 grad_phi[d] = m_i_inv * read_entry<T>(velocity_rhs_.block(d), i);
740 if constexpr (dim == 2) {
741 new_v_i = -magnetic_field[0] * cross_product_2d(grad_phi) /
742 magnetic_field.norm_square();
744 }
else if constexpr (dim == 3) {
745 new_v_i = -cross_product_3d(grad_phi, magnetic_field) /
746 magnetic_field.norm_square();
749 for (
unsigned int d = 0; d < dim; ++d)
750 U_i[1 + d] = rho_i * new_v_i[d];
753 if constexpr (view.have_energy_equation)
755 Number(0.5) * rho_i * (new_v_i.norm_square() - v_i.norm_square());
757 U_view.template write_tensor<T>(U_i, i);
760 cpu_simd_loop<Number>(
761 "time_step_parabolic_1c", body, 0, n_owned, n_owned);
765 template <
typename Description,
int dim,
typename Number>
766 void ParabolicModule<Description, dim, Number>::step(
767 const StateVector &old_state_vector,
769 StateVector &new_state_vector,
770 Number tau [[maybe_unused]],
771 const bool crank_nicolson_extrapolation [[maybe_unused]])
const
774 std::cout <<
"ParabolicModule<dim, Number>::step()" << std::endl;
775 std::cout <<
" perform time-step with tau = " << tau << std::endl;
776 if (crank_nicolson_extrapolation)
777 std::cout <<
" and extrapolate to t + 2 * tau" << std::endl;
780 const Number alpha = parabolic_system_->alpha();
782 const auto &old_U = std::get<0>(old_state_vector);
783 const auto old_U_view = old_U.view();
784 const auto &old_V = std::get<2>(old_state_vector);
785 const auto &old_potential = old_V.block(0);
787 auto &new_U = std::get<0>(new_state_vector);
788 auto &new_V = std::get<2>(new_state_vector);
789 auto &new_potential = new_V.block(0);
791 const unsigned int n_owned = offline_data_->n_locally_owned();
793 const auto lumped_mass_matrix_inverse_view =
794 offline_data_->lumped_mass_matrix_inverse().view();
796 constexpr unsigned int order_fe = 1;
797 constexpr unsigned int order_quad = 2;
803 new_potential = old_potential;
809 if ((gauss_law_restart_strategy_ !=
811 (gauss_law_restart_strategy_ !=
831 ComputingTimer::Scope scope(
"time step [P] 2 - update potential");
834 update_magnetic_field(t + tau);
841 const auto body_copy = [&](
auto sentinel,
unsigned int i) {
842 using T =
decltype(sentinel);
843 const auto view = hyperbolic_system_->template view<dim, T>();
845 const auto U_i = old_U_view.template read_tensor<T>(i);
846 const auto rho_i = view.density(U_i);
847 const auto m_i = view.momentum(U_i);
849 dealii::Tensor<1, (dim == 2 ? 1 : dim), T> magnetic_field;
850 for (
unsigned int d = 0; d < (dim == 2 ? 1 : dim); ++d)
851 magnetic_field[d] = read_entry<T>(magnetic_field_.block(d), i);
853 const auto velocity_rhs =
854 tau * alpha * rho_i *
857 write_entry<T>(density_, rho_i, i);
858 for (
unsigned int d = 0; d < dim; ++d)
859 write_entry<T>(velocity_rhs_.block(d), velocity_rhs[d], i);
862 cpu_simd_loop<Number>(
863 "time_step_parabolic_2a", body_copy, 0, n_owned, n_owned);
865 density_.update_ghost_values();
869 const auto body_laplace = [](
const auto &data,
873 FEEvaluation<dim, order_fe, order_quad, 1, Number> fee(
876 for (
unsigned int cell = range.first; cell < range.second; ++cell) {
878 fee.gather_evaluate(src, dealii::EvaluationFlags::gradients);
880 for (
unsigned int q = 0; q < fee.n_q_points; ++q) {
881 const auto grad_potential = fee.get_gradient(q);
882 fee.submit_gradient(grad_potential, q);
884 fee.integrate_scatter(dealii::EvaluationFlags::gradients, dst);
888 matrix_free_.template cell_loop<ScalarHostVector, ScalarHostVector>(
896 const auto body_velocity = [](
const auto &data,
900 FEEvaluation<dim, order_fe, order_quad, 1, Number>
902 FEEvaluation<dim, order_fe, order_quad, dim, Number>
905 for (
unsigned int cell = range.first; cell < range.second; ++cell) {
906 fee_pot.reinit(cell);
907 fee_vel.reinit(cell);
909 fee_vel.gather_evaluate(src, dealii::EvaluationFlags::values);
911 for (
unsigned int q = 0; q < fee_pot.n_q_points; ++q) {
912 if constexpr (dim == 1) {
913 decltype(fee_pot.get_gradient(q)) velocity_rhs;
914 velocity_rhs[0] = fee_vel.get_value(q);
915 fee_pot.submit_gradient(velocity_rhs, q);
917 fee_pot.submit_gradient(fee_vel.get_value(q), q);
920 fee_pot.integrate_scatter(dealii::EvaluationFlags::gradients, dst);
924 matrix_free_.template cell_loop<ScalarHostVector, BlockHostVector>(
932 if (selected_electrostatic_configuration_->is_time_dependent()) {
938 update_background_density(t);
940 Number factor = (crank_nicolson_extrapolation ? -0.5 : -1.0) * alpha;
942 const auto body = [&factor](
const auto &data,
946 FEEvaluation<dim, order_fe, order_quad, 1, Number>
947 fee_potential(data, 0, 1);
948 FEEvaluation<dim, order_fe, order_quad, 1, Number>
949 fee_background(data, 1, 1);
951 for (
unsigned int cell = range.first; cell < range.second; ++cell) {
952 fee_potential.reinit(cell);
953 fee_background.reinit(cell);
954 fee_background.gather_evaluate(src, EvaluationFlags::values);
956 for (
unsigned int q = 0; q < fee_potential.n_q_points; ++q) {
957 const auto background_q = fee_background.get_value(q);
958 fee_potential.submit_value(factor * background_q, q);
960 fee_potential.integrate_scatter(EvaluationFlags::values, dst);
964 matrix_free_.template cell_loop<ScalarHostVector, ScalarHostVector>(
974 update_background_density(
975 t + (crank_nicolson_extrapolation ? 2. : 1.) * tau);
979 matrix_free_.template cell_loop<ScalarHostVector, ScalarHostVector>(
992 update_operator_.set_alpha(alpha);
993 update_operator_.set_theta_tau(tau);
995 matrix_free_.get_affine_constraints(0).distribute(new_potential);
996 matrix_free_.get_affine_constraints(0).set_zero(potential_rhs_);
998 const auto tolerance =
999 (tolerance_linfty_norm_ ? potential_rhs_.linfty_norm()
1000 : potential_rhs_.l2_norm()) *
1003 typename dealii::SolverCG<ScalarHostVector>::AdditionalData solver_data;
1006 SolverControl solver_control(gmg_max_iter_, tolerance);
1007 dealii::SolverCG<ScalarHostVector> solver(solver_control,
1009 solver.solve(update_operator_,
1012 multigrid_preconditioner_);
1015 n_iterations_step_ =
1016 0.9 * n_iterations_step_ + 0.1 * solver_control.last_step();
1018 }
catch (SolverControl::NoConvergence &) {
1019 SolverControl solver_control(1000, tolerance);
1020 dealii::SolverCG<ScalarHostVector> solver(solver_control,
1023 solver.solve(update_operator_,
1026 diagonal_preconditioner_);
1029 n_iterations_step_ *= 0.9;
1030 n_iterations_step_ +=
1031 0.1 * gmg_max_iter_ + 0.1 * solver_control.last_step();
1034 matrix_free_.get_affine_constraints(0).distribute(new_potential);
1045 const auto body_velocity =
1046 [](
const auto &data,
auto &dst,
const auto &src,
const auto range) {
1047 FEEvaluation<dim, order_fe, order_quad, 1, Number>
1048 fee_pot(data, 0, 1);
1049 FEEvaluation<dim, order_fe, order_quad, dim, Number>
1050 fee_vel(data, 1, 1);
1052 for (
unsigned int cell = range.first; cell < range.second; ++cell) {
1053 fee_pot.reinit(cell);
1054 fee_vel.reinit(cell);
1056 fee_pot.gather_evaluate(src, dealii::EvaluationFlags::gradients);
1057 for (
unsigned int q = 0; q < fee_pot.n_q_points; ++q) {
1058 fee_vel.submit_value(fee_pot.get_gradient(q), q);
1060 fee_vel.integrate_scatter(dealii::EvaluationFlags::values, dst);
1064 matrix_free_.template cell_loop<BlockHostVector, ScalarHostVector>(
1077 const auto new_U_view = new_U.view();
1079 if (crank_nicolson_extrapolation) {
1080 new_potential *= Number(2.);
1081 new_potential -= old_potential;
1088 const auto body = [&](
auto sentinel,
unsigned int i) {
1089 using T =
decltype(sentinel);
1090 const auto view = hyperbolic_system_->template view<dim, T>();
1092 const auto m_i_inv =
1093 lumped_mass_matrix_inverse_view.template read_entry<T>(i);
1095 const auto old_U_i = old_U_view.template read_tensor<T>(i);
1096 const auto rho_i = view.density(old_U_i);
1097 const auto old_m_i = view.momentum(old_U_i);
1098 const auto old_v_i = old_m_i / rho_i;
1100 dealii::Tensor<1, (dim == 2 ? 1 : dim), T> magnetic_field;
1101 for (
unsigned int d = 0; d < (dim == 2 ? 1 : dim); ++d)
1102 magnetic_field[d] = read_entry<T>(magnetic_field_.block(d), i);
1104 dealii::Tensor<1, dim, T> grad_phi;
1105 for (
unsigned int d = 0; d < dim; ++d)
1106 grad_phi[d] = m_i_inv * read_entry<T>(velocity_rhs_.block(d), i);
1112 if (crank_nicolson_extrapolation)
1113 new_v_i = Number(2.) * new_v_i - old_v_i;
1115 auto new_U_i = old_U_i;
1116 for (
unsigned int d = 0; d < dim; ++d)
1117 new_U_i[1 + d] = rho_i * new_v_i[d];
1120 if constexpr (view.have_energy_equation)
1121 new_U_i[1 + dim] += Number(0.5) * rho_i *
1122 (new_v_i.norm_square() - old_v_i.norm_square());
1124 new_U_view.template write_tensor<T>(new_U_i, i);
1127 cpu_simd_loop<Number>(
1128 "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)