40 #include <boost/core/ignore_unused.hpp> 59 #include <boost/algorithm/string.hpp> 60 #include <boost/format.hpp> 61 #include <boost/graph/adjacency_iterator.hpp> 62 #include <boost/graph/adjacency_list.hpp> 63 #include <boost/graph/detail/edge.hpp> 67 namespace SpatialDomains
78 std::map<int, MeshEntity> element,
80 : m_session(session), m_dim(meshDim), m_numFields(0), m_elements(element),
81 m_compMap(compMap), m_fieldNameToId(), m_comm(session->GetComm()),
82 m_weightingRequired(false), m_weightBnd(false), m_weightDofs(false),
91 if (elIt->second.ghost)
108 int nParts,
bool shared,
bool overlapping,
int nLocal)
110 boost::ignore_unused(nLocal);
113 "Too few elements for this many processes.");
117 "Parallel partitioning requires shared filesystem.");
131 TiXmlElement *expansionTypes =
m_session->GetElement(
"Nektar/Expansions");
134 TiXmlElement *expansion = expansionTypes->FirstChildElement();
135 std::string expType = expansion->Value();
148 std::vector<unsigned int> composite;
149 std::vector<unsigned int> nummodes;
150 std::vector<std::string> fieldName;
152 const char *nModesStr = expansion->Attribute(
"NUMMODES");
154 "NUMMODES was not defined in EXPANSION section of input");
155 std::string numModesStr = nModesStr;
158 ASSERTL0(valid,
"Unable to correctly parse the number of modes.");
160 if (nummodes.size() == 1)
162 for (
int i = 1; i <
m_dim; i++)
164 nummodes.push_back(nummodes[0]);
168 "Number of modes should match mesh dimension");
170 const char *fStr = expansion->Attribute(
"FIELDS");
173 std::string fieldStr = fStr;
175 fieldStr.c_str(), fieldName);
176 ASSERTL0(valid,
"Unable to correctly parse the field string in " 179 for (
int i = 0; i < fieldName.size(); ++i)
191 fieldName.push_back(
"DefaultVar");
198 "Omitting field variables and explicitly listing " 199 "them in different ExpansionTypes is wrong practise");
206 std::string compositeStr = expansion->Attribute(
"COMPOSITE");
208 "COMPOSITE must be specified in expansion definition");
209 int beg = compositeStr.find_first_of(
"[");
210 int end = compositeStr.find_first_of(
"]");
211 std::string compositeListStr =
212 compositeStr.substr(beg + 1, end - beg - 1);
214 compositeListStr.c_str(), composite);
215 ASSERTL0(parseGood && !composite.empty(),
216 (std::string(
"Unable to read composite index range: ") +
221 for (
int i = 0; i < composite.size(); ++i)
223 auto &shapeType =
m_compMap[composite[i]].first;
224 auto &elmtIds =
m_compMap[composite[i]].second;
226 for (
int j = 0; j < fieldName.size(); j++)
228 for (
auto &elid : elmtIds)
236 expansion = expansion->NextSiblingElement(
"E");
239 else if (expType ==
"F")
241 ASSERTL0(expansion->Attribute(
"FILE"),
242 "Attribute FILE expected for type F expansion");
243 std::string filenameStr = expansion->Attribute(
"FILE");
245 "A filename must be specified for the FILE " 246 "attribute of expansion");
255 iofmt, comm,
m_session->GetSharedFilesystem());
258 std::vector<LibUtilities::FieldDefinitionsSharedPtr> fielddefs;
259 f->Import(filenameStr, fielddefs);
262 for (
int i = 0; i < fielddefs.size(); ++i)
265 for (
int j = 0; j < fielddefs[i]->m_fields.size(); ++j)
267 std::string fieldName = fielddefs[i]->m_fields[j];
276 int numHomoDir = fielddefs[i]->m_numHomogeneousDir;
278 for (
int j = 0; j < fielddefs[i]->m_elementIDs.size(); ++j)
280 int elid = fielddefs[i]->m_elementIDs[j];
281 std::vector<unsigned int> nummodes;
282 for (
int k = 0; k <
m_dim; k++)
284 nummodes.push_back(fielddefs[i]->m_numModes[cnt++]);
286 if (fielddefs[i]->m_uniOrder)
294 for (
int k = 0; k < fielddefs[i]->m_fields.size(); k++)
296 std::string fieldName = fielddefs[i]->m_fields[k];
299 m_shape[elid] = fielddefs[i]->m_shapeType;
306 "Expansion type not defined or not supported at the moment");
312 int nElmt = boost::num_vertices(
m_graph);
315 out <<
"# Partition information:" << std::endl;
316 out <<
"# No. elements : " << nElmt << std::endl;
317 out <<
"# No. partitions: " << nPart << std::endl;
318 out <<
"# ID nElmt nLocDof nBndDof" << std::endl;
321 std::vector<int> partElmtCount(nPart, 0);
322 std::vector<int> partLocCount(nPart, 0);
323 std::vector<int> partBndCount(nPart, 0);
325 std::map<int, int> elmtSizes;
326 std::map<int, int> elmtBndSizes;
328 for (std::map<int, NummodesPerField>::iterator expIt =
m_expansions.begin();
331 int elid = expIt->first;
334 for (NummodesPerField::iterator it = npf.begin(); it != npf.end(); ++it)
337 " Number of directional" 338 " modes in expansion spec for element id = " +
339 boost::lexical_cast<std::string>(elid) +
341 boost::lexical_cast<std::string>(it->first) +
342 " does not correspond to mesh dimension");
344 int na = it->second[0];
363 for (boost::tie(vertit, vertit_end) = boost::vertices(
m_graph);
364 vertit != vertit_end; ++vertit)
366 int partId =
m_graph[*vertit].partition;
367 partElmtCount[partId]++;
368 partLocCount[partId] += elmtSizes[
m_graph[*vertit].id];
369 partBndCount[partId] += elmtBndSizes[m_graph[*vertit].id];
372 for (
int i = 0; i < nPart; ++i)
374 out << i <<
" " << partElmtCount[i] <<
" " << partLocCount[i] <<
" " 375 << partBndCount[i] << std::endl;
381 if (!
m_session->DefinesElement(
"Nektar/Conditions/SolverInfo"))
388 TiXmlElement *solverInfoElement =
389 m_session->GetElement(
"Nektar/Conditions/SolverInfo");
391 TiXmlElement *solverInfo = solverInfoElement->FirstChildElement(
"I");
392 ASSERTL0(solverInfo,
"Cannot read SolverInfo tags");
397 ASSERTL0(solverInfo->Attribute(
"PROPERTY"),
398 "Missing PROPERTY attribute in solver info " 400 std::string solverProperty = solverInfo->Attribute(
"PROPERTY");
402 "Solver info properties must have a non-empty " 405 std::string solverPropertyUpper = boost::to_upper_copy(solverProperty);
408 ASSERTL0(solverInfo->Attribute(
"VALUE"),
409 "Missing VALUE attribute in solver info section. ");
410 std::string solverValue = solverInfo->Attribute(
"VALUE");
412 "Solver info properties must have a non-empty value");
414 std::string propertyValueUpper = boost::to_upper_copy(solverValue);
416 if (solverPropertyUpper ==
"WEIGHTPARTITIONS")
418 if (propertyValueUpper ==
"DOF")
423 else if (propertyValueUpper ==
"BOUNDARY")
428 else if (propertyValueUpper ==
"BOTH")
436 solverInfo = solverInfo->NextSiblingElement(
"I");
457 std::map<int, MeshEntity>::iterator eIt;
465 for (std::map<int, NummodesPerField>::iterator expIt =
m_expansions.begin();
468 int elid = expIt->first;
471 for (NummodesPerField::iterator it = npf.begin(); it != npf.end(); ++it)
474 " Number of directional" 475 " modes in expansion spec for element id = " +
476 boost::lexical_cast<std::string>(elid) +
478 boost::lexical_cast<std::string>(it->first) +
479 " does not correspond to mesh dimension");
481 int na = it->second[0];
514 std::unordered_map<int, int> vGraphEdges;
519 auto vert = boost::add_vertex(
m_graph);
531 for (
auto &eId : elmt.second.list)
535 auto edgeIt = vGraphEdges.find(eId);
536 if (edgeIt != vGraphEdges.end())
539 boost::add_edge(vcnt, edgeIt->second,
m_graph).first;
544 vGraphEdges[eId] = vcnt;
555 auto vert = boost::add_vertex(
m_graph);
556 m_graph[vert].id = ghost.first;
559 for (
auto &facet : ghost.second.list)
561 auto edgeIt = vGraphEdges.find(facet);
562 if (edgeIt != vGraphEdges.end())
565 boost::add_edge(vcnt, edgeIt->second,
m_graph).first;
593 int nGraphVerts = boost::num_vertices(
m_graph);
595 int nLocal = nGraphVerts - nGhost;
611 int nWeight = ncon * nLocal;
614 std::vector<int> adjncy_tmp, adjwgt_tmp;
621 for (boost::tie(vertit, vertit_end) = boost::vertices(
m_graph);
622 vertit != vertit_end && vcnt < nLocal; ++vertit)
624 for (boost::tie(adjvertit, adjvertit_end) =
625 boost::adjacent_vertices(*vertit,
m_graph);
626 adjvertit != adjvertit_end; ++adjvertit, ++acnt)
628 adjncy_tmp.push_back(
m_graph[*adjvertit].
id);
631 adjwgt_tmp.push_back(
m_graph[*vertit].edgeWeight[0]);
635 adjwgt_tmp.push_back(1);
646 vwgt[ncon * (vcnt - 1) + ccnt] =
m_graph[*vertit].weight[0];
651 vwgt[ncon * (vcnt - 1) + ccnt] =
670 if (
m_comm->GetColumnComm()->GetRank() == 0)
674 adjwgt, nParts, vol, part);
686 for (i = 1; i <
m_comm->GetColumnComm()->GetSize(); ++i)
688 m_comm->GetColumnComm()->Send(i, part);
694 m_comm->GetColumnComm()->Recv(0, part);
699 m_comm->GetColumnComm()->Block();
703 for (i = 1; i <
m_comm->GetRowComm()->GetSize(); ++i)
705 m_comm->GetRowComm()->Send(i, part);
712 "Error in calling graph partitioner.");
717 m_comm->GetRowComm()->Recv(0, part);
728 for (boost::tie(vertit, vertit_end) = boost::vertices(
m_graph);
729 vertit != vertit_end; ++vertit, ++i)
737 int nproc =
m_comm->GetSize();
738 std::vector<int> numToSend(nproc, 0), numToRecv(nproc);
739 std::map<int, std::vector<int>> procMap;
741 for (boost::tie(vertit, vertit_end) = boost::vertices(
m_graph);
742 vertit != vertit_end && i < nLocal; ++vertit, ++i)
744 int toProc = part[i];
746 procMap[toProc].push_back(
m_graph[*vertit].
id);
749 m_comm->AlltoAll(numToSend, numToRecv);
752 std::vector<int> sendOffsetMap(nproc), recvOffsetMap(nproc);
754 sendOffsetMap[0] = 0;
755 recvOffsetMap[0] = 0;
756 for (
int i = 1; i < nproc; ++i)
758 sendOffsetMap[i] = sendOffsetMap[i-1] + numToSend[i-1];
759 recvOffsetMap[i] = recvOffsetMap[i-1] + numToRecv[i-1];
763 int totalSend =
Vmath::Vsum(nproc, &numToSend[0], 1);
764 int totalRecv =
Vmath::Vsum(nproc, &numToRecv[0], 1);
766 std::vector<int> sendData(totalSend), recvData(totalRecv);
769 for (
auto &verts : procMap)
771 for (
auto &vert : verts.second)
773 sendData[cnt++] = vert;
778 m_comm->AlltoAllv(sendData, numToSend, sendOffsetMap,
779 recvData, numToRecv, recvOffsetMap);
783 std::unordered_set<int> uniqueIDs;
784 for (
auto &
id : recvData)
786 uniqueIDs.insert(
id);
790 uniqueIDs.begin(), uniqueIDs.end());
798 "parallel execution");
800 for (boost::tie(vertit, vertit_end) = boost::vertices(
m_graph);
801 vertit != vertit_end; ++vertit)
803 for (boost::tie(adjvertit, adjvertit_end) =
804 boost::adjacent_vertices(*vertit,
m_graph);
805 adjvertit != adjvertit_end; ++adjvertit)
807 if (part[*adjvertit] != part[*vertit])
820 unsigned int cnt = 0;
824 for (i = 0; i < nParts; ++i)
826 cnt = std::count(pPart.begin(), pPart.end(), i);
840 for (i = 0; i < pPart.num_elements(); ++i)
842 pPart[i] = i % nParts;
848 std::vector<unsigned int> &elmtid)
853 "procid is less than the number of partitions");
855 "Can only get this rank's processor IDs in parallel");
862 int na,
int nb,
int nc)
935 int na,
int nb,
int nc)
938 int n = std::max(na, std::max(nb, nc));
CompositeDescriptor m_compMap
#define ASSERTL0(condition, msg)
void PrintPartInfo(std::ostream &out)
#define NEKERROR(type, msg)
Assert Level 0 – Fundamental assert which is used whether in FULLDEBUG, DEBUG or OPT compilation mod...
LibUtilities::CommSharedPtr m_comm
virtual void PartitionGraphImpl(int &nVerts, int &nVertConds, Nektar::Array< Nektar::OneD, int > &xadj, Nektar::Array< Nektar::OneD, int > &adjcy, Nektar::Array< Nektar::OneD, int > &vertWgt, Nektar::Array< Nektar::OneD, int > &vertSize, Nektar::Array< Nektar::OneD, int > &edgeWgt, int &nparts, int &volume, Nektar::Array< Nektar::OneD, int > &part)=0
int getNumberOfBndCoefficients(int Na, int Nb)
int getNumberOfCoefficients(int Na, int Nb, int Nc)
boost::graph_traits< BoostGraph >::adjacency_iterator BoostAdjacencyIterator
int getNumberOfBndCoefficients(int Na, int Nb, int Nc)
std::map< int, MultiWeight > m_vertWeights
std::shared_ptr< Comm > CommSharedPtr
Pointer to a Communicator object.
int CalculateEdgeWeight(LibUtilities::ShapeType elmtType, int na, int nb, int nc)
int getNumberOfBndCoefficients(int Na, int Nb, int Nc)
std::map< int, MeshEntity > m_ghostElmts
int getNumberOfCoefficients(int Na, int Nb, int Nc)
FieldIOFactory & GetFieldIOFactory()
Returns the FieldIO factory.
CommFactory & GetCommFactory()
LibUtilities::SessionReaderSharedPtr m_session
void CheckPartitions(int nParts, Array< OneD, int > &pPart)
void GetElementIDs(const int procid, std::vector< unsigned int > &tmp)
std::map< int, MultiWeight > m_vertBndWeights
tBaseSharedPtr CreateInstance(tKey idKey, tParam... args)
Create an instance of the class referred to by idKey.
int getNumberOfCoefficients(int Na)
MeshPartition(const LibUtilities::SessionReaderSharedPtr session, int meshDim, std::map< int, MeshEntity > element, CompositeDescriptor compMap)
static const std::string GetFileType(const std::string &filename, CommSharedPtr comm)
Determine file type of given input file.
std::map< int, MultiWeight > m_edgeWeights
int getNumberOfCoefficients(int Na, int Nb)
boost::graph_traits< BoostGraph >::vertex_iterator BoostVertexIterator
std::map< int, NummodesPerField > m_expansions
void PartitionGraph(int nParts, bool overlapping=false)
Partition the graph.
std::map< int, LibUtilities::ShapeType > m_shape
static bool GenerateVector(const std::string &str, std::vector< T > &out)
Takes a comma-separated string and converts it to entries in a vector.
std::map< int, std::pair< LibUtilities::ShapeType, std::vector< int > > > CompositeDescriptor
int getNumberOfBndCoefficients(int Na)
int getNumberOfBndCoefficients(int Na, int Nb)
int getNumberOfCoefficients(int Na, int Nb, int Nc)
int getNumberOfBndCoefficients(int Na, int Nb, int Nc)
std::map< int, MeshEntity > m_elements
int getNumberOfCoefficients(int Na, int Nb)
std::map< std::string, int > m_fieldNameToId
std::map< std::string, NumModes > NummodesPerField
int getNumberOfCoefficients(int Na, int Nb, int Nc)
void PartitionMesh(int nParts, bool shared=false, bool overlapping=false, int nLocal=0)
int CalculateElementWeight(LibUtilities::ShapeType elmtType, bool bndWeight, int na, int nb, int nc)
MeshPartitionFactory & GetMeshPartitionFactory()
T Vsum(int n, const T *x, const int incx)
Subtract return sum(x)
std::shared_ptr< FieldIO > FieldIOSharedPtr
boost::graph_traits< BoostGraph >::edge_descriptor BoostEdge
std::shared_ptr< SessionReader > SessionReaderSharedPtr
#define SPATIAL_DOMAINS_EXPORT
int getNumberOfBndCoefficients(int Na, int Nb, int Nc)
Provides a generic Factory class.
std::vector< std::vector< unsigned int > > m_localPartition
static bool GenerateSeqVector(const std::string &str, std::vector< unsigned int > &out)
Takes a comma-separated compressed string and converts it to entries in a vector. ...