Nektar++
Classes | Public Member Functions | Protected Types | Protected Member Functions | Protected Attributes | List of all members
Nektar::SpatialDomains::MeshPartition Class Referenceabstract

#include <MeshPartition.h>

Inheritance diagram for Nektar::SpatialDomains::MeshPartition:
[legend]

Classes

struct  GraphEdgeProperties
 
struct  GraphVertexProperties
 

Public Member Functions

 MeshPartition (const LibUtilities::SessionReaderSharedPtr session, LibUtilities::CommSharedPtr comm, int meshDim, std::map< int, MeshEntity > element, CompositeDescriptor compMap)
 
virtual ~MeshPartition ()
 
void PartitionMesh (int nParts, bool shared=false, bool overlapping=false, int nLocal=0)
 
void PrintPartInfo (std::ostream &out)
 
void GetElementIDs (const int procid, std::vector< unsigned int > &tmp)
 

Protected Types

typedef std::vector< unsigned int > MultiWeight
 
typedef boost::adjacency_list< boost::setS, boost::vecS, boost::undirectedS, GraphVertexProperties, boost::property< boost::edge_index_t, unsigned int, GraphEdgeProperties > > BoostGraph
 
typedef boost::graph_traits< BoostGraph >::vertex_descriptor BoostVertex
 
typedef boost::graph_traits< BoostGraph >::edge_descriptor BoostEdge
 
typedef boost::graph_traits< BoostGraph >::edge_iterator BoostEdgeIterator
 
typedef boost::graph_traits< BoostGraph >::vertex_iterator BoostVertexIterator
 
typedef boost::graph_traits< BoostGraph >::adjacency_iterator BoostAdjacencyIterator
 
typedef std::vector< unsigned int > NumModes
 
typedef std::map< std::string, NumModesNummodesPerField
 

Protected Member Functions

void ReadExpansions ()
 
void ReadConditions ()
 
void WeightElements ()
 
void CreateGraph ()
 
void PartitionGraph (int nParts, bool overlapping=false)
 Partition the graph. More...
 
void CheckPartitions (int nParts, Array< OneD, int > &pPart)
 
int CalculateElementWeight (LibUtilities::ShapeType elmtType, bool bndWeight, int na, int nb, int nc)
 
int CalculateEdgeWeight (LibUtilities::ShapeType elmtType, int na, int nb, int nc)
 
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
 

Protected Attributes

LibUtilities::SessionReaderSharedPtr m_session
 
LibUtilities::CommSharedPtr m_comm
 
int m_dim
 
int m_numFields
 
std::map< int, MeshEntitym_elements
 
std::map< int, MeshEntitym_ghostElmts
 
CompositeDescriptor m_compMap
 
std::map< int, NummodesPerFieldm_expansions
 
std::map< int, LibUtilities::ShapeTypem_shape
 
std::map< std::string, int > m_fieldNameToId
 
std::map< int, MultiWeightm_vertWeights
 
std::map< int, MultiWeightm_vertBndWeights
 
std::map< int, MultiWeightm_edgeWeights
 
BoostGraph m_graph
 
std::map< int, std::vector< unsigned int > > m_localPartition
 
bool m_weightingRequired
 
bool m_weightBnd
 
bool m_weightDofs
 
bool m_shared
 
bool m_parallel
 

Detailed Description

Definition at line 64 of file MeshPartition.h.

Member Typedef Documentation

◆ BoostAdjacencyIterator

typedef boost::graph_traits<BoostGraph>::adjacency_iterator Nektar::SpatialDomains::MeshPartition::BoostAdjacencyIterator
protected

Definition at line 116 of file MeshPartition.h.

◆ BoostEdge

typedef boost::graph_traits<BoostGraph>::edge_descriptor Nektar::SpatialDomains::MeshPartition::BoostEdge
protected

Definition at line 111 of file MeshPartition.h.

◆ BoostEdgeIterator

typedef boost::graph_traits<BoostGraph>::edge_iterator Nektar::SpatialDomains::MeshPartition::BoostEdgeIterator
protected

Definition at line 112 of file MeshPartition.h.

◆ BoostGraph

typedef boost::adjacency_list< boost::setS, boost::vecS, boost::undirectedS, GraphVertexProperties, boost::property<boost::edge_index_t, unsigned int, GraphEdgeProperties> > Nektar::SpatialDomains::MeshPartition::BoostGraph
protected

Definition at line 108 of file MeshPartition.h.

◆ BoostVertex

typedef boost::graph_traits<BoostGraph>::vertex_descriptor Nektar::SpatialDomains::MeshPartition::BoostVertex
protected

Definition at line 110 of file MeshPartition.h.

◆ BoostVertexIterator

typedef boost::graph_traits<BoostGraph>::vertex_iterator Nektar::SpatialDomains::MeshPartition::BoostVertexIterator
protected

Definition at line 114 of file MeshPartition.h.

◆ MultiWeight

typedef std::vector<unsigned int> Nektar::SpatialDomains::MeshPartition::MultiWeight
protected

Definition at line 84 of file MeshPartition.h.

◆ NumModes

typedef std::vector<unsigned int> Nektar::SpatialDomains::MeshPartition::NumModes
protected

Definition at line 118 of file MeshPartition.h.

◆ NummodesPerField

typedef std::map<std::string, NumModes> Nektar::SpatialDomains::MeshPartition::NummodesPerField
protected

Definition at line 119 of file MeshPartition.h.

Constructor & Destructor Documentation

◆ MeshPartition()

Nektar::SpatialDomains::MeshPartition::MeshPartition ( const LibUtilities::SessionReaderSharedPtr  session,
LibUtilities::CommSharedPtr  comm,
int  meshDim,
std::map< int, MeshEntity element,
CompositeDescriptor  compMap 
)

