57#include <boost/algorithm/string.hpp>
58#include <boost/format.hpp>
59#include <boost/graph/adjacency_iterator.hpp>
60#include <boost/graph/adjacency_list.hpp>
61#include <boost/graph/detail/edge.hpp>
74 std::map<int, MeshEntity> element,
76 : m_session(session), m_comm(comm), m_dim(meshDim), m_numFields(0),
77 m_elements(element), m_compMap(compMap), m_fieldNameToId(),
78 m_weightingRequired(false), m_weightBnd(false), m_weightDofs(false),
87 if (elIt->second.ghost)
104 [[maybe_unused]]
int nLocal)
107 "Too few elements for this many processes.");
111 "Parallel partitioning requires shared filesystem.");
125 TiXmlElement *expansionTypes =
m_session->GetElement(
"Nektar/Expansions");
131 TiXmlElement *expansion = expansionTypes->FirstChildElement();
133 std::string expType = expansion->Value();
143 std::vector<unsigned int> composite;
144 std::vector<unsigned int> nummodes;
145 std::vector<std::string> fieldName;
147 const char *nModesStr = expansion->Attribute(
"NUMMODES");
149 "NUMMODES was not defined in EXPANSION section of input");
150 std::string numModesStr = nModesStr;
153 ASSERTL0(valid,
"Unable to correctly parse the number of modes.");
155 if (nummodes.size() == 1)
157 for (
int i = 1; i <
m_dim; i++)
159 nummodes.push_back(nummodes[0]);
163 "Number of modes should match mesh dimension");
165 const char *fStr = expansion->Attribute(
"FIELDS");
168 std::string fieldStr = fStr;
171 ASSERTL0(valid,
"Unable to correctly parse the field string in "
174 for (
int i = 0; i < fieldName.size(); ++i)
186 fieldName.push_back(
"DefaultVar");
193 "Omitting field variables and explicitly listing "
194 "them in different ExpansionTypes is wrong practise");
201 std::string compositeStr = expansion->Attribute(
"COMPOSITE");
203 "COMPOSITE must be specified in expansion definition");
204 int beg = compositeStr.find_first_of(
"[");
205 int end = compositeStr.find_first_of(
"]");
206 std::string compositeListStr =
207 compositeStr.substr(beg + 1, end - beg - 1);
209 compositeListStr.c_str(), composite);
210 ASSERTL0(parseGood && !composite.empty(),
211 (std::string(
"Unable to read composite index range: ") +
216 for (
int i = 0; i < composite.size(); ++i)
218 auto &shapeType =
m_compMap[composite[i]].first;
219 auto &elmtIds =
m_compMap[composite[i]].second;
221 for (
int j = 0; j < fieldName.size(); j++)
223 for (
auto &elid : elmtIds)
231 expansion = expansion->NextSiblingElement(
"E");
234 else if (expType ==
"F")
236 ASSERTL0(expansion->Attribute(
"FILE"),
237 "Attribute FILE expected for type F expansion");
238 std::string filenameStr = expansion->Attribute(
"FILE");
240 "A filename must be specified for the FILE "
241 "attribute of expansion");
252 iofmt, comm,
m_session->GetSharedFilesystem());
255 std::vector<LibUtilities::FieldDefinitionsSharedPtr> fielddefs;
256 f->Import(filenameStr, fielddefs);
259 for (
int i = 0; i < fielddefs.size(); ++i)
262 for (
int j = 0; j < fielddefs[i]->m_fields.size(); ++j)
264 std::string fieldName = fielddefs[i]->m_fields[j];
273 int numHomoDir = fielddefs[i]->m_numHomogeneousDir;
275 for (
int j = 0; j < fielddefs[i]->m_elementIDs.size(); ++j)
277 int elid = fielddefs[i]->m_elementIDs[j];
278 std::vector<unsigned int> nummodes;
279 for (
int k = 0; k <
m_dim; k++)
281 nummodes.push_back(fielddefs[i]->m_numModes[cnt++]);
283 if (fielddefs[i]->m_uniOrder)
291 for (
int k = 0; k < fielddefs[i]->m_fields.size(); k++)
293 std::string fieldName = fielddefs[i]->m_fields[k];
296 m_shape[elid] = fielddefs[i]->m_shapeType;
303 "Expansion type not defined or not supported at the moment");
309 int nElmt = boost::num_vertices(
m_graph);
312 out <<
"# Partition information:" << std::endl;
313 out <<
"# No. elements : " << nElmt << std::endl;
314 out <<
"# No. partitions: " << nPart << std::endl;
315 out <<
"# ID nElmt nLocDof nBndDof" << std::endl;
318 std::vector<int> partElmtCount(nPart, 0);
319 std::vector<int> partLocCount(nPart, 0);
320 std::vector<int> partBndCount(nPart, 0);
322 std::map<int, int> elmtSizes;
323 std::map<int, int> elmtBndSizes;
325 for (std::map<int, NummodesPerField>::iterator expIt =
m_expansions.begin();
328 int elid = expIt->first;
331 for (NummodesPerField::iterator it = npf.begin(); it != npf.end(); ++it)
334 " Number of directional"
335 " modes in expansion spec for element id = " +
336 std::to_string(elid) +
" and field " + it->first +
337 " does not correspond to mesh dimension");
339 int na = it->second[0];
358 for (boost::tie(vertit, vertit_end) = boost::vertices(
m_graph);
359 vertit != vertit_end; ++vertit)
361 int partId =
m_graph[*vertit].partition;
362 partElmtCount[partId]++;
363 partLocCount[partId] += elmtSizes[
m_graph[*vertit].id];
364 partBndCount[partId] += elmtBndSizes[
m_graph[*vertit].id];
367 for (
int i = 0; i < nPart; ++i)
369 out << i <<
" " << partElmtCount[i] <<
" " << partLocCount[i] <<
" "
370 << partBndCount[i] << std::endl;
376 if (!
m_session->DefinesElement(
"Nektar/Conditions/SolverInfo"))
383 TiXmlElement *solverInfoElement =
384 m_session->GetElement(
"Nektar/Conditions/SolverInfo");
389 TiXmlElement *solverInfo = solverInfoElement->FirstChildElement(
"I");
390 ASSERTL0(solverInfo,
"Cannot read SolverInfo tags");
395 ASSERTL0(solverInfo->Attribute(
"PROPERTY"),
396 "Missing PROPERTY attribute in solver info "
398 std::string solverProperty = solverInfo->Attribute(
"PROPERTY");
400 "Solver info properties must have a non-empty "
403 std::string solverPropertyUpper = boost::to_upper_copy(solverProperty);
406 ASSERTL0(solverInfo->Attribute(
"VALUE"),
407 "Missing VALUE attribute in solver info section. ");
408 std::string solverValue = solverInfo->Attribute(
"VALUE");
410 "Solver info properties must have a non-empty value");
412 std::string propertyValueUpper = boost::to_upper_copy(solverValue);
414 if (solverPropertyUpper ==
"WEIGHTPARTITIONS")
416 if (propertyValueUpper ==
"DOF")
421 else if (propertyValueUpper ==
"BOUNDARY")
426 else if (propertyValueUpper ==
"BOTH")
434 solverInfo = solverInfo->NextSiblingElement(
"I");
455 std::map<int, MeshEntity>::iterator eIt;
463 for (std::map<int, NummodesPerField>::iterator expIt =
m_expansions.begin();
466 int elid = expIt->first;
469 for (NummodesPerField::iterator it = npf.begin(); it != npf.end(); ++it)
472 " Number of directional"
473 " modes in expansion spec for element id = " +
474 std::to_string(elid) +
" and field " + it->first +
475 " does not correspond to mesh dimension");
477 int na = it->second[0];
510 std::unordered_map<int, std::vector<int>> vGraphEdges;
515 auto vert = boost::add_vertex(
m_graph);
527 for (
auto &eId : elmt.second.list)
531 auto edgeIt = vGraphEdges.find(eId);
532 if (edgeIt != vGraphEdges.end())
534 for (
auto &iId : edgeIt->second)
539 vGraphEdges[eId].push_back(vcnt);
545 vGraphEdges[eId] = Id;
556 auto vert = boost::add_vertex(
m_graph);
557 m_graph[vert].id = ghost.first;
560 for (
auto &facet : ghost.second.list)
562 auto edgeIt = vGraphEdges.find(facet);
563 if (edgeIt != vGraphEdges.end())
565 for (
auto &iId : edgeIt->second)
570 vGraphEdges[facet].push_back(vcnt);
597 int nGraphVerts = boost::num_vertices(
m_graph);
599 int nLocal = nGraphVerts - nGhost;
616 int nWeight = ncon * nLocal;
619 std::vector<int> adjncy_tmp, adjwgt_tmp;
626 for (boost::tie(vertit, vertit_end) = boost::vertices(
m_graph);
627 vertit != vertit_end && vcnt < nLocal; ++vertit)
629 for (boost::tie(adjvertit, adjvertit_end) =
630 boost::adjacent_vertices(*vertit,
m_graph);
631 adjvertit != adjvertit_end; ++adjvertit, ++acnt)
633 adjncy_tmp.push_back(
m_graph[*adjvertit].
id);
636 adjwgt_tmp.push_back(
m_graph[*vertit].edgeWeight[0]);
640 adjwgt_tmp.push_back(1);
651 vwgt[ncon * (vcnt - 1) + ccnt] =
m_graph[*vertit].weight[0];
656 vwgt[ncon * (vcnt - 1) + ccnt] =
675 if (
m_comm->GetColumnComm()->GetRank() == 0)
679 adjwgt, nParts, vol, part);
691 for (i = 1; i <
m_comm->GetColumnComm()->GetSize(); ++i)
693 m_comm->GetColumnComm()->Send(i, part);
699 m_comm->GetColumnComm()->Recv(0, part);
709 m_comm->GetRowComm()->Recv(0, part);
718 for (boost::tie(vertit, vertit_end) = boost::vertices(
m_graph);
719 vertit != vertit_end; ++vertit, ++i)
727 int nproc =
m_comm->GetSpaceComm()->GetSize(),
728 rank =
m_comm->GetSpaceComm()->GetRank();
729 std::vector<int> numToSend(nproc, 0), numToRecv(nproc);
730 std::map<int, std::vector<int>> procMap;
732 for (boost::tie(vertit, vertit_end) = boost::vertices(
m_graph);
733 vertit != vertit_end && i < nLocal; ++vertit, ++i)
735 int toProc = part[i];
737 procMap[toProc].push_back(
m_graph[*vertit].
id);
740 m_comm->GetSpaceComm()->AlltoAll(numToSend, numToRecv);
743 std::vector<int> sendOffsetMap(nproc), recvOffsetMap(nproc);
745 sendOffsetMap[0] = 0;
746 recvOffsetMap[0] = 0;
747 for (
int i = 1; i < nproc; ++i)
749 sendOffsetMap[i] = sendOffsetMap[i - 1] + numToSend[i - 1];
750 recvOffsetMap[i] = recvOffsetMap[i - 1] + numToRecv[i - 1];
754 int totalSend =
Vmath::Vsum(nproc, &numToSend[0], 1);
755 int totalRecv =
Vmath::Vsum(nproc, &numToRecv[0], 1);
757 std::vector<int> sendData(totalSend), recvData(totalRecv);
760 for (
auto &verts : procMap)
762 for (
auto &vert : verts.second)
764 sendData[cnt++] = vert;
769 m_comm->GetSpaceComm()->AlltoAllv(sendData, numToSend, sendOffsetMap,
770 recvData, numToRecv, recvOffsetMap);
774 std::unordered_set<int> uniqueIDs;
775 for (
auto &
id : recvData)
777 uniqueIDs.insert(
id);
781 uniqueIDs.begin(), uniqueIDs.end());
789 "parallel execution");
791 for (boost::tie(vertit, vertit_end) = boost::vertices(
m_graph);
792 vertit != vertit_end; ++vertit)
794 for (boost::tie(adjvertit, adjvertit_end) =
795 boost::adjacent_vertices(*vertit,
m_graph);
796 adjvertit != adjvertit_end; ++adjvertit)
798 if (part[*adjvertit] != part[*vertit])
811 unsigned int cnt = 0;
815 for (i = 0; i < nParts; ++i)
817 cnt = std::count(pPart.begin(), pPart.end(), i);
831 for (i = 0; i < pPart.size(); ++i)
833 pPart[i] = i % nParts;
839 std::vector<unsigned int> &elmtid)
851 bool bndWeight,
int na,
int nb,
928 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 void GetXMLElementTimeLevel(TiXmlElement *&element, const size_t timeLevel, const bool enableCheck=true)
Get XML elment time level (Parallel-in-Time)
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 v_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
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
std::map< int, std::vector< unsigned int > > m_localPartition
int CalculateElementWeight(LibUtilities::ShapeType elmtType, bool bndWeight, int na, int nb, int nc)
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
MeshPartition(const LibUtilities::SessionReaderSharedPtr session, LibUtilities::CommSharedPtr comm, int meshDim, std::map< int, MeshEntity > element, CompositeDescriptor compMap)
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)