Nektar++
MeshPartitionScotch.cpp
Go to the documentation of this file.
1///////////////////////////////////////////////////////////////////////////////
2//
3// File: MeshPartitionScotch.cpp
4//
5// For more information, please see: http://www.nektar.info
6//
7// The MIT License
8//
9// Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
10// Department of Aeronautics, Imperial College London (UK), and Scientific
11// Computing and Imaging Institute, University of Utah (USA).
12//
13// Permission is hereby granted, free of charge, to any person obtaining a
14// copy of this software and associated documentation files (the "Software"),
15// to deal in the Software without restriction, including without limitation
16// the rights to use, copy, modify, merge, publish, distribute, sublicense,
17// and/or sell copies of the Software, and to permit persons to whom the
18// Software is furnished to do so, subject to the following conditions:
19//
20// The above copyright notice and this permission notice shall be included
21// in all copies or substantial portions of the Software.
22//
23// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29// DEALINGS IN THE SOFTWARE.
30//
31// Description: Scotch partitioner interface
32//
33///////////////////////////////////////////////////////////////////////////////
34
35#include <boost/core/ignore_unused.hpp>
36
38
39namespace Nektar
40{
41namespace SpatialDomains
42{
43
47 "Partitioning using the Scotch library.");
48
51 "use-scotch", "", "Use Scotch for mesh partitioning.");
52
55 LibUtilities::CommSharedPtr comm, int meshDim,
56 std::map<int, MeshEntity> element, CompositeDescriptor compMap)
57 : MeshPartition(session, comm, meshDim, element, compMap)
58{
59}
60
62{
63}
64
66 int &nVerts, int &nVertConds, Nektar::Array<Nektar::OneD, int> &xadj,
70 Nektar::Array<Nektar::OneD, int> &edgeWgt, int &nparts, int &volume,
72{
73 boost::ignore_unused(nVertConds, edgeWgt);
74
75 int wgtflag = 0;
76 int *vwgt = 0;
77 int *vsize = 0;
78 if (vertWgt.size() > 0)
79 {
80 wgtflag += 1;
81 vwgt = &vertWgt[0];
82 }
83 if (vertSize.size() > 0)
84 {
85 wgtflag += 2;
86 vsize = &vertSize[0];
87 }
88 int numflag = 0;
89
90 PartGraphVKway(&nVerts, &xadj[0], &adjcy[0], vwgt, vsize, &wgtflag,
91 &numflag, &nparts, &volume, &part[0]);
92}
93
95 const SCOTCH_Num *const n, const SCOTCH_Num *const xadj,
96 const SCOTCH_Num *const adjncy, const SCOTCH_Num *const vwgt,
97 const SCOTCH_Num *const vsize, const SCOTCH_Num *const wgtflag,
98 const SCOTCH_Num *const numflag, const SCOTCH_Num *const nparts,
99 SCOTCH_Num *const volume, SCOTCH_Num *const part)
100{
101 SCOTCH_Num baseval;
102 const SCOTCH_Num *vwgt2;
103 const SCOTCH_Num *vsize2;
104 SCOTCH_Num vsizval; /// Communication volume of current vertex
105 SCOTCH_Num vertnbr;
106 SCOTCH_Num vertnum;
107 SCOTCH_Num edgenum;
108 const SCOTCH_Num *edgetax;
109 const SCOTCH_Num *parttax;
110 SCOTCH_Num *nghbtab;
111 SCOTCH_Num commvol;
112
113 vsize2 = ((*wgtflag & 1) != 0) ? vsize : NULL;
114 vwgt2 = ((*wgtflag & 2) != 0) ? vwgt : NULL;
115 baseval = *numflag;
116 vertnbr = *n;
117 edgetax = adjncy - baseval;
118
119 // If no communication load data provided
120 if (vsize2 == NULL)
121 {
122 if (PartGraph2(n, xadj, adjncy, vwgt2, NULL, numflag, nparts, part,
123 SCOTCH_STRATQUALITY, 0.01) != 0)
124 return;
125 }
126
127 // Will have to turn communication volumes into edge loads
128 else
129 {
130 const SCOTCH_Num *vsiztax;
131 SCOTCH_Num edgenbr;
132 SCOTCH_Num *edlotax;
133 int o;
134
135 edgenbr = xadj[vertnbr] - baseval;
136 if ((edlotax = (SCOTCH_Num *)malloc(edgenbr * sizeof(SCOTCH_Num))) ==
137 NULL)
138 {
139 return;
140 }
141
142 edlotax -= baseval; // Base access to edlotax
143 vsiztax = vsize2 - baseval;
144
145 // Un-based scan of vertex array xadj
146 for (vertnum = 0, edgenum = baseval; vertnum < vertnbr; vertnum++)
147 {
148 SCOTCH_Num vsizval; // Communication size of current vertex
149 SCOTCH_Num edgennd;
150
151 vsizval = vsize2[vertnum];
152 // Based traversal of edge array adjncy
153 for (edgennd = xadj[vertnum + 1]; edgenum < edgennd; edgenum++)
154 {
155
156 SCOTCH_Num vertend; // Based end vertex number
157
158 vertend = edgetax[edgenum];
159 edlotax[edgenum] = vsizval + vsiztax[vertend];
160 }
161 }
162
163 o = PartGraph2(n, xadj, adjncy, vwgt2, edlotax + baseval, numflag,
164 nparts, part, SCOTCH_STRATQUALITY, 0.01);
165
166 free(edlotax + baseval);
167
168 if (o != 0)
169 return;
170 }
171
172 if ((nghbtab = (SCOTCH_Num *)malloc(*nparts * sizeof(SCOTCH_Num))) == NULL)
173 {
174 return;
175 }
176
177 memset(nghbtab, ~0, *nparts * sizeof(SCOTCH_Num));
178
179 parttax = part - baseval;
180 vsizval = 1; // Assume no vertex communication sizes
181
182 // Un-based scan of vertex array xadj
183 for (vertnum = 0, edgenum = baseval, commvol = 0; vertnum < vertnbr;
184 vertnum++)
185 {
186 SCOTCH_Num partval;
187 SCOTCH_Num edgennd;
188
189 partval = part[vertnum];
190 nghbtab[partval] = vertnum; // Do not count local neighbors in
191 // communication volume
192 if (vsize2 != NULL)
193 vsizval = vsize2[vertnum];
194
195 // Based traversal of edge array adjncy
196 for (edgennd = xadj[vertnum + 1]; edgenum < edgennd; edgenum++)
197 {
198 SCOTCH_Num vertend; // Based end vertex number
199 SCOTCH_Num partend;
200
201 vertend = edgetax[edgenum];
202 partend = parttax[vertend];
203
204 // If first neighbor in this part set part as accounted for
205 if (nghbtab[partend] != vertnum)
206 {
207 nghbtab[partend] = vertnum;
208 commvol += vsizval;
209 }
210 }
211 }
212 *volume = commvol;
213
214 free(nghbtab);
215}
216
218 const SCOTCH_Num *const n, const SCOTCH_Num *const xadj,
219 const SCOTCH_Num *const adjncy, const SCOTCH_Num *const vwgt,
220 const SCOTCH_Num *const adjwgt, const SCOTCH_Num *const numflag,
221 const SCOTCH_Num *const nparts, SCOTCH_Num *const part, SCOTCH_Num flagval,
222 double kbalval)
223{
224 // Scotch graph object to interface with libScotch
225 SCOTCH_Graph *grafdat = SCOTCH_graphAlloc();
226 ASSERTL0(grafdat != nullptr,
227 "Failed to allocate Scotch graph for partitioning.");
228
229 SCOTCH_Strat stradat;
230 SCOTCH_Num baseval;
231 SCOTCH_Num vertnbr;
232 int o;
233
234 ASSERTL0(SCOTCH_graphInit(grafdat) == 0,
235 "Failed to initialise Scotch graph for partitioning.");
236
237 baseval = *numflag;
238 vertnbr = *n;
239
240 o = 1; // Assume something will go wrong
241 if (SCOTCH_graphBuild(grafdat, baseval, vertnbr, xadj, xadj + 1, vwgt, NULL,
242 xadj[vertnbr] - baseval, adjncy, adjwgt) == 0)
243 {
244 SCOTCH_stratInit(&stradat);
245 SCOTCH_stratGraphMapBuild(&stradat, flagval, *nparts, kbalval);
246#ifdef SCOTCH_DEBUG_ALL
247 // TRICK: next instruction called only if graph is consistent
248 if (SCOTCH_graphCheck(grafdat) == 0)
249#endif /* SCOTCH_DEBUG_ALL */
250 o = SCOTCH_graphPart(grafdat, *nparts, &stradat, part);
251 SCOTCH_stratExit(&stradat);
252 }
253 SCOTCH_graphExit(grafdat);
254
255 if (o != 0)
256 return (1);
257
258 if (baseval != 0)
259 { // MeTiS part array is based, Scotch is not
260 SCOTCH_Num vertnum;
261
262 for (vertnum = 0; vertnum < vertnbr; vertnum++)
263 part[vertnum] += baseval;
264 }
265
266 return (0);
267}
268
269} // namespace SpatialDomains
270} // namespace Nektar
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:215
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, std::string pDesc="")
Register a class with the factory.
Definition: NekFactory.hpp:198
static std::string RegisterCmdLineFlag(const std::string &pName, const std::string &pShortName, const std::string &pDescription)
Registers a command-line flag with the session reader.
static MeshPartitionSharedPtr create(const LibUtilities::SessionReaderSharedPtr session, LibUtilities::CommSharedPtr comm, int meshDim, std::map< int, MeshEntity > element, CompositeDescriptor compMap)
Creates an instance of this class.
static std::string className
Name of class.
MeshPartitionScotch(const LibUtilities::SessionReaderSharedPtr session, LibUtilities::CommSharedPtr comm, int meshDim, std::map< int, MeshEntity > element, CompositeDescriptor compMap)
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) override final
int PartGraph2(const SCOTCH_Num *const n, const SCOTCH_Num *const xadj, const SCOTCH_Num *const adjncy, const SCOTCH_Num *const vwgt, const SCOTCH_Num *const adjwgt, const SCOTCH_Num *const numflag, const SCOTCH_Num *const nparts, SCOTCH_Num *const part, SCOTCH_Num flagval, double kbalval)
void PartGraphVKway(const SCOTCH_Num *const n, const SCOTCH_Num *const xadj, const SCOTCH_Num *const adjncy, const SCOTCH_Num *const vwgt, const SCOTCH_Num *const vsize, const SCOTCH_Num *const wgtflag, const SCOTCH_Num *const numflag, const SCOTCH_Num *const nparts, SCOTCH_Num *const volume, SCOTCH_Num *const part)
std::shared_ptr< SessionReader > SessionReaderSharedPtr
std::shared_ptr< Comm > CommSharedPtr
Pointer to a Communicator object.
Definition: Comm.h:57
std::map< int, std::pair< LibUtilities::ShapeType, std::vector< int > > > CompositeDescriptor
Definition: MeshGraph.h:63
MeshPartitionFactory & GetMeshPartitionFactory()
The above copyright notice and this permission notice shall be included.
Definition: CoupledSolver.h:2