Definition at line 72 of file MeshPartition.cpp.

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),
79 m_parallel(false)
80{
81 // leave the meshpartition method of reading expansions and conditions
84
85 for (auto elIt = m_elements.cbegin(); elIt != m_elements.cend();)
86 {
87 if (elIt->second.ghost)
88 {
89 m_ghostElmts[elIt->first] = elIt->second;
90 elIt = m_elements.erase(elIt);
91 }
92 else
93 {
94 ++elIt;
95 }
96 }
97}
std::map< std::string, int > m_fieldNameToId
std::map< int, MeshEntity > m_ghostElmts
LibUtilities::SessionReaderSharedPtr m_session
std::map< int, MeshEntity > m_elements
LibUtilities::CommSharedPtr m_comm

References m_elements, m_ghostElmts, ReadConditions(), and ReadExpansions().

◆ ~MeshPartition()

Nektar::SpatialDomains::MeshPartition::~MeshPartition ( )
virtual

Definition at line 99 of file MeshPartition.cpp.

100{
101}

Member Function Documentation

◆ CalculateEdgeWeight()

int Nektar::SpatialDomains::MeshPartition::CalculateEdgeWeight ( LibUtilities::ShapeType  elmtType,
int  na,
int  nb,
int  nc 
)
protected

Calculate the number of modes needed for communication when in partition boundary, to be used as weighting for edges. Since we do not know exactly which face this refers to, assume the max order and quad face (for prisms) as arbitrary choices

Definition at line 924 of file MeshPartition.cpp.

926{
927 int weight = 0;
928 int n = std::max(na, std::max(nb, nc));
929 switch (elmtType)
930 {
933 break;
936 break;
939 break;
942 break;
945 weight = n;
946 break;
948 weight = 1;
949 break;
950 default:
951 break;
952 }
953
954 return weight;
955}
int getNumberOfCoefficients(int Na, int Nb)
Definition: ShapeType.hpp:133
int getNumberOfCoefficients(int Na, int Nb)
Definition: ShapeType.hpp:109

References Nektar::LibUtilities::eHexahedron, Nektar::LibUtilities::ePrism, Nektar::LibUtilities::ePyramid, Nektar::LibUtilities::eQuadrilateral, Nektar::LibUtilities::eSegment, Nektar::LibUtilities::eTetrahedron, Nektar::LibUtilities::eTriangle, Nektar::LibUtilities::StdTriData::getNumberOfCoefficients(), and Nektar::LibUtilities::StdQuadData::getNumberOfCoefficients().

Referenced by WeightElements().

◆ CalculateElementWeight()

int Nektar::SpatialDomains::MeshPartition::CalculateElementWeight ( LibUtilities::ShapeType  elmtType,
bool  bndWeight,
int  na,
int  nb,
int  nc 
)
protected

Definition at line 850 of file MeshPartition.cpp.

853{
854 int weight = 0;
855
856 switch (elmtType)
857 {
859 weight = bndWeight
861 na, nb, nc)
862 : LibUtilities::StdTetData::getNumberOfCoefficients(
863 na, nb, nc);
864 break;
866 weight =
867 bndWeight
869 na, nb, nc)
870 : LibUtilities::StdPrismData::getNumberOfCoefficients(
871 na, nb, nc);
872 break;
874 weight = bndWeight
876 na, nb, nc)
877 : LibUtilities::StdHexData::getNumberOfCoefficients(
878 na, nb, nc);
879 break;
881 weight = bndWeight
883 na, nb, nc)
884 : LibUtilities::StdPyrData::getNumberOfCoefficients(
885 na, nb, nc);
886 break;
888 weight =
889 bndWeight
891 nb)
892 : LibUtilities::StdQuadData::getNumberOfCoefficients(na,
893 nb);
894 break;
896 weight =
897 bndWeight
899 nb)
900 : LibUtilities::StdTriData::getNumberOfCoefficients(na, nb);
901 break;
903 weight =
904 bndWeight
906 : LibUtilities::StdSegData::getNumberOfCoefficients(na);
907 break;
909 weight = 1;
910 break;
911 default:
912 break;
913 }
914
915 return weight;
916}
int getNumberOfBndCoefficients(int Na, int Nb, int Nc)
Definition: ShapeType.hpp:161
int getNumberOfBndCoefficients(int Na, int Nb, int Nc)
Definition: ShapeType.hpp:290
int getNumberOfBndCoefficients(int Na, int Nb, int Nc)
Definition: ShapeType.hpp:259
int getNumberOfBndCoefficients(int Na, int Nb)
Definition: ShapeType.hpp:143
int getNumberOfBndCoefficients(int Na, int Nb, int Nc)
Definition: ShapeType.hpp:210
int getNumberOfBndCoefficients(int Na, int Nb)
Definition: ShapeType.hpp:121

References Nektar::LibUtilities::eHexahedron, Nektar::LibUtilities::ePoint, Nektar::LibUtilities::ePrism, Nektar::LibUtilities::ePyramid, Nektar::LibUtilities::eQuadrilateral, Nektar::LibUtilities::eSegment, Nektar::LibUtilities::eTetrahedron, Nektar::LibUtilities::eTriangle, Nektar::LibUtilities::StdSegData::getNumberOfBndCoefficients(), Nektar::LibUtilities::StdTriData::getNumberOfBndCoefficients(), Nektar::LibUtilities::StdQuadData::getNumberOfBndCoefficients(), Nektar::LibUtilities::StdHexData::getNumberOfBndCoefficients(), Nektar::LibUtilities::StdTetData::getNumberOfBndCoefficients(), Nektar::LibUtilities::StdPyrData::getNumberOfBndCoefficients(), Nektar::LibUtilities::StdPrismData::getNumberOfBndCoefficients(), Nektar::LibUtilities::StdSegData::getNumberOfCoefficients(), Nektar::LibUtilities::StdTriData::getNumberOfCoefficients(), Nektar::LibUtilities::StdQuadData::getNumberOfCoefficients(), Nektar::LibUtilities::StdHexData::getNumberOfCoefficients(), Nektar::LibUtilities::StdTetData::getNumberOfCoefficients(), Nektar::LibUtilities::StdPyrData::getNumberOfCoefficients(), and Nektar::LibUtilities::StdPrismData::getNumberOfCoefficients().

