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 66 of file MeshPartition.h.

Member Typedef Documentation

◆ BoostAdjacencyIterator

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

Definition at line 118 of file MeshPartition.h.

◆ BoostEdge

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

Definition at line 113 of file MeshPartition.h.

◆ BoostEdgeIterator

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

Definition at line 114 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 110 of file MeshPartition.h.

◆ BoostVertex

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

Definition at line 112 of file MeshPartition.h.

◆ BoostVertexIterator

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

Definition at line 116 of file MeshPartition.h.

◆ MultiWeight

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

Definition at line 86 of file MeshPartition.h.

◆ NumModes

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

Definition at line 120 of file MeshPartition.h.

◆ NummodesPerField

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

Definition at line 121 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 76 of file MeshPartition.cpp.

80 : m_session(session), m_comm(comm), m_dim(meshDim), m_numFields(0),
81 m_elements(element), m_compMap(compMap), m_fieldNameToId(),
82 m_weightingRequired(false), m_weightBnd(false), m_weightDofs(false),
83 m_parallel(false)
84{
85 // leave the meshpartition method of reading expansions and conditions
88
89 for (auto elIt = m_elements.cbegin(); elIt != m_elements.cend();)
90 {
91 if (elIt->second.ghost)
92 {
93 m_ghostElmts[elIt->first] = elIt->second;
94 elIt = m_elements.erase(elIt);
95 }
96 else
97 {
98 ++elIt;
99 }
100 }
101}
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 103 of file MeshPartition.cpp.

104{
105}

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 934 of file MeshPartition.cpp.

936{
937 int weight = 0;
938 int n = std::max(na, std::max(nb, nc));
939 switch (elmtType)
940 {
943 break;
946 break;
949 break;
952 break;
955 weight = n;
956 break;
958 weight = 1;
959 break;
960 default:
961 break;
962 }
963
964 return weight;
965}
int getNumberOfCoefficients(int Na, int Nb)
Definition: ShapeType.hpp:138
int getNumberOfCoefficients(int Na, int Nb)
Definition: ShapeType.hpp:114

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 860 of file MeshPartition.cpp.

863{
864 int weight = 0;
865
866 switch (elmtType)
867 {
869 weight = bndWeight
871 na, nb, nc)
872 : LibUtilities::StdTetData::getNumberOfCoefficients(
873 na, nb, nc);
874 break;
876 weight =
877 bndWeight
879 na, nb, nc)
880 : LibUtilities::StdPrismData::getNumberOfCoefficients(
881 na, nb, nc);
882 break;
884 weight = bndWeight
886 na, nb, nc)
887 : LibUtilities::StdHexData::getNumberOfCoefficients(
888 na, nb, nc);
889 break;
891 weight = bndWeight
893 na, nb, nc)
894 : LibUtilities::StdPyrData::getNumberOfCoefficients(
895 na, nb, nc);
896 break;
898 weight =
899 bndWeight
901 nb)
902 : LibUtilities::StdQuadData::getNumberOfCoefficients(na,
903 nb);
904 break;
906 weight =
907 bndWeight
909 nb)
910 : LibUtilities::StdTriData::getNumberOfCoefficients(na, nb);
911 break;
913 weight =
914 bndWeight
916 : LibUtilities::StdSegData::getNumberOfCoefficients(na);
917 break;
919 weight = 1;
920 break;
921 default:
922 break;
923 }
924
925 return weight;
926}
int getNumberOfBndCoefficients(int Na, int Nb, int Nc)
Definition: ShapeType.hpp:166
int getNumberOfBndCoefficients(int Na, int Nb, int Nc)
Definition: ShapeType.hpp:295
int getNumberOfBndCoefficients(int Na, int Nb, int Nc)
Definition: ShapeType.hpp:264
int getNumberOfBndCoefficients(int Na, int Nb)
Definition: ShapeType.hpp:148
int getNumberOfBndCoefficients(int Na, int Nb, int Nc)
Definition: ShapeType.hpp:215
int getNumberOfBndCoefficients(int Na, int Nb)
Definition: ShapeType.hpp:126

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 818 of file MeshPartition.cpp.

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

Referenced by PartitionGraph().

◆ CreateGraph()

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

Definition at line 516 of file MeshPartition.cpp.

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

850{
851 BoostVertexIterator vertit, vertit_end;
852
853 auto it = m_localPartition.find(procid);
854
855 ASSERTL0(it != m_localPartition.end(), "Unable to find local partition");
856
857 elmtid = m_localPartition[procid];
858}
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:215
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 604 of file MeshPartition.cpp.

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

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 107 of file MeshPartition.cpp.

109{
110 boost::ignore_unused(nLocal);
111
112 ASSERTL0(m_parallel || m_elements.size() >= nParts,
113 "Too few elements for this many processes.");
114 m_shared = shared;
115
116 ASSERTL0(!m_parallel || shared,
117 "Parallel partitioning requires shared filesystem.");
118
120 {
122 }
123 CreateGraph();
124
125 PartitionGraph(nParts, overlapping);
126}
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 313 of file MeshPartition.cpp.

