diff --git a/AMDiS/CMakeLists.txt b/AMDiS/CMakeLists.txt index 4e91547610b48b4f0f262ff984a2512496b7eca3..3b9b8190a3b362d1d44b7f1da6d040ad3699c4d3 100644 --- a/AMDiS/CMakeLists.txt +++ b/AMDiS/CMakeLists.txt @@ -225,6 +225,7 @@ if(ENABLE_PARALLEL_DOMAIN) ${SOURCE_DIR}/parallel/CheckerPartitioner.cc ${SOURCE_DIR}/parallel/ElementObjectDatabase.cc ${SOURCE_DIR}/parallel/InteriorBoundary.cc + ${SOURCE_DIR}/parallel/MatrixNnzStructure.cc ${SOURCE_DIR}/parallel/MeshDistributor.cc ${SOURCE_DIR}/parallel/MeshLevelData.cc ${SOURCE_DIR}/parallel/MeshManipulation.cc diff --git a/AMDiS/src/parallel/MatrixNnzStructure.cc b/AMDiS/src/parallel/MatrixNnzStructure.cc new file mode 100644 index 0000000000000000000000000000000000000000..82cc355a3c3036e173c54f403ec4583d97441ab5 --- /dev/null +++ b/AMDiS/src/parallel/MatrixNnzStructure.cc @@ -0,0 +1,318 @@ +// +// Software License for AMDiS +// +// Copyright (c) 2010 Dresden University of Technology +// All rights reserved. +// Authors: Simon Vey, Thomas Witkowski et al. +// +// This file is part of AMDiS +// +// See also license.opensource.txt in the distribution. + + +#include "Global.h" +#include "DOFMatrix.h" +#include "parallel/MatrixNnzStructure.h" +#include "parallel/ParallelDofMapping.h" + +namespace AMDiS { + + void MatrixNnzStructure::clear() + { + if (dnnz) { + delete [] dnnz; + dnnz = NULL; + } + + if (onnz) { + delete [] onnz; + onnz = NULL; + } + } + + + void MatrixNnzStructure::create(Matrix<DOFMatrix*> *mat, + MPI::Intracomm mpiComm, + ParallelDofMapping &rowDofMap, + ParallelDofMapping &colDofMap, + bool localMatrix) + { + FUNCNAME("MatrixNnzStructure::create()"); + + int nRankRows = rowDofMap.getRankDofs(); + int rankStartRowIndex = rowDofMap.getStartDofs(); + + int nRankCols = colDofMap.getRankDofs(); + int rankStartColIndex = colDofMap.getStartDofs(); + + create(nRankRows, (!localMatrix ? nRankRows : -1)); + + using mtl::tag::row; using mtl::tag::nz; using mtl::begin; using mtl::end; + namespace traits = mtl::traits; + typedef DOFMatrix::base_matrix_type Matrix; + typedef traits::range_generator<row, Matrix>::type cursor_type; + typedef traits::range_generator<nz, cursor_type>::type icursor_type; + + typedef vector<pair<int, int> > MatrixNnzEntry; + typedef map<int, DofContainer> RankToDofContainer; + + // Stores to each rank a list of nnz entries (i.e. pairs of row and column + // index) that this rank will send to. These nnz entries will be assembled + // on this rank, but because the row DOFs are not DOFs of this rank they + // will be send to the owner of the row DOFs. + map<int, MatrixNnzEntry> sendMatrixEntry; + + // Maps to each DOF that must be send to another rank the rank number of the + // receiving rank. + map<pair<DegreeOfFreedom, int>, int> sendDofToRank; + + int nComponents = mat->getNumRows(); + + // First, create for all ranks, to which we send data to, MatrixNnzEntry + // object with 0 entries. + for (int i = 0; i < nComponents; i++) { + const FiniteElemSpace* feSpace = NULL; + for (int j = 0; j < nComponents; j++) + if ((*mat)[i][j]) + feSpace = (*mat)[i][j]->getRowFeSpace(); + + for (DofComm::Iterator it(rowDofMap.getDofComm().getRecvDofs(), feSpace); + !it.end(); it.nextRank()) { + sendMatrixEntry[it.getRank()].resize(0); + + for (; !it.endDofIter(); it.nextDof()) + sendDofToRank[make_pair(it.getDofIndex(), i)] = it.getRank(); + } + } + + // Create list of ranks from which we receive data from. + std::set<int> recvFromRank; + for (int i = 0; i < nComponents; i++) { + const FiniteElemSpace* feSpace = NULL; + for (int j = 0; j < nComponents; j++) + if ((*mat)[i][j]) + feSpace = (*mat)[i][j]->getRowFeSpace(); + + for (DofComm::Iterator it(rowDofMap.getDofComm().getSendDofs(), feSpace); + !it.end(); it.nextRank()) + recvFromRank.insert(it.getRank()); + } + + + // === Traverse matrices to create nnz data. === + + for (int rowComp = 0; rowComp < nComponents; rowComp++) { + for (int colComp = 0; colComp < nComponents; colComp++) { + DOFMatrix *dofMat = (*mat)[rowComp][colComp]; + + if (!dofMat) + continue; + + const FiniteElemSpace *rowFeSpace = dofMat->getRowFeSpace(); + const FiniteElemSpace *colFeSpace = dofMat->getColFeSpace(); + + + // === Prepare MTL4 iterators for the current DOF matrix. === + + Matrix baseMat = dofMat->getBaseMatrix(); + traits::col<Matrix>::type col(baseMat); + traits::const_value<Matrix>::type value(baseMat); + cursor_type cursor = begin<row>(baseMat); + cursor_type cend = end<row>(baseMat); + + + // === Iterate on all DOFs of the row mapping. === + + DofMap::iterator rowIt = rowDofMap[rowFeSpace].begin(); + DofMap::iterator rowEndIt = rowDofMap[rowFeSpace].end(); + for (; rowIt != rowEndIt; ++rowIt) { + + // Go to the corresponding matrix row (note, both the mapping and the + // matrix rows are stored in increasing order). + while (*cursor != rowIt->first) + ++cursor; + + // The corresponding global matrix row index of the current row DOF. + int petscRowIdx = 0; + if (localMatrix) { + petscRowIdx = rowDofMap.getLocalMatIndex(rowComp, *cursor); + } else { + if (rowDofMap.isMatIndexFromGlobal()) + petscRowIdx = rowDofMap.getMatIndex(rowComp, rowIt->second.global); + else + petscRowIdx = rowDofMap.getMatIndex(rowComp, *cursor); + } + + + if (localMatrix || rowDofMap[rowFeSpace].isRankDof(*cursor)) { + // === The current row DOF is a rank DOF, so create the === + // === corresponding nnz values directly on rank's nnz data. === + + // This is the local row index of the local PETSc matrix. + int localPetscRowIdx = petscRowIdx; + + if (localMatrix == false) + localPetscRowIdx -= rankStartRowIndex; + + TEST_EXIT_DBG(localPetscRowIdx >= 0 && localPetscRowIdx < nRankRows) + ("Should not happen! \n Debug info: DOF = %d globalRowIndx = %d petscRowIdx = %d localPetscRowIdx = %d rStart = %d compontens = %d from %d nRankRows = %d\n", + *cursor, + rowDofMap[rowFeSpace][*cursor].global, + petscRowIdx, + localPetscRowIdx, + rankStartRowIndex, + rowComp, + nComponents, + nRankRows); + + + if (localMatrix) { + for (icursor_type icursor = begin<nz>(cursor), + icend = end<nz>(cursor); icursor != icend; ++icursor) + if (colDofMap[colFeSpace].isSet(col(*icursor))) + dnnz[localPetscRowIdx]++; + } else { + MultiIndex colDofIndex; + + // Traverse all non zero entries in this row. + for (icursor_type icursor = begin<nz>(cursor), + icend = end<nz>(cursor); icursor != icend; ++icursor) { + if (colDofMap[colFeSpace].find(col(*icursor), colDofIndex) == false) + continue; + + int petscColIdx = (colDofMap.isMatIndexFromGlobal() ? + colDofMap.getMatIndex(colComp, colDofIndex.global) : + colDofMap.getMatIndex(colComp, col(*icursor))); + + // The row DOF is a rank DOF, if also the column is a rank DOF, + // increment the diagNnz values for this row, + // otherwise the offdiagNnz value. + if (petscColIdx >= rankStartColIndex && + petscColIdx < rankStartColIndex + nRankCols) + dnnz[localPetscRowIdx]++; + else + onnz[localPetscRowIdx]++; + } + } + } else { + // === The current row DOF is not a rank DOF, i.e., its values === + // === are also created on this rank, but afterthere they will === + // === be send to another rank. So we need to send also the === + // === corresponding nnz structure of this row to the corres- === + // === ponding rank. === + + // Send all non zero entries to the member of the row DOF. + int sendToRank = sendDofToRank[make_pair(*cursor, rowComp)]; + MultiIndex colDofIndex; + + for (icursor_type icursor = begin<nz>(cursor), + icend = end<nz>(cursor); icursor != icend; ++icursor) { + if (colDofMap[colFeSpace].find(col(*icursor), colDofIndex) == false) + continue; + + int petscColIdx = (colDofMap.isMatIndexFromGlobal() ? + colDofMap.getMatIndex(colComp, colDofIndex.global) : + colDofMap.getMatIndex(colComp, col(*icursor))); + + sendMatrixEntry[sendToRank]. + push_back(make_pair(petscRowIdx, petscColIdx)); + } + + } // if (isRankDof[*cursor]) ... else ... + } // for each row in mat[i][j] + } + } + + + if (localMatrix == false) { + // === Send and recv the nnz row structure to/from other ranks. === + + StdMpi<MatrixNnzEntry> stdMpi(mpiComm, true); + stdMpi.send(sendMatrixEntry); + for (std::set<int>::iterator it = recvFromRank.begin(); + it != recvFromRank.end(); ++it) + stdMpi.recv(*it); + stdMpi.startCommunication(); + + + // === Evaluate the nnz structure this rank got from other ranks and add === + // === it to the PETSc nnz data structure. === + + for (map<int, MatrixNnzEntry>::iterator it = stdMpi.getRecvData().begin(); + it != stdMpi.getRecvData().end(); ++it) { + if (it->second.size() > 0) { + for (unsigned int i = 0; i < it->second.size(); i++) { + int r = it->second[i].first; + int c = it->second[i].second; + + int localRowIdx = r - rankStartRowIndex; + + TEST_EXIT_DBG(localRowIdx >= 0 && localRowIdx < nRankRows) + ("Got row index %d/%d (nRankRows = %d) from rank %d. Should not happen!\n", + r, localRowIdx, nRankRows, it->first); + + if (c < rankStartColIndex || c >= rankStartColIndex + nRankCols) + onnz[localRowIdx]++; + else + dnnz[localRowIdx]++; + } + } + } + } + + // The above algorithm for calculating the number of nnz per row over- + // approximates the value, i.e., the number is always equal or larger to + // the real number of nnz values in the global parallel matrix. For small + // matrices, the problem may arise, that the result is larger than the + // number of elements in a row. This is fixed in the following. + + if (nRankRows < 100) + for (int i = 0; i < nRankRows; i++) + dnnz[i] = std::min(dnnz[i], nRankCols); + +#if (DEBUG != 0) + int nMax = 0; + int nSum = 0; + for (int i = 0; i < nRankRows; i++) { + nMax = std::max(nMax, dnnz[i]); + nSum += dnnz[i]; + } + + MSG("NNZ in diag block: max = %d, avrg = %.0f\n", + nMax, (nSum > 0 ? (static_cast<double>(nSum) / nRankRows) : 0)); + + if (!localMatrix) { + nMax = 0; + nSum = 0; + + for (int i = 0; i < nRankRows; i++) { + nMax = std::max(nMax, nnz.onnz[i]); + nSum += nnz.onnz[i]; + } + + MSG("NNZ in offdiag block: max = %d, avrg = %.0f\n", + nMax, (nSum > 0 ? (static_cast<double>(nSum) / nRankRows) : 0)); + } +#endif + } + + + void MatrixNnzStructure::create(int nRows0, int nRows1) + { + if (nRows0 == 0) + return; + + TEST_EXIT_DBG(nRows0 > 0)("Should not happen!\n"); + + dnnz = new int[nRows0]; + for (int i = 0; i < nRows0; i++) + dnnz[i] = 0; + + if (nRows1 > 0) { + onnz = new int[nRows1]; + for (int i = 0; i < nRows1; i++) + onnz[i] = 0; + } + } + +} diff --git a/AMDiS/src/parallel/MatrixNnzStructure.h b/AMDiS/src/parallel/MatrixNnzStructure.h new file mode 100644 index 0000000000000000000000000000000000000000..ffce7113a1b199fc75d82047a09d21d662653b2e --- /dev/null +++ b/AMDiS/src/parallel/MatrixNnzStructure.h @@ -0,0 +1,67 @@ +// ============================================================================ +// == == +// == AMDiS - Adaptive multidimensional simulations == +// == == +// == http://www.amdis-fem.org == +// == == +// ============================================================================ +// +// Software License for AMDiS +// +// Copyright (c) 2010 Dresden University of Technology +// All rights reserved. +// Authors: Simon Vey, Thomas Witkowski et al. +// +// This file is part of AMDiS +// +// See also license.opensource.txt in the distribution. + + + +/** \file MatrixNnzStructure.h */ + +#ifndef AMDIS_MATRIX_NNZ_STRUCTURE_H +#define AMDIS_MATRIX_NNZ_STRUCTURE_H + +#include "AMDiS_fwd.h" +#include "parallel/ParallelDofMapping.h" + +namespace AMDiS { + + using namespace std; + + class MatrixNnzStructure { + public: + MatrixNnzStructure() + : dnnz(NULL), + onnz(NULL) + {} + + void clear(); + + void create(Matrix<DOFMatrix*> *mat, + MPI::Intracomm mpiComm, + ParallelDofMapping &rowDofMap, + ParallelDofMapping &colDofMap, + bool localMatrix = false); + + void create(Matrix<DOFMatrix*> *mat, + MPI::Intracomm mpiComm, + ParallelDofMapping &dofMap, + bool localMatrix = false) + { + create(mat, mpiComm, dofMap, dofMap, localMatrix); + } + + protected: + void create(int nRows0, int nRows1 = -1); + + public: + int *dnnz; + + int *onnz; + }; + +} + +#endif diff --git a/AMDiS/src/parallel/ParallelDofMapping.h b/AMDiS/src/parallel/ParallelDofMapping.h index 32eea63035ecc665ffd3f83b0b883756f5828895..7da23a1a31c5e2fedee5248d498417d9af96a2eb 100644 --- a/AMDiS/src/parallel/ParallelDofMapping.h +++ b/AMDiS/src/parallel/ParallelDofMapping.h @@ -204,6 +204,16 @@ namespace AMDiS { return dofMap; } + DofMap::iterator begin() + { + return dofMap.begin(); + } + + DofMap::iterator end() + { + return dofMap.end(); + } + /// Recomputes the mapping. void update(); @@ -226,7 +236,7 @@ namespace AMDiS { needGlobalMapping = b; } - /// Sets the DOF communicators. + /// Sets the DOF communicator. void setDofComm(DofComm &dc) { dofComm = &dc; @@ -333,6 +343,14 @@ namespace AMDiS { /// about DOFs that are on interior boundaries. void setDofComm(DofComm &dofComm); + /// Returns the DOF communicator. + DofComm& getDofComm() + { + TEST_EXIT_DBG(dofComm); + + return *dofComm; + } + void setComputeMatIndex(bool b, bool global = false) { needMatIndex = b; diff --git a/AMDiS/src/parallel/PetscSolverGlobalMatrix.cc b/AMDiS/src/parallel/PetscSolverGlobalMatrix.cc index 3b547ba236bae42ddc89811bf0fe20fa4c2dbe36..418fb714a173cc9c3afcb55d1cc46f5fd46ea30e 100644 --- a/AMDiS/src/parallel/PetscSolverGlobalMatrix.cc +++ b/AMDiS/src/parallel/PetscSolverGlobalMatrix.cc @@ -36,8 +36,7 @@ namespace AMDiS { // === If required, recompute non zero structure of the matrix. === if (checkMeshChange(mat)) - createPetscNnzStructure(mat); - + nnzInterior.create(mat, mpiCommGlobal, *interiorMap); // === Create PETSc vector (solution and a temporary vector). === @@ -134,26 +133,12 @@ namespace AMDiS { bool localMatrix = (subdomainLevel == 0); if (checkMeshChange(mat, localMatrix)) { - createPetscNnzStructureWithCoarseSpace(mat, - *interiorMap, - *interiorMap, - nnzInterior, - localMatrix); + nnzInterior.create(mat, mpiCommGlobal, *interiorMap, localMatrix); if (coarseSpaceMap) { - createPetscNnzStructureWithCoarseSpace(mat, - *coarseSpaceMap, - *coarseSpaceMap, - nnzCoarse); - - createPetscNnzStructureWithCoarseSpace(mat, - *coarseSpaceMap, - *interiorMap, - nnzCoarseInt); - createPetscNnzStructureWithCoarseSpace(mat, - *interiorMap, - *coarseSpaceMap, - nnzIntCoarse); + nnzCoarse.create(mat, mpiCommGlobal, *coarseSpaceMap); + nnzCoarseInt.create(mat, mpiCommGlobal, *coarseSpaceMap, *interiorMap); + nnzIntCoarse.create(mat, mpiCommGlobal, *interiorMap, *coarseSpaceMap); } } @@ -161,14 +146,12 @@ namespace AMDiS { MatCreateSeqAIJ(mpiCommLocal, nRowsRankInterior, nRowsRankInterior, 0, nnzInterior.dnnz, &matIntInt); - // MatSetOption(matIntInt, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE); } else { MatCreateAIJ(mpiCommLocal, nRowsRankInterior, nRowsRankInterior, nRowsOverallInterior, nRowsOverallInterior, 0, nnzInterior.dnnz, 0, nnzInterior.onnz, &matIntInt); - // MatSetOption(matIntInt, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE); } if (coarseSpaceMap) { @@ -179,25 +162,19 @@ namespace AMDiS { nRowsRankCoarse, nRowsRankCoarse, nRowsOverallCoarse, nRowsOverallCoarse, 0, nnzCoarse.dnnz, 0, nnzCoarse.onnz, - // 100, PETSC_NULL, 100, PETSC_NULL, &matCoarseCoarse); - // MatSetOption(matCoarseCoarse, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE); MatCreateAIJ(mpiCommGlobal, nRowsRankCoarse, nRowsRankInterior, nRowsOverallCoarse, nGlobalOverallInterior, - // 100, PETSC_NULL, 100, PETSC_NULL, 0, nnzCoarseInt.dnnz, 0, nnzCoarseInt.onnz, &matCoarseInt); - // MatSetOption(matCoarseInt, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE); MatCreateAIJ(mpiCommGlobal, nRowsRankInterior, nRowsRankCoarse, nGlobalOverallInterior, nRowsOverallCoarse, - // 100, PETSC_NULL, 100, PETSC_NULL, 0, nnzIntCoarse.dnnz, 0, nnzIntCoarse.onnz, &matIntCoarse); - // MatSetOption(matIntCoarse, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE); } // === Prepare traverse of sequentially created matrices. === @@ -1039,7 +1016,7 @@ namespace AMDiS { } } - +#if 0 void PetscSolverGlobalMatrix::createPetscNnzStructure(Matrix<DOFMatrix*> *mat) { FUNCNAME("PetscSolverGlobalMatrix::createPetscNnzStructure()"); @@ -1222,253 +1199,6 @@ namespace AMDiS { for (int i = 0; i < nRankRows; i++) nnzInterior.dnnz[i] = std::min(nnzInterior.dnnz[i], nRankRows); } - - - void PetscSolverGlobalMatrix::createPetscNnzStructureWithCoarseSpace(Matrix<DOFMatrix*> *mat, - ParallelDofMapping &rowDofMap, - ParallelDofMapping &colDofMap, - NnzStructure &nnz, - bool localMatrix) - { - FUNCNAME("PetscSolverGlobalMatrix::createPetscNnzStructure()"); - - vector<const FiniteElemSpace*> feSpaces = getFeSpaces(mat); - int nRankRows = rowDofMap.getRankDofs(); - int rankStartRowIndex = rowDofMap.getStartDofs(); - - int nRankCols = colDofMap.getRankDofs(); - int rankStartColIndex = colDofMap.getStartDofs(); - - nnz.create(nRankRows, (!localMatrix ? nRankRows : -1)); - - using mtl::tag::row; using mtl::tag::nz; using mtl::begin; using mtl::end; - namespace traits = mtl::traits; - typedef DOFMatrix::base_matrix_type Matrix; - typedef vector<pair<int, int> > MatrixNnzEntry; - typedef map<int, DofContainer> RankToDofContainer; - - // Stores to each rank a list of nnz entries (i.e. pairs of row and column - // index) that this rank will send to. These nnz entries will be assembled - // on this rank, but because the row DOFs are not DOFs of this rank they - // will be send to the owner of the row DOFs. - map<int, MatrixNnzEntry> sendMatrixEntry; - - // Maps to each DOF that must be send to another rank the rank number of the - // receiving rank. - map<pair<DegreeOfFreedom, int>, int> sendDofToRank; - - - // First, create for all ranks, to which we send data to, MatrixNnzEntry - // object with 0 entries. - for (unsigned int i = 0; i < feSpaces.size(); i++) { - for (DofComm::Iterator it(meshDistributor->getDofComm().getRecvDofs(), feSpaces[i]); - !it.end(); it.nextRank()) { - sendMatrixEntry[it.getRank()].resize(0); - - for (; !it.endDofIter(); it.nextDof()) - sendDofToRank[make_pair(it.getDofIndex(), i)] = it.getRank(); - } - } - - // Create list of ranks from which we receive data from. - std::set<int> recvFromRank; - for (unsigned int i = 0; i < feSpaces.size(); i++) - for (DofComm::Iterator it(meshDistributor->getDofComm().getSendDofs(), feSpaces[i]); - !it.end(); it.nextRank()) - recvFromRank.insert(it.getRank()); - - - // === Traverse matrices to create nnz data. === - - int nComponents = mat->getNumRows(); - for (int i = 0; i < nComponents; i++) { - for (int j = 0; j < nComponents; j++) { - if (!(*mat)[i][j]) - continue; - - TEST_EXIT_DBG((*mat)[i][j]->getRowFeSpace() == feSpaces[i]) - ("Should not happen!\n"); - TEST_EXIT_DBG((*mat)[i][j]->getColFeSpace() == feSpaces[j]) - ("Should not happen!\n"); - - Matrix bmat = (*mat)[i][j]->getBaseMatrix(); - - traits::col<Matrix>::type col(bmat); - traits::const_value<Matrix>::type value(bmat); - - typedef traits::range_generator<row, Matrix>::type cursor_type; - typedef traits::range_generator<nz, cursor_type>::type icursor_type; - - MultiIndex rowDofIndex; - - for (cursor_type cursor = begin<row>(bmat), - cend = end<row>(bmat); cursor != cend; ++cursor) { - - if (rowDofMap[feSpaces[i]].find(*cursor, rowDofIndex) == false) - continue; - - // The corresponding global matrix row index of the current row DOF. - int petscRowIdx = 0; - if (localMatrix) { - petscRowIdx = rowDofMap.getLocalMatIndex(i, *cursor); - } else { - if (rowDofMap.isMatIndexFromGlobal()) - petscRowIdx = rowDofMap.getMatIndex(i, rowDofIndex.global); - else - petscRowIdx = rowDofMap.getMatIndex(i, *cursor); - } - - if (localMatrix || rowDofMap[feSpaces[i]].isRankDof(*cursor)) { - - // === The current row DOF is a rank DOF, so create the === - // === corresponding nnz values directly on rank's nnz data. === - - // This is the local row index of the local PETSc matrix. - int localPetscRowIdx = petscRowIdx; - - if (localMatrix == false) - localPetscRowIdx -= rankStartRowIndex; - - TEST_EXIT_DBG(localPetscRowIdx >= 0 && localPetscRowIdx < nRankRows) - ("Should not happen! \n Debug info: DOF = %d globalRowIndx = %d petscRowIdx = %d localPetscRowIdx = %d rStart = %d compontens = %d from %d nRankRows = %d\n", - *cursor, - rowDofMap[feSpaces[i]][*cursor].global, - petscRowIdx, - localPetscRowIdx, - rankStartRowIndex, - i, - nComponents, - nRankRows); - - - if (localMatrix) { - for (icursor_type icursor = begin<nz>(cursor), - icend = end<nz>(cursor); icursor != icend; ++icursor) - if (colDofMap[feSpaces[j]].isSet(col(*icursor))) - nnz.dnnz[localPetscRowIdx]++; - } else { - MultiIndex colDofIndex; - - // Traverse all non zero entries in this row. - for (icursor_type icursor = begin<nz>(cursor), - icend = end<nz>(cursor); icursor != icend; ++icursor) { - if (colDofMap[feSpaces[j]].find(col(*icursor), colDofIndex) == false) - continue; - - int petscColIdx = (colDofMap.isMatIndexFromGlobal() ? - colDofMap.getMatIndex(j, colDofIndex.global) : - colDofMap.getMatIndex(j, col(*icursor))); - - // The row DOF is a rank DOF, if also the column is a rank DOF, - // increment the diagNnz values for this row, - // otherwise the offdiagNnz value. - if (petscColIdx >= rankStartColIndex && - petscColIdx < rankStartColIndex + nRankCols) - nnz.dnnz[localPetscRowIdx]++; - else - nnz.onnz[localPetscRowIdx]++; - } - } - } else { - // === The current row DOF is not a rank DOF, i.e., its values === - // === are also created on this rank, but afterthere they will === - // === be send to another rank. So we need to send also the === - // === corresponding nnz structure of this row to the corres- === - // === ponding rank. === - - // Send all non zero entries to the member of the row DOF. - int sendToRank = sendDofToRank[make_pair(*cursor, i)]; - MultiIndex colDofIndex; - - for (icursor_type icursor = begin<nz>(cursor), - icend = end<nz>(cursor); icursor != icend; ++icursor) { - if (colDofMap[feSpaces[j]].find(col(*icursor), colDofIndex) == false) - continue; - - int petscColIdx = (colDofMap.isMatIndexFromGlobal() ? - colDofMap.getMatIndex(j, colDofIndex.global) : - colDofMap.getMatIndex(j, col(*icursor))); - - sendMatrixEntry[sendToRank]. - push_back(make_pair(petscRowIdx, petscColIdx)); - } - - } // if (isRankDof[*cursor]) ... else ... - } // for each row in mat[i][j] - } - } - - - if (localMatrix == false) { - // === Send and recv the nnz row structure to/from other ranks. === - - StdMpi<MatrixNnzEntry> stdMpi(mpiCommGlobal, true); - stdMpi.send(sendMatrixEntry); - for (std::set<int>::iterator it = recvFromRank.begin(); - it != recvFromRank.end(); ++it) - stdMpi.recv(*it); - stdMpi.startCommunication(); - - - // === Evaluate the nnz structure this rank got from other ranks and add === - // === it to the PETSc nnz data structure. === - - for (map<int, MatrixNnzEntry>::iterator it = stdMpi.getRecvData().begin(); - it != stdMpi.getRecvData().end(); ++it) { - if (it->second.size() > 0) { - for (unsigned int i = 0; i < it->second.size(); i++) { - int r = it->second[i].first; - int c = it->second[i].second; - - int localRowIdx = r - rankStartRowIndex; - - TEST_EXIT_DBG(localRowIdx >= 0 && localRowIdx < nRankRows) - ("Got row index %d/%d (nRankRows = %d) from rank %d. Should not happen!\n", - r, localRowIdx, nRankRows, it->first); - - if (c < rankStartColIndex || c >= rankStartColIndex + nRankCols) - nnz.onnz[localRowIdx]++; - else - nnz.dnnz[localRowIdx]++; - } - } - } - } - - // The above algorithm for calculating the number of nnz per row over- - // approximates the value, i.e., the number is always equal or larger to - // the real number of nnz values in the global parallel matrix. For small - // matrices, the problem may arise, that the result is larger than the - // number of elements in a row. This is fixed in the following. - - if (nRankRows < 100) - for (int i = 0; i < nRankRows; i++) - nnz.dnnz[i] = std::min(nnz.dnnz[i], nRankCols); - -#if (DEBUG != 0) - int nMax = 0; - int nSum = 0; - for (int i = 0; i < nRankRows; i++) { - nMax = std::max(nMax, nnz.dnnz[i]); - nSum += nnz.dnnz[i]; - } - - MSG("NNZ in diag block: max = %d, avrg = %.0f\n", - nMax, (nSum > 0 ? (static_cast<double>(nSum) / nRankRows) : 0)); - - if (!localMatrix) { - nMax = 0; - nSum = 0; - - for (int i = 0; i < nRankRows; i++) { - nMax = std::max(nMax, nnz.onnz[i]); - nSum += nnz.onnz[i]; - } - - MSG("NNZ in offdiag block: max = %d, avrg = %.0f\n", - nMax, (nSum > 0 ? (static_cast<double>(nSum) / nRankRows) : 0)); - } #endif - } } diff --git a/AMDiS/src/parallel/PetscSolverGlobalMatrix.h b/AMDiS/src/parallel/PetscSolverGlobalMatrix.h index 728b1a2e6317ea996539165a27cc7525b6569078..c8624b53c71fc4c678c920f955ad48517a1a4aa6 100644 --- a/AMDiS/src/parallel/PetscSolverGlobalMatrix.h +++ b/AMDiS/src/parallel/PetscSolverGlobalMatrix.h @@ -25,55 +25,13 @@ #include <boost/tuple/tuple.hpp> #include "AMDiS_fwd.h" +#include "parallel/MatrixNnzStructure.h" #include "parallel/PetscSolver.h" namespace AMDiS { using namespace std; - struct NnzStructure { - NnzStructure() - : dnnz(NULL), - onnz(NULL) - {} - - void clear() - { - if (dnnz) { - delete [] dnnz; - dnnz = NULL; - } - - if (onnz) { - delete [] onnz; - onnz = NULL; - } - } - - void create(int nRows0, int nRows1 = -1) - { - if (nRows0 == 0) - return; - - TEST_EXIT_DBG(nRows0 > 0)("Should not happen!\n"); - - dnnz = new int[nRows0]; - for (int i = 0; i < nRows0; i++) - dnnz[i] = 0; - - if (nRows1 > 0) { - onnz = new int[nRows1]; - for (int i = 0; i < nRows1; i++) - onnz[i] = 0; - } - } - - int *dnnz; - - int *onnz; - }; - - class PetscSolverGlobalMatrix : public PetscSolver { @@ -118,14 +76,8 @@ namespace AMDiS { virtual void exitPreconditioner(PC pc); /// Creates a new non zero pattern structure for the PETSc matrix. - void createPetscNnzStructure(Matrix<DOFMatrix*> *mat); - - void createPetscNnzStructureWithCoarseSpace(Matrix<DOFMatrix*> *mat, - ParallelDofMapping &rowDofMap, - ParallelDofMapping &colDofMap, - NnzStructure &nnz, - bool localMatrix = false); - + // void createPetscNnzStructure(Matrix<DOFMatrix*> *mat); + /// Takes a DOF matrix and sends the values to the global PETSc matrix. void setDofMatrix(DOFMatrix* mat, int nRowMat = 0, int nColMat = 0); @@ -148,11 +100,9 @@ namespace AMDiS { protected: - NnzStructure nnzInterior; - - NnzStructure nnzCoarse; + MatrixNnzStructure nnzInterior, nnzCoarse; - NnzStructure nnzIntCoarse, nnzCoarseInt; + MatrixNnzStructure nnzIntCoarse, nnzCoarseInt; Vec petscSolVec;