42 #include <boost/config.hpp>
43 #include <boost/graph/adjacency_list.hpp>
44 #include <boost/graph/cuthill_mckee_ordering.hpp>
45 #include <boost/graph/properties.hpp>
46 #include <boost/graph/bandwidth.hpp>
47 #include <boost/algorithm/string/replace.hpp>
53 #ifdef NEKTAR_USE_SCOTCH
60 #define SCOTCH_CALL(scotchFunc, args) \
62 ASSERTL0(scotchFunc args == 0, \
63 std::string("Error in Scotch calling function ") \
64 + std::string(#scotchFunc)); \
70 namespace MultiRegions
94 const unsigned int bndPatch,
106 int npatch = numLocalBndCondPerPatch.size();
111 bndoffset[0] = intoffset[0] = 0;
112 for(
int i = 1; i <= npatch; ++i)
114 bndoffset[i] = bndoffset[i-1] + numLocalBndCondPerPatch[i-1];
115 intoffset[i] = intoffset[i-1] + numLocalIntCondPerPatch[i-1];
120 for(
int i = 0; i <
m_dofId.size(); ++i)
135 const int nPartition)
156 returnval += g->GetTotDofs();
165 static int level = 0;
166 static int offset = 0;
171 g->SetGlobalNumberingOffset();
186 static int level = 0;
188 cout <<
"LEVEL " <<
level <<
" " <<
m_BndDofs->GetNverts() << endl;
199 std::vector<SubGraphSharedPtr>& leaves)
const
205 g->CollectLeaves(leaves);
212 leaves.push_back(leave);
219 static int level = 0;
220 static int nLeaves = 0;
233 if (g->GetNdaughterGraphs() == 0 &&
234 g->GetBndDofsGraph()->GetNverts() == 0)
260 static int level = 0;
261 static int nLeaves = 0;
274 if (g->GetNdaughterGraphs() == 0)
299 const int nVerts) : m_IntBlocks(), m_daughterGraph()
306 for (
int i = 0 ; i < nVerts; i++)
330 graph->SetGlobalNumberingOffset();
333 graph->CutEmptyLeaves();
335 ncuts = graph->CutLeaves();
350 static int nIntDofs = 0;
351 static int level = 0;
366 returnval = nIntDofs;
379 static int level = 0;
382 cout <<
"LEVEL " <<
level << endl;
383 cout <<
"interior blocks" << endl;
418 for (
int i=0; i < nDofs; i++)
420 iperm[i] = iperm1[iperm[i]];
428 static int offset = 0;
429 static int level = 0;
441 for(
int j = 0; j <
m_IntBlocks[i]->GetNverts(); j++)
443 iperm[GlobIdOffset+j] = offset;
458 static int offset = 0;
459 static int level = 0;
469 int OrigGlobIdOffset =
m_IntBlocks[i]->GetIdOffset();
474 for(
int j = 0; j <
m_IntBlocks[i]->GetNverts(); j++)
476 newNverts += wgts[OrigGlobIdOffset+j];
477 offset += wgts[OrigGlobIdOffset+j];
505 const int leveltomask,
508 static int level = 0;
511 if(
level < leveltomask)
515 else if(
level == leveltomask)
523 for(
int j = 0; j < nVerts; j++)
525 maskarray[GlobIdOffset+j] = (
NekDouble) i;
532 "If statement should not arrive here");
539 const int whichlevel)
const
542 static int level = 0;
545 if(
level < whichlevel)
550 else if(
level == whichlevel)
557 "If statement should not arrive here");
566 const int whichlevel,
569 static int level = 0;
572 if(
level < whichlevel)
576 else if(
level == whichlevel)
579 "Array dimension not sufficient");
583 outarray[i] = (
unsigned int)
m_IntBlocks[i]->GetNverts();
589 "If statement should not arrive here");
596 const int whichlevel,
const int patch)
const
599 static int level = 0;
602 if(
level < whichlevel)
606 else if(
level == whichlevel)
613 "If statement should not arrive here");
624 std::vector<SubGraphSharedPtr> returnval;
625 static int level = 0;
628 if(
level < whichlevel)
632 else if(
level == whichlevel)
639 "If statement should not arrive here");
647 const int whichlevel)
const
650 static int level = 0;
653 if(
level < whichlevel)
657 else if(
level == whichlevel)
665 "If statement should not arrive here");
676 static int level = 0;
683 returnval = max(returnval,
level);
693 return g->GetNverts() == 0;
703 typedef boost::adjacency_list<
704 boost::setS, boost::vecS, boost::undirectedS> BoostGraph;
705 typedef boost::graph_traits<BoostGraph>::vertex_descriptor
713 int nGraphVerts = boost::num_vertices(graph);
715 ASSERTL1(perm. size() >= nGraphVerts &&
716 iperm.size() >= nGraphVerts,
717 "Non-matching dimensions");
721 std::vector<BoostVertex> reorderedVerts(nGraphVerts);
722 boost::cuthill_mckee_ordering(graph, reorderedVerts.rbegin());
725 for(
int i = 0; i < nGraphVerts; i++)
727 perm[i] = reorderedVerts[i];
728 iperm[ reorderedVerts[i] ] = i;
733 const BoostGraph &graph,
737 std::set<int> partVerts,
740 #ifndef NEKTAR_USE_SCOTCH
741 boost::ignore_unused(graph, perm, iperm, substructgraph, partVerts,
743 ASSERTL0(
false,
"Multi-level static condensation requires Nektar++"
744 " to be built with SCOTCH.");
746 int nGraphVerts = boost::num_vertices(graph);
747 int nGraphEdges = boost::num_edges (graph);
749 ASSERTL1(perm. size() >= nGraphVerts &&
750 iperm.size() >= nGraphVerts,
751 "Non-matching dimensions");
770 int acnt = 0, vcnt = 0, i, cnt;
771 int nPartition = partVerts.size();
772 int nNonPartition = nGraphVerts - partVerts.size();
784 for (i = cnt = 0; i < nGraphVerts; ++i)
786 if (partVerts.count(i) == 0)
788 initial_perm [i] = cnt;
789 iinitial_perm[cnt++] = i;
793 for (i = 0; i < nGraphVerts; ++i)
795 if (partVerts.count(i) > 0)
797 initial_perm [i] = cnt;
798 iinitial_perm[cnt++] = i;
803 boost::property_map<BoostGraph, boost::vertex_index_t>::type
804 index = get(boost::vertex_index, graph);
808 auto verts = boost::vertices(graph);
809 for (
auto vertit = verts.first; vertit != verts.second; ++vertit)
811 if (partVerts.count(index[*vertit]) > 0)
816 auto adjverts = boost::adjacent_vertices(*vertit,graph);
817 for (
auto adjvertit = adjverts.first;
818 adjvertit != adjverts.second; ++adjvertit)
820 if (partVerts.count(index[*adjvertit]) > 0)
824 adjncy[acnt++] = initial_perm[*adjvertit];
835 SCOTCH_Graph scGraph;
837 (&scGraph, 0, nNonPartition, &xadj[0], &xadj[1],
838 NULL, NULL, xadj[nNonPartition], &adjncy[0], NULL));
852 std::string strat_str =
853 "c{rat=0.7,cpr=n{sep=/(<TSTS>)?m{rat=0.7,vert=100,low="
854 "h{pass=10},asc=b{width=3,bnd=f{bal=<BBAL>},"
855 "org=(|h{pass=10})f{bal=<BBAL>}}}<SEPA>;,"
856 "ole=<OLEA>,ose=<OSEP>},unc=n{sep=/(<TSTS>)?m{rat=0.7,"
857 "vert=100,low=h{pass=10},asc=b{width=3,bnd=f{bal=<BBAL>},"
858 "org=(|h{pass=10})f{bal=<BBAL>}}}<SEPA>;"
859 ",ole=<OLEA>,ose=<OSEP>}}";
863 strat_str,
"<SEPA>",
"|m{rat=0.7,vert=100,low=h{pass=10},"
864 "asc=b{width=3,bnd=f{bal=<BBAL>},"
865 "org=(|h{pass=10})f{bal=<BBAL>}}}");
866 boost::replace_all(strat_str,
"<OSEP>",
"s");
867 boost::replace_all(strat_str,
"<OLEA>",
"s");
868 boost::replace_all(strat_str,
"<BBAL>",
"0.1");
871 "vert>"+std::to_string(mdswitch));
876 SCOTCH_CALL(SCOTCH_stratGraphOrder, (&strat, strat_str.c_str()));
895 (&scGraph, &strat, &iperm_tmp[0], &perm_tmp[0],
896 &cblknbr, &rangtab[0], &treetab[0]));
899 SCOTCH_graphExit(&scGraph);
900 SCOTCH_stratExit(&strat);
909 std::vector<MultiLevelBisectedGraphSharedPtr> graphs(cblknbr);
915 for (i = cblknbr-1; i >= 0; --i)
923 if (treetab[i] == -1)
938 std::vector<MultiLevelBisectedGraphSharedPtr> &daughters =
939 tmp->GetDaughterGraphs();
940 daughters.insert(daughters.begin(), graphs[i]);
945 for (i = 0; i < nGraphVerts; ++i)
947 if (partVerts.count(i) == 0)
949 iperm[i] = iperm_tmp[initial_perm[i]];
954 auto it = partVerts.begin(), it2 = partVerts.end();
955 for (i = nNonPartition; it != it2; ++it, ++i)
961 for (i = 0; i < nGraphVerts; ++i)
963 ASSERTL1(perm[iperm[i]] == i,
"Perm error "
964 + std::to_string(i));
969 std::vector<int> rootBlocks;
970 for (i = 0; i < cblknbr; ++i)
972 if (treetab[i] == -1)
974 rootBlocks.push_back(i);
979 if (rootBlocks.size() == 1)
981 root = graphs[rootBlocks[0]];
988 for (
int i = 0; i < rootBlocks.size(); ++i)
990 root->GetDaughterGraphs().push_back(graphs[rootBlocks[i]]);
997 ASSERTL0(root->GetTotDofs() == nNonPartition,
998 "Error in constructing Scotch graph for multi-level"
999 " static condensation.");
1022 substructgraph->UpdateBottomUpReordering(perm,iperm);
1028 for(
int i = 0; i < nGraphVerts; i++)
1043 int nGraphVerts = boost::num_vertices(graph);
1045 ASSERTL1(perm. size() >= nGraphVerts &&
1046 iperm.size() >= nGraphVerts,
1047 "Non-matching dimensions");
1049 for (
int i = 0; i < nGraphVerts; i++)
#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 ASSERTL1(condition, msg)
Assert Level 1 – Debugging which is used whether in FULLDEBUG or DEBUG compilation mode....
#define SCOTCH_CALL(scotchFunc, args)
#define sign(a, b)
return the sign(b)*a
General purpose memory allocation routines with the ability to allocate from thread specific memory p...
static std::shared_ptr< DataType > AllocateSharedPtr(const Args &...args)
Allocate a shared pointer from the memory pool.
void GetNintDofsPerPatch(const int whichlevel, Array< OneD, unsigned int > &outarray) const
void ExpandGraphWithVertexWeights(const Array< OneD, const int > &wgts)
int GetNumGlobalDofs(const int whichlevel) const
std::vector< SubGraphSharedPtr > GetInteriorBlocks() const
std::vector< SubGraphSharedPtr > m_IntBlocks
void SetBottomUpReordering(Array< OneD, int > &iperm) const
int GetInteriorOffset(const int whichlevel, const int patch=0) const
BottomUpSubStructuredGraph(MultiLevelBisectedGraphSharedPtr graph, int nPartition=0, bool globaloffset=false)
void UpdateBottomUpReordering(Array< OneD, int > &perm, Array< OneD, int > &iperm) const
BottomUpSubStructuredGraphSharedPtr m_daughterGraph
~BottomUpSubStructuredGraph(void)
void MaskPatches(const int leveltomask, Array< OneD, NekDouble > &maskarray) const
int GetNpatchesWithInterior(const int whichlevel) const
MultiLevelBisectedGraph(MultiLevelBisectedGraphSharedPtr oldLevel, const int nPartition)
void DumpNBndDofs(void) const
void SetGlobalNumberingOffset()
void CollectLeaves(std::vector< SubGraphSharedPtr > &leaves) const
SubGraphSharedPtr m_BndDofs
~MultiLevelBisectedGraph(void)
std::vector< MultiLevelBisectedGraphSharedPtr > m_daughterGraphs
Array< OneD, unsigned int > m_bndPatch
void SetPatchMap(const int n, const int patchId, const int dofId, const unsigned int bndPatch, const NekDouble sign)
void SetNewLevelMap(Array< OneD, const unsigned int > numLocalBndCondPerPatch, Array< OneD, const unsigned int > numLocalIntCondPerPatch)
Array< OneD, NekDouble > m_sign
Array< OneD, int > m_patchId
Array< OneD, int > m_dofId
Array< OneD, int > m_newLevelMap
void NoReordering(const BoostGraph &graph, Array< OneD, int > &perm, Array< OneD, int > &iperm)
void CuthillMckeeReordering(const BoostGraph &graph, Array< OneD, int > &perm, Array< OneD, int > &iperm)
void MultiLevelBisectionReordering(const BoostGraph &graph, Array< OneD, int > &perm, Array< OneD, int > &iperm, BottomUpSubStructuredGraphSharedPtr &substructgraph, std::set< int > partVerts, int mdswitch)
std::shared_ptr< BottomUpSubStructuredGraph > BottomUpSubStructuredGraphSharedPtr
bool SubGraphWithoutVerts(const SubGraphSharedPtr g)
std::shared_ptr< MultiLevelBisectedGraph > MultiLevelBisectedGraphSharedPtr
std::shared_ptr< SubGraph > SubGraphSharedPtr
The above copyright notice and this permission notice shall be included.