/*! \file mesh.cpp \author Olga Abramkina \brief Definition of class CMesh. */ #include "mesh.hpp" #include //#include namespace xios { /// ////////////////////// Définitions ////////////////////// /// CMesh::CMesh(void) : nbNodesGlo(0), nbEdgesGlo(0) , node_start(0), node_count(0) , edge_start(0), edge_count(0) , nbFaces_(0), nbNodes_(0), nbEdges_(0) , nodesAreWritten(false), edgesAreWritten(false), facesAreWritten(false) , node_lon(), node_lat() , edge_lon(), edge_lat(), edge_nodes() , face_lon(), face_lat() , face_nodes() , pNodeGlobalIndex(NULL), pEdgeGlobalIndex(NULL) { } CMesh::~CMesh(void) { if (pNodeGlobalIndex != NULL) delete pNodeGlobalIndex; if (pEdgeGlobalIndex != NULL) delete pEdgeGlobalIndex; } std::map CMesh::meshList = std::map (); std::map > CMesh::domainList = std::map >(); ///--------------------------------------------------------------- /*! * \fn bool CMesh::getMesh (StdString meshName) * Returns a pointer to a mesh. If a mesh has not been created, creates it and adds its name to the list of meshes meshList. * \param [in] meshName The name of a mesh ("name" attribute of a domain). * \param [in] nvertex Number of verteces (1 for nodes, 2 for edges, 3 and up for faces). */ CMesh* CMesh::getMesh (StdString meshName, int nvertex) { CMesh::domainList[meshName].push_back(nvertex); if ( CMesh::meshList.begin() != CMesh::meshList.end() ) { for (std::map::iterator it=CMesh::meshList.begin(); it!=CMesh::meshList.end(); ++it) { if (it->first == meshName) return &meshList[meshName]; else { CMesh newMesh; CMesh::meshList.insert( make_pair(meshName, newMesh) ); return &meshList[meshName]; } } } else { CMesh newMesh; CMesh::meshList.insert( make_pair(meshName, newMesh) ); return &meshList[meshName]; } } ///---------------------------------------------------------------- size_t hashPair(size_t first, size_t second) { HashXIOS sizetHash; size_t seed = sizetHash(first) + 0x9e3779b9 ; seed ^= sizetHash(second) + 0x9e3779b9 + (seed << 6) + (seed >> 2); return seed ; } ///---------------------------------------------------------------- size_t hashPairOrdered(size_t first, size_t second) { size_t seed; HashXIOS sizetHash; if (first < second) { seed = sizetHash(first) + 0x9e3779b9 ; seed ^= sizetHash(second) + 0x9e3779b9 + (seed << 6) + (seed >> 2); } else { seed = sizetHash(second) + 0x9e3779b9 ; seed ^= sizetHash(first) + 0x9e3779b9 + (seed << 6) + (seed >> 2); } return seed ; } ///---------------------------------------------------------------- /*! * \fn size_t generateNodeIndex(vector& valList, int rank) * Generates a node index. * If the same node is generated by two processes, each process will have its own node index. * \param [in] valList Vector storing four node hashes. * \param [in] rank MPI process rank. */ size_t generateNodeIndex(vector& valList, int rank) { // Sort is needed to avoid problems for nodes with lon = 0 generated by faces in east and west semisphere vector vec = valList; sort (vec.begin(), vec.end()); size_t seed = rank ; int it = 0; for(; it != vec.size(); ++it) { seed = hashPair(seed, vec[it]); } return seed ; } ///---------------------------------------------------------------- /*! * \fn size_t generateNodeIndex(vector& valList) * Generates a node index unique for all processes. * \param [in] valList Vector storing four node hashes. */ size_t generateNodeIndex(vector& valList) { // Sort is needed to avoid problems for nodes with lon = 0 generated by faces in east and west semisphere vector vec = valList; sort (vec.begin(), vec.end()); size_t seed = vec[0] ; int it = 1; for(; it != vec.size(); ++it) { seed = hashPair(seed, vec[it]); } return seed ; } ///---------------------------------------------------------------- /*! * \fn CArray& CMesh::createHashes (const double longitude, const double latitude) * Creates two hash values for each dimension, longitude and latitude. * \param [in] longitude Node longitude in degrees. * \param [in] latitude Node latitude in degrees ranged from 0 to 360. */ vector CMesh::createHashes (const double longitude, const double latitude) { double minBoundLon = 0. ; double maxBoundLon = 360. ; double minBoundLat = -90. ; double maxBoundLat = 90. ; double prec=1e-11 ; double precLon=prec ; double precLat=prec ; double lon = longitude; double lat = latitude; if (lon > (360.- prec)) lon = 0.; size_t maxsize_t=numeric_limits::max() ; if ( (maxBoundLon-minBoundLon)/maxsize_t > precLon) precLon=(maxBoundLon-minBoundLon)/maxsize_t ; if ( (maxBoundLat-minBoundLat)/maxsize_t > precLat) precLat=(maxBoundLat-minBoundLat)/maxsize_t ; size_t iMinLon=0 ; size_t iMaxLon=(maxBoundLon-minBoundLon)/precLon ; size_t iMinLat=0 ; size_t iMaxLat=(maxBoundLat-minBoundLat)/precLat ; vector hash(4); size_t lon0,lon1,lat0,lat1 ; lon0=(lon-minBoundLon)/precLon ; if ( ((lon0+1)*precLon + lon0*precLon)/2 > lon-minBoundLon) { if (lon0==iMinLon) lon1=iMaxLon ; else lon1=lon0-1 ; } else { if (lon0==iMaxLon) lon1=iMinLon ; else lon1=lon0+1 ; } lat0=(lat-minBoundLat)/precLat ; if ( ((lat0+1)*precLat + lat0*precLat)/2 > lat-minBoundLat) { if (lat0==iMinLat) lat1=lat0 ; else lat1=lat0-1 ; } else { if (lat0==iMaxLat) lat1=lat0 ; else lat1=lat0+1 ; } hash[0] = hashPair(lon0,lat0) ; hash[1] = hashPair(lon0,lat1) ; hash[2] = hashPair(lon1,lat0) ; hash[3] = hashPair(lon1,lat1) ; return hash; } // createHashes ///---------------------------------------------------------------- std::pair make_ordered_pair(int a, int b) { if ( a < b ) return std::pair(a,b); else return std::pair(b,a); } ///---------------------------------------------------------------- /*! * \fn void CMesh::createMesh(const CArray& lonvalue, const CArray& latvalue, const CArray& bounds_lon, const CArray& bounds_lat) * Creates or updates a mesh for the three types of mesh elements: nodes, edges, and faces. * \param [in] lonvalue Array of longitudes. * \param [in] latvalue Array of latitudes. * \param [in] bounds_lon Array of boundary longitudes. Its size depends on the element type. * \param [in] bounds_lat Array of boundary latitudes. Its size depends on the element type. */ // void CMesh::createMesh(const CArray& lonvalue, const CArray& latvalue, // const CArray& bounds_lon, const CArray& bounds_lat) // { // int nvertex = (bounds_lon.numElements() == 0) ? 1 : bounds_lon.rows(); // // if (nvertex == 1) // { // nbNodes_ = lonvalue.numElements(); // node_lon.resizeAndPreserve(nbNodes_); // node_lat.resizeAndPreserve(nbNodes_); // for (int nn = 0; nn < nbNodes_; ++nn) // { // if (map_nodes.find(make_pair (lonvalue(nn), latvalue(nn))) == map_nodes.end()) // { // map_nodes[make_pair (lonvalue(nn), latvalue(nn))] = nn ; // node_lon(nn) = lonvalue(nn); // node_lat(nn) = latvalue(nn); // } // } // } // else if (nvertex == 2) // { // nbEdges_ = bounds_lon.shape()[1]; // // // Create nodes and edge_node connectivity // node_lon.resizeAndPreserve(nbEdges_*nvertex); // Max possible number of nodes // node_lat.resizeAndPreserve(nbEdges_*nvertex); // edge_nodes.resizeAndPreserve(nvertex, nbEdges_); // // for (int ne = 0; ne < nbEdges_; ++ne) // { // for (int nv = 0; nv < nvertex; ++nv) // { // if (map_nodes.find(make_pair (bounds_lon(nv, ne), bounds_lat(nv ,ne))) == map_nodes.end()) // { // map_nodes[make_pair (bounds_lon(nv, ne), bounds_lat(nv, ne))] = nbNodes_ ; // edge_nodes(nv,ne) = nbNodes_ ; // node_lon(nbNodes_) = bounds_lon(nv, ne); // node_lat(nbNodes_) = bounds_lat(nv, ne); // ++nbNodes_ ; // } // else // edge_nodes(nv,ne) = map_nodes[make_pair (bounds_lon(nv, ne), bounds_lat(nv ,ne))]; // } // } // node_lon.resizeAndPreserve(nbNodes_); // node_lat.resizeAndPreserve(nbNodes_); // // // Create edges // edge_lon.resizeAndPreserve(nbEdges_); // edge_lat.resizeAndPreserve(nbEdges_); // // for (int ne = 0; ne < nbEdges_; ++ne) // { // if (map_edges.find(make_ordered_pair (edge_nodes(0,ne), edge_nodes(1,ne))) == map_edges.end()) // { // map_edges[make_ordered_pair ( edge_nodes(0,ne), edge_nodes(1,ne) )] = ne ; // edge_lon(ne) = lonvalue(ne); // edge_lat(ne) = latvalue(ne); // } // // } // edgesAreWritten = true; // } // else // { // nbFaces_ = bounds_lon.shape()[1]; // // // Create nodes and face_node connectivity // node_lon.resizeAndPreserve(nbFaces_*nvertex); // Max possible number of nodes // node_lat.resizeAndPreserve(nbFaces_*nvertex); // face_nodes.resize(nvertex, nbFaces_); // // for (int nf = 0; nf < nbFaces_; ++nf) // { // for (int nv = 0; nv < nvertex; ++nv) // { // if (map_nodes.find(make_pair (bounds_lon(nv, nf), bounds_lat(nv ,nf))) == map_nodes.end()) // { // map_nodes[make_pair (bounds_lon(nv, nf), bounds_lat(nv, nf))] = nbNodes_ ; // face_nodes(nv,nf) = nbNodes_ ; // node_lon(nbNodes_) = bounds_lon(nv, nf); // node_lat(nbNodes_) = bounds_lat(nv ,nf); // ++nbNodes_ ; // } // else // { // face_nodes(nv,nf) = map_nodes[make_pair (bounds_lon(nv, nf), bounds_lat(nv ,nf))]; // } // } // } // node_lon.resizeAndPreserve(nbNodes_); // node_lat.resizeAndPreserve(nbNodes_); // // // Create edges and edge_nodes connectivity // edge_lon.resizeAndPreserve(nbFaces_*nvertex); // Max possible number of edges // edge_lat.resizeAndPreserve(nbFaces_*nvertex); // edge_nodes.resizeAndPreserve(2, nbFaces_*nvertex); // edge_faces.resize(2, nbFaces_*nvertex); // face_edges.resize(nvertex, nbFaces_); // face_faces.resize(nvertex, nbFaces_); // // vector countEdges(nbFaces_*nvertex); // needed in case if edges have been already generated // vector countFaces(nbFaces_); // countEdges.assign(nbFaces_*nvertex, 0); // countFaces.assign(nbFaces_, 0); // int edge; // for (int nf = 0; nf < nbFaces_; ++nf) // { // for (int nv1 = 0; nv1 < nvertex; ++nv1) // { // int nv = 0; // int nv2 = (nv1 < nvertex -1 ) ? (nv1 + 1) : (nv1 + 1 - nvertex); // cyclic rotation // if (map_edges.find(make_ordered_pair (face_nodes(nv1,nf), face_nodes(nv2,nf))) == map_edges.end()) // { // map_edges[make_ordered_pair (face_nodes(nv1,nf), face_nodes(nv2,nf))] = nbEdges_ ; // face_edges(nv1,nf) = map_edges[make_ordered_pair (face_nodes(nv1,nf), face_nodes(nv2,nf))]; // edge_faces(0,nbEdges_) = nf; // edge_faces(1,nbEdges_) = -999; // face_faces(nv1,nf) = 999999; // edge_nodes(Range::all(),nbEdges_) = face_nodes(nv1,nf), face_nodes(nv2,nf); // edge_lon(nbEdges_) = ( abs( node_lon(face_nodes(nv1,nf)) - node_lon(face_nodes(nv2,nf))) < 180.) ? // (( node_lon(face_nodes(nv1,nf)) + node_lon(face_nodes(nv2,nf))) * 0.5) : // (( node_lon(face_nodes(nv1,nf)) + node_lon(face_nodes(nv2,nf))) * 0.5 -180.); // edge_lat(nbEdges_) = ( node_lat(face_nodes(nv1,nf)) + node_lat(face_nodes(nv2,nf)) ) * 0.5; // ++nbEdges_; // } // else // { // edge = map_edges[make_ordered_pair (face_nodes(nv1,nf), face_nodes(nv2,nf))]; // face_edges(nv1,nf) = edge; // if (edgesAreWritten) // { // edge_faces(countEdges[edge], edge) = nf; // if (countEdges[edge]==0) // { // face_faces(nv1,nf) = 999999; // } // else // { // int face1 = nf; // = edge_faces(1,edge) // int face2 = edge_faces(0,edge); // face_faces(countFaces[face1], face1) = face2; // face_faces(countFaces[face2], face2) = face1; // ++(countFaces[face1]); // ++(countFaces[face2]); // } // } // else // { // edge_faces(1,edge) = nf; // int face1 = nf; // = edge_faces(1,edge) // int face2 = edge_faces(0,edge); // face_faces(countFaces[face1], face1) = face2; // face_faces(countFaces[face2], face2) = face1; // ++(countFaces[face1]); // ++(countFaces[face2]); // } // ++(countEdges[edge]); // } // } // } // edge_nodes.resizeAndPreserve(2, nbEdges_); // edge_faces.resizeAndPreserve(2, nbEdges_); // edge_lon.resizeAndPreserve(nbEdges_); // edge_lat.resizeAndPreserve(nbEdges_); // // // Create faces // face_lon.resize(nbFaces_); // face_lat.resize(nbFaces_); // face_lon = lonvalue; // face_lat = latvalue; // facesAreWritten = true; // // } // nvertex > 2 // // } // createMesh() ///---------------------------------------------------------------- /*! * \fn void CMesh::createMeshEpsilon(const CArray& lonvalue, const CArray& latvalue, const CArray& bounds_lon, const CArray& bounds_lat) * Creates or updates a mesh for the three types of mesh elements: nodes, edges, and faces. * Precision check is implemented with two hash values for each dimension, longitude and latitude. * \param [in] comm * \param [in] lonvalue Array of longitudes. * \param [in] latvalue Array of latitudes. * \param [in] bounds_lon Array of boundary longitudes. Its size depends on the element type. * \param [in] bounds_lat Array of boundary latitudes. Its size depends on the element type. */ void CMesh::createMeshEpsilon(const MPI_Comm& comm, const CArray& lonvalue, const CArray& latvalue, const CArray& bounds_lon, const CArray& bounds_lat) { int nvertex = (bounds_lon.numElements() == 0) ? 1 : bounds_lon.rows(); int mpiRank, mpiSize; MPI_Comm_rank(comm, &mpiRank); MPI_Comm_size(comm, &mpiSize); double prec = 1e-11; // used in calculations of edge_lon/lat if (nvertex == 1) { nbNodes_ = lonvalue.numElements(); node_lon.resize(nbNodes_); node_lat.resize(nbNodes_); node_lon = lonvalue; node_lat = latvalue; // Global node indexes vector hashValues(4); CClientClientDHTSizet::Index2VectorInfoTypeMap nodeHash2IdxGlo; for (size_t nn = 0; nn < nbNodes_; ++nn) { hashValues = CMesh::createHashes(lonvalue(nn), latvalue(nn)); for (size_t nh = 0; nh < 4; ++nh) { nodeHash2IdxGlo[hashValues[nh]].push_back(mpiRank*nbNodes_ + nn); } } pNodeGlobalIndex = new CClientClientDHTSizet (nodeHash2IdxGlo, comm); nodesAreWritten = true; } else if (nvertex == 2) { nbEdges_ = bounds_lon.shape()[1]; edge_lon.resize(nbEdges_); edge_lat.resize(nbEdges_); edge_lon = lonvalue; edge_lat = latvalue; edge_nodes.resize(nvertex, nbEdges_); // For determining the global edge index unsigned long nbEdgesOnProc = nbEdges_; unsigned long nbEdgesAccum; MPI_Scan(&nbEdgesOnProc, &nbEdgesAccum, 1, MPI_UNSIGNED_LONG, MPI_SUM, comm); nbEdgesAccum -= nbEdges_; CClientClientDHTSizet::Index2VectorInfoTypeMap edgeHash2IdxGlo; CClientClientDHTSizet::Index2VectorInfoTypeMap edgeHash2Idx; // Case (1): node indexes have been generated by domain "nodes" if (nodesAreWritten) { vector hashValues(4); CArray nodeHashList(nbEdges_*nvertex*4); for (int ne = 0; ne < nbEdges_; ++ne) // size_t doesn't work with CArray { for (int nv = 0; nv < nvertex; ++nv) { hashValues = CMesh::createHashes(bounds_lon(nv, ne), bounds_lat(nv, ne)); for (int nh = 0; nh < 4; ++nh) { nodeHashList((ne*nvertex + nv)*4 + nh) = hashValues[nh]; } } } // Recuperating the node global indexing and writing edge_nodes // Creating map edgeHash2IdxGlo pNodeGlobalIndex->computeIndexInfoMapping(nodeHashList); CClientClientDHTSizet::Index2VectorInfoTypeMap& nodeHash2IdxGlo = pNodeGlobalIndex->getInfoIndexMap(); CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator it; size_t nodeIdxGlo1, nodeIdxGlo2; for (int ne = 0; ne < nbEdges_; ++ne) { for (int nv = 0; nv < nvertex; ++nv) { int nh = 0; it = nodeHash2IdxGlo.find(nodeHashList((ne*nvertex + nv)*4 + nh)); // The loop below is needed in case if a hash generated by domain "edges" differs // from that generated by domain "nodes" because of possible precision issues while (it == nodeHash2IdxGlo.end()) { ++nh; it = nodeHash2IdxGlo.find(nodeHashList((ne*nvertex + nv)*4 + nh)); } edge_nodes(nv,ne) = it->second[0]; if (nv ==0) nodeIdxGlo1 = it->second[0]; else nodeIdxGlo2 = it->second[0]; } size_t edgeIdxGlo = nbEdgesAccum + ne; edgeHash2IdxGlo[ hashPairOrdered(nodeIdxGlo1, nodeIdxGlo2) ].push_back(edgeIdxGlo); } } // nodesAreWritten // Case (2): node indexes have not been generated previously else { // (2.1) Creating a list of hashes for each node and a map nodeHash2Idx > vector hashValues(4); CClientClientDHTSizet::Index2VectorInfoTypeMap nodeHash2Idx; CArray nodeHashList(nbEdges_*nvertex*4); int nbHash = 0; for (int ne = 0; ne < nbEdges_; ++ne) { for (int nv = 0; nv < nvertex; ++nv) { hashValues = CMesh::createHashes(bounds_lon(nv, ne), bounds_lat(nv, ne)); for (int nh = 0; nh < 4; ++nh) { if (nodeHash2Idx[hashValues[nh]].size() == 0) { nodeHash2Idx[hashValues[nh]].push_back(generateNodeIndex(hashValues)); nodeHash2Idx[hashValues[nh]].push_back(mpiRank); nodeHashList(nbHash) = hashValues[nh]; ++nbHash; } } } } nodeHashList.resizeAndPreserve(nbHash); // (2.2) Generating global node indexes // The ownership criterion: priority of the process of smaller index // Maps generated in this step are: // Maps generated in this step are: // nodeHash2Info = // nodeIdx2Idx = > CClientClientDHTSizet dhtNodeHash(nodeHash2Idx, comm); dhtNodeHash.computeIndexInfoMapping(nodeHashList); CClientClientDHTSizet::Index2VectorInfoTypeMap& nodeHash2Info = dhtNodeHash.getInfoIndexMap(); CClientClientDHTSizet::Index2VectorInfoTypeMap nodeIdx2Idx; CArray nodeIdxList(nbEdges_*nvertex*4); size_t nIdx = 0; for (CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator it = nodeHash2Info.begin(); it != nodeHash2Info.end(); ++it) { size_t rankMin = (it->second)[1]; size_t idx = (it->second)[0]; for (int i = 2; i < (it->second).size();) { if ( (it->second)[i+1] < rankMin) { idx = (it->second)[i]; rankMin = (it->second)[i+1]; (it->second)[i+1] = (it->second)[i-1]; } i += 2; } if (nodeIdx2Idx.count(idx) == 0) { if (mpiRank == rankMin) { nodeIdx2Idx[idx].push_back(rankMin); nodeIdx2Idx[idx].push_back(idx); } nodeIdxList(nIdx) = idx; ++nIdx; } } nodeIdxList.resizeAndPreserve(nIdx); // CDHTAutoIndexing will not give consistent node numbering for varying number of procs. => // Solution: global node indexing by hand. // Maps modified in this step: // nodeIdx2Idx = unsigned long nodeCount = nodeIdx2Idx.size(); unsigned long nodeStart, nbNodes; MPI_Scan(&nodeCount, &nodeStart, 1, MPI_UNSIGNED_LONG, MPI_SUM, comm); int nNodes = nodeStart; MPI_Bcast(&nNodes, 1, MPI_UNSIGNED_LONG, mpiSize-1, comm); nbNodesGlo = nNodes; nodeStart -= nodeCount; node_start = nodeStart; node_count = nodeCount; CClientClientDHTSizet::Index2VectorInfoTypeMap dummyMap; // just a dummy map used to ensure that each node is numbered only once size_t count = 0; for (int ne = 0; ne < nbEdges_; ++ne) { for (int nv = 0; nv < nvertex; ++nv) { vector hashValues = CMesh::createHashes(bounds_lon(nv, ne), bounds_lat(nv, ne)); size_t nodeIdx = generateNodeIndex(hashValues); CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator it = nodeIdx2Idx.find(nodeIdx); if (it != nodeIdx2Idx.end()) { if (dummyMap.count(nodeIdx) == 0) { dummyMap[nodeIdx].push_back(nodeIdx); (it->second)[1] = node_start + count; ++count; } } } } CClientClientDHTSizet dhtNodeIdx(nodeIdx2Idx, comm); dhtNodeIdx.computeIndexInfoMapping(nodeIdxList); CClientClientDHTSizet::Index2VectorInfoTypeMap& nodeIdx2IdxGlo = dhtNodeIdx.getInfoIndexMap(); // (2.3) Saving variables: node_lon, node_lat, edge_nodes // Creating map nodeHash2IdxGlo // Creating map edgeHash2IdxGlo // nbNodesGlo = dhtNodeIdxGlo.getNbIndexesGlobal(); // node_count = dhtNodeIdxGlo.getIndexCount(); // node_start = dhtNodeIdxGlo.getIndexStart(); CClientClientDHTSizet::Index2VectorInfoTypeMap nodeHash2IdxGlo; node_lon.resize(node_count); node_lat.resize(node_count); vector edgeNodes; size_t idxGlo = 0; for (int ne = 0; ne < nbEdges_; ++ne) { for (int nv = 0; nv < nvertex; ++nv) { hashValues = CMesh::createHashes(bounds_lon(nv, ne), bounds_lat(nv, ne)); size_t myIdx = generateNodeIndex(hashValues); CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator itIdx = nodeIdx2IdxGlo.find(myIdx); idxGlo = (itIdx->second)[1]; if (mpiRank == (itIdx->second)[0]) { // node_lon(idxGlo - node_start) = (bounds_lon(nv, ne) == 360.) ? (0.) : (bounds_lon(nv, ne)); node_lon(idxGlo - node_start) = bounds_lon(nv, ne); node_lat(idxGlo - node_start) = bounds_lat(nv, ne); } edge_nodes(nv,ne) = idxGlo; for (int nh = 0; nh < 4; ++nh) nodeHash2IdxGlo[hashValues[nh]].push_back(idxGlo); edgeNodes.push_back(idxGlo); } if (edgeNodes[0] != edgeNodes[1]) { size_t edgeIdxGlo = nbEdgesAccum + ne; edgeHash2IdxGlo[ hashPairOrdered(edgeNodes[0], edgeNodes[1]) ].push_back(edgeIdxGlo); } edgeNodes.clear(); } pNodeGlobalIndex = new CClientClientDHTSizet (nodeHash2IdxGlo, comm); } // !nodesAreWritten pEdgeGlobalIndex = new CClientClientDHTSizet (edgeHash2IdxGlo, comm); edgesAreWritten = true; } //nvertex = 2 else { nbFaces_ = bounds_lon.shape()[1]; face_lon.resize(nbFaces_); face_lat.resize(nbFaces_); face_lon = lonvalue; face_lat = latvalue; face_nodes.resize(nvertex, nbFaces_); face_edges.resize(nvertex, nbFaces_); // For determining the global face index unsigned long nbFacesOnProc = nbFaces_; unsigned long nbFacesAccum; MPI_Scan(&nbFacesOnProc, &nbFacesAccum, 1, MPI_UNSIGNED_LONG, MPI_SUM, comm); nbFacesAccum -= nbFaces_; // Case (1): edges have been previously generated if (edgesAreWritten) { // (1.1) Recuperating node global indexing and saving face_nodes vector hashValues(4); CArray nodeHashList(nbFaces_*nvertex*4); for (int nf = 0; nf < nbFaces_; ++nf) { for (int nv = 0; nv < nvertex; ++nv) { hashValues = CMesh::createHashes(bounds_lon(nv, nf), bounds_lat(nv, nf)); for (int nh = 0; nh < 4; ++nh) nodeHashList((nf*nvertex + nv)*4 + nh) = hashValues[nh]; } } pNodeGlobalIndex->computeIndexInfoMapping(nodeHashList); CClientClientDHTSizet::Index2VectorInfoTypeMap& nodeHash2IdxGlo = pNodeGlobalIndex->getInfoIndexMap(); CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator it1, it2; CArray edgeHashList(nbFaces_*nvertex); size_t nEdge = 0; for (int nf = 0; nf < nbFaces_; ++nf) { for (int nv1 = 0; nv1 < nvertex; ++nv1) { int nh1 = 0; int nv2 = (nv1 < nvertex -1 ) ? (nv1 + 1) : (nv1 + 1 - nvertex); // cyclic rotation it1 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv1)*4 + nh1)); while (it1 == nodeHash2IdxGlo.end()) { ++nh1; it1 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv1)*4 + nh1)); } int nh2 = 0; it2 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv2)*4 + nh2)); while (it2 == nodeHash2IdxGlo.end()) { ++nh2; it2 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv1)*4 + nh2)); } face_nodes(nv1,nf) = it1->second[0]; if (it1->second[0] != it2->second[0]) { edgeHashList(nEdge) = hashPairOrdered(it1->second[0], it2->second[0]); ++nEdge; } } } edgeHashList.resizeAndPreserve(nEdge); // (1.2) Recuperating edge global indexing and saving face_edges pEdgeGlobalIndex->computeIndexInfoMapping(edgeHashList); CClientClientDHTSizet::Index2VectorInfoTypeMap& edgeHash2IdxGlo = pEdgeGlobalIndex->getInfoIndexMap(); CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator itEdgeHash; CClientClientDHTSizet::Index2VectorInfoTypeMap edgeHash2Rank; CClientClientDHTSizet::Index2VectorInfoTypeMap edgeIdxGlo2Face; CArray edgeIdxList(nbFaces_*nvertex); size_t iIdx = 0; for (int nf = 0; nf < nbFaces_; ++nf) { for (int nv1 = 0; nv1 < nvertex; ++nv1) { int nh1 = 0; int nv2 = (nv1 < nvertex -1 ) ? (nv1 + 1) : (nv1 + 1 - nvertex); // cyclic rotation it1 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv1)*4 + nh1)); while (it1 == nodeHash2IdxGlo.end()) { ++nh1; it1 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv1)*4 + nh1)); } int nh2 = 0; it2 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv2)*4 + nh2)); while (it2 == nodeHash2IdxGlo.end()) { ++nh2; it2 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv1)*4 + nh2)); } if (it1->second[0] != it2->second[0]) { size_t faceIdxGlo = nbFacesAccum + nf; size_t edgeHash = hashPairOrdered(it1->second[0], it2->second[0]); itEdgeHash = edgeHash2IdxGlo.find(edgeHash); size_t edgeIdxGlo = itEdgeHash->second[0]; face_edges(nv1,nf) = edgeIdxGlo; if (edgeIdxGlo2Face.count(edgeIdxGlo) == 0) { edgeIdxList(iIdx) = edgeIdxGlo; ++iIdx; } edgeIdxGlo2Face[edgeIdxGlo].push_back(faceIdxGlo); edgeHash2Rank[edgeHash].push_back(mpiRank); edgeHash2Rank[edgeHash].push_back(itEdgeHash->second[0]); } else { face_edges(nv1,nf) = 999999; } } } edgeIdxList.resizeAndPreserve(iIdx); // (1.3) Saving remaining variables edge_faces and face_faces // Establishing edge ownership // The ownership criterion: priority of the process with smaller rank CClientClientDHTSizet dhtEdgeHash (edgeHash2Rank, comm); dhtEdgeHash.computeIndexInfoMapping(edgeHashList); CClientClientDHTSizet::Index2VectorInfoTypeMap& edgeHash2Info = dhtEdgeHash.getInfoIndexMap(); // edgeHash2Info = > int edgeCount = 0; for (CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator it = edgeHash2Info.begin(); it != edgeHash2Info.end(); ++it) { vector edgeInfo = it->second; if (edgeInfo[0] == mpiRank) { ++edgeCount; } } unsigned long edgeStart, nbEdges; MPI_Scan(&edgeCount, &edgeStart, 1, MPI_UNSIGNED_LONG, MPI_SUM, comm); int nEdges = edgeStart; MPI_Bcast(&nEdges, 1, MPI_UNSIGNED_LONG, mpiSize-1, comm); nbEdgesGlo = nEdges; // edges to be splitted equally between procs if ( (nbEdgesGlo % mpiSize) == 0) { edge_count = nbEdgesGlo/mpiSize; edge_start = mpiRank*edge_count; } else { if (mpiRank == (mpiSize - 1) ) { edge_count = nbEdgesGlo/mpiSize; edge_start = mpiRank*(nbEdgesGlo/mpiSize + 1); } else { edge_count = nbEdgesGlo/mpiSize + 1; edge_start = mpiRank*edge_count; } } CArray edgeIdxGloList(edge_count); for (int i = 0; i < edge_count; ++i) { edgeIdxGloList(i) = i + edge_start; } CClientClientDHTSizet dhtEdgeIdxGlo2Face (edgeIdxGlo2Face, comm); CClientClientDHTSizet dhtEdge2Face (edgeIdxGlo2Face, comm); dhtEdgeIdxGlo2Face.computeIndexInfoMapping(edgeIdxGloList); CClientClientDHTSizet::Index2VectorInfoTypeMap& edgeIdxGlo2FaceIdx = dhtEdgeIdxGlo2Face.getInfoIndexMap(); dhtEdge2Face.computeIndexInfoMapping(edgeIdxList); CClientClientDHTSizet::Index2VectorInfoTypeMap& edgeIdx2FaceIdx = dhtEdge2Face.getInfoIndexMap(); edge_faces.resize(2, edge_count); for (int i = 0; i < edge_count; ++i) { CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator it = edgeIdxGlo2FaceIdx.find(i + edge_start); int indexGlo = it->first; vector faces = it->second; int face1 = faces[0]; edge_faces(0, indexGlo - edge_start) = face1; if (faces.size() == 2) { int face2 = faces[1]; edge_faces(1, indexGlo - edge_start) = face2; } else { edge_faces(1, indexGlo - edge_start) = -999; } } size_t tmp; vector tmpVec; for (CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator it = edgeIdx2FaceIdx.begin(); it != edgeIdx2FaceIdx.end(); it++) { tmp = it->first; tmpVec = it->second; tmp++; } CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator itFace1, itFace2, itIndex; face_faces.resize(nvertex, nbFaces_); for (int nf = 0; nf < nbFaces_; ++nf) { for (int nv1 = 0; nv1 < nvertex; ++nv1) { int nh1 = 0; int nv2 = (nv1 < nvertex -1 ) ? (nv1 + 1) : (nv1 + 1 - nvertex); // cyclic rotation it1 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv1)*4 + nh1)); while (it1 == nodeHash2IdxGlo.end()) { ++nh1; it1 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv1)*4 + nh1)); } int nh2 = 0; it2 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv2)*4 + nh2)); while (it2 == nodeHash2IdxGlo.end()) { ++nh2; it2 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv1)*4 + nh2)); } if (it1->second[0] != it2->second[0]) { size_t faceIdxGlo = nbFacesAccum + nf; size_t edgeHash = hashPairOrdered(it1->second[0], it2->second[0]); itEdgeHash = edgeHash2Info.find(edgeHash); int edgeIdxGlo = (itEdgeHash->second)[1]; if ( (itEdgeHash->second)[0] == mpiRank) { itFace1 = edgeIdx2FaceIdx.find(edgeIdxGlo); int face1 = itFace1->second[0]; if (itFace1->second.size() == 1) { face_faces(nv1, nf) = 999999; } else { int face2 = itFace1->second[1]; face_faces(nv1, nf) = (faceIdxGlo == face1 ? face2 : face1); } } // edge owner else { itFace1 = edgeIdx2FaceIdx.find(edgeIdxGlo); int face1 = itFace1->second[0]; int face2 = itFace1->second[1]; face_faces(nv1, nf) = (faceIdxGlo == face1 ? face2 : face1); } // not an edge owner } // node1 != node2 else { face_faces(nv1, nf) = 999999; } } } } // edgesAreWritten // Case (2): nodes have been previously generated else if (nodesAreWritten) { // (2.1) Generating nodeHashList vector hashValues(4); CArray nodeHashList(nbFaces_*nvertex*4); for (int nf = 0; nf < nbFaces_; ++nf) { for (int nv = 0; nv < nvertex; ++nv) { hashValues = CMesh::createHashes(bounds_lon(nv, nf), bounds_lat(nv, nf)); for (int nh = 0; nh < 4; ++nh) nodeHashList((nf*nvertex + nv)*4 + nh) = hashValues[nh]; } } // (2.2) Recuperating node global indexing and saving face_nodes // Generating edgeHash2Info = > and edgeHashList pNodeGlobalIndex->computeIndexInfoMapping(nodeHashList); CClientClientDHTSizet::Index2VectorInfoTypeMap& nodeHash2IdxGlo = pNodeGlobalIndex->getInfoIndexMap(); CClientClientDHTSizet::Index2VectorInfoTypeMap edgeHash2Idx; CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator it1, it2; CArray edgeHashList(nbFaces_*nvertex); int nEdgeHash = 0; for (int nf = 0; nf < nbFaces_; ++nf) { for (int nv1 = 0; nv1 < nvertex; ++nv1) { int nh1 = 0; int nv2 = (nv1 < nvertex -1 ) ? (nv1 + 1) : (nv1 + 1 - nvertex); // cyclic rotation it1 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv1)*4 + nh1)); while (it1 == nodeHash2IdxGlo.end()) { ++nh1; it1 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv1)*4 + nh1)); } int nh2 = 0; it2 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv2)*4 + nh2)); while (it2 == nodeHash2IdxGlo.end()) { ++nh2; it2 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv1)*4 + nh2)); } face_nodes(nv1,nf) = it1->second[0]; size_t edgeHash = hashPairOrdered(it1->second[0], it2->second[0]); if (edgeHash2Idx.count(edgeHash) == 0) { edgeHash2Idx[edgeHash].push_back(edgeHash); edgeHash2Idx[edgeHash].push_back(mpiRank); edgeHashList(nEdgeHash) = edgeHash; ++nEdgeHash; } } } edgeHashList.resizeAndPreserve(nEdgeHash); // (2.3) Generating global edge indexes // The ownership criterion: priority of the process with smaller rank // Maps generated in this step are: // edgeIdx2Idx = = > // edgeIdx2IdxGlo = > CClientClientDHTSizet dhtEdgeHash(edgeHash2Idx, comm); dhtEdgeHash.computeIndexInfoMapping(edgeHashList); CClientClientDHTSizet::Index2VectorInfoTypeMap& edgeHash2Info = dhtEdgeHash.getInfoIndexMap(); // edgeHash2Info = CClientClientDHTSizet::Index2VectorInfoTypeMap edgeIdx2Idx; for (CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator it = edgeHash2Info.begin(); it != edgeHash2Info.end(); ++it) { size_t rankMin = (it->second)[1]; size_t idx = (it->second)[0]; for (int i = 2; i < (it->second).size();) { if ((it->second)[i+1] < rankMin) { rankMin = (it->second)[i+1]; idx = (it->second)[i]; (it->second)[i+1] = (it->second)[i-1]; } i += 2; } if (edgeIdx2Idx.count(idx) == 0) { if (mpiRank == rankMin) { edgeIdx2Idx[idx].push_back(rankMin); edgeIdx2Idx[idx].push_back(idx); } } } unsigned long edgeCount = edgeIdx2Idx.size(); unsigned long edgeStart, nbEdges; MPI_Scan(&edgeCount, &edgeStart, 1, MPI_UNSIGNED_LONG, MPI_SUM, comm); int nEdges = edgeStart; MPI_Bcast(&nEdges, 1, MPI_UNSIGNED_LONG, mpiSize-1, comm); nbEdgesGlo = nEdges; edgeStart -= edgeCount; edge_start = edgeStart; edge_count = edgeCount; CClientClientDHTSizet::Index2VectorInfoTypeMap dummyEdgeMap; int count = 0; for (int nf = 0; nf < nbFaces_; ++nf) { for (int nv1 = 0; nv1 < nvertex; ++nv1) { // Getting global indexes of edge's nodes int nh1 = 0; int nv2 = (nv1 < nvertex -1 ) ? (nv1 + 1) : (nv1 + 1 - nvertex); // cyclic rotation it1 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv1)*4 + nh1)); while (it1 == nodeHash2IdxGlo.end()) { ++nh1; it1 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv1)*4 + nh1)); } int nh2 = 0; it2 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv2)*4 + nh2)); while (it2 == nodeHash2IdxGlo.end()) { ++nh2; it2 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv1)*4 + nh2)); } size_t nodeIdxGlo1 = it1->second[0]; size_t nodeIdxGlo2 = it2->second[0]; if (nodeIdxGlo1 != nodeIdxGlo2) { size_t edgeIdx = hashPairOrdered(nodeIdxGlo1, nodeIdxGlo2); CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator it = edgeIdx2Idx.find(edgeIdx); if (it != edgeIdx2Idx.end()) { if (dummyEdgeMap.count(edgeIdx) == 0) { dummyEdgeMap[edgeIdx].push_back(edgeIdx); (it->second)[1] = edge_start + count; ++count; } } } } } CClientClientDHTSizet dhtEdgeIdx(edgeIdx2Idx, comm); dhtEdgeIdx.computeIndexInfoMapping(edgeHashList); CClientClientDHTSizet::Index2VectorInfoTypeMap& edgeIdx2IdxGlo = dhtEdgeIdx.getInfoIndexMap(); // (2.4) Saving variables: edge_lon, edge_lat, face_edges edge_lon.resize(edge_count); edge_lat.resize(edge_count); edge_nodes.resize(2, edge_count); face_edges.resize(nvertex, nbFaces_); CClientClientDHTSizet::Index2VectorInfoTypeMap edgeIdxGlo2Face; CArray edgeIdxGloList(nbFaces_*nvertex); size_t iIdx = 0; for (int nf = 0; nf < nbFaces_; ++nf) { for (int nv1 = 0; nv1 < nvertex; ++nv1) { // Getting global indexes of edge's nodes int nh1 = 0; int nv2 = (nv1 < nvertex -1 ) ? (nv1 + 1) : (nv1 + 1 - nvertex); // cyclic rotation it1 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv1)*4 + nh1)); while (it1 == nodeHash2IdxGlo.end()) { ++nh1; it1 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv1)*4 + nh1)); } int nh2 = 0; it2 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv2)*4 + nh2)); while (it2 == nodeHash2IdxGlo.end()) { ++nh2; it2 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv1)*4 + nh2)); } // Getting edge global index size_t nodeIdxGlo1 = it1->second[0]; size_t nodeIdxGlo2 = it2->second[0]; size_t myIdx = hashPairOrdered(nodeIdxGlo1, nodeIdxGlo2); if (nodeIdxGlo1 != nodeIdxGlo2) { CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator itIdx = edgeIdx2IdxGlo.find(myIdx); int edgeIdxGlo = (itIdx->second)[1]; size_t faceIdxGlo = nbFacesAccum + nf; if (mpiRank == (itIdx->second)[0]) { double edgeLon; double diffLon = abs(bounds_lon(nv1, nf) - bounds_lon(nv2, nf)); if (diffLon < (180.- prec)) edgeLon = ( bounds_lon(nv1, nf) + bounds_lon(nv2, nf)) * 0.5; else if (diffLon > (180.+ prec)) edgeLon = (bounds_lon(nv1, nf) + bounds_lon(nv2, nf)) * 0.5 -180.; else edgeLon = 0.; edge_lon(edgeIdxGlo - edge_start) = edgeLon; edge_lat(edgeIdxGlo - edge_start) = ( bounds_lat(nv1, nf) + bounds_lat(nv2, nf) ) * 0.5; edge_nodes(0, edgeIdxGlo - edge_start) = nodeIdxGlo1; edge_nodes(1, edgeIdxGlo - edge_start) = nodeIdxGlo2; } face_edges(nv1,nf) = edgeIdxGlo; if (edgeIdxGlo2Face.count(edgeIdxGlo) == 0) { edgeIdxGloList(iIdx) = edgeIdxGlo; ++iIdx; } edgeIdxGlo2Face[edgeIdxGlo].push_back(faceIdxGlo); } // nodeIdxGlo1 != nodeIdxGlo2 else { face_edges(nv1,nf) = 999999; } } } edgeIdxGloList.resizeAndPreserve(iIdx); // (2.5) Saving remaining variables edge_faces and face_faces edge_faces.resize(2, edge_count); face_faces.resize(nvertex, nbFaces_); CClientClientDHTSizet dhtEdge2Face (edgeIdxGlo2Face, comm); dhtEdge2Face.computeIndexInfoMapping(edgeIdxGloList); CClientClientDHTSizet::Index2VectorInfoTypeMap& edgeIdxGlo2FaceIdx = dhtEdge2Face.getInfoIndexMap(); CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator itNodeIdxGlo1, itNodeIdxGlo2; CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator itIdx; for (int nf = 0; nf < nbFaces_; ++nf) { for (int nv1 = 0; nv1 < nvertex; ++nv1) { // Getting global indexes of edge's nodes int nh1 = 0; int nv2 = (nv1 < nvertex -1 ) ? (nv1 + 1) : (nv1 + 1 - nvertex); // cyclic rotation it1 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv1)*4 + nh1)); while (it1 == nodeHash2IdxGlo.end()) { ++nh1; it1 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv1)*4 + nh1)); } int nh2 = 0; it2 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv2)*4 + nh2)); while (it2 == nodeHash2IdxGlo.end()) { ++nh2; it2 = nodeHash2IdxGlo.find(nodeHashList((nf*nvertex + nv1)*4 + nh2)); } size_t nodeIdxGlo1 = it1->second[0]; size_t nodeIdxGlo2 = it2->second[0]; size_t myIdx = hashPairOrdered(nodeIdxGlo1, nodeIdxGlo2); itIdx = edgeIdx2IdxGlo.find(myIdx); size_t faceIdxGlo = nbFacesAccum + nf; int edgeIdxGlo = (itIdx->second)[1]; if (mpiRank == (itIdx->second)[0]) { it1 = edgeIdxGlo2FaceIdx.find(edgeIdxGlo); int face1 = it1->second[0]; if (it1->second.size() == 1) { edge_faces(0, edgeIdxGlo - edge_start) = face1; edge_faces(1, edgeIdxGlo - edge_start) = -999; face_faces(nv1, nf) = 999999; } else { int face2 = it1->second[1]; edge_faces(0, edgeIdxGlo - edge_start) = face1; edge_faces(1, edgeIdxGlo - edge_start) = face2; face_faces(nv1, nf) = (faceIdxGlo == face1 ? face2 : face1); } } else { it1 = edgeIdxGlo2FaceIdx.find(edgeIdxGlo); int face1 = it1->second[0]; int face2 = it1->second[1]; face_faces(nv1, nf) = (faceIdxGlo == face1 ? face2 : face1); } } } } // nodesAreWritten // Case (3): Neither nodes nor edges have been previously generated else { // (3.1) Creating a list of hashes for each node and a map nodeHash2Idx > vector hashValues(4); CClientClientDHTSizet::Index2VectorInfoTypeMap nodeHash2Idx; CArray nodeHashList(nbFaces_*nvertex*4); size_t iHash = 0; for (int nf = 0; nf < nbFaces_; ++nf) { for (int nv = 0; nv < nvertex; ++nv) { hashValues = CMesh::createHashes(bounds_lon(nv, nf), bounds_lat(nv, nf)); // size_t nodeIndex = generateNodeIndex(hashValues, mpiRank); size_t nodeIndex = generateNodeIndex(hashValues); for (int nh = 0; nh < 4; ++nh) { if (nodeHash2Idx.count(hashValues[nh])==0) { nodeHash2Idx[hashValues[nh]].push_back(nodeIndex); nodeHash2Idx[hashValues[nh]].push_back(mpiRank); nodeHashList(iHash) = hashValues[nh]; ++iHash; } } } } nodeHashList.resizeAndPreserve(iHash); // (3.2) Generating global node indexes // The ownership criterion: priority of the process with smaller rank. // With any other criterion it is not possible to have consistent node indexing for different number of procs. // Maps generated in this step are: // nodeHash2Info = // nodeIdx2Idx = > CClientClientDHTSizet dhtNodeHash(nodeHash2Idx, comm); dhtNodeHash.computeIndexInfoMapping(nodeHashList); CClientClientDHTSizet::Index2VectorInfoTypeMap& nodeHash2Info = dhtNodeHash.getInfoIndexMap(); CClientClientDHTSizet::Index2VectorInfoTypeMap nodeIdx2Idx; CArray nodeIdxList(nbFaces_*nvertex*4); size_t nIdx = 0; for (CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator it = nodeHash2Info.begin(); it != nodeHash2Info.end(); ++it) { size_t rankMin = (it->second)[1]; size_t idx = (it->second)[0]; for (int i = 2; i < (it->second).size();) { if ( (it->second)[i+1] < rankMin) { idx = (it->second)[i]; rankMin = (it->second)[i+1]; (it->second)[i+1] = (it->second)[i-1]; } i += 2; } if (nodeIdx2Idx.count(idx) == 0) { if (mpiRank == rankMin) { nodeIdx2Idx[idx].push_back(rankMin); nodeIdx2Idx[idx].push_back(idx); } nodeIdxList(nIdx) = idx; ++nIdx; } } // CDHTAutoIndexing dhtNodeIdxGlo = CDHTAutoIndexing(nodeIdx2Idx, comm); // CDHTAutoIndexing will not give consistent node numbering for varying number of procs. => // Solution: global node indexing by hand. // Maps modified in this step: // nodeIdx2Idx = unsigned long nodeCount = nodeIdx2Idx.size(); unsigned long nodeStart, nbNodes; MPI_Scan(&nodeCount, &nodeStart, 1, MPI_UNSIGNED_LONG, MPI_SUM, comm); int nNodes = nodeStart; MPI_Bcast(&nNodes, 1, MPI_UNSIGNED_LONG, mpiSize-1, comm); nbNodesGlo = nNodes; nodeStart -= nodeCount; node_start = nodeStart; node_count = nodeCount; CClientClientDHTSizet::Index2VectorInfoTypeMap dummyMap; // just a dummy map used to ensure that each node is numbered only once size_t count = 0; for (int nf = 0; nf < nbFaces_; ++nf) { for (int nv = 0; nv < nvertex; ++nv) { vector hashValues = CMesh::createHashes(bounds_lon(nv, nf), bounds_lat(nv, nf)); size_t nodeIdx = generateNodeIndex(hashValues); CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator it = nodeIdx2Idx.find(nodeIdx); if (it != nodeIdx2Idx.end()) { if (dummyMap.count(nodeIdx) == 0) { dummyMap[nodeIdx].push_back(nodeIdx); (it->second)[1] = node_start + count; ++count; } } } } nodeIdxList.resizeAndPreserve(nIdx); CClientClientDHTSizet dhtNodeIdx(nodeIdx2Idx, comm); dhtNodeIdx.computeIndexInfoMapping(nodeIdxList); CClientClientDHTSizet::Index2VectorInfoTypeMap& nodeIdx2IdxGlo = dhtNodeIdx.getInfoIndexMap(); // (3.3) Saving node data: node_lon, node_lat, and face_nodes // Generating edgeHash2Info = > and edgeHashList // nbNodesGlo = dhtNodeIdxGlo.getNbIndexesGlobal(); // node_count = dhtNodeIdxGlo.getIndexCount(); // node_start = dhtNodeIdxGlo.getIndexStart(); node_lon.resize(node_count); node_lat.resize(node_count); size_t nodeIdxGlo1 = 0; size_t nodeIdxGlo2 = 0; CClientClientDHTSizet::Index2VectorInfoTypeMap edgeHash2Idx; CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator itNodeIdxGlo1, itNodeIdxGlo2; CArray edgeHashList(nbFaces_*nvertex); size_t nEdgeHash = 0; for (int nf = 0; nf < nbFaces_; ++nf) { for (int nv1 = 0; nv1 < nvertex; ++nv1) { int nv2 = (nv1 < nvertex -1 ) ? (nv1 + 1) : (nv1 + 1 - nvertex); // cyclic rotation vector hashValues1 = CMesh::createHashes(bounds_lon(nv1, nf), bounds_lat(nv1, nf)); vector hashValues2 = CMesh::createHashes(bounds_lon(nv2, nf), bounds_lat(nv2, nf)); size_t nodeIdx1 = generateNodeIndex(hashValues1); size_t nodeIdx2 = generateNodeIndex(hashValues2); CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator itNodeIdx1 = nodeIdx2IdxGlo.find(nodeIdx1); CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator itNodeIdx2 = nodeIdx2IdxGlo.find(nodeIdx2); size_t ownerRank = (itNodeIdx1->second)[0]; nodeIdxGlo1 = (itNodeIdx1->second)[1]; nodeIdxGlo2 = (itNodeIdx2->second)[1]; if (mpiRank == ownerRank) { node_lon(nodeIdxGlo1 - node_start) = bounds_lon(nv1, nf); node_lat(nodeIdxGlo1 - node_start) = bounds_lat(nv1, nf); } if (nodeIdxGlo1 != nodeIdxGlo2) { size_t edgeHash = hashPairOrdered(nodeIdxGlo1, nodeIdxGlo2); edgeHash2Idx[edgeHash].push_back(edgeHash); edgeHash2Idx[edgeHash].push_back(mpiRank); edgeHashList(nEdgeHash) = edgeHash; ++nEdgeHash; } face_nodes(nv1,nf) = nodeIdxGlo1; } } edgeHashList.resizeAndPreserve(nEdgeHash); // (3.4) Generating global edge indexes // Maps generated in this step are: // edgeIdx2Idx = = > // edgeIdx2IdxGlo = > CClientClientDHTSizet dhtEdgeHash(edgeHash2Idx, comm); dhtEdgeHash.computeIndexInfoMapping(edgeHashList); CClientClientDHTSizet::Index2VectorInfoTypeMap& edgeHash2Info = dhtEdgeHash.getInfoIndexMap(); // edgeHash2Info = CClientClientDHTSizet::Index2VectorInfoTypeMap edgeIdx2Idx; for (CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator it = edgeHash2Info.begin(); it != edgeHash2Info.end(); ++it) { size_t rankMin = (it->second)[1]; size_t idx = (it->second)[0]; for (int i = 2; i < (it->second).size();) { if ((it->second)[i+1] < rankMin) { rankMin = (it->second)[i+1]; idx = (it->second)[i]; (it->second)[i+1] = (it->second)[i-1]; } i += 2; } if (edgeIdx2Idx.count(idx) == 0) { if (mpiRank == rankMin) { edgeIdx2Idx[idx].push_back(rankMin); edgeIdx2Idx[idx].push_back(idx); } } } unsigned long edgeCount = edgeIdx2Idx.size(); unsigned long edgeStart, nbEdges; MPI_Scan(&edgeCount, &edgeStart, 1, MPI_UNSIGNED_LONG, MPI_SUM, comm); int nEdges = edgeStart; MPI_Bcast(&nEdges, 1, MPI_UNSIGNED_LONG, mpiSize-1, comm); nbEdgesGlo = nEdges; edgeStart -= edgeCount; edge_start = edgeStart; edge_count = edgeCount; CClientClientDHTSizet::Index2VectorInfoTypeMap dummyEdgeMap; count = 0; for (int nf = 0; nf < nbFaces_; ++nf) { for (int nv1 = 0; nv1 < nvertex; ++nv1) { int nv2 = (nv1 < nvertex -1 ) ? (nv1 + 1) : (nv1 + 1 - nvertex); // cyclic rotation vector hashValues1 = CMesh::createHashes(bounds_lon(nv1, nf), bounds_lat(nv1, nf)); vector hashValues2 = CMesh::createHashes(bounds_lon(nv2, nf), bounds_lat(nv2, nf)); size_t nodeIdx1 = generateNodeIndex(hashValues1); size_t nodeIdx2 = generateNodeIndex(hashValues2); CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator itNodeIdx1 = nodeIdx2IdxGlo.find(nodeIdx1); CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator itNodeIdx2 = nodeIdx2IdxGlo.find(nodeIdx2); nodeIdxGlo1 = (itNodeIdx1->second)[1]; nodeIdxGlo2 = (itNodeIdx2->second)[1]; if (nodeIdxGlo1 != nodeIdxGlo2) { size_t edgeIdx = hashPairOrdered(nodeIdxGlo1, nodeIdxGlo2); CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator it = edgeIdx2Idx.find(edgeIdx); if (it != edgeIdx2Idx.end()) { if (dummyEdgeMap.count(edgeIdx) == 0) { dummyEdgeMap[edgeIdx].push_back(edgeIdx); (it->second)[1] = edge_start + count; ++count; } } } } } CClientClientDHTSizet dhtEdgeIdx(edgeIdx2Idx, comm); dhtEdgeIdx.computeIndexInfoMapping(edgeHashList); CClientClientDHTSizet::Index2VectorInfoTypeMap& edgeIdx2IdxGlo = dhtEdgeIdx.getInfoIndexMap(); // (3.5) Saving variables: edge_lon, edge_lat, face_edges // Creating map edgeIdxGlo2Face // nbEdgesGlo = dhtEdgeIdxGlo.getNbIndexesGlobal(); // edge_count = dhtEdgeIdxGlo.getIndexCount(); // edge_start = dhtEdgeIdxGlo.getIndexStart(); edge_lon.resize(edge_count); edge_lat.resize(edge_count); edge_nodes.resize(2, edge_count); face_edges.resize(nvertex, nbFaces_); CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator it1, it2; CClientClientDHTSizet::Index2VectorInfoTypeMap edgeIdxGlo2Face; CArray edgeIdxGloList(nbFaces_*nvertex); size_t nEdge = 0; for (int nf = 0; nf < nbFaces_; ++nf) { for (int nv1 = 0; nv1 < nvertex; ++nv1) { // Getting global indexes of edge's nodes int nv2 = (nv1 < nvertex -1 ) ? (nv1 + 1) : (nv1 + 1 - nvertex); // cyclic rotation vector hashValues1 = CMesh::createHashes(bounds_lon(nv1, nf), bounds_lat(nv1, nf)); vector hashValues2 = CMesh::createHashes(bounds_lon(nv2, nf), bounds_lat(nv2, nf)); size_t nodeIdx1 = generateNodeIndex(hashValues1); size_t nodeIdx2 = generateNodeIndex(hashValues2); it1 = nodeIdx2IdxGlo.find(nodeIdx1); it2 = nodeIdx2IdxGlo.find(nodeIdx2); size_t nodeIdxGlo1 = (it1->second)[1]; size_t nodeIdxGlo2 = (it2->second)[1]; if (nodeIdxGlo1 != nodeIdxGlo2) { size_t myIdx = hashPairOrdered(nodeIdxGlo1, nodeIdxGlo2); CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator itIdx = edgeIdx2IdxGlo.find(myIdx); int edgeIdxGlo = (itIdx->second)[1]; size_t faceIdxGlo = nbFacesAccum + nf; if (mpiRank == (itIdx->second)[0]) { double edgeLon; double diffLon = abs(bounds_lon(nv1, nf) - bounds_lon(nv2, nf)); if (diffLon < (180.- prec)) edgeLon = ( bounds_lon(nv1, nf) + bounds_lon(nv2, nf)) * 0.5; else if (diffLon > (180.+ prec)) edgeLon = (bounds_lon(nv1, nf) + bounds_lon(nv2, nf)) * 0.5 -180.; else edgeLon = 0.; edge_lon(edgeIdxGlo - edge_start) = edgeLon; edge_lat(edgeIdxGlo-edge_start) = ( bounds_lat(nv1, nf) + bounds_lat(nv2, nf) ) * 0.5; edge_nodes(0, edgeIdxGlo - edge_start) = nodeIdxGlo1; edge_nodes(1, edgeIdxGlo - edge_start) = nodeIdxGlo2; } face_edges(nv1,nf) = edgeIdxGlo; if (edgeIdxGlo2Face.count(edgeIdxGlo) == 0) { edgeIdxGloList(nEdge) = edgeIdxGlo; ++nEdge; } edgeIdxGlo2Face[edgeIdxGlo].push_back(faceIdxGlo); } // nodeIdxGlo1 != nodeIdxGlo2 else { face_edges(nv1,nf) = 999999; } } } edgeIdxGloList.resizeAndPreserve(nEdge); // (3.6) Saving remaining variables edge_faces and face_faces edge_faces.resize(2, edge_count); face_faces.resize(nvertex, nbFaces_); CClientClientDHTSizet dhtEdge2Face (edgeIdxGlo2Face, comm); dhtEdge2Face.computeIndexInfoMapping(edgeIdxGloList); CClientClientDHTSizet::Index2VectorInfoTypeMap& edgeIdxGlo2FaceIdx = dhtEdge2Face.getInfoIndexMap(); for (int nf = 0; nf < nbFaces_; ++nf) { for (int nv1 = 0; nv1 < nvertex; ++nv1) { // Getting global indexes of edge's nodes int nv2 = (nv1 < nvertex -1 ) ? (nv1 + 1) : (nv1 + 1 - nvertex); // cyclic rotation vector hashValues1 = CMesh::createHashes(bounds_lon(nv1, nf), bounds_lat(nv1, nf)); vector hashValues2 = CMesh::createHashes(bounds_lon(nv2, nf), bounds_lat(nv2, nf)); size_t myNodeIdx1 = generateNodeIndex(hashValues1); size_t myNodeIdx2 = generateNodeIndex(hashValues2); if (myNodeIdx1 != myNodeIdx2) { it1 = nodeIdx2IdxGlo.find(myNodeIdx1); it2 = nodeIdx2IdxGlo.find(myNodeIdx2); size_t nodeIdxGlo1 = (it1->second)[1]; size_t nodeIdxGlo2 = (it2->second)[1]; size_t myIdx = hashPairOrdered(nodeIdxGlo1, nodeIdxGlo2); CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator itIdx = edgeIdx2IdxGlo.find(myIdx); int edgeIdxGlo = (itIdx->second)[1]; size_t faceIdxGlo = nbFacesAccum + nf; if (mpiRank == (itIdx->second)[0]) { it1 = edgeIdxGlo2FaceIdx.find(edgeIdxGlo); int face1 = it1->second[0]; if (it1->second.size() == 1) { edge_faces(0, edgeIdxGlo - edge_start) = face1; edge_faces(1, edgeIdxGlo - edge_start) = -999; face_faces(nv1, nf) = 999999; } else { size_t face2 = it1->second[1]; edge_faces(0, edgeIdxGlo - edge_start) = face1; edge_faces(1, edgeIdxGlo - edge_start) = face2; face_faces(nv1, nf) = (faceIdxGlo == face1 ? face2 : face1); } } else { it1 = edgeIdxGlo2FaceIdx.find(edgeIdxGlo); int face1 = it1->second[0]; int face2 = it1->second[1]; face_faces(nv1, nf) = (faceIdxGlo == face1 ? face2 : face1); } } // myNodeIdx1 != myNodeIdx2 else face_faces(nv1, nf) = 999999; } } } facesAreWritten = true; } // nvertex >= 3 } // createMeshEpsilon ///---------------------------------------------------------------- /*! * \fn void CMesh::getGloNghbFacesNodeType(const MPI_Comm& comm, const CArray& face_idx, const CArray& bounds_lon, const CArray& bounds_lat, CArray& nghbFaces) * Finds neighboring cells of a local domain for node-type of neighbors. * \param [in] comm * \param [in] face_idx Array with global indexes. * \param [in] bounds_lon Array of boundary longitudes. * \param [in] bounds_lat Array of boundary latitudes. * \param [out] nghbFaces 2D array of storing global indexes of neighboring cells and their owner procs. */ void CMesh::getGloNghbFacesNodeType(const MPI_Comm& comm, const CArray& face_idx, const CArray& bounds_lon, const CArray& bounds_lat, CArray& nghbFaces) { int nvertex = bounds_lon.rows(); int nbFaces = bounds_lon.shape()[1]; nghbFaces.resize(2, nbFaces*10); // some estimate on max number of neighbouring cells int mpiRank, mpiSize; MPI_Comm_rank(comm, &mpiRank); MPI_Comm_size(comm, &mpiSize); // (1) Generating unique node indexes // (1.1) Creating a list of hashes for each node and a map nodeHash2Idx > vector hashValues(4); CClientClientDHTSizet::Index2VectorInfoTypeMap nodeHash2Idx; CArray nodeHashList(nbFaces*nvertex*4); size_t iIdx = 0; for (int nf = 0; nf < nbFaces; ++nf) { for (int nv = 0; nv < nvertex; ++nv) { hashValues = CMesh::createHashes(bounds_lon(nv, nf), bounds_lat(nv, nf)); size_t nodeIndex = generateNodeIndex(hashValues, mpiRank); for (int nh = 0; nh < 4; ++nh) { if (nodeHash2Idx.count(hashValues[nh])==0) { nodeHash2Idx[hashValues[nh]].push_back(nodeIndex); nodeHash2Idx[hashValues[nh]].push_back(mpiRank); nodeHashList(iIdx) = hashValues[nh]; ++iIdx; } } } } nodeHashList.resizeAndPreserve(iIdx); // (1.2) Generating node indexes // The ownership criterion: priority of the process holding the smaller index // Maps generated in this step are: // nodeHash2Info = // nodeIdx2IdxMin = // idxMin is a unique node identifier CClientClientDHTSizet dhtNodeHash(nodeHash2Idx, comm); dhtNodeHash.computeIndexInfoMapping(nodeHashList); CClientClientDHTSizet::Index2VectorInfoTypeMap& nodeHash2Info = dhtNodeHash.getInfoIndexMap(); CClientClientDHTSizet::Index2VectorInfoTypeMap nodeIdx2IdxMin; for (CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator it = nodeHash2Info.begin(); it != nodeHash2Info.end(); ++it) { size_t idxMin = (it->second)[0]; size_t idx = (it->second)[0]; for (int i = 2; i < (it->second).size();) { if (mpiRank == (it->second)[i+1]) { idx = (it->second)[i]; } if ((it->second)[i] < idxMin) { idxMin = (it->second)[i]; (it->second)[i] = (it->second)[i-2]; (it->second)[i+1] = (it->second)[i-1]; } i += 2; } (it->second)[0] = idxMin; if (nodeIdx2IdxMin.count(idx) == 0) { nodeIdx2IdxMin[idx].push_back(idxMin); } } // (2) Creating maps nodeIdxMin2Face = CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator it; CClientClientDHTSizet::Index2VectorInfoTypeMap nodeIdxMin2Face; CArray nodeIdxMinList(nbFaces*nvertex*4); size_t nNode = 0; for (int nf = 0; nf < nbFaces; ++nf) { for (int nv = 0; nv < nvertex; ++nv) { vector hashValues = CMesh::createHashes(bounds_lon(nv, nf), bounds_lat(nv, nf)); size_t myNodeIdx = generateNodeIndex(hashValues, mpiRank); it = nodeIdx2IdxMin.find(myNodeIdx); size_t nodeIdxMin = (it->second)[0]; size_t faceIdx = face_idx(nf); if (nodeIdxMin2Face.count(nodeIdxMin) == 0) { nodeIdxMinList(nNode) = nodeIdxMin; ++nNode; } nodeIdxMin2Face[nodeIdxMin].push_back(faceIdx); nodeIdxMin2Face[nodeIdxMin].push_back(mpiRank); } } nodeIdxMinList.resizeAndPreserve(nNode); // (3) Face_face connectivity // nodeIdxMin2Info = CClientClientDHTSizet dhtNode2Face (nodeIdxMin2Face, comm); dhtNode2Face.computeIndexInfoMapping(nodeIdxMinList); CClientClientDHTSizet::Index2VectorInfoTypeMap& nodeIdxMin2Info = dhtNode2Face.getInfoIndexMap(); CClientClientDHTSizet::Index2VectorInfoTypeMap mapFaces; // auxiliar map int nbNghb = 0; CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator itNode; for (int nf = 0; nf < nbFaces; ++nf) { for (int nv = 0; nv < nvertex; ++nv) { vector hashValues = CMesh::createHashes(bounds_lon(nv, nf), bounds_lat(nv, nf)); size_t myNodeIdx = generateNodeIndex(hashValues, mpiRank); itNode = nodeIdx2IdxMin.find(myNodeIdx); size_t nodeIdxMin = (itNode->second)[0]; itNode = nodeIdxMin2Info.find(nodeIdxMin); for (int i = 0; i < itNode->second.size();) { size_t face = itNode->second[i]; size_t rank = itNode->second[i+1]; if (rank != mpiRank) if (mapFaces.count(face) == 0) { nghbFaces(0, nbNghb) = face; nghbFaces(1, nbNghb) = rank; ++nbNghb; mapFaces[face].push_back(face); } i += 2; } } } nghbFaces.resizeAndPreserve(2, nbNghb); } // getGloNghbFacesNodeType ///---------------------------------------------------------------- /*! * \fn void CMesh::getGloNghbFacesEdgeType(const MPI_Comm& comm, const CArray& face_idx, const CArray& bounds_lon, const CArray& bounds_lat, CArray& nghbFaces) * Finds neighboring cells of a local domain for edge-type of neighbors. * \param [in] comm * \param [in] face_idx Array with global indexes. * \param [in] bounds_lon Array of boundary longitudes. * \param [in] bounds_lat Array of boundary latitudes. * \param [out] nghbFaces 2D array of storing global indexes of neighboring cells and their owner procs. */ void CMesh::getGloNghbFacesEdgeType(const MPI_Comm& comm, const CArray& face_idx, const CArray& bounds_lon, const CArray& bounds_lat, CArray& nghbFaces) { int nvertex = bounds_lon.rows(); int nbFaces = bounds_lon.shape()[1]; nghbFaces.resize(2, nbFaces*10); // estimate of max number of neighbouring cells int mpiRank, mpiSize; MPI_Comm_rank(comm, &mpiRank); MPI_Comm_size(comm, &mpiSize); // (1) Generating unique node indexes // (1.1) Creating a list of hashes for each node and a map nodeHash2Idx > vector hashValues(4); CClientClientDHTSizet::Index2VectorInfoTypeMap nodeHash2Idx; CArray nodeHashList(nbFaces*nvertex*4); size_t iIdx = 0; for (int nf = 0; nf < nbFaces; ++nf) { for (int nv = 0; nv < nvertex; ++nv) { hashValues = CMesh::createHashes(bounds_lon(nv, nf), bounds_lat(nv, nf)); size_t nodeIndex = generateNodeIndex(hashValues, mpiRank); for (int nh = 0; nh < 4; ++nh) { if (nodeHash2Idx.count(hashValues[nh])==0) { nodeHash2Idx[hashValues[nh]].push_back(nodeIndex); nodeHash2Idx[hashValues[nh]].push_back(mpiRank); nodeHashList(iIdx) = hashValues[nh]; ++iIdx; } } } } nodeHashList.resizeAndPreserve(iIdx); // (1.2) Generating node indexes // The ownership criterion: priority of the process holding the smaller index // Maps generated in this step are: // nodeHash2Info = // nodeIdx2IdxMin = // idxMin is a unique node identifier CClientClientDHTSizet dhtNodeHash(nodeHash2Idx, comm); dhtNodeHash.computeIndexInfoMapping(nodeHashList); CClientClientDHTSizet::Index2VectorInfoTypeMap& nodeHash2Info = dhtNodeHash.getInfoIndexMap(); CClientClientDHTSizet::Index2VectorInfoTypeMap nodeIdx2IdxMin; for (CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator it = nodeHash2Info.begin(); it != nodeHash2Info.end(); ++it) { size_t idxMin = (it->second)[0]; size_t idx = (it->second)[0]; for (int i = 2; i < (it->second).size();) { if (mpiRank == (it->second)[i+1]) { idx = (it->second)[i]; } if ((it->second)[i] < idxMin) { idxMin = (it->second)[i]; (it->second)[i] = (it->second)[i-2]; (it->second)[i+1] = (it->second)[i-1]; } i += 2; } (it->second)[0] = idxMin; if (nodeIdx2IdxMin.count(idx) == 0) { nodeIdx2IdxMin[idx].push_back(idxMin); } } // (2) Creating map edgeHash2Face = , where rank1 = rank2 = ... CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator it1, it2, it; CClientClientDHTSizet::Index2VectorInfoTypeMap edgeHash2Face; CArray edgeHashList(nbFaces*nvertex); size_t nEdge = 0; for (int nf = 0; nf < nbFaces; ++nf) { for (int nv1 = 0; nv1 < nvertex; ++nv1) { // Getting indexes of edge's nodes int nv2 = (nv1 < nvertex -1 ) ? (nv1 + 1) : (nv1 + 1 - nvertex); // cyclic rotation vector hashValues1 = CMesh::createHashes(bounds_lon(nv1, nf), bounds_lat(nv1, nf)); vector hashValues2 = CMesh::createHashes(bounds_lon(nv2, nf), bounds_lat(nv2, nf)); size_t myNodeIdx1 = generateNodeIndex(hashValues1, mpiRank); size_t myNodeIdx2 = generateNodeIndex(hashValues2, mpiRank); it1 = nodeIdx2IdxMin.find(myNodeIdx1); it2 = nodeIdx2IdxMin.find(myNodeIdx2); size_t nodeIdxMin1 = (it1->second)[0]; size_t nodeIdxMin2 = (it2->second)[0]; size_t faceIdx = face_idx(nf); if (nodeIdxMin1 != nodeIdxMin2) { size_t edgeHash = hashPairOrdered(nodeIdxMin1, nodeIdxMin2); if (edgeHash2Face.count(edgeHash) == 0) { edgeHashList(nEdge) = edgeHash; ++nEdge; } edgeHash2Face[edgeHash].push_back(faceIdx); edgeHash2Face[edgeHash].push_back(mpiRank); } // nodeIdxMin1 != nodeIdxMin2 } } edgeHashList.resizeAndPreserve(nEdge); // (3) Face_face connectivity int nbNghb = 0; CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator itNode1, itNode2; // edgeHash2Info = CClientClientDHTSizet dhtEdge2Face (edgeHash2Face, comm); dhtEdge2Face.computeIndexInfoMapping(edgeHashList); CClientClientDHTSizet::Index2VectorInfoTypeMap& edgeHash2Info = dhtEdge2Face.getInfoIndexMap(); CClientClientDHTSizet::Index2VectorInfoTypeMap mapFaces; // auxiliar map for (int nf = 0; nf < nbFaces; ++nf) { for (int nv1 = 0; nv1 < nvertex; ++nv1) { // Getting indexes of edge's nodes int nv2 = (nv1 < nvertex -1 ) ? (nv1 + 1) : (nv1 + 1 - nvertex); // cyclic rotation vector hashValues1 = CMesh::createHashes(bounds_lon(nv1, nf), bounds_lat(nv1, nf)); vector hashValues2 = CMesh::createHashes(bounds_lon(nv2, nf), bounds_lat(nv2, nf)); size_t myNodeIdx1 = generateNodeIndex(hashValues1, mpiRank); size_t myNodeIdx2 = generateNodeIndex(hashValues2, mpiRank); itNode1 = nodeIdx2IdxMin.find(myNodeIdx1); itNode2 = nodeIdx2IdxMin.find(myNodeIdx2); size_t nodeIdxMin1 = (itNode1->second)[0]; size_t nodeIdxMin2 = (itNode2->second)[0]; if (nodeIdxMin1 != nodeIdxMin2) { size_t edgeHash = hashPairOrdered(nodeIdxMin1, nodeIdxMin2); it1 = edgeHash2Info.find(edgeHash); for (int i = 0; i < it1->second.size();) { size_t face = it1->second[i]; size_t rank = it1->second[i+1]; if (rank != mpiRank) if (mapFaces.count(face) == 0) { nghbFaces(0, nbNghb) = face; nghbFaces(1, nbNghb) = rank; ++nbNghb; mapFaces[face].push_back(face); } i += 2; } } // nodeIdxMin1 != nodeIdxMin2 } } nghbFaces.resizeAndPreserve(2, nbNghb); } // getGloNghbFacesEdgeType ///---------------------------------------------------------------- /*! * \fn void getGlobalNghbFaces (const int nghbType, const MPI_Comm& comm, const CArray& face_idx, const CArray& bounds_lon, const CArray& bounds_lat, CArray& nghbFaces) * Finds neighboring faces owned by other procs. * \param [in] nghbType 0 for faces sharing nodes, otherwise for faces sharing edges. * \param [in] comm * \param [in] face_idx Array with global indexes. * \param [in] bounds_lon Array of boundary longitudes. * \param [in] bounds_lat Array of boundary latitudes. * \param [out] nghbFaces 2D array containing neighboring faces and owner ranks. */ void CMesh::getGlobalNghbFaces(const int nghbType, const MPI_Comm& comm, const CArray& face_idx, const CArray& bounds_lon, const CArray& bounds_lat, CArray& nghbFaces) { if (nghbType == 0) getGloNghbFacesNodeType(comm, face_idx, bounds_lon, bounds_lat, nghbFaces); else getGloNghbFacesEdgeType(comm, face_idx, bounds_lon, bounds_lat, nghbFaces); } // getGlobalNghbFaces ///---------------------------------------------------------------- /*! * \fn void getLocalNghbFaces (const int nghbType, const CArray& bounds_lon, const CArray& bounds_lat, CArray& nghbFaces) * \param [in] nghbType 0 for faces sharing nodes, otherwise for faces sharing edges. * \param [in] bounds_lon Array of boundary longitudes. * \param [in] bounds_lat Array of boundary latitudes. * \param [out] nghbFaces 1D array containing neighboring faces. */ void CMesh::getLocalNghbFaces(const int nghbType, const CArray& face_idx, const CArray& bounds_lon, const CArray& bounds_lat, CArray& nghbFaces, CArray& nbNghbFaces) { if (nghbType == 0) getLocNghbFacesNodeType(face_idx, bounds_lon, bounds_lat, nghbFaces, nbNghbFaces); else getLocNghbFacesEdgeType(face_idx, bounds_lon, bounds_lat, nghbFaces, nbNghbFaces); } // getLocalNghbFaces ///---------------------------------------------------------------- /*! * \fn void getLocNghbFacesNodeType (const CArray& bounds_lon, const CArray& bounds_lat, CArray& nghbFaces) * \param [in] face_idx Array with local face indexing. * \param [in] bounds_lon Array of boundary longitudes. * \param [in] bounds_lat Array of boundary latitudes. * \param [out] nghbFaces 2D array containing neighboring faces. * \param [out] nbNghbFaces Array containing number of neighboring faces. */ void CMesh::getLocNghbFacesNodeType (const CArray& face_idx, const CArray& bounds_lon, const CArray& bounds_lat, CArray& faceToFaces, CArray& nbNghbFaces) { int nvertex = bounds_lon.rows(); int nbFaces = bounds_lon.shape()[1]; int nbNodes = 0; nbNghbFaces.resize(nbFaces); nbNghbFaces = 0; // nodeToFaces connectivity CClientClientDHTSizet::Index2VectorInfoTypeMap nodeToFaces; for (int nf = 0; nf < nbFaces; ++nf) for (int nv = 0; nv < nvertex; ++nv) { size_t nodeHash = (CMesh::createHashes(bounds_lon(nv, nf), bounds_lat(nv ,nf)))[0]; nodeToFaces[nodeHash].push_back(face_idx(nf)); } // faceToFaces connectivity std::unordered_map mapFaces; // mapFaces = < hash(face1, face2), hash> (the mapped value is irrelevant) int maxNb = 20; // some assumption on the max possible number of neighboring cells faceToFaces.resize(maxNb, nbFaces); CClientClientDHTSizet::Index2VectorInfoTypeMap::iterator it; for (it = nodeToFaces.begin(); it != nodeToFaces.end(); ++it) { int size = it->second.size(); for (int i = 0; i < (size-1); ++i) { int face1 = it->second[i]; for (int j = i+1; j < size; ++j) { int face2 = it->second[j]; if (face2 != face1) { int hashFace = hashPairOrdered(face1, face2); if (mapFaces.count(hashFace) == 0) { faceToFaces(nbNghbFaces(face1), face1) = face2; faceToFaces(nbNghbFaces(face2), face2) = face1; ++nbNghbFaces(face1); ++nbNghbFaces(face2); mapFaces[hashFace] = hashFace; } } } } } } //getLocNghbFacesNodeType ///---------------------------------------------------------------- /*! * \fn void getLocNghbFacesEdgeType (const CArray& face_idx, * const CArray& bounds_lon, const CArray& bounds_lat, * CArray& nghbFaces, CArray& nbNghbFaces) * \param [in] face_idx Array with local face indexing. * \param [in] bounds_lon Array of boundary longitudes. * \param [in] bounds_lat Array of boundary latitudes. * \param [out] nghbFaces 2D array containing neighboring faces. * \param [out] nbNghbFaces Array containing number of neighboring faces. */ void CMesh::getLocNghbFacesEdgeType (const CArray& face_idx, const CArray& bounds_lon, const CArray& bounds_lat, CArray& faceToFaces, CArray& nbNghbFaces) { int nvertex = bounds_lon.rows(); int nbFaces = bounds_lon.shape()[1]; int nbNodes = 0; int nbEdges = 0; nbNghbFaces.resize(nbFaces); nbNghbFaces = 0; // faceToNodes connectivity CArray faceToNodes (nvertex, nbFaces); std::unordered_map > mapNodes; for (int nf = 0; nf < nbFaces; ++nf) for (int nv = 0; nv < nvertex; ++nv) { if (mapNodes.find(make_pair (bounds_lon(nv, nf), bounds_lat(nv ,nf))) == mapNodes.end()) { mapNodes[make_pair (bounds_lon(nv, nf), bounds_lat(nv, nf))] = nbNodes; faceToNodes(nv,nf) = nbNodes ; ++nbNodes ; } else faceToNodes(nv,nf) = mapNodes[make_pair (bounds_lon(nv, nf), bounds_lat(nv ,nf))]; } // faceToFaces connectivity std::unordered_map > mapEdges; faceToFaces.resize(nvertex, nbFaces); CArray edgeToFaces(2, nbFaces*nvertex); // max possible for (int nf = 0; nf < nbFaces; ++nf) { for (int nv1 = 0; nv1 < nvertex; ++nv1) { int nv2 = (nv1 < nvertex -1 ) ? (nv1 + 1) : (nv1 + 1 - nvertex); // cyclic rotation int face = face_idx(nf); int node1 = faceToNodes(nv1,face); int node2 = faceToNodes(nv2,face); if (node1 != node2) { if (mapEdges.find(make_ordered_pair (node1, node2)) == mapEdges.end()) { mapEdges[make_ordered_pair (node1, node2)] = nbEdges; edgeToFaces(0,nbEdges) = face; ++nbEdges; } else { int edge = mapEdges[make_ordered_pair (node1, node2)]; edgeToFaces(1, edge) = face; int face1 = face; int face2 = edgeToFaces(0,edge); faceToFaces(nbNghbFaces(face1), face1) = face2; faceToFaces(nbNghbFaces(face2), face2) = face1; ++nbNghbFaces(face1); ++nbNghbFaces(face2); } } // node1 != node2 } // nv } // nf } //getLocNghbFacesEdgeType } // namespace xios