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