#include /*I "petscmat.h" I*/ PetscErrorCode MatConvert_Shell(Mat oldmat,MatType newtype,MatReuse reuse,Mat *newmat) { Mat mat; Vec in,out; PetscScalar *array; PetscInt *dnnz,*onnz,*dnnzu,*onnzu; PetscInt cst,Nbs,mbs,nbs,rbs,cbs; PetscInt im,i,m,n,M,N,*rows,start; PetscFunctionBegin; PetscCall(MatGetOwnershipRange(oldmat,&start,NULL)); PetscCall(MatGetOwnershipRangeColumn(oldmat,&cst,NULL)); PetscCall(MatCreateVecs(oldmat,&in,&out)); PetscCall(MatGetLocalSize(oldmat,&m,&n)); PetscCall(MatGetSize(oldmat,&M,&N)); PetscCall(PetscMalloc1(m,&rows)); if (reuse != MAT_REUSE_MATRIX) { PetscCall(MatCreate(PetscObjectComm((PetscObject)oldmat),&mat)); PetscCall(MatSetSizes(mat,m,n,M,N)); PetscCall(MatSetType(mat,newtype)); PetscCall(MatSetBlockSizesFromMats(mat,oldmat,oldmat)); PetscCall(MatGetBlockSizes(mat,&rbs,&cbs)); mbs = m/rbs; nbs = n/cbs; Nbs = N/cbs; cst = cst/cbs; PetscCall(PetscMalloc4(mbs,&dnnz,mbs,&onnz,mbs,&dnnzu,mbs,&onnzu)); for (i=0; iuserdestroy) { PetscCall((*mmcfdata->userdestroy)(mmcfdata->userdata)); } PetscCall(MatDestroy(&mmcfdata->Dwork)); PetscCall(PetscFree(mmcfdata)); PetscFunctionReturn(0); } static PetscErrorCode MatProductNumericPhase_CF(Mat A, Mat B, Mat C, void *data) { MatMatCF *mmcfdata = (MatMatCF*)data; PetscFunctionBegin; PetscCheck(mmcfdata,PetscObjectComm((PetscObject)C),PETSC_ERR_PLIB,"Missing data"); PetscCheck(mmcfdata->numeric,PetscObjectComm((PetscObject)C),PETSC_ERR_PLIB,"Missing numeric operation"); /* the MATSHELL interface allows us to play with the product data */ PetscCall(PetscNew(&C->product)); C->product->type = mmcfdata->ptype; C->product->data = mmcfdata->userdata; C->product->Dwork = mmcfdata->Dwork; PetscCall(MatShellGetContext(A,&C->product->A)); C->product->B = B; PetscCall((*mmcfdata->numeric)(C)); PetscCall(PetscFree(C->product)); PetscFunctionReturn(0); } static PetscErrorCode MatProductSymbolicPhase_CF(Mat A, Mat B, Mat C, void **data) { MatMatCF *mmcfdata; PetscFunctionBegin; PetscCall(MatShellGetContext(A,&C->product->A)); PetscCall(MatProductSetFromOptions(C)); PetscCall(MatProductSymbolic(C)); /* the MATSHELL interface does not allow non-empty product data */ PetscCall(PetscNew(&mmcfdata)); mmcfdata->numeric = C->ops->productnumeric; mmcfdata->ptype = C->product->type; mmcfdata->userdata = C->product->data; mmcfdata->userdestroy = C->product->destroy; mmcfdata->Dwork = C->product->Dwork; C->product->Dwork = NULL; C->product->data = NULL; C->product->destroy = NULL; C->product->A = A; *data = mmcfdata; PetscFunctionReturn(0); } /* only for A of type shell, mainly used for MatMat operations of shells with AXPYs */ static PetscErrorCode MatProductSetFromOptions_CF(Mat D) { Mat A,B,Ain; void (*Af)(void) = NULL; PetscBool flg; PetscFunctionBegin; MatCheckProduct(D,1); if (D->product->type == MATPRODUCT_ABC) PetscFunctionReturn(0); A = D->product->A; B = D->product->B; PetscCall(MatIsShell(A,&flg)); if (!flg) PetscFunctionReturn(0); PetscCall(PetscObjectQueryFunction((PetscObject)A,"MatProductSetFromOptions_anytype_C",&Af)); if (Af == (void(*)(void))MatProductSetFromOptions_CF) { PetscCall(MatShellGetContext(A,&Ain)); } else PetscFunctionReturn(0); D->product->A = Ain; PetscCall(MatProductSetFromOptions(D)); D->product->A = A; if (D->ops->productsymbolic) { /* we have a symbolic match, now populate the MATSHELL operations */ PetscCall(MatShellSetMatProductOperation(A,D->product->type,MatProductSymbolicPhase_CF,MatProductNumericPhase_CF,MatProductDestroy_CF,((PetscObject)B)->type_name,NULL)); PetscCall(MatProductSetFromOptions(D)); } PetscFunctionReturn(0); } PetscErrorCode MatConvertFrom_Shell(Mat A,MatType newtype,MatReuse reuse,Mat *B) { Mat M; PetscBool flg; PetscFunctionBegin; PetscCall(PetscStrcmp(newtype,MATSHELL,&flg)); PetscCheck(flg,PETSC_COMM_SELF,PETSC_ERR_SUP,"Only conversion to MATSHELL"); if (reuse == MAT_INITIAL_MATRIX) { PetscCall(PetscObjectReference((PetscObject)A)); PetscCall(MatCreateShell(PetscObjectComm((PetscObject)A),A->rmap->n,A->cmap->n,A->rmap->N,A->cmap->N,A,&M)); PetscCall(MatSetBlockSizesFromMats(M,A,A)); PetscCall(MatShellSetOperation(M,MATOP_MULT, (void (*)(void))MatMult_CF)); PetscCall(MatShellSetOperation(M,MATOP_MULT_TRANSPOSE,(void (*)(void))MatMultTranspose_CF)); PetscCall(MatShellSetOperation(M,MATOP_GET_DIAGONAL, (void (*)(void))MatGetDiagonal_CF)); PetscCall(MatShellSetOperation(M,MATOP_DESTROY, (void (*)(void))MatDestroy_CF)); PetscCall(PetscObjectComposeFunction((PetscObject)M,"MatProductSetFromOptions_anytype_C",MatProductSetFromOptions_CF)); PetscCall(PetscFree(M->defaultvectype)); PetscCall(PetscStrallocpy(A->defaultvectype,&M->defaultvectype)); #if defined(PETSC_HAVE_DEVICE) PetscCall(MatBindToCPU(M,A->boundtocpu)); #endif *B = M; } else SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"Not implemented"); PetscFunctionReturn(0); }