Actual source code: block.c


  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>
  7: #include <petscviewer.h>

  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;

 15: static PetscErrorCode ISDestroy_Block(IS is)
 16: {
 17:   IS_Block *sub = (IS_Block *)is->data;

 19:   if (sub->allocated) PetscFree(sub->idx);
 20:   PetscObjectComposeFunction((PetscObject)is, "ISBlockSetIndices_C", NULL);
 21:   PetscObjectComposeFunction((PetscObject)is, "ISBlockGetIndices_C", NULL);
 22:   PetscObjectComposeFunction((PetscObject)is, "ISBlockRestoreIndices_C", NULL);
 23:   PetscObjectComposeFunction((PetscObject)is, "ISBlockGetSize_C", NULL);
 24:   PetscObjectComposeFunction((PetscObject)is, "ISBlockGetLocalSize_C", NULL);
 25:   PetscObjectComposeFunction((PetscObject)is, "ISShift_C", NULL);
 26:   PetscFree(is->data);
 27:   return 0;
 28: }

 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;

 36:   PetscLayoutGetBlockSize(is->map, &bs);
 37:   PetscLayoutGetSize(is->map, &numIdx);
 38:   numIdx /= bs;
 39:   bkey = key / bs;
 40:   mkey = key % bs;
 41:   if (mkey < 0) {
 42:     bkey--;
 43:     mkey += bs;
 44:   }
 45:   ISGetInfo(is, IS_SORTED, IS_LOCAL, PETSC_TRUE, &sorted);
 46:   if (sorted) {
 47:     PetscFindInt(bkey, numIdx, sub->idx, location);
 48:   } else {
 49:     const PetscInt *idx = sub->idx;

 51:     *location = -1;
 52:     for (i = 0; i < numIdx; i++) {
 53:       if (idx[i] == bkey) {
 54:         *location = i;
 55:         break;
 56:       }
 57:     }
 58:   }
 59:   if (*location >= 0) *location = *location * bs + mkey;
 60:   return 0;
 61: }

 63: static PetscErrorCode ISGetIndices_Block(IS in, const PetscInt *idx[])
 64: {
 65:   IS_Block *sub = (IS_Block *)in->data;
 66:   PetscInt  i, j, k, bs, n, *ii, *jj;

 68:   PetscLayoutGetBlockSize(in->map, &bs);
 69:   PetscLayoutGetLocalSize(in->map, &n);
 70:   n /= bs;
 71:   if (bs == 1) *idx = sub->idx;
 72:   else {
 73:     if (n) {
 74:       PetscMalloc1(bs * n, &jj);
 75:       *idx = jj;
 76:       k    = 0;
 77:       ii   = sub->idx;
 78:       for (i = 0; i < n; i++)
 79:         for (j = 0; j < bs; j++) jj[k++] = bs * ii[i] + j;
 80:     } else {
 81:       /* do not malloc for zero size because F90Array1dCreate() inside ISRestoreArrayF90() does not keep array when zero length array */
 82:       *idx = NULL;
 83:     }
 84:   }
 85:   return 0;
 86: }

 88: static PetscErrorCode ISRestoreIndices_Block(IS is, const PetscInt *idx[])
 89: {
 90:   IS_Block *sub = (IS_Block *)is->data;
 91:   PetscInt  bs;

 93:   PetscLayoutGetBlockSize(is->map, &bs);
 94:   if (bs != 1) {
 95:     PetscFree(*(void **)idx);
 96:   } else {
 97:     /* F90Array1dCreate() inside ISRestoreArrayF90() does not keep array when zero length array */
 99:   }
100:   return 0;
101: }

103: static PetscErrorCode ISInvertPermutation_Block(IS is, PetscInt nlocal, IS *isout)
104: {
105:   IS_Block   *sub = (IS_Block *)is->data;
106:   PetscInt    i, *ii, bs, n, *idx = sub->idx;
107:   PetscMPIInt size;

109:   MPI_Comm_size(PetscObjectComm((PetscObject)is), &size);
110:   PetscLayoutGetBlockSize(is->map, &bs);
111:   PetscLayoutGetLocalSize(is->map, &n);
112:   n /= bs;
113:   if (size == 1) {
114:     PetscMalloc1(n, &ii);
115:     for (i = 0; i < n; i++) ii[idx[i]] = i;
116:     ISCreateBlock(PETSC_COMM_SELF, bs, n, ii, PETSC_OWN_POINTER, isout);
117:     ISSetPermutation(*isout);
118:   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "No inversion written yet for block IS");
119:   return 0;
120: }

