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;
21: if (sub->allocated) {PetscFree(sub->idx);}
22: PetscObjectComposeFunction((PetscObject)is,"ISBlockSetIndices_C",NULL);
23: PetscObjectComposeFunction((PetscObject)is,"ISBlockGetIndices_C",NULL);
24: PetscObjectComposeFunction((PetscObject)is,"ISBlockRestoreIndices_C",NULL);
25: PetscObjectComposeFunction((PetscObject)is,"ISBlockGetSize_C",NULL);
26: PetscObjectComposeFunction((PetscObject)is,"ISBlockGetLocalSize_C",NULL);
27: PetscFree(is->data);
28: return(0);
29: }
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;
39: PetscLayoutGetBlockSize(is->map,&bs);
40: PetscLayoutGetSize(is->map,&numIdx);
41: numIdx /= bs;
42: bkey = key / bs;
43: mkey = key % bs;
44: if (mkey < 0) {
45: bkey--;
46: mkey += bs;
47: }
48: ISGetInfo(is,IS_SORTED,IS_LOCAL,PETSC_TRUE,&sorted);
49: if (sorted) {
50: PetscFindInt(bkey,numIdx,sub->idx,location);
51: } else {
52: const PetscInt *idx = sub->idx;
54: *location = -1;
55: for (i = 0; i < numIdx; i++) {
56: if (idx[i] == bkey) {
57: *location = i;
58: break;
59: }
60: }
61: }
62: if (*location >= 0) {
63: *location = *location * bs + mkey;
64: }
65: return(0);
66: }
68: static PetscErrorCode ISGetIndices_Block(IS in,const PetscInt *idx[])
69: {
70: IS_Block *sub = (IS_Block*)in->data;
72: PetscInt i,j,k,bs,n,*ii,*jj;
75: PetscLayoutGetBlockSize(in->map, &bs);
76: PetscLayoutGetLocalSize(in->map, &n);
77: n /= bs;
78: if (bs == 1) *idx = sub->idx;
79: else {
80: if (n) {
81: PetscMalloc1(bs*n,&jj);
82: *idx = jj;
83: k = 0;
84: ii = sub->idx;
85: for (i=0; i<n; i++)
86: for (j=0; j<bs; j++)
87: jj[k++] = bs*ii[i] + j;
88: } else {
89: /* do not malloc for zero size because F90Array1dCreate() inside ISRestoreArrayF90() does not keep array when zero length array */
90: *idx = NULL;
91: }
92: }
93: return(0);
94: }
96: static PetscErrorCode ISRestoreIndices_Block(IS is,const PetscInt *idx[])
97: {
98: IS_Block *sub = (IS_Block*)is->data;
99: PetscInt bs;
103: PetscLayoutGetBlockSize(is->map, &bs);
104: if (bs != 1) {
105: PetscFree(*(void**)idx);
106: } else {
107: /* F90Array1dCreate() inside ISRestoreArrayF90() does not keep array when zero length array */
108: if (is->map->n > 0 && *idx != sub->idx) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Must restore with value from ISGetIndices()");
109: }
110: return(0);
111: }
113: static PetscErrorCode ISInvertPermutation_Block(IS is,PetscInt nlocal,IS *isout)
114: {
115: IS_Block *sub = (IS_Block*)is->data;
116: PetscInt i,*ii,bs,n,*idx = sub->idx;
117: PetscMPIInt size;
121: MPI_Comm_size(PetscObjectComm((PetscObject)is),&size);
122: PetscLayoutGetBlockSize(is->map, &bs);
123: PetscLayoutGetLocalSize(is->map, &n);
124: n /= bs;
125: if (size == 1) {
126: PetscMalloc1(n,&ii);
127: for (i=0; i<n; i++) ii[idx[i]] = i;
128: ISCreateBlock(PETSC_COMM_SELF,bs,n,ii,PETSC_OWN_POINTER,isout);
129: ISSetPermutation(*isout);
130: } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"No inversion written yet for block IS");
131: return(0);
132: }
134: static PetscErrorCode ISView_Block(IS is, PetscViewer viewer)
135: {
136: IS_Block *sub = (IS_Block*)is->data;
138: PetscInt i,bs,n,*idx = sub->idx;
139: PetscBool iascii,ibinary;
142: PetscLayoutGetBlockSize(is->map, &bs);
143: PetscLayoutGetLocalSize(is->map, &n);
144: n /= bs;
145: PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);
146: PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERBINARY,&ibinary);
147: if (iascii) {
148: PetscViewerFormat fmt;
150: PetscViewerGetFormat(viewer,&fmt);
151: if (fmt == PETSC_VIEWER_ASCII_MATLAB) {
152: IS ist;
153: const char *name;
154: const PetscInt *idx;
155: PetscInt n;
157: PetscObjectGetName((PetscObject)is,&name);
158: ISGetLocalSize(is,&n);
159: ISGetIndices(is,&idx);
160: ISCreateGeneral(PetscObjectComm((PetscObject)is),n,idx,PETSC_USE_POINTER,&ist);
161: PetscObjectSetName((PetscObject)ist,name);
162: ISView(ist,viewer);
163: ISDestroy(&ist);
164: ISRestoreIndices(is,&idx);
165: } else {
166: PetscBool isperm;
168: ISGetInfo(is,IS_PERMUTATION,IS_GLOBAL,PETSC_FALSE,&isperm);
169: if (isperm) {PetscViewerASCIIPrintf(viewer,"Block Index set is permutation\n");}
170: PetscViewerASCIIPushSynchronized(viewer);
171: PetscViewerASCIISynchronizedPrintf(viewer,"Block size %D\n",bs);
172: PetscViewerASCIISynchronizedPrintf(viewer,"Number of block indices in set %D\n",n);
173: PetscViewerASCIISynchronizedPrintf(viewer,"The first indices of each block are\n");
174: for (i=0; i<n; i++) {
175: PetscViewerASCIISynchronizedPrintf(viewer,"Block %D Index %D\n",i,idx[i]);
176: }
177: PetscViewerFlush(viewer);
178: PetscViewerASCIIPopSynchronized(viewer);
179: }
180: } else if (ibinary) {
181: ISView_Binary(is,viewer);
182: }
183: return(0);
184: }
186: static PetscErrorCode ISSort_Block(IS is)
187: {
188: IS_Block *sub = (IS_Block*)is->data;
189: PetscInt bs, n;
193: PetscLayoutGetBlockSize(is->map, &bs);
194: PetscLayoutGetLocalSize(is->map, &n);
195: PetscIntSortSemiOrdered(n/bs,sub->idx);
196: return(0);
197: }
199: static PetscErrorCode ISSortRemoveDups_Block(IS is)
200: {
201: IS_Block *sub = (IS_Block*)is->data;
202: PetscInt bs, n, nb;
203: PetscBool sorted;
207: PetscLayoutGetBlockSize(is->map, &bs);
208: PetscLayoutGetLocalSize(is->map, &n);
209: nb = n/bs;
210: ISGetInfo(is,IS_SORTED,IS_LOCAL,PETSC_TRUE,&sorted);
211: if (sorted) {
212: PetscSortedRemoveDupsInt(&nb,sub->idx);
213: } else {
214: PetscSortRemoveDupsInt(&nb,sub->idx);
215: }
216: PetscLayoutDestroy(&is->map);
217: PetscLayoutCreateFromSizes(PetscObjectComm((PetscObject)is), nb*bs, PETSC_DECIDE, bs, &is->map);
218: return(0);
219: }
221: static PetscErrorCode ISSorted_Block(IS is,PetscBool *flg)
222: {
226: ISGetInfo(is,IS_SORTED,IS_LOCAL,PETSC_TRUE,flg);
227: return(0);
228: }
230: static PetscErrorCode ISSortedLocal_Block(IS is,PetscBool *flg)
231: {
232: IS_Block *sub = (IS_Block*)is->data;
233: PetscInt n, bs, i, *idx;
237: PetscLayoutGetLocalSize(is->map, &n);
238: PetscLayoutGetBlockSize(is->map, &bs);
239: n /= bs;
240: idx = sub->idx;
241: for (i = 1; i < n; i++) if (idx[i] < idx[i - 1]) break;
242: if (i < n) *flg = PETSC_FALSE;
243: else *flg = PETSC_TRUE;
244: return(0);
245: }
247: static PetscErrorCode ISUniqueLocal_Block(IS is,PetscBool *flg)
248: {
249: IS_Block *sub = (IS_Block*)is->data;
250: PetscInt n, bs, i, *idx, *idxcopy = NULL;
251: PetscBool sortedLocal;
255: PetscLayoutGetLocalSize(is->map, &n);
256: PetscLayoutGetBlockSize(is->map, &bs);
257: n /= bs;
258: idx = sub->idx;
259: ISGetInfo(is,IS_SORTED,IS_LOCAL,PETSC_TRUE,&sortedLocal);
260: if (!sortedLocal) {
261: PetscMalloc1(n, &idxcopy);
262: PetscArraycpy(idxcopy, idx, n);
263: PetscIntSortSemiOrdered(n, idxcopy);
264: idx = idxcopy;
265: }
266: for (i = 1; i < n; i++) if (idx[i] == idx[i - 1]) break;
267: if (i < n) *flg = PETSC_FALSE;
268: else *flg = PETSC_TRUE;
269: PetscFree(idxcopy);
270: return(0);
271: }
273: static PetscErrorCode ISPermutationLocal_Block(IS is,PetscBool *flg)
274: {
275: IS_Block *sub = (IS_Block*)is->data;
276: PetscInt n, bs, i, *idx, *idxcopy = NULL;
277: PetscBool sortedLocal;
281: PetscLayoutGetLocalSize(is->map, &n);
282: PetscLayoutGetBlockSize(is->map, &bs);
283: n /= bs;
284: idx = sub->idx;
285: ISGetInfo(is,IS_SORTED,IS_LOCAL,PETSC_TRUE,&sortedLocal);
286: if (!sortedLocal) {
287: PetscMalloc1(n, &idxcopy);
288: PetscArraycpy(idxcopy, idx, n);
289: PetscIntSortSemiOrdered(n, idxcopy);
290: idx = idxcopy;
291: }
292: for (i = 0; i < n; i++) if (idx[i] != i) break;
293: if (i < n) *flg = PETSC_FALSE;
294: else *flg = PETSC_TRUE;
295: PetscFree(idxcopy);
296: return(0);
297: }
299: static PetscErrorCode ISIntervalLocal_Block(IS is,PetscBool *flg)
300: {
301: IS_Block *sub = (IS_Block*)is->data;
302: PetscInt n, bs, i, *idx;
306: PetscLayoutGetLocalSize(is->map, &n);
307: PetscLayoutGetBlockSize(is->map, &bs);
308: n /= bs;
309: idx = sub->idx;
310: for (i = 1; i < n; i++) if (idx[i] != idx[i - 1] + 1) break;
311: if (i < n) *flg = PETSC_FALSE;
312: else *flg = PETSC_TRUE;
313: return(0);
314: }
316: static PetscErrorCode ISDuplicate_Block(IS is,IS *newIS)
317: {
319: IS_Block *sub = (IS_Block*)is->data;
320: PetscInt bs, n;
323: PetscLayoutGetBlockSize(is->map, &bs);
324: PetscLayoutGetLocalSize(is->map, &n);
325: n /= bs;
326: ISCreateBlock(PetscObjectComm((PetscObject)is),bs,n,sub->idx,PETSC_COPY_VALUES,newIS);
327: return(0);
328: }
330: static PetscErrorCode ISCopy_Block(IS is,IS isy)
331: {
332: IS_Block *is_block = (IS_Block*)is->data,*isy_block = (IS_Block*)isy->data;
333: PetscInt bs, n, N, bsy, ny, Ny;
337: PetscLayoutGetBlockSize(is->map, &bs);
338: PetscLayoutGetLocalSize(is->map, &n);
339: PetscLayoutGetSize(is->map, &N);
340: PetscLayoutGetBlockSize(isy->map, &bsy);
341: PetscLayoutGetLocalSize(isy->map, &ny);
342: PetscLayoutGetSize(isy->map, &Ny);
343: if (n != ny || N != Ny || bs != bsy) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Index sets incompatible");
344: PetscArraycpy(isy_block->idx,is_block->idx,(n/bs));
345: return(0);
346: }
348: static PetscErrorCode ISOnComm_Block(IS is,MPI_Comm comm,PetscCopyMode mode,IS *newis)
349: {
351: IS_Block *sub = (IS_Block*)is->data;
352: PetscInt bs, n;
355: if (mode == PETSC_OWN_POINTER) SETERRQ(comm,PETSC_ERR_ARG_WRONG,"Cannot use PETSC_OWN_POINTER");
356: PetscLayoutGetBlockSize(is->map, &bs);
357: PetscLayoutGetLocalSize(is->map, &n);
358: ISCreateBlock(comm,bs,n/bs,sub->idx,mode,newis);
359: return(0);
360: }
362: static PetscErrorCode ISSetBlockSize_Block(IS is,PetscInt bs)
363: {
367: if (is->map->bs > 0 && bs != is->map->bs) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Cannot change blocksize %D (to %D) if ISType is ISBLOCK",is->map->bs,bs);
368: PetscLayoutSetBlockSize(is->map, bs);
369: return(0);
370: }
372: static PetscErrorCode ISToGeneral_Block(IS inis)
373: {
374: IS_Block *sub = (IS_Block*)inis->data;
375: PetscInt bs,n;
376: const PetscInt *idx;
380: ISGetBlockSize(inis,&bs);
381: ISGetLocalSize(inis,&n);
382: ISGetIndices(inis,&idx);
383: if (bs == 1) {
384: PetscCopyMode mode = sub->allocated ? PETSC_OWN_POINTER : PETSC_USE_POINTER;
385: sub->allocated = PETSC_FALSE; /* prevent deallocation when changing the subtype*/
386: ISSetType(inis,ISGENERAL);
387: ISGeneralSetIndices(inis,n,idx,mode);
388: } else {
389: ISSetType(inis,ISGENERAL);
390: ISGeneralSetIndices(inis,n,idx,PETSC_OWN_POINTER);
391: }
392: return(0);
393: }
395: static struct _ISOps myops = { ISGetIndices_Block,
396: ISRestoreIndices_Block,
397: ISInvertPermutation_Block,
398: ISSort_Block,
399: ISSortRemoveDups_Block,
400: ISSorted_Block,
401: ISDuplicate_Block,
402: ISDestroy_Block,
403: ISView_Block,
404: ISLoad_Default,
405: ISCopy_Block,
406: ISToGeneral_Block,
407: ISOnComm_Block,
408: ISSetBlockSize_Block,
409: NULL,
410: ISLocate_Block,
411: /* we can have specialized local routines for determining properties,
412: * but unless the block size is the same on each process (which is not guaranteed at
413: * the moment), then trying to do something specialized for global properties is too
414: * complicated */
415: ISSortedLocal_Block,
416: NULL,
417: ISUniqueLocal_Block,
418: NULL,
419: ISPermutationLocal_Block,
420: NULL,
421: ISIntervalLocal_Block,
422: NULL};
424: /*@
425: ISBlockSetIndices - Set integers representing blocks of indices in an index set.
427: Collective on IS
429: Input Parameters:
430: + is - the index set
431: . bs - number of elements in each block
432: . n - the length of the index set (the number of blocks)
433: . 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
434: - mode - see PetscCopyMode, only PETSC_COPY_VALUES and PETSC_OWN_POINTER are supported
436: Notes:
437: When the communicator is not MPI_COMM_SELF, the operations on the
438: index sets, IS, are NOT conceptually the same as MPI_Group operations.
439: The index sets are then distributed sets of indices and thus certain operations
440: on them are collective.
442: Example:
443: If you wish to index the values {0,1,4,5}, then use
444: a block size of 2 and idx of {0,2}.
446: Level: beginner
448: .seealso: ISCreateStride(), ISCreateGeneral(), ISAllGather(), ISCreateBlock(), ISBLOCK, ISGeneralSetIndices()
449: @*/
450: PetscErrorCode ISBlockSetIndices(IS is,PetscInt bs,PetscInt n,const PetscInt idx[],PetscCopyMode mode)
451: {
455: ISClearInfoCache(is,PETSC_FALSE);
456: PetscUseMethod(is,"ISBlockSetIndices_C",(IS,PetscInt,PetscInt,const PetscInt[],PetscCopyMode),(is,bs,n,idx,mode));
457: return(0);
458: }
460: static PetscErrorCode ISBlockSetIndices_Block(IS is,PetscInt bs,PetscInt n,const PetscInt idx[],PetscCopyMode mode)
461: {
463: PetscInt i,min,max;
464: IS_Block *sub = (IS_Block*)is->data;
465: PetscLayout map;
468: if (bs < 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"block size < 1");
469: if (n < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"length < 0");
472: PetscLayoutCreateFromSizes(PetscObjectComm((PetscObject)is),n*bs,is->map->N,bs,&map);
473: PetscLayoutDestroy(&is->map);
474: is->map = map;
476: if (sub->allocated) {PetscFree(sub->idx);}
477: if (mode == PETSC_COPY_VALUES) {
478: PetscMalloc1(n,&sub->idx);
479: PetscLogObjectMemory((PetscObject)is,n*sizeof(PetscInt));
480: PetscArraycpy(sub->idx,idx,n);
481: sub->allocated = PETSC_TRUE;
482: } else if (mode == PETSC_OWN_POINTER) {
483: sub->idx = (PetscInt*) idx;
484: PetscLogObjectMemory((PetscObject)is,n*sizeof(PetscInt));
485: sub->allocated = PETSC_TRUE;
486: } else if (mode == PETSC_USE_POINTER) {
487: sub->idx = (PetscInt*) idx;
488: sub->allocated = PETSC_FALSE;
489: }
491: if (n) {
492: min = max = idx[0];
493: for (i=1; i<n; i++) {
494: if (idx[i] < min) min = idx[i];
495: if (idx[i] > max) max = idx[i];
496: }
497: is->min = bs*min;
498: is->max = bs*max+bs-1;
499: } else {
500: is->min = PETSC_MAX_INT;
501: is->max = PETSC_MIN_INT;
502: }
503: return(0);
504: }
506: /*@
507: ISCreateBlock - Creates a data structure for an index set containing
508: a list of integers. Each integer represents a fixed block size set of indices.
510: Collective
512: Input Parameters:
513: + comm - the MPI communicator
514: . bs - number of elements in each block
515: . n - the length of the index set (the number of blocks)
516: . 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
517: - mode - see PetscCopyMode, only PETSC_COPY_VALUES and PETSC_OWN_POINTER are supported in this routine
519: Output Parameter:
520: . is - the new index set
522: Notes:
523: When the communicator is not MPI_COMM_SELF, the operations on the
524: index sets, IS, are NOT conceptually the same as MPI_Group operations.
525: The index sets are then distributed sets of indices and thus certain operations
526: on them are collective.
528: Example:
529: If you wish to index the values {0,1,6,7}, then use
530: a block size of 2 and idx of {0,3}.
532: Level: beginner
534: .seealso: ISCreateStride(), ISCreateGeneral(), ISAllGather(), ISBlockSetIndices(), ISBLOCK, ISGENERAL
535: @*/
536: PetscErrorCode ISCreateBlock(MPI_Comm comm,PetscInt bs,PetscInt n,const PetscInt idx[],PetscCopyMode mode,IS *is)
537: {
542: if (bs < 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"block size < 1");
543: if (n < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"length < 0");
546: ISCreate(comm,is);
547: ISSetType(*is,ISBLOCK);
548: ISBlockSetIndices(*is,bs,n,idx,mode);
549: return(0);
550: }
552: static PetscErrorCode ISBlockGetIndices_Block(IS is,const PetscInt *idx[])
553: {
554: IS_Block *sub = (IS_Block*)is->data;
557: *idx = sub->idx;
558: return(0);
559: }
561: static PetscErrorCode ISBlockRestoreIndices_Block(IS is,const PetscInt *idx[])
562: {
564: return(0);
565: }
567: /*@C
568: ISBlockGetIndices - Gets the indices associated with each block.
570: Not Collective
572: Input Parameter:
573: . is - the index set
575: Output Parameter:
576: . idx - the integer indices, one for each block and count of block not indices
578: Level: intermediate
580: .seealso: ISGetIndices(), ISBlockRestoreIndices(), ISBLOCK, ISBlockSetIndices(), ISCreateBlock()
581: @*/
582: PetscErrorCode ISBlockGetIndices(IS is,const PetscInt *idx[])
583: {
587: PetscUseMethod(is,"ISBlockGetIndices_C",(IS,const PetscInt*[]),(is,idx));
588: return(0);
589: }
591: /*@C
592: ISBlockRestoreIndices - Restores the indices associated with each block.
594: Not Collective
596: Input Parameter:
597: . is - the index set
599: Output Parameter:
600: . idx - the integer indices
602: Level: intermediate
604: .seealso: ISRestoreIndices(), ISBlockGetIndices()
605: @*/
606: PetscErrorCode ISBlockRestoreIndices(IS is,const PetscInt *idx[])
607: {
611: PetscUseMethod(is,"ISBlockRestoreIndices_C",(IS,const PetscInt*[]),(is,idx));
612: return(0);
613: }
615: /*@
616: ISBlockGetLocalSize - Returns the local number of blocks in the index set.
618: Not Collective
620: Input Parameter:
621: . is - the index set
623: Output Parameter:
624: . size - the local number of blocks
626: Level: intermediate
628: .seealso: ISGetBlockSize(), ISBlockGetSize(), ISGetSize(), ISCreateBlock(), ISBLOCK
629: @*/
630: PetscErrorCode ISBlockGetLocalSize(IS is,PetscInt *size)
631: {
635: PetscUseMethod(is,"ISBlockGetLocalSize_C",(IS,PetscInt*),(is,size));
636: return(0);
637: }
639: static PetscErrorCode ISBlockGetLocalSize_Block(IS is,PetscInt *size)
640: {
641: PetscInt bs, n;
645: PetscLayoutGetBlockSize(is->map, &bs);
646: PetscLayoutGetLocalSize(is->map, &n);
647: *size = n/bs;
648: return(0);
649: }
651: /*@
652: ISBlockGetSize - Returns the global number of blocks in the index set.
654: Not Collective
656: Input Parameter:
657: . is - the index set
659: Output Parameter:
660: . size - the global number of blocks
662: Level: intermediate
664: .seealso: ISGetBlockSize(), ISBlockGetLocalSize(), ISGetSize(), ISCreateBlock(), ISBLOCK
665: @*/
666: PetscErrorCode ISBlockGetSize(IS is,PetscInt *size)
667: {
671: PetscUseMethod(is,"ISBlockGetSize_C",(IS,PetscInt*),(is,size));
672: return(0);
673: }
675: static PetscErrorCode ISBlockGetSize_Block(IS is,PetscInt *size)
676: {
677: PetscInt bs, N;
681: PetscLayoutGetBlockSize(is->map, &bs);
682: PetscLayoutGetSize(is->map, &N);
683: *size = N/bs;
684: return(0);
685: }
687: PETSC_EXTERN PetscErrorCode ISCreate_Block(IS is)
688: {
690: IS_Block *sub;
693: PetscNewLog(is,&sub);
694: is->data = (void *) sub;
695: PetscMemcpy(is->ops,&myops,sizeof(myops));
696: PetscObjectComposeFunction((PetscObject)is,"ISBlockSetIndices_C",ISBlockSetIndices_Block);
697: PetscObjectComposeFunction((PetscObject)is,"ISBlockGetIndices_C",ISBlockGetIndices_Block);
698: PetscObjectComposeFunction((PetscObject)is,"ISBlockRestoreIndices_C",ISBlockRestoreIndices_Block);
699: PetscObjectComposeFunction((PetscObject)is,"ISBlockGetSize_C",ISBlockGetSize_Block);
700: PetscObjectComposeFunction((PetscObject)is,"ISBlockGetLocalSize_C",ISBlockGetLocalSize_Block);
701: return(0);
702: }