1 #define PETSCMAT_DLL 2 3 #include "private/matimpl.h" /*I "petscmat.h" I*/ 4 5 typedef struct _Mat_CompositeLink *Mat_CompositeLink; 6 struct _Mat_CompositeLink { 7 Mat mat; 8 Vec work; 9 Mat_CompositeLink next,prev; 10 }; 11 12 typedef struct { 13 MatCompositeType type; 14 Mat_CompositeLink head,tail; 15 Vec work; 16 } Mat_Composite; 17 18 #undef __FUNCT__ 19 #define __FUNCT__ "MatDestroy_Composite" 20 PetscErrorCode MatDestroy_Composite(Mat mat) 21 { 22 PetscErrorCode ierr; 23 Mat_Composite *shell = (Mat_Composite*)mat->data; 24 Mat_CompositeLink next = shell->head,oldnext; 25 26 PetscFunctionBegin; 27 while (next) { 28 ierr = MatDestroy(next->mat);CHKERRQ(ierr); 29 if (next->work && (!next->next || next->work != next->next->work)) { 30 ierr = VecDestroy(next->work);CHKERRQ(ierr); 31 } 32 oldnext = next; 33 next = next->next; 34 ierr = PetscFree(oldnext);CHKERRQ(ierr); 35 } 36 if (shell->work) {ierr = VecDestroy(shell->work);CHKERRQ(ierr);} 37 ierr = PetscFree(shell);CHKERRQ(ierr); 38 mat->data = 0; 39 PetscFunctionReturn(0); 40 } 41 42 #undef __FUNCT__ 43 #define __FUNCT__ "MatMult_Composite_Multiplicative" 44 PetscErrorCode MatMult_Composite_Multiplicative(Mat A,Vec x,Vec y) 45 { 46 Mat_Composite *shell = (Mat_Composite*)A->data; 47 Mat_CompositeLink next = shell->head; 48 PetscErrorCode ierr; 49 Vec in,out; 50 51 PetscFunctionBegin; 52 if (!next) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must provide at least one matrix with MatCompositeAddMat()"); 53 in = x; 54 while (next->next) { 55 if (!next->work) { /* should reuse previous work if the same size */ 56 ierr = MatGetVecs(next->mat,PETSC_NULL,&next->work);CHKERRQ(ierr); 57 } 58 out = next->work; 59 ierr = MatMult(next->mat,in,out);CHKERRQ(ierr); 60 in = out; 61 next = next->next; 62 } 63 ierr = MatMult(next->mat,in,y);CHKERRQ(ierr); 64 PetscFunctionReturn(0); 65 } 66 67 #undef __FUNCT__ 68 #define __FUNCT__ "MatMultTranspose_Composite_Multiplicative" 69 PetscErrorCode MatMultTranspose_Composite_Multiplicative(Mat A,Vec x,Vec y) 70 { 71 Mat_Composite *shell = (Mat_Composite*)A->data; 72 Mat_CompositeLink tail = shell->tail; 73 PetscErrorCode ierr; 74 Vec in,out; 75 76 PetscFunctionBegin; 77 if (!tail) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must provide at least one matrix with MatCompositeAddMat()"); 78 in = x; 79 while (tail->prev) { 80 if (!tail->prev->work) { /* should reuse previous work if the same size */ 81 ierr = MatGetVecs(tail->mat,PETSC_NULL,&tail->prev->work);CHKERRQ(ierr); 82 } 83 out = tail->prev->work; 84 ierr = MatMultTranspose(tail->mat,in,out);CHKERRQ(ierr); 85 in = out; 86 tail = tail->prev; 87 } 88 ierr = MatMultTranspose(tail->mat,in,y);CHKERRQ(ierr); 89 PetscFunctionReturn(0); 90 } 91 92 #undef __FUNCT__ 93 #define __FUNCT__ "MatMult_Composite" 94 PetscErrorCode MatMult_Composite(Mat A,Vec x,Vec y) 95 { 96 Mat_Composite *shell = (Mat_Composite*)A->data; 97 Mat_CompositeLink next = shell->head; 98 PetscErrorCode ierr; 99 100 PetscFunctionBegin; 101 if (!next) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must provide at least one matrix with MatCompositeAddMat()"); 102 ierr = MatMult(next->mat,x,y);CHKERRQ(ierr); 103 while ((next = next->next)) { 104 ierr = MatMultAdd(next->mat,x,y,y);CHKERRQ(ierr); 105 } 106 PetscFunctionReturn(0); 107 } 108 109 #undef __FUNCT__ 110 #define __FUNCT__ "MatMultTranspose_Composite" 111 PetscErrorCode MatMultTranspose_Composite(Mat A,Vec x,Vec y) 112 { 113 Mat_Composite *shell = (Mat_Composite*)A->data; 114 Mat_CompositeLink next = shell->head; 115 PetscErrorCode ierr; 116 117 PetscFunctionBegin; 118 if (!next) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must provide at least one matrix with MatCompositeAddMat()"); 119 ierr = MatMultTranspose(next->mat,x,y);CHKERRQ(ierr); 120 while ((next = next->next)) { 121 ierr = MatMultTransposeAdd(next->mat,x,y,y);CHKERRQ(ierr); 122 } 123 PetscFunctionReturn(0); 124 } 125 126 #undef __FUNCT__ 127 #define __FUNCT__ "MatGetDiagonal_Composite" 128 PetscErrorCode MatGetDiagonal_Composite(Mat A,Vec v) 129 { 130 Mat_Composite *shell = (Mat_Composite*)A->data; 131 Mat_CompositeLink next = shell->head; 132 PetscErrorCode ierr; 133 134 PetscFunctionBegin; 135 if (!next) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must provide at least one matrix with MatCompositeAddMat()"); 136 ierr = MatGetDiagonal(next->mat,v);CHKERRQ(ierr); 137 if (next->next && !shell->work) { 138 ierr = VecDuplicate(v,&shell->work);CHKERRQ(ierr); 139 } 140 while ((next = next->next)) { 141 ierr = MatGetDiagonal(next->mat,shell->work);CHKERRQ(ierr); 142 ierr = VecAXPY(v,1.0,shell->work);CHKERRQ(ierr); 143 } 144 PetscFunctionReturn(0); 145 } 146 147 #undef __FUNCT__ 148 #define __FUNCT__ "MatAssemblyEnd_Composite" 149 PetscErrorCode MatAssemblyEnd_Composite(Mat Y,MatAssemblyType t) 150 { 151 PetscErrorCode ierr; 152 PetscTruth flg; 153 154 PetscFunctionBegin; 155 ierr = PetscOptionsHasName(((PetscObject)Y)->prefix,"-mat_composite_merge",&flg);CHKERRQ(ierr); 156 if (flg) { 157 ierr = MatCompositeMerge(Y);CHKERRQ(ierr); 158 } 159 PetscFunctionReturn(0); 160 } 161 162 163 static struct _MatOps MatOps_Values = {0, 164 0, 165 0, 166 MatMult_Composite, 167 0, 168 /* 5*/ MatMultTranspose_Composite, 169 0, 170 0, 171 0, 172 0, 173 /*10*/ 0, 174 0, 175 0, 176 0, 177 0, 178 /*15*/ 0, 179 0, 180 MatGetDiagonal_Composite, 181 0, 182 0, 183 /*20*/ 0, 184 MatAssemblyEnd_Composite, 185 0, 186 0, 187 0, 188 /*25*/ 0, 189 0, 190 0, 191 0, 192 0, 193 /*30*/ 0, 194 0, 195 0, 196 0, 197 0, 198 /*35*/ 0, 199 0, 200 0, 201 0, 202 0, 203 /*40*/ 0, 204 0, 205 0, 206 0, 207 0, 208 /*45*/ 0, 209 0, 210 0, 211 0, 212 0, 213 /*50*/ 0, 214 0, 215 0, 216 0, 217 0, 218 /*55*/ 0, 219 0, 220 0, 221 0, 222 0, 223 /*60*/ 0, 224 MatDestroy_Composite, 225 0, 226 0, 227 0, 228 /*65*/ 0, 229 0, 230 0, 231 0, 232 0, 233 /*70*/ 0, 234 0, 235 0, 236 0, 237 0, 238 /*75*/ 0, 239 0, 240 0, 241 0, 242 0, 243 /*80*/ 0, 244 0, 245 0, 246 0, 247 0, 248 /*85*/ 0, 249 0, 250 0, 251 0, 252 0, 253 /*90*/ 0, 254 0, 255 0, 256 0, 257 0, 258 /*95*/ 0, 259 0, 260 0, 261 0}; 262 263 /*MC 264 MATCOMPOSITE - A matrix defined by the sum (or product) of one or more matrices (all matrices are of same size and parallel layout). 265 266 Notes: to use the product of the matrices call MatCompositeSetType(mat,MAT_COMPOSITE_MULTIPLICATIVE); 267 268 Level: advanced 269 270 .seealso: MatCreateComposite(), MatCompositeAddMat(), MatSetType(), MatCompositeMerge(), MatCompositeSetType(), MatCompositeType 271 M*/ 272 273 EXTERN_C_BEGIN 274 #undef __FUNCT__ 275 #define __FUNCT__ "MatCreate_Composite" 276 PetscErrorCode PETSCMAT_DLLEXPORT MatCreate_Composite(Mat A) 277 { 278 Mat_Composite *b; 279 PetscErrorCode ierr; 280 281 PetscFunctionBegin; 282 ierr = PetscNewLog(A,Mat_Composite,&b);CHKERRQ(ierr); 283 A->data = (void*)b; 284 ierr = PetscMemcpy(A->ops,&MatOps_Values,sizeof(struct _MatOps));CHKERRQ(ierr); 285 286 ierr = PetscMapSetBlockSize(A->rmap,1);CHKERRQ(ierr); 287 ierr = PetscMapSetBlockSize(A->cmap,1);CHKERRQ(ierr); 288 ierr = PetscMapSetUp(A->rmap);CHKERRQ(ierr); 289 ierr = PetscMapSetUp(A->cmap);CHKERRQ(ierr); 290 291 A->assembled = PETSC_TRUE; 292 A->preallocated = PETSC_FALSE; 293 b->type = MAT_COMPOSITE_ADDITIVE; 294 ierr = PetscObjectChangeTypeName((PetscObject)A,MATCOMPOSITE);CHKERRQ(ierr); 295 PetscFunctionReturn(0); 296 } 297 EXTERN_C_END 298 299 #undef __FUNCT__ 300 #define __FUNCT__ "MatCreateComposite" 301 /*@C 302 MatCreateComposite - Creates a matrix as the sum of zero or more matrices 303 304 Collective on MPI_Comm 305 306 Input Parameters: 307 + comm - MPI communicator 308 . nmat - number of matrices to put in 309 - mats - the matrices 310 311 Output Parameter: 312 . A - the matrix 313 314 Level: advanced 315 316 Notes: 317 Alternative construction 318 $ MatCreate(comm,&mat); 319 $ MatSetSizes(mat,m,n,M,N); 320 $ MatSetType(mat,MATCOMPOSITE); 321 $ MatCompositeAddMat(mat,mats[0]); 322 $ .... 323 $ MatCompositeAddMat(mat,mats[nmat-1]); 324 $ MatAssemblyBegin(mat,MAT_FINAL_ASSEMBLY); 325 $ MatAssemblyEnd(mat,MAT_FINAL_ASSEMBLY); 326 327 For the multiplicative form the product is mat[nmat-1]*mat[nmat-2]*....*mat[0] 328 329 .seealso: MatDestroy(), MatMult(), MatCompositeAddMat(), MatCompositeMerge(), MatCompositeSetType(), MatCompositeType 330 331 @*/ 332 PetscErrorCode PETSCMAT_DLLEXPORT MatCreateComposite(MPI_Comm comm,PetscInt nmat,const Mat *mats,Mat *mat) 333 { 334 PetscErrorCode ierr; 335 PetscInt m,n,M,N,i; 336 337 PetscFunctionBegin; 338 if (nmat < 1) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Must pass in at least one matrix"); 339 PetscValidPointer(mat,3); 340 341 ierr = MatGetLocalSize(mats[0],&m,&n);CHKERRQ(ierr); 342 ierr = MatGetSize(mats[0],&M,&N);CHKERRQ(ierr); 343 ierr = MatCreate(comm,mat);CHKERRQ(ierr); 344 ierr = MatSetSizes(*mat,m,n,M,N);CHKERRQ(ierr); 345 ierr = MatSetType(*mat,MATCOMPOSITE);CHKERRQ(ierr); 346 for (i=0; i<nmat; i++) { 347 ierr = MatCompositeAddMat(*mat,mats[i]);CHKERRQ(ierr); 348 } 349 ierr = MatAssemblyBegin(*mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 350 ierr = MatAssemblyEnd(*mat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 351 PetscFunctionReturn(0); 352 } 353 354 #undef __FUNCT__ 355 #define __FUNCT__ "MatCompositeAddMat" 356 /*@ 357 MatCompositeAddMat - add another matrix to a composite matrix 358 359 Collective on Mat 360 361 Input Parameters: 362 + mat - the composite matrix 363 - smat - the partial matrix 364 365 Level: advanced 366 367 .seealso: MatCreateComposite() 368 @*/ 369 PetscErrorCode PETSCMAT_DLLEXPORT MatCompositeAddMat(Mat mat,Mat smat) 370 { 371 Mat_Composite *shell; 372 PetscErrorCode ierr; 373 Mat_CompositeLink ilink,next; 374 375 PetscFunctionBegin; 376 PetscValidHeaderSpecific(mat,MAT_COOKIE,1); 377 PetscValidHeaderSpecific(smat,MAT_COOKIE,2); 378 ierr = PetscNewLog(mat,struct _Mat_CompositeLink,&ilink);CHKERRQ(ierr); 379 ilink->next = 0; 380 ierr = PetscObjectReference((PetscObject)smat);CHKERRQ(ierr); 381 ilink->mat = smat; 382 383 shell = (Mat_Composite*)mat->data; 384 next = shell->head; 385 if (!next) { 386 shell->head = ilink; 387 } else { 388 while (next->next) { 389 next = next->next; 390 } 391 next->next = ilink; 392 ilink->prev = next; 393 } 394 shell->tail = ilink; 395 PetscFunctionReturn(0); 396 } 397 398 #undef __FUNCT__ 399 #define __FUNCT__ "MatCompositeSetType" 400 /*@C 401 MatCompositeSetType - Indicates if the matrix is defined as the sum of a set of matrices or the product 402 403 Collective on MPI_Comm 404 405 Input Parameters: 406 . mat - the composite matrix 407 408 409 Level: advanced 410 411 Notes: 412 The MatType of the resulting matrix will be the same as the MatType of the FIRST 413 matrix in the composite matrix. 414 415 .seealso: MatDestroy(), MatMult(), MatCompositeAddMat(), MatCreateComposite(), MATCOMPOSITE 416 417 @*/ 418 PetscErrorCode PETSCMAT_DLLEXPORT MatCompositeSetType(Mat mat,MatCompositeType type) 419 { 420 Mat_Composite *b = (Mat_Composite*)mat->data; 421 PetscTruth flg; 422 PetscErrorCode ierr; 423 424 PetscFunctionBegin; 425 ierr = PetscTypeCompare((PetscObject)mat,MATCOMPOSITE,&flg);CHKERRQ(ierr); 426 if (!flg) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Can only use with composite matrix"); 427 if (type == MAT_COMPOSITE_MULTIPLICATIVE) { 428 mat->ops->getdiagonal = 0; 429 mat->ops->mult = MatMult_Composite_Multiplicative; 430 mat->ops->multtranspose = MatMultTranspose_Composite_Multiplicative; 431 b->type = MAT_COMPOSITE_MULTIPLICATIVE; 432 } else { 433 mat->ops->getdiagonal = MatGetDiagonal_Composite; 434 mat->ops->mult = MatMult_Composite; 435 mat->ops->multtranspose = MatMultTranspose_Composite; 436 b->type = MAT_COMPOSITE_ADDITIVE; 437 } 438 PetscFunctionReturn(0); 439 } 440 441 442 #undef __FUNCT__ 443 #define __FUNCT__ "MatCompositeMerge" 444 /*@C 445 MatCompositeMerge - Given a composite matrix, replaces it with a "regular" matrix 446 by summing all the matrices inside the composite matrix. 447 448 Collective on MPI_Comm 449 450 Input Parameters: 451 . mat - the composite matrix 452 453 454 Options Database: 455 . -mat_composite_merge (you must call MatAssemblyBegin()/MatAssemblyEnd() to have this checked) 456 457 Level: advanced 458 459 Notes: 460 The MatType of the resulting matrix will be the same as the MatType of the FIRST 461 matrix in the composite matrix. 462 463 .seealso: MatDestroy(), MatMult(), MatCompositeAddMat(), MatCreateComposite(), MATCOMPOSITE 464 465 @*/ 466 PetscErrorCode PETSCMAT_DLLEXPORT MatCompositeMerge(Mat mat) 467 { 468 Mat_Composite *shell = (Mat_Composite*)mat->data; 469 Mat_CompositeLink next = shell->head, prev = shell->tail; 470 PetscErrorCode ierr; 471 Mat tmat,newmat; 472 473 PetscFunctionBegin; 474 if (!next) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must provide at least one matrix with MatCompositeAddMat()"); 475 476 PetscFunctionBegin; 477 if (shell->type == MAT_COMPOSITE_ADDITIVE) { 478 ierr = MatDuplicate(next->mat,MAT_COPY_VALUES,&tmat);CHKERRQ(ierr); 479 while ((next = next->next)) { 480 ierr = MatAXPY(tmat,1.0,next->mat,DIFFERENT_NONZERO_PATTERN);CHKERRQ(ierr); 481 } 482 } else { 483 ierr = MatDuplicate(next->mat,MAT_COPY_VALUES,&tmat);CHKERRQ(ierr); 484 while ((prev = prev->prev)) { 485 ierr = MatMatMult(tmat,prev->mat,MAT_INITIAL_MATRIX,PETSC_DECIDE,&newmat);CHKERRQ(ierr); 486 ierr = MatDestroy(tmat);CHKERRQ(ierr); 487 tmat = newmat; 488 } 489 } 490 ierr = MatHeaderReplace(mat,tmat);CHKERRQ(ierr); 491 PetscFunctionReturn(0); 492 } 493