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
tools.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) 2020 - 2026 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#ifndef dealii_matrix_free_tools_h
14#define dealii_matrix_free_tools_h
15
16#include <deal.II/base/config.h>
17
18#include <deal.II/grid/tria.h>
19
25
26#include <Kokkos_Core.hpp>
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_handler_index = 0,
105 const unsigned int quadrature_index = 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_handler_index = 0,
127 const unsigned int quadrature_index = 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_handler_index = 0,
154 const unsigned int quadrature_index = 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_handler_index = 0,
209 const unsigned int quadrature_index = 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_handler_index = 0,
258 const unsigned int quadrature_index = 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_handler_index = 0,
292 const unsigned int quadrature_index = 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_handler_index = 0,
321 const unsigned int quadrature_index = 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_handler_index = 0,
420 const unsigned int quadrature_index = 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_handler_index = 0,
469 const unsigned int quadrature_index = 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 const std::array<unsigned int, n_lanes> &cells =
815 this->phi->get_cell_ids();
816
817 inverse_lookup_count.resize(dofs_per_cell);
818 for (unsigned int v = 0; v < n_lanes_filled; ++v)
819 {
822
823 const unsigned int *dof_indices;
824 unsigned int index_indicators, next_index_indicators;
825
826 const unsigned int start =
827 cells[v] * n_fe_components + first_selected_component;
828 dof_indices =
829 dof_info.dof_indices.data() + dof_info.row_starts[start].first;
830 index_indicators = dof_info.row_starts[start].second;
831 next_index_indicators = dof_info.row_starts[start + 1].second;
832
833 // STEP 2a: setup locally-relevant constraint matrix in a
834 // coordinate list (COO)
835 locally_relevant_constraints.clear();
836
837 if (n_components == 1 || n_fe_components == 1)
838 {
839 unsigned int ind_local = 0;
840 for (; index_indicators != next_index_indicators;
841 ++index_indicators, ++ind_local)
842 {
843 const std::pair<unsigned short, unsigned short> indicator =
844 dof_info.constraint_indicator[index_indicators];
845
846 for (unsigned int j = 0; j < indicator.first;
847 ++j, ++ind_local)
848 locally_relevant_constraints.emplace_back(ind_local,
849 dof_indices[j],
850 1.0);
851
852 dof_indices += indicator.first;
853
854 const Number *data_val =
855 matrix_free.constraint_pool_begin(indicator.second);
856 const Number *end_pool =
857 matrix_free.constraint_pool_end(indicator.second);
858
859 for (; data_val != end_pool; ++data_val, ++dof_indices)
860 locally_relevant_constraints.emplace_back(ind_local,
861 *dof_indices,
862 *data_val);
863 }
864
865 AssertIndexRange(ind_local, dofs_per_component + 1);
866
867 for (; ind_local < dofs_per_component;
868 ++dof_indices, ++ind_local)
869 locally_relevant_constraints.emplace_back(ind_local,
870 *dof_indices,
871 1.0);
872 }
873 else
874 {
875 // case with vector-valued finite elements where all
876 // components are included in one single vector. Assumption:
877 // first come all entries to the first component, then all
878 // entries to the second one, and so on. This is ensured by
879 // the way MatrixFree reads out the indices.
880 for (unsigned int comp = 0; comp < n_components; ++comp)
881 {
882 unsigned int ind_local = 0;
883
884 // check whether there is any constraint on the current
885 // cell
886 for (; index_indicators != next_index_indicators;
887 ++index_indicators, ++ind_local)
888 {
889 const std::pair<unsigned short, unsigned short>
890 indicator =
891 dof_info.constraint_indicator[index_indicators];
892
893 // run through values up to next constraint
894 for (unsigned int j = 0; j < indicator.first;
895 ++j, ++ind_local)
896 locally_relevant_constraints.emplace_back(
897 comp * dofs_per_component + ind_local,
898 dof_indices[j],
899 1.0);
900 dof_indices += indicator.first;
901
902 const Number *data_val =
903 matrix_free.constraint_pool_begin(indicator.second);
904 const Number *end_pool =
905 matrix_free.constraint_pool_end(indicator.second);
906
907 for (; data_val != end_pool; ++data_val, ++dof_indices)
908 locally_relevant_constraints.emplace_back(
909 comp * dofs_per_component + ind_local,
910 *dof_indices,
911 *data_val);
912 }
913
914 AssertIndexRange(ind_local, dofs_per_component + 1);
915
916 // get the dof values past the last constraint
917 for (; ind_local < dofs_per_component;
918 ++dof_indices, ++ind_local)
919 locally_relevant_constraints.emplace_back(
920 comp * dofs_per_component + ind_local,
921 *dof_indices,
922 1.0);
923
924 if (comp + 1 < n_components)
925 next_index_indicators =
926 dof_info.row_starts[start + comp + 2].second;
927 }
928 }
929
930 // we only need partial sortedness for the algorithm below in that
931 // all entries for a particular row must be adjacent. this is
932 // ensured by the way we fill the field, but check it again
933 for (unsigned int i = 1; i < locally_relevant_constraints.size();
934 ++i)
935 Assert(std::get<0>(locally_relevant_constraints[i]) >=
936 std::get<0>(locally_relevant_constraints[i - 1]),
938
939 // STEP 2c: apply hanging-node constraints
940 if (dof_info.hanging_node_constraint_masks.size() > 0 &&
941 dof_info.hanging_node_constraint_masks_comp.size() > 0 &&
942 dof_info.hanging_node_constraint_masks_comp
943 [phi->get_active_fe_index()][first_selected_component])
944 {
945 const auto mask =
946 dof_info.hanging_node_constraint_masks[cells[v]];
947
948 // cell has hanging nodes
949 if (mask != ::internal::MatrixFreeFunctions::
951 {
952 // check if hanging node internpolation matrix has been set
953 // up
954 if (locally_relevant_constraints_hn_map.find(mask) ==
955 locally_relevant_constraints_hn_map.end())
956 fill_constraint_type_into_map(mask);
957
958 const auto &locally_relevant_constraints_hn =
959 locally_relevant_constraints_hn_map[mask];
960
961 locally_relevant_constraints_tmp.clear();
962 if (locally_relevant_constraints_tmp.capacity() <
963 locally_relevant_constraints.size())
964 locally_relevant_constraints_tmp.reserve(
965 locally_relevant_constraints.size() +
966 locally_relevant_constraints_hn.size());
967
968 // combine with other constraints: to avoid binary
969 // searches, we first build a list of where constraints
970 // are pointing to, and then merge the two lists
971 constraint_position.assign(dofs_per_cell,
973 for (auto &a : locally_relevant_constraints)
974 if (constraint_position[std::get<0>(a)] ==
976 constraint_position[std::get<0>(a)] =
977 std::distance(locally_relevant_constraints.data(),
978 &a);
979 is_constrained_hn.assign(dofs_per_cell, false);
980 for (auto &hn : locally_relevant_constraints_hn)
981 is_constrained_hn[std::get<0>(hn)] = 1;
982
983 // not constrained from hanging nodes
984 for (const auto &a : locally_relevant_constraints)
985 if (is_constrained_hn[std::get<0>(a)] == 0)
986 locally_relevant_constraints_tmp.push_back(a);
987
988 // dof is constrained by hanging nodes: build transitive
989 // closure
990 for (const auto &hn : locally_relevant_constraints_hn)
991 if (constraint_position[std::get<1>(hn)] !=
993 {
994 AssertIndexRange(constraint_position[std::get<1>(hn)],
995 locally_relevant_constraints.size());
996 auto other = locally_relevant_constraints.begin() +
997 constraint_position[std::get<1>(hn)];
998 AssertDimension(std::get<0>(*other), std::get<1>(hn));
999
1000 for (; other != locally_relevant_constraints.end() &&
1001 std::get<0>(*other) == std::get<1>(hn);
1002 ++other)
1003 locally_relevant_constraints_tmp.emplace_back(
1004 std::get<0>(hn),
1005 std::get<1>(*other),
1006 std::get<2>(hn) * std::get<2>(*other));
1007 }
1008
1009 std::swap(locally_relevant_constraints,
1010 locally_relevant_constraints_tmp);
1011 }
1012 }
1013
1014 // STEP 2d: transpose COO
1015 std::sort(locally_relevant_constraints.begin(),
1016 locally_relevant_constraints.end(),
1017 [](const auto &a, const auto &b) {
1018 if (std::get<1>(a) < std::get<1>(b))
1019 return true;
1020 return (std::get<1>(a) == std::get<1>(b)) &&
1021 (std::get<0>(a) < std::get<0>(b));
1022 });
1023
1024 // STEP 2e: translate COO to CRS
1025 auto &c_pool = c_pools[v];
1026 {
1027 c_pool.row_lid_to_gid.clear();
1028 c_pool.row.clear();
1029 c_pool.row.push_back(0);
1030 c_pool.col.clear();
1031 c_pool.val.clear();
1032
1033 if (locally_relevant_constraints.size() > 0)
1034 c_pool.row_lid_to_gid.emplace_back(
1035 std::get<1>(locally_relevant_constraints.front()));
1036 for (const auto &j : locally_relevant_constraints)
1037 {
1038 if (c_pool.row_lid_to_gid.back() != std::get<1>(j))
1039 {
1040 c_pool.row_lid_to_gid.push_back(std::get<1>(j));
1041 c_pool.row.push_back(c_pool.val.size());
1042 }
1043
1044 c_pool.col.emplace_back(std::get<0>(j));
1045 c_pool.val.emplace_back(std::get<2>(j));
1046 }
1047
1048 if (c_pool.val.size() > 0)
1049 c_pool.row.push_back(c_pool.val.size());
1050
1051 c_pool.inverse_lookup_rows.clear();
1052 c_pool.inverse_lookup_rows.resize(1 + dofs_per_cell);
1053 for (const unsigned int i : c_pool.col)
1054 c_pool.inverse_lookup_rows[1 + i]++;
1055 // transform to offsets
1056 std::partial_sum(c_pool.inverse_lookup_rows.begin(),
1057 c_pool.inverse_lookup_rows.end(),
1058 c_pool.inverse_lookup_rows.begin());
1059 AssertDimension(c_pool.inverse_lookup_rows.back(),
1060 c_pool.col.size());
1061
1062 c_pool.inverse_lookup_origins.resize(c_pool.col.size());
1063 std::fill(inverse_lookup_count.begin(),
1064 inverse_lookup_count.end(),
1065 0u);
1066 for (unsigned int row = 0; row < c_pool.row.size() - 1; ++row)
1067 for (unsigned int col = c_pool.row[row];
1068 col < c_pool.row[row + 1];
1069 ++col)
1070 {
1071 const unsigned int index = c_pool.col[col];
1072 c_pool.inverse_lookup_origins
1073 [c_pool.inverse_lookup_rows[index] +
1074 inverse_lookup_count[index]] = std::make_pair(row, col);
1075 ++inverse_lookup_count[index];
1076 }
1077 }
1078 }
1079
1080 // STEP 3: compute element matrix A_e, apply
1081 // locally-relevant constraints C_e^T * A_e * C_e, and get the
1082 // the diagonal entry
1083 // (C_e^T * A_e * C_e)(i,i)
1084 // or
1085 // C_e^T(i,:) * A_e * C_e(:,i).
1086 //
1087 // Since, we compute the element matrix column-by-column and as a
1088 // result never actually have the full element matrix, we actually
1089 // perform following steps:
1090 // 1) loop over all columns of the element matrix
1091 // a) compute column i
1092 // b) compute for each j (rows of C_e^T):
1093 // (C_e^T(j,:) * A_e(:,i)) * C_e(i,j)
1094 // or
1095 // (C_e^T(j,:) * A_e(:,i)) * C_e^T(j,i)
1096 // This gives a contribution the j-th entry of the
1097 // locally-relevant diagonal and comprises the multiplication
1098 // by the locally-relevant constraint matrix from the left and
1099 // the right. There is no contribution to the j-th vector
1100 // entry if the j-th row of C_e^T is empty or C_e^T(j,i) is
1101 // zero.
1102
1103 // set size locally-relevant diagonal
1104 for (unsigned int v = 0; v < n_lanes_filled; ++v)
1105 diagonals_local_constrained[v].assign(
1106 c_pools[v].row_lid_to_gid.size() *
1107 (n_fe_components == 1 ? n_components : 1),
1108 Number(0.0));
1109
1110 // check if fast path can be taken via FEEvaluation
1111 bool use_fast_path = true;
1112
1113 for (unsigned int v = 0; v < n_lanes_filled; ++v)
1114 {
1115 auto &c_pool = c_pools[v];
1116
1117 for (unsigned int i = 0; i < c_pool.row.size() - 1; ++i)
1118 {
1119 if ((c_pool.row[i + 1] - c_pool.row[i]) > 1)
1120 {
1121 use_fast_path = false;
1122 break;
1123 }
1124 else if (((c_pool.row[i + 1] - c_pool.row[i]) == 1) &&
1125 (c_pool.val[c_pool.row[i]] != 1.0))
1126 {
1127 use_fast_path = false;
1128 break;
1129 }
1130 }
1131
1132 if (use_fast_path == false)
1133 break;
1134 }
1135
1136 this->has_simple_constraints_ = use_fast_path;
1137 }
1138
1139 void
1140 fill_constraint_type_into_map(
1141 const ::internal::MatrixFreeFunctions::compressed_constraint_kind
1142 mask)
1143 {
1144 auto &constraints_hn = locally_relevant_constraints_hn_map[mask];
1145
1146 // assume that we constrain one face, i.e., (fe_degree + 1)^(dim-1)
1147 // unknowns - we might have more or less entries, but this is a good
1148 // first guess
1149 const unsigned int degree =
1150 phi->get_shape_info().data.front().fe_degree;
1151 constraints_hn.reserve(Utilities::pow(degree + 1, dim - 1));
1152
1153 // 1) collect hanging-node constraints for cell assuming
1154 // scalar finite element
1155 values_dofs.resize(dofs_per_component);
1156 std::array<
1158 VectorizedArrayType::size()>
1159 constraint_mask;
1160 constraint_mask.fill(::internal::MatrixFreeFunctions::
1162 constraint_mask[0] = mask;
1163
1164 for (unsigned int i = 0; i < dofs_per_component; ++i)
1165 {
1166 for (unsigned int j = 0; j < dofs_per_component; ++j)
1167 values_dofs[j] = VectorizedArrayType();
1168 values_dofs[i] = Number(1);
1169
1171 dim,
1172 Number,
1173 VectorizedArrayType>::apply(1,
1174 degree,
1175 phi->get_shape_info(),
1176 false,
1177 constraint_mask,
1178 values_dofs.data());
1179
1180 const Number tolerance =
1181 std::max(Number(1e-12),
1182 std::numeric_limits<Number>::epsilon() * 16);
1183 for (unsigned int j = 0; j < dofs_per_component; ++j)
1184 if (std::abs(values_dofs[j][0]) > tolerance &&
1185 (j != i ||
1186 std::abs(values_dofs[j][0] - Number(1)) > tolerance))
1187 constraints_hn.emplace_back(j, i, values_dofs[j][0]);
1188 }
1189
1190 // 2) extend for multiple components
1191 const unsigned int n_hn_constraints = constraints_hn.size();
1192 constraints_hn.resize(n_hn_constraints * n_components);
1193
1194 for (unsigned int c = 1; c < n_components; ++c)
1195 for (unsigned int i = 0; i < n_hn_constraints; ++i)
1196 constraints_hn[c * n_hn_constraints + i] = std::make_tuple(
1197 std::get<0>(constraints_hn[i]) + c * dofs_per_component,
1198 std::get<1>(constraints_hn[i]) + c * dofs_per_component,
1199 std::get<2>(constraints_hn[i]));
1200 }
1201
1202 void
1203 prepare_basis_vector(const unsigned int i)
1204 {
1205 this->i = i;
1206
1207 // compute i-th column of element stiffness matrix:
1208 // this could be simply performed as done at the moment with
1209 // matrix-free operator evaluation applied to a ith-basis vector
1210 VectorizedArrayType *dof_values = phi->begin_dof_values();
1211 for (unsigned int j = 0; j < dofs_per_cell; ++j)
1212 dof_values[j] = VectorizedArrayType();
1213 dof_values[i] = Number(1);
1214 }
1215
1216 void
1217 zero_basis_vector()
1218 {
1219 VectorizedArrayType *dof_values = phi->begin_dof_values();
1220 for (unsigned int j = 0; j < dofs_per_cell; ++j)
1221 dof_values[j] = VectorizedArrayType();
1222 }
1223
1224 void
1225 submit()
1226 {
1227 // if we have a block vector with components with the same DoFHandler,
1228 // we need to figure out which component and which DoF within the
1229 // component are we currently considering
1230 const unsigned int n_fe_components =
1231 phi->get_dof_info().start_components.back();
1232 const unsigned int comp =
1233 n_fe_components == 1 ? i / dofs_per_component : 0;
1234 const unsigned int i_comp =
1235 n_fe_components == 1 ? (i % dofs_per_component) : i;
1236
1237 // apply local constraint matrix from left and from right:
1238 // loop over all rows of transposed constrained matrix
1239 for (unsigned int v = 0; v < n_lanes_filled; ++v)
1240 {
1241 const auto &c_pool = c_pools[v];
1242
1243 for (unsigned int jj = c_pool.inverse_lookup_rows[i_comp];
1244 jj < c_pool.inverse_lookup_rows[i_comp + 1];
1245 ++jj)
1246 {
1247 const unsigned int j = c_pool.inverse_lookup_origins[jj].first;
1248 // apply constraint matrix from the left
1249 Number temp = 0.0;
1250 for (unsigned int k = c_pool.row[j]; k < c_pool.row[j + 1]; ++k)
1251 temp += c_pool.val[k] *
1252 phi->begin_dof_values()[comp * dofs_per_component +
1253 c_pool.col[k]][v];
1254
1255 // apply constraint matrix from the right
1256 diagonals_local_constrained
1257 [v][j + comp * c_pools[v].row_lid_to_gid.size()] +=
1258 temp * c_pool.val[c_pool.inverse_lookup_origins[jj].second];
1259 }
1260 }
1261 }
1262
1263 template <typename VectorType>
1264 inline void
1265 distribute_local_to_global(std::vector<VectorType *> &diagonal_global)
1266 {
1267 // STEP 4: assembly results: add into global vector
1268 const unsigned int n_fe_components =
1269 phi->get_dof_info().start_components.back();
1270
1271 if (n_fe_components == 1)
1272 AssertDimension(diagonal_global.size(), n_components);
1273
1274 for (unsigned int v = 0; v < n_lanes_filled; ++v)
1275 // if we have a block vector with components with the same
1276 // DoFHandler, we need to loop over all components manually and
1277 // need to apply the correct shift
1278 for (unsigned int j = 0; j < c_pools[v].row.size() - 1; ++j)
1279 for (unsigned int comp = 0;
1280 comp < (n_fe_components == 1 ?
1281 static_cast<unsigned int>(n_components) :
1282 1);
1283 ++comp)
1284 if (c_pools[v].row_lid_to_gid[j] != numbers::invalid_unsigned_int)
1286 *diagonal_global[n_fe_components == 1 ? comp : 0],
1287 c_pools[v].row_lid_to_gid[j],
1288 diagonals_local_constrained
1289 [v][j + comp * c_pools[v].row_lid_to_gid.size()]);
1290 }
1291
1292 bool
1293 has_simple_constraints() const
1294 {
1295 return has_simple_constraints_;
1296 }
1297
1298 private:
1299 FEEvaluationType *phi;
1301
1302 unsigned int dofs_per_component;
1303 unsigned int dofs_per_cell;
1304 unsigned int n_components;
1305
1306 unsigned int i;
1307
1308 unsigned int n_lanes_filled;
1309
1310 std::array<internal::LocalCSR<Number>, n_lanes> c_pools;
1311
1312 // local storage: buffer so that we access the global vector once
1313 // note: may be larger then dofs_per_cell in the presence of
1314 // constraints!
1315 std::array<std::vector<Number>, n_lanes> diagonals_local_constrained;
1316
1317 std::map<
1319 std::vector<std::tuple<unsigned int, unsigned int, Number>>>
1320 locally_relevant_constraints_hn_map;
1321
1322 // scratch arrays
1324
1325 std::vector<std::tuple<unsigned int, unsigned int, Number>>
1326 locally_relevant_constraints;
1327 std::vector<std::tuple<unsigned int, unsigned int, Number>>
1328 locally_relevant_constraints_tmp;
1329 std::vector<unsigned int> constraint_position;
1330 std::vector<unsigned char> is_constrained_hn;
1331 std::vector<unsigned int> inverse_lookup_count;
1332
1333 bool has_simple_constraints_;
1334 };
1335
1336 template <bool is_face,
1337 int dim,
1338 typename Number,
1339 typename VectorizedArrayType>
1340 bool
1341 is_fe_nothing(
1343 const std::pair<unsigned int, unsigned int> &range,
1344 const unsigned int dof_handler_index,
1345 const unsigned int quadrature_index,
1346 const unsigned int first_selected_component,
1347 const unsigned int fe_degree,
1348 const unsigned int n_q_points_1d,
1349 const bool is_interior_face = true)
1350 {
1351 const unsigned int static_n_q_points =
1352 is_face ? Utilities::pow(n_q_points_1d, dim - 1) :
1353 Utilities::pow(n_q_points_1d, dim);
1354
1355 unsigned int active_fe_index = 0;
1356 if (!is_face)
1357 active_fe_index =
1358 matrix_free.get_cell_active_fe_index(range, dof_handler_index);
1359 else if (is_interior_face)
1360 active_fe_index =
1361 matrix_free.get_face_range_category(range, dof_handler_index).first;
1362 else
1363 active_fe_index =
1364 matrix_free.get_face_range_category(range, dof_handler_index).second;
1365
1366 const auto init_data = ::internal::
1367 extract_initialization_data<is_face, dim, Number, VectorizedArrayType>(
1368 matrix_free,
1369 dof_handler_index,
1370 first_selected_component,
1371 quadrature_index,
1372 fe_degree,
1373 static_n_q_points,
1374 active_fe_index,
1375 numbers::invalid_unsigned_int /*active_quad_index*/,
1376 numbers::invalid_unsigned_int /*face_type*/);
1377
1378 return init_data.shape_info->dofs_per_component_on_cell == 0;
1379 }
1380
1381
1382
1386 template <int dim,
1387 int fe_degree,
1388 int n_q_points_1d,
1389 int n_components,
1390 typename Number,
1391 typename QuadOperation>
1392 class ComputeDiagonalCellAction
1393 {
1394 public:
1395 ComputeDiagonalCellAction(
1396 const unsigned int dof_handler_index,
1397 const QuadOperation &quad_operation,
1398 const EvaluationFlags::EvaluationFlags evaluation_flags,
1399 const EvaluationFlags::EvaluationFlags integration_flags)
1400 : m_dof_handler_index(dof_handler_index)
1401 , m_quad_operation(quad_operation)
1402 , m_evaluation_flags(evaluation_flags)
1403 , m_integration_flags(integration_flags)
1404 {}
1405
1406 KOKKOS_FUNCTION void
1410 {
1411 Portable::
1412 FEEvaluation<dim, fe_degree, n_q_points_1d, n_components, Number>
1413 fe_eval(data, m_dof_handler_index);
1415 *gpu_data = &data->precomputed_data[m_dof_handler_index];
1416 const int cell = data->cell_index;
1417
1418 constexpr int dofs_per_cell = decltype(fe_eval)::tensor_dofs_per_cell;
1419 typename decltype(fe_eval)::value_type
1420 diagonal[dofs_per_cell / n_components] = {};
1421 for (unsigned int i = 0; i < dofs_per_cell; ++i)
1422 {
1423 const auto c = i % n_components;
1424
1425 Kokkos::parallel_for(
1426 Kokkos::TeamThreadRange(data->team_member,
1427 dofs_per_cell / n_components),
1428 [&](unsigned int j) {
1429 typename decltype(fe_eval)::value_type val = {};
1430
1431 if constexpr (n_components == 1)
1432 {
1433 val = (i == j) ? 1 : 0;
1434 }
1435 else
1436 {
1437 val[c] = (i / n_components == j) ? 1 : 0;
1438 }
1439
1440 fe_eval.submit_dof_value(val, j);
1441 });
1442
1443 data->team_member.team_barrier();
1444
1445 Portable::internal::
1446 resolve_hanging_nodes<dim, fe_degree, false, Number>(
1447 data->team_member,
1448 gpu_data->constraint_weights,
1449 gpu_data->constraint_mask(cell * n_components + c),
1450 Kokkos::subview(data->shared_data[m_dof_handler_index].values,
1451 Kokkos::ALL,
1452 c));
1453
1454 fe_eval.evaluate(m_evaluation_flags);
1455 data->for_each_quad_point(
1456 [&](const int &q_point) { m_quad_operation(&fe_eval, q_point); });
1457 fe_eval.integrate(m_integration_flags);
1458
1459 Portable::internal::
1460 resolve_hanging_nodes<dim, fe_degree, true, Number>(
1461 data->team_member,
1462 gpu_data->constraint_weights,
1463 gpu_data->constraint_mask(cell * n_components + c),
1464 Kokkos::subview(data->shared_data[m_dof_handler_index].values,
1465 Kokkos::ALL,
1466 c));
1467
1468 Kokkos::single(Kokkos::PerTeam(data->team_member), [&] {
1469 if constexpr (n_components == 1)
1470 diagonal[i] = fe_eval.get_dof_value(i);
1471 else
1472 diagonal[i / n_components][i % n_components] =
1473 fe_eval.get_dof_value(i / n_components)[i % n_components];
1474 });
1475
1476 data->team_member.team_barrier();
1477 }
1478
1479 Kokkos::single(Kokkos::PerTeam(data->team_member), [&] {
1480 for (unsigned int i = 0; i < dofs_per_cell / n_components; ++i)
1481 fe_eval.submit_dof_value(diagonal[i], i);
1482 });
1483
1484 data->team_member.team_barrier();
1485
1486 // We need to do the same as distribute_local_to_global but without
1487 // constraints since we have already taken care of them earlier
1488 if (gpu_data->use_coloring)
1489 {
1490 Kokkos::parallel_for(
1491 Kokkos::TeamThreadRange(data->team_member, dofs_per_cell),
1492 [&](const int &i) {
1493 dst[gpu_data->local_to_global(i, cell)] +=
1494 data->shared_data[m_dof_handler_index].values(
1495 i % (dofs_per_cell / n_components),
1496 i / (dofs_per_cell / n_components));
1497 });
1498 }
1499 else
1500 {
1501 Kokkos::parallel_for(
1502 Kokkos::TeamThreadRange(data->team_member, dofs_per_cell),
1503 [&](const int &i) {
1504 Kokkos::atomic_add(&dst[gpu_data->local_to_global(i, cell)],
1505 data->shared_data[m_dof_handler_index]
1506 .values(i % (dofs_per_cell / n_components),
1507 i /
1508 (dofs_per_cell / n_components)));
1509 });
1510 }
1511 };
1512
1513 static constexpr unsigned int n_q_points =
1514 ::Utilities::pow(n_q_points_1d, dim);
1515
1516 private:
1517 const unsigned int m_dof_handler_index;
1518 const QuadOperation m_quad_operation;
1519 const EvaluationFlags::EvaluationFlags m_evaluation_flags;
1520 const EvaluationFlags::EvaluationFlags m_integration_flags;
1521 };
1522
1523 } // namespace internal
1524
1525
1526
1527 template <int dim,
1528 int fe_degree,
1529 int n_q_points_1d,
1530 int n_components,
1531 typename Number,
1532 typename MemorySpace,
1533 typename QuadOperation>
1534 void
1536 const Portable::MatrixFree<dim, Number> &matrix_free,
1538 const QuadOperation &quad_operation,
1539 EvaluationFlags::EvaluationFlags evaluation_flags,
1540 EvaluationFlags::EvaluationFlags integration_flags,
1541 const unsigned int dof_handler_index,
1542 const unsigned int quadrature_index,
1543 const unsigned int first_selected_component,
1544 const unsigned int first_vector_component)
1545 {
1546 Assert(quadrature_index == 0, ExcNotImplemented());
1547 Assert(first_selected_component == 0, ExcNotImplemented());
1548 Assert(first_vector_component == 0, ExcNotImplemented());
1549
1550 matrix_free.initialize_dof_vector(diagonal_global, dof_handler_index);
1551
1552
1553 internal::ComputeDiagonalCellAction<dim,
1554 fe_degree,
1555 n_q_points_1d,
1556 n_components,
1557 Number,
1558 QuadOperation>
1559 cell_action(dof_handler_index,
1560 quad_operation,
1561 evaluation_flags,
1562 integration_flags);
1564 matrix_free.cell_loop(cell_action, dummy, diagonal_global);
1565
1566 matrix_free.set_constrained_values(Number(1.),
1567 diagonal_global,
1568 dof_handler_index);
1569 }
1570
1571 template <int dim,
1572 int fe_degree,
1573 int n_q_points_1d,
1574 int n_components,
1575 typename Number,
1576 typename VectorizedArrayType,
1577 typename VectorType>
1578 void
1581 VectorType &diagonal_global,
1582 const std::function<void(FEEvaluation<dim,
1583 fe_degree,
1584 n_q_points_1d,
1585 n_components,
1586 Number,
1587 VectorizedArrayType> &)>
1588 &cell_operation,
1589 const unsigned int dof_handler_index,
1590 const unsigned int quadrature_index,
1591 const unsigned int first_selected_component,
1592 const unsigned int first_vector_component)
1593 {
1594 compute_diagonal<dim,
1595 fe_degree,
1596 n_q_points_1d,
1597 n_components,
1598 Number,
1599 VectorizedArrayType,
1600 VectorType>(matrix_free,
1601 diagonal_global,
1602 cell_operation,
1603 {},
1604 {},
1605 dof_handler_index,
1606 quadrature_index,
1607 first_selected_component,
1608 first_vector_component);
1609 }
1610
1611 template <typename CLASS,
1612 int dim,
1613 int fe_degree,
1614 int n_q_points_1d,
1615 int n_components,
1616 typename Number,
1617 typename VectorizedArrayType,
1618 typename VectorType>
1619 void
1622 VectorType &diagonal_global,
1623 void (CLASS::*cell_operation)(FEEvaluation<dim,
1624 fe_degree,
1625 n_q_points_1d,
1626 n_components,
1627 Number,
1628 VectorizedArrayType> &) const,
1629 const CLASS *owning_class,
1630 const unsigned int dof_handler_index,
1631 const unsigned int quadrature_index,
1632 const unsigned int first_selected_component,
1633 const unsigned int first_vector_component)
1634 {
1635 compute_diagonal<dim,
1636 fe_degree,
1637 n_q_points_1d,
1638 n_components,
1639 Number,
1640 VectorizedArrayType,
1641 VectorType>(
1642 matrix_free,
1643 diagonal_global,
1644 [&](auto &phi) { (owning_class->*cell_operation)(phi); },
1645 dof_handler_index,
1646 quadrature_index,
1647 first_selected_component,
1648 first_vector_component);
1649 }
1650
1651 template <int dim,
1652 int fe_degree,
1653 int n_q_points_1d,
1654 int n_components,
1655 typename Number,
1656 typename VectorizedArrayType,
1657 typename VectorType>
1658 void
1661 VectorType &diagonal_global,
1662 const std::function<void(FEEvaluation<dim,
1663 fe_degree,
1664 n_q_points_1d,
1665 n_components,
1666 Number,
1667 VectorizedArrayType> &)>
1668 &cell_operation,
1669 const std::function<void(FEFaceEvaluation<dim,
1670 fe_degree,
1671 n_q_points_1d,
1672 n_components,
1673 Number,
1674 VectorizedArrayType> &,
1675 FEFaceEvaluation<dim,
1676 fe_degree,
1677 n_q_points_1d,
1678 n_components,
1679 Number,
1680 VectorizedArrayType> &)>
1681 &face_operation,
1682 const std::function<void(FEFaceEvaluation<dim,
1683 fe_degree,
1684 n_q_points_1d,
1685 n_components,
1686 Number,
1687 VectorizedArrayType> &)>
1688 &boundary_operation,
1689 const unsigned int dof_handler_index,
1690 const unsigned int quadrature_index,
1691 const unsigned int first_selected_component,
1692 const unsigned int first_vector_component)
1693 {
1694 std::vector<typename ::internal::BlockVectorSelector<
1695 VectorType,
1696 IsBlockVector<VectorType>::value>::BaseVectorType *>
1697 diagonal_global_components(n_components);
1698
1699 for (unsigned int d = 0; d < n_components; ++d)
1700 diagonal_global_components[d] = ::internal::
1701 BlockVectorSelector<VectorType, IsBlockVector<VectorType>::value>::
1702 get_vector_component(diagonal_global, d + first_vector_component);
1703
1704 const auto &dof_info = matrix_free.get_dof_info(dof_handler_index);
1705
1706 if (dof_info.start_components.back() == 1)
1707 for (unsigned int comp = 0; comp < n_components; ++comp)
1708 {
1709 Assert(diagonal_global_components[comp] != nullptr,
1710 ExcMessage("The finite element underlying this FEEvaluation "
1711 "object is scalar, but you requested " +
1712 std::to_string(n_components) +
1713 " components via the template argument in "
1714 "FEEvaluation. In that case, you must pass an "
1715 "std::vector<VectorType> or a BlockVector to " +
1716 "read_dof_values and distribute_local_to_global."));
1718 *diagonal_global_components[comp], matrix_free, dof_info);
1719 }
1720 else
1721 {
1723 *diagonal_global_components[0], matrix_free, dof_info);
1724 }
1725
1726 using FEEvalType = FEEvaluation<dim,
1727 fe_degree,
1728 n_q_points_1d,
1729 n_components,
1730 Number,
1731 VectorizedArrayType>;
1732
1733 using FEFaceEvalType = FEFaceEvaluation<dim,
1734 fe_degree,
1735 n_q_points_1d,
1736 n_components,
1737 Number,
1738 VectorizedArrayType>;
1739
1740 internal::ComputeMatrixScratchData<dim, VectorizedArrayType, false>
1741 data_cell;
1742
1743 data_cell.dof_numbers = {dof_handler_index};
1744 data_cell.quad_numbers = {quadrature_index};
1745 data_cell.n_components = {n_components};
1746 data_cell.first_selected_components = {first_selected_component};
1747 data_cell.batch_type = {0};
1748
1749 data_cell.op_create =
1750 [&](const std::pair<unsigned int, unsigned int> &range) {
1751 std::vector<
1752 std::unique_ptr<FEEvaluationData<dim, VectorizedArrayType, false>>>
1753 phi;
1754
1755 if (!internal::is_fe_nothing<false>(matrix_free,
1756 range,
1757 dof_handler_index,
1758 quadrature_index,
1759 first_selected_component,
1760 fe_degree,
1761 n_q_points_1d))
1762 phi.emplace_back(
1763 std::make_unique<FEEvalType>(matrix_free,
1764 range,
1765 dof_handler_index,
1766 quadrature_index,
1767 first_selected_component));
1768
1769 return phi;
1770 };
1771
1772 data_cell.op_reinit = [](auto &phi, const unsigned batch) {
1773 if (phi.size() == 1)
1774 static_cast<FEEvalType &>(*phi[0]).reinit(batch);
1775 };
1776
1777 if (cell_operation)
1778 data_cell.op_compute = [&](auto &phi) {
1779 cell_operation(static_cast<FEEvalType &>(*phi[0]));
1780 };
1781
1782 internal::ComputeMatrixScratchData<dim, VectorizedArrayType, true>
1783 data_face;
1784
1785 data_face.dof_numbers = {dof_handler_index, dof_handler_index};
1786 data_face.quad_numbers = {quadrature_index, quadrature_index};
1787 data_face.n_components = {n_components, n_components};
1788 data_face.first_selected_components = {first_selected_component,
1789 first_selected_component};
1790 data_face.batch_type = {1, 2};
1791
1792 data_face.op_create =
1793 [&](const std::pair<unsigned int, unsigned int> &range) {
1794 std::vector<
1795 std::unique_ptr<FEEvaluationData<dim, VectorizedArrayType, true>>>
1796 phi;
1797
1798 if (!internal::is_fe_nothing<true>(matrix_free,
1799 range,
1800 dof_handler_index,
1801 quadrature_index,
1802 first_selected_component,
1803 fe_degree,
1804 n_q_points_1d,
1805 true) &&
1806 !internal::is_fe_nothing<true>(matrix_free,
1807 range,
1808 dof_handler_index,
1809 quadrature_index,
1810 first_selected_component,
1811 fe_degree,
1812 n_q_points_1d,
1813 false))
1814 {
1815 phi.emplace_back(
1816 std::make_unique<FEFaceEvalType>(matrix_free,
1817 range,
1818 true,
1819 dof_handler_index,
1820 quadrature_index,
1821 first_selected_component));
1822 phi.emplace_back(
1823 std::make_unique<FEFaceEvalType>(matrix_free,
1824 range,
1825 false,
1826 dof_handler_index,
1827 quadrature_index,
1828 first_selected_component));
1829 }
1830
1831 return phi;
1832 };
1833
1834 data_face.op_reinit = [](auto &phi, const unsigned batch) {
1835 if (phi.size() == 2)
1836 {
1837 static_cast<FEFaceEvalType &>(*phi[0]).reinit(batch);
1838 static_cast<FEFaceEvalType &>(*phi[1]).reinit(batch);
1839 }
1840 };
1841
1842 if (face_operation)
1843 data_face.op_compute = [&](auto &phi) {
1844 face_operation(static_cast<FEFaceEvalType &>(*phi[0]),
1845 static_cast<FEFaceEvalType &>(*phi[1]));
1846 };
1847
1848 internal::ComputeMatrixScratchData<dim, VectorizedArrayType, true>
1849 data_boundary;
1850
1851 data_boundary.dof_numbers = {dof_handler_index};
1852 data_boundary.quad_numbers = {quadrature_index};
1853 data_boundary.n_components = {n_components};
1854 data_boundary.first_selected_components = {first_selected_component};
1855 data_boundary.batch_type = {1};
1856
1857 data_boundary.op_create =
1858 [&](const std::pair<unsigned int, unsigned int> &range) {
1859 std::vector<
1860 std::unique_ptr<FEEvaluationData<dim, VectorizedArrayType, true>>>
1861 phi;
1862
1863 if (!internal::is_fe_nothing<true>(matrix_free,
1864 range,
1865 dof_handler_index,
1866 quadrature_index,
1867 first_selected_component,
1868 fe_degree,
1869 n_q_points_1d,
1870 true))
1871 phi.emplace_back(
1872 std::make_unique<FEFaceEvalType>(matrix_free,
1873 range,
1874 true,
1875 dof_handler_index,
1876 quadrature_index,
1877 first_selected_component));
1878
1879 return phi;
1880 };
1881
1882 data_boundary.op_reinit = [](auto &phi, const unsigned batch) {
1883 if (phi.size() == 1)
1884 static_cast<FEFaceEvalType &>(*phi[0]).reinit(batch);
1885 };
1886
1887 if (boundary_operation)
1888 data_boundary.op_compute = [&](auto &phi) {
1889 boundary_operation(static_cast<FEFaceEvalType &>(*phi[0]));
1890 };
1891
1892 internal::compute_diagonal(matrix_free,
1893 data_cell,
1894 data_face,
1895 data_boundary,
1896 diagonal_global,
1897 diagonal_global_components);
1898 }
1899
1900 namespace internal
1901 {
1902 template <int dim,
1903 typename Number,
1904 typename VectorizedArrayType,
1905 typename VectorType,
1906 typename VectorType2>
1907 void
1910 const internal::ComputeMatrixScratchData<dim, VectorizedArrayType, false>
1911 &data_cell,
1912 const internal::ComputeMatrixScratchData<dim, VectorizedArrayType, true>
1913 &data_face,
1914 const internal::ComputeMatrixScratchData<dim, VectorizedArrayType, true>
1915 &data_boundary,
1916 VectorType &diagonal_global,
1917 std::vector<VectorType2 *> &diagonal_global_components)
1918 {
1919 // TODO: can we remove diagonal_global_components as argument?
1920
1921 int dummy = 0;
1922
1923 using Helper =
1924 internal::ComputeDiagonalHelper<dim, VectorizedArrayType, false>;
1925
1926 using HelperFace =
1927 internal::ComputeDiagonalHelper<dim, VectorizedArrayType, true>;
1928
1931 scratch_data_internal;
1933
1934 const auto batch_operation =
1935 [&](auto &data,
1936 auto &scratch_data,
1937 const std::pair<unsigned int, unsigned int> &range) {
1938 if (!data.op_compute)
1939 return; // nothing to do
1940
1941 auto phi = data.op_create(range);
1942
1943 const unsigned int n_blocks = phi.size();
1944
1945 auto &helpers = scratch_data.get();
1946 helpers.resize(n_blocks);
1947
1948 for (unsigned int b = 0; b < n_blocks; ++b)
1949 helpers[b].initialize(*phi[b], matrix_free, data.n_components[b]);
1950
1951 for (unsigned int batch = range.first; batch < range.second; ++batch)
1952 {
1953 data.op_reinit(phi, batch);
1954
1955 for (unsigned int b = 0; b < n_blocks; ++b)
1956 helpers[b].reinit(batch);
1957
1958 if (n_blocks > 1)
1959 {
1960 Assert(std::all_of(helpers.begin(),
1961 helpers.end(),
1962 [](const auto &helper) {
1963 return helper.has_simple_constraints();
1964 }),
1966 }
1967
1968 for (unsigned int b = 0; b < n_blocks; ++b)
1969 {
1970 for (unsigned int i = 0;
1971 i < phi[b]->get_shape_info().dofs_per_component_on_cell *
1972 data.n_components[b];
1973 ++i)
1974 {
1975 for (unsigned int bb = 0; bb < n_blocks; ++bb)
1976 if (b == bb)
1977 helpers[bb].prepare_basis_vector(i);
1978 else
1979 helpers[bb].zero_basis_vector();
1980
1981 data.op_compute(phi);
1982 helpers[b].submit();
1983 }
1984
1985 helpers[b].distribute_local_to_global(
1986 diagonal_global_components);
1987 }
1988 }
1989 };
1990
1991 const auto cell_operation_wrapped =
1992 [&](const auto &, auto &, const auto &, const auto range) {
1993 batch_operation(data_cell, scratch_data, range);
1994 };
1995
1996 const auto face_operation_wrapped =
1997 [&](const auto &, auto &, const auto &, const auto range) {
1998 batch_operation(data_face, scratch_data_internal, range);
1999 };
2000
2001 const auto boundary_operation_wrapped =
2002 [&](const auto &, auto &, const auto &, const auto range) {
2003 batch_operation(data_boundary, scratch_data_bc, range);
2004 };
2005
2006 if (data_face.op_compute || data_boundary.op_compute)
2007 matrix_free.template loop<VectorType, int>(cell_operation_wrapped,
2008 face_operation_wrapped,
2009 boundary_operation_wrapped,
2010 diagonal_global,
2011 dummy,
2012 false);
2013 else
2014 matrix_free.template cell_loop<VectorType, int>(cell_operation_wrapped,
2015 diagonal_global,
2016 dummy,
2017 false);
2018 }
2019 } // namespace internal
2020
2021 template <typename CLASS,
2022 int dim,
2023 int fe_degree,
2024 int n_q_points_1d,
2025 int n_components,
2026 typename Number,
2027 typename VectorizedArrayType,
2028 typename VectorType>
2029 void
2032 VectorType &diagonal_global,
2033 void (CLASS::*cell_operation)(FEEvaluation<dim,
2034 fe_degree,
2035 n_q_points_1d,
2036 n_components,
2037 Number,
2038 VectorizedArrayType> &) const,
2039 void (CLASS::*face_operation)(FEFaceEvaluation<dim,
2040 fe_degree,
2041 n_q_points_1d,
2042 n_components,
2043 Number,
2044 VectorizedArrayType> &,
2045 FEFaceEvaluation<dim,
2046 fe_degree,
2047 n_q_points_1d,
2048 n_components,
2049 Number,
2050 VectorizedArrayType> &)
2051 const,
2052 void (CLASS::*boundary_operation)(FEFaceEvaluation<dim,
2053 fe_degree,
2054 n_q_points_1d,
2055 n_components,
2056 Number,
2057 VectorizedArrayType> &)
2058 const,
2059 const CLASS *owning_class,
2060 const unsigned int dof_handler_index,
2061 const unsigned int quadrature_index,
2062 const unsigned int first_selected_component,
2063 const unsigned int first_vector_component)
2064 {
2065 compute_diagonal<dim,
2066 fe_degree,
2067 n_q_points_1d,
2068 n_components,
2069 Number,
2070 VectorizedArrayType,
2071 VectorType>(
2072 matrix_free,
2073 diagonal_global,
2074 [&](auto &phi) { (owning_class->*cell_operation)(phi); },
2075 [&](auto &phi_m, auto &phi_p) {
2076 (owning_class->*face_operation)(phi_m, phi_p);
2077 },
2078 [&](auto &phi) { (owning_class->*boundary_operation)(phi); },
2079 dof_handler_index,
2080 quadrature_index,
2081 first_selected_component,
2082 first_vector_component);
2083 }
2084
2085 namespace internal
2086 {
2091 template <
2092 typename MatrixType,
2093 typename Number,
2094 std::enable_if_t<std::is_same_v<
2095 std::remove_const_t<
2096 std::remove_reference_t<typename MatrixType::value_type>>,
2097 std::remove_const_t<std::remove_reference_t<Number>>>> * = nullptr>
2099 create_new_affine_constraints_if_needed(
2100 const MatrixType &,
2101 const AffineConstraints<Number> &constraints,
2103 {
2104 return constraints;
2105 }
2106
2112 template <
2113 typename MatrixType,
2114 typename Number,
2115 std::enable_if_t<!std::is_same_v<
2116 std::remove_const_t<
2117 std::remove_reference_t<typename MatrixType::value_type>>,
2118 std::remove_const_t<std::remove_reference_t<Number>>>> * = nullptr>
2120 create_new_affine_constraints_if_needed(
2121 const MatrixType &,
2122 const AffineConstraints<Number> &constraints,
2124 &new_constraints)
2125 {
2126 new_constraints =
2127 std::make_unique<AffineConstraints<typename MatrixType::value_type>>();
2128 new_constraints->copy_from(constraints);
2129
2130 return *new_constraints;
2131 }
2132 } // namespace internal
2133
2134 template <int dim,
2135 int fe_degree,
2136 int n_q_points_1d,
2137 int n_components,
2138 typename Number,
2139 typename VectorizedArrayType,
2140 typename MatrixType>
2141 void
2144 const AffineConstraints<Number> &constraints_in,
2145 MatrixType &matrix,
2146 const std::function<void(FEEvaluation<dim,
2147 fe_degree,
2148 n_q_points_1d,
2149 n_components,
2150 Number,
2151 VectorizedArrayType> &)>
2152 &cell_operation,
2153 const unsigned int dof_handler_index,
2154 const unsigned int quadrature_index,
2155 const unsigned int first_selected_component)
2156 {
2157 compute_matrix<dim,
2158 fe_degree,
2159 n_q_points_1d,
2160 n_components,
2161 Number,
2162 VectorizedArrayType,
2163 MatrixType>(matrix_free,
2164 constraints_in,
2165 matrix,
2166 cell_operation,
2167 {},
2168 {},
2169 dof_handler_index,
2170 quadrature_index,
2171 first_selected_component);
2172 }
2173
2174 template <typename CLASS,
2175 int dim,
2176 int fe_degree,
2177 int n_q_points_1d,
2178 int n_components,
2179 typename Number,
2180 typename VectorizedArrayType,
2181 typename MatrixType>
2182 void
2185 const AffineConstraints<Number> &constraints,
2186 MatrixType &matrix,
2187 void (CLASS::*cell_operation)(FEEvaluation<dim,
2188 fe_degree,
2189 n_q_points_1d,
2190 n_components,
2191 Number,
2192 VectorizedArrayType> &) const,
2193 const CLASS *owning_class,
2194 const unsigned int dof_handler_index,
2195 const unsigned int quadrature_index,
2196 const unsigned int first_selected_component)
2197 {
2198 compute_matrix<dim,
2199 fe_degree,
2200 n_q_points_1d,
2201 n_components,
2202 Number,
2203 VectorizedArrayType,
2204 MatrixType>(
2205 matrix_free,
2206 constraints,
2207 matrix,
2208 [&](auto &phi) { (owning_class->*cell_operation)(phi); },
2209 dof_handler_index,
2210 quadrature_index,
2211 first_selected_component);
2212 }
2213
2214 template <int dim,
2215 int fe_degree,
2216 int n_q_points_1d,
2217 int n_components,
2218 typename Number,
2219 typename VectorizedArrayType,
2220 typename MatrixType>
2221 void
2224 const AffineConstraints<Number> &constraints_in,
2225 MatrixType &matrix,
2226 const std::function<void(FEEvaluation<dim,
2227 fe_degree,
2228 n_q_points_1d,
2229 n_components,
2230 Number,
2231 VectorizedArrayType> &)>
2232 &cell_operation,
2233 const std::function<void(FEFaceEvaluation<dim,
2234 fe_degree,
2235 n_q_points_1d,
2236 n_components,
2237 Number,
2238 VectorizedArrayType> &,
2239 FEFaceEvaluation<dim,
2240 fe_degree,
2241 n_q_points_1d,
2242 n_components,
2243 Number,
2244 VectorizedArrayType> &)>
2245 &face_operation,
2246 const std::function<void(FEFaceEvaluation<dim,
2247 fe_degree,
2248 n_q_points_1d,
2249 n_components,
2250 Number,
2251 VectorizedArrayType> &)>
2252 &boundary_operation,
2253 const unsigned int dof_handler_index,
2254 const unsigned int quadrature_index,
2255 const unsigned int first_selected_component)
2256 {
2257 using FEEvalType = FEEvaluation<dim,
2258 fe_degree,
2259 n_q_points_1d,
2260 n_components,
2261 Number,
2262 VectorizedArrayType>;
2263
2264 using FEFaceEvalType = FEFaceEvaluation<dim,
2265 fe_degree,
2266 n_q_points_1d,
2267 n_components,
2268 Number,
2269 VectorizedArrayType>;
2270
2271 internal::ComputeMatrixScratchData<dim, VectorizedArrayType, false>
2272 data_cell;
2273
2274 data_cell.dof_numbers = {dof_handler_index};
2275 data_cell.quad_numbers = {quadrature_index};
2276 data_cell.n_components = {n_components};
2277 data_cell.first_selected_components = {first_selected_component};
2278 data_cell.batch_type = {0};
2279
2280 data_cell.op_create =
2281 [&](const std::pair<unsigned int, unsigned int> &range) {
2282 std::vector<
2283 std::unique_ptr<FEEvaluationData<dim, VectorizedArrayType, false>>>
2284 phi;
2285
2286 if (!internal::is_fe_nothing<false>(matrix_free,
2287 range,
2288 dof_handler_index,
2289 quadrature_index,
2290 first_selected_component,
2291 fe_degree,
2292 n_q_points_1d))
2293 phi.emplace_back(
2294 std::make_unique<FEEvalType>(matrix_free,
2295 range,
2296 dof_handler_index,
2297 quadrature_index,
2298 first_selected_component));
2299
2300 return phi;
2301 };
2302
2303 data_cell.op_reinit = [](auto &phi, const unsigned batch) {
2304 if (phi.size() == 1)
2305 static_cast<FEEvalType &>(*phi[0]).reinit(batch);
2306 };
2307
2308 if (cell_operation)
2309 data_cell.op_compute = [&](auto &phi) {
2310 cell_operation(static_cast<FEEvalType &>(*phi[0]));
2311 };
2312
2313 internal::ComputeMatrixScratchData<dim, VectorizedArrayType, true>
2314 data_face;
2315
2316 data_face.dof_numbers = {dof_handler_index, dof_handler_index};
2317 data_face.quad_numbers = {quadrature_index, quadrature_index};
2318 data_face.n_components = {n_components, n_components};
2319 data_face.first_selected_components = {first_selected_component,
2320 first_selected_component};
2321 data_face.batch_type = {1, 2};
2322
2323 data_face.op_create =
2324 [&](const std::pair<unsigned int, unsigned int> &range) {
2325 std::vector<
2326 std::unique_ptr<FEEvaluationData<dim, VectorizedArrayType, true>>>
2327 phi;
2328
2329 if (!internal::is_fe_nothing<true>(matrix_free,
2330 range,
2331 dof_handler_index,
2332 quadrature_index,
2333 first_selected_component,
2334 fe_degree,
2335 n_q_points_1d,
2336 true) &&
2337 !internal::is_fe_nothing<true>(matrix_free,
2338 range,
2339 dof_handler_index,
2340 quadrature_index,
2341 first_selected_component,
2342 fe_degree,
2343 n_q_points_1d,
2344 false))
2345 {
2346 phi.emplace_back(
2347 std::make_unique<FEFaceEvalType>(matrix_free,
2348 range,
2349 true,
2350 dof_handler_index,
2351 quadrature_index,
2352 first_selected_component));
2353 phi.emplace_back(
2354 std::make_unique<FEFaceEvalType>(matrix_free,
2355 range,
2356 false,
2357 dof_handler_index,
2358 quadrature_index,
2359 first_selected_component));
2360 }
2361
2362 return phi;
2363 };
2364
2365 data_face.op_reinit = [](auto &phi, const unsigned batch) {
2366 if (phi.size() == 2)
2367 {
2368 static_cast<FEFaceEvalType &>(*phi[0]).reinit(batch);
2369 static_cast<FEFaceEvalType &>(*phi[1]).reinit(batch);
2370 }
2371 };
2372
2373 if (face_operation)
2374 data_face.op_compute = [&](auto &phi) {
2375 face_operation(static_cast<FEFaceEvalType &>(*phi[0]),
2376 static_cast<FEFaceEvalType &>(*phi[1]));
2377 };
2378
2379 internal::ComputeMatrixScratchData<dim, VectorizedArrayType, true>
2380 data_boundary;
2381
2382 data_boundary.dof_numbers = {dof_handler_index};
2383 data_boundary.quad_numbers = {quadrature_index};
2384 data_boundary.n_components = {n_components};
2385 data_boundary.first_selected_components = {first_selected_component};
2386 data_boundary.batch_type = {1};
2387
2388 data_boundary.op_create =
2389 [&](const std::pair<unsigned int, unsigned int> &range) {
2390 std::vector<
2391 std::unique_ptr<FEEvaluationData<dim, VectorizedArrayType, true>>>
2392 phi;
2393
2394 if (!internal::is_fe_nothing<true>(matrix_free,
2395 range,
2396 dof_handler_index,
2397 quadrature_index,
2398 first_selected_component,
2399 fe_degree,
2400 n_q_points_1d,
2401 true))
2402 phi.emplace_back(
2403 std::make_unique<FEFaceEvalType>(matrix_free,
2404 range,
2405 true,
2406 dof_handler_index,
2407 quadrature_index,
2408 first_selected_component));
2409
2410 return phi;
2411 };
2412
2413 data_boundary.op_reinit = [](auto &phi, const unsigned batch) {
2414 if (phi.size() == 1)
2415 static_cast<FEFaceEvalType &>(*phi[0]).reinit(batch);
2416 };
2417
2418 if (boundary_operation)
2419 data_boundary.op_compute = [&](auto &phi) {
2420 boundary_operation(static_cast<FEFaceEvalType &>(*phi[0]));
2421 };
2422
2423 internal::compute_matrix(
2424 matrix_free, constraints_in, data_cell, data_face, data_boundary, matrix);
2425 }
2426
2427 namespace internal
2428 {
2429 template <int dim,
2430 typename Number,
2431 typename VectorizedArrayType,
2432 typename MatrixType>
2433 void
2436 const AffineConstraints<Number> &constraints_in,
2437 const internal::ComputeMatrixScratchData<dim, VectorizedArrayType, false>
2438 &data_cell,
2439 const internal::ComputeMatrixScratchData<dim, VectorizedArrayType, true>
2440 &data_face,
2441 const internal::ComputeMatrixScratchData<dim, VectorizedArrayType, true>
2442 &data_boundary,
2443 MatrixType &matrix)
2444 {
2445 std::unique_ptr<AffineConstraints<typename MatrixType::value_type>>
2446 constraints_for_matrix;
2448 internal::create_new_affine_constraints_if_needed(
2449 matrix, constraints_in, constraints_for_matrix);
2450
2451 const auto batch_operation =
2452 [&matrix_free, &constraints, &matrix](
2453 auto &data, const std::pair<unsigned int, unsigned int> &range) {
2454 if (!data.op_compute)
2455 return; // nothing to do
2456
2457 auto phi = data.op_create(range);
2458
2459 const unsigned int n_blocks = phi.size();
2460
2461 if (n_blocks == 0)
2462 return;
2463
2464 Table<1, unsigned int> dofs_per_cell(n_blocks);
2465
2466 Table<1, std::vector<types::global_dof_index>> dof_indices(n_blocks);
2468 n_blocks, VectorizedArrayType::size());
2469 Table<1, std::vector<unsigned int>> lexicographic_numbering(n_blocks);
2470 Table<2,
2471 std::array<FullMatrix<typename MatrixType::value_type>,
2472 VectorizedArrayType::size()>>
2473 matrices(n_blocks, n_blocks);
2474
2475 for (unsigned int b = 0; b < n_blocks; ++b)
2476 {
2477 const auto &fe = matrix_free.get_dof_handler(data.dof_numbers[b])
2478 .get_fe(phi[b]->get_active_fe_index());
2479
2480 const auto component_base =
2481 matrix_free.get_dof_info(data.dof_numbers[b])
2482 .component_to_base_index[data.first_selected_components[b]];
2483 const auto component_in_base =
2484 data.first_selected_components[b] -
2485 matrix_free.get_dof_info(data.dof_numbers[b])
2486 .start_components[component_base];
2487
2488 const auto &shape_info = matrix_free.get_shape_info(
2489 data.dof_numbers[b],
2490 data.quad_numbers[b],
2491 component_base,
2492 phi[b]->get_active_fe_index(),
2493 phi[b]->get_active_quadrature_index());
2494
2495 dofs_per_cell[b] =
2496 shape_info.dofs_per_component_on_cell * data.n_components[b];
2497
2498 dof_indices[b].resize(fe.n_dofs_per_cell());
2499
2500 for (unsigned int v = 0; v < VectorizedArrayType::size(); ++v)
2501 dof_indices_mf[b][v].resize(dofs_per_cell[b]);
2502
2503 lexicographic_numbering[b].insert(
2504 lexicographic_numbering[b].begin(),
2505 shape_info.lexicographic_numbering.begin() +
2506 component_in_base * shape_info.dofs_per_component_on_cell,
2507 shape_info.lexicographic_numbering.begin() +
2508 (component_in_base + data.n_components[b]) *
2509 shape_info.dofs_per_component_on_cell);
2510 }
2511
2512 for (unsigned int bj = 0; bj < n_blocks; ++bj)
2513 for (unsigned int bi = 0; bi < n_blocks; ++bi)
2514 std::fill_n(matrices[bi][bj].begin(),
2515 VectorizedArrayType::size(),
2517 dofs_per_cell[bi], dofs_per_cell[bj]));
2518
2519 for (auto batch = range.first; batch < range.second; ++batch)
2520 {
2521 data.op_reinit(phi, batch);
2522
2523 const unsigned int n_filled_lanes =
2524 data.is_face ?
2525 matrix_free.n_active_entries_per_face_batch(batch) :
2526 matrix_free.n_active_entries_per_cell_batch(batch);
2527
2528 for (unsigned int v = 0; v < n_filled_lanes; ++v)
2529 for (unsigned int b = 0; b < n_blocks; ++b)
2530 {
2531 unsigned int const cell_index =
2532 (data.batch_type[b] == 0) ?
2533 (batch * VectorizedArrayType::size() + v) :
2534 ((data.batch_type[b] == 1) ?
2535 matrix_free.get_face_info(batch).cells_interior[v] :
2536 matrix_free.get_face_info(batch).cells_exterior[v]);
2537
2538 const auto cell_iterator = matrix_free.get_cell_iterator(
2539 cell_index / VectorizedArrayType::size(),
2540 cell_index % VectorizedArrayType::size(),
2541 data.dof_numbers[b]);
2542
2543 if (matrix_free.get_mg_level() !=
2545 cell_iterator->get_mg_dof_indices(dof_indices[b]);
2546 else
2547 cell_iterator->get_dof_indices(dof_indices[b]);
2548
2549 for (unsigned int j = 0; j < dofs_per_cell[b]; ++j)
2550 dof_indices_mf[b][v][j] =
2551 dof_indices[b][lexicographic_numbering[b][j]];
2552 }
2553
2554 for (unsigned int bj = 0; bj < n_blocks; ++bj)
2555 {
2556 for (unsigned int j = 0; j < dofs_per_cell[bj]; ++j)
2557 {
2558 for (unsigned int bi = 0; bi < n_blocks; ++bi)
2559 for (unsigned int i = 0; i < dofs_per_cell[bi]; ++i)
2560 phi[bi]->begin_dof_values()[i] =
2561 (bj == bi) ? static_cast<Number>(i == j) : 0.0;
2562
2563 data.op_compute(phi);
2564
2565 for (unsigned int bi = 0; bi < n_blocks; ++bi)
2566 for (unsigned int i = 0; i < dofs_per_cell[bi]; ++i)
2567 for (unsigned int v = 0; v < n_filled_lanes; ++v)
2568 matrices[bi][bj][v](i, j) =
2569 phi[bi]->begin_dof_values()[i][v];
2570 }
2571
2572 for (unsigned int v = 0; v < n_filled_lanes; ++v)
2573 for (unsigned int bi = 0; bi < n_blocks; ++bi)
2574 if (bi == bj)
2575 // specialization for blocks on the diagonal
2576 // to writing into diagonal elements of the
2577 // matrix if the corresponding degree of freedom
2578 // is constrained, see also the documentation
2579 // of AffineConstraints::distribute_local_to_global()
2580 constraints.distribute_local_to_global(
2581 matrices[bi][bi][v], dof_indices_mf[bi][v], matrix);
2582 else
2583 constraints.distribute_local_to_global(
2584 matrices[bi][bj][v],
2585 dof_indices_mf[bi][v],
2586 dof_indices_mf[bj][v],
2587 matrix);
2588 }
2589 }
2590 };
2591
2592 const auto cell_operation_wrapped =
2593 [&](const auto &, auto &, const auto &, const auto range) {
2594 batch_operation(data_cell, range);
2595 };
2596
2597 const auto face_operation_wrapped =
2598 [&](const auto &, auto &, const auto &, const auto range) {
2599 batch_operation(data_face, range);
2600 };
2601
2602 const auto boundary_operation_wrapped =
2603 [&](const auto &, auto &, const auto &, const auto range) {
2604 batch_operation(data_boundary, range);
2605 };
2606
2607 if (data_face.op_compute || data_boundary.op_compute)
2608 {
2609 matrix_free.template loop<MatrixType, MatrixType>(
2610 cell_operation_wrapped,
2611 face_operation_wrapped,
2612 boundary_operation_wrapped,
2613 matrix,
2614 matrix);
2615 }
2616 else
2617 matrix_free.template cell_loop<MatrixType, MatrixType>(
2618 cell_operation_wrapped, matrix, matrix);
2619
2620 matrix.compress(VectorOperation::add);
2621 }
2622 } // namespace internal
2623
2624 template <typename CLASS,
2625 int dim,
2626 int fe_degree,
2627 int n_q_points_1d,
2628 int n_components,
2629 typename Number,
2630 typename VectorizedArrayType,
2631 typename MatrixType>
2632 void
2635 const AffineConstraints<Number> &constraints,
2636 MatrixType &matrix,
2637 void (CLASS::*cell_operation)(FEEvaluation<dim,
2638 fe_degree,
2639 n_q_points_1d,
2640 n_components,
2641 Number,
2642 VectorizedArrayType> &) const,
2643 void (CLASS::*face_operation)(FEFaceEvaluation<dim,
2644 fe_degree,
2645 n_q_points_1d,
2646 n_components,
2647 Number,
2648 VectorizedArrayType> &,
2649 FEFaceEvaluation<dim,
2650 fe_degree,
2651 n_q_points_1d,
2652 n_components,
2653 Number,
2654 VectorizedArrayType> &)
2655 const,
2656 void (CLASS::*boundary_operation)(FEFaceEvaluation<dim,
2657 fe_degree,
2658 n_q_points_1d,
2659 n_components,
2660 Number,
2661 VectorizedArrayType> &)
2662 const,
2663 const CLASS *owning_class,
2664 const unsigned int dof_handler_index,
2665 const unsigned int quadrature_index,
2666 const unsigned int first_selected_component)
2667 {
2668 compute_matrix<dim,
2669 fe_degree,
2670 n_q_points_1d,
2671 n_components,
2672 Number,
2673 VectorizedArrayType,
2674 MatrixType>(
2675 matrix_free,
2676 constraints,
2677 matrix,
2678 [&](auto &phi) { (owning_class->*cell_operation)(phi); },
2679 [&](auto &phi_m, auto &phi_p) {
2680 (owning_class->*face_operation)(phi_m, phi_p);
2681 },
2682 [&](auto &phi) { (owning_class->*boundary_operation)(phi); },
2683 dof_handler_index,
2684 quadrature_index,
2685 first_selected_component);
2686 }
2687
2688#endif // DOXYGEN
2689
2690} // namespace MatrixFreeTools
2691
2693
2694
2695#endif
*  *  iterator begin()
*  *  Point< dim > operator()(const Point< dim > &p) const * 
***mech_lbc_system increment_interpolation_handlers push_back(scale_z_handler)
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 n_active_entries_per_cell_batch(const unsigned int cell_batch_index) const
unsigned int get_mg_level() const
std::pair< unsigned int, unsigned int > get_face_range_category(const std::pair< unsigned int, unsigned int > face_batch_range, const unsigned int dof_handler_index=numbers::invalid_unsigned_int) 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
unsigned int get_cell_active_fe_index(const std::pair< unsigned int, unsigned int > range, const unsigned int dof_handler_index=numbers::invalid_unsigned_int) 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 unsigned int dof_handler_index=0) const
void set_constrained_values(const Number value, VectorType &dst, const unsigned int dof_handler_index=0) 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:38
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
unsigned int level
Definition grid_out.cc:4642
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:314
std::vector< index_type > data
Definition mpi.cc:734
std::size_t size
Definition mpi.cc:733
EvaluationFlags
The EvaluationFlags enum.
@ matrix
Contents is actually a matrix.
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:47
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_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_handler_index=0, const unsigned int quadrature_index=0, const unsigned int first_selected_component=0)
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_handler_index=0, const unsigned int quadrature_index=0, const unsigned int first_selected_component=0, const unsigned int first_vector_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)
*  *  if(update_pressure &update_flags) *  compute_pressure(constitutive_request
*  *  *  RotationFunction< dim, Number >::RotationFunction Number(dim)
*  *  *  *  std::vector< Number > ThermoPlasticMaterial< dim, ViscoplasticYieldLaw, Number >::get_state_parameters   const
Kokkos::View< Number *, MemorySpace::Default::kokkos_space > DeviceVector
constexpr T pow(const T base, const int iexp)
Definition utilities.h:966
std::uint8_t compressed_constraint_kind
Definition dof_info.h:84
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 reinit(MatrixBlock< MatrixType > &v, const BlockSparsityPattern &p)
void check_vector_compatibility(const VectorType &vec, const MatrixFree< dim, Number, VectorizedArrayType > &, const internal::MatrixFreeFunctions::DoFInfo &dof_info)
constexpr unsigned int invalid_unsigned_int
Definition types.h:228
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:675
std::vector< unsigned int > start_components
Definition dof_info.h:669