OGS
MatrixElementCache.h
Go to the documentation of this file.
1
11#pragma once
12
13#include <algorithm>
14
18
20{
21namespace detail
22{
23#ifdef USE_PETSC
25 GlobalIndexType const n)
26{
27 if (i == -n)
28 {
29 return 0;
30 }
31 else
32 {
33 return std::abs(i);
34 }
35}
36#else
38 GlobalIndexType const /*n*/)
39{
40 return i;
41}
42#endif
43} // namespace detail
44
45template <std::size_t Dim>
47{
51
52 MatrixElementCacheEntry(std::array<GlobalIndexType, Dim> const& indices,
53 double value)
55 {
56 }
57
59 default;
61
62 std::array<GlobalIndexType, Dim> indices;
63 double value;
64};
65
66template <std::size_t Dim>
68{
69 static_assert(Dim == 1 || Dim == 2);
71 std::conditional_t<Dim == 1, GlobalVector, GlobalMatrix>;
72
73public:
75 : mat_or_vec_{mat_or_vec}
76 {
77 }
78
79 void add(std::vector<MatrixElementCacheEntry<Dim>> const& entries)
80 {
81#pragma omp critical
82 {
83 if constexpr (Dim == 2)
84 {
85 auto const n_cols = mat_or_vec_.getNumberOfColumns();
86
87 // TODO would be more efficient if our global matrix and vector
88 // implementations supported batch addition of matrix elements
89 // with arbitrary indices (not restricted to (n x m) shaped
90 // submatrices).
91 for (auto const [rc, value] : entries)
92 {
93 auto const [r, c] = rc;
94
95 auto const c_no_ghost =
97
98 mat_or_vec_.add(r, c_no_ghost, value);
99 }
100 }
101 else
102 {
103 // TODO batch addition would be more efficient. That needs the
104 // refactoring of the matrix element cache.
105 for (auto const [r, value] : entries)
106 {
107 mat_or_vec_.add(r.front(), value);
108 }
109 }
110 }
111 }
112
113private:
115};
116
119
120template <std::size_t Dim>
122{
123 static_assert(Dim == 1 || Dim == 2);
125
126 static constexpr std::size_t cache_capacity = 1'000'000;
127
128public:
130 : mat_or_vec_(mat_or_vec), stats_(stats)
131 {
132 cache_.reserve(cache_capacity);
133 }
134
135 void add(std::vector<double> const& local_data,
136 std::vector<GlobalIndexType> const& indices)
137 {
138 addToCache(local_data, indices);
139 }
140
142
143private:
144 void addToCache(std::vector<double> const& values,
145 std::vector<GlobalIndexType> const& indices)
146 {
147 if (values.empty())
148 {
149 return;
150 }
151
152 ensureEnoughSpace(values.size());
153
154 addToCacheImpl(values, indices,
155 std::integral_constant<std::size_t, Dim>{});
156 }
157
158 // Overload for vectors.
159 void addToCacheImpl(std::vector<double> const& values,
160 std::vector<GlobalIndexType> const& indices,
161 std::integral_constant<std::size_t, 1>)
162 {
163 auto const num_r_c = indices.size();
164
165 for (std::size_t r_local = 0; r_local < num_r_c; ++r_local)
166 {
167 ++stats_.count;
168 auto const value = values[r_local];
169
170 if (value == 0)
171 {
172 continue;
173 }
174 else
175 {
177 }
178
179 auto const r_global = indices[r_local];
180 cache_.emplace_back(std::array{r_global}, value);
181 }
182 }
183
184 // Overload for matrices.
185 void addToCacheImpl(std::vector<double> const& values,
186 std::vector<GlobalIndexType> const& indices,
187 std::integral_constant<std::size_t, 2>)
188 {
189 auto const num_r_c = indices.size();
190
191 // Note: There is an implicit storage order assumption, here!
192 auto const local_mat = MathLib::toMatrix(values, num_r_c, num_r_c);
193
194 for (std::size_t r_local = 0; r_local < num_r_c; ++r_local)
195 {
196 auto const r_global = indices[r_local];
197
198 for (std::size_t c_local = 0; c_local < num_r_c; ++c_local)
199 {
200 ++stats_.count;
201 auto const value = local_mat(r_local, c_local);
202
203 // TODO skipping zero values sometimes does not work together
204 // with the Eigen SparseLU linear solver. See also
205 // https://gitlab.opengeosys.org/ogs/ogs/-/merge_requests/4556#note_125561
206#if 0
207 if (value == 0)
208 {
209 continue;
210 }
211#endif
213
214 auto const c_global = indices[c_local];
215 cache_.emplace_back(std::array{r_global, c_global}, value);
216 }
217 }
218 }
219
220 void ensureEnoughSpace(std::size_t const space_needed)
221 {
222 auto const size_initial = cache_.size();
223 auto const cap_initial = cache_.capacity();
224
225 if (size_initial + space_needed <= cap_initial)
226 {
227 return;
228 }
229
230 addToGlobal();
231
232 // ensure again that there is enough capacity (corner case, if initial
233 // capacity is too small because of whatever arcane reason)
234 auto const size_after = cache_.size();
235 auto const cap_after = cache_.capacity();
236
237 if (size_after + space_needed > cap_after)
238 {
239 cache_.reserve(size_after + 2 * space_needed);
240 }
241 }
242
244 {
246 stats_.count_global += cache_.size();
247 cache_.clear();
248 }
249
250 std::vector<MatrixElementCacheEntry<Dim>> cache_;
253};
254
256{
259
260public:
262 MultiStats& stats)
263 : cache_b_(b, stats.b), cache_Jac_(Jac, stats.Jac)
264 {
265 }
266
267 void add(std::vector<double> const& local_b_data,
268 std::vector<double> const& local_Jac_data,
269 std::vector<GlobalIndexType> const& indices)
270 {
271 cache_b_.add(local_b_data, indices);
272 cache_Jac_.add(local_Jac_data, indices);
273 }
274
275private:
278};
279} // namespace ProcessLib::Assembly
GlobalMatrix::IndexType GlobalIndexType
Global vector based on Eigen vector.
Definition EigenVector.h:25
std::conditional_t< Dim==1, GlobalVector, GlobalMatrix > GlobalMatOrVec
ConcurrentMatrixView(GlobalMatOrVec &mat_or_vec)
void add(std::vector< MatrixElementCacheEntry< Dim > > const &entries)
void addToCacheImpl(std::vector< double > const &values, std::vector< GlobalIndexType > const &indices, std::integral_constant< std::size_t, 2 >)
static constexpr std::size_t cache_capacity
void addToCacheImpl(std::vector< double > const &values, std::vector< GlobalIndexType > const &indices, std::integral_constant< std::size_t, 1 >)
void addToCache(std::vector< double > const &values, std::vector< GlobalIndexType > const &indices)
void add(std::vector< double > const &local_data, std::vector< GlobalIndexType > const &indices)
MatrixElementCache(GlobalMatView &mat_or_vec, Stats &stats)
std::vector< MatrixElementCacheEntry< Dim > > cache_
void ensureEnoughSpace(std::size_t const space_needed)
MultiMatrixElementCache(GlobalVectorView &b, GlobalMatrixView &Jac, MultiStats &stats)
void add(std::vector< double > const &local_b_data, std::vector< double > const &local_Jac_data, std::vector< GlobalIndexType > const &indices)
Eigen::Map< const Matrix > toMatrix(std::vector< double > const &data, Eigen::MatrixXd::Index rows, Eigen::MatrixXd::Index cols)
GlobalIndexType transformToNonGhostIndex(GlobalIndexType const i, GlobalIndexType const n)
ConcurrentMatrixView(GlobalVector &) -> ConcurrentMatrixView< 1 >
MatrixElementCacheEntry & operator=(MatrixElementCacheEntry const &)=default
MatrixElementCacheEntry(MatrixElementCacheEntry &&)=default
std::array< GlobalIndexType, Dim > indices
MatrixElementCacheEntry & operator=(MatrixElementCacheEntry &&)=default
MatrixElementCacheEntry(std::array< GlobalIndexType, Dim > const &indices, double value)
MatrixElementCacheEntry(MatrixElementCacheEntry const &)=default