diff --git a/Partitioning/CMakeLists.txt b/Partitioning/CMakeLists.txt new file mode 100755 index 0000000000000000000000000000000000000000..d69d88ea4334f2040a66cc6dbdd3d53567969e82 --- /dev/null +++ b/Partitioning/CMakeLists.txt @@ -0,0 +1,51 @@ +cmake_minimum_required(VERSION 3.5) + +project(graphPartitioner) + +option(MPI "Compile the parallel version" OFF) + +file(GLOB FILES main.cpp + io.cpp + graph.cpp + topology.cpp) + +include_directories(include/gmsh) +include_directories(include/metis) + +if(MPI) + message("Parallel version") + + set(CMAKE_CXX_COMPILER "mpic++") + set(CMAKE_C_COMPILER "mpicc") + + find_package (MPI) + if (MPI_FOUND) + include_directories(${MPI_INCLUDE_PATH}) + endif(MPI_FOUND) + + add_definitions(-DPARALLEL) + + file(GLOB FILESMPI main_mpi.cpp + topology_mpi.cpp) +else(MPI) + message("Sequential version") +endif(MPI) + +if(APPLE) + message("OS X build") + link_directories(lib/osx) + set(EXECUTABLE_OUTPUT_PATH ../bin/osx) +else(APPLE) + message("NIC4 build") + link_directories(lib/nic4) + set(EXECUTABLE_OUTPUT_PATH ../bin/nic4) +endif(APPLE) + + +if(MPI) + add_executable(meshPartitioner_mpi ${FILES} ${FILESMPI}) + target_link_libraries(meshPartitioner_mpi Gmsh lapack blas parmetis metis) +else(MPI) + add_executable(meshPartitioner ${FILES}) + target_link_libraries(meshPartitioner Gmsh lapack blas metis) +endif(MPI) diff --git a/Partitioning/graph.cpp b/Partitioning/graph.cpp new file mode 100755 index 0000000000000000000000000000000000000000..30432292e6d7db5a7688cb0f266b0f01ddfe4a4c --- /dev/null +++ b/Partitioning/graph.cpp @@ -0,0 +1,160 @@ +#include <map> +#ifdef PARALLEL + #include <mpi.h> +#endif + +#include "MElementCut.h" + +#include "MTetrahedron.h" +#include "MHexahedron.h" +#include "MPrism.h" +#include "MPyramid.h" +#include "MTrihedron.h" + +#include "MTriangle.h" +#include "MQuadrangle.h" + +#include "MLine.h" + +#include "MPoint.h" + +#include "graph.h" + +void SEQ::GModelToGraph(GModel* gModel, int* eptr, int** eind, int *metisToGmshIndex) +{ + std::multimap<int, int> elementsToNodes; + + //Loop over regions + for(GModel::riter it = gModel->firstRegion(); it != gModel->lastRegion(); ++it) + { + GRegion *r = *it; + + fillElementsToNodes(elementsToNodes, r->tetrahedra.begin(), r->tetrahedra.end()); + fillElementsToNodes(elementsToNodes, r->hexahedra.begin(), r->hexahedra.end()); + fillElementsToNodes(elementsToNodes, r->prisms.begin(), r->prisms.end()); + fillElementsToNodes(elementsToNodes, r->pyramids.begin(), r->pyramids.end()); + fillElementsToNodes(elementsToNodes, r->trihedra.begin(), r->trihedra.end()); + fillElementsToNodes(elementsToNodes, r->polyhedra.begin(), r->polyhedra.end()); + } + + //Loop over faces + for(GModel::fiter it = gModel->firstFace(); it != gModel->lastFace(); ++it) + { + GFace *f = *it; + + fillElementsToNodes(elementsToNodes, f->triangles.begin(), f->triangles.end()); + fillElementsToNodes(elementsToNodes, f->quadrangles.begin(), f->quadrangles.end()); + fillElementsToNodes(elementsToNodes, f->polygons.begin(), f->polygons.end()); + } + + //Loop over edges + for(GModel::eiter it = gModel->firstEdge(); it != gModel->lastEdge(); ++it) + { + GEdge *e = *it; + + fillElementsToNodes(elementsToNodes, e->lines.begin(), e->lines.end()); + } + + //Loop over vertices + for(GModel::viter it = gModel->firstVertex(); it != gModel->lastVertex(); ++it) + { + GVertex *v = *it; + + fillElementsToNodes(elementsToNodes, v->points.begin(), v->points.end()); + } + + //create mesh format for METIS + unsigned int position = 0; + eptr[0] = 0; + unsigned int i = 0; + int itFirstLast = 0; + + for(std::multimap<int, int>::const_iterator it = elementsToNodes.begin(); it != elementsToNodes.end(); ++it) + { + if(itFirstLast != it->first+1) + { + metisToGmshIndex[i] = it->first + 1; + position += elementsToNodes.count(it->first); + eptr[i+1] = position; + i++; + itFirstLast = it->first+1; + } + } + + (*eind) = new int[position]; + unsigned int positionInd = 0; + for(std::multimap<int, int>::const_iterator it = elementsToNodes.begin(); it != elementsToNodes.end(); ++it) + { + int tag = it->second; + (*eind)[positionInd] = tag; + positionInd++; + } +} + +template <class ITERATOR> +void SEQ::fillElementsToNodes(std::multimap<int, int> &elementsToNodes, ITERATOR it_beg, ITERATOR it_end) +{ + for(ITERATOR it = it_beg; it != it_end; ++it) + { + const int tag = (*it)->getNum()-1; + + for(unsigned int j = 0; j < (*it)->getNumVertices(); j++) + { + elementsToNodes.insert(std::pair<int, int>(tag,(*it)->getVertex(j)->getNum()-1)); + } + } +} + +// Parallel + +#ifdef PARALLEL +int PAR::GModelToGraph(GModel* gModel, int* eptr, int** eind, int *metisToGmshIndex, int* elmdist) +{ + int nbproc, myrank; + MPI_Comm_rank(MPI_COMM_WORLD, &myrank); + MPI_Comm_size(MPI_COMM_WORLD, &nbproc); + + std::multimap<int, int> elementsToNodes; + + for(unsigned int i = elmdist[myrank]; i < elmdist[myrank+1]; i++) + { + MElement* elm = gModel->getMeshElementByTag(i+1); + const int tag = i; + + for(unsigned int j = 0; j < elm->getNumVertices(); j++) + { + elementsToNodes.insert(std::pair<int, int>(tag,elm->getVertex(j)->getNum()-1)); + } + } + + //create mesh format for METIS + unsigned int position = 0; + eptr[0] = 0; + unsigned int i = 0; + int itFirstLast = 0; + + for(std::multimap<int, int>::const_iterator it = elementsToNodes.begin(); it != elementsToNodes.end(); ++it) + { + if(itFirstLast != it->first+1) + { + metisToGmshIndex[i] = it->first + 1; + position += elementsToNodes.count(it->first); + eptr[i+1] = position; + i++; + itFirstLast = it->first+1; + } + } + + (*eind) = new int[position]; + unsigned int positionInd = 0; + for(std::multimap<int, int>::const_iterator it = elementsToNodes.begin(); it != elementsToNodes.end(); ++it) + { + int tag = it->second; + (*eind)[positionInd] = tag; + positionInd++; + } + + return position; +} +#endif + diff --git a/Partitioning/graph.h b/Partitioning/graph.h new file mode 100755 index 0000000000000000000000000000000000000000..d57706f7c225c3b39cbc4a011f2adb2c5aabff2b --- /dev/null +++ b/Partitioning/graph.h @@ -0,0 +1,19 @@ +#ifndef GRAPH_INCLUDED +#define GRAPH_INCLUDED + +#include "Gmsh.h" +#include "GModel.h" + +namespace SEQ { + void GModelToGraph(GModel* gModel, int* eptr, int** eind, int *metisToGmshIndex); + template <class ITERATOR> + void fillElementsToNodes(std::multimap<int, int> &nodesToElements, ITERATOR it_beg, ITERATOR it_end); +} + +#ifdef PARALLEL +namespace PAR { + int GModelToGraph(GModel* gModel, int* eptr, int** eind, int *metisToGmshIndex, int* elmdist); +} +#endif + +#endif //GRAPH_INCLUDED diff --git a/Partitioning/io.cpp b/Partitioning/io.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7021a881c2ddd525fd332b865512944ae77a17a7 --- /dev/null +++ b/Partitioning/io.cpp @@ -0,0 +1,374 @@ +#include <map> +#include <unordered_map> +#include <vector> +#include <fstream> + +#include "GModel.h" +#include "GEntity.h" + +#include "partitionFace.h" +#include "partitionEdge.h" +#include "partitionVertex.h" + +#include "io.h" + +void SEQ::writeModels(std::vector<GModel*> &models) +{ + for(unsigned int i = 0; i < models.size(); i++) + { + std::string str = "mesh_"; + str += std::to_string(i); + str += ".msh"; + + models[i]->writeMSH(str.c_str());//, 3.0); + } +} + +void SEQ::writeProFile(GModel* m, const int npart) +{ + std::ofstream file("partition.pro", std::ofstream::trunc); + + //-----------Group----------- + file << "Group{" << std::endl; + + //Omega + std::unordered_map<int, std::vector<int> > listOfOmega;//map between tag of omega and the physical's numbers that corresponds + for(GModel::piter it = m->firstPhysicalName(); it != m->lastPhysicalName(); ++it) + { + std::string name = it->second; + + if(name[0] == '_' && name[1] == 'o') + { + std::vector<int> num = getNumFromString(name); + + std::vector<int> vec = listOfOmega[num[0]]; + vec.push_back(it->first.second); + listOfOmega[num[0]] = vec; + } + } + //Omega_i + for(std::unordered_map<int, std::vector<int> >::iterator it = listOfOmega.begin(); it != listOfOmega.end(); ++it) + { + std::vector<int> vec = it->second; + file << "\tOmega_" << it->first << " = Region[{"; + + for(unsigned int i = 0; i < vec.size(); i++) + { + if(i != 0) + { + file << ", "; + } + file << vec[i]; + } + file << "}];" << std::endl; + } + file << std::endl; + + //Sigma + if(npart == 1) + { + file << "\tSigma_0_0 = Region[{}];" << std::endl; + file << "\tBndSigma_0_0 = Region[{}];" << std::endl; + file << "\tSigma_0 = Region[{}];" << std::endl; + file << "\tBndGammaInf_0_0 = Region[{}];" << std::endl; + file << "\tBndGammaD_0_0 = Region[{}];" << std::endl; + file << "\tBndGammaInf_0 = Region[{}];" << std::endl; + file << "\tBndGammaD_0 = Region[{}];" << std::endl; + file << "\tD_0() = {0};" << std::endl; + } + std::unordered_map<int, std::vector<int> > listOfSigma;//map between tag of sigma and the physical's numbers that corresponds + std::unordered_map<int, std::vector<int> > listOfBndSigma;//map between tag of sigma's boundary and the physical's numbers that corresponds + for(GModel::piter it = m->firstPhysicalName(); it != m->lastPhysicalName(); ++it) + { + std::string name = it->second; + + if(name[0] == '_' && name[1] == 's') + { + std::vector<int> num = getNumFromString(name); + + if(num.size() < 3) + { + for(unsigned int i = 0; i < num.size(); i++) + { + std::vector<int> vec = listOfSigma[num[i]]; + vec.push_back(it->first.second); + listOfSigma[num[i]] = vec; + } + } + else + { + for(unsigned int i = 0; i < num.size(); i++) + { + std::vector<int> vec = listOfBndSigma[num[i]]; + vec.push_back(it->first.second); + listOfBndSigma[num[i]] = vec; + } + } + } + } + file << std::endl; + //Sigma_i_j and BndSigma_i_j + std::unordered_map<int, std::vector<int> > listOfNeighbour;//map between tag of omega and tag of neighbours + for(std::unordered_map<int, std::vector<int> >::iterator it = listOfSigma.begin(); it != listOfSigma.end(); ++it) + { + for(std::unordered_map<int, std::vector<int> >::iterator it2 = it; it2 != listOfSigma.end(); ++it2) + { + if(it != it2) + { + std::vector<int> vec1 = it->second; + std::vector<int> vec2 = it2->second; + std::vector<int>* vecCommun = new std::vector<int>; + + if(communPhysicals(vec1, vec2, vecCommun)) + { + listOfNeighbour[it->first].push_back(it2->first); + listOfNeighbour[it2->first].push_back(it->first); + + file << "\tSigma_" << it->first << "_" << it2->first << " = Region[{"; + for(unsigned int i = 0; i < vecCommun->size(); i++) + { + if(i != 0) + { + file << ", "; + } + file << (*vecCommun)[i]; + } + file << "}];" << std::endl; + + file << "\tSigma_" << it2->first << "_" << it->first << " = Region[{"; + for(unsigned int i = 0; i < vecCommun->size(); i++) + { + if(i != 0) + { + file << ", "; + } + file << (*vecCommun)[i]; + } + file << "}];" << std::endl; + + if(listOfBndSigma.count(it->first) > 0) + { + std::vector<int> vec1 = listOfBndSigma[it->first]; + std::vector<int> vec2 = listOfBndSigma[it2->first]; + std::vector<int>* vecCommun = new std::vector<int>; + + if(communPhysicals(vec1, vec2, vecCommun)) + { + file << "\tBndSigma_" << it->first << "_" << it2->first << " = Region[{"; + for(unsigned int i = 0; i < vecCommun->size(); i++) + { + if(i != 0) + { + file << ", "; + } + file << (*vecCommun)[i]; + } + file << "}];" << std::endl; + + file << "\tBndSigma_" << it2->first << "_" << it->first << " = Region[{"; + for(unsigned int i = 0; i < vecCommun->size(); i++) + { + if(i != 0) + { + file << ", "; + } + file << (*vecCommun)[i]; + } + file << "}];" << std::endl; + } + else + { + file << "\tBndSigma_" << it->first << "_" << it2->first << " = Region[{}];" << std::endl; + file << "\tBndSigma_" << it2->first << "_" << it->first << " = Region[{}];" << std::endl; + } + } + else + { + file << "\tBndSigma_" << it->first << "_" << it2->first << " = Region[{}];" << std::endl; + file << "\tBndSigma_" << it2->first << "_" << it->first << " = Region[{}];" << std::endl; + } + + file << "\tBndGammaInf_" << it->first << "_" << it2->first << " = Region[{}];" << std::endl; + file << "\tBndGammaInf_" << it2->first << "_" << it->first << " = Region[{}];" << std::endl; + + file << "\tBndGammaD_" << it->first << "_" << it2->first << " = Region[{}];" << std::endl; + file << "\tBndGammaD_" << it2->first << "_" << it->first << " = Region[{}];" << std::endl; + + file << "\tBndGammaInf_" << it->first << " = Region[{}];" << std::endl; + file << "\tBndGammaInf_" << it2->first << " = Region[{}];" << std::endl; + + file << "\tBndGammaD_" << it->first << " = Region[{}];" << std::endl; + file << "\tBndGammaD_" << it2->first << " = Region[{}];" << std::endl; + } + delete vecCommun; + } + } + } + file << std::endl; + //Sigma_i + for(std::unordered_map<int, std::vector<int> >::iterator it = listOfSigma.begin(); it != listOfSigma.end(); ++it) + { + std::vector<int> vec = it->second; + file << "\tSigma_" << it->first << " = Region[{"; + + for(unsigned int i = 0; i < vec.size(); i++) + { + if(i != 0) + { + file << ", "; + } + file << vec[i]; + } + file << "}];" << std::endl; + } + file << std::endl; + //BndSigma_i + for(std::unordered_map<int, std::vector<int> >::iterator it = listOfBndSigma.begin(); it != listOfBndSigma.end(); ++it) + { + std::vector<int> vec = it->second; + file << "\tBndSigma_" << it->first << " = Region[{"; + + for(unsigned int i = 0; i < vec.size(); i++) + { + if(i != 0) + { + file << ", "; + } + file << vec[i]; + } + file << "}];" << std::endl; + } + file << std::endl << std::endl; + + //D + file << "\tD() = {"; + for(unsigned int i = 0; i < listOfOmega.size(); i++) + { + if(i != 0) + { + file << ", "; + } + file << i; + } + file << "};" << std::endl; + file << "\tN_DOM = #D();" << std::endl; + + //D_i + for(std::unordered_map<int, std::vector<int> >::iterator it = listOfNeighbour.begin(); it != listOfNeighbour.end(); ++it) + { + file << "\tD_" << it->first << " = {"; + for(unsigned int i = 0; i < it->second.size(); i++) + { + if(i != 0) + { + file << ", "; + } + file << it->second[i]; + } + file << "};" << std::endl; + } + + + file << "}" << std::endl << std::endl << std::endl; + //********************************************** + + + //-----------Function----------- + file << "Function {" << std::endl; + file << "\tmyD = {} ; // the domains that I'm in charge of" << std::endl; + for(unsigned int i = 0; i < listOfOmega.size(); i++) + { + file << "\tmyD_" << i << " = {};" << std::endl; + } + file << "\tListOfFields = {};" << std::endl; + file << "\tListOfConnectedFields = {};" << std::endl << std::endl; + + + file << "\tFor idom In {0:N_DOM-1}" << std::endl; + + file << "\t\tIf (idom % MPI_Size == MPI_Rank)" << std::endl; + + file << "\t\t\tmyD() += D(idom);" << std::endl; + file << "\t\t\tmyD~{idom} += D~{idom}();" << std::endl; + + file << "\t\tEndIf" << std::endl; + file << "\tEndFor" << std::endl; + + file << "\tFor ii In {0:#myD()-1}" << std::endl; + + file << "\t\ti = myD(ii);" << std::endl; + + file << "\t\tIf(#myD~{i}() == 2)" << std::endl; + file << "\t\t\tPrintf(\"We can do sweeping!\");" << std::endl; + file << "\t\tEndIf" << std::endl; + + file << "\t\tFor jj In {0:#myD~{i}()-1}" << std::endl; + file << "\t\t\tj = myD~{i}(jj);" << std::endl << std::endl; + + file << "\t\t\ttag_g~{i}~{j} = i * 1000 + j;" << std::endl; + file << "\t\t\ttag_g~{j}~{i} = j * 1000 + i;" << std::endl << std::endl; + + file << "\t\t\tListOfFields() += tag_g~{i}~{j};" << std::endl; + file << "\t\t\tListOfConnectedFields() += 1;" << std::endl; + file << "\t\t\tListOfConnectedFields() += tag_g~{j}~{i};" << std::endl; + + file << "\t\t\tIf(ANALYSIS == 0)" << std::endl; + file << "\t\t\t\tg_in~{i}~{j}[ Sigma~{i}~{j} ] = ComplexScalarField[XYZ[]]{ tag_g~{j}~{i} };" << std::endl; + file << "\t\t\tEndIf" << std::endl; + file << "\t\t\tIf(ANALYSIS == 1)" << std::endl; + file << "\t\t\t\tg_in~{i}~{j}[ Sigma~{i}~{j} ] = ComplexVectorField[XYZ[]]{ tag_g~{j}~{i} };" << std::endl; + file << "\t\t\tEndIf" << std::endl; + + file << "\t\tEndFor" << std::endl; + + file << "\tEndFor" << std::endl; + + file << "}" << std::endl; + + file.close(); +} + +std::vector<int> SEQ::getNumFromString(std::string name) +{ + std::vector<int> num; + std::string currentNum; + + for(unsigned int i = 0; i < name.size(); i++) + { + if(name[i] == '0' || name[i] == '1' || name[i] == '2'|| name[i] == '3'|| name[i] == '4'|| name[i] == '5'|| name[i] == '6'|| name[i] == '7'|| name[i] == '8'|| name[i] == '9') + { + currentNum += name[i]; + } + + if(name[i] == ',' || name[i] == '}') + { + num.push_back(stoi(currentNum)); + currentNum.clear(); + } + } + + return num; +} + +bool SEQ::communPhysicals(const std::vector<int> vec1, const std::vector<int> vec2, std::vector<int>* vecCommun) +{ + for(unsigned int i = 0; i < vec1.size(); i++) + { + for(unsigned int j = 0; j < vec2.size(); j++) + { + if(vec1[i] == vec2[j]) + { + vecCommun->push_back(vec1[i]); + } + } + } + + if(vecCommun->size() > 0) + { + return true; + } + return false; +} + + + diff --git a/Partitioning/io.h b/Partitioning/io.h new file mode 100644 index 0000000000000000000000000000000000000000..1dfa6c9319e055cf650a3e550abc917f2183070d --- /dev/null +++ b/Partitioning/io.h @@ -0,0 +1,11 @@ +#ifndef IO_INCLUDED +#define IO_INCLUDED + +namespace SEQ { + void writeModels(std::vector<GModel*> &models); + void writeProFile(GModel* m, const int npart); + std::vector<int> getNumFromString(std::string name); + bool communPhysicals(const std::vector<int> vec1, const std::vector<int> vec2, std::vector<int>* vecCommun); +} + +#endif /* IO_INCLUDED */ diff --git a/Partitioning/main.cpp b/Partitioning/main.cpp new file mode 100755 index 0000000000000000000000000000000000000000..3c943c997c7f3f0438652866f3e0a9a86a03a6b2 --- /dev/null +++ b/Partitioning/main.cpp @@ -0,0 +1,233 @@ +#include <iostream> +#include <cstdlib> +#include <string> +#include <ctime> +#include <fstream> + +#include "Gmsh.h" +#include "GModel.h" +#include "MElement.h" + +#ifdef PARALLEL + #include <mpi.h> + #include "main_mpi.h" +#else + #include "metis.h" +#endif + +#include "graph.h" +#include "topology.h" +#include "io.h" + +using namespace SEQ; + +int main(int argc, char **argv) +{ +#ifdef PARALLEL + int nbproc, myrank; + MPI_Init(&argc,&argv); + MPI_Comm_rank(MPI_COMM_WORLD, &myrank); + MPI_Comm_size(MPI_COMM_WORLD, &nbproc); + + clock_t t1, t2; + if(myrank == 0) + { + std::cout << "#############################################################################" << std::endl; + std::cout << "# #" << std::endl; + std::cout << "# # # ##### #### # # #" << std::endl; + std::cout << "# ## ## # # # # #" << std::endl; + std::cout << "# # # # #### ##### ##### #" << std::endl; + std::cout << "# # # # # # # #" << std::endl; + std::cout << "# # # ##### #### # # #" << std::endl; + std::cout << "# #" << std::endl; + std::cout << "# #" << std::endl; + std::cout << "# #### ### ##### ##### ### ##### ### ### # # ##### ##### #" << std::endl; + std::cout << "# # # # # # # # # # # # # ## # # # # #" << std::endl; + std::cout << "# #### ##### ##### # # # # # # # # # #### ##### #" << std::endl; + std::cout << "# # # # # ## # # # # # # # # # # # ## #" << std::endl; + std::cout << "# # # # # # # ### # ### ### # ## ##### # # #" << std::endl; + std::cout << "# #" << std::endl; + std::cout << "####################################################### Parallel version ####" << std::endl << std::endl; + + if(argc < 2) + { + std::cout << "Arguments missing! Syntaxe :" << std::endl; + std::cout << argv[0] << " \"mesh.msh\" \"nbrPartitions\"" << std::endl; + MPI_Finalize(); + return 0; + } + + if(atoi(argv[2]) < 1) + { + std::cout << "The number of partition must be greater than zero!" << std::endl; + MPI_Finalize(); + return 0; + } + t1 = clock(); + } + + MPI_Barrier(MPI_COMM_WORLD); + GmshInitialize(argc, argv); + main_mpi(nbproc, myrank, argv[1], atoi(argv[2])); + MPI_Barrier(MPI_COMM_WORLD); + GmshFinalize(); + + if(myrank == 0) + { + t2 = clock(); + float temps = (float)(t2-t1)/CLOCKS_PER_SEC; + + std::cout << "-> Partition done in " << temps << "seconds" << std::endl; + + std::ofstream time("time.txt", std::ofstream::app); + time << temps << std::endl; + time.close(); + } + MPI_Finalize(); +#else + std::cout << "#############################################################################" << std::endl; + std::cout << "# #" << std::endl; + std::cout << "# # # ##### #### # # #" << std::endl; + std::cout << "# ## ## # # # # #" << std::endl; + std::cout << "# # # # #### ##### ##### #" << std::endl; + std::cout << "# # # # # # # #" << std::endl; + std::cout << "# # # ##### #### # # #" << std::endl; + std::cout << "# #" << std::endl; + std::cout << "# #" << std::endl; + std::cout << "# #### ### ##### ##### ### ##### ### ### # # ##### ##### #" << std::endl; + std::cout << "# # # # # # # # # # # # # ## # # # # #" << std::endl; + std::cout << "# #### ##### ##### # # # # # # # # # #### ##### #" << std::endl; + std::cout << "# # # # # ## # # # # # # # # # # # ## #" << std::endl; + std::cout << "# # # # # # # ### # ### ### # ## ##### # # #" << std::endl; + std::cout << "# #" << std::endl; + std::cout << "#############################################################################" << std::endl << std::endl; + + if(argc < 2) + { + std::cout << "Arguments missing! Syntaxe :" << std::endl; + std::cout << argv[0] << " \"mesh.msh\" \"nbrPartitions\"" << std::endl; + return 0; + } + + if(atoi(argv[2]) < 1) + { + std::cout << "The number of partition must be greater than zero!" << std::endl; + return 0; + } + + float temps; + clock_t t1, t2; + t1 = clock(); + + GmshInitialize(argc, argv); + GModel *m = new GModel(); + std::cout << "Reading msh file... " << std::flush; + m->readMSH(argv[1]); + std::cout << "Done!" << std::endl; + + const int numElements = m->getNumMeshElements(); + const int numVertices = m->getNumMeshVertices(); + + idx_t nparts = atoi(argv[2]); + + if(nparts > 1) + { + idx_t *epart = new idx_t[numElements]; + idx_t *npart = new idx_t[numVertices]; + int* eptr = new int[numElements+1]; + int* eind = NULL; + int *metisToGmshIndex = new int[numElements]; + + std::cout << "Creating Metis structure... " << std::flush; + GModelToGraph(m, eptr, &eind, metisToGmshIndex); + std::cout << "Done!" << std::endl; + + std::cout << "Mesh partitioning... " << std::flush; + idx_t objval; + idx_t ncommon = m->getDim(); + idx_t options[METIS_NOPTIONS]; + METIS_SetDefaultOptions(options); + + const int error = METIS_PartMeshDual((idx_t*)&numElements, (idx_t*)&numVertices, (idx_t*)eptr, (idx_t*)eind, NULL, NULL, &ncommon, &nparts, NULL, options, &objval, epart, npart); + + switch(error) + { + case METIS_OK: + std::cout << "Done!" << std::endl; + break; + case METIS_ERROR_INPUT: + std::cout << "Metis error (input)!" << std::endl; + return 0; + break; + case METIS_ERROR_MEMORY: + std::cout << "Metis error (memory)!" << std::endl; + return 0; + break; + case METIS_ERROR: + std::cout << "Metis error!" << std::endl; + return 0; + break; + default: + std::cout << "Error!" << std::endl; + return 0; + break; + } + + for(unsigned int i = 0; i < numElements; i++) + { + m->getMeshElementByTag(metisToGmshIndex[i])->setPartition(epart[i]); + } + + delete[] eptr; + delete[] eind; + delete[] epart; + delete[] npart; + delete[] metisToGmshIndex; + } + + std::cout << "Creating new GModel... " << std::flush; + GModel* global = new GModel(); + std::vector<GModel*> models = createNewModels(m, global, nparts); + std::cout << "Done!" << std::endl; + + std::cout << "Assign mesh vertices to models... " << std::flush; + for (unsigned int i = 0; i < nparts; i++) + { + assignMeshVerticesToModel(models[i]); + } + assignMeshVerticesToModel(global); + std::cout << "Done!" << std::endl; + + std::cout << "Creating new elements... " << std::endl; + createPartitionBoundaries(global, models); + std::cout << "Done!" << std::endl; + + std::cout << "Writing partition meshes... " << std::flush; + writeModels(models); + std::cout << "Done!" << std::endl; + + std::cout << "Writing global mesh... " << std::flush; + global->writeMSH("global.msh", 3.0); + std::cout << "Done!" << std::endl; + + std::cout << "Writing .pro file... " << std::flush; + writeProFile(global, nparts); + std::cout << "Done!" << std::endl; + + freeModels(models, global); + + delete m; + GmshFinalize(); + + t2 = clock(); + temps = (float)(t2-t1)/CLOCKS_PER_SEC; + + std::cout << "-> Partition done in " << temps << "seconds" << std::endl; + + std::ofstream time("time.txt", std::ofstream::app); + time << temps << std::endl; + time.close(); +#endif + + return 0; +} diff --git a/Partitioning/main_mpi.cpp b/Partitioning/main_mpi.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c3b75dd73e30e48b18e4504c530f732623a0105e --- /dev/null +++ b/Partitioning/main_mpi.cpp @@ -0,0 +1,200 @@ +#include <iostream> +#include <mpi.h> + +#include "parmetis.h" +#include "Gmsh.h" +#include "GModel.h" +#include "MElement.h" + +#include "main_mpi.h" +#include "graph.h" +#include "topology.h" +#include "topology_mpi.h" +#include "io.h" + +using namespace PAR; + +int main_mpi(int nbproc, int myrank, std::string path, int nparts) +{ + GModel *m = new GModel(); + if(myrank == 0) std::cout << "Reading msh file... " << std::flush; + m->readMSH(path.c_str()); + if(myrank == 0) std::cout << "Done!" << std::endl; + + + const int numElements = m->getNumMeshElements(); + const int numVertices = m->getNumMeshVertices(); + + if(nparts > 1) + { + int *elmdist = new int[nbproc+1]; + elmdist[0] = 0; + for(unsigned int i = 1; i < nbproc; i++) + { + elmdist[i] = i*numElements/nbproc; + } + elmdist[nbproc] = numElements; + + /*for(unsigned int i = 0; i < nbproc+1; i++) + { + if(myrank == 0) std::cout << elmdist[i] << std::endl; + }*/ + + + int* eptr = new int[(elmdist[myrank+1]-elmdist[myrank])+1]; + int* eind = NULL; + int *metisToGmshIndex = new int[elmdist[myrank+1]-elmdist[myrank]]; + + if(myrank == 0) std::cout << "Creating Metis structure... " << std::flush; + const int pos = GModelToGraph(m, eptr, &eind, metisToGmshIndex, elmdist); + if(myrank == 0) std::cout << "Done!" << std::endl; + + + if(myrank == 0) std::cout << "Mesh partitioning... " << std::flush; + idx_t numflag = 0; + idx_t ncommon = m->getDim(); + idx_t *xadj = NULL; + idx_t *adjncy = NULL; + MPI_Comm comm = MPI_COMM_WORLD; + + int error = ParMETIS_V3_Mesh2Dual((idx_t*)elmdist, (idx_t*)eptr, (idx_t*)eind, &numflag, &ncommon, &xadj, &adjncy, &comm); + switch(error) + { + case METIS_OK: + break; + case METIS_ERROR: + std::cout << "[rank " << myrank << "] Metis error!" << std::endl; + MPI_Finalize(); + return 0; + break; + } + + idx_t objval; + idx_t wgtflag = 0; + idx_t ncon = 1; + real_t *tpwgts = new real_t[nparts]; + for(unsigned int i = 0; i < nparts; i++) + { + tpwgts[i] = 1./nparts; + } + real_t ubvec[1]; + ubvec[0] = 1.05; + idx_t options[3]; + options[0] = 0; + idx_t* part = new idx_t[elmdist[myrank+1]-elmdist[myrank]]; + error = ParMETIS_V3_PartKway((idx_t*)elmdist, xadj, adjncy, NULL, NULL, &wgtflag, &numflag, &ncon, (idx_t*)&nparts, tpwgts, ubvec, options, &objval, part, &comm); + + /*for(unsigned int i = 0; i < elmdist[myrank+1]-elmdist[myrank]; i++) + { + std::cout << "[rank " << myrank << "] " << part[i] << std::endl; + }*/ + + switch(error) + { + case METIS_OK: + if(myrank == 0) std::cout << "Done!" << std::endl; + break; + case METIS_ERROR: + std::cout << "[rank " << myrank << "] Metis error!" << std::endl; + MPI_Finalize(); + return 0; + break; + } + + MPI_Barrier(MPI_COMM_WORLD); + for(unsigned int i = 0; i < nbproc; i++) + { + if(i == myrank) + { + for(unsigned int j = 0; j < elmdist[myrank+1]-elmdist[myrank]; j++) + { + m->getMeshElementByTag(metisToGmshIndex[j])->setPartition(part[j]); + + for(unsigned int k = 0; k < nbproc; k++) + { + if(k != myrank) + { + //element tag + MPI_Send(&metisToGmshIndex[j], 1, MPI_INT, k, 1, MPI_COMM_WORLD); + //partition + MPI_Send(&part[j], 1, MPI_INT, k, 2, MPI_COMM_WORLD); + } + } + } + } + else + { + for(unsigned int j = 0; j < elmdist[i+1]-elmdist[i]; j++) + { + int tag = 0, numPart = 0; + MPI_Status status; + //element tag + MPI_Recv(&tag, 1, MPI_INT, i, 1, MPI_COMM_WORLD, &status); + //partition + MPI_Recv(&numPart, 1, MPI_INT, i, 2, MPI_COMM_WORLD, &status); + + m->getMeshElementByTag(tag)->setPartition(numPart); + } + } + } + + delete[] eptr; + delete[] eind; + delete[] metisToGmshIndex; + delete[] xadj; + delete[] adjncy; + delete[] tpwgts; + delete[] part; + delete[] elmdist; + } + + std::vector<int> myPart; + for(unsigned int i = 0; i < nparts; i++) + { + if((i+1)%nbproc == myrank) + { + myPart.push_back(i); + } + } + + if(myPart.size() != 0) + { + if(myrank == 0) std::cout << "Creating new GModel... " << std::flush; + GModel* global = new GModel(); + std::vector<GModel*> models = createNewModels(m, global, nparts, myPart); + if(myrank == 0) std::cout << "Done!" << std::endl; + + if(myrank == 0) std::cout << "Assign mesh vertices to models... " << std::flush; + for (unsigned int i = 0; i < myPart.size(); i++) + { + SEQ::assignMeshVerticesToModel(models[i]); + } + if(myrank == 0) SEQ::assignMeshVerticesToModel(global); + if(myrank == 0) std::cout << "Done!" << std::endl; + + if(myrank == 0) std::cout << "Creating new elements... " << std::endl; + SEQ::createPartitionBoundaries(global, models); + if(myrank == 0) std::cout << "Done!" << std::endl; + + if(myrank == 0) std::cout << "Writing partition meshes... " << std::flush; + SEQ::writeModels(models); + if(myrank == 0) std::cout << "Done!" << std::endl; + + if(myrank == 0) std::cout << "Writing global mesh... " << std::flush; + if(myrank == 0) global->writeMSH("global.msh", 3.0); + if(myrank == 0) std::cout << "Done!" << std::endl; + + if(myrank == 0) std::cout << "Writing .pro file... " << std::flush; + if(myrank == 0) SEQ::writeProFile(global, nparts); + if(myrank == 0) std::cout << "Done!" << std::endl; + + SEQ::freeModels(models, global); + } + else + { + std::cout << "[rank " << myrank << "] Unused rank because nparts is smaller than nbproc!" << std::endl; + } + + delete m; + return 0; +} diff --git a/Partitioning/main_mpi.h b/Partitioning/main_mpi.h new file mode 100644 index 0000000000000000000000000000000000000000..15da23ac2dffb59c740e7022da527d211b8ed88f --- /dev/null +++ b/Partitioning/main_mpi.h @@ -0,0 +1,8 @@ +#ifndef MAIN_MPI_INCLUDED +#define MAIN_MPI_INCLUDED + +#include <string> + +int main_mpi(int nbproc, int myrank, std::string path, int nparts); + +#endif //MAIN_MPI_INCLUDED diff --git a/Partitioning/topology.cpp b/Partitioning/topology.cpp new file mode 100644 index 0000000000000000000000000000000000000000..656d42f93921ba5ca5e28c1cdfa99c5fcf0fd48c --- /dev/null +++ b/Partitioning/topology.cpp @@ -0,0 +1,1190 @@ +#include <iostream> +#include <set> +#include <map> +#include <unordered_map> +#include <string> + +#include "MElement.h" +#include "MElementCut.h" + +#include "MTetrahedron.h" +#include "MHexahedron.h" +#include "MPrism.h" +#include "MPyramid.h" +#include "MTrihedron.h" + +#include "MTriangle.h" +#include "MQuadrangle.h" + +#include "MPoint.h" + +#include "MElementCut.h" + +#include "discreteRegion.h" +#include "discreteFace.h" +#include "discreteEdge.h" +#include "discreteVertex.h" + +#include "partitionFace.h" +#include "partitionEdge.h" +#include "partitionVertex.h" + +#include "topology.h" + +int SEQ::createPartitionBoundaries(GModel *model, std::vector<GModel*> models) +{ + unsigned int numElem[6]; + const int meshDim = model->getNumMeshElements(numElem); + + std::set<partitionFace*, Less_partitionFace> pfaces; + std::set<partitionEdge*, Less_partitionEdge> pedges; + std::set<partitionVertex*, Less_partitionVertex> pvertices; + + std::vector< std::set<partitionFace*, Less_partitionFace> > pfacesOfModels(models.size(), std::set<partitionFace*, Less_partitionFace>() ); + std::vector< std::set<partitionEdge*, Less_partitionEdge> > pedgesOfModels(models.size(), std::set<partitionEdge*, Less_partitionEdge>() ); + std::vector< std::set<partitionVertex*, Less_partitionVertex> > pverticesOfModels(models.size(), std::set<partitionVertex*, Less_partitionVertex>() ); + + std::unordered_map<MFace, std::vector<MElement*> , Hash_Face, Equal_Face> faceToElement; + std::unordered_map<MEdge, std::vector<MElement*> , Hash_Edge, Equal_Edge> edgeToElement; + std::unordered_map<MVertex*, std::vector<MElement*> > vertexToElement; + + //Create partition faces + std::cout << "\tCreate partition faces... " << std::flush; + if (meshDim == 3) + { + for(GModel::riter it = model->firstRegion(); it != model->lastRegion(); ++it) + { + fillit_(faceToElement, (*it)->tetrahedra.begin(), (*it)->tetrahedra.end()); + fillit_(faceToElement, (*it)->hexahedra.begin(), (*it)->hexahedra.end()); + fillit_(faceToElement, (*it)->prisms.begin(), (*it)->prisms.end()); + fillit_(faceToElement, (*it)->pyramids.begin(), (*it)->pyramids.end()); + fillit_(faceToElement, (*it)->trihedra.begin(), (*it)->trihedra.end()); + fillit_(faceToElement, (*it)->polyhedra.begin(), (*it)->polyhedra.end()); + } + + for(std::unordered_map<MFace, std::vector<MElement*> , Hash_Face, Equal_Face>::const_iterator it = faceToElement.begin(); it != faceToElement.end(); ++it) + { + MFace f = it->first; + std::vector<MElement*> voe = it->second; + + assignPartitionBoundary(model, f, pfaces, voe, models, pfacesOfModels); + } + } + std::cout << "Done!" << std::endl; + + //Create partition edges + std::cout << "\tCreate partition edges... " << std::flush; + if (meshDim >= 2) + { + if (meshDim == 2) + { + for(GModel::fiter it = model->firstFace(); it != model->lastFace(); ++it) + { + fillit_(edgeToElement, (*it)->triangles.begin(), (*it)->triangles.end()); + fillit_(edgeToElement, (*it)->quadrangles.begin(), (*it)->quadrangles.end()); + fillit_(edgeToElement, (*it)->polygons.begin(), (*it)->polygons.end()); + } + } + + if (meshDim == 3) + { + for(GModel::riter it = model->firstRegion(); it != model->lastRegion(); ++it) + { + fillit_(edgeToElement, (*it)->tetrahedra.begin(), (*it)->tetrahedra.end()); + fillit_(edgeToElement, (*it)->hexahedra.begin(), (*it)->hexahedra.end()); + fillit_(edgeToElement, (*it)->prisms.begin(), (*it)->prisms.end()); + fillit_(edgeToElement, (*it)->pyramids.begin(), (*it)->pyramids.end()); + fillit_(edgeToElement, (*it)->trihedra.begin(), (*it)->trihedra.end()); + fillit_(edgeToElement, (*it)->polyhedra.begin(), (*it)->polyhedra.end()); + } + } + + for(std::unordered_map<MEdge, std::vector<MElement*> , Hash_Edge, Equal_Edge>::const_iterator it = edgeToElement.begin(); it != edgeToElement.end(); ++it) + { + MEdge e = it->first; + + std::vector<MElement*> voe = it->second; + + assignPartitionBoundary(model, e, pedges, voe, pfaces, models, pedgesOfModels); + } + } + std::cout << "Done!" << std::endl; + + //Create partition vertices + std::cout << "\tCreate partition vertices... " << std::flush; + if (meshDim >= 1) + { + if (meshDim == 1) + { + for(GModel::eiter it = model->firstEdge(); it != model->lastEdge(); ++it) + { + fillit_(vertexToElement, (*it)->lines.begin(), (*it)->lines.end()); + } + } + + if (meshDim == 2) + { + for(GModel::fiter it = model->firstFace(); it != model->lastFace(); ++it) + { + fillit_(vertexToElement, (*it)->triangles.begin(), (*it)->triangles.end()); + fillit_(vertexToElement, (*it)->quadrangles.begin(), (*it)->quadrangles.end()); + fillit_(vertexToElement, (*it)->polygons.begin(), (*it)->polygons.end()); + } + } + + if (meshDim == 3) + { + for(GModel::riter it = model->firstRegion(); it != model->lastRegion(); ++it) + { + fillit_(vertexToElement, (*it)->tetrahedra.begin(), (*it)->tetrahedra.end()); + fillit_(vertexToElement, (*it)->hexahedra.begin(), (*it)->hexahedra.end()); + fillit_(vertexToElement, (*it)->prisms.begin(), (*it)->prisms.end()); + fillit_(vertexToElement, (*it)->pyramids.begin(), (*it)->pyramids.end()); + fillit_(vertexToElement, (*it)->trihedra.begin(), (*it)->trihedra.end()); + fillit_(vertexToElement, (*it)->polyhedra.begin(), (*it)->polyhedra.end()); + } + } + + for(std::unordered_map<MVertex*, std::vector<MElement*> >::const_iterator it = vertexToElement.begin(); it != vertexToElement.end(); ++it) + { + MVertex *v = it->first; + std::vector<MElement*> voe = it->second; + + assignPartitionBoundary(model, v, pvertices, voe, pedges, pfaces, models, pverticesOfModels); + } + } + std::cout << "Done!" << std::endl; + + return 0; +} + +template <class ITERATOR> +void SEQ::fillit_(std::unordered_map<MFace, std::vector<MElement*> , Hash_Face, Equal_Face> &faceToElement, ITERATOR it_beg, ITERATOR it_end) +{ + for (ITERATOR IT = it_beg; IT != it_end ; ++IT) + { + MElement *el = *IT; + for(unsigned int j = 0; j < el->getNumFaces(); j++) + { + faceToElement[el->getFace(j)].push_back(el); + } + } +} + +template <class ITERATOR> +void SEQ::fillit_(std::unordered_map<MEdge, std::vector<MElement*> , Hash_Edge, Equal_Edge> &edgeToElement, ITERATOR it_beg, ITERATOR it_end) +{ + for (ITERATOR IT = it_beg; IT != it_end; ++IT) + { + MElement *el = *IT; + for(unsigned int j = 0; j < el->getNumEdges(); j++) + { + edgeToElement[el->getEdge(j)].push_back(el); + } + } +} + +template <class ITERATOR> +void SEQ::fillit_(std::unordered_map<MVertex*, std::vector<MElement*> > &vertexToElement, ITERATOR it_beg, ITERATOR it_end) +{ + for (ITERATOR IT = it_beg; IT != it_end ; ++IT) + { + MElement *el = *IT; + for(unsigned int j = 0; j < el->getNumVertices(); j++) + { + vertexToElement[el->getVertex(j)].push_back(el); + } + } +} + +void SEQ::assignPartitionBoundary(GModel *model, MFace &me, std::set<partitionFace*, Less_partitionFace> &pfaces, std::vector<MElement*> &v, std::vector<GModel*> models, std::vector< std::set<partitionFace*, Less_partitionFace> > &pfacesOfModels) +{ + std::vector<int> v2; + v2.push_back(v[0]->getPartition()); + + for (unsigned int i = 1; i < v.size(); i++) + { + bool found = false; + for (unsigned int j = 0; j < v2.size(); j++) + { + if (v[i]->getPartition() == v2[j]) + { + found = true; + break; + } + } + + if (!found) + { + v2.push_back(v[i]->getPartition()); + } + } + + //If there is less than two partitions touching the face: stop + if (v2.size() < 2) + { + return; + } + + const int numPhysical = model->getMaxPhysicalNumber(-1)+1; + + partitionFace pf(model, 1, v2); + std::set<partitionFace*, Less_partitionFace>::iterator it = pfaces.find(&pf); + + partitionFace *ppf; + //Create the new partition entity for the global mesh + if (it == pfaces.end()) + { + //Create new entity and add them to the global model + ppf = new partitionFace(model, -(int)pfaces.size()-1, v2); + pfaces.insert(ppf); + model->add(ppf); + + //Create its new physical name + ppf->addPhysicalEntity(numPhysical); + + std::string name = "_sigma{"; + for(unsigned int j = 0; j < ppf->_partitions.size(); j++) + { + if(j > 0) + { + name += ","; + } + name += std::to_string(ppf->_partitions[j]); + } + name += "}"; + + model->setPhysicalName(name, ppf->dim(), numPhysical); + } + else + { + ppf = *it; + } + + int numFace = 0; + for(unsigned int i = 0; i < v[0]->getNumFaces(); i++) + { + const MFace e = v[0]->getFace(i); + if(e == me) + { + numFace = i; + break; + } + } + + if(me.getNumVertices() == 3) + { + std::vector<MVertex*> verts; + v[0]->getFaceVertices(numFace, verts); + + if(verts.size() == 3) + { + ppf->triangles.push_back(new MTriangle(verts)); + } + else if(verts.size() == 6) + { + ppf->triangles.push_back(new MTriangle6(verts)); + } + else + { + ppf->triangles.push_back(new MTriangleN(verts, verts[0]->getPolynomialOrder())); + } + } + else if(me.getNumVertices() == 4) + { + std::vector<MVertex*> verts; + v[0]->getFaceVertices(numFace, verts); + + if(verts.size() == 4) + { + ppf->quadrangles.push_back(new MQuadrangle(verts)); + } + else if(verts.size() == 8) + { + ppf->quadrangles.push_back(new MQuadrangle8(verts)); + } + else if(verts.size() == 9) + { + ppf->quadrangles.push_back(new MQuadrangle9(verts)); + } + else + { + ppf->quadrangles.push_back(new MQuadrangleN(verts, verts[0]->getPolynomialOrder())); + } + } + + for(unsigned int i = 0; i < v2.size(); i++) + { + partitionFace pf(model, 1, v2); + std::set<partitionFace*, Less_partitionFace>::iterator it = pfacesOfModels[v2[i]].find(&pf); + + //Create the new partition entity for partitioned meshes + partitionFace *ppf; + if (it == pfacesOfModels[v2[i]].end()) + { + //Create new entity and add them to partitioned models + ppf = new partitionFace(models[v2[i]], -(int)pfacesOfModels[v2[i]].size()-1, v2); + pfacesOfModels[v2[i]].insert(ppf); + models[v2[i]]->add(ppf); + + //Create its new physical name + ppf->addPhysicalEntity(numPhysical); + + std::string name = "_sigma{"; + for(unsigned int j = 0; j < ppf->_partitions.size(); j++) + { + if(j > 0) + { + name += ","; + } + name += std::to_string(ppf->_partitions[j]); + } + name += "}"; + + models[v2[i]]->setPhysicalName(name, ppf->dim(), numPhysical); + } + else + { + ppf = *it; + } + + int numEdge = 0; + int numElm = 0; + for(unsigned int j = 0; j < v.size(); j++) + { + if(v[j]->getPartition() == v2[i]) + { + numElm = j; + for(unsigned int k = 0; k < v[j]->getNumFaces(); k++) + { + const MFace e = v[j]->getFace(k); + if(e == me) + { + numFace = k; + break; + } + } + break; + } + } + + if(me.getNumVertices() == 3) + { + std::vector<MVertex*> verts; + v[numElm]->getFaceVertices(numFace, verts); + + if(verts.size() == 3) + { + ppf->triangles.push_back(new MTriangle(verts)); + } + else if(verts.size() == 6) + { + ppf->triangles.push_back(new MTriangle6(verts)); + } + else + { + ppf->triangles.push_back(new MTriangleN(verts, verts[0]->getPolynomialOrder())); + } + } + else if(me.getNumVertices() == 4) + { + std::vector<MVertex*> verts; + v[numElm]->getFaceVertices(numFace, verts); + + if(verts.size() == 4) + { + ppf->quadrangles.push_back(new MQuadrangle(verts)); + } + else if(verts.size() == 8) + { + ppf->quadrangles.push_back(new MQuadrangle8(verts)); + } + else if(verts.size() == 9) + { + ppf->quadrangles.push_back(new MQuadrangle9(verts)); + } + else + { + ppf->quadrangles.push_back(new MQuadrangleN(verts, verts[0]->getPolynomialOrder())); + } + } + } +} + +void SEQ::assignPartitionBoundary(GModel *model, MEdge &me, std::set<partitionEdge*, Less_partitionEdge> &pedges, std::vector<MElement*> &v, std::set<partitionFace*, Less_partitionFace> &pfaces, std::vector<GModel*> models, std::vector< std::set<partitionEdge*, Less_partitionEdge> > &pedgesOfModels) +{ + std::vector<int> v2; + v2.push_back(v[0]->getPartition()); + + for (unsigned int i = 1; i < v.size(); i++) + { + bool found = false; + for (unsigned int j = 0; j < v2.size(); j++) + { + if (v[i]->getPartition() == v2[j]) + { + found = true; + break; + } + } + + if (!found) + { + v2.push_back(v[i]->getPartition()); + } + } + + //If there is less than two partitions touching the edge: stop + if (v2.size() < 2) + { + return; + } + + partitionFace pf(model, 1, v2); + std::set<partitionFace*, Less_partitionFace>::iterator itf = pfaces.find(&pf); + + //If the edge is on a partitionFace + if (itf != pfaces.end()) + { + return; + } + + const int numPhysical = model->getMaxPhysicalNumber(-1)+1; + + partitionEdge pe(model, 1, nullptr, nullptr, v2); + std::set<partitionEdge*, Less_partitionEdge>::iterator it = pedges.find(&pe); + + partitionEdge *ppe; + //Create the new partition entity for the global mesh + if (it == pedges.end()) + { + //Create new entity and add them to the global model + ppe = new partitionEdge(model, -(int)pedges.size()-1, 0, 0, v2); + pedges.insert(ppe); + model->add(ppe); + + //Create its new physical name + ppe->addPhysicalEntity(numPhysical); + + std::string name = "_sigma{"; + for(unsigned int j = 0; j < ppe->_partitions.size(); j++) + { + if(j > 0) + { + name += ","; + } + name += std::to_string(ppe->_partitions[j]); + } + name += "}"; + + model->setPhysicalName(name, ppe->dim(), numPhysical); + } + else + { + ppe = *it; + } + + int numEdge = 0; + for(unsigned int i = 0; i < v[0]->getNumEdges(); i++) + { + const MEdge e = v[0]->getEdge(i); + if(e == me) + { + numEdge = i; + break; + } + } + + if(me.getNumVertices() == 2) + { + std::vector<MVertex*> verts; + v[0]->getEdgeVertices(numEdge, verts); + + if(verts.size() == 2) + { + ppe->lines.push_back(new MLine(verts)); + } + else if(verts.size() == 3) + { + ppe->lines.push_back(new MLine3(verts)); + } + else + { + ppe->lines.push_back(new MLineN(verts)); + } + } + + for(unsigned int i = 0; i < v2.size(); i++) + { + partitionEdge pe(models[v2[i]], 1, nullptr, nullptr, v2); + std::set<partitionEdge*, Less_partitionEdge>::iterator it = pedgesOfModels[v2[i]].find(&pe); + + //Create the new partition entity for partitioned meshes + partitionEdge *ppe; + if (it == pedgesOfModels[v2[i]].end()) + { + //Create new entity and add them to partitioned models + ppe = new partitionEdge(models[v2[i]], -(int)pedgesOfModels[v2[i]].size()-1, 0, 0, v2); + pedgesOfModels[v2[i]].insert(ppe); + models[v2[i]]->add(ppe); + + //Create its new physical name + ppe->addPhysicalEntity(numPhysical); + + std::string name = "_sigma{"; + for(unsigned int j = 0; j < ppe->_partitions.size(); j++) + { + if(j > 0) + { + name += ","; + } + name += std::to_string(ppe->_partitions[j]); + } + name += "}"; + + models[v2[i]]->setPhysicalName(name, ppe->dim(), numPhysical); + } + else + { + ppe = *it; + } + + int numEdge = 0; + int numElm = 0; + + for(unsigned int j = 0; j < v.size(); j++) + { + if(v[j]->getPartition() == v2[i]) + { + numElm = j; + for(unsigned int k = 0; k < v[j]->getNumEdges(); k++) + { + const MEdge e = v[j]->getEdge(k); + if(e == me) + { + numEdge = k; + break; + } + } + break; + } + } + + if(me.getNumVertices() == 2) + { + std::vector<MVertex*> verts; + v[numElm]->getEdgeVertices(numEdge, verts); + + if(verts.size() == 2) + { + ppe->lines.push_back(new MLine(verts)); + } + else if(verts.size() == 3) + { + ppe->lines.push_back(new MLine3(verts)); + } + else + { + ppe->lines.push_back(new MLineN(verts)); + } + } + } +} + +void SEQ::assignPartitionBoundary(GModel *model, MVertex *ve, std::set<partitionVertex*, Less_partitionVertex> &pvertices, std::vector<MElement*> &v, std::set<partitionEdge*, Less_partitionEdge> &pedges, std::set<partitionFace*, Less_partitionFace> &pfaces, std::vector<GModel*> models, std::vector< std::set<partitionVertex*, Less_partitionVertex> > &pverticesOfModels) +{ + std::vector<int> v2; + v2.push_back(v[0]->getPartition()); + + for (unsigned int i = 1; i < v.size(); i++) + { + bool found = false; + for (unsigned int j = 0; j < v2.size(); j++) + { + if (v[i]->getPartition() == v2[j]) + { + found = true; + break; + } + } + + if (!found) + { + v2.push_back(v[i]->getPartition()); + } + } + + //If there is less than two partitions touching the vertex: stop + if (v2.size() < 2) + { + return; + } + + partitionFace pf(model, 1, v2); + std::set<partitionFace*, Less_partitionFace>::iterator itf = pfaces.find(&pf); + + //If the vertex is on a partitionFace + if (itf != pfaces.end()) + { + return; + } + + partitionEdge pe(model, 1, 0, 0, v2); + std::set<partitionEdge*, Less_partitionEdge>::iterator ite = pedges.find(&pe); + + //If the vertex is on a partitionFace + if (ite != pedges.end()) + { + return; + } + + const int numPhysical = model->getMaxPhysicalNumber(-1)+1; + + partitionVertex pv(model, 1, v2); + std::set<partitionVertex*, Less_partitionVertex>::iterator it = pvertices.find(&pv); + + partitionVertex *ppv; + //Create the new partition entity for the global mesh + if (it == pvertices.end()) + { + ppv = new partitionVertex(model, -(int)pvertices.size()-1,v2); + pvertices.insert (ppv); + model->add(ppv); + + //Create its new physical name + ppv->addPhysicalEntity(numPhysical); + + std::string name = "_sigma{"; + for(unsigned int j = 0; j < ppv->_partitions.size(); j++) + { + if(j > 0) + { + name += ","; + } + name += std::to_string(ppv->_partitions[j]); + } + name += "}"; + + model->setPhysicalName(name, ppv->dim(), numPhysical); + } + else + { + ppv = *it; + } + + ppv->points.push_back(new MPoint(ve)); + + for(unsigned int i = 0; i < v2.size(); i++) + { + partitionVertex pv(model, 1, v2); + std::set<partitionVertex*, Less_partitionVertex>::iterator it = pverticesOfModels[v2[i]].find(&pv); + + partitionVertex *ppv; + //Create the new partition entity for the global mesh + if (it == pverticesOfModels[v2[i]].end()) + { + ppv = new partitionVertex(model, -(int)pverticesOfModels[v2[i]].size()-1,v2); + pverticesOfModels[v2[i]].insert (ppv); + models[v2[i]]->add(ppv); + + //Create its new physical name + ppv->addPhysicalEntity(numPhysical); + + std::string name = "_sigma{"; + for(unsigned int j = 0; j < ppv->_partitions.size(); j++) + { + if(j > 0) + { + name += ","; + } + name += std::to_string(ppv->_partitions[j]); + } + name += "}"; + + models[v2[i]]->setPhysicalName(name, ppv->dim(), numPhysical); + } + else + { + ppv = *it; + } + + ppv->points.push_back(new MPoint(ve)); + } +} + +std::vector<GModel*> SEQ::createNewModels(GModel *gModel, GModel *global, int nparts) +{ + int maxDim = -1; + std::vector<GModel*> newModels(nparts, nullptr); + + for (unsigned int i = 0; i < nparts; i++) + { + newModels[i] = new GModel(); + } + + //Loop over regions + for(GModel::riter it = gModel->firstRegion(); it != gModel->lastRegion(); ++it) + { + GRegion *r = *it; + + std::vector<GRegion *> newModelHaveRegion(nparts, nullptr); + std::vector<GRegion *> globalHaveRegion(nparts, nullptr); + + //Tetrahedra + for(unsigned int i = 0; i < r->tetrahedra.size(); i++) + { + const int partition = r->tetrahedra[i]->getPartition(); + if(!newModelHaveRegion[partition]) + { + discreteRegion *dr = new discreteRegion(newModels[partition], newModels[partition]->getNumRegions()+1); + newModels[partition]->add(dr); + newModelHaveRegion[partition] = dr; + + discreteRegion *drGlobal = new discreteRegion(global, global->getNumRegions()+1); + global->add(drGlobal); + globalHaveRegion[partition] = drGlobal; + + maxDim = 3; + addPhysical(newModels[partition], dr, gModel, r, global, drGlobal, partition, maxDim); + } + + newModelHaveRegion[partition]->tetrahedra.push_back(r->tetrahedra[i]); + globalHaveRegion[partition]->tetrahedra.push_back(r->tetrahedra[i]); + } + + + //Hexahedra + for(unsigned int i = 0; i < r->hexahedra.size(); i++) + { + const int partition = r->hexahedra[i]->getPartition(); + if(!newModelHaveRegion[partition]) + { + discreteRegion *dr = new discreteRegion(newModels[partition], newModels[partition]->getNumRegions()+1); + newModels[partition]->add(dr); + newModelHaveRegion[partition] = dr; + + discreteRegion *drGlobal = new discreteRegion(global, global->getNumRegions()+1); + global->add(drGlobal); + globalHaveRegion[partition] = drGlobal; + + maxDim = 3; + addPhysical(newModels[partition], dr, gModel, r, global, drGlobal, partition, maxDim); + } + + newModelHaveRegion[partition]->hexahedra.push_back(r->hexahedra[i]); + globalHaveRegion[partition]->hexahedra.push_back(r->hexahedra[i]); + } + + //Prisms + for(unsigned int i = 0; i < r->prisms.size(); i++) + { + const int partition = r->prisms[i]->getPartition(); + if(!newModelHaveRegion[partition]) + { + discreteRegion *dr = new discreteRegion(newModels[partition], newModels[partition]->getNumRegions()+1); + newModels[partition]->add(dr); + newModelHaveRegion[partition] = dr; + + discreteRegion *drGlobal = new discreteRegion(global, global->getNumRegions()+1); + global->add(drGlobal); + globalHaveRegion[partition] = drGlobal; + + maxDim = 3; + addPhysical(newModels[partition], dr, gModel, r, global, drGlobal, partition, maxDim); + } + + newModelHaveRegion[partition]->prisms.push_back(r->prisms[i]); + globalHaveRegion[partition]->prisms.push_back(r->prisms[i]); + } + + //Pyramids + for(unsigned int i = 0; i < r->pyramids.size(); i++) + { + const int partition = r->pyramids[i]->getPartition(); + if(!newModelHaveRegion[partition]) + { + discreteRegion *dr = new discreteRegion(newModels[partition], newModels[partition]->getNumRegions()+1); + newModels[partition]->add(dr); + newModelHaveRegion[partition] = dr; + + discreteRegion *drGlobal = new discreteRegion(global, global->getNumRegions()+1); + global->add(drGlobal); + globalHaveRegion[partition] = drGlobal; + + maxDim = 3; + addPhysical(newModels[partition], dr, gModel, r, global, drGlobal, partition, maxDim); + } + + newModelHaveRegion[partition]->pyramids.push_back(r->pyramids[i]); + globalHaveRegion[partition]->pyramids.push_back(r->pyramids[i]); + } + + //Trihedra + for(unsigned int i = 0; i < r->trihedra.size(); i++) + { + const int partition = r->trihedra[i]->getPartition(); + if(!newModelHaveRegion[partition]) + { + discreteRegion *dr = new discreteRegion(newModels[partition], newModels[partition]->getNumRegions()+1); + newModels[partition]->add(dr); + newModelHaveRegion[partition] = dr; + + discreteRegion *drGlobal = new discreteRegion(global, global->getNumRegions()+1); + global->add(drGlobal); + globalHaveRegion[partition] = drGlobal; + + maxDim = 3; + addPhysical(newModels[partition], dr, gModel, r, global, drGlobal, partition, maxDim); + } + + newModelHaveRegion[partition]->trihedra.push_back(r->trihedra[i]); + globalHaveRegion[partition]->trihedra.push_back(r->trihedra[i]); + } + + //Polyhedra + for(unsigned int i = 0; i < r->polyhedra.size(); i++) + { + const int partition = r->polyhedra[i]->getPartition(); + if(!newModelHaveRegion[partition]) + { + discreteRegion *dr = new discreteRegion(newModels[partition], newModels[partition]->getNumRegions()+1); + newModels[partition]->add(dr); + newModelHaveRegion[partition] = dr; + + discreteRegion *drGlobal = new discreteRegion(global, global->getNumRegions()+1); + global->add(drGlobal); + globalHaveRegion[partition] = drGlobal; + + maxDim = 3; + addPhysical(newModels[partition], dr, gModel, r, global, drGlobal, partition, maxDim); + } + + newModelHaveRegion[partition]->polyhedra.push_back(r->polyhedra[i]); + globalHaveRegion[partition]->polyhedra.push_back(r->polyhedra[i]); + } + } + + //Loop over faces + for(GModel::fiter it = gModel->firstFace(); it != gModel->lastFace(); ++it) + { + GFace *f = *it; + + std::vector<GFace *> newModelHaveFace(nparts, nullptr); + std::vector<GFace *> globalModelHaveFace(nparts, nullptr); + + //Triangles + for(unsigned int i = 0; i < f->triangles.size(); i++) + { + const int partition = f->triangles[i]->getPartition(); + if(!newModelHaveFace[partition]) + { + discreteFace *df = new discreteFace(newModels[partition], newModels[partition]->getNumFaces()+1); + newModels[partition]->add(df); + newModelHaveFace[partition] = df; + + discreteFace *dfGlobal = new discreteFace(global, global->getNumFaces()+1); + global->add(dfGlobal); + globalModelHaveFace[partition] = dfGlobal; + + if(maxDim == -1) + { + maxDim = 2; + } + addPhysical(newModels[partition], df, gModel, f, global, dfGlobal, partition, maxDim); + } + + newModelHaveFace[partition]->triangles.push_back(f->triangles[i]); + globalModelHaveFace[partition]->triangles.push_back(f->triangles[i]); + } + + //Quadrangles + for(unsigned int i = 0; i < f->quadrangles.size(); i++) + { + const int partition = f->quadrangles[i]->getPartition(); + if(!newModelHaveFace[partition]) + { + discreteFace *df = new discreteFace(newModels[partition], newModels[partition]->getNumFaces()+1); + newModels[partition]->add(df); + newModelHaveFace[partition] = df; + + discreteFace *dfGlobal = new discreteFace(global, global->getNumFaces()+1); + global->add(dfGlobal); + globalModelHaveFace[partition] = dfGlobal; + + if(maxDim == -1) + { + maxDim = 2; + } + addPhysical(newModels[partition], df, gModel, f, global, dfGlobal, partition, maxDim); + } + + newModelHaveFace[partition]->quadrangles.push_back(f->quadrangles[i]); + globalModelHaveFace[partition]->quadrangles.push_back(f->quadrangles[i]); + } + + //Polygons + for(unsigned int i = 0; i < f->polygons.size(); i++) + { + const int partition = f->polygons[i]->getPartition(); + if(!newModelHaveFace[partition]) + { + discreteFace *df = new discreteFace(newModels[partition], newModels[partition]->getNumFaces()+1); + newModels[partition]->add(df); + newModelHaveFace[partition] = df; + + discreteFace *dfGlobal = new discreteFace(global, global->getNumFaces()+1); + global->add(dfGlobal); + globalModelHaveFace[partition] = dfGlobal; + + if(maxDim == -1) + { + maxDim = 2; + } + addPhysical(newModels[partition], df, gModel, f, global, dfGlobal, partition, maxDim); + } + + newModelHaveFace[partition]->polygons.push_back(f->polygons[i]); + globalModelHaveFace[partition]->quadrangles.push_back(f->quadrangles[i]); + } + } + + //Loop over edges + for(GModel::eiter it = gModel->firstEdge(); it != gModel->lastEdge(); ++it) + { + GEdge *e = *it; + + std::vector<GEdge *> newModelHaveEdge(nparts, nullptr); + std::vector<GEdge *> globalModelHaveEdge(nparts, nullptr); + + //Lines + for(unsigned int i = 0; i < e->lines.size(); i++) + { + const int partition = e->lines[i]->getPartition(); + if(!newModelHaveEdge[partition]) + { + discreteEdge *de = new discreteEdge(newModels[partition], newModels[partition]->getNumEdges()+1, nullptr, nullptr); + newModels[partition]->add(de); + newModelHaveEdge[partition] = de; + + discreteEdge *deGlobal = new discreteEdge(global, global->getNumEdges()+1, nullptr, nullptr); + global->add(deGlobal); + globalModelHaveEdge[partition] = deGlobal; + + if(maxDim == -1) + { + maxDim = 1; + } + addPhysical(newModels[partition], de, gModel, e, global, deGlobal, partition, maxDim); + } + + newModelHaveEdge[partition]->lines.push_back(e->lines[i]); + globalModelHaveEdge[partition]->lines.push_back(e->lines[i]); + } + } + + //Loop over vertices + for(GModel::viter it = gModel->firstVertex(); it != gModel->lastVertex(); ++it) + { + GVertex *v = *it; + + std::vector<GVertex *> newModelHaveVertex(nparts, nullptr); + std::vector<GVertex *> globalModelHaveVertex(nparts, nullptr); + + for(unsigned int i = 0; i < v->points.size(); i++) + { + const int partition = v->points[i]->getPartition(); + if(!newModelHaveVertex[partition]) + { + discreteVertex *dv = new discreteVertex(newModels[partition], newModels[partition]->getNumVertices()+1); + newModels[partition]->add(dv); + newModelHaveVertex[partition] = dv; + + discreteVertex *dvGlobal = new discreteVertex(global, global->getNumVertices()+1); + global->add(dvGlobal); + globalModelHaveVertex[partition] = dvGlobal; + + if(maxDim == -1) + { + maxDim = 0; + } + addPhysical(newModels[partition], dv, gModel, v, global, dvGlobal, partition, maxDim); + } + + newModelHaveVertex[partition]->points.push_back(v->points[i]); + globalModelHaveVertex[partition]->points.push_back(v->points[i]); + } + } + + return newModels; +} + +void SEQ::assignMeshVerticesToModel(GModel *gModel) +{ + std::unordered_map<MVertex*, GEntity*> vertexToEntity; + + //Loop over regions + for(GModel::riter it = gModel->firstRegion(); it != gModel->lastRegion(); ++it) + { + GRegion *r = *it; + + fillVertexToEntity(vertexToEntity, r, r->tetrahedra.begin(), r->tetrahedra.end()); + fillVertexToEntity(vertexToEntity, r, r->hexahedra.begin(), r->hexahedra.end()); + fillVertexToEntity(vertexToEntity, r, r->prisms.begin(), r->prisms.end()); + fillVertexToEntity(vertexToEntity, r, r->pyramids.begin(), r->pyramids.end()); + fillVertexToEntity(vertexToEntity, r, r->trihedra.begin(), r->trihedra.end()); + fillVertexToEntity(vertexToEntity, r, r->polyhedra.begin(), r->polyhedra.end()); + } + + //Loop over faces + for(GModel::fiter it = gModel->firstFace(); it != gModel->lastFace(); ++it) + { + GFace *f = *it; + + fillVertexToEntity(vertexToEntity, f, f->triangles.begin(), f->triangles.end()); + fillVertexToEntity(vertexToEntity, f, f->quadrangles.begin(), f->quadrangles.end()); + fillVertexToEntity(vertexToEntity, f, f->polygons.begin(), f->polygons.end()); + } + + //Loop over edges + for(GModel::eiter it = gModel->firstEdge(); it != gModel->lastEdge(); ++it) + { + GEdge *e = *it; + + fillVertexToEntity(vertexToEntity, e, e->lines.begin(), e->lines.end()); + } + + //Loop over vertices + for(GModel::viter it = gModel->firstVertex(); it != gModel->lastVertex(); ++it) + { + GVertex *v = *it; + + fillVertexToEntity(vertexToEntity, v, v->points.begin(), v->points.end()); + } + + //Fill the entities + for(std::unordered_map<MVertex*, GEntity*>::iterator it = vertexToEntity.begin(); it != vertexToEntity.end(); ++it) + { + it->second->addMeshVertex(it->first); + } +} + +template <class ITERATOR> +void SEQ::fillVertexToEntity(std::unordered_map<MVertex*, GEntity*> &vertexToEntity, GEntity* entity, ITERATOR it_beg, ITERATOR it_end) +{ + for(ITERATOR it = it_beg; it != it_end; ++it) + { + const int numVertices = (*it)->getNumVertices(); + for(unsigned int j = 0; j < numVertices; j++) + { + if(vertexToEntity.find((*it)->getVertex(j)) != vertexToEntity.end()) + { + if(vertexToEntity[(*it)->getVertex(j)]->dim() > entity->dim()) + { + vertexToEntity[(*it)->getVertex(j)] = entity; + } + } + else + { + vertexToEntity[(*it)->getVertex(j)] = entity; + } + } + } +} + +void SEQ::freeModels(std::vector<GModel*> &models, GModel *global) +{ + for(unsigned int i = 0; i < models.size(); i++) + { + std::vector<GEntity*> entities; + models[i]->getEntities(entities); + + for(unsigned int j = 0; j < entities.size(); j++) + { + switch(entities[j]->dim()) + { + case 3: + models[i]->remove(static_cast<GRegion*>(entities[j])); + break; + case 2: + models[i]->remove(static_cast<GFace*>(entities[j])); + break; + case 1: + models[i]->remove(static_cast<GEdge*>(entities[j])); + break; + case 0: + models[i]->remove(static_cast<GVertex*>(entities[j])); + break; + default: + break; + } + } + } + + if(global == nullptr) return; + + std::vector<GEntity*> entities; + global->getEntities(entities); + + for(unsigned int j = 0; j < entities.size(); j++) + { + switch(entities[j]->dim()) + { + case 3: + global->remove(static_cast<GRegion*>(entities[j])); + break; + case 2: + global->remove(static_cast<GFace*>(entities[j])); + break; + case 1: + global->remove(static_cast<GEdge*>(entities[j])); + break; + case 0: + global->remove(static_cast<GVertex*>(entities[j])); + break; + default: + break; + } + } +} + +void SEQ::addPhysical(GModel *newModel, GEntity *newEntity, GModel *oldModel, GEntity *oldEntity, GModel *globalModel, GEntity *globalEntity, int partition, int maxDim) +{ + std::vector<int> oldPhysical = oldEntity->getPhysicalEntities(); + std::string name; + + if(maxDim == oldEntity->dim()) + { + name = "_omega{"; + name += std::to_string(partition); + name += "}"; + + const int number = oldModel->getMaxPhysicalNumber(-1)+1+partition; + + newModel->setPhysicalName(name, newEntity->dim(), number); + newEntity->addPhysicalEntity(number); + + globalModel->setPhysicalName(name, globalEntity->dim(), number); + globalEntity->addPhysicalEntity(number); + } + + for(unsigned int i = 0; i < oldPhysical.size(); i++) + { + name = oldModel->getPhysicalName(oldEntity->dim(), oldPhysical[i]); + + if(name[0] != '_') + { + newModel->setPhysicalName(name, newEntity->dim(), oldPhysical[i]); + newEntity->addPhysicalEntity(oldPhysical[i]); + + globalModel->setPhysicalName(name, globalEntity->dim(), oldPhysical[i]); + globalEntity->addPhysicalEntity(oldPhysical[i]); + } + } +} + + + + + + + diff --git a/Partitioning/topology.h b/Partitioning/topology.h new file mode 100644 index 0000000000000000000000000000000000000000..6bad8f7e40445c8681cad0e8d5aa6d831dd5daa6 --- /dev/null +++ b/Partitioning/topology.h @@ -0,0 +1,41 @@ +#ifndef TOPOLOGY_INCLUDED +#define TOPOLOGY_INCLUDED + +#include <unordered_map> + +#include "GModel.h" + +#include "partitionFace.h" +#include "partitionEdge.h" +#include "partitionVertex.h" + +#include "MFaceHash.h" +#include "MEdgeHash.h" + +namespace SEQ { + int createPartitionBoundaries(GModel *model, std::vector<GModel*> models); + + template <class ITERATOR> + void fillit_(std::unordered_map<MFace, std::vector<MElement*> , Hash_Face, Equal_Face> &faceToElement, ITERATOR it_beg, ITERATOR it_end); + template <class ITERATOR> + void fillit_(std::unordered_map<MEdge, std::vector<MElement*> , Hash_Edge, Equal_Edge> &edgeToElement, ITERATOR it_beg, ITERATOR it_end); + template <class ITERATOR> + void fillit_(std::unordered_map<MVertex*, std::vector<MElement*> > &vertexToElement, ITERATOR it_beg, ITERATOR it_end); + + void assignPartitionBoundary(GModel *model, MFace &me, std::set<partitionFace*, Less_partitionFace> &pfaces, std::vector<MElement*> &v, std::vector<GModel*> models, std::vector< std::set<partitionFace*, Less_partitionFace> > &pfacesOfModels); + void assignPartitionBoundary(GModel *model, MEdge &me, std::set<partitionEdge*, Less_partitionEdge> &pedges, std::vector<MElement*> &v, std::set<partitionFace*, Less_partitionFace> &pfaces, std::vector<GModel*> models, std::vector< std::set<partitionEdge*, Less_partitionEdge> > &pedgesOfModels); + void assignPartitionBoundary(GModel *model, MVertex *ve, std::set<partitionVertex*, Less_partitionVertex> &pvertices, std::vector<MElement*> &v, std::set<partitionEdge*, Less_partitionEdge> &pedges, std::set<partitionFace*, Less_partitionFace> &pfaces, std::vector<GModel*> models, std::vector< std::set<partitionVertex*, Less_partitionVertex> > &pverticesOfModels); + + std::vector<GModel*> createNewModels(GModel *gModel, GModel *global, int nparts); + + void assignMeshVerticesToModel(GModel *gModel); + template <class ITERATOR> + void fillVertexToEntity(std::unordered_map<MVertex*, GEntity*> &vertexToEntity, GEntity* entity, ITERATOR it_beg, ITERATOR it_end); + + void freeModels(std::vector<GModel*> &models, GModel *global); + + void addPhysical(GModel *newModel, GEntity *newEntity, GModel *oldModel, GEntity *oldEntity, GModel *globalModel, GEntity *globalEntity, int partition, int maxDim); +} + + +#endif //TOPOLOGY_INCLUDED diff --git a/Partitioning/topology_mpi.cpp b/Partitioning/topology_mpi.cpp new file mode 100644 index 0000000000000000000000000000000000000000..202896fa3d0f46da586ca64f35d197d271d6455a --- /dev/null +++ b/Partitioning/topology_mpi.cpp @@ -0,0 +1,509 @@ +#include <iostream> +#include <set> +#include <map> +#include <unordered_map> +#include <string> +#include <algorithm> +#include <mpi.h> + +#include "MElement.h" +#include "MElementCut.h" + +#include "MTetrahedron.h" +#include "MHexahedron.h" +#include "MPrism.h" +#include "MPyramid.h" +#include "MTrihedron.h" + +#include "MTriangle.h" +#include "MQuadrangle.h" + +#include "MPoint.h" + +#include "MElementCut.h" + +#include "discreteRegion.h" +#include "discreteFace.h" +#include "discreteEdge.h" +#include "discreteVertex.h" + +#include "partitionFace.h" +#include "partitionEdge.h" +#include "partitionVertex.h" + +#include "topology_mpi.h" +#include "topology.h" + +std::vector<GModel*> PAR::createNewModels(GModel *gModel, GModel *global, int nparts, std::vector<int> myPart) +{ + int nbproc, myrank; + MPI_Comm_rank(MPI_COMM_WORLD, &myrank); + MPI_Comm_size(MPI_COMM_WORLD, &nbproc); + + int maxDim = -1; + std::vector<GModel*> newModels(myPart.size(), nullptr); + + for (unsigned int i = 0; i < myPart.size(); i++) + { + newModels[i] = new GModel(); + } + + //Loop over regions + for(GModel::riter it = gModel->firstRegion(); it != gModel->lastRegion(); ++it) + { + GRegion *r = *it; + + std::vector<GRegion *> newModelHaveRegion(nparts, nullptr); + std::vector<GRegion *> globalHaveRegion(nparts, nullptr); + + //Tetrahedra + for(unsigned int i = 0; i < r->tetrahedra.size(); i++) + { + const int partition = r->tetrahedra[i]->getPartition(); + if(std::find(myPart.begin(), myPart.end(), partition) != myPart.end()) + { + int position = getPos(myPart, partition); + if(!newModelHaveRegion[partition]) + { + discreteRegion *dr = new discreteRegion(newModels[position], newModels[position]->getNumRegions()+1); + newModels[position]->add(dr); + newModelHaveRegion[partition] = dr; + + maxDim = 3; + addPhysical(newModels[position], dr, gModel, r, partition, maxDim); + } + + newModelHaveRegion[partition]->tetrahedra.push_back(r->tetrahedra[i]); + } + if(!globalHaveRegion[partition] && global != nullptr) + { + discreteRegion *drGlobal = new discreteRegion(global, global->getNumRegions()+1); + global->add(drGlobal); + globalHaveRegion[partition] = drGlobal; + + maxDim = 3; + addPhysical(global, drGlobal, gModel, r, partition, maxDim); + } + + if(global != nullptr) globalHaveRegion[partition]->tetrahedra.push_back(r->tetrahedra[i]); + } + + + //Hexahedra + for(unsigned int i = 0; i < r->hexahedra.size(); i++) + { + const int partition = r->hexahedra[i]->getPartition(); + if(std::find(myPart.begin(), myPart.end(), partition) != myPart.end()) + { + int position = getPos(myPart, partition); + if(!newModelHaveRegion[partition]) + { + discreteRegion *dr = new discreteRegion(newModels[position], newModels[position]->getNumRegions()+1); + newModels[position]->add(dr); + newModelHaveRegion[partition] = dr; + + maxDim = 3; + addPhysical(newModels[position], dr, gModel, r, partition, maxDim); + } + + newModelHaveRegion[partition]->hexahedra.push_back(r->hexahedra[i]); + } + if(!globalHaveRegion[partition] && global != nullptr) + { + discreteRegion *drGlobal = new discreteRegion(global, global->getNumRegions()+1); + global->add(drGlobal); + globalHaveRegion[partition] = drGlobal; + + maxDim = 3; + addPhysical(global, drGlobal, gModel, r, partition, maxDim); + } + + if(global != nullptr) globalHaveRegion[partition]->hexahedra.push_back(r->hexahedra[i]); + } + + //Prisms + for(unsigned int i = 0; i < r->prisms.size(); i++) + { + const int partition = r->prisms[i]->getPartition(); + if(std::find(myPart.begin(), myPart.end(), partition) != myPart.end()) + { + int position = getPos(myPart, partition); + if(!newModelHaveRegion[partition]) + { + discreteRegion *dr = new discreteRegion(newModels[position], newModels[position]->getNumRegions()+1); + newModels[position]->add(dr); + newModelHaveRegion[partition] = dr; + + maxDim = 3; + addPhysical(newModels[position], dr, gModel, r, partition, maxDim); + } + + newModelHaveRegion[partition]->prisms.push_back(r->prisms[i]); + } + if(!globalHaveRegion[partition] && global != nullptr) + { + discreteRegion *drGlobal = new discreteRegion(global, global->getNumRegions()+1); + global->add(drGlobal); + globalHaveRegion[partition] = drGlobal; + + maxDim = 3; + addPhysical(global, drGlobal, gModel, r, partition, maxDim); + } + + if(global != nullptr) globalHaveRegion[partition]->prisms.push_back(r->prisms[i]); + } + + //Pyramids + for(unsigned int i = 0; i < r->pyramids.size(); i++) + { + const int partition = r->pyramids[i]->getPartition(); + if(std::find(myPart.begin(), myPart.end(), partition) != myPart.end()) + { + int position = getPos(myPart, partition); + if(!newModelHaveRegion[partition]) + { + discreteRegion *dr = new discreteRegion(newModels[position], newModels[position]->getNumRegions()+1); + newModels[position]->add(dr); + newModelHaveRegion[partition] = dr; + + maxDim = 3; + addPhysical(newModels[position], dr, gModel, r, partition, maxDim); + } + + newModelHaveRegion[partition]->pyramids.push_back(r->pyramids[i]); + } + if(!globalHaveRegion[partition] && global != nullptr) + { + discreteRegion *drGlobal = new discreteRegion(global, global->getNumRegions()+1); + global->add(drGlobal); + globalHaveRegion[partition] = drGlobal; + + maxDim = 3; + addPhysical(global, drGlobal, gModel, r, partition, maxDim); + } + + if(global != nullptr) globalHaveRegion[partition]->pyramids.push_back(r->pyramids[i]); + } + + //Trihedra + for(unsigned int i = 0; i < r->trihedra.size(); i++) + { + const int partition = r->trihedra[i]->getPartition(); + if(std::find(myPart.begin(), myPart.end(), partition) != myPart.end()) + { + int position = getPos(myPart, partition); + if(!newModelHaveRegion[partition]) + { + discreteRegion *dr = new discreteRegion(newModels[position], newModels[position]->getNumRegions()+1); + newModels[position]->add(dr); + newModelHaveRegion[partition] = dr; + + maxDim = 3; + addPhysical(newModels[position], dr, gModel, r, partition, maxDim); + } + + newModelHaveRegion[partition]->trihedra.push_back(r->trihedra[i]); + } + if(!globalHaveRegion[partition] && global != nullptr) + { + discreteRegion *drGlobal = new discreteRegion(global, global->getNumRegions()+1); + global->add(drGlobal); + globalHaveRegion[partition] = drGlobal; + + maxDim = 3; + addPhysical(global, drGlobal, gModel, r, partition, maxDim); + } + + if(global != nullptr) globalHaveRegion[partition]->trihedra.push_back(r->trihedra[i]); + } + + //Polyhedra + for(unsigned int i = 0; i < r->polyhedra.size(); i++) + { + const int partition = r->polyhedra[i]->getPartition(); + if(std::find(myPart.begin(), myPart.end(), partition) != myPart.end()) + { + int position = getPos(myPart, partition); + if(!newModelHaveRegion[partition]) + { + discreteRegion *dr = new discreteRegion(newModels[position], newModels[position]->getNumRegions()+1); + newModels[position]->add(dr); + newModelHaveRegion[partition] = dr; + + maxDim = 3; + addPhysical(newModels[position], dr, gModel, r, partition, maxDim); + } + + newModelHaveRegion[partition]->polyhedra.push_back(r->polyhedra[i]); + } + if(!globalHaveRegion[partition] && global != nullptr) + { + discreteRegion *drGlobal = new discreteRegion(global, global->getNumRegions()+1); + global->add(drGlobal); + globalHaveRegion[partition] = drGlobal; + + maxDim = 3; + addPhysical(global, drGlobal, gModel, r, partition, maxDim); + } + + if(global != nullptr) globalHaveRegion[partition]->polyhedra.push_back(r->polyhedra[i]); + } + } + + //Loop over faces + for(GModel::fiter it = gModel->firstFace(); it != gModel->lastFace(); ++it) + { + GFace *f = *it; + + std::vector<GFace *> newModelHaveFace(nparts, nullptr); + std::vector<GFace *> globalHaveFace(nparts, nullptr); + + //Triangles + for(unsigned int i = 0; i < f->triangles.size(); i++) + { + const int partition = f->triangles[i]->getPartition(); + if(std::find(myPart.begin(), myPart.end(), partition) != myPart.end()) + { + int position = getPos(myPart, partition); + if(!newModelHaveFace[partition]) + { + discreteFace *df = new discreteFace(newModels[position], newModels[position]->getNumFaces()+1); + newModels[position]->add(df); + newModelHaveFace[partition] = df; + + if(maxDim == -1) + { + maxDim = 2; + } + addPhysical(newModels[position], df, gModel, f, partition, maxDim); + } + + newModelHaveFace[partition]->triangles.push_back(f->triangles[i]); + } + if(!globalHaveFace[partition] && global != nullptr) + { + discreteFace *dfGlobal = new discreteFace(global, global->getNumFaces()+1); + global->add(dfGlobal); + globalHaveFace[partition] = dfGlobal; + + if(maxDim == -1) + { + maxDim = 2; + } + addPhysical(global, dfGlobal, gModel, f, partition, maxDim); + } + + if(global != nullptr) globalHaveFace[partition]->triangles.push_back(f->triangles[i]); + } + + //Quadrangles + for(unsigned int i = 0; i < f->quadrangles.size(); i++) + { + const int partition = f->quadrangles[i]->getPartition(); + if(std::find(myPart.begin(), myPart.end(), partition) != myPart.end()) + { + int position = getPos(myPart, partition); + if(!newModelHaveFace[partition]) + { + discreteFace *df = new discreteFace(newModels[position], newModels[position]->getNumFaces()+1); + newModels[position]->add(df); + newModelHaveFace[partition] = df; + + if(maxDim == -1) + { + maxDim = 2; + } + addPhysical(newModels[position], df, gModel, f, partition, maxDim); + } + + newModelHaveFace[partition]->quadrangles.push_back(f->quadrangles[i]); + } + if(!globalHaveFace[partition] && global != nullptr) + { + discreteFace *dfGlobal = new discreteFace(global, global->getNumFaces()+1); + global->add(dfGlobal); + globalHaveFace[partition] = dfGlobal; + + if(maxDim == -1) + { + maxDim = 2; + } + addPhysical(global, dfGlobal, gModel, f, partition, maxDim); + } + + if(global != nullptr) globalHaveFace[partition]->quadrangles.push_back(f->quadrangles[i]); + } + + //Polygons + for(unsigned int i = 0; i < f->polygons.size(); i++) + { + const int partition = f->polygons[i]->getPartition(); + if(std::find(myPart.begin(), myPart.end(), partition) != myPart.end()) + { + int position = getPos(myPart, partition); + if(!newModelHaveFace[partition]) + { + discreteFace *df = new discreteFace(newModels[position], newModels[position]->getNumFaces()+1); + newModels[position]->add(df); + newModelHaveFace[partition] = df; + + if(maxDim == -1) + { + maxDim = 2; + } + addPhysical(newModels[position], df, gModel, f, partition, maxDim); + } + + newModelHaveFace[partition]->polygons.push_back(f->polygons[i]); + } + if(!globalHaveFace[partition] && global != nullptr) + { + discreteFace *dfGlobal = new discreteFace(global, global->getNumFaces()+1); + global->add(dfGlobal); + globalHaveFace[partition] = dfGlobal; + + if(maxDim == -1) + { + maxDim = 2; + } + addPhysical(global, dfGlobal, gModel, f, partition, maxDim); + } + + if(global != nullptr) globalHaveFace[partition]->polygons.push_back(f->polygons[i]); + } + } + + //Loop over edges + for(GModel::eiter it = gModel->firstEdge(); it != gModel->lastEdge(); ++it) + { + GEdge *e = *it; + + std::vector<GEdge *> newModelHaveEdge(nparts, nullptr); + std::vector<GEdge *> globalHaveEdge(nparts, nullptr); + + //Lines + for(unsigned int i = 0; i < e->lines.size(); i++) + { + const int partition = e->lines[i]->getPartition(); + if(std::find(myPart.begin(), myPart.end(), partition) != myPart.end()) + { + int position = getPos(myPart, partition); + if(!newModelHaveEdge[partition]) + { + discreteEdge *de = new discreteEdge(newModels[position], newModels[position]->getNumEdges()+1, nullptr, nullptr); + newModels[position]->add(de); + newModelHaveEdge[partition] = de; + + if(maxDim == -1) + { + maxDim = 1; + } + addPhysical(newModels[position], de, gModel, e, partition, maxDim); + } + + newModelHaveEdge[partition]->lines.push_back(e->lines[i]); + } + if(!globalHaveEdge[partition] && global != nullptr) + { + discreteEdge *deGlobal = new discreteEdge(global, global->getNumEdges()+1, nullptr, nullptr); + global->add(deGlobal); + globalHaveEdge[partition] = deGlobal; + + if(maxDim == -1) + { + maxDim = 1; + } + addPhysical(global, deGlobal, gModel, e, partition, maxDim); + } + + if(global != nullptr) globalHaveEdge[partition]->lines.push_back(e->lines[i]); + } + } + + //Loop over vertices + for(GModel::viter it = gModel->firstVertex(); it != gModel->lastVertex(); ++it) + { + GVertex *v = *it; + + std::vector<GVertex *> newModelHaveVertex(nparts, nullptr); + std::vector<GVertex *> globalHaveVertex(nparts, nullptr); + + for(unsigned int i = 0; i < v->points.size(); i++) + { + const int partition = v->points[i]->getPartition(); + if(std::find(myPart.begin(), myPart.end(), partition) != myPart.end()) + { + int position = getPos(myPart, partition); + if(!newModelHaveVertex[partition]) + { + discreteVertex *dv = new discreteVertex(newModels[position], newModels[position]->getNumVertices()+1); + newModels[position]->add(dv); + newModelHaveVertex[partition] = dv; + + if(maxDim == -1) + { + maxDim = 0; + } + addPhysical(newModels[position], dv, gModel, v, partition, maxDim); + } + + newModelHaveVertex[partition]->points.push_back(v->points[i]); + } + if(!globalHaveVertex[partition] && global != nullptr) + { + discreteVertex *dvGlobal = new discreteVertex(global, global->getNumVertices()+1); + global->add(dvGlobal); + globalHaveVertex[partition] = dvGlobal; + + if(maxDim == -1) + { + maxDim = 0; + } + addPhysical(global, dvGlobal, gModel, v, partition, maxDim); + } + + if(global != nullptr) globalHaveVertex[partition]->points.push_back(v->points[i]); + } + } + + return newModels; +} + +void PAR::addPhysical(GModel *newModel, GEntity *newEntity, GModel *oldModel, GEntity *oldEntity, int partition, int maxDim) +{ + std::vector<int> oldPhysical = oldEntity->getPhysicalEntities(); + std::string name; + + if(maxDim == oldEntity->dim()) + { + name = "_omega{"; + name += std::to_string(partition); + name += "}"; + + const int number = oldModel->getMaxPhysicalNumber(-1)+1+partition; + + newModel->setPhysicalName(name, newEntity->dim(), number); + newEntity->addPhysicalEntity(number); + } + + for(unsigned int i = 0; i < oldPhysical.size(); i++) + { + name = oldModel->getPhysicalName(oldEntity->dim(), oldPhysical[i]); + + if(name[0] != '_') + { + newModel->setPhysicalName(name, newEntity->dim(), oldPhysical[i]); + newEntity->addPhysicalEntity(oldPhysical[i]); + } + } +} + +int PAR::getPos(std::vector<int> myPart, int partition) +{ + for(unsigned int i = 0; i < myPart.size(); i++) + { + if(myPart[i] == partition) return i; + } + + return -1; +} diff --git a/Partitioning/topology_mpi.h b/Partitioning/topology_mpi.h new file mode 100644 index 0000000000000000000000000000000000000000..265573830ab787950b6ba4e53e4baad70876297d --- /dev/null +++ b/Partitioning/topology_mpi.h @@ -0,0 +1,21 @@ +#ifndef TOPOLOGY_MPI_INCLUDED +#define TOPOLOGY_MPI_INCLUDED + +#include <unordered_map> + +#include "GModel.h" + +#include "partitionFace.h" +#include "partitionEdge.h" +#include "partitionVertex.h" + +#include "MFaceHash.h" +#include "MEdgeHash.h" + +namespace PAR { + std::vector<GModel*> createNewModels(GModel *gModel, GModel *global, int nparts, std::vector<int> myPart); + void addPhysical(GModel *newModel, GEntity *newEntity, GModel *oldModel, GEntity *oldEntity, int partition, int maxDim); + int getPos(std::vector<int> myPart, int partition); +} + +#endif //TOPOLOGY_MPI_INCLUDED