40#include <boost/algorithm/string/replace.hpp>
41#include <boost/config.hpp>
42#include <boost/graph/adjacency_list.hpp>
43#include <boost/graph/bandwidth.hpp>
44#include <boost/graph/cuthill_mckee_ordering.hpp>
45#include <boost/graph/properties.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)); \
99 int npatch = numLocalBndCondPerPatch.size();
104 bndoffset[0] = intoffset[0] = 0;
105 for (
int i = 1; i <= npatch; ++i)
107 bndoffset[i] = bndoffset[i - 1] + numLocalBndCondPerPatch[i - 1];
108 intoffset[i] = intoffset[i - 1] + numLocalIntCondPerPatch[i - 1];
113 for (
int i = 0; i <
m_dofId.size(); ++i)
149 returnval += g->GetTotDofs();
158 static int level = 0;
159 static int offset = 0;
164 g->SetGlobalNumberingOffset();
179 static int level = 0;
181 cout <<
"LEVEL " <<
level <<
" " <<
m_BndDofs->GetNverts() << endl;
192 std::vector<SubGraphSharedPtr> &leaves)
const
198 g->CollectLeaves(leaves);
205 leaves.push_back(leave);
212 static int level = 0;
213 static int nLeaves = 0;
226 if (g->GetNdaughterGraphs() == 0 &&
227 g->GetBndDofsGraph()->GetNverts() == 0)
253 static int level = 0;
254 static int nLeaves = 0;
267 if (g->GetNdaughterGraphs() == 0)
291 : m_IntBlocks(), m_daughterGraph()
298 for (
int i = 0; i < nVerts; i++)
307 : m_IntBlocks(), m_daughterGraph()
319 graph->SetGlobalNumberingOffset();
322 graph->CutEmptyLeaves();
324 ncuts = graph->CutLeaves();
339 static int nIntDofs = 0;
340 static int level = 0;
355 returnval = nIntDofs;
368 static int level = 0;
371 cout <<
"LEVEL " <<
level << endl;
372 cout <<
"interior blocks" << endl;
375 cout <<
" " << i <<
"/" <<
m_IntBlocks.size() - 1 <<
": "
405 for (
int i = 0; i < nDofs; i++)
407 iperm[i] = iperm1[iperm[i]];
415 static int offset = 0;
416 static int level = 0;
428 for (
int j = 0; j <
m_IntBlocks[i]->GetNverts(); j++)
430 iperm[GlobIdOffset + j] = offset;
445 static int offset = 0;
446 static int level = 0;
456 int OrigGlobIdOffset =
m_IntBlocks[i]->GetIdOffset();
461 for (
int j = 0; j <
m_IntBlocks[i]->GetNverts(); j++)
463 newNverts += wgts[OrigGlobIdOffset + j];
464 offset += wgts[OrigGlobIdOffset + j];
492 static int level = 0;
495 if (
level < leveltomask)
499 else if (
level == leveltomask)
507 for (
int j = 0; j < nVerts; j++)
509 maskarray[GlobIdOffset + j] = (
NekDouble)i;
522 const int whichlevel)
const
525 static int level = 0;
528 if (
level < whichlevel)
532 else if (
level == whichlevel)
549 static int level = 0;
552 if (
level < whichlevel)
556 else if (
level == whichlevel)
559 "Array dimension not sufficient");
563 outarray[i] = (
unsigned int)
m_IntBlocks[i]->GetNverts();
575 const int patch)
const
578 static int level = 0;
581 if (
level < whichlevel)
585 else if (
level == whichlevel)
600 const int whichlevel)
const
602 std::vector<SubGraphSharedPtr> returnval;
603 static int level = 0;
606 if (
level < whichlevel)
610 else if (
level == whichlevel)
626 static int level = 0;
629 if (
level < whichlevel)
633 else if (
level == whichlevel)
651 static int level = 0;
658 returnval = max(returnval,
level);
667 return g->GetNverts() == 0;
677typedef boost::adjacency_list<boost::setS, boost::vecS, boost::undirectedS>
679typedef boost::graph_traits<BoostGraph>::vertex_descriptor BoostVertex;
685 int nGraphVerts = boost::num_vertices(graph);
687 ASSERTL1(perm.size() >= nGraphVerts && iperm.size() >= nGraphVerts,
688 "Non-matching dimensions");
692 std::vector<BoostVertex> reorderedVerts(nGraphVerts);
693 boost::cuthill_mckee_ordering(graph, reorderedVerts.rbegin());
696 for (
int i = 0; i < nGraphVerts; i++)
698 perm[i] = reorderedVerts[i];
699 iperm[reorderedVerts[i]] = i;
704 [[maybe_unused]]
const BoostGraph &graph,
708 [[maybe_unused]] std::set<int> partVerts, [[maybe_unused]]
int mdswitch)
710#ifndef NEKTAR_USE_SCOTCH
711 ASSERTL0(
false,
"Multi-level static condensation requires Nektar++"
712 " to be built with SCOTCH.");
714 int nGraphVerts = boost::num_vertices(graph);
715 int nGraphEdges = boost::num_edges(graph);
717 ASSERTL1(perm.size() >= nGraphVerts && iperm.size() >= nGraphVerts,
718 "Non-matching dimensions");
737 int acnt = 0, vcnt = 0, i, cnt;
738 int nPartition = partVerts.size();
739 int nNonPartition = nGraphVerts - partVerts.size();
751 for (i = cnt = 0; i < nGraphVerts; ++i)
753 if (partVerts.count(i) == 0)
755 initial_perm[i] = cnt;
756 iinitial_perm[cnt++] = i;
760 for (i = 0; i < nGraphVerts; ++i)
762 if (partVerts.count(i) > 0)
764 initial_perm[i] = cnt;
765 iinitial_perm[cnt++] = i;
770 boost::property_map<BoostGraph, boost::vertex_index_t>::type index =
771 get(boost::vertex_index, graph);
775 auto verts = boost::vertices(graph);
776 for (
auto vertit = verts.first; vertit != verts.second; ++vertit)
778 if (partVerts.count(index[*vertit]) > 0)
783 auto adjverts = boost::adjacent_vertices(*vertit, graph);
784 for (
auto adjvertit = adjverts.first; adjvertit != adjverts.second;
787 if (partVerts.count(index[*adjvertit]) > 0)
791 adjncy[acnt++] = initial_perm[*adjvertit];
802 SCOTCH_Graph *scGraph = SCOTCH_graphAlloc();
804 "Failed to allocate Scotch graph for substructuring.");
806 ASSERTL0(SCOTCH_graphInit(scGraph) == 0,
807 "Failed to initialise Scotch graph for substructuring.");
810 (scGraph, 0, nNonPartition, &xadj[0], &xadj[1],
nullptr,
811 nullptr, xadj[nNonPartition], &adjncy[0],
nullptr));
825 std::string strat_str =
826 "c{rat=0.7,cpr=n{sep=/(<TSTS>)?m{rat=0.7,vert=100,low="
827 "h{pass=10},asc=b{width=3,bnd=f{bal=<BBAL>},"
828 "org=(|h{pass=10})f{bal=<BBAL>}}}<SEPA>;,"
829 "ole=<OLEA>,ose=<OSEP>},unc=n{sep=/(<TSTS>)?m{rat=0.7,"
830 "vert=100,low=h{pass=10},asc=b{width=3,bnd=f{bal=<BBAL>},"
831 "org=(|h{pass=10})f{bal=<BBAL>}}}<SEPA>;"
832 ",ole=<OLEA>,ose=<OSEP>}}";
835 boost::replace_all(strat_str,
"<SEPA>",
836 "|m{rat=0.7,vert=100,low=h{pass=10},"
837 "asc=b{width=3,bnd=f{bal=<BBAL>},"
838 "org=(|h{pass=10})f{bal=<BBAL>}}}");
839 boost::replace_all(strat_str,
"<OSEP>",
"s");
840 boost::replace_all(strat_str,
"<OLEA>",
"s");
841 boost::replace_all(strat_str,
"<BBAL>",
"0.1");
842 boost::replace_all(strat_str,
"<TSTS>",
843 "vert>" + std::to_string(mdswitch));
848 SCOTCH_CALL(SCOTCH_stratGraphOrder, (&strat, strat_str.c_str()));
867 (scGraph, &strat, &iperm_tmp[0], &perm_tmp[0], &cblknbr,
868 &rangtab[0], &treetab[0]));
871 SCOTCH_graphExit(scGraph);
872 SCOTCH_stratExit(&strat);
881 std::vector<MultiLevelBisectedGraphSharedPtr> graphs(cblknbr);
887 for (i = cblknbr - 1; i >= 0; --i)
892 rangtab[i + 1] - rangtab[i]);
896 if (treetab[i] == -1)
911 std::vector<MultiLevelBisectedGraphSharedPtr> &daughters =
912 tmp->GetDaughterGraphs();
913 daughters.insert(daughters.begin(), graphs[i]);
918 for (i = 0; i < nGraphVerts; ++i)
920 if (partVerts.count(i) == 0)
922 iperm[i] = iperm_tmp[initial_perm[i]];
927 auto it = partVerts.begin(), it2 = partVerts.end();
928 for (i = nNonPartition; it != it2; ++it, ++i)
934 for (i = 0; i < nGraphVerts; ++i)
936 ASSERTL1(perm[iperm[i]] == i,
"Perm error " + std::to_string(i));
941 std::vector<int> rootBlocks;
942 for (i = 0; i < cblknbr; ++i)
944 if (treetab[i] == -1)
946 rootBlocks.push_back(i);
951 if (rootBlocks.size() == 1)
953 root = graphs[rootBlocks[0]];
959 for (
int i = 0; i < rootBlocks.size(); ++i)
961 root->GetDaughterGraphs().push_back(graphs[rootBlocks[i]]);
968 ASSERTL0(root->GetTotDofs() == nNonPartition,
969 "Error in constructing Scotch graph for multi-level"
970 " static condensation.");
978 root, nPartition,
true);
994 substructgraph->UpdateBottomUpReordering(perm, iperm);
1000 for (
int i = 0; i < nGraphVerts; i++)
1015 int nGraphVerts = boost::num_vertices(graph);
1017 ASSERTL1(perm.size() >= nGraphVerts && iperm.size() >= nGraphVerts,
1018 "Non-matching dimensions");
1020 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