Referenced by PrintPartInfo(), and WeightElements().

◆ CheckPartitions()

void Nektar::SpatialDomains::MeshPartition::CheckPartitions ( int  nParts,
Array< OneD, int > &  pPart 
)
protected

Definition at line 808 of file MeshPartition.cpp.

809{
810 unsigned int i = 0;
811 unsigned int cnt = 0;
812 bool valid = true;
813
814 // Check that every process has at least one element assigned
815 for (i = 0; i < nParts; ++i)
816 {
817 cnt = std::count(pPart.begin(), pPart.end(), i);
818 if (cnt == 0)
819 {
820 valid = false;
821 }
822 }
823
824 // If the graph partitioner produced an invalid partition, repartition
825 // naively. Elements are assigned to processes in a round-robin fashion.
826 // It is assumed that graph partitioner failure only occurs when the number
827 // of elements is approx. the number of processes, so this approach should
828 // not be too inefficient communication-wise.
829 if (!valid)
830 {
831 for (i = 0; i < pPart.size(); ++i)
832 {
833 pPart[i] = i % nParts;
834 }
835 }
836}

Referenced by PartitionGraph().

◆ CreateGraph()

void Nektar::SpatialDomains::MeshPartition::CreateGraph ( )
protected

Definition at line 506 of file MeshPartition.cpp.

507{
508 // Maps edge/face to first mesh element id.
509 // On locating second mesh element id, graph edge is created instead.
510 std::unordered_map<int, std::vector<int>> vGraphEdges;
511 int vcnt = 0;
512
513 for (auto &elmt : m_elements)
514 {
515 auto vert = boost::add_vertex(m_graph);
516 m_graph[vert].id = elmt.first;
517 m_graph[vert].partition = 0;
518
520 {
521 m_graph[vert].weight = m_vertWeights[elmt.second.origId];
522 m_graph[vert].bndWeight = m_vertBndWeights[elmt.second.origId];
523 m_graph[vert].edgeWeight = m_edgeWeights[elmt.second.origId];
524 }
525
526 // Process element entries and add graph edges
527 for (auto &eId : elmt.second.list)
528 {
529 // Look to see if we've examined this edge/face before
530 // If so, we've got both graph vertices so add edge
531 auto edgeIt = vGraphEdges.find(eId);
532 if (edgeIt != vGraphEdges.end())
533 {
534 for (auto &iId : edgeIt->second)
535 {
536 BoostEdge e = boost::add_edge(vcnt, iId, m_graph).first;
537 m_graph[e].id = vcnt;
538 }
539 vGraphEdges[eId].push_back(vcnt);
540 }
541 else
542 {
543 std::vector<int> Id;
544 Id.push_back(vcnt);
545 vGraphEdges[eId] = Id;
546 }
547 }
548
549 // Increment counter for graph vertex id.
550 ++vcnt;
551 }
552
553 // Now process ghost elements.
554 for (auto &ghost : m_ghostElmts)
555 {
556 auto vert = boost::add_vertex(m_graph);
557 m_graph[vert].id = ghost.first;
558 m_graph[vert].partition = -1;
559
560 for (auto &facet : ghost.second.list)
561 {
562 auto edgeIt = vGraphEdges.find(facet);
563 if (edgeIt != vGraphEdges.end())
564 {
565 for (auto &iId : edgeIt->second)
566 {
567 BoostEdge e = boost::add_edge(vcnt, iId, m_graph).first;
568 m_graph[e].id = vcnt;
569 }
570 vGraphEdges[facet].push_back(vcnt);
571 }
572 }
573
574 // Increment counter for graph vertex id.
575 ++vcnt;
576 }
577}
std::map< int, MultiWeight > m_edgeWeights
std::map< int, MultiWeight > m_vertBndWeights
std::map< int, MultiWeight > m_vertWeights
boost::graph_traits< BoostGraph >::edge_descriptor BoostEdge

References m_edgeWeights, m_elements, m_ghostElmts, m_graph, m_vertBndWeights, m_vertWeights, and m_weightingRequired.

Referenced by PartitionMesh().

◆ GetElementIDs()

void Nektar::SpatialDomains::MeshPartition::GetElementIDs ( const int  procid,
std::vector< unsigned int > &  tmp 
)

Definition at line 838 of file MeshPartition.cpp.

840{
841 BoostVertexIterator vertit, vertit_end;
842
843 auto it = m_localPartition.find(procid);
844
845 ASSERTL0(it != m_localPartition.end(), "Unable to find local partition");
846
847 elmtid = m_localPartition[procid];
848}
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:208
boost::graph_traits< BoostGraph >::vertex_iterator BoostVertexIterator
std::map< int, std::vector< unsigned int > > m_localPartition

References ASSERTL0, and m_localPartition.

◆ PartitionGraph()

void Nektar::SpatialDomains::MeshPartition::PartitionGraph ( int  nParts,
bool  overlapping = false 
)
protected

Partition the graph.

This routine partitions the graph pGraph into nParts, producing subgraphs that are populated in pLocalPartition. If the overlapping option is set (which is used for post-processing purposes), the resulting partitions are extended to cover neighbouring elements by additional vertex on the dual graph, which produces overlapping partitions (i.e. the intersection of two connected partitions is non-empty).

