From 43d8d8cb7c944f1eb5bde059b5704608fdf1d30a Mon Sep 17 00:00:00 2001
From: Christoph Lehmann <christoph.lehmann@ufz.de>
Date: Tue, 8 Mar 2016 11:18:45 +0100
Subject: [PATCH] [MaL] PETSc matrix stores pointer to matrix

---
 MathLib/LinAlg/PETSc/PETScMatrix.cpp | 69 +++++++++++++++++++++-------
 MathLib/LinAlg/PETSc/PETScMatrix.h   | 44 ++++++++++--------
 2 files changed, 79 insertions(+), 34 deletions(-)

diff --git a/MathLib/LinAlg/PETSc/PETScMatrix.cpp b/MathLib/LinAlg/PETSc/PETScMatrix.cpp
index d04845c6d4a..a0c56f6b21b 100644
--- a/MathLib/LinAlg/PETSc/PETScMatrix.cpp
+++ b/MathLib/LinAlg/PETSc/PETScMatrix.cpp
@@ -48,6 +48,41 @@ PETScMatrix::PETScMatrix (const PetscInt nrows, const PetscInt ncols, const PETS
     create(mat_opt.d_nz, mat_opt.o_nz);
 }
 
+PETScMatrix::PETScMatrix(const PETScMatrix &A)
+    : _A(new PETSc_Mat)
+    , _nrows(A._nrows)
+    , _ncols(A._ncols)
+    , _n_loc_rows(A._n_loc_rows)
+    , _n_loc_cols(A._n_loc_cols)
+    , _start_rank(A._start_rank)
+    , _end_rank(A._end_rank)
+{
+    _A.reset(new PETSc_Mat);
+    MatConvert(*A._A, MATSAME, MAT_INITIAL_MATRIX, _A.get());
+}
+
+PETScMatrix&
+PETScMatrix::operator=(PETScMatrix const& A)
+{
+    _nrows = A._nrows;
+    _ncols = A._ncols;
+    _n_loc_rows = A._n_loc_rows;
+    _n_loc_cols = A._n_loc_cols;
+    _start_rank = A._start_rank;
+    _end_rank = A._end_rank;
+
+    if (_A) {
+        // TODO this is the slowest option for copying
+        MatCopy(*A._A, *_A, DIFFERENT_NONZERO_PATTERN);
+    } else {
+        destroy();
+        _A.reset(new PETSc_Mat);
+        MatConvert(*A._A, MATSAME, MAT_INITIAL_MATRIX, _A.get());
+    }
+
+    return *this;
+}
+
 void PETScMatrix::setRowsColumnsZero(std::vector<PetscInt> const& row_pos)
 {
     // Each rank (compute core) processes only the rows that belong to the rank itself.
@@ -58,11 +93,11 @@ void PETScMatrix::setRowsColumnsZero(std::vector<PetscInt> const& row_pos)
     // This avoids all reductions in the zero row routines
     // and thus improves performance for very large process counts.
     // See PETSc doc about MAT_NO_OFF_PROC_ZERO_ROWS.
-    MatSetOption(_A, MAT_NO_OFF_PROC_ZERO_ROWS, PETSC_TRUE); 
+    MatSetOption(*_A, MAT_NO_OFF_PROC_ZERO_ROWS, PETSC_TRUE);
     if(nrows>0)
-        MatZeroRows(_A, nrows, &row_pos[0], one, PETSC_NULL, PETSC_NULL);
+        MatZeroRows(*_A, nrows, &row_pos[0], one, PETSC_NULL, PETSC_NULL);
     else
-        MatZeroRows(_A, 0, PETSC_NULL, one, PETSC_NULL, PETSC_NULL);
+        MatZeroRows(*_A, 0, PETSC_NULL, one, PETSC_NULL, PETSC_NULL);
 }
 
 void PETScMatrix::viewer(const std::string &file_name, const PetscViewerFormat vw_format)
