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