Parameters
nPartsNumber of partitions.
pLocalPartitionVector of sub-graphs representing each
overlappingTrue if resulting partitions should overlap.

Definition at line 594 of file MeshPartition.cpp.

595{
596 int i;
597 int nGraphVerts = boost::num_vertices(m_graph);
598 int nGhost = m_ghostElmts.size();
599 int nLocal = nGraphVerts - nGhost;
600
601 int ncon = 1;
603 {
604 ncon = 2;
605 }
606
607 // Convert boost graph into CSR format
608 BoostVertexIterator vertit, vertit_end;
609 BoostAdjacencyIterator adjvertit, adjvertit_end;
610 Array<OneD, int> part(nGraphVerts, 0);
611
612 if (m_comm->GetRowComm()->TreatAsRankZero() || m_parallel)
613 {
614 int acnt = 0;
615 int vcnt = 0;
616 int nWeight = ncon * nLocal;
617
618 Array<OneD, int> xadj(nLocal + 1);
619 std::vector<int> adjncy_tmp, adjwgt_tmp;
620 Array<OneD, int> vwgt(nWeight, 1);
621 Array<OneD, int> vsize(nLocal, 1);
622
623 // Initialise starting point of adjacency array.
624 xadj[0] = 0;
625
626 for (boost::tie(vertit, vertit_end) = boost::vertices(m_graph);
627 vertit != vertit_end && vcnt < nLocal; ++vertit)
628 {
629 for (boost::tie(adjvertit, adjvertit_end) =
630 boost::adjacent_vertices(*vertit, m_graph);
631 adjvertit != adjvertit_end; ++adjvertit, ++acnt)
632 {
633 adjncy_tmp.push_back(m_graph[*adjvertit].id);
635 {
636 adjwgt_tmp.push_back(m_graph[*vertit].edgeWeight[0]);
637 }
638 else
639 {
640 adjwgt_tmp.push_back(1);
641 }
642 }
643
644 xadj[++vcnt] = acnt;
645
647 {
648 int ccnt = 0;
649 if (m_weightDofs)
650 {
651 vwgt[ncon * (vcnt - 1) + ccnt] = m_graph[*vertit].weight[0];
652 ccnt++;
653 }
654 if (m_weightBnd)
655 {
656 vwgt[ncon * (vcnt - 1) + ccnt] =
657 m_graph[*vertit].bndWeight[0];
658 }
659 }
660 }
661
662 Array<OneD, int> adjncy(adjncy_tmp.size(), &adjncy_tmp[0]);
663 Array<OneD, int> adjwgt(adjwgt_tmp.size(), &adjwgt_tmp[0]);
664
665 // Call partitioner to partition graph
666 int vol = 0;
667
668 try
669 {
670 //////////////////////////////////////////////////////
671 // On a cartesian communicator do mesh partition just on the first
672 // column
673 // so there is no doubt the partitions are all the same in all the
674 // columns
675 if (m_comm->GetColumnComm()->GetRank() == 0)
676 {
677 // Attempt partitioning.
678 v_PartitionGraphImpl(nLocal, ncon, xadj, adjncy, vwgt, vsize,
679 adjwgt, nParts, vol, part);
680
681 // Check the partitioner produced a valid partition and fix if
682 // not.
683 if (!m_parallel)
684 {
685 CheckPartitions(nParts, part);
686 }
687
688 if (!m_shared)
689 {
690 // distribute among columns
691 for (i = 1; i < m_comm->GetColumnComm()->GetSize(); ++i)
692 {
693 m_comm->GetColumnComm()->Send(i, part);
694 }
695 }
696 }
697 else
698 {
699 m_comm->GetColumnComm()->Recv(0, part);
700 }
701 }
702 catch (...)
703 {
704 NEKERROR(ErrorUtil::efatal, "Error in calling graph partitioner.");
705 }
706 }
707 else if (!m_parallel)
708 {
709 m_comm->GetRowComm()->Recv(0, part);
710 }
711
712 // Create storage for this (and possibly other) process's partitions.
713 i = 0;
714
715 if (!m_parallel)
716 {
717 // Populate subgraph(s) for each rank.
718 for (boost::tie(vertit, vertit_end) = boost::vertices(m_graph);
719 vertit != vertit_end; ++vertit, ++i)
720 {
721 m_localPartition[part[i]].push_back(m_graph[*vertit].id);
722 }
723 }
724 else
725 {
726 // Figure out how many vertices we're going to get from each processor.
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;
731
732 for (boost::tie(vertit, vertit_end) = boost::vertices(m_graph);
733 vertit != vertit_end && i < nLocal; ++vertit, ++i)
734 {
735 int toProc = part[i];
736 numToSend[toProc]++;
737 procMap[toProc].push_back(m_graph[*vertit].id);
738 }
739
740 m_comm->GetSpaceComm()->AlltoAll(numToSend, numToRecv);
741
742 // Build offsets for all-to-all communication
743 std::vector<int> sendOffsetMap(nproc), recvOffsetMap(nproc);
744
745 sendOffsetMap[0] = 0;
746 recvOffsetMap[0] = 0;
747 for (int i = 1; i < nproc; ++i)
748 {
749 sendOffsetMap[i] = sendOffsetMap[i - 1] + numToSend[i - 1];
750 recvOffsetMap[i] = recvOffsetMap[i - 1] + numToRecv[i - 1];
751 }
752
753 // Build data to send
754 int totalSend = Vmath::Vsum(nproc, &numToSend[0], 1);
755 int totalRecv = Vmath::Vsum(nproc, &numToRecv[0], 1);
756
757 std::vector<int> sendData(totalSend), recvData(totalRecv);
758
759 int cnt = 0;
760 for (auto &verts : procMap)
761 {
762 for (auto &vert : verts.second)
763 {
764 sendData[cnt++] = vert;
765 }
766 }
767
768 // Send ID map to processors
769 m_comm->GetSpaceComm()->AlltoAllv(sendData, numToSend, sendOffsetMap,
770 recvData, numToRecv, recvOffsetMap);
771
772 // Finally, populate m_localPartition for this processor. Could contain
773 // duplicates so erase those first.
774 std::unordered_set<int> uniqueIDs;
775 for (auto &id : recvData)
776 {
777 uniqueIDs.insert(id);
778 }
779
780 m_localPartition[rank].insert(m_localPartition[rank].begin(),
781 uniqueIDs.begin(), uniqueIDs.end());
782 }
783
784 // If the overlapping option is set (for post-processing purposes),
785 // add vertices that correspond to the neighbouring elements.
786 if (overlapping)
787 {
788 ASSERTL0(!m_parallel, "Overlapping partitioning not supported in "
789 "parallel execution");
790
791 for (boost::tie(vertit, vertit_end) = boost::vertices(m_graph);
792 vertit != vertit_end; ++vertit)
793 {
794 for (boost::tie(adjvertit, adjvertit_end) =
795 boost::adjacent_vertices(*vertit, m_graph);
796 adjvertit != adjvertit_end; ++adjvertit)
797 {
798 if (part[*adjvertit] != part[*vertit])
799 {
800 m_localPartition[part[*vertit]].push_back(
801 m_graph[*adjvertit].id);
802 }
803 }
804 }
805 }
806}
#define NEKERROR(type, msg)
Assert Level 0 – Fundamental assert which is used whether in FULLDEBUG, DEBUG or OPT compilation mode...
Definition: ErrorUtil.hpp:202
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
boost::graph_traits< BoostGraph >::adjacency_iterator BoostAdjacencyIterator
void CheckPartitions(int nParts, Array< OneD, int > &pPart)
T Vsum(int n, const T *x, const int incx)
Subtract return sum(x)
Definition: Vmath.hpp:608

