deal.II version 9.7.0
\(\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: LGPL-2.1-or-later
4// Copyright (C) 1998 - 2025 by the deal.II authors
5//
6// This file is part of the deal.II library.
7//
8// Part of the source code is dual licensed under Apache-2.0 WITH
9// LLVM-exception OR LGPL-2.1-or-later. Detailed license information
10// governing the source code and code contributions can be found in
11// LICENSE.md and CONTRIBUTING.md at the top level directory of deal.II.
12//
13// ------------------------------------------------------------------------
14
15#ifndef dealii_affine_constraints_h
16#define dealii_affine_constraints_h
17
18#include <deal.II/base/config.h>
19
23#include <deal.II/base/table.h>
26
28#include <deal.II/lac/vector.h>
30
31#include <boost/range/iterator_range.hpp>
32
33#include <algorithm>
34#include <set>
35#include <type_traits>
36#include <utility>
37#include <vector>
38
40
41// Forward declarations
42#ifndef DOXYGEN
43template <typename>
44class FullMatrix;
45class SparsityPattern;
49template <typename number>
50class SparseMatrix;
51template <typename number>
53
54namespace internal
55{
56 namespace AffineConstraints
57 {
59
77 struct Distributing
78 {
79 Distributing(const size_type global_row = numbers::invalid_size_type,
80 const size_type local_row = numbers::invalid_size_type);
81
82 Distributing(const Distributing &in);
83
84 Distributing &
85 operator=(const Distributing &in);
86
87 bool
88 operator<(const Distributing &in) const
89 {
90 return global_row < in.global_row;
91 }
92
93 size_type global_row;
94 size_type local_row;
95 mutable size_type constraint_position;
96 };
97
98
99
111 template <typename number>
112 struct DataCache
113 {
114 DataCache();
115
116 void
117 reinit();
118
120 insert_new_index(const std::pair<size_type, number> &pair);
121
122 void
123 append_index(const size_type index,
124 const std::pair<size_type, number> &pair);
125
127 get_size(const size_type index) const;
128
129 const std::pair<size_type, number> *
130 get_entry(const size_type index) const;
131
132 size_type row_length;
133
134 std::vector<std::pair<size_type, number>> data;
135
136 std::vector<size_type> individual_size;
137 };
138
139
140
169 template <typename number>
170 class GlobalRowsFromLocal
171 {
172 public:
176 GlobalRowsFromLocal();
177
178 void
179 reinit(const size_type n_local_rows);
180
181 void
182 insert_index(const size_type global_row,
183 const size_type local_row,
184 const number constraint_value);
185 void
186 sort();
187
188 void
189 print(std::ostream &os);
190
195 size() const;
196
202 size(const size_type counter_index) const;
203
208 global_row(const size_type counter_index) const;
209
213 size_type &
214 global_row(const size_type counter_index);
215
222 local_row(const size_type counter_index) const;
223
227 size_type &
228 local_row(const size_type counter_index);
229
236 local_row(const size_type counter_index,
237 const size_type index_in_constraint) const;
238
243 number
244 constraint_value(const size_type counter_index,
245 const size_type index_in_constraint) const;
246
253 bool
254 have_indirect_rows() const;
255
260 void
261 insert_constraint(const size_type constrained_local_dof);
262
271 n_constraints() const;
272
278 n_inhomogeneities() const;
279
286 void
287 set_ith_constraint_inhomogeneous(const size_type i);
288
294 constraint_origin(size_type i) const;
295
301 std::vector<Distributing> total_row_indices;
302
303 private:
307 DataCache<number> data_cache;
308
313 size_type n_active_rows;
314
319 size_type n_inhomogeneous_rows;
320 };
321
322
323
341 template <typename number>
342 struct ScratchData
343 {
347 ScratchData()
348 : in_use(false)
349 {}
350
354 ScratchData(const ScratchData &)
355 : in_use(false)
356 {}
357
361 bool in_use;
362
366 std::vector<std::pair<size_type, size_type>> new_entries;
367
371 std::vector<size_type> rows;
372
376 std::vector<size_type> columns;
377
381 std::vector<number> values;
382
386 std::vector<size_type> block_starts;
387
391 std::vector<size_type> vector_indices;
392
396 std::vector<number> vector_values;
397
401 GlobalRowsFromLocal<number> global_rows;
402
406 GlobalRowsFromLocal<number> global_columns;
407 };
408 } // namespace AffineConstraints
409} // namespace internal
410
411namespace internal
412{
413 namespace AffineConstraintsImplementation
414 {
415 template <typename VectorType>
416 void
417 set_zero_all(const std::vector<types::global_dof_index> &cm,
418 VectorType &vec);
419
420 template <class T>
421 void
422 set_zero_all(const std::vector<types::global_dof_index> &cm,
423 ::Vector<T> &vec);
424
425 template <class T>
426 void
427 set_zero_all(const std::vector<types::global_dof_index> &cm,
428 ::BlockVector<T> &vec);
429 } // namespace AffineConstraintsImplementation
430} // namespace internal
431#endif
432
433
434
507template <typename number = double>
509{
510public:
515
543
562
586 "Use the constructor with two index set arguments.")
587 explicit AffineConstraints(const IndexSet &locally_stored_constraints);
588
621 const IndexSet &locally_stored_constraints);
622
626 explicit AffineConstraints(const AffineConstraints &affine_constraints);
627
631 AffineConstraints(AffineConstraints &&affine_constraints) noexcept =
632 default; // NOLINT
633
644 operator=(const AffineConstraints &) = delete;
645
650 operator=(AffineConstraints &&affine_constraints) noexcept =
651 default; // NOLINT
652
659 template <typename other_number>
660 void
661 copy_from(const AffineConstraints<other_number> &other);
662
671 void
673
683 "Use the reinit() function with two index set arguments.")
684 void
685 reinit(const IndexSet &locally_stored_constraints);
686
695 void
697 const IndexSet &locally_stored_constraints);
698
707 bool
708 can_store_line(const size_type line_n) const;
709
718 const IndexSet &
720
727 const IndexSet &
729
758 DEAL_II_DEPRECATED_WITH_COMMENT("Use get_view() and merge() instead.")
759 void
761 const IndexSet &filter);
762
767
813 void
815 const size_type constrained_dof,
816 const ArrayView<const std::pair<size_type, number>> &dependencies,
817 const number inhomogeneity = 0);
818
836 void
837 constrain_dof_to_zero(const size_type constrained_dof);
838
843 void
844 add_line(const size_type line_n);
845
858 void
859 add_lines(const std::vector<bool> &lines);
860
873 void
875
888 void
890
906 void
907 add_entry(const size_type constrained_dof_index,
908 const size_type column,
909 const number weight);
910
916 void
918 const size_type constrained_dof_index,
919 const std::vector<std::pair<size_type, number>> &col_weight_pairs);
920
932 void
933 set_inhomogeneity(const size_type constrained_dof_index, const number value);
934
956 void
958
964 bool
965 is_closed() const;
966
972 bool
973 is_closed(const MPI_Comm comm) const;
974
999 template <typename other_number>
1000 void
1002 const AffineConstraints<other_number> &other_constraints,
1003 const MergeConflictBehavior merge_conflict_behavior = no_conflicts_allowed,
1004 const bool allow_different_local_lines = false);
1005
1018 void
1019 shift(const size_type offset);
1020
1070 get_view(const IndexSet &mask) const;
1071
1079 void
1081
1085
1090
1094 size_type
1096
1101 size_type
1103
1109 size_type
1111
1121 bool
1122 is_constrained(const size_type line_n) const;
1123
1135 bool
1137
1144 bool
1146 const size_type line_n_2) const;
1147
1158 size_type
1160
1165 bool
1167
1173 bool
1175
1180 const std::vector<std::pair<size_type, number>> *
1182
1187 number
1188 get_inhomogeneity(const size_type line_n) const;
1189
1210 void
1211 print(std::ostream &out) const;
1212
1225 void
1226 write_dot(std::ostream &) const;
1227
1232 std::size_t
1234
1241 void
1242 resolve_indices(std::vector<types::global_dof_index> &indices) const;
1243
1247
1252
1269 void
1270 condense(SparsityPattern &sparsity) const;
1271
1275 void
1277
1282 void
1284
1289 void
1291
1299 void
1300 condense(SparseMatrix<number> &matrix) const;
1301
1305 void
1306 condense(BlockSparseMatrix<number> &matrix) const;
1307
1319 template <typename VectorType>
1320 void
1321 condense(VectorType &vec) const;
1322
1329 template <typename VectorType>
1330 void
1331 condense(const VectorType &vec_ghosted, VectorType &output) const;
1332
1345 template <typename VectorType>
1346 void
1347 condense(SparseMatrix<number> &matrix, VectorType &vector) const;
1348
1353 template <typename BlockVectorType>
1354 void
1355 condense(BlockSparseMatrix<number> &matrix, BlockVectorType &vector) const;
1356
1363 template <typename VectorType>
1364 void
1365 set_zero(VectorType &vec) const;
1366
1370
1375
1422 template <class InVector, class OutVector>
1423 void
1424 distribute_local_to_global(const InVector &local_vector,
1425 const std::vector<size_type> &local_dof_indices,
1426 OutVector &global_vector) const;
1427
1475 template <typename VectorType>
1476 void
1477 distribute_local_to_global(const Vector<number> &local_vector,
1478 const std::vector<size_type> &local_dof_indices,
1479 VectorType &global_vector,
1480 const FullMatrix<number> &local_matrix) const;
1481
1501 template <typename VectorType>
1502 void
1504 const Vector<number> &local_vector,
1505 const std::vector<size_type> &local_dof_indices_row,
1506 const std::vector<size_type> &local_dof_indices_col,
1507 VectorType &global_vector,
1508 const FullMatrix<number> &local_matrix,
1509 bool diagonal = false) const;
1510
1514 template <typename VectorType>
1515 void
1517 const number value,
1518 VectorType &global_vector) const;
1519
1552 template <typename ForwardIteratorVec,
1553 typename ForwardIteratorInd,
1554 typename VectorType>
1555 void
1556 distribute_local_to_global(ForwardIteratorVec local_vector_begin,
1557 ForwardIteratorVec local_vector_end,
1558 ForwardIteratorInd local_indices_begin,
1559 VectorType &global_vector) const;
1560
1612 template <typename MatrixType>
1613 void
1614 distribute_local_to_global(const FullMatrix<number> &local_matrix,
1615 const std::vector<size_type> &local_dof_indices,
1616 MatrixType &global_matrix) const;
1617
1645 template <typename MatrixType>
1646 void
1647 distribute_local_to_global(const FullMatrix<number> &local_matrix,
1648 const std::vector<size_type> &row_indices,
1649 const std::vector<size_type> &col_indices,
1650 MatrixType &global_matrix) const;
1651
1668 template <typename MatrixType>
1669 void
1670 distribute_local_to_global(const FullMatrix<number> &local_matrix,
1671 const std::vector<size_type> &row_indices,
1672 const AffineConstraints &column_affine_constraints,
1673 const std::vector<size_type> &column_indices,
1674 MatrixType &global_matrix) const;
1675
1696 template <typename MatrixType, typename VectorType>
1697 void
1698 distribute_local_to_global(const FullMatrix<number> &local_matrix,
1699 const Vector<number> &local_vector,
1700 const std::vector<size_type> &local_dof_indices,
1701 MatrixType &global_matrix,
1702 VectorType &global_vector,
1703 bool use_inhomogeneities_for_rhs = false) const;
1704
1758 void
1760 const std::vector<size_type> &local_dof_indices,
1761 SparsityPatternBase &sparsity_pattern,
1762 const bool keep_constrained_entries = true,
1763 const Table<2, bool> &dof_mask = Table<2, bool>()) const;
1764
1768 void
1770 const std::vector<size_type> &row_indices,
1771 const std::vector<size_type> &col_indices,
1772 SparsityPatternBase &sparsity_pattern,
1773 const bool keep_constrained_entries = true,
1774 const Table<2, bool> &dof_mask = Table<2, bool>()) const;
1775
1780 void
1782 const std::vector<size_type> &row_indices,
1783 const AffineConstraints<number> &col_constraints,
1784 const std::vector<size_type> &col_indices,
1785 SparsityPatternBase &sparsity_pattern,
1786 const bool keep_constrained_entries = true,
1787 const Table<2, bool> &dof_mask = Table<2, bool>()) const;
1788
1808 template <typename ForwardIteratorVec,
1809 typename ForwardIteratorInd,
1810 typename VectorType>
1811 void
1812 get_dof_values(const VectorType &global_vector,
1813 ForwardIteratorInd local_indices_begin,
1814 ForwardIteratorVec local_vector_begin,
1815 ForwardIteratorVec local_vector_end) const;
1816
1820
1825
1838 template <typename VectorType>
1839 void
1840 distribute(VectorType &vec) const;
1841
1845
1850 {
1855 using Entries = std::vector<std::pair<size_type, number>>;
1856
1863
1872
1877
1882 const typename AffineConstraints<
1884 const number inhomogeneity = 0.0);
1885
1889 ConstraintLine(const ConstraintLine &other) = default;
1890
1894 ConstraintLine(ConstraintLine &&other) noexcept = default;
1895
1900 operator=(const ConstraintLine &other) = default;
1901
1906 operator=(ConstraintLine &&other) noexcept = default;
1907
1912 std::size_t
1914
1920 template <class Archive>
1921 void
1922 serialize(Archive &ar, const unsigned int)
1923 {
1925 }
1926
1930 friend void
1932 {
1933 std::swap(l1.index, l2.index);
1934 std::swap(l1.entries, l2.entries);
1935 std::swap(l1.inhomogeneity, l2.inhomogeneity);
1936 }
1937 };
1938
1942 using const_iterator = typename std::vector<ConstraintLine>::const_iterator;
1943
1947 using LineRange = boost::iterator_range<const_iterator>;
1948
1957 LineRange
1958 get_lines() const;
1959
1988 bool
1989 is_consistent_in_parallel(const std::vector<IndexSet> &locally_owned_dofs,
1990 const IndexSet &locally_active_dofs,
1991 const MPI_Comm mpi_communicator,
1992 const bool verbose = false) const;
1993
2053 void
2055 const IndexSet &constraints_to_make_consistent,
2056 const MPI_Comm mpi_communicator);
2057
2065 "You are attempting an operation on an AffineConstraints object "
2066 "that requires the object to not be 'closed', i.e., for which you "
2067 "must not already have called the close() member function. But the "
2068 "object is already closed, and so the operation can not be "
2069 "performed.");
2077 "You are attempting an operation on an AffineConstraints object "
2078 "that requires the object to be 'closed', i.e., for which you "
2079 "needed to call the close() member function. But the object "
2080 "is not currently closed, and so the operation can not be "
2081 "performed.");
2088 size_type,
2089 << "The specified line " << arg1 << " does not exist.");
2096 size_type,
2097 size_type,
2098 number,
2099 number,
2100 << "The entry for the indices " << arg1 << " and " << arg2
2101 << " already exists, but the values " << arg3 << " (old) and "
2102 << arg4 << " (new) differ "
2103 << "by " << (arg4 - arg3) << '.');
2110 int,
2111 int,
2112 << "You tried to constrain DoF " << arg1 << " to DoF " << arg2
2113 << ", but that one is also constrained. This is not allowed!");
2120 size_type,
2121 << "Degree of freedom " << arg1
2122 << " is constrained from both object in a merge operation.");
2129 size_type,
2130 << "In the given argument a degree of freedom is constrained "
2131 << "to another DoF with number " << arg1
2132 << ", which however is constrained by this object. This is not"
2133 << " allowed.");
2140 size_type,
2141 << "The index set given to this constraints object indicates "
2142 << "constraints for degree of freedom " << arg1
2143 << " should not be stored by this object, but a constraint "
2144 << "is being added.");
2145
2152 size_type,
2153 size_type,
2154 << "The index set given to this constraints object indicates "
2155 << "constraints using degree of freedom " << arg2
2156 << " should not be stored by this object, but a constraint "
2157 << "for degree of freedom " << arg1 << " uses it.");
2158
2165 int,
2166 int,
2167 << "While distributing the constraint for DoF " << arg1
2168 << ", it turns out that one of the processors "
2169 << "who own the " << arg2 << " degrees of freedom that x_"
2170 << arg1 << " is constrained against does not know about "
2171 << "the constraint on x_" << arg1
2172 << ". Did you not initialize the AffineConstraints container "
2173 << "with the appropriate locally_relevant set so "
2174 << "that every processor who owns a DoF that constrains "
2175 << "another DoF also knows about this constraint?");
2176
2177 template <typename>
2178 friend class AffineConstraints;
2179
2180private:
2192 std::vector<ConstraintLine> lines;
2193
2226 std::vector<size_type> lines_cache;
2227
2235
2242
2252
2257
2259 internal::AffineConstraints::ScratchData<number>>
2261
2266 size_type
2267 calculate_line_index(const size_type line_n) const;
2268
2273 template <typename MatrixType, typename VectorType>
2274 void
2276 const Vector<number> &local_vector,
2277 const std::vector<size_type> &local_dof_indices,
2278 MatrixType &global_matrix,
2279 VectorType &global_vector,
2280 const bool use_inhomogeneities_for_rhs,
2281 const std::bool_constant<false>) const;
2282
2287 template <typename MatrixType, typename VectorType>
2288 void
2290 const Vector<number> &local_vector,
2291 const std::vector<size_type> &local_dof_indices,
2292 MatrixType &global_matrix,
2293 VectorType &global_vector,
2294 const bool use_inhomogeneities_for_rhs,
2295 const std::bool_constant<true>) const;
2296
2304 void
2305 make_sorted_row_list(const std::vector<size_type> &local_dof_indices,
2306 internal::AffineConstraints::GlobalRowsFromLocal<number>
2307 &global_rows) const;
2308
2316 void
2317 make_sorted_row_list(const std::vector<size_type> &local_dof_indices,
2318 std::vector<size_type> &active_dofs) const;
2319
2323 template <typename MatrixScalar, typename VectorScalar>
2326 const size_type i,
2327 const internal::AffineConstraints::GlobalRowsFromLocal<number> &global_rows,
2328 const Vector<VectorScalar> &local_vector,
2329 const std::vector<size_type> &local_dof_indices,
2330 const FullMatrix<MatrixScalar> &local_matrix) const;
2331};
2332
2333/* ---------------- template and inline functions ----------------- */
2334
2335template <typename number>
2339
2340
2341
2342template <typename number>
2344 const IndexSet &locally_stored_constraints)
2345 : AffineConstraints<number>(locally_stored_constraints,
2346 locally_stored_constraints)
2347{}
2348
2349
2350
2351template <typename number>
2354 const IndexSet &locally_stored_constraints)
2355 : lines()
2357 , local_lines(locally_stored_constraints)
2358 , sorted(false)
2359{
2360 Assert(locally_owned_dofs.is_subset_of(locally_stored_constraints),
2361 ExcMessage("The set of locally stored constraints needs to be a "
2362 "superset of the locally owned DoFs."));
2363
2364 // make sure the IndexSet is compressed. Otherwise this can lead to crashes
2365 // that are hard to find (only happen in release mode).
2366 // see tests/mpi/affine_constraints_crash_01
2367 local_lines.compress();
2368}
2369
2370
2371
2372template <typename number>
2374 const AffineConstraints &affine_constraints)
2376 , lines(affine_constraints.lines)
2377 , lines_cache(affine_constraints.lines_cache)
2378 , locally_owned_dofs(affine_constraints.locally_owned_dofs)
2379 , local_lines(affine_constraints.local_lines)
2381 affine_constraints.needed_elements_for_distribute)
2382 , sorted(affine_constraints.sorted)
2383{}
2384
2385
2386
2387template <typename number>
2388inline void
2390{
2391 Assert(sorted == false, ExcMatrixIsClosed());
2392
2393 // the following can happen when we compute with distributed meshes and dof
2394 // handlers and we constrain a degree of freedom whose number we don't have
2395 // locally. if we don't abort here the program will try to allocate several
2396 // terabytes of memory to resize the various arrays below :-)
2398 const size_type line_index = calculate_line_index(line_n);
2399
2400 // check whether line already exists; it may, in which case we can just quit
2401 if (is_constrained(line_n))
2402 return;
2403
2404 // if necessary enlarge vector of existing entries for cache
2405 if (line_index >= lines_cache.size())
2406 lines_cache.resize(std::max(2 * static_cast<size_type>(lines_cache.size()),
2407 line_index + 1),
2409
2410 // push a new line to the end of the list
2411 lines.emplace_back();
2412 lines.back().index = line_n;
2413 lines.back().inhomogeneity = 0.;
2414 lines_cache[line_index] = lines.size() - 1;
2415}
2416
2417
2418
2419template <typename number>
2420inline void
2422 const size_type column,
2423 const number weight)
2424{
2425 Assert(sorted == false, ExcMatrixIsClosed());
2426 Assert(constrained_dof_index != column,
2427 ExcMessage("Can't constrain a degree of freedom to itself"));
2428
2429 // Ensure that the current line is present in the cache:
2430 const size_type line_index = calculate_line_index(constrained_dof_index);
2431 Assert(line_index < lines_cache.size(),
2432 ExcMessage("The current AffineConstraints does not contain the line "
2433 "for the current entry. Call AffineConstraints::add_line "
2434 "before calling this function."));
2435
2436 // if in debug mode, check whether an entry for this column already exists
2437 // and if it's the same as the one entered at present
2438 //
2439 // in any case: exit the function if an entry for this column already
2440 // exists, since we don't want to enter it twice
2443 Assert(!local_lines.size() || local_lines.is_element(column),
2444 ExcColumnNotStoredHere(constrained_dof_index, column));
2445 ConstraintLine *line_ptr = &lines[lines_cache[line_index]];
2446 Assert(line_ptr->index == constrained_dof_index, ExcInternalError());
2447 for (const auto &p : line_ptr->entries)
2448 if (p.first == column)
2449 {
2450 Assert(std::abs(p.second - weight) < 1.e-14,
2452 constrained_dof_index, column, p.second, weight));
2453 return;
2454 }
2455
2456 line_ptr->entries.emplace_back(column, weight);
2457}
2458
2459
2460
2461template <typename number>
2462inline void
2464 const size_type constrained_dof_index,
2465 const number value)
2466{
2467 const size_type line_index = calculate_line_index(constrained_dof_index);
2468 Assert(line_index < lines_cache.size() &&
2470 ExcMessage("call add_line() before calling set_inhomogeneity()"));
2471 Assert(lines_cache[line_index] < lines.size(), ExcInternalError());
2472 ConstraintLine *line_ptr = &lines[lines_cache[line_index]];
2473 line_ptr->inhomogeneity = value;
2474}
2475
2476
2477
2478template <typename number>
2479template <typename VectorType>
2480inline void
2482{
2483 // since lines is a private member, we cannot pass it to the functions
2484 // above. therefore, copy the content which is cheap
2485 std::vector<size_type> constrained_lines(lines.size());
2486 for (unsigned int i = 0; i < lines.size(); ++i)
2487 constrained_lines[i] = lines[i].index;
2488 internal::AffineConstraintsImplementation::set_zero_all(constrained_lines,
2489 vec);
2490}
2491
2492template <typename number>
2495{
2496 return lines.size();
2497}
2498
2499template <typename number>
2502{
2503 return std::count_if(lines.begin(),
2504 lines.end(),
2505 [](const ConstraintLine &line) {
2506 return (line.entries.size() == 1) &&
2507 (line.entries[0].second == number(1.));
2508 });
2509}
2510
2511template <typename number>
2514{
2515 return std::count_if(lines.begin(),
2516 lines.end(),
2517 [](const ConstraintLine &line) {
2518 return (line.inhomogeneity != number(0.));
2519 });
2520}
2521
2522template <typename number>
2523inline bool
2525{
2526 if (lines.empty())
2527 return false;
2528
2529 const size_type line_index = calculate_line_index(index);
2530 return ((line_index < lines_cache.size()) &&
2531 (lines_cache[line_index] != numbers::invalid_size_type));
2532}
2533
2534template <typename number>
2535inline bool
2537 const size_type line_n) const
2538{
2539 // check whether the entry is constrained. could use is_constrained, but
2540 // that means computing the line index twice
2541 const size_type line_index = calculate_line_index(line_n);
2542 if (line_index >= lines_cache.size() ||
2544 return false;
2545 else
2546 {
2547 Assert(lines_cache[line_index] < lines.size(), ExcInternalError());
2548 return (lines[lines_cache[line_index]].inhomogeneity != number(0.));
2549 }
2550}
2551
2552template <typename number>
2553inline const std::vector<std::pair<types::global_dof_index, number>> *
2555{
2556 if (lines.empty())
2557 return nullptr;
2558
2559 // check whether the entry is constrained. could use is_constrained, but
2560 // that means computing the line index twice
2561 const size_type line_index = calculate_line_index(line_n);
2562 if (line_index >= lines_cache.size() ||
2564 return nullptr;
2565 else
2566 return &lines[lines_cache[line_index]].entries;
2567}
2568
2569template <typename number>
2570inline number
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 0;
2579 else
2580 return lines[lines_cache[line_index]].inhomogeneity;
2581}
2582
2583template <typename number>
2586{
2587 // IndexSet is unused (serial case)
2588 if (local_lines.size() == 0)
2589 return line_n;
2590
2591 Assert(local_lines.is_element(line_n), ExcRowNotStoredHere(line_n));
2592
2593 return local_lines.index_within_set(line_n);
2594}
2595
2596
2597
2598template <typename number>
2599inline bool
2601{
2602 return local_lines.size() == 0 || local_lines.is_element(line_n);
2603}
2604
2605
2606
2607template <typename number>
2608inline const IndexSet &
2613
2614
2615
2616template <typename number>
2617inline const IndexSet &
2622
2623
2624
2625template <typename number>
2626template <typename VectorType>
2627inline void
2629 const size_type index,
2630 const number value,
2631 VectorType &global_vector) const
2632{
2633 Assert(lines.empty() || sorted == true, ExcMatrixNotClosed());
2634
2635 if (is_constrained(index) == false)
2636 global_vector(index) += value;
2637 else
2638 {
2639 const ConstraintLine &position =
2641 for (size_type j = 0; j < position.entries.size(); ++j)
2642 global_vector(position.entries[j].first) +=
2643 value * position.entries[j].second;
2644 }
2645}
2646
2647template <typename number>
2648template <typename ForwardIteratorVec,
2649 typename ForwardIteratorInd,
2650 typename VectorType>
2651inline void
2653 ForwardIteratorVec local_vector_begin,
2654 ForwardIteratorVec local_vector_end,
2655 ForwardIteratorInd local_indices_begin,
2656 VectorType &global_vector) const
2657{
2658 Assert(lines.empty() || sorted == true, ExcMatrixNotClosed());
2659 for (; local_vector_begin != local_vector_end;
2660 ++local_vector_begin, ++local_indices_begin)
2661 {
2662 if (is_constrained(*local_indices_begin) == false)
2663 internal::ElementAccess<VectorType>::add(*local_vector_begin,
2664 *local_indices_begin,
2665 global_vector);
2666 else
2667 {
2668 const ConstraintLine &position =
2669 lines[lines_cache[calculate_line_index(*local_indices_begin)]];
2670 for (size_type j = 0; j < position.entries.size(); ++j)
2672 (*local_vector_begin) * position.entries[j].second,
2673 position.entries[j].first,
2674 global_vector);
2675 }
2676 }
2677}
2678
2679template <typename number>
2680template <class InVector, class OutVector>
2681inline void
2683 const InVector &local_vector,
2684 const std::vector<size_type> &local_dof_indices,
2685 OutVector &global_vector) const
2686{
2687 Assert(global_vector.has_ghost_elements() == false, ExcGhostsPresent());
2688 Assert(local_vector.size() == local_dof_indices.size(),
2689 ExcDimensionMismatch(local_vector.size(), local_dof_indices.size()));
2690 distribute_local_to_global(local_vector.begin(),
2691 local_vector.end(),
2692 local_dof_indices.begin(),
2693 global_vector);
2694}
2695
2696template <typename number>
2697template <typename ForwardIteratorVec,
2698 typename ForwardIteratorInd,
2699 typename VectorType>
2700inline void
2702 const VectorType &global_vector,
2703 ForwardIteratorInd local_indices_begin,
2704 ForwardIteratorVec local_vector_begin,
2705 ForwardIteratorVec local_vector_end) const
2706{
2707 Assert(lines.empty() || sorted == true, ExcMatrixNotClosed());
2708 for (; local_vector_begin != local_vector_end;
2709 ++local_vector_begin, ++local_indices_begin)
2710 {
2711 if (is_constrained(*local_indices_begin) == false)
2712 *local_vector_begin = global_vector(*local_indices_begin);
2713 else
2714 {
2715 const ConstraintLine &position =
2716 lines[lines_cache[calculate_line_index(*local_indices_begin)]];
2717 typename VectorType::value_type value = position.inhomogeneity;
2718 for (size_type j = 0; j < position.entries.size(); ++j)
2719 value += (global_vector(position.entries[j].first) *
2720 position.entries[j].second);
2721 *local_vector_begin = value;
2722 }
2723 }
2724}
2725
2726// Forward declarations
2727#ifndef DOXYGEN
2728template <typename MatrixType>
2729class BlockMatrixBase;
2730template <typename SparsityPatternType>
2732template <typename number>
2734
2735namespace internal
2736{
2737 namespace AffineConstraints
2738 {
2756 template <typename MatrixType>
2757 struct IsBlockMatrix
2758 {
2759 private:
2765 template <typename T>
2766 static std::true_type
2767 check(const BlockMatrixBase<T> *);
2768
2773 template <typename T>
2774 static std::true_type
2775 check(const BlockSparseMatrixEZ<T> *);
2776
2781 static std::false_type
2782 check(...);
2783
2784 public:
2791 static const bool value =
2792 std::is_same_v<decltype(check(std::declval<MatrixType *>())),
2793 std::true_type>;
2794 };
2795
2796 // instantiation of the static member
2797 template <typename MatrixType>
2798 const bool IsBlockMatrix<MatrixType>::value;
2799
2800 } // namespace AffineConstraints
2801} // namespace internal
2802#endif
2803
2804
2805
2806template <typename number>
2807template <typename other_number>
2808inline void
2811{
2812 lines.clear();
2813 lines.reserve(other.lines.size());
2814
2815 for (const auto &l : other.lines)
2816 lines.emplace_back(l.index,
2817 typename ConstraintLine::Entries(l.entries.begin(),
2818 l.entries.end()),
2819 l.inhomogeneity);
2820
2821 lines_cache = other.lines_cache;
2822 local_lines = other.local_lines;
2823 sorted = other.sorted;
2824
2827}
2828
2829
2830template <typename number>
2831template <typename other_number>
2832void
2834 const AffineConstraints<other_number> &other_constraints,
2835 const MergeConflictBehavior merge_conflict_behavior,
2836 const bool allow_different_local_lines)
2837{
2838 Assert(allow_different_local_lines ||
2839 local_lines == other_constraints.local_lines,
2840 ExcMessage(
2841 "local_lines for this and the other objects are not the same "
2842 "although allow_different_local_lines is false."));
2843
2844 // store the previous state with respect to sorting
2845 const bool object_was_sorted = sorted;
2846 sorted = false;
2847
2848 // first action is to fold into the present object possible constraints
2849 // in the second object. we don't strictly need to do this any more since
2850 // the AffineConstraints container has learned to deal with chains of
2851 // constraints in the close() function, but we have traditionally done
2852 // this and it's not overly hard to do.
2853 //
2854 // for this, loop over all constraints and replace the constraint lines
2855 // with a new one where constraints are replaced if necessary.
2856 typename ConstraintLine::Entries tmp;
2857 for (ConstraintLine &line : lines)
2858 {
2859 tmp.clear();
2860 for (const std::pair<size_type, number> &entry : line.entries)
2861 {
2862 // if the present dof is not stored, or not constrained, or if we
2863 // won't take the constraint from the other object, then simply copy
2864 // it over
2865 if ((other_constraints.local_lines.size() != 0. &&
2866 other_constraints.local_lines.is_element(entry.first) ==
2867 false) ||
2868 other_constraints.is_constrained(entry.first) == false ||
2869 ((merge_conflict_behavior != right_object_wins) &&
2870 other_constraints.is_constrained(entry.first) &&
2871 this->is_constrained(entry.first)))
2872 tmp.push_back(entry);
2873 else
2874 // otherwise resolve further constraints by replacing the old
2875 // entry by a sequence of new entries taken from the other
2876 // object, but with multiplied weights
2877 {
2878 const auto *other_entries =
2879 other_constraints.get_constraint_entries(entry.first);
2880 Assert(other_entries != nullptr, ExcInternalError());
2881
2882 const number weight = entry.second;
2883
2884 for (const auto &other_entry : *other_entries)
2885 tmp.emplace_back(other_entry.first,
2886 other_entry.second * weight);
2887
2888 line.inhomogeneity +=
2889 other_constraints.get_inhomogeneity(entry.first) * weight;
2890 }
2891 }
2892 // finally exchange old and newly resolved line
2893 line.entries.swap(tmp);
2894 }
2895
2896 if (local_lines.size() != 0)
2897 local_lines.add_indices(other_constraints.local_lines);
2898
2899 {
2900 // do not bother to resize the lines cache exactly since it is pretty
2901 // cheap to adjust it along the way.
2902 std::fill(lines_cache.begin(),
2903 lines_cache.end(),
2905
2906 // reset lines_cache for our own constraints
2907 size_type index = 0;
2908 for (const ConstraintLine &line : lines)
2909 {
2910 const size_type local_line_no = calculate_line_index(line.index);
2911 if (local_line_no >= lines_cache.size())
2912 lines_cache.resize(local_line_no + 1, numbers::invalid_size_type);
2913 lines_cache[local_line_no] = index++;
2914 }
2915
2916 // Add other_constraints to lines cache and our list of constraints
2917 for (const auto &line : other_constraints.lines)
2918 {
2919 const size_type local_line_no = calculate_line_index(line.index);
2920 if (local_line_no >= lines_cache.size())
2921 {
2922 lines_cache.resize(local_line_no + 1, numbers::invalid_size_type);
2923 lines.emplace_back(line.index,
2924 typename ConstraintLine::Entries(
2925 line.entries.begin(), line.entries.end()),
2926 line.inhomogeneity);
2927 lines_cache[local_line_no] = index++;
2928 }
2929 else if (lines_cache[local_line_no] == numbers::invalid_size_type)
2930 {
2931 // there are no constraints for that line yet
2932 lines.emplace_back(line.index,
2933 typename ConstraintLine::Entries(
2934 line.entries.begin(), line.entries.end()),
2935 line.inhomogeneity);
2936 AssertIndexRange(local_line_no, lines_cache.size());
2937 lines_cache[local_line_no] = index++;
2938 }
2939 else
2940 {
2941 // we already store that line
2942 switch (merge_conflict_behavior)
2943 {
2945 AssertThrow(false,
2947 break;
2948
2949 case left_object_wins:
2950 // ignore this constraint
2951 break;
2952
2953 case right_object_wins:
2954 AssertIndexRange(local_line_no, lines_cache.size());
2955 lines[lines_cache[local_line_no]] = {
2956 line.index,
2957 typename ConstraintLine::Entries(line.entries.begin(),
2958 line.entries.end()),
2959 static_cast<number>(line.inhomogeneity)};
2960 break;
2961
2962 default:
2964 }
2965 }
2966 }
2967
2968 // check that we set the pointers correctly
2969 for (size_type i = 0; i < lines_cache.size(); ++i)
2973 }
2974
2975 // if the object was sorted before, then make sure it is so afterward as
2976 // well. otherwise leave everything in the unsorted state
2977 if (object_was_sorted == true)
2978 close();
2979}
2980
2981
2982
2983template <typename number>
2984template <typename MatrixType>
2985inline void
2987 const FullMatrix<number> &local_matrix,
2988 const std::vector<size_type> &local_dof_indices,
2989 MatrixType &global_matrix) const
2990{
2991 // create a dummy and hand on to the function actually implementing this
2992 // feature in the cm.templates.h file.
2995 local_matrix,
2996 dummy,
2997 local_dof_indices,
2998 global_matrix,
2999 dummy,
3000 false,
3001 std::integral_constant<
3002 bool,
3003 internal::AffineConstraints::IsBlockMatrix<MatrixType>::value>());
3004}
3005
3006
3007
3008template <typename number>
3009template <typename MatrixType, typename VectorType>
3010inline void
3012 const FullMatrix<number> &local_matrix,
3013 const Vector<number> &local_vector,
3014 const std::vector<size_type> &local_dof_indices,
3015 MatrixType &global_matrix,
3016 VectorType &global_vector,
3017 bool use_inhomogeneities_for_rhs) const
3018{
3019 // enter the internal function with the respective block information set,
3020 // the actual implementation follows in the cm.templates.h file.
3022 local_matrix,
3023 local_vector,
3024 local_dof_indices,
3025 global_matrix,
3026 global_vector,
3027 use_inhomogeneities_for_rhs,
3028 std::integral_constant<
3029 bool,
3030 internal::AffineConstraints::IsBlockMatrix<MatrixType>::value>());
3031}
3032
3033
3034
3035template <typename number>
3044
3045
3046
3048
3049#endif
void add_entries(const size_type constrained_dof_index, const std::vector< std::pair< size_type, number > > &col_weight_pairs)
bool is_closed() const
types::global_dof_index size_type
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 double weight)
double 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)
std::size_t memory_consumption() const
typename std::vector< ConstraintLine >::const_iterator const_iterator
void set_inhomogeneity(const size_type constrained_dof_index, const double 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, double > > * 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
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
size_type size() const
Definition index_set.h:1791
bool is_element(const size_type index) const
Definition index_set.h:1909
A class that provides a separate storage location on each thread that accesses the object.
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:40
#define DEAL_II_DEPRECATED_WITH_COMMENT(comment)
Definition config.h:287
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:41
#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)
const bool IsBlockVector< VectorType >::value
void reinit(MatrixBlock< MatrixType > &v, const BlockSparsityPattern &p)
constexpr types::global_dof_index invalid_dof_index
Definition types.h:269
constexpr types::global_dof_index invalid_size_type
Definition types.h:250
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:32
unsigned int global_dof_index
Definition types.h:94
*braid_SplitCommworld & comm
std::vector< std::pair< size_type, number > > Entries
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)
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)