37 template <
int dim,
typename Number,
bool is_face_>
49 std::function<std::vector<std::unique_ptr<FEEvalType>>(
50 const std::pair<unsigned int, unsigned int> &)>
52 std::function<void(std::vector<std::unique_ptr<FEEvalType>> &,
55 std::function<void(std::vector<std::unique_ptr<FEEvalType>> &)>
65 template <
int dim,
typename AdditionalData>
68 AdditionalData &additional_data);
85 typename VectorizedArrayType,
90 VectorType &diagonal_global,
96 VectorizedArrayType> &)>
98 const unsigned int dof_no = 0,
99 const unsigned int quad_no = 0,
100 const unsigned int first_selected_component = 0);
107 template <
typename CLASS,
113 typename VectorizedArrayType,
118 VectorType &diagonal_global,
124 VectorizedArrayType> &) const,
125 const CLASS *owning_class,
126 const unsigned
int dof_no = 0,
127 const unsigned
int quad_no = 0,
128 const unsigned
int first_selected_component = 0);
147 typename VectorizedArrayType,
152 VectorType &diagonal_global,
158 VectorizedArrayType> &)>
165 VectorizedArrayType> &,
171 VectorizedArrayType> &)>
178 VectorizedArrayType> &)>
180 const unsigned int dof_no = 0,
181 const unsigned int quad_no = 0,
182 const unsigned int first_selected_component = 0);
189 template <
typename CLASS,
195 typename VectorizedArrayType,
200 VectorType &diagonal_global,
206 VectorizedArrayType> &) const,
212 VectorizedArrayType> &,
218 VectorizedArrayType> &)
225 VectorizedArrayType> &)
227 const CLASS *owning_class,
228 const unsigned
int dof_no = 0,
229 const unsigned
int quad_no = 0,
230 const unsigned
int first_selected_component = 0);
247 typename VectorizedArrayType,
259 VectorizedArrayType> &)>
261 const unsigned int dof_no = 0,
262 const unsigned int quad_no = 0,
263 const unsigned int first_selected_component = 0);
270 template <
typename CLASS,
276 typename VectorizedArrayType,
288 VectorizedArrayType> &) const,
289 const CLASS *owning_class,
290 const unsigned
int dof_no = 0,
291 const unsigned
int quad_no = 0,
292 const unsigned
int first_selected_component = 0);
303 typename VectorizedArrayType,
334 typename VectorizedArrayType,
346 VectorizedArrayType> &)>
353 VectorizedArrayType> &,
359 VectorizedArrayType> &)>
366 VectorizedArrayType> &)>
368 const unsigned int dof_no = 0,
369 const unsigned int quad_no = 0,
370 const unsigned int first_selected_component = 0);
377 template <
typename CLASS,
383 typename VectorizedArrayType,
395 VectorizedArrayType> &) const,
401 VectorizedArrayType> &,
407 VectorizedArrayType> &)
414 VectorizedArrayType> &)
416 const CLASS *owning_class,
417 const unsigned
int dof_no = 0,
418 const unsigned
int quad_no = 0,
419 const unsigned
int first_selected_component = 0);
471 std::vector<unsigned int> valid_fe_indices;
473 const auto &fe_collection =
475 .get_fe_collection();
477 for (
unsigned int i = 0; i < fe_collection.size(); ++i)
478 if (fe_collection[i].n_dofs_per_cell() > 0)
479 valid_fe_indices.push_back(i);
493 template <
typename VectorTypeOut,
typename VectorTypeIn>
498 const VectorTypeIn &,
499 const std::pair<unsigned int, unsigned int> &)> &cell_operation,
501 const VectorTypeIn &src,
502 const bool zero_dst_vector =
false)
const
504 const auto ebd_cell_operation = [&](
const auto &
matrix_free,
508 const auto category =
matrix_free.get_cell_range_category(range);
517 ebd_cell_operation, dst, src, zero_dst_vector);
527 template <
typename VectorTypeOut,
typename VectorTypeIn>
532 const VectorTypeIn &,
533 const std::pair<unsigned int, unsigned int> &)> &cell_operation,
537 const VectorTypeIn &,
538 const std::pair<unsigned int, unsigned int> &)> &face_operation,
542 const VectorTypeIn &,
543 const std::pair<unsigned int, unsigned int> &,
544 const bool)> &boundary_operation,
546 const VectorTypeIn &src,
547 const bool zero_dst_vector =
false)
const
549 const auto ebd_cell_operation = [&](
const auto &
matrix_free,
553 const auto category =
matrix_free.get_cell_range_category(range);
561 const auto ebd_internal_or_boundary_face_operation =
566 const auto category =
matrix_free.get_face_range_category(range);
568 const unsigned int type =
584 ebd_internal_or_boundary_face_operation,
585 ebd_internal_or_boundary_face_operation,
608 template <
int dim,
typename AdditionalData>
611 AdditionalData &additional_data)
614 const unsigned int level = additional_data.mg_level;
619 additional_data.cell_vectorization_category.assign(
622 additional_data.cell_vectorization_category.assign(tria.
n_active_cells(),
629 std::sort(bids.begin(), bids.end());
632 unsigned int n_bids = bids.size() + 1;
634 for (
unsigned int i = 0; i < GeometryInfo<dim>::faces_per_cell;
635 i++, offset = offset * n_bids)
639 const auto to_category = [&](
const auto &cell) {
640 unsigned int c_num = 0;
641 for (
unsigned int i = 0; i < GeometryInfo<dim>::faces_per_cell; ++i)
643 const auto face = cell->face(i);
644 if (face->at_boundary() && !cell->has_periodic_neighbor(i))
646 factors[i] * (1 + std::distance(bids.begin(),
647 std::find(bids.begin(),
649 face->boundary_id())));
658 if (cell->is_locally_owned())
660 .cell_vectorization_category[cell->active_cell_index()] =
668 if (cell->is_locally_owned_on_level())
669 additional_data.cell_vectorization_category[cell->index()] =
675 additional_data.hold_all_faces_to_owned_cells =
true;
676 additional_data.cell_vectorization_categories_strict =
true;
677 additional_data.mapping_update_flags_faces_by_cells =
678 additional_data.mapping_update_flags_inner_faces |
679 additional_data.mapping_update_flags_boundary_faces;
684 template <
typename Number>
687 std::vector<unsigned int> row_lid_to_gid;
688 std::vector<unsigned int> row;
689 std::vector<unsigned int> col;
690 std::vector<Number> val;
692 std::vector<unsigned int> inverse_lookup_rows;
693 std::vector<std::pair<unsigned int, unsigned int>> inverse_lookup_origins;
696 template <
typename FEEvaluationType,
bool is_face>
697 class ComputeDiagonalHelper
700 using Number =
typename FEEvaluationType::number_type;
701 using VectorizedArrayType =
typename FEEvaluationType::NumberType;
703 static const unsigned int dim = FEEvaluationType::dimension;
704 static const unsigned int n_components = FEEvaluationType::n_components;
705 static const unsigned int n_lanes = VectorizedArrayType::size();
707 ComputeDiagonalHelper()
709 , dofs_per_component(0)
712 ComputeDiagonalHelper(
const ComputeDiagonalHelper &)
714 , dofs_per_component(0)
718 initialize(FEEvaluationType &phi)
722 if (dofs_per_component != phi.dofs_per_component)
724 locally_relevant_constraints_hn_map.clear();
725 dofs_per_component = phi.dofs_per_component;
731 reinit(
const unsigned int cell)
733 this->phi->reinit(cell);
736 const auto &dof_info = phi->get_dof_info();
737 const unsigned int n_fe_components = dof_info.start_components.back();
738 const auto &matrix_free = phi->get_matrix_free();
744 const unsigned int first_selected_component =
745 n_fe_components == 1 ? 0 : phi->get_first_selected_component();
747 this->n_lanes_filled =
756 std::vector<std::tuple<unsigned int, unsigned int, Number>>
757 locally_relevant_constraints, locally_relevant_constraints_tmp;
758 locally_relevant_constraints.reserve(phi->dofs_per_cell);
759 std::vector<unsigned int> constraint_position;
760 std::vector<unsigned char> is_constrained_hn;
762 const std::array<unsigned int, n_lanes> &cells =
763 this->phi->get_cell_ids();
765 for (
unsigned int v = 0; v < n_lanes_filled; ++v)
770 const unsigned int *dof_indices;
771 unsigned int index_indicators, next_index_indicators;
773 const unsigned int start =
774 cells[v] * n_fe_components + first_selected_component;
776 dof_info.dof_indices.data() + dof_info.row_starts[start].first;
777 index_indicators = dof_info.row_starts[start].second;
778 next_index_indicators = dof_info.row_starts[start + 1].second;
782 locally_relevant_constraints.clear();
784 if (n_components == 1 || n_fe_components == 1)
786 unsigned int ind_local = 0;
787 for (; index_indicators != next_index_indicators;
788 ++index_indicators, ++ind_local)
790 const std::pair<unsigned short, unsigned short> indicator =
791 dof_info.constraint_indicator[index_indicators];
793 for (
unsigned int j = 0; j < indicator.first;
795 locally_relevant_constraints.emplace_back(ind_local,
799 dof_indices += indicator.first;
801 const Number *data_val =
803 const Number *end_pool =
806 for (; data_val != end_pool; ++data_val, ++dof_indices)
807 locally_relevant_constraints.emplace_back(ind_local,
814 for (; ind_local < dofs_per_component;
815 ++dof_indices, ++ind_local)
816 locally_relevant_constraints.emplace_back(ind_local,
827 for (
unsigned int comp = 0; comp < n_components; ++comp)
829 unsigned int ind_local = 0;
833 for (; index_indicators != next_index_indicators;
834 ++index_indicators, ++ind_local)
836 const std::pair<unsigned short, unsigned short>
838 dof_info.constraint_indicator[index_indicators];
841 for (
unsigned int j = 0; j < indicator.first;
843 locally_relevant_constraints.emplace_back(
844 comp * dofs_per_component + ind_local,
847 dof_indices += indicator.first;
849 const Number *data_val =
851 const Number *end_pool =
854 for (; data_val != end_pool; ++data_val, ++dof_indices)
855 locally_relevant_constraints.emplace_back(
856 comp * dofs_per_component + ind_local,
864 for (; ind_local < dofs_per_component;
865 ++dof_indices, ++ind_local)
866 locally_relevant_constraints.emplace_back(
867 comp * dofs_per_component + ind_local,
871 if (comp + 1 < n_components)
872 next_index_indicators =
873 dof_info.row_starts[start + comp + 2].second;
880 for (
unsigned int i = 1; i < locally_relevant_constraints.size();
882 Assert(std::get<0>(locally_relevant_constraints[i]) >=
883 std::get<0>(locally_relevant_constraints[i - 1]),
887 if (dof_info.hanging_node_constraint_masks.size() > 0 &&
888 dof_info.hanging_node_constraint_masks_comp.size() > 0 &&
889 dof_info.hanging_node_constraint_masks_comp
890 [phi->get_active_fe_index()][first_selected_component])
893 dof_info.hanging_node_constraint_masks[cells[v]];
896 if (mask != ::internal::MatrixFreeFunctions::
901 if (locally_relevant_constraints_hn_map.find(mask) ==
902 locally_relevant_constraints_hn_map.end())
903 fill_constraint_type_into_map(mask);
905 const auto &locally_relevant_constraints_hn =
906 locally_relevant_constraints_hn_map[
mask];
908 locally_relevant_constraints_tmp.clear();
909 if (locally_relevant_constraints_tmp.capacity() <
910 locally_relevant_constraints.size())
911 locally_relevant_constraints_tmp.reserve(
912 locally_relevant_constraints.size() +
913 locally_relevant_constraints_hn.size());
918 constraint_position.assign(phi->dofs_per_cell,
920 for (
auto &a : locally_relevant_constraints)
921 if (constraint_position[
std::get<0>(a)] ==
923 constraint_position[
std::get<0>(a)] =
924 std::distance(locally_relevant_constraints.data(),
926 is_constrained_hn.assign(phi->dofs_per_cell,
false);
927 for (
auto &hn : locally_relevant_constraints_hn)
928 is_constrained_hn[
std::get<0>(hn)] = 1;
931 for (
const auto &a : locally_relevant_constraints)
932 if (is_constrained_hn[
std::get<0>(a)] == 0)
933 locally_relevant_constraints_tmp.push_back(a);
937 for (
const auto &hn : locally_relevant_constraints_hn)
938 if (constraint_position[
std::get<1>(hn)] !=
942 locally_relevant_constraints.size());
943 auto other = locally_relevant_constraints.begin() +
944 constraint_position[std::get<1>(hn)];
947 for (; other != locally_relevant_constraints.end() &&
948 std::get<0>(*other) == std::get<1>(hn);
950 locally_relevant_constraints_tmp.emplace_back(
953 std::get<2>(hn) * std::get<2>(*other));
956 std::swap(locally_relevant_constraints,
957 locally_relevant_constraints_tmp);
962 std::sort(locally_relevant_constraints.begin(),
963 locally_relevant_constraints.end(),
964 [](
const auto &a,
const auto &b) {
965 if (std::get<1>(a) < std::get<1>(b))
967 return (std::get<1>(a) == std::get<1>(b)) &&
968 (std::get<0>(a) < std::get<0>(b));
972 auto &c_pool = c_pools[v];
974 c_pool.row_lid_to_gid.clear();
976 c_pool.row.push_back(0);
980 if (locally_relevant_constraints.size() > 0)
981 c_pool.row_lid_to_gid.emplace_back(
982 std::get<1>(locally_relevant_constraints.front()));
983 for (
const auto &j : locally_relevant_constraints)
985 if (c_pool.row_lid_to_gid.back() != std::get<1>(j))
987 c_pool.row_lid_to_gid.push_back(std::get<1>(j));
988 c_pool.row.push_back(c_pool.val.size());
991 c_pool.col.emplace_back(std::get<0>(j));
992 c_pool.val.emplace_back(std::get<2>(j));
995 if (c_pool.val.size() > 0)
996 c_pool.row.push_back(c_pool.val.size());
998 c_pool.inverse_lookup_rows.clear();
999 c_pool.inverse_lookup_rows.resize(1 + phi->dofs_per_cell);
1000 for (
const unsigned int i : c_pool.col)
1001 c_pool.inverse_lookup_rows[1 + i]++;
1003 std::partial_sum(c_pool.inverse_lookup_rows.begin(),
1004 c_pool.inverse_lookup_rows.end(),
1005 c_pool.inverse_lookup_rows.begin());
1009 c_pool.inverse_lookup_origins.resize(c_pool.col.size());
1010 std::vector<unsigned int> inverse_lookup_count(
1011 phi->dofs_per_cell);
1012 for (
unsigned int row = 0; row < c_pool.row.size() - 1; ++row)
1013 for (
unsigned int col = c_pool.row[row];
1014 col < c_pool.row[row + 1];
1017 const unsigned int index = c_pool.col[col];
1018 c_pool.inverse_lookup_origins
1019 [c_pool.inverse_lookup_rows[
index] +
1020 inverse_lookup_count[
index]] = std::make_pair(row, col);
1021 ++inverse_lookup_count[
index];
1050 for (
unsigned int v = 0; v < n_lanes_filled; ++v)
1051 diagonals_local_constrained[v].assign(
1052 c_pools[v].row_lid_to_gid.size() *
1053 (n_fe_components == 1 ? n_components : 1),
1057 bool use_fast_path =
true;
1059 for (
unsigned int v = 0; v < n_lanes_filled; ++v)
1061 auto &c_pool = c_pools[v];
1063 for (
unsigned int i = 0; i < c_pool.row.size() - 1; ++i)
1065 if ((c_pool.row[i + 1] - c_pool.row[i]) > 1)
1067 use_fast_path =
false;
1070 else if (((c_pool.row[i + 1] - c_pool.row[i]) == 1) &&
1071 (c_pool.val[c_pool.row[i]] != 1.0))
1073 use_fast_path =
false;
1078 if (use_fast_path ==
false)
1084 temp_values.resize(phi->dofs_per_cell);
1089 temp_values.clear();
1094 fill_constraint_type_into_map(
1095 const ::internal::MatrixFreeFunctions::compressed_constraint_kind
1098 auto &constraints_hn = locally_relevant_constraints_hn_map[
mask];
1103 const unsigned int degree =
1104 phi->get_shape_info().data.front().fe_degree;
1109 values_dofs.resize(dofs_per_component);
1112 VectorizedArrayType::size()>
1114 constraint_mask.fill(::internal::MatrixFreeFunctions::
1116 constraint_mask[0] =
mask;
1118 for (
unsigned int i = 0; i < dofs_per_component; ++i)
1120 for (
unsigned int j = 0; j < dofs_per_component; ++j)
1121 values_dofs[j] = VectorizedArrayType();
1122 values_dofs[i] = Number(1);
1127 VectorizedArrayType>::apply(1,
1129 phi->get_shape_info(),
1132 values_dofs.data());
1134 const Number tolerance =
1136 std::numeric_limits<Number>::epsilon() * 16);
1137 for (
unsigned int j = 0; j < dofs_per_component; ++j)
1138 if (
std::abs(values_dofs[j][0]) > tolerance &&
1140 std::abs(values_dofs[j][0] - Number(1)) > tolerance))
1141 constraints_hn.emplace_back(j, i, values_dofs[j][0]);
1145 const unsigned int n_hn_constraints = constraints_hn.size();
1146 constraints_hn.resize(n_hn_constraints * n_components);
1148 for (
unsigned int c = 1; c < n_components; ++c)
1149 for (
unsigned int i = 0; i < n_hn_constraints; ++i)
1150 constraints_hn[c * n_hn_constraints + i] = std::make_tuple(
1151 std::get<0>(constraints_hn[i]) + c * dofs_per_component,
1152 std::get<1>(constraints_hn[i]) + c * dofs_per_component,
1153 std::get<2>(constraints_hn[i]));
1157 prepare_basis_vector(
const unsigned int i)
1164 VectorizedArrayType *dof_values = phi->begin_dof_values();
1165 for (
const unsigned int j : phi->dof_indices())
1166 dof_values[j] = VectorizedArrayType();
1167 dof_values[i] = Number(1);
1173 VectorizedArrayType *dof_values = phi->begin_dof_values();
1174 for (
const unsigned int j : phi->dof_indices())
1175 dof_values[j] = VectorizedArrayType();
1181 if (!temp_values.empty())
1183 temp_values[i] = phi->begin_dof_values()[i];
1190 const unsigned int n_fe_components =
1191 phi->get_dof_info().start_components.back();
1192 const unsigned int comp =
1193 n_fe_components == 1 ? i / dofs_per_component : 0;
1194 const unsigned int i_comp =
1195 n_fe_components == 1 ? (i % dofs_per_component) : i;
1199 for (
unsigned int v = 0; v < n_lanes_filled; ++v)
1201 const auto &c_pool = c_pools[v];
1203 for (
unsigned int jj = c_pool.inverse_lookup_rows[i_comp];
1204 jj < c_pool.inverse_lookup_rows[i_comp + 1];
1207 const unsigned int j = c_pool.inverse_lookup_origins[jj].first;
1210 for (
unsigned int k = c_pool.row[j]; k < c_pool.row[j + 1]; ++k)
1211 temp += c_pool.val[k] *
1212 phi->begin_dof_values()[comp * dofs_per_component +
1216 diagonals_local_constrained
1217 [v][j + comp * c_pools[v].row_lid_to_gid.size()] +=
1218 temp * c_pool.val[c_pool.inverse_lookup_origins[jj].second];
1223 template <
typename VectorType>
1225 distribute_local_to_global(
1226 std::array<VectorType *, n_components> &diagonal_global)
1228 if (!temp_values.empty())
1230 for (
unsigned int j = 0; j < temp_values.size(); ++j)
1231 phi->begin_dof_values()[j] = temp_values[j];
1233 phi->distribute_local_to_global(diagonal_global);
1239 const unsigned int n_fe_components =
1240 phi->get_dof_info().start_components.back();
1242 for (
unsigned int v = 0; v < n_lanes_filled; ++v)
1246 for (
unsigned int j = 0; j < c_pools[v].row.size() - 1; ++j)
1247 for (
unsigned int comp = 0;
1248 comp < (n_fe_components == 1 ?
1249 static_cast<unsigned int>(n_components) :
1253 *diagonal_global[n_fe_components == 1 ? comp : 0],
1254 c_pools[v].row_lid_to_gid[j],
1255 diagonals_local_constrained
1256 [v][j + comp * c_pools[v].row_lid_to_gid.size()]);
1260 use_fast_path()
const
1262 return !temp_values.empty();
1266 FEEvaluationType *phi;
1268 unsigned int dofs_per_component;
1272 unsigned int n_lanes_filled;
1274 std::array<internal::LocalCSR<Number>, n_lanes> c_pools;
1279 std::array<std::vector<Number>, n_lanes> diagonals_local_constrained;
1283 std::vector<std::tuple<unsigned int, unsigned int, Number>>>
1284 locally_relevant_constraints_hn_map;
1291 template <
bool is_face,
1294 typename VectorizedArrayType>
1298 const std::pair<unsigned int, unsigned int> &range,
1299 const unsigned int dof_no,
1300 const unsigned int quad_no,
1301 const unsigned int first_selected_component,
1302 const unsigned int fe_degree,
1303 const unsigned int n_q_points_1d,
1304 const bool is_interior_face =
true)
1306 const unsigned int static_n_q_points =
1310 unsigned int active_fe_index = 0;
1313 else if (is_interior_face)
1318 const auto init_data = ::internal::
1319 extract_initialization_data<is_face, dim, Number, VectorizedArrayType>(
1322 first_selected_component,
1330 return init_data.shape_info->dofs_per_component_on_cell == 0;
1340 typename VectorizedArrayType,
1341 typename VectorType>
1345 VectorType &diagonal_global,
1351 VectorizedArrayType> &)>
1353 const unsigned int dof_no,
1354 const unsigned int quad_no,
1355 const unsigned int first_selected_component)
1362 VectorizedArrayType,
1363 VectorType>(matrix_free,
1370 first_selected_component);
1373 template <
typename CLASS,
1379 typename VectorizedArrayType,
1380 typename VectorType>
1384 VectorType &diagonal_global,
1390 VectorizedArrayType> &) const,
1391 const CLASS *owning_class,
1392 const unsigned
int dof_no,
1393 const unsigned
int quad_no,
1394 const unsigned
int first_selected_component)
1401 VectorizedArrayType,
1405 [&](
auto &phi) { (owning_class->*cell_operation)(phi); },
1408 first_selected_component);
1416 typename VectorizedArrayType,
1417 typename VectorType>
1421 VectorType &diagonal_global,
1427 VectorizedArrayType> &)>
1434 VectorizedArrayType> &,
1440 VectorizedArrayType> &)>
1447 VectorizedArrayType> &)>
1448 &boundary_operation,
1449 const unsigned int dof_no,
1450 const unsigned int quad_no,
1451 const unsigned int first_selected_component)
1455 std::array<typename ::internal::BlockVectorSelector<
1459 diagonal_global_components;
1461 for (
unsigned int d = 0;
d < n_components; ++
d)
1462 diagonal_global_components[d] = ::internal::
1464 get_vector_component(diagonal_global,
d + first_selected_component);
1466 const auto &dof_info = matrix_free.
get_dof_info(dof_no);
1468 if (dof_info.start_components.back() == 1)
1469 for (
unsigned int comp = 0; comp < n_components; ++comp)
1471 Assert(diagonal_global_components[comp] !=
nullptr,
1472 ExcMessage(
"The finite element underlying this FEEvaluation "
1473 "object is scalar, but you requested " +
1474 std::to_string(n_components) +
1475 " components via the template argument in "
1476 "FEEvaluation. In that case, you must pass an "
1477 "std::vector<VectorType> or a BlockVector to " +
1478 "read_dof_values and distribute_local_to_global."));
1480 *diagonal_global_components[comp], matrix_free, dof_info);
1485 *diagonal_global_components[0], matrix_free, dof_info);
1494 VectorizedArrayType>,
1503 VectorizedArrayType>,
1510 const auto cell_operation_wrapped =
1514 const std::pair<unsigned int, unsigned int> &range) {
1515 if (!cell_operation)
1519 if (internal::is_fe_nothing<false>(matrix_free,
1523 first_selected_component,
1528 Helper &helper = scratch_data.
get();
1535 VectorizedArrayType>
1536 phi(matrix_free, range, dof_no, quad_no, first_selected_component);
1537 helper.initialize(phi);
1539 for (
unsigned int cell = range.first; cell < range.second; ++cell)
1541 helper.reinit(cell);
1543 for (
unsigned int i = 0; i < phi.dofs_per_cell; ++i)
1545 helper.prepare_basis_vector(i);
1546 cell_operation(phi);
1550 helper.distribute_local_to_global(diagonal_global_components);
1554 const auto face_operation_wrapped =
1558 const std::pair<unsigned int, unsigned int> &range) {
1559 if (!face_operation)
1563 if (internal::is_fe_nothing<true>(matrix_free,
1567 first_selected_component,
1571 internal::is_fe_nothing<true>(matrix_free,
1575 first_selected_component,
1581 HelperFace &helper_m = scratch_data_m.
get();
1582 HelperFace &helper_p = scratch_data_p.
get();
1589 VectorizedArrayType>
1595 first_selected_component);
1601 VectorizedArrayType>
1607 first_selected_component);
1609 helper_m.initialize(phi_m);
1610 helper_p.initialize(phi_p);
1612 for (
unsigned int face = range.first; face < range.second; ++face)
1614 helper_m.reinit(face);
1615 helper_p.reinit(face);
1618 Assert(helper_m.use_fast_path() && helper_p.use_fast_path(),
1621 for (
unsigned int i = 0; i < phi_m.dofs_per_cell; ++i)
1623 helper_m.prepare_basis_vector(i);
1624 helper_p.zero_basis_vector();
1625 face_operation(phi_m, phi_p);
1629 helper_m.distribute_local_to_global(diagonal_global_components);
1631 for (
unsigned int i = 0; i < phi_p.dofs_per_cell; ++i)
1633 helper_m.zero_basis_vector();
1634 helper_p.prepare_basis_vector(i);
1635 face_operation(phi_m, phi_p);
1639 helper_p.distribute_local_to_global(diagonal_global_components);
1643 const auto boundary_operation_wrapped =
1647 const std::pair<unsigned int, unsigned int> &range) {
1648 if (!boundary_operation)
1652 if (internal::is_fe_nothing<true>(matrix_free,
1656 first_selected_component,
1662 HelperFace &helper = scratch_data_m.
get();
1669 VectorizedArrayType>
1675 first_selected_component);
1676 helper.initialize(phi);
1678 for (
unsigned int face = range.first; face < range.second; ++face)
1680 helper.reinit(face);
1682 for (
unsigned int i = 0; i < phi.dofs_per_cell; ++i)
1684 helper.prepare_basis_vector(i);
1685 boundary_operation(phi);
1689 helper.distribute_local_to_global(diagonal_global_components);
1693 if (face_operation || boundary_operation)
1694 matrix_free.template loop<VectorType, int>(cell_operation_wrapped,
1695 face_operation_wrapped,
1696 boundary_operation_wrapped,
1701 matrix_free.template cell_loop<VectorType, int>(cell_operation_wrapped,
1707 template <
typename CLASS,
1713 typename VectorizedArrayType,
1714 typename VectorType>
1718 VectorType &diagonal_global,
1724 VectorizedArrayType> &) const,
1730 VectorizedArrayType> &,
1736 VectorizedArrayType> &)
1743 VectorizedArrayType> &)
1745 const CLASS *owning_class,
1746 const unsigned
int dof_no,
1747 const unsigned
int quad_no,
1748 const unsigned
int first_selected_component)
1755 VectorizedArrayType,
1759 [&](
auto &phi) { (owning_class->*cell_operation)(phi); },
1760 [&](
auto &phi_m,
auto &phi_p) {
1761 (owning_class->*face_operation)(phi_m, phi_p);
1763 [&](
auto &phi) { (owning_class->*boundary_operation)(phi); },
1766 first_selected_component);
1776 typename MatrixType,
1778 std::enable_if_t<std::is_same_v<
1779 std::remove_const_t<
1780 std::remove_reference_t<typename MatrixType::value_type>>,
1781 std::remove_const_t<std::remove_reference_t<Number>>>> * =
nullptr>
1783 create_new_affine_constraints_if_needed(
1797 typename MatrixType,
1799 std::enable_if_t<!std::is_same_v<
1800 std::remove_const_t<
1801 std::remove_reference_t<typename MatrixType::value_type>>,
1802 std::remove_const_t<std::remove_reference_t<Number>>>> * =
nullptr>
1804 create_new_affine_constraints_if_needed(
1811 std::make_unique<AffineConstraints<typename MatrixType::value_type>>();
1812 new_constraints->
copy_from(constraints);
1814 return *new_constraints;
1823 typename VectorizedArrayType,
1824 typename MatrixType>
1835 VectorizedArrayType> &)>
1837 const unsigned int dof_no,
1838 const unsigned int quad_no,
1839 const unsigned int first_selected_component)
1846 VectorizedArrayType,
1847 MatrixType>(matrix_free,
1855 first_selected_component);
1858 template <
typename CLASS,
1864 typename VectorizedArrayType,
1865 typename MatrixType>
1876 VectorizedArrayType> &) const,
1877 const CLASS *owning_class,
1878 const unsigned
int dof_no,
1879 const unsigned
int quad_no,
1880 const unsigned
int first_selected_component)
1887 VectorizedArrayType,
1892 [&](
auto &phi) { (owning_class->*cell_operation)(phi); },
1895 first_selected_component);
1903 typename VectorizedArrayType,
1904 typename MatrixType>
1915 VectorizedArrayType> &)>
1922 VectorizedArrayType> &,
1928 VectorizedArrayType> &)>
1935 VectorizedArrayType> &)>
1936 &boundary_operation,
1937 const unsigned int dof_no,
1938 const unsigned int quad_no,
1939 const unsigned int first_selected_component)
1946 VectorizedArrayType>;
1953 VectorizedArrayType>;
1955 internal::ComputeMatrixScratchData<dim, VectorizedArrayType, false>
1958 data_cell.dof_numbers = {dof_no};
1959 data_cell.quad_numbers = {quad_no};
1960 data_cell.first_selected_components = {first_selected_component};
1961 data_cell.batch_type = {0};
1963 data_cell.op_create =
1964 [&](
const std::pair<unsigned int, unsigned int> &range) {
1966 std::unique_ptr<FEEvaluationData<dim, VectorizedArrayType, false>>>
1969 if (!internal::is_fe_nothing<false>(matrix_free,
1973 first_selected_component,
1976 phi.emplace_back(std::make_unique<FEEvalType>(
1977 matrix_free, range, dof_no, quad_no, first_selected_component));
1982 data_cell.op_reinit = [](
auto &phi,
const unsigned batch) {
1983 static_cast<FEEvalType &
>(*phi[0]).
reinit(batch);
1987 data_cell.op_compute = [&](
auto &phi) {
1988 cell_operation(
static_cast<FEEvalType &
>(*phi[0]));
1991 internal::ComputeMatrixScratchData<dim, VectorizedArrayType, true>
1994 data_face.dof_numbers = {dof_no, dof_no};
1995 data_face.quad_numbers = {quad_no, quad_no};
1996 data_face.first_selected_components = {first_selected_component,
1997 first_selected_component};
1998 data_face.batch_type = {1, 2};
2000 data_face.op_create =
2001 [&](
const std::pair<unsigned int, unsigned int> &range) {
2003 std::unique_ptr<FEEvaluationData<dim, VectorizedArrayType, true>>>
2006 if (!internal::is_fe_nothing<true>(matrix_free,
2010 first_selected_component,
2014 !internal::is_fe_nothing<true>(matrix_free,
2018 first_selected_component,
2024 std::make_unique<FEFaceEvalType>(matrix_free,
2029 first_selected_component));
2031 std::make_unique<FEFaceEvalType>(matrix_free,
2036 first_selected_component));
2042 data_face.op_reinit = [](
auto &phi,
const unsigned batch) {
2043 static_cast<FEFaceEvalType &
>(*phi[0]).
reinit(batch);
2044 static_cast<FEFaceEvalType &
>(*phi[1]).
reinit(batch);
2048 data_face.op_compute = [&](
auto &phi) {
2049 face_operation(
static_cast<FEFaceEvalType &
>(*phi[0]),
2050 static_cast<FEFaceEvalType &
>(*phi[1]));
2053 internal::ComputeMatrixScratchData<dim, VectorizedArrayType, true>
2056 data_boundary.dof_numbers = {dof_no};
2057 data_boundary.quad_numbers = {quad_no};
2058 data_boundary.first_selected_components = {first_selected_component};
2059 data_boundary.batch_type = {1};
2062 .op_create = [&](
const std::pair<unsigned int, unsigned int> &range) {
2064 std::unique_ptr<FEEvaluationData<dim, VectorizedArrayType, true>>>
2067 if (!internal::is_fe_nothing<true>(matrix_free,
2071 first_selected_component,
2075 phi.emplace_back(std::make_unique<FEFaceEvalType>(
2076 matrix_free, range,
true, dof_no, quad_no, first_selected_component));
2081 data_boundary.op_reinit = [](
auto &phi,
const unsigned batch) {
2082 static_cast<FEFaceEvalType &
>(*phi[0]).
reinit(batch);
2085 if (boundary_operation)
2086 data_boundary.op_compute = [&](
auto &phi) {
2087 boundary_operation(
static_cast<FEFaceEvalType &
>(*phi[0]));
2091 matrix_free, constraints_in, data_cell, data_face, data_boundary, matrix);
2098 typename VectorizedArrayType,
2099 typename MatrixType>
2104 const internal::ComputeMatrixScratchData<dim, VectorizedArrayType, false>
2106 const internal::ComputeMatrixScratchData<dim, VectorizedArrayType, true>
2108 const internal::ComputeMatrixScratchData<dim, VectorizedArrayType, true>
2112 std::unique_ptr<AffineConstraints<typename MatrixType::value_type>>
2113 constraints_for_matrix;
2115 internal::create_new_affine_constraints_if_needed(
2116 matrix, constraints_in, constraints_for_matrix);
2118 const auto batch_operation =
2119 [&matrix_free, &constraints, &
matrix](
2120 auto &data,
const std::pair<unsigned int, unsigned int> &range) {
2121 if (!data.op_compute)
2124 auto phi = data.op_create(range);
2126 const unsigned int n_blocks = phi.size();
2135 n_blocks, VectorizedArrayType::size());
2138 std::array<FullMatrix<typename MatrixType::value_type>,
2139 VectorizedArrayType::size()>>
2140 matrices(n_blocks, n_blocks);
2145 data.dof_numbers[b],
2146 data.quad_numbers[b],
2147 data.first_selected_components[b],
2148 phi[b]->get_active_fe_index(),
2149 phi[b]->get_active_quadrature_index());
2152 shape_info.dofs_per_component_on_cell * shape_info.n_components;
2154 dof_indices[
b].resize(dofs_per_cell[b]);
2156 for (
unsigned int v = 0; v < VectorizedArrayType::size(); ++v)
2157 dof_indices_mf[b][v].resize(dofs_per_cell[b]);
2159 lexicographic_numbering[
b] = shape_info.lexicographic_numbering;
2162 for (
unsigned int bj = 0; bj <
n_blocks; ++bj)
2163 for (
unsigned int bi = 0; bi <
n_blocks; ++bi)
2164 std::fill_n(matrices[bi][bj].
begin(),
2165 VectorizedArrayType::size(),
2167 dofs_per_cell[bi], dofs_per_cell[bj]));
2169 for (
auto batch = range.first; batch < range.second; ++batch)
2171 data.op_reinit(phi, batch);
2173 const unsigned int n_filled_lanes =
2178 for (
unsigned int v = 0; v < n_filled_lanes; ++v)
2182 (data.batch_type[
b] == 0) ?
2183 (batch * VectorizedArrayType::size() + v) :
2184 ((data.batch_type[
b] == 1) ?
2185 matrix_free.get_face_info(batch).cells_interior[v] :
2186 matrix_free.get_face_info(batch).cells_exterior[v]);
2191 data.dof_numbers[b]);
2195 cell_iterator->get_mg_dof_indices(dof_indices[b]);
2197 cell_iterator->get_dof_indices(dof_indices[b]);
2199 for (
unsigned int j = 0; j < dof_indices[
b].size(); ++j)
2200 dof_indices_mf[b][v][j] =
2201 dof_indices[b][lexicographic_numbering[b][j]];
2204 for (
unsigned int bj = 0; bj <
n_blocks; ++bj)
2206 for (
unsigned int j = 0; j < dofs_per_cell[bj]; ++j)
2208 for (
unsigned int bi = 0; bi <
n_blocks; ++bi)
2209 for (
unsigned int i = 0; i < dofs_per_cell[bi]; ++i)
2210 phi[bi]->begin_dof_values()[i] =
2211 (bj == bi) ?
static_cast<Number
>(i == j) : 0.0;
2213 data.op_compute(phi);
2215 for (
unsigned int bi = 0; bi <
n_blocks; ++bi)
2216 for (
unsigned int i = 0; i < dofs_per_cell[bi]; ++i)
2217 for (
unsigned int v = 0; v < n_filled_lanes; ++v)
2218 matrices[bi][bj][v](i, j) =
2219 phi[bi]->begin_dof_values()[i][v];
2222 for (
unsigned int v = 0; v < n_filled_lanes; ++v)
2223 for (
unsigned int bi = 0; bi <
n_blocks; ++bi)
2231 matrices[bi][bi][v], dof_indices_mf[bi][v], matrix);
2234 matrices[bi][bj][v],
2235 dof_indices_mf[bi][v],
2236 dof_indices_mf[bj][v],
2242 const auto cell_operation_wrapped =
2243 [&](
const auto &,
auto &,
const auto &,
const auto range) {
2244 batch_operation(data_cell, range);
2247 const auto face_operation_wrapped =
2248 [&](
const auto &,
auto &,
const auto &,
const auto range) {
2249 batch_operation(data_face, range);
2252 const auto boundary_operation_wrapped =
2253 [&](
const auto &,
auto &,
const auto &,
const auto range) {
2254 batch_operation(data_boundary, range);
2257 if (data_face.op_compute || data_boundary.op_compute)
2259 matrix_free.template loop<MatrixType, MatrixType>(
2260 cell_operation_wrapped,
2261 face_operation_wrapped,
2262 boundary_operation_wrapped,
2267 matrix_free.template cell_loop<MatrixType, MatrixType>(
2268 cell_operation_wrapped, matrix, matrix);
2274 template <
typename CLASS,
2280 typename VectorizedArrayType,
2281 typename MatrixType>
2292 VectorizedArrayType> &) const,
2298 VectorizedArrayType> &,
2304 VectorizedArrayType> &)
2311 VectorizedArrayType> &)
2313 const CLASS *owning_class,
2314 const unsigned
int dof_no,
2315 const unsigned
int quad_no,
2316 const unsigned
int first_selected_component)
2323 VectorizedArrayType,
2328 [&](
auto &phi) { (owning_class->*cell_operation)(phi); },
2329 [&](
auto &phi_m,
auto &phi_p) {
2330 (owning_class->*face_operation)(phi_m, phi_p);
2332 [&](
auto &phi) { (owning_class->*boundary_operation)(phi); },
2335 first_selected_component);