References ASSERTL0, CheckPartitions(), Nektar::ErrorUtil::efatal, m_comm, m_ghostElmts, m_graph, m_localPartition, m_parallel, m_shared, m_weightBnd, m_weightDofs, m_weightingRequired, NEKERROR, v_PartitionGraphImpl(), and Vmath::Vsum().

Referenced by PartitionMesh().

◆ PartitionMesh()

void Nektar::SpatialDomains::MeshPartition::PartitionMesh ( int  nParts,
bool  shared = false,
bool  overlapping = false,
int  nLocal = 0 
)

Definition at line 103 of file MeshPartition.cpp.

105{
106 ASSERTL0(m_parallel || m_elements.size() >= nParts,
107 "Too few elements for this many processes.");
108 m_shared = shared;
109
110 ASSERTL0(!m_parallel || shared,
111 "Parallel partitioning requires shared filesystem.");
112
114 {
116 }
117 CreateGraph();
118
119 PartitionGraph(nParts, overlapping);
120}
void PartitionGraph(int nParts, bool overlapping=false)
Partition the graph.

References ASSERTL0, CreateGraph(), m_elements, m_parallel, m_shared, m_weightingRequired, PartitionGraph(), and WeightElements().

◆ PrintPartInfo()

void Nektar::SpatialDomains::MeshPartition::PrintPartInfo ( std::ostream &  out)

Definition at line 307 of file MeshPartition.cpp.

308{
309 int nElmt = boost::num_vertices(m_graph);
310 int nPart = m_localPartition.size();
311
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;
316
317 BoostVertexIterator vertit, vertit_end;
318 std::vector<int> partElmtCount(nPart, 0);
319 std::vector<int> partLocCount(nPart, 0);
320 std::vector<int> partBndCount(nPart, 0);
321
322 std::map<int, int> elmtSizes;
323 std::map<int, int> elmtBndSizes;
324
325 for (std::map<int, NummodesPerField>::iterator expIt = m_expansions.begin();
326 expIt != m_expansions.end(); ++expIt)
327 {
328 int elid = expIt->first;
329 NummodesPerField npf = expIt->second;
330
331 for (NummodesPerField::iterator it = npf.begin(); it != npf.end(); ++it)
332 {
333 ASSERTL0(it->second.size() == m_dim,
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");
338
339 int na = it->second[0];
340 int nb = 0;
341 int nc = 0;
342 if (m_dim >= 2)
343 {
344 nb = it->second[1];
345 }
346 if (m_dim == 3)
347 {
348 nc = it->second[2];
349 }
350
351 elmtSizes[elid] =
352 CalculateElementWeight(m_shape[elid], false, na, nb, nc);
353 elmtBndSizes[elid] =
354 CalculateElementWeight(m_shape[elid], true, na, nb, nc);
355 }
356 }
357
358 for (boost::tie(vertit, vertit_end) = boost::vertices(m_graph);
359 vertit != vertit_end; ++vertit)
360 {
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];
365 }
366
367 for (int i = 0; i < nPart; ++i)
368 {
369 out << i << " " << partElmtCount[i] << " " << partLocCount[i] << " "
370 << partBndCount[i] << std::endl;
371 }
372}
std::map< int, NummodesPerField > m_expansions
int CalculateElementWeight(LibUtilities::ShapeType elmtType, bool bndWeight, int na, int nb, int nc)
std::map< std::string, NumModes > NummodesPerField
std::map< int, LibUtilities::ShapeType > m_shape

References ASSERTL0, CalculateElementWeight(), m_dim, m_expansions, m_graph, m_localPartition, and m_shape.

◆ ReadConditions()

void Nektar::SpatialDomains::MeshPartition::ReadConditions ( )
protected

Definition at line 374 of file MeshPartition.cpp.

