1 /* 2 Creates a matrix class for using the Neumann-Neumann type preconditioners. 3 This stores the matrices in globally unassembled form. Each processor 4 assembles only its local Neumann problem and the parallel matrix vector 5 product is handled "implicitly". 6 7 Currently this allows for only one subdomain per processor. 8 */ 9 10 #include <petsc/private/matisimpl.h> /*I "petscmat.h" I*/ 11 #include <petsc/private/sfimpl.h> 12 #include <petsc/private/vecimpl.h> 13 #include <petsc/private/hashseti.h> 14 15 #define MATIS_MAX_ENTRIES_INSERTION 2048 16 static PetscErrorCode MatSetValuesLocal_IS(Mat,PetscInt,const PetscInt*,PetscInt,const PetscInt*,const PetscScalar*,InsertMode); 17 static PetscErrorCode MatSetValuesBlockedLocal_IS(Mat,PetscInt,const PetscInt*,PetscInt,const PetscInt*,const PetscScalar*,InsertMode); 18 static PetscErrorCode MatISSetUpScatters_Private(Mat); 19 20 static PetscErrorCode MatISContainerDestroyPtAP_Private(void *ptr) 21 { 22 MatISPtAP ptap = (MatISPtAP)ptr; 23 24 PetscFunctionBegin; 25 PetscCall(MatDestroySubMatrices(ptap->ris1 ? 2 : 1,&ptap->lP)); 26 PetscCall(ISDestroy(&ptap->cis0)); 27 PetscCall(ISDestroy(&ptap->cis1)); 28 PetscCall(ISDestroy(&ptap->ris0)); 29 PetscCall(ISDestroy(&ptap->ris1)); 30 PetscCall(PetscFree(ptap)); 31 PetscFunctionReturn(0); 32 } 33 34 static PetscErrorCode MatPtAPNumeric_IS_XAIJ(Mat A, Mat P, Mat C) 35 { 36 MatISPtAP ptap; 37 Mat_IS *matis = (Mat_IS*)A->data; 38 Mat lA,lC; 39 MatReuse reuse; 40 IS ris[2],cis[2]; 41 PetscContainer c; 42 PetscInt n; 43 44 PetscFunctionBegin; 45 PetscCall(PetscObjectQuery((PetscObject)C,"_MatIS_PtAP",(PetscObject*)&c)); 46 PetscCheck(c,PetscObjectComm((PetscObject)C),PETSC_ERR_PLIB,"Missing PtAP information"); 47 PetscCall(PetscContainerGetPointer(c,(void**)&ptap)); 48 ris[0] = ptap->ris0; 49 ris[1] = ptap->ris1; 50 cis[0] = ptap->cis0; 51 cis[1] = ptap->cis1; 52 n = ptap->ris1 ? 2 : 1; 53 reuse = ptap->lP ? MAT_REUSE_MATRIX : MAT_INITIAL_MATRIX; 54 PetscCall(MatCreateSubMatrices(P,n,ris,cis,reuse,&ptap->lP)); 55 56 PetscCall(MatISGetLocalMat(A,&lA)); 57 PetscCall(MatISGetLocalMat(C,&lC)); 58 if (ptap->ris1) { /* unsymmetric A mapping */ 59 Mat lPt; 60 61 PetscCall(MatTranspose(ptap->lP[1],MAT_INITIAL_MATRIX,&lPt)); 62 PetscCall(MatMatMatMult(lPt,lA,ptap->lP[0],reuse,ptap->fill,&lC)); 63 if (matis->storel2l) { 64 PetscCall(PetscObjectCompose((PetscObject)(A),"_MatIS_PtAP_l2l",(PetscObject)lPt)); 65 } 66 PetscCall(MatDestroy(&lPt)); 67 } else { 68 PetscCall(MatPtAP(lA,ptap->lP[0],reuse,ptap->fill,&lC)); 69 if (matis->storel2l) { 70 PetscCall(PetscObjectCompose((PetscObject)C,"_MatIS_PtAP_l2l",(PetscObject)ptap->lP[0])); 71 } 72 } 73 if (reuse == MAT_INITIAL_MATRIX) { 74 PetscCall(MatISSetLocalMat(C,lC)); 75 PetscCall(MatDestroy(&lC)); 76 } 77 PetscCall(MatAssemblyBegin(C,MAT_FINAL_ASSEMBLY)); 78 PetscCall(MatAssemblyEnd(C,MAT_FINAL_ASSEMBLY)); 79 PetscFunctionReturn(0); 80 } 81 82 static PetscErrorCode MatGetNonzeroColumnsLocal_Private(Mat PT,IS *cis) 83 { 84 Mat Po,Pd; 85 IS zd,zo; 86 const PetscInt *garray; 87 PetscInt *aux,i,bs; 88 PetscInt dc,stc,oc,ctd,cto; 89 PetscBool ismpiaij,ismpibaij,isseqaij,isseqbaij; 90 MPI_Comm comm; 91 92 PetscFunctionBegin; 93 PetscValidHeaderSpecific(PT,MAT_CLASSID,1); 94 PetscValidPointer(cis,2); 95 PetscCall(PetscObjectGetComm((PetscObject)PT,&comm)); 96 bs = 1; 97 PetscCall(PetscObjectBaseTypeCompare((PetscObject)PT,MATMPIAIJ,&ismpiaij)); 98 PetscCall(PetscObjectBaseTypeCompare((PetscObject)PT,MATMPIBAIJ,&ismpibaij)); 99 PetscCall(PetscObjectBaseTypeCompare((PetscObject)PT,MATSEQAIJ,&isseqaij)); 100 PetscCall(PetscObjectTypeCompare((PetscObject)PT,MATSEQBAIJ,&isseqbaij)); 101 if (isseqaij || isseqbaij) { 102 Pd = PT; 103 Po = NULL; 104 garray = NULL; 105 } else if (ismpiaij) { 106 PetscCall(MatMPIAIJGetSeqAIJ(PT,&Pd,&Po,&garray)); 107 } else if (ismpibaij) { 108 PetscCall(MatMPIBAIJGetSeqBAIJ(PT,&Pd,&Po,&garray)); 109 PetscCall(MatGetBlockSize(PT,&bs)); 110 } else SETERRQ(comm,PETSC_ERR_SUP,"Not for matrix type %s",((PetscObject)(PT))->type_name); 111 112 /* identify any null columns in Pd or Po */ 113 /* We use a tolerance comparison since it may happen that, with geometric multigrid, 114 some of the columns are not really zero, but very close to */ 115 zo = zd = NULL; 116 if (Po) { 117 PetscCall(MatFindNonzeroRowsOrCols_Basic(Po,PETSC_TRUE,PETSC_SMALL,&zo)); 118 } 119 PetscCall(MatFindNonzeroRowsOrCols_Basic(Pd,PETSC_TRUE,PETSC_SMALL,&zd)); 120 121 PetscCall(MatGetLocalSize(PT,NULL,&dc)); 122 PetscCall(MatGetOwnershipRangeColumn(PT,&stc,NULL)); 123 if (Po) PetscCall(MatGetLocalSize(Po,NULL,&oc)); 124 else oc = 0; 125 PetscCall(PetscMalloc1((dc+oc)/bs,&aux)); 126 if (zd) { 127 const PetscInt *idxs; 128 PetscInt nz; 129 130 /* this will throw an error if bs is not valid */ 131 PetscCall(ISSetBlockSize(zd,bs)); 132 PetscCall(ISGetLocalSize(zd,&nz)); 133 PetscCall(ISGetIndices(zd,&idxs)); 134 ctd = nz/bs; 135 for (i=0; i<ctd; i++) aux[i] = (idxs[bs*i]+stc)/bs; 136 PetscCall(ISRestoreIndices(zd,&idxs)); 137 } else { 138 ctd = dc/bs; 139 for (i=0; i<ctd; i++) aux[i] = i+stc/bs; 140 } 141 if (zo) { 142 const PetscInt *idxs; 143 PetscInt nz; 144 145 /* this will throw an error if bs is not valid */ 146 PetscCall(ISSetBlockSize(zo,bs)); 147 PetscCall(ISGetLocalSize(zo,&nz)); 148 PetscCall(ISGetIndices(zo,&idxs)); 149 cto = nz/bs; 150 for (i=0; i<cto; i++) aux[i+ctd] = garray[idxs[bs*i]/bs]; 151 PetscCall(ISRestoreIndices(zo,&idxs)); 152 } else { 153 cto = oc/bs; 154 for (i=0; i<cto; i++) aux[i+ctd] = garray[i]; 155 } 156 PetscCall(ISCreateBlock(comm,bs,ctd+cto,aux,PETSC_OWN_POINTER,cis)); 157 PetscCall(ISDestroy(&zd)); 158 PetscCall(ISDestroy(&zo)); 159 PetscFunctionReturn(0); 160 } 161 162 static PetscErrorCode MatPtAPSymbolic_IS_XAIJ(Mat A,Mat P,PetscReal fill,Mat C) 163 { 164 Mat PT,lA; 165 MatISPtAP ptap; 166 ISLocalToGlobalMapping Crl2g,Ccl2g,rl2g,cl2g; 167 PetscContainer c; 168 MatType lmtype; 169 const PetscInt *garray; 170 PetscInt ibs,N,dc; 171 MPI_Comm comm; 172 173 PetscFunctionBegin; 174 PetscCall(PetscObjectGetComm((PetscObject)A,&comm)); 175 PetscCall(MatSetType(C,MATIS)); 176 PetscCall(MatISGetLocalMat(A,&lA)); 177 PetscCall(MatGetType(lA,&lmtype)); 178 PetscCall(MatISSetLocalMatType(C,lmtype)); 179 PetscCall(MatGetSize(P,NULL,&N)); 180 PetscCall(MatGetLocalSize(P,NULL,&dc)); 181 PetscCall(MatSetSizes(C,dc,dc,N,N)); 182 /* Not sure about this 183 PetscCall(MatGetBlockSizes(P,NULL,&ibs)); 184 PetscCall(MatSetBlockSize(*C,ibs)); 185 */ 186 187 PetscCall(PetscNew(&ptap)); 188 PetscCall(PetscContainerCreate(PETSC_COMM_SELF,&c)); 189 PetscCall(PetscContainerSetPointer(c,ptap)); 190 PetscCall(PetscContainerSetUserDestroy(c,MatISContainerDestroyPtAP_Private)); 191 PetscCall(PetscObjectCompose((PetscObject)C,"_MatIS_PtAP",(PetscObject)c)); 192 PetscCall(PetscContainerDestroy(&c)); 193 ptap->fill = fill; 194 195 PetscCall(MatISGetLocalToGlobalMapping(A,&rl2g,&cl2g)); 196 197 PetscCall(ISLocalToGlobalMappingGetBlockSize(cl2g,&ibs)); 198 PetscCall(ISLocalToGlobalMappingGetSize(cl2g,&N)); 199 PetscCall(ISLocalToGlobalMappingGetBlockIndices(cl2g,&garray)); 200 PetscCall(ISCreateBlock(comm,ibs,N/ibs,garray,PETSC_COPY_VALUES,&ptap->ris0)); 201 PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(cl2g,&garray)); 202 203 PetscCall(MatCreateSubMatrix(P,ptap->ris0,NULL,MAT_INITIAL_MATRIX,&PT)); 204 PetscCall(MatGetNonzeroColumnsLocal_Private(PT,&ptap->cis0)); 205 PetscCall(ISLocalToGlobalMappingCreateIS(ptap->cis0,&Ccl2g)); 206 PetscCall(MatDestroy(&PT)); 207 208 Crl2g = NULL; 209 if (rl2g != cl2g) { /* unsymmetric A mapping */ 210 PetscBool same,lsame = PETSC_FALSE; 211 PetscInt N1,ibs1; 212 213 PetscCall(ISLocalToGlobalMappingGetSize(rl2g,&N1)); 214 PetscCall(ISLocalToGlobalMappingGetBlockSize(rl2g,&ibs1)); 215 PetscCall(ISLocalToGlobalMappingGetBlockIndices(rl2g,&garray)); 216 PetscCall(ISCreateBlock(comm,ibs,N/ibs,garray,PETSC_COPY_VALUES,&ptap->ris1)); 217 PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(rl2g,&garray)); 218 if (ibs1 == ibs && N1 == N) { /* check if the l2gmaps are the same */ 219 const PetscInt *i1,*i2; 220 221 PetscCall(ISBlockGetIndices(ptap->ris0,&i1)); 222 PetscCall(ISBlockGetIndices(ptap->ris1,&i2)); 223 PetscCall(PetscArraycmp(i1,i2,N,&lsame)); 224 } 225 PetscCall(MPIU_Allreduce(&lsame,&same,1,MPIU_BOOL,MPI_LAND,comm)); 226 if (same) { 227 PetscCall(ISDestroy(&ptap->ris1)); 228 } else { 229 PetscCall(MatCreateSubMatrix(P,ptap->ris1,NULL,MAT_INITIAL_MATRIX,&PT)); 230 PetscCall(MatGetNonzeroColumnsLocal_Private(PT,&ptap->cis1)); 231 PetscCall(ISLocalToGlobalMappingCreateIS(ptap->cis1,&Crl2g)); 232 PetscCall(MatDestroy(&PT)); 233 } 234 } 235 /* Not sure about this 236 if (!Crl2g) { 237 PetscCall(MatGetBlockSize(C,&ibs)); 238 PetscCall(ISLocalToGlobalMappingSetBlockSize(Ccl2g,ibs)); 239 } 240 */ 241 PetscCall(MatSetLocalToGlobalMapping(C,Crl2g ? Crl2g : Ccl2g,Ccl2g)); 242 PetscCall(ISLocalToGlobalMappingDestroy(&Crl2g)); 243 PetscCall(ISLocalToGlobalMappingDestroy(&Ccl2g)); 244 245 C->ops->ptapnumeric = MatPtAPNumeric_IS_XAIJ; 246 PetscFunctionReturn(0); 247 } 248 249 /* ----------------------------------------- */ 250 static PetscErrorCode MatProductSymbolic_PtAP_IS_XAIJ(Mat C) 251 { 252 Mat_Product *product = C->product; 253 Mat A=product->A,P=product->B; 254 PetscReal fill=product->fill; 255 256 PetscFunctionBegin; 257 PetscCall(MatPtAPSymbolic_IS_XAIJ(A,P,fill,C)); 258 C->ops->productnumeric = MatProductNumeric_PtAP; 259 PetscFunctionReturn(0); 260 } 261 262 static PetscErrorCode MatProductSetFromOptions_IS_XAIJ_PtAP(Mat C) 263 { 264 PetscFunctionBegin; 265 C->ops->productsymbolic = MatProductSymbolic_PtAP_IS_XAIJ; 266 PetscFunctionReturn(0); 267 } 268 269 PETSC_INTERN PetscErrorCode MatProductSetFromOptions_IS_XAIJ(Mat C) 270 { 271 Mat_Product *product = C->product; 272 273 PetscFunctionBegin; 274 if (product->type == MATPRODUCT_PtAP) { 275 PetscCall(MatProductSetFromOptions_IS_XAIJ_PtAP(C)); 276 } 277 PetscFunctionReturn(0); 278 } 279 280 /* ----------------------------------------- */ 281 static PetscErrorCode MatISContainerDestroyFields_Private(void *ptr) 282 { 283 MatISLocalFields lf = (MatISLocalFields)ptr; 284 PetscInt i; 285 286 PetscFunctionBegin; 287 for (i=0;i<lf->nr;i++) { 288 PetscCall(ISDestroy(&lf->rf[i])); 289 } 290 for (i=0;i<lf->nc;i++) { 291 PetscCall(ISDestroy(&lf->cf[i])); 292 } 293 PetscCall(PetscFree2(lf->rf,lf->cf)); 294 PetscCall(PetscFree(lf)); 295 PetscFunctionReturn(0); 296 } 297 298 static PetscErrorCode MatConvert_SeqXAIJ_IS(Mat A,MatType type,MatReuse reuse,Mat *newmat) 299 { 300 Mat B,lB; 301 302 PetscFunctionBegin; 303 if (reuse != MAT_REUSE_MATRIX) { 304 ISLocalToGlobalMapping rl2g,cl2g; 305 PetscInt bs; 306 IS is; 307 308 PetscCall(MatGetBlockSize(A,&bs)); 309 PetscCall(ISCreateStride(PetscObjectComm((PetscObject)A),A->rmap->n/bs,0,1,&is)); 310 if (bs > 1) { 311 IS is2; 312 PetscInt i,*aux; 313 314 PetscCall(ISGetLocalSize(is,&i)); 315 PetscCall(ISGetIndices(is,(const PetscInt**)&aux)); 316 PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A),bs,i,aux,PETSC_COPY_VALUES,&is2)); 317 PetscCall(ISRestoreIndices(is,(const PetscInt**)&aux)); 318 PetscCall(ISDestroy(&is)); 319 is = is2; 320 } 321 PetscCall(ISSetIdentity(is)); 322 PetscCall(ISLocalToGlobalMappingCreateIS(is,&rl2g)); 323 PetscCall(ISDestroy(&is)); 324 PetscCall(ISCreateStride(PetscObjectComm((PetscObject)A),A->cmap->n/bs,0,1,&is)); 325 if (bs > 1) { 326 IS is2; 327 PetscInt i,*aux; 328 329 PetscCall(ISGetLocalSize(is,&i)); 330 PetscCall(ISGetIndices(is,(const PetscInt**)&aux)); 331 PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A),bs,i,aux,PETSC_COPY_VALUES,&is2)); 332 PetscCall(ISRestoreIndices(is,(const PetscInt**)&aux)); 333 PetscCall(ISDestroy(&is)); 334 is = is2; 335 } 336 PetscCall(ISSetIdentity(is)); 337 PetscCall(ISLocalToGlobalMappingCreateIS(is,&cl2g)); 338 PetscCall(ISDestroy(&is)); 339 PetscCall(MatCreateIS(PetscObjectComm((PetscObject)A),bs,A->rmap->n,A->cmap->n,A->rmap->N,A->cmap->N,rl2g,cl2g,&B)); 340 PetscCall(ISLocalToGlobalMappingDestroy(&rl2g)); 341 PetscCall(ISLocalToGlobalMappingDestroy(&cl2g)); 342 PetscCall(MatDuplicate(A,MAT_COPY_VALUES,&lB)); 343 if (reuse == MAT_INITIAL_MATRIX) *newmat = B; 344 } else { 345 B = *newmat; 346 PetscCall(PetscObjectReference((PetscObject)A)); 347 lB = A; 348 } 349 PetscCall(MatISSetLocalMat(B,lB)); 350 PetscCall(MatDestroy(&lB)); 351 PetscCall(MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY)); 352 PetscCall(MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY)); 353 if (reuse == MAT_INPLACE_MATRIX) { 354 PetscCall(MatHeaderReplace(A,&B)); 355 } 356 PetscFunctionReturn(0); 357 } 358 359 static PetscErrorCode MatISScaleDisassembling_Private(Mat A) 360 { 361 Mat_IS *matis = (Mat_IS*)(A->data); 362 PetscScalar *aa; 363 const PetscInt *ii,*jj; 364 PetscInt i,n,m; 365 PetscInt *ecount,**eneighs; 366 PetscBool flg; 367 368 PetscFunctionBegin; 369 PetscCall(MatGetRowIJ(matis->A,0,PETSC_FALSE,PETSC_FALSE,&m,&ii,&jj,&flg)); 370 PetscCheck(flg,PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot get IJ structure"); 371 PetscCall(ISLocalToGlobalMappingGetNodeInfo(matis->rmapping,&n,&ecount,&eneighs)); 372 PetscCheck(m == n,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected %" PetscInt_FMT " != %" PetscInt_FMT,m,n); 373 PetscCall(MatSeqAIJGetArray(matis->A,&aa)); 374 for (i=0;i<n;i++) { 375 if (ecount[i] > 1) { 376 PetscInt j; 377 378 for (j=ii[i];j<ii[i+1];j++) { 379 PetscInt i2 = jj[j],p,p2; 380 PetscReal scal = 0.0; 381 382 for (p=0;p<ecount[i];p++) { 383 for (p2=0;p2<ecount[i2];p2++) { 384 if (eneighs[i][p] == eneighs[i2][p2]) { scal += 1.0; break; } 385 } 386 } 387 if (scal) aa[j] /= scal; 388 } 389 } 390 } 391 PetscCall(ISLocalToGlobalMappingRestoreNodeInfo(matis->rmapping,&n,&ecount,&eneighs)); 392 PetscCall(MatSeqAIJRestoreArray(matis->A,&aa)); 393 PetscCall(MatRestoreRowIJ(matis->A,0,PETSC_FALSE,PETSC_FALSE,&m,&ii,&jj,&flg)); 394 PetscCheck(flg,PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot restore IJ structure"); 395 PetscFunctionReturn(0); 396 } 397 398 typedef enum {MAT_IS_DISASSEMBLE_L2G_NATURAL,MAT_IS_DISASSEMBLE_L2G_MAT, MAT_IS_DISASSEMBLE_L2G_ND} MatISDisassemblel2gType; 399 400 static PetscErrorCode MatMPIXAIJComputeLocalToGlobalMapping_Private(Mat A, ISLocalToGlobalMapping *l2g) 401 { 402 Mat Ad,Ao; 403 IS is,ndmap,ndsub; 404 MPI_Comm comm; 405 const PetscInt *garray,*ndmapi; 406 PetscInt bs,i,cnt,nl,*ncount,*ndmapc; 407 PetscBool ismpiaij,ismpibaij; 408 const char *const MatISDisassemblel2gTypes[] = {"NATURAL","MAT","ND","MatISDisassemblel2gType","MAT_IS_DISASSEMBLE_L2G_",NULL}; 409 MatISDisassemblel2gType mode = MAT_IS_DISASSEMBLE_L2G_NATURAL; 410 MatPartitioning part; 411 PetscSF sf; 412 PetscObject dm; 413 414 PetscFunctionBegin; 415 PetscOptionsBegin(PetscObjectComm((PetscObject)A),((PetscObject)A)->prefix,"MatIS l2g disassembling options","Mat"); 416 PetscCall(PetscOptionsEnum("-mat_is_disassemble_l2g_type","Type of local-to-global mapping to be used for disassembling","MatISDisassemblel2gType",MatISDisassemblel2gTypes,(PetscEnum)mode,(PetscEnum*)&mode,NULL)); 417 PetscOptionsEnd(); 418 if (mode == MAT_IS_DISASSEMBLE_L2G_MAT) { 419 PetscCall(MatGetLocalToGlobalMapping(A,l2g,NULL)); 420 PetscFunctionReturn(0); 421 } 422 PetscCall(PetscObjectGetComm((PetscObject)A,&comm)); 423 PetscCall(PetscObjectBaseTypeCompare((PetscObject)A,MATMPIAIJ ,&ismpiaij)); 424 PetscCall(PetscObjectBaseTypeCompare((PetscObject)A,MATMPIBAIJ,&ismpibaij)); 425 PetscCall(MatGetBlockSize(A,&bs)); 426 switch (mode) { 427 case MAT_IS_DISASSEMBLE_L2G_ND: 428 PetscCall(MatPartitioningCreate(comm,&part)); 429 PetscCall(MatPartitioningSetAdjacency(part,A)); 430 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)part,((PetscObject)A)->prefix)); 431 PetscCall(MatPartitioningSetFromOptions(part)); 432 PetscCall(MatPartitioningApplyND(part,&ndmap)); 433 PetscCall(MatPartitioningDestroy(&part)); 434 PetscCall(ISBuildTwoSided(ndmap,NULL,&ndsub)); 435 PetscCall(MatMPIAIJSetUseScalableIncreaseOverlap(A,PETSC_TRUE)); 436 PetscCall(MatIncreaseOverlap(A,1,&ndsub,1)); 437 PetscCall(ISLocalToGlobalMappingCreateIS(ndsub,l2g)); 438 439 /* it may happen that a separator node is not properly shared */ 440 PetscCall(ISLocalToGlobalMappingGetNodeInfo(*l2g,&nl,&ncount,NULL)); 441 PetscCall(PetscSFCreate(comm,&sf)); 442 PetscCall(ISLocalToGlobalMappingGetIndices(*l2g,&garray)); 443 PetscCall(PetscSFSetGraphLayout(sf,A->rmap,nl,NULL,PETSC_OWN_POINTER,garray)); 444 PetscCall(ISLocalToGlobalMappingRestoreIndices(*l2g,&garray)); 445 PetscCall(PetscCalloc1(A->rmap->n,&ndmapc)); 446 PetscCall(PetscSFReduceBegin(sf,MPIU_INT,ncount,ndmapc,MPI_REPLACE)); 447 PetscCall(PetscSFReduceEnd(sf,MPIU_INT,ncount,ndmapc,MPI_REPLACE)); 448 PetscCall(ISLocalToGlobalMappingRestoreNodeInfo(*l2g,NULL,&ncount,NULL)); 449 PetscCall(ISGetIndices(ndmap,&ndmapi)); 450 for (i = 0, cnt = 0; i < A->rmap->n; i++) 451 if (ndmapi[i] < 0 && ndmapc[i] < 2) 452 cnt++; 453 454 PetscCall(MPIU_Allreduce(&cnt,&i,1,MPIU_INT,MPI_MAX,comm)); 455 if (i) { /* we detected isolated separator nodes */ 456 Mat A2,A3; 457 IS *workis,is2; 458 PetscScalar *vals; 459 PetscInt gcnt = i,*dnz,*onz,j,*lndmapi; 460 ISLocalToGlobalMapping ll2g; 461 PetscBool flg; 462 const PetscInt *ii,*jj; 463 464 /* communicate global id of separators */ 465 MatPreallocateBegin(comm,A->rmap->n,A->cmap->n,dnz,onz); 466 for (i = 0, cnt = 0; i < A->rmap->n; i++) 467 dnz[i] = ndmapi[i] < 0 ? i + A->rmap->rstart : -1; 468 469 PetscCall(PetscMalloc1(nl,&lndmapi)); 470 PetscCall(PetscSFBcastBegin(sf,MPIU_INT,dnz,lndmapi,MPI_REPLACE)); 471 472 /* compute adjacency of isolated separators node */ 473 PetscCall(PetscMalloc1(gcnt,&workis)); 474 for (i = 0, cnt = 0; i < A->rmap->n; i++) { 475 if (ndmapi[i] < 0 && ndmapc[i] < 2) { 476 PetscCall(ISCreateStride(comm,1,i+A->rmap->rstart,1,&workis[cnt++])); 477 } 478 } 479 for (i = cnt; i < gcnt; i++) { 480 PetscCall(ISCreateStride(comm,0,0,1,&workis[i])); 481 } 482 for (i = 0; i < gcnt; i++) { 483 PetscCall(PetscObjectSetName((PetscObject)workis[i],"ISOLATED")); 484 PetscCall(ISViewFromOptions(workis[i],NULL,"-view_isolated_separators")); 485 } 486 487 /* no communications since all the ISes correspond to locally owned rows */ 488 PetscCall(MatIncreaseOverlap(A,gcnt,workis,1)); 489 490 /* end communicate global id of separators */ 491 PetscCall(PetscSFBcastEnd(sf,MPIU_INT,dnz,lndmapi,MPI_REPLACE)); 492 493 /* communicate new layers : create a matrix and transpose it */ 494 PetscCall(PetscArrayzero(dnz,A->rmap->n)); 495 PetscCall(PetscArrayzero(onz,A->rmap->n)); 496 for (i = 0, j = 0; i < A->rmap->n; i++) { 497 if (ndmapi[i] < 0 && ndmapc[i] < 2) { 498 const PetscInt* idxs; 499 PetscInt s; 500 501 PetscCall(ISGetLocalSize(workis[j],&s)); 502 PetscCall(ISGetIndices(workis[j],&idxs)); 503 PetscCall(MatPreallocateSet(i+A->rmap->rstart,s,idxs,dnz,onz)); 504 j++; 505 } 506 } 507 PetscCheck(j == cnt,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected local count %" PetscInt_FMT " != %" PetscInt_FMT,j,cnt); 508 509 for (i = 0; i < gcnt; i++) { 510 PetscCall(PetscObjectSetName((PetscObject)workis[i],"EXTENDED")); 511 PetscCall(ISViewFromOptions(workis[i],NULL,"-view_isolated_separators")); 512 } 513 514 for (i = 0, j = 0; i < A->rmap->n; i++) j = PetscMax(j,dnz[i]+onz[i]); 515 PetscCall(PetscMalloc1(j,&vals)); 516 for (i = 0; i < j; i++) vals[i] = 1.0; 517 518 PetscCall(MatCreate(comm,&A2)); 519 PetscCall(MatSetType(A2,MATMPIAIJ)); 520 PetscCall(MatSetSizes(A2,A->rmap->n,A->cmap->n,A->rmap->N,A->cmap->N)); 521 PetscCall(MatMPIAIJSetPreallocation(A2,0,dnz,0,onz)); 522 PetscCall(MatSetOption(A2,MAT_NO_OFF_PROC_ENTRIES,PETSC_TRUE)); 523 for (i = 0, j = 0; i < A2->rmap->n; i++) { 524 PetscInt row = i+A2->rmap->rstart,s = dnz[i] + onz[i]; 525 const PetscInt* idxs; 526 527 if (s) { 528 PetscCall(ISGetIndices(workis[j],&idxs)); 529 PetscCall(MatSetValues(A2,1,&row,s,idxs,vals,INSERT_VALUES)); 530 PetscCall(ISRestoreIndices(workis[j],&idxs)); 531 j++; 532 } 533 } 534 PetscCheck(j == cnt,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected local count %" PetscInt_FMT " != %" PetscInt_FMT,j,cnt); 535 PetscCall(PetscFree(vals)); 536 PetscCall(MatAssemblyBegin(A2,MAT_FINAL_ASSEMBLY)); 537 PetscCall(MatAssemblyEnd(A2,MAT_FINAL_ASSEMBLY)); 538 PetscCall(MatTranspose(A2,MAT_INPLACE_MATRIX,&A2)); 539 540 /* extract submatrix corresponding to the coupling "owned separators" x "isolated separators" */ 541 for (i = 0, j = 0; i < nl; i++) 542 if (lndmapi[i] >= 0) lndmapi[j++] = lndmapi[i]; 543 PetscCall(ISCreateGeneral(comm,j,lndmapi,PETSC_USE_POINTER,&is)); 544 PetscCall(MatMPIAIJGetLocalMatCondensed(A2,MAT_INITIAL_MATRIX,&is,NULL,&A3)); 545 PetscCall(ISDestroy(&is)); 546 PetscCall(MatDestroy(&A2)); 547 548 /* extend local to global map to include connected isolated separators */ 549 PetscCall(PetscObjectQuery((PetscObject)A3,"_petsc_GetLocalMatCondensed_iscol",(PetscObject*)&is)); 550 PetscCheck(is,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Missing column map"); 551 PetscCall(ISLocalToGlobalMappingCreateIS(is,&ll2g)); 552 PetscCall(MatGetRowIJ(A3,0,PETSC_FALSE,PETSC_FALSE,&i,&ii,&jj,&flg)); 553 PetscCheck(flg,PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot get IJ structure"); 554 PetscCall(ISCreateGeneral(PETSC_COMM_SELF,ii[i],jj,PETSC_COPY_VALUES,&is)); 555 PetscCall(MatRestoreRowIJ(A3,0,PETSC_FALSE,PETSC_FALSE,&i,&ii,&jj,&flg)); 556 PetscCheck(flg,PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot get IJ structure"); 557 PetscCall(ISLocalToGlobalMappingApplyIS(ll2g,is,&is2)); 558 PetscCall(ISDestroy(&is)); 559 PetscCall(ISLocalToGlobalMappingDestroy(&ll2g)); 560 561 /* add new nodes to the local-to-global map */ 562 PetscCall(ISLocalToGlobalMappingDestroy(l2g)); 563 PetscCall(ISExpand(ndsub,is2,&is)); 564 PetscCall(ISDestroy(&is2)); 565 PetscCall(ISLocalToGlobalMappingCreateIS(is,l2g)); 566 PetscCall(ISDestroy(&is)); 567 568 PetscCall(MatDestroy(&A3)); 569 PetscCall(PetscFree(lndmapi)); 570 MatPreallocateEnd(dnz,onz); 571 for (i = 0; i < gcnt; i++) { 572 PetscCall(ISDestroy(&workis[i])); 573 } 574 PetscCall(PetscFree(workis)); 575 } 576 PetscCall(ISRestoreIndices(ndmap,&ndmapi)); 577 PetscCall(PetscSFDestroy(&sf)); 578 PetscCall(PetscFree(ndmapc)); 579 PetscCall(ISDestroy(&ndmap)); 580 PetscCall(ISDestroy(&ndsub)); 581 PetscCall(ISLocalToGlobalMappingSetBlockSize(*l2g,bs)); 582 PetscCall(ISLocalToGlobalMappingViewFromOptions(*l2g,NULL,"-matis_nd_l2g_view")); 583 break; 584 case MAT_IS_DISASSEMBLE_L2G_NATURAL: 585 PetscCall(PetscObjectQuery((PetscObject)A,"__PETSc_dm",(PetscObject*)&dm)); 586 if (dm) { /* if a matrix comes from a DM, most likely we can use the l2gmap if any */ 587 PetscCall(MatGetLocalToGlobalMapping(A,l2g,NULL)); 588 PetscCall(PetscObjectReference((PetscObject)*l2g)); 589 if (*l2g) PetscFunctionReturn(0); 590 } 591 if (ismpiaij) { 592 PetscCall(MatMPIAIJGetSeqAIJ(A,&Ad,&Ao,&garray)); 593 } else if (ismpibaij) { 594 PetscCall(MatMPIBAIJGetSeqBAIJ(A,&Ad,&Ao,&garray)); 595 } else SETERRQ(comm,PETSC_ERR_SUP,"Type %s",((PetscObject)A)->type_name); 596 if (A->rmap->n) { 597 PetscInt dc,oc,stc,*aux; 598 599 PetscCall(MatGetLocalSize(Ad,NULL,&dc)); 600 PetscCall(MatGetLocalSize(Ao,NULL,&oc)); 601 PetscCheck(!oc || garray,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"garray not present"); 602 PetscCall(MatGetOwnershipRangeColumn(A,&stc,NULL)); 603 PetscCall(PetscMalloc1((dc+oc)/bs,&aux)); 604 for (i=0; i<dc/bs; i++) aux[i] = i+stc/bs; 605 for (i=0; i<oc/bs; i++) aux[i+dc/bs] = (ismpiaij ? garray[i*bs]/bs : garray[i]); 606 PetscCall(ISCreateBlock(comm,bs,(dc+oc)/bs,aux,PETSC_OWN_POINTER,&is)); 607 } else { 608 PetscCall(ISCreateBlock(comm,1,0,NULL,PETSC_OWN_POINTER,&is)); 609 } 610 PetscCall(ISLocalToGlobalMappingCreateIS(is,l2g)); 611 PetscCall(ISDestroy(&is)); 612 break; 613 default: 614 SETERRQ(comm,PETSC_ERR_ARG_WRONG,"Unsupported l2g disassembling type %d",mode); 615 } 616 PetscFunctionReturn(0); 617 } 618 619 PETSC_INTERN PetscErrorCode MatConvert_XAIJ_IS(Mat A,MatType type,MatReuse reuse,Mat *newmat) 620 { 621 Mat lA,Ad,Ao,B = NULL; 622 ISLocalToGlobalMapping rl2g,cl2g; 623 IS is; 624 MPI_Comm comm; 625 void *ptrs[2]; 626 const char *names[2] = {"_convert_csr_aux","_convert_csr_data"}; 627 const PetscInt *garray; 628 PetscScalar *dd,*od,*aa,*data; 629 const PetscInt *di,*dj,*oi,*oj; 630 const PetscInt *odi,*odj,*ooi,*ooj; 631 PetscInt *aux,*ii,*jj; 632 PetscInt bs,lc,dr,dc,oc,str,stc,nnz,i,jd,jo,cum; 633 PetscBool flg,ismpiaij,ismpibaij,was_inplace = PETSC_FALSE; 634 PetscMPIInt size; 635 636 PetscFunctionBegin; 637 PetscCall(PetscObjectGetComm((PetscObject)A,&comm)); 638 PetscCallMPI(MPI_Comm_size(comm,&size)); 639 if (size == 1) { 640 PetscCall(MatConvert_SeqXAIJ_IS(A,type,reuse,newmat)); 641 PetscFunctionReturn(0); 642 } 643 if (reuse != MAT_REUSE_MATRIX && A->cmap->N == A->rmap->N) { 644 PetscCall(MatMPIXAIJComputeLocalToGlobalMapping_Private(A,&rl2g)); 645 PetscCall(MatCreate(comm,&B)); 646 PetscCall(MatSetType(B,MATIS)); 647 PetscCall(MatSetSizes(B,A->rmap->n,A->cmap->n,A->rmap->N,A->cmap->N)); 648 PetscCall(MatSetLocalToGlobalMapping(B,rl2g,rl2g)); 649 PetscCall(MatGetBlockSize(A,&bs)); 650 PetscCall(MatSetBlockSize(B,bs)); 651 PetscCall(ISLocalToGlobalMappingDestroy(&rl2g)); 652 if (reuse == MAT_INPLACE_MATRIX) was_inplace = PETSC_TRUE; 653 reuse = MAT_REUSE_MATRIX; 654 } 655 if (reuse == MAT_REUSE_MATRIX) { 656 Mat *newlA, lA; 657 IS rows, cols; 658 const PetscInt *ridx, *cidx; 659 PetscInt rbs, cbs, nr, nc; 660 661 if (!B) B = *newmat; 662 PetscCall(MatISGetLocalToGlobalMapping(B,&rl2g,&cl2g)); 663 PetscCall(ISLocalToGlobalMappingGetBlockIndices(rl2g,&ridx)); 664 PetscCall(ISLocalToGlobalMappingGetBlockIndices(cl2g,&cidx)); 665 PetscCall(ISLocalToGlobalMappingGetSize(rl2g,&nr)); 666 PetscCall(ISLocalToGlobalMappingGetSize(cl2g,&nc)); 667 PetscCall(ISLocalToGlobalMappingGetBlockSize(rl2g,&rbs)); 668 PetscCall(ISLocalToGlobalMappingGetBlockSize(cl2g,&cbs)); 669 PetscCall(ISCreateBlock(comm,rbs,nr/rbs,ridx,PETSC_USE_POINTER,&rows)); 670 if (rl2g != cl2g) { 671 PetscCall(ISCreateBlock(comm,cbs,nc/cbs,cidx,PETSC_USE_POINTER,&cols)); 672 } else { 673 PetscCall(PetscObjectReference((PetscObject)rows)); 674 cols = rows; 675 } 676 PetscCall(MatISGetLocalMat(B,&lA)); 677 PetscCall(MatCreateSubMatrices(A,1,&rows,&cols,MAT_INITIAL_MATRIX,&newlA)); 678 PetscCall(MatConvert(newlA[0],MATSEQAIJ,MAT_INPLACE_MATRIX,&newlA[0])); 679 PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(rl2g,&ridx)); 680 PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(cl2g,&cidx)); 681 PetscCall(ISDestroy(&rows)); 682 PetscCall(ISDestroy(&cols)); 683 if (!lA->preallocated) { /* first time */ 684 PetscCall(MatDuplicate(newlA[0],MAT_COPY_VALUES,&lA)); 685 PetscCall(MatISSetLocalMat(B,lA)); 686 PetscCall(PetscObjectDereference((PetscObject)lA)); 687 } 688 PetscCall(MatCopy(newlA[0],lA,SAME_NONZERO_PATTERN)); 689 PetscCall(MatDestroySubMatrices(1,&newlA)); 690 PetscCall(MatISScaleDisassembling_Private(B)); 691 PetscCall(MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY)); 692 PetscCall(MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY)); 693 if (was_inplace) PetscCall(MatHeaderReplace(A,&B)); 694 else *newmat = B; 695 PetscFunctionReturn(0); 696 } 697 /* rectangular case, just compress out the column space */ 698 PetscCall(PetscObjectBaseTypeCompare((PetscObject)A,MATMPIAIJ ,&ismpiaij)); 699 PetscCall(PetscObjectBaseTypeCompare((PetscObject)A,MATMPIBAIJ,&ismpibaij)); 700 if (ismpiaij) { 701 bs = 1; 702 PetscCall(MatMPIAIJGetSeqAIJ(A,&Ad,&Ao,&garray)); 703 } else if (ismpibaij) { 704 PetscCall(MatGetBlockSize(A,&bs)); 705 PetscCall(MatMPIBAIJGetSeqBAIJ(A,&Ad,&Ao,&garray)); 706 PetscCall(MatConvert(Ad,MATSEQAIJ,MAT_INITIAL_MATRIX,&Ad)); 707 PetscCall(MatConvert(Ao,MATSEQAIJ,MAT_INITIAL_MATRIX,&Ao)); 708 } else SETERRQ(comm,PETSC_ERR_SUP,"Type %s",((PetscObject)A)->type_name); 709 PetscCall(MatSeqAIJGetArray(Ad,&dd)); 710 PetscCall(MatSeqAIJGetArray(Ao,&od)); 711 PetscCheck(garray,comm,PETSC_ERR_ARG_WRONGSTATE,"garray not present"); 712 713 /* access relevant information from MPIAIJ */ 714 PetscCall(MatGetOwnershipRange(A,&str,NULL)); 715 PetscCall(MatGetOwnershipRangeColumn(A,&stc,NULL)); 716 PetscCall(MatGetLocalSize(A,&dr,&dc)); 717 PetscCall(MatGetLocalSize(Ao,NULL,&oc)); 718 PetscCall(MatGetRowIJ(Ad,0,PETSC_FALSE,PETSC_FALSE,&i,&di,&dj,&flg)); 719 PetscCheck(flg,PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot get IJ structure"); 720 PetscCall(MatGetRowIJ(Ao,0,PETSC_FALSE,PETSC_FALSE,&i,&oi,&oj,&flg)); 721 PetscCheck(flg,PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot get IJ structure"); 722 nnz = di[dr] + oi[dr]; 723 /* store original pointers to be restored later */ 724 odi = di; odj = dj; ooi = oi; ooj = oj; 725 726 /* generate l2g maps for rows and cols */ 727 PetscCall(ISCreateStride(comm,dr/bs,str/bs,1,&is)); 728 if (bs > 1) { 729 IS is2; 730 731 PetscCall(ISGetLocalSize(is,&i)); 732 PetscCall(ISGetIndices(is,(const PetscInt**)&aux)); 733 PetscCall(ISCreateBlock(comm,bs,i,aux,PETSC_COPY_VALUES,&is2)); 734 PetscCall(ISRestoreIndices(is,(const PetscInt**)&aux)); 735 PetscCall(ISDestroy(&is)); 736 is = is2; 737 } 738 PetscCall(ISLocalToGlobalMappingCreateIS(is,&rl2g)); 739 PetscCall(ISDestroy(&is)); 740 if (dr) { 741 PetscCall(PetscMalloc1((dc+oc)/bs,&aux)); 742 for (i=0; i<dc/bs; i++) aux[i] = i+stc/bs; 743 for (i=0; i<oc/bs; i++) aux[i+dc/bs] = garray[i]; 744 PetscCall(ISCreateBlock(comm,bs,(dc+oc)/bs,aux,PETSC_OWN_POINTER,&is)); 745 lc = dc+oc; 746 } else { 747 PetscCall(ISCreateBlock(comm,bs,0,NULL,PETSC_OWN_POINTER,&is)); 748 lc = 0; 749 } 750 PetscCall(ISLocalToGlobalMappingCreateIS(is,&cl2g)); 751 PetscCall(ISDestroy(&is)); 752 753 /* create MATIS object */ 754 PetscCall(MatCreate(comm,&B)); 755 PetscCall(MatSetSizes(B,dr,dc,PETSC_DECIDE,PETSC_DECIDE)); 756 PetscCall(MatSetType(B,MATIS)); 757 PetscCall(MatSetBlockSize(B,bs)); 758 PetscCall(MatSetLocalToGlobalMapping(B,rl2g,cl2g)); 759 PetscCall(ISLocalToGlobalMappingDestroy(&rl2g)); 760 PetscCall(ISLocalToGlobalMappingDestroy(&cl2g)); 761 762 /* merge local matrices */ 763 PetscCall(PetscMalloc1(nnz+dr+1,&aux)); 764 PetscCall(PetscMalloc1(nnz,&data)); 765 ii = aux; 766 jj = aux+dr+1; 767 aa = data; 768 *ii = *(di++) + *(oi++); 769 for (jd=0,jo=0,cum=0;*ii<nnz;cum++) 770 { 771 for (;jd<*di;jd++) { *jj++ = *dj++; *aa++ = *dd++; } 772 for (;jo<*oi;jo++) { *jj++ = *oj++ + dc; *aa++ = *od++; } 773 *(++ii) = *(di++) + *(oi++); 774 } 775 for (;cum<dr;cum++) *(++ii) = nnz; 776 777 PetscCall(MatRestoreRowIJ(Ad,0,PETSC_FALSE,PETSC_FALSE,&i,&odi,&odj,&flg)); 778 PetscCheck(flg,PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot restore IJ structure"); 779 PetscCall(MatRestoreRowIJ(Ao,0,PETSC_FALSE,PETSC_FALSE,&i,&ooi,&ooj,&flg)); 780 PetscCheck(flg,PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot restore IJ structure"); 781 PetscCall(MatSeqAIJRestoreArray(Ad,&dd)); 782 PetscCall(MatSeqAIJRestoreArray(Ao,&od)); 783 784 ii = aux; 785 jj = aux+dr+1; 786 aa = data; 787 PetscCall(MatCreateSeqAIJWithArrays(PETSC_COMM_SELF,dr,lc,ii,jj,aa,&lA)); 788 789 /* create containers to destroy the data */ 790 ptrs[0] = aux; 791 ptrs[1] = data; 792 for (i=0; i<2; i++) { 793 PetscContainer c; 794 795 PetscCall(PetscContainerCreate(PETSC_COMM_SELF,&c)); 796 PetscCall(PetscContainerSetPointer(c,ptrs[i])); 797 PetscCall(PetscContainerSetUserDestroy(c,PetscContainerUserDestroyDefault)); 798 PetscCall(PetscObjectCompose((PetscObject)lA,names[i],(PetscObject)c)); 799 PetscCall(PetscContainerDestroy(&c)); 800 } 801 if (ismpibaij) { /* destroy converted local matrices */ 802 PetscCall(MatDestroy(&Ad)); 803 PetscCall(MatDestroy(&Ao)); 804 } 805 806 /* finalize matrix */ 807 PetscCall(MatISSetLocalMat(B,lA)); 808 PetscCall(MatDestroy(&lA)); 809 PetscCall(MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY)); 810 PetscCall(MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY)); 811 if (reuse == MAT_INPLACE_MATRIX) { 812 PetscCall(MatHeaderReplace(A,&B)); 813 } else *newmat = B; 814 PetscFunctionReturn(0); 815 } 816 817 PETSC_INTERN PetscErrorCode MatConvert_Nest_IS(Mat A,MatType type,MatReuse reuse,Mat *newmat) 818 { 819 Mat **nest,*snest,**rnest,lA,B; 820 IS *iscol,*isrow,*islrow,*islcol; 821 ISLocalToGlobalMapping rl2g,cl2g; 822 MPI_Comm comm; 823 PetscInt *lr,*lc,*l2gidxs; 824 PetscInt i,j,nr,nc,rbs,cbs; 825 PetscBool convert,lreuse,*istrans; 826 827 PetscFunctionBegin; 828 PetscCall(MatNestGetSubMats(A,&nr,&nc,&nest)); 829 lreuse = PETSC_FALSE; 830 rnest = NULL; 831 if (reuse == MAT_REUSE_MATRIX) { 832 PetscBool ismatis,isnest; 833 834 PetscCall(PetscObjectTypeCompare((PetscObject)*newmat,MATIS,&ismatis)); 835 PetscCheck(ismatis,PetscObjectComm((PetscObject)*newmat),PETSC_ERR_USER,"Cannot reuse matrix of type %s",((PetscObject)(*newmat))->type_name); 836 PetscCall(MatISGetLocalMat(*newmat,&lA)); 837 PetscCall(PetscObjectTypeCompare((PetscObject)lA,MATNEST,&isnest)); 838 if (isnest) { 839 PetscCall(MatNestGetSubMats(lA,&i,&j,&rnest)); 840 lreuse = (PetscBool)(i == nr && j == nc); 841 if (!lreuse) rnest = NULL; 842 } 843 } 844 PetscCall(PetscObjectGetComm((PetscObject)A,&comm)); 845 PetscCall(PetscCalloc2(nr,&lr,nc,&lc)); 846 PetscCall(PetscCalloc6(nr,&isrow,nc,&iscol,nr,&islrow,nc,&islcol,nr*nc,&snest,nr*nc,&istrans)); 847 PetscCall(MatNestGetISs(A,isrow,iscol)); 848 for (i=0;i<nr;i++) { 849 for (j=0;j<nc;j++) { 850 PetscBool ismatis; 851 PetscInt l1,l2,lb1,lb2,ij=i*nc+j; 852 853 /* Null matrix pointers are allowed in MATNEST */ 854 if (!nest[i][j]) continue; 855 856 /* Nested matrices should be of type MATIS */ 857 PetscCall(PetscObjectTypeCompare((PetscObject)nest[i][j],MATTRANSPOSEMAT,&istrans[ij])); 858 if (istrans[ij]) { 859 Mat T,lT; 860 PetscCall(MatTransposeGetMat(nest[i][j],&T)); 861 PetscCall(PetscObjectTypeCompare((PetscObject)T,MATIS,&ismatis)); 862 PetscCheck(ismatis,comm,PETSC_ERR_SUP,"Cannot convert from MATNEST to MATIS! Matrix block (%" PetscInt_FMT ",%" PetscInt_FMT ") (transposed) is not of type MATIS",i,j); 863 PetscCall(MatISGetLocalMat(T,&lT)); 864 PetscCall(MatCreateTranspose(lT,&snest[ij])); 865 } else { 866 PetscCall(PetscObjectTypeCompare((PetscObject)nest[i][j],MATIS,&ismatis)); 867 PetscCheck(ismatis,comm,PETSC_ERR_SUP,"Cannot convert from MATNEST to MATIS! Matrix block (%" PetscInt_FMT ",%" PetscInt_FMT ") is not of type MATIS",i,j); 868 PetscCall(MatISGetLocalMat(nest[i][j],&snest[ij])); 869 } 870 871 /* Check compatibility of local sizes */ 872 PetscCall(MatGetSize(snest[ij],&l1,&l2)); 873 PetscCall(MatGetBlockSizes(snest[ij],&lb1,&lb2)); 874 if (!l1 || !l2) continue; 875 PetscCheck(!lr[i] || l1 == lr[i],PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot convert from MATNEST to MATIS! Matrix block (%" PetscInt_FMT ",%" PetscInt_FMT ") has invalid local size %" PetscInt_FMT " != %" PetscInt_FMT,i,j,lr[i],l1); 876 PetscCheck(!lc[j] || l2 == lc[j],PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot convert from MATNEST to MATIS! Matrix block (%" PetscInt_FMT ",%" PetscInt_FMT ") has invalid local size %" PetscInt_FMT " != %" PetscInt_FMT,i,j,lc[j],l2); 877 lr[i] = l1; 878 lc[j] = l2; 879 880 /* check compatibilty for local matrix reusage */ 881 if (rnest && !rnest[i][j] != !snest[ij]) lreuse = PETSC_FALSE; 882 } 883 } 884 885 if (PetscDefined (USE_DEBUG)) { 886 /* Check compatibility of l2g maps for rows */ 887 for (i=0;i<nr;i++) { 888 rl2g = NULL; 889 for (j=0;j<nc;j++) { 890 PetscInt n1,n2; 891 892 if (!nest[i][j]) continue; 893 if (istrans[i*nc+j]) { 894 Mat T; 895 896 PetscCall(MatTransposeGetMat(nest[i][j],&T)); 897 PetscCall(MatISGetLocalToGlobalMapping(T,NULL,&cl2g)); 898 } else { 899 PetscCall(MatISGetLocalToGlobalMapping(nest[i][j],&cl2g,NULL)); 900 } 901 PetscCall(ISLocalToGlobalMappingGetSize(cl2g,&n1)); 902 if (!n1) continue; 903 if (!rl2g) { 904 rl2g = cl2g; 905 } else { 906 const PetscInt *idxs1,*idxs2; 907 PetscBool same; 908 909 PetscCall(ISLocalToGlobalMappingGetSize(rl2g,&n2)); 910 PetscCheck(n1 == n2,PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot convert from MATNEST to MATIS! Matrix block (%" PetscInt_FMT ",%" PetscInt_FMT ") has invalid row l2gmap size %" PetscInt_FMT " != %" PetscInt_FMT,i,j,n1,n2); 911 PetscCall(ISLocalToGlobalMappingGetIndices(cl2g,&idxs1)); 912 PetscCall(ISLocalToGlobalMappingGetIndices(rl2g,&idxs2)); 913 PetscCall(PetscArraycmp(idxs1,idxs2,n1,&same)); 914 PetscCall(ISLocalToGlobalMappingRestoreIndices(cl2g,&idxs1)); 915 PetscCall(ISLocalToGlobalMappingRestoreIndices(rl2g,&idxs2)); 916 PetscCheck(same,PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot convert from MATNEST to MATIS! Matrix block (%" PetscInt_FMT ",%" PetscInt_FMT ") has invalid row l2gmap",i,j); 917 } 918 } 919 } 920 /* Check compatibility of l2g maps for columns */ 921 for (i=0;i<nc;i++) { 922 rl2g = NULL; 923 for (j=0;j<nr;j++) { 924 PetscInt n1,n2; 925 926 if (!nest[j][i]) continue; 927 if (istrans[j*nc+i]) { 928 Mat T; 929 930 PetscCall(MatTransposeGetMat(nest[j][i],&T)); 931 PetscCall(MatISGetLocalToGlobalMapping(T,&cl2g,NULL)); 932 } else { 933 PetscCall(MatISGetLocalToGlobalMapping(nest[j][i],NULL,&cl2g)); 934 } 935 PetscCall(ISLocalToGlobalMappingGetSize(cl2g,&n1)); 936 if (!n1) continue; 937 if (!rl2g) { 938 rl2g = cl2g; 939 } else { 940 const PetscInt *idxs1,*idxs2; 941 PetscBool same; 942 943 PetscCall(ISLocalToGlobalMappingGetSize(rl2g,&n2)); 944 PetscCheck(n1 == n2,PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot convert from MATNEST to MATIS! Matrix block (%" PetscInt_FMT ",%" PetscInt_FMT ") has invalid column l2gmap size %" PetscInt_FMT " != %" PetscInt_FMT,j,i,n1,n2); 945 PetscCall(ISLocalToGlobalMappingGetIndices(cl2g,&idxs1)); 946 PetscCall(ISLocalToGlobalMappingGetIndices(rl2g,&idxs2)); 947 PetscCall(PetscArraycmp(idxs1,idxs2,n1,&same)); 948 PetscCall(ISLocalToGlobalMappingRestoreIndices(cl2g,&idxs1)); 949 PetscCall(ISLocalToGlobalMappingRestoreIndices(rl2g,&idxs2)); 950 PetscCheck(same,PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot convert from MATNEST to MATIS! Matrix block (%" PetscInt_FMT ",%" PetscInt_FMT ") has invalid column l2gmap",j,i); 951 } 952 } 953 } 954 } 955 956 B = NULL; 957 if (reuse != MAT_REUSE_MATRIX) { 958 PetscInt stl; 959 960 /* Create l2g map for the rows of the new matrix and index sets for the local MATNEST */ 961 for (i=0,stl=0;i<nr;i++) stl += lr[i]; 962 PetscCall(PetscMalloc1(stl,&l2gidxs)); 963 for (i=0,stl=0;i<nr;i++) { 964 Mat usedmat; 965 Mat_IS *matis; 966 const PetscInt *idxs; 967 968 /* local IS for local NEST */ 969 PetscCall(ISCreateStride(PETSC_COMM_SELF,lr[i],stl,1,&islrow[i])); 970 971 /* l2gmap */ 972 j = 0; 973 usedmat = nest[i][j]; 974 while (!usedmat && j < nc-1) usedmat = nest[i][++j]; 975 PetscCheck(usedmat,comm,PETSC_ERR_SUP,"Cannot find valid row mat"); 976 977 if (istrans[i*nc+j]) { 978 Mat T; 979 PetscCall(MatTransposeGetMat(usedmat,&T)); 980 usedmat = T; 981 } 982 matis = (Mat_IS*)(usedmat->data); 983 PetscCall(ISGetIndices(isrow[i],&idxs)); 984 if (istrans[i*nc+j]) { 985 PetscCall(PetscSFBcastBegin(matis->csf,MPIU_INT,idxs,l2gidxs+stl,MPI_REPLACE)); 986 PetscCall(PetscSFBcastEnd(matis->csf,MPIU_INT,idxs,l2gidxs+stl,MPI_REPLACE)); 987 } else { 988 PetscCall(PetscSFBcastBegin(matis->sf,MPIU_INT,idxs,l2gidxs+stl,MPI_REPLACE)); 989 PetscCall(PetscSFBcastEnd(matis->sf,MPIU_INT,idxs,l2gidxs+stl,MPI_REPLACE)); 990 } 991 PetscCall(ISRestoreIndices(isrow[i],&idxs)); 992 stl += lr[i]; 993 } 994 PetscCall(ISLocalToGlobalMappingCreate(comm,1,stl,l2gidxs,PETSC_OWN_POINTER,&rl2g)); 995 996 /* Create l2g map for columns of the new matrix and index sets for the local MATNEST */ 997 for (i=0,stl=0;i<nc;i++) stl += lc[i]; 998 PetscCall(PetscMalloc1(stl,&l2gidxs)); 999 for (i=0,stl=0;i<nc;i++) { 1000 Mat usedmat; 1001 Mat_IS *matis; 1002 const PetscInt *idxs; 1003 1004 /* local IS for local NEST */ 1005 PetscCall(ISCreateStride(PETSC_COMM_SELF,lc[i],stl,1,&islcol[i])); 1006 1007 /* l2gmap */ 1008 j = 0; 1009 usedmat = nest[j][i]; 1010 while (!usedmat && j < nr-1) usedmat = nest[++j][i]; 1011 PetscCheck(usedmat,comm,PETSC_ERR_SUP,"Cannot find valid column mat"); 1012 if (istrans[j*nc+i]) { 1013 Mat T; 1014 PetscCall(MatTransposeGetMat(usedmat,&T)); 1015 usedmat = T; 1016 } 1017 matis = (Mat_IS*)(usedmat->data); 1018 PetscCall(ISGetIndices(iscol[i],&idxs)); 1019 if (istrans[j*nc+i]) { 1020 PetscCall(PetscSFBcastBegin(matis->sf,MPIU_INT,idxs,l2gidxs+stl,MPI_REPLACE)); 1021 PetscCall(PetscSFBcastEnd(matis->sf,MPIU_INT,idxs,l2gidxs+stl,MPI_REPLACE)); 1022 } else { 1023 PetscCall(PetscSFBcastBegin(matis->csf,MPIU_INT,idxs,l2gidxs+stl,MPI_REPLACE)); 1024 PetscCall(PetscSFBcastEnd(matis->csf,MPIU_INT,idxs,l2gidxs+stl,MPI_REPLACE)); 1025 } 1026 PetscCall(ISRestoreIndices(iscol[i],&idxs)); 1027 stl += lc[i]; 1028 } 1029 PetscCall(ISLocalToGlobalMappingCreate(comm,1,stl,l2gidxs,PETSC_OWN_POINTER,&cl2g)); 1030 1031 /* Create MATIS */ 1032 PetscCall(MatCreate(comm,&B)); 1033 PetscCall(MatSetSizes(B,A->rmap->n,A->cmap->n,A->rmap->N,A->cmap->N)); 1034 PetscCall(MatGetBlockSizes(A,&rbs,&cbs)); 1035 PetscCall(MatSetBlockSizes(B,rbs,cbs)); 1036 PetscCall(MatSetType(B,MATIS)); 1037 PetscCall(MatISSetLocalMatType(B,MATNEST)); 1038 { /* hack : avoid setup of scatters */ 1039 Mat_IS *matis = (Mat_IS*)(B->data); 1040 matis->islocalref = PETSC_TRUE; 1041 } 1042 PetscCall(MatSetLocalToGlobalMapping(B,rl2g,cl2g)); 1043 PetscCall(ISLocalToGlobalMappingDestroy(&rl2g)); 1044 PetscCall(ISLocalToGlobalMappingDestroy(&cl2g)); 1045 PetscCall(MatCreateNest(PETSC_COMM_SELF,nr,islrow,nc,islcol,snest,&lA)); 1046 PetscCall(MatNestSetVecType(lA,VECNEST)); 1047 for (i=0;i<nr*nc;i++) { 1048 if (istrans[i]) { 1049 PetscCall(MatDestroy(&snest[i])); 1050 } 1051 } 1052 PetscCall(MatISSetLocalMat(B,lA)); 1053 PetscCall(MatDestroy(&lA)); 1054 { /* hack : setup of scatters done here */ 1055 Mat_IS *matis = (Mat_IS*)(B->data); 1056 1057 matis->islocalref = PETSC_FALSE; 1058 PetscCall(MatISSetUpScatters_Private(B)); 1059 } 1060 PetscCall(MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY)); 1061 PetscCall(MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY)); 1062 if (reuse == MAT_INPLACE_MATRIX) { 1063 PetscCall(MatHeaderReplace(A,&B)); 1064 } else { 1065 *newmat = B; 1066 } 1067 } else { 1068 if (lreuse) { 1069 PetscCall(MatISGetLocalMat(*newmat,&lA)); 1070 for (i=0;i<nr;i++) { 1071 for (j=0;j<nc;j++) { 1072 if (snest[i*nc+j]) { 1073 PetscCall(MatNestSetSubMat(lA,i,j,snest[i*nc+j])); 1074 if (istrans[i*nc+j]) { 1075 PetscCall(MatDestroy(&snest[i*nc+j])); 1076 } 1077 } 1078 } 1079 } 1080 } else { 1081 PetscInt stl; 1082 for (i=0,stl=0;i<nr;i++) { 1083 PetscCall(ISCreateStride(PETSC_COMM_SELF,lr[i],stl,1,&islrow[i])); 1084 stl += lr[i]; 1085 } 1086 for (i=0,stl=0;i<nc;i++) { 1087 PetscCall(ISCreateStride(PETSC_COMM_SELF,lc[i],stl,1,&islcol[i])); 1088 stl += lc[i]; 1089 } 1090 PetscCall(MatCreateNest(PETSC_COMM_SELF,nr,islrow,nc,islcol,snest,&lA)); 1091 for (i=0;i<nr*nc;i++) { 1092 if (istrans[i]) { 1093 PetscCall(MatDestroy(&snest[i])); 1094 } 1095 } 1096 PetscCall(MatISSetLocalMat(*newmat,lA)); 1097 PetscCall(MatDestroy(&lA)); 1098 } 1099 PetscCall(MatAssemblyBegin(*newmat,MAT_FINAL_ASSEMBLY)); 1100 PetscCall(MatAssemblyEnd(*newmat,MAT_FINAL_ASSEMBLY)); 1101 } 1102 1103 /* Create local matrix in MATNEST format */ 1104 convert = PETSC_FALSE; 1105 PetscCall(PetscOptionsGetBool(NULL,((PetscObject)A)->prefix,"-matis_convert_local_nest",&convert,NULL)); 1106 if (convert) { 1107 Mat M; 1108 MatISLocalFields lf; 1109 PetscContainer c; 1110 1111 PetscCall(MatISGetLocalMat(*newmat,&lA)); 1112 PetscCall(MatConvert(lA,MATAIJ,MAT_INITIAL_MATRIX,&M)); 1113 PetscCall(MatISSetLocalMat(*newmat,M)); 1114 PetscCall(MatDestroy(&M)); 1115 1116 /* attach local fields to the matrix */ 1117 PetscCall(PetscNew(&lf)); 1118 PetscCall(PetscMalloc2(nr,&lf->rf,nc,&lf->cf)); 1119 for (i=0;i<nr;i++) { 1120 PetscInt n,st; 1121 1122 PetscCall(ISGetLocalSize(islrow[i],&n)); 1123 PetscCall(ISStrideGetInfo(islrow[i],&st,NULL)); 1124 PetscCall(ISCreateStride(comm,n,st,1,&lf->rf[i])); 1125 } 1126 for (i=0;i<nc;i++) { 1127 PetscInt n,st; 1128 1129 PetscCall(ISGetLocalSize(islcol[i],&n)); 1130 PetscCall(ISStrideGetInfo(islcol[i],&st,NULL)); 1131 PetscCall(ISCreateStride(comm,n,st,1,&lf->cf[i])); 1132 } 1133 lf->nr = nr; 1134 lf->nc = nc; 1135 PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)(*newmat)),&c)); 1136 PetscCall(PetscContainerSetPointer(c,lf)); 1137 PetscCall(PetscContainerSetUserDestroy(c,MatISContainerDestroyFields_Private)); 1138 PetscCall(PetscObjectCompose((PetscObject)(*newmat),"_convert_nest_lfields",(PetscObject)c)); 1139 PetscCall(PetscContainerDestroy(&c)); 1140 } 1141 1142 /* Free workspace */ 1143 for (i=0;i<nr;i++) { 1144 PetscCall(ISDestroy(&islrow[i])); 1145 } 1146 for (i=0;i<nc;i++) { 1147 PetscCall(ISDestroy(&islcol[i])); 1148 } 1149 PetscCall(PetscFree6(isrow,iscol,islrow,islcol,snest,istrans)); 1150 PetscCall(PetscFree2(lr,lc)); 1151 PetscFunctionReturn(0); 1152 } 1153 1154 static PetscErrorCode MatDiagonalScale_IS(Mat A, Vec l, Vec r) 1155 { 1156 Mat_IS *matis = (Mat_IS*)A->data; 1157 Vec ll,rr; 1158 const PetscScalar *Y,*X; 1159 PetscScalar *x,*y; 1160 1161 PetscFunctionBegin; 1162 if (l) { 1163 ll = matis->y; 1164 PetscCall(VecGetArrayRead(l,&Y)); 1165 PetscCall(VecGetArray(ll,&y)); 1166 PetscCall(PetscSFBcastBegin(matis->sf,MPIU_SCALAR,Y,y,MPI_REPLACE)); 1167 } else { 1168 ll = NULL; 1169 } 1170 if (r) { 1171 rr = matis->x; 1172 PetscCall(VecGetArrayRead(r,&X)); 1173 PetscCall(VecGetArray(rr,&x)); 1174 PetscCall(PetscSFBcastBegin(matis->csf,MPIU_SCALAR,X,x,MPI_REPLACE)); 1175 } else { 1176 rr = NULL; 1177 } 1178 if (ll) { 1179 PetscCall(PetscSFBcastEnd(matis->sf,MPIU_SCALAR,Y,y,MPI_REPLACE)); 1180 PetscCall(VecRestoreArrayRead(l,&Y)); 1181 PetscCall(VecRestoreArray(ll,&y)); 1182 } 1183 if (rr) { 1184 PetscCall(PetscSFBcastEnd(matis->csf,MPIU_SCALAR,X,x,MPI_REPLACE)); 1185 PetscCall(VecRestoreArrayRead(r,&X)); 1186 PetscCall(VecRestoreArray(rr,&x)); 1187 } 1188 PetscCall(MatDiagonalScale(matis->A,ll,rr)); 1189 PetscFunctionReturn(0); 1190 } 1191 1192 static PetscErrorCode MatGetInfo_IS(Mat A,MatInfoType flag,MatInfo *ginfo) 1193 { 1194 Mat_IS *matis = (Mat_IS*)A->data; 1195 MatInfo info; 1196 PetscLogDouble isend[6],irecv[6]; 1197 PetscInt bs; 1198 1199 PetscFunctionBegin; 1200 PetscCall(MatGetBlockSize(A,&bs)); 1201 if (matis->A->ops->getinfo) { 1202 PetscCall(MatGetInfo(matis->A,MAT_LOCAL,&info)); 1203 isend[0] = info.nz_used; 1204 isend[1] = info.nz_allocated; 1205 isend[2] = info.nz_unneeded; 1206 isend[3] = info.memory; 1207 isend[4] = info.mallocs; 1208 } else { 1209 isend[0] = 0.; 1210 isend[1] = 0.; 1211 isend[2] = 0.; 1212 isend[3] = 0.; 1213 isend[4] = 0.; 1214 } 1215 isend[5] = matis->A->num_ass; 1216 if (flag == MAT_LOCAL) { 1217 ginfo->nz_used = isend[0]; 1218 ginfo->nz_allocated = isend[1]; 1219 ginfo->nz_unneeded = isend[2]; 1220 ginfo->memory = isend[3]; 1221 ginfo->mallocs = isend[4]; 1222 ginfo->assemblies = isend[5]; 1223 } else if (flag == MAT_GLOBAL_MAX) { 1224 PetscCall(MPIU_Allreduce(isend,irecv,6,MPIU_PETSCLOGDOUBLE,MPI_MAX,PetscObjectComm((PetscObject)A))); 1225 1226 ginfo->nz_used = irecv[0]; 1227 ginfo->nz_allocated = irecv[1]; 1228 ginfo->nz_unneeded = irecv[2]; 1229 ginfo->memory = irecv[3]; 1230 ginfo->mallocs = irecv[4]; 1231 ginfo->assemblies = irecv[5]; 1232 } else if (flag == MAT_GLOBAL_SUM) { 1233 PetscCall(MPIU_Allreduce(isend,irecv,5,MPIU_PETSCLOGDOUBLE,MPI_SUM,PetscObjectComm((PetscObject)A))); 1234 1235 ginfo->nz_used = irecv[0]; 1236 ginfo->nz_allocated = irecv[1]; 1237 ginfo->nz_unneeded = irecv[2]; 1238 ginfo->memory = irecv[3]; 1239 ginfo->mallocs = irecv[4]; 1240 ginfo->assemblies = A->num_ass; 1241 } 1242 ginfo->block_size = bs; 1243 ginfo->fill_ratio_given = 0; 1244 ginfo->fill_ratio_needed = 0; 1245 ginfo->factor_mallocs = 0; 1246 PetscFunctionReturn(0); 1247 } 1248 1249 static PetscErrorCode MatTranspose_IS(Mat A,MatReuse reuse,Mat *B) 1250 { 1251 Mat C,lC,lA; 1252 1253 PetscFunctionBegin; 1254 if (reuse == MAT_REUSE_MATRIX) PetscCall(MatTransposeCheckNonzeroState_Private(A,*B)); 1255 if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_INPLACE_MATRIX) { 1256 ISLocalToGlobalMapping rl2g,cl2g; 1257 PetscCall(MatCreate(PetscObjectComm((PetscObject)A),&C)); 1258 PetscCall(MatSetSizes(C,A->cmap->n,A->rmap->n,A->cmap->N,A->rmap->N)); 1259 PetscCall(MatSetBlockSizes(C,PetscAbs(A->cmap->bs),PetscAbs(A->rmap->bs))); 1260 PetscCall(MatSetType(C,MATIS)); 1261 PetscCall(MatGetLocalToGlobalMapping(A,&rl2g,&cl2g)); 1262 PetscCall(MatSetLocalToGlobalMapping(C,cl2g,rl2g)); 1263 } else C = *B; 1264 1265 /* perform local transposition */ 1266 PetscCall(MatISGetLocalMat(A,&lA)); 1267 PetscCall(MatTranspose(lA,MAT_INITIAL_MATRIX,&lC)); 1268 PetscCall(MatSetLocalToGlobalMapping(lC,lA->cmap->mapping,lA->rmap->mapping)); 1269 PetscCall(MatISSetLocalMat(C,lC)); 1270 PetscCall(MatDestroy(&lC)); 1271 1272 if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_REUSE_MATRIX) { 1273 *B = C; 1274 } else { 1275 PetscCall(MatHeaderMerge(A,&C)); 1276 } 1277 PetscCall(MatAssemblyBegin(*B,MAT_FINAL_ASSEMBLY)); 1278 PetscCall(MatAssemblyEnd(*B,MAT_FINAL_ASSEMBLY)); 1279 PetscFunctionReturn(0); 1280 } 1281 1282 static PetscErrorCode MatDiagonalSet_IS(Mat A,Vec D,InsertMode insmode) 1283 { 1284 Mat_IS *is = (Mat_IS*)A->data; 1285 1286 PetscFunctionBegin; 1287 if (D) { /* MatShift_IS pass D = NULL */ 1288 PetscCall(VecScatterBegin(is->rctx,D,is->y,INSERT_VALUES,SCATTER_FORWARD)); 1289 PetscCall(VecScatterEnd(is->rctx,D,is->y,INSERT_VALUES,SCATTER_FORWARD)); 1290 } 1291 PetscCall(VecPointwiseDivide(is->y,is->y,is->counter)); 1292 PetscCall(MatDiagonalSet(is->A,is->y,insmode)); 1293 PetscFunctionReturn(0); 1294 } 1295 1296 static PetscErrorCode MatShift_IS(Mat A,PetscScalar a) 1297 { 1298 Mat_IS *is = (Mat_IS*)A->data; 1299 1300 PetscFunctionBegin; 1301 PetscCall(VecSet(is->y,a)); 1302 PetscCall(MatDiagonalSet_IS(A,NULL,ADD_VALUES)); 1303 PetscFunctionReturn(0); 1304 } 1305 1306 static PetscErrorCode MatSetValuesLocal_SubMat_IS(Mat A,PetscInt m,const PetscInt *rows, PetscInt n,const PetscInt *cols,const PetscScalar *values,InsertMode addv) 1307 { 1308 PetscInt rows_l[MATIS_MAX_ENTRIES_INSERTION],cols_l[MATIS_MAX_ENTRIES_INSERTION]; 1309 1310 PetscFunctionBegin; 1311 PetscCheck(m <= MATIS_MAX_ENTRIES_INSERTION && n <= MATIS_MAX_ENTRIES_INSERTION,PETSC_COMM_SELF,PETSC_ERR_SUP,"Number of row/column indices must be <= %d: they are %" PetscInt_FMT " %" PetscInt_FMT,MATIS_MAX_ENTRIES_INSERTION,m,n); 1312 PetscCall(ISLocalToGlobalMappingApply(A->rmap->mapping,m,rows,rows_l)); 1313 PetscCall(ISLocalToGlobalMappingApply(A->cmap->mapping,n,cols,cols_l)); 1314 PetscCall(MatSetValuesLocal_IS(A,m,rows_l,n,cols_l,values,addv)); 1315 PetscFunctionReturn(0); 1316 } 1317 1318 static PetscErrorCode MatSetValuesBlockedLocal_SubMat_IS(Mat A,PetscInt m,const PetscInt *rows, PetscInt n,const PetscInt *cols,const PetscScalar *values,InsertMode addv) 1319 { 1320 PetscInt rows_l[MATIS_MAX_ENTRIES_INSERTION],cols_l[MATIS_MAX_ENTRIES_INSERTION]; 1321 1322 PetscFunctionBegin; 1323 PetscCheck(m <= MATIS_MAX_ENTRIES_INSERTION && n <= MATIS_MAX_ENTRIES_INSERTION,PETSC_COMM_SELF,PETSC_ERR_SUP,"Number of row/column block indices must be <= %d: they are %" PetscInt_FMT " %" PetscInt_FMT,MATIS_MAX_ENTRIES_INSERTION,m,n); 1324 PetscCall(ISLocalToGlobalMappingApplyBlock(A->rmap->mapping,m,rows,rows_l)); 1325 PetscCall(ISLocalToGlobalMappingApplyBlock(A->cmap->mapping,n,cols,cols_l)); 1326 PetscCall(MatSetValuesBlockedLocal_IS(A,m,rows_l,n,cols_l,values,addv)); 1327 PetscFunctionReturn(0); 1328 } 1329 1330 static PetscErrorCode MatCreateSubMatrix_IS(Mat mat,IS irow,IS icol,MatReuse scall,Mat *newmat) 1331 { 1332 Mat locmat,newlocmat; 1333 Mat_IS *newmatis; 1334 const PetscInt *idxs; 1335 PetscInt i,m,n; 1336 1337 PetscFunctionBegin; 1338 if (scall == MAT_REUSE_MATRIX) { 1339 PetscBool ismatis; 1340 1341 PetscCall(PetscObjectTypeCompare((PetscObject)*newmat,MATIS,&ismatis)); 1342 PetscCheck(ismatis,PetscObjectComm((PetscObject)*newmat),PETSC_ERR_ARG_WRONG,"Cannot reuse matrix! Not of MATIS type"); 1343 newmatis = (Mat_IS*)(*newmat)->data; 1344 PetscCheck(newmatis->getsub_ris,PetscObjectComm((PetscObject)*newmat),PETSC_ERR_ARG_WRONG,"Cannot reuse matrix! Misses local row IS"); 1345 PetscCheck(newmatis->getsub_cis,PetscObjectComm((PetscObject)*newmat),PETSC_ERR_ARG_WRONG,"Cannot reuse matrix! Misses local col IS"); 1346 } 1347 /* irow and icol may not have duplicate entries */ 1348 if (PetscDefined(USE_DEBUG)) { 1349 Vec rtest,ltest; 1350 const PetscScalar *array; 1351 1352 PetscCall(MatCreateVecs(mat,<est,&rtest)); 1353 PetscCall(ISGetLocalSize(irow,&n)); 1354 PetscCall(ISGetIndices(irow,&idxs)); 1355 for (i=0;i<n;i++) { 1356 PetscCall(VecSetValue(rtest,idxs[i],1.0,ADD_VALUES)); 1357 } 1358 PetscCall(VecAssemblyBegin(rtest)); 1359 PetscCall(VecAssemblyEnd(rtest)); 1360 PetscCall(VecGetLocalSize(rtest,&n)); 1361 PetscCall(VecGetOwnershipRange(rtest,&m,NULL)); 1362 PetscCall(VecGetArrayRead(rtest,&array)); 1363 for (i=0;i<n;i++) PetscCheck(array[i] == 0. || array[i] == 1.,PETSC_COMM_SELF,PETSC_ERR_SUP,"Index %" PetscInt_FMT " counted %" PetscInt_FMT " times! Irow may not have duplicate entries",i+m,(PetscInt)PetscRealPart(array[i])); 1364 PetscCall(VecRestoreArrayRead(rtest,&array)); 1365 PetscCall(ISRestoreIndices(irow,&idxs)); 1366 PetscCall(ISGetLocalSize(icol,&n)); 1367 PetscCall(ISGetIndices(icol,&idxs)); 1368 for (i=0;i<n;i++) { 1369 PetscCall(VecSetValue(ltest,idxs[i],1.0,ADD_VALUES)); 1370 } 1371 PetscCall(VecAssemblyBegin(ltest)); 1372 PetscCall(VecAssemblyEnd(ltest)); 1373 PetscCall(VecGetLocalSize(ltest,&n)); 1374 PetscCall(VecGetOwnershipRange(ltest,&m,NULL)); 1375 PetscCall(VecGetArrayRead(ltest,&array)); 1376 for (i=0;i<n;i++) PetscCheck(array[i] == 0. || array[i] == 1.,PETSC_COMM_SELF,PETSC_ERR_SUP,"Index %" PetscInt_FMT " counted %" PetscInt_FMT " times! Icol may not have duplicate entries",i+m,(PetscInt)PetscRealPart(array[i])); 1377 PetscCall(VecRestoreArrayRead(ltest,&array)); 1378 PetscCall(ISRestoreIndices(icol,&idxs)); 1379 PetscCall(VecDestroy(&rtest)); 1380 PetscCall(VecDestroy(<est)); 1381 } 1382 if (scall == MAT_INITIAL_MATRIX) { 1383 Mat_IS *matis = (Mat_IS*)mat->data; 1384 ISLocalToGlobalMapping rl2g; 1385 IS is; 1386 PetscInt *lidxs,*lgidxs,*newgidxs; 1387 PetscInt ll,newloc,irbs,icbs,arbs,acbs,rbs,cbs; 1388 PetscBool cong; 1389 MPI_Comm comm; 1390 1391 PetscCall(PetscObjectGetComm((PetscObject)mat,&comm)); 1392 PetscCall(MatGetBlockSizes(mat,&arbs,&acbs)); 1393 PetscCall(ISGetBlockSize(irow,&irbs)); 1394 PetscCall(ISGetBlockSize(icol,&icbs)); 1395 rbs = arbs == irbs ? irbs : 1; 1396 cbs = acbs == icbs ? icbs : 1; 1397 PetscCall(ISGetLocalSize(irow,&m)); 1398 PetscCall(ISGetLocalSize(icol,&n)); 1399 PetscCall(MatCreate(comm,newmat)); 1400 PetscCall(MatSetType(*newmat,MATIS)); 1401 PetscCall(MatSetSizes(*newmat,m,n,PETSC_DECIDE,PETSC_DECIDE)); 1402 PetscCall(MatSetBlockSizes(*newmat,rbs,cbs)); 1403 /* communicate irow to their owners in the layout */ 1404 PetscCall(ISGetIndices(irow,&idxs)); 1405 PetscCall(PetscLayoutMapLocal(mat->rmap,m,idxs,&ll,&lidxs,&lgidxs)); 1406 PetscCall(ISRestoreIndices(irow,&idxs)); 1407 PetscCall(PetscArrayzero(matis->sf_rootdata,matis->sf->nroots)); 1408 for (i=0;i<ll;i++) matis->sf_rootdata[lidxs[i]] = lgidxs[i]+1; 1409 PetscCall(PetscFree(lidxs)); 1410 PetscCall(PetscFree(lgidxs)); 1411 PetscCall(PetscSFBcastBegin(matis->sf,MPIU_INT,matis->sf_rootdata,matis->sf_leafdata,MPI_REPLACE)); 1412 PetscCall(PetscSFBcastEnd(matis->sf,MPIU_INT,matis->sf_rootdata,matis->sf_leafdata,MPI_REPLACE)); 1413 for (i=0,newloc=0;i<matis->sf->nleaves;i++) if (matis->sf_leafdata[i]) newloc++; 1414 PetscCall(PetscMalloc1(newloc,&newgidxs)); 1415 PetscCall(PetscMalloc1(newloc,&lidxs)); 1416 for (i=0,newloc=0;i<matis->sf->nleaves;i++) 1417 if (matis->sf_leafdata[i]) { 1418 lidxs[newloc] = i; 1419 newgidxs[newloc++] = matis->sf_leafdata[i]-1; 1420 } 1421 PetscCall(ISCreateGeneral(comm,newloc,newgidxs,PETSC_OWN_POINTER,&is)); 1422 PetscCall(ISLocalToGlobalMappingCreateIS(is,&rl2g)); 1423 PetscCall(ISLocalToGlobalMappingSetBlockSize(rl2g,rbs)); 1424 PetscCall(ISDestroy(&is)); 1425 /* local is to extract local submatrix */ 1426 newmatis = (Mat_IS*)(*newmat)->data; 1427 PetscCall(ISCreateGeneral(comm,newloc,lidxs,PETSC_OWN_POINTER,&newmatis->getsub_ris)); 1428 PetscCall(MatHasCongruentLayouts(mat,&cong)); 1429 if (cong && irow == icol && matis->csf == matis->sf) { 1430 PetscCall(MatSetLocalToGlobalMapping(*newmat,rl2g,rl2g)); 1431 PetscCall(PetscObjectReference((PetscObject)newmatis->getsub_ris)); 1432 newmatis->getsub_cis = newmatis->getsub_ris; 1433 } else { 1434 ISLocalToGlobalMapping cl2g; 1435 1436 /* communicate icol to their owners in the layout */ 1437 PetscCall(ISGetIndices(icol,&idxs)); 1438 PetscCall(PetscLayoutMapLocal(mat->cmap,n,idxs,&ll,&lidxs,&lgidxs)); 1439 PetscCall(ISRestoreIndices(icol,&idxs)); 1440 PetscCall(PetscArrayzero(matis->csf_rootdata,matis->csf->nroots)); 1441 for (i=0;i<ll;i++) matis->csf_rootdata[lidxs[i]] = lgidxs[i]+1; 1442 PetscCall(PetscFree(lidxs)); 1443 PetscCall(PetscFree(lgidxs)); 1444 PetscCall(PetscSFBcastBegin(matis->csf,MPIU_INT,matis->csf_rootdata,matis->csf_leafdata,MPI_REPLACE)); 1445 PetscCall(PetscSFBcastEnd(matis->csf,MPIU_INT,matis->csf_rootdata,matis->csf_leafdata,MPI_REPLACE)); 1446 for (i=0,newloc=0;i<matis->csf->nleaves;i++) if (matis->csf_leafdata[i]) newloc++; 1447 PetscCall(PetscMalloc1(newloc,&newgidxs)); 1448 PetscCall(PetscMalloc1(newloc,&lidxs)); 1449 for (i=0,newloc=0;i<matis->csf->nleaves;i++) 1450 if (matis->csf_leafdata[i]) { 1451 lidxs[newloc] = i; 1452 newgidxs[newloc++] = matis->csf_leafdata[i]-1; 1453 } 1454 PetscCall(ISCreateGeneral(comm,newloc,newgidxs,PETSC_OWN_POINTER,&is)); 1455 PetscCall(ISLocalToGlobalMappingCreateIS(is,&cl2g)); 1456 PetscCall(ISLocalToGlobalMappingSetBlockSize(cl2g,cbs)); 1457 PetscCall(ISDestroy(&is)); 1458 /* local is to extract local submatrix */ 1459 PetscCall(ISCreateGeneral(comm,newloc,lidxs,PETSC_OWN_POINTER,&newmatis->getsub_cis)); 1460 PetscCall(MatSetLocalToGlobalMapping(*newmat,rl2g,cl2g)); 1461 PetscCall(ISLocalToGlobalMappingDestroy(&cl2g)); 1462 } 1463 PetscCall(ISLocalToGlobalMappingDestroy(&rl2g)); 1464 } else { 1465 PetscCall(MatISGetLocalMat(*newmat,&newlocmat)); 1466 } 1467 PetscCall(MatISGetLocalMat(mat,&locmat)); 1468 newmatis = (Mat_IS*)(*newmat)->data; 1469 PetscCall(MatCreateSubMatrix(locmat,newmatis->getsub_ris,newmatis->getsub_cis,scall,&newlocmat)); 1470 if (scall == MAT_INITIAL_MATRIX) { 1471 PetscCall(MatISSetLocalMat(*newmat,newlocmat)); 1472 PetscCall(MatDestroy(&newlocmat)); 1473 } 1474 PetscCall(MatAssemblyBegin(*newmat,MAT_FINAL_ASSEMBLY)); 1475 PetscCall(MatAssemblyEnd(*newmat,MAT_FINAL_ASSEMBLY)); 1476 PetscFunctionReturn(0); 1477 } 1478 1479 static PetscErrorCode MatCopy_IS(Mat A,Mat B,MatStructure str) 1480 { 1481 Mat_IS *a = (Mat_IS*)A->data,*b; 1482 PetscBool ismatis; 1483 1484 PetscFunctionBegin; 1485 PetscCall(PetscObjectTypeCompare((PetscObject)B,MATIS,&ismatis)); 1486 PetscCheck(ismatis,PetscObjectComm((PetscObject)B),PETSC_ERR_SUP,"Need to be implemented"); 1487 b = (Mat_IS*)B->data; 1488 PetscCall(MatCopy(a->A,b->A,str)); 1489 PetscCall(PetscObjectStateIncrease((PetscObject)B)); 1490 PetscFunctionReturn(0); 1491 } 1492 1493 static PetscErrorCode MatMissingDiagonal_IS(Mat A,PetscBool *missing,PetscInt *d) 1494 { 1495 Vec v; 1496 const PetscScalar *array; 1497 PetscInt i,n; 1498 1499 PetscFunctionBegin; 1500 *missing = PETSC_FALSE; 1501 PetscCall(MatCreateVecs(A,NULL,&v)); 1502 PetscCall(MatGetDiagonal(A,v)); 1503 PetscCall(VecGetLocalSize(v,&n)); 1504 PetscCall(VecGetArrayRead(v,&array)); 1505 for (i=0;i<n;i++) if (array[i] == 0.) break; 1506 PetscCall(VecRestoreArrayRead(v,&array)); 1507 PetscCall(VecDestroy(&v)); 1508 if (i != n) *missing = PETSC_TRUE; 1509 if (d) { 1510 *d = -1; 1511 if (*missing) { 1512 PetscInt rstart; 1513 PetscCall(MatGetOwnershipRange(A,&rstart,NULL)); 1514 *d = i+rstart; 1515 } 1516 } 1517 PetscFunctionReturn(0); 1518 } 1519 1520 static PetscErrorCode MatISSetUpSF_IS(Mat B) 1521 { 1522 Mat_IS *matis = (Mat_IS*)(B->data); 1523 const PetscInt *gidxs; 1524 PetscInt nleaves; 1525 1526 PetscFunctionBegin; 1527 if (matis->sf) PetscFunctionReturn(0); 1528 PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)B),&matis->sf)); 1529 PetscCall(ISLocalToGlobalMappingGetIndices(matis->rmapping,&gidxs)); 1530 PetscCall(ISLocalToGlobalMappingGetSize(matis->rmapping,&nleaves)); 1531 PetscCall(PetscSFSetGraphLayout(matis->sf,B->rmap,nleaves,NULL,PETSC_OWN_POINTER,gidxs)); 1532 PetscCall(ISLocalToGlobalMappingRestoreIndices(matis->rmapping,&gidxs)); 1533 PetscCall(PetscMalloc2(matis->sf->nroots,&matis->sf_rootdata,matis->sf->nleaves,&matis->sf_leafdata)); 1534 if (matis->rmapping != matis->cmapping) { /* setup SF for columns */ 1535 PetscCall(ISLocalToGlobalMappingGetSize(matis->cmapping,&nleaves)); 1536 PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)B),&matis->csf)); 1537 PetscCall(ISLocalToGlobalMappingGetIndices(matis->cmapping,&gidxs)); 1538 PetscCall(PetscSFSetGraphLayout(matis->csf,B->cmap,nleaves,NULL,PETSC_OWN_POINTER,gidxs)); 1539 PetscCall(ISLocalToGlobalMappingRestoreIndices(matis->cmapping,&gidxs)); 1540 PetscCall(PetscMalloc2(matis->csf->nroots,&matis->csf_rootdata,matis->csf->nleaves,&matis->csf_leafdata)); 1541 } else { 1542 matis->csf = matis->sf; 1543 matis->csf_leafdata = matis->sf_leafdata; 1544 matis->csf_rootdata = matis->sf_rootdata; 1545 } 1546 PetscFunctionReturn(0); 1547 } 1548 1549 /*@ 1550 MatISStoreL2L - Store local-to-local operators during the Galerkin process of MatPtAP. 1551 1552 Collective 1553 1554 Input Parameters: 1555 + A - the matrix 1556 - store - the boolean flag 1557 1558 Level: advanced 1559 1560 Notes: 1561 1562 .seealso: `MatCreate()`, `MatCreateIS()`, `MatISSetPreallocation()`, `MatPtAP()` 1563 @*/ 1564 PetscErrorCode MatISStoreL2L(Mat A, PetscBool store) 1565 { 1566 PetscFunctionBegin; 1567 PetscValidHeaderSpecific(A,MAT_CLASSID,1); 1568 PetscValidType(A,1); 1569 PetscValidLogicalCollectiveBool(A,store,2); 1570 PetscTryMethod(A,"MatISStoreL2L_C",(Mat,PetscBool),(A,store)); 1571 PetscFunctionReturn(0); 1572 } 1573 1574 static PetscErrorCode MatISStoreL2L_IS(Mat A, PetscBool store) 1575 { 1576 Mat_IS *matis = (Mat_IS*)(A->data); 1577 1578 PetscFunctionBegin; 1579 matis->storel2l = store; 1580 if (!store) { 1581 PetscCall(PetscObjectCompose((PetscObject)(A),"_MatIS_PtAP_l2l",NULL)); 1582 } 1583 PetscFunctionReturn(0); 1584 } 1585 1586 /*@ 1587 MatISFixLocalEmpty - Compress out zero local rows from the local matrices 1588 1589 Collective 1590 1591 Input Parameters: 1592 + A - the matrix 1593 - fix - the boolean flag 1594 1595 Level: advanced 1596 1597 Notes: When fix is true, new local matrices and l2g maps are generated during the final assembly process. 1598 1599 .seealso: `MatCreate()`, `MatCreateIS()`, `MatISSetPreallocation()`, `MatAssemblyEnd()`, `MAT_FINAL_ASSEMBLY` 1600 @*/ 1601 PetscErrorCode MatISFixLocalEmpty(Mat A, PetscBool fix) 1602 { 1603 PetscFunctionBegin; 1604 PetscValidHeaderSpecific(A,MAT_CLASSID,1); 1605 PetscValidType(A,1); 1606 PetscValidLogicalCollectiveBool(A,fix,2); 1607 PetscTryMethod(A,"MatISFixLocalEmpty_C",(Mat,PetscBool),(A,fix)); 1608 PetscFunctionReturn(0); 1609 } 1610 1611 static PetscErrorCode MatISFixLocalEmpty_IS(Mat A, PetscBool fix) 1612 { 1613 Mat_IS *matis = (Mat_IS*)(A->data); 1614 1615 PetscFunctionBegin; 1616 matis->locempty = fix; 1617 PetscFunctionReturn(0); 1618 } 1619 1620 /*@ 1621 MatISSetPreallocation - Preallocates memory for a MATIS parallel matrix. 1622 1623 Collective 1624 1625 Input Parameters: 1626 + B - the matrix 1627 . d_nz - number of nonzeros per row in DIAGONAL portion of local submatrix 1628 (same value is used for all local rows) 1629 . d_nnz - array containing the number of nonzeros in the various rows of the 1630 DIAGONAL portion of the local submatrix (possibly different for each row) 1631 or NULL, if d_nz is used to specify the nonzero structure. 1632 The size of this array is equal to the number of local rows, i.e 'm'. 1633 For matrices that will be factored, you must leave room for (and set) 1634 the diagonal entry even if it is zero. 1635 . o_nz - number of nonzeros per row in the OFF-DIAGONAL portion of local 1636 submatrix (same value is used for all local rows). 1637 - o_nnz - array containing the number of nonzeros in the various rows of the 1638 OFF-DIAGONAL portion of the local submatrix (possibly different for 1639 each row) or NULL, if o_nz is used to specify the nonzero 1640 structure. The size of this array is equal to the number 1641 of local rows, i.e 'm'. 1642 1643 If the *_nnz parameter is given then the *_nz parameter is ignored 1644 1645 Level: intermediate 1646 1647 Notes: 1648 This function has the same interface as the MPIAIJ preallocation routine in order to simplify the transition 1649 from the asssembled format to the unassembled one. It overestimates the preallocation of MATIS local 1650 matrices; for exact preallocation, the user should set the preallocation directly on local matrix objects. 1651 1652 .seealso: `MatCreate()`, `MatCreateIS()`, `MatMPIAIJSetPreallocation()`, `MatISGetLocalMat()`, `MATIS` 1653 @*/ 1654 PetscErrorCode MatISSetPreallocation(Mat B,PetscInt d_nz,const PetscInt d_nnz[],PetscInt o_nz,const PetscInt o_nnz[]) 1655 { 1656 PetscFunctionBegin; 1657 PetscValidHeaderSpecific(B,MAT_CLASSID,1); 1658 PetscValidType(B,1); 1659 PetscTryMethod(B,"MatISSetPreallocation_C",(Mat,PetscInt,const PetscInt[],PetscInt,const PetscInt[]),(B,d_nz,d_nnz,o_nz,o_nnz)); 1660 PetscFunctionReturn(0); 1661 } 1662 1663 /* this is used by DMDA */ 1664 PETSC_EXTERN PetscErrorCode MatISSetPreallocation_IS(Mat B,PetscInt d_nz,const PetscInt d_nnz[],PetscInt o_nz,const PetscInt o_nnz[]) 1665 { 1666 Mat_IS *matis = (Mat_IS*)(B->data); 1667 PetscInt bs,i,nlocalcols; 1668 1669 PetscFunctionBegin; 1670 PetscCall(MatSetUp(B)); 1671 if (!d_nnz) for (i=0;i<matis->sf->nroots;i++) matis->sf_rootdata[i] = d_nz; 1672 else for (i=0;i<matis->sf->nroots;i++) matis->sf_rootdata[i] = d_nnz[i]; 1673 1674 if (!o_nnz) for (i=0;i<matis->sf->nroots;i++) matis->sf_rootdata[i] += o_nz; 1675 else for (i=0;i<matis->sf->nroots;i++) matis->sf_rootdata[i] += o_nnz[i]; 1676 1677 PetscCall(PetscSFBcastBegin(matis->sf,MPIU_INT,matis->sf_rootdata,matis->sf_leafdata,MPI_REPLACE)); 1678 PetscCall(MatGetSize(matis->A,NULL,&nlocalcols)); 1679 PetscCall(MatGetBlockSize(matis->A,&bs)); 1680 PetscCall(PetscSFBcastEnd(matis->sf,MPIU_INT,matis->sf_rootdata,matis->sf_leafdata,MPI_REPLACE)); 1681 1682 for (i=0;i<matis->sf->nleaves;i++) matis->sf_leafdata[i] = PetscMin(matis->sf_leafdata[i],nlocalcols); 1683 PetscCall(MatSeqAIJSetPreallocation(matis->A,0,matis->sf_leafdata)); 1684 #if defined(PETSC_HAVE_HYPRE) 1685 PetscCall(MatHYPRESetPreallocation(matis->A,0,matis->sf_leafdata,0,NULL)); 1686 #endif 1687 1688 for (i=0;i<matis->sf->nleaves/bs;i++) { 1689 PetscInt b; 1690 1691 matis->sf_leafdata[i] = matis->sf_leafdata[i*bs]/bs; 1692 for (b=1;b<bs;b++) { 1693 matis->sf_leafdata[i] = PetscMax(matis->sf_leafdata[i],matis->sf_leafdata[i*bs+b]/bs); 1694 } 1695 } 1696 PetscCall(MatSeqBAIJSetPreallocation(matis->A,bs,0,matis->sf_leafdata)); 1697 1698 nlocalcols /= bs; 1699 for (i=0;i<matis->sf->nleaves/bs;i++) matis->sf_leafdata[i] = PetscMin(matis->sf_leafdata[i],nlocalcols - i); 1700 PetscCall(MatSeqSBAIJSetPreallocation(matis->A,bs,0,matis->sf_leafdata)); 1701 1702 /* for other matrix types */ 1703 PetscCall(MatSetUp(matis->A)); 1704 PetscFunctionReturn(0); 1705 } 1706 1707 PETSC_EXTERN PetscErrorCode MatISSetMPIXAIJPreallocation_Private(Mat A, Mat B, PetscBool maxreduce) 1708 { 1709 Mat_IS *matis = (Mat_IS*)(A->data); 1710 PetscInt *my_dnz,*my_onz,*dnz,*onz,*mat_ranges,*row_ownership; 1711 const PetscInt *global_indices_r,*global_indices_c; 1712 PetscInt i,j,bs,rows,cols; 1713 PetscInt lrows,lcols; 1714 PetscInt local_rows,local_cols; 1715 PetscMPIInt size; 1716 PetscBool isdense,issbaij; 1717 1718 PetscFunctionBegin; 1719 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A),&size)); 1720 PetscCall(MatGetSize(A,&rows,&cols)); 1721 PetscCall(MatGetBlockSize(A,&bs)); 1722 PetscCall(MatGetSize(matis->A,&local_rows,&local_cols)); 1723 PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A,MATSEQDENSE,&isdense)); 1724 PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A,MATSEQSBAIJ,&issbaij)); 1725 PetscCall(ISLocalToGlobalMappingGetIndices(matis->rmapping,&global_indices_r)); 1726 if (matis->rmapping != matis->cmapping) { 1727 PetscCall(ISLocalToGlobalMappingGetIndices(matis->cmapping,&global_indices_c)); 1728 } else global_indices_c = global_indices_r; 1729 1730 if (issbaij) PetscCall(MatGetRowUpperTriangular(matis->A)); 1731 /* 1732 An SF reduce is needed to sum up properly on shared rows. 1733 Note that generally preallocation is not exact, since it overestimates nonzeros 1734 */ 1735 PetscCall(MatGetLocalSize(A,&lrows,&lcols)); 1736 MatPreallocateBegin(PetscObjectComm((PetscObject)A),lrows,lcols,dnz,onz); 1737 /* All processes need to compute entire row ownership */ 1738 PetscCall(PetscMalloc1(rows,&row_ownership)); 1739 PetscCall(MatGetOwnershipRanges(A,(const PetscInt**)&mat_ranges)); 1740 for (i=0;i<size;i++) { 1741 for (j=mat_ranges[i];j<mat_ranges[i+1];j++) row_ownership[j] = i; 1742 } 1743 PetscCall(MatGetOwnershipRangesColumn(A,(const PetscInt**)&mat_ranges)); 1744 1745 /* 1746 my_dnz and my_onz contains exact contribution to preallocation from each local mat 1747 then, they will be summed up properly. This way, preallocation is always sufficient 1748 */ 1749 PetscCall(PetscCalloc2(local_rows,&my_dnz,local_rows,&my_onz)); 1750 /* preallocation as a MATAIJ */ 1751 if (isdense) { /* special case for dense local matrices */ 1752 for (i=0;i<local_rows;i++) { 1753 PetscInt owner = row_ownership[global_indices_r[i]]; 1754 for (j=0;j<local_cols;j++) { 1755 PetscInt index_col = global_indices_c[j]; 1756 if (index_col > mat_ranges[owner]-1 && index_col < mat_ranges[owner+1]) { /* diag block */ 1757 my_dnz[i] += 1; 1758 } else { /* offdiag block */ 1759 my_onz[i] += 1; 1760 } 1761 } 1762 } 1763 } else if (matis->A->ops->getrowij) { 1764 const PetscInt *ii,*jj,*jptr; 1765 PetscBool done; 1766 PetscCall(MatGetRowIJ(matis->A,0,PETSC_FALSE,PETSC_FALSE,&local_rows,&ii,&jj,&done)); 1767 PetscCheck(done,PetscObjectComm((PetscObject)(matis->A)),PETSC_ERR_PLIB,"Error in MatGetRowIJ"); 1768 jptr = jj; 1769 for (i=0;i<local_rows;i++) { 1770 PetscInt index_row = global_indices_r[i]; 1771 for (j=0;j<ii[i+1]-ii[i];j++,jptr++) { 1772 PetscInt owner = row_ownership[index_row]; 1773 PetscInt index_col = global_indices_c[*jptr]; 1774 if (index_col > mat_ranges[owner]-1 && index_col < mat_ranges[owner+1]) { /* diag block */ 1775 my_dnz[i] += 1; 1776 } else { /* offdiag block */ 1777 my_onz[i] += 1; 1778 } 1779 /* same as before, interchanging rows and cols */ 1780 if (issbaij && index_col != index_row) { 1781 owner = row_ownership[index_col]; 1782 if (index_row > mat_ranges[owner]-1 && index_row < mat_ranges[owner+1]) { 1783 my_dnz[*jptr] += 1; 1784 } else { 1785 my_onz[*jptr] += 1; 1786 } 1787 } 1788 } 1789 } 1790 PetscCall(MatRestoreRowIJ(matis->A,0,PETSC_FALSE,PETSC_FALSE,&local_rows,&ii,&jj,&done)); 1791 PetscCheck(done,PetscObjectComm((PetscObject)(matis->A)),PETSC_ERR_PLIB,"Error in MatRestoreRowIJ"); 1792 } else { /* loop over rows and use MatGetRow */ 1793 for (i=0;i<local_rows;i++) { 1794 const PetscInt *cols; 1795 PetscInt ncols,index_row = global_indices_r[i]; 1796 PetscCall(MatGetRow(matis->A,i,&ncols,&cols,NULL)); 1797 for (j=0;j<ncols;j++) { 1798 PetscInt owner = row_ownership[index_row]; 1799 PetscInt index_col = global_indices_c[cols[j]]; 1800 if (index_col > mat_ranges[owner]-1 && index_col < mat_ranges[owner+1]) { /* diag block */ 1801 my_dnz[i] += 1; 1802 } else { /* offdiag block */ 1803 my_onz[i] += 1; 1804 } 1805 /* same as before, interchanging rows and cols */ 1806 if (issbaij && index_col != index_row) { 1807 owner = row_ownership[index_col]; 1808 if (index_row > mat_ranges[owner]-1 && index_row < mat_ranges[owner+1]) { 1809 my_dnz[cols[j]] += 1; 1810 } else { 1811 my_onz[cols[j]] += 1; 1812 } 1813 } 1814 } 1815 PetscCall(MatRestoreRow(matis->A,i,&ncols,&cols,NULL)); 1816 } 1817 } 1818 if (global_indices_c != global_indices_r) { 1819 PetscCall(ISLocalToGlobalMappingRestoreIndices(matis->cmapping,&global_indices_c)); 1820 } 1821 PetscCall(ISLocalToGlobalMappingRestoreIndices(matis->rmapping,&global_indices_r)); 1822 PetscCall(PetscFree(row_ownership)); 1823 1824 /* Reduce my_dnz and my_onz */ 1825 if (maxreduce) { 1826 PetscCall(PetscSFReduceBegin(matis->sf,MPIU_INT,my_dnz,dnz,MPI_MAX)); 1827 PetscCall(PetscSFReduceBegin(matis->sf,MPIU_INT,my_onz,onz,MPI_MAX)); 1828 PetscCall(PetscSFReduceEnd(matis->sf,MPIU_INT,my_dnz,dnz,MPI_MAX)); 1829 PetscCall(PetscSFReduceEnd(matis->sf,MPIU_INT,my_onz,onz,MPI_MAX)); 1830 } else { 1831 PetscCall(PetscSFReduceBegin(matis->sf,MPIU_INT,my_dnz,dnz,MPI_SUM)); 1832 PetscCall(PetscSFReduceBegin(matis->sf,MPIU_INT,my_onz,onz,MPI_SUM)); 1833 PetscCall(PetscSFReduceEnd(matis->sf,MPIU_INT,my_dnz,dnz,MPI_SUM)); 1834 PetscCall(PetscSFReduceEnd(matis->sf,MPIU_INT,my_onz,onz,MPI_SUM)); 1835 } 1836 PetscCall(PetscFree2(my_dnz,my_onz)); 1837 1838 /* Resize preallocation if overestimated */ 1839 for (i=0;i<lrows;i++) { 1840 dnz[i] = PetscMin(dnz[i],lcols); 1841 onz[i] = PetscMin(onz[i],cols-lcols); 1842 } 1843 1844 /* Set preallocation */ 1845 PetscCall(MatSetBlockSizesFromMats(B,A,A)); 1846 PetscCall(MatSeqAIJSetPreallocation(B,0,dnz)); 1847 PetscCall(MatMPIAIJSetPreallocation(B,0,dnz,0,onz)); 1848 for (i=0;i<lrows;i+=bs) { 1849 PetscInt b, d = dnz[i],o = onz[i]; 1850 1851 for (b=1;b<bs;b++) { 1852 d = PetscMax(d,dnz[i+b]); 1853 o = PetscMax(o,onz[i+b]); 1854 } 1855 dnz[i/bs] = PetscMin(d/bs + d%bs,lcols/bs); 1856 onz[i/bs] = PetscMin(o/bs + o%bs,(cols-lcols)/bs); 1857 } 1858 PetscCall(MatSeqBAIJSetPreallocation(B,bs,0,dnz)); 1859 PetscCall(MatMPIBAIJSetPreallocation(B,bs,0,dnz,0,onz)); 1860 PetscCall(MatMPISBAIJSetPreallocation(B,bs,0,dnz,0,onz)); 1861 MatPreallocateEnd(dnz,onz); 1862 if (issbaij) PetscCall(MatRestoreRowUpperTriangular(matis->A)); 1863 PetscCall(MatSetOption(B,MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE)); 1864 PetscFunctionReturn(0); 1865 } 1866 1867 PETSC_INTERN PetscErrorCode MatConvert_IS_XAIJ(Mat mat, MatType mtype, MatReuse reuse, Mat *M) 1868 { 1869 Mat_IS *matis = (Mat_IS*)(mat->data); 1870 Mat local_mat,MT; 1871 PetscInt rbs,cbs,rows,cols,lrows,lcols; 1872 PetscInt local_rows,local_cols; 1873 PetscBool isseqdense,isseqsbaij,isseqaij,isseqbaij; 1874 PetscMPIInt size; 1875 const PetscScalar *array; 1876 1877 PetscFunctionBegin; 1878 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat),&size)); 1879 if (size == 1 && mat->rmap->N == matis->A->rmap->N && mat->cmap->N == matis->A->cmap->N) { 1880 Mat B; 1881 IS irows = NULL,icols = NULL; 1882 PetscInt rbs,cbs; 1883 1884 PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->rmapping,&rbs)); 1885 PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->cmapping,&cbs)); 1886 if (reuse != MAT_REUSE_MATRIX) { /* check if l2g maps are one-to-one */ 1887 IS rows,cols; 1888 const PetscInt *ridxs,*cidxs; 1889 PetscInt i,nw,*work; 1890 1891 PetscCall(ISLocalToGlobalMappingGetBlockIndices(matis->rmapping,&ridxs)); 1892 PetscCall(ISLocalToGlobalMappingGetSize(matis->rmapping,&nw)); 1893 nw = nw/rbs; 1894 PetscCall(PetscCalloc1(nw,&work)); 1895 for (i=0;i<nw;i++) work[ridxs[i]] += 1; 1896 for (i=0;i<nw;i++) if (!work[i] || work[i] > 1) break; 1897 if (i == nw) { 1898 PetscCall(ISCreateBlock(PETSC_COMM_SELF,rbs,nw,ridxs,PETSC_USE_POINTER,&rows)); 1899 PetscCall(ISSetPermutation(rows)); 1900 PetscCall(ISInvertPermutation(rows,PETSC_DECIDE,&irows)); 1901 PetscCall(ISDestroy(&rows)); 1902 } 1903 PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(matis->rmapping,&ridxs)); 1904 PetscCall(PetscFree(work)); 1905 if (irows && matis->rmapping != matis->cmapping) { 1906 PetscCall(ISLocalToGlobalMappingGetBlockIndices(matis->cmapping,&cidxs)); 1907 PetscCall(ISLocalToGlobalMappingGetSize(matis->cmapping,&nw)); 1908 nw = nw/cbs; 1909 PetscCall(PetscCalloc1(nw,&work)); 1910 for (i=0;i<nw;i++) work[cidxs[i]] += 1; 1911 for (i=0;i<nw;i++) if (!work[i] || work[i] > 1) break; 1912 if (i == nw) { 1913 PetscCall(ISCreateBlock(PETSC_COMM_SELF,cbs,nw,cidxs,PETSC_USE_POINTER,&cols)); 1914 PetscCall(ISSetPermutation(cols)); 1915 PetscCall(ISInvertPermutation(cols,PETSC_DECIDE,&icols)); 1916 PetscCall(ISDestroy(&cols)); 1917 } 1918 PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(matis->cmapping,&cidxs)); 1919 PetscCall(PetscFree(work)); 1920 } else if (irows) { 1921 PetscCall(PetscObjectReference((PetscObject)irows)); 1922 icols = irows; 1923 } 1924 } else { 1925 PetscCall(PetscObjectQuery((PetscObject)(*M),"_MatIS_IS_XAIJ_irows",(PetscObject*)&irows)); 1926 PetscCall(PetscObjectQuery((PetscObject)(*M),"_MatIS_IS_XAIJ_icols",(PetscObject*)&icols)); 1927 if (irows) PetscCall(PetscObjectReference((PetscObject)irows)); 1928 if (icols) PetscCall(PetscObjectReference((PetscObject)icols)); 1929 } 1930 if (!irows || !icols) { 1931 PetscCall(ISDestroy(&icols)); 1932 PetscCall(ISDestroy(&irows)); 1933 goto general_assembly; 1934 } 1935 PetscCall(MatConvert(matis->A,mtype,MAT_INITIAL_MATRIX,&B)); 1936 if (reuse != MAT_INPLACE_MATRIX) { 1937 PetscCall(MatCreateSubMatrix(B,irows,icols,reuse,M)); 1938 PetscCall(PetscObjectCompose((PetscObject)(*M),"_MatIS_IS_XAIJ_irows",(PetscObject)irows)); 1939 PetscCall(PetscObjectCompose((PetscObject)(*M),"_MatIS_IS_XAIJ_icols",(PetscObject)icols)); 1940 } else { 1941 Mat C; 1942 1943 PetscCall(MatCreateSubMatrix(B,irows,icols,MAT_INITIAL_MATRIX,&C)); 1944 PetscCall(MatHeaderReplace(mat,&C)); 1945 } 1946 PetscCall(MatDestroy(&B)); 1947 PetscCall(ISDestroy(&icols)); 1948 PetscCall(ISDestroy(&irows)); 1949 PetscFunctionReturn(0); 1950 } 1951 general_assembly: 1952 PetscCall(MatGetSize(mat,&rows,&cols)); 1953 PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->rmapping,&rbs)); 1954 PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->cmapping,&cbs)); 1955 PetscCall(MatGetLocalSize(mat,&lrows,&lcols)); 1956 PetscCall(MatGetSize(matis->A,&local_rows,&local_cols)); 1957 PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A,MATSEQDENSE,&isseqdense)); 1958 PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A,MATSEQAIJ,&isseqaij)); 1959 PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A,MATSEQBAIJ,&isseqbaij)); 1960 PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A,MATSEQSBAIJ,&isseqsbaij)); 1961 PetscCheck(isseqdense || isseqaij || isseqbaij || isseqsbaij,PETSC_COMM_SELF,PETSC_ERR_SUP,"Not for matrix type %s",((PetscObject)(matis->A))->type_name); 1962 if (PetscDefined (USE_DEBUG)) { 1963 PetscBool lb[4],bb[4]; 1964 1965 lb[0] = isseqdense; 1966 lb[1] = isseqaij; 1967 lb[2] = isseqbaij; 1968 lb[3] = isseqsbaij; 1969 PetscCall(MPIU_Allreduce(lb,bb,4,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)mat))); 1970 PetscCheck(bb[0] || bb[1] || bb[2] || bb[3],PETSC_COMM_SELF,PETSC_ERR_SUP,"Local matrices must have the same type"); 1971 } 1972 1973 if (reuse != MAT_REUSE_MATRIX) { 1974 PetscCall(MatCreate(PetscObjectComm((PetscObject)mat),&MT)); 1975 PetscCall(MatSetSizes(MT,lrows,lcols,rows,cols)); 1976 PetscCall(MatSetType(MT,mtype)); 1977 PetscCall(MatSetBlockSizes(MT,rbs,cbs)); 1978 PetscCall(MatISSetMPIXAIJPreallocation_Private(mat,MT,PETSC_FALSE)); 1979 } else { 1980 PetscInt mrbs,mcbs,mrows,mcols,mlrows,mlcols; 1981 1982 /* some checks */ 1983 MT = *M; 1984 PetscCall(MatGetBlockSizes(MT,&mrbs,&mcbs)); 1985 PetscCall(MatGetSize(MT,&mrows,&mcols)); 1986 PetscCall(MatGetLocalSize(MT,&mlrows,&mlcols)); 1987 PetscCheck(mrows == rows,PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot reuse matrix. Wrong number of rows (%" PetscInt_FMT " != %" PetscInt_FMT ")",rows,mrows); 1988 PetscCheck(mcols == cols,PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot reuse matrix. Wrong number of cols (%" PetscInt_FMT " != %" PetscInt_FMT ")",cols,mcols); 1989 PetscCheck(mlrows == lrows,PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot reuse matrix. Wrong number of local rows (%" PetscInt_FMT " != %" PetscInt_FMT ")",lrows,mlrows); 1990 PetscCheck(mlcols == lcols,PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot reuse matrix. Wrong number of local cols (%" PetscInt_FMT " != %" PetscInt_FMT ")",lcols,mlcols); 1991 PetscCheck(mrbs == rbs,PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot reuse matrix. Wrong row block size (%" PetscInt_FMT " != %" PetscInt_FMT ")",rbs,mrbs); 1992 PetscCheck(mcbs == cbs,PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot reuse matrix. Wrong col block size (%" PetscInt_FMT " != %" PetscInt_FMT ")",cbs,mcbs); 1993 PetscCall(MatZeroEntries(MT)); 1994 } 1995 1996 if (isseqsbaij || isseqbaij) { 1997 PetscCall(MatConvert(matis->A,MATSEQAIJ,MAT_INITIAL_MATRIX,&local_mat)); 1998 isseqaij = PETSC_TRUE; 1999 } else { 2000 PetscCall(PetscObjectReference((PetscObject)matis->A)); 2001 local_mat = matis->A; 2002 } 2003 2004 /* Set values */ 2005 PetscCall(MatSetLocalToGlobalMapping(MT,matis->rmapping,matis->cmapping)); 2006 if (isseqdense) { /* special case for dense local matrices */ 2007 PetscInt i,*dummy; 2008 2009 PetscCall(PetscMalloc1(PetscMax(local_rows,local_cols),&dummy)); 2010 for (i=0;i<PetscMax(local_rows,local_cols);i++) dummy[i] = i; 2011 PetscCall(MatSetOption(MT,MAT_ROW_ORIENTED,PETSC_FALSE)); 2012 PetscCall(MatDenseGetArrayRead(local_mat,&array)); 2013 PetscCall(MatSetValuesLocal(MT,local_rows,dummy,local_cols,dummy,array,ADD_VALUES)); 2014 PetscCall(MatDenseRestoreArrayRead(local_mat,&array)); 2015 PetscCall(PetscFree(dummy)); 2016 } else if (isseqaij) { 2017 const PetscInt *blocks; 2018 PetscInt i,nvtxs,*xadj,*adjncy, nb; 2019 PetscBool done; 2020 PetscScalar *sarray; 2021 2022 PetscCall(MatGetRowIJ(local_mat,0,PETSC_FALSE,PETSC_FALSE,&nvtxs,(const PetscInt**)&xadj,(const PetscInt**)&adjncy,&done)); 2023 PetscCheck(done,PetscObjectComm((PetscObject)local_mat),PETSC_ERR_PLIB,"Error in MatGetRowIJ"); 2024 PetscCall(MatSeqAIJGetArray(local_mat,&sarray)); 2025 PetscCall(MatGetVariableBlockSizes(local_mat,&nb,&blocks)); 2026 if (nb) { /* speed up assembly for special blocked matrices (used by BDDC) */ 2027 PetscInt sum; 2028 2029 for (i=0,sum=0;i<nb;i++) sum += blocks[i]; 2030 if (sum == nvtxs) { 2031 PetscInt r; 2032 2033 for (i=0,r=0;i<nb;i++) { 2034 PetscAssert(blocks[i] == xadj[r+1] - xadj[r],PETSC_COMM_SELF,PETSC_ERR_PLIB,"Invalid block sizes prescribed for block %" PetscInt_FMT ": expected %" PetscInt_FMT ", got %" PetscInt_FMT,i,blocks[i],xadj[r+1] - xadj[r]); 2035 PetscCall(MatSetValuesLocal(MT,blocks[i],adjncy+xadj[r],blocks[i],adjncy+xadj[r],sarray+xadj[r],ADD_VALUES)); 2036 r += blocks[i]; 2037 } 2038 } else { 2039 for (i=0;i<nvtxs;i++) { 2040 PetscCall(MatSetValuesLocal(MT,1,&i,xadj[i+1]-xadj[i],adjncy+xadj[i],sarray+xadj[i],ADD_VALUES)); 2041 } 2042 } 2043 } else { 2044 for (i=0;i<nvtxs;i++) { 2045 PetscCall(MatSetValuesLocal(MT,1,&i,xadj[i+1]-xadj[i],adjncy+xadj[i],sarray+xadj[i],ADD_VALUES)); 2046 } 2047 } 2048 PetscCall(MatRestoreRowIJ(local_mat,0,PETSC_FALSE,PETSC_FALSE,&nvtxs,(const PetscInt**)&xadj,(const PetscInt**)&adjncy,&done)); 2049 PetscCheck(done,PetscObjectComm((PetscObject)local_mat),PETSC_ERR_PLIB,"Error in MatRestoreRowIJ"); 2050 PetscCall(MatSeqAIJRestoreArray(local_mat,&sarray)); 2051 } else { /* very basic values insertion for all other matrix types */ 2052 PetscInt i; 2053 2054 for (i=0;i<local_rows;i++) { 2055 PetscInt j; 2056 const PetscInt *local_indices_cols; 2057 2058 PetscCall(MatGetRow(local_mat,i,&j,&local_indices_cols,&array)); 2059 PetscCall(MatSetValuesLocal(MT,1,&i,j,local_indices_cols,array,ADD_VALUES)); 2060 PetscCall(MatRestoreRow(local_mat,i,&j,&local_indices_cols,&array)); 2061 } 2062 } 2063 PetscCall(MatAssemblyBegin(MT,MAT_FINAL_ASSEMBLY)); 2064 PetscCall(MatDestroy(&local_mat)); 2065 PetscCall(MatAssemblyEnd(MT,MAT_FINAL_ASSEMBLY)); 2066 if (isseqdense) PetscCall(MatSetOption(MT,MAT_ROW_ORIENTED,PETSC_TRUE)); 2067 if (reuse == MAT_INPLACE_MATRIX) { 2068 PetscCall(MatHeaderReplace(mat,&MT)); 2069 } else if (reuse == MAT_INITIAL_MATRIX) { 2070 *M = MT; 2071 } 2072 PetscFunctionReturn(0); 2073 } 2074 2075 /*@ 2076 MatISGetMPIXAIJ - Converts MATIS matrix into a parallel AIJ format 2077 2078 Input Parameters: 2079 + mat - the matrix (should be of type MATIS) 2080 - reuse - either MAT_INITIAL_MATRIX or MAT_REUSE_MATRIX 2081 2082 Output Parameter: 2083 . newmat - the matrix in AIJ format 2084 2085 Level: developer 2086 2087 Notes: 2088 This function has been deprecated and it will be removed in future releases. Update your code to use the MatConvert() interface. 2089 2090 .seealso: `MATIS`, `MatConvert()` 2091 @*/ 2092 PetscErrorCode MatISGetMPIXAIJ(Mat mat, MatReuse reuse, Mat *newmat) 2093 { 2094 PetscFunctionBegin; 2095 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 2096 PetscValidLogicalCollectiveEnum(mat,reuse,2); 2097 PetscValidPointer(newmat,3); 2098 if (reuse == MAT_REUSE_MATRIX) { 2099 PetscValidHeaderSpecific(*newmat,MAT_CLASSID,3); 2100 PetscCheckSameComm(mat,1,*newmat,3); 2101 PetscCheck(mat != *newmat,PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"Cannot reuse the same matrix"); 2102 } 2103 PetscUseMethod(mat,"MatISGetMPIXAIJ_C",(Mat,MatType,MatReuse,Mat*),(mat,MATAIJ,reuse,newmat)); 2104 PetscFunctionReturn(0); 2105 } 2106 2107 static PetscErrorCode MatDuplicate_IS(Mat mat,MatDuplicateOption op,Mat *newmat) 2108 { 2109 Mat_IS *matis = (Mat_IS*)(mat->data); 2110 PetscInt rbs,cbs,m,n,M,N; 2111 Mat B,localmat; 2112 2113 PetscFunctionBegin; 2114 PetscCall(ISLocalToGlobalMappingGetBlockSize(mat->rmap->mapping,&rbs)); 2115 PetscCall(ISLocalToGlobalMappingGetBlockSize(mat->cmap->mapping,&cbs)); 2116 PetscCall(MatGetSize(mat,&M,&N)); 2117 PetscCall(MatGetLocalSize(mat,&m,&n)); 2118 PetscCall(MatCreate(PetscObjectComm((PetscObject)mat),&B)); 2119 PetscCall(MatSetSizes(B,m,n,M,N)); 2120 PetscCall(MatSetBlockSize(B,rbs == cbs ? rbs : 1)); 2121 PetscCall(MatSetType(B,MATIS)); 2122 PetscCall(MatISSetLocalMatType(B,matis->lmattype)); 2123 PetscCall(MatSetLocalToGlobalMapping(B,mat->rmap->mapping,mat->cmap->mapping)); 2124 PetscCall(MatDuplicate(matis->A,op,&localmat)); 2125 PetscCall(MatSetLocalToGlobalMapping(localmat,matis->A->rmap->mapping,matis->A->cmap->mapping)); 2126 PetscCall(MatISSetLocalMat(B,localmat)); 2127 PetscCall(MatDestroy(&localmat)); 2128 PetscCall(MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY)); 2129 PetscCall(MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY)); 2130 *newmat = B; 2131 PetscFunctionReturn(0); 2132 } 2133 2134 static PetscErrorCode MatIsHermitian_IS(Mat A,PetscReal tol,PetscBool *flg) 2135 { 2136 Mat_IS *matis = (Mat_IS*)A->data; 2137 PetscBool local_sym; 2138 2139 PetscFunctionBegin; 2140 PetscCall(MatIsHermitian(matis->A,tol,&local_sym)); 2141 PetscCall(MPIU_Allreduce(&local_sym,flg,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)A))); 2142 PetscFunctionReturn(0); 2143 } 2144 2145 static PetscErrorCode MatIsSymmetric_IS(Mat A,PetscReal tol,PetscBool *flg) 2146 { 2147 Mat_IS *matis = (Mat_IS*)A->data; 2148 PetscBool local_sym; 2149 2150 PetscFunctionBegin; 2151 if (matis->rmapping != matis->cmapping) { 2152 *flg = PETSC_FALSE; 2153 PetscFunctionReturn(0); 2154 } 2155 PetscCall(MatIsSymmetric(matis->A,tol,&local_sym)); 2156 PetscCall(MPIU_Allreduce(&local_sym,flg,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)A))); 2157 PetscFunctionReturn(0); 2158 } 2159 2160 static PetscErrorCode MatIsStructurallySymmetric_IS(Mat A,PetscBool *flg) 2161 { 2162 Mat_IS *matis = (Mat_IS*)A->data; 2163 PetscBool local_sym; 2164 2165 PetscFunctionBegin; 2166 if (matis->rmapping != matis->cmapping) { 2167 *flg = PETSC_FALSE; 2168 PetscFunctionReturn(0); 2169 } 2170 PetscCall(MatIsStructurallySymmetric(matis->A,&local_sym)); 2171 PetscCall(MPIU_Allreduce(&local_sym,flg,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)A))); 2172 PetscFunctionReturn(0); 2173 } 2174 2175 static PetscErrorCode MatDestroy_IS(Mat A) 2176 { 2177 Mat_IS *b = (Mat_IS*)A->data; 2178 2179 PetscFunctionBegin; 2180 PetscCall(PetscFree(b->bdiag)); 2181 PetscCall(PetscFree(b->lmattype)); 2182 PetscCall(MatDestroy(&b->A)); 2183 PetscCall(VecScatterDestroy(&b->cctx)); 2184 PetscCall(VecScatterDestroy(&b->rctx)); 2185 PetscCall(VecDestroy(&b->x)); 2186 PetscCall(VecDestroy(&b->y)); 2187 PetscCall(VecDestroy(&b->counter)); 2188 PetscCall(ISDestroy(&b->getsub_ris)); 2189 PetscCall(ISDestroy(&b->getsub_cis)); 2190 if (b->sf != b->csf) { 2191 PetscCall(PetscSFDestroy(&b->csf)); 2192 PetscCall(PetscFree2(b->csf_rootdata,b->csf_leafdata)); 2193 } else b->csf = NULL; 2194 PetscCall(PetscSFDestroy(&b->sf)); 2195 PetscCall(PetscFree2(b->sf_rootdata,b->sf_leafdata)); 2196 PetscCall(ISLocalToGlobalMappingDestroy(&b->rmapping)); 2197 PetscCall(ISLocalToGlobalMappingDestroy(&b->cmapping)); 2198 PetscCall(MatDestroy(&b->dA)); 2199 PetscCall(MatDestroy(&b->assembledA)); 2200 PetscCall(PetscFree(A->data)); 2201 PetscCall(PetscObjectChangeTypeName((PetscObject)A,NULL)); 2202 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatISSetLocalMatType_C",NULL)); 2203 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatISGetLocalMat_C",NULL)); 2204 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatISSetLocalMat_C",NULL)); 2205 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatISRestoreLocalMat_C",NULL)); 2206 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatISGetMPIXAIJ_C",NULL)); 2207 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatISSetPreallocation_C",NULL)); 2208 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatISStoreL2L_C",NULL)); 2209 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatISFixLocalEmpty_C",NULL)); 2210 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatISGetLocalToGlobalMapping_C",NULL)); 2211 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_mpiaij_C",NULL)); 2212 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_mpibaij_C",NULL)); 2213 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_mpisbaij_C",NULL)); 2214 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_seqaij_C",NULL)); 2215 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_seqbaij_C",NULL)); 2216 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_seqsbaij_C",NULL)); 2217 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_aij_C",NULL)); 2218 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatSetPreallocationCOOLocal_C",NULL)); 2219 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatSetPreallocationCOO_C",NULL)); 2220 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatSetValuesCOO_C",NULL)); 2221 PetscFunctionReturn(0); 2222 } 2223 2224 static PetscErrorCode MatMult_IS(Mat A,Vec x,Vec y) 2225 { 2226 Mat_IS *is = (Mat_IS*)A->data; 2227 PetscScalar zero = 0.0; 2228 2229 PetscFunctionBegin; 2230 /* scatter the global vector x into the local work vector */ 2231 PetscCall(VecScatterBegin(is->cctx,x,is->x,INSERT_VALUES,SCATTER_FORWARD)); 2232 PetscCall(VecScatterEnd(is->cctx,x,is->x,INSERT_VALUES,SCATTER_FORWARD)); 2233 2234 /* multiply the local matrix */ 2235 PetscCall(MatMult(is->A,is->x,is->y)); 2236 2237 /* scatter product back into global memory */ 2238 PetscCall(VecSet(y,zero)); 2239 PetscCall(VecScatterBegin(is->rctx,is->y,y,ADD_VALUES,SCATTER_REVERSE)); 2240 PetscCall(VecScatterEnd(is->rctx,is->y,y,ADD_VALUES,SCATTER_REVERSE)); 2241 PetscFunctionReturn(0); 2242 } 2243 2244 static PetscErrorCode MatMultAdd_IS(Mat A,Vec v1,Vec v2,Vec v3) 2245 { 2246 Vec temp_vec; 2247 2248 PetscFunctionBegin; /* v3 = v2 + A * v1.*/ 2249 if (v3 != v2) { 2250 PetscCall(MatMult(A,v1,v3)); 2251 PetscCall(VecAXPY(v3,1.0,v2)); 2252 } else { 2253 PetscCall(VecDuplicate(v2,&temp_vec)); 2254 PetscCall(MatMult(A,v1,temp_vec)); 2255 PetscCall(VecAXPY(temp_vec,1.0,v2)); 2256 PetscCall(VecCopy(temp_vec,v3)); 2257 PetscCall(VecDestroy(&temp_vec)); 2258 } 2259 PetscFunctionReturn(0); 2260 } 2261 2262 static PetscErrorCode MatMultTranspose_IS(Mat A,Vec y,Vec x) 2263 { 2264 Mat_IS *is = (Mat_IS*)A->data; 2265 2266 PetscFunctionBegin; 2267 /* scatter the global vector x into the local work vector */ 2268 PetscCall(VecScatterBegin(is->rctx,y,is->y,INSERT_VALUES,SCATTER_FORWARD)); 2269 PetscCall(VecScatterEnd(is->rctx,y,is->y,INSERT_VALUES,SCATTER_FORWARD)); 2270 2271 /* multiply the local matrix */ 2272 PetscCall(MatMultTranspose(is->A,is->y,is->x)); 2273 2274 /* scatter product back into global vector */ 2275 PetscCall(VecSet(x,0)); 2276 PetscCall(VecScatterBegin(is->cctx,is->x,x,ADD_VALUES,SCATTER_REVERSE)); 2277 PetscCall(VecScatterEnd(is->cctx,is->x,x,ADD_VALUES,SCATTER_REVERSE)); 2278 PetscFunctionReturn(0); 2279 } 2280 2281 static PetscErrorCode MatMultTransposeAdd_IS(Mat A,Vec v1,Vec v2,Vec v3) 2282 { 2283 Vec temp_vec; 2284 2285 PetscFunctionBegin; /* v3 = v2 + A' * v1.*/ 2286 if (v3 != v2) { 2287 PetscCall(MatMultTranspose(A,v1,v3)); 2288 PetscCall(VecAXPY(v3,1.0,v2)); 2289 } else { 2290 PetscCall(VecDuplicate(v2,&temp_vec)); 2291 PetscCall(MatMultTranspose(A,v1,temp_vec)); 2292 PetscCall(VecAXPY(temp_vec,1.0,v2)); 2293 PetscCall(VecCopy(temp_vec,v3)); 2294 PetscCall(VecDestroy(&temp_vec)); 2295 } 2296 PetscFunctionReturn(0); 2297 } 2298 2299 static PetscErrorCode MatView_IS(Mat A,PetscViewer viewer) 2300 { 2301 Mat_IS *a = (Mat_IS*)A->data; 2302 PetscViewer sviewer; 2303 PetscBool isascii,view = PETSC_TRUE; 2304 2305 PetscFunctionBegin; 2306 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii)); 2307 if (isascii) { 2308 PetscViewerFormat format; 2309 2310 PetscCall(PetscViewerGetFormat(viewer,&format)); 2311 if (format == PETSC_VIEWER_ASCII_INFO) view = PETSC_FALSE; 2312 } 2313 if (!view) PetscFunctionReturn(0); 2314 PetscCall(PetscViewerGetSubViewer(viewer,PETSC_COMM_SELF,&sviewer)); 2315 PetscCall(MatView(a->A,sviewer)); 2316 PetscCall(PetscViewerRestoreSubViewer(viewer,PETSC_COMM_SELF,&sviewer)); 2317 PetscCall(PetscViewerFlush(viewer)); 2318 PetscFunctionReturn(0); 2319 } 2320 2321 static PetscErrorCode MatInvertBlockDiagonal_IS(Mat mat,const PetscScalar **values) 2322 { 2323 Mat_IS *is = (Mat_IS*)mat->data; 2324 MPI_Datatype nodeType; 2325 const PetscScalar *lv; 2326 PetscInt bs; 2327 2328 PetscFunctionBegin; 2329 PetscCall(MatGetBlockSize(mat,&bs)); 2330 PetscCall(MatSetBlockSize(is->A,bs)); 2331 PetscCall(MatInvertBlockDiagonal(is->A,&lv)); 2332 if (!is->bdiag) { 2333 PetscCall(PetscMalloc1(bs*mat->rmap->n,&is->bdiag)); 2334 } 2335 PetscCallMPI(MPI_Type_contiguous(bs,MPIU_SCALAR,&nodeType)); 2336 PetscCallMPI(MPI_Type_commit(&nodeType)); 2337 PetscCall(PetscSFReduceBegin(is->sf,nodeType,lv,is->bdiag,MPI_REPLACE)); 2338 PetscCall(PetscSFReduceEnd(is->sf,nodeType,lv,is->bdiag,MPI_REPLACE)); 2339 PetscCallMPI(MPI_Type_free(&nodeType)); 2340 if (values) *values = is->bdiag; 2341 PetscFunctionReturn(0); 2342 } 2343 2344 static PetscErrorCode MatISSetUpScatters_Private(Mat A) 2345 { 2346 Vec cglobal,rglobal; 2347 IS from; 2348 Mat_IS *is = (Mat_IS*)A->data; 2349 PetscScalar sum; 2350 const PetscInt *garray; 2351 PetscInt nr,rbs,nc,cbs; 2352 VecType rtype; 2353 2354 PetscFunctionBegin; 2355 PetscCall(ISLocalToGlobalMappingGetSize(is->rmapping,&nr)); 2356 PetscCall(ISLocalToGlobalMappingGetBlockSize(is->rmapping,&rbs)); 2357 PetscCall(ISLocalToGlobalMappingGetSize(is->cmapping,&nc)); 2358 PetscCall(ISLocalToGlobalMappingGetBlockSize(is->cmapping,&cbs)); 2359 PetscCall(VecDestroy(&is->x)); 2360 PetscCall(VecDestroy(&is->y)); 2361 PetscCall(VecDestroy(&is->counter)); 2362 PetscCall(VecScatterDestroy(&is->rctx)); 2363 PetscCall(VecScatterDestroy(&is->cctx)); 2364 PetscCall(MatCreateVecs(is->A,&is->x,&is->y)); 2365 PetscCall(VecBindToCPU(is->y,PETSC_TRUE)); 2366 PetscCall(VecGetRootType_Private(is->y,&rtype)); 2367 PetscCall(PetscFree(A->defaultvectype)); 2368 PetscCall(PetscStrallocpy(rtype,&A->defaultvectype)); 2369 PetscCall(MatCreateVecs(A,&cglobal,&rglobal)); 2370 PetscCall(VecBindToCPU(rglobal,PETSC_TRUE)); 2371 PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->rmapping,&garray)); 2372 PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A),rbs,nr/rbs,garray,PETSC_USE_POINTER,&from)); 2373 PetscCall(VecScatterCreate(rglobal,from,is->y,NULL,&is->rctx)); 2374 PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->rmapping,&garray)); 2375 PetscCall(ISDestroy(&from)); 2376 if (is->rmapping != is->cmapping) { 2377 PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->cmapping,&garray)); 2378 PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A),cbs,nc/cbs,garray,PETSC_USE_POINTER,&from)); 2379 PetscCall(VecScatterCreate(cglobal,from,is->x,NULL,&is->cctx)); 2380 PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->cmapping,&garray)); 2381 PetscCall(ISDestroy(&from)); 2382 } else { 2383 PetscCall(PetscObjectReference((PetscObject)is->rctx)); 2384 is->cctx = is->rctx; 2385 } 2386 PetscCall(VecDestroy(&cglobal)); 2387 2388 /* interface counter vector (local) */ 2389 PetscCall(VecDuplicate(is->y,&is->counter)); 2390 PetscCall(VecBindToCPU(is->counter,PETSC_TRUE)); 2391 PetscCall(VecSet(is->y,1.)); 2392 PetscCall(VecScatterBegin(is->rctx,is->y,rglobal,ADD_VALUES,SCATTER_REVERSE)); 2393 PetscCall(VecScatterEnd(is->rctx,is->y,rglobal,ADD_VALUES,SCATTER_REVERSE)); 2394 PetscCall(VecScatterBegin(is->rctx,rglobal,is->counter,INSERT_VALUES,SCATTER_FORWARD)); 2395 PetscCall(VecScatterEnd(is->rctx,rglobal,is->counter,INSERT_VALUES,SCATTER_FORWARD)); 2396 PetscCall(VecBindToCPU(is->y,PETSC_FALSE)); 2397 PetscCall(VecBindToCPU(is->counter,PETSC_FALSE)); 2398 2399 /* special functions for block-diagonal matrices */ 2400 PetscCall(VecSum(rglobal,&sum)); 2401 A->ops->invertblockdiagonal = NULL; 2402 if ((PetscInt)(PetscRealPart(sum)) == A->rmap->N && A->rmap->N == A->cmap->N && is->rmapping == is->cmapping) A->ops->invertblockdiagonal = MatInvertBlockDiagonal_IS; 2403 PetscCall(VecDestroy(&rglobal)); 2404 2405 /* setup SF for general purpose shared indices based communications */ 2406 PetscCall(MatISSetUpSF_IS(A)); 2407 PetscFunctionReturn(0); 2408 } 2409 2410 static PetscErrorCode MatISFilterL2GMap(Mat A, ISLocalToGlobalMapping map, ISLocalToGlobalMapping *nmap, ISLocalToGlobalMapping *lmap) 2411 { 2412 IS is; 2413 ISLocalToGlobalMappingType l2gtype; 2414 const PetscInt *idxs; 2415 PetscHSetI ht; 2416 PetscInt *nidxs; 2417 PetscInt i,n,bs,c; 2418 PetscBool flg[] = {PETSC_FALSE,PETSC_FALSE}; 2419 2420 PetscFunctionBegin; 2421 PetscCall(ISLocalToGlobalMappingGetSize(map,&n)); 2422 PetscCall(ISLocalToGlobalMappingGetBlockSize(map,&bs)); 2423 PetscCall(ISLocalToGlobalMappingGetBlockIndices(map,&idxs)); 2424 PetscCall(PetscHSetICreate(&ht)); 2425 PetscCall(PetscMalloc1(n/bs,&nidxs)); 2426 for (i=0,c=0;i<n/bs;i++) { 2427 PetscBool missing; 2428 if (idxs[i] < 0) { flg[0] = PETSC_TRUE; continue; } 2429 PetscCall(PetscHSetIQueryAdd(ht,idxs[i],&missing)); 2430 if (!missing) flg[1] = PETSC_TRUE; 2431 else nidxs[c++] = idxs[i]; 2432 } 2433 PetscCall(PetscHSetIDestroy(&ht)); 2434 PetscCall(MPIU_Allreduce(MPI_IN_PLACE,flg,2,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)A))); 2435 if (!flg[0] && !flg[1]) { /* Entries are all non negative and unique */ 2436 *nmap = NULL; 2437 *lmap = NULL; 2438 PetscCall(PetscFree(nidxs)); 2439 PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(map,&idxs)); 2440 PetscFunctionReturn(0); 2441 } 2442 2443 /* New l2g map without negative or repeated indices */ 2444 PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A),bs,c,nidxs,PETSC_USE_POINTER,&is)); 2445 PetscCall(ISLocalToGlobalMappingCreateIS(is,nmap)); 2446 PetscCall(ISDestroy(&is)); 2447 PetscCall(ISLocalToGlobalMappingGetType(map,&l2gtype)); 2448 PetscCall(ISLocalToGlobalMappingSetType(*nmap,l2gtype)); 2449 2450 /* New local l2g map for repeated indices */ 2451 PetscCall(ISGlobalToLocalMappingApplyBlock(*nmap,IS_GTOLM_MASK,n/bs,idxs,NULL,nidxs)); 2452 PetscCall(ISCreateBlock(PETSC_COMM_SELF,bs,n/bs,nidxs,PETSC_USE_POINTER,&is)); 2453 PetscCall(ISLocalToGlobalMappingCreateIS(is,lmap)); 2454 PetscCall(ISDestroy(&is)); 2455 2456 PetscCall(PetscFree(nidxs)); 2457 PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(map,&idxs)); 2458 PetscFunctionReturn(0); 2459 } 2460 2461 static PetscErrorCode MatSetLocalToGlobalMapping_IS(Mat A,ISLocalToGlobalMapping rmapping,ISLocalToGlobalMapping cmapping) 2462 { 2463 Mat_IS *is = (Mat_IS*)A->data; 2464 ISLocalToGlobalMapping localrmapping = NULL, localcmapping = NULL; 2465 PetscBool cong, freem[] = { PETSC_FALSE, PETSC_FALSE }; 2466 PetscInt nr,rbs,nc,cbs; 2467 2468 PetscFunctionBegin; 2469 if (rmapping) PetscCheckSameComm(A,1,rmapping,2); 2470 if (cmapping) PetscCheckSameComm(A,1,cmapping,3); 2471 2472 PetscCall(ISLocalToGlobalMappingDestroy(&is->rmapping)); 2473 PetscCall(ISLocalToGlobalMappingDestroy(&is->cmapping)); 2474 PetscCall(PetscLayoutSetUp(A->rmap)); 2475 PetscCall(PetscLayoutSetUp(A->cmap)); 2476 PetscCall(MatHasCongruentLayouts(A,&cong)); 2477 2478 /* If NULL, local space matches global space */ 2479 if (!rmapping) { 2480 IS is; 2481 2482 PetscCall(ISCreateStride(PetscObjectComm((PetscObject)A),A->rmap->N,0,1,&is)); 2483 PetscCall(ISLocalToGlobalMappingCreateIS(is,&rmapping)); 2484 if (A->rmap->bs > 0) PetscCall(ISLocalToGlobalMappingSetBlockSize(rmapping,A->rmap->bs)); 2485 PetscCall(ISDestroy(&is)); 2486 freem[0] = PETSC_TRUE; 2487 if (!cmapping && cong && A->rmap->bs == A->cmap->bs) cmapping = rmapping; 2488 } else if (!is->islocalref) { /* check if the l2g map has negative or repeated entries */ 2489 PetscCall(MatISFilterL2GMap(A,rmapping,&is->rmapping,&localrmapping)); 2490 if (rmapping == cmapping) { 2491 PetscCall(PetscObjectReference((PetscObject)is->rmapping)); 2492 is->cmapping = is->rmapping; 2493 PetscCall(PetscObjectReference((PetscObject)localrmapping)); 2494 localcmapping = localrmapping; 2495 } 2496 } 2497 if (!cmapping) { 2498 IS is; 2499 2500 PetscCall(ISCreateStride(PetscObjectComm((PetscObject)A),A->cmap->N,0,1,&is)); 2501 PetscCall(ISLocalToGlobalMappingCreateIS(is,&cmapping)); 2502 if (A->cmap->bs > 0) PetscCall(ISLocalToGlobalMappingSetBlockSize(cmapping,A->cmap->bs)); 2503 PetscCall(ISDestroy(&is)); 2504 freem[1] = PETSC_TRUE; 2505 } else if (cmapping != rmapping && !is->islocalref) { /* check if the l2g map has negative or repeated entries */ 2506 PetscCall(MatISFilterL2GMap(A,cmapping,&is->cmapping,&localcmapping)); 2507 } 2508 if (!is->rmapping) { 2509 PetscCall(PetscObjectReference((PetscObject)rmapping)); 2510 is->rmapping = rmapping; 2511 } 2512 if (!is->cmapping) { 2513 PetscCall(PetscObjectReference((PetscObject)cmapping)); 2514 is->cmapping = cmapping; 2515 } 2516 2517 /* Clean up */ 2518 PetscCall(MatDestroy(&is->A)); 2519 if (is->csf != is->sf) { 2520 PetscCall(PetscSFDestroy(&is->csf)); 2521 PetscCall(PetscFree2(is->csf_rootdata,is->csf_leafdata)); 2522 } else is->csf = NULL; 2523 PetscCall(PetscSFDestroy(&is->sf)); 2524 PetscCall(PetscFree2(is->sf_rootdata,is->sf_leafdata)); 2525 PetscCall(PetscFree(is->bdiag)); 2526 2527 /* check if the two mappings are actually the same for square matrices since MATIS has some optimization for this case 2528 (DOLFIN passes 2 different objects) */ 2529 PetscCall(ISLocalToGlobalMappingGetSize(is->rmapping,&nr)); 2530 PetscCall(ISLocalToGlobalMappingGetBlockSize(is->rmapping,&rbs)); 2531 PetscCall(ISLocalToGlobalMappingGetSize(is->cmapping,&nc)); 2532 PetscCall(ISLocalToGlobalMappingGetBlockSize(is->cmapping,&cbs)); 2533 if (is->rmapping != is->cmapping && cong) { 2534 PetscBool same = PETSC_FALSE; 2535 if (nr == nc && cbs == rbs) { 2536 const PetscInt *idxs1,*idxs2; 2537 2538 PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->rmapping,&idxs1)); 2539 PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->cmapping,&idxs2)); 2540 PetscCall(PetscArraycmp(idxs1,idxs2,nr/rbs,&same)); 2541 PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->rmapping,&idxs1)); 2542 PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->cmapping,&idxs2)); 2543 } 2544 PetscCall(MPIU_Allreduce(MPI_IN_PLACE,&same,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)A))); 2545 if (same) { 2546 PetscCall(ISLocalToGlobalMappingDestroy(&is->cmapping)); 2547 PetscCall(PetscObjectReference((PetscObject)is->rmapping)); 2548 is->cmapping = is->rmapping; 2549 } 2550 } 2551 PetscCall(PetscLayoutSetBlockSize(A->rmap,rbs)); 2552 PetscCall(PetscLayoutSetBlockSize(A->cmap,cbs)); 2553 /* Pass the user defined maps to the layout */ 2554 PetscCall(PetscLayoutSetISLocalToGlobalMapping(A->rmap,rmapping)); 2555 PetscCall(PetscLayoutSetISLocalToGlobalMapping(A->cmap,cmapping)); 2556 if (freem[0]) PetscCall(ISLocalToGlobalMappingDestroy(&rmapping)); 2557 if (freem[1]) PetscCall(ISLocalToGlobalMappingDestroy(&cmapping)); 2558 2559 /* Create the local matrix A */ 2560 PetscCall(MatCreate(PETSC_COMM_SELF,&is->A)); 2561 PetscCall(MatSetType(is->A,is->lmattype)); 2562 PetscCall(MatSetSizes(is->A,nr,nc,nr,nc)); 2563 PetscCall(MatSetBlockSizes(is->A,rbs,cbs)); 2564 PetscCall(MatSetOptionsPrefix(is->A,"is_")); 2565 PetscCall(MatAppendOptionsPrefix(is->A,((PetscObject)A)->prefix)); 2566 PetscCall(PetscLayoutSetUp(is->A->rmap)); 2567 PetscCall(PetscLayoutSetUp(is->A->cmap)); 2568 PetscCall(MatSetLocalToGlobalMapping(is->A,localrmapping,localcmapping)); 2569 PetscCall(ISLocalToGlobalMappingDestroy(&localrmapping)); 2570 PetscCall(ISLocalToGlobalMappingDestroy(&localcmapping)); 2571 2572 /* setup scatters and local vectors for MatMult */ 2573 if (!is->islocalref) PetscCall(MatISSetUpScatters_Private(A)); 2574 A->preallocated = PETSC_TRUE; 2575 PetscFunctionReturn(0); 2576 } 2577 2578 static PetscErrorCode MatSetUp_IS(Mat A) 2579 { 2580 ISLocalToGlobalMapping rmap, cmap; 2581 2582 PetscFunctionBegin; 2583 PetscCall(MatGetLocalToGlobalMapping(A,&rmap,&cmap)); 2584 if (!rmap && !cmap) { 2585 PetscCall(MatSetLocalToGlobalMapping(A,NULL,NULL)); 2586 } 2587 PetscFunctionReturn(0); 2588 } 2589 2590 static PetscErrorCode MatSetValues_IS(Mat mat, PetscInt m,const PetscInt *rows, PetscInt n,const PetscInt *cols, const PetscScalar *values, InsertMode addv) 2591 { 2592 Mat_IS *is = (Mat_IS*)mat->data; 2593 PetscInt rows_l[MATIS_MAX_ENTRIES_INSERTION],cols_l[MATIS_MAX_ENTRIES_INSERTION]; 2594 2595 PetscFunctionBegin; 2596 PetscCall(ISGlobalToLocalMappingApply(is->rmapping,IS_GTOLM_MASK,m,rows,&m,rows_l)); 2597 if (m != n || rows != cols || is->cmapping != is->rmapping) { 2598 PetscCall(ISGlobalToLocalMappingApply(is->cmapping,IS_GTOLM_MASK,n,cols,&n,cols_l)); 2599 PetscCall(MatSetValues(is->A,m,rows_l,n,cols_l,values,addv)); 2600 } else { 2601 PetscCall(MatSetValues(is->A,m,rows_l,m,rows_l,values,addv)); 2602 } 2603 PetscFunctionReturn(0); 2604 } 2605 2606 static PetscErrorCode MatSetValuesBlocked_IS(Mat mat, PetscInt m,const PetscInt *rows, PetscInt n,const PetscInt *cols, const PetscScalar *values, InsertMode addv) 2607 { 2608 Mat_IS *is = (Mat_IS*)mat->data; 2609 PetscInt rows_l[MATIS_MAX_ENTRIES_INSERTION],cols_l[MATIS_MAX_ENTRIES_INSERTION]; 2610 2611 PetscFunctionBegin; 2612 PetscCall(ISGlobalToLocalMappingApplyBlock(is->rmapping,IS_GTOLM_MASK,m,rows,&m,rows_l)); 2613 if (m != n || rows != cols || is->cmapping != is->rmapping) { 2614 PetscCall(ISGlobalToLocalMappingApply(is->cmapping,IS_GTOLM_MASK,n,cols,&n,cols_l)); 2615 PetscCall(MatSetValuesBlocked(is->A,m,rows_l,n,cols_l,values,addv)); 2616 } else { 2617 PetscCall(MatSetValuesBlocked(is->A,m,rows_l,n,rows_l,values,addv)); 2618 } 2619 PetscFunctionReturn(0); 2620 } 2621 2622 static PetscErrorCode MatSetValuesLocal_IS(Mat A,PetscInt m,const PetscInt *rows, PetscInt n,const PetscInt *cols,const PetscScalar *values,InsertMode addv) 2623 { 2624 Mat_IS *is = (Mat_IS*)A->data; 2625 2626 PetscFunctionBegin; 2627 if (is->A->rmap->mapping || is->A->cmap->mapping) { 2628 PetscCall(MatSetValuesLocal(is->A,m,rows,n,cols,values,addv)); 2629 } else { 2630 PetscCall(MatSetValues(is->A,m,rows,n,cols,values,addv)); 2631 } 2632 PetscFunctionReturn(0); 2633 } 2634 2635 static PetscErrorCode MatSetValuesBlockedLocal_IS(Mat A,PetscInt m,const PetscInt *rows, PetscInt n,const PetscInt *cols,const PetscScalar *values,InsertMode addv) 2636 { 2637 Mat_IS *is = (Mat_IS*)A->data; 2638 2639 PetscFunctionBegin; 2640 if (is->A->rmap->mapping || is->A->cmap->mapping) { 2641 PetscCall(MatSetValuesBlockedLocal(is->A,m,rows,n,cols,values,addv)); 2642 } else { 2643 PetscCall(MatSetValuesBlocked(is->A,m,rows,n,cols,values,addv)); 2644 } 2645 PetscFunctionReturn(0); 2646 } 2647 2648 static PetscErrorCode MatISZeroRowsColumnsLocal_Private(Mat A,PetscInt n,const PetscInt rows[],PetscScalar diag,PetscBool columns) 2649 { 2650 Mat_IS *is = (Mat_IS*)A->data; 2651 2652 PetscFunctionBegin; 2653 if (!n) { 2654 is->pure_neumann = PETSC_TRUE; 2655 } else { 2656 PetscInt i; 2657 is->pure_neumann = PETSC_FALSE; 2658 2659 if (columns) { 2660 PetscCall(MatZeroRowsColumns(is->A,n,rows,diag,NULL,NULL)); 2661 } else { 2662 PetscCall(MatZeroRows(is->A,n,rows,diag,NULL,NULL)); 2663 } 2664 if (diag != 0.) { 2665 const PetscScalar *array; 2666 PetscCall(VecGetArrayRead(is->counter,&array)); 2667 for (i=0; i<n; i++) { 2668 PetscCall(MatSetValue(is->A,rows[i],rows[i],diag/(array[rows[i]]),INSERT_VALUES)); 2669 } 2670 PetscCall(VecRestoreArrayRead(is->counter,&array)); 2671 } 2672 PetscCall(MatAssemblyBegin(is->A,MAT_FINAL_ASSEMBLY)); 2673 PetscCall(MatAssemblyEnd(is->A,MAT_FINAL_ASSEMBLY)); 2674 } 2675 PetscFunctionReturn(0); 2676 } 2677 2678 static PetscErrorCode MatZeroRowsColumns_Private_IS(Mat A,PetscInt n,const PetscInt rows[],PetscScalar diag,Vec x,Vec b,PetscBool columns) 2679 { 2680 Mat_IS *matis = (Mat_IS*)A->data; 2681 PetscInt nr,nl,len,i; 2682 PetscInt *lrows; 2683 2684 PetscFunctionBegin; 2685 if (PetscUnlikelyDebug(columns || diag != 0. || (x && b))) { 2686 PetscBool cong; 2687 2688 PetscCall(PetscLayoutCompare(A->rmap,A->cmap,&cong)); 2689 cong = (PetscBool)(cong && matis->sf == matis->csf); 2690 PetscCheck(cong || !columns,PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"Columns can be zeroed if and only if A->rmap and A->cmap are congruent and the l2g maps are the same for MATIS"); 2691 PetscCheck(cong || diag == 0.,PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"Nonzero diagonal value supported if and only if A->rmap and A->cmap are congruent and the l2g maps are the same for MATIS"); 2692 PetscCheck(cong || !x || !b,PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"A->rmap and A->cmap need to be congruent, and the l2g maps be the same"); 2693 } 2694 /* get locally owned rows */ 2695 PetscCall(PetscLayoutMapLocal(A->rmap,n,rows,&len,&lrows,NULL)); 2696 /* fix right hand side if needed */ 2697 if (x && b) { 2698 const PetscScalar *xx; 2699 PetscScalar *bb; 2700 2701 PetscCall(VecGetArrayRead(x, &xx)); 2702 PetscCall(VecGetArray(b, &bb)); 2703 for (i=0;i<len;++i) bb[lrows[i]] = diag*xx[lrows[i]]; 2704 PetscCall(VecRestoreArrayRead(x, &xx)); 2705 PetscCall(VecRestoreArray(b, &bb)); 2706 } 2707 /* get rows associated to the local matrices */ 2708 PetscCall(MatGetSize(matis->A,&nl,NULL)); 2709 PetscCall(PetscArrayzero(matis->sf_leafdata,nl)); 2710 PetscCall(PetscArrayzero(matis->sf_rootdata,A->rmap->n)); 2711 for (i=0;i<len;i++) matis->sf_rootdata[lrows[i]] = 1; 2712 PetscCall(PetscFree(lrows)); 2713 PetscCall(PetscSFBcastBegin(matis->sf,MPIU_INT,matis->sf_rootdata,matis->sf_leafdata,MPI_REPLACE)); 2714 PetscCall(PetscSFBcastEnd(matis->sf,MPIU_INT,matis->sf_rootdata,matis->sf_leafdata,MPI_REPLACE)); 2715 PetscCall(PetscMalloc1(nl,&lrows)); 2716 for (i=0,nr=0;i<nl;i++) if (matis->sf_leafdata[i]) lrows[nr++] = i; 2717 PetscCall(MatISZeroRowsColumnsLocal_Private(A,nr,lrows,diag,columns)); 2718 PetscCall(PetscFree(lrows)); 2719 PetscCall(MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY)); 2720 PetscCall(MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY)); 2721 PetscFunctionReturn(0); 2722 } 2723 2724 static PetscErrorCode MatZeroRows_IS(Mat A,PetscInt n,const PetscInt rows[],PetscScalar diag,Vec x,Vec b) 2725 { 2726 PetscFunctionBegin; 2727 PetscCall(MatZeroRowsColumns_Private_IS(A,n,rows,diag,x,b,PETSC_FALSE)); 2728 PetscFunctionReturn(0); 2729 } 2730 2731 static PetscErrorCode MatZeroRowsColumns_IS(Mat A,PetscInt n,const PetscInt rows[],PetscScalar diag,Vec x,Vec b) 2732 { 2733 PetscFunctionBegin; 2734 PetscCall(MatZeroRowsColumns_Private_IS(A,n,rows,diag,x,b,PETSC_TRUE)); 2735 PetscFunctionReturn(0); 2736 } 2737 2738 static PetscErrorCode MatAssemblyBegin_IS(Mat A,MatAssemblyType type) 2739 { 2740 Mat_IS *is = (Mat_IS*)A->data; 2741 2742 PetscFunctionBegin; 2743 PetscCall(MatAssemblyBegin(is->A,type)); 2744 PetscFunctionReturn(0); 2745 } 2746 2747 static PetscErrorCode MatAssemblyEnd_IS(Mat A,MatAssemblyType type) 2748 { 2749 Mat_IS *is = (Mat_IS*)A->data; 2750 PetscBool lnnz; 2751 2752 PetscFunctionBegin; 2753 PetscCall(MatAssemblyEnd(is->A,type)); 2754 /* fix for local empty rows/cols */ 2755 if (is->locempty && type == MAT_FINAL_ASSEMBLY) { 2756 Mat newlA; 2757 ISLocalToGlobalMapping rl2g,cl2g; 2758 IS nzr,nzc; 2759 PetscInt nr,nc,nnzr,nnzc; 2760 PetscBool lnewl2g,newl2g; 2761 2762 PetscCall(MatGetSize(is->A,&nr,&nc)); 2763 PetscCall(MatFindNonzeroRowsOrCols_Basic(is->A,PETSC_FALSE,PETSC_SMALL,&nzr)); 2764 if (!nzr) { 2765 PetscCall(ISCreateStride(PetscObjectComm((PetscObject)is->A),nr,0,1,&nzr)); 2766 } 2767 PetscCall(MatFindNonzeroRowsOrCols_Basic(is->A,PETSC_TRUE,PETSC_SMALL,&nzc)); 2768 if (!nzc) { 2769 PetscCall(ISCreateStride(PetscObjectComm((PetscObject)is->A),nc,0,1,&nzc)); 2770 } 2771 PetscCall(ISGetSize(nzr,&nnzr)); 2772 PetscCall(ISGetSize(nzc,&nnzc)); 2773 if (nnzr != nr || nnzc != nc) { /* need new global l2g map */ 2774 lnewl2g = PETSC_TRUE; 2775 PetscCallMPI(MPI_Allreduce(&lnewl2g,&newl2g,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)A))); 2776 2777 /* extract valid submatrix */ 2778 PetscCall(MatCreateSubMatrix(is->A,nzr,nzc,MAT_INITIAL_MATRIX,&newlA)); 2779 } else { /* local matrix fully populated */ 2780 lnewl2g = PETSC_FALSE; 2781 PetscCallMPI(MPI_Allreduce(&lnewl2g,&newl2g,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)A))); 2782 PetscCall(PetscObjectReference((PetscObject)is->A)); 2783 newlA = is->A; 2784 } 2785 2786 /* attach new global l2g map if needed */ 2787 if (newl2g) { 2788 IS zr,zc; 2789 const PetscInt *ridxs,*cidxs,*zridxs,*zcidxs; 2790 PetscInt *nidxs,i; 2791 2792 PetscCall(ISComplement(nzr,0,nr,&zr)); 2793 PetscCall(ISComplement(nzc,0,nc,&zc)); 2794 PetscCall(PetscMalloc1(PetscMax(nr,nc),&nidxs)); 2795 PetscCall(ISLocalToGlobalMappingGetIndices(is->rmapping,&ridxs)); 2796 PetscCall(ISLocalToGlobalMappingGetIndices(is->cmapping,&cidxs)); 2797 PetscCall(ISGetIndices(zr,&zridxs)); 2798 PetscCall(ISGetIndices(zc,&zcidxs)); 2799 PetscCall(ISGetLocalSize(zr,&nnzr)); 2800 PetscCall(ISGetLocalSize(zc,&nnzc)); 2801 2802 PetscCall(PetscArraycpy(nidxs,ridxs,nr)); 2803 for (i = 0; i < nnzr; i++) nidxs[zridxs[i]] = -1; 2804 PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A),1,nr,nidxs,PETSC_COPY_VALUES,&rl2g)); 2805 PetscCall(PetscArraycpy(nidxs,cidxs,nc)); 2806 for (i = 0; i < nnzc; i++) nidxs[zcidxs[i]] = -1; 2807 PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A),1,nc,nidxs,PETSC_COPY_VALUES,&cl2g)); 2808 2809 PetscCall(ISRestoreIndices(zr,&zridxs)); 2810 PetscCall(ISRestoreIndices(zc,&zcidxs)); 2811 PetscCall(ISLocalToGlobalMappingRestoreIndices(is->rmapping,&ridxs)); 2812 PetscCall(ISLocalToGlobalMappingRestoreIndices(is->cmapping,&cidxs)); 2813 PetscCall(ISDestroy(&nzr)); 2814 PetscCall(ISDestroy(&nzc)); 2815 PetscCall(ISDestroy(&zr)); 2816 PetscCall(ISDestroy(&zc)); 2817 PetscCall(PetscFree(nidxs)); 2818 PetscCall(MatSetLocalToGlobalMapping(A,rl2g,cl2g)); 2819 PetscCall(ISLocalToGlobalMappingDestroy(&rl2g)); 2820 PetscCall(ISLocalToGlobalMappingDestroy(&cl2g)); 2821 } 2822 PetscCall(MatISSetLocalMat(A,newlA)); 2823 PetscCall(MatDestroy(&newlA)); 2824 PetscCall(ISDestroy(&nzr)); 2825 PetscCall(ISDestroy(&nzc)); 2826 is->locempty = PETSC_FALSE; 2827 } 2828 lnnz = (PetscBool)(is->A->nonzerostate == is->lnnzstate); 2829 is->lnnzstate = is->A->nonzerostate; 2830 PetscCall(MPIU_Allreduce(MPI_IN_PLACE,&lnnz,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)A))); 2831 if (lnnz) A->nonzerostate++; 2832 PetscFunctionReturn(0); 2833 } 2834 2835 static PetscErrorCode MatISGetLocalMat_IS(Mat mat,Mat *local) 2836 { 2837 Mat_IS *is = (Mat_IS*)mat->data; 2838 2839 PetscFunctionBegin; 2840 *local = is->A; 2841 PetscFunctionReturn(0); 2842 } 2843 2844 static PetscErrorCode MatISRestoreLocalMat_IS(Mat mat,Mat *local) 2845 { 2846 PetscFunctionBegin; 2847 *local = NULL; 2848 PetscFunctionReturn(0); 2849 } 2850 2851 /*@ 2852 MatISGetLocalMat - Gets the local matrix stored inside a MATIS matrix. 2853 2854 Input Parameter: 2855 . mat - the matrix 2856 2857 Output Parameter: 2858 . local - the local matrix 2859 2860 Level: advanced 2861 2862 Notes: 2863 This can be called if you have precomputed the nonzero structure of the 2864 matrix and want to provide it to the inner matrix object to improve the performance 2865 of the MatSetValues() operation. 2866 2867 Call MatISRestoreLocalMat() when finished with the local matrix. 2868 2869 .seealso: `MATIS` 2870 @*/ 2871 PetscErrorCode MatISGetLocalMat(Mat mat,Mat *local) 2872 { 2873 PetscFunctionBegin; 2874 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 2875 PetscValidPointer(local,2); 2876 PetscUseMethod(mat,"MatISGetLocalMat_C",(Mat,Mat*),(mat,local)); 2877 PetscFunctionReturn(0); 2878 } 2879 2880 /*@ 2881 MatISRestoreLocalMat - Restores the local matrix obtained with MatISGetLocalMat() 2882 2883 Input Parameter: 2884 . mat - the matrix 2885 2886 Output Parameter: 2887 . local - the local matrix 2888 2889 Level: advanced 2890 2891 .seealso: `MATIS` 2892 @*/ 2893 PetscErrorCode MatISRestoreLocalMat(Mat mat,Mat *local) 2894 { 2895 PetscFunctionBegin; 2896 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 2897 PetscValidPointer(local,2); 2898 PetscUseMethod(mat,"MatISRestoreLocalMat_C",(Mat,Mat*),(mat,local)); 2899 PetscFunctionReturn(0); 2900 } 2901 2902 static PetscErrorCode MatISSetLocalMatType_IS(Mat mat,MatType mtype) 2903 { 2904 Mat_IS *is = (Mat_IS*)mat->data; 2905 2906 PetscFunctionBegin; 2907 if (is->A) PetscCall(MatSetType(is->A,mtype)); 2908 PetscCall(PetscFree(is->lmattype)); 2909 PetscCall(PetscStrallocpy(mtype,&is->lmattype)); 2910 PetscFunctionReturn(0); 2911 } 2912 2913 /*@ 2914 MatISSetLocalMatType - Specifies the type of local matrix 2915 2916 Input Parameters: 2917 + mat - the matrix 2918 - mtype - the local matrix type 2919 2920 Output Parameter: 2921 2922 Level: advanced 2923 2924 .seealso: `MATIS`, `MatSetType()`, `MatType` 2925 @*/ 2926 PetscErrorCode MatISSetLocalMatType(Mat mat,MatType mtype) 2927 { 2928 PetscFunctionBegin; 2929 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 2930 PetscUseMethod(mat,"MatISSetLocalMatType_C",(Mat,MatType),(mat,mtype)); 2931 PetscFunctionReturn(0); 2932 } 2933 2934 static PetscErrorCode MatISSetLocalMat_IS(Mat mat,Mat local) 2935 { 2936 Mat_IS *is = (Mat_IS*)mat->data; 2937 PetscInt nrows,ncols,orows,ocols; 2938 MatType mtype,otype; 2939 PetscBool sametype = PETSC_TRUE; 2940 2941 PetscFunctionBegin; 2942 if (is->A && !is->islocalref) { 2943 PetscCall(MatGetSize(is->A,&orows,&ocols)); 2944 PetscCall(MatGetSize(local,&nrows,&ncols)); 2945 PetscCheck(orows == nrows && ocols == ncols,PETSC_COMM_SELF,PETSC_ERR_ARG_SIZ,"Local MATIS matrix should be of size %" PetscInt_FMT "x%" PetscInt_FMT " (you passed a %" PetscInt_FMT "x%" PetscInt_FMT " matrix)",orows,ocols,nrows,ncols); 2946 PetscCall(MatGetType(local,&mtype)); 2947 PetscCall(MatGetType(is->A,&otype)); 2948 PetscCall(PetscStrcmp(mtype,otype,&sametype)); 2949 } 2950 PetscCall(PetscObjectReference((PetscObject)local)); 2951 PetscCall(MatDestroy(&is->A)); 2952 is->A = local; 2953 PetscCall(MatGetType(is->A,&mtype)); 2954 PetscCall(MatISSetLocalMatType(mat,mtype)); 2955 if (!sametype && !is->islocalref) { 2956 PetscCall(MatISSetUpScatters_Private(mat)); 2957 } 2958 PetscFunctionReturn(0); 2959 } 2960 2961 /*@ 2962 MatISSetLocalMat - Replace the local matrix stored inside a MATIS object. 2963 2964 Collective on Mat 2965 2966 Input Parameters: 2967 + mat - the matrix 2968 - local - the local matrix 2969 2970 Output Parameter: 2971 2972 Level: advanced 2973 2974 Notes: 2975 This can be called if you have precomputed the local matrix and 2976 want to provide it to the matrix object MATIS. 2977 2978 .seealso: `MATIS` 2979 @*/ 2980 PetscErrorCode MatISSetLocalMat(Mat mat,Mat local) 2981 { 2982 PetscFunctionBegin; 2983 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 2984 PetscValidHeaderSpecific(local,MAT_CLASSID,2); 2985 PetscUseMethod(mat,"MatISSetLocalMat_C",(Mat,Mat),(mat,local)); 2986 PetscFunctionReturn(0); 2987 } 2988 2989 static PetscErrorCode MatZeroEntries_IS(Mat A) 2990 { 2991 Mat_IS *a = (Mat_IS*)A->data; 2992 2993 PetscFunctionBegin; 2994 PetscCall(MatZeroEntries(a->A)); 2995 PetscFunctionReturn(0); 2996 } 2997 2998 static PetscErrorCode MatScale_IS(Mat A,PetscScalar a) 2999 { 3000 Mat_IS *is = (Mat_IS*)A->data; 3001 3002 PetscFunctionBegin; 3003 PetscCall(MatScale(is->A,a)); 3004 PetscFunctionReturn(0); 3005 } 3006 3007 static PetscErrorCode MatGetDiagonal_IS(Mat A, Vec v) 3008 { 3009 Mat_IS *is = (Mat_IS*)A->data; 3010 3011 PetscFunctionBegin; 3012 /* get diagonal of the local matrix */ 3013 PetscCall(MatGetDiagonal(is->A,is->y)); 3014 3015 /* scatter diagonal back into global vector */ 3016 PetscCall(VecSet(v,0)); 3017 PetscCall(VecScatterBegin(is->rctx,is->y,v,ADD_VALUES,SCATTER_REVERSE)); 3018 PetscCall(VecScatterEnd(is->rctx,is->y,v,ADD_VALUES,SCATTER_REVERSE)); 3019 PetscFunctionReturn(0); 3020 } 3021 3022 static PetscErrorCode MatSetOption_IS(Mat A,MatOption op,PetscBool flg) 3023 { 3024 Mat_IS *a = (Mat_IS*)A->data; 3025 3026 PetscFunctionBegin; 3027 PetscCall(MatSetOption(a->A,op,flg)); 3028 PetscFunctionReturn(0); 3029 } 3030 3031 static PetscErrorCode MatAXPY_IS(Mat Y,PetscScalar a,Mat X,MatStructure str) 3032 { 3033 Mat_IS *y = (Mat_IS*)Y->data; 3034 Mat_IS *x; 3035 3036 PetscFunctionBegin; 3037 if (PetscDefined(USE_DEBUG)) { 3038 PetscBool ismatis; 3039 PetscCall(PetscObjectTypeCompare((PetscObject)X,MATIS,&ismatis)); 3040 PetscCheck(ismatis,PetscObjectComm((PetscObject)Y),PETSC_ERR_SUP,"Cannot call MatAXPY(Y,a,X,str) with X not of type MATIS"); 3041 } 3042 x = (Mat_IS*)X->data; 3043 PetscCall(MatAXPY(y->A,a,x->A,str)); 3044 PetscFunctionReturn(0); 3045 } 3046 3047 static PetscErrorCode MatGetLocalSubMatrix_IS(Mat A,IS row,IS col,Mat *submat) 3048 { 3049 Mat lA; 3050 Mat_IS *matis = (Mat_IS*)(A->data); 3051 ISLocalToGlobalMapping rl2g,cl2g; 3052 IS is; 3053 const PetscInt *rg,*rl; 3054 PetscInt nrg; 3055 PetscInt N,M,nrl,i,*idxs; 3056 3057 PetscFunctionBegin; 3058 PetscCall(ISLocalToGlobalMappingGetIndices(A->rmap->mapping,&rg)); 3059 PetscCall(ISGetLocalSize(row,&nrl)); 3060 PetscCall(ISGetIndices(row,&rl)); 3061 PetscCall(ISLocalToGlobalMappingGetSize(A->rmap->mapping,&nrg)); 3062 if (PetscDefined(USE_DEBUG)) { 3063 for (i=0; i<nrl; i++) PetscCheck(rl[i]<nrg,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Local row index %" PetscInt_FMT " -> %" PetscInt_FMT " greater then maximum possible %" PetscInt_FMT,i,rl[i],nrg); 3064 } 3065 PetscCall(PetscMalloc1(nrg,&idxs)); 3066 /* map from [0,nrl) to row */ 3067 for (i=0;i<nrl;i++) idxs[i] = rl[i]; 3068 for (i=nrl;i<nrg;i++) idxs[i] = -1; 3069 PetscCall(ISRestoreIndices(row,&rl)); 3070 PetscCall(ISLocalToGlobalMappingRestoreIndices(A->rmap->mapping,&rg)); 3071 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)A),nrg,idxs,PETSC_OWN_POINTER,&is)); 3072 PetscCall(ISLocalToGlobalMappingCreateIS(is,&rl2g)); 3073 PetscCall(ISDestroy(&is)); 3074 /* compute new l2g map for columns */ 3075 if (col != row || matis->rmapping != matis->cmapping || matis->A->rmap->mapping != matis->A->cmap->mapping) { 3076 const PetscInt *cg,*cl; 3077 PetscInt ncg; 3078 PetscInt ncl; 3079 3080 PetscCall(ISLocalToGlobalMappingGetIndices(A->cmap->mapping,&cg)); 3081 PetscCall(ISGetLocalSize(col,&ncl)); 3082 PetscCall(ISGetIndices(col,&cl)); 3083 PetscCall(ISLocalToGlobalMappingGetSize(A->cmap->mapping,&ncg)); 3084 if (PetscDefined(USE_DEBUG)) { 3085 for (i=0; i<ncl; i++) PetscCheck(cl[i]<ncg,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Local column index %" PetscInt_FMT " -> %" PetscInt_FMT " greater then maximum possible %" PetscInt_FMT,i,cl[i],ncg); 3086 } 3087 PetscCall(PetscMalloc1(ncg,&idxs)); 3088 /* map from [0,ncl) to col */ 3089 for (i=0;i<ncl;i++) idxs[i] = cl[i]; 3090 for (i=ncl;i<ncg;i++) idxs[i] = -1; 3091 PetscCall(ISRestoreIndices(col,&cl)); 3092 PetscCall(ISLocalToGlobalMappingRestoreIndices(A->cmap->mapping,&cg)); 3093 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)A),ncg,idxs,PETSC_OWN_POINTER,&is)); 3094 PetscCall(ISLocalToGlobalMappingCreateIS(is,&cl2g)); 3095 PetscCall(ISDestroy(&is)); 3096 } else { 3097 PetscCall(PetscObjectReference((PetscObject)rl2g)); 3098 cl2g = rl2g; 3099 } 3100 /* create the MATIS submatrix */ 3101 PetscCall(MatGetSize(A,&M,&N)); 3102 PetscCall(MatCreate(PetscObjectComm((PetscObject)A),submat)); 3103 PetscCall(MatSetSizes(*submat,PETSC_DECIDE,PETSC_DECIDE,M,N)); 3104 PetscCall(MatSetType(*submat,MATIS)); 3105 matis = (Mat_IS*)((*submat)->data); 3106 matis->islocalref = PETSC_TRUE; 3107 PetscCall(MatSetLocalToGlobalMapping(*submat,rl2g,cl2g)); 3108 PetscCall(MatISGetLocalMat(A,&lA)); 3109 PetscCall(MatISSetLocalMat(*submat,lA)); 3110 PetscCall(MatSetUp(*submat)); 3111 PetscCall(MatAssemblyBegin(*submat,MAT_FINAL_ASSEMBLY)); 3112 PetscCall(MatAssemblyEnd(*submat,MAT_FINAL_ASSEMBLY)); 3113 PetscCall(ISLocalToGlobalMappingDestroy(&rl2g)); 3114 PetscCall(ISLocalToGlobalMappingDestroy(&cl2g)); 3115 3116 /* remove unsupported ops */ 3117 PetscCall(PetscMemzero((*submat)->ops,sizeof(struct _MatOps))); 3118 (*submat)->ops->destroy = MatDestroy_IS; 3119 (*submat)->ops->setvalueslocal = MatSetValuesLocal_SubMat_IS; 3120 (*submat)->ops->setvaluesblockedlocal = MatSetValuesBlockedLocal_SubMat_IS; 3121 (*submat)->ops->assemblybegin = MatAssemblyBegin_IS; 3122 (*submat)->ops->assemblyend = MatAssemblyEnd_IS; 3123 PetscFunctionReturn(0); 3124 } 3125 3126 static PetscErrorCode MatSetFromOptions_IS(PetscOptionItems *PetscOptionsObject, Mat A) 3127 { 3128 Mat_IS *a = (Mat_IS*)A->data; 3129 char type[256]; 3130 PetscBool flg; 3131 3132 PetscFunctionBegin; 3133 PetscOptionsHeadBegin(PetscOptionsObject,"MATIS options"); 3134 PetscCall(PetscOptionsBool("-matis_keepassembled","Store an assembled version if needed","MatISKeepAssembled",a->keepassembled,&a->keepassembled,NULL)); 3135 PetscCall(PetscOptionsBool("-matis_fixempty","Fix local matrices in case of empty local rows/columns","MatISFixLocalEmpty",a->locempty,&a->locempty,NULL)); 3136 PetscCall(PetscOptionsBool("-matis_storel2l","Store local-to-local matrices generated from PtAP operations","MatISStoreL2L",a->storel2l,&a->storel2l,NULL)); 3137 PetscCall(PetscOptionsFList("-matis_localmat_type","Matrix type","MatISSetLocalMatType",MatList,a->lmattype,type,256,&flg)); 3138 if (flg) PetscCall(MatISSetLocalMatType(A,type)); 3139 if (a->A) PetscCall(MatSetFromOptions(a->A)); 3140 PetscOptionsHeadEnd(); 3141 PetscFunctionReturn(0); 3142 } 3143 3144 /*@ 3145 MatCreateIS - Creates a "process" unassembled matrix, assembled on each 3146 process but not across processes. 3147 3148 Input Parameters: 3149 + comm - MPI communicator that will share the matrix 3150 . bs - block size of the matrix 3151 . m,n,M,N - local and/or global sizes of the left and right vector used in matrix vector products 3152 . rmap - local to global map for rows 3153 - cmap - local to global map for cols 3154 3155 Output Parameter: 3156 . A - the resulting matrix 3157 3158 Level: advanced 3159 3160 Notes: 3161 See MATIS for more details. 3162 m and n are NOT related to the size of the map; they represent the size of the local parts of the distributed vectors 3163 used in MatMult operations. The sizes of rmap and cmap define the size of the local matrices. 3164 If rmap (cmap) is NULL, then the local row (column) spaces matches the global space. 3165 3166 .seealso: `MATIS`, `MatSetLocalToGlobalMapping()` 3167 @*/ 3168 PetscErrorCode MatCreateIS(MPI_Comm comm,PetscInt bs,PetscInt m,PetscInt n,PetscInt M,PetscInt N,ISLocalToGlobalMapping rmap,ISLocalToGlobalMapping cmap,Mat *A) 3169 { 3170 PetscFunctionBegin; 3171 PetscCall(MatCreate(comm,A)); 3172 PetscCall(MatSetSizes(*A,m,n,M,N)); 3173 if (bs > 0) { 3174 PetscCall(MatSetBlockSize(*A,bs)); 3175 } 3176 PetscCall(MatSetType(*A,MATIS)); 3177 PetscCall(MatSetLocalToGlobalMapping(*A,rmap,cmap)); 3178 PetscFunctionReturn(0); 3179 } 3180 3181 static PetscErrorCode MatHasOperation_IS(Mat A, MatOperation op, PetscBool *has) 3182 { 3183 Mat_IS *a = (Mat_IS*)A->data; 3184 MatOperation tobefiltered[] = { MATOP_MULT_ADD, MATOP_MULT_TRANSPOSE_ADD, MATOP_GET_DIAGONAL_BLOCK, MATOP_INCREASE_OVERLAP}; 3185 3186 PetscFunctionBegin; 3187 *has = PETSC_FALSE; 3188 if (!((void**)A->ops)[op] || !a->A) PetscFunctionReturn(0); 3189 *has = PETSC_TRUE; 3190 for (PetscInt i = 0; i < (PetscInt)PETSC_STATIC_ARRAY_LENGTH(tobefiltered); i++) if (op == tobefiltered[i]) PetscFunctionReturn(0); 3191 PetscCall(MatHasOperation(a->A,op,has)); 3192 PetscFunctionReturn(0); 3193 } 3194 3195 static PetscErrorCode MatSetValuesCOO_IS(Mat A,const PetscScalar v[],InsertMode imode) 3196 { 3197 Mat_IS *a = (Mat_IS*)A->data; 3198 3199 PetscFunctionBegin; 3200 PetscCall(MatSetValuesCOO(a->A,v,imode)); 3201 PetscCall(MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY)); 3202 PetscCall(MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY)); 3203 PetscFunctionReturn(0); 3204 } 3205 3206 static PetscErrorCode MatSetPreallocationCOOLocal_IS(Mat A,PetscCount ncoo,PetscInt coo_i[],PetscInt coo_j[]) 3207 { 3208 Mat_IS *a = (Mat_IS*)A->data; 3209 3210 PetscFunctionBegin; 3211 PetscCheck(a->A,PetscObjectComm((PetscObject)A),PETSC_ERR_ORDER,"Need to provide l2g map first via MatSetLocalToGlobalMapping"); 3212 if (a->A->rmap->mapping || a->A->cmap->mapping) { 3213 PetscCall(MatSetPreallocationCOOLocal(a->A,ncoo,coo_i,coo_j)); 3214 } else { 3215 PetscCall(MatSetPreallocationCOO(a->A,ncoo,coo_i,coo_j)); 3216 } 3217 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatSetValuesCOO_C",MatSetValuesCOO_IS)); 3218 A->preallocated = PETSC_TRUE; 3219 PetscFunctionReturn(0); 3220 } 3221 3222 static PetscErrorCode MatSetPreallocationCOO_IS(Mat A,PetscCount ncoo,PetscInt coo_i[],PetscInt coo_j[]) 3223 { 3224 Mat_IS *a = (Mat_IS*)A->data; 3225 3226 PetscFunctionBegin; 3227 PetscCheck(a->A,PetscObjectComm((PetscObject)A),PETSC_ERR_ORDER,"Need to provide l2g map first via MatSetLocalToGlobalMapping"); 3228 PetscCheck(ncoo <= PETSC_MAX_INT,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"ncoo %" PetscCount_FMT " overflowed PetscInt; configure --with-64-bit-indices or request support",ncoo); 3229 PetscCall(ISGlobalToLocalMappingApply(a->rmapping,IS_GTOLM_MASK,ncoo,coo_i,NULL,coo_i)); 3230 PetscCall(ISGlobalToLocalMappingApply(a->cmapping,IS_GTOLM_MASK,ncoo,coo_j,NULL,coo_j)); 3231 PetscCall(MatSetPreallocationCOO(a->A,ncoo,coo_i,coo_j)); 3232 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatSetValuesCOO_C",MatSetValuesCOO_IS)); 3233 A->preallocated = PETSC_TRUE; 3234 PetscFunctionReturn(0); 3235 } 3236 3237 static PetscErrorCode MatISGetAssembled_Private(Mat A, Mat *tA) 3238 { 3239 Mat_IS *a = (Mat_IS*)A->data; 3240 PetscObjectState Astate, aAstate = PETSC_MIN_INT; 3241 PetscObjectState Annzstate, aAnnzstate = PETSC_MIN_INT; 3242 3243 PetscFunctionBegin; 3244 PetscCall(PetscObjectStateGet((PetscObject)A,&Astate)); 3245 Annzstate = A->nonzerostate; 3246 if (a->assembledA) { 3247 PetscCall(PetscObjectStateGet((PetscObject)a->assembledA,&aAstate)); 3248 aAnnzstate = a->assembledA->nonzerostate; 3249 } 3250 if (aAnnzstate != Annzstate) PetscCall(MatDestroy(&a->assembledA)); 3251 if (Astate != aAstate || !a->assembledA) { 3252 MatType aAtype; 3253 PetscMPIInt size; 3254 PetscInt rbs, cbs, bs; 3255 3256 /* the assembled form is used as temporary storage for parallel operations 3257 like createsubmatrices and the like, do not waste device memory */ 3258 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A),&size)); 3259 PetscCall(ISLocalToGlobalMappingGetBlockSize(a->cmapping,&cbs)); 3260 PetscCall(ISLocalToGlobalMappingGetBlockSize(a->rmapping,&rbs)); 3261 bs = rbs == cbs ? rbs : 1; 3262 if (a->assembledA) PetscCall(MatGetType(a->assembledA,&aAtype)); 3263 else if (size > 1) aAtype = bs > 1 ? MATMPIBAIJ : MATMPIAIJ; 3264 else aAtype = bs > 1 ? MATSEQBAIJ : MATSEQAIJ; 3265 3266 PetscCall(MatConvert(A,aAtype,a->assembledA ? MAT_REUSE_MATRIX : MAT_INITIAL_MATRIX,&a->assembledA)); 3267 PetscCall(PetscObjectStateSet((PetscObject)a->assembledA,Astate)); 3268 a->assembledA->nonzerostate = Annzstate; 3269 } 3270 PetscCall(PetscObjectReference((PetscObject)a->assembledA)); 3271 *tA = a->assembledA; 3272 if (!a->keepassembled) PetscCall(MatDestroy(&a->assembledA)); 3273 PetscFunctionReturn(0); 3274 } 3275 3276 static PetscErrorCode MatISRestoreAssembled_Private(Mat A, Mat *tA) 3277 { 3278 PetscFunctionBegin; 3279 PetscCall(MatDestroy(tA)); 3280 *tA = NULL; 3281 PetscFunctionReturn(0); 3282 } 3283 3284 static PetscErrorCode MatGetDiagonalBlock_IS(Mat A, Mat *dA) 3285 { 3286 Mat_IS *a = (Mat_IS*)A->data; 3287 PetscObjectState Astate, dAstate = PETSC_MIN_INT; 3288 3289 PetscFunctionBegin; 3290 PetscCall(PetscObjectStateGet((PetscObject)A,&Astate)); 3291 if (a->dA) PetscCall(PetscObjectStateGet((PetscObject)a->dA,&dAstate)); 3292 if (Astate != dAstate) { 3293 Mat tA; 3294 MatType ltype; 3295 3296 PetscCall(MatDestroy(&a->dA)); 3297 PetscCall(MatISGetAssembled_Private(A,&tA)); 3298 PetscCall(MatGetDiagonalBlock(tA,&a->dA)); 3299 PetscCall(MatPropagateSymmetryOptions(tA,a->dA)); 3300 PetscCall(MatGetType(a->A,<ype)); 3301 PetscCall(MatConvert(a->dA,ltype,MAT_INPLACE_MATRIX,&a->dA)); 3302 PetscCall(PetscObjectReference((PetscObject)a->dA)); 3303 PetscCall(MatISRestoreAssembled_Private(A,&tA)); 3304 PetscCall(PetscObjectStateSet((PetscObject)a->dA,Astate)); 3305 } 3306 *dA = a->dA; 3307 PetscFunctionReturn(0); 3308 } 3309 3310 static PetscErrorCode MatCreateSubMatrices_IS(Mat A,PetscInt n,const IS irow[],const IS icol[],MatReuse reuse,Mat *submat[]) 3311 { 3312 Mat tA; 3313 3314 PetscFunctionBegin; 3315 PetscCall(MatISGetAssembled_Private(A,&tA)); 3316 PetscCall(MatCreateSubMatrices(tA,n,irow,icol,reuse,submat)); 3317 /* MatCreateSubMatrices_MPIAIJ is a mess at the moment */ 3318 #if 0 3319 { 3320 Mat_IS *a = (Mat_IS*)A->data; 3321 MatType ltype; 3322 VecType vtype; 3323 char *flg; 3324 3325 PetscCall(MatGetType(a->A,<ype)); 3326 PetscCall(MatGetVecType(a->A,&vtype)); 3327 PetscCall(PetscStrstr(vtype,"cuda",&flg)); 3328 if (!flg) PetscCall(PetscStrstr(vtype,"hip",&flg)); 3329 if (!flg) PetscCall(PetscStrstr(vtype,"kokkos",&flg)); 3330 if (flg) { 3331 for (PetscInt i = 0; i < n; i++) { 3332 Mat sA = (*submat)[i]; 3333 3334 PetscCall(MatConvert(sA,ltype,MAT_INPLACE_MATRIX,&sA)); 3335 (*submat)[i] = sA; 3336 } 3337 } 3338 } 3339 #endif 3340 PetscCall(MatISRestoreAssembled_Private(A,&tA)); 3341 PetscFunctionReturn(0); 3342 } 3343 3344 static PetscErrorCode MatIncreaseOverlap_IS(Mat A, PetscInt n, IS is[], PetscInt ov) 3345 { 3346 Mat tA; 3347 3348 PetscFunctionBegin; 3349 PetscCall(MatISGetAssembled_Private(A,&tA)); 3350 PetscCall(MatIncreaseOverlap(tA,n,is,ov)); 3351 PetscCall(MatISRestoreAssembled_Private(A,&tA)); 3352 PetscFunctionReturn(0); 3353 } 3354 3355 /*@ 3356 MatISGetLocalToGlobalMapping - Gets the local-to-global numbering of the MATIS object 3357 3358 Not Collective 3359 3360 Input Parameter: 3361 . A - the matrix 3362 3363 Output Parameters: 3364 + rmapping - row mapping 3365 - cmapping - column mapping 3366 3367 Notes: The returned map can be different from the one used to construct the MATIS object, since it will not contain negative or repeated indices. 3368 3369 Level: advanced 3370 3371 .seealso: `MatSetLocalToGlobalMapping()` 3372 @*/ 3373 PetscErrorCode MatISGetLocalToGlobalMapping(Mat A,ISLocalToGlobalMapping *rmapping,ISLocalToGlobalMapping *cmapping) 3374 { 3375 PetscFunctionBegin; 3376 PetscValidHeaderSpecific(A,MAT_CLASSID,1); 3377 PetscValidType(A,1); 3378 if (rmapping) PetscValidPointer(rmapping,2); 3379 if (cmapping) PetscValidPointer(cmapping,3); 3380 PetscUseMethod(A,"MatISGetLocalToGlobalMapping_C",(Mat,ISLocalToGlobalMapping*,ISLocalToGlobalMapping*),(A,rmapping,cmapping)); 3381 PetscFunctionReturn(0); 3382 } 3383 3384 static PetscErrorCode MatISGetLocalToGlobalMapping_IS(Mat A,ISLocalToGlobalMapping *r, ISLocalToGlobalMapping *c) 3385 { 3386 Mat_IS *a = (Mat_IS*)A->data; 3387 3388 PetscFunctionBegin; 3389 if (r) *r = a->rmapping; 3390 if (c) *c = a->cmapping; 3391 PetscFunctionReturn(0); 3392 } 3393 3394 /*MC 3395 MATIS - MATIS = "is" - A matrix type to be used for using the non-overlapping domain decomposition methods (e.g. PCBDDC or KSPFETIDP). 3396 This stores the matrices in globally unassembled form. Each processor assembles only its local Neumann problem and the parallel matrix vector 3397 product is handled "implicitly". 3398 3399 Options Database Keys: 3400 + -mat_type is - sets the matrix type to "is" during a call to MatSetFromOptions() 3401 . -matis_fixempty - Fixes local matrices in case of empty local rows/columns. 3402 - -matis_storel2l - stores the local-to-local operators generated by the Galerkin process of MatPtAP(). 3403 3404 Notes: 3405 Options prefix for the inner matrix are given by -is_mat_xxx 3406 3407 You must call MatSetLocalToGlobalMapping() before using this matrix type. 3408 3409 You can do matrix preallocation on the local matrix after you obtain it with 3410 MatISGetLocalMat(); otherwise, you could use MatISSetPreallocation() 3411 3412 Level: advanced 3413 3414 .seealso: `Mat`, `MatISGetLocalMat()`, `MatSetLocalToGlobalMapping()`, `MatISSetPreallocation()`, `MatCreateIS()`, `PCBDDC`, `KSPFETIDP` 3415 3416 M*/ 3417 PETSC_EXTERN PetscErrorCode MatCreate_IS(Mat A) 3418 { 3419 Mat_IS *a; 3420 3421 PetscFunctionBegin; 3422 PetscCall(PetscNewLog(A,&a)); 3423 PetscCall(PetscStrallocpy(MATAIJ,&a->lmattype)); 3424 A->data = (void*)a; 3425 3426 /* matrix ops */ 3427 PetscCall(PetscMemzero(A->ops,sizeof(struct _MatOps))); 3428 A->ops->mult = MatMult_IS; 3429 A->ops->multadd = MatMultAdd_IS; 3430 A->ops->multtranspose = MatMultTranspose_IS; 3431 A->ops->multtransposeadd = MatMultTransposeAdd_IS; 3432 A->ops->destroy = MatDestroy_IS; 3433 A->ops->setlocaltoglobalmapping = MatSetLocalToGlobalMapping_IS; 3434 A->ops->setvalues = MatSetValues_IS; 3435 A->ops->setvaluesblocked = MatSetValuesBlocked_IS; 3436 A->ops->setvalueslocal = MatSetValuesLocal_IS; 3437 A->ops->setvaluesblockedlocal = MatSetValuesBlockedLocal_IS; 3438 A->ops->zerorows = MatZeroRows_IS; 3439 A->ops->zerorowscolumns = MatZeroRowsColumns_IS; 3440 A->ops->assemblybegin = MatAssemblyBegin_IS; 3441 A->ops->assemblyend = MatAssemblyEnd_IS; 3442 A->ops->view = MatView_IS; 3443 A->ops->zeroentries = MatZeroEntries_IS; 3444 A->ops->scale = MatScale_IS; 3445 A->ops->getdiagonal = MatGetDiagonal_IS; 3446 A->ops->setoption = MatSetOption_IS; 3447 A->ops->ishermitian = MatIsHermitian_IS; 3448 A->ops->issymmetric = MatIsSymmetric_IS; 3449 A->ops->isstructurallysymmetric = MatIsStructurallySymmetric_IS; 3450 A->ops->duplicate = MatDuplicate_IS; 3451 A->ops->missingdiagonal = MatMissingDiagonal_IS; 3452 A->ops->copy = MatCopy_IS; 3453 A->ops->getlocalsubmatrix = MatGetLocalSubMatrix_IS; 3454 A->ops->createsubmatrix = MatCreateSubMatrix_IS; 3455 A->ops->axpy = MatAXPY_IS; 3456 A->ops->diagonalset = MatDiagonalSet_IS; 3457 A->ops->shift = MatShift_IS; 3458 A->ops->transpose = MatTranspose_IS; 3459 A->ops->getinfo = MatGetInfo_IS; 3460 A->ops->diagonalscale = MatDiagonalScale_IS; 3461 A->ops->setfromoptions = MatSetFromOptions_IS; 3462 A->ops->setup = MatSetUp_IS; 3463 A->ops->hasoperation = MatHasOperation_IS; 3464 A->ops->getdiagonalblock = MatGetDiagonalBlock_IS; 3465 A->ops->createsubmatrices = MatCreateSubMatrices_IS; 3466 A->ops->increaseoverlap = MatIncreaseOverlap_IS; 3467 3468 /* special MATIS functions */ 3469 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatISSetLocalMatType_C",MatISSetLocalMatType_IS)); 3470 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatISGetLocalMat_C",MatISGetLocalMat_IS)); 3471 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatISRestoreLocalMat_C",MatISRestoreLocalMat_IS)); 3472 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatISSetLocalMat_C",MatISSetLocalMat_IS)); 3473 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatISGetMPIXAIJ_C",MatConvert_IS_XAIJ)); 3474 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatISSetPreallocation_C",MatISSetPreallocation_IS)); 3475 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatISStoreL2L_C",MatISStoreL2L_IS)); 3476 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatISFixLocalEmpty_C",MatISFixLocalEmpty_IS)); 3477 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatISGetLocalToGlobalMapping_C",MatISGetLocalToGlobalMapping_IS)); 3478 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_mpiaij_C",MatConvert_IS_XAIJ)); 3479 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_mpibaij_C",MatConvert_IS_XAIJ)); 3480 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_mpisbaij_C",MatConvert_IS_XAIJ)); 3481 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_seqaij_C",MatConvert_IS_XAIJ)); 3482 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_seqbaij_C",MatConvert_IS_XAIJ)); 3483 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_seqsbaij_C",MatConvert_IS_XAIJ)); 3484 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatConvert_is_aij_C",MatConvert_IS_XAIJ)); 3485 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatSetPreallocationCOOLocal_C",MatSetPreallocationCOOLocal_IS)); 3486 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatSetPreallocationCOO_C",MatSetPreallocationCOO_IS)); 3487 PetscCall(PetscObjectChangeTypeName((PetscObject)A,MATIS)); 3488 PetscFunctionReturn(0); 3489 } 3490