diff --git a/src/mesh/CMakeLists.txt b/src/mesh/CMakeLists.txt index c28b0643fd8bbf1b2677512423d2185d9a7ff970..10ea744770b20545201c5eaa9b6b947de7bd3ee8 100644 --- a/src/mesh/CMakeLists.txt +++ b/src/mesh/CMakeLists.txt @@ -9,7 +9,7 @@ add_library( ConnectivityComputer.cpp GmshReader.cpp) -#include_directories(${PASTIS_SOURCE_DIR}/utils) +include_directories(${PASTIS_SOURCE_DIR}/utils) # Additional dependencies #add_dependencies(PastisMesh) diff --git a/src/mesh/GmshReader.cpp b/src/mesh/GmshReader.cpp index 3a2d5c6ecc290a6ae71c234dd0551c7b48a22dca..e599ea8083c4d0a25471fab73c22192c1478af50 100644 --- a/src/mesh/GmshReader.cpp +++ b/src/mesh/GmshReader.cpp @@ -12,6 +12,8 @@ #include <Mesh.hpp> #include <RefFaceList.hpp> +#include <Messenger.hpp> +#include <Partitioner.hpp> #include <map> #include <regex> @@ -141,162 +143,178 @@ ErrorHandler(const std::string& filename, GmshReader::GmshReader(const std::string& filename) : m_filename(filename) { - try { - m_fin.open(m_filename); - if (not m_fin) { - perr() << "cannot read file '" << m_filename << "'\n"; - std::exit(0); - } + if (commRank() == 0) { + try { + m_fin.open(m_filename); + if (not m_fin) { + perr() << "cannot read file '" << m_filename << "'\n"; + std::exit(0); + } - // gmsh 2.2 format keywords - __keywordList["$MeshFormat"] = MESHFORMAT; - __keywordList["$EndMeshFormat"] = ENDMESHFORMAT; - __keywordList["$Nodes"] = NODES; - __keywordList["$EndNodes"] = ENDNODES; - __keywordList["$Elements"] = ELEMENTS; - __keywordList["$EndElements"] = ENDELEMENTS; - __keywordList["$PhysicalNames"] = PHYSICALNAMES; - __keywordList["$EndPhysicalNames"] = ENDPHYSICALNAMES; - - __numberOfPrimitiveNodes.resize(16); - __numberOfPrimitiveNodes[ 0] = 2; // edge - __numberOfPrimitiveNodes[ 1] = 3; // triangle - __numberOfPrimitiveNodes[ 2] = 4; // quadrangle - __numberOfPrimitiveNodes[ 3] = 4; // Tetrahedron - __numberOfPrimitiveNodes[ 4] = 8; // Hexaredron - __numberOfPrimitiveNodes[ 5] = 6; // Prism - __numberOfPrimitiveNodes[ 6] = 5; // Pyramid - __numberOfPrimitiveNodes[ 7] = 3; // second order edge - __numberOfPrimitiveNodes[ 8] = 6; // second order triangle - __numberOfPrimitiveNodes[ 9] = 9; // second order quadrangle - __numberOfPrimitiveNodes[10] = 10; // second order tetrahedron - __numberOfPrimitiveNodes[11] = 27; // second order hexahedron - __numberOfPrimitiveNodes[12] = 18; // second order prism - __numberOfPrimitiveNodes[13] = 14; // second order pyramid - __numberOfPrimitiveNodes[14] = 1; // point - - __primitivesNames[0] = "edges"; - __supportedPrimitives[0] = true; - __primitivesNames[1] = "triangles"; - __supportedPrimitives[1] = true; - __primitivesNames[2] = "quadrangles"; - __supportedPrimitives[2] = true; - __primitivesNames[3] = "tetrahedra"; - __supportedPrimitives[3] = true; - __primitivesNames[4] = "hexahedra"; - __supportedPrimitives[4] = true; - __primitivesNames[5] = "prisms"; - __supportedPrimitives[5] = false; - __primitivesNames[6] = "pyramids"; - __supportedPrimitives[6] = false; - __primitivesNames[7] = "second order edges"; - __supportedPrimitives[7] = false; - __primitivesNames[8] = "second order triangles"; - __supportedPrimitives[8] = false; - __primitivesNames[9] = "second order quadrangles"; - __supportedPrimitives[9] = false; - __primitivesNames[10] = "second order tetrahedra"; - __supportedPrimitives[10]= false; - __primitivesNames[11] = "second order hexahedra"; - __supportedPrimitives[11]= false; - __primitivesNames[12] = "second order prisms"; - __supportedPrimitives[12]= false; - __primitivesNames[13] = "second order pyramids"; - __supportedPrimitives[13]= false; - __primitivesNames[14] = "point"; - __supportedPrimitives[14]= true; - - pout() << "Reading file '" << m_filename << "'\n"; - - // Getting vertices list - GmshReader::Keyword kw = this->__nextKeyword(); - switch(kw.second) { - // case NOD: { - // this->__readGmsh1(); - // break; - // } - case MESHFORMAT: { - double fileVersion = this->_getReal(); - if (fileVersion != 2.2) { - throw ErrorHandler(__FILE__,__LINE__, - "Cannot read Gmsh format '"+stringify(fileVersion)+"'", - ErrorHandler::normal); - } - int fileType = this->_getInteger(); - __binary = (fileType == 1); - if ((fileType < 0) or (fileType > 1)) { - throw ErrorHandler(__FILE__,__LINE__, - "Cannot read Gmsh file type '"+stringify(fileType)+"'", - ErrorHandler::normal); - } + // gmsh 2.2 format keywords + __keywordList["$MeshFormat"] = MESHFORMAT; + __keywordList["$EndMeshFormat"] = ENDMESHFORMAT; + __keywordList["$Nodes"] = NODES; + __keywordList["$EndNodes"] = ENDNODES; + __keywordList["$Elements"] = ELEMENTS; + __keywordList["$EndElements"] = ENDELEMENTS; + __keywordList["$PhysicalNames"] = PHYSICALNAMES; + __keywordList["$EndPhysicalNames"] = ENDPHYSICALNAMES; + + __numberOfPrimitiveNodes.resize(16); + __numberOfPrimitiveNodes[ 0] = 2; // edge + __numberOfPrimitiveNodes[ 1] = 3; // triangle + __numberOfPrimitiveNodes[ 2] = 4; // quadrangle + __numberOfPrimitiveNodes[ 3] = 4; // Tetrahedron + __numberOfPrimitiveNodes[ 4] = 8; // Hexaredron + __numberOfPrimitiveNodes[ 5] = 6; // Prism + __numberOfPrimitiveNodes[ 6] = 5; // Pyramid + __numberOfPrimitiveNodes[ 7] = 3; // second order edge + __numberOfPrimitiveNodes[ 8] = 6; // second order triangle + __numberOfPrimitiveNodes[ 9] = 9; // second order quadrangle + __numberOfPrimitiveNodes[10] = 10; // second order tetrahedron + __numberOfPrimitiveNodes[11] = 27; // second order hexahedron + __numberOfPrimitiveNodes[12] = 18; // second order prism + __numberOfPrimitiveNodes[13] = 14; // second order pyramid + __numberOfPrimitiveNodes[14] = 1; // point + + __primitivesNames[0] = "edges"; + __supportedPrimitives[0] = true; + __primitivesNames[1] = "triangles"; + __supportedPrimitives[1] = true; + __primitivesNames[2] = "quadrangles"; + __supportedPrimitives[2] = true; + __primitivesNames[3] = "tetrahedra"; + __supportedPrimitives[3] = true; + __primitivesNames[4] = "hexahedra"; + __supportedPrimitives[4] = true; + __primitivesNames[5] = "prisms"; + __supportedPrimitives[5] = false; + __primitivesNames[6] = "pyramids"; + __supportedPrimitives[6] = false; + __primitivesNames[7] = "second order edges"; + __supportedPrimitives[7] = false; + __primitivesNames[8] = "second order triangles"; + __supportedPrimitives[8] = false; + __primitivesNames[9] = "second order quadrangles"; + __supportedPrimitives[9] = false; + __primitivesNames[10] = "second order tetrahedra"; + __supportedPrimitives[10]= false; + __primitivesNames[11] = "second order hexahedra"; + __supportedPrimitives[11]= false; + __primitivesNames[12] = "second order prisms"; + __supportedPrimitives[12]= false; + __primitivesNames[13] = "second order pyramids"; + __supportedPrimitives[13]= false; + __primitivesNames[14] = "point"; + __supportedPrimitives[14]= true; + + pout() << "Reading file '" << m_filename << "'\n"; + + // Getting vertices list + GmshReader::Keyword kw = this->__nextKeyword(); + switch(kw.second) { + // case NOD: { + // this->__readGmsh1(); + // break; + // } + case MESHFORMAT: { + double fileVersion = this->_getReal(); + if (fileVersion != 2.2) { + throw ErrorHandler(__FILE__,__LINE__, + "Cannot read Gmsh format '"+stringify(fileVersion)+"'", + ErrorHandler::normal); + } + int fileType = this->_getInteger(); + __binary = (fileType == 1); + if ((fileType < 0) or (fileType > 1)) { + throw ErrorHandler(__FILE__,__LINE__, + "Cannot read Gmsh file type '"+stringify(fileType)+"'", + ErrorHandler::normal); + } - int dataSize = this->_getInteger(); - if (dataSize != sizeof(double)) { - throw ErrorHandler(__FILE__,__LINE__, - "Data size not supported '"+stringify(dataSize)+"'", - ErrorHandler::normal); - } + int dataSize = this->_getInteger(); + if (dataSize != sizeof(double)) { + throw ErrorHandler(__FILE__,__LINE__, + "Data size not supported '"+stringify(dataSize)+"'", + ErrorHandler::normal); + } - if (__binary) { - // int one=0; - - // fseek(__ifh,1L,SEEK_CUR); - // fread(reinterpret_cast<char*>(&one),sizeof(int),1,__ifh); - - // if (one == 1) { - // __convertEndian = false; - // } else { - // invertEndianess(one); - - // if (one == 1) { - // __convertEndian = true; - // } else { - // throw ErrorHandler(__FILE__,__LINE__, - // "Cannot determine endianess", - // ErrorHandler::normal); - // } - // } - - // pout() << "- Binary format: "; - // #ifdef WORDS_BIGENDIAN - // if (not __convertEndian) { - // pout() << "big endian\n"; - // } else { - // pout() << "little endian\n"; - // } - // #else // WORDS_BIGENDIAN - // if (not __convertEndian) { - // pout() << "little endian\n"; - // } else { - // pout() << "big endian\n"; - // } - // #endif // WORDS_BIGENDIAN - } + if (__binary) { + // int one=0; + + // fseek(__ifh,1L,SEEK_CUR); + // fread(reinterpret_cast<char*>(&one),sizeof(int),1,__ifh); + + // if (one == 1) { + // __convertEndian = false; + // } else { + // invertEndianess(one); + + // if (one == 1) { + // __convertEndian = true; + // } else { + // throw ErrorHandler(__FILE__,__LINE__, + // "Cannot determine endianess", + // ErrorHandler::normal); + // } + // } + + // pout() << "- Binary format: "; + // #ifdef WORDS_BIGENDIAN + // if (not __convertEndian) { + // pout() << "big endian\n"; + // } else { + // pout() << "little endian\n"; + // } + // #else // WORDS_BIGENDIAN + // if (not __convertEndian) { + // pout() << "little endian\n"; + // } else { + // pout() << "big endian\n"; + // } + // #endif // WORDS_BIGENDIAN + } - kw = this->__nextKeyword(); - if (kw.second != ENDMESHFORMAT) { + kw = this->__nextKeyword(); + if (kw.second != ENDMESHFORMAT) { + throw ErrorHandler(__FILE__,__LINE__, + "reading file '"+m_filename + +"': expecting $EndMeshFormat, '"+kw.first+"' was found", + ErrorHandler::normal); + } + + this->__readGmshFormat2_2(); + + break; + } + default: { throw ErrorHandler(__FILE__,__LINE__, - "reading file '"+m_filename - +"': expecting $EndMeshFormat, '"+kw.first+"' was found", + "cannot determine format version of '"+m_filename+"'", ErrorHandler::normal); } + } - this->__readGmshFormat2_2(); + this->__proceedData(); + // this->__createMesh(); + } + catch(const ErrorHandler& e) { + e.writeErrorMessage(); + std::exit(0); + } + } - break; - } - default: { - throw ErrorHandler(__FILE__,__LINE__, - "cannot determine format version of '"+m_filename+"'", - ErrorHandler::normal); - } + if (commSize() > 1) { + pout() << "Sequential mesh read! Need to be dispatched\n"; + CSRGraph mesh_graph; + if (commRank() == 0) { + mesh_graph = m_mesh->cellToCellGraph(); } - this->__proceedData(); - // this->__createMesh(); - } - catch(const ErrorHandler& e) { - e.writeErrorMessage(); + Partitioner P; + Array<int> new_cell_owner = P.partition(mesh_graph); + + Messenger::destroy(); std::exit(0); } } diff --git a/src/utils/Partitioner.cpp b/src/utils/Partitioner.cpp index b3bfd7e705432de9aceb8f5dc8d6a9e34c16ce51..b4c24c5d908019649dcccb52b28ffd81df074091 100644 --- a/src/utils/Partitioner.cpp +++ b/src/utils/Partitioner.cpp @@ -2,86 +2,81 @@ #include <Messenger.hpp> #include <pastis_config.hpp> +#include <PastisOStream.hpp> + #ifdef PASTIS_HAS_MPI +#define IDXTYPEWIDTH 64 +#define REALTYPEWIDTH 64 #include <parmetis.h> -#include <vector> -Partitioner:: -Partitioner() -{ - std::cout << commRank() << " / " << commSize() << '\n' << std::flush; - MPI_Barrier(MPI_COMM_WORLD); - if (commSize() != 3) { - Messenger::destroy(); - std::cerr << "Commsize=" << commSize() << ". Need 3 PE to test"; - std::exit(1); - } +#include <vector> + - idx_t wgtflag = 0; - idx_t numflag = 0; - idx_t ncon = 1; - idx_t npart= 3; - real_t wgts = 1./npart; - std::vector<real_t> tpwgts{wgts, wgts, wgts}; - std::vector<real_t> ubvec{1.05}; - std::vector<idx_t> options{0,0,0}; - idx_t edgecut = 0; - std::vector<idx_t> part(5); +Array<int> Partitioner::partition(const CSRGraph& graph) +{ + pout() << "Partitioning graph into " + << rang::style::bold << commSize() << rang::style::reset + << " parts\n"; MPI_Comm mpi_comm_; MPI_Comm_dup(MPI_COMM_WORLD, &mpi_comm_); MPI_Comm* mpi_comm = & mpi_comm_; - switch (commRank()) { - case 0: { - std::vector<idx_t> xadj {0,2,5,8,11,13}; - std::vector<idx_t> adjncy {1,5,0,2,6,1,3,7,2,4,8,3,9}; - std::vector<idx_t> vtxdist{0,5,10,15}; - - ParMETIS_V3_PartKway(&(vtxdist[0]), &(xadj[0]), &(adjncy[0]), - NULL, NULL, &wgtflag, &numflag, - &ncon, &npart, &(tpwgts[0]), &(ubvec[0]), - &(options[0]), &edgecut, &(part[0]), mpi_comm); - break; - } - case 1: { - std::vector<idx_t> xadj {0,3,7,11,15,18}; - std::vector<idx_t> adjncy {0,6,10,1,5,7,11,2,6,8,12,3,7,9,13,4,8,14}; - std::vector<idx_t> vtxdist{0,5,10,15}; - - ParMETIS_V3_PartKway(&(vtxdist[0]), &(xadj[0]), &(adjncy[0]), - NULL, NULL, &wgtflag, &numflag, - &ncon, &npart, &(tpwgts[0]), &(ubvec[0]), - &(options[0]), &edgecut, &(part[0]), mpi_comm); - break; - } - case 2: { - std::vector<idx_t> xadj {0,2,5,8,11,13}; - std::vector<idx_t> adjncy {5,11,6,10,12,7,11,13,8,12,14,9,13}; - std::vector<idx_t> vtxdist{0,5,10,15}; - - ParMETIS_V3_PartKway(&(vtxdist[0]), &(xadj[0]), &(adjncy[0]), - NULL, NULL, &wgtflag, &numflag, - &ncon, &npart, &(tpwgts[0]), &(ubvec[0]), - &(options[0]), &edgecut, &(part[0]), mpi_comm); - break; - } - default: { - std::cerr << "unexpected rank " << commRank() << "!\n"; - std::exit(0); - } + + int wgtflag = 0; + int numflag = 0; + int ncon = 1; + int npart= commSize(); + std::vector<float> tpwgts; + for (int i_part=0; i_part<npart; ++i_part) { + tpwgts.push_back(1./npart); } + std::vector<float> ubvec{1.05}; + std::vector<int> options{1,1,0}; + int edgecut = 0; + Array<int> part(0); - std::cerr << commRank() << " FINISHED\n"; - MPI_Barrier(MPI_COMM_WORLD); + MPI_Group world_group; + MPI_Comm_group(MPI_COMM_WORLD, &world_group); - Messenger::destroy(); - std::exit(0); + MPI_Group mesh_group; + std::vector<int> group_ranks{0}; + MPI_Group_incl(world_group, group_ranks.size(), &(group_ranks[0]), &mesh_group); + + MPI_Comm parmetis_comm; + MPI_Comm_create_group(MPI_COMM_WORLD, mesh_group, 1, &parmetis_comm); + + int local_number_of_cells = graph.entries().size()-1; + + if (commRank() ==0) { + part = Array<int>(local_number_of_cells); + std::vector<int> vtxdist{0,local_number_of_cells}; + + static_assert(std::is_same<int, int>()); + + const Array<int>& entries = graph.entries(); + const Array<int>& neighbors = graph.neighbors(); + + int result + = ParMETIS_V3_PartKway(&(vtxdist[0]), &(entries[0]), &(neighbors[0]), + NULL, NULL, &wgtflag, &numflag, + &ncon, &npart, &(tpwgts[0]), &(ubvec[0]), + &(options[0]), &edgecut, &(part[0]), &parmetis_comm); + if (result == METIS_ERROR) { + perr() << "Metis Error\n"; + std::exit(1); + } + } + + return part; } #else // PASTIS_HAS_MPI -Partitioner::Partitioner() {} +Array<int> Partitioner::partition(const CSRGraph& graph) +{ + return Array<int>(0); +} #endif // PASTIS_HAS_MPI diff --git a/src/utils/Partitioner.hpp b/src/utils/Partitioner.hpp index 88e3e267250d5a7e8e3b0c37994dc06cca79de1a..427d67f30d4af57f2fe096ffdb8b91736906ee0c 100644 --- a/src/utils/Partitioner.hpp +++ b/src/utils/Partitioner.hpp @@ -1,12 +1,16 @@ #ifndef PARTITIONER_HPP #define PARTITIONER_HPP +#include <CSRGraph.hpp> + class Partitioner { public: - Partitioner(); + Partitioner() = default; Partitioner(const Partitioner&) = default; ~Partitioner() = default; + + Array<int> partition(const CSRGraph& graph); };