diff --git a/MathLib/LinAlg/FinalizeVectorAssembly.h b/MathLib/LinAlg/FinalizeVectorAssembly.h new file mode 100644 index 0000000000000000000000000000000000000000..f970875037e433ea27021b4ed8fa13cb72a539af --- /dev/null +++ b/MathLib/LinAlg/FinalizeVectorAssembly.h @@ -0,0 +1,27 @@ +/** + * \file FinalizeVectorAssembly.h + * \author Wenqing Wang + * \date Oct, 2013 + * + * \copyright + * Copyright (c) 2013, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + * + */ + +#ifndef FINALIZEVECTORASSEMBLY_H_ +#define FINALIZEVECTORASSEMBLY_H_ + +namespace MathLib +{ + +template <typename VEC_T> +void finalizeVectorAssembly(VEC_T &) +{ +} + +} // MathLib + +#endif diff --git a/MathLib/LinAlg/PETSc/PETScVector.cpp b/MathLib/LinAlg/PETSc/PETScVector.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5e33f259bbbdd97cb52ed6d8ea3306d24ecbcc01 --- /dev/null +++ b/MathLib/LinAlg/PETSc/PETScVector.cpp @@ -0,0 +1,164 @@ +/** + * \file PETScVector.cpp + * \brief Definition of member functions of class PETScVector, + * which provides an interface to PETSc vector routines. + * + * Note: the return message of PETSc routines is ommited in + * the source code. If it is really needed, it can be activated by + * adding a PetscErrorCode type variable before each PETSc fucntion + * + * \author Wenqing Wang + * \date Nov 2011 - Sep 2013 + * + * \copyright + * Copyright (c) 2013, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + * + */ + + +#include "PETScVector.h" + +namespace MathLib +{ +PETScVector::PETScVector(const PetscInt vec_size, const bool is_global_size) +{ + if( is_global_size ) + { + VecCreate(PETSC_COMM_WORLD, &_v); + VecSetSizes(_v, PETSC_DECIDE, vec_size); + } + else + { + // Fix size partitioning + // the size can be associated to specific memory allocation of a matrix + VecCreateMPI(PETSC_COMM_WORLD, vec_size, PETSC_DECIDE, &_v); + } + VecSetFromOptions(_v); + // VecSetUp(_v); // for petsc ver.>3.3 + VecGetOwnershipRange(_v, &_start_rank, &_end_rank); + + VecGetLocalSize(_v, &_size_loc); + VecGetSize(_v, &_size); +} + +PETScVector::PETScVector(const PETScVector &existing_vec, const bool deep_copy) +{ + VecDuplicate(existing_vec._v, &_v); + + VecGetOwnershipRange(_v, &_start_rank,&_end_rank); + VecGetLocalSize(_v, &_size_loc); + VecGetSize(_v, &_size); + + // Copy values + if(deep_copy) + { + VecCopy(existing_vec._v, _v); + } +} + +//----------------------------------------------------------------- +void PETScVector::gatherLocalVectors( PetscScalar local_array[], + PetscScalar global_array[]) +{ + // Collect vectors from processors. + int size_rank; + MPI_Comm_size(PETSC_COMM_WORLD, &size_rank); + + // number of elements to be sent for each rank + std::vector<PetscInt> i_cnt(size_rank); + + MPI_Allgather(&_size_loc, 1, MPI_INT, &i_cnt[0], 1, MPI_INT, PETSC_COMM_WORLD); + + // collect local array + PetscInt offset = 0; + // offset in the receive vector of the data from each rank + std::vector<PetscInt> i_disp(size_rank); + for(PetscInt i=0; i<size_rank; i++) + { + i_disp[i] = offset; + offset += i_cnt[i]; + } + + MPI_Allgatherv(local_array, _size_loc, MPI_DOUBLE, + global_array, &i_cnt[0], &i_disp[0], MPI_DOUBLE, PETSC_COMM_WORLD); + +} + +void PETScVector::getGlobalVector(PetscScalar u[]) +{ + +#ifdef TEST_MEM_PETSC + PetscLogDouble mem1, mem2; + PetscMemoryGetCurrentUsage(&mem1); +#endif + + PetscScalar *xp = nullptr; + VecGetArray(_v, &xp); + + gatherLocalVectors(xp, u); + + //This following line may be needed late on + // for a communication load balance: + //MPI_Barrier(PETSC_COMM_WORLD); + + VecRestoreArray(_v, &xp); + + //TEST +#ifdef TEST_MEM_PETSC + PetscMemoryGetCurrentUsage(&mem2); + PetscPrintf(PETSC_COMM_WORLD, "### Memory usage by Updating. Before :%f After:%f Increase:%d\n", mem1, mem2, (int)(mem2 - mem1)); +#endif +} + +PetscScalar PETScVector::getNorm(MathLib::VecNormType nmtype) const +{ + NormType petsc_norm = NORM_1; + switch(nmtype) + { + case MathLib::VecNormType::NORM1: + petsc_norm = NORM_1; + break; + case MathLib::VecNormType::NORM2: + petsc_norm = NORM_2; + break; + case MathLib::VecNormType::INFINITY_N: + petsc_norm = NORM_INFINITY; + break; + default: + break; + } + + PetscScalar norm = 0.; + VecNorm(_v, petsc_norm, &norm); + return norm; +} + +void PETScVector::viewer(const std::string &file_name, const PetscViewerFormat vw_format) +{ + PetscViewer viewer; + PetscViewerASCIIOpen(PETSC_COMM_WORLD, file_name.c_str(), &viewer); + PetscViewerPushFormat(viewer, vw_format); + + finalizeAssembly(); + + PetscObjectSetName((PetscObject)_v, file_name.c_str()); + VecView(_v, viewer); + +#define nEXIT_TEST +#ifdef EXIT_TEST + VecDestroy(&_v); + PetscFinalize(); + exit(0); +#endif + +} + +void finalizeVectorAssembly(PETScVector &vec) +{ + vec.finalizeAssembly(); +} + +} //end of namespace diff --git a/MathLib/LinAlg/PETSc/PETScVector.h b/MathLib/LinAlg/PETSc/PETScVector.h new file mode 100644 index 0000000000000000000000000000000000000000..37552355f09a7bb4511af547f580b2c6431bae93 --- /dev/null +++ b/MathLib/LinAlg/PETSc/PETScVector.h @@ -0,0 +1,266 @@ +/** + * \file PETScVector.h + * \brief Declaration of class PETScVector, which provides an interface to + * PETSc vector routines. + * + * \author Wenqing Wang + * \date Nov 2011 - Sep 2013 + * + * \copyright + * Copyright (c) 2013, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + * + */ + +#ifndef PETSCVECTOR_H_ +#define PETSCVECTOR_H_ + +#include <string> +#include <vector> + +#include "petscvec.h" +#include "LinAlg/VectorNorms.h" + +typedef Vec PETSc_Vec; + +namespace MathLib +{ +/*! + \class PETScVector + + \brief Wrapper class for PETSc vector +*/ +class PETScVector +{ + public: + + /*! + \brief Constructor + \param vec_size The size of the vector, either global or local + \param is_global_size The flag of the global size, the default is true + */ + PETScVector(const PetscInt vec_size, const bool is_global_size = true); + + /*! + \brief Copy constructor + \param existing_vec The vector to be copied + \param deep_copy The flag for a deep copy, which means to copy the values as well, + the default is true + */ + PETScVector(const PETScVector &existing_vec, const bool deep_copy = true); + + ~PETScVector() + { + VecDestroy(&_v); + } + + /// Perform MPI collection of assembled entries in buffer + void finalizeAssembly() + { + VecAssemblyBegin(_v); + VecAssemblyEnd(_v); + } + + /// Get the global size of the vector + PetscInt size() const + { + return _size; + } + + /// Get the number of entries in the same rank + PetscInt getLocalSize() const + { + return _size_loc; + } + + /// Get the start index of the local vector + PetscInt getRangeBegin() const + { + return _start_rank; + } + + /// Get the end index of the local vector + PetscInt getRangeEnd() const + { + return _end_rank; + } + + /*! + Get norm of vector + \param nmtype Norm type, default Euclidean norm + */ + PetscScalar getNorm(const MathLib::VecNormType nmtype = MathLib::VecNormType::NORM2) const; + + /*! + Insert a single entry with value. + + \param i Entry index + \param value Entry value + + */ + void set(const PetscInt i, const PetscScalar value) + { + VecSetValue(_v, i, value, INSERT_VALUES); + } + + /*! + Add a value to an entry. + + \param i Number of the entry + \param value Value. + */ + void add(const PetscInt i, const PetscScalar value) + { + VecSetValue(_v, i, value, ADD_VALUES); + } + + /*! + Add values to several entries + \param e_idxs Indicies of entries to be added + Note: size_t cannot be the type of e_idxs template argument + \param sub_vec Entries to be added + */ + template<class T_SUBVEC> void add(const std::vector<PetscInt> &e_idxs, + const T_SUBVEC &sub_vec) + { + VecSetValues(_v, e_idxs.size(), &e_idxs[0], &sub_vec[0], ADD_VALUES); + } + + /*! + Add values to several entries + \param e_idxs Indicies of entries to be added. + Note: size_t cannot be the type of e_idxs template argument + \param sub_vec Entries to be added + */ + template<class T_SUBVEC> void set(const std::vector<PetscInt> &e_idxs, + const T_SUBVEC &sub_vec) + { + VecSetValues(_v, e_idxs.size(), &e_idxs[0], &sub_vec[0], INSERT_VALUES); + } + + /*! + Get several entries + \param e_idxs Indicies of entries to be gotten. + Note: size_t cannot be the type of e_idxs template argument + \param sub_vec Values of entries + */ + template<class T_SUBVEC> void get(const std::vector<PetscInt> &e_idxs, + T_SUBVEC &sub_vec) + { + VecGetValues(_v, e_idxs.size(), &e_idxs[0], &sub_vec[0]); + } + + /*! + Get local vector, i.e. entries in the same rank + + \param loc_vec Pointer to array where stores the local vector, + memory allocation is not needed + */ + PetscScalar *getLocalVector() const + { + PetscScalar *loc_vec; + VecGetArray(_v, &loc_vec); + return loc_vec; + } + + /*! + Get global vector + + \param u Array to store the global vector. Memory allocation is needed in advance + */ + void getGlobalVector(PetscScalar u[]); + + /// Get an entry value. This is an expensive operation, + /// and it only get local value. Use it for only test purpose + PetscScalar get(const PetscInt idx) const + { + double x; + VecGetValues(_v, 1, &idx, &x); + return x; + } + + /// Get PETsc vector. Use it only for test purpose + PETSc_Vec &getData() + { + return _v; + } + + /// Initialize the vector with a constant value + void operator = (const PetscScalar val) + { + VecSet(_v, val); + } + /// Overloaded operator: assign + void operator = (const PETScVector &v_in) + { + VecCopy(_v, v_in._v); + } + + /// Overloaded operator: add + void operator += (const PETScVector& v_in) + { + VecAXPY(_v, 1.0, v_in._v); + } + + /// Overloaded operator: subtract + void operator -= (const PETScVector& v_in) + { + VecAXPY(_v, -1.0, v_in._v); + } + + /*! View the global vector for test purpose. Do not use it for output a big vector. + \param file_name File name for output + \vw_format File format listed as: + PETSC_VIEWER_DEFAULT Default format + PETSC_VIEWER_ASCII_MATLAB MATLAB format + PETSC_VIEWER_ASCII_DENSE Print matrix as dense + PETSC_VIEWER_ASCII_IMPL Implementation-specific format + (which is in many cases the same as the default) + PETSC_VIEWER_ASCII_INFO Basic information about object + PETSC_VIEWER_ASCII_INFO_DETAIL More detailed info about object + PETSC_VIEWER_ASCII_COMMON Identical output format for all objects of a particular type + PETSC_VIEWER_ASCII_INDEX (for vectors) Prints the vector element number next to + each vector entry + PETSC_VIEWER_ASCII_SYMMODU Print parallel vectors without indicating the processor ranges + PETSC_VIEWER_ASCII_VTK Outputs the object to a VTK file + PETSC_VIEWER_NATIVE Store the object to the binary file in its native format + (for example, dense matrices are stored as dense), + DMDA vectors are dumped directly to the file instead of + being first put in the natural ordering + PETSC_VIEWER_DRAW_BASIC Views the vector with a simple 1d plot + PETSC_VIEWER_DRAW_LG Views the vector with a line graph + PETSC_VIEWER_DRAW_CONTOUR Views the vector with a contour plot + */ + void viewer(const std::string &file_name, + const PetscViewerFormat vw_format = PETSC_VIEWER_ASCII_MATLAB ); + + private: + PETSc_Vec _v; + + /// Starting index in a rank + PetscInt _start_rank; + /// Ending index in a rank + PetscInt _end_rank; + + /// Size of the vector + PetscInt _size; + /// Size of local entries + PetscInt _size_loc; + + /*! + \brief Collect local vectors + \param local_array Local array + \param global_array Global array + */ + void gatherLocalVectors(PetscScalar local_array[], + PetscScalar global_array[]); + + friend void finalizeVectorAssembly(PETScVector &vec); +}; + +void finalizeVectorAssembly(PETScVector &vec); + +} // end namespace +#endif