MFEM v4.10.0
Finite element discretization library
Loading...
Searching...
No Matches
blockoperator.cpp
Go to the documentation of this file.
1// Copyright (c) 2010-2026, Lawrence Livermore National Security, LLC. Produced
2// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3// LICENSE and NOTICE for details. LLNL-CODE-806117.
4//
5// This file is part of the MFEM library. For more information and source code
6// availability visit https://mfem.org.
7//
8// MFEM is free software; you can redistribute it and/or modify it under the
9// terms of the BSD-3 license. We welcome feedback and contributions, see file
10// CONTRIBUTING.md for details.
11
12#include "../general/array.hpp"
13#include "operator.hpp"
14#include "blockvector.hpp"
15#include "blockoperator.hpp"
16
17
18namespace mfem
19{
20
22 : Operator(offsets.Last()),
23 owns_blocks(0),
24 nRowBlocks(offsets.Size() - 1),
25 nColBlocks(offsets.Size() - 1),
26 row_offsets(offsets),
27 col_offsets(offsets),
28 op(nRowBlocks, nRowBlocks),
29 coef(nRowBlocks, nColBlocks)
30{
31 op = nullptr;
32}
33
35 const Array<int> &col_offsets_)
36 : Operator(row_offsets_.Last(), col_offsets_.Last()),
37 owns_blocks(0),
38 nRowBlocks(row_offsets_.Size()-1),
39 nColBlocks(col_offsets_.Size()-1),
40 row_offsets(row_offsets_),
41 col_offsets(col_offsets_),
42 op(nRowBlocks, nColBlocks),
43 coef(nRowBlocks, nColBlocks)
44{
45 op = nullptr;
46}
47
49{
50 SetBlock(iblock, iblock, opt, c);
51}
52
53void BlockOperator::SetBlock(int iRow, int iCol, Operator *opt, real_t c)
54{
55 if (owns_blocks && op(iRow, iCol))
56 {
57 delete op(iRow, iCol);
58 }
59 op(iRow, iCol) = opt;
60 coef(iRow, iCol) = c;
61
62 MFEM_VERIFY(row_offsets[iRow+1] - row_offsets[iRow] == opt->NumRows() &&
63 col_offsets[iCol+1] - col_offsets[iCol] == opt->NumCols(),
64 "incompatible Operator dimensions");
65}
66
67// Operator application
68void BlockOperator::Mult(const Vector &x, Vector &y) const
69{
70 MFEM_ASSERT(x.Size() == width, "incorrect input Vector size");
71 MFEM_ASSERT(y.Size() == height, "incorrect output Vector size");
72
73 x.Read();
74 y.Write();
75 y = 0.0;
76
77 xblock.Update(const_cast<Vector&>(x), col_offsets);
78 yblock.Update(y, row_offsets);
79
80 for (int iRow=0; iRow < nRowBlocks; ++iRow)
81 {
82 tmp.SetSize(row_offsets[iRow+1] - row_offsets[iRow]);
83 tmp.UseDevice(true);
84 for (int jCol=0; jCol < nColBlocks; ++jCol)
85 {
86 if (op(iRow,jCol) && coef(iRow,jCol) != 0.)
87 {
88 op(iRow,jCol)->Mult(xblock.GetBlock(jCol), tmp);
89 yblock.GetBlock(iRow).Add(coef(iRow,jCol), tmp);
90 }
91 }
92 }
93
94 for (int iRow=0; iRow < nRowBlocks; ++iRow)
95 {
96 yblock.GetBlock(iRow).SyncAliasMemory(y);
97 }
98}
99
100// Action of the transpose operator
102{
103 MFEM_ASSERT(x.Size() == height, "incorrect input Vector size");
104 MFEM_ASSERT(y.Size() == width, "incorrect output Vector size");
105
106 x.Read();
107 y.Write();
108 y = 0.0;
109
110 xblock.Update(const_cast<Vector&>(x), row_offsets);
111 yblock.Update(y, col_offsets);
112
113 for (int iRow=0; iRow < nColBlocks; ++iRow)
114 {
115 tmp.SetSize(col_offsets[iRow+1] - col_offsets[iRow]);
116 tmp.UseDevice(true);
117 for (int jCol=0; jCol < nRowBlocks; ++jCol)
118 {
119 if (op(jCol,iRow) && coef(jCol,iRow) != 0.)
120 {
121 op(jCol,iRow)->MultTranspose(xblock.GetBlock(jCol), tmp);
122 yblock.GetBlock(iRow).Add(coef(jCol,iRow), tmp);
123 }
124 }
125 }
126
127 for (int iRow=0; iRow < nColBlocks; ++iRow)
128 {
129 yblock.GetBlock(iRow).SyncAliasMemory(y);
130 }
131}
132
133#ifdef MFEM_USE_MPI
134
136{
137 Array2D<const HypreParMatrix*> blocks(nRowBlocks, nColBlocks);
138 for (int i = 0; i < nRowBlocks; ++i)
139 {
140 for (int j = 0; j < nColBlocks; ++j)
141 {
142 if (IsZeroBlock(i, j))
143 {
144 blocks(i, j) = nullptr;
145 }
146 else
147 {
148 auto mat = dynamic_cast<const HypreParMatrix*>(&GetBlock(i, j));
149 MFEM_VERIFY(mat,"BlockOperator block (" << i << "," << j
150 << ") is not a HypreParMatrix.");
151 blocks(i, j) = mat;
152 }
153 }
154 }
155 Array2D<real_t> coef_mut = coef; // make a non-const copy
156 return HypreParMatrixFromBlocks(blocks, &coef_mut);
157}
158#endif
159
161{
162 if (owns_blocks)
163 {
164 for (int iRow=0; iRow < nRowBlocks; ++iRow)
165 {
166 for (int jCol=0; jCol < nColBlocks; ++jCol)
167 {
168 delete op(iRow, jCol);
169 }
170 }
171 }
172}
173
175 const Array<int> & offsets_):
176 Solver(offsets_.Last()),
177 owns_blocks(0),
178 nBlocks(offsets_.Size() - 1),
179 offsets(0),
180 ops(nBlocks)
181{
182 ops = nullptr;
183 offsets.MakeRef(offsets_);
184}
185
187{
188 MFEM_VERIFY(offsets[iblock+1] - offsets[iblock] == op->Height() &&
189 offsets[iblock+1] - offsets[iblock] == op->Width(),
190 "incompatible Operator dimensions");
191
192 if (owns_blocks && ops[iblock])
193 {
194 delete ops[iblock];
195 }
196 ops[iblock] = op;
197}
198
199// Operator application
201{
202 MFEM_ASSERT(x.Size() == width, "incorrect input Vector size");
203 MFEM_ASSERT(y.Size() == height, "incorrect output Vector size");
204
205 x.Read();
206 y.Write();
207 y = 0.0;
208
209 xblock.Update(const_cast<Vector&>(x), offsets);
210 yblock.Update(y, offsets);
211
212 for (int i=0; i<nBlocks; ++i)
213 {
214 if (ops[i])
215 {
216 ops[i]->Mult(xblock.GetBlock(i), yblock.GetBlock(i));
217 }
218 else
219 {
220 yblock.GetBlock(i) = xblock.GetBlock(i);
221 }
222 }
223
224 for (int i=0; i<nBlocks; ++i)
225 {
226 yblock.GetBlock(i).SyncAliasMemory(y);
227 }
228}
229
230// Action of the transpose operator
232 Vector & y) const
233{
234 MFEM_ASSERT(x.Size() == height, "incorrect input Vector size");
235 MFEM_ASSERT(y.Size() == width, "incorrect output Vector size");
236
237 x.Read();
238 y.Write();
239 y = 0.0;
240
241 xblock.Update(const_cast<Vector&>(x),offsets);
242 yblock.Update(y,offsets);
243
244 for (int i=0; i<nBlocks; ++i)
245 {
246 if (ops[i])
247 {
248 (ops[i])->MultTranspose(xblock.GetBlock(i), yblock.GetBlock(i));
249 }
250 else
251 {
252 yblock.GetBlock(i) = xblock.GetBlock(i);
253 }
254 }
255
256 for (int i=0; i<nBlocks; ++i)
257 {
258 yblock.GetBlock(i).SyncAliasMemory(y);
259 }
260}
261
263{
264 if (owns_blocks)
265 {
266 for (int i=0; i<nBlocks; ++i)
267 {
268 delete ops[i];
269 }
270 }
271}
272
274 const Array<int> & offsets_)
275 : Solver(offsets_.Last()),
276 owns_blocks(0),
277 nBlocks(offsets_.Size() - 1),
278 offsets(0),
279 ops(nBlocks, nBlocks)
280{
281 ops = nullptr;
282 offsets.MakeRef(offsets_);
283}
284
286 Operator *op)
287{
288 MFEM_VERIFY(offsets[iblock+1] - offsets[iblock] == op->Height() &&
289 offsets[iblock+1] - offsets[iblock] == op->Width(),
290 "incompatible Operator dimensions");
291
292 SetBlock(iblock, iblock, op);
293}
294
296 Operator *op)
297{
298 MFEM_VERIFY(iRow >= iCol,"cannot set block in upper triangle");
299 MFEM_VERIFY(offsets[iRow+1] - offsets[iRow] == op->NumRows() &&
300 offsets[iCol+1] - offsets[iCol] == op->NumCols(),
301 "incompatible Operator dimensions");
302
303 ops(iRow, iCol) = op;
304}
305
306// Operator application
308 Vector &y) const
309{
310 MFEM_ASSERT(x.Size() == width, "incorrect input Vector size");
311 MFEM_ASSERT(y.Size() == height, "incorrect output Vector size");
312
313 x.Read();
314 y.Write();
315 y = 0.0;
316
317 xblock.Update(const_cast<Vector&>(x),offsets);
318 yblock.Update(y,offsets);
319
320 for (int iRow=0; iRow < nBlocks; ++iRow)
321 {
322 tmp.SetSize(offsets[iRow+1] - offsets[iRow]);
323 tmp.UseDevice(true);
324 tmp2.SetSize(offsets[iRow+1] - offsets[iRow]);
325 tmp2.UseDevice(true);
326 tmp2 = 0.0;
327 tmp2 += xblock.GetBlock(iRow);
328 for (int jCol=0; jCol < iRow; ++jCol)
329 {
330 if (ops(iRow,jCol))
331 {
332 ops(iRow,jCol)->Mult(yblock.GetBlock(jCol), tmp);
333 tmp2 -= tmp;
334 }
335 }
336 if (ops(iRow,iRow))
337 {
338 ops(iRow,iRow)->Mult(tmp2, yblock.GetBlock(iRow));
339 }
340 else
341 {
342 yblock.GetBlock(iRow) = tmp2;
343 }
344 }
345
346 for (int iRow=0; iRow < nBlocks; ++iRow)
347 {
348 yblock.GetBlock(iRow).SyncAliasMemory(y);
349 }
350}
351
352// Action of the transpose operator
354 Vector &y) const
355{
356 MFEM_ASSERT(x.Size() == height, "incorrect input Vector size");
357 MFEM_ASSERT(y.Size() == width, "incorrect output Vector size");
358
359 x.Read();
360 y.Write();
361 y = 0.0;
362
363 xblock.Update(const_cast<Vector&>(x), offsets);
364 yblock.Update(y, offsets);
365
366 for (int iRow=nBlocks-1; iRow >=0; --iRow)
367 {
368 tmp.SetSize(offsets[iRow+1] - offsets[iRow]);
369 tmp.UseDevice(true);
370 tmp2.SetSize(offsets[iRow+1] - offsets[iRow]);
371 tmp2.UseDevice(true);
372 tmp2 = 0.0;
373 tmp2 += xblock.GetBlock(iRow);
374 for (int jCol=iRow+1; jCol < nBlocks; ++jCol)
375 {
376 if (ops(jCol,iRow))
377 {
378 ops(jCol,iRow)->MultTranspose(yblock.GetBlock(jCol), tmp);
379 tmp2 -= tmp;
380 }
381 }
382 if (ops(iRow,iRow))
383 {
384 ops(iRow,iRow)->MultTranspose(tmp2, yblock.GetBlock(iRow));
385 }
386 else
387 {
388 yblock.GetBlock(iRow) = tmp2;
389 }
390 }
391
392 for (int iRow=nBlocks-1; iRow >=0; --iRow)
393 {
394 yblock.GetBlock(iRow).SyncAliasMemory(y);
395 }
396}
397
399{
400 if (owns_blocks)
401 {
402 for (int iRow=0; iRow < nBlocks; ++iRow)
403 {
404 for (int jCol=0; jCol < nBlocks; ++jCol)
405 {
406 delete ops(jCol,iRow);
407 }
408 }
409 }
410}
411
412} // namespace mfem
Dynamic 2D array using row-major layout.
Definition array.hpp:459
void MakeRef(T *data_, int size_, bool own_data=false)
Make this Array a reference to a pointer.
Definition array.hpp:1082
void Mult(const Vector &x, Vector &y) const override
Operator application.
void MultTranspose(const Vector &x, Vector &y) const override
Action of the transpose operator.
BlockDiagonalPreconditioner(const Array< int > &offsets)
Constructor that specifies the block structure.
void SetDiagonalBlock(int iblock, Operator *op)
Add a square block op in the block-entry (iblock, iblock).
void SetDiagonalBlock(int iblock, Operator *op)
Add block op in the block-entry (iblock, iblock).
void Mult(const Vector &x, Vector &y) const override
Operator application.
BlockLowerTriangularPreconditioner(const Array< int > &offsets)
void SetBlock(int iRow, int iCol, Operator *op)
Add a block opt in the block-entry (iblock, jblock).
void MultTranspose(const Vector &x, Vector &y) const override
Action of the transpose operator.
int IsZeroBlock(int i, int j) const
Check if block (i,j) is a zero block.
void SetDiagonalBlock(int iblock, Operator *op, real_t c=1.0)
Add block op in the block-entry (iblock, iblock).
void Mult(const Vector &x, Vector &y) const override
Operator application.
BlockOperator(const Array< int > &offsets)
void SetBlock(int iRow, int iCol, Operator *op, real_t c=1.0)
Add a block op in the block-entry (iblock, jblock).
Operator & GetBlock(int i, int j)
Return a reference to block i,j.
void MultTranspose(const Vector &x, Vector &y) const override
Action of the transpose operator.
HypreParMatrix * GetMonolithicHypreParMatrix() const
Returns a monolithic HypreParMatrix formed by merging the blocks of this BlockOperator,...
void Update(real_t *data, const Array< int > &bOffsets)
Update method.
Vector & GetBlock(int i)
Get the i-th vector in the block.
Wrapper for hypre's ParCSR matrix class.
Definition hypre.hpp:419
Abstract operator.
Definition operator.hpp:27
int width
Dimension of the input / number of columns in the matrix.
Definition operator.hpp:30
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
Definition operator.hpp:68
int height
Dimension of the output / number of rows in the matrix.
Definition operator.hpp:29
int NumCols() const
Get the number of columns (size of input) of the Operator. Synonym with Width().
Definition operator.hpp:77
int Width() const
Get the width (size of input) of the Operator. Synonym with NumCols().
Definition operator.hpp:74
int NumRows() const
Get the number of rows (size of output) of the Operator. Synonym with Height().
Definition operator.hpp:71
Base class for solvers.
Definition operator.hpp:855
Vector data type.
Definition vector.hpp:82
virtual const real_t * Read(bool on_dev=true) const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), on_dev).
Definition vector.hpp:520
void SyncAliasMemory(const Vector &v) const
Update the alias memory location of the vector to match v.
Definition vector.hpp:275
int Size() const
Returns the size of the vector.
Definition vector.hpp:234
virtual void UseDevice(bool use_dev) const
Enable execution of Vector operations using the mfem::Device.
Definition vector.hpp:145
void SetSize(int s)
Resize the vector to size s.
Definition vector.hpp:633
virtual real_t * Write(bool on_dev=true)
Shortcut for mfem::Write(vec.GetMemory(), vec.Size(), on_dev).
Definition vector.hpp:528
Vector & Add(const real_t a, const Vector &Va)
(*this) += a * Va
Definition vector.cpp:326
HypreParMatrix * HypreParMatrixFromBlocks(Array2D< const HypreParMatrix * > &blocks, Array2D< real_t > *blockCoeff)
Returns a merged hypre matrix constructed from hypre matrix blocks.
Definition hypre.cpp:3237
float real_t
Definition config.hpp:46