// ============================================================================ // == == // == AMDiS - Adaptive multidimensional simulations == // == == // ============================================================================ // == == // == TU Dresden == // == == // == Institut für Wissenschaftliches Rechnen == // == Zellescher Weg 12-14 == // == 01069 Dresden == // == germany == // == == // ============================================================================ // == == // == https://gforge.zih.tu-dresden.de/projects/amdis/ == // == == // ============================================================================ /** \file ParallelDomainBase.h */ #ifndef AMDIS_PARALLELDOMAINBASE_H #define AMDIS_PARALLELDOMAINBASE_H #include #include #include #include #include "Global.h" #include "ProblemTimeInterface.h" #include "ProblemIterationInterface.h" #include "FiniteElemSpace.h" #include "AdaptInfo.h" #include "parallel/InteriorBoundary.h" #include "Serializer.h" #include "BoundaryManager.h" #include "AMDiS_fwd.h" namespace AMDiS { struct DofPtrSortFct { bool operator() (const DegreeOfFreedom *dof0, const DegreeOfFreedom *dof1) { return (*dof0 < *dof1); } }; class ParMetisPartitioner; class ParallelDomainBase : public ProblemIterationInterface, public ProblemTimeInterface { protected: /// Defines a mapping type from DOFs to rank numbers. typedef std::map DofToRank; /// Defines a mapping type from DOFs to a set of rank numbers. typedef std::map > DofToPartitions; /// Defines a mapping type from rank numbers to sets of DOFs. typedef std::map RankToDofContainer; /// Defines a mapping type from DOF indices to DOF indices. typedef std::map DofMapping; /// Defines a mapping type from DOFs to boolean values. typedef std::map DofToBool; /// Defines a mapping type from DOF indices to boolean values. typedef std::map DofIndexToBool; /// Defines a mapping type from rank numbers to sets of coordinates. typedef std::map > > RankToCoords; /// Forward type (it maps rank numbers to the interior boundary objects). typedef InteriorBoundary::RankToBoundMap RankToBoundMap; typedef std::map ElementIdxToDofs; typedef std::map DofIndexMap; typedef std::map > PeriodicDofMap; typedef std::vector MeshCodeVec; public: ParallelDomainBase(ProblemVec *problemStat, ProblemInstatVec *problemInstat); virtual ~ParallelDomainBase() {} virtual void initParallelization(AdaptInfo *adaptInfo); virtual void exitParallelization(AdaptInfo *adaptInfo); /** \brief * This function checks if the mesh has changed on at least on rank. In this case, * the interior boundaries are adapted on all ranks such that they fit together on * all ranks. Furthermore the function \ref updateLocalGlobalNumbering() is called * to update the dof numberings and mappings on all rank due to the new mesh * structure. */ void checkMeshChange(); void updateDofAdmins(); /** \brief * Test, if the mesh consists of macro elements only. The mesh partitioning of * the parallelization works for macro meshes only and would fail, if the mesh * is already refined in some way. Therefore, this function will exit the program * if it finds a non macro element in the mesh. */ void testForMacroMesh(); /// Set for each element on the partitioning level the number of leaf elements. double setElemWeights(AdaptInfo *adaptInfo); void partitionMesh(AdaptInfo *adaptInfo); virtual void setTime(AdaptInfo *adaptInfo) { if (timeIF) timeIF->setTime(adaptInfo); } virtual void initTimestep(AdaptInfo *adaptInfo) { if (timeIF) timeIF->initTimestep(adaptInfo); } virtual void closeTimestep(AdaptInfo *adaptInfo) { if (timeIF) timeIF->closeTimestep(adaptInfo); } virtual void solveInitialProblem(AdaptInfo *adaptInfo); virtual void transferInitialSolution(AdaptInfo *adaptInfo) { if (timeIF) timeIF->transferInitialSolution(adaptInfo); } virtual void beginIteration(AdaptInfo *adaptInfo) { iterationIF->beginIteration(adaptInfo); } virtual Flag oneIteration(AdaptInfo *adaptInfo, Flag toDo = FULL_ITERATION); virtual Flag buildAndAdapt(AdaptInfo *adaptInfo, Flag toDo); virtual void endIteration(AdaptInfo *adaptInfo) { iterationIF->endIteration(adaptInfo); } virtual void solve() = 0; virtual int getNumProblems() { return 0; } inline virtual std::string getName() { return name; } /// Returns \ref nRankDOFs, the number of DOFs in the rank mesh. int getNumberRankDofs() { return nRankDofs; } virtual ProblemStatBase *getProblem(int number = 0) { return NULL; } // Writes all data of this object to an output stream. virtual void serialize(std::ostream &out); // Reads the object data from an input stream. virtual void deserialize(std::istream &in); protected: /** \brief * Determines the interior boundaries, i.e. boundaries between ranks, and stores * all information about them in \ref interiorBoundary. */ void createInteriorBoundaryInfo(); /** \brief * Deterimes the interior boundaries between ranks, that are based on the * neighbourhood information of the macro elements. That means that in 2d the * function search for all edge based interior boundaries and in 3d for all face * based interior boundaries. This function cannot find boundaries of substructure * elements, i.e. vertex boundaries in 2d and vertex and edge boundaries in 3d. */ void createMacroElementInteriorBoundaryInfo(); /** \brief * Determines all interior boundaries between rank that consist of element's * substructures. In 2d these may be only vertices. In 3d there may be also * interior boundaries consisting of either a whole edge or of a single vertex. */ void createSubstructureInteriorBoundaryInfo(); /// Removes all macro elements from the mesh that are not part of ranks partition. void removeMacroElements(); /// Creates from a macro mesh a correct local and global DOF index numbering. void createLocalGlobalNumbering(); /// Updates the local and global DOF numbering after the mesh has been changed. void updateLocalGlobalNumbering(); /** \brief * Creates to all dofs in rank's partition that are on a periodic boundary the * mapping from dof index to the other periodic dof indices. This information * is stored in \ref periodicDof. */ void createPeriodicMap(); /** \brief * This function create new mappings from local to global indices, * \ref mapLocalGlobalDofs, and from local to dof indices, \ref mapLocalToDofIndex. * Furthermore, using the first argument the dof indices in ranks partition are * changed. * * \param[in] rankDofsNewLocalIndex Map from dof pointers of all dofs in rank * to new dof indices. * \param[in] rankOwnedDofsNewLocalIndex Map from dof pointers of dofs owned by * the rank to the new local index. * \param[in] rankDofsNewGlobalIndex Map from dof pointers of all dofs in rank * to the new global index. */ void createLocalMappings(DofIndexMap &rankDofsNewLocalIndex, DofIndexMap &rankOwnedDofsNewLocalIndex, DofIndexMap &rankDofsNewGlobalIndex); /** \brief * This function traverses the whole mesh, i.e. before it is really partitioned, * and collects information about which DOF corresponds to which rank. Can only * be used, if \ref partitionVec is set correctly. This is only the case, when * the macro mesh is partitioned. * * \param[out] partitionDOFs Stores to each DOF pointer the set of ranks the DOF * is part of. * \param[out] rankDOFs Stores all rank DOFs. * \param[out] boundaryDOFs Stores all DOFs in ranks partition that are on an * interior boundary but correspond to another rank. */ void createDofMemberInfo(DofToPartitions& partitionDofs, DofContainer& rankOwnedDofs, DofContainer& rankAllDofs, DofToRank& boundaryDofs, DofToBool& vertexDof); /** \brief * Checks for all given interior boundaries if the elements fit together on both * sides of the boundaries. If this is not the case, the mesh is adapted. Because * refinement of a certain element may forces the refinement of other elements, * it is not guaranteed that all rank's meshes fit together after this function * terminates. Hence, it must be called until a stable mesh refinement is reached. * If the mesh has been changed by this function, it returns true. Otherwise, it * returns false, i.e., the given interior boundaries fit together on both sides. * * \param[in] allBound Defines a map from rank to interior boundaries which * should be checked. */ bool checkAndAdaptBoundary(RankToBoundMap &allBound); void dbgCreateElementMap(ElementIdxToDofs &elMap); void dbgTestElementMap(ElementIdxToDofs &elMap); void dbgTestInteriorBoundary(); /** \brief * This function is used for debugging only. It traverses all interior boundaries * and compares the dof indices on them with the dof indices of the boundarys * neighbours. The function fails, when dof indices on an interior boundary do * not fit together. * * \param printCoords If true, the coords of all common dofs are printed to * the screen. */ void dbgTestCommonDofs(bool printCoords = false); /** \brief * This function is used for debugging only. It prints all information from * the local to global dof mapping, see \ref mapLocalGlobalDofs. * * \param rank If specified, only the information from the given rank is printed. */ void printMapLocalGlobal(int rank = -1); /** \brief * This function is used for debugging only. It prints all information about * the periodic mapping of dofs, that are on periodic boundaries. * * \param rank If specified, only the information from the given rank is printed. */ void printMapPeriodic(int rank = -1); /** \brief * This function is used for debugging only. It prints information about dofs * in rank's partition. * * \param rank If specified, only the information from the given * rank is printed. * \param rankDofs List of all dofs in ranks partition that are owned by rank. * \param rankAllDofs List of all dofs in ranks partition. */ void printRankDofs(int rank, DofContainer& rankDofs, DofContainer& rankAllDofs); /** \brief * This functions create a Paraview file with the macro mesh where the elements * are colored by the partition they are part of. This function can be used for * debugging. */ void writePartitioningMesh(std::string filename); /** \brief * This function must be used if the values of a DOFVector must be synchronised * over all ranks. That means, that each rank sends the values of the DOFs, which * are owned by the rank and lie on an interior bounday, to all other ranks also * having these DOFs. * * This function must be used, for example, after the lineary system is solved, or * after the DOFVector is set by some user defined functions, e.g., initial * solution functions. */ void synchVector(DOFVector &vec); /** \brief * Works in the same way as the function above defined for DOFVectors. Due to * performance, this function does not call \ref synchVector for each DOFVector, * but instead sends all values of all DOFVectors all at once. */ void synchVector(SystemVector &vec); // Removes all periodic boundaries from a given boundary map. void removeBoundaryCondition(BoundaryIndexMap& boundaryMap); bool fitElementToMeshCode(MeshStructure &code, Element *el, int ithSide, int elType, int &refCounter); bool fitElementToMeshCode2(MeshStructure &code, Element *el, int ithSide, int elType, int &refCounter); /// Writes a vector of dof pointers to an output stream. void serialize(std::ostream &out, DofContainer &data); /// Reads a vector of dof pointers from an input stream. void deserialize(std::istream &in, DofContainer &data, std::map &dofMap); /// Writes a \ref RankToDofContainer to an output stream. void serialize(std::ostream &out, RankToDofContainer &data); /// Reads a \ref RankToDofContainer from an input stream. void deserialize(std::istream &in, RankToDofContainer &data, std::map &dofMap); /// Writes a periodic dof mapping to an output stream. void serialize(std::ostream &out, PeriodicDofMap &data); /// Reads a periodic dof mapping from an input stream. void deserialize(std::istream &in, PeriodicDofMap &data); /// Writes a mapping from dof pointers to some values to an output stream. template void serialize(std::ostream &out, std::map &data) { int mapSize = data.size(); SerUtil::serialize(out, mapSize); for (typename std::map::iterator it = data.begin(); it != data.end(); ++it) { int v1 = (*(it->first)); T v2 = it->second; SerUtil::serialize(out, v1); SerUtil::serialize(out, v2); } } /// Reads a mapping from dof pointer to some values from an input stream. template void deserialize(std::istream &in, std::map &data, std::map &dofMap) { FUNCNAME("ParallelDomainBase::deserialize()"); int mapSize = 0; SerUtil::deserialize(in, mapSize); for (int i = 0; i < mapSize; i++) { int v1 = 0; T v2; SerUtil::deserialize(in, v1); SerUtil::deserialize(in, v2); TEST_EXIT_DBG(dofMap.count(v1) != 0)("Cannot find DOF %d in map!\n", v1); data[dofMap[v1]] = v2; } } inline void orderDofs(const DegreeOfFreedom* dof0, const DegreeOfFreedom* dof1, const DegreeOfFreedom* dof2, DofContainer &vec) { DofPtrSortFct dofPtrSort; vec.resize(3); vec[0] = dof0; vec[1] = dof1; vec[2] = dof2; sort(vec.begin(), vec.end(), dofPtrSort); } inline void orderDofs(const DegreeOfFreedom* dof0, const DegreeOfFreedom* dof1, const DegreeOfFreedom* dof2, const DegreeOfFreedom* dof3, DofContainer &vec) { DofPtrSortFct dofPtrSort; vec.resize(4); vec[0] = dof0; vec[1] = dof1; vec[2] = dof2; vec[3] = dof3; sort(vec.begin(), vec.end(), dofPtrSort); } inline void printColValues(int row, std::vector& cols, std::vector& values) { for (int i = 0; i < static_cast(cols.size()); i++) std::cout << "Mat[" << row << "][" << cols[i] << "] = " << values[i] << "\n"; } protected: /// ProblemIterationInterface *iterationIF; /// ProblemTimeInterface *timeIF; /// ProblemVec *probStat; /// The rank of the current process. int mpiRank; /// Overall number of processes. int mpiSize; /** \brief * MPI communicator collected all processes, which should * be used for calculation. The Debug procces is not included * in this communicator. */ MPI::Intracomm mpiComm; /// Name of the problem (as used in the init files) std::string name; /// Finite element space of the problem. FiniteElemSpace *feSpace; /// Mesh of the problem. Mesh *mesh; /** \brief * A refinement manager that should be used on the mesh. It is used to refine * elements at interior boundaries in order to fit together with elements on the * other side of the interior boundary. */ RefinementManager *refineManager; /// Info level. int info; /// Pointer to the paritioner which is used to devide a mesh into partitions. ParMetisPartitioner *partitioner; /// Weights for the elements, i.e., the number of leaf elements within this element. std::map elemWeights; /// Is true, if the mesh was not partitioned before, otherwise it's false. bool initialPartitionMesh; /** \brief * Stores to every coarse element index the number of the partition it * corresponds to. */ std::map partitionVec; /** \brief * Stores an old partitioning of elements. To every element index the number * of the parition it corresponds to is stored. */ std::map oldPartitionVec; /// Number of DOFs in the rank mesh. int nRankDofs; /** \brief * Defines the interior boundaries of the domain that result from partitioning * the whole mesh. Contains only the boundaries, which are owned by the rank, i.e., * the object gives for every neighbour rank i the boundaries this rank owns and * shares with rank i. */ InteriorBoundary myIntBoundary; /** \brief * Defines the interior boundaries of the domain that result from partitioning * the whole mesh. Contains only the boundaries, which are not owned by the rank, * i.e., the object gives for every neighbour rank i the boundaries that are * owned by rank i and are shared with this rank. */ InteriorBoundary otherIntBoundary; /** \brief * */ InteriorBoundary periodicBoundary; /** \brief * This map contains for each rank the list of dofs the current rank must send * to exchange solution dofs at the interior boundaries. */ RankToDofContainer sendDofs; /** \brief * This map contains for each rank the list of DOFs from which the current rank * will receive DOF values (i.e., this are all DOFs at an interior boundary). The * DOF indices are given in rank's local numbering. */ RankToDofContainer recvDofs; /// Maps local to global dof indices. DofMapping mapLocalGlobalDofs; /// Maps local dof indices to real dof indices. DofMapping mapLocalToDofIndex; /** \brief * Maps all DOFs in ranks partition to a bool value. If it is true, the DOF is * owned by the rank. Otherwise, its an interior boundary DOF that is owned by * another rank. */ DofIndexToBool isRankDof; /** \brief * Maps every dof pointer in ranks macro mesh to a boolean variable indicating * wheather this dof is a vertex dof (true) or not (false). */ DofToBool vertexDof; /** \brief * If periodic boundaries are used, this map stores to each dof in rank's * partition, that is on periodic boundaries, the corresponding periodic dofs. * The mapping is defined by using global dof indices. */ PeriodicDofMap periodicDof; /// Is the index of the first row of the linear system, which is owned by the rank. int rstart; /** \brief * Number of components of the equation. Is used to calculate the exact number * of rows in the the overall linear system. */ int nComponents; /// Number of rows of the whole linear system that are stored on this rank. int nRankRows; /// Overall number of the rows in the lineary system. int nOverallRows; /** \brief * If the problem definition has been read from a serialization file, this * variable is true, otherwise it is false. This variable is used to stop the * initialization function, if the problem definition has already been read from * a serialization file. */ bool deserialized; /** \brief * Stores the mesh change index. This is used to recognize changes in the mesh * structure (e.g. through refinement or coarsening managers). */ long lastMeshChangeIndex; }; } #endif // AMDIS_PARALLELDOMAINBASE_H