Nektar++
Loading...
Searching...
No Matches
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
37
39{
40
44 "Partitioning using the Scotch library.");
45
48 "use-scotch", "", "Use Scotch for mesh partitioning.");
49
52 LibUtilities::CommSharedPtr comm, int meshDim,
53 std::map<int, MeshEntity> element, CompositeDescriptor compMap)
54 : MeshPartition(session, comm, meshDim, element, compMap)
55{
56}
57
59 int &nVerts, [[maybe_unused]] int &nVertConds,
64 [[maybe_unused]] Nektar::Array<Nektar::OneD, int> &edgeWgt, int &nparts,
65 int &volume, Nektar::Array<Nektar::OneD, int> &part)
66{
67
68 // This method seems to fail if we have elements in the graph that
69 // are isolated from others can happen when post-processing (i.e. mesh on a
70 // surface). So remove these elementsand add in at the end
71 std::set<unsigned> isolated;
72 for (int i = 0; i < nVerts; ++i)
73 {
74 if (xadj[i] == xadj[i + 1])
75 {
76 isolated.insert(i);
77 }
78 }
79
80 if (isolated.size())
81 {
83 for (auto i : isolated)
84 {
85 // contract xadjacent list
86 Vmath::Vcopy(nVerts - i, xadj + i + 1, 1, tmp = xadj + i, 1);
87 nVerts--;
88 }
89 }
90
91 int wgtflag = 0;
92 int *vwgt = nullptr;
93 int *vsize = nullptr;
94 if (vertWgt.size() > 0)
95 {
96 wgtflag += 1;
97 vwgt = &vertWgt[0];
98 }
99 if (vertSize.size() > 0)
100 {
101 wgtflag += 2;
102 vsize = &vertSize[0];
103 }
104 int numflag = 0;
105
106 PartGraphVKway(&nVerts, &xadj[0], &adjcy[0], vwgt, vsize, &wgtflag,
107 &numflag, &nparts, &volume, &part[0]);
108
109 // distribute isolated elements to each partition in order.
110 if (isolated.size())
111 {
113 unsigned topart = 0;
114 for (auto i : isolated)
115 {
116 // contract xadjacent list
117 if (nVerts - i)
118 {
119 Vmath::Vcopy(nVerts - i, part + i, 1, tmp = part + i + 1, 1);
120 }
121 part[i] = topart % nparts;
122 nVerts++;
123 topart++;
124 }
125 }
126}
127
129 const SCOTCH_Num *const n, const SCOTCH_Num *const xadj,
130 const SCOTCH_Num *const adjncy, const SCOTCH_Num *const vwgt,
131 const SCOTCH_Num *const vsize, const SCOTCH_Num *const wgtflag,
132 const SCOTCH_Num *const numflag, const SCOTCH_Num *const nparts,
133 SCOTCH_Num *const volume, SCOTCH_Num *const part)
134{
135 SCOTCH_Num baseval;
136 const SCOTCH_Num *vwgt2;
137 const SCOTCH_Num *vsize2;
138 SCOTCH_Num vsizval; /// Communication volume of current vertex
139 SCOTCH_Num vertnbr;
140 SCOTCH_Num vertnum;
141 SCOTCH_Num edgenum;
142 const SCOTCH_Num *edgetax;
143 const SCOTCH_Num *parttax;
144 SCOTCH_Num *nghbtab;
145 SCOTCH_Num commvol;
146
147 vsize2 = ((*wgtflag & 1) != 0) ? vsize : nullptr;
148 vwgt2 = ((*wgtflag & 2) != 0) ? vwgt : nullptr;
149 baseval = *numflag;
150 vertnbr = *n;
151 edgetax = adjncy - baseval;
152
153 // If no communication load data provided
154 if (vsize2 == nullptr)
155 {
156 if (PartGraph2(n, xadj, adjncy, vwgt2, nullptr, numflag, nparts, part,
157 SCOTCH_STRATQUALITY, 0.01) != 0)
158 {
159 return;
160 }
161 }
162
163 // Will have to turn communication volumes into edge loads
164 else
165 {
166 const SCOTCH_Num *vsiztax;
167 SCOTCH_Num edgenbr;
168 SCOTCH_Num *edlotax;
169 int o;
170
171 edgenbr = xadj[vertnbr] - baseval;
172 if ((edlotax = (SCOTCH_Num *)malloc(edgenbr * sizeof(SCOTCH_Num))) ==
173 nullptr)
174 {
175 return;
176 }
177
178 edlotax -= baseval; // Base access to edlotax
179 vsiztax = vsize2 - baseval;
180
181 // Un-based scan of vertex array xadj
182 for (vertnum = 0, edgenum = baseval; vertnum < vertnbr; vertnum++)
183 {
184 SCOTCH_Num vsizval; // Communication size of current vertex
185 SCOTCH_Num edgennd;
186
187 vsizval = vsize2[vertnum];
188 // Based traversal of edge array adjncy
189 for (edgennd = xadj[vertnum + 1]; edgenum < edgennd; edgenum++)
190 {
191
192 SCOTCH_Num vertend; // Based end vertex number
193
194 vertend = edgetax[edgenum];
195 edlotax[edgenum] = vsizval + vsiztax[vertend];
196 }
197 }
198
199 o = PartGraph2(n, xadj, adjncy, vwgt2, edlotax + baseval, numflag,
200 nparts, part, SCOTCH_STRATQUALITY, 0.01);
201
202 free(edlotax + baseval);
203
204 if (o != 0)
205 {
206 return;
207 }
208 }
209
210 if ((nghbtab = (SCOTCH_Num *)malloc(*nparts * sizeof(SCOTCH_Num))) ==
211 nullptr)
212 {
213 return;
214 }
215
216 memset(nghbtab, ~0, *nparts * sizeof(SCOTCH_Num));
217
218 parttax = part - baseval;
219 vsizval = 1; // Assume no vertex communication sizes
220
221 // Un-based scan of vertex array xadj
222 for (vertnum = 0, edgenum = baseval, commvol = 0; vertnum < vertnbr;
223 vertnum++)
224 {
225 SCOTCH_Num partval;
226 SCOTCH_Num edgennd;
227
228 partval = part[vertnum];
229 nghbtab[partval] = vertnum; // Do not count local neighbors in
230 // communication volume
231 if (vsize2 != nullptr)
232 {
233 vsizval = vsize2[vertnum];
234 }
235
236 // Based traversal of edge array adjncy
237 for (edgennd = xadj[vertnum + 1]; edgenum < edgennd; edgenum++)
238 {
239 SCOTCH_Num vertend; // Based end vertex number
240 SCOTCH_Num partend;
241
242 vertend = edgetax[edgenum];
243 partend = parttax[vertend];
244
245 // If first neighbor in this part set part as accounted for
246 if (nghbtab[partend] != vertnum)
247 {
248 nghbtab[partend] = vertnum;
249 commvol += vsizval;
250 }
251 }
252 }
253 *volume = commvol;
254
255 free(nghbtab);
256}
257
259 const SCOTCH_Num *const n, const SCOTCH_Num *const xadj,
260 const SCOTCH_Num *const adjncy, const SCOTCH_Num *const vwgt,
261 const SCOTCH_Num *const adjwgt, const SCOTCH_Num *const numflag,
262 const SCOTCH_Num *const nparts, SCOTCH_Num *const part, SCOTCH_Num flagval,
263 double kbalval)
264{
265 // Scotch graph object to interface with libScotch
266 SCOTCH_Graph *grafdat = SCOTCH_graphAlloc();
267 ASSERTL0(grafdat != nullptr,
268 "Failed to allocate Scotch graph for partitioning.");
269
270 SCOTCH_Strat stradat;
271 SCOTCH_Num baseval;
272 SCOTCH_Num vertnbr;
273 int o;
274
275 ASSERTL0(SCOTCH_graphInit(grafdat) == 0,
276 "Failed to initialise Scotch graph for partitioning.");
277
278 baseval = *numflag;
279 vertnbr = *n;
280
281 o = 1; // Assume something will go wrong
282 if (SCOTCH_graphBuild(grafdat, baseval, vertnbr, xadj, xadj + 1, vwgt,
283 nullptr, xadj[vertnbr] - baseval, adjncy,
284 adjwgt) == 0)
285 {
286 SCOTCH_stratInit(&stradat);
287 SCOTCH_stratGraphMapBuild(&stradat, flagval, *nparts, kbalval);
288#ifdef SCOTCH_DEBUG_ALL
289 // TRICK: next instruction called only if graph is consistent
290 if (SCOTCH_graphCheck(grafdat) == 0)
291#endif /* SCOTCH_DEBUG_ALL */
292 o = SCOTCH_graphPart(grafdat, *nparts, &stradat, part);
293 SCOTCH_stratExit(&stradat);
294 }
295 SCOTCH_graphExit(grafdat);
296
297 if (o != 0)
298 {
299 return (1);
300 }
301
302 if (baseval != 0)
303 { // MeTiS part array is based, Scotch is not
304 SCOTCH_Num vertnum;
305
306 for (vertnum = 0; vertnum < vertnbr; vertnum++)
307 {
308 part[vertnum] += baseval;
309 }
310 }
311
312 return (0);
313}
314
315} // namespace Nektar::SpatialDomains
#define ASSERTL0(condition, msg)
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, std::string pDesc="")
Register a class with the factory.
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.
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) final
static std::string className
Name of class.
MeshPartitionScotch(const LibUtilities::SessionReaderSharedPtr session, LibUtilities::CommSharedPtr comm, int meshDim, std::map< int, MeshEntity > element, CompositeDescriptor compMap)
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:55
std::map< int, std::pair< LibUtilities::ShapeType, std::vector< int > > > CompositeDescriptor
Definition MeshGraph.h:124
MeshPartitionFactory & GetMeshPartitionFactory()
void Vcopy(int n, const T *x, const int incx, T *y, const int incy)
Definition Vmath.hpp:825