deal.II version GIT relicensing-6834-g5b78e6bcdf 2026-10-01 11:20:01+00:00
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
Loading...
Searching...
No Matches
fe_remote_evaluation.h
Go to the documentation of this file.
1// -----------------------------------------------------------------------------
2//
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception OR LGPL-2.1-or-later
4// Copyright (C) 2023 - 2025 by the deal.II authors
5//
6// This file is part of the deal.II library.
7//
8// Detailed license information governing the source code and contributions
9// can be found in LICENSE.md and CONTRIBUTING.md at the top level directory.
10//
11// -----------------------------------------------------------------------------
12
13
14#ifndef dealii_matrix_free_fe_remote_evaluation_h
15#define dealii_matrix_free_fe_remote_evaluation_h
16
18
21
25
27
28#include <algorithm>
29#include <variant>
30
32
33namespace internal
34{
39 template <int dim, int n_components, typename value_type_>
41 {
42 using value_type = typename internal::FEPointEvaluation::
43 EvaluatorTypeTraits<dim, dim, n_components, value_type_>::value_type;
44
45 using gradient_type = typename internal::FEPointEvaluation::
46 EvaluatorTypeTraits<dim, dim, n_components, value_type_>::
47 real_gradient_type;
48
53
58 };
59
69 {
73 unsigned int
74 get_shift(const unsigned int index) const;
75
79 unsigned int
80 get_shift(const unsigned int cell_index,
81 const unsigned int face_number) const;
82
86 unsigned int
87 size() const;
88
92 unsigned int start = 0;
93
97 std::vector<unsigned int> ptrs_ptrs;
98
102 std::vector<unsigned int> ptrs;
103 };
104
110 template <int dim, int n_components, typename value_type_>
112 {
119
120 public:
127
134 const value_type
135 get_value(const unsigned int q) const;
136
143 const gradient_type
144 get_gradient(const unsigned int q) const;
145
154 void
155 reinit(const unsigned int index);
156
163 void
164 reinit(const unsigned int index_0, const unsigned int index_1);
165
166 private:
172
177
181 unsigned int data_offset;
182 };
183
184} // namespace internal
185
186
187
197template <int dim>
199{
203 std::shared_ptr<Utilities::MPI::RemotePointEvaluation<dim>> rpe;
204
209 std::vector<std::pair<unsigned int, unsigned int>> batch_id_n_entities;
210
216 std::vector<std::pair<unsigned int, unsigned int>>
218};
219
226template <int dim>
228{
232 std::shared_ptr<Utilities::MPI::RemotePointEvaluation<dim>> rpe;
233
237 std::vector<unsigned int> indices;
238
244 std::vector<unsigned int>
246};
247
254template <int dim>
256{
260 std::shared_ptr<Utilities::MPI::RemotePointEvaluation<dim>> rpe;
261
266 std::vector<
267 std::pair<typename Triangulation<dim>::cell_iterator, unsigned int>>
269
275 std::vector<
276 std::pair<typename Triangulation<dim>::cell_iterator, unsigned int>>
278};
279
283template <int dim>
285{
286public:
292 void
294 &comm_objects,
295 const std::pair<unsigned int, unsigned int> &face_batch_range,
296 const std::vector<unsigned int> &quadrature_sizes);
297
303 void
305 const std::vector<FERemoteCommunicationObject<dim>> &comm_objects,
306 const std::pair<unsigned int, unsigned int> &face_range,
307 const std::vector<unsigned int> &quadrature_sizes);
308
315 template <typename Iterator>
316 void
318 const std::vector<FERemoteCommunicationObjectTwoLevel<dim>> &comm_objects,
319 const IteratorRange<Iterator> &cell_iterator_range,
320 const std::vector<std::vector<unsigned int>> &quadrature_sizes);
321
322
323
327 template <int n_components,
328 typename PrecomputedEvaluationDataType,
329 typename MeshType,
330 typename VectorType>
331 void
333 PrecomputedEvaluationDataType &dst,
334 const MeshType &mesh,
335 const VectorType &src,
336 const EvaluationFlags::EvaluationFlags eval_flags,
337 const unsigned int first_selected_component,
339
344 get_view() const;
345
346private:
352
356 std::vector<std::variant<FERemoteCommunicationObjectEntityBatches<dim>,
360
366 {
367 public:
372 template <typename T1, typename T2>
373 static void
376 const std::vector<T2> &src,
377 const std::vector<unsigned int> &indices);
378
383 template <typename T1, typename T2>
384 static void
385 copy_data(
388 const std::vector<T2> &src,
389 const std::vector<std::pair<typename Triangulation<dim>::cell_iterator,
390 unsigned int>> &cell_face_nos);
391
396 template <typename T1, typename T2>
397 static void
400 const std::vector<T2> &src,
401 const std::vector<std::pair<unsigned int, unsigned int>>
402 &batch_id_n_entities);
403
404 private:
408 template <typename T1, std::size_t n_lanes>
409 static void
411 const unsigned int v,
412 const T1 &src);
413
417 template <typename T1, int rank_, std::size_t n_lanes, int dim_>
418 static void
420 const unsigned int v,
421 const Tensor<rank_, dim_, T1> &src);
422
426 template <typename T1,
427 int rank_,
428 std::size_t n_lanes,
429 int n_components_,
430 int dim_>
431 static void
433 Tensor<rank_,
434 n_components_,
435 Tensor<rank_, dim_, VectorizedArray<T1, n_lanes>>> &dst,
436 const unsigned int v,
437 const Tensor<rank_, n_components_, Tensor<rank_, dim_, T1>> &src);
438
443 template <typename T1, typename T2>
444 static void
445 copy_data_entries(T1 &, const unsigned int, const T2 &);
446 };
447};
448
449
450
455namespace Utilities
456{
474 template <int dim,
475 typename Number,
476 typename VectorizedArrayType = VectorizedArray<Number>>
480 const std::vector<
481 std::pair<types::boundary_id, std::function<std::vector<bool>()>>>
482 &non_matching_faces_marked_vertices,
483 const unsigned int quadrature_index = 0,
484 const unsigned int dof_handler_index = 0,
485 const double tolerance = 1e-9);
486
487
488
507 template <int dim,
508 typename Number,
509 typename VectorizedArrayType = VectorizedArray<Number>>
513 const std::vector<
514 std::pair<types::boundary_id, std::function<std::vector<bool>()>>>
515 &non_matching_faces_marked_vertices,
516 const unsigned int n_q_pnts_1D,
517 const unsigned int dof_handler_index = 0,
518 NonMatching::MappingInfo<dim, dim, Number> *nm_mapping_info = nullptr,
519 const double tolerance = 1e-9);
520} // namespace Utilities
521
522
523
535template <int dim, int n_components, typename value_type>
632
633
634
635namespace internal
636{
637 unsigned int
639 {
640 Assert(ptrs_ptrs.size() == 0, ExcMessage("Two level CRS set up"));
641
643 ExcMessage("Index has to be valid!"));
644
646 AssertIndexRange(index - start, ptrs.size());
647 return ptrs[index - start];
648 }
649
650 unsigned int
652 const unsigned int face_number) const
653 {
654 Assert(ptrs_ptrs.size() > 0, ExcMessage("No two level CRS set up"));
655
657 ExcMessage("Cell index has to be valid!"));
659 ExcMessage("Face number has to be valid!"));
660
662
664 const unsigned int face_index = ptrs_ptrs[cell_index - start] + face_number;
665 AssertIndexRange(face_index, ptrs.size());
666 return ptrs[face_index];
667 }
668
669 unsigned int
671 {
672 Assert(ptrs.size() > 0, ExcInternalError());
673 return ptrs.back();
674 }
675
676 template <int dim, int n_components, typename value_type_>
685
686 template <int dim, int n_components, typename value_type_>
687 const typename PrecomputedEvaluationData<dim,
688 n_components,
689 value_type_>::value_type
691 const unsigned int q) const
692 {
694 ExcMessage("reinit() not called."));
695 AssertIndexRange(data_offset + q, data.values.size());
696 return data.values[data_offset + q];
697 }
698
699 template <int dim, int n_components, typename value_type_>
701 gradient_type
703 get_gradient(const unsigned int q) const
704 {
706 ExcMessage("reinit() not called."));
707 AssertIndexRange(data_offset + q, data.gradients.size());
708 return data.gradients[data_offset + q];
709 }
710
711 template <int dim, int n_components, typename value_type_>
712 void
714 const unsigned int index)
715 {
716 data_offset = view.get_shift(index);
717 }
718
719 template <int dim, int n_components, typename value_type_>
720 void
722 const unsigned int index_0,
723 const unsigned int index_1)
724 {
725 data_offset = view.get_shift(index_0, index_1);
726 }
727
728} // namespace internal
729
730
731
732template <int dim>
733std::vector<std::pair<unsigned int, unsigned int>>
735 const
736{
737 return batch_id_n_entities;
738}
739
740template <int dim>
741std::vector<unsigned int>
746
747template <int dim>
748std::vector<std::pair<typename Triangulation<dim>::cell_iterator, unsigned int>>
753
754
755
756template <int dim>
757void
760 &comm_objects,
761 const std::pair<unsigned int, unsigned int> &face_batch_range,
762 const std::vector<unsigned int> &quadrature_sizes)
763{
764 // erase type by converting to the base object
765 communication_objects.clear();
766 for (const auto &co : comm_objects)
767 communication_objects.push_back(co);
768
769 // fetch points and update communication patterns
770 const unsigned int n_cells = quadrature_sizes.size();
771 AssertDimension(n_cells, face_batch_range.second - face_batch_range.first);
772
773 // construct view:
774 view.start = face_batch_range.first;
775
776 view.ptrs.resize(n_cells + 1);
777
778 view.ptrs[0] = 0;
779 for (unsigned int face = 0; face < n_cells; ++face)
780 {
781 view.ptrs[face + 1] = view.ptrs[face] + quadrature_sizes[face];
782 }
783}
784
785template <int dim>
786void
788 const std::vector<FERemoteCommunicationObject<dim>> &comm_objects,
789 const std::pair<unsigned int, unsigned int> &face_range,
790 const std::vector<unsigned int> &quadrature_sizes)
791{
792 // erase type
793 communication_objects.clear();
794 for (const auto &co : comm_objects)
795 communication_objects.push_back(co);
796
797 const unsigned int n_faces = quadrature_sizes.size();
798 AssertDimension(n_faces, face_range.second - face_range.first);
799
800 // construct view:
801 view.start = face_range.first;
802
803 view.ptrs.resize(n_faces + 1);
804
805 view.ptrs[0] = 0;
806 for (unsigned int face = 0; face < n_faces; ++face)
807 view.ptrs[face + 1] = view.ptrs[face] + quadrature_sizes[face];
808}
809
810template <int dim>
811template <typename Iterator>
812void
814 const std::vector<FERemoteCommunicationObjectTwoLevel<dim>> &comm_objects,
815 const IteratorRange<Iterator> &cell_iterator_range,
816 const std::vector<std::vector<unsigned int>> &quadrature_sizes)
817{
818 // erase type
819 communication_objects.clear();
820 for (const auto &co : comm_objects)
821 communication_objects.push_back(co);
822
823 const unsigned int n_cells = quadrature_sizes.size();
824 AssertDimension(n_cells,
825 std::distance(cell_iterator_range.begin(),
826 cell_iterator_range.end()));
827
828 // construct view:
829 auto &cell_ptrs = view.ptrs_ptrs;
830 auto &face_ptrs = view.ptrs;
831
832 view.start = 0;
833 cell_ptrs.resize(n_cells);
834 unsigned int n_faces = 0;
835 for (const auto &cell : cell_iterator_range)
836 {
837 cell_ptrs[cell->active_cell_index()] = n_faces;
838 n_faces += cell->n_faces();
839 }
840
841 face_ptrs.resize(n_faces + 1);
842 face_ptrs[0] = 0;
843 for (const auto &cell : cell_iterator_range)
844 {
845 for (const auto &f : cell->face_indices())
846 {
847 const unsigned int face_index =
848 cell_ptrs[cell->active_cell_index()] + f;
849
850 face_ptrs[face_index + 1] =
851 face_ptrs[face_index] +
852 quadrature_sizes[cell->active_cell_index()][f];
853 }
854 }
855}
856
857template <int dim>
858template <int n_components,
859 typename PrecomputedEvaluationDataType,
860 typename MeshType,
861 typename VectorType>
862void
864 PrecomputedEvaluationDataType &dst,
865 const MeshType &mesh,
866 const VectorType &src,
867 const EvaluationFlags::EvaluationFlags eval_flags,
868 const unsigned int first_selected_component,
870{
871 const bool has_ghost_elements = src.has_ghost_elements();
872
873 if (has_ghost_elements == false)
874 src.update_ghost_values();
875
876
877 for (const auto &communication_object : communication_objects)
878 {
879 if (eval_flags & EvaluationFlags::values)
880 {
881 std::visit(
882 [&](const auto &obj) {
883 CopyInstructions::copy_data(
884 view,
885 dst.values,
886 VectorTools::point_values<n_components>(
887 *obj.rpe, mesh, src, vec_flags, first_selected_component),
888 obj.get_communication_object_pntrs());
889 },
890 communication_object);
891 }
892
893 if (eval_flags & EvaluationFlags::gradients)
894 {
895 std::visit(
896 [&](const auto &obj) {
897 CopyInstructions::copy_data(
898 view,
899 dst.gradients,
900 VectorTools::point_gradients<n_components>(
901 *obj.rpe, mesh, src, vec_flags, first_selected_component),
902 obj.get_communication_object_pntrs());
903 },
904 communication_object);
905 }
906
908 }
909
910 if (has_ghost_elements == false)
911 src.zero_out_ghost_values();
912}
913
914template <int dim>
917{
918 return view;
919}
920
921template <int dim>
922template <typename T1, typename T2>
923void
927 const std::vector<T2> &src,
928 const std::vector<unsigned int> &indices)
929{
930 dst.resize(view.size());
931
932 unsigned int c = 0;
933 for (const auto idx : indices)
934 {
935 for (unsigned int j = view.get_shift(idx); j < view.get_shift(idx + 1);
936 ++j, ++c)
937 {
938 AssertIndexRange(j, dst.size());
939 AssertIndexRange(c, src.size());
940 dst[j] = src[c];
941 }
942 }
943}
944
945template <int dim>
946template <typename T1, typename T2>
947void
951 const std::vector<T2> &src,
952 const std::vector<std::pair<typename Triangulation<dim>::cell_iterator,
953 unsigned int>> &cell_face_nos)
954{
955 dst.resize(view.size());
956
957 unsigned int c = 0;
958 for (const auto &[cell, f] : cell_face_nos)
959 {
960 for (unsigned int j = view.get_shift(cell->active_cell_index(), f);
961 j < view.get_shift(cell->active_cell_index(), f + 1);
962 ++j, ++c)
963 {
964 AssertIndexRange(j, dst.size());
965 AssertIndexRange(c, src.size());
966
967 dst[j] = src[c];
968 }
969 }
970}
971
972template <int dim>
973template <typename T1, typename T2>
974void
978 const std::vector<T2> &src,
979 const std::vector<std::pair<unsigned int, unsigned int>> &batch_id_n_entities)
980{
981 dst.resize(view.size());
982
983 unsigned int c = 0;
984 for (const auto &[batch_id, n_entries] : batch_id_n_entities)
985 {
986 for (unsigned int v = 0; v < n_entries; ++v)
987 for (unsigned int j = view.get_shift(batch_id);
988 j < view.get_shift(batch_id + 1);
989 ++j, ++c)
990 {
991 AssertIndexRange(j, dst.size());
992 AssertIndexRange(c, src.size());
993
994 copy_data_entries(dst[j], v, src[c]);
995 }
996 }
997}
998
999template <int dim>
1000template <typename T1, std::size_t n_lanes>
1001void
1004 const unsigned int v,
1005 const T1 &src)
1006{
1007 AssertIndexRange(v, n_lanes);
1008
1009 dst[v] = src;
1010}
1011
1012template <int dim>
1013template <typename T1, int rank_, std::size_t n_lanes, int dim_>
1014void
1016 Tensor<rank_, dim_, VectorizedArray<T1, n_lanes>> &dst,
1017 const unsigned int v,
1018 const Tensor<rank_, dim_, T1> &src)
1019{
1020 AssertIndexRange(v, n_lanes);
1021
1022 if constexpr (rank_ == 1)
1023 {
1024 for (unsigned int i = 0; i < dim_; ++i)
1025 dst[i][v] = src[i];
1026 }
1027 else
1028 {
1029 for (unsigned int i = 0; i < rank_; ++i)
1030 for (unsigned int j = 0; j < dim_; ++j)
1031 dst[i][j][v] = src[i][j];
1032 }
1033}
1034
1035template <int dim>
1036template <typename T1,
1037 int rank_,
1038 std::size_t n_lanes,
1039 int n_components_,
1040 int dim_>
1041void
1043 Tensor<rank_,
1044 n_components_,
1045 Tensor<rank_, dim_, VectorizedArray<T1, n_lanes>>> &dst,
1046 const unsigned int v,
1047 const Tensor<rank_, n_components_, Tensor<rank_, dim_, T1>> &src)
1048{
1049 if constexpr (rank_ == 1)
1050 {
1051 for (unsigned int i = 0; i < n_components_; ++i)
1052 copy_data(dst[i], v, src[i]);
1053 }
1054 else
1055 {
1056 for (unsigned int i = 0; i < rank_; ++i)
1057 for (unsigned int j = 0; j < n_components_; ++j)
1058 dst[i][j][v] = src[i][j];
1059 }
1060}
1061
1062template <int dim>
1063template <typename T1, typename T2>
1064void
1066 T1 &,
1067 const unsigned int,
1068 const T2 &)
1069{
1070 Assert(false,
1071 ExcMessage(
1072 "copy_data_entries() not implemented for given arguments."));
1073}
1074
1075
1076
1077namespace Utilities
1078{
1079 template <int dim, typename Number, typename VectorizedArrayType>
1083 const std::vector<
1084 std::pair<types::boundary_id, std::function<std::vector<bool>()>>>
1085 &non_matching_faces_marked_vertices,
1086 const unsigned int quadrature_index,
1087 const unsigned int dof_handler_index,
1088 const double tolerance)
1089 {
1090 const auto &dof_handler = matrix_free.get_dof_handler(dof_handler_index);
1091 const auto &tria = dof_handler.get_triangulation();
1092 const auto &mapping = *matrix_free.get_mapping_info().mapping;
1093
1094 // Communication objects know about the communication pattern. I.e.,
1095 // they know about the cells and quadrature points that have to be
1096 // evaluated at remote faces. This information is given via
1097 // RemotePointEvaluation. Additionally, the communication objects
1098 // have to be able to match the quadrature points of the remote
1099 // points (that provide exterior information) to the quadrature points
1100 // defined at the interior cell. In case of point-to-point interpolation
1101 // a vector of pairs with face batch Ids and the number of faces in the
1102 // batch is needed. @c FERemoteCommunicationObjectEntityBatches
1103 // is a container to store this information.
1104 //
1105 // We need multiple communication objects (one for each non-matching face
1106 // ID).
1107 std::vector<FERemoteCommunicationObjectEntityBatches<dim>> comm_objects;
1108
1109 // Additionally to the communication objects we need a vector
1110 // that stores quadrature rule sizes for every face batch.
1111 // The quadrature can have size zero in case of non non-matching faces,
1112 // i.e. boundary faces. Internally this information is needed to correctly
1113 // access values over multiple communication objects.
1114 std::vector<unsigned int> global_quadrature_sizes(
1116
1117 // Get the range of face batches we have to look at during construction of
1118 // the communication objects. We only have to look at boundary faces.
1119 const auto face_batch_range =
1120 std::make_pair(matrix_free.n_inner_face_batches(),
1121 matrix_free.n_inner_face_batches() +
1122 matrix_free.n_boundary_face_batches());
1123
1124 // Iterate over all non-matching face IDs.
1125 for (const auto &[nm_face, marked_vertices] :
1126 non_matching_faces_marked_vertices)
1127 {
1128 // Construct the communication object for every face ID:
1129 // 1) RemotePointEvaluation with user specified function for marked
1130 // vertices.
1131 auto rpe = std::make_shared<Utilities::MPI::RemotePointEvaluation<dim>>(
1132 tolerance, false, 0, marked_vertices);
1133
1134 // 2) Face batch IDs and number of faces in batch.
1135 std::vector<std::pair<unsigned int, unsigned int>>
1136 face_batch_id_n_faces;
1137
1138 // Points that are searched by rpe.
1139 std::vector<Point<dim>> points;
1140
1141 // Temporarily set up FEFaceEvaluation to access the quadrature points
1142 // at the faces on the non-matching interface.
1143 FEFaceEvaluation<dim, -1, 0, 1, Number> phi(matrix_free,
1144 true,
1145 dof_handler_index,
1146 quadrature_index);
1147
1148 // Iterate over the boundary faces.
1149 for (unsigned int bface = 0;
1150 bface < face_batch_range.second - face_batch_range.first;
1151 ++bface)
1152 {
1153 const unsigned int face = face_batch_range.first + bface;
1154
1155 if (matrix_free.get_boundary_id(face) == nm_face)
1156 {
1157 phi.reinit(face);
1158
1159 // If @c face is on the current side of the non-matching
1160 // interface. Add the face batch ID and the number of faces in
1161 // the batch to the corresponding data structure.
1162 const unsigned int n_faces =
1163 matrix_free.n_active_entries_per_face_batch(face);
1164 face_batch_id_n_faces.emplace_back(face, n_faces);
1165
1166 // Append the quadrature points to the points we need to search
1167 // for.
1168 for (unsigned int v = 0; v < n_faces; ++v)
1169 {
1170 for (unsigned int q : phi.quadrature_point_indices())
1171 {
1172 const auto point = phi.quadrature_point(q);
1173 Point<dim> temp;
1174 for (unsigned int i = 0; i < dim; ++i)
1175 temp[i] = point[i][v];
1176
1177 points.push_back(temp);
1178 }
1179 }
1180
1181 // Insert the quadrature size into the global vector.
1182 // First check that each face is only considered once.
1183 Assert(global_quadrature_sizes[bface] ==
1185 ExcMessage(
1186 "Quadrature for given face already provided."));
1187
1188 global_quadrature_sizes[bface] = phi.n_q_points;
1189 }
1190 }
1191
1192 // Reinit RPE and ensure all points are found.
1193 rpe->reinit(points, tria, mapping);
1194 Assert(rpe->all_points_found(),
1195 ExcMessage("Not all remote points found."));
1196
1197 // Add communication object to the list of objects.
1199 co.batch_id_n_entities = face_batch_id_n_faces;
1200 co.rpe = rpe;
1201 comm_objects.push_back(co);
1202 }
1203
1204 // Reinit the communicator `FERemoteEvaluationCommunicator`
1205 // with the communication objects.
1206 FERemoteEvaluationCommunicator<dim> remote_communicator;
1207
1208 // if no quadrature size is set, an empty quadrature is considered
1209 std::replace(global_quadrature_sizes.begin(),
1210 global_quadrature_sizes.end(),
1212 0u);
1213
1214 remote_communicator.reinit_faces(comm_objects,
1215 face_batch_range,
1216 global_quadrature_sizes);
1217
1218 return remote_communicator;
1219 }
1220
1221
1222
1223 template <int dim, typename Number, typename VectorizedArrayType>
1227 const std::vector<
1228 std::pair<types::boundary_id, std::function<std::vector<bool>()>>>
1229 &non_matching_faces_marked_vertices,
1230 const unsigned int n_q_pnts_1D,
1231 const unsigned int dof_handler_index,
1233 const double tolerance)
1234 {
1235 const auto &dof_handler = matrix_free.get_dof_handler(dof_handler_index);
1236 const auto &tria = dof_handler.get_triangulation();
1237 const auto &mapping = *matrix_free.get_mapping_info().mapping;
1238
1239 constexpr unsigned int n_lanes = VectorizedArray<Number>::size();
1240
1241 std::pair<unsigned int, unsigned int> face_range =
1242 std::make_pair(matrix_free.n_inner_face_batches(),
1243 matrix_free.n_inner_face_batches() +
1244 matrix_free.n_boundary_face_batches());
1245
1246 std::vector<Quadrature<dim - 1>> global_quadrature_vector(
1247 (matrix_free.n_inner_face_batches() +
1248 matrix_free.n_boundary_face_batches()) *
1249 n_lanes);
1250
1251 // In case of Nitsche-type mortaring a vector of face indices is
1252 // needed as communication object.
1253 // @c FERemoteCommunicationObjectFaces is a container to store this
1254 // information.
1255 //
1256 // We need multiple communication objects (one for each non-matching face
1257 // ID).
1258 std::vector<FERemoteCommunicationObject<dim>> comm_objects;
1259
1260 // Create bounding boxes and GridTools::Cache which is needed in
1261 // the following loop.
1262 std::vector<BoundingBox<dim>> local_boxes;
1263 for (const auto &cell : tria.active_cell_iterators())
1264 if (cell->is_locally_owned())
1265 local_boxes.emplace_back(mapping.get_bounding_box(cell));
1266
1267 // Create r-tree of bounding boxes
1268 const auto local_tree = pack_rtree(local_boxes);
1269
1270 // Compress r-tree to a minimal set of bounding boxes
1271 std::vector<std::vector<BoundingBox<dim>>> global_bboxes(1);
1272 global_bboxes[0] = extract_rtree_level(local_tree, 0);
1273
1274 const GridTools::Cache<dim, dim> cache(tria, mapping);
1275
1276 // Iterate over all sides of the non-matching interface.
1277 for (const auto &[nm_face, marked_vertices] :
1278 non_matching_faces_marked_vertices)
1279 {
1280 // 1) compute cell face pairs
1281 std::vector<
1282 std::pair<typename Triangulation<dim>::cell_iterator, unsigned int>>
1283 cell_face_pairs;
1284
1285 std::vector<unsigned int> indices;
1286
1287 for (unsigned int face = face_range.first; face < face_range.second;
1288 ++face)
1289 {
1290 if (matrix_free.get_boundary_id(face) == nm_face)
1291 {
1292 for (unsigned int v = 0;
1293 v < matrix_free.n_active_entries_per_face_batch(face);
1294 ++v)
1295 {
1296 const auto &[c, f] = matrix_free.get_face_iterator(face, v);
1297
1298 cell_face_pairs.emplace_back(std::make_pair(c, f));
1299 indices.push_back(face * n_lanes + v);
1300 }
1301 }
1302 }
1303
1304 // 2) Create RPE.
1305 // In the Nitsche-type case we do not collect points for the setup
1306 // of RemotePointEvaluation. Instead we compute intersections between
1307 // the faces and set up RemotePointEvaluation with the computed
1308 // intersections.
1309
1310 // Build intersection requests. Intersection requests
1311 // correspond to vertices at faces.
1312 std::vector<std::vector<Point<dim>>> intersection_requests;
1313 for (const auto &[cell, f] : cell_face_pairs)
1314 {
1315 std::vector<Point<dim>> vertices(cell->face(f)->n_vertices());
1316 std::copy_n(mapping.get_vertices(cell, f).begin(),
1317 cell->face(f)->n_vertices(),
1318 vertices.begin());
1319 intersection_requests.emplace_back(vertices);
1320 }
1321
1322 // Compute intersection data with user specified function for marked
1323 // vertices.
1324 auto intersection_data =
1326 dim - 1>(cache,
1327 intersection_requests,
1328 global_bboxes,
1329 marked_vertices(),
1330 tolerance);
1331
1332 // Convert to RPE.
1333 std::vector<Quadrature<dim>> mapped_quadratures_recv_comp;
1334
1335 auto rpe =
1336 std::make_shared<Utilities::MPI::RemotePointEvaluation<dim>>();
1337 rpe->reinit(
1338 intersection_data
1339 .template convert_to_distributed_compute_point_locations_internal<
1340 dim>(n_q_pnts_1D, tria, mapping, &mapped_quadratures_recv_comp),
1341 tria,
1342 mapping);
1343
1344 // 3) Fill global quadrature vector.
1345 for (unsigned int i = 0; i < intersection_requests.size(); ++i)
1346 {
1347 const auto idx = indices[i];
1348
1349 // We do not use a structural binding here, since with
1350 // C++17 capturing structural bindings in lambdas leads
1351 // to an ill formed program.
1352 const auto &cell = std::get<0>(cell_face_pairs[i]);
1353 const auto &f = std::get<1>(cell_face_pairs[i]);
1354
1355 std::vector<Point<dim - 1>> q_points;
1356 std::vector<double> weights;
1357 for (unsigned int ptr = intersection_data.recv_ptrs[i];
1358 ptr < intersection_data.recv_ptrs[i + 1];
1359 ++ptr)
1360 {
1361 const auto &quad = mapped_quadratures_recv_comp[ptr];
1362
1363 const auto &ps = quad.get_points();
1364 std::transform(
1365 ps.begin(),
1366 ps.end(),
1367 std::back_inserter(q_points),
1368 [&](const Point<dim> &p) {
1369 return mapping.project_real_point_to_unit_point_on_face(
1370 cell, f, p);
1371 });
1372
1373 const auto &ws = quad.get_weights();
1374 weights.insert(weights.end(), ws.begin(), ws.end());
1375 }
1376 Quadrature<dim - 1> quad(q_points, weights);
1377
1378 Assert(global_quadrature_vector[idx].size() == 0,
1379 ExcMessage("Quadrature for given face already provided."));
1380
1381 global_quadrature_vector[idx] = quad;
1382 }
1383
1384 // Add communication object.
1386 co.indices = indices;
1387 co.rpe = rpe;
1388 comm_objects.push_back(co);
1389 }
1390
1391 // Reinit the communicator with the communication objects.
1392 FERemoteEvaluationCommunicator<dim> remote_communicator;
1393
1394 std::vector<unsigned int> global_quadrature_sizes(
1395 global_quadrature_vector.size());
1396 std::transform(global_quadrature_vector.cbegin(),
1397 global_quadrature_vector.cend(),
1398 global_quadrature_sizes.begin(),
1399 [](const auto &q) { return q.size(); });
1400
1401 remote_communicator.reinit_faces(
1402 comm_objects,
1403 std::make_pair(0, global_quadrature_vector.size()),
1404 global_quadrature_sizes);
1405
1406 if (nm_mapping_info != nullptr)
1407 {
1408 std::vector<
1409 std::pair<typename DoFHandler<dim>::cell_iterator, unsigned int>>
1410 vector_face_accessors;
1411 vector_face_accessors.reserve((matrix_free.n_inner_face_batches() +
1412 matrix_free.n_boundary_face_batches()) *
1413 n_lanes);
1414
1415 // fill container for inner face batches
1416 unsigned int face_batch = 0;
1417 for (; face_batch < matrix_free.n_inner_face_batches(); ++face_batch)
1418 {
1419 for (unsigned int v = 0; v < n_lanes; ++v)
1420 {
1421 if (v < matrix_free.n_active_entries_per_face_batch(face_batch))
1422 vector_face_accessors.push_back(
1423 matrix_free.get_face_iterator(face_batch, v));
1424 else
1425 vector_face_accessors.push_back(
1426 matrix_free.get_face_iterator(face_batch, 0));
1427 }
1428 }
1429 // and boundary face batches
1430 for (; face_batch < (matrix_free.n_inner_face_batches() +
1431 matrix_free.n_boundary_face_batches());
1432 ++face_batch)
1433 {
1434 for (unsigned int v = 0; v < n_lanes; ++v)
1435 {
1436 if (v < matrix_free.n_active_entries_per_face_batch(face_batch))
1437 vector_face_accessors.push_back(
1438 matrix_free.get_face_iterator(face_batch, v));
1439 else
1440 vector_face_accessors.push_back(
1441 matrix_free.get_face_iterator(face_batch, 0));
1442 }
1443 }
1444
1445 nm_mapping_info->reinit_faces(vector_face_accessors,
1446 global_quadrature_vector);
1447 }
1448
1449 return remote_communicator;
1450 }
1451} // namespace Utilities
1452
1453
1454
1455template <int dim, int n_components, typename value_type>
1456template <typename MeshType>
1459 const MeshType &mesh,
1460 const unsigned int first_selected_component,
1461 const VectorTools::EvaluationFlags::EvaluationFlags evaluation_flags)
1462 : comm(&comm)
1463 , first_selected_component(first_selected_component)
1464 , evaluation_flags(evaluation_flags)
1465{
1466 set_mesh(mesh);
1467}
1468
1469template <int dim, int n_components, typename value_type>
1470template <typename VectorType>
1471void
1473 const VectorType &src,
1475{
1476 if (tria)
1477 {
1478 Assert(n_components == 1, ExcNotImplemented());
1479 comm->template update_ghost_values<n_components>(this->data,
1480 *tria,
1481 src,
1482 flags,
1483 first_selected_component,
1484 evaluation_flags);
1485 }
1486 else if (dof_handler)
1487 {
1488 comm->template update_ghost_values<n_components>(this->data,
1489 *dof_handler,
1490 src,
1491 flags,
1492 first_selected_component,
1493 evaluation_flags);
1494 }
1495 else
1497}
1498
1499template <int dim, int n_components, typename value_type>
1502{
1504 comm->get_view());
1505 return data_accessor;
1506}
1507
1508template <int dim, int n_components, typename value_type>
1509void
1511 const Triangulation<dim> &tria)
1512{
1513 this->tria = &tria;
1514}
1515
1516template <int dim, int n_components, typename value_type>
1517void
1519 const DoFHandler<dim> &dof_handler)
1520{
1521 this->dof_handler = &dof_handler;
1522}
1523
1525
1526#endif
size_type size() const
void resize(const size_type new_size)
static void copy_data(const internal::PrecomputedEvaluationDataView &view, AlignedVector< T1 > &dst, const std::vector< T2 > &src, const std::vector< unsigned int > &indices)
static void copy_data_entries(VectorizedArray< T1, n_lanes > &dst, const unsigned int v, const T1 &src)
const internal::PrecomputedEvaluationDataView & get_view() const
void reinit_faces(const std::vector< FERemoteCommunicationObjectEntityBatches< dim > > &comm_objects, const std::pair< unsigned int, unsigned int > &face_batch_range, const std::vector< unsigned int > &quadrature_sizes)
void update_ghost_values(PrecomputedEvaluationDataType &dst, const MeshType &mesh, const VectorType &src, const EvaluationFlags::EvaluationFlags eval_flags, const unsigned int first_selected_component, const VectorTools::EvaluationFlags::EvaluationFlags vec_flags) const
internal::PrecomputedEvaluationDataView view
std::vector< std::variant< FERemoteCommunicationObjectEntityBatches< dim >, FERemoteCommunicationObject< dim >, FERemoteCommunicationObjectTwoLevel< dim > > > communication_objects
FERemoteEvaluation(const FERemoteEvaluationCommunicator< dim > &comm, const MeshType &mesh, const unsigned int first_selected_component=0, const VectorTools::EvaluationFlags::EvaluationFlags evaluation_flags=VectorTools::EvaluationFlags::avg)
ObserverPointer< const DoFHandler< dim > > dof_handler
ObserverPointer< const FERemoteEvaluationCommunicator< dim > > comm
void set_mesh(const Triangulation< dim > &tria)
internal::PrecomputedEvaluationData< dim, n_components, value_type > data
ObserverPointer< const Triangulation< dim > > tria
const VectorTools::EvaluationFlags::EvaluationFlags evaluation_flags
const unsigned int first_selected_component
internal::PrecomputedEvaluationDataAccessor< dim, n_components, value_type > get_data_accessor() const
void gather_evaluate(const VectorType &src, const EvaluationFlags::EvaluationFlags flags)
IteratorOverIterators end() const
IteratorOverIterators begin()
std::pair< typename DoFHandler< dim >::cell_iterator, unsigned int > get_face_iterator(const unsigned int face_batch_index, const unsigned int lane_index, const bool interior=true, const unsigned int fe_component=0) const
types::boundary_id get_boundary_id(const unsigned int face_batch_index) const
unsigned int n_inner_face_batches() const
const DoFHandler< dim > & get_dof_handler(const unsigned int dof_handler_index=0) const
const internal::MatrixFreeFunctions::MappingInfo< dim, Number, VectorizedArrayType > & get_mapping_info() const
unsigned int n_boundary_face_batches() const
unsigned int n_active_entries_per_face_batch(const unsigned int face_batch_index) const
void reinit_faces(const ContainerType &cell_iterator_range, const std::vector< std::vector< Quadrature< dim - 1 > > > &quadrature_vector, const unsigned int n_unfiltered_cells=numbers::invalid_unsigned_int)
Definition point.h:111
const gradient_type get_gradient(const unsigned int q) const
PrecomputedEvaluationDataAccessor(const PrecomputedEvaluationData< dim, n_components, value_type_ > &data, const PrecomputedEvaluationDataView &view)
const PrecomputedEvaluationDataView & view
typename PrecomputedEvaluationData< dim, n_components, value_type_ >::value_type value_type
const PrecomputedEvaluationData< dim, n_components, value_type_ > & data
const value_type get_value(const unsigned int q) const
typename PrecomputedEvaluationData< dim, n_components, value_type_ >::gradient_type gradient_type
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
#define DEAL_II_NOT_IMPLEMENTED()
unsigned int cell_index
static ::ExceptionBase & ExcNotImplemented()
#define Assert(cond, exc)
#define AssertDimension(dim1, dim2)
#define AssertIndexRange(index, range)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcMessage(std::string arg1)
std::vector< index_type > data
Definition mpi.cc:734
std::size_t size
Definition mpi.cc:733
const MPI_Comm comm
Definition mpi.cc:912
EvaluationFlags
The EvaluationFlags enum.
DistributedComputeIntersectionLocationsInternal< structdim, spacedim > distributed_compute_intersection_locations(const Cache< dim, spacedim > &cache, const std::vector< std::vector< Point< spacedim > > > &intersection_requests, const std::vector< std::vector< BoundingBox< spacedim > > > &global_bboxes, const std::vector< bool > &marked_vertices, const double tolerance)
FERemoteEvaluationCommunicator< dim > compute_remote_communicator_faces_point_to_point_interpolation(const MatrixFree< dim, Number, VectorizedArrayType > &matrix_free, const std::vector< std::pair< types::boundary_id, std::function< std::vector< bool >()> > > &non_matching_faces_marked_vertices, const unsigned int quadrature_index=0, const unsigned int dof_handler_index=0, const double tolerance=1e-9)
FERemoteEvaluationCommunicator< dim > compute_remote_communicator_faces_nitsche_type_mortaring(const MatrixFree< dim, Number, VectorizedArrayType > &matrix_free, const std::vector< std::pair< types::boundary_id, std::function< std::vector< bool >()> > > &non_matching_faces_marked_vertices, const unsigned int n_q_pnts_1D, const unsigned int dof_handler_index=0, NonMatching::MappingInfo< dim, dim, Number > *nm_mapping_info=nullptr, const double tolerance=1e-9)
constexpr unsigned int invalid_unsigned_int
Definition types.h:228
std::vector< BoundingBox< boost::geometry::dimension< typename Rtree::indexable_type >::value > > extract_rtree_level(const Rtree &tree, const unsigned int level)
RTree< typename LeafTypeIterator::value_type, IndexType, IndexableGetter > pack_rtree(const LeafTypeIterator &begin, const LeafTypeIterator &end)
std::vector< std::pair< unsigned int, unsigned int > > batch_id_n_entities
std::vector< std::pair< unsigned int, unsigned int > > get_communication_object_pntrs() const
std::shared_ptr< Utilities::MPI::RemotePointEvaluation< dim > > rpe
std::shared_ptr< Utilities::MPI::RemotePointEvaluation< dim > > rpe
std::vector< std::pair< typename Triangulation< dim >::cell_iterator, unsigned int > > cell_face_nos
std::vector< std::pair< typename Triangulation< dim >::cell_iterator, unsigned int > > get_communication_object_pntrs() const
std::shared_ptr< Utilities::MPI::RemotePointEvaluation< dim > > rpe
std::vector< unsigned int > indices
std::vector< unsigned int > get_communication_object_pntrs() const
unsigned int get_shift(const unsigned int index) const
typename internal::FEPointEvaluation::EvaluatorTypeTraits< dim, dim, n_components, value_type_ >::value_type value_type
typename internal::FEPointEvaluation::EvaluatorTypeTraits< dim, dim, n_components, value_type_ >::real_gradient_type gradient_type
AlignedVector< gradient_type > gradients