MFEM v4.8.0
Finite element discretization library
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
blockoperator.cpp
Go to the documentation of this file.
1// Copyright (c) 2010-2025, 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
17namespace mfem
18{
19
21 : Operator(offsets.Last()),
22 owns_blocks(0),
23 nRowBlocks(offsets.Size() - 1),
24 nColBlocks(offsets.Size() - 1),
25 row_offsets(offsets),
26 col_offsets(offsets),
27 op(nRowBlocks, nRowBlocks),
28 coef(nRowBlocks, nColBlocks)
29{
30 op = nullptr;
31}
32
34 const Array<int> &col_offsets_)
35 : Operator(row_offsets_.Last(), col_offsets_.Last()),
36 owns_blocks(0),
37 nRowBlocks(row_offsets_.Size()-1),
38 nColBlocks(col_offsets_.Size()-1),
39 row_offsets(row_offsets_),
40 col_offsets(col_offsets_),
41 op(nRowBlocks, nColBlocks),
42 coef(nRowBlocks, nColBlocks)
43{
44 op = nullptr;
45}
46
48{
49 SetBlock(iblock, iblock, opt, c);
50}
51
52void BlockOperator::SetBlock(int iRow, int iCol, Operator *opt, real_t c)
53{
54 if (owns_blocks && op(iRow, iCol))
55 {
56 delete op(iRow, iCol);
57 }
58 op(iRow, iCol) = opt;
59 coef(iRow, iCol) = c;
60
61 MFEM_VERIFY(row_offsets[iRow+1] - row_offsets[iRow] == opt->NumRows() &&
62 col_offsets[iCol+1] - col_offsets[iCol] == opt->NumCols(),
63 "incompatible Operator dimensions");
64}
65
66// Operator application
67void BlockOperator::Mult(const Vector &x, Vector &y) const
68{
69 MFEM_ASSERT(x.Size() == width, "incorrect input Vector size");
70 MFEM_ASSERT(y.Size() == height, "incorrect output Vector size");
71
72 x.Read();
73 y.Write();
74 y = 0.0;
75
76 xblock.Update(const_cast<Vector&>(x), col_offsets);
77 yblock.Update(y, row_offsets);
78
79 for (int iRow=0; iRow < nRowBlocks; ++iRow)
80 {
81 tmp.SetSize(row_offsets[iRow+1] - row_offsets[iRow]);
82 tmp.UseDevice(true);
83 for (int jCol=0; jCol < nColBlocks; ++jCol)
84 {
85 if (op(iRow,jCol) && coef(iRow,jCol) != 0.)
86 {
87 op(iRow,jCol)->Mult(xblock.GetBlock(jCol), tmp);
88 yblock.GetBlock(iRow).Add(coef(iRow,jCol), tmp);
89 }
90 }
91 }
92
93 for (int iRow=0; iRow < nRowBlocks; ++iRow)
94 {
95 yblock.GetBlock(iRow).SyncAliasMemory(y);
96 }
97}
98
99// Action of the transpose operator
101{
102 MFEM_ASSERT(x.Size() == height, "incorrect input Vector size");
103 MFEM_ASSERT(y.Size() == width, "incorrect output Vector size");
104
105 x.Read();
106 y.Write();
107 y = 0.0;
108
109 xblock.Update(const_cast<Vector&>(x), row_offsets);
110 yblock.Update(y, col_offsets);
111
112 for (int iRow=0; iRow < nColBlocks; ++iRow)
113 {
114 tmp.SetSize(col_offsets[iRow+1] - col_offsets[iRow]);
115 tmp.UseDevice(true);
116 for (int jCol=0; jCol < nRowBlocks; ++jCol)
117 {
118 if (op(jCol,iRow) && coef(jCol,iRow) != 0.)
119 {
120 op(jCol,iRow)->MultTranspose(xblock.GetBlock(jCol), tmp);
121 yblock.GetBlock(iRow).Add(coef(jCol,iRow), tmp);
122 }
123 }
124 }
125
126 for (int iRow=0; iRow < nColBlocks; ++iRow)
127 {
128 yblock.GetBlock(iRow).SyncAliasMemory(y);
129 }
130}
131
133{
134 if (owns_blocks)
135 {
136 for (int iRow=0; iRow < nRowBlocks; ++iRow)
137 {
138 for (int jCol=0; jCol < nColBlocks; ++jCol)
139 {
140 delete op(iRow, jCol);
141 }
142 }
143 }
144}
145
147 const Array<int> & offsets_):
148 Solver(offsets_.Last()),
149 owns_blocks(0),
150 nBlocks(offsets_.Size() - 1),
151 offsets(0),
152 ops(nBlocks)
153{
154 ops = nullptr;
155 offsets.MakeRef(offsets_);
156}
157
159{
160 MFEM_VERIFY(offsets[iblock+1] - offsets[iblock] == op->Height() &&
161 offsets[iblock+1] - offsets[iblock] == op->Width(),
162 "incompatible Operator dimensions");
163
164 if (owns_blocks && ops[iblock])
165 {
166 delete ops[iblock];
167 }
168 ops[iblock] = op;
169}
170
171// Operator application
173{
174 MFEM_ASSERT(x.Size() == width, "incorrect input Vector size");
175 MFEM_ASSERT(y.Size() == height, "incorrect output Vector size");
176
177 x.Read();
178 y.Write();
179 y = 0.0;
180
181 xblock.Update(const_cast<Vector&>(x), offsets);
182 yblock.Update(y, offsets);
183
184 for (int i=0; i<nBlocks; ++i)
185 {
186 if (ops[i])
187 {
188 ops[i]->Mult(xblock.GetBlock(i), yblock.GetBlock(i));
189 }
190 else
191 {
192 yblock.GetBlock(i) = xblock.GetBlock(i);
193 }
194 }
195
196 for (int i=0; i<nBlocks; ++i)
197 {
198 yblock.GetBlock(i).SyncAliasMemory(y);
199 }
200}
201
202// Action of the transpose operator
204 Vector & y) const
205{
206 MFEM_ASSERT(x.Size() == height, "incorrect input Vector size");
207 MFEM_ASSERT(y.Size() == width, "incorrect output Vector size");
208
209 x.Read();
210 y.Write();
211 y = 0.0;
212
213 xblock.Update(const_cast<Vector&>(x),offsets);
214 yblock.Update(y,offsets);
215
216 for (int i=0; i<nBlocks; ++i)
217 {
218 if (ops[i])
219 {
220 (ops[i])->MultTranspose(xblock.GetBlock(i), yblock.GetBlock(i));
221 }
222 else
223 {
224 yblock.GetBlock(i) = xblock.GetBlock(i);
225 }
226 }
227
228 for (int i=0; i<nBlocks; ++i)
229 {
230 yblock.GetBlock(i).SyncAliasMemory(y);
231 }
232}
233
235{
236 if (owns_blocks)
237 {
238 for (int i=0; i<nBlocks; ++i)
239 {
240 delete ops[i];
241 }
242 }
243}
244
246 const Array<int> & offsets_)
247 : Solver(offsets_.Last()),
248 owns_blocks(0),
249 nBlocks(offsets_.Size() - 1),
250 offsets(0),
251 ops(nBlocks, nBlocks)
252{
253 ops = nullptr;
254 offsets.MakeRef(offsets_);
255}
256
258 Operator *op)
259{
260 MFEM_VERIFY(offsets[iblock+1] - offsets[iblock] == op->Height() &&
261 offsets[iblock+1] - offsets[iblock] == op->Width(),
262 "incompatible Operator dimensions");
263
264 SetBlock(iblock, iblock, op);
265}
266
268 Operator *op)
269{
270 MFEM_VERIFY(iRow >= iCol,"cannot set block in upper triangle");
271 MFEM_VERIFY(offsets[iRow+1] - offsets[iRow] == op->NumRows() &&
272 offsets[iCol+1] - offsets[iCol] == op->NumCols(),
273 "incompatible Operator dimensions");
274
275 ops(iRow, iCol) = op;
276}
277
278// Operator application
280 Vector &y) const
281{
282 MFEM_ASSERT(x.Size() == width, "incorrect input Vector size");
283 MFEM_ASSERT(y.Size() == height, "incorrect output Vector size");
284
285 x.Read();
286 y.Write();
287 y = 0.0;
288
289 xblock.Update(const_cast<Vector&>(x),offsets);
290 yblock.Update(y,offsets);
291
292 for (int iRow=0; iRow < nBlocks; ++iRow)
293 {
294 tmp.SetSize(offsets[iRow+1] - offsets[iRow]);
295 tmp.UseDevice(true);
296 tmp2.SetSize(offsets[iRow+1] - offsets[iRow]);
297 tmp2.UseDevice(true);
298 tmp2 = 0.0;
299 tmp2 += xblock.GetBlock(iRow);
300 for (int jCol=0; jCol < iRow; ++jCol)
301 {
302 if (ops(iRow,jCol))
303 {
304 ops(iRow,jCol)->Mult(yblock.GetBlock(jCol), tmp);
305 tmp2 -= tmp;
306 }
307 }
308 if (ops(iRow,iRow))
309 {
310 ops(iRow,iRow)->Mult(tmp2, yblock.GetBlock(iRow));
311 }
312 else
313 {
314 yblock.GetBlock(iRow) = tmp2;
315 }
316 }
317
318 for (int iRow=0; iRow < nBlocks; ++iRow)
319 {
320 yblock.GetBlock(iRow).SyncAliasMemory(y);
321 }
322}
323
324// Action of the transpose operator
326 Vector &y) const
327{
328 MFEM_ASSERT(x.Size() == height, "incorrect input Vector size");
329 MFEM_ASSERT(y.Size() == width, "incorrect output Vector size");
330
331 x.Read();
332 y.Write();
333 y = 0.0;
334
335 xblock.Update(const_cast<Vector&>(x), offsets);
336 yblock.Update(y, offsets);
337
338 for (int iRow=nBlocks-1; iRow >=0; --iRow)
339 {
340 tmp.SetSize(offsets[iRow+1] - offsets[iRow]);
341 tmp.UseDevice(true);
342 tmp2.SetSize(offsets[iRow+1] - offsets[iRow]);
343 tmp2.UseDevice(true);
344 tmp2 = 0.0;
345 tmp2 += xblock.GetBlock(iRow);
346 for (int jCol=iRow+1; jCol < nBlocks; ++jCol)
347 {
348 if (ops(jCol,iRow))
349 {
350 ops(jCol,iRow)->MultTranspose(yblock.GetBlock(jCol), tmp);
351 tmp2 -= tmp;
352 }
353 }
354 if (ops(iRow,iRow))
355 {
356 ops(iRow,iRow)->MultTranspose(tmp2, yblock.GetBlock(iRow));
357 }
358 else
359 {
360 yblock.GetBlock(iRow) = tmp2;
361 }
362 }
363
364 for (int iRow=nBlocks-1; iRow >=0; --iRow)
365 {
366 yblock.GetBlock(iRow).SyncAliasMemory(y);
367 }
368}
369
371{
372 if (owns_blocks)
373 {
374 for (int iRow=0; iRow < nBlocks; ++iRow)
375 {
376 for (int jCol=0; jCol < nBlocks; ++jCol)
377 {
378 delete ops(jCol,iRow);
379 }
380 }
381 }
382}
383
384} // namespace mfem
void MakeRef(T *data_, int size_, bool own_data=false)
Make this Array a reference to a pointer.
Definition array.hpp:943
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.
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).
void MultTranspose(const Vector &x, Vector &y) const override
Action of the transpose operator.
void Update(real_t *data, const Array< int > &bOffsets)
Update method.
Vector & GetBlock(int i)
Get the i-th vector in the block.
Abstract operator.
Definition operator.hpp:25
int width
Dimension of the input / number of columns in the matrix.
Definition operator.hpp:28
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
Definition operator.hpp:66
int height
Dimension of the output / number of rows in the matrix.
Definition operator.hpp:27
int NumCols() const
Get the number of columns (size of input) of the Operator. Synonym with Width().
Definition operator.hpp:75
int Width() const
Get the width (size of input) of the Operator. Synonym with NumCols().
Definition operator.hpp:72
int NumRows() const
Get the number of rows (size of output) of the Operator. Synonym with Height().
Definition operator.hpp:69
Base class for solvers.
Definition operator.hpp:780
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:494
void SyncAliasMemory(const Vector &v) const
Update the alias memory location of the vector to match v.
Definition vector.hpp:267
int Size() const
Returns the size of the vector.
Definition vector.hpp:226
virtual void UseDevice(bool use_dev) const
Enable execution of Vector operations using the mfem::Device.
Definition vector.hpp:144
void SetSize(int s)
Resize the vector to size s.
Definition vector.hpp:558
virtual real_t * Write(bool on_dev=true)
Shortcut for mfem::Write(vec.GetMemory(), vec.Size(), on_dev).
Definition vector.hpp:502
Vector & Add(const real_t a, const Vector &Va)
(*this) += a * Va
Definition vector.cpp:322
float real_t
Definition config.hpp:43