14#include <deal.II/base/graph_coloring.h>
15#include <deal.II/base/parallel.h>
16#include <deal.II/base/work_stream.h>
17#include <deal.II/dofs/dof_renumbering.h>
18#include <deal.II/dofs/dof_tools.h>
19#include <deal.II/fe/fe_values.h>
20#include <deal.II/grid/grid_tools.h>
21#include <deal.II/lac/dynamic_sparsity_pattern.h>
22#include <deal.II/lac/la_parallel_vector.h>
23#ifdef DEAL_II_WITH_TRILINOS
24#include <deal.II/lac/trilinos_sparse_matrix.h>
27#ifdef FORCE_DEAL_II_SPARSE_MATRIX
28#undef DEAL_II_WITH_TRILINOS
33 using namespace dealii;
36 template <
int dim,
typename Number>
38 const MPI_Comm &mpi_communicator,
40 const std::string &subsection )
41 : ParameterAcceptor(subsection)
42 , discretization_(&discretization)
43 , mpi_communicator_(mpi_communicator)
48 template <
int dim,
typename Number>
57 auto &dof_handler = *dof_handler_;
58 const IndexSet &locally_owned = dof_handler.locally_owned_dofs();
60 IndexSet locally_relevant;
61 DoFTools::extract_locally_relevant_dofs(dof_handler, locally_relevant);
63 affine_constraints_.reinit(locally_relevant);
64 DoFTools::make_hanging_node_constraints(dof_handler, affine_constraints_);
66#ifndef DEAL_II_WITH_TRILINOS
67 AssertThrow(affine_constraints_.n_constraints() == 0,
68 ExcMessage(
"ryujin was built without Trilinos support - no "
69 "hanging node support available"));
77 const auto &periodic_faces =
78 discretization_->triangulation().get_periodic_face_map();
80 for (
const auto &[left, value] : periodic_faces) {
81 const auto &[right, orientation] = value;
83 typename DoFHandler<dim>::cell_iterator dof_cell_left(
84 &left.first->get_triangulation(),
89 typename DoFHandler<dim>::cell_iterator dof_cell_right(
90 &right.first->get_triangulation(),
95 if constexpr (dim != 1 && std::is_same<Number, double>::value) {
96 DoFTools::make_periodicity_constraints(
97 dof_cell_left->face(left.second),
98 dof_cell_right->face(right.second),
101#
if DEAL_II_VERSION_GTE(9, 6, 0)
109 AssertThrow(
false, dealii::ExcNotImplemented());
114 affine_constraints_.close();
116 sparsity_pattern_.reinit(
117 dof_handler.n_dofs(), dof_handler.n_dofs(), locally_relevant);
118#ifdef DEAL_II_WITH_TRILINOS
119 DoFTools::make_sparsity_pattern(
120 dof_handler, sparsity_pattern_, affine_constraints_,
false);
129 dof_handler, sparsity_pattern_, affine_constraints_,
false);
138 SparsityTools::distribute_sparsity_pattern(
139 sparsity_pattern_, locally_owned, mpi_communicator_, locally_relevant);
143 template <
int dim,
typename Number>
144 void OfflineData<dim, Number>::setup(
const unsigned int problem_dimension)
147 std::cout <<
"OfflineData<dim, Number>::setup()" << std::endl;
154 const auto &triangulation = discretization_->triangulation();
156 dof_handler_ = std::make_unique<dealii::DoFHandler<dim>>(triangulation);
157 auto &dof_handler = *dof_handler_;
159 dof_handler.distribute_dofs(discretization_->finite_element());
161 n_locally_owned_ = dof_handler.locally_owned_dofs().n_elements();
167 DoFRenumbering::Cuthill_McKee(dof_handler);
178 dof_handler, mpi_communicator_, n_locally_owned_, 1);
187 create_constraints_and_sparsity_pattern();
189 dof_handler, sparsity_pattern_, VectorizedArray<Number>::size());
206 VectorizedArray<Number>::size());
212 const auto consistent_stride_range [[maybe_unused]] = [&]() {
213 constexpr auto group_size = VectorizedArray<Number>::size();
214 const IndexSet &locally_owned = dof_handler.locally_owned_dofs();
215 const auto offset = n_locally_owned_ != 0 ? *locally_owned.begin() : 0;
217 unsigned int group_row_length = 0;
219 for (; i < n_locally_internal_; ++i) {
220 if (i % group_size == 0) {
221 group_row_length = sparsity_pattern_.row_length(offset + i);
223 if (group_row_length != sparsity_pattern_.row_length(offset + i)) {
228 return i / group_size * group_size;
234 const auto mpi_allreduce_logical_or = [&](
const bool local_value) {
235 std::function<bool(
const bool &,
const bool &)> comparator =
236 [](
const bool &left,
const bool &right) ->
bool {
237 return left || right;
239 return Utilities::MPI::all_reduce(
240 local_value, mpi_communicator_, comparator);
247 create_constraints_and_sparsity_pattern();
257#if DEAL_II_VERSION_GTE(9, 5, 0)
258 if (mpi_allreduce_logical_or(affine_constraints_.n_constraints() > 0)) {
259 if (mpi_allreduce_logical_or(
260 consistent_stride_range() != n_locally_internal_)) {
270 VectorizedArray<Number>::size());
271 create_constraints_and_sparsity_pattern();
272 n_locally_internal_ = consistent_stride_range();
282 Assert(consistent_stride_range() == n_locally_internal_,
283 dealii::ExcInternalError());
289 const IndexSet &locally_owned = dof_handler.locally_owned_dofs();
290 Assert(n_locally_owned_ == locally_owned.n_elements(),
291 dealii::ExcInternalError());
293 IndexSet locally_relevant;
294 DoFTools::extract_locally_relevant_dofs(dof_handler, locally_relevant);
297 IndexSet additional_dofs(dof_handler.n_dofs());
298 for (
auto &entry : sparsity_pattern_)
299 if (!locally_relevant.is_element(entry.column())) {
300 Assert(locally_owned.is_element(entry.row()), ExcInternalError());
301 additional_dofs.add_index(entry.column());
303 additional_dofs.compress();
304 locally_relevant.add_indices(additional_dofs);
305 locally_relevant.compress();
308 n_locally_relevant_ = locally_relevant.n_elements();
310 scalar_partitioner_ = std::make_shared<dealii::Utilities::MPI::Partitioner>(
311 locally_owned, locally_relevant, mpi_communicator_);
313 vector_partitioner_ =
322 if (mpi_allreduce_logical_or(affine_constraints_.n_constraints() > 0)) {
326 n_export_indices_ = 0;
327 for (
const auto &it : scalar_partitioner_->import_indices())
328 if (it.second <= n_locally_internal_)
329 n_export_indices_ = std::max(n_export_indices_, it.second);
331 constexpr auto simd_length = VectorizedArray<Number>::size();
333 (n_export_indices_ + simd_length - 1) / simd_length * simd_length;
338 unsigned int control = 0;
339 for (
const auto &it : scalar_partitioner_->import_indices())
340 if (it.second <= n_locally_internal_)
341 control = std::max(control, it.second);
343 Assert(control <= n_export_indices_, ExcInternalError());
344 Assert(n_export_indices_ <= n_locally_internal_, ExcInternalError());
353 sparsity_pattern_simd_.reinit(
354 n_locally_internal_, sparsity_pattern_, scalar_partitioner_);
360 lumped_mass_matrix_.reinit(scalar_partitioner_);
361 lumped_mass_matrix_inverse_.reinit(scalar_partitioner_);
363 mass_matrix_.reinit(sparsity_pattern_simd_);
364 betaij_matrix_.reinit(sparsity_pattern_simd_);
365 cij_matrix_.reinit(sparsity_pattern_simd_);
369 template <
int dim,
typename Number>
370 void OfflineData<dim, Number>::assemble()
373 std::cout <<
"OfflineData<dim, Number>::assemble()" << std::endl;
376 auto &dof_handler = *dof_handler_;
378 measure_of_omega_ = 0.;
380#ifdef DEAL_II_WITH_TRILINOS
383 AffineConstraints<double> affine_constraints_assembly;
384 affine_constraints_assembly.reinit(affine_constraints_.get_local_lines());
385 for (
auto line : affine_constraints_.get_lines()) {
386 affine_constraints_assembly.add_line(line.index);
387 for (
auto entry : line.entries)
388 affine_constraints_assembly.add_entry(
389 line.index, entry.first, entry.second);
390 affine_constraints_assembly.set_inhomogeneity(line.index,
393 affine_constraints_assembly.close();
395 const IndexSet &locally_owned = dof_handler.locally_owned_dofs();
396 TrilinosWrappers::SparsityPattern trilinos_sparsity_pattern;
397 trilinos_sparsity_pattern.reinit(
398 locally_owned, sparsity_pattern_, mpi_communicator_);
400 TrilinosWrappers::SparseMatrix mass_matrix_tmp;
401 TrilinosWrappers::SparseMatrix betaij_matrix_tmp;
402 std::array<TrilinosWrappers::SparseMatrix, dim> cij_matrix_tmp;
404 mass_matrix_tmp.reinit(trilinos_sparsity_pattern);
405 betaij_matrix_tmp.reinit(trilinos_sparsity_pattern);
406 for (
auto &matrix : cij_matrix_tmp)
407 matrix.reinit(trilinos_sparsity_pattern);
412 AffineConstraints<Number> affine_constraints_assembly;
413 affine_constraints_assembly.copy_from(affine_constraints_);
416 SparsityPattern sparsity_pattern_assembly;
418 DynamicSparsityPattern dsp(n_locally_relevant_, n_locally_relevant_);
419 for (
const auto &entry : sparsity_pattern_) {
420 const auto i = scalar_partitioner_->global_to_local(entry.row());
421 const auto j = scalar_partitioner_->global_to_local(entry.column());
424 sparsity_pattern_assembly.copy_from(dsp);
427 dealii::SparseMatrix<Number> mass_matrix_tmp;
428 dealii::SparseMatrix<Number> betaij_matrix_tmp;
429 std::array<dealii::SparseMatrix<Number>, dim> cij_matrix_tmp;
431 mass_matrix_tmp.reinit(sparsity_pattern_assembly);
432 betaij_matrix_tmp.reinit(sparsity_pattern_assembly);
433 for (
auto &matrix : cij_matrix_tmp)
434 matrix.reinit(sparsity_pattern_assembly);
437 const unsigned int dofs_per_cell =
438 discretization_->finite_element().dofs_per_cell;
440 const unsigned int n_q_points = discretization_->quadrature().size();
448 const auto local_assemble_system =
449 [&](
const auto &cell,
auto &scratch,
auto ©) {
452 auto &is_locally_owned = copy.is_locally_owned_;
453 auto &local_dof_indices = copy.local_dof_indices_;
455 auto &cell_mass_matrix = copy.cell_mass_matrix_;
456 auto &cell_betaij_matrix = copy.cell_betaij_matrix_;
457 auto &cell_cij_matrix = copy.cell_cij_matrix_;
458 auto &cell_measure = copy.cell_measure_;
460 auto &fe_values = scratch.fe_values_;
462#ifdef DEAL_II_WITH_TRILINOS
463 is_locally_owned = cell->is_locally_owned();
471 is_locally_owned = !cell->is_artificial();
473 if (!is_locally_owned)
476 cell_mass_matrix.reinit(dofs_per_cell, dofs_per_cell);
477 cell_betaij_matrix.reinit(dofs_per_cell, dofs_per_cell);
478 for (
auto &matrix : cell_cij_matrix)
479 matrix.reinit(dofs_per_cell, dofs_per_cell);
481 fe_values.reinit(cell);
483 local_dof_indices.resize(dofs_per_cell);
484 cell->get_dof_indices(local_dof_indices);
487 cell_mass_matrix = 0.;
488 cell_betaij_matrix = 0.;
489 for (
auto &matrix : cell_cij_matrix)
493 for (
unsigned int q_point = 0; q_point < n_q_points; ++q_point) {
494 const auto JxW = fe_values.JxW(q_point);
496 if (cell->is_locally_owned())
497 cell_measure += Number(JxW);
499 for (
unsigned int j = 0; j < dofs_per_cell; ++j) {
500 const auto value_JxW = fe_values.shape_value(j, q_point) * JxW;
501 const auto grad_JxW = fe_values.shape_grad(j, q_point) * JxW;
503 for (
unsigned int i = 0; i < dofs_per_cell; ++i) {
505 const auto value = fe_values.shape_value(i, q_point);
506 const auto grad = fe_values.shape_grad(i, q_point);
508 cell_mass_matrix(i, j) += Number(value * value_JxW);
509 cell_betaij_matrix(i, j) += Number(grad * grad_JxW);
510 for (
unsigned int d = 0; d < dim; ++d)
511 cell_cij_matrix[d](i, j) += Number((value * grad_JxW)[d]);
518 const auto copy_local_to_global = [&](
const auto ©) {
519 const auto &is_locally_owned = copy.is_locally_owned_;
520 auto local_dof_indices = copy.local_dof_indices_;
521 const auto &cell_mass_matrix = copy.cell_mass_matrix_;
522 const auto &cell_cij_matrix = copy.cell_cij_matrix_;
523 const auto &cell_betaij_matrix = copy.cell_betaij_matrix_;
524 const auto &cell_measure = copy.cell_measure_;
526 if (!is_locally_owned)
529#ifndef DEAL_II_WITH_TRILINOS
533 affine_constraints_assembly.distribute_local_to_global(
534 cell_mass_matrix, local_dof_indices, mass_matrix_tmp);
536 for (
int k = 0; k < dim; ++k) {
537 affine_constraints_assembly.distribute_local_to_global(
538 cell_cij_matrix[k], local_dof_indices, cij_matrix_tmp[k]);
541 affine_constraints_assembly.distribute_local_to_global(
542 cell_betaij_matrix, local_dof_indices, betaij_matrix_tmp);
544 measure_of_omega_ += cell_measure;
547 WorkStream::run(dof_handler.begin_active(),
549 local_assemble_system,
550 copy_local_to_global,
551 AssemblyScratchData<dim>(*discretization_),
552#ifdef DEAL_II_WITH_TRILINOS
553 AssemblyCopyData<dim, double>());
555 AssemblyCopyData<dim, Number>());
559 Utilities::MPI::sum(measure_of_omega_, mpi_communicator_);
561#ifdef DEAL_II_WITH_TRILINOS
564 for (
auto &it : cij_matrix_tmp)
573#ifdef DEAL_II_WITH_TRILINOS
574 using scalar_type = dealii::LinearAlgebra::distributed::Vector<double>;
575 scalar_type one(scalar_partitioner_);
578 scalar_type local_lumped_mass_matrix(scalar_partitioner_);
579 mass_matrix_tmp.vmult(local_lumped_mass_matrix, one);
582 for (
unsigned int i = 0; i < scalar_partitioner_->locally_owned_size();
584 lumped_mass_matrix_.local_element(i) =
585 local_lumped_mass_matrix.local_element(i);
586 lumped_mass_matrix_inverse_.local_element(i) =
587 1. / lumped_mass_matrix_.local_element(i);
589 lumped_mass_matrix_.update_ghost_values();
590 lumped_mass_matrix_inverse_.update_ghost_values();
594 Vector<Number> one(mass_matrix_tmp.m());
597 Vector<Number> local_lumped_mass_matrix(mass_matrix_tmp.m());
598 mass_matrix_tmp.vmult(local_lumped_mass_matrix, one);
600 for (
unsigned int i = 0; i < scalar_partitioner_->locally_owned_size();
602 lumped_mass_matrix_.local_element(i) = local_lumped_mass_matrix(i);
603 lumped_mass_matrix_inverse_.local_element(i) =
604 1. / lumped_mass_matrix_.local_element(i);
606 lumped_mass_matrix_.update_ghost_values();
607 lumped_mass_matrix_inverse_.update_ghost_values();
611#ifdef DEAL_II_WITH_TRILINOS
612 betaij_matrix_.read_in(betaij_matrix_tmp,
false);
613 mass_matrix_.read_in(mass_matrix_tmp,
false);
614 cij_matrix_.read_in(cij_matrix_tmp,
false);
616 betaij_matrix_.read_in(betaij_matrix_tmp,
true);
617 mass_matrix_.read_in(mass_matrix_tmp,
true);
618 cij_matrix_.read_in(cij_matrix_tmp,
true);
620 betaij_matrix_.update_ghost_rows();
621 mass_matrix_.update_ghost_rows();
622 cij_matrix_.update_ghost_rows();
626 boundary_map_ = construct_boundary_map(
627 dof_handler.begin_active(), dof_handler.end(), *scalar_partitioner_);
629 coupling_boundary_pairs_ = collect_coupling_boundary_pairs(
630 dof_handler.begin_active(), dof_handler.end(), *scalar_partitioner_);
634 template <
int dim,
typename Number>
635 void OfflineData<dim, Number>::create_multigrid_data()
638 std::cout <<
"OfflineData<dim, Number>::create_multigrid_data()"
642 auto &dof_handler = *dof_handler_;
644 dof_handler.distribute_mg_dofs();
646 const auto n_levels = dof_handler.get_triangulation().n_global_levels();
648 AffineConstraints<float> level_constraints;
651 level_boundary_map_.resize(n_levels);
652 level_lumped_mass_matrix_.resize(n_levels);
654 for (
unsigned int level = 0; level < n_levels; ++level) {
657 IndexSet relevant_dofs;
658 dealii::DoFTools::extract_locally_relevant_level_dofs(
659 dof_handler, level, relevant_dofs);
660 const auto partitioner = std::make_shared<Utilities::MPI::Partitioner>(
661 dof_handler.locally_owned_mg_dofs(level),
663 lumped_mass_matrix_.get_mpi_communicator());
664 level_lumped_mass_matrix_[level].reinit(partitioner);
665 std::vector<types::global_dof_index> dof_indices(
666 dof_handler.get_fe().dofs_per_cell);
667 Vector<Number> mass_values(dof_handler.get_fe().dofs_per_cell);
668 FEValues<dim> fe_values(discretization_->mapping(),
669 discretization_->finite_element(),
670 discretization_->quadrature(),
671 update_values | update_JxW_values);
672 for (
const auto &cell : dof_handler.cell_iterators_on_level(level))
675 if (cell->is_locally_owned_on_level()) {
676 fe_values.reinit(cell);
677 for (
unsigned int i = 0; i < mass_values.size(); ++i) {
679 for (
unsigned int q = 0; q < fe_values.n_quadrature_points; ++q)
680 sum += fe_values.shape_value(i, q) * fe_values.JxW(q);
681 mass_values(i) = sum;
683 cell->get_mg_dof_indices(dof_indices);
684 level_constraints.distribute_local_to_global(
685 mass_values, dof_indices, level_lumped_mass_matrix_[level]);
691 level_boundary_map_[level] = construct_boundary_map(
692 dof_handler.begin_mg(level), dof_handler.end_mg(level), *partitioner);
697 template <
int dim,
typename Number>
698 template <
typename ITERATOR1,
typename ITERATOR2>
699 typename OfflineData<dim, Number>::boundary_map_type
701 const ITERATOR1 &begin,
702 const ITERATOR2 &end,
703 const Utilities::MPI::Partitioner &partitioner)
const
706 std::cout <<
"OfflineData<dim, Number>::construct_boundary_map()"
710 decltype(boundary_map_) preliminary_map;
712 std::vector<dealii::types::global_dof_index> local_dof_indices;
714 const dealii::QGauss<dim - 1> face_quadrature(3);
715 dealii::FEFaceValues<dim> fe_face_values(discretization_->mapping(),
716 discretization_->finite_element(),
718 dealii::update_normal_vectors |
719 dealii::update_values |
720 dealii::update_JxW_values);
722 const unsigned int dofs_per_cell =
723 discretization_->finite_element().dofs_per_cell;
725 const auto support_points =
726 discretization_->finite_element().get_unit_support_points();
728 for (
auto cell = begin; cell != end; ++cell) {
730 if (!cell->is_locally_owned_on_level())
733 local_dof_indices.resize(dofs_per_cell);
734 cell->get_active_or_mg_dof_indices(local_dof_indices);
736 for (
auto f : GeometryInfo<dim>::face_indices()) {
737 const auto face = cell->face(f);
738 const auto id = face->boundary_id();
740 if (!face->at_boundary())
751 fe_face_values.reinit(cell, f);
752 const unsigned int n_face_q_points = face_quadrature.size();
754 for (
unsigned int j = 0; j < dofs_per_cell; ++j) {
756 if (!discretization_->finite_element().has_support_on_face(j, f))
759 Number boundary_mass = 0.;
760 dealii::Tensor<1, dim, Number> normal;
762 for (
unsigned int q = 0; q < n_face_q_points; ++q) {
763 const auto JxW = fe_face_values.JxW(q);
764 const auto phi_i = fe_face_values.shape_value(j, q);
766 boundary_mass += phi_i * JxW;
767 normal += phi_i * fe_face_values.normal_vector(q) * JxW;
770 const auto global_index = local_dof_indices[j];
771 const auto index = partitioner.global_to_local(global_index);
774 if (index >= n_locally_owned_)
778 const unsigned int row_length =
779 sparsity_pattern_simd_.row_length(index);
783 Point<dim> position =
784 discretization_->mapping().transform_unit_to_real_cell(
785 cell, support_points[j]);
791 preliminary_map.insert(
792 {index, {normal, boundary_mass, boundary_mass, id, position}});
808 decltype(boundary_map_) filtered_map;
809 std::set<dealii::types::global_dof_index> boundary_dofs;
810 for (
auto entry : preliminary_map) {
811 bool inserted =
false;
812 const auto range = filtered_map.equal_range(entry.first);
813 for (
auto it = range.first; it != range.second; ++it) {
814 const auto &[new_normal,
818 new_point] = entry.second;
819 auto &[normal, normal_mass, boundary_mass, id, point] = it->second;
824 Assert(point.distance(new_point) < 1.0e-14, dealii::ExcInternalError());
826 if (normal * new_normal / normal.norm() / new_normal.norm() > 0.08) {
828 normal += new_normal;
829 boundary_mass += new_boundary_mass;
834 filtered_map.insert(entry);
839 for (
auto &it : filtered_map) {
840 auto &[normal, normal_mass, boundary_mass, id, point] = it.second;
841 const auto new_normal_mass =
842 normal.norm() + std::numeric_limits<Number>::epsilon();
844 normal_mass = new_normal_mass;
845 normal /= new_normal_mass;
852 template <
int dim,
typename Number>
853 template <
typename ITERATOR1,
typename ITERATOR2>
856 const ITERATOR1 &begin,
857 const ITERATOR2 &end,
858 const Utilities::MPI::Partitioner &partitioner)
const
861 std::cout <<
"OfflineData<dim, Number>::collect_coupling_boundary_pairs()"
871 std::set<unsigned int> locally_relevant_boundary_indices;
873 std::vector<dealii::types::global_dof_index> local_dof_indices;
875 const unsigned int dofs_per_cell =
876 discretization_->finite_element().dofs_per_cell;
878 for (
auto cell = begin; cell != end; ++cell) {
881 if (cell->is_artificial())
884 local_dof_indices.resize(dofs_per_cell);
885 cell->get_active_or_mg_dof_indices(local_dof_indices);
887 for (
auto f : GeometryInfo<dim>::face_indices()) {
888 const auto face = cell->face(f);
889 const auto id = face->boundary_id();
891 if (!face->at_boundary())
898 for (
unsigned int j = 0; j < dofs_per_cell; ++j) {
900 if (!discretization_->finite_element().has_support_on_face(j, f))
903 const auto global_index = local_dof_indices[j];
904 const auto index = partitioner.global_to_local(global_index);
907 if (index >= n_locally_relevant_)
910 locally_relevant_boundary_indices.insert(index);
919 coupling_boundary_pairs_type result;
921 for (
const auto i : locally_relevant_boundary_indices) {
924 if (i >= n_locally_owned_)
927 const unsigned int row_length = sparsity_pattern_simd_.row_length(i);
933 const unsigned int *js = sparsity_pattern_simd_.columns(i);
934 constexpr auto simd_length = VectorizedArray<Number>::size();
936 for (
unsigned int col_idx = 1; col_idx < row_length; ++col_idx) {
937 const auto j = *(i < n_locally_internal_ ? js + col_idx * simd_length
940 if (locally_relevant_boundary_indices.count(j) != 0) {
941 result.push_back({i, col_idx, j});
OfflineData(const MPI_Comm &mpi_communicator, const Discretization< dim > &discretization, const std::string &subsection="/OfflineData")
void make_extended_sparsity_pattern(const dealii::DoFHandler< dim > &dof_handler, SPARSITY &dsp, const dealii::AffineConstraints< Number > &affine_constraints, bool keep_constrained)
void transform_to_local_range(const dealii::Utilities::MPI::Partitioner &partitioner, dealii::AffineConstraints< Number > &affine_constraints)
unsigned int internal_range(dealii::DoFHandler< dim > &dof_handler, const dealii::DynamicSparsityPattern &sparsity, const std::size_t group_size)
unsigned int export_indices_first(dealii::DoFHandler< dim > &dof_handler, const MPI_Comm &mpi_communicator, const unsigned int n_locally_internal, const std::size_t group_size)
unsigned int inconsistent_strides_last(dealii::DoFHandler< dim > &dof_handler, const dealii::DynamicSparsityPattern &sparsity, const unsigned int n_locally_internal, const std::size_t group_size)
std::shared_ptr< const dealii::Utilities::MPI::Partitioner > create_vector_partitioner(const std::shared_ptr< const dealii::Utilities::MPI::Partitioner > &scalar_partitioner, const unsigned int n_components)
DEAL_II_ALWAYS_INLINE FT add(const FT &flux_left_ij, const FT &flux_right_ij)