26 nRowBlocks(offsets.Size()-1),
27 nColBlocks(offsets.Size()-1),
28 Aij(nRowBlocks, nColBlocks)
39 nRowBlocks(row_offsets_.Size()-1),
40 nColBlocks(col_offsets_.Size()-1),
41 Aij(nRowBlocks, nColBlocks)
54 it != Aij.GetRow(0)+(Aij.NumRows()*Aij.NumCols()); ++it)
64 if (nRowBlocks <= i || nColBlocks <= j)
69 if (mat->
Height() != row_offsets[i+1] - row_offsets[i])
74 if (mat->
Width() != col_offsets[j+1] - col_offsets[j])
85 if (nRowBlocks <= i || nColBlocks <= j)
101 if (nRowBlocks <= i || nColBlocks <= j)
119 for (
int jcol = 0; jcol != nColBlocks; ++jcol)
121 for (
int irow = 0; irow != nRowBlocks; ++irow)
125 nnz_elem+= Aij(irow,jcol)->NumNonZeroElems();
138 findGlobalRow(i, iblock, iloc);
139 findGlobalCol(j, jblock, jloc);
146 return Aij(iblock, jblock)->Elem(iloc, jloc);
151 static const real_t zero = 0.0;
155 findGlobalRow(i, iblock, iloc);
156 findGlobalCol(j, jblock, jloc);
162 return static_cast<const SparseMatrix *
>(Aij(iblock, jblock))->
Elem(iloc, jloc);
170 findGlobalRow(i, iblock, iloc);
172 for (
int jblock = 0; jblock < nColBlocks; ++jblock)
174 if (Aij(iblock,jblock) != NULL)
176 rowsize += Aij(iblock,jblock)->RowSize(iloc);
185 int iblock, iloc, rowsize;
186 findGlobalRow(row, iblock, iloc);
194 int * it_cols = cols.
GetData();
197 for (
int jblock = 0; jblock < nColBlocks; ++jblock)
199 if (Aij(iblock,jblock) != NULL)
201 Aij(iblock,jblock)->GetRow(iloc, bcols, bsrow);
202 for (
int i = 0; i < bcols.
Size(); ++i)
204 *(it_cols++) = bcols[i] + col_offsets[jblock];
205 *(it_srow++) = bsrow(i);
217 for (iiblock = 0; iiblock < nRowBlocks; ++iiblock)
219 idx = rc - row_offsets[iiblock];
220 if (idx < 0 ) {
break; }
223 idx = rc - row_offsets[iiblock];
226 MFEM_ASSERT(nRowBlocks == nColBlocks,
227 "BlockMatrix::EliminateRowCol: nRowBlocks != nColBlocks");
229 MFEM_ASSERT(row_offsets[iiblock] == col_offsets[iiblock],
230 "BlockMatrix::EliminateRowCol: row_offsets["
231 << iiblock <<
"] != col_offsets["<<iiblock<<
"]");
233 MFEM_ASSERT(Aij(iiblock, iiblock),
234 "BlockMatrix::EliminateRowCol: Null diagonal block");
237 for (
int jjblock = 0; jjblock < nRowBlocks; ++jjblock)
239 if (iiblock == jjblock) {
continue; }
240 if (Aij(iiblock,jjblock)) { Aij(iiblock,jjblock)->EliminateRow(idx); }
242 for (
int jjblock = 0; jjblock < nRowBlocks; ++jjblock)
244 if (iiblock == jjblock) {
continue; }
245 if (Aij(jjblock,iiblock)) { Aij(jjblock,iiblock)->EliminateCol(idx); }
247 Aij(iiblock, iiblock)->EliminateRowCol(idx,dpolicy);
253 if (nRowBlocks != nColBlocks)
255 mfem_error(
"BlockMatrix::EliminateRowCol: nRowBlocks != nColBlocks");
258 for (
int iiblock = 0; iiblock < nRowBlocks; ++iiblock)
260 if (row_offsets[iiblock] != col_offsets[iiblock])
262 mfem::out <<
"BlockMatrix::EliminateRowCol: row_offsets["
263 << iiblock <<
"] != col_offsets["<<iiblock<<
"]\n";
270 Vector block_sol, block_rhs;
272 for (
int iiblock = 0; iiblock < nRowBlocks; ++iiblock)
274 int dsize = row_offsets[iiblock+1] - row_offsets[iiblock];
275 block_dofs.
MakeRef(ess_bc_dofs.
GetData()+row_offsets[iiblock], dsize);
279 if (Aij(iiblock, iiblock))
281 for (
int i = 0; i < block_dofs.
Size(); ++i)
285 Aij(iiblock, iiblock)->EliminateRowCol(i,block_sol(i), block_rhs);
291 for (
int i = 0; i < block_dofs.
Size(); ++i)
295 mfem_error(
"BlockMatrix::EliminateRowCol: Null diagonal block \n");
300 for (
int jjblock = 0; jjblock < nRowBlocks; ++jjblock)
302 if (jjblock != iiblock && Aij(iiblock, jjblock))
304 for (
int i = 0; i < block_dofs.
Size(); ++i)
308 Aij(iiblock, jjblock)->EliminateRow(i);
312 if (jjblock != iiblock && Aij(jjblock, iiblock))
315 row_offsets[jjblock+1] - row_offsets[jjblock]);
316 Aij(jjblock, iiblock)->EliminateCols(block_dofs, &block_sol, &block_rhs);
326 "BlockMatrix::EliminateRowCols: Elimination matrix pointer is null");
327 MFEM_VERIFY(nRowBlocks == nColBlocks,
328 "BlockMatrix::EliminateRowCols supported only for"
329 "nRowBlocks = nColBlocks");
331 std::vector<Array<int>> cols(nRowBlocks);
332 std::vector<Array<int>> rows(nRowBlocks);
335 for (
int k = 0; k < vdofs.
Size(); k++)
337 int vdof = (vdofs[k]) >=0 ? vdofs[k] : -1 - vdofs[k];
340 findGlobalCol(vdof,iblock,dof);
341 cols[iblock].Append(dof);
350 for (
int j = 0; j<nColBlocks; j++)
352 if (!cols[j].Size()) {
continue; }
353 int blocksize = col_offsets[j+1] - col_offsets[j];
354 Array<int> colmarker(blocksize); colmarker = 0;
355 for (
int i = 0; i < cols[j].Size(); i++) { colmarker[cols[j][i]] = 1; }
356 for (
int i = 0; i<nRowBlocks; i++)
358 if (i == j) {
continue; }
361 for (
int k = 0; k < cols[j].Size(); k++)
372 MFEM_VERIFY(nRowBlocks == nColBlocks,
"not a square matrix");
374 for (
int iblock = 0; iblock < nRowBlocks; ++iblock)
376 if (Aij(iblock,iblock))
379 for (
int i = 0; i < Aij(iblock, iblock)->NumRows(); ++i)
382 for (
int jblock = 0; jblock < nColBlocks; ++jblock)
383 if (Aij(iblock,jblock))
385 norm += Aij(iblock,jblock)->GetRowNorml1(i);
388 if (norm <= threshold)
390 for (
int jblock = 0; jblock < nColBlocks; ++jblock)
392 if (Aij(iblock,jblock))
394 Aij(iblock,jblock)->EliminateRow(
404 for (
int i = 0; i < row_offsets[iblock+1] - row_offsets[iblock]; ++i)
407 for (
int jblock = 0; jblock < nColBlocks; ++jblock)
409 if (Aij(iblock,jblock))
411 norm += Aij(iblock,jblock)->GetRowNorml1(i);
415 MFEM_VERIFY(!(norm <= threshold),
"diagonal block is NULL:"
416 " iblock = " << iblock <<
", i = " << i <<
", norm = "
425 for (
int iblock = 0; iblock < nRowBlocks; ++iblock)
427 for (
int jblock = 0; jblock < nColBlocks; ++jblock)
429 if (!Aij(iblock,jblock)) {
continue; }
430 if (!Aij(iblock,jblock)->Finalized())
432 Aij(iblock,jblock)->Finalize(skip_zeros, fix_empty_rows);
442 mfem_error(
"Error: x and y can't point to the same data \n");
445 MFEM_ASSERT(
width == x.
Size(),
"Input vector size (" << x.
Size()
446 <<
") must match matrix width (" <<
width <<
")");
447 MFEM_ASSERT(
height == y.
Size(),
"Output vector size (" << y.
Size()
448 <<
") must match matrix height (" <<
height <<
")");
457 mfem_error(
"Error: x and y can't point to the same data \n");
460 Vector xblockview, yblockview;
462 for (
int iblock = 0; iblock != nRowBlocks; ++iblock)
465 row_offsets[iblock+1] - row_offsets[iblock]);
467 for (
int jblock = 0; jblock != nColBlocks; ++jblock)
469 if (Aij(iblock, jblock) != NULL)
472 x.
GetData() + col_offsets[jblock],
473 col_offsets[jblock+1] - col_offsets[jblock]);
475 Aij(iblock, jblock)->AddMult(xblockview, yblockview, val);
485 mfem_error(
"Error: x and y can't point to the same data \n");
497 mfem_error(
"Error: x and y can't point to the same data \n");
500 Vector xblockview, yblockview;
502 for (
int iblock = 0; iblock != nColBlocks; ++iblock)
505 col_offsets[iblock+1] - col_offsets[iblock]);
507 for (
int jblock = 0; jblock != nRowBlocks; ++jblock)
509 if (Aij(jblock, iblock) != NULL)
512 x.
GetData() + row_offsets[jblock],
513 row_offsets[jblock+1] - row_offsets[jblock]);
515 Aij(jblock, iblock)->AddMultTranspose(xblockview, yblockview, val);
526 for (
int i = 0; i<rows.
Size(); i++)
528 int dof = (rows[i]>=0) ? rows[i] : -1-rows[i];
532 for (
int k = 0; k <cols.
Size(); k++)
534 s += srow[k] * x[cols[k]];
545 for (
int i = 0; i<rows.
Size(); i++)
547 int dof = (rows[i]>=0) ? rows[i] : -1-rows[i];
551 for (
int k = 0; k <cols.
Size(); k++)
553 s += srow[k] * x[cols[k]];
564 int * i_amono =
Memory<int>(row_offsets[nRowBlocks]+2);
568 for (
int i = 0; i < row_offsets[nRowBlocks]+2; i++)
573 int * i_amono_construction = i_amono+1;
575 for (
int iblock = 0; iblock != nRowBlocks; ++iblock)
577 for (
int irow(row_offsets[iblock]); irow < row_offsets[iblock+1]; ++irow)
579 int local_row = irow - row_offsets[iblock];
580 int ind = i_amono_construction[irow];
581 for (
int jblock = 0; jblock < nColBlocks; ++jblock)
583 if (Aij(iblock,jblock) != NULL)
584 ind += Aij(iblock, jblock)->GetI()[local_row+1]
585 - Aij(iblock, jblock)->GetI()[local_row];
587 i_amono_construction[irow+1] = ind;
592 for (
int iblock = 0; iblock != nRowBlocks; ++iblock)
594 for (
int jblock = 0; jblock != nColBlocks; ++jblock)
596 if (Aij(iblock,jblock) != NULL)
598 int nrow = row_offsets[iblock+1]-row_offsets[iblock];
599 int * i_aij = Aij(iblock, jblock)->GetI();
600 int * j_aij = Aij(iblock, jblock)->GetJ();
601 real_t * data_aij = Aij(iblock, jblock)->GetData();
602 int *i_it = i_amono_construction+row_offsets[iblock];
604 int loc_start_index = 0;
605 int loc_end_index = 0;
606 int glob_start_index = 0;
608 int shift(col_offsets[jblock]);
609 for (
int * i_it_aij(i_aij+1); i_it_aij != i_aij+nrow+1; ++i_it_aij)
611 glob_start_index = *i_it;
614 if (glob_start_index > nnz)
616 mfem::out<<
"glob_start_index = " << glob_start_index <<
"\n";
617 mfem::out<<
"Block:" << iblock <<
" " << jblock <<
"\n";
621 loc_end_index = *(i_it_aij);
622 for (
int cnt = 0; cnt < loc_end_index-loc_start_index; cnt++)
624 data[glob_start_index+cnt] = data_aij[loc_start_index+cnt];
625 j_amono[glob_start_index+cnt] = j_aij[loc_start_index+cnt] + shift;
628 *i_it += loc_end_index-loc_start_index;
630 loc_start_index = loc_end_index;
636 return new SparseMatrix(i_amono, j_amono, data, row_offsets[nRowBlocks],
637 col_offsets[nColBlocks]);
646 os<<
"% size " << row_offsets.
Last() <<
" " << col_offsets.
Last() <<
"\n";
647 os<<
"% Non Zeros " << nnz_elem <<
"\n";
649 std::ios::fmtflags old_fmt = os.flags();
650 os.setf(std::ios::scientific);
651 std::streamsize old_prec = os.precision(14);
652 for (i = 0; i < row_offsets.
Last(); i++)
654 GetRow(i, row_ind, row_data);
655 for (j = 0; j < row_ind.
Size(); j++)
657 os << i+1 <<
" " << row_ind[j]+1 <<
" " << row_data[j] << std::endl;
661 os << row_offsets.
Last() <<
" " << col_offsets.
Last () <<
" 0.0\n";
663 os.precision(old_prec);
672 for (
int irowAt = 0; irowAt < At->
NumRowBlocks(); ++irowAt)
674 for (
int jcolAt = 0; jcolAt < At->
NumColBlocks(); ++jcolAt)
704 if (CijPieces.
Size() > 1)
713 else if (CijPieces.
Size() == 1)
715 C->
SetBlock(irowC, jcolC, CijPieces[0]);
Abstract data type for sparse matrices.
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
int Size() const
Return the logical size of the array.
void MakeRef(T *data_, int size_, bool own_data=false)
Make this Array a reference to a pointer.
int Append(const T &el)
Append element 'el' to array, resize if necessary.
T * GetData()
Returns the data.
T & Last()
Return the last element in the array.
virtual ~BlockMatrix()
Destructor.
virtual void AddMult(const Vector &x, Vector &y, const real_t val=1.) const
Matrix-Vector Multiplication y = y + val*A*x.
int RowSize(const int i) const
Return the number of non zeros in row i.
Array< int > & ColOffsets()
Return the columns offsets for block starts.
void EliminateRowCol(int rc, DiagonalPolicy dpolicy=DIAG_ONE)
Eliminate the row and column rc from the matrix.
void PartMult(const Array< int > &rows, const Vector &x, Vector &y) const
Partial matrix vector multiplication of (*this) with x involving only the rows given by rows....
virtual void EliminateZeroRows(const real_t threshold=1e-12)
If the matrix is square, this method will place 1 on the diagonal (i,i) if row i has "almost" zero l1...
virtual void AddMultTranspose(const Vector &x, Vector &y, const real_t val=1.) const
MatrixTranspose-Vector Multiplication y = y + val*A'*x.
BlockMatrix(const Array< int > &offsets)
Constructor for square block matrices.
void SetBlock(int i, int j, SparseMatrix *mat)
Set A(i,j) = mat.
virtual void PrintMatlab(std::ostream &os=mfem::out) const
Export the monolithic matrix to file.
virtual real_t & Elem(int i, int j)
Returns reference to a_{ij}.
int NumColBlocks() const
Return the number of column blocks.
int IsZeroBlock(int i, int j) const
Check if block (i,j) is a zero block.
void EliminateRowCols(const Array< int > &vdofs, BlockMatrix *Ae, DiagonalPolicy dpolicy=DIAG_ONE)
Eliminate the rows and columns corresponding to the entries in vdofs + save the eliminated entries in...
SparseMatrix & GetBlock(int i, int j)
Return a reference to block (i,j). Reference may be invalid if Aij(i,j) == NULL.
virtual int GetRow(const int row, Array< int > &cols, Vector &srow) const
Gets the columns indexes and values for row row.
Array< int > & RowOffsets()
Return the row offsets for block starts.
virtual int NumNonZeroElems() const
Returns the total number of non zeros in the matrix.
int owns_blocks
If owns_blocks the SparseMatrix objects Aij will be deallocated.
virtual void Finalize(int skip_zeros=1)
Finalize all the submatrices.
void PartAddMult(const Array< int > &rows, const Vector &x, Vector &y, const real_t a=1.0) const
Partial matrix vector multiplication of (*this) with x involving only the rows given by rows....
virtual void Mult(const Vector &x, Vector &y) const
Matrix-Vector Multiplication y = A*x.
virtual void MultTranspose(const Vector &x, Vector &y) const
MatrixTranspose-Vector Multiplication y = A'*x.
int NumRowBlocks() const
Return the number of row blocks.
SparseMatrix * CreateMonolithic() const
Returns a monolithic CSR matrix that represents this operator.
Class used by MFEM to store pointers to host and/or device memory.
int width
Dimension of the input / number of columns in the matrix.
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
int height
Dimension of the output / number of rows in the matrix.
DiagonalPolicy
Defines operator diagonal policy upon elimination of rows and/or columns.
@ DIAG_ONE
Set the diagonal value to one.
@ DIAG_ZERO
Set the diagonal value to zero.
int Width() const
Get the width (size of input) of the Operator. Synonym with NumCols().
void EliminateRowCol(int rc, const real_t sol, Vector &rhs, DiagonalPolicy dpolicy=DIAG_ONE)
Eliminate row rc and column rc and modify the rhs using sol.
void EliminateRow(int row, const real_t sol, Vector &rhs)
Eliminates a column from the transpose matrix.
void EliminateCols(const Array< int > &cols, const Vector *x=NULL, Vector *b=NULL)
Eliminate all columns i for which cols[i] != 0.
void SetDataAndSize(real_t *d, int s)
Set the Vector data and size.
int Size() const
Returns the size of the vector.
void SetSize(int s)
Resize the vector to size s.
real_t * GetData() const
Return a pointer to the beginning of the Vector data.
void mfem_error(const char *msg)
void Mult(const Table &A, const Table &B, Table &C)
C = A * B (as boolean matrices)
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
void Transpose(const Table &A, Table &At, int ncols_A_)
Transpose a Table.
void Add(const DenseMatrix &A, const DenseMatrix &B, real_t alpha, DenseMatrix &C)
C = A + alpha*B.