375{
376 if (!m_session->DefinesElement("Nektar/Conditions/SolverInfo"))
377 {
378 // No SolverInfo = no change of default action to weight
379 // mesh graph.
380 return;
381 }
382
383 TiXmlElement *solverInfoElement =
384 m_session->GetElement("Nektar/Conditions/SolverInfo");
385
386 // Use fine-level solver info for mesh partition (Parallel-in-Time)
388
389 TiXmlElement *solverInfo = solverInfoElement->FirstChildElement("I");
390 ASSERTL0(solverInfo, "Cannot read SolverInfo tags");
391
392 while (solverInfo)
393 {
394 // read the property name
395 ASSERTL0(solverInfo->Attribute("PROPERTY"),
396 "Missing PROPERTY attribute in solver info "
397 "section. ");
398 std::string solverProperty = solverInfo->Attribute("PROPERTY");
399 ASSERTL0(!solverProperty.empty(),
400 "Solver info properties must have a non-empty "
401 "name. ");
402 // make sure that solver property is capitalised
403 std::string solverPropertyUpper = boost::to_upper_copy(solverProperty);
404
405 // read the value
406 ASSERTL0(solverInfo->Attribute("VALUE"),
407 "Missing VALUE attribute in solver info section. ");
408 std::string solverValue = solverInfo->Attribute("VALUE");
409 ASSERTL0(!solverValue.empty(),
410 "Solver info properties must have a non-empty value");
411 // make sure that property value is capitalised
412 std::string propertyValueUpper = boost::to_upper_copy(solverValue);
413
414 if (solverPropertyUpper == "WEIGHTPARTITIONS")
415 {
416 if (propertyValueUpper == "DOF")
417 {
418 m_weightingRequired = true;
419 m_weightDofs = true;
420 }
421 else if (propertyValueUpper == "BOUNDARY")
422 {
423 m_weightingRequired = true;
424 m_weightBnd = true;
425 }
426 else if (propertyValueUpper == "BOTH")
427 {
428 m_weightingRequired = true;
429 m_weightDofs = true;
430 m_weightBnd = true;
431 }
432 return;
433 }
434 solverInfo = solverInfo->NextSiblingElement("I");
435 }
436}
static void GetXMLElementTimeLevel(TiXmlElement *&element, const size_t timeLevel, const bool enableCheck=true)
Get XML elment time level (Parallel-in-Time)

References ASSERTL0, Nektar::LibUtilities::SessionReader::GetXMLElementTimeLevel(), m_session, m_weightBnd, m_weightDofs, and m_weightingRequired.

Referenced by MeshPartition().

◆ ReadExpansions()

void Nektar::SpatialDomains::MeshPartition::ReadExpansions ( )
protected

Definition at line 122 of file MeshPartition.cpp.

