xref: /petsc/src/vec/is/is/impls/block/block.c (revision 579e05a67b7d73bfff661e11b21e54918f27642d)
1 
2 /*
3      Provides the functions for index sets (IS) defined by a list of integers.
4    These are for blocks of data, each block is indicated with a single integer.
5 */
6 #include <petsc/private/isimpl.h>               /*I  "petscis.h"     I*/
7 #include <petscviewer.h>
8 
9 typedef struct {
10   PetscBool sorted;      /* are the blocks sorted? */
11   PetscBool allocated;   /* did we allocate the index array ourselves? */
12   PetscInt  *idx;
13 } IS_Block;
14 
15 static PetscErrorCode ISDestroy_Block(IS is)
16 {
17   IS_Block       *sub = (IS_Block*)is->data;
18   PetscErrorCode ierr;
19 
20   PetscFunctionBegin;
21   if (sub->allocated) {ierr = PetscFree(sub->idx);CHKERRQ(ierr);}
22   ierr = PetscObjectComposeFunction((PetscObject)is,"ISBlockSetIndices_C",NULL);CHKERRQ(ierr);
23   ierr = PetscObjectComposeFunction((PetscObject)is,"ISBlockGetIndices_C",NULL);CHKERRQ(ierr);
24   ierr = PetscObjectComposeFunction((PetscObject)is,"ISBlockRestoreIndices_C",NULL);CHKERRQ(ierr);
25   ierr = PetscObjectComposeFunction((PetscObject)is,"ISBlockGetSize_C",NULL);CHKERRQ(ierr);
26   ierr = PetscObjectComposeFunction((PetscObject)is,"ISBlockGetLocalSize_C",NULL);CHKERRQ(ierr);
27   ierr = PetscFree(is->data);CHKERRQ(ierr);
28   PetscFunctionReturn(0);
29 }
30 
31 static PetscErrorCode ISLocate_Block(IS is,PetscInt key,PetscInt *location)
32 {
33   IS_Block       *sub = (IS_Block*)is->data;
34   PetscInt       numIdx, i, bs, bkey, mkey;
35   PetscBool      sorted;
36   PetscErrorCode ierr;
37 
38   PetscFunctionBegin;
39   ierr = PetscLayoutGetBlockSize(is->map,&bs);CHKERRQ(ierr);
40   ierr = PetscLayoutGetSize(is->map,&numIdx);CHKERRQ(ierr);
41   numIdx /= bs;
42   bkey    = key / bs;
43   mkey    = key % bs;
44   if (mkey < 0) {
45     bkey--;
46     mkey += bs;
47   }
48   ierr = ISGetInfo(is,IS_SORTED,IS_LOCAL,PETSC_TRUE,&sorted);CHKERRQ(ierr);
49   if (sorted) {
50     ierr = PetscFindInt(bkey,numIdx,sub->idx,location);CHKERRQ(ierr);
51   } else {
52     const PetscInt *idx = sub->idx;
53 
54     *location = -1;
55     for (i = 0; i < numIdx; i++) {
56       if (idx[i] == bkey) {
57         *location = i;
58         break;
59       }
60     }
61   }
62   if (*location >= 0) {
63     *location = *location * bs + mkey;
64   }
65   PetscFunctionReturn(0);
66 }
67 
68 static PetscErrorCode ISGetIndices_Block(IS in,const PetscInt *idx[])
69 {
70   IS_Block       *sub = (IS_Block*)in->data;
71   PetscErrorCode ierr;
72   PetscInt       i,j,k,bs,n,*ii,*jj;
73 
74   PetscFunctionBegin;
75   ierr = PetscLayoutGetBlockSize(in->map, &bs);CHKERRQ(ierr);
76   ierr = PetscLayoutGetLocalSize(in->map, &n);CHKERRQ(ierr);
77   n   /= bs;
78   if (bs == 1) *idx = sub->idx;
79   else {
80     ierr = PetscMalloc1(bs*n,&jj);CHKERRQ(ierr);
81     *idx = jj;
82     k    = 0;
83     ii   = sub->idx;
84     for (i=0; i<n; i++)
85       for (j=0; j<bs; j++)
86         jj[k++] = bs*ii[i] + j;
87   }
88   PetscFunctionReturn(0);
89 }
90 
91 static PetscErrorCode ISRestoreIndices_Block(IS is,const PetscInt *idx[])
92 {
93   IS_Block       *sub = (IS_Block*)is->data;
94   PetscInt       bs;
95   PetscErrorCode ierr;
96 
97   PetscFunctionBegin;
98   ierr = PetscLayoutGetBlockSize(is->map, &bs);CHKERRQ(ierr);
99   if (bs != 1) {
100     ierr = PetscFree(*(void**)idx);CHKERRQ(ierr);
101   } else {
102     if (*idx != sub->idx) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Must restore with value from ISGetIndices()");
103   }
104   PetscFunctionReturn(0);
105 }
106 
107 static PetscErrorCode ISInvertPermutation_Block(IS is,PetscInt nlocal,IS *isout)
108 {
109   IS_Block       *sub = (IS_Block*)is->data;
110   PetscInt       i,*ii,bs,n,*idx = sub->idx;
111   PetscMPIInt    size;
112   PetscErrorCode ierr;
113 
114   PetscFunctionBegin;
115   ierr = MPI_Comm_size(PetscObjectComm((PetscObject)is),&size);CHKERRQ(ierr);
116   ierr = PetscLayoutGetBlockSize(is->map, &bs);CHKERRQ(ierr);
117   ierr = PetscLayoutGetLocalSize(is->map, &n);CHKERRQ(ierr);
118   n   /= bs;
119   if (size == 1) {
120     ierr = PetscMalloc1(n,&ii);CHKERRQ(ierr);
121     for (i=0; i<n; i++) ii[idx[i]] = i;
122     ierr = ISCreateBlock(PETSC_COMM_SELF,bs,n,ii,PETSC_OWN_POINTER,isout);CHKERRQ(ierr);
123     ierr = ISSetPermutation(*isout);CHKERRQ(ierr);
124   } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"No inversion written yet for block IS");
125   PetscFunctionReturn(0);
126 }
127 
128 static PetscErrorCode ISView_Block(IS is, PetscViewer viewer)
129 {
130   IS_Block       *sub = (IS_Block*)is->data;
131   PetscErrorCode ierr;
132   PetscInt       i,bs,n,*idx = sub->idx;
133   PetscBool      iascii;
134 
135   PetscFunctionBegin;
136   ierr = PetscLayoutGetBlockSize(is->map, &bs);CHKERRQ(ierr);
137   ierr = PetscLayoutGetLocalSize(is->map, &n);CHKERRQ(ierr);
138   n   /= bs;
139   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
140   if (iascii) {
141     PetscViewerFormat fmt;
142 
143     ierr = PetscViewerGetFormat(viewer,&fmt);CHKERRQ(ierr);
144     if (fmt == PETSC_VIEWER_ASCII_MATLAB) {
145       IS             ist;
146       const char     *name;
147       const PetscInt *idx;
148       PetscInt       n;
149 
150       ierr = PetscObjectGetName((PetscObject)is,&name);CHKERRQ(ierr);
151       ierr = ISGetLocalSize(is,&n);CHKERRQ(ierr);
152       ierr = ISGetIndices(is,&idx);CHKERRQ(ierr);
153       ierr = ISCreateGeneral(PetscObjectComm((PetscObject)is),n,idx,PETSC_USE_POINTER,&ist);CHKERRQ(ierr);
154       ierr = PetscObjectSetName((PetscObject)ist,name);CHKERRQ(ierr);
155       ierr = ISView(ist,viewer);CHKERRQ(ierr);
156       ierr = ISDestroy(&ist);CHKERRQ(ierr);
157       ierr = ISRestoreIndices(is,&idx);CHKERRQ(ierr);
158     } else {
159       PetscBool isperm;
160 
161       ierr = ISGetInfo(is,IS_PERMUTATION,IS_GLOBAL,PETSC_FALSE,&isperm);CHKERRQ(ierr);
162       if (isperm) {ierr = PetscViewerASCIIPrintf(viewer,"Block Index set is permutation\n");CHKERRQ(ierr);}
163       ierr = PetscViewerASCIIPushSynchronized(viewer);CHKERRQ(ierr);
164       ierr = PetscViewerASCIISynchronizedPrintf(viewer,"Block size %D\n",bs);CHKERRQ(ierr);
165       ierr = PetscViewerASCIISynchronizedPrintf(viewer,"Number of block indices in set %D\n",n);CHKERRQ(ierr);
166       ierr = PetscViewerASCIISynchronizedPrintf(viewer,"The first indices of each block are\n");CHKERRQ(ierr);
167       for (i=0; i<n; i++) {
168         ierr = PetscViewerASCIISynchronizedPrintf(viewer,"Block %D Index %D\n",i,idx[i]);CHKERRQ(ierr);
169       }
170       ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
171       ierr = PetscViewerASCIIPopSynchronized(viewer);CHKERRQ(ierr);
172     }
173   }
174   PetscFunctionReturn(0);
175 }
176 
177 static PetscErrorCode ISSort_Block(IS is)
178 {
179   IS_Block       *sub = (IS_Block*)is->data;
180   PetscInt       bs, n;
181   PetscErrorCode ierr;
182 
183   PetscFunctionBegin;
184   ierr = PetscLayoutGetBlockSize(is->map, &bs);CHKERRQ(ierr);
185   ierr = PetscLayoutGetLocalSize(is->map, &n);CHKERRQ(ierr);
186   ierr = PetscSortInt(n/bs,sub->idx);CHKERRQ(ierr);
187   PetscFunctionReturn(0);
188 }
189 
190 static PetscErrorCode ISSortRemoveDups_Block(IS is)
191 {
192   IS_Block       *sub = (IS_Block*)is->data;
193   PetscInt       bs, n, nb;
194   PetscBool      sorted;
195   PetscErrorCode ierr;
196 
197   PetscFunctionBegin;
198   ierr = PetscLayoutGetBlockSize(is->map, &bs);CHKERRQ(ierr);
199   ierr = PetscLayoutGetLocalSize(is->map, &n);CHKERRQ(ierr);
200   nb   = n/bs;
201   ierr = ISGetInfo(is,IS_SORTED,IS_LOCAL,PETSC_TRUE,&sorted);CHKERRQ(ierr);
202   if (sorted) {
203     ierr = PetscSortedRemoveDupsInt(&nb,sub->idx);CHKERRQ(ierr);
204   } else {
205     ierr = PetscSortRemoveDupsInt(&nb,sub->idx);CHKERRQ(ierr);
206   }
207   ierr = PetscLayoutDestroy(&is->map);CHKERRQ(ierr);
208   ierr = PetscLayoutCreateFromSizes(PetscObjectComm((PetscObject)is), nb*bs, PETSC_DECIDE, bs, &is->map);CHKERRQ(ierr);
209   PetscFunctionReturn(0);
210 }
211 
212 static PetscErrorCode ISSorted_Block(IS is,PetscBool  *flg)
213 {
214   PetscErrorCode ierr;
215 
216   PetscFunctionBegin;
217   ierr = ISGetInfo(is,IS_SORTED,IS_LOCAL,PETSC_TRUE,flg);CHKERRQ(ierr);
218   PetscFunctionReturn(0);
219 }
220 
221 static PetscErrorCode ISSortedLocal_Block(IS is,PetscBool *flg)
222 {
223   IS_Block       *sub = (IS_Block*)is->data;
224   PetscInt       n, bs, i, *idx;
225   PetscErrorCode ierr;
226 
227   PetscFunctionBegin;
228   ierr = PetscLayoutGetLocalSize(is->map, &n);CHKERRQ(ierr);
229   ierr = PetscLayoutGetBlockSize(is->map, &bs);CHKERRQ(ierr);
230   n   /= bs;
231   idx  = sub->idx;
232   for (i = 1; i < n; i++) if (idx[i] < idx[i - 1]) break;
233   if (i < n) *flg = PETSC_FALSE;
234   else       *flg = PETSC_TRUE;
235   PetscFunctionReturn(0);
236 }
237 
238 static PetscErrorCode ISUniqueLocal_Block(IS is,PetscBool *flg)
239 {
240   IS_Block       *sub = (IS_Block*)is->data;
241   PetscInt       n, bs, i, *idx, *idxcopy = NULL;
242   PetscBool      sortedLocal;
243   PetscErrorCode ierr;
244 
245   PetscFunctionBegin;
246   ierr = PetscLayoutGetLocalSize(is->map, &n);CHKERRQ(ierr);
247   ierr = PetscLayoutGetBlockSize(is->map, &bs);CHKERRQ(ierr);
248   n   /= bs;
249   idx  = sub->idx;
250   ierr = ISGetInfo(is,IS_SORTED,IS_LOCAL,PETSC_TRUE,&sortedLocal);CHKERRQ(ierr);
251   if (!sortedLocal) {
252     ierr = PetscMalloc1(n, &idxcopy);CHKERRQ(ierr);
253     ierr = PetscArraycpy(idxcopy, idx, n);CHKERRQ(ierr);
254     ierr = PetscSortInt(n, idxcopy);CHKERRQ(ierr);
255     idx = idxcopy;
256   }
257   for (i = 1; i < n; i++) if (idx[i] == idx[i - 1]) break;
258   if (i < n) *flg = PETSC_FALSE;
259   else       *flg = PETSC_TRUE;
260   ierr = PetscFree(idxcopy);CHKERRQ(ierr);
261   PetscFunctionReturn(0);
262 }
263 
264 static PetscErrorCode ISPermutationLocal_Block(IS is,PetscBool *flg)
265 {
266   IS_Block       *sub = (IS_Block*)is->data;
267   PetscInt       n, bs, i, *idx, *idxcopy = NULL;
268   PetscBool      sortedLocal;
269   PetscErrorCode ierr;
270 
271   PetscFunctionBegin;
272   ierr = PetscLayoutGetLocalSize(is->map, &n);CHKERRQ(ierr);
273   ierr = PetscLayoutGetBlockSize(is->map, &bs);CHKERRQ(ierr);
274   n   /= bs;
275   idx  = sub->idx;
276   ierr = ISGetInfo(is,IS_SORTED,IS_LOCAL,PETSC_TRUE,&sortedLocal);CHKERRQ(ierr);
277   if (!sortedLocal) {
278     ierr = PetscMalloc1(n, &idxcopy);CHKERRQ(ierr);
279     ierr = PetscArraycpy(idxcopy, idx, n);CHKERRQ(ierr);
280     ierr = PetscSortInt(n, idxcopy);CHKERRQ(ierr);
281     idx = idxcopy;
282   }
283   for (i = 0; i < n; i++) if (idx[i] != i) break;
284   if (i < n) *flg = PETSC_FALSE;
285   else       *flg = PETSC_TRUE;
286   ierr = PetscFree(idxcopy);CHKERRQ(ierr);
287   PetscFunctionReturn(0);
288 }
289 
290 static PetscErrorCode ISIntervalLocal_Block(IS is,PetscBool *flg)
291 {
292   IS_Block       *sub = (IS_Block*)is->data;
293   PetscInt       n, bs, i, *idx;
294   PetscErrorCode ierr;
295 
296   PetscFunctionBegin;
297   ierr = PetscLayoutGetLocalSize(is->map, &n);CHKERRQ(ierr);
298   ierr = PetscLayoutGetBlockSize(is->map, &bs);CHKERRQ(ierr);
299   n   /= bs;
300   idx  = sub->idx;
301   for (i = 1; i < n; i++) if (idx[i] != idx[i - 1] + 1) break;
302   if (i < n) *flg = PETSC_FALSE;
303   else       *flg = PETSC_TRUE;
304   PetscFunctionReturn(0);
305 }
306 
307 static PetscErrorCode ISDuplicate_Block(IS is,IS *newIS)
308 {
309   PetscErrorCode ierr;
310   IS_Block       *sub = (IS_Block*)is->data;
311   PetscInt        bs, n;
312 
313   PetscFunctionBegin;
314   ierr = PetscLayoutGetBlockSize(is->map, &bs);CHKERRQ(ierr);
315   ierr = PetscLayoutGetLocalSize(is->map, &n);CHKERRQ(ierr);
316   n   /= bs;
317   ierr = ISCreateBlock(PetscObjectComm((PetscObject)is),bs,n,sub->idx,PETSC_COPY_VALUES,newIS);CHKERRQ(ierr);
318   PetscFunctionReturn(0);
319 }
320 
321 static PetscErrorCode ISIdentity_Block(IS is,PetscBool  *ident)
322 {
323   PetscErrorCode ierr;
324 
325   PetscFunctionBegin;
326   ierr = ISGetInfo(is,IS_IDENTITY,IS_GLOBAL,PETSC_TRUE,ident);CHKERRQ(ierr);
327   PetscFunctionReturn(0);
328 }
329 
330 static PetscErrorCode ISCopy_Block(IS is,IS isy)
331 {
332   IS_Block       *is_block = (IS_Block*)is->data,*isy_block = (IS_Block*)isy->data;
333   PetscInt       bs, n, N, bsy, ny, Ny;
334   PetscErrorCode ierr;
335 
336   PetscFunctionBegin;
337   ierr = PetscLayoutGetBlockSize(is->map, &bs);CHKERRQ(ierr);
338   ierr = PetscLayoutGetLocalSize(is->map, &n);CHKERRQ(ierr);
339   ierr = PetscLayoutGetSize(is->map, &N);CHKERRQ(ierr);
340   ierr = PetscLayoutGetBlockSize(isy->map, &bsy);CHKERRQ(ierr);
341   ierr = PetscLayoutGetLocalSize(isy->map, &ny);CHKERRQ(ierr);
342   ierr = PetscLayoutGetSize(isy->map, &Ny);CHKERRQ(ierr);
343   if (n != ny || N != Ny || bs != bsy) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Index sets incompatible");
344   ierr = PetscArraycpy(isy_block->idx,is_block->idx,(n/bs));CHKERRQ(ierr);
345   PetscFunctionReturn(0);
346 }
347 
348 static PetscErrorCode ISOnComm_Block(IS is,MPI_Comm comm,PetscCopyMode mode,IS *newis)
349 {
350   PetscErrorCode ierr;
351   IS_Block       *sub = (IS_Block*)is->data;
352   PetscInt       bs, n;
353 
354   PetscFunctionBegin;
355   if (mode == PETSC_OWN_POINTER) SETERRQ(comm,PETSC_ERR_ARG_WRONG,"Cannot use PETSC_OWN_POINTER");
356   ierr = PetscLayoutGetBlockSize(is->map, &bs);CHKERRQ(ierr);
357   ierr = PetscLayoutGetLocalSize(is->map, &n);CHKERRQ(ierr);
358   ierr = ISCreateBlock(comm,bs,n/bs,sub->idx,mode,newis);CHKERRQ(ierr);
359   PetscFunctionReturn(0);
360 }
361 
362 static PetscErrorCode ISSetBlockSize_Block(IS is,PetscInt bs)
363 {
364   PetscErrorCode ierr;
365 
366   PetscFunctionBegin;
367   ierr = PetscLayoutSetBlockSize(is->map, bs);CHKERRQ(ierr);
368   PetscFunctionReturn(0);
369 }
370 
371 static PetscErrorCode ISToGeneral_Block(IS inis)
372 {
373   IS_Block       *sub   = (IS_Block*)inis->data;
374   PetscInt       bs,n;
375   const PetscInt *idx;
376   PetscErrorCode ierr;
377 
378   PetscFunctionBegin;
379   ierr = ISGetBlockSize(inis,&bs);CHKERRQ(ierr);
380   ierr = ISGetLocalSize(inis,&n);CHKERRQ(ierr);
381   ierr = ISGetIndices(inis,&idx);CHKERRQ(ierr);
382   if (bs == 1) {
383     PetscCopyMode mode = sub->allocated ? PETSC_OWN_POINTER : PETSC_USE_POINTER;
384     sub->allocated = PETSC_FALSE; /* prevent deallocation when changing the subtype*/
385     ierr = ISSetType(inis,ISGENERAL);CHKERRQ(ierr);
386     ierr = ISGeneralSetIndices(inis,n,idx,mode);CHKERRQ(ierr);
387   } else {
388     ierr = ISSetType(inis,ISGENERAL);CHKERRQ(ierr);
389     ierr = ISGeneralSetIndices(inis,n,idx,PETSC_OWN_POINTER);CHKERRQ(ierr);
390   }
391   PetscFunctionReturn(0);
392 }
393 
394 
395 static struct _ISOps myops = { ISGetIndices_Block,
396                                ISRestoreIndices_Block,
397                                ISInvertPermutation_Block,
398                                ISSort_Block,
399                                ISSortRemoveDups_Block,
400                                ISSorted_Block,
401                                ISDuplicate_Block,
402                                ISDestroy_Block,
403                                ISView_Block,
404                                ISLoad_Default,
405                                ISIdentity_Block,
406                                ISCopy_Block,
407                                ISToGeneral_Block,
408                                ISOnComm_Block,
409                                ISSetBlockSize_Block,
410                                0,
411                                ISLocate_Block,
412                                /* we can have specialized local routines for determining properties,
413                                 * but unless the block size is the same on each process (which is not guaranteed at
414                                 * the moment), then trying to do something specialized for global properties is too
415                                 * complicated */
416                                ISSortedLocal_Block,
417                                NULL,
418                                ISUniqueLocal_Block,
419                                NULL,
420                                ISPermutationLocal_Block,
421                                NULL,
422                                ISIntervalLocal_Block,
423                                NULL};
424 
425 /*@
426    ISBlockSetIndices - The indices are relative to entries, not blocks.
427 
428    Collective on IS
429 
430    Input Parameters:
431 +  is - the index set
432 .  bs - number of elements in each block, one for each block and count of block not indices
433 .   n - the length of the index set (the number of blocks)
434 .  idx - the list of integers, these are by block, not by location
435 -  mode - see PetscCopyMode, only PETSC_COPY_VALUES and PETSC_OWN_POINTER are supported
436 
437 
438    Notes:
439    When the communicator is not MPI_COMM_SELF, the operations on the
440    index sets, IS, are NOT conceptually the same as MPI_Group operations.
441    The index sets are then distributed sets of indices and thus certain operations
442    on them are collective.
443 
444    Example:
445    If you wish to index the values {0,1,4,5}, then use
446    a block size of 2 and idx of {0,2}.
447 
448    Level: beginner
449 
450 .seealso: ISCreateStride(), ISCreateGeneral(), ISAllGather()
451 @*/
452 PetscErrorCode  ISBlockSetIndices(IS is,PetscInt bs,PetscInt n,const PetscInt idx[],PetscCopyMode mode)
453 {
454   PetscErrorCode ierr;
455 
456   PetscFunctionBegin;
457   ierr = ISClearInfoCache(is,PETSC_FALSE);CHKERRQ(ierr);
458   ierr = PetscUseMethod(is,"ISBlockSetIndices_C",(IS,PetscInt,PetscInt,const PetscInt[],PetscCopyMode),(is,bs,n,idx,mode));CHKERRQ(ierr);
459   PetscFunctionReturn(0);
460 }
461 
462 static PetscErrorCode  ISBlockSetIndices_Block(IS is,PetscInt bs,PetscInt n,const PetscInt idx[],PetscCopyMode mode)
463 {
464   PetscErrorCode ierr;
465   PetscInt       i,min,max;
466   IS_Block       *sub = (IS_Block*)is->data;
467   PetscLayout    map;
468 
469   PetscFunctionBegin;
470   if (bs < 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"block size < 1");
471   if (n < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"length < 0");
472   if (n) PetscValidIntPointer(idx,3);
473 
474   ierr = PetscLayoutCreateFromSizes(PetscObjectComm((PetscObject)is),n*bs,is->map->N,bs,&map);CHKERRQ(ierr);
475   ierr = PetscLayoutDestroy(&is->map);CHKERRQ(ierr);
476   is->map = map;
477 
478   if (sub->allocated) {ierr = PetscFree(sub->idx);CHKERRQ(ierr);}
479   if (mode == PETSC_COPY_VALUES) {
480     ierr = PetscMalloc1(n,&sub->idx);CHKERRQ(ierr);
481     ierr = PetscLogObjectMemory((PetscObject)is,n*sizeof(PetscInt));CHKERRQ(ierr);
482     ierr = PetscArraycpy(sub->idx,idx,n);CHKERRQ(ierr);
483     sub->allocated = PETSC_TRUE;
484   } else if (mode == PETSC_OWN_POINTER) {
485     sub->idx = (PetscInt*) idx;
486     ierr = PetscLogObjectMemory((PetscObject)is,n*sizeof(PetscInt));CHKERRQ(ierr);
487     sub->allocated = PETSC_TRUE;
488   } else if (mode == PETSC_USE_POINTER) {
489     sub->idx = (PetscInt*) idx;
490     sub->allocated = PETSC_FALSE;
491   }
492 
493   if (n) {
494     min = max = idx[0];
495     for (i=1; i<n; i++) {
496       if (idx[i] < min) min = idx[i];
497       if (idx[i] > max) max = idx[i];
498     }
499     is->min = bs*min;
500     is->max = bs*max+bs-1;
501   } else {
502     is->min = PETSC_MAX_INT;
503     is->max = PETSC_MIN_INT;
504   }
505   PetscFunctionReturn(0);
506 }
507 
508 /*@
509    ISCreateBlock - Creates a data structure for an index set containing
510    a list of integers. The indices are relative to entries, not blocks.
511 
512    Collective
513 
514    Input Parameters:
515 +  comm - the MPI communicator
516 .  bs - number of elements in each block
517 .  n - the length of the index set (the number of blocks)
518 .  idx - the list of integers, one for each block and count of block not indices
519 -  mode - see PetscCopyMode, only PETSC_COPY_VALUES and PETSC_OWN_POINTER are supported in this routine
520 
521    Output Parameter:
522 .  is - the new index set
523 
524    Notes:
525    When the communicator is not MPI_COMM_SELF, the operations on the
526    index sets, IS, are NOT conceptually the same as MPI_Group operations.
527    The index sets are then distributed sets of indices and thus certain operations
528    on them are collective.
529 
530    Example:
531    If you wish to index the values {0,1,6,7}, then use
532    a block size of 2 and idx of {0,3}.
533 
534    Level: beginner
535 
536 .seealso: ISCreateStride(), ISCreateGeneral(), ISAllGather()
537 @*/
538 PetscErrorCode  ISCreateBlock(MPI_Comm comm,PetscInt bs,PetscInt n,const PetscInt idx[],PetscCopyMode mode,IS *is)
539 {
540   PetscErrorCode ierr;
541 
542   PetscFunctionBegin;
543   PetscValidPointer(is,5);
544   if (bs < 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"block size < 1");
545   if (n < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"length < 0");
546   if (n) PetscValidIntPointer(idx,4);
547 
548   ierr = ISCreate(comm,is);CHKERRQ(ierr);
549   ierr = ISSetType(*is,ISBLOCK);CHKERRQ(ierr);
550   ierr = ISBlockSetIndices(*is,bs,n,idx,mode);CHKERRQ(ierr);
551   PetscFunctionReturn(0);
552 }
553 
554 static PetscErrorCode  ISBlockGetIndices_Block(IS is,const PetscInt *idx[])
555 {
556   IS_Block *sub = (IS_Block*)is->data;
557 
558   PetscFunctionBegin;
559   *idx = sub->idx;
560   PetscFunctionReturn(0);
561 }
562 
563 static PetscErrorCode  ISBlockRestoreIndices_Block(IS is,const PetscInt *idx[])
564 {
565   PetscFunctionBegin;
566   PetscFunctionReturn(0);
567 }
568 
569 /*@C
570    ISBlockGetIndices - Gets the indices associated with each block.
571 
572    Not Collective
573 
574    Input Parameter:
575 .  is - the index set
576 
577    Output Parameter:
578 .  idx - the integer indices, one for each block and count of block not indices
579 
580    Level: intermediate
581 
582 .seealso: ISGetIndices(), ISBlockRestoreIndices()
583 @*/
584 PetscErrorCode  ISBlockGetIndices(IS is,const PetscInt *idx[])
585 {
586   PetscErrorCode ierr;
587 
588   PetscFunctionBegin;
589   ierr = PetscUseMethod(is,"ISBlockGetIndices_C",(IS,const PetscInt*[]),(is,idx));CHKERRQ(ierr);
590   PetscFunctionReturn(0);
591 }
592 
593 /*@C
594    ISBlockRestoreIndices - Restores the indices associated with each block.
595 
596    Not Collective
597 
598    Input Parameter:
599 .  is - the index set
600 
601    Output Parameter:
602 .  idx - the integer indices
603 
604    Level: intermediate
605 
606 .seealso: ISRestoreIndices(), ISBlockGetIndices()
607 @*/
608 PetscErrorCode  ISBlockRestoreIndices(IS is,const PetscInt *idx[])
609 {
610   PetscErrorCode ierr;
611 
612   PetscFunctionBegin;
613   ierr = PetscUseMethod(is,"ISBlockRestoreIndices_C",(IS,const PetscInt*[]),(is,idx));CHKERRQ(ierr);
614   PetscFunctionReturn(0);
615 }
616 
617 /*@
618    ISBlockGetLocalSize - Returns the local number of blocks in the index set.
619 
620    Not Collective
621 
622    Input Parameter:
623 .  is - the index set
624 
625    Output Parameter:
626 .  size - the local number of blocks
627 
628    Level: intermediate
629 
630 
631 .seealso: ISGetBlockSize(), ISBlockGetSize(), ISGetSize(), ISCreateBlock()
632 @*/
633 PetscErrorCode  ISBlockGetLocalSize(IS is,PetscInt *size)
634 {
635   PetscErrorCode ierr;
636 
637   PetscFunctionBegin;
638   ierr = PetscUseMethod(is,"ISBlockGetLocalSize_C",(IS,PetscInt*),(is,size));CHKERRQ(ierr);
639   PetscFunctionReturn(0);
640 }
641 
642 static PetscErrorCode  ISBlockGetLocalSize_Block(IS is,PetscInt *size)
643 {
644   PetscInt       bs, n;
645   PetscErrorCode ierr;
646 
647   PetscFunctionBegin;
648   ierr = PetscLayoutGetBlockSize(is->map, &bs);CHKERRQ(ierr);
649   ierr = PetscLayoutGetLocalSize(is->map, &n);CHKERRQ(ierr);
650   *size = n/bs;
651   PetscFunctionReturn(0);
652 }
653 
654 /*@
655    ISBlockGetSize - Returns the global number of blocks in the index set.
656 
657    Not Collective
658 
659    Input Parameter:
660 .  is - the index set
661 
662    Output Parameter:
663 .  size - the global number of blocks
664 
665    Level: intermediate
666 
667 
668 .seealso: ISGetBlockSize(), ISBlockGetLocalSize(), ISGetSize(), ISCreateBlock()
669 @*/
670 PetscErrorCode  ISBlockGetSize(IS is,PetscInt *size)
671 {
672   PetscErrorCode ierr;
673 
674   PetscFunctionBegin;
675   ierr = PetscUseMethod(is,"ISBlockGetSize_C",(IS,PetscInt*),(is,size));CHKERRQ(ierr);
676   PetscFunctionReturn(0);
677 }
678 
679 static PetscErrorCode  ISBlockGetSize_Block(IS is,PetscInt *size)
680 {
681   PetscInt       bs, N;
682   PetscErrorCode ierr;
683 
684   PetscFunctionBegin;
685   ierr = PetscLayoutGetBlockSize(is->map, &bs);CHKERRQ(ierr);
686   ierr = PetscLayoutGetSize(is->map, &N);CHKERRQ(ierr);
687   *size = N/bs;
688   PetscFunctionReturn(0);
689 }
690 
691 PETSC_EXTERN PetscErrorCode ISCreate_Block(IS is)
692 {
693   PetscErrorCode ierr;
694   IS_Block       *sub;
695 
696   PetscFunctionBegin;
697   ierr = PetscNewLog(is,&sub);CHKERRQ(ierr);
698   is->data = (void *) sub;
699   ierr = PetscMemcpy(is->ops,&myops,sizeof(myops));CHKERRQ(ierr);
700   ierr = PetscObjectComposeFunction((PetscObject)is,"ISBlockSetIndices_C",ISBlockSetIndices_Block);CHKERRQ(ierr);
701   ierr = PetscObjectComposeFunction((PetscObject)is,"ISBlockGetIndices_C",ISBlockGetIndices_Block);CHKERRQ(ierr);
702   ierr = PetscObjectComposeFunction((PetscObject)is,"ISBlockRestoreIndices_C",ISBlockRestoreIndices_Block);CHKERRQ(ierr);
703   ierr = PetscObjectComposeFunction((PetscObject)is,"ISBlockGetSize_C",ISBlockGetSize_Block);CHKERRQ(ierr);
704   ierr = PetscObjectComposeFunction((PetscObject)is,"ISBlockGetLocalSize_C",ISBlockGetLocalSize_Block);CHKERRQ(ierr);
705   PetscFunctionReturn(0);
706 }
707