1
2 #include <petsc/private/isimpl.h> /*I "petscis.h" I*/
3 #include <petscviewer.h>
4 #include <petscsf.h>
5
6 const char *const ISColoringTypes[] = {"global","ghosted","ISColoringType","IS_COLORING_",NULL};
7
ISColoringReference(ISColoring coloring)8 PetscErrorCode ISColoringReference(ISColoring coloring)
9 {
10 PetscFunctionBegin;
11 coloring->refct++;
12 PetscFunctionReturn(0);
13 }
14
15 /*@C
16
17 ISColoringSetType - indicates if the coloring is for the local representation (including ghost points) or the global representation
18
19 Collective on coloring
20
21 Input Parameters:
22 + coloring - the coloring object
23 - type - either IS_COLORING_LOCAL or IS_COLORING_GLOBAL
24
25 Notes:
26 With IS_COLORING_LOCAL the coloring is in the numbering of the local vector, for IS_COLORING_GLOBAL it is in the number of the global vector
27
28 Level: intermediate
29
30 .seealso: MatFDColoringCreate(), ISColoring, ISColoringCreate(), IS_COLORING_LOCAL, IS_COLORING_GLOBAL, ISColoringGetType()
31
32 @*/
ISColoringSetType(ISColoring coloring,ISColoringType type)33 PetscErrorCode ISColoringSetType(ISColoring coloring,ISColoringType type)
34 {
35 PetscFunctionBegin;
36 coloring->ctype = type;
37 PetscFunctionReturn(0);
38 }
39
40 /*@C
41
42 ISColoringGetType - gets if the coloring is for the local representation (including ghost points) or the global representation
43
44 Collective on coloring
45
46 Input Parameter:
47 . coloring - the coloring object
48
49 Output Parameter:
50 . type - either IS_COLORING_LOCAL or IS_COLORING_GLOBAL
51
52 Level: intermediate
53
54 .seealso: MatFDColoringCreate(), ISColoring, ISColoringCreate(), IS_COLORING_LOCAL, IS_COLORING_GLOBAL, ISColoringSetType()
55
56 @*/
ISColoringGetType(ISColoring coloring,ISColoringType * type)57 PetscErrorCode ISColoringGetType(ISColoring coloring,ISColoringType *type)
58 {
59 PetscFunctionBegin;
60 *type = coloring->ctype;
61 PetscFunctionReturn(0);
62 }
63
64 /*@
65 ISColoringDestroy - Destroys a coloring context.
66
67 Collective on ISColoring
68
69 Input Parameter:
70 . iscoloring - the coloring context
71
72 Level: advanced
73
74 .seealso: ISColoringView(), MatColoring
75 @*/
ISColoringDestroy(ISColoring * iscoloring)76 PetscErrorCode ISColoringDestroy(ISColoring *iscoloring)
77 {
78 PetscInt i;
79 PetscErrorCode ierr;
80
81 PetscFunctionBegin;
82 if (!*iscoloring) PetscFunctionReturn(0);
83 PetscValidPointer((*iscoloring),1);
84 if (--(*iscoloring)->refct > 0) {*iscoloring = NULL; PetscFunctionReturn(0);}
85
86 if ((*iscoloring)->is) {
87 for (i=0; i<(*iscoloring)->n; i++) {
88 ierr = ISDestroy(&(*iscoloring)->is[i]);CHKERRQ(ierr);
89 }
90 ierr = PetscFree((*iscoloring)->is);CHKERRQ(ierr);
91 }
92 if ((*iscoloring)->allocated) {ierr = PetscFree((*iscoloring)->colors);CHKERRQ(ierr);}
93 ierr = PetscCommDestroy(&(*iscoloring)->comm);CHKERRQ(ierr);
94 ierr = PetscFree((*iscoloring));CHKERRQ(ierr);
95 PetscFunctionReturn(0);
96 }
97
98 /*
99 ISColoringViewFromOptions - Processes command line options to determine if/how an ISColoring object is to be viewed.
100
101 Collective on ISColoring
102
103 Input Parameters:
104 + obj - the ISColoring object
105 . prefix - prefix to use for viewing, or NULL to use prefix of 'mat'
106 - optionname - option to activate viewing
107
108 Level: intermediate
109
110 Developer Note: This cannot use PetscObjectViewFromOptions() because ISColoring is not a PetscObject
111
112 */
ISColoringViewFromOptions(ISColoring obj,PetscObject bobj,const char optionname[])113 PetscErrorCode ISColoringViewFromOptions(ISColoring obj,PetscObject bobj,const char optionname[])
114 {
115 PetscErrorCode ierr;
116 PetscViewer viewer;
117 PetscBool flg;
118 PetscViewerFormat format;
119 char *prefix;
120
121 PetscFunctionBegin;
122 prefix = bobj ? bobj->prefix : NULL;
123 ierr = PetscOptionsGetViewer(obj->comm,NULL,prefix,optionname,&viewer,&format,&flg);CHKERRQ(ierr);
124 if (flg) {
125 ierr = PetscViewerPushFormat(viewer,format);CHKERRQ(ierr);
126 ierr = ISColoringView(obj,viewer);CHKERRQ(ierr);
127 ierr = PetscViewerPopFormat(viewer);CHKERRQ(ierr);
128 ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr);
129 }
130 PetscFunctionReturn(0);
131 }
132
133 /*@C
134 ISColoringView - Views a coloring context.
135
136 Collective on ISColoring
137
138 Input Parameters:
139 + iscoloring - the coloring context
140 - viewer - the viewer
141
142 Level: advanced
143
144 .seealso: ISColoringDestroy(), ISColoringGetIS(), MatColoring
145 @*/
ISColoringView(ISColoring iscoloring,PetscViewer viewer)146 PetscErrorCode ISColoringView(ISColoring iscoloring,PetscViewer viewer)
147 {
148 PetscInt i;
149 PetscErrorCode ierr;
150 PetscBool iascii;
151 IS *is;
152
153 PetscFunctionBegin;
154 PetscValidPointer(iscoloring,1);
155 if (!viewer) {
156 ierr = PetscViewerASCIIGetStdout(iscoloring->comm,&viewer);CHKERRQ(ierr);
157 }
158 PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
159
160 ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
161 if (iascii) {
162 MPI_Comm comm;
163 PetscMPIInt size,rank;
164
165 ierr = PetscObjectGetComm((PetscObject)viewer,&comm);CHKERRQ(ierr);
166 ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
167 ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
168 ierr = PetscViewerASCIIPrintf(viewer,"ISColoring Object: %d MPI processes\n",size);CHKERRQ(ierr);
169 ierr = PetscViewerASCIIPrintf(viewer,"ISColoringType: %s\n",ISColoringTypes[iscoloring->ctype]);CHKERRQ(ierr);
170 ierr = PetscViewerASCIIPushSynchronized(viewer);CHKERRQ(ierr);
171 ierr = PetscViewerASCIISynchronizedPrintf(viewer,"[%d] Number of colors %d\n",rank,iscoloring->n);CHKERRQ(ierr);
172 ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
173 ierr = PetscViewerASCIIPopSynchronized(viewer);CHKERRQ(ierr);
174 }
175
176 ierr = ISColoringGetIS(iscoloring,PETSC_USE_POINTER,PETSC_IGNORE,&is);CHKERRQ(ierr);
177 for (i=0; i<iscoloring->n; i++) {
178 ierr = ISView(iscoloring->is[i],viewer);CHKERRQ(ierr);
179 }
180 ierr = ISColoringRestoreIS(iscoloring,PETSC_USE_POINTER,&is);CHKERRQ(ierr);
181 PetscFunctionReturn(0);
182 }
183
184 /*@C
185 ISColoringGetColors - Returns an array with the color for each node
186
187 Not Collective
188
189 Input Parameter:
190 . iscoloring - the coloring context
191
192 Output Parameters:
193 + n - number of nodes
194 . nc - number of colors
195 - colors - color for each node
196
197 Level: advanced
198
199 .seealso: ISColoringRestoreIS(), ISColoringView(), ISColoringGetIS()
200 @*/
ISColoringGetColors(ISColoring iscoloring,PetscInt * n,PetscInt * nc,const ISColoringValue ** colors)201 PetscErrorCode ISColoringGetColors(ISColoring iscoloring,PetscInt *n,PetscInt *nc,const ISColoringValue **colors)
202 {
203 PetscFunctionBegin;
204 PetscValidPointer(iscoloring,1);
205
206 if (n) *n = iscoloring->N;
207 if (nc) *nc = iscoloring->n;
208 if (colors) *colors = iscoloring->colors;
209 PetscFunctionReturn(0);
210 }
211
212 /*@C
213 ISColoringGetIS - Extracts index sets from the coloring context. Each is contains the nodes of one color
214
215 Collective on ISColoring
216
217 Input Parameter:
218 + iscoloring - the coloring context
219 - mode - if this value is PETSC_OWN_POINTER then the caller owns the pointer and must free the array of IS and each IS in the array
220
221 Output Parameters:
222 + nn - number of index sets in the coloring context
223 - is - array of index sets
224
225 Level: advanced
226
227 .seealso: ISColoringRestoreIS(), ISColoringView(), ISColoringGetColoring()
228 @*/
ISColoringGetIS(ISColoring iscoloring,PetscCopyMode mode,PetscInt * nn,IS * isis[])229 PetscErrorCode ISColoringGetIS(ISColoring iscoloring,PetscCopyMode mode, PetscInt *nn,IS *isis[])
230 {
231 PetscErrorCode ierr;
232
233 PetscFunctionBegin;
234 PetscValidPointer(iscoloring,1);
235
236 if (nn) *nn = iscoloring->n;
237 if (isis) {
238 if (!iscoloring->is) {
239 PetscInt *mcolors,**ii,nc = iscoloring->n,i,base, n = iscoloring->N;
240 ISColoringValue *colors = iscoloring->colors;
241 IS *is;
242
243 if (PetscDefined(USE_DEBUG)) {
244 for (i=0; i<n; i++) {
245 if (((PetscInt)colors[i]) >= nc) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Coloring is our of range index %d value %d number colors %d",(int)i,(int)colors[i],(int)nc);
246 }
247 }
248
249 /* generate the lists of nodes for each color */
250 ierr = PetscCalloc1(nc,&mcolors);CHKERRQ(ierr);
251 for (i=0; i<n; i++) mcolors[colors[i]]++;
252
253 ierr = PetscMalloc1(nc,&ii);CHKERRQ(ierr);
254 ierr = PetscMalloc1(n,&ii[0]);CHKERRQ(ierr);
255 for (i=1; i<nc; i++) ii[i] = ii[i-1] + mcolors[i-1];
256 ierr = PetscArrayzero(mcolors,nc);CHKERRQ(ierr);
257
258 if (iscoloring->ctype == IS_COLORING_GLOBAL) {
259 ierr = MPI_Scan(&iscoloring->N,&base,1,MPIU_INT,MPI_SUM,iscoloring->comm);CHKERRQ(ierr);
260 base -= iscoloring->N;
261 for (i=0; i<n; i++) ii[colors[i]][mcolors[colors[i]]++] = i + base; /* global idx */
262 } else if (iscoloring->ctype == IS_COLORING_LOCAL) {
263 for (i=0; i<n; i++) ii[colors[i]][mcolors[colors[i]]++] = i; /* local idx */
264 } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Not provided for this ISColoringType type");
265
266 ierr = PetscMalloc1(nc,&is);CHKERRQ(ierr);
267 for (i=0; i<nc; i++) {
268 ierr = ISCreateGeneral(iscoloring->comm,mcolors[i],ii[i],PETSC_COPY_VALUES,is+i);CHKERRQ(ierr);
269 }
270
271 if (mode != PETSC_OWN_POINTER) iscoloring->is = is;
272 *isis = is;
273 ierr = PetscFree(ii[0]);CHKERRQ(ierr);
274 ierr = PetscFree(ii);CHKERRQ(ierr);
275 ierr = PetscFree(mcolors);CHKERRQ(ierr);
276 } else {
277 *isis = iscoloring->is;
278 }
279 }
280 PetscFunctionReturn(0);
281 }
282
283 /*@C
284 ISColoringRestoreIS - Restores the index sets extracted from the coloring context
285
286 Collective on ISColoring
287
288 Input Parameter:
289 + iscoloring - the coloring context
290 . mode - who retains ownership of the is
291 - is - array of index sets
292
293 Level: advanced
294
295 .seealso: ISColoringGetIS(), ISColoringView()
296 @*/
ISColoringRestoreIS(ISColoring iscoloring,PetscCopyMode mode,IS * is[])297 PetscErrorCode ISColoringRestoreIS(ISColoring iscoloring,PetscCopyMode mode,IS *is[])
298 {
299 PetscFunctionBegin;
300 PetscValidPointer(iscoloring,1);
301
302 /* currently nothing is done here */
303 PetscFunctionReturn(0);
304 }
305
306
307 /*@
308 ISColoringCreate - Generates an ISColoring context from lists (provided
309 by each processor) of colors for each node.
310
311 Collective
312
313 Input Parameters:
314 + comm - communicator for the processors creating the coloring
315 . ncolors - max color value
316 . n - number of nodes on this processor
317 . colors - array containing the colors for this processor, color numbers begin at 0.
318 - mode - see PetscCopyMode for meaning of this flag.
319
320 Output Parameter:
321 . iscoloring - the resulting coloring data structure
322
323 Options Database Key:
324 . -is_coloring_view - Activates ISColoringView()
325
326 Level: advanced
327
328 Notes:
329 By default sets coloring type to IS_COLORING_GLOBAL
330
331 .seealso: MatColoringCreate(), ISColoringView(), ISColoringDestroy(), ISColoringSetType()
332
333 @*/
ISColoringCreate(MPI_Comm comm,PetscInt ncolors,PetscInt n,const ISColoringValue colors[],PetscCopyMode mode,ISColoring * iscoloring)334 PetscErrorCode ISColoringCreate(MPI_Comm comm,PetscInt ncolors,PetscInt n,const ISColoringValue colors[],PetscCopyMode mode,ISColoring *iscoloring)
335 {
336 PetscErrorCode ierr;
337 PetscMPIInt size,rank,tag;
338 PetscInt base,top,i;
339 PetscInt nc,ncwork;
340 MPI_Status status;
341
342 PetscFunctionBegin;
343 if (ncolors != PETSC_DECIDE && ncolors > IS_COLORING_MAX) {
344 if (ncolors > PETSC_MAX_UINT16) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Max color value exceeds %d limit. This number is unrealistic. Perhaps a bug in code?\nCurrent max: %d user requested: %D",PETSC_MAX_UINT16,PETSC_IS_COLORING_MAX,ncolors);
345 else SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Max color value exceeds limit. Perhaps reconfigure PETSc with --with-is-color-value-type=short?\n Current max: %d user requested: %D",PETSC_IS_COLORING_MAX,ncolors);
346 }
347 ierr = PetscNew(iscoloring);CHKERRQ(ierr);
348 ierr = PetscCommDuplicate(comm,&(*iscoloring)->comm,&tag);CHKERRQ(ierr);
349 comm = (*iscoloring)->comm;
350
351 /* compute the number of the first node on my processor */
352 ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
353
354 /* should use MPI_Scan() */
355 ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
356 if (!rank) {
357 base = 0;
358 top = n;
359 } else {
360 ierr = MPI_Recv(&base,1,MPIU_INT,rank-1,tag,comm,&status);CHKERRQ(ierr);
361 top = base+n;
362 }
363 if (rank < size-1) {
364 ierr = MPI_Send(&top,1,MPIU_INT,rank+1,tag,comm);CHKERRQ(ierr);
365 }
366
367 /* compute the total number of colors */
368 ncwork = 0;
369 for (i=0; i<n; i++) {
370 if (ncwork < colors[i]) ncwork = colors[i];
371 }
372 ncwork++;
373 ierr = MPIU_Allreduce(&ncwork,&nc,1,MPIU_INT,MPI_MAX,comm);CHKERRQ(ierr);
374 if (nc > ncolors) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of colors passed in %D is less then the actual number of colors in array %D",ncolors,nc);
375 (*iscoloring)->n = nc;
376 (*iscoloring)->is = NULL;
377 (*iscoloring)->N = n;
378 (*iscoloring)->refct = 1;
379 (*iscoloring)->ctype = IS_COLORING_GLOBAL;
380 if (mode == PETSC_COPY_VALUES) {
381 ierr = PetscMalloc1(n,&(*iscoloring)->colors);CHKERRQ(ierr);
382 ierr = PetscLogObjectMemory((PetscObject)(*iscoloring),n*sizeof(ISColoringValue));CHKERRQ(ierr);
383 ierr = PetscArraycpy((*iscoloring)->colors,colors,n);CHKERRQ(ierr);
384 (*iscoloring)->allocated = PETSC_TRUE;
385 } else if (mode == PETSC_OWN_POINTER) {
386 (*iscoloring)->colors = (ISColoringValue*)colors;
387 (*iscoloring)->allocated = PETSC_TRUE;
388 } else {
389 (*iscoloring)->colors = (ISColoringValue*)colors;
390 (*iscoloring)->allocated = PETSC_FALSE;
391 }
392 ierr = ISColoringViewFromOptions(*iscoloring,NULL,"-is_coloring_view");CHKERRQ(ierr);
393 ierr = PetscInfo1(0,"Number of colors %D\n",nc);CHKERRQ(ierr);
394 PetscFunctionReturn(0);
395 }
396
397 /*@
398 ISBuildTwoSided - Takes an IS that describes where we will go. Generates an IS that contains new numbers from remote or local
399 on the IS.
400
401 Collective on IS
402
403 Input Parameters:
404 + ito - an IS describes where we will go. Negative target rank will be ignored
405 - toindx - an IS describes what indices should send. NULL means sending natural numbering
406
407 Output Parameter:
408 . rows - contains new numbers from remote or local
409
410 Level: advanced
411
412 .seealso: MatPartitioningCreate(), ISPartitioningToNumbering(), ISPartitioningCount()
413
414 @*/
ISBuildTwoSided(IS ito,IS toindx,IS * rows)415 PetscErrorCode ISBuildTwoSided(IS ito,IS toindx, IS *rows)
416 {
417 const PetscInt *ito_indices,*toindx_indices;
418 PetscInt *send_indices,rstart,*recv_indices,nrecvs,nsends;
419 PetscInt *tosizes,*fromsizes,i,j,*tosizes_tmp,*tooffsets_tmp,ito_ln;
420 PetscMPIInt *toranks,*fromranks,size,target_rank,*fromperm_newtoold,nto,nfrom;
421 PetscLayout isrmap;
422 MPI_Comm comm;
423 PetscSF sf;
424 PetscSFNode *iremote;
425 PetscErrorCode ierr;
426
427 PetscFunctionBegin;
428 ierr = PetscObjectGetComm((PetscObject)ito,&comm);CHKERRQ(ierr);
429 ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
430 ierr = ISGetLocalSize(ito,&ito_ln);CHKERRQ(ierr);
431 /* why we do not have ISGetLayout? */
432 isrmap = ito->map;
433 ierr = PetscLayoutGetRange(isrmap,&rstart,NULL);CHKERRQ(ierr);
434 ierr = ISGetIndices(ito,&ito_indices);CHKERRQ(ierr);
435 ierr = PetscCalloc2(size,&tosizes_tmp,size+1,&tooffsets_tmp);CHKERRQ(ierr);
436 for (i=0; i<ito_ln; i++) {
437 if (ito_indices[i]<0) continue;
438 if (ito_indices[i]>=size) SETERRQ2(comm,PETSC_ERR_ARG_OUTOFRANGE,"target rank %d is larger than communicator size %d ",ito_indices[i],size);
439 tosizes_tmp[ito_indices[i]]++;
440 }
441 nto = 0;
442 for (i=0; i<size; i++) {
443 tooffsets_tmp[i+1] = tooffsets_tmp[i]+tosizes_tmp[i];
444 if (tosizes_tmp[i]>0) nto++;
445 }
446 ierr = PetscCalloc2(nto,&toranks,2*nto,&tosizes);CHKERRQ(ierr);
447 nto = 0;
448 for (i=0; i<size; i++) {
449 if (tosizes_tmp[i]>0) {
450 toranks[nto] = i;
451 tosizes[2*nto] = tosizes_tmp[i];/* size */
452 tosizes[2*nto+1] = tooffsets_tmp[i];/* offset */
453 nto++;
454 }
455 }
456 nsends = tooffsets_tmp[size];
457 ierr = PetscCalloc1(nsends,&send_indices);CHKERRQ(ierr);
458 if (toindx) {
459 ierr = ISGetIndices(toindx,&toindx_indices);CHKERRQ(ierr);
460 }
461 for (i=0; i<ito_ln; i++) {
462 if (ito_indices[i]<0) continue;
463 target_rank = ito_indices[i];
464 send_indices[tooffsets_tmp[target_rank]] = toindx? toindx_indices[i]:(i+rstart);
465 tooffsets_tmp[target_rank]++;
466 }
467 if (toindx) {
468 ierr = ISRestoreIndices(toindx,&toindx_indices);CHKERRQ(ierr);
469 }
470 ierr = ISRestoreIndices(ito,&ito_indices);CHKERRQ(ierr);
471 ierr = PetscFree2(tosizes_tmp,tooffsets_tmp);CHKERRQ(ierr);
472 ierr = PetscCommBuildTwoSided(comm,2,MPIU_INT,nto,toranks,tosizes,&nfrom,&fromranks,&fromsizes);CHKERRQ(ierr);
473 ierr = PetscFree2(toranks,tosizes);CHKERRQ(ierr);
474 ierr = PetscMalloc1(nfrom,&fromperm_newtoold);CHKERRQ(ierr);
475 for (i=0; i<nfrom; i++) fromperm_newtoold[i] = i;
476 ierr = PetscSortMPIIntWithArray(nfrom,fromranks,fromperm_newtoold);CHKERRQ(ierr);
477 nrecvs = 0;
478 for (i=0; i<nfrom; i++) nrecvs += fromsizes[i*2];
479 ierr = PetscCalloc1(nrecvs,&recv_indices);CHKERRQ(ierr);
480 ierr = PetscMalloc1(nrecvs,&iremote);CHKERRQ(ierr);
481 nrecvs = 0;
482 for (i=0; i<nfrom; i++) {
483 for (j=0; j<fromsizes[2*fromperm_newtoold[i]]; j++) {
484 iremote[nrecvs].rank = fromranks[i];
485 iremote[nrecvs++].index = fromsizes[2*fromperm_newtoold[i]+1]+j;
486 }
487 }
488 ierr = PetscSFCreate(comm,&sf);CHKERRQ(ierr);
489 ierr = PetscSFSetGraph(sf,nsends,nrecvs,NULL,PETSC_OWN_POINTER,iremote,PETSC_OWN_POINTER);CHKERRQ(ierr);
490 ierr = PetscSFSetType(sf,PETSCSFBASIC);CHKERRQ(ierr);
491 /* how to put a prefix ? */
492 ierr = PetscSFSetFromOptions(sf);CHKERRQ(ierr);
493 ierr = PetscSFBcastBegin(sf,MPIU_INT,send_indices,recv_indices);CHKERRQ(ierr);
494 ierr = PetscSFBcastEnd(sf,MPIU_INT,send_indices,recv_indices);CHKERRQ(ierr);
495 ierr = PetscSFDestroy(&sf);CHKERRQ(ierr);
496 ierr = PetscFree(fromranks);CHKERRQ(ierr);
497 ierr = PetscFree(fromsizes);CHKERRQ(ierr);
498 ierr = PetscFree(fromperm_newtoold);CHKERRQ(ierr);
499 ierr = PetscFree(send_indices);CHKERRQ(ierr);
500 if (rows) {
501 ierr = PetscSortInt(nrecvs,recv_indices);CHKERRQ(ierr);
502 ierr = ISCreateGeneral(comm,nrecvs,recv_indices,PETSC_OWN_POINTER,rows);CHKERRQ(ierr);
503 } else {
504 ierr = PetscFree(recv_indices);CHKERRQ(ierr);
505 }
506 PetscFunctionReturn(0);
507 }
508
509
510 /*@
511 ISPartitioningToNumbering - Takes an ISPartitioning and on each processor
512 generates an IS that contains a new global node number for each index based
513 on the partitioing.
514
515 Collective on IS
516
517 Input Parameters:
518 . partitioning - a partitioning as generated by MatPartitioningApply()
519 or MatPartitioningApplyND()
520
521 Output Parameter:
522 . is - on each processor the index set that defines the global numbers
523 (in the new numbering) for all the nodes currently (before the partitioning)
524 on that processor
525
526 Level: advanced
527
528 .seealso: MatPartitioningCreate(), AOCreateBasic(), ISPartitioningCount()
529
530 @*/
ISPartitioningToNumbering(IS part,IS * is)531 PetscErrorCode ISPartitioningToNumbering(IS part,IS *is)
532 {
533 MPI_Comm comm;
534 IS ndorder;
535 PetscInt i,np,npt,n,*starts = NULL,*sums = NULL,*lsizes = NULL,*newi = NULL;
536 const PetscInt *indices = NULL;
537 PetscErrorCode ierr;
538
539 PetscFunctionBegin;
540 PetscValidHeaderSpecific(part,IS_CLASSID,1);
541 PetscValidPointer(is,2);
542 /* see if the partitioning comes from nested dissection */
543 ierr = PetscObjectQuery((PetscObject)part,"_petsc_matpartitioning_ndorder",(PetscObject*)&ndorder);CHKERRQ(ierr);
544 if (ndorder) {
545 ierr = PetscObjectReference((PetscObject)ndorder);CHKERRQ(ierr);
546 *is = ndorder;
547 PetscFunctionReturn(0);
548 }
549
550 ierr = PetscObjectGetComm((PetscObject)part,&comm);CHKERRQ(ierr);
551 /* count the number of partitions, i.e., virtual processors */
552 ierr = ISGetLocalSize(part,&n);CHKERRQ(ierr);
553 ierr = ISGetIndices(part,&indices);CHKERRQ(ierr);
554 np = 0;
555 for (i=0; i<n; i++) np = PetscMax(np,indices[i]);
556 ierr = MPIU_Allreduce(&np,&npt,1,MPIU_INT,MPI_MAX,comm);CHKERRQ(ierr);
557 np = npt+1; /* so that it looks like a MPI_Comm_size output */
558
559 /*
560 lsizes - number of elements of each partition on this particular processor
561 sums - total number of "previous" nodes for any particular partition
562 starts - global number of first element in each partition on this processor
563 */
564 ierr = PetscMalloc3(np,&lsizes,np,&starts,np,&sums);CHKERRQ(ierr);
565 ierr = PetscArrayzero(lsizes,np);CHKERRQ(ierr);
566 for (i=0; i<n; i++) lsizes[indices[i]]++;
567 ierr = MPIU_Allreduce(lsizes,sums,np,MPIU_INT,MPI_SUM,comm);CHKERRQ(ierr);
568 ierr = MPI_Scan(lsizes,starts,np,MPIU_INT,MPI_SUM,comm);CHKERRQ(ierr);
569 for (i=0; i<np; i++) starts[i] -= lsizes[i];
570 for (i=1; i<np; i++) {
571 sums[i] += sums[i-1];
572 starts[i] += sums[i-1];
573 }
574
575 /*
576 For each local index give it the new global number
577 */
578 ierr = PetscMalloc1(n,&newi);CHKERRQ(ierr);
579 for (i=0; i<n; i++) newi[i] = starts[indices[i]]++;
580 ierr = PetscFree3(lsizes,starts,sums);CHKERRQ(ierr);
581
582 ierr = ISRestoreIndices(part,&indices);CHKERRQ(ierr);
583 ierr = ISCreateGeneral(comm,n,newi,PETSC_OWN_POINTER,is);CHKERRQ(ierr);
584 ierr = ISSetPermutation(*is);CHKERRQ(ierr);
585 PetscFunctionReturn(0);
586 }
587
588 /*@
589 ISPartitioningCount - Takes a ISPartitioning and determines the number of
590 resulting elements on each (partition) process
591
592 Collective on IS
593
594 Input Parameters:
595 + partitioning - a partitioning as generated by MatPartitioningApply() or
596 MatPartitioningApplyND()
597 - len - length of the array count, this is the total number of partitions
598
599 Output Parameter:
600 . count - array of length size, to contain the number of elements assigned
601 to each partition, where size is the number of partitions generated
602 (see notes below).
603
604 Level: advanced
605
606 Notes:
607 By default the number of partitions generated (and thus the length
608 of count) is the size of the communicator associated with IS,
609 but it can be set by MatPartitioningSetNParts. The resulting array
610 of lengths can for instance serve as input of PCBJacobiSetTotalBlocks.
611 If the partitioning has been obtained by MatPartitioningApplyND(),
612 the returned count does not include the separators.
613
614 .seealso: MatPartitioningCreate(), AOCreateBasic(), ISPartitioningToNumbering(),
615 MatPartitioningSetNParts(), MatPartitioningApply(), MatPartitioningApplyND()
616
617 @*/
ISPartitioningCount(IS part,PetscInt len,PetscInt count[])618 PetscErrorCode ISPartitioningCount(IS part,PetscInt len,PetscInt count[])
619 {
620 MPI_Comm comm;
621 PetscInt i,n,*lsizes;
622 const PetscInt *indices;
623 PetscErrorCode ierr;
624 PetscMPIInt npp;
625
626 PetscFunctionBegin;
627 ierr = PetscObjectGetComm((PetscObject)part,&comm);CHKERRQ(ierr);
628 if (len == PETSC_DEFAULT) {
629 PetscMPIInt size;
630 ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
631 len = (PetscInt) size;
632 }
633
634 /* count the number of partitions */
635 ierr = ISGetLocalSize(part,&n);CHKERRQ(ierr);
636 ierr = ISGetIndices(part,&indices);CHKERRQ(ierr);
637 if (PetscDefined(USE_DEBUG)) {
638 PetscInt np = 0,npt;
639 for (i=0; i<n; i++) np = PetscMax(np,indices[i]);
640 ierr = MPIU_Allreduce(&np,&npt,1,MPIU_INT,MPI_MAX,comm);CHKERRQ(ierr);
641 np = npt+1; /* so that it looks like a MPI_Comm_size output */
642 if (np > len) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_SIZ,"Length of count array %D is less than number of partitions %D",len,np);
643 }
644
645 /*
646 lsizes - number of elements of each partition on this particular processor
647 sums - total number of "previous" nodes for any particular partition
648 starts - global number of first element in each partition on this processor
649 */
650 ierr = PetscCalloc1(len,&lsizes);CHKERRQ(ierr);
651 for (i=0; i<n; i++) {
652 if (indices[i] > -1) lsizes[indices[i]]++;
653 }
654 ierr = ISRestoreIndices(part,&indices);CHKERRQ(ierr);
655 ierr = PetscMPIIntCast(len,&npp);CHKERRQ(ierr);
656 ierr = MPIU_Allreduce(lsizes,count,npp,MPIU_INT,MPI_SUM,comm);CHKERRQ(ierr);
657 ierr = PetscFree(lsizes);CHKERRQ(ierr);
658 PetscFunctionReturn(0);
659 }
660
661 /*@
662 ISAllGather - Given an index set (IS) on each processor, generates a large
663 index set (same on each processor) by concatenating together each
664 processors index set.
665
666 Collective on IS
667
668 Input Parameter:
669 . is - the distributed index set
670
671 Output Parameter:
672 . isout - the concatenated index set (same on all processors)
673
674 Notes:
675 ISAllGather() is clearly not scalable for large index sets.
676
677 The IS created on each processor must be created with a common
678 communicator (e.g., PETSC_COMM_WORLD). If the index sets were created
679 with PETSC_COMM_SELF, this routine will not work as expected, since
680 each process will generate its own new IS that consists only of
681 itself.
682
683 The communicator for this new IS is PETSC_COMM_SELF
684
685 Level: intermediate
686
687 .seealso: ISCreateGeneral(), ISCreateStride(), ISCreateBlock()
688 @*/
ISAllGather(IS is,IS * isout)689 PetscErrorCode ISAllGather(IS is,IS *isout)
690 {
691 PetscErrorCode ierr;
692 PetscInt *indices,n,i,N,step,first;
693 const PetscInt *lindices;
694 MPI_Comm comm;
695 PetscMPIInt size,*sizes = NULL,*offsets = NULL,nn;
696 PetscBool stride;
697
698 PetscFunctionBegin;
699 PetscValidHeaderSpecific(is,IS_CLASSID,1);
700 PetscValidPointer(isout,2);
701
702 ierr = PetscObjectGetComm((PetscObject)is,&comm);CHKERRQ(ierr);
703 ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
704 ierr = ISGetLocalSize(is,&n);CHKERRQ(ierr);
705 ierr = PetscObjectTypeCompare((PetscObject)is,ISSTRIDE,&stride);CHKERRQ(ierr);
706 if (size == 1 && stride) { /* should handle parallel ISStride also */
707 ierr = ISStrideGetInfo(is,&first,&step);CHKERRQ(ierr);
708 ierr = ISCreateStride(PETSC_COMM_SELF,n,first,step,isout);CHKERRQ(ierr);
709 } else {
710 ierr = PetscMalloc2(size,&sizes,size,&offsets);CHKERRQ(ierr);
711
712 ierr = PetscMPIIntCast(n,&nn);CHKERRQ(ierr);
713 ierr = MPI_Allgather(&nn,1,MPI_INT,sizes,1,MPI_INT,comm);CHKERRQ(ierr);
714 offsets[0] = 0;
715 for (i=1; i<size; i++) {
716 PetscInt s = offsets[i-1] + sizes[i-1];
717 ierr = PetscMPIIntCast(s,&offsets[i]);CHKERRQ(ierr);
718 }
719 N = offsets[size-1] + sizes[size-1];
720
721 ierr = PetscMalloc1(N,&indices);CHKERRQ(ierr);
722 ierr = ISGetIndices(is,&lindices);CHKERRQ(ierr);
723 ierr = MPI_Allgatherv((void*)lindices,nn,MPIU_INT,indices,sizes,offsets,MPIU_INT,comm);CHKERRQ(ierr);
724 ierr = ISRestoreIndices(is,&lindices);CHKERRQ(ierr);
725 ierr = PetscFree2(sizes,offsets);CHKERRQ(ierr);
726
727 ierr = ISCreateGeneral(PETSC_COMM_SELF,N,indices,PETSC_OWN_POINTER,isout);CHKERRQ(ierr);
728 }
729 PetscFunctionReturn(0);
730 }
731
732 /*@C
733 ISAllGatherColors - Given a a set of colors on each processor, generates a large
734 set (same on each processor) by concatenating together each processors colors
735
736 Collective
737
738 Input Parameter:
739 + comm - communicator to share the indices
740 . n - local size of set
741 - lindices - local colors
742
743 Output Parameter:
744 + outN - total number of indices
745 - outindices - all of the colors
746
747 Notes:
748 ISAllGatherColors() is clearly not scalable for large index sets.
749
750
751 Level: intermediate
752
753 .seealso: ISCreateGeneral(), ISCreateStride(), ISCreateBlock(), ISAllGather()
754 @*/
ISAllGatherColors(MPI_Comm comm,PetscInt n,ISColoringValue * lindices,PetscInt * outN,ISColoringValue * outindices[])755 PetscErrorCode ISAllGatherColors(MPI_Comm comm,PetscInt n,ISColoringValue *lindices,PetscInt *outN,ISColoringValue *outindices[])
756 {
757 ISColoringValue *indices;
758 PetscErrorCode ierr;
759 PetscInt i,N;
760 PetscMPIInt size,*offsets = NULL,*sizes = NULL, nn = n;
761
762 PetscFunctionBegin;
763 ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
764 ierr = PetscMalloc2(size,&sizes,size,&offsets);CHKERRQ(ierr);
765
766 ierr = MPI_Allgather(&nn,1,MPI_INT,sizes,1,MPI_INT,comm);CHKERRQ(ierr);
767 offsets[0] = 0;
768 for (i=1; i<size; i++) offsets[i] = offsets[i-1] + sizes[i-1];
769 N = offsets[size-1] + sizes[size-1];
770 ierr = PetscFree2(sizes,offsets);CHKERRQ(ierr);
771
772 ierr = PetscMalloc1(N+1,&indices);CHKERRQ(ierr);
773 ierr = MPI_Allgatherv(lindices,(PetscMPIInt)n,MPIU_COLORING_VALUE,indices,sizes,offsets,MPIU_COLORING_VALUE,comm);CHKERRQ(ierr);
774
775 *outindices = indices;
776 if (outN) *outN = N;
777 PetscFunctionReturn(0);
778 }
779
780 /*@
781 ISComplement - Given an index set (IS) generates the complement index set. That is all
782 all indices that are NOT in the given set.
783
784 Collective on IS
785
786 Input Parameter:
787 + is - the index set
788 . nmin - the first index desired in the local part of the complement
789 - nmax - the largest index desired in the local part of the complement (note that all indices in is must be greater or equal to nmin and less than nmax)
790
791 Output Parameter:
792 . isout - the complement
793
794 Notes:
795 The communicator for this new IS is the same as for the input IS
796
797 For a parallel IS, this will generate the local part of the complement on each process
798
799 To generate the entire complement (on each process) of a parallel IS, first call ISAllGather() and then
800 call this routine.
801
802 Level: intermediate
803
804 .seealso: ISCreateGeneral(), ISCreateStride(), ISCreateBlock(), ISAllGather()
805 @*/
ISComplement(IS is,PetscInt nmin,PetscInt nmax,IS * isout)806 PetscErrorCode ISComplement(IS is,PetscInt nmin,PetscInt nmax,IS *isout)
807 {
808 PetscErrorCode ierr;
809 const PetscInt *indices;
810 PetscInt n,i,j,unique,cnt,*nindices;
811 PetscBool sorted;
812
813 PetscFunctionBegin;
814 PetscValidHeaderSpecific(is,IS_CLASSID,1);
815 PetscValidPointer(isout,3);
816 if (nmin < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"nmin %D cannot be negative",nmin);
817 if (nmin > nmax) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"nmin %D cannot be greater than nmax %D",nmin,nmax);
818 ierr = ISSorted(is,&sorted);CHKERRQ(ierr);
819 if (!sorted) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Index set must be sorted");
820
821 ierr = ISGetLocalSize(is,&n);CHKERRQ(ierr);
822 ierr = ISGetIndices(is,&indices);CHKERRQ(ierr);
823 if (PetscDefined(USE_DEBUG)) {
824 for (i=0; i<n; i++) {
825 if (indices[i] < nmin) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Index %D's value %D is smaller than minimum given %D",i,indices[i],nmin);
826 if (indices[i] >= nmax) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Index %D's value %D is larger than maximum given %D",i,indices[i],nmax);
827 }
828 }
829 /* Count number of unique entries */
830 unique = (n>0);
831 for (i=0; i<n-1; i++) {
832 if (indices[i+1] != indices[i]) unique++;
833 }
834 ierr = PetscMalloc1(nmax-nmin-unique,&nindices);CHKERRQ(ierr);
835 cnt = 0;
836 for (i=nmin,j=0; i<nmax; i++) {
837 if (j<n && i==indices[j]) do { j++; } while (j<n && i==indices[j]);
838 else nindices[cnt++] = i;
839 }
840 if (cnt != nmax-nmin-unique) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Number of entries found in complement %D does not match expected %D",cnt,nmax-nmin-unique);
841 ierr = ISCreateGeneral(PetscObjectComm((PetscObject)is),cnt,nindices,PETSC_OWN_POINTER,isout);CHKERRQ(ierr);
842 ierr = ISRestoreIndices(is,&indices);CHKERRQ(ierr);
843 PetscFunctionReturn(0);
844 }
845