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));
#define ASSERTL0(condition, msg)
#define NEKERROR(type, msg)
Assert Level 0 – Fundamental assert which is used whether in FULLDEBUG, DEBUG or OPT compilation mode...
#define SPATIAL_DOMAINS_EXPORT
static const std::string GetFileType(const std::string &filename, CommSharedPtr comm)
Determine file type of given input file.
Provides a generic Factory class.
tBaseSharedPtr CreateInstance(tKey idKey, tParam... args)
Create an instance of the class referred to by idKey.
static bool GenerateVector(const std::string &str, std::vector< T > &out)
Takes a comma-separated string and converts it to entries in a vector.
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.
boost::graph_traits< BoostGraph >::vertex_iterator BoostVertexIterator
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
std::vector< std::vector< unsigned int > > m_localPartition
void PartitionGraph(int nParts, bool overlapping=false)
Partition the graph.
std::map< int, NummodesPerField > m_expansions
boost::graph_traits< BoostGraph >::adjacency_iterator BoostAdjacencyIterator
std::map< int, MultiWeight > m_edgeWeights
CompositeDescriptor m_compMap
std::map< std::string, int > m_fieldNameToId
std::map< int, MeshEntity > m_ghostElmts
LibUtilities::SessionReaderSharedPtr m_session
std::map< int, MultiWeight > m_vertBndWeights
std::map< int, MultiWeight > m_vertWeights
void PrintPartInfo(std::ostream &out)
void GetElementIDs(const int procid, std::vector< unsigned int > &tmp)
boost::graph_traits< BoostGraph >::edge_descriptor BoostEdge
int CalculateElementWeight(LibUtilities::ShapeType elmtType, bool bndWeight, int na, int nb, int nc)
MeshPartition(const LibUtilities::SessionReaderSharedPtr session, int meshDim, std::map< int, MeshEntity > element, CompositeDescriptor compMap)
std::map< std::string, NumModes > NummodesPerField
int CalculateEdgeWeight(LibUtilities::ShapeType elmtType, int na, int nb, int nc)
void PartitionMesh(int nParts, bool shared=false, bool overlapping=false, int nLocal=0)
std::map< int, MeshEntity > m_elements
LibUtilities::CommSharedPtr m_comm
void CheckPartitions(int nParts, Array< OneD, int > &pPart)
std::map< int, LibUtilities::ShapeType > m_shape
int getNumberOfCoefficients(int Na, int Nb, int Nc)
int getNumberOfBndCoefficients(int Na, int Nb, int Nc)
int getNumberOfCoefficients(int Na, int Nb, int Nc)
int getNumberOfBndCoefficients(int Na, int Nb, int Nc)
int getNumberOfCoefficients(int Na, int Nb, int Nc)
int getNumberOfBndCoefficients(int Na, int Nb, int Nc)
int getNumberOfCoefficients(int Na, int Nb)
int getNumberOfBndCoefficients(int Na, int Nb)
int getNumberOfCoefficients(int Na)
int getNumberOfBndCoefficients(int Na)
int getNumberOfBndCoefficients(int Na, int Nb, int Nc)
int getNumberOfCoefficients(int Na, int Nb, int Nc)
int getNumberOfCoefficients(int Na, int Nb)
int getNumberOfBndCoefficients(int Na, int Nb)
std::shared_ptr< FieldIO > FieldIOSharedPtr
std::shared_ptr< SessionReader > SessionReaderSharedPtr
FieldIOFactory & GetFieldIOFactory()
Returns the FieldIO factory.
CommFactory & GetCommFactory()
std::shared_ptr< Comm > CommSharedPtr
Pointer to a Communicator object.
std::map< int, std::pair< LibUtilities::ShapeType, std::vector< int > > > CompositeDescriptor
MeshPartitionFactory & GetMeshPartitionFactory()
T Vsum(int n, const T *x, const int incx)
Subtract return sum(x)