deal.II version GIT relicensing-6809-ge913b9bb34 2026-09-25 17: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
affine_constraints.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) 1998 - 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_affine_constraints_h
14#define dealii_affine_constraints_h
15
16#include <deal.II/base/config.h>
17
21#include <deal.II/base/table.h>
24
26#include <deal.II/lac/vector.h>
28
29#include <algorithm>
30#include <set>
31#include <type_traits>
32#include <utility>
33#include <vector>
34
36
37// Forward declarations
38#ifndef DOXYGEN
39template <typename>
40class FullMatrix;
41class SparsityPattern;
45template <typename number>
46class SparseMatrix;
47template <typename number>
49
50namespace internal
51{
52 namespace AffineConstraints
53 {
55
73 struct Distributing
74 {
75 Distributing(const size_type global_row = numbers::invalid_size_type,
76 const size_type local_row = numbers::invalid_size_type);
77
78 Distributing(const Distributing &in);
79
80 Distributing &
81 operator=(const Distributing &in);
82
83 bool
84 operator<(const Distributing &in) const
85 {
86 return global_row < in.global_row;
87 }
88
89 size_type global_row;
90 size_type local_row;
91 mutable size_type constraint_position;
92 };
93
94
95
107 template <typename number>
108 struct DataCache
109 {
110 DataCache();
111
112 void
113 reinit();
114
116 insert_new_index(const std::pair<size_type, number> &pair);
117
118 void
119 append_index(const size_type index,
120 const std::pair<size_type, number> &pair);
121
123 get_size(const size_type index) const;
124
125 const std::pair<size_type, number> *
126 get_entry(const size_type index) const;
127
128 size_type row_length;
129
130 std::vector<std::pair<size_type, number>> data;
131
132 std::vector<size_type> individual_size;
133 };
134
135
136
165 template <typename number>
166 class GlobalRowsFromLocal
167 {
168 public:
172 GlobalRowsFromLocal();
173
174 void
175 reinit(const size_type n_local_rows);
176
177 void
178 insert_index(const size_type global_row,
179 const size_type local_row,
180 const number constraint_value);
181 void
182 sort();
183
184 void
185 print(std::ostream &os);
186
191 size() const;
192
198 size(const size_type counter_index) const;
199
204 global_row(const size_type counter_index) const;
205
209 size_type &
210 global_row(const size_type counter_index);
211
218 local_row(const size_type counter_index) const;
219
223 size_type &
224 local_row(const size_type counter_index);
225
232 local_row(const size_type counter_index,
233 const size_type index_in_constraint) const;
234
239 number
240 constraint_value(const size_type counter_index,
241 const size_type index_in_constraint) const;
242
249 bool
250 have_indirect_rows() const;
251
256 void
257 insert_constraint(const size_type constrained_local_dof);
258
267 n_constraints() const;
268
274 n_inhomogeneities() const;
275
282 void
283 set_ith_constraint_inhomogeneous(const size_type i);
284
290 constraint_origin(size_type i) const;
291
297 std::vector<Distributing> total_row_indices;
298
299 private:
303 DataCache<number> data_cache;
304
309 size_type n_active_rows;
310
315 size_type n_inhomogeneous_rows;
316 };
317
318
319
337 template <typename number>
338 struct ScratchData
339 {
343 ScratchData()
344 : in_use(false)
345 {}
346
350 ScratchData(const ScratchData &)
351 : in_use(false)
352 {}
353
357 bool in_use;
358
362 std::vector<std::pair<size_type, size_type>> new_entries;
363
367 std::vector<size_type> rows;
368
372 std::vector<size_type> columns;
373
377 std::vector<number> values;
378
382 std::vector<size_type> block_starts;
383
387 std::vector<size_type> vector_indices;
388
392 std::vector<number> vector_values;
393
397 GlobalRowsFromLocal<number> global_rows;
398
402 GlobalRowsFromLocal<number> global_columns;
403 };
404 } // namespace AffineConstraints
405} // namespace internal
406
407namespace internal
408{
409 namespace AffineConstraintsImplementation
410 {
411 template <typename VectorType>
412 void
413 set_zero_all(const std::vector<types::global_dof_index> &cm,
414 VectorType &vec);
415
416 template <class T>
417 void
418 set_zero_all(const std::vector<types::global_dof_index> &cm,
419 ::Vector<T> &vec);
420
421 template <class T>
422 void
423 set_zero_all(const std::vector<types::global_dof_index> &cm,
424 ::BlockVector<T> &vec);
425 } // namespace AffineConstraintsImplementation
426} // namespace internal
427#endif
428
429
430
541template <typename number = double>
543{
544public:
549
577
596
620 "Use the constructor with two index set arguments.")
621 explicit AffineConstraints(const IndexSet &locally_stored_constraints);
622
655 const IndexSet &locally_stored_constraints);
656
660 explicit AffineConstraints(const AffineConstraints &affine_constraints);
661
665 AffineConstraints(AffineConstraints &&affine_constraints) noexcept =
666 default; // NOLINT
667
678 operator=(const AffineConstraints &) = delete;
679
684 operator=(AffineConstraints &&affine_constraints) noexcept =
685 default; // NOLINT
686
693 template <typename other_number>
694 void
695 copy_from(const AffineConstraints<other_number> &other);
696
705 void
707
717 "Use the reinit() function with two index set arguments.")
718 void
719 reinit(const IndexSet &locally_stored_constraints);
720
729 void
731 const IndexSet &locally_stored_constraints);
732
741 bool
742 can_store_line(const size_type line_n) const;
743
752 const IndexSet &
754
761 const IndexSet &
763
792 DEAL_II_DEPRECATED_WITH_COMMENT("Use get_view() and merge() instead.")
793 void
795 const IndexSet &filter);
796
847 void
849 const size_type constrained_dof,
850 const ArrayView<const std::pair<size_type, number>> &dependencies,
851 const number inhomogeneity = 0);
852
870 void
871 constrain_dof_to_zero(const size_type constrained_dof);
872
877 void
878 add_line(const size_type line_n);
879
892 void
893 add_lines(const std::vector<bool> &lines);
894
907 void
909
922 void
924
940 void
941 add_entry(const size_type constrained_dof_index,
942 const size_type column,
943 const number weight);
944
950 void
952 const size_type constrained_dof_index,
953 const std::vector<std::pair<size_type, number>> &col_weight_pairs);
954
966 void
967 set_inhomogeneity(const size_type constrained_dof_index, const number value);
968
990 void
992
998 bool
999 is_closed() const;
1000
1006 bool
1008
1033 template <typename other_number>
1034 void
1036 const AffineConstraints<other_number> &other_constraints,
1037 const MergeConflictBehavior merge_conflict_behavior = no_conflicts_allowed,
1038 const bool allow_different_local_lines = false);
1039
1052 void
1053 shift(const size_type offset);
1054
1104 get_view(const IndexSet &mask) const;
1105
1113 void
1115
1128 size_type
1130
1135 size_type
1137
1143 size_type
1145
1155 bool
1156 is_constrained(const size_type line_n) const;
1157
1169 bool
1171
1178 bool
1180 const size_type line_n_2) const;
1181
1192 size_type
1194
1199 bool
1201
1207 bool
1209
1214 const std::vector<std::pair<size_type, number>> *
1216
1221 number
1222 get_inhomogeneity(const size_type line_n) const;
1223
1244 void
1245 print(std::ostream &out) const;
1246
1259 void
1260 write_dot(std::ostream &) const;
1261
1266 std::size_t
1268
1275 void
1276 resolve_indices(std::vector<types::global_dof_index> &indices) const;
1277
1303 void
1304 condense(SparsityPattern &sparsity) const;
1305
1309 void
1311
1316 void
1318
1323 void
1325
1333 void
1334 condense(SparseMatrix<number> &matrix) const;
1335
1339 void
1340 condense(BlockSparseMatrix<number> &matrix) const;
1341
1353 template <typename VectorType>
1354 void
1355 condense(VectorType &vec) const;
1356
1363 template <typename VectorType>
1364 void
1365 condense(const VectorType &vec_ghosted, VectorType &output) const;
1366
1379 template <typename VectorType>
1380 void
1381 condense(SparseMatrix<number> &matrix, VectorType &vector) const;
1382
1387 template <typename BlockVectorType>
1388 void
1389 condense(BlockSparseMatrix<number> &matrix, BlockVectorType &vector) const;
1390
1397 template <typename VectorType>
1398 void
1399 set_zero(VectorType &vec) const;
1400
1456 template <class InVector, class OutVector>
1457 void
1458 distribute_local_to_global(const InVector &local_vector,
1459 const std::vector<size_type> &local_dof_indices,
1460 OutVector &global_vector) const;
1461
1509 template <typename VectorType>
1510 void
1511 distribute_local_to_global(const Vector<number> &local_vector,
1512 const std::vector<size_type> &local_dof_indices,
1513 VectorType &global_vector,
1514 const FullMatrix<number> &local_matrix) const;
1515
1535 template <typename VectorType>
1536 void
1538 const Vector<number> &local_vector,
1539 const std::vector<size_type> &local_dof_indices_row,
1540 const std::vector<size_type> &local_dof_indices_col,
1541 VectorType &global_vector,
1542 const FullMatrix<number> &local_matrix,
1543 bool diagonal = false) const;
1544
1548 template <typename VectorType>
1549 void
1551 const number value,
1552 VectorType &global_vector) const;
1553
1586 template <typename ForwardIteratorVec,
1587 typename ForwardIteratorInd,
1588 typename VectorType>
1589 void
1590 distribute_local_to_global(ForwardIteratorVec local_vector_begin,
1591 ForwardIteratorVec local_vector_end,
1592 ForwardIteratorInd local_indices_begin,
1593 VectorType &global_vector) const;
1594
1646 template <typename MatrixType>
1647 void
1648 distribute_local_to_global(const FullMatrix<number> &local_matrix,
1649 const std::vector<size_type> &local_dof_indices,
1650 MatrixType &global_matrix) const;
1651
1679 template <typename MatrixType>
1680 void
1681 distribute_local_to_global(const FullMatrix<number> &local_matrix,
1682 const std::vector<size_type> &row_indices,
1683 const std::vector<size_type> &col_indices,
1684 MatrixType &global_matrix) const;
1685
1702 template <typename MatrixType>
1703 void
1704 distribute_local_to_global(const FullMatrix<number> &local_matrix,
1705 const std::vector<size_type> &row_indices,
1706 const AffineConstraints &column_affine_constraints,
1707 const std::vector<size_type> &column_indices,
1708 MatrixType &global_matrix) const;
1709
1730 template <typename MatrixType, typename VectorType>
1731 void
1732 distribute_local_to_global(const FullMatrix<number> &local_matrix,
1733 const Vector<number> &local_vector,
1734 const std::vector<size_type> &local_dof_indices,
1735 MatrixType &global_matrix,
1736 VectorType &global_vector,
1737 bool use_inhomogeneities_for_rhs = false) const;
1738
1792 void
1794 const std::vector<size_type> &local_dof_indices,
1795 SparsityPatternBase &sparsity_pattern,
1796 const bool keep_constrained_entries = true,
1797 const Table<2, bool> &dof_mask = Table<2, bool>()) const;
1798
1802 void
1804 const std::vector<size_type> &row_indices,
1805 const std::vector<size_type> &col_indices,
1806 SparsityPatternBase &sparsity_pattern,
1807 const bool keep_constrained_entries = true,
1808 const Table<2, bool> &dof_mask = Table<2, bool>()) const;
1809
1814 void
1816 const std::vector<size_type> &row_indices,
1817 const AffineConstraints<number> &col_constraints,
1818 const std::vector<size_type> &col_indices,
1819 SparsityPatternBase &sparsity_pattern,
1820 const bool keep_constrained_entries = true,
1821 const Table<2, bool> &dof_mask = Table<2, bool>()) const;
1822
1842 template <typename ForwardIteratorVec,
1843 typename ForwardIteratorInd,
1844 typename VectorType>
1845 void
1846 get_dof_values(const VectorType &global_vector,
1847 ForwardIteratorInd local_indices_begin,
1848 ForwardIteratorVec local_vector_begin,
1849 ForwardIteratorVec local_vector_end) const;
1850
1872 template <typename VectorType>
1873 void
1874 distribute(VectorType &vec) const;
1875
1884 {
1889 using Entries = std::vector<std::pair<size_type, number>>;
1890
1897
1906
1911
1915 ConstraintLine(const size_type &index = numbers::invalid_dof_index,
1916 const typename AffineConstraints<
1917 number>::ConstraintLine::Entries &entries = {},
1918 const number inhomogeneity = 0.0);
1919
1923 ConstraintLine(const ConstraintLine &other) = default;
1924
1928 ConstraintLine(ConstraintLine &&other) noexcept = default;
1929
1934 operator=(const ConstraintLine &other) = default;
1935
1940 operator=(ConstraintLine &&other) noexcept = default;
1941
1946 std::size_t
1948
1954 template <class Archive>
1955 void
1956 serialize(Archive &ar, const unsigned int)
1957 {
1958 ar &index &entries &inhomogeneity;
1959 }
1960
1964 friend void
1966 {
1967 std::swap(l1.index, l2.index);
1968 std::swap(l1.entries, l2.entries);
1969 std::swap(l1.inhomogeneity, l2.inhomogeneity);
1970 }
1971 };
1972
1976 using const_iterator = typename std::vector<ConstraintLine>::const_iterator;
1977
1981 using LineRange = boost::iterator_range<const_iterator>;
1982
1991 LineRange
1992 get_lines() const;
1993
2022 bool
2023 is_consistent_in_parallel(const std::vector<IndexSet> &locally_owned_dofs,
2024 const IndexSet &locally_active_dofs,
2025 const MPI_Comm mpi_communicator,
2026 const bool verbose = false) const;
2027
2087 void
2089 const IndexSet &constraints_to_make_consistent,
2090 const MPI_Comm mpi_communicator);
2091
2099 "You are attempting an operation on an AffineConstraints object "
2100 "that requires the object to not be 'closed', i.e., for which you "
2101 "must not already have called the close() member function. But the "
2102 "object is already closed, and so the operation can not be "
2103 "performed.");
2111 "You are attempting an operation on an AffineConstraints object "
2112 "that requires the object to be 'closed', i.e., for which you "
2113 "needed to call the close() member function. But the object "
2114 "is not currently closed, and so the operation can not be "
2115 "performed.");
2122 size_type,
2123 << "The specified line " << arg1 << " does not exist.");
2130 size_type,
2131 size_type,
2132 number,
2133 number,
2134 << "The entry for the indices " << arg1 << " and " << arg2
2135 << " already exists, but the values " << arg3 << " (old) and "
2136 << arg4 << " (new) differ "
2137 << "by " << (arg4 - arg3) << '.');
2144 int,
2145 int,
2146 << "You tried to constrain DoF " << arg1 << " to DoF " << arg2
2147 << ", but that one is also constrained. This is not allowed!");
2154 size_type,
2155 << "Degree of freedom " << arg1
2156 << " is constrained from both object in a merge operation.");
2163 size_type,
2164 << "In the given argument a degree of freedom is constrained "
2165 << "to another DoF with number " << arg1
2166 << ", which however is constrained by this object. This is not"
2167 << " allowed.");
2174 size_type,
2175 << "The index set given to this constraints object indicates "
2176 << "constraints for degree of freedom " << arg1
2177 << " should not be stored by this object, but a constraint "
2178 << "is being added.");
2179
2186 size_type,
2187 size_type,
2188 << "The index set given to this constraints object indicates "
2189 << "constraints using degree of freedom " << arg2
2190 << " should not be stored by this object, but a constraint "
2191 << "for degree of freedom " << arg1 << " uses it.");
2192
2199 int,
2200 int,
2201 << "While distributing the constraint for DoF " << arg1
2202 << ", it turns out that one of the processors "
2203 << "who own the " << arg2 << " degrees of freedom that x_"
2204 << arg1 << " is constrained against does not know about "
2205 << "the constraint on x_" << arg1
2206 << ". Did you not initialize the AffineConstraints container "
2207 << "with the appropriate locally_relevant set so "
2208 << "that every processor who owns a DoF that constrains "
2209 << "another DoF also knows about this constraint?");
2210
2211 template <typename>
2212 friend class AffineConstraints;
2213
2214private:
2226 std::vector<ConstraintLine> lines;
2227
2260 std::vector<size_type> lines_cache;
2261
2269
2276
2286
2291
2293 internal::AffineConstraints::ScratchData<number>>
2295
2300 size_type
2301 calculate_line_index(const size_type line_n) const;
2302
2307 template <typename MatrixType, typename VectorType>
2308 void
2310 const Vector<number> &local_vector,
2311 const std::vector<size_type> &local_dof_indices,
2312 MatrixType &global_matrix,
2313 VectorType &global_vector,
2314 const bool use_inhomogeneities_for_rhs,
2315 const std::bool_constant<false>) const;
2316
2321 template <typename MatrixType, typename VectorType>
2322 void
2324 const Vector<number> &local_vector,
2325 const std::vector<size_type> &local_dof_indices,
2326 MatrixType &global_matrix,
2327 VectorType &global_vector,
2328 const bool use_inhomogeneities_for_rhs,
2329 const std::bool_constant<true>) const;
2330
2338 void
2339 make_sorted_row_list(const std::vector<size_type> &local_dof_indices,
2340 internal::AffineConstraints::GlobalRowsFromLocal<number>
2341 &global_rows) const;
2342
2350 void
2351 make_sorted_row_list(const std::vector<size_type> &local_dof_indices,
2352 std::vector<size_type> &active_dofs) const;
2353
2357 template <typename MatrixScalar, typename VectorScalar>
2360 const size_type i,
2361 const internal::AffineConstraints::GlobalRowsFromLocal<number> &global_rows,
2362 const Vector<VectorScalar> &local_vector,
2363 const std::vector<size_type> &local_dof_indices,
2364 const FullMatrix<MatrixScalar> &local_matrix) const;
2365};
2366
2367/* ---------------- template and inline functions ----------------- */
2368
2369template <typename number>
2373
2374
2375
2376template <typename number>
2378 const IndexSet &locally_stored_constraints)
2379 : AffineConstraints<number>(locally_stored_constraints,
2380 locally_stored_constraints)
2381{}
2382
2383
2384
2385template <typename number>
2388 const IndexSet &locally_stored_constraints)
2389 : lines()
2391 , local_lines(locally_stored_constraints)
2392 , sorted(false)
2393{
2394 Assert(locally_owned_dofs.is_subset_of(locally_stored_constraints),
2395 ExcMessage("The set of locally stored constraints needs to be a "
2396 "superset of the locally owned DoFs."));
2397
2398 // make sure the IndexSet is compressed. Otherwise this can lead to crashes
2399 // that are hard to find (only happen in release mode).
2400 // see tests/mpi/affine_constraints_crash_01
2402}
2403
2404
2405
2406template <typename number>
2408 const AffineConstraints &affine_constraints)
2410 , lines(affine_constraints.lines)
2411 , lines_cache(affine_constraints.lines_cache)
2412 , locally_owned_dofs(affine_constraints.locally_owned_dofs)
2413 , local_lines(affine_constraints.local_lines)
2415 affine_constraints.needed_elements_for_distribute)
2416 , sorted(affine_constraints.sorted)
2417{}
2418
2419
2420
2421template <typename number>
2422inline void
2424{
2425 Assert(sorted == false, ExcMatrixIsClosed());
2426
2427 // the following can happen when we compute with distributed meshes and dof
2428 // handlers and we constrain a degree of freedom whose number we don't have
2429 // locally. if we don't abort here the program will try to allocate several
2430 // terabytes of memory to resize the various arrays below :-)
2432 const size_type line_index = calculate_line_index(line_n);
2433
2434 // check whether line already exists; it may, in which case we can just quit
2435 if (is_constrained(line_n))
2436 return;
2437
2438 // if necessary enlarge vector of existing entries for cache
2439 if (line_index >= lines_cache.size())
2440 lines_cache.resize(std::max(2 * static_cast<size_type>(lines_cache.size()),
2441 line_index + 1),
2443
2444 // push a new line to the end of the list
2445 lines.emplace_back();
2446 lines.back().index = line_n;
2447 lines.back().inhomogeneity = 0.;
2448 lines_cache[line_index] = lines.size() - 1;
2449}
2450
2451
2452
2453template <typename number>
2454inline void
2456 const size_type column,
2457 const number weight)
2458{
2459 Assert(sorted == false, ExcMatrixIsClosed());
2460 Assert(constrained_dof_index != column,
2461 ExcMessage("Can't constrain a degree of freedom to itself"));
2462
2463 // Ensure that the current line is present in the cache:
2464 const size_type line_index = calculate_line_index(constrained_dof_index);
2465 Assert(line_index < lines_cache.size(),
2466 ExcMessage("The current AffineConstraints does not contain the line "
2467 "for the current entry. Call AffineConstraints::add_line "
2468 "before calling this function."));
2469
2470 // if in debug mode, check whether an entry for this column already exists
2471 // and if it's the same as the one entered at present
2472 //
2473 // in any case: exit the function if an entry for this column already
2474 // exists, since we don't want to enter it twice
2478 ExcColumnNotStoredHere(constrained_dof_index, column));
2479 ConstraintLine *line_ptr = &lines[lines_cache[line_index]];
2480 Assert(line_ptr->index == constrained_dof_index, ExcInternalError());
2481 for (const auto &p : line_ptr->entries)
2482 if (p.first == column)
2483 {
2484 Assert(std::abs(p.second - weight) < 1.e-14,
2486 constrained_dof_index, column, p.second, weight));
2487 return;
2488 }
2489
2490 line_ptr->entries.emplace_back(column, weight);
2491}
2492
2493
2494
2495template <typename number>
2496inline void
2498 const size_type constrained_dof_index,
2499 const number value)
2500{
2501 const size_type line_index = calculate_line_index(constrained_dof_index);
2502 Assert(line_index < lines_cache.size() &&
2504 ExcMessage("call add_line() before calling set_inhomogeneity()"));
2505 Assert(lines_cache[line_index] < lines.size(), ExcInternalError());
2506 ConstraintLine *line_ptr = &lines[lines_cache[line_index]];
2507 line_ptr->inhomogeneity = value;
2508}
2509
2510
2511
2512template <typename number>
2513template <typename VectorType>
2514inline void
2516{
2517 // since lines is a private member, we cannot pass it to the functions
2518 // above. therefore, copy the content which is cheap
2519 std::vector<size_type> constrained_lines(lines.size());
2520 for (unsigned int i = 0; i < lines.size(); ++i)
2521 constrained_lines[i] = lines[i].index;
2522 internal::AffineConstraintsImplementation::set_zero_all(constrained_lines,
2523 vec);
2524}
2525
2526template <typename number>
2529{
2530 return lines.size();
2531}
2532
2533template <typename number>
2536{
2537 return std::count_if(lines.begin(),
2538 lines.end(),
2539 [](const ConstraintLine &line) {
2540 return (line.entries.size() == 1) &&
2541 (line.entries[0].second == number(1.));
2542 });
2543}
2544
2545template <typename number>
2548{
2549 return std::count_if(lines.begin(),
2550 lines.end(),
2551 [](const ConstraintLine &line) {
2552 return (line.inhomogeneity != number(0.));
2553 });
2554}
2555
2556template <typename number>
2557inline bool
2559{
2560 if (lines.empty())
2561 return false;
2562
2563 const size_type line_index = calculate_line_index(index);
2564 return ((line_index < lines_cache.size()) &&
2565 (lines_cache[line_index] != numbers::invalid_size_type));
2566}
2567
2568template <typename number>
2569inline bool
2571 const size_type line_n) const
2572{
2573 // check whether the entry is constrained. could use is_constrained, but
2574 // that means computing the line index twice
2575 const size_type line_index = calculate_line_index(line_n);
2576 if (line_index >= lines_cache.size() ||
2578 return false;
2579 else
2580 {
2581 Assert(lines_cache[line_index] < lines.size(), ExcInternalError());
2582 return (lines[lines_cache[line_index]].inhomogeneity != number(0.));
2583 }
2584}
2585
2586template <typename number>
2587inline const std::vector<std::pair<types::global_dof_index, number>> *
2589{
2590 if (lines.empty())
2591 return nullptr;
2592
2593 // check whether the entry is constrained. could use is_constrained, but
2594 // that means computing the line index twice
2595 const size_type line_index = calculate_line_index(line_n);
2596 if (line_index >= lines_cache.size() ||
2598 return nullptr;
2599 else
2600 return &lines[lines_cache[line_index]].entries;
2601}
2602
2603template <typename number>
2604inline number
2606{
2607 // check whether the entry is constrained. could use is_constrained, but
2608 // that means computing the line index twice
2609 const size_type line_index = calculate_line_index(line_n);
2610 if (line_index >= lines_cache.size() ||
2612 return 0;
2613 else
2614 return lines[lines_cache[line_index]].inhomogeneity;
2615}
2616
2617template <typename number>
2620{
2621 // IndexSet is unused (serial case)
2622 if (local_lines.size() == 0)
2623 return line_n;
2624
2626
2627 return local_lines.index_within_set(line_n);
2628}
2629
2630
2631
2632template <typename number>
2633inline bool
2635{
2636 return local_lines.size() == 0 || local_lines.is_element(line_n);
2637}
2638
2639
2640
2641template <typename number>
2642inline const IndexSet &
2647
2648
2649
2650template <typename number>
2651inline const IndexSet &
2656
2657
2658
2659template <typename number>
2660template <typename VectorType>
2661inline void
2663 const size_type index,
2664 const number value,
2665 VectorType &global_vector) const
2666{
2667 Assert(lines.empty() || sorted == true, ExcMatrixNotClosed());
2668
2669 if (is_constrained(index) == false)
2670 global_vector(index) += value;
2671 else
2672 {
2673 const ConstraintLine &position =
2675 for (size_type j = 0; j < position.entries.size(); ++j)
2676 global_vector(position.entries[j].first) +=
2677 value * position.entries[j].second;
2678 }
2679}
2680
2681template <typename number>
2682template <typename ForwardIteratorVec,
2683 typename ForwardIteratorInd,
2684 typename VectorType>
2685inline void
2687 ForwardIteratorVec local_vector_begin,
2688 ForwardIteratorVec local_vector_end,
2689 ForwardIteratorInd local_indices_begin,
2690 VectorType &global_vector) const
2691{
2692 Assert(lines.empty() || sorted == true, ExcMatrixNotClosed());
2693 for (; local_vector_begin != local_vector_end;
2694 ++local_vector_begin, ++local_indices_begin)
2695 {
2696 if (is_constrained(*local_indices_begin) == false)
2697 internal::ElementAccess<VectorType>::add(*local_vector_begin,
2698 *local_indices_begin,
2699 global_vector);
2700 else
2701 {
2702 const ConstraintLine &position =
2703 lines[lines_cache[calculate_line_index(*local_indices_begin)]];
2704 for (size_type j = 0; j < position.entries.size(); ++j)
2706 (*local_vector_begin) * position.entries[j].second,
2707 position.entries[j].first,
2708 global_vector);
2709 }
2710 }
2711}
2712
2713template <typename number>
2714template <class InVector, class OutVector>
2715inline void
2717 const InVector &local_vector,
2718 const std::vector<size_type> &local_dof_indices,
2719 OutVector &global_vector) const
2720{
2721 Assert(global_vector.has_ghost_elements() == false, ExcGhostsPresent());
2722 Assert(local_vector.size() == local_dof_indices.size(),
2723 ExcDimensionMismatch(local_vector.size(), local_dof_indices.size()));
2724 distribute_local_to_global(local_vector.begin(),
2725 local_vector.end(),
2726 local_dof_indices.begin(),
2727 global_vector);
2728}
2729
2730template <typename number>
2731template <typename ForwardIteratorVec,
2732 typename ForwardIteratorInd,
2733 typename VectorType>
2734inline void
2736 const VectorType &global_vector,
2737 ForwardIteratorInd local_indices_begin,
2738 ForwardIteratorVec local_vector_begin,
2739 ForwardIteratorVec local_vector_end) const
2740{
2741 Assert(lines.empty() || sorted == true, ExcMatrixNotClosed());
2742 for (; local_vector_begin != local_vector_end;
2743 ++local_vector_begin, ++local_indices_begin)
2744 {
2745 if (is_constrained(*local_indices_begin) == false)
2746 *local_vector_begin = global_vector(*local_indices_begin);
2747 else
2748 {
2749 const ConstraintLine &position =
2750 lines[lines_cache[calculate_line_index(*local_indices_begin)]];
2751 typename VectorType::value_type value = position.inhomogeneity;
2752 for (size_type j = 0; j < position.entries.size(); ++j)
2753 value += (global_vector(position.entries[j].first) *
2754 position.entries[j].second);
2755 *local_vector_begin = value;
2756 }
2757 }
2758}
2759
2760// Forward declarations
2761#ifndef DOXYGEN
2762template <typename MatrixType>
2763class BlockMatrixBase;
2764template <typename SparsityPatternType>
2766template <typename number>
2768
2769namespace internal
2770{
2771 namespace AffineConstraints
2772 {
2790 template <typename MatrixType>
2791 struct IsBlockMatrix
2792 {
2793 private:
2797 template <typename T>
2798 static std::true_type
2799 check(const BlockMatrixBase<T> *);
2800
2805 static std::false_type
2806 check(...);
2807
2808 public:
2815 static const bool value =
2816 std::is_same_v<decltype(check(std::declval<MatrixType *>())),
2817 std::true_type>;
2818 };
2819
2820 // instantiation of the static member
2821 template <typename MatrixType>
2822 const bool IsBlockMatrix<MatrixType>::value;
2823
2824 } // namespace AffineConstraints
2825} // namespace internal
2826#endif
2827
2828
2829
2830template <typename number>
2831template <typename other_number>
2832inline void
2835{
2836 lines.clear();
2837 lines.reserve(other.lines.size());
2838
2839 for (const auto &l : other.lines)
2840 lines.emplace_back(l.index,
2841 typename ConstraintLine::Entries(l.entries.begin(),
2842 l.entries.end()),
2843 l.inhomogeneity);
2844
2845 lines_cache = other.lines_cache;
2846 local_lines = other.local_lines;
2847 sorted = other.sorted;
2848
2849 locally_owned_dofs = other.locally_owned_dofs;
2850 needed_elements_for_distribute = other.needed_elements_for_distribute;
2851}
2852
2853
2854template <typename number>
2855template <typename other_number>
2856void
2858 const AffineConstraints<other_number> &other_constraints,
2859 const MergeConflictBehavior merge_conflict_behavior,
2860 const bool allow_different_local_lines)
2861{
2862 Assert(allow_different_local_lines ||
2863 local_lines == other_constraints.local_lines,
2864 ExcMessage(
2865 "local_lines for this and the other objects are not the same "
2866 "although allow_different_local_lines is false."));
2867
2868 // store the previous state with respect to sorting
2869 const bool object_was_sorted = sorted;
2870 sorted = false;
2871
2872 // first action is to fold into the present object possible constraints
2873 // in the second object. we don't strictly need to do this any more since
2874 // the AffineConstraints container has learned to deal with chains of
2875 // constraints in the close() function, but we have traditionally done
2876 // this and it's not overly hard to do.
2877 //
2878 // for this, loop over all constraints and replace the constraint lines
2879 // with a new one where constraints are replaced if necessary.
2880 typename ConstraintLine::Entries tmp;
2881 for (ConstraintLine &line : lines)
2882 {
2883 tmp.clear();
2884 for (const std::pair<size_type, number> &entry : line.entries)
2885 {
2886 // if the present dof is not stored, or not constrained, or if we
2887 // won't take the constraint from the other object, then simply copy
2888 // it over
2889 if ((other_constraints.local_lines.size() != 0. &&
2890 other_constraints.local_lines.is_element(entry.first) ==
2891 false) ||
2892 other_constraints.is_constrained(entry.first) == false ||
2893 ((merge_conflict_behavior != right_object_wins) &&
2894 other_constraints.is_constrained(entry.first) &&
2895 this->is_constrained(entry.first)))
2896 tmp.push_back(entry);
2897 else
2898 // otherwise resolve further constraints by replacing the old
2899 // entry by a sequence of new entries taken from the other
2900 // object, but with multiplied weights
2901 {
2902 const auto *other_entries =
2903 other_constraints.get_constraint_entries(entry.first);
2904 Assert(other_entries != nullptr, ExcInternalError());
2905
2906 const number weight = entry.second;
2907
2908 for (const auto &other_entry : *other_entries)
2909 tmp.emplace_back(other_entry.first,
2910 other_entry.second * weight);
2911
2912 line.inhomogeneity +=
2913 other_constraints.get_inhomogeneity(entry.first) * weight;
2914 }
2915 }
2916 // finally exchange old and newly resolved line
2917 line.entries.swap(tmp);
2918 }
2919
2920 if (local_lines.size() != 0)
2921 local_lines.add_indices(other_constraints.local_lines);
2922
2923 {
2924 // do not bother to resize the lines cache exactly since it is pretty
2925 // cheap to adjust it along the way.
2926 std::fill(lines_cache.begin(),
2927 lines_cache.end(),
2929
2930 // reset lines_cache for our own constraints
2931 size_type index = 0;
2932 for (const ConstraintLine &line : lines)
2933 {
2934 const size_type local_line_no = calculate_line_index(line.index);
2935 if (local_line_no >= lines_cache.size())
2936 lines_cache.resize(local_line_no + 1, numbers::invalid_size_type);
2937 lines_cache[local_line_no] = index++;
2938 }
2939
2940 // Add other_constraints to lines cache and our list of constraints
2941 for (const auto &line : other_constraints.lines)
2942 {
2943 const size_type local_line_no = calculate_line_index(line.index);
2944 if (local_line_no >= lines_cache.size())
2945 {
2946 lines_cache.resize(local_line_no + 1, numbers::invalid_size_type);
2947 lines.emplace_back(line.index,
2948 typename ConstraintLine::Entries(
2949 line.entries.begin(), line.entries.end()),
2950 line.inhomogeneity);
2951 lines_cache[local_line_no] = index++;
2952 }
2953 else if (lines_cache[local_line_no] == numbers::invalid_size_type)
2954 {
2955 // there are no constraints for that line yet
2956 lines.emplace_back(line.index,
2957 typename ConstraintLine::Entries(
2958 line.entries.begin(), line.entries.end()),
2959 line.inhomogeneity);
2960 AssertIndexRange(local_line_no, lines_cache.size());
2961 lines_cache[local_line_no] = index++;
2962 }
2963 else
2964 {
2965 // we already store that line
2966 switch (merge_conflict_behavior)
2967 {
2968 case no_conflicts_allowed:
2969 AssertThrow(false,
2970 ExcDoFIsConstrainedFromBothObjects(line.index));
2971 break;
2972
2973 case left_object_wins:
2974 // ignore this constraint
2975 break;
2976
2977 case right_object_wins:
2978 AssertIndexRange(local_line_no, lines_cache.size());
2979 lines[lines_cache[local_line_no]] = {
2980 line.index,
2981 typename ConstraintLine::Entries(line.entries.begin(),
2982 line.entries.end()),
2983 static_cast<number>(line.inhomogeneity)};
2984 break;
2985
2986 default:
2988 }
2989 }
2990 }
2991
2992 // check that we set the pointers correctly
2993 for (size_type i = 0; i < lines_cache.size(); ++i)
2994 if (lines_cache[i] != numbers::invalid_size_type)
2995 Assert(i == calculate_line_index(lines[lines_cache[i]].index),
2997 }
2998
2999 // if the object was sorted before, then make sure it is so afterward as
3000 // well. otherwise leave everything in the unsorted state
3001 if (object_was_sorted == true)
3002 close();
3003}
3004
3005
3006
3007template <typename number>
3008template <typename MatrixType>
3009inline void
3011 const FullMatrix<number> &local_matrix,
3012 const std::vector<size_type> &local_dof_indices,
3013 MatrixType &global_matrix) const
3014{
3015 // create a dummy and hand on to the function actually implementing this
3016 // feature in the cm.templates.h file.
3018 distribute_local_to_global(
3019 local_matrix,
3020 dummy,
3021 local_dof_indices,
3022 global_matrix,
3023 dummy,
3024 false,
3025 std::bool_constant<
3026 internal::AffineConstraints::IsBlockMatrix<MatrixType>::value>());
3027}
3028
3029
3030
3031template <typename number>
3032template <typename MatrixType, typename VectorType>
3033inline void
3035 const FullMatrix<number> &local_matrix,
3036 const Vector<number> &local_vector,
3037 const std::vector<size_type> &local_dof_indices,
3038 MatrixType &global_matrix,
3039 VectorType &global_vector,
3040 bool use_inhomogeneities_for_rhs) const
3041{
3042 // enter the internal function with the respective block information set,
3043 // the actual implementation follows in the cm.templates.h file.
3044 distribute_local_to_global(
3045 local_matrix,
3046 local_vector,
3047 local_dof_indices,
3048 global_matrix,
3049 global_vector,
3050 use_inhomogeneities_for_rhs,
3051 std::bool_constant<
3052 internal::AffineConstraints::IsBlockMatrix<MatrixType>::value>());
3053}
3054
3055
3056
3057template <typename number>
3059 const size_type &index,
3061 const number inhomogeneity)
3062 : index(index)
3063 , entries(entries)
3064 , inhomogeneity(inhomogeneity)
3065{}
3066
3067
3068
3070
3071#endif
*  x_component_mask set(0, true)
void add_entries(const size_type constrained_dof_index, const std::vector< std::pair< size_type, number > > &col_weight_pairs)
bool is_closed() const
size_type n_inhomogeneities() const
bool has_inhomogeneities() const
LineRange get_lines() const
void add_line(const size_type line_n)
const IndexSet & get_locally_owned_indices() const
void add_selected_constraints(const AffineConstraints &constraints_in, const IndexSet &filter)
bool can_store_line(const size_type line_n) const
void add_constraint(const size_type constrained_dof, const ArrayView< const std::pair< size_type, number > > &dependencies, const number inhomogeneity=0)
Threads::ThreadLocalStorage< internal::AffineConstraints::ScratchData< number > > scratch_data
friend class AffineConstraints
void merge(const AffineConstraints< other_number > &other_constraints, const MergeConflictBehavior merge_conflict_behavior=no_conflicts_allowed, const bool allow_different_local_lines=false)
void add_entry(const size_type constrained_dof_index, const size_type column, const number weight)
number get_inhomogeneity(const size_type line_n) const
void make_sorted_row_list(const std::vector< size_type > &local_dof_indices, std::vector< size_type > &active_dofs) const
void get_dof_values(const VectorType &global_vector, ForwardIteratorInd local_indices_begin, ForwardIteratorVec local_vector_begin, ForwardIteratorVec local_vector_end) const
void distribute_local_to_global(const InVector &local_vector, const std::vector< size_type > &local_dof_indices, OutVector &global_vector) const
void make_sorted_row_list(const std::vector< size_type > &local_dof_indices, internal::AffineConstraints::GlobalRowsFromLocal< number > &global_rows) const
const IndexSet & get_local_lines() const
void add_entries_local_to_global(const std::vector< size_type > &local_dof_indices, SparsityPatternBase &sparsity_pattern, const bool keep_constrained_entries=true, const Table< 2, bool > &dof_mask=Table< 2, bool >()) const
void shift(const size_type offset)
size_type n_identities() const
std::size_t memory_consumption() const
typename std::vector< ConstraintLine >::const_iterator const_iterator
void set_inhomogeneity(const size_type constrained_dof_index, const number value)
void condense(SparsityPattern &sparsity) const
size_type max_constraint_indirections() const
ProductType< VectorScalar, MatrixScalar >::type resolve_vector_entry(const size_type i, const internal::AffineConstraints::GlobalRowsFromLocal< number > &global_rows, const Vector< VectorScalar > &local_vector, const std::vector< size_type > &local_dof_indices, const FullMatrix< MatrixScalar > &local_matrix) const
void distribute(VectorType &vec) const
void resolve_indices(std::vector< types::global_dof_index > &indices) const
std::vector< ConstraintLine > lines
bool is_constrained(const size_type line_n) const
AffineConstraints get_view(const IndexSet &mask) const
IndexSet needed_elements_for_distribute
void make_consistent_in_parallel(const IndexSet &locally_owned_dofs, const IndexSet &constraints_to_make_consistent, const MPI_Comm mpi_communicator)
const std::vector< std::pair< size_type, number > > * get_constraint_entries(const size_type line_n) const
size_type calculate_line_index(const size_type line_n) const
void distribute_local_to_global(const FullMatrix< number > &local_matrix, const Vector< number > &local_vector, const std::vector< size_type > &local_dof_indices, MatrixType &global_matrix, VectorType &global_vector, const bool use_inhomogeneities_for_rhs, const std::bool_constant< true >) const
bool is_inhomogeneously_constrained(const size_type index) const
void copy_from(const AffineConstraints< other_number > &other)
std::vector< size_type > lines_cache
void constrain_dof_to_zero(const size_type constrained_dof)
void distribute_local_to_global(const FullMatrix< number > &local_matrix, const Vector< number > &local_vector, const std::vector< size_type > &local_dof_indices, MatrixType &global_matrix, VectorType &global_vector, const bool use_inhomogeneities_for_rhs, const std::bool_constant< false >) const
bool is_consistent_in_parallel(const std::vector< IndexSet > &locally_owned_dofs, const IndexSet &locally_active_dofs, const MPI_Comm mpi_communicator, const bool verbose=false) const
bool is_identity_constrained(const size_type line_n) const
size_type n_constraints() const
void print(std::ostream &out) const
void write_dot(std::ostream &) const
void set_zero(VectorType &vec) const
void add_lines(const std::vector< bool > &lines)
boost::iterator_range< const_iterator > LineRange
bool are_identity_constrained(const size_type line_n_1, const size_type line_n_2) const
bool is_subset_of(const IndexSet &other) const
Definition index_set.cc:691
size_type size() const
Definition index_set.h:1759
size_type index_within_set(const size_type global_index) const
Definition index_set.h:1977
bool is_element(const size_type index) const
Definition index_set.h:1877
void compress() const
Definition index_set.h:1767
A class that provides a separate storage location on each thread that accesses the object.
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
#define DEAL_II_DEPRECATED_WITH_COMMENT(comment)
Definition config.h:295
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
#define DEAL_II_NOT_IMPLEMENTED()
static ::ExceptionBase & ExcMatrixNotClosed()
static ::ExceptionBase & ExcGhostsPresent()
#define DeclException4(Exception4, type1, type2, type3, type4, outsequence)
static ::ExceptionBase & ExcDoFIsConstrainedFromBothObjects(size_type arg1)
static ::ExceptionBase & ExcDoFConstrainedToConstrainedDoF(int arg1, int arg2)
#define Assert(cond, exc)
static ::ExceptionBase & ExcMatrixIsClosed()
#define DeclException2(Exception2, type1, type2, outsequence)
static ::ExceptionBase & ExcDoFIsConstrainedToConstrainedDoF(size_type arg1)
static ::ExceptionBase & ExcColumnNotStoredHere(size_type arg1, size_type arg2)
static ::ExceptionBase & ExcRowNotStoredHere(size_type arg1)
#define AssertIndexRange(index, range)
#define DeclExceptionMsg(Exception, defaulttext)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcIncorrectConstraint(int arg1, int arg2)
static ::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
#define DeclException1(Exception1, type1, outsequence)
static ::ExceptionBase & ExcEntryAlreadyExists(size_type arg1, size_type arg2, number arg3, number arg4)
static ::ExceptionBase & ExcMessage(std::string arg1)
static ::ExceptionBase & ExcLineInexistent(size_type arg1)
#define AssertThrow(cond, exc)
std::vector< index_type > data
Definition mpi.cc:734
std::size_t size
Definition mpi.cc:733
const MPI_Comm comm
Definition mpi.cc:912
void reinit(MatrixBlock< MatrixType > &v, const BlockSparsityPattern &p)
constexpr types::global_dof_index invalid_dof_index
Definition types.h:259
constexpr types::global_dof_index invalid_size_type
Definition types.h:240
STL namespace.
::VectorizedArray< Number, width > max(const ::VectorizedArray< Number, width > &, const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > abs(const ::VectorizedArray< Number, width > &)
Definition types.h:30
unsigned int global_dof_index
Definition types.h:92
void serialize(Archive &ar, const unsigned int)
ConstraintLine & operator=(const ConstraintLine &other)=default
ConstraintLine(const ConstraintLine &other)=default
ConstraintLine(const size_type &index=numbers::invalid_dof_index, const typename AffineConstraints< number >::ConstraintLine::Entries &entries={}, const number inhomogeneity=0.0)
std::vector< std::pair< size_type, number > > Entries
ConstraintLine(ConstraintLine &&other) noexcept=default
ConstraintLine & operator=(ConstraintLine &&other) noexcept=default
std::size_t memory_consumption() const
friend void swap(ConstraintLine &l1, ConstraintLine &l2) noexcept
typename internal::ProductTypeImpl< std::decay_t< T >, std::decay_t< U > >::type type
static void add(const typename VectorType::value_type value, const types::global_dof_index i, VectorType &V)
bool operator<(const SynchronousIterators< Iterators > &a, const SynchronousIterators< Iterators > &b)