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