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 252 #undef __FUNCT__ 253 #define __FUNCT__ "ISBlockSetIndices" 254 /*@ 255 ISBlockSetIndices - The indices are relative to entries, not blocks. 256 257 Collective on IS 258 259 Input Parameters: 260 + is - the index set 261 . bs - number of elements in each block, one for each block and count of block not indices 262 . n - the length of the index set (the number of blocks) 263 . idx - the list of integers, these are by block, not by location 264 + mode - see PetscCopyMode, only PETSC_COPY_VALUES and PETSC_OWN_POINTER are supported 265 266 267 Notes: 268 When the communicator is not MPI_COMM_SELF, the operations on the 269 index sets, IS, are NOT conceptually the same as MPI_Group operations. 270 The index sets are then distributed sets of indices and thus certain operations 271 on them are collective. 272 273 Example: 274 If you wish to index the values {0,1,4,5}, then use 275 a block size of 2 and idx of {0,2}. 276 277 Level: beginner 278 279 Concepts: IS^block 280 Concepts: index sets^block 281 Concepts: block^index set 282 283 .seealso: ISCreateStride(), ISCreateGeneral(), ISAllGather() 284 @*/ 285 PetscErrorCode ISBlockSetIndices(IS is,PetscInt bs,PetscInt n,const PetscInt idx[],PetscCopyMode mode) 286 { 287 PetscErrorCode ierr; 288 289 PetscFunctionBegin; 290 ierr = PetscUseMethod(is,"ISBlockSetIndices_C",(IS,PetscInt,PetscInt,const PetscInt[],PetscCopyMode),(is,bs,n,idx,mode));CHKERRQ(ierr); 291 PetscFunctionReturn(0); 292 } 293 294 EXTERN_C_BEGIN 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(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 EXTERN_C_END 334 335 #undef __FUNCT__ 336 #define __FUNCT__ "ISCreateBlock" 337 /*@ 338 ISCreateBlock - Creates a data structure for an index set containing 339 a list of integers. The indices are relative to entries, not blocks. 340 341 Collective on MPI_Comm 342 343 Input Parameters: 344 + comm - the MPI communicator 345 . bs - number of elements in each block 346 . n - the length of the index set (the number of blocks) 347 . idx - the list of integers, one for each block and count of block not indices 348 - mode - see PetscCopyMode, only PETSC_COPY_VALUES and PETSC_OWN_POINTER are supported in this routine 349 350 Output Parameter: 351 . is - the new index set 352 353 Notes: 354 When the communicator is not MPI_COMM_SELF, the operations on the 355 index sets, IS, are NOT conceptually the same as MPI_Group operations. 356 The index sets are then distributed sets of indices and thus certain operations 357 on them are collective. 358 359 Example: 360 If you wish to index the values {0,1,6,7}, then use 361 a block size of 2 and idx of {0,3}. 362 363 Level: beginner 364 365 Concepts: IS^block 366 Concepts: index sets^block 367 Concepts: block^index set 368 369 .seealso: ISCreateStride(), ISCreateGeneral(), ISAllGather() 370 @*/ 371 PetscErrorCode ISCreateBlock(MPI_Comm comm,PetscInt bs,PetscInt n,const PetscInt idx[],PetscCopyMode mode,IS *is) 372 { 373 PetscErrorCode ierr; 374 375 PetscFunctionBegin; 376 PetscValidPointer(is,5); 377 if (n < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"length < 0"); 378 if (n) PetscValidIntPointer(idx,4); 379 380 ierr = ISCreate(comm,is);CHKERRQ(ierr); 381 ierr = ISSetType(*is,ISBLOCK);CHKERRQ(ierr); 382 ierr = ISBlockSetIndices(*is,bs,n,idx,mode);CHKERRQ(ierr); 383 PetscFunctionReturn(0); 384 } 385 386 EXTERN_C_BEGIN 387 #undef __FUNCT__ 388 #define __FUNCT__ "ISBlockGetIndices_Block" 389 PetscErrorCode ISBlockGetIndices_Block(IS is,const PetscInt *idx[]) 390 { 391 IS_Block *sub = (IS_Block*)is->data; 392 393 PetscFunctionBegin; 394 *idx = sub->idx; 395 PetscFunctionReturn(0); 396 } 397 EXTERN_C_END 398 399 EXTERN_C_BEGIN 400 #undef __FUNCT__ 401 #define __FUNCT__ "ISBlockRestoreIndices_Block" 402 PetscErrorCode ISBlockRestoreIndices_Block(IS is,const PetscInt *idx[]) 403 { 404 PetscFunctionBegin; 405 PetscFunctionReturn(0); 406 } 407 EXTERN_C_END 408 409 #undef __FUNCT__ 410 #define __FUNCT__ "ISBlockGetIndices" 411 /*@C 412 ISBlockGetIndices - Gets the indices associated with each block. 413 414 Not Collective 415 416 Input Parameter: 417 . is - the index set 418 419 Output Parameter: 420 . idx - the integer indices, one for each block and count of block not indices 421 422 Level: intermediate 423 424 Concepts: IS^block 425 Concepts: index sets^getting indices 426 Concepts: index sets^block 427 428 .seealso: ISGetIndices(), ISBlockRestoreIndices() 429 @*/ 430 PetscErrorCode ISBlockGetIndices(IS is,const PetscInt *idx[]) 431 { 432 PetscErrorCode ierr; 433 434 PetscFunctionBegin; 435 ierr = PetscUseMethod(is,"ISBlockGetIndices_C",(IS,const PetscInt*[]),(is,idx));CHKERRQ(ierr); 436 PetscFunctionReturn(0); 437 } 438 439 #undef __FUNCT__ 440 #define __FUNCT__ "ISBlockRestoreIndices" 441 /*@C 442 ISBlockRestoreIndices - Restores the indices associated with each block. 443 444 Not Collective 445 446 Input Parameter: 447 . is - the index set 448 449 Output Parameter: 450 . idx - the integer indices 451 452 Level: intermediate 453 454 Concepts: IS^block 455 Concepts: index sets^getting indices 456 Concepts: index sets^block 457 458 .seealso: ISRestoreIndices(), ISBlockGetIndices() 459 @*/ 460 PetscErrorCode ISBlockRestoreIndices(IS is,const PetscInt *idx[]) 461 { 462 PetscErrorCode ierr; 463 464 PetscFunctionBegin; 465 ierr = PetscUseMethod(is,"ISBlockRestoreIndices_C",(IS,const PetscInt*[]),(is,idx));CHKERRQ(ierr); 466 PetscFunctionReturn(0); 467 } 468 469 #undef __FUNCT__ 470 #define __FUNCT__ "ISBlockGetLocalSize" 471 /*@ 472 ISBlockGetLocalSize - Returns the local number of blocks in the index set. 473 474 Not Collective 475 476 Input Parameter: 477 . is - the index set 478 479 Output Parameter: 480 . size - the local number of blocks 481 482 Level: intermediate 483 484 Concepts: IS^block sizes 485 Concepts: index sets^block sizes 486 487 .seealso: ISGetBlockSize(), ISBlockGetSize(), ISGetSize(), ISCreateBlock() 488 @*/ 489 PetscErrorCode ISBlockGetLocalSize(IS is,PetscInt *size) 490 { 491 PetscErrorCode ierr; 492 493 PetscFunctionBegin; 494 ierr = PetscUseMethod(is,"ISBlockGetLocalSize_C",(IS,PetscInt*),(is,size));CHKERRQ(ierr); 495 PetscFunctionReturn(0); 496 } 497 498 EXTERN_C_BEGIN 499 #undef __FUNCT__ 500 #define __FUNCT__ "ISBlockGetLocalSize_Block" 501 PetscErrorCode ISBlockGetLocalSize_Block(IS is,PetscInt *size) 502 { 503 IS_Block *sub = (IS_Block*)is->data; 504 505 PetscFunctionBegin; 506 *size = sub->n; 507 PetscFunctionReturn(0); 508 } 509 EXTERN_C_END 510 511 #undef __FUNCT__ 512 #define __FUNCT__ "ISBlockGetSize" 513 /*@ 514 ISBlockGetSize - Returns the global number of blocks in the index set. 515 516 Not Collective 517 518 Input Parameter: 519 . is - the index set 520 521 Output Parameter: 522 . size - the global number of blocks 523 524 Level: intermediate 525 526 Concepts: IS^block sizes 527 Concepts: index sets^block sizes 528 529 .seealso: ISGetBlockSize(), ISBlockGetLocalSize(), ISGetSize(), ISCreateBlock() 530 @*/ 531 PetscErrorCode ISBlockGetSize(IS is,PetscInt *size) 532 { 533 PetscErrorCode ierr; 534 535 PetscFunctionBegin; 536 ierr = PetscUseMethod(is,"ISBlockGetSize_C",(IS,PetscInt*),(is,size));CHKERRQ(ierr); 537 PetscFunctionReturn(0); 538 } 539 540 EXTERN_C_BEGIN 541 #undef __FUNCT__ 542 #define __FUNCT__ "ISBlockGetSize_Block" 543 PetscErrorCode ISBlockGetSize_Block(IS is,PetscInt *size) 544 { 545 IS_Block *sub = (IS_Block*)is->data; 546 547 PetscFunctionBegin; 548 *size = sub->N; 549 PetscFunctionReturn(0); 550 } 551 EXTERN_C_END 552 553 #undef __FUNCT__ 554 #define __FUNCT__ "ISToGeneral_Block" 555 PetscErrorCode ISToGeneral_Block(IS inis) 556 { 557 PetscErrorCode ierr; 558 const PetscInt *idx; 559 PetscInt n; 560 561 PetscFunctionBegin; 562 ierr = ISGetLocalSize(inis,&n);CHKERRQ(ierr); 563 ierr = ISGetIndices(inis,&idx);CHKERRQ(ierr); 564 ierr = ISSetType(inis,ISGENERAL);CHKERRQ(ierr); 565 ierr = ISGeneralSetIndices(inis,n,idx,PETSC_OWN_POINTER);CHKERRQ(ierr); 566 PetscFunctionReturn(0); 567 } 568 569 EXTERN_C_BEGIN 570 #undef __FUNCT__ 571 #define __FUNCT__ "ISCreate_Block" 572 PetscErrorCode ISCreate_Block(IS is) 573 { 574 PetscErrorCode ierr; 575 IS_Block *sub; 576 577 PetscFunctionBegin; 578 ierr = PetscNewLog(is,IS_Block,&sub);CHKERRQ(ierr); 579 is->data = sub; 580 ierr = PetscObjectComposeFunction((PetscObject)is,"ISBlockSetIndices_C","ISBlockSetIndices_Block",ISBlockSetIndices_Block);CHKERRQ(ierr); 581 ierr = PetscObjectComposeFunction((PetscObject)is,"ISBlockGetIndices_C","ISBlockGetIndices_Block",ISBlockGetIndices_Block);CHKERRQ(ierr); 582 ierr = PetscObjectComposeFunction((PetscObject)is,"ISBlockRestoreIndices_C","ISBlockRestoreIndices_Block",ISBlockRestoreIndices_Block);CHKERRQ(ierr); 583 ierr = PetscObjectComposeFunction((PetscObject)is,"ISBlockGetSize_C","ISBlockGetSize_Block",ISBlockGetSize_Block);CHKERRQ(ierr); 584 ierr = PetscObjectComposeFunction((PetscObject)is,"ISBlockGetLocalSize_C","ISBlockGetLocalSize_Block",ISBlockGetLocalSize_Block);CHKERRQ(ierr); 585 PetscFunctionReturn(0); 586 } 587 EXTERN_C_END 588