Forked from
gmsh / gmsh
11701 commits behind the upstream repository.
-
Christophe Geuzaine authored
new options to enable image output at arbitrary sizes (cannot simply resize the main window, as some OSes forbid resizing the main window larger than the screen)
Christophe Geuzaine authorednew options to enable image output at arbitrary sizes (cannot simply resize the main window, as some OSes forbid resizing the main window larger than the screen)
linearSystemPETSc.hpp 11.37 KiB
#ifdef HAVE_PETSC
#include <petsc.h>
#include <petscksp.h>
#include "linearSystemPETSc.h"
#if (PETSC_VERSION_RELEASE == 0 || ((PETSC_VERSION_MAJOR == 3) && (PETSC_VERSION_MINOR >= 2)))
#define PetscTruth PetscBool
#define PetscOptionsGetTruth PetscOptionsGetBool
#endif
static void _try(int ierr)
{
CHKERRABORT(PETSC_COMM_WORLD, ierr);
}
template <class scalar>
void linearSystemPETSc<scalar>::_kspCreate()
{
_try(KSPCreate(_comm, &_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(MPI_Comm com)
{
_comm = com;
_isAllocated = false;
_blockSize = 0;
_kspAllocated = false;
_matrixModified=true;
}
template <class scalar>
linearSystemPETSc<scalar>::~linearSystemPETSc()
{
clear();
if(_kspAllocated)
#if (PETSC_VERSION_RELEASE == 0 || ((PETSC_VERSION_MAJOR == 3) && (PETSC_VERSION_MINOR >= 2)))
_try(KSPDestroy(&_ksp));
#else
_try(KSPDestroy(_ksp));
#endif
}
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(_comm, &_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));
int nbColumns;
_localSize = _localRowEnd - _localRowStart;
_try(MatGetSize(_a, &_globalSize, &nbColumns));
// preallocation option must be set after other options
_try(VecCreate(_comm, &_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>::createMatrix(){
if (isAllocated())
#if (PETSC_VERSION_RELEASE == 0 || ((PETSC_VERSION_MAJOR == 3) && (PETSC_VERSION_MINOR >= 2)))
_try(MatDestroy(&_a));
#else
_try(MatDestroy(_a));
#endif
_try(MatCreate(_comm, &_a));
_try(MatSetSizes(_a, _localSize, _localSize, _globalSize, _globalSize));
// 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));
_entriesPreAllocated = false;
_matrixModified = true;
_isAllocated = true;
};
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));
/*
PetscViewer fd;
_try(PetscViewerASCIIOpen(PETSC_COMM_WORLD, "mat.m", &fd));
_try(PetscViewerSetFormat(fd, PETSC_VIEWER_ASCII_MATLAB));
_try(PetscObjectSetName((PetscObject)_a, "A"));
_try(MatView(_a, fd));
*/
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){
#if (PETSC_VERSION_RELEASE == 0 || ((PETSC_VERSION_MAJOR == 3) && (PETSC_VERSION_MINOR >= 2)))
_try(MatDestroy(&_a));
_try(VecDestroy(&_x));
_try(VecDestroy(&_b));
#else
_try(MatDestroy(_a));
_try(VecDestroy(_x));
_try(VecDestroy(_b));
#endif
}
_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
_try(VecGetValues(_b, 1, &row, &val));
#endif
}
template <class scalar>
double linearSystemPETSc<scalar>::normInfRightHandSide() const
{
PetscReal nor;
VecAssemblyBegin(_b);
VecAssemblyEnd(_b);
_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));
_matrixModified=true;
}
template <class scalar>
void linearSystemPETSc<scalar>::addToSolution(int row, const scalar &val)
{
PetscInt i = row;
PetscScalar s = val;
_try(VecSetValues(_x, 1, &i, &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
_try(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>
void linearSystemPETSc<scalar>::zeroSolution()
{
if (_isAllocated) {
_try(VecAssemblyBegin(_x));
_try(VecAssemblyEnd(_x));
_try(VecZeroEntries(_x));
}
}
template <class scalar>
int linearSystemPETSc<scalar>::systemSolve()
{
if (!_kspAllocated)
_kspCreate();
if (!_matrixModified || linearSystem<scalar>::_parameters["matrix_reuse"] == "same_matrix")
_try(KSPSetOperators(_ksp, _a, _a, SAME_PRECONDITIONER));
else if (linearSystem<scalar>::_parameters["matrix_reuse"] == "same_sparsity")
_try(KSPSetOperators(_ksp, _a, _a, SAME_NONZERO_PATTERN));
else
_try(KSPSetOperators(_ksp, _a, _a, DIFFERENT_NONZERO_PATTERN));
_try(MatAssemblyBegin(_a, MAT_FINAL_ASSEMBLY));
_try(MatAssemblyEnd(_a, MAT_FINAL_ASSEMBLY));
_matrixModified=false;
/*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)
#if defined(PETSC_USE_COMPLEX)
for (int i = 0; i < info.nz_allocated; i++)
data.push_back(v[i].real());
#else
for (int i = 0; i < info.nz_allocated; i++)
data.push_back(v[i]);
#endif
_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