MFEM  v3.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
blockmatrix.cpp
Go to the documentation of this file.
1 // Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
2 // the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
3 // reserved. See file COPYRIGHT for details.
4 //
5 // This file is part of the MFEM library. For more information and source code
6 // availability see http://mfem.googlecode.com.
7 //
8 // MFEM is free software; you can redistribute it and/or modify it under the
9 // terms of the GNU Lesser General Public License (as published by the Free
10 // Software Foundation) version 2.1 dated February 1999.
11 
12 #include "../general/array.hpp"
13 #include "matrix.hpp"
14 #include "sparsemat.hpp"
15 #include "blockvector.hpp"
16 #include "blockmatrix.hpp"
17 
18 namespace mfem
19 {
20 
22  AbstractSparseMatrix(offsets.Last()),
23  owns_blocks(false),
24  nRowBlocks(offsets.Size()-1),
25  nColBlocks(offsets.Size()-1),
26  row_offsets(const_cast< Array<int>& >(offsets).GetData(), offsets.Size()),
27  col_offsets(const_cast< Array<int>& >(offsets).GetData(), offsets.Size()),
28  Aij(nRowBlocks, nColBlocks)
29 {
30  Aij = (SparseMatrix *)NULL;
31 }
32 
33 BlockMatrix::BlockMatrix(const Array<int> & row_offsets_, const Array<int> & col_offsets_):
34  AbstractSparseMatrix(row_offsets_.Last(), col_offsets_.Last()),
35  owns_blocks(false),
36  nRowBlocks(row_offsets_.Size()-1),
37  nColBlocks(col_offsets_.Size()-1),
38  row_offsets(const_cast< Array<int>& >(row_offsets_).GetData(), row_offsets_.Size()),
39  col_offsets(const_cast< Array<int>& >(col_offsets_).GetData(), col_offsets_.Size()),
40  Aij(nRowBlocks, nColBlocks)
41 {
42  Aij = (SparseMatrix *)NULL;
43 }
44 
45 
47 {
48  if (owns_blocks)
49  for (SparseMatrix ** it = Aij.GetRow(0);
50  it != Aij.GetRow(0)+(Aij.NumRows()*Aij.NumCols()); ++it)
51  delete *it;
52 }
53 
54 void BlockMatrix::SetBlock(int i, int j, SparseMatrix * mat)
55 {
56 #ifdef MFEM_DEBUG
57  if (nRowBlocks <= i || nColBlocks <= j)
58  mfem_error("BlockMatrix::SetBlock #0");
59 
60  if (mat->Height() != row_offsets[i+1] - row_offsets[i])
61  mfem_error("BlockMatrix::SetBlock #1");
62 
63  if (mat->Width() != col_offsets[j+1] - col_offsets[j])
64  mfem_error("BlockMatrix::SetBlock #2");
65 #endif
66  Aij(i,j) = mat;
67 }
68 
70 {
71 #ifdef MFEM_DEBUG
72  if (nRowBlocks <= i || nColBlocks <= j)
73  mfem_error("BlockMatrix::Block #0");
74 
75  if (IsZeroBlock(i,j))
76  mfem_error("BlockMatrix::Block #1");
77 #endif
78  return *Aij(i,j);
79 }
80 
81 const SparseMatrix & BlockMatrix::GetBlock(int i, int j) const
82 {
83 #ifdef MFEM_DEBUG
84  if (nRowBlocks <= i || nColBlocks <= j)
85  mfem_error("BlockMatrix::Block const #0");
86 
87  if (IsZeroBlock(i,j))
88  mfem_error("BlockMatrix::Block const #1");
89 #endif
90 
91  return *Aij(i,j);
92 }
93 
94 
96 {
97  int nnz_elem = 0;
98  for (int jcol = 0; jcol != nColBlocks; ++jcol)
99  for (int irow = 0; irow != nRowBlocks; ++irow)
100  {
101  if (Aij(irow,jcol))
102  nnz_elem+= Aij(irow,jcol)->NumNonZeroElems();
103  }
104  return nnz_elem;
105 }
106 
107 
108 double& BlockMatrix::Elem (int i, int j)
109 {
110  int iloc, iblock;
111  int jloc, jblock;
112 
113  findGlobalRow(i, iblock, iloc);
114  findGlobalCol(j, jblock, jloc);
115 
116  if (IsZeroBlock(i, j))
117  mfem_error("BlockMatrix::Elem");
118 
119  return Aij(iblock, jblock)->Elem(iloc, jloc);
120 }
121 
122 const double& BlockMatrix::Elem (int i, int j) const
123 {
124  int iloc, iblock;
125  int jloc, jblock;
126 
127  findGlobalRow(i, iblock, iloc);
128  findGlobalCol(j, jblock, jloc);
129 
130  if (IsZeroBlock(i, j))
131  mfem_error("BlockMatrix::Elem");
132 
133  return Aij(iblock, jblock)->Elem(iloc, jloc);
134 }
135 
136 int BlockMatrix::RowSize(const int i) const
137 {
138  int rowsize = 0;
139 
140  int iblock, iloc;
141  findGlobalRow(i, iblock, iloc);
142 
143  for (int jblock = 0; jblock < nColBlocks; ++jblock)
144  if (Aij(iblock,jblock) != NULL)
145  rowsize += Aij(iblock,jblock)->RowSize(iloc);
146 
147  return rowsize;
148 }
149 
150 int BlockMatrix::GetRow(const int row, Array<int> &cols, Vector &srow) const
151 {
152  int iblock, iloc, rowsize;
153  findGlobalRow(row, iblock, iloc);
154  rowsize = RowSize(row);
155  cols.SetSize(rowsize);
156  srow.SetSize(rowsize);
157 
158  Array<int> bcols;
159  Vector bsrow;
160 
161  int * it_cols = cols.GetData();
162  double *it_srow = srow.GetData();
163 
164  for (int jblock = 0; jblock < nColBlocks; ++jblock)
165  if (Aij(iblock,jblock) != NULL)
166  {
167  Aij(iblock,jblock)->GetRow(iloc, bcols, bsrow);
168  for (int i = 0; i < bcols.Size(); ++i)
169  {
170  *(it_cols++) = bcols[i] + col_offsets[jblock];
171  *(it_srow++) = bsrow(i);
172  }
173  }
174 
175  return 0;
176 }
177 
178 void BlockMatrix::EliminateRowCol(Array<int> & ess_bc_dofs, Vector & sol, Vector & rhs)
179 {
180  if (nRowBlocks != nColBlocks)
181  mfem_error("BlockMatrix::EliminateRowCol: nRowBlocks != nColBlocks");
182 
183  for (int iiblock = 0; iiblock < nRowBlocks; ++iiblock)
184  if (row_offsets[iiblock] != col_offsets[iiblock])
185  {
186  std::cout << "BlockMatrix::EliminateRowCol: row_offests["
187  << iiblock << "] != col_offsets["<<iiblock<<"]\n";
188  mfem_error();
189  }
190 
191  //We also have to do the same for each Aij
192  Array<int> block_dofs;
193  Vector block_sol, block_rhs;
194 
195  for (int iiblock = 0; iiblock < nRowBlocks; ++iiblock)
196  {
197  int dsize = row_offsets[iiblock+1] - row_offsets[iiblock];
198  block_dofs.MakeRef(ess_bc_dofs.GetData()+row_offsets[iiblock], dsize);
199  block_sol.SetDataAndSize(sol.GetData()+row_offsets[iiblock], dsize);
200  block_rhs.SetDataAndSize(rhs.GetData()+row_offsets[iiblock], dsize);
201 
202  if (Aij(iiblock, iiblock))
203  {
204  for (int i = 0; i < block_dofs.Size(); ++i)
205  if (block_dofs[i])
206  Aij(iiblock, iiblock)->EliminateRowCol(i,block_sol(i), block_rhs);
207  }
208  else
209  {
210  for (int i = 0; i < block_dofs.Size(); ++i)
211  if (block_dofs[i])
212  mfem_error("BlockMatrix::EliminateRowCol: Null diagonal block \n");
213  }
214 
215  for (int jjblock = 0; jjblock < nRowBlocks; ++jjblock)
216  {
217  if (jjblock != iiblock && Aij(iiblock, jjblock))
218  {
219  for (int i = 0; i < block_dofs.Size(); ++i)
220  if (block_dofs[i])
221  Aij(iiblock, jjblock)->EliminateRow(i);
222  }
223  if (jjblock != iiblock && Aij(jjblock, iiblock))
224  {
225  block_rhs.SetDataAndSize(rhs.GetData()+row_offsets[jjblock],
226  row_offsets[jjblock+1] - row_offsets[jjblock]);
227  Aij(jjblock, iiblock)->EliminateCols(block_dofs, &block_sol, &block_rhs);
228  }
229  }
230  }
231 }
232 
234 {
235  if (nRowBlocks != nColBlocks)
236  mfem_error("BlockMatrix::EliminateZeroRows() #1");
237 
238  for (int iblock = 0; iblock < nRowBlocks; ++iblock)
239  {
240  if (Aij(iblock,iblock))
241  {
242  double norm;
243  for (int i = 0; i < Aij(iblock, iblock)->NumRows(); ++i)
244  {
245  norm = 0.;
246  for (int jblock = 0; jblock < nColBlocks; ++jblock)
247  if (Aij(iblock,jblock))
248  norm += Aij(iblock,jblock)->GetRowNorml1(i);
249 
250  if (norm < 1e-12)
251  {
252  for (int jblock = 0; jblock < nColBlocks; ++jblock)
253  if (Aij(iblock,jblock))
254  Aij(iblock,jblock)->EliminateRow(i, iblock==jblock);
255  }
256  }
257  }
258  else
259  {
260  double norm;
261  for (int i = 0; i < row_offsets[iblock+1] - row_offsets[iblock]; ++i)
262  {
263  norm = 0.;
264  for (int jblock = 0; jblock < nColBlocks; ++jblock)
265  if (Aij(iblock,jblock))
266  norm += Aij(iblock,jblock)->GetRowNorml1(i);
267 
268  if (norm < 1e-12)
269  {
270  std::cout<<"i = " << i << "\n";
271  std::cout<<"norm = " << norm << "\n";
272  mfem_error("BlockMatrix::EliminateZeroRows() #2");
273  }
274  }
275  }
276  }
277 }
278 
279 void BlockMatrix::Mult(const Vector & x, Vector & y) const
280 {
281  if (x.GetData() == y.GetData())
282  mfem_error("Error: x and y can't point to the same datas \n");
283 
284  y = 0.;
285  AddMult(x, y, 1.0);
286 }
287 
288 void BlockMatrix::AddMult(const Vector & x, Vector & y, const double val) const
289 {
290  if (x.GetData() == y.GetData())
291  mfem_error("Error: x and y can't point to the same datas \n");
292 
293  Vector xblockview, yblockview;
294 
295  for (int iblock = 0; iblock != nRowBlocks; ++iblock)
296  {
297  yblockview.SetDataAndSize(y.GetData() + row_offsets[iblock],
298  row_offsets[iblock+1] - row_offsets[iblock]);
299 
300  for (int jblock = 0; jblock != nColBlocks; ++jblock)
301  {
302  if (Aij(iblock, jblock) != NULL)
303  {
304  xblockview.SetDataAndSize(
305  x.GetData() + col_offsets[jblock],
306  col_offsets[jblock+1] - col_offsets[jblock]);
307 
308  Aij(iblock, jblock)->AddMult(xblockview, yblockview, val);
309  }
310  }
311  }
312 }
313 
314 void BlockMatrix::MultTranspose(const Vector & x, Vector & y) const
315 {
316  if (x.GetData() == y.GetData())
317  mfem_error("Error: x and y can't point to the same datas \n");
318 
319  y = 0.;
320  AddMultTranspose(x, y, 1.0);
321 }
322 
324  const double val) const
325 {
326  if (x.GetData() == y.GetData())
327  mfem_error("Error: x and y can't point to the same datas \n");
328 
329  Vector xblockview, yblockview;
330 
331  for (int iblock = 0; iblock != nColBlocks; ++iblock)
332  {
333  yblockview.SetDataAndSize(y.GetData() + col_offsets[iblock],
334  col_offsets[iblock+1] - col_offsets[iblock]);
335 
336  for (int jblock = 0; jblock != nRowBlocks; ++jblock)
337  {
338  if (Aij(jblock, iblock) != NULL)
339  {
340  xblockview.SetDataAndSize(
341  x.GetData() + row_offsets[jblock],
342  row_offsets[jblock+1] - row_offsets[jblock]);
343 
344  Aij(jblock, iblock)->AddMultTranspose(xblockview, yblockview, val);
345  }
346  }
347  }
348 }
349 
351 {
352  int nnz = NumNonZeroElems();
353 
354  int * i_amono = new int[ row_offsets[nRowBlocks]+2 ];
355  int * j_amono = new int[ nnz ];
356  double * data = new double[ nnz ];
357 
358  for (int i = 0; i < row_offsets[nRowBlocks]+2; i++)
359  i_amono[i] = 0;
360 
361  int * i_amono_construction = i_amono+1;
362 
363  int * i_it(i_amono_construction);
364 
365  for (int iblock = 0; iblock != nRowBlocks; ++iblock)
366  {
367  for (int irow(row_offsets[iblock]); irow < row_offsets[iblock+1]; ++irow)
368  {
369  int local_row = irow - row_offsets[iblock];
370  int ind = i_amono_construction[irow];
371  for (int jblock = 0; jblock < nColBlocks; ++jblock)
372  {
373  if (Aij(iblock,jblock) != NULL)
374  ind += Aij(iblock, jblock)->GetI()[local_row+1]
375  - Aij(iblock, jblock)->GetI()[local_row];
376  }
377  i_amono_construction[irow+1] = ind;
378  }
379  }
380 
381  // Fill in the jarray and copy the data
382  for (int iblock = 0; iblock != nRowBlocks; ++iblock)
383  {
384  for (int jblock = 0; jblock != nColBlocks; ++jblock)
385  {
386  if (Aij(iblock,jblock) != NULL)
387  {
388  int nrow = row_offsets[iblock+1]-row_offsets[iblock];
389  int * i_aij = Aij(iblock, jblock)->GetI();
390  int * j_aij = Aij(iblock, jblock)->GetJ();
391  double * data_aij = Aij(iblock, jblock)->GetData();
392  i_it = i_amono_construction+row_offsets[iblock];
393 
394  int loc_start_index = 0;
395  int loc_end_index = 0;
396  int glob_start_index = 0;
397 
398  int shift(col_offsets[jblock]);
399  for (int * i_it_aij(i_aij+1); i_it_aij != i_aij+nrow+1; ++i_it_aij)
400  {
401  glob_start_index = *i_it;
402 
403 #ifdef MFEM_DEBUG
404  if (glob_start_index > nnz)
405  {
406  std::cout<<"glob_start_index = " << glob_start_index << "\n";
407  std::cout<<"Block:" << iblock << " " << jblock << "\n";
408  std::cout<<std::endl;
409  }
410 #endif
411  loc_end_index = *(i_it_aij);
412  for (int cnt = 0; cnt < loc_end_index-loc_start_index; cnt++) {
413  data[glob_start_index+cnt] = data_aij[loc_start_index+cnt];
414  j_amono[glob_start_index+cnt] = j_aij[loc_start_index+cnt] + shift;
415  }
416 
417  *i_it += loc_end_index-loc_start_index;
418  ++i_it;
419  loc_start_index = loc_end_index;
420  }
421  }
422  }
423  }
424 
425  return new SparseMatrix(i_amono, j_amono, data, row_offsets[nRowBlocks], col_offsets[nColBlocks]);
426 }
427 
428 void BlockMatrix::PrintMatlab(std::ostream & os) const
429 {
430 
431  Vector row_data;
432  Array<int> row_ind;
433  int nnz_elem = NumNonZeroElems();
434  os<<"% size " << row_offsets.Last() << " " << col_offsets.Last() << "\n";
435  os<<"% Non Zeros " << nnz_elem << "\n";
436  int i, j;
437  std::ios::fmtflags old_fmt = os.flags();
438  os.setf(std::ios::scientific);
439  std::streamsize old_prec = os.precision(14);
440  for (i = 0; i < row_offsets.Last(); i++)
441  {
442  GetRow(i, row_ind, row_data);
443  for (j = 0; j < row_ind.Size(); j++)
444  os << i+1 << " " << row_ind[j]+1 << " " << row_data[j] << std::endl;
445  }
446 
447  os.precision(old_prec);
448  os.flags(old_fmt);
449 }
450 
452 {
453  BlockMatrix * At = new BlockMatrix(A.ColOffsets(), A.RowOffsets());
454  At->owns_blocks = 1;
455 
456  for (int irowAt = 0; irowAt < At->NumRowBlocks(); ++irowAt)
457  for (int jcolAt = 0; jcolAt < At->NumColBlocks(); ++jcolAt)
458  if (!A.IsZeroBlock(jcolAt, irowAt))
459  At->SetBlock(irowAt, jcolAt, Transpose(A.GetBlock(jcolAt, irowAt)));
460  return At;
461 }
462 
463 BlockMatrix * Mult(const BlockMatrix & A, const BlockMatrix & B)
464 {
465  BlockMatrix * C= new BlockMatrix(A.RowOffsets(), B.ColOffsets());
466  C->owns_blocks = 1;
467  Array<SparseMatrix *> CijPieces(A.NumColBlocks());
468 
469  for (int irowC = 0; irowC < A.NumRowBlocks(); ++irowC)
470  for (int jcolC = 0; jcolC < B.NumColBlocks(); ++jcolC)
471  {
472  CijPieces.SetSize(0, static_cast<SparseMatrix *>(NULL));
473  for (int k = 0; k < A.NumColBlocks(); ++k)
474  if (!A.IsZeroBlock(irowC, k) && !B.IsZeroBlock(k, jcolC))
475  CijPieces.Append(Mult(A.GetBlock(irowC, k), B.GetBlock(k, jcolC)));
476 
477  if (CijPieces.Size() > 1)
478  {
479  C->SetBlock(irowC, jcolC, Add(CijPieces));
480  for (SparseMatrix ** it = CijPieces.GetData();
481  it != CijPieces.GetData()+CijPieces.Size(); ++it)
482  delete *it;
483  }
484  else if (CijPieces.Size() == 1)
485  {
486  C->SetBlock(irowC, jcolC, CijPieces[0]);
487  }
488  }
489 
490  return C;
491 }
492 
493 }
int Size() const
Logical size of the array.
Definition: array.hpp:108
void PrintMatlab(std::ostream &os=std::cout) const
Export the monolithic matrix to file.
SparseMatrix * CreateMonolithic() const
Returns a monolithic CSR matrix that represents this operator.
int owns_blocks
if owns_blocks the SparseMatrix objects Aij will be deallocated.
void SetSize(int s)
Resizes the vector if the new size is different.
Definition: vector.hpp:248
void Mult(const Table &A, const Table &B, Table &C)
C = A * B (as boolean matrices)
Definition: table.cpp:351
int Width() const
Get the width (size of input) of the Operator. Synonym with NumCols.
Definition: operator.hpp:41
Abstract data type for sparse matrices.
Definition: matrix.hpp:69
T * GetData()
Returns the data.
Definition: array.hpp:90
BlockMatrix(const Array< int > &offsets)
Constructor for square block matrices.
Definition: blockmatrix.cpp:21
double * GetData() const
Definition: vector.hpp:80
virtual void AddMultTranspose(const Vector &x, Vector &y, const double val=1.) const
MatrixTranspose-Vector Multiplication y = y + val*A&#39;*x.
virtual int GetRow(const int row, Array< int > &cols, Vector &srow) const
void Add(const DenseMatrix &A, const DenseMatrix &B, double alpha, DenseMatrix &C)
C = A + alpha*B.
Definition: densemat.cpp:2430
void SetBlock(int i, int j, SparseMatrix *mat)
Set A(i,j) = mat.
Definition: blockmatrix.cpp:54
virtual double & Elem(int i, int j)
Returns reference to a_{ij}.
virtual void EliminateZeroRows()
Data type sparse matrix.
Definition: sparsemat.hpp:38
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows.
Definition: operator.hpp:35
int IsZeroBlock(int i, int j) const
Check if block (i,j) is a zero block.
Definition: blockmatrix.hpp:51
int NumRowBlocks() const
Return the number of row blocks.
Definition: blockmatrix.hpp:42
Array< int > & ColOffsets()
Return the columns offsets for block starts.
Definition: blockmatrix.hpp:55
void Transpose(const Table &A, Table &At, int _ncols_A)
Transpose a Table.
Definition: table.cpp:305
Array< int > & RowOffsets()
Return the row offsets for block starts.
Definition: blockmatrix.hpp:53
void EliminateRowCol(Array< int > &ess_bc_dofs, Vector &sol, Vector &rhs)
Symmetric elimination of the marked degree of freedom.
virtual int NumNonZeroElems() const
Returns the total number of non zeros in the matrix.
Definition: blockmatrix.cpp:95
virtual ~BlockMatrix()
Destructor.
Definition: blockmatrix.cpp:46
double * GetData() const
Return element data.
Definition: sparsemat.hpp:101
virtual void MultTranspose(const Vector &x, Vector &y) const
MatrixTranspose-Vector Multiplication y = A&#39;*x.
virtual void Mult(const Vector &x, Vector &y) const
Matrix-Vector Multiplication y = A*x.
void mfem_error(const char *msg)
Definition: error.cpp:23
void SetSize(int nsize)
Change logical size of the array, keep existing entries.
Definition: array.hpp:293
int NumColBlocks() const
Return the number of column blocks.
Definition: blockmatrix.hpp:44
void SetDataAndSize(double *d, int s)
Definition: vector.hpp:64
virtual void AddMult(const Vector &x, Vector &y, const double val=1.) const
Matrix-Vector Multiplication y = y + val*A*x.
SparseMatrix & GetBlock(int i, int j)
Return a reference to block (i,j). Reference may be invalid if Aij(i,j) == NULL.
Definition: blockmatrix.cpp:69
T & Last()
Return the last element in the array.
Definition: array.hpp:361
void MakeRef(T *, int)
Make this Array a reference to a poiter.
Definition: array.hpp:416
Vector data type.
Definition: vector.hpp:29
int RowSize(const int i) const
Return the number of non zeros in row i.