KTH framework for Nek5000 toolboxes; testing version  0.0.1
partitioner.c
Go to the documentation of this file.
1 #include "gslib.h"
2 
3 #if defined(PARRSB)
4 #include "parRSB.h"
5 #endif
6 
7 #define MAXNV 8 /* maximum number of vertices per element */
8 typedef struct {long long vtx[MAXNV]; long long eid; int proc;} edata;
9 
10 
11 #ifdef PARMETIS
12 
13 #include "parmetis.h"
14 #include "defs.h"
15 
16 int parMETIS_partMesh(int *part, long long *vl, int nel, int nv, int *opt, comm_ext ce)
17 {
18  int i, j;
19  int ierrm;
20  double time, time0;
21 
22  MPI_Comm comms;
23  struct comm comm;
24  int color;
25  int ibuf;
26 
27  struct crystal cr;
28  struct array A;
29  edata *row;
30 
31  long long nell;
32  long long *nelarray;
33  idx_t *elmdist;
34  idx_t *evlptr;
35  idx_t *part_;
36  real_t *tpwgts;
37  idx_t edgecut;
38  real_t ubvec;
39  idx_t *elmwgt;
40  idx_t wgtflag;
41  idx_t numflag;
42  idx_t ncon;
43  idx_t ncommonnodes;
44  idx_t nparts;
45  idx_t nelsm;
46  idx_t options[10];
47 
48  ierrm = METIS_OK;
49  nell = nel;
50  edgecut = 0;
51  wgtflag = 0;
52  numflag = 0;
53  ncon = 1;
54  ubvec = 1.02;
55  elmwgt = NULL; /* no weights */
56  ncommonnodes = 2;
57 
58  part_ = (idx_t*) malloc(nel*sizeof(idx_t));
59 
60  if (sizeof(idx_t) != sizeof(long long)){
61  printf("ERROR: invalid sizeof(idx_t)!\n");
62  goto err;
63  }
64  if (nv != 4 && nv != 8){
65  printf("ERROR: nv is %d but only 4 and 8 are supported!\n", nv);
66  goto err;
67  }
68 
69  color = MPI_UNDEFINED;
70  if (nel > 0) color = 1;
71  MPI_Comm_split(ce, color, 0, &comms);
72  if (color == MPI_UNDEFINED)
73  goto end;
74 
75  comm_init(&comm,comms);
76  if (comm.id == 0)
77  printf("Running parMETIS ... "), fflush(stdout);
78 
79  nelarray = (long long*) malloc(comm.np*sizeof(long long));
80  MPI_Allgather(&nell, 1, MPI_LONG_LONG_INT, nelarray, 1, MPI_LONG_LONG_INT, comm.c);
81  elmdist = (idx_t*) malloc((comm.np+1)*sizeof(idx_t));
82  elmdist[0] = 0;
83  for (i=0; i<comm.np; ++i)
84  elmdist[i+1] = elmdist[i] + (idx_t)nelarray[i];
85  free(nelarray);
86 
87  evlptr = (idx_t*) malloc((nel+1)*sizeof(idx_t));
88  evlptr[0] = 0;
89  for (i=0; i<nel; ++i)
90  evlptr[i+1] = evlptr[i] + nv;
91  nelsm = elmdist[comm.id+1] - elmdist[comm.id];
92  evlptr[nelsm]--;
93 
94  if (nv == 8) ncommonnodes = 4;
95  nparts = comm.np;
96 
97  options[0] = 1;
98  options[PMV3_OPTION_DBGLVL] = 0;
99  options[PMV3_OPTION_SEED] = 0;
100  if (opt[0] != 0) {
101  options[PMV3_OPTION_DBGLVL] = opt[1];
102  if (opt[2] != 0) {
103  options[3] = PARMETIS_PSR_UNCOUPLED;
104  nparts = opt[2];
105  }
106  }
107 
108  tpwgts = (real_t*) malloc(ncon*nparts*sizeof(real_t));
109  for (i=0; i<ncon*nparts; ++i)
110  tpwgts[i] = 1./(real_t)nparts;
111 
112  if (options[3] == PARMETIS_PSR_UNCOUPLED)
113  for (i=0; i<nel; ++i)
114  part_[i] = comm.id;
115 
116  comm_barrier(&comm);
117  time0 = comm_time();
118  ierrm = ParMETIS_V3_PartMeshKway(elmdist,
119  evlptr,
120  (idx_t*)vl,
121  elmwgt,
122  &wgtflag,
123  &numflag,
124  &ncon,
125  &ncommonnodes,
126  &nparts,
127  tpwgts,
128  &ubvec,
129  options,
130  &edgecut,
131  part_,
132  &comm.c);
133 
134  time = comm_time() - time0;
135  if (comm.id == 0)
136  printf("%lf sec\n", time), fflush(stdout);
137 
138  for (i=0; i<nel; ++i)
139  part[i] = part_[i];
140 
141  free(elmdist);
142  free(evlptr);
143  free(tpwgts);
144  MPI_Comm_free(&comms);
145  comm_free(&comm);
146 
147 end:
148  comm_init(&comm,ce);
149  comm_allreduce(&comm, gs_int, gs_min, &ierrm, 1, &ibuf);
150  if (ierrm != METIS_OK) goto err;
151  return 0;
152 
153 err:
154  return 1;
155 }
156 #endif
157 
158 void printPartStat(long long *vtx, int nel, int nv, comm_ext ce)
159 {
160  int i,j;
161 
162  struct comm comm;
163  int np, id;
164 
165  int Nmsg;
166  int *Ncomm;
167 
168  int nelMin, nelMax;
169  int ncMin, ncMax, ncSum;
170  int nsMin, nsMax, nsSum;
171  int nssMin, nssMax, nssSum;
172 
173  struct gs_data *gsh;
174  int b;
175 
176  int numPoints;
177  long long *data;
178 
179  comm_init(&comm,ce);
180  np = comm.np;
181  id = comm.id;
182 
183  if (np == 1) return;
184 
185  numPoints = nel*nv;
186  data = (long long*) malloc(numPoints*sizeof(long long));
187  for(i = 0; i < numPoints; i++) data[i] = vtx[i];
188 
189  gsh = gs_setup(data, numPoints, &comm, 0, gs_pairwise, 0);
190 
191  pw_data_nmsg(gsh, &Nmsg);
192  Ncomm = (int *) malloc(Nmsg*sizeof(int));
193  pw_data_size(gsh, Ncomm);
194 
195  gs_free(gsh);
196  free(data);
197 
198  ncMax = Nmsg;
199  ncMin = Nmsg;
200  ncSum = Nmsg;
201  comm_allreduce(&comm, gs_int, gs_max, &ncMax , 1, &b);
202  comm_allreduce(&comm, gs_int, gs_min, &ncMin , 1, &b);
203  comm_allreduce(&comm, gs_int, gs_add, &ncSum , 1, &b);
204 
205  nsMax = Ncomm[0];
206  nsMin = Ncomm[0];
207  nsSum = Ncomm[0];
208  for (i=1; i<Nmsg; ++i){
209  nsMax = Ncomm[i] > Ncomm[i-1] ? Ncomm[i] : Ncomm[i-1];
210  nsMin = Ncomm[i] < Ncomm[i-1] ? Ncomm[i] : Ncomm[i-1];
211  nsSum += Ncomm[i];
212  }
213  comm_allreduce(&comm, gs_int, gs_max, &nsMax , 1, &b);
214  comm_allreduce(&comm, gs_int, gs_min, &nsMin , 1, &b);
215 
216  nssMin = nsSum;
217  nssMax = nsSum;
218  nssSum = nsSum;
219  comm_allreduce(&comm, gs_int, gs_max, &nssMax , 1, &b);
220  comm_allreduce(&comm, gs_int, gs_min, &nssMin , 1, &b);
221  comm_allreduce(&comm, gs_int, gs_add, &nssSum , 1, &b);
222 
223  nsSum = nsSum/Nmsg;
224  comm_allreduce(&comm, gs_int, gs_add, &nsSum , 1, &b);
225 
226  nelMax = nel;
227  nelMin = nel;
228  comm_allreduce(&comm, gs_int, gs_max, &nelMax, 1, &b);
229  comm_allreduce(&comm, gs_int, gs_min, &nelMin, 1, &b);
230 
231  if (id == 0) {
232  printf(
233  " Max neighbors: %d | Min neighbors: %d | Avg neighbors: %lf\n",
234  ncMax, ncMin, (double)ncSum/np);
235  printf(
236  " Max nvolume: %d | Min nvolume: %d | Avg nvolume: %lf\n",
237  nsMax, nsMin, (double)nsSum/np);
238  printf(
239  " Max volume: %d | Min volume: %d | Avg volume: %lf\n",
240  nssMax, nssMin, (double)nssSum/np);
241  printf(
242  " Max elements: %d | Min elements: %d | Balance: %lf\n",
243  nelMax, nelMin, (double)nelMax/nelMin);
244  fflush(stdout);
245  }
246 
247  comm_free(&comm);
248 }
249 
250 int redistributeData(int *nel_,long long *vl,long long *el,int *part,
251  int nv,int lelt,struct comm *comm)
252 {
253  int nel=*nel_;
254 
255  struct crystal cr;
256  struct array eList;
257  edata *data;
258 
259  int count,e,n,ibuf;
260 
261  /* redistribute data */
262  array_init(edata, &eList, nel), eList.n = nel;
263  for(data = eList.ptr, e = 0; e < nel; ++e) {
264  data[e].proc = part[e];
265  data[e].eid = el[e];
266  for(n = 0; n < nv; ++n) {
267  data[e].vtx[n] = vl[e*nv + n];
268  }
269  }
270 
271  crystal_init(&cr,comm);
272  sarray_transfer(edata, &eList, proc, 0, &cr);
273  crystal_free(&cr);
274 
275  *nel_=nel=eList.n;
276 
277  count = 0;
278  if (nel > lelt) count = 1;
279  comm_allreduce(comm, gs_int, gs_add, &count, 1, &ibuf);
280  if (count > 0) {
281  if (comm->id == 0)
282  printf("ERROR: resulting parition requires lelt=%d!\n", nel);
283  return 1;
284  }
285 
286  for(data = eList.ptr, e = 0; e < nel; ++e) {
287  el[e] = data[e].eid;
288  for(n = 0; n < nv; ++n) {
289  vl[e*nv + n] = data[e].vtx[n];
290  }
291  }
292 
293  array_free(&eList);
294 
295  return 0;
296 }
297 
298 #define fpartMesh FORTRAN_UNPREFIXED(fpartmesh,FPARTMESH)
299 void fpartMesh(long long *el, long long *vl, double *xyz,
300  const int *lelt, int *nell, const int *nve,
301  int *fcomm, int *fmode,int *rtval)
302 {
303  struct comm comm;
304 
305  int nel, nv, mode;
306  int e, n;
307  int count, ierr, ibuf;
308  int *part;
309  int opt[3];
310 
311  nel = *nell;
312  nv = *nve;
313  mode = *fmode;
314 
315 #if defined(MPI)
316  comm_ext cext = MPI_Comm_f2c(*fcomm);
317 #else
318  comm_ext cext = 0;
319 #endif
320  comm_init(&comm, cext);
321 
322  part = (int*) malloc(*lelt * sizeof(int));
323 
324  /* printPartStat(vl, nel, nv, cext); */
325 
326  ierr = 1;
327 #if defined(PARRSB)
328  int rsb,rcb;
329  rsb=mode&1;
330  rcb=mode&2;
331 
332  opt[0] = 1;
333  opt[1] = 2; /* verbosity */
334  opt[2] = 0;
335 
336  if(rcb){
337  ierr = parRCB_partMesh(part, xyz, nel, nv, opt, comm.c);
338  if (ierr != 0) goto err;
339 
340  ierr=redistributeData(&nel,vl,el,part,nv,*lelt,&comm);
341  if (ierr != 0) goto err;
342 
343  /* printPartStat(vl, nel, nv, cext); */
344  }
345 
346  if(rsb){
347  ierr = parRSB_partMesh(part, vl, nel, nv, opt, comm.c);
348  if (ierr != 0) goto err;
349 
350  ierr=redistributeData(&nel,vl,el,part,nv,*lelt,&comm);
351  if (ierr != 0) goto err;
352 
353  /* printPartStat(vl, nel, nv, cext); */
354  }
355 #elif defined(PARMETIS)
356  int metis; metis=mode&4;
357 
358  if(metis){
359  opt[0] = 1;
360  opt[1] = 0; /* verbosity */
361  opt[2] = comm.np;
362 
363  ierr = parMETIS_partMesh(part, vl, nel, nv, opt, comm.c);
364 
365  ierr=redistributeData(&nel,vl,el,part,nv,*lelt,&comm);
366  if (ierr != 0) goto err;
367 
368  /* printPartStat(vl, nel, nv, cext); */
369  }
370 #endif
371 
372  *nell = nel;
373  *rtval = 0;
374  return;
375 
376 err:
377  fflush(stdout);
378  *rtval = 1;
379 }
380 
381 #define fprintPartStat FORTRAN_UNPREFIXED(printpartstat,PRINTPARTSTAT)
382 void fprintPartStat(long long *vtx, int *nel, int *nv, int *comm)
383 {
384 
385 #if defined(MPI)
386  comm_ext c = MPI_Comm_f2c(*comm);
387 #else
388  comm_ext c = 0;
389 #endif
390 
391  printPartStat(vtx, *nel, *nv, c);
392 }
subroutine lelt
Definition: cvode_aux.h:9
#define fprintPartStat
Definition: partitioner.c:381
#define fpartMesh
Definition: partitioner.c:298
#define MAXNV
Definition: partitioner.c:7
int redistributeData(int *nel_, long long *vl, long long *el, int *part, int nv, int lelt, struct comm *comm)
Definition: partitioner.c:250
void printPartStat(long long *vtx, int nel, int nv, comm_ext ce)
Definition: partitioner.c:158
int proc
Definition: partitioner.c:8
long long eid
Definition: partitioner.c:8
struct comm comm
Definition: fem_amg_preco.h:43