123{
124 // Find the Expansions tag
125 TiXmlElement *expansionTypes = m_session->GetElement("Nektar/Expansions");
126
127 // Use fine-level expansion for mesh partition (Parallel-in-Time)
129
130 // Find the Expansion type
131 TiXmlElement *expansion = expansionTypes->FirstChildElement();
132
133 std::string expType = expansion->Value();
134
135 // Expansiontypes will contain plenty of data, where relevant at this stage
136 // are composite ID(s) that this expansion type describes, nummodes and a
137 // list of fields that this expansion relates to. If this does not exist the
138 // variable is only set to "DefaultVar".
139 if (expType == "E")
140 {
141 while (expansion)
142 {
143 std::vector<unsigned int> composite;
144 std::vector<unsigned int> nummodes;
145 std::vector<std::string> fieldName;
146
147 const char *nModesStr = expansion->Attribute("NUMMODES");
148 ASSERTL0(nModesStr,
149 "NUMMODES was not defined in EXPANSION section of input");
150 std::string numModesStr = nModesStr;
151 bool valid =
152 ParseUtils::GenerateVector(numModesStr.c_str(), nummodes);
153 ASSERTL0(valid, "Unable to correctly parse the number of modes.");
154
155 if (nummodes.size() == 1)
156 {
157 for (int i = 1; i < m_dim; i++)
158 {
159 nummodes.push_back(nummodes[0]);
160 }
161 }
162 ASSERTL0(nummodes.size() == m_dim,
163 "Number of modes should match mesh dimension");
164
165 const char *fStr = expansion->Attribute("FIELDS");
166 if (fStr)
167 {
168 std::string fieldStr = fStr;
169 bool valid =
170 ParseUtils::GenerateVector(fieldStr.c_str(), fieldName);
171 ASSERTL0(valid, "Unable to correctly parse the field string in "
172 "ExpansionTypes.");
173
174 for (int i = 0; i < fieldName.size(); ++i)
175 {
176 if (m_fieldNameToId.count(fieldName[i]) == 0)
177 {
178 int k = m_fieldNameToId.size();
179 m_fieldNameToId[fieldName[i]] = k;
180 m_numFields++;
181 }
182 }
183 }
184 else
185 {
186 fieldName.push_back("DefaultVar");
187 int k = m_fieldNameToId.size();
188
189 if (m_fieldNameToId.count("DefaultVar") == 0)
190 {
191 ASSERTL0(
192 k == 0,
193 "Omitting field variables and explicitly listing "
194 "them in different ExpansionTypes is wrong practise");
195
196 m_fieldNameToId["DefaultVar"] = k;
197 m_numFields++;
198 }
199 }
200
201 std::string compositeStr = expansion->Attribute("COMPOSITE");
202 ASSERTL0(compositeStr.length() > 3,
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);
208 bool parseGood = ParseUtils::GenerateSeqVector(
209 compositeListStr.c_str(), composite);
210 ASSERTL0(parseGood && !composite.empty(),
211 (std::string("Unable to read composite index range: ") +
212 compositeListStr)
213 .c_str());
214
215 // construct mapping (elmt id, field name) -> nummodes
216 for (int i = 0; i < composite.size(); ++i)
217 {
218 auto &shapeType = m_compMap[composite[i]].first;
219 auto &elmtIds = m_compMap[composite[i]].second;
220
221 for (int j = 0; j < fieldName.size(); j++)
222 {
223 for (auto &elid : elmtIds)
224 {
225 m_expansions[elid][fieldName[j]] = nummodes;
226 m_shape[elid] = shapeType;
227 }
228 }
229 }
230
231 expansion = expansion->NextSiblingElement("E");
232 }
233 }
234 else if (expType == "F")
235 {
236 ASSERTL0(expansion->Attribute("FILE"),
237 "Attribute FILE expected for type F expansion");
238 std::string filenameStr = expansion->Attribute("FILE");
239 ASSERTL0(!filenameStr.empty(),
240 "A filename must be specified for the FILE "
241 "attribute of expansion");
242
243 // Create fieldIO object to load file
244 // need a serial communicator to avoid problems with
245 // shared file system
248 std::string iofmt =
249 LibUtilities::FieldIO::GetFileType(filenameStr, comm);
252 iofmt, comm, m_session->GetSharedFilesystem());
253
254 // Load field definitions from file
255 std::vector<LibUtilities::FieldDefinitionsSharedPtr> fielddefs;
256 f->Import(filenameStr, fielddefs);
257
258 // Parse field definitions
259 for (int i = 0; i < fielddefs.size(); ++i)
260 {
261 // Name of fields
262 for (int j = 0; j < fielddefs[i]->m_fields.size(); ++j)
263 {
264 std::string fieldName = fielddefs[i]->m_fields[j];
265 if (m_fieldNameToId.count(fieldName) == 0)
266 {
267 int k = m_fieldNameToId.size();
268 m_fieldNameToId[fieldName] = k;
269 m_numFields++;
270 }
271 }
272 // Number of modes and shape for each element
273 int numHomoDir = fielddefs[i]->m_numHomogeneousDir;
274 int cnt = 0;
275 for (int j = 0; j < fielddefs[i]->m_elementIDs.size(); ++j)
276 {
277 int elid = fielddefs[i]->m_elementIDs[j];
278 std::vector<unsigned int> nummodes;
279 for (int k = 0; k < m_dim; k++)
280 {
281 nummodes.push_back(fielddefs[i]->m_numModes[cnt++]);
282 }
283 if (fielddefs[i]->m_uniOrder)
284 {
285 cnt = 0;
286 }
287 else
288 {
289 cnt += numHomoDir;
290 }
291 for (int k = 0; k < fielddefs[i]->m_fields.size(); k++)
292 {
293 std::string fieldName = fielddefs[i]->m_fields[k];
294 m_expansions[elid][fieldName] = nummodes;
295 }
296 m_shape[elid] = fielddefs[i]->m_shapeType;
297 }
298 }
299 }
300 else
301 {
302 ASSERTL0(false,
303 "Expansion type not defined or not supported at the moment");
304 }
305}
static const std::string GetFileType(const std::string &filename, CommSharedPtr comm)
Determine file type of given input file.
Definition: FieldIO.cpp:95
tBaseSharedPtr CreateInstance(tKey idKey, tParam... args)
Create an instance of the class referred to by idKey.
Definition: NekFactory.hpp:143
static bool GenerateVector(const std::string &str, std::vector< T > &out)
Takes a comma-separated string and converts it to entries in a vector.
Definition: ParseUtils.cpp:130
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.
Definition: ParseUtils.cpp:104
std::shared_ptr< FieldIO > FieldIOSharedPtr
Definition: FieldIO.h:322
FieldIOFactory & GetFieldIOFactory()
Returns the FieldIO factory.
Definition: FieldIO.cpp:70
CommFactory & GetCommFactory()
std::shared_ptr< Comm > CommSharedPtr
Pointer to a Communicator object.
Definition: Comm.h:55

References ASSERTL0, Nektar::LibUtilities::NekFactory< tKey, tBase, tParam >::CreateInstance(), Nektar::ParseUtils::GenerateSeqVector(), Nektar::ParseUtils::GenerateVector(), Nektar::LibUtilities::GetCommFactory(), Nektar::LibUtilities::GetFieldIOFactory(), Nektar::LibUtilities::FieldIO::GetFileType(), Nektar::LibUtilities::SessionReader::GetXMLElementTimeLevel(), m_compMap, m_dim, m_expansions, m_fieldNameToId, m_numFields, m_session, and m_shape.

Referenced by MeshPartition().

◆ v_PartitionGraphImpl()

virtual void Nektar::SpatialDomains::MeshPartition::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 
)
protectedpure virtual

◆ WeightElements()

void Nektar::SpatialDomains::MeshPartition::WeightElements ( )
protected

Definition at line 452 of file MeshPartition.cpp.

