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