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
79 std::map<int, MeshEntity> element,
81 : m_session(session), m_comm(comm), m_dim(meshDim), m_numFields(0),
82 m_elements(element), m_compMap(compMap), m_fieldNameToId(),
83 m_weightingRequired(false), m_weightBnd(false), m_weightDofs(false),
92 if (elIt->second.ghost)
109 int nParts,
bool shared,
bool overlapping,
int nLocal)
111 boost::ignore_unused(nLocal);
114 "Too few elements for this many processes.");
118 "Parallel partitioning requires shared filesystem.");
132 TiXmlElement *expansionTypes =
m_session->GetElement(
"Nektar/Expansions");
135 TiXmlElement *expansion = expansionTypes->FirstChildElement();
136 std::string expType = expansion->Value();
146 std::vector<unsigned int> composite;
147 std::vector<unsigned int> nummodes;
148 std::vector<std::string> fieldName;
150 const char *nModesStr = expansion->Attribute(
"NUMMODES");
152 "NUMMODES was not defined in EXPANSION section of input");
153 std::string numModesStr = nModesStr;
156 ASSERTL0(valid,
"Unable to correctly parse the number of modes.");
158 if (nummodes.size() == 1)
160 for (
int i = 1; i <
m_dim; i++)
162 nummodes.push_back(nummodes[0]);
166 "Number of modes should match mesh dimension");
168 const char *fStr = expansion->Attribute(
"FIELDS");
171 std::string fieldStr = fStr;
173 fieldStr.c_str(), fieldName);
174 ASSERTL0(valid,
"Unable to correctly parse the field string in "
177 for (
int i = 0; i < fieldName.size(); ++i)
189 fieldName.push_back(
"DefaultVar");
196 "Omitting field variables and explicitly listing "
197 "them in different ExpansionTypes is wrong practise");
204 std::string compositeStr = expansion->Attribute(
"COMPOSITE");
206 "COMPOSITE must be specified in expansion definition");
207 int beg = compositeStr.find_first_of(
"[");
208 int end = compositeStr.find_first_of(
"]");
209 std::string compositeListStr =
210 compositeStr.substr(beg + 1, end - beg - 1);
212 compositeListStr.c_str(), composite);
213 ASSERTL0(parseGood && !composite.empty(),
214 (std::string(
"Unable to read composite index range: ") +
219 for (
int i = 0; i < composite.size(); ++i)
221 auto &shapeType =
m_compMap[composite[i]].first;
222 auto &elmtIds =
m_compMap[composite[i]].second;
224 for (
int j = 0; j < fieldName.size(); j++)
226 for (
auto &elid : elmtIds)
234 expansion = expansion->NextSiblingElement(
"E");
237 else if (expType ==
"F")
239 ASSERTL0(expansion->Attribute(
"FILE"),
240 "Attribute FILE expected for type F expansion");
241 std::string filenameStr = expansion->Attribute(
"FILE");
243 "A filename must be specified for the FILE "
244 "attribute of expansion");
253 iofmt, comm,
m_session->GetSharedFilesystem());
256 std::vector<LibUtilities::FieldDefinitionsSharedPtr> fielddefs;
257 f->Import(filenameStr, fielddefs);
260 for (
int i = 0; i < fielddefs.size(); ++i)
263 for (
int j = 0; j < fielddefs[i]->m_fields.size(); ++j)
265 std::string fieldName = fielddefs[i]->m_fields[j];
274 int numHomoDir = fielddefs[i]->m_numHomogeneousDir;
276 for (
int j = 0; j < fielddefs[i]->m_elementIDs.size(); ++j)
278 int elid = fielddefs[i]->m_elementIDs[j];
279 std::vector<unsigned int> nummodes;
280 for (
int k = 0; k <
m_dim; k++)
282 nummodes.push_back(fielddefs[i]->m_numModes[cnt++]);
284 if (fielddefs[i]->m_uniOrder)
292 for (
int k = 0; k < fielddefs[i]->m_fields.size(); k++)
294 std::string fieldName = fielddefs[i]->m_fields[k];
297 m_shape[elid] = fielddefs[i]->m_shapeType;
304 "Expansion type not defined or not supported at the moment");
310 int nElmt = boost::num_vertices(
m_graph);
313 out <<
"# Partition information:" << std::endl;
314 out <<
"# No. elements : " << nElmt << std::endl;
315 out <<
"# No. partitions: " << nPart << std::endl;
316 out <<
"# ID nElmt nLocDof nBndDof" << std::endl;
319 std::vector<int> partElmtCount(nPart, 0);
320 std::vector<int> partLocCount(nPart, 0);
321 std::vector<int> partBndCount(nPart, 0);
323 std::map<int, int> elmtSizes;
324 std::map<int, int> elmtBndSizes;
326 for (std::map<int, NummodesPerField>::iterator expIt =
m_expansions.begin();
329 int elid = expIt->first;
332 for (NummodesPerField::iterator it = npf.begin(); it != npf.end(); ++it)
335 " Number of directional"
336 " modes in expansion spec for element id = " +
337 boost::lexical_cast<std::string>(elid) +
339 boost::lexical_cast<std::string>(it->first) +
340 " does not correspond to mesh dimension");
342 int na = it->second[0];
361 for (boost::tie(vertit, vertit_end) = boost::vertices(
m_graph);
362 vertit != vertit_end; ++vertit)
364 int partId =
m_graph[*vertit].partition;
365 partElmtCount[partId]++;
366 partLocCount[partId] += elmtSizes[
m_graph[*vertit].id];
367 partBndCount[partId] += elmtBndSizes[
m_graph[*vertit].id];
370 for (
int i = 0; i < nPart; ++i)
372 out << i <<
" " << partElmtCount[i] <<
" " << partLocCount[i] <<
" "
373 << partBndCount[i] << std::endl;
379 if (!
m_session->DefinesElement(
"Nektar/Conditions/SolverInfo"))
386 TiXmlElement *solverInfoElement =
387 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 boost::lexical_cast<std::string>(elid) +
476 boost::lexical_cast<std::string>(it->first) +
477 " does not correspond to mesh dimension");
479 int na = it->second[0];
512 std::unordered_map<int, int> vGraphEdges;
517 auto vert = boost::add_vertex(
m_graph);
529 for (
auto &eId : elmt.second.list)
533 auto edgeIt = vGraphEdges.find(eId);
534 if (edgeIt != vGraphEdges.end())
537 boost::add_edge(vcnt, edgeIt->second,
m_graph).first;
542 vGraphEdges[eId] = vcnt;
553 auto vert = boost::add_vertex(
m_graph);
554 m_graph[vert].id = ghost.first;
557 for (
auto &facet : ghost.second.list)
559 auto edgeIt = vGraphEdges.find(facet);
560 if (edgeIt != vGraphEdges.end())
563 boost::add_edge(vcnt, edgeIt->second,
m_graph).first;
591 int nGraphVerts = boost::num_vertices(
m_graph);
593 int nLocal = nGraphVerts - nGhost;
610 int nWeight = ncon * nLocal;
613 std::vector<int> adjncy_tmp, adjwgt_tmp;
620 for (boost::tie(vertit, vertit_end) = boost::vertices(
m_graph);
621 vertit != vertit_end && vcnt < nLocal; ++vertit)
623 for (boost::tie(adjvertit, adjvertit_end) =
624 boost::adjacent_vertices(*vertit,
m_graph);
625 adjvertit != adjvertit_end; ++adjvertit, ++acnt)
627 adjncy_tmp.push_back(
m_graph[*adjvertit].
id);
630 adjwgt_tmp.push_back(
m_graph[*vertit].edgeWeight[0]);
634 adjwgt_tmp.push_back(1);
645 vwgt[ncon * (vcnt - 1) + ccnt] =
m_graph[*vertit].weight[0];
650 vwgt[ncon * (vcnt - 1) + ccnt] =
669 if (
m_comm->GetColumnComm()->GetRank() == 0)
673 adjwgt, nParts, vol, part);
685 for (i = 1; i <
m_comm->GetColumnComm()->GetSize(); ++i)
687 m_comm->GetColumnComm()->Send(i, part);
693 m_comm->GetColumnComm()->Recv(0, part);
699 "Error in calling graph partitioner.");
704 m_comm->GetRowComm()->Recv(0, part);
713 for (boost::tie(vertit, vertit_end) = boost::vertices(
m_graph);
714 vertit != vertit_end; ++vertit, ++i)
722 int nproc =
m_comm->GetSize(), rank =
m_comm->GetRank();
723 std::vector<int> numToSend(nproc, 0), numToRecv(nproc);
724 std::map<int, std::vector<int>> procMap;
726 for (boost::tie(vertit, vertit_end) = boost::vertices(
m_graph);
727 vertit != vertit_end && i < nLocal; ++vertit, ++i)
729 int toProc = part[i];
731 procMap[toProc].push_back(
m_graph[*vertit].
id);
734 m_comm->AlltoAll(numToSend, numToRecv);
737 std::vector<int> sendOffsetMap(nproc), recvOffsetMap(nproc);
739 sendOffsetMap[0] = 0;
740 recvOffsetMap[0] = 0;
741 for (
int i = 1; i < nproc; ++i)
743 sendOffsetMap[i] = sendOffsetMap[i-1] + numToSend[i-1];
744 recvOffsetMap[i] = recvOffsetMap[i-1] + numToRecv[i-1];
748 int totalSend =
Vmath::Vsum(nproc, &numToSend[0], 1);
749 int totalRecv =
Vmath::Vsum(nproc, &numToRecv[0], 1);
751 std::vector<int> sendData(totalSend), recvData(totalRecv);
754 for (
auto &verts : procMap)
756 for (
auto &vert : verts.second)
758 sendData[cnt++] = vert;
763 m_comm->AlltoAllv(sendData, numToSend, sendOffsetMap,
764 recvData, numToRecv, recvOffsetMap);
768 std::unordered_set<int> uniqueIDs;
769 for (
auto &
id : recvData)
771 uniqueIDs.insert(
id);
775 uniqueIDs.begin(), uniqueIDs.end());
783 "parallel execution");
785 for (boost::tie(vertit, vertit_end) = boost::vertices(
m_graph);
786 vertit != vertit_end; ++vertit)
788 for (boost::tie(adjvertit, adjvertit_end) =
789 boost::adjacent_vertices(*vertit,
m_graph);
790 adjvertit != adjvertit_end; ++adjvertit)
792 if (part[*adjvertit] != part[*vertit])
805 unsigned int cnt = 0;
809 for (i = 0; i < nParts; ++i)
811 cnt = std::count(pPart.begin(), pPart.end(), i);
825 for (i = 0; i < pPart.size(); ++i)
827 pPart[i] = i % nParts;
833 std::vector<unsigned int> &elmtid)
846 int na,
int nb,
int nc)
919 int na,
int nb,
int nc)
922 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
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()
The above copyright notice and this permission notice shall be included.
T Vsum(int n, const T *x, const int incx)
Subtract return sum(x)