453{
454 std::vector<unsigned int> weight(m_numFields, 1);
455 std::map<int, MeshEntity>::iterator eIt;
456 for (eIt = m_elements.begin(); eIt != m_elements.end(); ++eIt)
457 {
458 m_vertWeights[eIt->second.origId] = weight;
459 m_vertBndWeights[eIt->second.origId] = weight;
460 m_edgeWeights[eIt->second.origId] = weight;
461 }
462
463 for (std::map<int, NummodesPerField>::iterator expIt = m_expansions.begin();
464 expIt != m_expansions.end(); ++expIt)
465 {
466 int elid = expIt->first;
467 NummodesPerField npf = expIt->second;
468
469 for (NummodesPerField::iterator it = npf.begin(); it != npf.end(); ++it)
470 {
471 ASSERTL0(it->second.size() == m_dim,
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");
476
477 int na = it->second[0];
478 int nb = 0;
479 int nc = 0;
480 if (m_dim >= 2)
481 {
482 nb = it->second[1];
483 }
484 if (m_dim == 3)
485 {
486 nc = it->second[2];
487 }
488
489 // Assume for parallel partitioning that this is just missing from
490 // our partition.
491 if (m_vertWeights.find(elid) == m_vertWeights.end())
492 {
493 continue;
494 }
495
496 m_vertWeights[elid][m_fieldNameToId[it->first]] =
497 CalculateElementWeight(m_shape[elid], false, na, nb, nc);
498 m_vertBndWeights[elid][m_fieldNameToId[it->first]] =
499 CalculateElementWeight(m_shape[elid], true, na, nb, nc);
500 m_edgeWeights[elid][m_fieldNameToId[it->first]] =
501 CalculateEdgeWeight(m_shape[elid], na, nb, nc);
502 }
503 } // for i
504}
int CalculateEdgeWeight(LibUtilities::ShapeType elmtType, int na, int nb, int nc)

References ASSERTL0, CalculateEdgeWeight(), CalculateElementWeight(), m_dim, m_edgeWeights, m_elements, m_expansions, m_fieldNameToId, m_numFields, m_shape, m_vertBndWeights, and m_vertWeights.

Referenced by PartitionMesh().

Member Data Documentation

◆ m_comm

LibUtilities::CommSharedPtr Nektar::SpatialDomains::MeshPartition::m_comm
protected

◆ m_compMap

CompositeDescriptor Nektar::SpatialDomains::MeshPartition::m_compMap
protected

Definition at line 129 of file MeshPartition.h.

Referenced by ReadExpansions().

◆ m_dim

int Nektar::SpatialDomains::MeshPartition::m_dim
protected

Definition at line 124 of file MeshPartition.h.

Referenced by PrintPartInfo(), ReadExpansions(), and WeightElements().

◆ m_edgeWeights

std::map<int, MultiWeight> Nektar::SpatialDomains::MeshPartition::m_edgeWeights
protected

Definition at line 141 of file MeshPartition.h.

Referenced by CreateGraph(), and WeightElements().

◆ m_elements

std::map<int, MeshEntity> Nektar::SpatialDomains::MeshPartition::m_elements
protected

Definition at line 127 of file MeshPartition.h.

Referenced by CreateGraph(), MeshPartition(), PartitionMesh(), and WeightElements().

◆ m_expansions

std::map<int, NummodesPerField> Nektar::SpatialDomains::MeshPartition::m_expansions
protected

Definition at line 133 of file MeshPartition.h.

Referenced by PrintPartInfo(), ReadExpansions(), and WeightElements().

◆ m_fieldNameToId

std::map<std::string, int> Nektar::SpatialDomains::MeshPartition::m_fieldNameToId
protected

Definition at line 138 of file MeshPartition.h.

Referenced by ReadExpansions(), and WeightElements().

◆ m_ghostElmts

std::map<int, MeshEntity> Nektar::SpatialDomains::MeshPartition::m_ghostElmts
protected

Definition at line 128 of file MeshPartition.h.

Referenced by CreateGraph(), MeshPartition(), and PartitionGraph().

◆ m_graph

BoostGraph Nektar::SpatialDomains::MeshPartition::m_graph
protected

Definition at line 143 of file MeshPartition.h.

Referenced by CreateGraph(), PartitionGraph(), and PrintPartInfo().

◆ m_localPartition

std::map<int, std::vector<unsigned int> > Nektar::SpatialDomains::MeshPartition::m_localPartition
protected

Definition at line 144 of file MeshPartition.h.

Referenced by GetElementIDs(), PartitionGraph(), and PrintPartInfo().

◆ m_numFields

int Nektar::SpatialDomains::MeshPartition::m_numFields
protected

Definition at line 125 of file MeshPartition.h.

Referenced by ReadExpansions(), and WeightElements().

◆ m_parallel

bool Nektar::SpatialDomains::MeshPartition::m_parallel
protected

◆ m_session

LibUtilities::SessionReaderSharedPtr Nektar::SpatialDomains::MeshPartition::m_session
protected

Definition at line 121 of file MeshPartition.h.

Referenced by ReadConditions(), and ReadExpansions().

◆ m_shape

std::map<int, LibUtilities::ShapeType> Nektar::SpatialDomains::MeshPartition::m_shape
protected

Definition at line 136 of file MeshPartition.h.

Referenced by PrintPartInfo(), ReadExpansions(), and WeightElements().

◆ m_shared

bool Nektar::SpatialDomains::MeshPartition::m_shared
protected

Definition at line 149 of file MeshPartition.h.

Referenced by PartitionGraph(), and PartitionMesh().

◆ m_vertBndWeights

std::map<int, MultiWeight> Nektar::SpatialDomains::MeshPartition::m_vertBndWeights
protected

Definition at line 140 of file MeshPartition.h.

Referenced by CreateGraph(), and WeightElements().

◆ m_vertWeights

std::map<int, MultiWeight> Nektar::SpatialDomains::MeshPartition::m_vertWeights
protected

Definition at line 139 of file MeshPartition.h.

Referenced by CreateGraph(), and WeightElements().

◆ m_weightBnd

bool Nektar::SpatialDomains::MeshPartition::m_weightBnd
protected

Definition at line 147 of file MeshPartition.h.

Referenced by PartitionGraph(), and ReadConditions().

◆ m_weightDofs

bool Nektar::SpatialDomains::MeshPartition::m_weightDofs
protected

Definition at line 148 of file MeshPartition.h.

Referenced by PartitionGraph(), and ReadConditions().

◆ m_weightingRequired

bool Nektar::SpatialDomains::MeshPartition::m_weightingRequired
protected

Definition at line 146 of file MeshPartition.h.

Referenced by CreateGraph(), PartitionGraph(), PartitionMesh(), and ReadConditions().