122: static PetscErrorCode ISView_Block(IS is, PetscViewer viewer)
123: {
124:   IS_Block *sub = (IS_Block *)is->data;
125:   PetscInt  i, bs, n, *idx = sub->idx;
126:   PetscBool iascii, ibinary;

128:   PetscLayoutGetBlockSize(is->map, &bs);
129:   PetscLayoutGetLocalSize(is->map, &n);
130:   n /= bs;
131:   PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii);
132:   PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &ibinary);
133:   if (iascii) {
134:     PetscViewerFormat fmt;

136:     PetscViewerGetFormat(viewer, &fmt);
137:     if (fmt == PETSC_VIEWER_ASCII_MATLAB) {
138:       IS              ist;
139:       const char     *name;
140:       const PetscInt *idx;
141:       PetscInt        n;

143:       PetscObjectGetName((PetscObject)is, &name);
144:       ISGetLocalSize(is, &n);
145:       ISGetIndices(is, &idx);
146:       ISCreateGeneral(PetscObjectComm((PetscObject)is), n, idx, PETSC_USE_POINTER, &ist);
147:       PetscObjectSetName((PetscObject)ist, name);
148:       ISView(ist, viewer);
149:       ISDestroy(&ist);
150:       ISRestoreIndices(is, &idx);
151:     } else {
152:       PetscBool isperm;

154:       ISGetInfo(is, IS_PERMUTATION, IS_GLOBAL, PETSC_FALSE, &isperm);
155:       if (isperm) PetscViewerASCIIPrintf(viewer, "Block Index set is permutation\n");
156:       PetscViewerASCIIPushSynchronized(viewer);
157:       PetscViewerASCIISynchronizedPrintf(viewer, "Block size %" PetscInt_FMT "\n", bs);
158:       PetscViewerASCIISynchronizedPrintf(viewer, "Number of block indices in set %" PetscInt_FMT "\n", n);
159:       PetscViewerASCIISynchronizedPrintf(viewer, "The first indices of each block are\n");
160:       for (i = 0; i < n; i++) PetscViewerASCIISynchronizedPrintf(viewer, "Block %" PetscInt_FMT " Index %" PetscInt_FMT "\n", i, idx[i]);
161:       PetscViewerFlush(viewer);
162:       PetscViewerASCIIPopSynchronized(viewer);
163:     }
164:   } else if (ibinary) ISView_Binary(is, viewer);
165:   return 0;
166: }

168: static PetscErrorCode ISSort_Block(IS is)
169: {
170:   IS_Block *sub = (IS_Block *)is->data;
171:   PetscInt  bs, n;

173:   PetscLayoutGetBlockSize(is->map, &bs);
174:   PetscLayoutGetLocalSize(is->map, &n);
175:   PetscIntSortSemiOrdered(n / bs, sub->idx);
176:   return 0;
177: }

179: static PetscErrorCode ISSortRemoveDups_Block(IS is)
180: {
181:   IS_Block *sub = (IS_Block *)is->data;
182:   PetscInt  bs, n, nb;
183:   PetscBool sorted;

185:   PetscLayoutGetBlockSize(is->map, &bs);
186:   PetscLayoutGetLocalSize(is->map, &n);
187:   nb = n / bs;
188:   ISGetInfo(is, IS_SORTED, IS_LOCAL, PETSC_TRUE, &sorted);
189:   if (sorted) {
190:     PetscSortedRemoveDupsInt(&nb, sub->idx);
191:   } else {
192:     PetscSortRemoveDupsInt(&nb, sub->idx);
193:   }
194:   PetscLayoutDestroy(&is->map);
195:   PetscLayoutCreateFromSizes(PetscObjectComm((PetscObject)is), nb * bs, PETSC_DECIDE, bs, &is->map);
196:   return 0;
197: }

199: static PetscErrorCode ISSorted_Block(IS is, PetscBool *flg)
200: {
201:   ISGetInfo(is, IS_SORTED, IS_LOCAL, PETSC_TRUE, flg);
202:   return 0;
203: }