@@ -73,13 +108,13 @@ void PETScMatrix::viewer(const std::string &file_name, const PetscViewerFormat v
 
     finalizeAssembly();
 
-    PetscObjectSetName((PetscObject)_A,"Stiffness_matrix");
-    MatView(_A,viewer);
+    PetscObjectSetName((PetscObject)*_A,"Stiffness_matrix");
+    MatView(*_A,viewer);
 
 // This preprocessor is only for debugging, e.g. dump the matrix and exit the program.
 //#define EXIT_TEST
 #ifdef EXIT_TEST
-    MatDestroy(&_A);
+    MatDestroy(_A);
     PetscFinalize();
     exit(0);
 #endif
@@ -88,20 +123,22 @@ void PETScMatrix::viewer(const std::string &file_name, const PetscViewerFormat v
 
 void PETScMatrix::create(const PetscInt d_nz, const PetscInt o_nz)
 {
-    MatCreate(PETSC_COMM_WORLD, &_A);
-    MatSetSizes(_A, _n_loc_rows, _n_loc_cols, _nrows, _ncols);
+    _A.reset(new PETSc_Mat);
+
+    MatCreate(PETSC_COMM_WORLD, _A.get());
+    MatSetSizes(*_A, _n_loc_rows, _n_loc_cols, _nrows, _ncols);
 
-    MatSetFromOptions(_A);
+    MatSetFromOptions(*_A);
 
-    MatSetType(_A, MATMPIAIJ);
-    MatSeqAIJSetPreallocation(_A, d_nz, PETSC_NULL);
-    MatMPIAIJSetPreallocation(_A, d_nz, PETSC_NULL, o_nz, PETSC_NULL);
-    // If pre-allocation does not work one can use MatSetUp(_A), which is much
+    MatSetType(*_A, MATMPIAIJ);
+    MatSeqAIJSetPreallocation(*_A, d_nz, PETSC_NULL);
+    MatMPIAIJSetPreallocation(*_A, d_nz, PETSC_NULL, o_nz, PETSC_NULL);
+    // If pre-allocation does not work one can use MatSetUp(*_A), which is much
     // slower.
 
-    MatGetOwnershipRange(_A, &_start_rank, &_end_rank);
-    MatGetSize(_A, &_nrows,  &_ncols);
-    MatGetLocalSize(_A, &_n_loc_rows, &_n_loc_cols);
+    MatGetOwnershipRange(*_A, &_start_rank, &_end_rank);
+    MatGetSize(*_A, &_nrows,  &_ncols);
+    MatGetLocalSize(*_A, &_n_loc_rows, &_n_loc_cols);
 }
 
 bool finalizeMatrixAssembly(PETScMatrix &mat, const MatAssemblyType asm_type)
diff --git a/MathLib/LinAlg/PETSc/PETScMatrix.h b/MathLib/LinAlg/PETSc/PETScMatrix.h
index 091facf9eb8..d063d585037 100644
--- a/MathLib/LinAlg/PETSc/PETScMatrix.h
+++ b/MathLib/LinAlg/PETSc/PETScMatrix.h
@@ -15,6 +15,7 @@
 #ifndef PETSCMATRIX_H_
 #define PETSCMATRIX_H_
 
+#include <memory>
 #include <string>
 #include <vector>
 
@@ -37,10 +38,7 @@ class PETScMatrix
         using IndexType = PetscInt;
 
     public:
-        // TODO preliminary
-        PETScMatrix() {
-            // TODO implement
-        }
+        PETScMatrix() {}
 
         /*!
           \brief        Constructor for a square matrix partitioning with more options
@@ -60,9 +58,13 @@ class PETScMatrix
 
         ~PETScMatrix()
         {
-            MatDestroy(&_A);
+            destroy();
         }
 
+        PETScMatrix(PETScMatrix const& A);
+
+        PETScMatrix& operator=(PETScMatrix const& A);
+
         /*!
            \brief          Perform MPI collection of assembled entries in buffer
            \param asm_type Assmebly type, either MAT_FLUSH_ASSEMBLY
@@ -70,8 +72,8 @@ class PETScMatrix
         */
         void finalizeAssembly(const MatAssemblyType asm_type = MAT_FINAL_ASSEMBLY)
         {
-            MatAssemblyBegin(_A, asm_type);
-            MatAssemblyEnd(_A, asm_type);
+            MatAssemblyBegin(*_A, asm_type);
+            MatAssemblyEnd(*_A, asm_type);
         }
 
         /// Get the number of rows.
@@ -114,20 +116,24 @@ class PETScMatrix
         /// Get matrix reference.
         PETSc_Mat &getRawMatrix()
         {
-            return _A;
+            return *_A;
         }
-        // TODO preliminary
-        // this method is dangerous insofar you can do arbitrary things also
-        // with a const PETSc matrix.
+
+        /*! Get a matrix reference.
+         *
+         * \warning
+         * This method is dangerous insofar as you can do arbitrary things also
+         * with a const PETSc matrix.
+         */
         PETSc_Mat const& getRawMatrix() const
         {
-            return _A;
+            return *_A;
         }
 
         /// Set all entries to zero.
         void setZero()
         {
-            MatZeroEntries(_A);
+            MatZeroEntries(*_A);
         }
 
         /*
@@ -149,7 +155,7 @@ class PETScMatrix
         */
         void multiply(const PETScVector &vec, PETScVector &vec_r)
         {
-            MatMult(_A, vec.getData(), vec_r.getData() );
+            MatMult(*_A, vec.getData(), vec_r.getData() );
         }
 
         /*!
@@ -160,7 +166,7 @@ class PETScMatrix
         */
         void set(const PetscInt i, const PetscInt j, const PetscScalar value)
         {
-            MatSetValue(_A, i, j, value, INSERT_VALUES);
+            MatSetValue(*_A, i, j, value, INSERT_VALUES);
         }
 
         /*!
@@ -171,7 +177,7 @@ class PETScMatrix
         */
         void add(const PetscInt i, const PetscInt j, const PetscScalar value)
         {
-            MatSetValue(_A, i, j, value, ADD_VALUES);
+            MatSetValue(*_A, i, j, value, ADD_VALUES);
         }
 
         /// Add sub-matrix at positions given by \c indices.
@@ -231,8 +237,10 @@ class PETScMatrix
                     const PetscViewerFormat vw_format = PETSC_VIEWER_ASCII_MATLAB );
 
     private:
+        void destroy() { if (_A) MatDestroy(_A.get()); _A.reset(nullptr); }
+
         /// PETSc matrix
-        PETSc_Mat _A;
+        std::unique_ptr<PETSc_Mat> _A;
 
         /// Number of the global rows
         PetscInt _nrows;
@@ -278,7 +286,7 @@ void PETScMatrix::add(std::vector<PetscInt> const& row_pos,
     const PetscInt nrows = static_cast<PetscInt> (row_pos.size());
     const PetscInt ncols = static_cast<PetscInt> (col_pos.size());
 
-    MatSetValues(_A, nrows, &row_pos[0], ncols, &col_pos[0], &sub_mat(0,0), ADD_VALUES);
+    MatSetValues(*_A, nrows, &row_pos[0], ncols, &col_pos[0], &sub_mat(0,0), ADD_VALUES);
 };
 
 /*!
-- 
GitLab