39 template <
int dim,
typename Number,
bool is_face_>
52 std::function<std::vector<std::unique_ptr<FEEvalType>>(
53 const std::pair<unsigned int, unsigned int> &)>
55 std::function<void(std::vector<std::unique_ptr<FEEvalType>> &,
58 std::function<void(std::vector<std::unique_ptr<FEEvalType>> &)>
68 template <
int dim,
typename AdditionalData>
71 AdditionalData &additional_data);
91 typename VectorizedArrayType,
96 VectorType &diagonal_global,
102 VectorizedArrayType> &)>
104 const unsigned int dof_no = 0,
105 const unsigned int quad_no = 0,
106 const unsigned int first_selected_component = 0,
107 const unsigned int first_vector_component = 0);
118 typename QuadOperation>
123 const QuadOperation &quad_operation,
126 const unsigned int dof_no = 0,
127 const unsigned int quad_no = 0,
128 const unsigned int first_selected_component = 0,
129 const unsigned int first_vector_component = 0);
134 template <
typename CLASS,
140 typename VectorizedArrayType,
145 VectorType &diagonal_global,
151 VectorizedArrayType> &) const,
152 const CLASS *owning_class,
153 const unsigned
int dof_no = 0,
154 const unsigned
int quad_no = 0,
155 const unsigned
int first_selected_component = 0,
156 const unsigned
int first_vector_component = 0);
175 typename VectorizedArrayType,
180 VectorType &diagonal_global,
186 VectorizedArrayType> &)>
193 VectorizedArrayType> &,
199 VectorizedArrayType> &)>
206 VectorizedArrayType> &)>
208 const unsigned int dof_no = 0,
209 const unsigned int quad_no = 0,
210 const unsigned int first_selected_component = 0,
211 const unsigned int first_vector_component = 0);
218 template <
typename CLASS,
224 typename VectorizedArrayType,
229 VectorType &diagonal_global,
235 VectorizedArrayType> &) const,
241 VectorizedArrayType> &,
247 VectorizedArrayType> &)
254 VectorizedArrayType> &)
256 const CLASS *owning_class,
257 const unsigned
int dof_no = 0,
258 const unsigned
int quad_no = 0,
259 const unsigned
int first_selected_component = 0,
260 const unsigned
int first_vector_component = 0);
277 typename VectorizedArrayType,
289 VectorizedArrayType> &)>
291 const unsigned int dof_no = 0,
292 const unsigned int quad_no = 0,
293 const unsigned int first_selected_component = 0);
300 template <
typename CLASS,
306 typename VectorizedArrayType,
318 VectorizedArrayType> &) const,
319 const CLASS *owning_class,
320 const unsigned
int dof_no = 0,
321 const unsigned
int quad_no = 0,
322 const unsigned
int first_selected_component = 0);
333 typename VectorizedArrayType,
335 typename VectorType2>
345 VectorType &diagonal_global,
346 std::vector<VectorType2 *> &diagonal_global_components);
354 typename VectorizedArrayType,
385 typename VectorizedArrayType,
397 VectorizedArrayType> &)>
404 VectorizedArrayType> &,
410 VectorizedArrayType> &)>
417 VectorizedArrayType> &)>
419 const unsigned int dof_no = 0,
420 const unsigned int quad_no = 0,
421 const unsigned int first_selected_component = 0);
428 template <
typename CLASS,
434 typename VectorizedArrayType,
446 VectorizedArrayType> &) const,
452 VectorizedArrayType> &,
458 VectorizedArrayType> &)
465 VectorizedArrayType> &)
467 const CLASS *owning_class,
468 const unsigned
int dof_no = 0,
469 const unsigned
int quad_no = 0,
470 const unsigned
int first_selected_component = 0);
522 std::vector<unsigned int> valid_fe_indices;
524 const auto &fe_collection =
526 .get_fe_collection();
528 for (
unsigned int i = 0; i < fe_collection.size(); ++i)
529 if (fe_collection[i].n_dofs_per_cell() > 0)
530 valid_fe_indices.push_back(i);
544 template <
typename VectorTypeOut,
typename VectorTypeIn>
549 const VectorTypeIn &,
550 const std::pair<unsigned int, unsigned int> &)> &cell_operation,
552 const VectorTypeIn &src,
553 const bool zero_dst_vector =
false)
const
555 const auto ebd_cell_operation = [&](
const auto &
matrix_free,
559 const auto category =
matrix_free.get_cell_range_category(range);
567 matrix_free->template cell_loop<VectorTypeOut, VectorTypeIn>(
568 ebd_cell_operation, dst, src, zero_dst_vector);
578 template <
typename VectorTypeOut,
typename VectorTypeIn>
583 const VectorTypeIn &,
584 const std::pair<unsigned int, unsigned int> &)> &cell_operation,
588 const VectorTypeIn &,
589 const std::pair<unsigned int, unsigned int> &)> &face_operation,
593 const VectorTypeIn &,
594 const std::pair<unsigned int, unsigned int> &,
595 const bool)> &boundary_operation,
597 const VectorTypeIn &src,
598 const bool zero_dst_vector =
false)
const
600 const auto ebd_cell_operation = [&](
const auto &
matrix_free,
604 const auto category =
matrix_free.get_cell_range_category(range);
612 const auto ebd_internal_or_boundary_face_operation =
617 const auto category =
matrix_free.get_face_range_category(range);
619 const unsigned int type =
633 matrix_free->template loop<VectorTypeOut, VectorTypeIn>(
635 ebd_internal_or_boundary_face_operation,
636 ebd_internal_or_boundary_face_operation,
659 template <
int dim,
typename AdditionalData>
662 AdditionalData &additional_data)
665 const unsigned int level = additional_data.mg_level;
670 additional_data.cell_vectorization_category.assign(
673 additional_data.cell_vectorization_category.assign(tria.
n_active_cells(),
680 std::sort(bids.begin(), bids.end());
683 unsigned int n_bids = bids.size() + 1;
685 for (
unsigned int i = 0; i < GeometryInfo<dim>::faces_per_cell;
686 i++, offset = offset * n_bids)
690 const auto to_category = [&](
const auto &cell) {
691 unsigned int c_num = 0;
692 for (
unsigned int i = 0; i < GeometryInfo<dim>::faces_per_cell; ++i)
694 const auto face = cell->face(i);
695 if (face->at_boundary() && !cell->has_periodic_neighbor(i))
697 factors[i] * (1 + std::distance(bids.begin(),
698 std::find(bids.begin(),
700 face->boundary_id())));
709 if (cell->is_locally_owned())
711 .cell_vectorization_category[cell->active_cell_index()] =
719 if (cell->is_locally_owned_on_level())
720 additional_data.cell_vectorization_category[cell->index()] =
726 additional_data.hold_all_faces_to_owned_cells =
true;
727 additional_data.cell_vectorization_categories_strict =
true;
728 additional_data.mapping_update_flags_faces_by_cells =
729 additional_data.mapping_update_flags_inner_faces |
730 additional_data.mapping_update_flags_boundary_faces;
735 template <
typename Number>
738 std::vector<unsigned int> row_lid_to_gid;
739 std::vector<unsigned int> row;
740 std::vector<unsigned int> col;
741 std::vector<Number> val;
743 std::vector<unsigned int> inverse_lookup_rows;
744 std::vector<std::pair<unsigned int, unsigned int>> inverse_lookup_origins;
747 template <
int dim,
typename VectorizedArrayType,
bool is_face>
748 class ComputeDiagonalHelper
751 using FEEvaluationType =
754 using Number =
typename VectorizedArrayType::value_type;
755 static const unsigned int n_lanes = VectorizedArrayType::size();
757 ComputeDiagonalHelper()
759 , matrix_free(nullptr)
760 , dofs_per_component(0)
764 ComputeDiagonalHelper(
const ComputeDiagonalHelper &)
766 , matrix_free(nullptr)
767 , dofs_per_component(0)
773 FEEvaluationType &phi,
775 const unsigned int n_components)
779 if (dofs_per_component !=
780 phi.get_shape_info().dofs_per_component_on_cell)
782 locally_relevant_constraints_hn_map.
clear();
784 phi.get_shape_info().dofs_per_component_on_cell;
786 this->n_components = n_components;
787 this->dofs_per_cell = n_components * dofs_per_component;
789 this->matrix_free = &matrix_free;
793 reinit(
const unsigned int cell)
796 const auto &matrix_free = *this->matrix_free;
804 const unsigned int first_selected_component =
805 n_fe_components == 1 ? 0 : phi->get_first_selected_component();
807 this->n_lanes_filled =
816 std::vector<std::tuple<unsigned int, unsigned int, Number>>
817 locally_relevant_constraints, locally_relevant_constraints_tmp;
818 locally_relevant_constraints.reserve(dofs_per_cell);
819 std::vector<unsigned int> constraint_position;
820 std::vector<unsigned char> is_constrained_hn;
822 const std::array<unsigned int, n_lanes> &cells =
823 this->phi->get_cell_ids();
825 for (
unsigned int v = 0; v < n_lanes_filled; ++v)
830 const unsigned int *dof_indices;
831 unsigned int index_indicators, next_index_indicators;
833 const unsigned int start =
834 cells[v] * n_fe_components + first_selected_component;
836 dof_info.dof_indices.data() + dof_info.row_starts[start].first;
837 index_indicators = dof_info.row_starts[start].second;
838 next_index_indicators = dof_info.row_starts[start + 1].second;
842 locally_relevant_constraints.clear();
844 if (n_components == 1 || n_fe_components == 1)
846 unsigned int ind_local = 0;
847 for (; index_indicators != next_index_indicators;
848 ++index_indicators, ++ind_local)
850 const std::pair<unsigned short, unsigned short> indicator =
851 dof_info.constraint_indicator[index_indicators];
853 for (
unsigned int j = 0; j < indicator.first;
855 locally_relevant_constraints.emplace_back(ind_local,
859 dof_indices += indicator.first;
861 const Number *data_val =
863 const Number *end_pool =
866 for (; data_val != end_pool; ++data_val, ++dof_indices)
867 locally_relevant_constraints.emplace_back(ind_local,
874 for (; ind_local < dofs_per_component;
875 ++dof_indices, ++ind_local)
876 locally_relevant_constraints.emplace_back(ind_local,
887 for (
unsigned int comp = 0; comp < n_components; ++comp)
889 unsigned int ind_local = 0;
893 for (; index_indicators != next_index_indicators;
894 ++index_indicators, ++ind_local)
896 const std::pair<unsigned short, unsigned short>
898 dof_info.constraint_indicator[index_indicators];
901 for (
unsigned int j = 0; j < indicator.first;
903 locally_relevant_constraints.emplace_back(
904 comp * dofs_per_component + ind_local,
907 dof_indices += indicator.first;
909 const Number *data_val =
911 const Number *end_pool =
914 for (; data_val != end_pool; ++data_val, ++dof_indices)
915 locally_relevant_constraints.emplace_back(
916 comp * dofs_per_component + ind_local,
924 for (; ind_local < dofs_per_component;
925 ++dof_indices, ++ind_local)
926 locally_relevant_constraints.emplace_back(
927 comp * dofs_per_component + ind_local,
931 if (comp + 1 < n_components)
932 next_index_indicators =
933 dof_info.row_starts[start + comp + 2].second;
940 for (
unsigned int i = 1; i < locally_relevant_constraints.size();
942 Assert(std::get<0>(locally_relevant_constraints[i]) >=
943 std::get<0>(locally_relevant_constraints[i - 1]),
947 if (dof_info.hanging_node_constraint_masks.size() > 0 &&
948 dof_info.hanging_node_constraint_masks_comp.size() > 0 &&
949 dof_info.hanging_node_constraint_masks_comp
950 [phi->get_active_fe_index()][first_selected_component])
953 dof_info.hanging_node_constraint_masks[cells[v]];
956 if (mask != ::internal::MatrixFreeFunctions::
961 if (locally_relevant_constraints_hn_map.find(mask) ==
962 locally_relevant_constraints_hn_map.end())
963 fill_constraint_type_into_map(mask);
965 const auto &locally_relevant_constraints_hn =
966 locally_relevant_constraints_hn_map[
mask];
968 locally_relevant_constraints_tmp.clear();
969 if (locally_relevant_constraints_tmp.capacity() <
970 locally_relevant_constraints.size())
971 locally_relevant_constraints_tmp.reserve(
972 locally_relevant_constraints.size() +
973 locally_relevant_constraints_hn.size());
978 constraint_position.assign(dofs_per_cell,
980 for (
auto &a : locally_relevant_constraints)
981 if (constraint_position[
std::get<0>(a)] ==
983 constraint_position[
std::get<0>(a)] =
984 std::distance(locally_relevant_constraints.
data(),
986 is_constrained_hn.assign(dofs_per_cell,
false);
987 for (
auto &hn : locally_relevant_constraints_hn)
988 is_constrained_hn[
std::get<0>(hn)] = 1;
991 for (
const auto &a : locally_relevant_constraints)
992 if (is_constrained_hn[
std::get<0>(a)] == 0)
993 locally_relevant_constraints_tmp.push_back(a);
997 for (
const auto &hn : locally_relevant_constraints_hn)
998 if (constraint_position[
std::get<1>(hn)] !=
1002 locally_relevant_constraints.size());
1003 auto other = locally_relevant_constraints.begin() +
1004 constraint_position[std::get<1>(hn)];
1007 for (; other != locally_relevant_constraints.end() &&
1008 std::get<0>(*other) == std::get<1>(hn);
1010 locally_relevant_constraints_tmp.emplace_back(
1012 std::get<1>(*other),
1013 std::get<2>(hn) * std::get<2>(*other));
1016 std::swap(locally_relevant_constraints,
1017 locally_relevant_constraints_tmp);
1022 std::sort(locally_relevant_constraints.begin(),
1023 locally_relevant_constraints.end(),
1024 [](
const auto &a,
const auto &b) {
1025 if (std::get<1>(a) < std::get<1>(b))
1027 return (std::get<1>(a) == std::get<1>(b)) &&
1028 (std::get<0>(a) < std::get<0>(b));
1032 auto &c_pool = c_pools[v];
1034 c_pool.row_lid_to_gid.clear();
1036 c_pool.row.push_back(0);
1040 if (locally_relevant_constraints.size() > 0)
1041 c_pool.row_lid_to_gid.emplace_back(
1042 std::get<1>(locally_relevant_constraints.front()));
1043 for (
const auto &j : locally_relevant_constraints)
1045 if (c_pool.row_lid_to_gid.back() != std::get<1>(j))
1047 c_pool.row_lid_to_gid.push_back(std::get<1>(j));
1048 c_pool.row.push_back(c_pool.val.size());
1051 c_pool.col.emplace_back(std::get<0>(j));
1052 c_pool.val.emplace_back(std::get<2>(j));
1055 if (c_pool.val.size() > 0)
1056 c_pool.row.push_back(c_pool.val.size());
1058 c_pool.inverse_lookup_rows.clear();
1059 c_pool.inverse_lookup_rows.resize(1 + dofs_per_cell);
1060 for (
const unsigned int i : c_pool.col)
1061 c_pool.inverse_lookup_rows[1 + i]++;
1063 std::partial_sum(c_pool.inverse_lookup_rows.begin(),
1064 c_pool.inverse_lookup_rows.end(),
1065 c_pool.inverse_lookup_rows.begin());
1069 c_pool.inverse_lookup_origins.resize(c_pool.col.size());
1070 std::vector<unsigned int> inverse_lookup_count(dofs_per_cell);
1071 for (
unsigned int row = 0; row < c_pool.row.size() - 1; ++row)
1072 for (
unsigned int col = c_pool.row[row];
1073 col < c_pool.row[row + 1];
1076 const unsigned int index = c_pool.col[col];
1077 c_pool.inverse_lookup_origins
1078 [c_pool.inverse_lookup_rows[
index] +
1079 inverse_lookup_count[
index]] = std::make_pair(row, col);
1080 ++inverse_lookup_count[
index];
1109 for (
unsigned int v = 0; v < n_lanes_filled; ++v)
1110 diagonals_local_constrained[v].assign(
1111 c_pools[v].row_lid_to_gid.size() *
1112 (n_fe_components == 1 ? n_components : 1),
1116 bool use_fast_path =
true;
1118 for (
unsigned int v = 0; v < n_lanes_filled; ++v)
1120 auto &c_pool = c_pools[v];
1122 for (
unsigned int i = 0; i < c_pool.row.size() - 1; ++i)
1124 if ((c_pool.row[i + 1] - c_pool.row[i]) > 1)
1126 use_fast_path =
false;
1129 else if (((c_pool.row[i + 1] - c_pool.row[i]) == 1) &&
1130 (c_pool.val[c_pool.row[i]] != 1.0))
1132 use_fast_path =
false;
1137 if (use_fast_path ==
false)
1141 this->has_simple_constraints_ = use_fast_path;
1145 fill_constraint_type_into_map(
1146 const ::internal::MatrixFreeFunctions::compressed_constraint_kind
1149 auto &constraints_hn = locally_relevant_constraints_hn_map[
mask];
1154 const unsigned int degree =
1155 phi->get_shape_info().data.front().fe_degree;
1160 values_dofs.resize(dofs_per_component);
1163 VectorizedArrayType::size()>
1165 constraint_mask.fill(::internal::MatrixFreeFunctions::
1167 constraint_mask[0] =
mask;
1169 for (
unsigned int i = 0; i < dofs_per_component; ++i)
1171 for (
unsigned int j = 0; j < dofs_per_component; ++j)
1172 values_dofs[j] = VectorizedArrayType();
1173 values_dofs[i] = Number(1);
1178 VectorizedArrayType>::apply(1,
1180 phi->get_shape_info(),
1183 values_dofs.data());
1185 const Number tolerance =
1187 std::numeric_limits<Number>::epsilon() * 16);
1188 for (
unsigned int j = 0; j < dofs_per_component; ++j)
1189 if (
std::abs(values_dofs[j][0]) > tolerance &&
1191 std::abs(values_dofs[j][0] - Number(1)) > tolerance))
1192 constraints_hn.emplace_back(j, i, values_dofs[j][0]);
1196 const unsigned int n_hn_constraints = constraints_hn.size();
1197 constraints_hn.resize(n_hn_constraints * n_components);
1199 for (
unsigned int c = 1; c < n_components; ++c)
1200 for (
unsigned int i = 0; i < n_hn_constraints; ++i)
1201 constraints_hn[c * n_hn_constraints + i] = std::make_tuple(
1202 std::get<0>(constraints_hn[i]) + c * dofs_per_component,
1203 std::get<1>(constraints_hn[i]) + c * dofs_per_component,
1204 std::get<2>(constraints_hn[i]));
1208 prepare_basis_vector(
const unsigned int i)
1215 VectorizedArrayType *dof_values = phi->begin_dof_values();
1216 for (
unsigned int j = 0; j < dofs_per_cell; ++j)
1217 dof_values[j] = VectorizedArrayType();
1218 dof_values[i] = Number(1);
1224 VectorizedArrayType *dof_values = phi->begin_dof_values();
1225 for (
unsigned int j = 0; j < dofs_per_cell; ++j)
1226 dof_values[j] = VectorizedArrayType();
1235 const unsigned int n_fe_components =
1236 phi->get_dof_info().start_components.back();
1237 const unsigned int comp =
1238 n_fe_components == 1 ? i / dofs_per_component : 0;
1239 const unsigned int i_comp =
1240 n_fe_components == 1 ? (i % dofs_per_component) : i;
1244 for (
unsigned int v = 0; v < n_lanes_filled; ++v)
1246 const auto &c_pool = c_pools[v];
1248 for (
unsigned int jj = c_pool.inverse_lookup_rows[i_comp];
1249 jj < c_pool.inverse_lookup_rows[i_comp + 1];
1252 const unsigned int j = c_pool.inverse_lookup_origins[jj].first;
1255 for (
unsigned int k = c_pool.row[j]; k < c_pool.row[j + 1]; ++k)
1256 temp += c_pool.val[k] *
1257 phi->begin_dof_values()[comp * dofs_per_component +
1261 diagonals_local_constrained
1262 [v][j + comp * c_pools[v].row_lid_to_gid.size()] +=
1263 temp * c_pool.val[c_pool.inverse_lookup_origins[jj].second];
1268 template <
typename VectorType>
1270 distribute_local_to_global(std::vector<VectorType *> &diagonal_global)
1273 const unsigned int n_fe_components =
1274 phi->get_dof_info().start_components.back();
1276 if (n_fe_components == 1)
1279 for (
unsigned int v = 0; v < n_lanes_filled; ++v)
1283 for (
unsigned int j = 0; j < c_pools[v].row.size() - 1; ++j)
1284 for (
unsigned int comp = 0;
1285 comp < (n_fe_components == 1 ?
1286 static_cast<unsigned int>(n_components) :
1290 *diagonal_global[n_fe_components == 1 ? comp : 0],
1291 c_pools[v].row_lid_to_gid[j],
1292 diagonals_local_constrained
1293 [v][j + comp * c_pools[v].row_lid_to_gid.
size()]);
1297 has_simple_constraints()
const
1299 return has_simple_constraints_;
1303 FEEvaluationType *phi;
1306 unsigned int dofs_per_component;
1307 unsigned int dofs_per_cell;
1308 unsigned int n_components;
1312 unsigned int n_lanes_filled;
1314 std::array<internal::LocalCSR<Number>, n_lanes> c_pools;
1319 std::array<std::vector<Number>, n_lanes> diagonals_local_constrained;
1323 std::vector<std::tuple<unsigned int, unsigned int, Number>>>
1324 locally_relevant_constraints_hn_map;
1329 bool has_simple_constraints_;
1332 template <
bool is_face,
1335 typename VectorizedArrayType>
1339 const std::pair<unsigned int, unsigned int> &range,
1340 const unsigned int dof_no,
1341 const unsigned int quad_no,
1342 const unsigned int first_selected_component,
1343 const unsigned int fe_degree,
1344 const unsigned int n_q_points_1d,
1345 const bool is_interior_face =
true)
1347 const unsigned int static_n_q_points =
1351 unsigned int active_fe_index = 0;
1354 else if (is_interior_face)
1359 const auto init_data = ::internal::
1360 extract_initialization_data<is_face, dim, Number, VectorizedArrayType>(
1363 first_selected_component,
1371 return init_data.shape_info->dofs_per_component_on_cell == 0;
1381 typename QuadOperation>
1385 CellAction(
const QuadOperation &quad_operation,
1388 : m_quad_operation(quad_operation)
1389 , m_evaluation_flags(evaluation_flags)
1390 , m_integration_flags(integration_flags)
1393 KOKKOS_FUNCTION
void
1394 operator()(
const unsigned int cell,
1401 gpu_data, shared_data);
1402 m_quad_operation.set_matrix_free_data(*gpu_data);
1403 m_quad_operation.set_cell(cell);
1404 constexpr int dofs_per_cell =
decltype(fe_eval)::tensor_dofs_per_cell;
1405 Number
diagonal[dofs_per_cell] = {};
1406 for (
unsigned int i = 0; i < dofs_per_cell; ++i)
1408 Kokkos::parallel_for(
1409 Kokkos::TeamThreadRange(shared_data->
team_member, dofs_per_cell),
1410 [&](
int j) { fe_eval.submit_dof_value(i == j ? 1 : 0, j); });
1414 Portable::internal::
1415 resolve_hanging_nodes<dim, fe_degree, false, Number>(
1419 Kokkos::subview(shared_data->
values, Kokkos::ALL, 0));
1421 fe_eval.evaluate(m_evaluation_flags);
1422 fe_eval.apply_for_each_quad_point(m_quad_operation);
1423 fe_eval.integrate(m_integration_flags);
1425 Portable::internal::
1426 resolve_hanging_nodes<dim, fe_degree, true, Number>(
1430 Kokkos::subview(shared_data->
values, Kokkos::ALL, 0));
1432 Kokkos::single(Kokkos::PerTeam(shared_data->
team_member),
1433 [&] { diagonal[i] = fe_eval.get_dof_value(i); });
1438 Kokkos::single(Kokkos::PerTeam(shared_data->
team_member), [&] {
1439 for (unsigned int i = 0; i < dofs_per_cell; ++i)
1440 fe_eval.submit_dof_value(diagonal[i], i);
1449 Kokkos::parallel_for(Kokkos::TeamThreadRange(shared_data->
team_member,
1452 dst[gpu_data->local_to_global(cell, i)] +=
1453 shared_data->values(i, 0);
1458 Kokkos::parallel_for(
1459 Kokkos::TeamThreadRange(shared_data->
team_member, dofs_per_cell),
1461 Kokkos::atomic_add(&dst[gpu_data->local_to_global(cell, i)],
1462 shared_data->values(i, 0));
1467 static constexpr unsigned int n_local_dofs = QuadOperation::n_local_dofs;
1468 static constexpr unsigned int n_q_points = QuadOperation::n_q_points;
1471 mutable QuadOperation m_quad_operation;
1483 typename QuadOperation>
1488 const QuadOperation &quad_operation,
1491 const unsigned int dof_no,
1492 const unsigned int quad_no,
1493 const unsigned int first_selected_component,
1494 const unsigned int first_vector_component)
1504 CellAction<dim, fe_degree, n_q_points_1d, Number, QuadOperation>
1505 cell_action(quad_operation, evaluation_flags, integration_flags);
1507 matrix_free.
cell_loop(cell_action, dummy, diagonal_global);
1517 typename VectorizedArrayType,
1522 VectorType &diagonal_global,
1528 VectorizedArrayType> &)>
1530 const unsigned int dof_no,
1531 const unsigned int quad_no,
1532 const unsigned int first_selected_component,
1533 const unsigned int first_vector_component)
1540 VectorizedArrayType,
1548 first_selected_component,
1549 first_vector_component);
1552 template <
typename CLASS,
1558 typename VectorizedArrayType,
1563 VectorType &diagonal_global,
1569 VectorizedArrayType> &) const,
1570 const CLASS *owning_class,
1571 const unsigned
int dof_no,
1572 const unsigned
int quad_no,
1573 const unsigned
int first_selected_component,
1574 const unsigned
int first_vector_component)
1581 VectorizedArrayType,
1585 [&](
auto &phi) { (owning_class->*cell_operation)(phi); },
1588 first_selected_component,
1589 first_vector_component);
1597 typename VectorizedArrayType,
1602 VectorType &diagonal_global,
1608 VectorizedArrayType> &)>
1615 VectorizedArrayType> &,
1621 VectorizedArrayType> &)>
1628 VectorizedArrayType> &)>
1629 &boundary_operation,
1630 const unsigned int dof_no,
1631 const unsigned int quad_no,
1632 const unsigned int first_selected_component,
1633 const unsigned int first_vector_component)
1635 std::vector<typename ::internal::BlockVectorSelector<
1638 diagonal_global_components(n_components);
1640 for (
unsigned int d = 0;
d < n_components; ++
d)
1641 diagonal_global_components[d] = ::internal::
1643 get_vector_component(diagonal_global,
d + first_vector_component);
1645 const auto &dof_info = matrix_free.
get_dof_info(dof_no);
1647 if (dof_info.start_components.back() == 1)
1648 for (
unsigned int comp = 0; comp < n_components; ++comp)
1650 Assert(diagonal_global_components[comp] !=
nullptr,
1651 ExcMessage(
"The finite element underlying this FEEvaluation "
1652 "object is scalar, but you requested " +
1653 std::to_string(n_components) +
1654 " components via the template argument in "
1655 "FEEvaluation. In that case, you must pass an "
1656 "std::vector<VectorType> or a BlockVector to " +
1657 "read_dof_values and distribute_local_to_global."));
1659 *diagonal_global_components[comp], matrix_free, dof_info);
1664 *diagonal_global_components[0], matrix_free, dof_info);
1672 VectorizedArrayType>;
1679 VectorizedArrayType>;
1681 internal::ComputeMatrixScratchData<dim, VectorizedArrayType, false>
1684 data_cell.dof_numbers = {dof_no};
1685 data_cell.quad_numbers = {quad_no};
1686 data_cell.n_components = {n_components};
1687 data_cell.first_selected_components = {first_selected_component};
1688 data_cell.batch_type = {0};
1690 data_cell.op_create =
1691 [&](
const std::pair<unsigned int, unsigned int> &range) {
1693 std::unique_ptr<FEEvaluationData<dim, VectorizedArrayType, false>>>
1696 if (!internal::is_fe_nothing<false>(matrix_free,
1700 first_selected_component,
1703 phi.emplace_back(std::make_unique<FEEvalType>(
1704 matrix_free, range, dof_no, quad_no, first_selected_component));
1709 data_cell.op_reinit = [](
auto &phi,
const unsigned batch) {
1710 if (phi.size() == 1)
1711 static_cast<FEEvalType &
>(*phi[0]).reinit(batch);
1715 data_cell.op_compute = [&](
auto &phi) {
1716 cell_operation(
static_cast<FEEvalType &
>(*phi[0]));
1719 internal::ComputeMatrixScratchData<dim, VectorizedArrayType, true>
1722 data_face.dof_numbers = {dof_no, dof_no};
1723 data_face.quad_numbers = {quad_no, quad_no};
1724 data_face.n_components = {n_components, n_components};
1725 data_face.first_selected_components = {first_selected_component,
1726 first_selected_component};
1727 data_face.batch_type = {1, 2};
1729 data_face.op_create =
1730 [&](
const std::pair<unsigned int, unsigned int> &range) {
1732 std::unique_ptr<FEEvaluationData<dim, VectorizedArrayType, true>>>
1735 if (!internal::is_fe_nothing<true>(matrix_free,
1739 first_selected_component,
1743 !internal::is_fe_nothing<true>(matrix_free,
1747 first_selected_component,
1753 std::make_unique<FEFaceEvalType>(matrix_free,
1758 first_selected_component));
1760 std::make_unique<FEFaceEvalType>(matrix_free,
1765 first_selected_component));
1771 data_face.op_reinit = [](
auto &phi,
const unsigned batch) {
1772 if (phi.size() == 2)
1774 static_cast<FEFaceEvalType &
>(*phi[0]).
reinit(batch);
1775 static_cast<FEFaceEvalType &
>(*phi[1]).
reinit(batch);
1780 data_face.op_compute = [&](
auto &phi) {
1781 face_operation(
static_cast<FEFaceEvalType &
>(*phi[0]),
1782 static_cast<FEFaceEvalType &
>(*phi[1]));
1785 internal::ComputeMatrixScratchData<dim, VectorizedArrayType, true>
1788 data_boundary.dof_numbers = {dof_no};
1789 data_boundary.quad_numbers = {quad_no};
1790 data_boundary.n_components = {n_components};
1791 data_boundary.first_selected_components = {first_selected_component};
1792 data_boundary.batch_type = {1};
1795 .op_create = [&](
const std::pair<unsigned int, unsigned int> &range) {
1797 std::unique_ptr<FEEvaluationData<dim, VectorizedArrayType, true>>>
1800 if (!internal::is_fe_nothing<true>(matrix_free,
1804 first_selected_component,
1808 phi.emplace_back(std::make_unique<FEFaceEvalType>(
1809 matrix_free, range,
true, dof_no, quad_no, first_selected_component));
1814 data_boundary.op_reinit = [](
auto &phi,
const unsigned batch) {
1815 if (phi.size() == 1)
1816 static_cast<FEFaceEvalType &
>(*phi[0]).reinit(batch);
1819 if (boundary_operation)
1820 data_boundary.op_compute = [&](
auto &phi) {
1821 boundary_operation(
static_cast<FEFaceEvalType &
>(*phi[0]));
1829 diagonal_global_components);
1836 typename VectorizedArrayType,
1838 typename VectorType2>
1842 const internal::ComputeMatrixScratchData<dim, VectorizedArrayType, false>
1844 const internal::ComputeMatrixScratchData<dim, VectorizedArrayType, true>
1846 const internal::ComputeMatrixScratchData<dim, VectorizedArrayType, true>
1848 VectorType &diagonal_global,
1849 std::vector<VectorType2 *> &diagonal_global_components)
1856 internal::ComputeDiagonalHelper<dim, VectorizedArrayType, false>;
1859 internal::ComputeDiagonalHelper<dim, VectorizedArrayType, true>;
1863 scratch_data_internal;
1866 const auto batch_operation =
1869 const std::pair<unsigned int, unsigned int> &range) {
1870 if (!
data.op_compute)
1873 auto phi =
data.op_create(range);
1875 const unsigned int n_blocks = phi.size();
1877 auto &helpers = scratch_data.
get();
1878 helpers.resize(n_blocks);
1881 helpers[b].initialize(*phi[b], matrix_free,
data.n_components[b]);
1883 for (
unsigned int batch = range.first; batch < range.second; ++batch)
1885 data.op_reinit(phi, batch);
1888 helpers[b].
reinit(batch);
1892 Assert(std::all_of(helpers.begin(),
1894 [](
const auto &helper) {
1895 return helper.has_simple_constraints();
1902 for (
unsigned int i = 0;
1903 i < phi[
b]->get_shape_info().dofs_per_component_on_cell *
1904 data.n_components[b];
1907 for (
unsigned int bb = 0; bb <
n_blocks; ++bb)
1909 helpers[bb].prepare_basis_vector(i);
1911 helpers[bb].zero_basis_vector();
1913 data.op_compute(phi);
1914 helpers[
b].submit();
1917 helpers[
b].distribute_local_to_global(
1918 diagonal_global_components);
1923 const auto cell_operation_wrapped =
1924 [&](
const auto &,
auto &,
const auto &,
const auto range) {
1925 batch_operation(data_cell, scratch_data, range);
1928 const auto face_operation_wrapped =
1929 [&](
const auto &,
auto &,
const auto &,
const auto range) {
1930 batch_operation(data_face, scratch_data_internal, range);
1933 const auto boundary_operation_wrapped =
1934 [&](
const auto &,
auto &,
const auto &,
const auto range) {
1935 batch_operation(data_boundary, scratch_data_bc, range);
1938 if (data_face.op_compute || data_boundary.op_compute)
1939 matrix_free.template loop<VectorType, int>(cell_operation_wrapped,
1940 face_operation_wrapped,
1941 boundary_operation_wrapped,
1946 matrix_free.template cell_loop<VectorType, int>(cell_operation_wrapped,
1953 template <
typename CLASS,
1959 typename VectorizedArrayType,
1964 VectorType &diagonal_global,
1970 VectorizedArrayType> &) const,
1976 VectorizedArrayType> &,
1982 VectorizedArrayType> &)
1989 VectorizedArrayType> &)
1991 const CLASS *owning_class,
1992 const unsigned
int dof_no,
1993 const unsigned
int quad_no,
1994 const unsigned
int first_selected_component,
1995 const unsigned
int first_vector_component)
2002 VectorizedArrayType,
2006 [&](
auto &phi) { (owning_class->*cell_operation)(phi); },
2007 [&](
auto &phi_m,
auto &phi_p) {
2008 (owning_class->*face_operation)(phi_m, phi_p);
2010 [&](
auto &phi) { (owning_class->*boundary_operation)(phi); },
2013 first_selected_component,
2014 first_vector_component);
2026 std::enable_if_t<std::is_same_v<
2027 std::remove_const_t<
2028 std::remove_reference_t<typename MatrixType::value_type>>,
2029 std::remove_const_t<std::remove_reference_t<Number>>>> * =
nullptr>
2031 create_new_affine_constraints_if_needed(
2047 std::enable_if_t<!std::is_same_v<
2048 std::remove_const_t<
2049 std::remove_reference_t<typename MatrixType::value_type>>,
2050 std::remove_const_t<std::remove_reference_t<Number>>>> * =
nullptr>
2052 create_new_affine_constraints_if_needed(
2059 std::make_unique<AffineConstraints<typename MatrixType::value_type>>();
2060 new_constraints->
copy_from(constraints);
2062 return *new_constraints;
2071 typename VectorizedArrayType,
2083 VectorizedArrayType> &)>
2085 const unsigned int dof_no,
2086 const unsigned int quad_no,
2087 const unsigned int first_selected_component)
2094 VectorizedArrayType,
2103 first_selected_component);
2106 template <
typename CLASS,
2112 typename VectorizedArrayType,
2124 VectorizedArrayType> &) const,
2125 const CLASS *owning_class,
2126 const unsigned
int dof_no,
2127 const unsigned
int quad_no,
2128 const unsigned
int first_selected_component)
2135 VectorizedArrayType,
2140 [&](
auto &phi) { (owning_class->*cell_operation)(phi); },
2143 first_selected_component);
2151 typename VectorizedArrayType,
2163 VectorizedArrayType> &)>
2170 VectorizedArrayType> &,
2176 VectorizedArrayType> &)>
2183 VectorizedArrayType> &)>
2184 &boundary_operation,
2185 const unsigned int dof_no,
2186 const unsigned int quad_no,
2187 const unsigned int first_selected_component)
2194 VectorizedArrayType>;
2201 VectorizedArrayType>;
2203 internal::ComputeMatrixScratchData<dim, VectorizedArrayType, false>
2206 data_cell.dof_numbers = {dof_no};
2207 data_cell.quad_numbers = {quad_no};
2208 data_cell.n_components = {n_components};
2209 data_cell.first_selected_components = {first_selected_component};
2210 data_cell.batch_type = {0};
2212 data_cell.op_create =
2213 [&](
const std::pair<unsigned int, unsigned int> &range) {
2215 std::unique_ptr<FEEvaluationData<dim, VectorizedArrayType, false>>>
2218 if (!internal::is_fe_nothing<false>(matrix_free,
2222 first_selected_component,
2225 phi.emplace_back(std::make_unique<FEEvalType>(
2226 matrix_free, range, dof_no, quad_no, first_selected_component));
2231 data_cell.op_reinit = [](
auto &phi,
const unsigned batch) {
2232 if (phi.size() == 1)
2233 static_cast<FEEvalType &
>(*phi[0]).reinit(batch);
2237 data_cell.op_compute = [&](
auto &phi) {
2238 cell_operation(
static_cast<FEEvalType &
>(*phi[0]));
2241 internal::ComputeMatrixScratchData<dim, VectorizedArrayType, true>
2244 data_face.dof_numbers = {dof_no, dof_no};
2245 data_face.quad_numbers = {quad_no, quad_no};
2246 data_face.n_components = {n_components, n_components};
2247 data_face.first_selected_components = {first_selected_component,
2248 first_selected_component};
2249 data_face.batch_type = {1, 2};
2251 data_face.op_create =
2252 [&](
const std::pair<unsigned int, unsigned int> &range) {
2254 std::unique_ptr<FEEvaluationData<dim, VectorizedArrayType, true>>>
2257 if (!internal::is_fe_nothing<true>(matrix_free,
2261 first_selected_component,
2265 !internal::is_fe_nothing<true>(matrix_free,
2269 first_selected_component,
2275 std::make_unique<FEFaceEvalType>(matrix_free,
2280 first_selected_component));
2282 std::make_unique<FEFaceEvalType>(matrix_free,
2287 first_selected_component));
2293 data_face.op_reinit = [](
auto &phi,
const unsigned batch) {
2294 if (phi.size() == 2)
2296 static_cast<FEFaceEvalType &
>(*phi[0]).
reinit(batch);
2297 static_cast<FEFaceEvalType &
>(*phi[1]).
reinit(batch);
2302 data_face.op_compute = [&](
auto &phi) {
2303 face_operation(
static_cast<FEFaceEvalType &
>(*phi[0]),
2304 static_cast<FEFaceEvalType &
>(*phi[1]));
2307 internal::ComputeMatrixScratchData<dim, VectorizedArrayType, true>
2310 data_boundary.dof_numbers = {dof_no};
2311 data_boundary.quad_numbers = {quad_no};
2312 data_boundary.n_components = {n_components};
2313 data_boundary.first_selected_components = {first_selected_component};
2314 data_boundary.batch_type = {1};
2317 .op_create = [&](
const std::pair<unsigned int, unsigned int> &range) {
2319 std::unique_ptr<FEEvaluationData<dim, VectorizedArrayType, true>>>
2322 if (!internal::is_fe_nothing<true>(matrix_free,
2326 first_selected_component,
2330 phi.emplace_back(std::make_unique<FEFaceEvalType>(
2331 matrix_free, range,
true, dof_no, quad_no, first_selected_component));
2336 data_boundary.op_reinit = [](
auto &phi,
const unsigned batch) {
2337 if (phi.size() == 1)
2338 static_cast<FEFaceEvalType &
>(*phi[0]).reinit(batch);
2341 if (boundary_operation)
2342 data_boundary.op_compute = [&](
auto &phi) {
2343 boundary_operation(
static_cast<FEFaceEvalType &
>(*phi[0]));
2347 matrix_free, constraints_in, data_cell, data_face, data_boundary, matrix);
2354 typename VectorizedArrayType,
2360 const internal::ComputeMatrixScratchData<dim, VectorizedArrayType, false>
2362 const internal::ComputeMatrixScratchData<dim, VectorizedArrayType, true>
2364 const internal::ComputeMatrixScratchData<dim, VectorizedArrayType, true>
2368 std::unique_ptr<AffineConstraints<typename MatrixType::value_type>>
2369 constraints_for_matrix;
2371 internal::create_new_affine_constraints_if_needed(
2372 matrix, constraints_in, constraints_for_matrix);
2374 const auto batch_operation =
2375 [&matrix_free, &constraints, &
matrix](
2376 auto &
data,
const std::pair<unsigned int, unsigned int> &range) {
2377 if (!
data.op_compute)
2380 auto phi =
data.op_create(range);
2382 const unsigned int n_blocks = phi.size();
2391 n_blocks, VectorizedArrayType::size());
2394 std::array<FullMatrix<typename MatrixType::value_type>,
2395 VectorizedArrayType::size()>>
2396 matrices(n_blocks, n_blocks);
2401 .get_fe(phi[b]->get_active_fe_index());
2403 const auto component_base =
2406 const auto component_in_base =
2407 data.first_selected_components[
b] -
2412 data.dof_numbers[b],
2413 data.quad_numbers[b],
2415 phi[b]->get_active_fe_index(),
2416 phi[b]->get_active_quadrature_index());
2419 shape_info.dofs_per_component_on_cell *
data.n_components[
b];
2421 dof_indices[
b].resize(fe.n_dofs_per_cell());
2423 for (
unsigned int v = 0; v < VectorizedArrayType::size(); ++v)
2424 dof_indices_mf[b][v].resize(dofs_per_cell[b]);
2426 lexicographic_numbering[
b].insert(
2427 lexicographic_numbering[b].
begin(),
2428 shape_info.lexicographic_numbering.begin() +
2429 component_in_base * shape_info.dofs_per_component_on_cell,
2430 shape_info.lexicographic_numbering.begin() +
2431 (component_in_base +
data.n_components[
b]) *
2432 shape_info.dofs_per_component_on_cell);
2435 for (
unsigned int bj = 0; bj <
n_blocks; ++bj)
2436 for (
unsigned int bi = 0; bi <
n_blocks; ++bi)
2437 std::fill_n(matrices[bi][bj].
begin(),
2438 VectorizedArrayType::size(),
2440 dofs_per_cell[bi], dofs_per_cell[bj]));
2442 for (
auto batch = range.first; batch < range.second; ++batch)
2444 data.op_reinit(phi, batch);
2446 const unsigned int n_filled_lanes =
2451 for (
unsigned int v = 0; v < n_filled_lanes; ++v)
2455 (
data.batch_type[
b] == 0) ?
2456 (batch * VectorizedArrayType::size() + v) :
2457 ((
data.batch_type[
b] == 1) ?
2458 matrix_free.get_face_info(batch).cells_interior[v] :
2459 matrix_free.get_face_info(batch).cells_exterior[v]);
2464 data.dof_numbers[b]);
2468 cell_iterator->get_mg_dof_indices(dof_indices[b]);
2470 cell_iterator->get_dof_indices(dof_indices[b]);
2472 for (
unsigned int j = 0; j < dofs_per_cell[
b]; ++j)
2473 dof_indices_mf[b][v][j] =
2474 dof_indices[b][lexicographic_numbering[b][j]];
2477 for (
unsigned int bj = 0; bj <
n_blocks; ++bj)
2479 for (
unsigned int j = 0; j < dofs_per_cell[bj]; ++j)
2481 for (
unsigned int bi = 0; bi <
n_blocks; ++bi)
2482 for (
unsigned int i = 0; i < dofs_per_cell[bi]; ++i)
2483 phi[bi]->begin_dof_values()[i] =
2484 (bj == bi) ?
static_cast<Number
>(i == j) : 0.0;
2486 data.op_compute(phi);
2488 for (
unsigned int bi = 0; bi <
n_blocks; ++bi)
2489 for (
unsigned int i = 0; i < dofs_per_cell[bi]; ++i)
2490 for (
unsigned int v = 0; v < n_filled_lanes; ++v)
2491 matrices[bi][bj][v](i, j) =
2492 phi[bi]->begin_dof_values()[i][v];
2495 for (
unsigned int v = 0; v < n_filled_lanes; ++v)
2496 for (
unsigned int bi = 0; bi <
n_blocks; ++bi)
2504 matrices[bi][bi][v], dof_indices_mf[bi][v], matrix);
2507 matrices[bi][bj][v],
2508 dof_indices_mf[bi][v],
2509 dof_indices_mf[bj][v],
2515 const auto cell_operation_wrapped =
2516 [&](
const auto &,
auto &,
const auto &,
const auto range) {
2517 batch_operation(data_cell, range);
2520 const auto face_operation_wrapped =
2521 [&](
const auto &,
auto &,
const auto &,
const auto range) {
2522 batch_operation(data_face, range);
2525 const auto boundary_operation_wrapped =
2526 [&](
const auto &,
auto &,
const auto &,
const auto range) {
2527 batch_operation(data_boundary, range);
2530 if (data_face.op_compute || data_boundary.op_compute)
2532 matrix_free.template loop<MatrixType, MatrixType>(
2533 cell_operation_wrapped,
2534 face_operation_wrapped,
2535 boundary_operation_wrapped,
2540 matrix_free.template cell_loop<MatrixType, MatrixType>(
2541 cell_operation_wrapped, matrix, matrix);
2547 template <
typename CLASS,
2553 typename VectorizedArrayType,
2565 VectorizedArrayType> &) const,
2571 VectorizedArrayType> &,
2577 VectorizedArrayType> &)
2584 VectorizedArrayType> &)
2586 const CLASS *owning_class,
2587 const unsigned
int dof_no,
2588 const unsigned
int quad_no,
2589 const unsigned
int first_selected_component)
2596 VectorizedArrayType,
2601 [&](
auto &phi) { (owning_class->*cell_operation)(phi); },
2602 [&](
auto &phi_m,
auto &phi_p) {
2603 (owning_class->*face_operation)(phi_m, phi_p);
2605 [&](
auto &phi) { (owning_class->*boundary_operation)(phi); },
2608 first_selected_component);