205: static PetscErrorCode ISSortedLocal_Block(IS is, PetscBool *flg)
206: {
207:   IS_Block *sub = (IS_Block *)is->data;
208:   PetscInt  n, bs, i, *idx;

210:   PetscLayoutGetLocalSize(is->map, &n);
211:   PetscLayoutGetBlockSize(is->map, &bs);
212:   n /= bs;
213:   idx = sub->idx;
214:   for (i = 1; i < n; i++)
215:     if (idx[i] < idx[i - 1]) break;
216:   if (i < n) *flg = PETSC_FALSE;
217:   else *flg = PETSC_TRUE;
218:   return 0;
219: }

221: static PetscErrorCode ISUniqueLocal_Block(IS is, PetscBool *flg)
222: {
223:   IS_Block *sub = (IS_Block *)is->data;
224:   PetscInt  n, bs, i, *idx, *idxcopy = NULL;
225:   PetscBool sortedLocal;

227:   PetscLayoutGetLocalSize(is->map, &n);
228:   PetscLayoutGetBlockSize(is->map, &bs);
229:   n /= bs;
230:   idx = sub->idx;
231:   ISGetInfo(is, IS_SORTED, IS_LOCAL, PETSC_TRUE, &sortedLocal);
232:   if (!sortedLocal) {
233:     PetscMalloc1(n, &idxcopy);
234:     PetscArraycpy(idxcopy, idx, n);
235:     PetscIntSortSemiOrdered(n, idxcopy);
236:     idx = idxcopy;
237:   }
238:   for (i = 1; i < n; i++)
239:     if (idx[i] == idx[i - 1]) break;
240:   if (i < n) *flg = PETSC_FALSE;
241:   else *flg = PETSC_TRUE;
242:   PetscFree(idxcopy);
243:   return 0;
244: }

246: static PetscErrorCode ISPermutationLocal_Block(IS is, PetscBool *flg)
247: {
248:   IS_Block *sub = (IS_Block *)is->data;
249:   PetscInt  n, bs, i, *idx, *idxcopy = NULL;
250:   PetscBool sortedLocal;

252:   PetscLayoutGetLocalSize(is->map, &n);
253:   PetscLayoutGetBlockSize(is->map, &bs);
254:   n /= bs;
255:   idx = sub->idx;
256:   ISGetInfo(is, IS_SORTED, IS_LOCAL, PETSC_TRUE, &sortedLocal);
257:   if (!sortedLocal) {
258:     PetscMalloc1(n, &idxcopy);
259:     PetscArraycpy(idxcopy, idx, n);
260:     PetscIntSortSemiOrdered(n, idxcopy);
261:     idx = idxcopy;
262:   }
263:   for (i = 0; i < n; i++)
264:     if (idx[i] != i) break;
265:   if (i < n) *flg = PETSC_FALSE;
266:   else *flg = PETSC_TRUE;
267:   PetscFree(idxcopy);
268:   return 0;
269: }

271: static PetscErrorCode ISIntervalLocal_Block(IS is, PetscBool *flg)
272: {
273:   IS_Block *sub = (IS_Block *)is->data;
274:   PetscInt  n, bs, i, *idx;

276:   PetscLayoutGetLocalSize(is->map, &n);
277:   PetscLayoutGetBlockSize(is->map, &bs);
278:   n /= bs;
279:   idx = sub->idx;
280:   for (i = 1; i < n; i++)
281:     if (idx[i] != idx[i - 1] + 1) break;
282:   if (i < n) *flg = PETSC_FALSE;
283:   else *flg = PETSC_TRUE;
284:   return 0;
285: }

287: static PetscErrorCode ISDuplicate_Block(IS is, IS *newIS)
288: {
289:   IS_Block *sub = (IS_Block *)is->data;
290:   PetscInt  bs, n;

292:   PetscLayoutGetBlockSize(is->map, &bs);
293:   PetscLayoutGetLocalSize(is->map, &n);
294:   n /= bs;
295:   ISCreateBlock(PetscObjectComm((PetscObject)is), bs, n, sub->idx, PETSC_COPY_VALUES, newIS);
296:   return 0;
297: }

299: static PetscErrorCode ISCopy_Block(IS is, IS isy)
300: {
301:   IS_Block *is_block = (IS_Block *)is->data, *isy_block = (IS_Block *)isy->data;
302:   PetscInt  bs, n;

304:   PetscLayoutGetBlockSize(is->map, &bs);
305:   PetscLayoutGetLocalSize(is->map, &n);
306:   PetscArraycpy(isy_block->idx, is_block->idx, n / bs);
307:   return 0;
308: }

