67
68
//-----------------------------------------------------------------------------
68
PETScMatrix::PETScMatrix(boost::shared_ptr<Mat> A, bool use_gpu) :
69
PETScBaseMatrix(A), _use_gpu(use_gpu)
71
#ifndef HAS_PETSC_CUSP
69
PETScMatrix::PETScMatrix(Mat A) : PETScBaseMatrix(A), _use_gpu(false)
71
// Do nothing (reference count to A is incremented in base class)
73
//-----------------------------------------------------------------------------
74
PETScMatrix::PETScMatrix(const PETScMatrix& A) : PETScBaseMatrix(NULL),
74
dolfin_error("PETScMatrix.cpp",
76
"PETSc not compiled with Cusp support");
79
PetscErrorCode ierr = MatDuplicate(A.mat(), MAT_COPY_VALUES, &_matA);
80
if (ierr != 0) petsc_error(ierr, __FILE__, "MatDuplicate");
80
//-----------------------------------------------------------------------------
81
PETScMatrix::PETScMatrix(const PETScMatrix& A): _use_gpu(false)
85
83
//-----------------------------------------------------------------------------
86
84
PETScMatrix::~PETScMatrix()
86
// Do nothing (PETSc matrix is destroyed in base class)
90
88
//-----------------------------------------------------------------------------
91
boost::shared_ptr<GenericMatrix> PETScMatrix::copy() const
89
std::shared_ptr<GenericMatrix> PETScMatrix::copy() const
93
boost::shared_ptr<GenericMatrix> B;
95
B.reset(new PETScMatrix());
98
// Create copy of PETSc matrix
99
boost::shared_ptr<Mat> _Acopy(new Mat, PETScMatrixDeleter());
100
PetscErrorCode ierr = MatDuplicate(*_A, MAT_COPY_VALUES, _Acopy.get());
101
if (ierr != 0) petsc_error(ierr, __FILE__, "MatDuplicate");
103
// Create PETScMatrix
104
B.reset(new PETScMatrix(_Acopy));
91
return std::shared_ptr<GenericMatrix>(new PETScMatrix(*this));
109
93
//-----------------------------------------------------------------------------
110
94
void PETScMatrix::init(const TensorLayout& tensor_layout)
121
105
= tensor_layout.local_range(1);
122
106
const std::size_t m = row_range.second - row_range.first;
123
107
const std::size_t n = col_range.second - col_range.first;
124
dolfin_assert(M > 0 && N > 0 && m > 0 && n > 0);
126
109
// Get sparsity pattern
127
110
dolfin_assert(tensor_layout.sparsity_pattern());
128
111
const GenericSparsityPattern& sparsity_pattern
129
112
= *tensor_layout.sparsity_pattern();
131
// Create matrix (any old matrix is destroyed automatically)
132
if (_A && !_A.unique())
134
dolfin_error("PETScMatrix.cpp",
135
"initialize PETSc matrix",
136
"More than one object points to the underlying PETSc object");
116
#ifdef DOLFIN_DEPRECATION_ERROR
117
error("PETScMatrix may not be initialized more than once. Remove build definiton -DDOLFIN_DEPRECATION_ERROR to change this to a warning.");
119
warning("PETScMatrix may not be initialized more than once. In version > 1.4, this will become an error.");
138
_A.reset(new Mat, PETScMatrixDeleter());
140
124
// Initialize matrix
141
125
if (row_range.first == 0 && row_range.second == M)
145
129
std::vector<std::size_t> num_nonzeros(M);
146
130
sparsity_pattern.num_nonzeros_diagonal(num_nonzeros);
149
//cout << "Number of nonzeros for PETSc matrix:" << endl;
150
//for (unsigned int i = 0; i < M; i++)
151
// cout << "i = " << i << ": " << num_nonzeros[i] << endl;
154
ierr = MatCreate(PETSC_COMM_SELF, _A.get());
133
ierr = MatCreate(PETSC_COMM_SELF, &_matA);
155
134
if (ierr != 0) petsc_error(ierr, __FILE__, "MatCreate");
158
ierr = MatSetSizes(*_A, M, N, M, N);
137
ierr = MatSetSizes(_matA, M, N, M, N);
159
138
if (ierr != 0) petsc_error(ierr, __FILE__, "MatSetSizes");
161
140
// Set matrix type according to chosen architecture
164
ierr = MatSetType(*_A, MATSEQAIJ);
143
ierr = MatSetType(_matA, MATSEQAIJ);
165
144
if (ierr != 0) petsc_error(ierr, __FILE__, "MatSetType");
167
146
#ifdef HAS_PETSC_CUSP
170
ierr = MatSetType(*_A, MATSEQAIJCUSP);
149
ierr = MatSetType(_matA, MATSEQAIJCUSP);
171
150
if (ierr != 0) petsc_error(ierr, __FILE__, "MatSetType");
175
154
// Set block size
176
155
if (tensor_layout.block_size > 1)
178
ierr = MatSetBlockSize(*_A, tensor_layout.block_size);
157
ierr = MatSetBlockSize(_matA, tensor_layout.block_size);
179
158
if (ierr != 0) petsc_error(ierr, __FILE__, "MatSetBlockSize");
186
165
// Copy number of non-zeros to PetscInt type
187
166
const std::vector<PetscInt> _num_nonzeros(num_nonzeros.begin(),
188
167
num_nonzeros.end());
189
ierr = MatSeqAIJSetPreallocation(*_A, 0, _num_nonzeros.data());
168
ierr = MatSeqAIJSetPreallocation(_matA, 0, _num_nonzeros.data());
190
169
if (ierr != 0) petsc_error(ierr, __FILE__, "MatSeqAIJSetPreallocation");
192
171
// Set column indices
202
181
// cout << " Col: " << _column_indices[i][j] << endl;
203
182
column_indices.insert(column_indices.end(), _column_indices[i].begin(), _column_indices[i].end());
205
MatSeqAIJSetColumnIndices(*_A, &column_indices[0]);
184
MatSeqAIJSetColumnIndices(_matA, &column_indices[0]);
216
195
// FIXME: Try using MatStashSetInitialSize to optimise performance
218
//info("Initializing parallel PETSc matrix (MPIAIJ) of size %d x %d.", M, N);
219
//info("Local range is [%d, %d] x [%d, %d].",
220
// row_range.first, row_range.second, col_range.first, col_range.second);
222
197
// Get number of nonzeros for each row from sparsity pattern
223
198
std::vector<std::size_t> num_nonzeros_diagonal;
224
199
std::vector<std::size_t> num_nonzeros_off_diagonal;
226
201
sparsity_pattern.num_nonzeros_off_diagonal(num_nonzeros_off_diagonal);
229
ierr = MatCreate(PETSC_COMM_WORLD, _A.get());
204
ierr = MatCreate(PETSC_COMM_WORLD, &_matA);
230
205
if (ierr != 0) petsc_error(ierr, __FILE__, "MatCreate");
233
ierr = MatSetSizes(*_A, m, n, M, N);
208
ierr = MatSetSizes(_matA, m, n, M, N);
234
209
if (ierr != 0) petsc_error(ierr, __FILE__, "MatSetSizes");
236
211
// Set matrix type
237
ierr = MatSetType(*_A, MATMPIAIJ);
212
ierr = MatSetType(_matA, MATMPIAIJ);
238
213
if (ierr != 0) petsc_error(ierr, __FILE__, "MatSetType");
240
215
// Set block size
241
216
if (tensor_layout.block_size > 1)
243
ierr = MatSetBlockSize(*_A, tensor_layout.block_size);
218
ierr = MatSetBlockSize(_matA, tensor_layout.block_size);
244
219
if (ierr != 0) petsc_error(ierr, __FILE__, "MatSetBlockSize");
246
221
// Allocate space (using data from sparsity pattern)
250
225
const std::vector<PetscInt>
251
226
_num_nonzeros_off_diagonal(num_nonzeros_off_diagonal.begin(),
252
227
num_nonzeros_off_diagonal.end());
253
ierr = MatMPIAIJSetPreallocation(*_A, 0, _num_nonzeros_diagonal.data(),
228
ierr = MatMPIAIJSetPreallocation(_matA, 0, _num_nonzeros_diagonal.data(),
254
229
0, _num_nonzeros_off_diagonal.data());
255
230
if (ierr != 0) petsc_error(ierr, __FILE__, "MatMPIAIJSetPreallocation");
258
233
// Set some options
260
235
// Do not allow more entries than have been pre-allocated
261
ierr = MatSetOption(*_A, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE);
262
if (ierr != 0) petsc_error(ierr, __FILE__, "MatSetOption");
264
ierr = MatSetOption(*_A, MAT_KEEP_NONZERO_PATTERN, PETSC_TRUE);
265
if (ierr != 0) petsc_error(ierr, __FILE__, "MatSetOption");
267
ierr = MatSetFromOptions(*_A);
236
ierr = MatSetOption(_matA, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE);
237
if (ierr != 0) petsc_error(ierr, __FILE__, "MatSetOption");
239
ierr = MatSetOption(_matA, MAT_KEEP_NONZERO_PATTERN, PETSC_TRUE);
240
if (ierr != 0) petsc_error(ierr, __FILE__, "MatSetOption");
242
ierr = MatSetFromOptions(_matA);
268
243
if (ierr != 0) petsc_error(ierr, __FILE__, "MatSetFromOptions");
270
245
#if PETSC_VERSION_MAJOR == 3 && PETSC_VERSION_MINOR > 2
271
ierr = MatSetUp(*_A.get());
246
ierr = MatSetUp(_matA);
272
247
if (ierr != 0) petsc_error(ierr, __FILE__, "MatSetUp");
275
250
//-----------------------------------------------------------------------------
251
bool PETScMatrix::empty() const
253
return _matA ? false : true;
255
//-----------------------------------------------------------------------------
276
256
void PETScMatrix::get(double* block,
277
257
std::size_t m, const dolfin::la_index* rows,
278
258
std::size_t n, const dolfin::la_index* cols) const
280
260
// Get matrix entries (must be on this process)
282
PetscErrorCode ierr = MatGetValues(*_A, m, rows, n, cols, block);
261
dolfin_assert(_matA);
262
PetscErrorCode ierr = MatGetValues(_matA, m, rows, n, cols, block);
283
263
if (ierr != 0) petsc_error(ierr, __FILE__, "MatGetValues");
285
265
//-----------------------------------------------------------------------------
287
267
std::size_t m, const dolfin::la_index* rows,
288
268
std::size_t n, const dolfin::la_index* cols)
291
PetscErrorCode ierr = MatSetValues(*_A, m, rows, n, cols, block,
270
dolfin_assert(_matA);
271
PetscErrorCode ierr = MatSetValues(_matA, m, rows, n, cols, block,
293
273
if (ierr != 0) petsc_error(ierr, __FILE__, "MatSetValues");
297
277
std::size_t m, const dolfin::la_index* rows,
298
278
std::size_t n, const dolfin::la_index* cols)
301
PetscErrorCode ierr = MatSetValues(*_A, m, rows, n, cols, block, ADD_VALUES);
280
dolfin_assert(_matA);
281
PetscErrorCode ierr = MatSetValues(_matA, m, rows, n, cols, block, ADD_VALUES);
302
282
if (ierr != 0) petsc_error(ierr, __FILE__, "MatSetValues");
304
284
//-----------------------------------------------------------------------------
308
288
PetscErrorCode ierr;
310
290
const PETScMatrix* AA = &as_type<const PETScMatrix>(A);
291
dolfin_assert(_matA);
312
292
dolfin_assert(AA->mat());
313
293
if (same_nonzero_pattern)
315
ierr = MatAXPY(*_A, a, *AA->mat(), SAME_NONZERO_PATTERN);
295
ierr = MatAXPY(_matA, a, AA->mat(), SAME_NONZERO_PATTERN);
316
296
if (ierr != 0) petsc_error(ierr, __FILE__, "MatAXPY");
320
ierr = MatAXPY(*_A, a, *AA->mat(), DIFFERENT_NONZERO_PATTERN);
300
ierr = MatAXPY(_matA, a, AA->mat(), DIFFERENT_NONZERO_PATTERN);
321
301
if (ierr != 0) petsc_error(ierr, __FILE__, "MatAXPY");
325
305
void PETScMatrix::getrow(std::size_t row, std::vector<std::size_t>& columns,
326
306
std::vector<double>& values) const
308
dolfin_assert(_matA);
330
310
PetscErrorCode ierr;
331
311
const PetscInt *cols = 0;
332
312
const double *vals = 0;
333
313
PetscInt ncols = 0;
334
ierr = MatGetRow(*_A, row, &ncols, &cols, &vals);
314
ierr = MatGetRow(_matA, row, &ncols, &cols, &vals);
335
315
if (ierr != 0) petsc_error(ierr, __FILE__, "MatGetRow");
337
317
// Assign values to std::vectors
338
318
columns.assign(cols, cols + ncols);
339
319
values.assign(vals, vals + ncols);
341
ierr = MatRestoreRow(*_A, row, &ncols, &cols, &vals);
321
ierr = MatRestoreRow(_matA, row, &ncols, &cols, &vals);
342
322
if (ierr != 0) petsc_error(ierr, __FILE__, "MatRestorRow");
344
324
//-----------------------------------------------------------------------------
377
357
const PetscInt _m = m;
378
358
ierr = ISCreateGeneral(PETSC_COMM_SELF, _m, rows, PETSC_COPY_VALUES, &is);
379
359
if (ierr != 0) petsc_error(ierr, __FILE__, "ISCreateGeneral");
380
ierr = MatZeroRowsIS(*_A, is, null, NULL, NULL);
360
ierr = MatZeroRowsIS(_matA, is, null, NULL, NULL);
381
361
if (ierr != 0) petsc_error(ierr, __FILE__, "MatZeroRowsIS");
382
362
ierr = ISDestroy(&is);
383
363
if (ierr != 0) petsc_error(ierr, __FILE__, "ISDestroy");
393
373
const PetscInt _m = m;
394
374
ierr = ISCreateGeneral(PETSC_COMM_SELF, _m, rows, PETSC_COPY_VALUES, &is);
395
375
if (ierr != 0) petsc_error(ierr, __FILE__, "ISCreateGeneral");
396
ierr = MatZeroRowsIS(*_A, is, one, NULL, NULL);
376
ierr = MatZeroRowsIS(_matA, is, one, NULL, NULL);
397
377
if (ierr == PETSC_ERR_ARG_WRONGSTATE)
399
379
dolfin_error("PETScMatrix.cpp",
432
412
"Vector for matrix-vector result has wrong size");
435
PetscErrorCode ierr = MatMult(*_A, *xx.vec(), *yy.vec());
415
PetscErrorCode ierr = MatMult(_matA, xx.vec(), yy.vec());
436
416
if (ierr != 0) petsc_error(ierr, __FILE__, "MatMult");
438
418
//-----------------------------------------------------------------------------
439
419
void PETScMatrix::transpmult(const GenericVector& x, GenericVector& y) const
421
dolfin_assert(_matA);
443
423
const PETScVector& xx = as_type<const PETScVector>(x);
444
424
PETScVector& yy = as_type<PETScVector>(y);
461
441
"Vector for transpose matrix-vector result has wrong size");
464
PetscErrorCode ierr = MatMultTranspose(*_A, *xx.vec(), *yy.vec());
444
PetscErrorCode ierr = MatMultTranspose(_matA, xx.vec(), yy.vec());
465
445
if (ierr != 0) petsc_error(ierr, __FILE__, "MatMultTranspose");
467
447
//-----------------------------------------------------------------------------
448
void PETScMatrix::set_diagonal(const GenericVector& x)
450
dolfin_assert(_matA);
452
const PETScVector& xx = x.down_cast<PETScVector>();
453
if (size(1) != size(0) || size(0) != xx.size())
455
dolfin_error("PETScMatrix.cpp",
456
"set diagonal of a PETSc matrix",
457
"Matrix and vector dimensions don't match for matrix-vector set");
460
PetscErrorCode ierr = MatDiagonalSet(_matA, xx.vec(), INSERT_VALUES);
461
if (ierr != 0) petsc_error(ierr, __FILE__, "MatDiagonalSet");
464
//-----------------------------------------------------------------------------
468
465
double PETScMatrix::norm(std::string norm_type) const
467
dolfin_assert(_matA);
472
469
// Check that norm is known
473
470
if (norm_types.count(norm_type) == 0)
480
477
double value = 0.0;
481
PetscErrorCode ierr = MatNorm(*_A, norm_types.find(norm_type)->second,
478
PetscErrorCode ierr = MatNorm(_matA, norm_types.find(norm_type)->second,
483
480
if (ierr != 0) petsc_error(ierr, __FILE__, "MatNorm");
489
486
Timer timer("Apply (PETScMatrix)");
488
dolfin_assert(_matA);
492
489
PetscErrorCode ierr;
493
490
if (mode == "add")
495
ierr = MatAssemblyBegin(*_A, MAT_FINAL_ASSEMBLY);
492
ierr = MatAssemblyBegin(_matA, MAT_FINAL_ASSEMBLY);
496
493
if (ierr != 0) petsc_error(ierr, __FILE__, "MatAssemblyBegin");
497
ierr = MatAssemblyEnd(*_A, MAT_FINAL_ASSEMBLY);
494
ierr = MatAssemblyEnd(_matA, MAT_FINAL_ASSEMBLY);
498
495
if (ierr != 0) petsc_error(ierr, __FILE__, "MatAssemblyEnd");
500
497
else if (mode == "insert")
502
ierr = MatAssemblyBegin(*_A, MAT_FINAL_ASSEMBLY);
499
ierr = MatAssemblyBegin(_matA, MAT_FINAL_ASSEMBLY);
503
500
if (ierr != 0) petsc_error(ierr, __FILE__, "MatAssemblyBegin");
504
ierr = MatAssemblyEnd(*_A, MAT_FINAL_ASSEMBLY);
501
ierr = MatAssemblyEnd(_matA, MAT_FINAL_ASSEMBLY);
505
502
if (ierr != 0) petsc_error(ierr, __FILE__, "MatAssemblyEnd");
507
504
else if (mode == "flush")
509
ierr = MatAssemblyBegin(*_A, MAT_FLUSH_ASSEMBLY);
506
ierr = MatAssemblyBegin(_matA, MAT_FLUSH_ASSEMBLY);
510
507
if (ierr != 0) petsc_error(ierr, __FILE__, "MatAssemblyBegin");
511
ierr = MatAssemblyEnd(*_A, MAT_FLUSH_ASSEMBLY);
508
ierr = MatAssemblyEnd(_matA, MAT_FLUSH_ASSEMBLY);
512
509
if (ierr != 0) petsc_error(ierr, __FILE__, "MatAssemblyEnd");
521
518
//-----------------------------------------------------------------------------
519
MPI_Comm PETScMatrix::mpi_comm() const
521
dolfin_assert(_matA);
522
MPI_Comm mpi_comm = MPI_COMM_NULL;
523
PetscObjectGetComm((PetscObject)_matA, &mpi_comm);
526
//-----------------------------------------------------------------------------
522
527
void PETScMatrix::zero()
525
PetscErrorCode ierr = MatZeroEntries(*_A);
529
dolfin_assert(_matA);
530
PetscErrorCode ierr = MatZeroEntries(_matA);
526
531
if (ierr != 0) petsc_error(ierr, __FILE__, "MatZeroEntries");
528
533
//-----------------------------------------------------------------------------
529
534
const PETScMatrix& PETScMatrix::operator*= (double a)
532
PetscErrorCode ierr = MatScale(*_A, a);
536
dolfin_assert(_matA);
537
PetscErrorCode ierr = MatScale(_matA, a);
533
538
if (ierr != 0) petsc_error(ierr, __FILE__, "MatScale");
536
541
//-----------------------------------------------------------------------------
537
542
const PETScMatrix& PETScMatrix::operator/= (double a)
540
MatScale(*_A, 1.0/a);
544
dolfin_assert(_matA);
545
MatScale(_matA, 1.0/a);
543
548
//-----------------------------------------------------------------------------
549
554
//-----------------------------------------------------------------------------
550
555
bool PETScMatrix::is_symmetric(double tol) const
557
dolfin_assert(_matA);
553
558
PetscBool symmetric = PETSC_FALSE;
554
PetscErrorCode ierr = MatIsSymmetric(*_A, tol, &symmetric);
559
PetscErrorCode ierr = MatIsSymmetric(_matA, tol, &symmetric);
555
560
if (ierr != 0) petsc_error(ierr, __FILE__, "MatIsSymmetric");
556
561
return symmetric == PETSC_TRUE ? true : false;
565
570
return PETScCuspFactory::instance();
568
// Return something to keep the compiler happy. Code will never be reached.
573
// Return something to keep the compiler happy. Code will never be
569
575
return PETScFactory::instance();
571
577
//-----------------------------------------------------------------------------
572
578
const PETScMatrix& PETScMatrix::operator= (const PETScMatrix& A)
584
#ifdef DOLFIN_DEPRECATION_ERROR
585
error("PETScVector may not be initialized more than once. Remove build definiton -DDOLFIN_DEPRECATION_ERROR to change this to a warning. Error is in PETScMatrix::operator=.");
587
warning("PETScVector may not be initialized more than once. In version > 1.4, this will become an error. Warning is in PETScMatrix::operator=.");
576
593
else if (this != &A) // Check for self-assignment
578
if (_A && !_A.unique())
580
dolfin_error("PETScMatrix.cpp",
581
"assign to PETSc matrix",
582
"More than one object points to the underlying PETSc object");
597
// Get reference count to _matA
598
PetscInt ref_count = 0;
599
PetscObjectGetReference((PetscObject)_matA, &ref_count);
602
dolfin_error("PETScMatrix.cpp",
603
"assign to PETSc matrix",
604
"More than one object points to the underlying PETSc object");
606
#ifdef DOLFIN_DEPRECATION_ERROR
607
error("PETScMatrix may not be initialized more than once. Remove build definiton -DDOLFIN_DEPRECATION_ERROR to change this to a warning. Error is in PETScMatrix::operator=.");
609
warning("PETScMatrix may not be initialized more than once. In version > 1.4, this will become an error. Warning is in PETScMatrix::operator=.");
584
_A.reset(new Mat, PETScMatrixDeleter());
586
614
// Duplicate with the same pattern as A.A
587
PetscErrorCode ierr = MatDuplicate(*A.mat(), MAT_COPY_VALUES, _A.get());
615
PetscErrorCode ierr = MatDuplicate(A.mat(), MAT_COPY_VALUES, &_matA);
588
616
if (ierr != 0) petsc_error(ierr, __FILE__, "MatDuplicate");
599
627
FILE_MODE_WRITE, &view_out);
600
628
if (ierr != 0) petsc_error(ierr, __FILE__, "PetscViewerBinaryOpen");
602
ierr = MatView(*(_A.get()), view_out);
630
ierr = MatView(_matA, view_out);
603
631
if (ierr != 0) petsc_error(ierr, __FILE__, "MatView");
605
633
ierr = PetscViewerDestroy(&view_out);
617
645
warning("Verbose output for PETScMatrix not implemented, calling PETSc MatView directly.");
619
647
// FIXME: Maybe this could be an option?
648
dolfin_assert(_matA);
621
649
PetscErrorCode ierr;
622
if (MPI::num_processes() > 1)
650
if (MPI::size(MPI_COMM_WORLD) > 1)
624
ierr = MatView(*_A, PETSC_VIEWER_STDOUT_WORLD);
652
ierr = MatView(_matA, PETSC_VIEWER_STDOUT_WORLD);
625
653
if (ierr != 0) petsc_error(ierr, __FILE__, "MatView");
629
ierr = MatView(*_A, PETSC_VIEWER_STDOUT_SELF);
657
ierr = MatView(_matA, PETSC_VIEWER_STDOUT_SELF);
630
658
if (ierr != 0) petsc_error(ierr, __FILE__, "MatView");