deal.II version GIT relicensing-2287-g6548a49e0a 2024-12-20 18:30:00+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
tools.h
Go to the documentation of this file.
1// ------------------------------------------------------------------------
2//
3// SPDX-License-Identifier: LGPL-2.1-or-later
4// Copyright (C) 2020 - 2024 by the deal.II authors
5//
6// This file is part of the deal.II library.
7//
8// Part of the source code is dual licensed under Apache-2.0 WITH
9// LLVM-exception OR LGPL-2.1-or-later. Detailed license information
10// governing the source code and code contributions can be found in
11// LICENSE.md and CONTRIBUTING.md at the top level directory of deal.II.
12//
13// ------------------------------------------------------------------------
14
15#ifndef dealii_matrix_free_tools_h
16#define dealii_matrix_free_tools_h
17
18#include <deal.II/base/config.h>
19
20#include <deal.II/grid/tria.h>
21
27
28
30
36{
37 namespace internal
38 {
39 template <int dim, typename Number, bool is_face_>
41 {
42 public:
44
45 std::vector<unsigned int> dof_numbers;
46 std::vector<unsigned int> quad_numbers;
47 std::vector<unsigned int> n_components;
48 std::vector<unsigned int> first_selected_components;
49 std::vector<unsigned int> batch_type;
50 static const bool is_face = is_face_;
51
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>> &,
56 const unsigned int)>
58 std::function<void(std::vector<std::unique_ptr<FEEvalType>> &)>
60 };
61 } // namespace internal
62
68 template <int dim, typename AdditionalData>
69 void
71 AdditionalData &additional_data);
72
73
74
86 template <int dim,
87 int fe_degree,
88 int n_q_points_1d,
89 int n_components,
90 typename Number,
91 typename VectorizedArrayType,
92 typename VectorType>
93 void
96 VectorType &diagonal_global,
97 const std::function<void(FEEvaluation<dim,
98 fe_degree,
99 n_q_points_1d,
100 n_components,
101 Number,
102 VectorizedArrayType> &)>
103 &cell_operation,
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);
108
112 template <int dim,
113 int fe_degree,
114 int n_q_points_1d,
115 int n_components,
116 typename Number,
117 typename MemorySpace,
118 typename QuadOperation>
119 void
121 const Portable::MatrixFree<dim, Number> &matrix_free,
123 const QuadOperation &quad_operation,
124 EvaluationFlags::EvaluationFlags evaluation_flags,
125 EvaluationFlags::EvaluationFlags integration_flags,
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);
130
134 template <typename CLASS,
135 int dim,
136 int fe_degree,
137 int n_q_points_1d,
138 int n_components,
139 typename Number,
140 typename VectorizedArrayType,
141 typename VectorType>
142 void
145 VectorType &diagonal_global,
146 void (CLASS::*cell_operation)(FEEvaluation<dim,
147 fe_degree,
148 n_q_points_1d,
149 n_components,
150 Number,
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);
157
158
159
170 template <int dim,
171 int fe_degree,
172 int n_q_points_1d,
173 int n_components,
174 typename Number,
175 typename VectorizedArrayType,
176 typename VectorType>
177 void
180 VectorType &diagonal_global,
181 const std::function<void(FEEvaluation<dim,
182 fe_degree,
183 n_q_points_1d,
184 n_components,
185 Number,
186 VectorizedArrayType> &)>
187 &cell_operation,
188 const std::function<void(FEFaceEvaluation<dim,
189 fe_degree,
190 n_q_points_1d,
191 n_components,
192 Number,
193 VectorizedArrayType> &,
195 fe_degree,
196 n_q_points_1d,
197 n_components,
198 Number,
199 VectorizedArrayType> &)>
200 &face_operation,
201 const std::function<void(FEFaceEvaluation<dim,
202 fe_degree,
203 n_q_points_1d,
204 n_components,
205 Number,
206 VectorizedArrayType> &)>
207 &boundary_operation,
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);
212
213
214
218 template <typename CLASS,
219 int dim,
220 int fe_degree,
221 int n_q_points_1d,
222 int n_components,
223 typename Number,
224 typename VectorizedArrayType,
225 typename VectorType>
226 void
229 VectorType &diagonal_global,
230 void (CLASS::*cell_operation)(FEEvaluation<dim,
231 fe_degree,
232 n_q_points_1d,
233 n_components,
234 Number,
235 VectorizedArrayType> &) const,
236 void (CLASS::*face_operation)(FEFaceEvaluation<dim,
237 fe_degree,
238 n_q_points_1d,
239 n_components,
240 Number,
241 VectorizedArrayType> &,
243 fe_degree,
244 n_q_points_1d,
245 n_components,
246 Number,
247 VectorizedArrayType> &)
248 const,
249 void (CLASS::*boundary_operation)(FEFaceEvaluation<dim,
250 fe_degree,
251 n_q_points_1d,
252 n_components,
253 Number,
254 VectorizedArrayType> &)
255 const,
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);
261
262
263
272 template <int dim,
273 int fe_degree,
274 int n_q_points_1d,
275 int n_components,
276 typename Number,
277 typename VectorizedArrayType,
278 typename MatrixType>
279 void
282 const AffineConstraints<Number> &constraints,
283 MatrixType &matrix,
284 const std::function<void(FEEvaluation<dim,
285 fe_degree,
286 n_q_points_1d,
287 n_components,
288 Number,
289 VectorizedArrayType> &)>
290 &cell_operation,
291 const unsigned int dof_no = 0,
292 const unsigned int quad_no = 0,
293 const unsigned int first_selected_component = 0);
294
295
296
300 template <typename CLASS,
301 int dim,
302 int fe_degree,
303 int n_q_points_1d,
304 int n_components,
305 typename Number,
306 typename VectorizedArrayType,
307 typename MatrixType>
308 void
311 const AffineConstraints<Number> &constraints,
312 MatrixType &matrix,
313 void (CLASS::*cell_operation)(FEEvaluation<dim,
314 fe_degree,
315 n_q_points_1d,
316 n_components,
317 Number,
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);
323
324
325 namespace internal
326 {
331 template <int dim,
332 typename Number,
333 typename VectorizedArrayType,
334 typename VectorType,
335 typename VectorType2>
336 void
340 &data_cell,
342 &data_face,
344 &data_boundary,
345 VectorType &diagonal_global,
346 std::vector<VectorType2 *> &diagonal_global_components);
347
352 template <int dim,
353 typename Number,
354 typename VectorizedArrayType,
355 typename MatrixType>
356 void
359 const AffineConstraints<Number> &constraints,
361 &cell_operation,
363 &face_operation,
365 &boundary_operation,
366 MatrixType &matrix);
367 } // namespace internal
368
369
370
380 template <int dim,
381 int fe_degree,
382 int n_q_points_1d,
383 int n_components,
384 typename Number,
385 typename VectorizedArrayType,
386 typename MatrixType>
387 void
390 const AffineConstraints<Number> &constraints,
391 MatrixType &matrix,
392 const std::function<void(FEEvaluation<dim,
393 fe_degree,
394 n_q_points_1d,
395 n_components,
396 Number,
397 VectorizedArrayType> &)>
398 &cell_operation,
399 const std::function<void(FEFaceEvaluation<dim,
400 fe_degree,
401 n_q_points_1d,
402 n_components,
403 Number,
404 VectorizedArrayType> &,
406 fe_degree,
407 n_q_points_1d,
408 n_components,
409 Number,
410 VectorizedArrayType> &)>
411 &face_operation,
412 const std::function<void(FEFaceEvaluation<dim,
413 fe_degree,
414 n_q_points_1d,
415 n_components,
416 Number,
417 VectorizedArrayType> &)>
418 &boundary_operation,
419 const unsigned int dof_no = 0,
420 const unsigned int quad_no = 0,
421 const unsigned int first_selected_component = 0);
422
423
424
428 template <typename CLASS,
429 int dim,
430 int fe_degree,
431 int n_q_points_1d,
432 int n_components,
433 typename Number,
434 typename VectorizedArrayType,
435 typename MatrixType>
436 void
439 const AffineConstraints<Number> &constraints,
440 MatrixType &matrix,
441 void (CLASS::*cell_operation)(FEEvaluation<dim,
442 fe_degree,
443 n_q_points_1d,
444 n_components,
445 Number,
446 VectorizedArrayType> &) const,
447 void (CLASS::*face_operation)(FEFaceEvaluation<dim,
448 fe_degree,
449 n_q_points_1d,
450 n_components,
451 Number,
452 VectorizedArrayType> &,
454 fe_degree,
455 n_q_points_1d,
456 n_components,
457 Number,
458 VectorizedArrayType> &)
459 const,
460 void (CLASS::*boundary_operation)(FEFaceEvaluation<dim,
461 fe_degree,
462 n_q_points_1d,
463 n_components,
464 Number,
465 VectorizedArrayType> &)
466 const,
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);
471
472
473
482 template <int dim,
483 typename Number,
484 typename VectorizedArrayType = VectorizedArray<Number>>
486 {
487 public:
493 {
497 AdditionalData(const unsigned int dof_index = 0)
499 {}
500
504 unsigned int dof_index;
505 };
506
516 void
518 const AdditionalData &additional_data = AdditionalData())
519 {
520 this->matrix_free = &matrix_free;
521
522 std::vector<unsigned int> valid_fe_indices;
523
524 const auto &fe_collection =
525 matrix_free.get_dof_handler(additional_data.dof_index)
526 .get_fe_collection();
527
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);
531
532 // TODO: relax this so that arbitrary number of valid
533 // FEs can be accepted
534 AssertDimension(valid_fe_indices.size(), 1);
535
536 fe_index_valid = *valid_fe_indices.begin();
537 }
538
544 template <typename VectorTypeOut, typename VectorTypeIn>
545 void
546 cell_loop(const std::function<void(
548 VectorTypeOut &,
549 const VectorTypeIn &,
550 const std::pair<unsigned int, unsigned int> &)> &cell_operation,
551 VectorTypeOut &dst,
552 const VectorTypeIn &src,
553 const bool zero_dst_vector = false) const
554 {
555 const auto ebd_cell_operation = [&](const auto &matrix_free,
556 auto &dst,
557 const auto &src,
558 const auto &range) {
559 const auto category = matrix_free.get_cell_range_category(range);
560
561 if (category != fe_index_valid)
562 return;
563
564 cell_operation(matrix_free, dst, src, range);
565 };
566
567 matrix_free->template cell_loop<VectorTypeOut, VectorTypeIn>(
568 ebd_cell_operation, dst, src, zero_dst_vector);
569 }
570
578 template <typename VectorTypeOut, typename VectorTypeIn>
579 void
580 loop(const std::function<
582 VectorTypeOut &,
583 const VectorTypeIn &,
584 const std::pair<unsigned int, unsigned int> &)> &cell_operation,
585 const std::function<
587 VectorTypeOut &,
588 const VectorTypeIn &,
589 const std::pair<unsigned int, unsigned int> &)> &face_operation,
590 const std::function<
592 VectorTypeOut &,
593 const VectorTypeIn &,
594 const std::pair<unsigned int, unsigned int> &,
595 const bool)> &boundary_operation,
596 VectorTypeOut &dst,
597 const VectorTypeIn &src,
598 const bool zero_dst_vector = false) const
599 {
600 const auto ebd_cell_operation = [&](const auto &matrix_free,
601 auto &dst,
602 const auto &src,
603 const auto &range) {
604 const auto category = matrix_free.get_cell_range_category(range);
605
606 if (category != fe_index_valid)
607 return;
608
609 cell_operation(matrix_free, dst, src, range);
610 };
611
612 const auto ebd_internal_or_boundary_face_operation =
613 [&](const auto &matrix_free,
614 auto &dst,
615 const auto &src,
616 const auto &range) {
617 const auto category = matrix_free.get_face_range_category(range);
618
619 const unsigned int type =
620 static_cast<unsigned int>(category.first == fe_index_valid) +
621 static_cast<unsigned int>(category.second == fe_index_valid);
622
623 if (type == 0)
624 return; // deactivated face -> nothing to do
625
626 if (type == 1) // boundary face
627 boundary_operation(
628 matrix_free, dst, src, range, category.first == fe_index_valid);
629 else if (type == 2) // internal face
630 face_operation(matrix_free, dst, src, range);
631 };
632
633 matrix_free->template loop<VectorTypeOut, VectorTypeIn>(
634 ebd_cell_operation,
635 ebd_internal_or_boundary_face_operation,
636 ebd_internal_or_boundary_face_operation,
637 dst,
638 src,
639 zero_dst_vector);
640 }
641
642 private:
648
652 unsigned int fe_index_valid;
653 };
654
655 // implementations
656
657#ifndef DOXYGEN
658
659 template <int dim, typename AdditionalData>
660 void
662 AdditionalData &additional_data)
663 {
664 // ... determine if we are on an active or a multigrid level
665 const unsigned int level = additional_data.mg_level;
666 const bool is_mg = (level != numbers::invalid_unsigned_int);
667
668 // ... create empty list for the category of each cell
669 if (is_mg)
670 additional_data.cell_vectorization_category.assign(
671 std::distance(tria.begin(level), tria.end(level)), 0);
672 else
673 additional_data.cell_vectorization_category.assign(tria.n_active_cells(),
674 0);
675
676 // ... set up scaling factor
677 std::vector<unsigned int> factors(GeometryInfo<dim>::faces_per_cell);
678
679 auto bids = tria.get_boundary_ids();
680 std::sort(bids.begin(), bids.end());
681
682 {
683 unsigned int n_bids = bids.size() + 1;
684 int offset = 1;
685 for (unsigned int i = 0; i < GeometryInfo<dim>::faces_per_cell;
686 i++, offset = offset * n_bids)
687 factors[i] = offset;
688 }
689
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)
693 {
694 const auto face = cell->face(i);
695 if (face->at_boundary() && !cell->has_periodic_neighbor(i))
696 c_num +=
697 factors[i] * (1 + std::distance(bids.begin(),
698 std::find(bids.begin(),
699 bids.end(),
700 face->boundary_id())));
701 }
702 return c_num;
703 };
704
705 if (!is_mg)
706 {
707 for (auto cell = tria.begin_active(); cell != tria.end(); ++cell)
708 {
709 if (cell->is_locally_owned())
710 additional_data
711 .cell_vectorization_category[cell->active_cell_index()] =
712 to_category(cell);
713 }
714 }
715 else
716 {
717 for (auto cell = tria.begin(level); cell != tria.end(level); ++cell)
718 {
719 if (cell->is_locally_owned_on_level())
720 additional_data.cell_vectorization_category[cell->index()] =
721 to_category(cell);
722 }
723 }
724
725 // ... finalize set up of matrix_free
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;
731 }
732
733 namespace internal
734 {
735 template <typename Number>
736 struct LocalCSR
737 {
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;
742
743 std::vector<unsigned int> inverse_lookup_rows;
744 std::vector<std::pair<unsigned int, unsigned int>> inverse_lookup_origins;
745 };
746
747 template <int dim, typename VectorizedArrayType, bool is_face>
748 class ComputeDiagonalHelper
749 {
750 public:
751 using FEEvaluationType =
753
754 using Number = typename VectorizedArrayType::value_type;
755 static const unsigned int n_lanes = VectorizedArrayType::size();
756
757 ComputeDiagonalHelper()
758 : phi(nullptr)
759 , matrix_free(nullptr)
760 , dofs_per_component(0)
761 , n_components(0)
762 {}
763
764 ComputeDiagonalHelper(const ComputeDiagonalHelper &)
765 : phi(nullptr)
766 , matrix_free(nullptr)
767 , dofs_per_component(0)
768 , n_components(0)
769 {}
770
771 void
772 initialize(
773 FEEvaluationType &phi,
775 const unsigned int n_components)
776 {
777 // if we are in hp mode and the number of unknowns changed, we must
778 // clear the map of entries
779 if (dofs_per_component !=
780 phi.get_shape_info().dofs_per_component_on_cell)
781 {
782 locally_relevant_constraints_hn_map.clear();
783 dofs_per_component =
784 phi.get_shape_info().dofs_per_component_on_cell;
785 }
786 this->n_components = n_components;
787 this->dofs_per_cell = n_components * dofs_per_component;
788 this->phi = &phi;
789 this->matrix_free = &matrix_free;
790 }
791
792 void
793 reinit(const unsigned int cell)
794 {
795 // STEP 1: get relevant information from FEEvaluation
796 const auto &matrix_free = *this->matrix_free;
797 const auto &dof_info = phi->get_dof_info();
798 const unsigned int n_fe_components = dof_info.start_components.back();
799
800 // if we have a block vector with components with the same DoFHandler,
801 // each component is described with same set of constraints and
802 // we consider the shift in components only during access of the global
803 // vector
804 const unsigned int first_selected_component =
805 n_fe_components == 1 ? 0 : phi->get_first_selected_component();
806
807 this->n_lanes_filled =
808 is_face ? matrix_free.n_active_entries_per_face_batch(cell) :
809 matrix_free.n_active_entries_per_cell_batch(cell);
810
811 // STEP 2: setup CSR storage of transposed locally-relevant
812 // constraint matrix
813
814 // (constrained local index, global index of dof
815 // constraints, weight)
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;
821
822 const std::array<unsigned int, n_lanes> &cells =
823 this->phi->get_cell_ids();
824
825 for (unsigned int v = 0; v < n_lanes_filled; ++v)
826 {
829
830 const unsigned int *dof_indices;
831 unsigned int index_indicators, next_index_indicators;
832
833 const unsigned int start =
834 cells[v] * n_fe_components + first_selected_component;
835 dof_indices =
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;
839
840 // STEP 2a: setup locally-relevant constraint matrix in a
841 // coordinate list (COO)
842 locally_relevant_constraints.clear();
843
844 if (n_components == 1 || n_fe_components == 1)
845 {
846 unsigned int ind_local = 0;
847 for (; index_indicators != next_index_indicators;
848 ++index_indicators, ++ind_local)
849 {
850 const std::pair<unsigned short, unsigned short> indicator =
851 dof_info.constraint_indicator[index_indicators];
852
853 for (unsigned int j = 0; j < indicator.first;
854 ++j, ++ind_local)
855 locally_relevant_constraints.emplace_back(ind_local,
856 dof_indices[j],
857 1.0);
858
859 dof_indices += indicator.first;
860
861 const Number *data_val =
862 matrix_free.constraint_pool_begin(indicator.second);
863 const Number *end_pool =
864 matrix_free.constraint_pool_end(indicator.second);
865
866 for (; data_val != end_pool; ++data_val, ++dof_indices)
867 locally_relevant_constraints.emplace_back(ind_local,
868 *dof_indices,
869 *data_val);
870 }
871
872 AssertIndexRange(ind_local, dofs_per_component + 1);
873
874 for (; ind_local < dofs_per_component;
875 ++dof_indices, ++ind_local)
876 locally_relevant_constraints.emplace_back(ind_local,
877 *dof_indices,
878 1.0);
879 }
880 else
881 {
882 // case with vector-valued finite elements where all
883 // components are included in one single vector. Assumption:
884 // first come all entries to the first component, then all
885 // entries to the second one, and so on. This is ensured by
886 // the way MatrixFree reads out the indices.
887 for (unsigned int comp = 0; comp < n_components; ++comp)
888 {
889 unsigned int ind_local = 0;
890
891 // check whether there is any constraint on the current
892 // cell
893 for (; index_indicators != next_index_indicators;
894 ++index_indicators, ++ind_local)
895 {
896 const std::pair<unsigned short, unsigned short>
897 indicator =
898 dof_info.constraint_indicator[index_indicators];
899
900 // run through values up to next constraint
901 for (unsigned int j = 0; j < indicator.first;
902 ++j, ++ind_local)
903 locally_relevant_constraints.emplace_back(
904 comp * dofs_per_component + ind_local,
905 dof_indices[j],
906 1.0);
907 dof_indices += indicator.first;
908
909 const Number *data_val =
910 matrix_free.constraint_pool_begin(indicator.second);
911 const Number *end_pool =
912 matrix_free.constraint_pool_end(indicator.second);
913
914 for (; data_val != end_pool; ++data_val, ++dof_indices)
915 locally_relevant_constraints.emplace_back(
916 comp * dofs_per_component + ind_local,
917 *dof_indices,
918 *data_val);
919 }
920
921 AssertIndexRange(ind_local, dofs_per_component + 1);
922
923 // get the dof values past the last constraint
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,
928 *dof_indices,
929 1.0);
930
931 if (comp + 1 < n_components)
932 next_index_indicators =
933 dof_info.row_starts[start + comp + 2].second;
934 }
935 }
936
937 // we only need partial sortedness for the algorithm below in that
938 // all entries for a particular row must be adjacent. this is
939 // ensured by the way we fill the field, but check it again
940 for (unsigned int i = 1; i < locally_relevant_constraints.size();
941 ++i)
942 Assert(std::get<0>(locally_relevant_constraints[i]) >=
943 std::get<0>(locally_relevant_constraints[i - 1]),
945
946 // STEP 2c: apply hanging-node constraints
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])
951 {
952 const auto mask =
953 dof_info.hanging_node_constraint_masks[cells[v]];
954
955 // cell has hanging nodes
956 if (mask != ::internal::MatrixFreeFunctions::
958 {
959 // check if hanging node internpolation matrix has been set
960 // up
961 if (locally_relevant_constraints_hn_map.find(mask) ==
962 locally_relevant_constraints_hn_map.end())
963 fill_constraint_type_into_map(mask);
964
965 const auto &locally_relevant_constraints_hn =
966 locally_relevant_constraints_hn_map[mask];
967
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());
974
975 // combine with other constraints: to avoid binary
976 // searches, we first build a list of where constraints
977 // are pointing to, and then merge the two lists
978 constraint_position.assign(dofs_per_cell,
980 for (auto &a : locally_relevant_constraints)
981 if (constraint_position[std::get<0>(a)] ==
982 numbers::invalid_unsigned_int)
983 constraint_position[std::get<0>(a)] =
984 std::distance(locally_relevant_constraints.data(),
985 &a);
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;
989
990 // not constrained from hanging nodes
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);
994
995 // dof is constrained by hanging nodes: build transitive
996 // closure
997 for (const auto &hn : locally_relevant_constraints_hn)
998 if (constraint_position[std::get<1>(hn)] !=
999 numbers::invalid_unsigned_int)
1000 {
1001 AssertIndexRange(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)];
1005 AssertDimension(std::get<0>(*other), std::get<1>(hn));
1006
1007 for (; other != locally_relevant_constraints.end() &&
1008 std::get<0>(*other) == std::get<1>(hn);
1009 ++other)
1010 locally_relevant_constraints_tmp.emplace_back(
1011 std::get<0>(hn),
1012 std::get<1>(*other),
1013 std::get<2>(hn) * std::get<2>(*other));
1014 }
1015
1016 std::swap(locally_relevant_constraints,
1017 locally_relevant_constraints_tmp);
1018 }
1019 }
1020
1021 // STEP 2d: transpose COO
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))
1026 return true;
1027 return (std::get<1>(a) == std::get<1>(b)) &&
1028 (std::get<0>(a) < std::get<0>(b));
1029 });
1030
1031 // STEP 2e: translate COO to CRS
1032 auto &c_pool = c_pools[v];
1033 {
1034 c_pool.row_lid_to_gid.clear();
1035 c_pool.row.clear();
1036 c_pool.row.push_back(0);
1037 c_pool.col.clear();
1038 c_pool.val.clear();
1039
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)
1044 {
1045 if (c_pool.row_lid_to_gid.back() != std::get<1>(j))
1046 {
1047 c_pool.row_lid_to_gid.push_back(std::get<1>(j));
1048 c_pool.row.push_back(c_pool.val.size());
1049 }
1050
1051 c_pool.col.emplace_back(std::get<0>(j));
1052 c_pool.val.emplace_back(std::get<2>(j));
1053 }
1054
1055 if (c_pool.val.size() > 0)
1056 c_pool.row.push_back(c_pool.val.size());
1057
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]++;
1062 // transform to offsets
1063 std::partial_sum(c_pool.inverse_lookup_rows.begin(),
1064 c_pool.inverse_lookup_rows.end(),
1065 c_pool.inverse_lookup_rows.begin());
1066 AssertDimension(c_pool.inverse_lookup_rows.back(),
1067 c_pool.col.size());
1068
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];
1074 ++col)
1075 {
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];
1081 }
1082 }
1083 }
1084
1085 // STEP 3: compute element matrix A_e, apply
1086 // locally-relevant constraints C_e^T * A_e * C_e, and get the
1087 // the diagonal entry
1088 // (C_e^T * A_e * C_e)(i,i)
1089 // or
1090 // C_e^T(i,:) * A_e * C_e(:,i).
1091 //
1092 // Since, we compute the element matrix column-by-column and as a
1093 // result never actually have the full element matrix, we actually
1094 // perform following steps:
1095 // 1) loop over all columns of the element matrix
1096 // a) compute column i
1097 // b) compute for each j (rows of C_e^T):
1098 // (C_e^T(j,:) * A_e(:,i)) * C_e(i,j)
1099 // or
1100 // (C_e^T(j,:) * A_e(:,i)) * C_e^T(j,i)
1101 // This gives a contribution the j-th entry of the
1102 // locally-relevant diagonal and comprises the multiplication
1103 // by the locally-relevant constraint matrix from the left and
1104 // the right. There is no contribution to the j-th vector
1105 // entry if the j-th row of C_e^T is empty or C_e^T(j,i) is
1106 // zero.
1107
1108 // set size locally-relevant diagonal
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),
1113 Number(0.0));
1114
1115 // check if fast path can be taken via FEEvaluation
1116 bool use_fast_path = true;
1117
1118 for (unsigned int v = 0; v < n_lanes_filled; ++v)
1119 {
1120 auto &c_pool = c_pools[v];
1121
1122 for (unsigned int i = 0; i < c_pool.row.size() - 1; ++i)
1123 {
1124 if ((c_pool.row[i + 1] - c_pool.row[i]) > 1)
1125 {
1126 use_fast_path = false;
1127 break;
1128 }
1129 else if (((c_pool.row[i + 1] - c_pool.row[i]) == 1) &&
1130 (c_pool.val[c_pool.row[i]] != 1.0))
1131 {
1132 use_fast_path = false;
1133 break;
1134 }
1135 }
1136
1137 if (use_fast_path == false)
1138 break;
1139 }
1140
1141 this->has_simple_constraints_ = use_fast_path;
1142 }
1143
1144 void
1145 fill_constraint_type_into_map(
1146 const ::internal::MatrixFreeFunctions::compressed_constraint_kind
1147 mask)
1148 {
1149 auto &constraints_hn = locally_relevant_constraints_hn_map[mask];
1150
1151 // assume that we constrain one face, i.e., (fe_degree + 1)^(dim-1)
1152 // unknowns - we might have more or less entries, but this is a good
1153 // first guess
1154 const unsigned int degree =
1155 phi->get_shape_info().data.front().fe_degree;
1156 constraints_hn.reserve(Utilities::pow(degree + 1, dim - 1));
1157
1158 // 1) collect hanging-node constraints for cell assuming
1159 // scalar finite element
1160 values_dofs.resize(dofs_per_component);
1161 std::array<
1163 VectorizedArrayType::size()>
1164 constraint_mask;
1165 constraint_mask.fill(::internal::MatrixFreeFunctions::
1167 constraint_mask[0] = mask;
1168
1169 for (unsigned int i = 0; i < dofs_per_component; ++i)
1170 {
1171 for (unsigned int j = 0; j < dofs_per_component; ++j)
1172 values_dofs[j] = VectorizedArrayType();
1173 values_dofs[i] = Number(1);
1174
1176 dim,
1177 Number,
1178 VectorizedArrayType>::apply(1,
1179 degree,
1180 phi->get_shape_info(),
1181 false,
1182 constraint_mask,
1183 values_dofs.data());
1184
1185 const Number tolerance =
1186 std::max(Number(1e-12),
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 &&
1190 (j != i ||
1191 std::abs(values_dofs[j][0] - Number(1)) > tolerance))
1192 constraints_hn.emplace_back(j, i, values_dofs[j][0]);
1193 }
1194
1195 // 2) extend for multiple components
1196 const unsigned int n_hn_constraints = constraints_hn.size();
1197 constraints_hn.resize(n_hn_constraints * n_components);
1198
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]));
1205 }
1206
1207 void
1208 prepare_basis_vector(const unsigned int i)
1209 {
1210 this->i = i;
1211
1212 // compute i-th column of element stiffness matrix:
1213 // this could be simply performed as done at the moment with
1214 // matrix-free operator evaluation applied to a ith-basis vector
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);
1219 }
1220
1221 void
1222 zero_basis_vector()
1223 {
1224 VectorizedArrayType *dof_values = phi->begin_dof_values();
1225 for (unsigned int j = 0; j < dofs_per_cell; ++j)
1226 dof_values[j] = VectorizedArrayType();
1227 }
1228
1229 void
1230 submit()
1231 {
1232 // if we have a block vector with components with the same DoFHandler,
1233 // we need to figure out which component and which DoF within the
1234 // component are we currently considering
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;
1241
1242 // apply local constraint matrix from left and from right:
1243 // loop over all rows of transposed constrained matrix
1244 for (unsigned int v = 0; v < n_lanes_filled; ++v)
1245 {
1246 const auto &c_pool = c_pools[v];
1247
1248 for (unsigned int jj = c_pool.inverse_lookup_rows[i_comp];
1249 jj < c_pool.inverse_lookup_rows[i_comp + 1];
1250 ++jj)
1251 {
1252 const unsigned int j = c_pool.inverse_lookup_origins[jj].first;
1253 // apply constraint matrix from the left
1254 Number temp = 0.0;
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 +
1258 c_pool.col[k]][v];
1259
1260 // apply constraint matrix from the right
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];
1264 }
1265 }
1266 }
1267
1268 template <typename VectorType>
1269 inline void
1270 distribute_local_to_global(std::vector<VectorType *> &diagonal_global)
1271 {
1272 // STEP 4: assembly results: add into global vector
1273 const unsigned int n_fe_components =
1274 phi->get_dof_info().start_components.back();
1275
1276 if (n_fe_components == 1)
1277 AssertDimension(diagonal_global.size(), n_components);
1278
1279 for (unsigned int v = 0; v < n_lanes_filled; ++v)
1280 // if we have a block vector with components with the same
1281 // DoFHandler, we need to loop over all components manually and
1282 // need to apply the correct shift
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) :
1287 1);
1288 ++comp)
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()]);
1294 }
1295
1296 bool
1297 has_simple_constraints() const
1298 {
1299 return has_simple_constraints_;
1300 }
1301
1302 private:
1303 FEEvaluationType *phi;
1305
1306 unsigned int dofs_per_component;
1307 unsigned int dofs_per_cell;
1308 unsigned int n_components;
1309
1310 unsigned int i;
1311
1312 unsigned int n_lanes_filled;
1313
1314 std::array<internal::LocalCSR<Number>, n_lanes> c_pools;
1315
1316 // local storage: buffer so that we access the global vector once
1317 // note: may be larger then dofs_per_cell in the presence of
1318 // constraints!
1319 std::array<std::vector<Number>, n_lanes> diagonals_local_constrained;
1320
1321 std::map<
1323 std::vector<std::tuple<unsigned int, unsigned int, Number>>>
1324 locally_relevant_constraints_hn_map;
1325
1326 // scratch array
1328
1329 bool has_simple_constraints_;
1330 };
1331
1332 template <bool is_face,
1333 int dim,
1334 typename Number,
1335 typename VectorizedArrayType>
1336 bool
1337 is_fe_nothing(
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)
1346 {
1347 const unsigned int static_n_q_points =
1348 is_face ? Utilities::pow(n_q_points_1d, dim - 1) :
1349 Utilities::pow(n_q_points_1d, dim);
1350
1351 unsigned int active_fe_index = 0;
1352 if (!is_face)
1353 active_fe_index = matrix_free.get_cell_active_fe_index(range);
1354 else if (is_interior_face)
1355 active_fe_index = matrix_free.get_face_range_category(range).first;
1356 else
1357 active_fe_index = matrix_free.get_face_range_category(range).second;
1358
1359 const auto init_data = ::internal::
1360 extract_initialization_data<is_face, dim, Number, VectorizedArrayType>(
1361 matrix_free,
1362 dof_no,
1363 first_selected_component,
1364 quad_no,
1365 fe_degree,
1366 static_n_q_points,
1367 active_fe_index,
1368 numbers::invalid_unsigned_int /*active_quad_index*/,
1369 numbers::invalid_unsigned_int /*face_type*/);
1370
1371 return init_data.shape_info->dofs_per_component_on_cell == 0;
1372 }
1373
1374 } // namespace internal
1375
1376
1377 template <int dim,
1378 int fe_degree,
1379 int n_q_points_1d,
1380 typename Number,
1381 typename QuadOperation>
1382 class CellAction
1383 {
1384 public:
1385 CellAction(const QuadOperation &quad_operation,
1386 const EvaluationFlags::EvaluationFlags evaluation_flags,
1387 const EvaluationFlags::EvaluationFlags integration_flags)
1388 : m_quad_operation(quad_operation)
1389 , m_evaluation_flags(evaluation_flags)
1390 , m_integration_flags(integration_flags)
1391 {}
1392
1393 KOKKOS_FUNCTION void
1394 operator()(const unsigned int cell,
1395 const typename Portable::MatrixFree<dim, Number>::Data *gpu_data,
1397 const Number *,
1398 Number *dst) const
1399 {
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)
1407 {
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); });
1411
1412 shared_data->team_member.team_barrier();
1413
1414 Portable::internal::
1415 resolve_hanging_nodes<dim, fe_degree, false, Number>(
1416 shared_data->team_member,
1417 gpu_data->constraint_weights,
1418 gpu_data->constraint_mask(cell),
1419 Kokkos::subview(shared_data->values, Kokkos::ALL, 0));
1420
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);
1424
1425 Portable::internal::
1426 resolve_hanging_nodes<dim, fe_degree, true, Number>(
1427 shared_data->team_member,
1428 gpu_data->constraint_weights,
1429 gpu_data->constraint_mask(cell),
1430 Kokkos::subview(shared_data->values, Kokkos::ALL, 0));
1431
1432 Kokkos::single(Kokkos::PerTeam(shared_data->team_member),
1433 [&] { diagonal[i] = fe_eval.get_dof_value(i); });
1434
1435 shared_data->team_member.team_barrier();
1436 }
1437
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);
1441 });
1442
1443 shared_data->team_member.team_barrier();
1444
1445 // We need to do the same as distribute_local_to_global but without
1446 // constraints since we have already taken care of them earlier
1447 if (gpu_data->use_coloring)
1448 {
1449 Kokkos::parallel_for(Kokkos::TeamThreadRange(shared_data->team_member,
1450 dofs_per_cell),
1451 [&](const int &i) {
1452 dst[gpu_data->local_to_global(cell, i)] +=
1453 shared_data->values(i, 0);
1454 });
1455 }
1456 else
1457 {
1458 Kokkos::parallel_for(
1459 Kokkos::TeamThreadRange(shared_data->team_member, dofs_per_cell),
1460 [&](const int &i) {
1461 Kokkos::atomic_add(&dst[gpu_data->local_to_global(cell, i)],
1462 shared_data->values(i, 0));
1463 });
1464 }
1465 };
1466
1467 static constexpr unsigned int n_local_dofs = QuadOperation::n_local_dofs;
1468 static constexpr unsigned int n_q_points = QuadOperation::n_q_points;
1469
1470 private:
1471 mutable QuadOperation m_quad_operation;
1472 const EvaluationFlags::EvaluationFlags m_evaluation_flags;
1473 const EvaluationFlags::EvaluationFlags m_integration_flags;
1474 };
1475
1476
1477 template <int dim,
1478 int fe_degree,
1479 int n_q_points_1d,
1480 int n_components,
1481 typename Number,
1482 typename MemorySpace,
1483 typename QuadOperation>
1484 void
1486 const Portable::MatrixFree<dim, Number> &matrix_free,
1488 const QuadOperation &quad_operation,
1489 EvaluationFlags::EvaluationFlags evaluation_flags,
1490 EvaluationFlags::EvaluationFlags integration_flags,
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)
1495 {
1496 Assert(dof_no == 0, ExcNotImplemented());
1497 Assert(quad_no == 0, ExcNotImplemented());
1498 Assert(first_selected_component == 0, ExcNotImplemented());
1499 Assert(first_vector_component == 0, ExcNotImplemented());
1500
1501 matrix_free.initialize_dof_vector(diagonal_global);
1502
1503
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);
1508
1509 matrix_free.set_constrained_values(Number(1.), diagonal_global);
1510 }
1511
1512 template <int dim,
1513 int fe_degree,
1514 int n_q_points_1d,
1515 int n_components,
1516 typename Number,
1517 typename VectorizedArrayType,
1518 typename VectorType>
1519 void
1522 VectorType &diagonal_global,
1523 const std::function<void(FEEvaluation<dim,
1524 fe_degree,
1525 n_q_points_1d,
1526 n_components,
1527 Number,
1528 VectorizedArrayType> &)>
1529 &cell_operation,
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)
1534 {
1535 compute_diagonal<dim,
1536 fe_degree,
1537 n_q_points_1d,
1538 n_components,
1539 Number,
1540 VectorizedArrayType,
1541 VectorType>(matrix_free,
1542 diagonal_global,
1543 cell_operation,
1544 {},
1545 {},
1546 dof_no,
1547 quad_no,
1548 first_selected_component,
1549 first_vector_component);
1550 }
1551
1552 template <typename CLASS,
1553 int dim,
1554 int fe_degree,
1555 int n_q_points_1d,
1556 int n_components,
1557 typename Number,
1558 typename VectorizedArrayType,
1559 typename VectorType>
1560 void
1563 VectorType &diagonal_global,
1564 void (CLASS::*cell_operation)(FEEvaluation<dim,
1565 fe_degree,
1566 n_q_points_1d,
1567 n_components,
1568 Number,
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)
1575 {
1576 compute_diagonal<dim,
1577 fe_degree,
1578 n_q_points_1d,
1579 n_components,
1580 Number,
1581 VectorizedArrayType,
1582 VectorType>(
1583 matrix_free,
1584 diagonal_global,
1585 [&](auto &phi) { (owning_class->*cell_operation)(phi); },
1586 dof_no,
1587 quad_no,
1588 first_selected_component,
1589 first_vector_component);
1590 }
1591
1592 template <int dim,
1593 int fe_degree,
1594 int n_q_points_1d,
1595 int n_components,
1596 typename Number,
1597 typename VectorizedArrayType,
1598 typename VectorType>
1599 void
1602 VectorType &diagonal_global,
1603 const std::function<void(FEEvaluation<dim,
1604 fe_degree,
1605 n_q_points_1d,
1606 n_components,
1607 Number,
1608 VectorizedArrayType> &)>
1609 &cell_operation,
1610 const std::function<void(FEFaceEvaluation<dim,
1611 fe_degree,
1612 n_q_points_1d,
1613 n_components,
1614 Number,
1615 VectorizedArrayType> &,
1616 FEFaceEvaluation<dim,
1617 fe_degree,
1618 n_q_points_1d,
1619 n_components,
1620 Number,
1621 VectorizedArrayType> &)>
1622 &face_operation,
1623 const std::function<void(FEFaceEvaluation<dim,
1624 fe_degree,
1625 n_q_points_1d,
1626 n_components,
1627 Number,
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)
1634 {
1635 std::vector<typename ::internal::BlockVectorSelector<
1636 VectorType,
1637 IsBlockVector<VectorType>::value>::BaseVectorType *>
1638 diagonal_global_components(n_components);
1639
1640 for (unsigned int d = 0; d < n_components; ++d)
1641 diagonal_global_components[d] = ::internal::
1642 BlockVectorSelector<VectorType, IsBlockVector<VectorType>::value>::
1643 get_vector_component(diagonal_global, d + first_vector_component);
1644
1645 const auto &dof_info = matrix_free.get_dof_info(dof_no);
1646
1647 if (dof_info.start_components.back() == 1)
1648 for (unsigned int comp = 0; comp < n_components; ++comp)
1649 {
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);
1660 }
1661 else
1662 {
1664 *diagonal_global_components[0], matrix_free, dof_info);
1665 }
1666
1667 using FEEvalType = FEEvaluation<dim,
1668 fe_degree,
1669 n_q_points_1d,
1670 n_components,
1671 Number,
1672 VectorizedArrayType>;
1673
1674 using FEFaceEvalType = FEFaceEvaluation<dim,
1675 fe_degree,
1676 n_q_points_1d,
1677 n_components,
1678 Number,
1679 VectorizedArrayType>;
1680
1681 internal::ComputeMatrixScratchData<dim, VectorizedArrayType, false>
1682 data_cell;
1683
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};
1689
1690 data_cell.op_create =
1691 [&](const std::pair<unsigned int, unsigned int> &range) {
1692 std::vector<
1693 std::unique_ptr<FEEvaluationData<dim, VectorizedArrayType, false>>>
1694 phi;
1695
1696 if (!internal::is_fe_nothing<false>(matrix_free,
1697 range,
1698 dof_no,
1699 quad_no,
1700 first_selected_component,
1701 fe_degree,
1702 n_q_points_1d))
1703 phi.emplace_back(std::make_unique<FEEvalType>(
1704 matrix_free, range, dof_no, quad_no, first_selected_component));
1705
1706 return phi;
1707 };
1708
1709 data_cell.op_reinit = [](auto &phi, const unsigned batch) {
1710 if (phi.size() == 1)
1711 static_cast<FEEvalType &>(*phi[0]).reinit(batch);
1712 };
1713
1714 if (cell_operation)
1715 data_cell.op_compute = [&](auto &phi) {
1716 cell_operation(static_cast<FEEvalType &>(*phi[0]));
1717 };
1718
1719 internal::ComputeMatrixScratchData<dim, VectorizedArrayType, true>
1720 data_face;
1721
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};
1728
1729 data_face.op_create =
1730 [&](const std::pair<unsigned int, unsigned int> &range) {
1731 std::vector<
1732 std::unique_ptr<FEEvaluationData<dim, VectorizedArrayType, true>>>
1733 phi;
1734
1735 if (!internal::is_fe_nothing<true>(matrix_free,
1736 range,
1737 dof_no,
1738 quad_no,
1739 first_selected_component,
1740 fe_degree,
1741 n_q_points_1d,
1742 true) &&
1743 !internal::is_fe_nothing<true>(matrix_free,
1744 range,
1745 dof_no,
1746 quad_no,
1747 first_selected_component,
1748 fe_degree,
1749 n_q_points_1d,
1750 false))
1751 {
1752 phi.emplace_back(
1753 std::make_unique<FEFaceEvalType>(matrix_free,
1754 range,
1755 true,
1756 dof_no,
1757 quad_no,
1758 first_selected_component));
1759 phi.emplace_back(
1760 std::make_unique<FEFaceEvalType>(matrix_free,
1761 range,
1762 false,
1763 dof_no,
1764 quad_no,
1765 first_selected_component));
1766 }
1767
1768 return phi;
1769 };
1770
1771 data_face.op_reinit = [](auto &phi, const unsigned batch) {
1772 if (phi.size() == 2)
1773 {
1774 static_cast<FEFaceEvalType &>(*phi[0]).reinit(batch);
1775 static_cast<FEFaceEvalType &>(*phi[1]).reinit(batch);
1776 }
1777 };
1778
1779 if (face_operation)
1780 data_face.op_compute = [&](auto &phi) {
1781 face_operation(static_cast<FEFaceEvalType &>(*phi[0]),
1782 static_cast<FEFaceEvalType &>(*phi[1]));
1783 };
1784
1785 internal::ComputeMatrixScratchData<dim, VectorizedArrayType, true>
1786 data_boundary;
1787
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};
1793
1794 data_boundary
1795 .op_create = [&](const std::pair<unsigned int, unsigned int> &range) {
1796 std::vector<
1797 std::unique_ptr<FEEvaluationData<dim, VectorizedArrayType, true>>>
1798 phi;
1799
1800 if (!internal::is_fe_nothing<true>(matrix_free,
1801 range,
1802 dof_no,
1803 quad_no,
1804 first_selected_component,
1805 fe_degree,
1806 n_q_points_1d,
1807 true))
1808 phi.emplace_back(std::make_unique<FEFaceEvalType>(
1809 matrix_free, range, true, dof_no, quad_no, first_selected_component));
1810
1811 return phi;
1812 };
1813
1814 data_boundary.op_reinit = [](auto &phi, const unsigned batch) {
1815 if (phi.size() == 1)
1816 static_cast<FEFaceEvalType &>(*phi[0]).reinit(batch);
1817 };
1818
1819 if (boundary_operation)
1820 data_boundary.op_compute = [&](auto &phi) {
1821 boundary_operation(static_cast<FEFaceEvalType &>(*phi[0]));
1822 };
1823
1824 internal::compute_diagonal(matrix_free,
1825 data_cell,
1826 data_face,
1827 data_boundary,
1828 diagonal_global,
1829 diagonal_global_components);
1830 }
1831
1832 namespace internal
1833 {
1834 template <int dim,
1835 typename Number,
1836 typename VectorizedArrayType,
1837 typename VectorType,
1838 typename VectorType2>
1839 void
1842 const internal::ComputeMatrixScratchData<dim, VectorizedArrayType, false>
1843 &data_cell,
1844 const internal::ComputeMatrixScratchData<dim, VectorizedArrayType, true>
1845 &data_face,
1846 const internal::ComputeMatrixScratchData<dim, VectorizedArrayType, true>
1847 &data_boundary,
1848 VectorType &diagonal_global,
1849 std::vector<VectorType2 *> &diagonal_global_components)
1850 {
1851 // TODO: can we remove diagonal_global_components as argument?
1852
1853 int dummy = 0;
1854
1855 using Helper =
1856 internal::ComputeDiagonalHelper<dim, VectorizedArrayType, false>;
1857
1858 using HelperFace =
1859 internal::ComputeDiagonalHelper<dim, VectorizedArrayType, true>;
1860
1863 scratch_data_internal;
1865
1866 const auto batch_operation =
1867 [&](auto &data,
1868 auto &scratch_data,
1869 const std::pair<unsigned int, unsigned int> &range) {
1870 if (!data.op_compute)
1871 return; // nothing to do
1872
1873 auto phi = data.op_create(range);
1874
1875 const unsigned int n_blocks = phi.size();
1876
1877 auto &helpers = scratch_data.get();
1878 helpers.resize(n_blocks);
1879
1880 for (unsigned int b = 0; b < n_blocks; ++b)
1881 helpers[b].initialize(*phi[b], matrix_free, data.n_components[b]);
1882
1883 for (unsigned int batch = range.first; batch < range.second; ++batch)
1884 {
1885 data.op_reinit(phi, batch);
1886
1887 for (unsigned int b = 0; b < n_blocks; ++b)
1888 helpers[b].reinit(batch);
1889
1890 if (n_blocks > 1)
1891 {
1892 Assert(std::all_of(helpers.begin(),
1893 helpers.end(),
1894 [](const auto &helper) {
1895 return helper.has_simple_constraints();
1896 }),
1898 }
1899
1900 for (unsigned int b = 0; b < n_blocks; ++b)
1901 {
1902 for (unsigned int i = 0;
1903 i < phi[b]->get_shape_info().dofs_per_component_on_cell *
1904 data.n_components[b];
1905 ++i)
1906 {
1907 for (unsigned int bb = 0; bb < n_blocks; ++bb)
1908 if (b == bb)
1909 helpers[bb].prepare_basis_vector(i);
1910 else
1911 helpers[bb].zero_basis_vector();
1912
1913 data.op_compute(phi);
1914 helpers[b].submit();
1915 }
1916
1917 helpers[b].distribute_local_to_global(
1918 diagonal_global_components);
1919 }
1920 }
1921 };
1922
1923 const auto cell_operation_wrapped =
1924 [&](const auto &, auto &, const auto &, const auto range) {
1925 batch_operation(data_cell, scratch_data, range);
1926 };
1927
1928 const auto face_operation_wrapped =
1929 [&](const auto &, auto &, const auto &, const auto range) {
1930 batch_operation(data_face, scratch_data_internal, range);
1931 };
1932
1933 const auto boundary_operation_wrapped =
1934 [&](const auto &, auto &, const auto &, const auto range) {
1935 batch_operation(data_boundary, scratch_data_bc, range);
1936 };
1937
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,
1942 diagonal_global,
1943 dummy,
1944 false);
1945 else
1946 matrix_free.template cell_loop<VectorType, int>(cell_operation_wrapped,
1947 diagonal_global,
1948 dummy,
1949 false);
1950 }
1951 } // namespace internal
1952
1953 template <typename CLASS,
1954 int dim,
1955 int fe_degree,
1956 int n_q_points_1d,
1957 int n_components,
1958 typename Number,
1959 typename VectorizedArrayType,
1960 typename VectorType>
1961 void
1964 VectorType &diagonal_global,
1965 void (CLASS::*cell_operation)(FEEvaluation<dim,
1966 fe_degree,
1967 n_q_points_1d,
1968 n_components,
1969 Number,
1970 VectorizedArrayType> &) const,
1971 void (CLASS::*face_operation)(FEFaceEvaluation<dim,
1972 fe_degree,
1973 n_q_points_1d,
1974 n_components,
1975 Number,
1976 VectorizedArrayType> &,
1977 FEFaceEvaluation<dim,
1978 fe_degree,
1979 n_q_points_1d,
1980 n_components,
1981 Number,
1982 VectorizedArrayType> &)
1983 const,
1984 void (CLASS::*boundary_operation)(FEFaceEvaluation<dim,
1985 fe_degree,
1986 n_q_points_1d,
1987 n_components,
1988 Number,
1989 VectorizedArrayType> &)
1990 const,
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)
1996 {
1997 compute_diagonal<dim,
1998 fe_degree,
1999 n_q_points_1d,
2000 n_components,
2001 Number,
2002 VectorizedArrayType,
2003 VectorType>(
2004 matrix_free,
2005 diagonal_global,
2006 [&](auto &phi) { (owning_class->*cell_operation)(phi); },
2007 [&](auto &phi_m, auto &phi_p) {
2008 (owning_class->*face_operation)(phi_m, phi_p);
2009 },
2010 [&](auto &phi) { (owning_class->*boundary_operation)(phi); },
2011 dof_no,
2012 quad_no,
2013 first_selected_component,
2014 first_vector_component);
2015 }
2016
2017 namespace internal
2018 {
2023 template <
2024 typename MatrixType,
2025 typename Number,
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(
2032 const MatrixType &,
2033 const AffineConstraints<Number> &constraints,
2035 {
2036 return constraints;
2037 }
2038
2044 template <
2045 typename MatrixType,
2046 typename Number,
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(
2053 const MatrixType &,
2054 const AffineConstraints<Number> &constraints,
2056 &new_constraints)
2057 {
2058 new_constraints =
2059 std::make_unique<AffineConstraints<typename MatrixType::value_type>>();
2060 new_constraints->copy_from(constraints);
2061
2062 return *new_constraints;
2063 }
2064 } // namespace internal
2065
2066 template <int dim,
2067 int fe_degree,
2068 int n_q_points_1d,
2069 int n_components,
2070 typename Number,
2071 typename VectorizedArrayType,
2072 typename MatrixType>
2073 void
2076 const AffineConstraints<Number> &constraints_in,
2077 MatrixType &matrix,
2078 const std::function<void(FEEvaluation<dim,
2079 fe_degree,
2080 n_q_points_1d,
2081 n_components,
2082 Number,
2083 VectorizedArrayType> &)>
2084 &cell_operation,
2085 const unsigned int dof_no,
2086 const unsigned int quad_no,
2087 const unsigned int first_selected_component)
2088 {
2089 compute_matrix<dim,
2090 fe_degree,
2091 n_q_points_1d,
2092 n_components,
2093 Number,
2094 VectorizedArrayType,
2095 MatrixType>(matrix_free,
2096 constraints_in,
2097 matrix,
2098 cell_operation,
2099 {},
2100 {},
2101 dof_no,
2102 quad_no,
2103 first_selected_component);
2104 }
2105
2106 template <typename CLASS,
2107 int dim,
2108 int fe_degree,
2109 int n_q_points_1d,
2110 int n_components,
2111 typename Number,
2112 typename VectorizedArrayType,
2113 typename MatrixType>
2114 void
2117 const AffineConstraints<Number> &constraints,
2118 MatrixType &matrix,
2119 void (CLASS::*cell_operation)(FEEvaluation<dim,
2120 fe_degree,
2121 n_q_points_1d,
2122 n_components,
2123 Number,
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)
2129 {
2130 compute_matrix<dim,
2131 fe_degree,
2132 n_q_points_1d,
2133 n_components,
2134 Number,
2135 VectorizedArrayType,
2136 MatrixType>(
2137 matrix_free,
2138 constraints,
2139 matrix,
2140 [&](auto &phi) { (owning_class->*cell_operation)(phi); },
2141 dof_no,
2142 quad_no,
2143 first_selected_component);
2144 }
2145
2146 template <int dim,
2147 int fe_degree,
2148 int n_q_points_1d,
2149 int n_components,
2150 typename Number,
2151 typename VectorizedArrayType,
2152 typename MatrixType>
2153 void
2156 const AffineConstraints<Number> &constraints_in,
2157 MatrixType &matrix,
2158 const std::function<void(FEEvaluation<dim,
2159 fe_degree,
2160 n_q_points_1d,
2161 n_components,
2162 Number,
2163 VectorizedArrayType> &)>
2164 &cell_operation,
2165 const std::function<void(FEFaceEvaluation<dim,
2166 fe_degree,
2167 n_q_points_1d,
2168 n_components,
2169 Number,
2170 VectorizedArrayType> &,
2171 FEFaceEvaluation<dim,
2172 fe_degree,
2173 n_q_points_1d,
2174 n_components,
2175 Number,
2176 VectorizedArrayType> &)>
2177 &face_operation,
2178 const std::function<void(FEFaceEvaluation<dim,
2179 fe_degree,
2180 n_q_points_1d,
2181 n_components,
2182 Number,
2183 VectorizedArrayType> &)>
2184 &boundary_operation,
2185 const unsigned int dof_no,
2186 const unsigned int quad_no,
2187 const unsigned int first_selected_component)
2188 {
2189 using FEEvalType = FEEvaluation<dim,
2190 fe_degree,
2191 n_q_points_1d,
2192 n_components,
2193 Number,
2194 VectorizedArrayType>;
2195
2196 using FEFaceEvalType = FEFaceEvaluation<dim,
2197 fe_degree,
2198 n_q_points_1d,
2199 n_components,
2200 Number,
2201 VectorizedArrayType>;
2202
2203 internal::ComputeMatrixScratchData<dim, VectorizedArrayType, false>
2204 data_cell;
2205
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};
2211
2212 data_cell.op_create =
2213 [&](const std::pair<unsigned int, unsigned int> &range) {
2214 std::vector<
2215 std::unique_ptr<FEEvaluationData<dim, VectorizedArrayType, false>>>
2216 phi;
2217
2218 if (!internal::is_fe_nothing<false>(matrix_free,
2219 range,
2220 dof_no,
2221 quad_no,
2222 first_selected_component,
2223 fe_degree,
2224 n_q_points_1d))
2225 phi.emplace_back(std::make_unique<FEEvalType>(
2226 matrix_free, range, dof_no, quad_no, first_selected_component));
2227
2228 return phi;
2229 };
2230
2231 data_cell.op_reinit = [](auto &phi, const unsigned batch) {
2232 if (phi.size() == 1)
2233 static_cast<FEEvalType &>(*phi[0]).reinit(batch);
2234 };
2235
2236 if (cell_operation)
2237 data_cell.op_compute = [&](auto &phi) {
2238 cell_operation(static_cast<FEEvalType &>(*phi[0]));
2239 };
2240
2241 internal::ComputeMatrixScratchData<dim, VectorizedArrayType, true>
2242 data_face;
2243
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};
2250
2251 data_face.op_create =
2252 [&](const std::pair<unsigned int, unsigned int> &range) {
2253 std::vector<
2254 std::unique_ptr<FEEvaluationData<dim, VectorizedArrayType, true>>>
2255 phi;
2256
2257 if (!internal::is_fe_nothing<true>(matrix_free,
2258 range,
2259 dof_no,
2260 quad_no,
2261 first_selected_component,
2262 fe_degree,
2263 n_q_points_1d,
2264 true) &&
2265 !internal::is_fe_nothing<true>(matrix_free,
2266 range,
2267 dof_no,
2268 quad_no,
2269 first_selected_component,
2270 fe_degree,
2271 n_q_points_1d,
2272 false))
2273 {
2274 phi.emplace_back(
2275 std::make_unique<FEFaceEvalType>(matrix_free,
2276 range,
2277 true,
2278 dof_no,
2279 quad_no,
2280 first_selected_component));
2281 phi.emplace_back(
2282 std::make_unique<FEFaceEvalType>(matrix_free,
2283 range,
2284 false,
2285 dof_no,
2286 quad_no,
2287 first_selected_component));
2288 }
2289
2290 return phi;
2291 };
2292
2293 data_face.op_reinit = [](auto &phi, const unsigned batch) {
2294 if (phi.size() == 2)
2295 {
2296 static_cast<FEFaceEvalType &>(*phi[0]).reinit(batch);
2297 static_cast<FEFaceEvalType &>(*phi[1]).reinit(batch);
2298 }
2299 };
2300
2301 if (face_operation)
2302 data_face.op_compute = [&](auto &phi) {
2303 face_operation(static_cast<FEFaceEvalType &>(*phi[0]),
2304 static_cast<FEFaceEvalType &>(*phi[1]));
2305 };
2306
2307 internal::ComputeMatrixScratchData<dim, VectorizedArrayType, true>
2308 data_boundary;
2309
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};
2315
2316 data_boundary
2317 .op_create = [&](const std::pair<unsigned int, unsigned int> &range) {
2318 std::vector<
2319 std::unique_ptr<FEEvaluationData<dim, VectorizedArrayType, true>>>
2320 phi;
2321
2322 if (!internal::is_fe_nothing<true>(matrix_free,
2323 range,
2324 dof_no,
2325 quad_no,
2326 first_selected_component,
2327 fe_degree,
2328 n_q_points_1d,
2329 true))
2330 phi.emplace_back(std::make_unique<FEFaceEvalType>(
2331 matrix_free, range, true, dof_no, quad_no, first_selected_component));
2332
2333 return phi;
2334 };
2335
2336 data_boundary.op_reinit = [](auto &phi, const unsigned batch) {
2337 if (phi.size() == 1)
2338 static_cast<FEFaceEvalType &>(*phi[0]).reinit(batch);
2339 };
2340
2341 if (boundary_operation)
2342 data_boundary.op_compute = [&](auto &phi) {
2343 boundary_operation(static_cast<FEFaceEvalType &>(*phi[0]));
2344 };
2345
2347 matrix_free, constraints_in, data_cell, data_face, data_boundary, matrix);
2348 }
2349
2350 namespace internal
2351 {
2352 template <int dim,
2353 typename Number,
2354 typename VectorizedArrayType,
2355 typename MatrixType>
2356 void
2359 const AffineConstraints<Number> &constraints_in,
2360 const internal::ComputeMatrixScratchData<dim, VectorizedArrayType, false>
2361 &data_cell,
2362 const internal::ComputeMatrixScratchData<dim, VectorizedArrayType, true>
2363 &data_face,
2364 const internal::ComputeMatrixScratchData<dim, VectorizedArrayType, true>
2365 &data_boundary,
2366 MatrixType &matrix)
2367 {
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);
2373
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)
2378 return; // nothing to do
2379
2380 auto phi = data.op_create(range);
2381
2382 const unsigned int n_blocks = phi.size();
2383
2384 if (n_blocks == 0)
2385 return;
2386
2387 Table<1, unsigned int> dofs_per_cell(n_blocks);
2388
2389 Table<1, std::vector<types::global_dof_index>> dof_indices(n_blocks);
2391 n_blocks, VectorizedArrayType::size());
2392 Table<1, std::vector<unsigned int>> lexicographic_numbering(n_blocks);
2393 Table<2,
2394 std::array<FullMatrix<typename MatrixType::value_type>,
2395 VectorizedArrayType::size()>>
2396 matrices(n_blocks, n_blocks);
2397
2398 for (unsigned int b = 0; b < n_blocks; ++b)
2399 {
2400 const auto &fe = matrix_free.get_dof_handler(data.dof_numbers[b])
2401 .get_fe(phi[b]->get_active_fe_index());
2402
2403 const auto component_base =
2404 matrix_free.get_dof_info(data.dof_numbers[b])
2405 .component_to_base_index[data.first_selected_components[b]];
2406 const auto component_in_base =
2407 data.first_selected_components[b] -
2408 matrix_free.get_dof_info(data.dof_numbers[b])
2409 .start_components[component_base];
2410
2411 const auto &shape_info = matrix_free.get_shape_info(
2412 data.dof_numbers[b],
2413 data.quad_numbers[b],
2414 component_base,
2415 phi[b]->get_active_fe_index(),
2416 phi[b]->get_active_quadrature_index());
2417
2418 dofs_per_cell[b] =
2419 shape_info.dofs_per_component_on_cell * data.n_components[b];
2420
2421 dof_indices[b].resize(fe.n_dofs_per_cell());
2422
2423 for (unsigned int v = 0; v < VectorizedArrayType::size(); ++v)
2424 dof_indices_mf[b][v].resize(dofs_per_cell[b]);
2425
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);
2433 }
2434
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]));
2441
2442 for (auto batch = range.first; batch < range.second; ++batch)
2443 {
2444 data.op_reinit(phi, batch);
2445
2446 const unsigned int n_filled_lanes =
2447 data.is_face ?
2448 matrix_free.n_active_entries_per_face_batch(batch) :
2449 matrix_free.n_active_entries_per_cell_batch(batch);
2450
2451 for (unsigned int v = 0; v < n_filled_lanes; ++v)
2452 for (unsigned int b = 0; b < n_blocks; ++b)
2453 {
2454 unsigned int const cell_index =
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]);
2460
2461 const auto cell_iterator = matrix_free.get_cell_iterator(
2462 cell_index / VectorizedArrayType::size(),
2463 cell_index % VectorizedArrayType::size(),
2464 data.dof_numbers[b]);
2465
2466 if (matrix_free.get_mg_level() !=
2468 cell_iterator->get_mg_dof_indices(dof_indices[b]);
2469 else
2470 cell_iterator->get_dof_indices(dof_indices[b]);
2471
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]];
2475 }
2476
2477 for (unsigned int bj = 0; bj < n_blocks; ++bj)
2478 {
2479 for (unsigned int j = 0; j < dofs_per_cell[bj]; ++j)
2480 {
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;
2485
2486 data.op_compute(phi);
2487
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];
2493 }
2494
2495 for (unsigned int v = 0; v < n_filled_lanes; ++v)
2496 for (unsigned int bi = 0; bi < n_blocks; ++bi)
2497 if (bi == bj)
2498 // specialization for blocks on the diagonal
2499 // to writing into diagonal elements of the
2500 // matrix if the corresponding degree of freedom
2501 // is constrained, see also the documentation
2502 // of AffineConstraints::distribute_local_to_global()
2503 constraints.distribute_local_to_global(
2504 matrices[bi][bi][v], dof_indices_mf[bi][v], matrix);
2505 else
2506 constraints.distribute_local_to_global(
2507 matrices[bi][bj][v],
2508 dof_indices_mf[bi][v],
2509 dof_indices_mf[bj][v],
2510 matrix);
2511 }
2512 }
2513 };
2514
2515 const auto cell_operation_wrapped =
2516 [&](const auto &, auto &, const auto &, const auto range) {
2517 batch_operation(data_cell, range);
2518 };
2519
2520 const auto face_operation_wrapped =
2521 [&](const auto &, auto &, const auto &, const auto range) {
2522 batch_operation(data_face, range);
2523 };
2524
2525 const auto boundary_operation_wrapped =
2526 [&](const auto &, auto &, const auto &, const auto range) {
2527 batch_operation(data_boundary, range);
2528 };
2529
2530 if (data_face.op_compute || data_boundary.op_compute)
2531 {
2532 matrix_free.template loop<MatrixType, MatrixType>(
2533 cell_operation_wrapped,
2534 face_operation_wrapped,
2535 boundary_operation_wrapped,
2536 matrix,
2537 matrix);
2538 }
2539 else
2540 matrix_free.template cell_loop<MatrixType, MatrixType>(
2541 cell_operation_wrapped, matrix, matrix);
2542
2543 matrix.compress(VectorOperation::add);
2544 }
2545 } // namespace internal
2546
2547 template <typename CLASS,
2548 int dim,
2549 int fe_degree,
2550 int n_q_points_1d,
2551 int n_components,
2552 typename Number,
2553 typename VectorizedArrayType,
2554 typename MatrixType>
2555 void
2558 const AffineConstraints<Number> &constraints,
2559 MatrixType &matrix,
2560 void (CLASS::*cell_operation)(FEEvaluation<dim,
2561 fe_degree,
2562 n_q_points_1d,
2563 n_components,
2564 Number,
2565 VectorizedArrayType> &) const,
2566 void (CLASS::*face_operation)(FEFaceEvaluation<dim,
2567 fe_degree,
2568 n_q_points_1d,
2569 n_components,
2570 Number,
2571 VectorizedArrayType> &,
2572 FEFaceEvaluation<dim,
2573 fe_degree,
2574 n_q_points_1d,
2575 n_components,
2576 Number,
2577 VectorizedArrayType> &)
2578 const,
2579 void (CLASS::*boundary_operation)(FEFaceEvaluation<dim,
2580 fe_degree,
2581 n_q_points_1d,
2582 n_components,
2583 Number,
2584 VectorizedArrayType> &)
2585 const,
2586 const CLASS *owning_class,
2587 const unsigned int dof_no,
2588 const unsigned int quad_no,
2589 const unsigned int first_selected_component)
2590 {
2591 compute_matrix<dim,
2592 fe_degree,
2593 n_q_points_1d,
2594 n_components,
2595 Number,
2596 VectorizedArrayType,
2597 MatrixType>(
2598 matrix_free,
2599 constraints,
2600 matrix,
2601 [&](auto &phi) { (owning_class->*cell_operation)(phi); },
2602 [&](auto &phi_m, auto &phi_p) {
2603 (owning_class->*face_operation)(phi_m, phi_p);
2604 },
2605 [&](auto &phi) { (owning_class->*boundary_operation)(phi); },
2606 dof_no,
2607 quad_no,
2608 first_selected_component);
2609 }
2610
2611#endif // DOXYGEN
2612
2613} // namespace MatrixFreeTools
2614
2616
2617
2618#endif
void distribute_local_to_global(const InVector &local_vector, const std::vector< size_type > &local_dof_indices, OutVector &global_vector) const
void copy_from(const AffineConstraints< other_number > &other)
void loop(const std::function< void(const MatrixFree< dim, Number, VectorizedArrayType > &, VectorTypeOut &, const VectorTypeIn &, const std::pair< unsigned int, unsigned int > &)> &cell_operation, const std::function< void(const MatrixFree< dim, Number, VectorizedArrayType > &, VectorTypeOut &, const VectorTypeIn &, const std::pair< unsigned int, unsigned int > &)> &face_operation, const std::function< void(const MatrixFree< dim, Number, VectorizedArrayType > &, VectorTypeOut &, const VectorTypeIn &, const std::pair< unsigned int, unsigned int > &, const bool)> &boundary_operation, VectorTypeOut &dst, const VectorTypeIn &src, const bool zero_dst_vector=false) const
Definition tools.h:580
ObserverPointer< const MatrixFree< dim, Number, VectorizedArrayType > > matrix_free
Definition tools.h:647
void cell_loop(const std::function< void(const MatrixFree< dim, Number, VectorizedArrayType > &, VectorTypeOut &, const VectorTypeIn &, const std::pair< unsigned int, unsigned int > &)> &cell_operation, VectorTypeOut &dst, const VectorTypeIn &src, const bool zero_dst_vector=false) const
Definition tools.h:546
void reinit(const MatrixFree< dim, Number, VectorizedArrayType > &matrix_free, const AdditionalData &additional_data=AdditionalData())
Definition tools.h:517
std::vector< unsigned int > n_components
Definition tools.h:47
std::vector< unsigned int > quad_numbers
Definition tools.h:46
std::vector< unsigned int > batch_type
Definition tools.h:49
std::vector< unsigned int > dof_numbers
Definition tools.h:45
std::function< void(std::vector< std::unique_ptr< FEEvalType > > &, const unsigned int)> op_reinit
Definition tools.h:57
std::function< void(std::vector< std::unique_ptr< FEEvalType > > &)> op_compute
Definition tools.h:59
std::function< std::vector< std::unique_ptr< FEEvalType > >(const std::pair< unsigned int, unsigned int > &)> op_create
Definition tools.h:54
std::vector< unsigned int > first_selected_components
Definition tools.h:48
unsigned int get_cell_active_fe_index(const std::pair< unsigned int, unsigned int > range) const
unsigned int n_active_entries_per_cell_batch(const unsigned int cell_batch_index) const
unsigned int get_mg_level() const
void clear()
const internal::MatrixFreeFunctions::DoFInfo & get_dof_info(const unsigned int dof_handler_index_component=0) const
const Number * constraint_pool_begin(const unsigned int pool_index) const
const DoFHandler< dim > & get_dof_handler(const unsigned int dof_handler_index=0) const
DoFHandler< dim >::cell_iterator get_cell_iterator(const unsigned int cell_batch_index, const unsigned int lane_index, const unsigned int dof_handler_index=0) const
std::pair< unsigned int, unsigned int > get_face_range_category(const std::pair< unsigned int, unsigned int > face_batch_range) const
const Number * constraint_pool_end(const unsigned int pool_index) const
unsigned int n_active_entries_per_face_batch(const unsigned int face_batch_index) const
const internal::MatrixFreeFunctions::ShapeInfo< Number > & get_shape_info(const unsigned int dof_handler_index_component=0, const unsigned int quad_index=0, const unsigned int fe_base_element=0, const unsigned int hp_active_fe_index=0, const unsigned int hp_active_quad_index=0) const
void initialize_dof_vector(LinearAlgebra::distributed::Vector< Number, MemorySpaceType > &vec) const
void set_constrained_values(const Number val, VectorType &dst) const
void cell_loop(const Functor &func, const VectorType &src, VectorType &dst) const
A class that provides a separate storage location on each thread that accesses the object.
cell_iterator begin(const unsigned int level=0) const
unsigned int n_active_cells() const
cell_iterator end() const
virtual std::vector< types::boundary_id > get_boundary_ids() const
active_cell_iterator begin_active(const unsigned int level=0) const
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:498
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:499
unsigned int level
Definition grid_out.cc:4632
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)
void cell_action(IteratorType cell, DoFInfoBox< dim, DOFINFO > &dof_info, INFOBOX &info, const std::function< void(DOFINFO &, typename INFOBOX::CellInfo &)> &cell_worker, const std::function< void(DOFINFO &, typename INFOBOX::CellInfo &)> &boundary_worker, const std::function< void(DOFINFO &, DOFINFO &, typename INFOBOX::CellInfo &, typename INFOBOX::CellInfo &)> &face_worker, const LoopControl &loop_control)
Definition loop.h:316
std::vector< index_type > data
Definition mpi.cc:735
std::size_t size
Definition mpi.cc:734
EvaluationFlags
The EvaluationFlags enum.
@ matrix
Contents is actually a matrix.
@ diagonal
Matrix is diagonal.
Tpetra::Vector< Number, LO, GO, NodeType< MemorySpace > > VectorType
Tpetra::CrsMatrix< Number, LO, GO, NodeType< MemorySpace > > MatrixType
std::enable_if_t< IsBlockVector< VectorType >::value, unsigned int > n_blocks(const VectorType &vector)
Definition operators.h:49
void compute_diagonal(const MatrixFree< dim, Number, VectorizedArrayType > &matrix_free, const internal::ComputeMatrixScratchData< dim, VectorizedArrayType, false > &data_cell, const internal::ComputeMatrixScratchData< dim, VectorizedArrayType, true > &data_face, const internal::ComputeMatrixScratchData< dim, VectorizedArrayType, true > &data_boundary, VectorType &diagonal_global, std::vector< VectorType2 * > &diagonal_global_components)
void compute_matrix(const MatrixFree< dim, Number, VectorizedArrayType > &matrix_free, const AffineConstraints< Number > &constraints, const internal::ComputeMatrixScratchData< dim, VectorizedArrayType, false > &cell_operation, const internal::ComputeMatrixScratchData< dim, VectorizedArrayType, true > &face_operation, const internal::ComputeMatrixScratchData< dim, VectorizedArrayType, true > &boundary_operation, MatrixType &matrix)
void compute_diagonal(const MatrixFree< dim, Number, VectorizedArrayType > &matrix_free, VectorType &diagonal_global, const std::function< void(FEEvaluation< dim, fe_degree, n_q_points_1d, n_components, Number, VectorizedArrayType > &)> &cell_operation, const unsigned int dof_no=0, const unsigned int quad_no=0, const unsigned int first_selected_component=0, const unsigned int first_vector_component=0)
void compute_matrix(const MatrixFree< dim, Number, VectorizedArrayType > &matrix_free, const AffineConstraints< Number > &constraints, MatrixType &matrix, const std::function< void(FEEvaluation< dim, fe_degree, n_q_points_1d, n_components, Number, VectorizedArrayType > &)> &cell_operation, const unsigned int dof_no=0, const unsigned int quad_no=0, const unsigned int first_selected_component=0)
void categorize_by_boundary_ids(const Triangulation< dim > &tria, AdditionalData &additional_data)
SymmetricTensor< 2, dim, Number > b(const Tensor< 2, dim, Number > &F)
SymmetricTensor< 2, dim, Number > d(const Tensor< 2, dim, Number > &F, const Tensor< 2, dim, Number > &dF_dt)
VectorType::value_type * begin(VectorType &V)
constexpr T pow(const T base, const int iexp)
Definition utilities.h:966
std::uint8_t compressed_constraint_kind
Definition dof_info.h:86
constexpr compressed_constraint_kind unconstrained_compressed_constraint_kind
void vector_access_add(VectorType &vec, const unsigned int entry, const typename VectorType::value_type &val)
void check_vector_compatibility(const VectorType &vec, const MatrixFree< dim, Number, VectorizedArrayType > &matrix_free, const internal::MatrixFreeFunctions::DoFInfo &dof_info)
void reinit(MatrixBlock< MatrixType > &v, const BlockSparsityPattern &p)
static const unsigned int invalid_unsigned_int
Definition types.h:220
STL namespace.
::VectorizedArray< Number, width > max(const ::VectorizedArray< Number, width > &, const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > pow(const ::VectorizedArray< Number, width > &, const Number p)
::VectorizedArray< Number, width > abs(const ::VectorizedArray< Number, width > &)
Kokkos::View< Number *, MemorySpace::Default::kokkos_space > constraint_weights
Kokkos::View<::internal::MatrixFreeFunctions::ConstraintKinds *, MemorySpace::Default::kokkos_space > constraint_mask
std::vector< unsigned int > component_to_base_index
Definition dof_info.h:677
std::vector< unsigned int > start_components
Definition dof_info.h:671