diff --git a/Solver/linearSystem.cpp b/Solver/linearSystem.cpp index cc3be3107b87de6b69382ddeefcd982366a9c37b..7c271733adf338e427f7431f8cbf096c17ceeb0e 100644 --- a/Solver/linearSystem.cpp +++ b/Solver/linearSystem.cpp @@ -2,7 +2,6 @@ #include "linearSystemFull.h" #include "linearSystemCSR.h" #include "linearSystemGMM.h" -#include "linearSystemPETSc.h" #include "Bindings.h" @@ -46,9 +45,6 @@ void linearSystemBase::registerBindings(binding *b){ cm = cb->addMethod("systemSolve", &linearSystem<fullMatrix<double> >::systemSolve); cm->setDescription("compute x = A^{-1}b"); cb->setParentClass<linearSystemBase>(); -#ifdef HAVE_PETSC - linearSystemPETScRegisterBindings (b); -#endif } void linearSystemBase::setParameter (std::string key, std::string value) { diff --git a/Solver/linearSystemPETSc.cpp b/Solver/linearSystemPETSc.cpp index 6c3184f962636e7e2831a93cb717edcab06fb206..d0d34079eef311c4941251ca5d64e691c39c95ed 100644 --- a/Solver/linearSystemPETSc.cpp +++ b/Solver/linearSystemPETSc.cpp @@ -1,10 +1,20 @@ #include "GmshConfig.h" - #if defined(HAVE_PETSC) +#include "petsc.h" #include "linearSystemPETSc.h" #include "fullMatrix.h" #include <stdlib.h> #include "GmshMessage.h" + +#include "linearSystemPETSc.hpp" + +template class linearSystemPETSc<double>; +#ifdef PETSC_USE_COMPLEX +template class linearSystemPETSc<std::complex<double> >; +#endif + + + void linearSystemPETScBlockDouble::_kspCreate() { KSPCreate(PETSC_COMM_WORLD, &_ksp); if (this->_parameters.count("petscPrefix")) @@ -234,25 +244,4 @@ double linearSystemPETScBlockDouble::normInfRightHandSide() const return nor; } -#include "Bindings.h" -void linearSystemPETScRegisterBindings(binding *b) -{ - // FIXME on complex arithmetic this crashes - #if !defined(PETSC_USE_COMPLEX) - classBinding *cb; - methodBinding *cm; - cb = b->addClass<linearSystemPETSc<PetscScalar> >("linearSystemPETSc"); - cb->setDescription("A linear system solver, based on PETSc"); - cm = cb->setConstructor<linearSystemPETSc<PetscScalar> >(); - cm->setDescription ("A new PETSc<PetscScalar> solver"); - cb->setParentClass<linearSystem<PetscScalar> >(); - cm->setArgNames(NULL); -/* cb = b->addClass<linearSystemPETScBlockDouble >("linearSystemPETScBlock"); - cb->setDescription("A linear system solver, based on PETSc"); - cm = cb->setConstructor<linearSystemPETScBlockDouble >(); - cm->setDescription ("A new PETScBlockDouble solver"); - cb->setParentClass<linearSystem<fullMatrix<PetscScalar> > >();*/ - #endif -} - #endif // HAVE_PETSC diff --git a/Solver/linearSystemPETSc.h b/Solver/linearSystemPETSc.h index ba452033a8d2fc8adc2614681976e316bb95aee8..a2e908a547c3c0c15a16a621c0dd1a45267784b0 100644 --- a/Solver/linearSystemPETSc.h +++ b/Solver/linearSystemPETSc.h @@ -40,11 +40,8 @@ #include "sparsityPattern.h" #include "fullMatrix.h" #include <vector> - #if defined(HAVE_PETSC) -#include <petsc.h> -#include <petscksp.h> - +#include "petsc.h" template <class scalar> class linearSystemPETSc : public linearSystem<scalar> { protected: @@ -55,269 +52,31 @@ class linearSystemPETSc : public linearSystem<scalar> { KSP _ksp; int _localRowStart, _localRowEnd, _localSize, _globalSize; sparsityPattern _sparsity; - static void _try(int ierr) { CHKERRABORT(PETSC_COMM_WORLD, ierr); } - void _kspCreate() { - _try(KSPCreate(PETSC_COMM_WORLD, &_ksp)); - PC pc; - _try(KSPGetPC(_ksp, &pc)); - // set some default options - //_try(PCSetType(pc, PCLU));//LU for direct solver and PCILU for indirect solver -/* _try(PCFactorSetMatOrderingType(pc, MATORDERING_RCM)); - _try(PCFactorSetLevels(pc, 1));*/ - _try(KSPSetTolerances(_ksp, 1.e-8, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT)); - // override the default options with the ones from the option - // database (if any) - if (this->_parameters.count("petscPrefix")) - _try(KSPAppendOptionsPrefix(_ksp, this->_parameters["petscPrefix"].c_str())); - _try(KSPSetFromOptions(_ksp)); - _try(PCSetFromOptions(pc)); - _kspAllocated = true; - } + void _kspCreate(); public: - linearSystemPETSc() : _isAllocated(false) {_blockSize = 0; _kspAllocated = false;} - virtual ~linearSystemPETSc(){ - clear(); - if (_kspAllocated) - _try (KSPDestroy (_ksp)); - } - void insertInSparsityPattern (int i, int j) { - i -= _localRowStart; - if (i<0 || i>= _localSize) return; - _sparsity.insertEntry (i,j); - } + linearSystemPETSc(); + virtual ~linearSystemPETSc(); + void insertInSparsityPattern (int i, int j); virtual bool isAllocated() const { return _isAllocated; } - virtual void preAllocateEntries() { - if (_entriesPreAllocated) return; - if (!_isAllocated) Msg::Fatal("system must be allocated first"); - if (_sparsity.getNbRows() == 0) { - PetscInt prealloc = 300; - PetscTruth set; - PetscOptionsGetInt(PETSC_NULL, "-petsc_prealloc", &prealloc, &set); - if (_blockSize == 0) { - _try(MatSeqAIJSetPreallocation(_a, prealloc, PETSC_NULL)); - } else { - _try(MatSeqBAIJSetPreallocation(_a, _blockSize, 5, PETSC_NULL)); - } - } else { - std::vector<int> nByRowDiag (_localSize), nByRowOffDiag (_localSize); - for (int i = 0; i < _localSize; i++) { - int n; - const int *r = _sparsity.getRow(i, n); - for (int j = 0; j < n; j++) { - if (r[j] >= _localRowStart && r[j] < _localRowEnd) - nByRowDiag[i] ++; - else - nByRowOffDiag[i] ++; - } - } - if (_blockSize == 0) { - _try(MatSeqAIJSetPreallocation(_a, 0, &nByRowDiag[0])); - _try(MatMPIAIJSetPreallocation(_a, 0, &nByRowDiag[0], 0, &nByRowOffDiag[0])); - } else { - _try(MatSeqBAIJSetPreallocation(_a, _blockSize, 0, &nByRowDiag[0])); - _try(MatMPIBAIJSetPreallocation(_a, _blockSize, 0, &nByRowDiag[0], 0, &nByRowOffDiag[0])); - } - _sparsity.clear(); - } - _entriesPreAllocated = true; - } - virtual void allocate(int nbRows) - { - clear(); - _try(MatCreate(PETSC_COMM_WORLD, &_a)); - _try(MatSetSizes(_a, nbRows, nbRows, PETSC_DETERMINE, PETSC_DETERMINE)); - // override the default options with the ones from the option - // database (if any) - if (this->_parameters.count("petscOptions")) - _try(PetscOptionsInsertString(this->_parameters["petscOptions"].c_str())); - if (this->_parameters.count("petscPrefix")) - _try(MatAppendOptionsPrefix(_a, this->_parameters["petscPrefix"].c_str())); - _try(MatSetFromOptions(_a)); - _try(MatGetOwnershipRange(_a, &_localRowStart, &_localRowEnd)); - _try(MatGetSize(_a, &_globalSize, &_localSize)); - // preallocation option must be set after other options - _try(VecCreate(PETSC_COMM_WORLD, &_x)); - _try(VecSetSizes(_x, nbRows, PETSC_DETERMINE)); - // override the default options with the ones from the option - // database (if any) - if (this->_parameters.count("petscPrefix")) - _try(VecAppendOptionsPrefix(_x, this->_parameters["petscPrefix"].c_str())); - _try(VecSetFromOptions(_x)); - _try(VecDuplicate(_x, &_b)); - _isAllocated = true; - _entriesPreAllocated = false; - } - void print() { - _try(MatAssemblyBegin(_a, MAT_FINAL_ASSEMBLY)); - _try(MatAssemblyEnd(_a, MAT_FINAL_ASSEMBLY)); - _try(VecAssemblyBegin(_b)); - _try(VecAssemblyEnd(_b)); - if(Msg::GetCommRank()==0) - printf("a :\n"); - MatView(_a, PETSC_VIEWER_STDOUT_WORLD); - if(Msg::GetCommRank()==0) - printf("b :\n"); - VecView(_b, PETSC_VIEWER_STDOUT_WORLD); - if(Msg::GetCommRank()==0) - printf("x :\n"); - VecView(_x, PETSC_VIEWER_STDOUT_WORLD); - } - virtual void clear() - { - if(_isAllocated){ - _try(MatDestroy(_a)); - _try(VecDestroy(_x)); - _try(VecDestroy(_b)); - } - _isAllocated = false; - } - virtual void getFromMatrix(int row, int col, scalar &val) const - { - Msg::Error("getFromMatrix not implemented for PETSc"); - } - virtual void addToRightHandSide(int row, const scalar &val) - { - PetscInt i = row; - PetscScalar s = val; - _try(VecSetValues(_b, 1, &i, &s, ADD_VALUES)); - } - virtual void getFromRightHandSide(int row, scalar &val) const - { -#if defined(PETSC_USE_COMPLEX) - PetscScalar *tmp; - _try(VecGetArray(_b, &tmp)); - PetscScalar s = tmp[row]; - _try(VecRestoreArray(_b, &tmp)); - // FIXME specialize this routine - val = s.real(); -#else - VecGetValues(_b, 1, &row, &val); -#endif - } - virtual double normInfRightHandSide() const - { - PetscReal nor; - _try(VecNorm(_b, NORM_INFINITY, &nor)); - return nor; - } - virtual void addToMatrix(int row, int col, const scalar &val) - { - if (!_entriesPreAllocated) - preAllocateEntries(); - PetscInt i = row, j = col; - PetscScalar s = val; - _try(MatSetValues(_a, 1, &i, 1, &j, &s, ADD_VALUES)); - } - virtual void getFromSolution(int row, scalar &val) const - { -#if defined(PETSC_USE_COMPLEX) - PetscScalar *tmp; - _try(VecGetArray(_x, &tmp)); - PetscScalar s = tmp[row]; - _try(VecRestoreArray(_x, &tmp)); - val = s.real(); -#else - VecGetValues(_x, 1, &row, &val); -#endif - } - virtual void zeroMatrix() - { - if (_isAllocated && _entriesPreAllocated) { - _try(MatAssemblyBegin(_a, MAT_FINAL_ASSEMBLY)); - _try(MatAssemblyEnd(_a, MAT_FINAL_ASSEMBLY)); - _try(MatZeroEntries(_a)); - } - } - virtual void zeroRightHandSide() - { - if (_isAllocated) { - _try(VecAssemblyBegin(_b)); - _try(VecAssemblyEnd(_b)); - _try(VecZeroEntries(_b)); - } - } - virtual int systemSolve() - { - if (!_kspAllocated) - _kspCreate(); - if (linearSystem<scalar>::_parameters["matrix_reuse"] == "same_sparsity") - _try(KSPSetOperators(_ksp, _a, _a, SAME_NONZERO_PATTERN)); - else if (linearSystem<scalar>::_parameters["matrix_reuse"] == "same_matrix") - _try(KSPSetOperators(_ksp, _a, _a, SAME_PRECONDITIONER)); - else - _try(KSPSetOperators(_ksp, _a, _a, DIFFERENT_NONZERO_PATTERN)); - _try(MatAssemblyBegin(_a, MAT_FINAL_ASSEMBLY)); - _try(MatAssemblyEnd(_a, MAT_FINAL_ASSEMBLY)); - /*MatInfo info; - MatGetInfo(_a, MAT_LOCAL, &info); - printf("mallocs %.0f nz_allocated %.0f nz_used %.0f nz_unneeded %.0f\n", info.mallocs, info.nz_allocated, info.nz_used, info.nz_unneeded);*/ - _try(VecAssemblyBegin(_b)); - _try(VecAssemblyEnd(_b)); - _try(KSPSolve(_ksp, _b, _x)); - //_try(KSPView(ksp, PETSC_VIEWER_STDOUT_SELF)); - //PetscInt its; - //_try(KSPGetIterationNumber(ksp, &its)); - //Msg::Info("%d iterations", its); - return 1; - } + virtual void preAllocateEntries(); + virtual void allocate(int nbRows); + void print(); + virtual void clear(); + virtual void getFromMatrix(int row, int col, scalar &val) const; + virtual void addToRightHandSide(int row, const scalar &val); + virtual void getFromRightHandSide(int row, scalar &val) const; + virtual double normInfRightHandSide() const; + virtual void addToMatrix(int row, int col, const scalar &val); + virtual void getFromSolution(int row, scalar &val) const; + virtual void zeroMatrix(); + virtual void zeroRightHandSide(); + virtual int systemSolve(); Mat &getMatrix(){ return _a; } - - std::vector<scalar> getData() - { - _try(MatAssemblyBegin(_a, MAT_FINAL_ASSEMBLY)); - _try(MatAssemblyEnd(_a, MAT_FINAL_ASSEMBLY)); - PetscScalar *v; - _try(MatGetArray(_a,&v)); - MatInfo info; - _try(MatGetInfo(_a,MAT_LOCAL,&info)); - std::vector<scalar> data; // Maybe I should reserve or resize (SAM) - for (int i = 0; i < info.nz_allocated; i++) - data.push_back(v[i]); - _try(MatRestoreArray(_a,&v)); - return data; - } - - std::vector<int> getRowPointers() - { - _try(MatAssemblyBegin(_a, MAT_FINAL_ASSEMBLY)); - _try(MatAssemblyEnd(_a, MAT_FINAL_ASSEMBLY)); - PetscInt *rows; - PetscInt *columns; - PetscInt n; - PetscTruth done; - _try(MatGetRowIJ(_a,0,PETSC_FALSE,PETSC_FALSE,&n,&rows,&columns,&done)); //case done == PETSC_FALSE should be handled - std::vector<int> rowPointers; // Maybe I should reserve or resize (SAM) - for (int i = 0; i <= n; i++) - rowPointers.push_back(rows[i]); - _try(MatRestoreRowIJ(_a,0,PETSC_FALSE,PETSC_FALSE,&n,&rows,&columns,&done)); - return rowPointers; - } - - std::vector<int> getColumnsIndices() - { - _try(MatAssemblyBegin(_a, MAT_FINAL_ASSEMBLY)); - _try(MatAssemblyEnd(_a, MAT_FINAL_ASSEMBLY)); - PetscInt *rows; - PetscInt *columns; - PetscInt n; - PetscTruth done; - _try(MatGetRowIJ(_a,0,PETSC_FALSE,PETSC_FALSE,&n,&rows,&columns,&done)); //case done == PETSC_FALSE should be handled - MatInfo info; - _try(MatGetInfo(_a,MAT_LOCAL,&info)); - std::vector<int> columnIndices; // Maybe I should reserve or resize (SAM) - for (int i = 0; i < info.nz_allocated; i++) - columnIndices.push_back(columns[i]); - _try(MatRestoreRowIJ(_a,0,PETSC_FALSE,PETSC_FALSE,&n,&rows,&columns,&done)); - return columnIndices; - } - - - + std::vector<scalar> getData(); + std::vector<int> getRowPointers(); + std::vector<int> getColumnsIndices(); }; -class binding; -void linearSystemPETScRegisterBindings(binding *b); - class linearSystemPETScBlockDouble : public linearSystem<fullMatrix<double> > { bool _entriesPreAllocated, _isAllocated, _kspAllocated; sparsityPattern _sparsity; @@ -366,9 +125,5 @@ class linearSystemPETSc : public linearSystem<scalar> { virtual int systemSolve() { return 0; } virtual double normInfRightHandSide() const{return 0;} }; - - #endif - - #endif diff --git a/Solver/linearSystemPETSc.hpp b/Solver/linearSystemPETSc.hpp new file mode 100644 index 0000000000000000000000000000000000000000..99c0ad0021b05416304cb5af6dfb902f05972d3c --- /dev/null +++ b/Solver/linearSystemPETSc.hpp @@ -0,0 +1,307 @@ +#ifdef HAVE_PETSC +#include <petsc.h> +#include <petscksp.h> +#include "linearSystemPETSc.h" +static void _try(int ierr) +{ + CHKERRABORT(PETSC_COMM_WORLD, ierr); +} + +template <class scalar> +void linearSystemPETSc<scalar>::_kspCreate() +{ + _try(KSPCreate(PETSC_COMM_WORLD, &_ksp)); + PC pc; + _try(KSPGetPC(_ksp, &pc)); + // set some default options + //_try(PCSetType(pc, PCLU));//LU for direct solver and PCILU for indirect solver + /* _try(PCFactorSetMatOrderingType(pc, MATORDERING_RCM)); + _try(PCFactorSetLevels(pc, 1));*/ + _try(KSPSetTolerances(_ksp, 1.e-8, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT)); + // override the default options with the ones from the option + // database (if any) + if (this->_parameters.count("petscPrefix")) + _try(KSPAppendOptionsPrefix(_ksp, this->_parameters["petscPrefix"].c_str())); + _try(KSPSetFromOptions(_ksp)); + _try(PCSetFromOptions(pc)); + _kspAllocated = true; +} + +template <class scalar> +linearSystemPETSc<scalar>::linearSystemPETSc() +{ + _isAllocated = false; + _blockSize = 0; + _kspAllocated = false; +} + +template <class scalar> +linearSystemPETSc<scalar>::~linearSystemPETSc() +{ + clear(); + if (_kspAllocated) + _try (KSPDestroy (_ksp)); +} + +template <class scalar> +void linearSystemPETSc<scalar>::insertInSparsityPattern (int i, int j) +{ + i -= _localRowStart; + if (i<0 || i>= _localSize) return; + _sparsity.insertEntry (i,j); +} + +template <class scalar> +void linearSystemPETSc<scalar>::preAllocateEntries() +{ + if (_entriesPreAllocated) return; + if (!_isAllocated) Msg::Fatal("system must be allocated first"); + if (_sparsity.getNbRows() == 0) { + PetscInt prealloc = 300; + PetscTruth set; + PetscOptionsGetInt(PETSC_NULL, "-petsc_prealloc", &prealloc, &set); + if (_blockSize == 0) { + _try(MatSeqAIJSetPreallocation(_a, prealloc, PETSC_NULL)); + } else { + _try(MatSeqBAIJSetPreallocation(_a, _blockSize, 5, PETSC_NULL)); + } + } else { + std::vector<int> nByRowDiag (_localSize), nByRowOffDiag (_localSize); + for (int i = 0; i < _localSize; i++) { + int n; + const int *r = _sparsity.getRow(i, n); + for (int j = 0; j < n; j++) { + if (r[j] >= _localRowStart && r[j] < _localRowEnd) + nByRowDiag[i] ++; + else + nByRowOffDiag[i] ++; + } + } + if (_blockSize == 0) { + _try(MatSeqAIJSetPreallocation(_a, 0, &nByRowDiag[0])); + _try(MatMPIAIJSetPreallocation(_a, 0, &nByRowDiag[0], 0, &nByRowOffDiag[0])); + } else { + _try(MatSeqBAIJSetPreallocation(_a, _blockSize, 0, &nByRowDiag[0])); + _try(MatMPIBAIJSetPreallocation(_a, _blockSize, 0, &nByRowDiag[0], 0, &nByRowOffDiag[0])); + } + _sparsity.clear(); + } + _entriesPreAllocated = true; +} + +template <class scalar> +void linearSystemPETSc<scalar>::allocate(int nbRows) +{ + clear(); + _try(MatCreate(PETSC_COMM_WORLD, &_a)); + _try(MatSetSizes(_a, nbRows, nbRows, PETSC_DETERMINE, PETSC_DETERMINE)); + // override the default options with the ones from the option + // database (if any) + if (this->_parameters.count("petscOptions")) + _try(PetscOptionsInsertString(this->_parameters["petscOptions"].c_str())); + if (this->_parameters.count("petscPrefix")) + _try(MatAppendOptionsPrefix(_a, this->_parameters["petscPrefix"].c_str())); + _try(MatSetFromOptions(_a)); + _try(MatGetOwnershipRange(_a, &_localRowStart, &_localRowEnd)); + _try(MatGetSize(_a, &_globalSize, &_localSize)); + // preallocation option must be set after other options + _try(VecCreate(PETSC_COMM_WORLD, &_x)); + _try(VecSetSizes(_x, nbRows, PETSC_DETERMINE)); + // override the default options with the ones from the option + // database (if any) + if (this->_parameters.count("petscPrefix")) + _try(VecAppendOptionsPrefix(_x, this->_parameters["petscPrefix"].c_str())); + _try(VecSetFromOptions(_x)); + _try(VecDuplicate(_x, &_b)); + _isAllocated = true; + _entriesPreAllocated = false; +} + +template <class scalar> +void linearSystemPETSc<scalar>::print() +{ + _try(MatAssemblyBegin(_a, MAT_FINAL_ASSEMBLY)); + _try(MatAssemblyEnd(_a, MAT_FINAL_ASSEMBLY)); + _try(VecAssemblyBegin(_b)); + _try(VecAssemblyEnd(_b)); + if(Msg::GetCommRank()==0) + printf("a :\n"); + MatView(_a, PETSC_VIEWER_STDOUT_WORLD); + if(Msg::GetCommRank()==0) + printf("b :\n"); + VecView(_b, PETSC_VIEWER_STDOUT_WORLD); + if(Msg::GetCommRank()==0) + printf("x :\n"); + VecView(_x, PETSC_VIEWER_STDOUT_WORLD); +} + +template <class scalar> +void linearSystemPETSc<scalar>::clear() +{ + if(_isAllocated){ + _try(MatDestroy(_a)); + _try(VecDestroy(_x)); + _try(VecDestroy(_b)); + } + _isAllocated = false; +} + +template <class scalar> +void linearSystemPETSc<scalar>::getFromMatrix(int row, int col, scalar &val) const +{ + Msg::Error("getFromMatrix not implemented for PETSc"); +} + +template <class scalar> +void linearSystemPETSc<scalar>::addToRightHandSide(int row, const scalar &val) +{ + PetscInt i = row; + PetscScalar s = val; + _try(VecSetValues(_b, 1, &i, &s, ADD_VALUES)); +} + +template <class scalar> +void linearSystemPETSc<scalar>::getFromRightHandSide(int row, scalar &val) const +{ +#if defined(PETSC_USE_COMPLEX) + PetscScalar *tmp; + _try(VecGetArray(_b, &tmp)); + PetscScalar s = tmp[row]; + _try(VecRestoreArray(_b, &tmp)); + // FIXME specialize this routine + val = s.real(); +#else + VecGetValues(_b, 1, &row, &val); +#endif +} + +template <class scalar> +double linearSystemPETSc<scalar>::normInfRightHandSide() const +{ + PetscReal nor; + _try(VecNorm(_b, NORM_INFINITY, &nor)); + return nor; +} + +template <class scalar> +void linearSystemPETSc<scalar>::addToMatrix(int row, int col, const scalar &val) +{ + if (!_entriesPreAllocated) + preAllocateEntries(); + PetscInt i = row, j = col; + PetscScalar s = val; + _try(MatSetValues(_a, 1, &i, 1, &j, &s, ADD_VALUES)); +} + +template <class scalar> +void linearSystemPETSc<scalar>::getFromSolution(int row, scalar &val) const +{ +#if defined(PETSC_USE_COMPLEX) + PetscScalar *tmp; + _try(VecGetArray(_x, &tmp)); + PetscScalar s = tmp[row]; + _try(VecRestoreArray(_x, &tmp)); + val = s.real(); +#else + VecGetValues(_x, 1, &row, &val); +#endif +} + +template <class scalar> +void linearSystemPETSc<scalar>::zeroMatrix() +{ + if (_isAllocated && _entriesPreAllocated) { + _try(MatAssemblyBegin(_a, MAT_FINAL_ASSEMBLY)); + _try(MatAssemblyEnd(_a, MAT_FINAL_ASSEMBLY)); + _try(MatZeroEntries(_a)); + } +} + +template <class scalar> +void linearSystemPETSc<scalar>::zeroRightHandSide() +{ + if (_isAllocated) { + _try(VecAssemblyBegin(_b)); + _try(VecAssemblyEnd(_b)); + _try(VecZeroEntries(_b)); + } +} + +template <class scalar> +int linearSystemPETSc<scalar>::systemSolve() +{ + if (!_kspAllocated) + _kspCreate(); + if (linearSystem<scalar>::_parameters["matrix_reuse"] == "same_sparsity") + _try(KSPSetOperators(_ksp, _a, _a, SAME_NONZERO_PATTERN)); + else if (linearSystem<scalar>::_parameters["matrix_reuse"] == "same_matrix") + _try(KSPSetOperators(_ksp, _a, _a, SAME_PRECONDITIONER)); + else + _try(KSPSetOperators(_ksp, _a, _a, DIFFERENT_NONZERO_PATTERN)); + _try(MatAssemblyBegin(_a, MAT_FINAL_ASSEMBLY)); + _try(MatAssemblyEnd(_a, MAT_FINAL_ASSEMBLY)); + /*MatInfo info; + MatGetInfo(_a, MAT_LOCAL, &info); + printf("mallocs %.0f nz_allocated %.0f nz_used %.0f nz_unneeded %.0f\n", info.mallocs, info.nz_allocated, info.nz_used, info.nz_unneeded);*/ + _try(VecAssemblyBegin(_b)); + _try(VecAssemblyEnd(_b)); + _try(KSPSolve(_ksp, _b, _x)); + //_try(KSPView(ksp, PETSC_VIEWER_STDOUT_SELF)); + //PetscInt its; + //_try(KSPGetIterationNumber(ksp, &its)); + //Msg::Info("%d iterations", its); + return 1; +} + +template <class scalar> +std::vector<scalar> linearSystemPETSc<scalar>::getData() +{ + _try(MatAssemblyBegin(_a, MAT_FINAL_ASSEMBLY)); + _try(MatAssemblyEnd(_a, MAT_FINAL_ASSEMBLY)); + PetscScalar *v; + _try(MatGetArray(_a,&v)); + MatInfo info; + _try(MatGetInfo(_a,MAT_LOCAL,&info)); + std::vector<scalar> data; // Maybe I should reserve or resize (SAM) + for (int i = 0; i < info.nz_allocated; i++) + data.push_back(v[i]); + _try(MatRestoreArray(_a,&v)); + return data; +} + +template <class scalar> +std::vector<int> linearSystemPETSc<scalar>::getRowPointers() +{ + _try(MatAssemblyBegin(_a, MAT_FINAL_ASSEMBLY)); + _try(MatAssemblyEnd(_a, MAT_FINAL_ASSEMBLY)); + PetscInt *rows; + PetscInt *columns; + PetscInt n; + PetscTruth done; + _try(MatGetRowIJ(_a,0,PETSC_FALSE,PETSC_FALSE,&n,&rows,&columns,&done)); //case done == PETSC_FALSE should be handled + std::vector<int> rowPointers; // Maybe I should reserve or resize (SAM) + for (int i = 0; i <= n; i++) + rowPointers.push_back(rows[i]); + _try(MatRestoreRowIJ(_a,0,PETSC_FALSE,PETSC_FALSE,&n,&rows,&columns,&done)); + return rowPointers; +} + +template <class scalar> +std::vector<int> linearSystemPETSc<scalar>::getColumnsIndices() +{ + _try(MatAssemblyBegin(_a, MAT_FINAL_ASSEMBLY)); + _try(MatAssemblyEnd(_a, MAT_FINAL_ASSEMBLY)); + PetscInt *rows; + PetscInt *columns; + PetscInt n; + PetscTruth done; + _try(MatGetRowIJ(_a,0,PETSC_FALSE,PETSC_FALSE,&n,&rows,&columns,&done)); //case done == PETSC_FALSE should be handled + MatInfo info; + _try(MatGetInfo(_a,MAT_LOCAL,&info)); + std::vector<int> columnIndices; // Maybe I should reserve or resize (SAM) + for (int i = 0; i < info.nz_allocated; i++) + columnIndices.push_back(columns[i]); + _try(MatRestoreRowIJ(_a,0,PETSC_FALSE,PETSC_FALSE,&n,&rows,&columns,&done)); + return columnIndices; +} +#endif