310: static PetscErrorCode ISOnComm_Block(IS is, MPI_Comm comm, PetscCopyMode mode, IS *newis)
311: {
312:   IS_Block *sub = (IS_Block *)is->data;
313:   PetscInt  bs, n;

316:   PetscLayoutGetBlockSize(is->map, &bs);
317:   PetscLayoutGetLocalSize(is->map, &n);
318:   ISCreateBlock(comm, bs, n / bs, sub->idx, mode, newis);
319:   return 0;
320: }

322: static PetscErrorCode ISShift_Block(IS is, PetscInt shift, IS isy)
323: {
324:   IS_Block *isb  = (IS_Block *)is->data;
325:   IS_Block *isby = (IS_Block *)isy->data;
326:   PetscInt  i, n, bs;

328:   PetscLayoutGetLocalSize(is->map, &n);
329:   PetscLayoutGetBlockSize(is->map, &bs);
330:   shift /= bs;
331:   for (i = 0; i < n / bs; i++) isby->idx[i] = isb->idx[i] + shift;
332:   return 0;
333: }

335: static PetscErrorCode ISSetBlockSize_Block(IS is, PetscInt bs)
336: {
338:   PetscLayoutSetBlockSize(is->map, bs);
339:   return 0;
340: }

342: static PetscErrorCode ISToGeneral_Block(IS inis)
343: {
344:   IS_Block       *sub = (IS_Block *)inis->data;
345:   PetscInt        bs, n;
346:   const PetscInt *idx;

348:   ISGetBlockSize(inis, &bs);
349:   ISGetLocalSize(inis, &n);
350:   ISGetIndices(inis, &idx);
351:   if (bs == 1) {
352:     PetscCopyMode mode = sub->allocated ? PETSC_OWN_POINTER : PETSC_USE_POINTER;
353:     sub->allocated     = PETSC_FALSE; /* prevent deallocation when changing the subtype*/
354:     ISSetType(inis, ISGENERAL);
355:     ISGeneralSetIndices(inis, n, idx, mode);
356:   } else {
357:     ISSetType(inis, ISGENERAL);
358:     ISGeneralSetIndices(inis, n, idx, PETSC_OWN_POINTER);
359:   }
360:   return 0;
361: }

363: 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,
364:                               /* we can have specialized local routines for determining properties,
365:                                 * but unless the block size is the same on each process (which is not guaranteed at
366:                                 * the moment), then trying to do something specialized for global properties is too
367:                                 * complicated */
368:                               ISSortedLocal_Block, NULL, ISUniqueLocal_Block, NULL, ISPermutationLocal_Block, NULL, ISIntervalLocal_Block, NULL};

370: /*@
371:    ISBlockSetIndices - Set integers representing blocks of indices in an index set of `ISType` `ISBLOCK`

373:    Collective

375:    Input Parameters:
376: +  is - the index set
377: .  bs - number of elements in each block
378: .   n - the length of the index set (the number of blocks)
379: .  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
380: -  mode - see `PetscCopyMode`, only `PETSC_COPY_VALUES` and `PETSC_OWN_POINTER` are supported

382:    Level: beginner

384:    Notes:
385:    When the communicator is not `MPI_COMM_SELF`, the operations on the
386:    index sets, IS, are NOT conceptually the same as `MPI_Group` operations.
387:    The index sets are then distributed sets of indices and thus certain operations
388:    on them are collective.

390:    The convenience routine `ISCreateBlock()` allows one to create the `IS` and provide the blocks in a single function call.
391:    Example:
392:    If you wish to index the values {0,1,4,5}, then use
393:    a block size of 2 and idx of {0,2}.

395: .seealso: [](sec_scatter), `IS`, `ISCreateStride()`, `ISCreateGeneral()`, `ISAllGather()`, `ISCreateBlock()`, `ISBLOCK`, `ISGeneralSetIndices()`
396: @*/
397: PetscErrorCode ISBlockSetIndices(IS is, PetscInt bs, PetscInt n, const PetscInt idx[], PetscCopyMode mode)
398: {
399:   ISClearInfoCache(is, PETSC_FALSE);
400:   PetscUseMethod(is, "ISBlockSetIndices_C", (IS, PetscInt, PetscInt, const PetscInt[], PetscCopyMode), (is, bs, n, idx, mode));
401:   return 0;
402: }

