LifeV
BlockOperator.cpp
Go to the documentation of this file.
1 /*
2  * BlockOperator.cpp
3  *
4  * Created on: Sep 20, 2010
5  * Author: uvilla
6  */
7 
8 #include <lifev/core/linear_algebra/BlockOperator.hpp>
9 
10 namespace LifeV
11 {
12 namespace Operators
13 {
15  M_name("BlockOperator"),
16  M_useTranspose(false),
18 {
19 
20 }
21 
22 void BlockOperator::setUp(const boost::shared_ptr<BlockEpetra_Map> & map, const commPtr_Type & comm)
23 {
24  M_comm = comm;
25 
26  M_nBlockRows = map->nBlocks();
28  M_domainMap = map;
29  M_rangeMap = M_domainMap;
30  M_oper.resize(M_nBlockRows, M_nBlockCols);
31 }
32 
33 
34 //! SetUp for a "rectangular operator"
35 void BlockOperator::setUp(const boost::shared_ptr<BlockEpetra_Map> & domainMap,
36  const boost::shared_ptr<BlockEpetra_Map> & rangeMap,
37  const commPtr_Type & comm)
38 {
39  M_comm = comm;
40 
41  M_nBlockRows = rangeMap->nBlocks();
42  M_nBlockCols = domainMap->nBlocks();
43 
44  M_domainMap = domainMap;
45  M_rangeMap = rangeMap;
46 
47  M_oper.resize(M_nBlockRows, M_nBlockCols);
48 
49 }
50 
51 //! SetUp when the operator is given like a boost::matrix
52 void BlockOperator::setUp(const operatorPtrContainer_Type & blockOper, const commPtr_Type & comm)
53 {
54  M_comm = comm;
55  M_nBlockRows = blockOper.size1();
56  M_nBlockCols = blockOper.size2();
57 
60 
61  for(UInt iblock=0; iblock < M_nBlockRows; ++iblock)
62  for(UInt jblock=0; jblock < M_nBlockCols; ++jblock)
63  {
64  if(blockOper(iblock,jblock) != 0 && rangeBlockMaps[iblock]==0)
65  {
66  rangeBlockMaps[iblock].reset(new Epetra_Map(blockOper(iblock,jblock)->OperatorRangeMap() ));
67  jblock = M_nBlockCols;
68  }
69  }
70 
71  for(UInt jblock=0; jblock < M_nBlockCols; ++jblock)
72  for(UInt iblock=0; iblock < M_nBlockRows; ++iblock)
73  {
74  if(blockOper(iblock,jblock) != 0 && domainBlockMaps[jblock]==0)
75  {
76  domainBlockMaps[jblock].reset(new Epetra_Map(blockOper(iblock,jblock)->OperatorDomainMap() ));
77  iblock = M_nBlockRows;
78  }
79  }
80 
81  M_domainMap.reset(new BlockEpetra_Map(domainBlockMaps));
82  M_rangeMap.reset(new BlockEpetra_Map(rangeBlockMaps));
83 
84  M_oper = blockOper;
86 
87 }
88 
89 //! set a component of the block operator
90 void BlockOperator::setBlock(UInt iblock, UInt jblock, const operatorPtr_Type & operBlock)
91 {
92  ASSERT_PRE(M_rangeMap->blockMap(iblock)->PointSameAs(operBlock->OperatorRangeMap()), "Wrong range map");
93  ASSERT_PRE(M_domainMap->blockMap(jblock)->PointSameAs(operBlock->OperatorDomainMap()), "Wrong domain map");
94 
95  M_oper(iblock, jblock) = operBlock;
96 }
97 
98 
100 {
101  // Check for Structure with respect to the main diagonal
102  bool thereAreUpperDiagonalBlocks(false);
103  for(UInt iblock = 0; iblock < M_nBlockRows - 1; ++iblock)
104  for(UInt jblock = iblock+1; jblock < M_nBlockCols; ++jblock)
105  if(M_oper(iblock,jblock).get() != 0 && (M_oper(iblock, jblock)->HasNormInf() ? M_oper(iblock, jblock)->NormInf()!=0 : true) )
106  thereAreUpperDiagonalBlocks = true;
107 
108  bool thereAreLowerDiagonalBlocks(false);
109  for(UInt iblock = 1; iblock < M_nBlockRows; ++iblock)
110  for(UInt jblock = 0; jblock < iblock; ++jblock)
111  if(M_oper(iblock,jblock).get() != 0 && (M_oper(iblock, jblock)->HasNormInf() ? M_oper(iblock, jblock)->NormInf()!=0 : true) )
112  thereAreLowerDiagonalBlocks = true;
113 
114  // Check for Structure with respect to the antidiagonal
115  bool thereAreUpperAntiDiagonalBlocks(false);
116  for(UInt iblock = 0; iblock < M_nBlockRows-1; ++iblock)
117  for(UInt jblock = 0; jblock < iblock; ++jblock)
118  if(M_oper(iblock,jblock).get() != 0 && (M_oper(iblock, jblock)->HasNormInf() ? M_oper(iblock, jblock)->NormInf()!=0 : true) )
119  thereAreUpperAntiDiagonalBlocks = true;
120 
121  bool thereAreLowerAntiDiagonalBlocks(false);
122  for(UInt iblock = 1; iblock < M_nBlockRows; ++iblock)
123  for(UInt jblock = iblock+1; jblock < M_nBlockCols; ++jblock)
124  if(M_oper(iblock,jblock).get() != 0 && (M_oper(iblock, jblock)->HasNormInf() ? M_oper(iblock, jblock)->NormInf()!=0 : true) )
125  thereAreLowerAntiDiagonalBlocks = true;
126 
127  // Filling the empty blocks with null operators
128  for(UInt iblock = 0; iblock < M_nBlockRows; ++iblock)
129  for(UInt jblock = 0; jblock < M_nBlockCols; ++jblock)
130  {
131  if(M_oper(iblock,jblock).get() == 0)
132  {
133  NullOperator * nullOp(new NullOperator);
134  nullOp->setUp(M_domainMap->blockMap(jblock), M_rangeMap->blockMap(iblock) );
135  M_oper(iblock,jblock).reset(nullOp);
136  }
137  ASSERT(M_rangeMap->blockMap(iblock)->PointSameAs(M_oper(iblock,jblock)->OperatorRangeMap()), "Wrong range map");
138  ASSERT(M_domainMap->blockMap(jblock)->PointSameAs(M_oper(iblock,jblock)->OperatorDomainMap()), "Wrong domain map");
139  }
140 
142  {
144  return;
145  }
146 
147  if(!thereAreLowerDiagonalBlocks && !thereAreUpperDiagonalBlocks)
148  {
150  return;
151  }
152  if(thereAreLowerDiagonalBlocks && !thereAreUpperDiagonalBlocks)
153  {
155  return;
156  }
157  if(!thereAreLowerDiagonalBlocks && thereAreUpperDiagonalBlocks)
158  {
160  return;
161  }
162  if(!thereAreLowerAntiDiagonalBlocks && !thereAreUpperAntiDiagonalBlocks)
163  {
165  return;
166  }
167  if(thereAreLowerAntiDiagonalBlocks && !thereAreUpperAntiDiagonalBlocks)
168  {
170  return;
171  }
172  if(!thereAreLowerAntiDiagonalBlocks && thereAreUpperAntiDiagonalBlocks)
173  {
175  return;
176  }
177 
179 }
180 
181 int BlockOperator::SetUseTranspose(bool useTranspose)
182 {
183  M_useTranspose = useTranspose;
184 #ifdef HAVE_LIFEV_DEBUG
185  // Checking that all the blocks support the transpose option
186  for (UInt i(0); i<M_nBlockRows; ++i)
187  for (UInt j(0); j<M_nBlockCols; ++j)
188  {
189  EPETRA_CHK_ERR(M_oper(i,j)->SetUseTranspose(true));
190  EPETRA_CHK_ERR(M_oper(i,j)->SetUseTranspose(false));
191  }
192 #endif
193  return 0;
194 }
195 
196 int BlockOperator::Apply(const vector_Type & X, vector_Type & Y) const
197 {
198  int error(-1);
199  if (M_useTranspose)
200  error = applyTranspose(X,Y);
201  else
202  error = applyNoTranspose(X,Y);
203  return error;
204 }
205 
206 int BlockOperator::ApplyInverse(const vector_Type & X, vector_Type & Y) const
207 {
208  ASSERT_PRE(M_nBlockRows == M_nBlockCols, "The operator must be squared");
209  ASSERT_PRE(M_domainMap->monolithicMap()->SameAs(*M_rangeMap->monolithicMap() ), "The operator must be squared");
210  ASSERT_PRE(Y.Map().SameAs(*M_domainMap->monolithicMap()),"The map of Y is not conforming with domain map.");
211  ASSERT_PRE(X.Map().SameAs(*M_rangeMap->monolithicMap()), "The map of X is not conforming with range map.");
212  ASSERT_PRE(X.NumVectors() == Y.NumVectors(), "The number of vectors in X and Y is different" );
213 
214  switch(M_structure)
215  {
216  case Diagonal:
217  case AntiDiagonal:
218  return blockJacobi(X,Y);
219  break;
220  case LowerTriangular:
221  case LowerAntiTriangular:
223  break;
224  case UpperTriangular:
225  case UpperAntiTriangular:
227  break;
228  case NoStructure:
229  Y.Scale(1.0/0.0);
230  return -1;
231  break;
232  case Rectangular:
233  Y.Scale(1.0/0.0);
234  return -1;
235  break;
236  default:
237  Y.Scale(1.0/0.0);
238  return -1;
239  break;
240  }
241  return -1;
242 }
243 
244 const BlockOperator::operatorPtr_Type& BlockOperator::block(UInt iblock, UInt jblock) const
245 {
246  ASSERT (iblock<M_nBlockRows,"Error! Index out of bounds.\n");
247  ASSERT (jblock<M_nBlockCols,"Error! Index out of bounds.\n");
248  return M_oper(iblock,jblock);
249 }
250 
251 //===========================================================================//
252 //===========================================================================//
253 // Private Methods //
254 //===========================================================================//
255 //===========================================================================//
256 
257 int BlockOperator::applyNoTranspose(const vector_Type & X, vector_Type & Y) const
258 {
259  ASSERT_PRE(X.Map().SameAs(*(M_domainMap->monolithicMap())),"The map of X is not conforming with domain map.");
260  ASSERT_PRE(Y.Map().SameAs(*(M_rangeMap->monolithicMap())), "The map of Y is not conforming with range map.");
261  ASSERT_PRE(X.NumVectors() == Y.NumVectors(), "The number of vectors in X and Y is different" );
262 
263  const std::unique_ptr<BlockEpetra_MultiVector> Xview( createBlockView(X, *M_domainMap) );
264  const std::unique_ptr<BlockEpetra_MultiVector> Yview( createBlockView(Y, *M_rangeMap) );
265  BlockEpetra_MultiVector tmpY(*M_rangeMap, X.NumVectors(), true);
266 
267  Yview->PutScalar(0.0);
268 
269 
270  // Perform the mat-vec multiplications
271  for(UInt iblock=0; iblock < M_nBlockRows; ++iblock)
272  for(UInt jblock=0; jblock < M_nBlockCols; ++jblock)
273  {
274  EPETRA_CHK_ERR(M_oper(iblock, jblock)->Apply(Xview->block(jblock), tmpY.block(iblock) ));
275  EPETRA_CHK_ERR(Yview->block(iblock).Update(1.0, tmpY.block(iblock), 1.0));
276  }
277 
278  return 0;
279 }
280 
281 int BlockOperator::applyTranspose(const vector_Type & X, vector_Type & Y) const
282 {
283  ASSERT_PRE(X.Map().SameAs(*(M_rangeMap->monolithicMap())),"The map of X is not conforming with domain map.");
284  ASSERT_PRE(Y.Map().SameAs(*(M_domainMap->monolithicMap())), "The map of Y is not conforming with range map.");
285  ASSERT_PRE(X.NumVectors() == Y.NumVectors(), "The number of vectors in X and Y is different" );
286 
287  const std::unique_ptr<BlockEpetra_MultiVector> Xview( createBlockView(X, *M_rangeMap) );
288  const std::unique_ptr<BlockEpetra_MultiVector> Yview( createBlockView(Y, *M_domainMap) );
289  BlockEpetra_MultiVector tmpY(*M_domainMap, X.NumVectors(), true);
290 
291  Yview->PutScalar(0.0);
292 
293  // Perform the mat-vec multiplications
294  for(UInt iblock=0; iblock < M_nBlockCols; ++iblock)
295  for(UInt jblock=0; jblock < M_nBlockRows; ++jblock)
296  {
297  EPETRA_CHK_ERR(M_oper(iblock,jblock)->SetUseTranspose(true));
298  EPETRA_CHK_ERR(M_oper(iblock, jblock)->Apply(Xview->block(jblock), tmpY.block(iblock) ));
299  EPETRA_CHK_ERR(Yview->block(iblock).Update(1.0, tmpY.block(iblock), 1.0));
300  EPETRA_CHK_ERR(M_oper(iblock,jblock)->SetUseTranspose(false));
301  }
302 
303  return 0;
304 }
305 
306 int BlockOperator::blockJacobi(const vector_Type & X, vector_Type & Y) const
307 {
308  const std::unique_ptr<BlockEpetra_MultiVector> Xcopy( new BlockEpetra_MultiVector(Copy, X, *M_rangeMap) );
309  const std::unique_ptr<BlockEpetra_MultiVector> Yview( new BlockEpetra_MultiVector(View, Y, *M_rangeMap) );
310 
311  Yview->PutScalar(0.0);
312 
313  if (M_structure==Diagonal)
314  {
315  // Diagonal case
316  for (UInt iblock = 0; iblock < M_nBlockRows; ++iblock)
317  EPETRA_CHK_ERR(M_oper(iblock, iblock)->ApplyInverse(Xcopy->block(iblock), Yview->block(iblock) ));
318  }
319  else
320  {
321  // Anti Diagonal case
322  for (UInt iblock = 0; iblock < M_nBlockRows; ++iblock)
323  {
324  UInt jblock = M_nBlockCols-iblock-1;
325  EPETRA_CHK_ERR(M_oper(iblock, jblock)->ApplyInverse(Xcopy->block(jblock), Yview->block(iblock) ));
326  }
327  }
328  return 0;
329 }
330 
331 int BlockOperator::blockLowerTriangularSolve(const vector_Type & X, vector_Type & Y) const
332 {
333  const std::unique_ptr<BlockEpetra_MultiVector> Xcopy( new BlockEpetra_MultiVector(Copy, X, *M_rangeMap) );
334  const std::unique_ptr<BlockEpetra_MultiVector> Yview( new BlockEpetra_MultiVector(View, Y, *M_rangeMap) );
335  BlockEpetra_MultiVector Z(*M_rangeMap, X.NumVectors(), true);
336 
337  Yview->PutScalar(0.0);
338  Z.PutScalar(0.0);
339 
341  {
342  // Lower Triangular case
343  for (UInt iblock = 0; iblock < M_nBlockRows; ++iblock)
344  {
345  EPETRA_CHK_ERR(M_oper(iblock, iblock)->ApplyInverse(Xcopy->block(iblock), Yview->block(iblock) ));
346  for(UInt kblock = iblock+1; kblock < M_nBlockRows; ++kblock)
347  {
348  EPETRA_CHK_ERR( M_oper(kblock, iblock)->Apply(Yview->block(iblock), Z.block(kblock) ) );
349  EPETRA_CHK_ERR( Xcopy->block(kblock).Update(-1.0, Z.block(kblock), 1.0) );
350  }
351  }
352  }
353  else
354  {
355  // Lower Triangular with respect to the anti-diagonal case
356  for (UInt iblock = 0; iblock<M_nBlockRows; ++iblock)
357  {
358  UInt jblock = M_nBlockCols-iblock-1;
359  EPETRA_CHK_ERR(M_oper(iblock, jblock)->ApplyInverse(Xcopy->block(iblock), Yview->block(jblock) ));
360  for(UInt kblock = iblock+1; kblock<M_nBlockRows; ++kblock)
361  {
362  EPETRA_CHK_ERR( M_oper(kblock, jblock)->Apply(Yview->block(jblock), Z.block(kblock) ) );
363  EPETRA_CHK_ERR( Xcopy->block(kblock).Update(-1.0, Z.block(kblock), 1.0) );
364  }
365  }
366  }
367 
368  return 0;
369 }
370 
371 int BlockOperator::blockUpperTriangularSolve(const vector_Type & X, vector_Type & Y) const
372 {
373  const std::unique_ptr<BlockEpetra_MultiVector> Xcopy( new BlockEpetra_MultiVector(Copy, X, *M_rangeMap) );
374  const std::unique_ptr<BlockEpetra_MultiVector> Yview( new BlockEpetra_MultiVector(View, Y, *M_rangeMap) );
375  BlockEpetra_MultiVector Z(*M_rangeMap, X.NumVectors(), true);
376 
377  Yview->PutScalar(0.0);
378  Z.PutScalar(0.0);
379 
381  {
382  // Upper Triangular case
383  for(int iblock = M_nBlockRows - 1 ; iblock > -1 ; --iblock)
384  {
385  EPETRA_CHK_ERR(M_oper(iblock, iblock)->ApplyInverse(Xcopy->block(iblock), Yview->block(iblock) ));
386  for(int kblock = 0; kblock < iblock; ++kblock)
387  {
388  EPETRA_CHK_ERR( M_oper(kblock, iblock)->Apply(Yview->block(iblock), Z.block(kblock) ) );
389  EPETRA_CHK_ERR( Xcopy->block(kblock).Update(-1.0, Z.block(kblock), 1.0) );
390  }
391  }
392  }
393  else
394  {
395  // Upper Triangular with respect to the anti-diagonal case
396  for(int iblock = M_nBlockRows - 1 ; iblock > -1 ; --iblock)
397  {
398  UInt jblock = M_nBlockCols-iblock-1;
399  EPETRA_CHK_ERR(M_oper(iblock, jblock)->ApplyInverse(Xcopy->block(iblock), Yview->block(jblock) ));
400  for(int kblock = 0; kblock < iblock; ++kblock)
401  {
402  EPETRA_CHK_ERR( M_oper(kblock, jblock)->Apply(Yview->block(jblock), Z.block(kblock) ) );
403  EPETRA_CHK_ERR( Xcopy->block(kblock).Update(-1.0, Z.block(kblock), 1.0) );
404  }
405  }
406  }
407 
408  return 0;
409 }
410 
411 } /* end namespace Operators */
412 
413 } /*end namespace */
void setUp(const operatorPtrContainer_Type &blockOper, const commPtr_Type &comm)
SetUp when the operator is given like a boost::matrix.
This class handles block access to parallel monolithic Vectors with an underling block structure...
int applyTranspose(const vector_Type &X, vector_Type &Y) const
Compute Y = Op&#39;*X;.
void setUp(const boost::shared_ptr< BlockEpetra_Map > &domainMap, const boost::shared_ptr< BlockEpetra_Map > &rangeMap, const commPtr_Type &comm)
SetUp for a "rectangular operator".
int SetUseTranspose(bool useTranspose)
If true the transpose of the operator will be computed.
UInt M_nBlockCols
Number of blocks in each column.
void setBlock(UInt iblock, UInt jblock, const operatorPtr_Type &operBlock)
set a component of the block operator
Structure M_structure
structure of the block operator
operatorPtrContainer_Type M_oper
block operator represented like a dense matrix of pointers to Operators
const operatorPtr_Type & block(UInt iblock, UInt jblock) const
Returns a const pointer to the (i,j) block.
void updateInverseJacobian(const UInt &iQuadPt)
int blockUpperTriangularSolve(const vector_Type &X, vector_Type &Y) const
Y = backwardsubstitution(X)
void fillComplete()
Complete the block matrix with null operators.
int blockJacobi(const vector_Type &X, vector_Type &Y) const
Y = diag(block(i,i)^-1)*X.
#define ASSERT_PRE(X, A)
Definition: LifeAssert.hpp:96
std::vector< mapPtr_Type > mapPtrContainer_Type
#define ASSERT(X, A)
Definition: LifeAssert.hpp:90
A abstract class for handling n-by-m block operators This class inherits from LifeV::LinearOperatorAl...
commPtr_Type M_comm
Communicator.
boost::numeric::ublas::matrix< operatorPtr_Type > operatorPtrContainer_Type
UInt M_nBlockRows
Number of blocks in each row.
A derived class from Epetra_MultiVector specialized to handle parallel block structured Vectors...
int applyNoTranspose(const vector_Type &X, vector_Type &Y) const
Compute Y = Op*X;.
int blockLowerTriangularSolve(const vector_Type &X, vector_Type &Y) const
Y = forwardsubstitution(X)
virtual int ApplyInverse(const vector_Type &X, vector_Type &Y) const
Compute Y = Op;.
virtual int Apply(const vector_Type &X, vector_Type &Y) const
Compute Y = Op*X;.
void setUp(const boost::shared_ptr< BlockEpetra_Map > &map, const commPtr_Type &comm)
SetUp for a "square operator".
uint32_type UInt
generic unsigned integer (used mainly for addressing)
Definition: LifeV.hpp:191
bool M_useTranspose
whenever transpose should be used
BlockOperator()
Empty Constructor.