xref: /petsc/src/mat/impls/localref/mlocalref.c (revision ce94432eddcd14845bc7e8083b7f8ea723b9bf7d)
12c0dbf93SJed Brown 
2b45d2f2cSJed Brown #include <petsc-private/matimpl.h>          /*I "petscmat.h" I*/
3afcb2eb5SJed Brown #include <petsc-private/isimpl.h>
42c0dbf93SJed Brown 
52c0dbf93SJed Brown typedef struct {
62c0dbf93SJed Brown   Mat Top;
72c0dbf93SJed Brown   PetscErrorCode (*SetValues)(Mat,PetscInt,const PetscInt[],PetscInt,const PetscInt[],const PetscScalar[],InsertMode);
82c0dbf93SJed Brown   PetscErrorCode (*SetValuesBlocked)(Mat,PetscInt,const PetscInt[],PetscInt,const PetscInt[],const PetscScalar[],InsertMode);
92c0dbf93SJed Brown } Mat_LocalRef;
102c0dbf93SJed Brown 
112c0dbf93SJed Brown /* These need to be macros because they use sizeof */
122c0dbf93SJed Brown #define IndexSpaceGet(buf,nrow,ncol,irowm,icolm) do {                   \
13a52dc253SJed Brown     if (nrow + ncol > (PetscInt)(sizeof(buf)/sizeof(buf[0]))) {         \
142c0dbf93SJed Brown       ierr = PetscMalloc2(nrow,PetscInt,&irowm,ncol,PetscInt,&icolm);CHKERRQ(ierr); \
152c0dbf93SJed Brown     } else {                                                            \
162c0dbf93SJed Brown       irowm = &buf[0];                                                  \
172c0dbf93SJed Brown       icolm = &buf[nrow];                                               \
182c0dbf93SJed Brown     }                                                                   \
192c0dbf93SJed Brown } while (0)
202c0dbf93SJed Brown 
212c0dbf93SJed Brown #define IndexSpaceRestore(buf,nrow,ncol,irowm,icolm) do {       \
22a52dc253SJed Brown     if (nrow + ncol > (PetscInt)(sizeof(buf)/sizeof(buf[0]))) { \
232c0dbf93SJed Brown       ierr = PetscFree2(irowm,icolm);CHKERRQ(ierr);             \
242c0dbf93SJed Brown     }                                                           \
252c0dbf93SJed Brown } while (0)
262c0dbf93SJed Brown 
272c0dbf93SJed Brown static void BlockIndicesExpand(PetscInt n,const PetscInt idx[],PetscInt bs,PetscInt idxm[])
282c0dbf93SJed Brown {
292c0dbf93SJed Brown   PetscInt i,j;
302c0dbf93SJed Brown   for (i=0; i<n; i++) {
312c0dbf93SJed Brown     for (j=0; j<bs; j++) {
322c0dbf93SJed Brown       idxm[i*bs+j] = idx[i]*bs + j;
332c0dbf93SJed Brown     }
342c0dbf93SJed Brown   }
352c0dbf93SJed Brown }
362c0dbf93SJed Brown 
372c0dbf93SJed Brown #undef __FUNCT__
382c0dbf93SJed Brown #define __FUNCT__ "MatSetValuesBlockedLocal_LocalRef_Block"
392c0dbf93SJed Brown static PetscErrorCode MatSetValuesBlockedLocal_LocalRef_Block(Mat A,PetscInt nrow,const PetscInt irow[],PetscInt ncol,const PetscInt icol[],const PetscScalar y[],InsertMode addv)
402c0dbf93SJed Brown {
412c0dbf93SJed Brown   Mat_LocalRef   *lr = (Mat_LocalRef*)A->data;
422c0dbf93SJed Brown   PetscErrorCode ierr;
432c0dbf93SJed Brown   PetscInt       buf[4096],*irowm,*icolm;
442c0dbf93SJed Brown 
452c0dbf93SJed Brown   PetscFunctionBegin;
462c0dbf93SJed Brown   if (!nrow || !ncol) PetscFunctionReturn(0);
472c0dbf93SJed Brown   IndexSpaceGet(buf,nrow,ncol,irowm,icolm);
48992144d0SBarry Smith   ierr = ISLocalToGlobalMappingApply(A->rmap->bmapping,nrow,irow,irowm);CHKERRQ(ierr);
49992144d0SBarry Smith   ierr = ISLocalToGlobalMappingApply(A->cmap->bmapping,ncol,icol,icolm);CHKERRQ(ierr);
502c0dbf93SJed Brown   ierr = (*lr->SetValuesBlocked)(lr->Top,nrow,irowm,ncol,icolm,y,addv);CHKERRQ(ierr);
512c0dbf93SJed Brown   IndexSpaceRestore(buf,nrow,ncol,irowm,icolm);
522c0dbf93SJed Brown   PetscFunctionReturn(0);
532c0dbf93SJed Brown }
542c0dbf93SJed Brown 
552c0dbf93SJed Brown #undef __FUNCT__
562c0dbf93SJed Brown #define __FUNCT__ "MatSetValuesBlockedLocal_LocalRef_Scalar"
572c0dbf93SJed Brown static PetscErrorCode MatSetValuesBlockedLocal_LocalRef_Scalar(Mat A,PetscInt nrow,const PetscInt irow[],PetscInt ncol,const PetscInt icol[],const PetscScalar y[],InsertMode addv)
582c0dbf93SJed Brown {
592c0dbf93SJed Brown   Mat_LocalRef   *lr = (Mat_LocalRef*)A->data;
602c0dbf93SJed Brown   PetscErrorCode ierr;
612c0dbf93SJed Brown   PetscInt       bs = A->rmap->bs,buf[4096],*irowm,*icolm;
622c0dbf93SJed Brown 
632c0dbf93SJed Brown   PetscFunctionBegin;
642c0dbf93SJed Brown   IndexSpaceGet(buf,nrow*bs,ncol*bs,irowm,icolm);
652c0dbf93SJed Brown   BlockIndicesExpand(nrow,irow,bs,irowm);
662c0dbf93SJed Brown   BlockIndicesExpand(ncol,icol,bs,icolm);
67992144d0SBarry Smith   ierr = ISLocalToGlobalMappingApply(A->rmap->mapping,nrow*bs,irowm,irowm);CHKERRQ(ierr);
68992144d0SBarry Smith   ierr = ISLocalToGlobalMappingApply(A->cmap->mapping,ncol*bs,icolm,icolm);CHKERRQ(ierr);
692c0dbf93SJed Brown   ierr = (*lr->SetValues)(lr->Top,nrow*bs,irowm,ncol*bs,icolm,y,addv);CHKERRQ(ierr);
702c0dbf93SJed Brown   IndexSpaceRestore(buf,nrow*bs,ncol*bs,irowm,icolm);
712c0dbf93SJed Brown   PetscFunctionReturn(0);
722c0dbf93SJed Brown }
732c0dbf93SJed Brown 
742c0dbf93SJed Brown #undef __FUNCT__
752c0dbf93SJed Brown #define __FUNCT__ "MatSetValuesLocal_LocalRef_Scalar"
762c0dbf93SJed Brown static PetscErrorCode MatSetValuesLocal_LocalRef_Scalar(Mat A,PetscInt nrow,const PetscInt irow[],PetscInt ncol,const PetscInt icol[],const PetscScalar y[],InsertMode addv)
772c0dbf93SJed Brown {
782c0dbf93SJed Brown   Mat_LocalRef   *lr = (Mat_LocalRef*)A->data;
792c0dbf93SJed Brown   PetscErrorCode ierr;
802c0dbf93SJed Brown   PetscInt       buf[4096],*irowm,*icolm;
812c0dbf93SJed Brown 
822c0dbf93SJed Brown   PetscFunctionBegin;
832c0dbf93SJed Brown   IndexSpaceGet(buf,nrow,ncol,irowm,icolm);
84992144d0SBarry Smith   ierr = ISLocalToGlobalMappingApply(A->rmap->mapping,nrow,irow,irowm);CHKERRQ(ierr);
85992144d0SBarry Smith   ierr = ISLocalToGlobalMappingApply(A->cmap->mapping,ncol,icol,icolm);CHKERRQ(ierr);
862c0dbf93SJed Brown   ierr = (*lr->SetValues)(lr->Top,nrow,irowm,ncol,icolm,y,addv);CHKERRQ(ierr);
872c0dbf93SJed Brown   IndexSpaceRestore(buf,nrow,ncol,irowm,icolm);
882c0dbf93SJed Brown   PetscFunctionReturn(0);
892c0dbf93SJed Brown }
902c0dbf93SJed Brown 
912c0dbf93SJed Brown #undef __FUNCT__
922c0dbf93SJed Brown #define __FUNCT__ "ISL2GCompose"
932265a299SJed Brown /* Compose an IS with an ISLocalToGlobalMapping to map from IS source indices to global indices */
942c0dbf93SJed Brown static PetscErrorCode ISL2GCompose(IS is,ISLocalToGlobalMapping ltog,ISLocalToGlobalMapping *cltog)
952c0dbf93SJed Brown {
962c0dbf93SJed Brown   PetscErrorCode ierr;
972c0dbf93SJed Brown   const PetscInt *idx;
982c0dbf93SJed Brown   PetscInt       m,*idxm;
992c0dbf93SJed Brown 
1002c0dbf93SJed Brown   PetscFunctionBegin;
101b3e8af9fSJed Brown   PetscValidHeaderSpecific(is,IS_CLASSID,1);
102b3e8af9fSJed Brown   PetscValidHeaderSpecific(ltog,IS_LTOGM_CLASSID,2);
103b3e8af9fSJed Brown   PetscValidPointer(cltog,3);
1042c0dbf93SJed Brown   ierr = ISGetLocalSize(is,&m);CHKERRQ(ierr);
1052c0dbf93SJed Brown   ierr = ISGetIndices(is,&idx);CHKERRQ(ierr);
1062c0dbf93SJed Brown #if defined(PETSC_USE_DEBUG)
1072c0dbf93SJed Brown   {
1082c0dbf93SJed Brown     PetscInt i;
1092c0dbf93SJed Brown     for (i=0; i<m; i++) {
1102c0dbf93SJed Brown       if (idx[i] < 0 || ltog->n <= idx[i]) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"is[%D] = %D is not in the local range [0:%D]",i,idx[i],ltog->n);
1112c0dbf93SJed Brown     }
1122c0dbf93SJed Brown   }
1132c0dbf93SJed Brown #endif
1142c0dbf93SJed Brown   ierr = PetscMalloc(m*sizeof(PetscInt),&idxm);CHKERRQ(ierr);
1152c0dbf93SJed Brown   if (ltog) {
1162c0dbf93SJed Brown     ierr = ISLocalToGlobalMappingApply(ltog,m,idx,idxm);CHKERRQ(ierr);
1172c0dbf93SJed Brown   } else {
1182c0dbf93SJed Brown     ierr = PetscMemcpy(idxm,idx,m*sizeof(PetscInt));CHKERRQ(ierr);
1192c0dbf93SJed Brown   }
120*ce94432eSBarry Smith   ierr = ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)is),m,idxm,PETSC_OWN_POINTER,cltog);CHKERRQ(ierr);
1212c0dbf93SJed Brown   ierr = ISRestoreIndices(is,&idx);CHKERRQ(ierr);
1222c0dbf93SJed Brown   PetscFunctionReturn(0);
1232c0dbf93SJed Brown }
1242c0dbf93SJed Brown 
1252c0dbf93SJed Brown #undef __FUNCT__
1262c0dbf93SJed Brown #define __FUNCT__ "ISL2GComposeBlock"
1272c0dbf93SJed Brown static PetscErrorCode ISL2GComposeBlock(IS is,ISLocalToGlobalMapping ltog,ISLocalToGlobalMapping *cltog)
1282c0dbf93SJed Brown {
1292c0dbf93SJed Brown   PetscErrorCode ierr;
1302c0dbf93SJed Brown   const PetscInt *idx;
1312c0dbf93SJed Brown   PetscInt       m,*idxm;
1322c0dbf93SJed Brown 
1332c0dbf93SJed Brown   PetscFunctionBegin;
134b3e8af9fSJed Brown   PetscValidHeaderSpecific(is,IS_CLASSID,1);
135b3e8af9fSJed Brown   PetscValidHeaderSpecific(ltog,IS_LTOGM_CLASSID,2);
136b3e8af9fSJed Brown   PetscValidPointer(cltog,3);
1372c0dbf93SJed Brown   ierr = ISBlockGetLocalSize(is,&m);CHKERRQ(ierr);
1382c0dbf93SJed Brown   ierr = ISBlockGetIndices(is,&idx);CHKERRQ(ierr);
1392c0dbf93SJed Brown #if defined(PETSC_USE_DEBUG)
1402c0dbf93SJed Brown   {
1412c0dbf93SJed Brown     PetscInt i;
1422c0dbf93SJed Brown     for (i=0; i<m; i++) {
1432c0dbf93SJed Brown       if (idx[i] < 0 || ltog->n <= idx[i]) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"is[%D] = %D is not in the local range [0:%D]",i,idx[i],ltog->n);
1442c0dbf93SJed Brown     }
1452c0dbf93SJed Brown   }
1462c0dbf93SJed Brown #endif
1472c0dbf93SJed Brown   ierr = PetscMalloc(m*sizeof(PetscInt),&idxm);CHKERRQ(ierr);
1482c0dbf93SJed Brown   if (ltog) {
1492c0dbf93SJed Brown     ierr = ISLocalToGlobalMappingApply(ltog,m,idx,idxm);CHKERRQ(ierr);
1502c0dbf93SJed Brown   } else {
1512c0dbf93SJed Brown     ierr = PetscMemcpy(idxm,idx,m*sizeof(PetscInt));CHKERRQ(ierr);
1522c0dbf93SJed Brown   }
153*ce94432eSBarry Smith   ierr = ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)is),m,idxm,PETSC_OWN_POINTER,cltog);CHKERRQ(ierr);
1542c0dbf93SJed Brown   ierr = ISBlockRestoreIndices(is,&idx);CHKERRQ(ierr);
1552c0dbf93SJed Brown   PetscFunctionReturn(0);
1562c0dbf93SJed Brown }
1572c0dbf93SJed Brown 
1582c0dbf93SJed Brown #undef __FUNCT__
1592c0dbf93SJed Brown #define __FUNCT__ "MatDestroy_LocalRef"
1602c0dbf93SJed Brown static PetscErrorCode MatDestroy_LocalRef(Mat B)
1612c0dbf93SJed Brown {
1622c0dbf93SJed Brown   PetscErrorCode ierr;
1632c0dbf93SJed Brown 
1642c0dbf93SJed Brown   PetscFunctionBegin;
1652c0dbf93SJed Brown   ierr = PetscFree(B->data);CHKERRQ(ierr);
1662c0dbf93SJed Brown   PetscFunctionReturn(0);
1672c0dbf93SJed Brown }
1682c0dbf93SJed Brown 
1692c0dbf93SJed Brown 
1702c0dbf93SJed Brown #undef __FUNCT__
1712c0dbf93SJed Brown #define __FUNCT__ "MatCreateLocalRef"
1722c0dbf93SJed Brown /*@
1732c0dbf93SJed Brown    MatCreateLocalRef - Gets a logical reference to a local submatrix, for use in assembly
1742c0dbf93SJed Brown 
1752c0dbf93SJed Brown    Not Collective
1762c0dbf93SJed Brown 
1772c0dbf93SJed Brown    Input Arguments:
1782c0dbf93SJed Brown + A - Full matrix, generally parallel
1792c0dbf93SJed Brown . isrow - Local index set for the rows
1802c0dbf93SJed Brown - iscol - Local index set for the columns
1812c0dbf93SJed Brown 
1822c0dbf93SJed Brown    Output Arguments:
1832c0dbf93SJed Brown . newmat - New serial Mat
1842c0dbf93SJed Brown 
1852c0dbf93SJed Brown    Level: developer
1862c0dbf93SJed Brown 
1872c0dbf93SJed Brown    Notes:
1882c0dbf93SJed Brown    Most will use MatGetLocalSubMatrix() which returns a real matrix corresponding to the local
1892c0dbf93SJed Brown    block if it available, such as with matrix formats that store these blocks separately.
1902c0dbf93SJed Brown 
1912c0dbf93SJed Brown    The new matrix forwards MatSetValuesLocal() and MatSetValuesBlockedLocal() to the global system.
1922c0dbf93SJed Brown    In general, it does not define MatMult() or any other functions.  Local submatrices can be nested.
1932c0dbf93SJed Brown 
1942c0dbf93SJed Brown .seealso: MatSetValuesLocal(), MatSetValuesBlockedLocal(), MatGetLocalSubMatrix(), MatCreateSubMatrix()
1952c0dbf93SJed Brown @*/
1967087cfbeSBarry Smith PetscErrorCode  MatCreateLocalRef(Mat A,IS isrow,IS iscol,Mat *newmat)
1972c0dbf93SJed Brown {
1982c0dbf93SJed Brown   PetscErrorCode ierr;
1992c0dbf93SJed Brown   Mat_LocalRef   *lr;
2002c0dbf93SJed Brown   Mat            B;
2012c0dbf93SJed Brown   PetscInt       m,n;
2022c0dbf93SJed Brown   PetscBool      islr;
2032c0dbf93SJed Brown 
2042c0dbf93SJed Brown   PetscFunctionBegin;
2052c0dbf93SJed Brown   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
2062c0dbf93SJed Brown   PetscValidHeaderSpecific(isrow,IS_CLASSID,2);
2072c0dbf93SJed Brown   PetscValidHeaderSpecific(iscol,IS_CLASSID,3);
2082c0dbf93SJed Brown   PetscValidPointer(newmat,4);
2092c0dbf93SJed Brown   *newmat = 0;
2102c0dbf93SJed Brown 
2112c0dbf93SJed Brown   ierr = MatCreate(PETSC_COMM_SELF,&B);CHKERRQ(ierr);
2122c0dbf93SJed Brown   ierr = ISGetLocalSize(isrow,&m);CHKERRQ(ierr);
2132c0dbf93SJed Brown   ierr = ISGetLocalSize(iscol,&n);CHKERRQ(ierr);
2142c0dbf93SJed Brown   ierr = MatSetSizes(B,m,n,m,n);CHKERRQ(ierr);
2152c0dbf93SJed Brown   ierr = PetscObjectChangeTypeName((PetscObject)B,MATLOCALREF);CHKERRQ(ierr);
216be7c243fSJed Brown   ierr = MatSetUp(B);CHKERRQ(ierr);
2172c0dbf93SJed Brown 
2182c0dbf93SJed Brown   B->ops->destroy = MatDestroy_LocalRef;
2192c0dbf93SJed Brown 
2202c0dbf93SJed Brown   ierr    = PetscNewLog(B,Mat_LocalRef,&lr);CHKERRQ(ierr);
2212c0dbf93SJed Brown   B->data = (void*)lr;
2222c0dbf93SJed Brown 
223251f4c67SDmitry Karpeev   ierr = PetscObjectTypeCompare((PetscObject)A,MATLOCALREF,&islr);CHKERRQ(ierr);
2242265a299SJed Brown   if (islr) {
2252265a299SJed Brown     Mat_LocalRef *alr = (Mat_LocalRef*)A->data;
2262265a299SJed Brown     lr->Top = alr->Top;
2272265a299SJed Brown   } else {
2282265a299SJed Brown     /* This does not increase the reference count because MatLocalRef is not allowed to live longer than its parent */
2292265a299SJed Brown     lr->Top = A;
2302265a299SJed Brown   }
2312265a299SJed Brown   {
2322c0dbf93SJed Brown     ISLocalToGlobalMapping rltog,cltog;
2332c0dbf93SJed Brown     PetscInt               abs,rbs,cbs;
2342c0dbf93SJed Brown 
2352265a299SJed Brown     /* We will translate directly to global indices for the top level */
2362c0dbf93SJed Brown     lr->SetValues        = MatSetValues;
2372c0dbf93SJed Brown     lr->SetValuesBlocked = MatSetValuesBlocked;
2382c0dbf93SJed Brown 
2392c0dbf93SJed Brown     B->ops->setvalueslocal = MatSetValuesLocal_LocalRef_Scalar;
2402205254eSKarl Rupp 
241992144d0SBarry Smith     ierr = ISL2GCompose(isrow,A->rmap->mapping,&rltog);CHKERRQ(ierr);
242992144d0SBarry Smith     if (isrow == iscol && A->rmap->mapping == A->cmap->mapping) {
2432c0dbf93SJed Brown       ierr  = PetscObjectReference((PetscObject)rltog);CHKERRQ(ierr);
2442c0dbf93SJed Brown       cltog = rltog;
2452c0dbf93SJed Brown     } else {
246992144d0SBarry Smith       ierr = ISL2GCompose(iscol,A->cmap->mapping,&cltog);CHKERRQ(ierr);
2472c0dbf93SJed Brown     }
2482c0dbf93SJed Brown     ierr = MatSetLocalToGlobalMapping(B,rltog,cltog);CHKERRQ(ierr);
2496bf464f9SBarry Smith     ierr = ISLocalToGlobalMappingDestroy(&rltog);CHKERRQ(ierr);
2506bf464f9SBarry Smith     ierr = ISLocalToGlobalMappingDestroy(&cltog);CHKERRQ(ierr);
2512c0dbf93SJed Brown 
2522c0dbf93SJed Brown     ierr = MatGetBlockSize(A,&abs);CHKERRQ(ierr);
253520db06cSJed Brown     ierr = ISGetBlockSize(isrow,&rbs);CHKERRQ(ierr);
254520db06cSJed Brown     ierr = ISGetBlockSize(iscol,&cbs);CHKERRQ(ierr);
2552c0dbf93SJed Brown     if (rbs == cbs) {           /* submatrix has block structure, so user can insert values with blocked interface */
25692ea8381SJed Brown       ierr = PetscLayoutSetBlockSize(B->rmap,rbs);CHKERRQ(ierr);
25792ea8381SJed Brown       ierr = PetscLayoutSetBlockSize(B->cmap,cbs);CHKERRQ(ierr);
25892ea8381SJed Brown       if (abs != rbs || abs == 1) {
2592c0dbf93SJed Brown         /* Top-level matrix has different block size, so we have to call its scalar insertion interface */
2602c0dbf93SJed Brown         B->ops->setvaluesblockedlocal = MatSetValuesBlockedLocal_LocalRef_Scalar;
2612c0dbf93SJed Brown       } else {
2622c0dbf93SJed Brown         /* Block sizes match so we can forward values to the top level using the block interface */
2632c0dbf93SJed Brown         B->ops->setvaluesblockedlocal = MatSetValuesBlockedLocal_LocalRef_Block;
26426fbe8dcSKarl Rupp 
265992144d0SBarry Smith         ierr = ISL2GComposeBlock(isrow,A->rmap->bmapping,&rltog);CHKERRQ(ierr);
266992144d0SBarry Smith         if (isrow == iscol && A->rmap->bmapping == A->cmap->bmapping) {
2672c0dbf93SJed Brown           ierr  =  PetscObjectReference((PetscObject)rltog);CHKERRQ(ierr);
2682c0dbf93SJed Brown           cltog = rltog;
2692c0dbf93SJed Brown         } else {
270992144d0SBarry Smith           ierr = ISL2GComposeBlock(iscol,A->cmap->bmapping,&cltog);CHKERRQ(ierr);
2712c0dbf93SJed Brown         }
2722c0dbf93SJed Brown         ierr = MatSetLocalToGlobalMappingBlock(B,rltog,cltog);CHKERRQ(ierr);
2736bf464f9SBarry Smith         ierr = ISLocalToGlobalMappingDestroy(&rltog);CHKERRQ(ierr);
2746bf464f9SBarry Smith         ierr = ISLocalToGlobalMappingDestroy(&cltog);CHKERRQ(ierr);
2752c0dbf93SJed Brown       }
2762c0dbf93SJed Brown     }
2772c0dbf93SJed Brown   }
2782c0dbf93SJed Brown   *newmat = B;
2792c0dbf93SJed Brown   PetscFunctionReturn(0);
2802c0dbf93SJed Brown }
281