1 2 #include "matnestimpl.h" /*I "petscmat.h" I*/ 3 4 static PetscErrorCode MatSetUp_NestIS_Private(Mat,PetscInt,const IS[],PetscInt,const IS[]); 5 static PetscErrorCode MatGetVecs_Nest(Mat A,Vec *right,Vec *left); 6 7 /* private functions */ 8 #undef __FUNCT__ 9 #define __FUNCT__ "MatNestGetSizes_Private" 10 static PetscErrorCode MatNestGetSizes_Private(Mat A,PetscInt *m,PetscInt *n,PetscInt *M,PetscInt *N) 11 { 12 Mat_Nest *bA = (Mat_Nest*)A->data; 13 PetscInt i,j; 14 PetscErrorCode ierr; 15 16 PetscFunctionBegin; 17 *m = *n = *M = *N = 0; 18 for (i=0; i<bA->nr; i++) { /* rows */ 19 PetscInt sm,sM; 20 ierr = ISGetLocalSize(bA->isglobal.row[i],&sm);CHKERRQ(ierr); 21 ierr = ISGetSize(bA->isglobal.row[i],&sM);CHKERRQ(ierr); 22 *m += sm; 23 *M += sM; 24 } 25 for (j=0; j<bA->nc; j++) { /* cols */ 26 PetscInt sn,sN; 27 ierr = ISGetLocalSize(bA->isglobal.col[j],&sn);CHKERRQ(ierr); 28 ierr = ISGetSize(bA->isglobal.col[j],&sN);CHKERRQ(ierr); 29 *n += sn; 30 *N += sN; 31 } 32 PetscFunctionReturn(0); 33 } 34 35 /* operations */ 36 #undef __FUNCT__ 37 #define __FUNCT__ "MatMult_Nest" 38 static PetscErrorCode MatMult_Nest(Mat A,Vec x,Vec y) 39 { 40 Mat_Nest *bA = (Mat_Nest*)A->data; 41 Vec *bx = bA->right,*by = bA->left; 42 PetscInt i,j,nr = bA->nr,nc = bA->nc; 43 PetscErrorCode ierr; 44 45 PetscFunctionBegin; 46 for (i=0; i<nr; i++) {ierr = VecGetSubVector(y,bA->isglobal.row[i],&by[i]);CHKERRQ(ierr);} 47 for (i=0; i<nc; i++) {ierr = VecGetSubVector(x,bA->isglobal.col[i],&bx[i]);CHKERRQ(ierr);} 48 for (i=0; i<nr; i++) { 49 ierr = VecZeroEntries(by[i]);CHKERRQ(ierr); 50 for (j=0; j<nc; j++) { 51 if (!bA->m[i][j]) continue; 52 /* y[i] <- y[i] + A[i][j] * x[j] */ 53 ierr = MatMultAdd(bA->m[i][j],bx[j],by[i],by[i]);CHKERRQ(ierr); 54 } 55 } 56 for (i=0; i<nr; i++) {ierr = VecRestoreSubVector(y,bA->isglobal.row[i],&by[i]);CHKERRQ(ierr);} 57 for (i=0; i<nc; i++) {ierr = VecRestoreSubVector(x,bA->isglobal.col[i],&bx[i]);CHKERRQ(ierr);} 58 PetscFunctionReturn(0); 59 } 60 61 #undef __FUNCT__ 62 #define __FUNCT__ "MatMultAdd_Nest" 63 static PetscErrorCode MatMultAdd_Nest(Mat A,Vec x,Vec y,Vec z) 64 { 65 Mat_Nest *bA = (Mat_Nest*)A->data; 66 Vec *bx = bA->right,*bz = bA->left; 67 PetscInt i,j,nr = bA->nr,nc = bA->nc; 68 PetscErrorCode ierr; 69 70 PetscFunctionBegin; 71 for (i=0; i<nr; i++) {ierr = VecGetSubVector(z,bA->isglobal.row[i],&bz[i]);CHKERRQ(ierr);} 72 for (i=0; i<nc; i++) {ierr = VecGetSubVector(x,bA->isglobal.col[i],&bx[i]);CHKERRQ(ierr);} 73 for (i=0; i<nr; i++) { 74 if (y != z) { 75 Vec by; 76 ierr = VecGetSubVector(y,bA->isglobal.row[i],&by);CHKERRQ(ierr); 77 ierr = VecCopy(by,bz[i]);CHKERRQ(ierr); 78 ierr = VecRestoreSubVector(y,bA->isglobal.row[i],&by);CHKERRQ(ierr); 79 } 80 for (j=0; j<nc; j++) { 81 if (!bA->m[i][j]) continue; 82 /* y[i] <- y[i] + A[i][j] * x[j] */ 83 ierr = MatMultAdd(bA->m[i][j],bx[j],bz[i],bz[i]);CHKERRQ(ierr); 84 } 85 } 86 for (i=0; i<nr; i++) {ierr = VecRestoreSubVector(z,bA->isglobal.row[i],&bz[i]);CHKERRQ(ierr);} 87 for (i=0; i<nc; i++) {ierr = VecRestoreSubVector(x,bA->isglobal.col[i],&bx[i]);CHKERRQ(ierr);} 88 PetscFunctionReturn(0); 89 } 90 91 #undef __FUNCT__ 92 #define __FUNCT__ "MatMultTranspose_Nest" 93 static PetscErrorCode MatMultTranspose_Nest(Mat A,Vec x,Vec y) 94 { 95 Mat_Nest *bA = (Mat_Nest*)A->data; 96 Vec *bx = bA->left,*by = bA->right; 97 PetscInt i,j,nr = bA->nr,nc = bA->nc; 98 PetscErrorCode ierr; 99 100 PetscFunctionBegin; 101 for (i=0; i<nr; i++) {ierr = VecGetSubVector(x,bA->isglobal.row[i],&bx[i]);CHKERRQ(ierr);} 102 for (i=0; i<nc; i++) {ierr = VecGetSubVector(y,bA->isglobal.col[i],&by[i]);CHKERRQ(ierr);} 103 for (j=0; j<nc; j++) { 104 ierr = VecZeroEntries(by[j]);CHKERRQ(ierr); 105 for (i=0; i<nr; i++) { 106 if (!bA->m[j][i]) continue; 107 /* y[j] <- y[j] + (A[i][j])^T * x[i] */ 108 ierr = MatMultTransposeAdd(bA->m[i][j],bx[i],by[j],by[j]);CHKERRQ(ierr); 109 } 110 } 111 for (i=0; i<nr; i++) {ierr = VecRestoreSubVector(x,bA->isglobal.row[i],&bx[i]);CHKERRQ(ierr);} 112 for (i=0; i<nc; i++) {ierr = VecRestoreSubVector(y,bA->isglobal.col[i],&by[i]);CHKERRQ(ierr);} 113 PetscFunctionReturn(0); 114 } 115 116 #undef __FUNCT__ 117 #define __FUNCT__ "MatMultTransposeAdd_Nest" 118 static PetscErrorCode MatMultTransposeAdd_Nest(Mat A,Vec x,Vec y,Vec z) 119 { 120 Mat_Nest *bA = (Mat_Nest*)A->data; 121 Vec *bx = bA->left,*bz = bA->right; 122 PetscInt i,j,nr = bA->nr,nc = bA->nc; 123 PetscErrorCode ierr; 124 125 PetscFunctionBegin; 126 for (i=0; i<nr; i++) {ierr = VecGetSubVector(x,bA->isglobal.row[i],&bx[i]);CHKERRQ(ierr);} 127 for (i=0; i<nc; i++) {ierr = VecGetSubVector(z,bA->isglobal.col[i],&bz[i]);CHKERRQ(ierr);} 128 for (j=0; j<nc; j++) { 129 if (y != z) { 130 Vec by; 131 ierr = VecGetSubVector(y,bA->isglobal.col[j],&by);CHKERRQ(ierr); 132 ierr = VecCopy(by,bz[j]);CHKERRQ(ierr); 133 ierr = VecRestoreSubVector(y,bA->isglobal.col[j],&by);CHKERRQ(ierr); 134 } 135 for (i=0; i<nr; i++) { 136 if (!bA->m[j][i]) continue; 137 /* z[j] <- y[j] + (A[i][j])^T * x[i] */ 138 ierr = MatMultTransposeAdd(bA->m[i][j],bx[i],bz[j],bz[j]);CHKERRQ(ierr); 139 } 140 } 141 for (i=0; i<nr; i++) {ierr = VecRestoreSubVector(x,bA->isglobal.row[i],&bx[i]);CHKERRQ(ierr);} 142 for (i=0; i<nc; i++) {ierr = VecRestoreSubVector(z,bA->isglobal.col[i],&bz[i]);CHKERRQ(ierr);} 143 PetscFunctionReturn(0); 144 } 145 146 #undef __FUNCT__ 147 #define __FUNCT__ "MatNestDestroyISList" 148 static PetscErrorCode MatNestDestroyISList(PetscInt n,IS **list) 149 { 150 PetscErrorCode ierr; 151 IS *lst = *list; 152 PetscInt i; 153 154 PetscFunctionBegin; 155 if (!lst) PetscFunctionReturn(0); 156 for (i=0; i<n; i++) if (lst[i]) {ierr = ISDestroy(&lst[i]);CHKERRQ(ierr);} 157 ierr = PetscFree(lst);CHKERRQ(ierr); 158 *list = PETSC_NULL; 159 PetscFunctionReturn(0); 160 } 161 162 #undef __FUNCT__ 163 #define __FUNCT__ "MatDestroy_Nest" 164 static PetscErrorCode MatDestroy_Nest(Mat A) 165 { 166 Mat_Nest *vs = (Mat_Nest*)A->data; 167 PetscInt i,j; 168 PetscErrorCode ierr; 169 170 PetscFunctionBegin; 171 /* release the matrices and the place holders */ 172 ierr = MatNestDestroyISList(vs->nr,&vs->isglobal.row);CHKERRQ(ierr); 173 ierr = MatNestDestroyISList(vs->nc,&vs->isglobal.col);CHKERRQ(ierr); 174 ierr = MatNestDestroyISList(vs->nr,&vs->islocal.row);CHKERRQ(ierr); 175 ierr = MatNestDestroyISList(vs->nc,&vs->islocal.col);CHKERRQ(ierr); 176 177 ierr = PetscFree(vs->row_len);CHKERRQ(ierr); 178 ierr = PetscFree(vs->col_len);CHKERRQ(ierr); 179 180 ierr = PetscFree2(vs->left,vs->right);CHKERRQ(ierr); 181 182 /* release the matrices and the place holders */ 183 if (vs->m) { 184 for (i=0; i<vs->nr; i++) { 185 for (j=0; j<vs->nc; j++) { 186 ierr = MatDestroy(&vs->m[i][j]);CHKERRQ(ierr); 187 } 188 ierr = PetscFree( vs->m[i] );CHKERRQ(ierr); 189 } 190 ierr = PetscFree(vs->m);CHKERRQ(ierr); 191 } 192 ierr = PetscFree(A->data);CHKERRQ(ierr); 193 194 ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestGetSubMat_C", "",0);CHKERRQ(ierr); 195 ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestSetSubMat_C", "",0);CHKERRQ(ierr); 196 ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestGetSubMats_C", "",0);CHKERRQ(ierr); 197 ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestGetSize_C", "",0);CHKERRQ(ierr); 198 ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestSetVecType_C", "",0);CHKERRQ(ierr); 199 ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestSetSubMats_C", "",0);CHKERRQ(ierr); 200 PetscFunctionReturn(0); 201 } 202 203 #undef __FUNCT__ 204 #define __FUNCT__ "MatAssemblyBegin_Nest" 205 static PetscErrorCode MatAssemblyBegin_Nest(Mat A,MatAssemblyType type) 206 { 207 Mat_Nest *vs = (Mat_Nest*)A->data; 208 PetscInt i,j; 209 PetscErrorCode ierr; 210 211 PetscFunctionBegin; 212 for (i=0; i<vs->nr; i++) { 213 for (j=0; j<vs->nc; j++) { 214 if (vs->m[i][j]) { ierr = MatAssemblyBegin(vs->m[i][j],type);CHKERRQ(ierr); } 215 } 216 } 217 PetscFunctionReturn(0); 218 } 219 220 #undef __FUNCT__ 221 #define __FUNCT__ "MatAssemblyEnd_Nest" 222 static PetscErrorCode MatAssemblyEnd_Nest(Mat A, MatAssemblyType type) 223 { 224 Mat_Nest *vs = (Mat_Nest*)A->data; 225 PetscInt i,j; 226 PetscErrorCode ierr; 227 228 PetscFunctionBegin; 229 for (i=0; i<vs->nr; i++) { 230 for (j=0; j<vs->nc; j++) { 231 if (vs->m[i][j]) { ierr = MatAssemblyEnd(vs->m[i][j],type);CHKERRQ(ierr); } 232 } 233 } 234 PetscFunctionReturn(0); 235 } 236 237 #undef __FUNCT__ 238 #define __FUNCT__ "MatNestFindNonzeroSubMatRow" 239 static PetscErrorCode MatNestFindNonzeroSubMatRow(Mat A,PetscInt row,Mat *B) 240 { 241 PetscErrorCode ierr; 242 Mat_Nest *vs = (Mat_Nest*)A->data; 243 PetscInt j; 244 Mat sub; 245 246 PetscFunctionBegin; 247 sub = (row < vs->nc) ? vs->m[row][row] : PETSC_NULL; /* Prefer to find on the diagonal */ 248 for (j=0; !sub && j<vs->nc; j++) sub = vs->m[row][j]; 249 if (sub) {ierr = MatPreallocated(sub);CHKERRQ(ierr);} /* Ensure that the sizes are available */ 250 *B = sub; 251 PetscFunctionReturn(0); 252 } 253 254 #undef __FUNCT__ 255 #define __FUNCT__ "MatNestFindNonzeroSubMatCol" 256 static PetscErrorCode MatNestFindNonzeroSubMatCol(Mat A,PetscInt col,Mat *B) 257 { 258 PetscErrorCode ierr; 259 Mat_Nest *vs = (Mat_Nest*)A->data; 260 PetscInt i; 261 Mat sub; 262 263 PetscFunctionBegin; 264 sub = (col < vs->nr) ? vs->m[col][col] : PETSC_NULL; /* Prefer to find on the diagonal */ 265 for (i=0; !sub && i<vs->nr; i++) sub = vs->m[i][col]; 266 if (sub) {ierr = MatPreallocated(sub);CHKERRQ(ierr);} /* Ensure that the sizes are available */ 267 *B = sub; 268 PetscFunctionReturn(0); 269 } 270 271 #undef __FUNCT__ 272 #define __FUNCT__ "MatNestFindIS" 273 static PetscErrorCode MatNestFindIS(Mat A,PetscInt n,const IS list[],IS is,PetscInt *found) 274 { 275 PetscErrorCode ierr; 276 PetscInt i; 277 PetscBool flg; 278 279 PetscFunctionBegin; 280 PetscValidPointer(list,3); 281 PetscValidHeaderSpecific(is,IS_CLASSID,4); 282 PetscValidIntPointer(found,5); 283 *found = -1; 284 for (i=0; i<n; i++) { 285 if (!list[i]) continue; 286 ierr = ISEqual(list[i],is,&flg);CHKERRQ(ierr); 287 if (flg) { 288 *found = i; 289 PetscFunctionReturn(0); 290 } 291 } 292 SETERRQ(((PetscObject)A)->comm,PETSC_ERR_ARG_INCOMP,"Could not find index set"); 293 PetscFunctionReturn(0); 294 } 295 296 #undef __FUNCT__ 297 #define __FUNCT__ "MatNestGetRow" 298 /* Get a block row as a new MatNest */ 299 static PetscErrorCode MatNestGetRow(Mat A,PetscInt row,Mat *B) 300 { 301 Mat_Nest *vs = (Mat_Nest*)A->data; 302 char keyname[256]; 303 PetscErrorCode ierr; 304 305 PetscFunctionBegin; 306 *B = PETSC_NULL; 307 ierr = PetscSNPrintf(keyname,sizeof keyname,"NestRow_%D",row);CHKERRQ(ierr); 308 ierr = PetscObjectQuery((PetscObject)A,keyname,(PetscObject*)B);CHKERRQ(ierr); 309 if (*B) PetscFunctionReturn(0); 310 311 ierr = MatCreateNest(((PetscObject)A)->comm,1,PETSC_NULL,vs->nc,vs->isglobal.col,vs->m[row],B);CHKERRQ(ierr); 312 (*B)->assembled = A->assembled; 313 ierr = PetscObjectCompose((PetscObject)A,keyname,(PetscObject)*B);CHKERRQ(ierr); 314 ierr = PetscObjectDereference((PetscObject)*B);CHKERRQ(ierr); /* Leave the only remaining reference in the composition */ 315 PetscFunctionReturn(0); 316 } 317 318 #undef __FUNCT__ 319 #define __FUNCT__ "MatNestFindSubMat" 320 static PetscErrorCode MatNestFindSubMat(Mat A,struct MatNestISPair *is,IS isrow,IS iscol,Mat *B) 321 { 322 Mat_Nest *vs = (Mat_Nest*)A->data; 323 PetscErrorCode ierr; 324 PetscInt row,col; 325 PetscBool same,isFullCol; 326 327 PetscFunctionBegin; 328 /* Check if full column space. This is a hack */ 329 isFullCol = PETSC_FALSE; 330 ierr = PetscTypeCompare((PetscObject)iscol,ISSTRIDE,&same);CHKERRQ(ierr); 331 if (same) { 332 PetscInt n,first,step,i,an,am,afirst,astep; 333 ierr = ISStrideGetInfo(iscol,&first,&step);CHKERRQ(ierr); 334 ierr = ISGetLocalSize(iscol,&n);CHKERRQ(ierr); 335 isFullCol = PETSC_TRUE; 336 for (i=0,an=0; i<vs->nc; i++) { 337 ierr = ISStrideGetInfo(is->col[i],&afirst,&astep);CHKERRQ(ierr); 338 ierr = ISGetLocalSize(is->col[i],&am);CHKERRQ(ierr); 339 if (afirst != an || astep != step) isFullCol = PETSC_FALSE; 340 an += am; 341 } 342 if (an != n) isFullCol = PETSC_FALSE; 343 } 344 345 if (isFullCol) { 346 PetscInt row; 347 ierr = MatNestFindIS(A,vs->nr,is->row,isrow,&row);CHKERRQ(ierr); 348 ierr = MatNestGetRow(A,row,B);CHKERRQ(ierr); 349 } else { 350 ierr = MatNestFindIS(A,vs->nr,is->row,isrow,&row);CHKERRQ(ierr); 351 ierr = MatNestFindIS(A,vs->nc,is->col,iscol,&col);CHKERRQ(ierr); 352 *B = vs->m[row][col]; 353 } 354 PetscFunctionReturn(0); 355 } 356 357 #undef __FUNCT__ 358 #define __FUNCT__ "MatGetSubMatrix_Nest" 359 static PetscErrorCode MatGetSubMatrix_Nest(Mat A,IS isrow,IS iscol,MatReuse reuse,Mat *B) 360 { 361 PetscErrorCode ierr; 362 Mat_Nest *vs = (Mat_Nest*)A->data; 363 Mat sub; 364 365 PetscFunctionBegin; 366 ierr = MatNestFindSubMat(A,&vs->isglobal,isrow,iscol,&sub);CHKERRQ(ierr); 367 switch (reuse) { 368 case MAT_INITIAL_MATRIX: 369 if (sub) { ierr = PetscObjectReference((PetscObject)sub);CHKERRQ(ierr); } 370 *B = sub; 371 break; 372 case MAT_REUSE_MATRIX: 373 if (sub != *B) SETERRQ(((PetscObject)A)->comm,PETSC_ERR_ARG_WRONGSTATE,"Submatrix was not used before in this call"); 374 break; 375 case MAT_IGNORE_MATRIX: /* Nothing to do */ 376 break; 377 } 378 PetscFunctionReturn(0); 379 } 380 381 #undef __FUNCT__ 382 #define __FUNCT__ "MatGetLocalSubMatrix_Nest" 383 PetscErrorCode MatGetLocalSubMatrix_Nest(Mat A,IS isrow,IS iscol,Mat *B) 384 { 385 PetscErrorCode ierr; 386 Mat_Nest *vs = (Mat_Nest*)A->data; 387 Mat sub; 388 389 PetscFunctionBegin; 390 ierr = MatNestFindSubMat(A,&vs->islocal,isrow,iscol,&sub);CHKERRQ(ierr); 391 /* We allow the submatrix to be NULL, perhaps it would be better for the user to return an empty matrix instead */ 392 if (sub) {ierr = PetscObjectReference((PetscObject)sub);CHKERRQ(ierr);} 393 *B = sub; 394 PetscFunctionReturn(0); 395 } 396 397 #undef __FUNCT__ 398 #define __FUNCT__ "MatRestoreLocalSubMatrix_Nest" 399 static PetscErrorCode MatRestoreLocalSubMatrix_Nest(Mat A,IS isrow,IS iscol,Mat *B) 400 { 401 PetscErrorCode ierr; 402 Mat_Nest *vs = (Mat_Nest*)A->data; 403 Mat sub; 404 405 PetscFunctionBegin; 406 ierr = MatNestFindSubMat(A,&vs->islocal,isrow,iscol,&sub);CHKERRQ(ierr); 407 if (*B != sub) SETERRQ(((PetscObject)A)->comm,PETSC_ERR_ARG_WRONGSTATE,"Local submatrix has not been gotten"); 408 if (sub) { 409 if (((PetscObject)sub)->refct <= 1) SETERRQ(((PetscObject)A)->comm,PETSC_ERR_ARG_WRONGSTATE,"Local submatrix has had reference count decremented too many times"); 410 ierr = MatDestroy(B);CHKERRQ(ierr); 411 } 412 PetscFunctionReturn(0); 413 } 414 415 #undef __FUNCT__ 416 #define __FUNCT__ "MatGetDiagonal_Nest" 417 static PetscErrorCode MatGetDiagonal_Nest(Mat A,Vec v) 418 { 419 Mat_Nest *bA = (Mat_Nest*)A->data; 420 PetscInt i; 421 PetscErrorCode ierr; 422 423 PetscFunctionBegin; 424 for (i=0; i<bA->nr; i++) { 425 Vec bv; 426 ierr = VecGetSubVector(v,bA->isglobal.row[i],&bv);CHKERRQ(ierr); 427 if (bA->m[i][i]) { 428 ierr = MatGetDiagonal(bA->m[i][i],bv);CHKERRQ(ierr); 429 } else { 430 ierr = VecSet(bv,1.0);CHKERRQ(ierr); 431 } 432 ierr = VecRestoreSubVector(v,bA->isglobal.row[i],&bv);CHKERRQ(ierr); 433 } 434 PetscFunctionReturn(0); 435 } 436 437 #undef __FUNCT__ 438 #define __FUNCT__ "MatDiagonalScale_Nest" 439 static PetscErrorCode MatDiagonalScale_Nest(Mat A,Vec l,Vec r) 440 { 441 Mat_Nest *bA = (Mat_Nest*)A->data; 442 Vec bl,*br; 443 PetscInt i,j; 444 PetscErrorCode ierr; 445 446 PetscFunctionBegin; 447 ierr = PetscMalloc(bA->nc*sizeof(Vec),&br);CHKERRQ(ierr); 448 for (j=0; j<bA->nc; j++) {ierr = VecGetSubVector(r,bA->isglobal.col[j],&br[j]);CHKERRQ(ierr);} 449 for (i=0; i<bA->nr; i++) { 450 ierr = VecGetSubVector(l,bA->isglobal.row[i],&bl);CHKERRQ(ierr); 451 for (j=0; j<bA->nc; j++) { 452 if (bA->m[i][j]) { 453 ierr = MatDiagonalScale(bA->m[i][j],bl,br[j]);CHKERRQ(ierr); 454 } 455 } 456 ierr = VecRestoreSubVector(l,bA->isglobal.row[i],&bl);CHKERRQ(ierr); 457 } 458 for (j=0; j<bA->nc; j++) {ierr = VecRestoreSubVector(r,bA->isglobal.col[j],&br[j]);CHKERRQ(ierr);} 459 ierr = PetscFree(br);CHKERRQ(ierr); 460 PetscFunctionReturn(0); 461 } 462 463 #undef __FUNCT__ 464 #define __FUNCT__ "MatScale_Nest" 465 static PetscErrorCode MatScale_Nest(Mat A,PetscScalar a) 466 { 467 Mat_Nest *bA = (Mat_Nest*)A->data; 468 PetscInt i,j; 469 PetscErrorCode ierr; 470 471 PetscFunctionBegin; 472 for (i=0; i<bA->nr; i++) { 473 for (j=0; j<bA->nc; j++) { 474 if (bA->m[i][j]) { 475 ierr = MatScale(bA->m[i][j],a);CHKERRQ(ierr); 476 } 477 } 478 } 479 PetscFunctionReturn(0); 480 } 481 482 #undef __FUNCT__ 483 #define __FUNCT__ "MatShift_Nest" 484 static PetscErrorCode MatShift_Nest(Mat A,PetscScalar a) 485 { 486 Mat_Nest *bA = (Mat_Nest*)A->data; 487 PetscInt i; 488 PetscErrorCode ierr; 489 490 PetscFunctionBegin; 491 for (i=0; i<bA->nr; i++) { 492 if (!bA->m[i][i]) SETERRQ2(((PetscObject)A)->comm,PETSC_ERR_SUP,"No support for shifting an empty diagonal block, insert a matrix in block (%D,%D)",i,i); 493 ierr = MatShift(bA->m[i][i],a);CHKERRQ(ierr); 494 } 495 PetscFunctionReturn(0); 496 } 497 498 #undef __FUNCT__ 499 #define __FUNCT__ "MatGetVecs_Nest" 500 static PetscErrorCode MatGetVecs_Nest(Mat A,Vec *right,Vec *left) 501 { 502 Mat_Nest *bA = (Mat_Nest*)A->data; 503 Vec *L,*R; 504 MPI_Comm comm; 505 PetscInt i,j; 506 PetscErrorCode ierr; 507 508 PetscFunctionBegin; 509 comm = ((PetscObject)A)->comm; 510 if (right) { 511 /* allocate R */ 512 ierr = PetscMalloc( sizeof(Vec) * bA->nc, &R );CHKERRQ(ierr); 513 /* Create the right vectors */ 514 for (j=0; j<bA->nc; j++) { 515 for (i=0; i<bA->nr; i++) { 516 if (bA->m[i][j]) { 517 ierr = MatGetVecs(bA->m[i][j],&R[j],PETSC_NULL);CHKERRQ(ierr); 518 break; 519 } 520 } 521 if (i==bA->nr) { 522 /* have an empty column */ 523 SETERRQ( ((PetscObject)A)->comm, PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null column."); 524 } 525 } 526 ierr = VecCreateNest(comm,bA->nc,bA->isglobal.col,R,right);CHKERRQ(ierr); 527 /* hand back control to the nest vector */ 528 for (j=0; j<bA->nc; j++) { 529 ierr = VecDestroy(&R[j]);CHKERRQ(ierr); 530 } 531 ierr = PetscFree(R);CHKERRQ(ierr); 532 } 533 534 if (left) { 535 /* allocate L */ 536 ierr = PetscMalloc( sizeof(Vec) * bA->nr, &L );CHKERRQ(ierr); 537 /* Create the left vectors */ 538 for (i=0; i<bA->nr; i++) { 539 for (j=0; j<bA->nc; j++) { 540 if (bA->m[i][j]) { 541 ierr = MatGetVecs(bA->m[i][j],PETSC_NULL,&L[i]);CHKERRQ(ierr); 542 break; 543 } 544 } 545 if (j==bA->nc) { 546 /* have an empty row */ 547 SETERRQ( ((PetscObject)A)->comm, PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null row."); 548 } 549 } 550 551 ierr = VecCreateNest(comm,bA->nr,bA->isglobal.row,L,left);CHKERRQ(ierr); 552 for (i=0; i<bA->nr; i++) { 553 ierr = VecDestroy(&L[i]);CHKERRQ(ierr); 554 } 555 556 ierr = PetscFree(L);CHKERRQ(ierr); 557 } 558 PetscFunctionReturn(0); 559 } 560 561 #undef __FUNCT__ 562 #define __FUNCT__ "MatView_Nest" 563 static PetscErrorCode MatView_Nest(Mat A,PetscViewer viewer) 564 { 565 Mat_Nest *bA = (Mat_Nest*)A->data; 566 PetscBool isascii; 567 PetscInt i,j; 568 PetscErrorCode ierr; 569 570 PetscFunctionBegin; 571 ierr = PetscTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii);CHKERRQ(ierr); 572 if (isascii) { 573 574 PetscViewerASCIIPrintf(viewer,"Matrix object: \n" ); 575 PetscViewerASCIIPushTab( viewer ); /* push0 */ 576 PetscViewerASCIIPrintf( viewer, "type=nest, rows=%d, cols=%d \n",bA->nr,bA->nc); 577 578 PetscViewerASCIIPrintf(viewer,"MatNest structure: \n" ); 579 for (i=0; i<bA->nr; i++) { 580 for (j=0; j<bA->nc; j++) { 581 const MatType type; 582 char name[256] = "",prefix[256] = ""; 583 PetscInt NR,NC; 584 PetscBool isNest = PETSC_FALSE; 585 586 if (!bA->m[i][j]) { 587 PetscViewerASCIIPrintf( viewer, "(%D,%D) : PETSC_NULL \n",i,j); 588 continue; 589 } 590 ierr = MatGetSize(bA->m[i][j],&NR,&NC);CHKERRQ(ierr); 591 ierr = MatGetType( bA->m[i][j], &type );CHKERRQ(ierr); 592 if (((PetscObject)bA->m[i][j])->name) {ierr = PetscSNPrintf(name,sizeof name,"name=\"%s\", ",((PetscObject)bA->m[i][j])->name);CHKERRQ(ierr);} 593 if (((PetscObject)bA->m[i][j])->prefix) {ierr = PetscSNPrintf(prefix,sizeof prefix,"prefix=\"%s\", ",((PetscObject)bA->m[i][j])->prefix);CHKERRQ(ierr);} 594 ierr = PetscTypeCompare((PetscObject)bA->m[i][j],MATNEST,&isNest);CHKERRQ(ierr); 595 596 ierr = PetscViewerASCIIPrintf(viewer,"(%D,%D) : %s%stype=%s, rows=%D, cols=%D \n",i,j,name,prefix,type,NR,NC);CHKERRQ(ierr); 597 598 if (isNest) { 599 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); /* push1 */ 600 ierr = MatView(bA->m[i][j],viewer);CHKERRQ(ierr); 601 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); /* pop1 */ 602 } 603 } 604 } 605 PetscViewerASCIIPopTab(viewer); /* pop0 */ 606 } 607 PetscFunctionReturn(0); 608 } 609 610 #undef __FUNCT__ 611 #define __FUNCT__ "MatZeroEntries_Nest" 612 static PetscErrorCode MatZeroEntries_Nest(Mat A) 613 { 614 Mat_Nest *bA = (Mat_Nest*)A->data; 615 PetscInt i,j; 616 PetscErrorCode ierr; 617 618 PetscFunctionBegin; 619 for (i=0; i<bA->nr; i++) { 620 for (j=0; j<bA->nc; j++) { 621 if (!bA->m[i][j]) continue; 622 ierr = MatZeroEntries(bA->m[i][j]);CHKERRQ(ierr); 623 } 624 } 625 PetscFunctionReturn(0); 626 } 627 628 #undef __FUNCT__ 629 #define __FUNCT__ "MatDuplicate_Nest" 630 static PetscErrorCode MatDuplicate_Nest(Mat A,MatDuplicateOption op,Mat *B) 631 { 632 Mat_Nest *bA = (Mat_Nest*)A->data; 633 Mat *b; 634 PetscInt i,j,nr = bA->nr,nc = bA->nc; 635 PetscErrorCode ierr; 636 637 PetscFunctionBegin; 638 ierr = PetscMalloc(nr*nc*sizeof(Mat),&b);CHKERRQ(ierr); 639 for (i=0; i<nr; i++) { 640 for (j=0; j<nc; j++) { 641 if (bA->m[i][j]) { 642 ierr = MatDuplicate(bA->m[i][j],op,&b[i*nc+j]);CHKERRQ(ierr); 643 } else { 644 b[i*nc+j] = PETSC_NULL; 645 } 646 } 647 } 648 ierr = MatCreateNest(((PetscObject)A)->comm,nr,bA->isglobal.row,nc,bA->isglobal.col,b,B);CHKERRQ(ierr); 649 /* Give the new MatNest exclusive ownership */ 650 for (i=0; i<nr*nc; i++) { 651 ierr = MatDestroy(&b[i]);CHKERRQ(ierr); 652 } 653 ierr = PetscFree(b);CHKERRQ(ierr); 654 655 ierr = MatAssemblyBegin(*B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 656 ierr = MatAssemblyEnd(*B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 657 PetscFunctionReturn(0); 658 } 659 660 /* nest api */ 661 EXTERN_C_BEGIN 662 #undef __FUNCT__ 663 #define __FUNCT__ "MatNestGetSubMat_Nest" 664 PetscErrorCode MatNestGetSubMat_Nest(Mat A,PetscInt idxm,PetscInt jdxm,Mat *mat) 665 { 666 Mat_Nest *bA = (Mat_Nest*)A->data; 667 PetscFunctionBegin; 668 if (idxm >= bA->nr) SETERRQ2(((PetscObject)A)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Row too large: row %D max %D",idxm,bA->nr-1); 669 if (jdxm >= bA->nc) SETERRQ2(((PetscObject)A)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Col too large: row %D max %D",jdxm,bA->nc-1); 670 *mat = bA->m[idxm][jdxm]; 671 PetscFunctionReturn(0); 672 } 673 EXTERN_C_END 674 675 #undef __FUNCT__ 676 #define __FUNCT__ "MatNestGetSubMat" 677 /*@C 678 MatNestGetSubMat - Returns a single, sub-matrix from a nest matrix. 679 680 Not collective 681 682 Input Parameters: 683 + A - nest matrix 684 . idxm - index of the matrix within the nest matrix 685 - jdxm - index of the matrix within the nest matrix 686 687 Output Parameter: 688 . sub - matrix at index idxm,jdxm within the nest matrix 689 690 Level: developer 691 692 .seealso: MatNestGetSize(), MatNestGetSubMats() 693 @*/ 694 PetscErrorCode MatNestGetSubMat(Mat A,PetscInt idxm,PetscInt jdxm,Mat *sub) 695 { 696 PetscErrorCode ierr; 697 698 PetscFunctionBegin; 699 ierr = PetscUseMethod(A,"MatNestGetSubMat_C",(Mat,PetscInt,PetscInt,Mat*),(A,idxm,jdxm,sub));CHKERRQ(ierr); 700 PetscFunctionReturn(0); 701 } 702 703 EXTERN_C_BEGIN 704 #undef __FUNCT__ 705 #define __FUNCT__ "MatNestSetSubMat_Nest" 706 PetscErrorCode MatNestSetSubMat_Nest(Mat A,PetscInt idxm,PetscInt jdxm,Mat mat) 707 { 708 Mat_Nest *bA = (Mat_Nest*)A->data; 709 PetscInt m,n,M,N,mi,ni,Mi,Ni; 710 PetscErrorCode ierr; 711 712 PetscFunctionBegin; 713 if (idxm >= bA->nr) SETERRQ2(((PetscObject)A)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Row too large: row %D max %D",idxm,bA->nr-1); 714 if (jdxm >= bA->nc) SETERRQ2(((PetscObject)A)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Col too large: row %D max %D",jdxm,bA->nc-1); 715 ierr = MatGetLocalSize(mat,&m,&n);CHKERRQ(ierr); 716 ierr = MatGetSize(mat,&M,&N);CHKERRQ(ierr); 717 ierr = ISGetLocalSize(bA->isglobal.row[idxm],&mi);CHKERRQ(ierr); 718 ierr = ISGetSize(bA->isglobal.row[idxm],&Mi);CHKERRQ(ierr); 719 ierr = ISGetLocalSize(bA->isglobal.col[jdxm],&ni);CHKERRQ(ierr); 720 ierr = ISGetSize(bA->isglobal.col[jdxm],&Ni);CHKERRQ(ierr); 721 if (M != Mi || N != Ni) SETERRQ4(((PetscObject)mat)->comm,PETSC_ERR_ARG_INCOMP,"Submatrix dimension (%D,%D) incompatible with nest block (%D,%D)",M,N,Mi,Ni); 722 if (m != mi || n != ni) SETERRQ4(((PetscObject)mat)->comm,PETSC_ERR_ARG_INCOMP,"Submatrix local dimension (%D,%D) incompatible with nest block (%D,%D)",m,n,mi,ni); 723 ierr = PetscObjectReference((PetscObject)mat);CHKERRQ(ierr); 724 ierr = MatDestroy(&bA->m[idxm][jdxm]);CHKERRQ(ierr); 725 bA->m[idxm][jdxm] = mat; 726 PetscFunctionReturn(0); 727 } 728 EXTERN_C_END 729 730 #undef __FUNCT__ 731 #define __FUNCT__ "MatNestSetSubMat" 732 /*@C 733 MatNestSetSubMat - Set a single submatrix in the nest matrix. 734 735 Logically collective on the submatrix communicator 736 737 Input Parameters: 738 + A - nest matrix 739 . idxm - index of the matrix within the nest matrix 740 . jdxm - index of the matrix within the nest matrix 741 - sub - matrix at index idxm,jdxm within the nest matrix 742 743 Notes: 744 The new submatrix must have the same size and communicator as that block of the nest. 745 746 This increments the reference count of the submatrix. 747 748 Level: developer 749 750 .seealso: MatNestSetSubMats(), MatNestGetSubMat() 751 @*/ 752 PetscErrorCode MatNestSetSubMat(Mat A,PetscInt idxm,PetscInt jdxm,Mat sub) 753 { 754 PetscErrorCode ierr; 755 756 PetscFunctionBegin; 757 ierr = PetscUseMethod(A,"MatNestSetSubMat_C",(Mat,PetscInt,PetscInt,Mat),(A,idxm,jdxm,sub));CHKERRQ(ierr); 758 PetscFunctionReturn(0); 759 } 760 761 EXTERN_C_BEGIN 762 #undef __FUNCT__ 763 #define __FUNCT__ "MatNestGetSubMats_Nest" 764 PetscErrorCode MatNestGetSubMats_Nest(Mat A,PetscInt *M,PetscInt *N,Mat ***mat) 765 { 766 Mat_Nest *bA = (Mat_Nest*)A->data; 767 PetscFunctionBegin; 768 if (M) { *M = bA->nr; } 769 if (N) { *N = bA->nc; } 770 if (mat) { *mat = bA->m; } 771 PetscFunctionReturn(0); 772 } 773 EXTERN_C_END 774 775 #undef __FUNCT__ 776 #define __FUNCT__ "MatNestGetSubMats" 777 /*@C 778 MatNestGetSubMats - Returns the entire two dimensional array of matrices defining a nest matrix. 779 780 Not collective 781 782 Input Parameters: 783 . A - nest matrix 784 785 Output Parameter: 786 + M - number of rows in the nest matrix 787 . N - number of cols in the nest matrix 788 - mat - 2d array of matrices 789 790 Notes: 791 792 The user should not free the array mat. 793 794 Level: developer 795 796 .seealso: MatNestGetSize(), MatNestGetSubMat() 797 @*/ 798 PetscErrorCode MatNestGetSubMats(Mat A,PetscInt *M,PetscInt *N,Mat ***mat) 799 { 800 PetscErrorCode ierr; 801 802 PetscFunctionBegin; 803 ierr = PetscUseMethod(A,"MatNestGetSubMats_C",(Mat,PetscInt*,PetscInt*,Mat***),(A,M,N,mat));CHKERRQ(ierr); 804 PetscFunctionReturn(0); 805 } 806 807 EXTERN_C_BEGIN 808 #undef __FUNCT__ 809 #define __FUNCT__ "MatNestGetSize_Nest" 810 PetscErrorCode MatNestGetSize_Nest(Mat A,PetscInt *M,PetscInt *N) 811 { 812 Mat_Nest *bA = (Mat_Nest*)A->data; 813 814 PetscFunctionBegin; 815 if (M) { *M = bA->nr; } 816 if (N) { *N = bA->nc; } 817 PetscFunctionReturn(0); 818 } 819 EXTERN_C_END 820 821 #undef __FUNCT__ 822 #define __FUNCT__ "MatNestGetSize" 823 /*@C 824 MatNestGetSize - Returns the size of the nest matrix. 825 826 Not collective 827 828 Input Parameters: 829 . A - nest matrix 830 831 Output Parameter: 832 + M - number of rows in the nested mat 833 - N - number of cols in the nested mat 834 835 Notes: 836 837 Level: developer 838 839 .seealso: MatNestGetSubMat(), MatNestGetSubMats() 840 @*/ 841 PetscErrorCode MatNestGetSize(Mat A,PetscInt *M,PetscInt *N) 842 { 843 PetscErrorCode ierr; 844 845 PetscFunctionBegin; 846 ierr = PetscUseMethod(A,"MatNestGetSize_C",(Mat,PetscInt*,PetscInt*),(A,M,N));CHKERRQ(ierr); 847 PetscFunctionReturn(0); 848 } 849 850 EXTERN_C_BEGIN 851 #undef __FUNCT__ 852 #define __FUNCT__ "MatNestSetVecType_Nest" 853 PetscErrorCode MatNestSetVecType_Nest(Mat A,const VecType vtype) 854 { 855 PetscErrorCode ierr; 856 PetscBool flg; 857 858 PetscFunctionBegin; 859 ierr = PetscStrcmp(vtype,VECNEST,&flg);CHKERRQ(ierr); 860 /* In reality, this only distinguishes VECNEST and "other" */ 861 A->ops->getvecs = flg ? MatGetVecs_Nest : 0; 862 PetscFunctionReturn(0); 863 } 864 EXTERN_C_END 865 866 #undef __FUNCT__ 867 #define __FUNCT__ "MatNestSetVecType" 868 /*@C 869 MatNestSetVecType - Sets the type of Vec returned by MatGetVecs() 870 871 Not collective 872 873 Input Parameters: 874 + A - nest matrix 875 - vtype - type to use for creating vectors 876 877 Notes: 878 879 Level: developer 880 881 .seealso: MatGetVecs() 882 @*/ 883 PetscErrorCode MatNestSetVecType(Mat A,const VecType vtype) 884 { 885 PetscErrorCode ierr; 886 887 PetscFunctionBegin; 888 ierr = PetscTryMethod(A,"MatNestSetVecType_C",(Mat,const VecType),(A,vtype));CHKERRQ(ierr); 889 PetscFunctionReturn(0); 890 } 891 892 EXTERN_C_BEGIN 893 #undef __FUNCT__ 894 #define __FUNCT__ "MatNestSetSubMats_Nest" 895 PetscErrorCode MatNestSetSubMats_Nest(Mat A,PetscInt nr,const IS is_row[],PetscInt nc,const IS is_col[],const Mat a[]) 896 { 897 Mat_Nest *s = (Mat_Nest*)A->data; 898 PetscInt i,j,m,n,M,N; 899 PetscErrorCode ierr; 900 901 PetscFunctionBegin; 902 s->nr = nr; 903 s->nc = nc; 904 905 /* Create space for submatrices */ 906 ierr = PetscMalloc(sizeof(Mat*)*nr,&s->m);CHKERRQ(ierr); 907 for (i=0; i<nr; i++) { 908 ierr = PetscMalloc(sizeof(Mat)*nc,&s->m[i]);CHKERRQ(ierr); 909 } 910 for (i=0; i<nr; i++) { 911 for (j=0; j<nc; j++) { 912 s->m[i][j] = a[i*nc+j]; 913 if (a[i*nc+j]) { 914 ierr = PetscObjectReference((PetscObject)a[i*nc+j]);CHKERRQ(ierr); 915 } 916 } 917 } 918 919 ierr = MatSetUp_NestIS_Private(A,nr,is_row,nc,is_col);CHKERRQ(ierr); 920 921 ierr = PetscMalloc(sizeof(PetscInt)*nr,&s->row_len);CHKERRQ(ierr); 922 ierr = PetscMalloc(sizeof(PetscInt)*nc,&s->col_len);CHKERRQ(ierr); 923 for (i=0; i<nr; i++) s->row_len[i]=-1; 924 for (j=0; j<nc; j++) s->col_len[j]=-1; 925 926 ierr = MatNestGetSizes_Private(A,&m,&n,&M,&N);CHKERRQ(ierr); 927 928 ierr = PetscLayoutSetSize(A->rmap,M);CHKERRQ(ierr); 929 ierr = PetscLayoutSetLocalSize(A->rmap,m);CHKERRQ(ierr); 930 ierr = PetscLayoutSetBlockSize(A->rmap,1);CHKERRQ(ierr); 931 ierr = PetscLayoutSetSize(A->cmap,N);CHKERRQ(ierr); 932 ierr = PetscLayoutSetLocalSize(A->cmap,n);CHKERRQ(ierr); 933 ierr = PetscLayoutSetBlockSize(A->cmap,1);CHKERRQ(ierr); 934 935 ierr = PetscLayoutSetUp(A->rmap);CHKERRQ(ierr); 936 ierr = PetscLayoutSetUp(A->cmap);CHKERRQ(ierr); 937 938 ierr = PetscMalloc2(nr,Vec,&s->left,nc,Vec,&s->right);CHKERRQ(ierr); 939 ierr = PetscMemzero(s->left,nr*sizeof(Vec));CHKERRQ(ierr); 940 ierr = PetscMemzero(s->right,nc*sizeof(Vec));CHKERRQ(ierr); 941 PetscFunctionReturn(0); 942 } 943 EXTERN_C_END 944 945 #undef __FUNCT__ 946 #define __FUNCT__ "MatNestSetSubMats" 947 /*@ 948 MatNestSetSubMats - Sets the nested submatrices 949 950 Collective on Mat 951 952 Input Parameter: 953 + N - nested matrix 954 . nr - number of nested row blocks 955 . is_row - index sets for each nested row block, or PETSC_NULL to make contiguous 956 . nc - number of nested column blocks 957 . is_col - index sets for each nested column block, or PETSC_NULL to make contiguous 958 - a - row-aligned array of nr*nc submatrices, empty submatrices can be passed using PETSC_NULL 959 960 Level: advanced 961 962 .seealso: MatCreateNest(), MATNEST 963 @*/ 964 PetscErrorCode MatNestSetSubMats(Mat A,PetscInt nr,const IS is_row[],PetscInt nc,const IS is_col[],const Mat a[]) 965 { 966 PetscErrorCode ierr; 967 PetscInt i; 968 969 PetscFunctionBegin; 970 PetscValidHeaderSpecific(A,MAT_CLASSID,1); 971 if (nr < 0) SETERRQ(((PetscObject)A)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Number of rows cannot be negative"); 972 if (nr && is_row) { 973 PetscValidPointer(is_row,3); 974 for (i=0; i<nr; i++) PetscValidHeaderSpecific(is_row[i],IS_CLASSID,3); 975 } 976 if (nc < 0) SETERRQ(((PetscObject)A)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Number of columns cannot be negative"); 977 if (nc && is_col) { 978 PetscValidPointer(is_col,5); 979 for (i=0; i<nr; i++) PetscValidHeaderSpecific(is_col[i],IS_CLASSID,5); 980 } 981 if (nr*nc) PetscValidPointer(a,6); 982 ierr = PetscUseMethod(A,"MatNestSetSubMats_C",(Mat,PetscInt,const IS[],PetscInt,const IS[],const Mat[]),(A,nr,is_row,nc,is_col,a));CHKERRQ(ierr); 983 PetscFunctionReturn(0); 984 } 985 986 #undef __FUNCT__ 987 #define __FUNCT__ "MatNestCreateAggregateL2G_Private" 988 static PetscErrorCode MatNestCreateAggregateL2G_Private(Mat A,PetscInt n,const IS islocal[],const IS isglobal[],PetscBool colflg,ISLocalToGlobalMapping *ltog,ISLocalToGlobalMapping *ltogb) 989 { 990 PetscErrorCode ierr; 991 PetscBool flg; 992 PetscInt i,j,m,mi,*ix; 993 994 PetscFunctionBegin; 995 for (i=0,m=0,flg=PETSC_FALSE; i<n; i++) { 996 if (islocal[i]) { 997 ierr = ISGetSize(islocal[i],&mi);CHKERRQ(ierr); 998 flg = PETSC_TRUE; /* We found a non-trivial entry */ 999 } else { 1000 ierr = ISGetSize(isglobal[i],&mi);CHKERRQ(ierr); 1001 } 1002 m += mi; 1003 } 1004 if (flg) { 1005 ierr = PetscMalloc(m*sizeof(*ix),&ix);CHKERRQ(ierr); 1006 for (i=0,n=0; i<n; i++) { 1007 ISLocalToGlobalMapping smap = PETSC_NULL; 1008 VecScatter scat; 1009 IS isreq; 1010 Vec lvec,gvec; 1011 union {char padding[sizeof(PetscScalar)]; PetscInt integer;} *x; 1012 Mat sub; 1013 1014 if (sizeof (*x) != sizeof(PetscScalar)) SETERRQ(((PetscObject)A)->comm,PETSC_ERR_SUP,"No support when scalars smaller than integers"); 1015 if (colflg) { 1016 ierr = MatNestFindNonzeroSubMatRow(A,i,&sub);CHKERRQ(ierr); 1017 } else { 1018 ierr = MatNestFindNonzeroSubMatCol(A,i,&sub);CHKERRQ(ierr); 1019 } 1020 if (sub) {ierr = MatGetLocalToGlobalMapping(sub,&smap,PETSC_NULL);CHKERRQ(ierr);} 1021 if (islocal[i]) { 1022 ierr = ISGetSize(islocal[i],&mi);CHKERRQ(ierr); 1023 } else { 1024 ierr = ISGetSize(isglobal[i],&mi);CHKERRQ(ierr); 1025 } 1026 for (j=0; j<mi; j++) ix[m+j] = j; 1027 if (smap) {ierr = ISLocalToGlobalMappingApply(smap,mi,ix+m,ix+m);CHKERRQ(ierr);} 1028 /* 1029 Now we need to extract the monolithic global indices that correspond to the given split global indices. 1030 In many/most cases, we only want MatGetLocalSubMatrix() to work, in which case we only need to know the size of the local spaces. 1031 The approach here is ugly because it uses VecScatter to move indices. 1032 */ 1033 ierr = VecCreateSeq(PETSC_COMM_SELF,mi,&lvec);CHKERRQ(ierr); 1034 ierr = VecCreateMPI(((PetscObject)isglobal[i])->comm,mi,PETSC_DECIDE,&gvec);CHKERRQ(ierr); 1035 ierr = ISCreateGeneral(((PetscObject)isglobal[i])->comm,mi,ix+m,PETSC_COPY_VALUES,&isreq);CHKERRQ(ierr); 1036 ierr = VecScatterCreate(gvec,isreq,lvec,PETSC_NULL,&scat);CHKERRQ(ierr); 1037 ierr = VecGetArray(gvec,(PetscScalar**)&x);CHKERRQ(ierr); 1038 for (j=0; j<mi; j++) x[j].integer = ix[m+j]; 1039 ierr = VecRestoreArray(gvec,(PetscScalar**)&x);CHKERRQ(ierr); 1040 ierr = VecScatterBegin(scat,gvec,lvec,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 1041 ierr = VecScatterEnd(scat,gvec,lvec,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 1042 ierr = VecGetArray(lvec,(PetscScalar**)&x);CHKERRQ(ierr); 1043 for (j=0; j<mi; j++) ix[m+j] = x[j].integer; 1044 ierr = VecRestoreArray(lvec,(PetscScalar**)&x);CHKERRQ(ierr); 1045 ierr = VecDestroy(&lvec);CHKERRQ(ierr); 1046 ierr = VecDestroy(&gvec);CHKERRQ(ierr); 1047 ierr = ISDestroy(&isreq);CHKERRQ(ierr); 1048 ierr = VecScatterDestroy(&scat);CHKERRQ(ierr); 1049 m += mi; 1050 } 1051 ierr = ISLocalToGlobalMappingCreate(((PetscObject)A)->comm,m,ix,PETSC_OWN_POINTER,ltog);CHKERRQ(ierr); 1052 *ltogb = PETSC_NULL; 1053 } else { 1054 *ltog = PETSC_NULL; 1055 *ltogb = PETSC_NULL; 1056 } 1057 PetscFunctionReturn(0); 1058 } 1059 1060 1061 /* If an IS was provided, there is nothing Nest needs to do, otherwise Nest will build a strided IS */ 1062 /* 1063 nprocessors = NP 1064 Nest x^T = ( (g_0,g_1,...g_nprocs-1), (h_0,h_1,...h_NP-1) ) 1065 proc 0: => (g_0,h_0,) 1066 proc 1: => (g_1,h_1,) 1067 ... 1068 proc nprocs-1: => (g_NP-1,h_NP-1,) 1069 1070 proc 0: proc 1: proc nprocs-1: 1071 is[0] = ( 0,1,2,...,nlocal(g_0)-1 ) ( 0,1,...,nlocal(g_1)-1 ) ( 0,1,...,nlocal(g_NP-1) ) 1072 1073 proc 0: 1074 is[1] = ( nlocal(g_0),nlocal(g_0)+1,...,nlocal(g_0)+nlocal(h_0)-1 ) 1075 proc 1: 1076 is[1] = ( nlocal(g_1),nlocal(g_1)+1,...,nlocal(g_1)+nlocal(h_1)-1 ) 1077 1078 proc NP-1: 1079 is[1] = ( nlocal(g_NP-1),nlocal(g_NP-1)+1,...,nlocal(g_NP-1)+nlocal(h_NP-1)-1 ) 1080 */ 1081 #undef __FUNCT__ 1082 #define __FUNCT__ "MatSetUp_NestIS_Private" 1083 static PetscErrorCode MatSetUp_NestIS_Private(Mat A,PetscInt nr,const IS is_row[],PetscInt nc,const IS is_col[]) 1084 { 1085 Mat_Nest *vs = (Mat_Nest*)A->data; 1086 PetscInt i,j,offset,n,nsum,bs; 1087 PetscErrorCode ierr; 1088 Mat sub; 1089 1090 PetscFunctionBegin; 1091 ierr = PetscMalloc(sizeof(IS)*nr,&vs->isglobal.row);CHKERRQ(ierr); 1092 ierr = PetscMalloc(sizeof(IS)*nc,&vs->isglobal.col);CHKERRQ(ierr); 1093 if (is_row) { /* valid IS is passed in */ 1094 /* refs on is[] are incremeneted */ 1095 for (i=0; i<vs->nr; i++) { 1096 ierr = PetscObjectReference((PetscObject)is_row[i]);CHKERRQ(ierr); 1097 vs->isglobal.row[i] = is_row[i]; 1098 } 1099 } else { /* Create the ISs by inspecting sizes of a submatrix in each row */ 1100 nsum = 0; 1101 for (i=0; i<vs->nr; i++) { /* Add up the local sizes to compute the aggregate offset */ 1102 ierr = MatNestFindNonzeroSubMatRow(A,i,&sub);CHKERRQ(ierr); 1103 if (!sub) SETERRQ1(((PetscObject)A)->comm,PETSC_ERR_ARG_WRONG,"No nonzero submatrix in row %D",i); 1104 ierr = MatGetLocalSize(sub,&n,PETSC_NULL);CHKERRQ(ierr); 1105 if (n < 0) SETERRQ(((PetscObject)A)->comm,PETSC_ERR_ARG_WRONGSTATE,"Sizes have not yet been set for submatrix"); 1106 nsum += n; 1107 } 1108 offset = 0; 1109 #if defined(PETSC_HAVE_MPI_EXSCAN) 1110 ierr = MPI_Exscan(&nsum,&offset,1,MPIU_INT,MPI_SUM,((PetscObject)A)->comm);CHKERRQ(ierr); 1111 #else 1112 SETERRQ(((PetscObject)A)->comm,PETSC_ERR_ARG_WRONGSTATE,"Sorry but this code requires MPI_EXSCAN that doesn't exist on your machine's version of MPI, install a MPI2 with PETSc to get this functionality"); 1113 #endif 1114 for (i=0; i<vs->nr; i++) { 1115 ierr = MatNestFindNonzeroSubMatRow(A,i,&sub);CHKERRQ(ierr); 1116 ierr = MatGetLocalSize(sub,&n,PETSC_NULL);CHKERRQ(ierr); 1117 ierr = MatGetBlockSize(sub,&bs);CHKERRQ(ierr); 1118 ierr = ISCreateStride(((PetscObject)sub)->comm,n,offset,1,&vs->isglobal.row[i]);CHKERRQ(ierr); 1119 ierr = ISSetBlockSize(vs->isglobal.row[i],bs);CHKERRQ(ierr); 1120 offset += n; 1121 } 1122 } 1123 1124 if (is_col) { /* valid IS is passed in */ 1125 /* refs on is[] are incremeneted */ 1126 for (j=0; j<vs->nc; j++) { 1127 ierr = PetscObjectReference((PetscObject)is_col[j]);CHKERRQ(ierr); 1128 vs->isglobal.col[j] = is_col[j]; 1129 } 1130 } else { /* Create the ISs by inspecting sizes of a submatrix in each column */ 1131 offset = A->cmap->rstart; 1132 nsum = 0; 1133 for (j=0; j<vs->nc; j++) { 1134 ierr = MatNestFindNonzeroSubMatCol(A,j,&sub);CHKERRQ(ierr); 1135 if (!sub) SETERRQ1(((PetscObject)A)->comm,PETSC_ERR_ARG_WRONG,"No nonzero submatrix in column %D",i); 1136 ierr = MatGetLocalSize(sub,PETSC_NULL,&n);CHKERRQ(ierr); 1137 if (n < 0) SETERRQ(((PetscObject)A)->comm,PETSC_ERR_ARG_WRONGSTATE,"Sizes have not yet been set for submatrix"); 1138 nsum += n; 1139 } 1140 offset = 0; 1141 #if defined(PETSC_HAVE_MPI_EXSCAN) 1142 ierr = MPI_Exscan(&nsum,&offset,1,MPIU_INT,MPI_SUM,((PetscObject)A)->comm);CHKERRQ(ierr); 1143 #else 1144 SETERRQ(((PetscObject)A)->comm,PETSC_ERR_ARG_WRONGSTATE,"Sorry but this code requires MPI_EXSCAN that doesn't exist on your machine's version of MPI, install a MPI2 with PETSc to get this functionality"); 1145 #endif 1146 for (j=0; j<vs->nc; j++) { 1147 ierr = MatNestFindNonzeroSubMatCol(A,j,&sub);CHKERRQ(ierr); 1148 ierr = MatGetLocalSize(sub,PETSC_NULL,&n);CHKERRQ(ierr); 1149 ierr = MatGetBlockSize(sub,&bs);CHKERRQ(ierr); 1150 ierr = ISCreateStride(((PetscObject)sub)->comm,n,offset,1,&vs->isglobal.col[j]);CHKERRQ(ierr); 1151 ierr = ISSetBlockSize(vs->isglobal.col[j],bs);CHKERRQ(ierr); 1152 offset += n; 1153 } 1154 } 1155 1156 /* Set up the local ISs */ 1157 ierr = PetscMalloc(vs->nr*sizeof(IS),&vs->islocal.row);CHKERRQ(ierr); 1158 ierr = PetscMalloc(vs->nc*sizeof(IS),&vs->islocal.col);CHKERRQ(ierr); 1159 for (i=0,offset=0; i<vs->nr; i++) { 1160 IS isloc; 1161 ISLocalToGlobalMapping rmap = PETSC_NULL; 1162 PetscInt nlocal,bs; 1163 ierr = MatNestFindNonzeroSubMatRow(A,i,&sub);CHKERRQ(ierr); 1164 if (sub) {ierr = MatGetLocalToGlobalMapping(sub,&rmap,PETSC_NULL);CHKERRQ(ierr);} 1165 if (rmap) { 1166 ierr = MatGetBlockSize(sub,&bs);CHKERRQ(ierr); 1167 ierr = ISLocalToGlobalMappingGetSize(rmap,&nlocal);CHKERRQ(ierr); 1168 ierr = ISCreateStride(PETSC_COMM_SELF,nlocal,offset,1,&isloc);CHKERRQ(ierr); 1169 ierr = ISSetBlockSize(isloc,bs);CHKERRQ(ierr); 1170 } else { 1171 nlocal = 0; 1172 isloc = PETSC_NULL; 1173 } 1174 vs->islocal.row[i] = isloc; 1175 offset += nlocal; 1176 } 1177 for (i=0,offset=0; i<vs->nc; i++) { 1178 IS isloc; 1179 ISLocalToGlobalMapping cmap = PETSC_NULL; 1180 PetscInt nlocal,bs; 1181 ierr = MatNestFindNonzeroSubMatCol(A,i,&sub);CHKERRQ(ierr); 1182 if (sub) {ierr = MatGetLocalToGlobalMapping(sub,PETSC_NULL,&cmap);CHKERRQ(ierr);} 1183 if (cmap) { 1184 ierr = MatGetBlockSize(sub,&bs);CHKERRQ(ierr); 1185 ierr = ISLocalToGlobalMappingGetSize(cmap,&nlocal);CHKERRQ(ierr); 1186 ierr = ISCreateStride(PETSC_COMM_SELF,nlocal,offset,1,&isloc);CHKERRQ(ierr); 1187 ierr = ISSetBlockSize(isloc,bs);CHKERRQ(ierr); 1188 } else { 1189 nlocal = 0; 1190 isloc = PETSC_NULL; 1191 } 1192 vs->islocal.col[i] = isloc; 1193 offset += nlocal; 1194 } 1195 1196 /* Set up the aggregate ISLocalToGlobalMapping */ 1197 { 1198 ISLocalToGlobalMapping rmap,rmapb,cmap,cmapb; 1199 ierr = MatNestCreateAggregateL2G_Private(A,vs->nr,vs->islocal.row,vs->isglobal.row,PETSC_FALSE,&rmap,&rmapb);CHKERRQ(ierr); 1200 ierr = MatNestCreateAggregateL2G_Private(A,vs->nc,vs->islocal.col,vs->isglobal.col,PETSC_TRUE,&cmap,&cmapb);CHKERRQ(ierr); 1201 if (rmap && cmap) {ierr = MatSetLocalToGlobalMapping(A,rmap,cmap);CHKERRQ(ierr);} 1202 if (rmapb && cmapb) {ierr = MatSetLocalToGlobalMappingBlock(A,rmapb,cmapb);CHKERRQ(ierr);} 1203 ierr = ISLocalToGlobalMappingDestroy(&rmap);CHKERRQ(ierr); 1204 ierr = ISLocalToGlobalMappingDestroy(&rmapb);CHKERRQ(ierr); 1205 ierr = ISLocalToGlobalMappingDestroy(&cmap);CHKERRQ(ierr); 1206 ierr = ISLocalToGlobalMappingDestroy(&cmapb);CHKERRQ(ierr); 1207 } 1208 1209 #if defined(PETSC_USE_DEBUG) 1210 for (i=0; i<vs->nr; i++) { 1211 for (j=0; j<vs->nc; j++) { 1212 PetscInt m,n,M,N,mi,ni,Mi,Ni; 1213 Mat B = vs->m[i][j]; 1214 if (!B) continue; 1215 ierr = MatGetSize(B,&M,&N);CHKERRQ(ierr); 1216 ierr = MatGetLocalSize(B,&m,&n);CHKERRQ(ierr); 1217 ierr = ISGetSize(vs->isglobal.row[i],&Mi);CHKERRQ(ierr); 1218 ierr = ISGetSize(vs->isglobal.col[j],&Ni);CHKERRQ(ierr); 1219 ierr = ISGetLocalSize(vs->isglobal.row[i],&mi);CHKERRQ(ierr); 1220 ierr = ISGetLocalSize(vs->isglobal.col[j],&ni);CHKERRQ(ierr); 1221 if (M != Mi || N != Ni) SETERRQ6(((PetscObject)sub)->comm,PETSC_ERR_ARG_INCOMP,"Global sizes (%D,%D) of nested submatrix (%D,%D) do not agree with space defined by index sets (%D,%D)",M,N,i,j,Mi,Ni); 1222 if (m != mi || n != ni) SETERRQ6(((PetscObject)sub)->comm,PETSC_ERR_ARG_INCOMP,"Local sizes (%D,%D) of nested submatrix (%D,%D) do not agree with space defined by index sets (%D,%D)",m,n,i,j,mi,ni); 1223 } 1224 } 1225 #endif 1226 1227 /* Set A->assembled if all non-null blocks are currently assembled */ 1228 for (i=0; i<vs->nr; i++) { 1229 for (j=0; j<vs->nc; j++) { 1230 if (vs->m[i][j] && !vs->m[i][j]->assembled) PetscFunctionReturn(0); 1231 } 1232 } 1233 A->assembled = PETSC_TRUE; 1234 PetscFunctionReturn(0); 1235 } 1236 1237 #undef __FUNCT__ 1238 #define __FUNCT__ "MatCreateNest" 1239 /*@ 1240 MatCreateNest - Creates a new matrix containing several nested submatrices, each stored separately 1241 1242 Collective on Mat 1243 1244 Input Parameter: 1245 + comm - Communicator for the new Mat 1246 . nr - number of nested row blocks 1247 . is_row - index sets for each nested row block, or PETSC_NULL to make contiguous 1248 . nc - number of nested column blocks 1249 . is_col - index sets for each nested column block, or PETSC_NULL to make contiguous 1250 - a - row-aligned array of nr*nc submatrices, empty submatrices can be passed using PETSC_NULL 1251 1252 Output Parameter: 1253 . B - new matrix 1254 1255 Level: advanced 1256 1257 .seealso: MatCreate(), VecCreateNest(), DMGetMatrix(), MATNEST 1258 @*/ 1259 PetscErrorCode MatCreateNest(MPI_Comm comm,PetscInt nr,const IS is_row[],PetscInt nc,const IS is_col[],const Mat a[],Mat *B) 1260 { 1261 Mat A; 1262 PetscErrorCode ierr; 1263 1264 PetscFunctionBegin; 1265 *B = 0; 1266 ierr = MatCreate(comm,&A);CHKERRQ(ierr); 1267 ierr = MatSetType(A,MATNEST);CHKERRQ(ierr); 1268 ierr = MatNestSetSubMats(A,nr,is_row,nc,is_col,a);CHKERRQ(ierr); 1269 *B = A; 1270 PetscFunctionReturn(0); 1271 } 1272 1273 /*MC 1274 MATNEST - MATNEST = "nest" - Matrix type consisting of nested submatrices, each stored separately. 1275 1276 Level: intermediate 1277 1278 Notes: 1279 This matrix type permits scalable use of PCFieldSplit and avoids the large memory costs of extracting submatrices. 1280 It allows the use of symmetric and block formats for parts of multi-physics simulations. 1281 It is usually used with DMComposite and DMGetMatrix() 1282 1283 .seealso: MatCreate(), MatType, MatCreateNest() 1284 M*/ 1285 EXTERN_C_BEGIN 1286 #undef __FUNCT__ 1287 #define __FUNCT__ "MatCreate_Nest" 1288 PetscErrorCode MatCreate_Nest(Mat A) 1289 { 1290 Mat_Nest *s; 1291 PetscErrorCode ierr; 1292 1293 PetscFunctionBegin; 1294 ierr = PetscNewLog(A,Mat_Nest,&s);CHKERRQ(ierr); 1295 A->data = (void*)s; 1296 s->nr = s->nc = -1; 1297 s->m = PETSC_NULL; 1298 1299 ierr = PetscMemzero(A->ops,sizeof(*A->ops));CHKERRQ(ierr); 1300 A->ops->mult = MatMult_Nest; 1301 A->ops->multadd = MatMultAdd_Nest; 1302 A->ops->multtranspose = MatMultTranspose_Nest; 1303 A->ops->multtransposeadd = MatMultTransposeAdd_Nest; 1304 A->ops->assemblybegin = MatAssemblyBegin_Nest; 1305 A->ops->assemblyend = MatAssemblyEnd_Nest; 1306 A->ops->zeroentries = MatZeroEntries_Nest; 1307 A->ops->duplicate = MatDuplicate_Nest; 1308 A->ops->getsubmatrix = MatGetSubMatrix_Nest; 1309 A->ops->destroy = MatDestroy_Nest; 1310 A->ops->view = MatView_Nest; 1311 A->ops->getvecs = 0; /* Use VECNEST by calling MatNestSetVecType(A,VECNEST) */ 1312 A->ops->getlocalsubmatrix = MatGetLocalSubMatrix_Nest; 1313 A->ops->restorelocalsubmatrix = MatRestoreLocalSubMatrix_Nest; 1314 A->ops->getdiagonal = MatGetDiagonal_Nest; 1315 A->ops->diagonalscale = MatDiagonalScale_Nest; 1316 A->ops->scale = MatScale_Nest; 1317 A->ops->shift = MatShift_Nest; 1318 1319 A->spptr = 0; 1320 A->same_nonzero = PETSC_FALSE; 1321 A->assembled = PETSC_FALSE; 1322 1323 /* expose Nest api's */ 1324 ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestGetSubMat_C", "MatNestGetSubMat_Nest", MatNestGetSubMat_Nest);CHKERRQ(ierr); 1325 ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestSetSubMat_C", "MatNestSetSubMat_Nest", MatNestSetSubMat_Nest);CHKERRQ(ierr); 1326 ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestGetSubMats_C", "MatNestGetSubMats_Nest", MatNestGetSubMats_Nest);CHKERRQ(ierr); 1327 ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestGetSize_C", "MatNestGetSize_Nest", MatNestGetSize_Nest);CHKERRQ(ierr); 1328 ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestSetVecType_C", "MatNestSetVecType_Nest", MatNestSetVecType_Nest);CHKERRQ(ierr); 1329 ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatNestSetSubMats_C", "MatNestSetSubMats_Nest", MatNestSetSubMats_Nest);CHKERRQ(ierr); 1330 1331 ierr = PetscObjectChangeTypeName((PetscObject)A,MATNEST);CHKERRQ(ierr); 1332 PetscFunctionReturn(0); 1333 } 1334 EXTERN_C_END 1335