404: static PetscErrorCode ISBlockSetIndices_Block(IS is, PetscInt bs, PetscInt n, const PetscInt idx[], PetscCopyMode mode)
405: {
406:   PetscInt    i, min, max;
407:   IS_Block   *sub = (IS_Block *)is->data;
408:   PetscLayout map;


414:   PetscLayoutCreateFromSizes(PetscObjectComm((PetscObject)is), n * bs, is->map->N, bs, &map);
415:   PetscLayoutDestroy(&is->map);
416:   is->map = map;

418:   if (sub->allocated) PetscFree(sub->idx);
419:   if (mode == PETSC_COPY_VALUES) {
420:     PetscMalloc1(n, &sub->idx);
421:     PetscArraycpy(sub->idx, idx, n);
422:     sub->allocated = PETSC_TRUE;
423:   } else if (mode == PETSC_OWN_POINTER) {
424:     sub->idx       = (PetscInt *)idx;
425:     sub->allocated = PETSC_TRUE;
426:   } else if (mode == PETSC_USE_POINTER) {
427:     sub->idx       = (PetscInt *)idx;
428:     sub->allocated = PETSC_FALSE;
429:   }

431:   if (n) {
432:     min = max = idx[0];
433:     for (i = 1; i < n; i++) {
434:       if (idx[i] < min) min = idx[i];
435:       if (idx[i] > max) max = idx[i];
436:     }
437:     is->min = bs * min;
438:     is->max = bs * max + bs - 1;
439:   } else {
440:     is->min = PETSC_MAX_INT;
441:     is->max = PETSC_MIN_INT;
442:   }
443:   return 0;
444: }

446: /*@
447:    ISCreateBlock - Creates a data structure for an index set containing
448:    a list of integers. Each integer represents a fixed block size set of indices.

450:    Collective

452:    Input Parameters:
453: +  comm - the MPI communicator
454: .  bs - number of elements in each block
455: .  n - the length of the index set (the number of blocks)
456: .  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
457: -  mode - see `PetscCopyMode`, only `PETSC_COPY_VALUES` and `PETSC_OWN_POINTER` are supported in this routine

459:    Output Parameter:
460: .  is - the new index set

462:    Level: beginner

464:    Notes:
465:    When the communicator is not `MPI_COMM_SELF`, the operations on the
466:    index sets, `IS`, are NOT conceptually the same as `MPI_Group` operations.
467:    The index sets are then distributed sets of indices and thus certain operations
468:    on them are collective.

470:    The routine `ISBlockSetIndices()` can be used to provide the indices to a preexisting block `IS`

472:    Example:
473:    If you wish to index the values {0,1,6,7}, then use
474:    a block size of 2 and idx of {0,3}.

476: .seealso: [](sec_scatter), `IS`, `ISCreateStride()`, `ISCreateGeneral()`, `ISAllGather()`, `ISBlockSetIndices()`, `ISBLOCK`, `ISGENERAL`
477: @*/
478: PetscErrorCode ISCreateBlock(MPI_Comm comm, PetscInt bs, PetscInt n, const PetscInt idx[], PetscCopyMode mode, IS *is)
479: {

485:   ISCreate(comm, is);
486:   ISSetType(*is, ISBLOCK);
487:   ISBlockSetIndices(*is, bs, n, idx, mode);
488:   return 0;
489: }

491: static PetscErrorCode ISBlockGetIndices_Block(IS is, const PetscInt *idx[])
492: {
493:   IS_Block *sub = (IS_Block *)is->data;

495:   *idx = sub->idx;
496:   return 0;
497: }

499: static PetscErrorCode ISBlockRestoreIndices_Block(IS is, const PetscInt *idx[])
500: {
501:   return 0;
502: }

504: /*@C
505:    ISBlockGetIndices - Gets the indices associated with each block in an `ISBLOCK`

507:    Not Collective

509:    Input Parameter:
510: .  is - the index set

512:    Output Parameter:
513: .  idx - the integer indices, one for each block and count of block not indices

515:    Level: intermediate

517:    Note:
518:    Call `ISBlockRestoreIndices()` when you no longer need access to the indices

520: .seealso: [](sec_scatter), `IS`, `ISBLOCK`, `ISGetIndices()`, `ISBlockRestoreIndices()`, `ISBLOCK`, `ISBlockSetIndices()`, `ISCreateBlock()`
521: @*/
522: PetscErrorCode ISBlockGetIndices(IS is, const PetscInt *idx[])
523: {
524:   PetscUseMethod(is, "ISBlockGetIndices_C", (IS, const PetscInt *[]), (is, idx));
525:   return 0;
526: }

