Actual source code: mlocalref.c
petsc-3.7.3 2016-08-01
2: #include <petsc/private/matimpl.h> /*I "petscmat.h" I*/
4: typedef struct {
5: Mat Top;
6: PetscBool rowisblock;
7: PetscBool colisblock;
8: PetscErrorCode (*SetValues)(Mat,PetscInt,const PetscInt[],PetscInt,const PetscInt[],const PetscScalar[],InsertMode);
9: PetscErrorCode (*SetValuesBlocked)(Mat,PetscInt,const PetscInt[],PetscInt,const PetscInt[],const PetscScalar[],InsertMode);
10: } Mat_LocalRef;
12: /* These need to be macros because they use sizeof */
13: #define IndexSpaceGet(buf,nrow,ncol,irowm,icolm) do { \
14: if (nrow + ncol > (PetscInt)(sizeof(buf)/sizeof(buf[0]))) { \
15: PetscMalloc2(nrow,&irowm,ncol,&icolm); \
16: } else { \
17: irowm = &buf[0]; \
18: icolm = &buf[nrow]; \
19: } \
20: } while (0)
22: #define IndexSpaceRestore(buf,nrow,ncol,irowm,icolm) do { \
23: if (nrow + ncol > (PetscInt)(sizeof(buf)/sizeof(buf[0]))) { \
24: PetscFree2(irowm,icolm); \
25: } \
26: } while (0)
28: static void BlockIndicesExpand(PetscInt n,const PetscInt idx[],PetscInt bs,PetscInt idxm[])
29: {
30: PetscInt i,j;
31: for (i=0; i<n; i++) {
32: for (j=0; j<bs; j++) {
33: idxm[i*bs+j] = idx[i]*bs + j;
34: }
35: }
36: }
40: static PetscErrorCode MatSetValuesBlockedLocal_LocalRef_Block(Mat A,PetscInt nrow,const PetscInt irow[],PetscInt ncol,const PetscInt icol[],const PetscScalar y[],InsertMode addv)
41: {
42: Mat_LocalRef *lr = (Mat_LocalRef*)A->data;
44: PetscInt buf[4096],*irowm,*icolm;
47: if (!nrow || !ncol) return(0);
48: IndexSpaceGet(buf,nrow,ncol,irowm,icolm);
49: ISLocalToGlobalMappingApplyBlock(A->rmap->mapping,nrow,irow,irowm);
50: ISLocalToGlobalMappingApplyBlock(A->cmap->mapping,ncol,icol,icolm);
51: (*lr->SetValuesBlocked)(lr->Top,nrow,irowm,ncol,icolm,y,addv);
52: IndexSpaceRestore(buf,nrow,ncol,irowm,icolm);
53: return(0);
54: }
58: static PetscErrorCode MatSetValuesBlockedLocal_LocalRef_Scalar(Mat A,PetscInt nrow,const PetscInt irow[],PetscInt ncol,const PetscInt icol[],const PetscScalar y[],InsertMode addv)
59: {
60: Mat_LocalRef *lr = (Mat_LocalRef*)A->data;
62: PetscInt rbs,cbs,buf[4096],*irowm,*icolm;
65: MatGetBlockSizes(A,&rbs,&cbs);
66: IndexSpaceGet(buf,nrow*rbs,ncol*cbs,irowm,icolm);
67: BlockIndicesExpand(nrow,irow,rbs,irowm);
68: BlockIndicesExpand(ncol,icol,cbs,icolm);
69: ISLocalToGlobalMappingApplyBlock(A->rmap->mapping,nrow*rbs,irowm,irowm);
70: ISLocalToGlobalMappingApplyBlock(A->cmap->mapping,ncol*cbs,icolm,icolm);
71: (*lr->SetValues)(lr->Top,nrow*rbs,irowm,ncol*cbs,icolm,y,addv);
72: IndexSpaceRestore(buf,nrow*rbs,ncol*cbs,irowm,icolm);
73: return(0);
74: }
78: static PetscErrorCode MatSetValuesLocal_LocalRef_Scalar(Mat A,PetscInt nrow,const PetscInt irow[],PetscInt ncol,const PetscInt icol[],const PetscScalar y[],InsertMode addv)
79: {
80: Mat_LocalRef *lr = (Mat_LocalRef*)A->data;
82: PetscInt buf[4096],*irowm,*icolm;
85: IndexSpaceGet(buf,nrow,ncol,irowm,icolm);
86: /* If the row IS defining this submatrix was an ISBLOCK, then the unblocked LGMapApply is the right one to use. If
87: * instead it was (say) an ISSTRIDE with a block size > 1, then we need to use LGMapApplyBlock */
88: if (lr->rowisblock) {
89: ISLocalToGlobalMappingApply(A->rmap->mapping,nrow,irow,irowm);
90: } else {
91: ISLocalToGlobalMappingApplyBlock(A->rmap->mapping,nrow,irow,irowm);
92: }
93: /* As above, but for the column IS. */
94: if (lr->colisblock) {
95: ISLocalToGlobalMappingApply(A->cmap->mapping,ncol,icol,icolm);
96: } else {
97: ISLocalToGlobalMappingApplyBlock(A->cmap->mapping,ncol,icol,icolm);
98: }
99: (*lr->SetValues)(lr->Top,nrow,irowm,ncol,icolm,y,addv);
100: IndexSpaceRestore(buf,nrow,ncol,irowm,icolm);
101: return(0);
102: }
106: /* Compose an IS with an ISLocalToGlobalMapping to map from IS source indices to global indices */
107: static PetscErrorCode ISL2GCompose(IS is,ISLocalToGlobalMapping ltog,ISLocalToGlobalMapping *cltog)
108: {
110: const PetscInt *idx;
111: PetscInt m,*idxm;
112: PetscInt bs;
113: PetscBool isblock;
119: PetscObjectTypeCompare((PetscObject)is,ISBLOCK,&isblock);
120: if (isblock) {
121: PetscInt lbs;
123: ISGetBlockSize(is,&bs);
124: ISLocalToGlobalMappingGetBlockSize(ltog,&lbs);
125: if (bs == lbs) {
126: ISGetLocalSize(is,&m);
127: m = m/bs;
128: ISBlockGetIndices(is,&idx);
129: PetscMalloc1(m,&idxm);
130: ISLocalToGlobalMappingApplyBlock(ltog,m,idx,idxm);
131: ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)is),bs,m,idxm,PETSC_OWN_POINTER,cltog);
132: ISBlockRestoreIndices(is,&idx);
133: return(0);
134: }
135: }
136: ISGetLocalSize(is,&m);
137: ISGetIndices(is,&idx);
138: ISGetBlockSize(is,&bs);
139: PetscMalloc1(m,&idxm);
140: if (ltog) {
141: ISLocalToGlobalMappingApply(ltog,m,idx,idxm);
142: } else {
143: PetscMemcpy(idxm,idx,m*sizeof(PetscInt));
144: }
145: ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)is),bs,m,idxm,PETSC_OWN_POINTER,cltog);
146: ISRestoreIndices(is,&idx);
147: return(0);
148: }
152: static PetscErrorCode ISL2GComposeBlock(IS is,ISLocalToGlobalMapping ltog,ISLocalToGlobalMapping *cltog)
153: {
155: const PetscInt *idx;
156: PetscInt m,*idxm,bs;
162: ISBlockGetLocalSize(is,&m);
163: ISBlockGetIndices(is,&idx);
164: ISLocalToGlobalMappingGetBlockSize(ltog,&bs);
165: PetscMalloc1(m,&idxm);
166: if (ltog) {
167: ISLocalToGlobalMappingApplyBlock(ltog,m,idx,idxm);
168: } else {
169: PetscMemcpy(idxm,idx,m*sizeof(PetscInt));
170: }
171: ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)is),bs,m,idxm,PETSC_OWN_POINTER,cltog);
172: ISBlockRestoreIndices(is,&idx);
173: return(0);
174: }
178: static PetscErrorCode MatDestroy_LocalRef(Mat B)
179: {
183: PetscFree(B->data);
184: return(0);
185: }
190: /*@
191: MatCreateLocalRef - Gets a logical reference to a local submatrix, for use in assembly
193: Not Collective
195: Input Arguments:
196: + A - Full matrix, generally parallel
197: . isrow - Local index set for the rows
198: - iscol - Local index set for the columns
200: Output Arguments:
201: . newmat - New serial Mat
203: Level: developer
205: Notes:
206: Most will use MatGetLocalSubMatrix() which returns a real matrix corresponding to the local
207: block if it available, such as with matrix formats that store these blocks separately.
209: The new matrix forwards MatSetValuesLocal() and MatSetValuesBlockedLocal() to the global system.
210: In general, it does not define MatMult() or any other functions. Local submatrices can be nested.
212: .seealso: MatSetValuesLocal(), MatSetValuesBlockedLocal(), MatGetLocalSubMatrix(), MatCreateSubMatrix()
213: @*/
214: PetscErrorCode MatCreateLocalRef(Mat A,IS isrow,IS iscol,Mat *newmat)
215: {
217: Mat_LocalRef *lr;
218: Mat B;
219: PetscInt m,n;
220: PetscBool islr;
227: if (!A->rmap->mapping) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Matrix must have local to global mapping provided before this call");
228: *newmat = 0;
230: MatCreate(PETSC_COMM_SELF,&B);
231: ISGetLocalSize(isrow,&m);
232: ISGetLocalSize(iscol,&n);
233: MatSetSizes(B,m,n,m,n);
234: PetscObjectChangeTypeName((PetscObject)B,MATLOCALREF);
235: MatSetUp(B);
237: B->ops->destroy = MatDestroy_LocalRef;
239: PetscNewLog(B,&lr);
240: B->data = (void*)lr;
242: PetscObjectTypeCompare((PetscObject)A,MATLOCALREF,&islr);
243: if (islr) {
244: Mat_LocalRef *alr = (Mat_LocalRef*)A->data;
245: lr->Top = alr->Top;
246: } else {
247: /* This does not increase the reference count because MatLocalRef is not allowed to live longer than its parent */
248: lr->Top = A;
249: }
250: {
251: ISLocalToGlobalMapping rltog,cltog;
252: PetscInt arbs,acbs,rbs,cbs;
254: /* We will translate directly to global indices for the top level */
255: lr->SetValues = MatSetValues;
256: lr->SetValuesBlocked = MatSetValuesBlocked;
258: B->ops->setvalueslocal = MatSetValuesLocal_LocalRef_Scalar;
260: ISL2GCompose(isrow,A->rmap->mapping,&rltog);
261: if (isrow == iscol && A->rmap->mapping == A->cmap->mapping) {
262: PetscObjectReference((PetscObject)rltog);
263: cltog = rltog;
264: } else {
265: ISL2GCompose(iscol,A->cmap->mapping,&cltog);
266: }
267: /* Remember if the ISes we used to pull out the submatrix are of type ISBLOCK. Will be used later in
268: * MatSetValuesLocal_LocalRef_Scalar. */
269: PetscObjectTypeCompare((PetscObject)isrow,ISBLOCK,&lr->rowisblock);
270: PetscObjectTypeCompare((PetscObject)iscol,ISBLOCK,&lr->colisblock);
271: MatSetLocalToGlobalMapping(B,rltog,cltog);
272: ISLocalToGlobalMappingDestroy(&rltog);
273: ISLocalToGlobalMappingDestroy(&cltog);
275: MatGetBlockSizes(A,&arbs,&acbs);
276: ISGetBlockSize(isrow,&rbs);
277: ISGetBlockSize(iscol,&cbs);
278: /* Always support block interface insertion on submatrix */
279: PetscLayoutSetBlockSize(B->rmap,rbs);
280: PetscLayoutSetBlockSize(B->cmap,cbs);
281: if (arbs != rbs || acbs != cbs || (arbs == 1 && acbs == 1)) {
282: /* Top-level matrix has different block size, so we have to call its scalar insertion interface */
283: B->ops->setvaluesblockedlocal = MatSetValuesBlockedLocal_LocalRef_Scalar;
284: } else {
285: /* Block sizes match so we can forward values to the top level using the block interface */
286: B->ops->setvaluesblockedlocal = MatSetValuesBlockedLocal_LocalRef_Block;
288: ISL2GComposeBlock(isrow,A->rmap->mapping,&rltog);
289: if (isrow == iscol && A->rmap->mapping == A->cmap->mapping) {
290: PetscObjectReference((PetscObject)rltog);
291: cltog = rltog;
292: } else {
293: ISL2GComposeBlock(iscol,A->cmap->mapping,&cltog);
294: }
295: MatSetLocalToGlobalMapping(B,rltog,cltog);
296: ISLocalToGlobalMappingDestroy(&rltog);
297: ISLocalToGlobalMappingDestroy(&cltog);
298: }
299: }
300: *newmat = B;
301: return(0);
302: }