314{
315 int nElmt = boost::num_vertices(m_graph);
316 int nPart = m_localPartition.size();
317
318 out << "# Partition information:" << std::endl;
319 out << "# No. elements : " << nElmt << std::endl;
320 out << "# No. partitions: " << nPart << std::endl;
321 out << "# ID nElmt nLocDof nBndDof" << std::endl;
322
323 BoostVertexIterator vertit, vertit_end;
324 std::vector<int> partElmtCount(nPart, 0);
325 std::vector<int> partLocCount(nPart, 0);
326 std::vector<int> partBndCount(nPart, 0);
327
328 std::map<int, int> elmtSizes;
329 std::map<int, int> elmtBndSizes;
330
331 for (std::map<int, NummodesPerField>::iterator expIt = m_expansions.begin();
332 expIt != m_expansions.end(); ++expIt)
333 {
334 int elid = expIt->first;
335 NummodesPerField npf = expIt->second;
336
337 for (NummodesPerField::iterator it = npf.begin(); it != npf.end(); ++it)
338 {
339 ASSERTL0(it->second.size() == m_dim,
340 " Number of directional"
341 " modes in expansion spec for element id = " +
342 boost::lexical_cast<std::string>(elid) +
343 " and field " +
344 boost::lexical_cast<std::string>(it->first) +
345 " does not correspond to mesh dimension");
346
347 int na = it->second[0];
348 int nb = 0;
349 int nc = 0;
350 if (m_dim >= 2)
351 {
352 nb = it->second[1];
353 }
354 if (m_dim == 3)
355 {
356 nc = it->second[2];
357 }
358
359 elmtSizes[elid] =
360 CalculateElementWeight(m_shape[elid], false, na, nb, nc);
361 elmtBndSizes[elid] =
362 CalculateElementWeight(m_shape[elid], true, na, nb, nc);
363 }
364 }
365
366 for (boost::tie(vertit, vertit_end) = boost::vertices(m_graph);
367 vertit != vertit_end; ++vertit)
368 {
369 int partId = m_graph[*vertit].partition;
370 partElmtCount[partId]++;
371 partLocCount[partId] += elmtSizes[m_graph[*vertit].id];
372 partBndCount[partId] += elmtBndSizes[m_graph[*vertit].id];
373 }
374
375 for (int i = 0; i < nPart; ++i)
376 {
377 out << i << " " << partElmtCount[i] << " " << partLocCount[i] << " "
378 << partBndCount[i] << std::endl;
379 }
380}
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 382 of file MeshPartition.cpp.

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

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

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 460 of file MeshPartition.cpp.

461{
462 std::vector<unsigned int> weight(m_numFields, 1);
463 std::map<int, MeshEntity>::iterator eIt;
464 for (eIt = m_elements.begin(); eIt != m_elements.end(); ++eIt)
465 {
466 m_vertWeights[eIt->second.origId] = weight;
467 m_vertBndWeights[eIt->second.origId] = weight;
468 m_edgeWeights[eIt->second.origId] = weight;
469 }
470
471 for (std::map<int, NummodesPerField>::iterator expIt = m_expansions.begin();
472 expIt != m_expansions.end(); ++expIt)
473 {
474 int elid = expIt->first;
475 NummodesPerField npf = expIt->second;
476
477 for (NummodesPerField::iterator it = npf.begin(); it != npf.end(); ++it)
478 {
479 ASSERTL0(it->second.size() == m_dim,
480 " Number of directional"
481 " modes in expansion spec for element id = " +
482 boost::lexical_cast<std::string>(elid) +
483 " and field " +
484 boost::lexical_cast<std::string>(it->first) +
485 " does not correspond to mesh dimension");
486
487 int na = it->second[0];
488 int nb = 0;
489 int nc = 0;
490 if (m_dim >= 2)
491 {
492 nb = it->second[1];
493 }
494 if (m_dim == 3)
495 {
496 nc = it->second[2];
497 }
498
499 // Assume for parallel partitioning that this is just missing from
500 // our partition.
501 if (m_vertWeights.find(elid) == m_vertWeights.end())
502 {
503 continue;
504 }
505
506 m_vertWeights[elid][m_fieldNameToId[it->first]] =
507 CalculateElementWeight(m_shape[elid], false, na, nb, nc);
508 m_vertBndWeights[elid][m_fieldNameToId[it->first]] =
509 CalculateElementWeight(m_shape[elid], true, na, nb, nc);
510 m_edgeWeights[elid][m_fieldNameToId[it->first]] =
511 CalculateEdgeWeight(m_shape[elid], na, nb, nc);
512 }
513 } // for i
514}
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 131 of file MeshPartition.h.

Referenced by ReadExpansions().

◆ m_dim

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

Definition at line 126 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 143 of file MeshPartition.h.

Referenced by CreateGraph(), and WeightElements().

◆ m_elements

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

Definition at line 129 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 135 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 140 of file MeshPartition.h.

Referenced by ReadExpansions(), and WeightElements().

◆ m_ghostElmts

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

Definition at line 130 of file MeshPartition.h.

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

◆ m_graph

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

Definition at line 145 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 146 of file MeshPartition.h.

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

◆ m_numFields

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

Definition at line 127 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 123 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 138 of file MeshPartition.h.

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

◆ m_shared

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

Definition at line 151 of file MeshPartition.h.

Referenced by PartitionGraph(), and PartitionMesh().

◆ m_vertBndWeights

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

Definition at line 142 of file MeshPartition.h.

Referenced by CreateGraph(), and WeightElements().

◆ m_vertWeights

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

Definition at line 141 of file MeshPartition.h.

Referenced by CreateGraph(), and WeightElements().

◆ m_weightBnd

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

Definition at line 149 of file MeshPartition.h.

Referenced by PartitionGraph(), and ReadConditions().

◆ m_weightDofs

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

Definition at line 150 of file MeshPartition.h.

Referenced by PartitionGraph(), and ReadConditions().

◆ m_weightingRequired

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

Definition at line 148 of file MeshPartition.h.

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