528: /*@C
529:    ISBlockRestoreIndices - Restores the indices associated with each block  in an `ISBLOCK` obtained with `ISBlockGetIndices()`

531:    Not Collective

533:    Input Parameter:
534: .  is - the index set

536:    Output Parameter:
537: .  idx - the integer indices

539:    Level: intermediate

541: .seealso: [](sec_scatter), `IS`, `ISBLOCK`, `ISRestoreIndices()`, `ISBlockGetIndices()`
542: @*/
543: PetscErrorCode ISBlockRestoreIndices(IS is, const PetscInt *idx[])
544: {
545:   PetscUseMethod(is, "ISBlockRestoreIndices_C", (IS, const PetscInt *[]), (is, idx));
546:   return 0;
547: }

549: /*@
550:    ISBlockGetLocalSize - Returns the local number of blocks in the index set of `ISType` `ISBLOCK`

552:    Not Collective

554:    Input Parameter:
555: .  is - the index set

557:    Output Parameter:
558: .  size - the local number of blocks

560:    Level: intermediate

562: .seealso: [](sec_scatter), `IS`, `ISGetBlockSize()`, `ISBlockGetSize()`, `ISGetSize()`, `ISCreateBlock()`, `ISBLOCK`
563: @*/
564: PetscErrorCode ISBlockGetLocalSize(IS is, PetscInt *size)
565: {
566:   PetscUseMethod(is, "ISBlockGetLocalSize_C", (IS, PetscInt *), (is, size));
567:   return 0;
568: }

570: static PetscErrorCode ISBlockGetLocalSize_Block(IS is, PetscInt *size)
571: {
572:   PetscInt bs, n;

574:   PetscLayoutGetBlockSize(is->map, &bs);
575:   PetscLayoutGetLocalSize(is->map, &n);
576:   *size = n / bs;
577:   return 0;
578: }

580: /*@
581:    ISBlockGetSize - Returns the global number of blocks in parallel in the index set of `ISType` `ISBLOCK`

583:    Not Collective

585:    Input Parameter:
586: .  is - the index set

588:    Output Parameter:
589: .  size - the global number of blocks

591:    Level: intermediate

593: .seealso: [](sec_scatter), `IS`, `ISGetBlockSize()`, `ISBlockGetLocalSize()`, `ISGetSize()`, `ISCreateBlock()`, `ISBLOCK`
594: @*/
595: PetscErrorCode ISBlockGetSize(IS is, PetscInt *size)
596: {
597:   PetscUseMethod(is, "ISBlockGetSize_C", (IS, PetscInt *), (is, size));
598:   return 0;
599: }

601: static PetscErrorCode ISBlockGetSize_Block(IS is, PetscInt *size)
602: {
603:   PetscInt bs, N;

605:   PetscLayoutGetBlockSize(is->map, &bs);
606:   PetscLayoutGetSize(is->map, &N);
607:   *size = N / bs;
608:   return 0;
609: }

611: PETSC_EXTERN PetscErrorCode ISCreate_Block(IS is)
612: {
613:   IS_Block *sub;

615:   PetscNew(&sub);
616:   is->data = (void *)sub;
617:   PetscMemcpy(is->ops, &myops, sizeof(myops));
618:   PetscObjectComposeFunction((PetscObject)is, "ISBlockSetIndices_C", ISBlockSetIndices_Block);
619:   PetscObjectComposeFunction((PetscObject)is, "ISBlockGetIndices_C", ISBlockGetIndices_Block);
620:   PetscObjectComposeFunction((PetscObject)is, "ISBlockRestoreIndices_C", ISBlockRestoreIndices_Block);
621:   PetscObjectComposeFunction((PetscObject)is, "ISBlockGetSize_C", ISBlockGetSize_Block);
622:   PetscObjectComposeFunction((PetscObject)is, "ISBlockGetLocalSize_C", ISBlockGetLocalSize_Block);
623:   PetscObjectComposeFunction((PetscObject)is, "ISShift_C", ISShift_Block);
624:   return 0;
625: }