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