1 /* 2 This provides a simple shell for Fortran (and C programmers) to 3 create a very simple matrix class for use with KSP without coding 4 much of anything. 5 */ 6 7 #include "src/mat/matimpl.h" /*I "petscmat.h" I*/ 8 #include "vecimpl.h" 9 10 typedef struct { 11 PetscErrorCode (*destroy)(Mat); 12 PetscErrorCode (*mult)(Mat,Vec,Vec); 13 PetscTruth scale,shift; 14 PetscScalar vscale,vshift; 15 void *ctx; 16 } Mat_Shell; 17 18 #undef __FUNCT__ 19 #define __FUNCT__ "MatShellGetContext" 20 /*@ 21 MatShellGetContext - Returns the user-provided context associated with a shell matrix. 22 23 Not Collective 24 25 Input Parameter: 26 . mat - the matrix, should have been created with MatCreateShell() 27 28 Output Parameter: 29 . ctx - the user provided context 30 31 Level: advanced 32 33 Notes: 34 This routine is intended for use within various shell matrix routines, 35 as set with MatShellSetOperation(). 36 37 .keywords: matrix, shell, get, context 38 39 .seealso: MatCreateShell(), MatShellSetOperation(), MatShellSetContext() 40 @*/ 41 PetscErrorCode MatShellGetContext(Mat mat,void **ctx) 42 { 43 PetscErrorCode ierr; 44 PetscTruth flg; 45 46 PetscFunctionBegin; 47 PetscValidHeaderSpecific(mat,MAT_COOKIE,1); 48 PetscValidPointer(ctx,2); 49 ierr = PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr); 50 if (!flg) *ctx = 0; 51 else *ctx = ((Mat_Shell*)(mat->data))->ctx; 52 PetscFunctionReturn(0); 53 } 54 55 #undef __FUNCT__ 56 #define __FUNCT__ "MatDestroy_Shell" 57 PetscErrorCode MatDestroy_Shell(Mat mat) 58 { 59 PetscErrorCode ierr; 60 Mat_Shell *shell; 61 62 PetscFunctionBegin; 63 shell = (Mat_Shell*)mat->data; 64 if (shell->destroy) {ierr = (*shell->destroy)(mat);CHKERRQ(ierr);} 65 ierr = PetscFree(shell);CHKERRQ(ierr); 66 PetscFunctionReturn(0); 67 } 68 69 #undef __FUNCT__ 70 #define __FUNCT__ "MatMult_Shell" 71 PetscErrorCode MatMult_Shell(Mat A,Vec x,Vec y) 72 { 73 Mat_Shell *shell = (Mat_Shell*)A->data; 74 PetscErrorCode ierr; 75 76 PetscFunctionBegin; 77 ierr = (*shell->mult)(A,x,y);CHKERRQ(ierr); 78 if (shell->shift && shell->scale) { 79 ierr = VecAXPBY(&shell->vshift,&shell->vscale,x,y);CHKERRQ(ierr); 80 } else if (shell->scale) { 81 ierr = VecScale(&shell->vscale,y);CHKERRQ(ierr); 82 } else { 83 ierr = VecAXPY(&shell->vshift,x,y);CHKERRQ(ierr); 84 } 85 PetscFunctionReturn(0); 86 } 87 88 #undef __FUNCT__ 89 #define __FUNCT__ "MatShift_Shell" 90 PetscErrorCode MatShift_Shell(const PetscScalar *a,Mat Y) 91 { 92 Mat_Shell *shell = (Mat_Shell*)Y->data; 93 94 PetscFunctionBegin; 95 if (shell->scale || shell->shift) { 96 shell->vshift += *a; 97 } else { 98 shell->mult = Y->ops->mult; 99 Y->ops->mult = MatMult_Shell; 100 shell->vshift = *a; 101 } 102 shell->shift = PETSC_TRUE; 103 PetscFunctionReturn(0); 104 } 105 106 #undef __FUNCT__ 107 #define __FUNCT__ "MatScale_Shell" 108 PetscErrorCode MatScale_Shell(const PetscScalar *a,Mat Y) 109 { 110 Mat_Shell *shell = (Mat_Shell*)Y->data; 111 112 PetscFunctionBegin; 113 if (shell->scale || shell->shift) { 114 shell->vscale *= *a; 115 } else { 116 shell->mult = Y->ops->mult; 117 Y->ops->mult = MatMult_Shell; 118 shell->vscale = *a; 119 } 120 shell->scale = PETSC_TRUE; 121 PetscFunctionReturn(0); 122 } 123 124 #undef __FUNCT__ 125 #define __FUNCT__ "MatAssemblyEnd_Shell" 126 PetscErrorCode MatAssemblyEnd_Shell(Mat Y,MatAssemblyType t) 127 { 128 Mat_Shell *shell = (Mat_Shell*)Y->data; 129 130 PetscFunctionBegin; 131 if ((shell->shift || shell->scale) && t == MAT_FINAL_ASSEMBLY) { 132 shell->scale = PETSC_FALSE; 133 shell->shift = PETSC_FALSE; 134 shell->vshift = 0.0; 135 shell->vscale = 1.0; 136 Y->ops->mult = shell->mult; 137 } 138 PetscFunctionReturn(0); 139 } 140 141 EXTERN PetscErrorCode MatConvert_Shell(Mat,const MatType,Mat*); 142 143 #undef __FUNCT__ 144 #define __FUNCT__ "MatSetBlockSize_Shell" 145 PetscErrorCode MatSetBlockSize_Shell(Mat A,PetscInt bs) 146 { 147 PetscFunctionBegin; 148 PetscFunctionReturn(0); 149 } 150 151 static struct _MatOps MatOps_Values = {0, 152 0, 153 0, 154 0, 155 /* 4*/ 0, 156 0, 157 0, 158 0, 159 0, 160 0, 161 /*10*/ 0, 162 0, 163 0, 164 0, 165 0, 166 /*15*/ 0, 167 0, 168 0, 169 0, 170 0, 171 /*20*/ 0, 172 MatAssemblyEnd_Shell, 173 0, 174 0, 175 0, 176 /*25*/ 0, 177 0, 178 0, 179 0, 180 0, 181 /*30*/ 0, 182 0, 183 0, 184 0, 185 0, 186 /*35*/ 0, 187 0, 188 0, 189 0, 190 0, 191 /*40*/ 0, 192 0, 193 0, 194 0, 195 0, 196 /*45*/ 0, 197 MatScale_Shell, 198 MatShift_Shell, 199 0, 200 0, 201 /*50*/ MatSetBlockSize_Shell, 202 0, 203 0, 204 0, 205 0, 206 /*55*/ 0, 207 0, 208 0, 209 0, 210 0, 211 /*60*/ 0, 212 MatDestroy_Shell, 213 0, 214 MatGetPetscMaps_Petsc, 215 0, 216 /*65*/ 0, 217 0, 218 0, 219 0, 220 0, 221 /*70*/ 0, 222 MatConvert_Shell, 223 0, 224 0, 225 0, 226 /*75*/ 0, 227 0, 228 0, 229 0, 230 0, 231 /*80*/ 0, 232 0, 233 0, 234 0, 235 0, 236 /*85*/ 0, 237 0, 238 0, 239 0, 240 0, 241 /*90*/ 0, 242 0, 243 0, 244 0, 245 0, 246 /*95*/ 0, 247 0, 248 0, 249 0}; 250 251 /*MC 252 MATSHELL - MATSHELL = "shell" - A matrix type to be used to define your own matrix type -- perhaps matrix free. 253 254 Level: advanced 255 256 .seealso: MatCreateShell 257 M*/ 258 259 EXTERN_C_BEGIN 260 #undef __FUNCT__ 261 #define __FUNCT__ "MatCreate_Shell" 262 PetscErrorCode MatCreate_Shell(Mat A) 263 { 264 Mat_Shell *b; 265 PetscErrorCode ierr; 266 267 PetscFunctionBegin; 268 ierr = PetscMemcpy(A->ops,&MatOps_Values,sizeof(struct _MatOps));CHKERRQ(ierr); 269 270 ierr = PetscNew(Mat_Shell,&b);CHKERRQ(ierr); 271 PetscLogObjectMemory(A,sizeof(struct _p_Mat)+sizeof(Mat_Shell)); 272 ierr = PetscMemzero(b,sizeof(Mat_Shell));CHKERRQ(ierr); 273 A->data = (void*)b; 274 275 if (A->m == PETSC_DECIDE || A->n == PETSC_DECIDE) { 276 SETERRQ(PETSC_ERR_ARG_WRONG,"Must give local row and column count for matrix"); 277 } 278 279 ierr = PetscSplitOwnership(A->comm,&A->m,&A->M);CHKERRQ(ierr); 280 ierr = PetscSplitOwnership(A->comm,&A->n,&A->N);CHKERRQ(ierr); 281 282 ierr = PetscMapCreateMPI(A->comm,A->m,A->M,&A->rmap);CHKERRQ(ierr); 283 ierr = PetscMapCreateMPI(A->comm,A->n,A->N,&A->cmap);CHKERRQ(ierr); 284 285 b->ctx = 0; 286 b->scale = PETSC_FALSE; 287 b->shift = PETSC_FALSE; 288 b->vshift = 0.0; 289 b->vscale = 1.0; 290 b->mult = 0; 291 A->assembled = PETSC_TRUE; 292 A->preallocated = PETSC_TRUE; 293 PetscFunctionReturn(0); 294 } 295 EXTERN_C_END 296 297 #undef __FUNCT__ 298 #define __FUNCT__ "MatCreateShell" 299 /*@C 300 MatCreateShell - Creates a new matrix class for use with a user-defined 301 private data storage format. 302 303 Collective on MPI_Comm 304 305 Input Parameters: 306 + comm - MPI communicator 307 . m - number of local rows (must be given) 308 . n - number of local columns (must be given) 309 . M - number of global rows (may be PETSC_DETERMINE) 310 . N - number of global columns (may be PETSC_DETERMINE) 311 - ctx - pointer to data needed by the shell matrix routines 312 313 Output Parameter: 314 . A - the matrix 315 316 Level: advanced 317 318 Usage: 319 $ extern int mult(Mat,Vec,Vec); 320 $ MatCreateShell(comm,m,n,M,N,ctx,&mat); 321 $ MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult); 322 $ [ Use matrix for operations that have been set ] 323 $ MatDestroy(mat); 324 325 Notes: 326 The shell matrix type is intended to provide a simple class to use 327 with KSP (such as, for use with matrix-free methods). You should not 328 use the shell type if you plan to define a complete matrix class. 329 330 PETSc requires that matrices and vectors being used for certain 331 operations are partitioned accordingly. For example, when 332 creating a shell matrix, A, that supports parallel matrix-vector 333 products using MatMult(A,x,y) the user should set the number 334 of local matrix rows to be the number of local elements of the 335 corresponding result vector, y. Note that this is information is 336 required for use of the matrix interface routines, even though 337 the shell matrix may not actually be physically partitioned. 338 For example, 339 340 $ 341 $ Vec x, y 342 $ extern int mult(Mat,Vec,Vec); 343 $ Mat A 344 $ 345 $ VecCreateMPI(comm,PETSC_DECIDE,M,&y); 346 $ VecCreateMPI(comm,PETSC_DECIDE,N,&x); 347 $ VecGetLocalSize(y,&m); 348 $ VecGetLocalSize(x,&n); 349 $ MatCreateShell(comm,m,n,M,N,ctx,&A); 350 $ MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult); 351 $ MatMult(A,x,y); 352 $ MatDestroy(A); 353 $ VecDestroy(y); VecDestroy(x); 354 $ 355 356 .keywords: matrix, shell, create 357 358 .seealso: MatShellSetOperation(), MatHasOperation(), MatShellGetContext(), MatShellSetContext() 359 @*/ 360 PetscErrorCode MatCreateShell(MPI_Comm comm,PetscInt m,PetscInt n,PetscInt M,PetscInt N,void *ctx,Mat *A) 361 { 362 PetscErrorCode ierr; 363 364 PetscFunctionBegin; 365 ierr = MatCreate(comm,m,n,M,N,A);CHKERRQ(ierr); 366 ierr = MatSetType(*A,MATSHELL);CHKERRQ(ierr); 367 ierr = MatShellSetContext(*A,ctx);CHKERRQ(ierr); 368 PetscFunctionReturn(0); 369 } 370 371 #undef __FUNCT__ 372 #define __FUNCT__ "MatShellSetContext" 373 /*@C 374 MatShellSetContext - sets the context for a shell matrix 375 376 Collective on Mat 377 378 Input Parameters: 379 + mat - the shell matrix 380 - ctx - the context 381 382 Level: advanced 383 384 385 .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation() 386 @*/ 387 PetscErrorCode MatShellSetContext(Mat mat,void *ctx) 388 { 389 Mat_Shell *shell = (Mat_Shell*)mat->data; 390 PetscErrorCode ierr; 391 PetscTruth flg; 392 393 PetscFunctionBegin; 394 PetscValidHeaderSpecific(mat,MAT_COOKIE,1); 395 ierr = PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr); 396 if (flg) { 397 shell->ctx = ctx; 398 } 399 PetscFunctionReturn(0); 400 } 401 402 #undef __FUNCT__ 403 #define __FUNCT__ "MatShellSetOperation" 404 /*@C 405 MatShellSetOperation - Allows user to set a matrix operation for 406 a shell matrix. 407 408 Collective on Mat 409 410 Input Parameters: 411 + mat - the shell matrix 412 . op - the name of the operation 413 - f - the function that provides the operation. 414 415 Level: advanced 416 417 Usage: 418 $ extern int usermult(Mat,Vec,Vec); 419 $ ierr = MatCreateShell(comm,m,n,M,N,ctx,&A); 420 $ ierr = MatShellSetOperation(A,MATOP_MULT,(void(*)(void))usermult); 421 422 Notes: 423 See the file include/petscmat.h for a complete list of matrix 424 operations, which all have the form MATOP_<OPERATION>, where 425 <OPERATION> is the name (in all capital letters) of the 426 user interface routine (e.g., MatMult() -> MATOP_MULT). 427 428 All user-provided functions should have the same calling 429 sequence as the usual matrix interface routines, since they 430 are intended to be accessed via the usual matrix interface 431 routines, e.g., 432 $ MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec) 433 434 Within each user-defined routine, the user should call 435 MatShellGetContext() to obtain the user-defined context that was 436 set by MatCreateShell(). 437 438 .keywords: matrix, shell, set, operation 439 440 .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellSetContext() 441 @*/ 442 PetscErrorCode MatShellSetOperation(Mat mat,MatOperation op,void (*f)(void)) 443 { 444 PetscErrorCode ierr; 445 PetscTruth flg; 446 447 PetscFunctionBegin; 448 PetscValidHeaderSpecific(mat,MAT_COOKIE,1); 449 if (op == MATOP_DESTROY) { 450 ierr = PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr); 451 if (flg) { 452 Mat_Shell *shell = (Mat_Shell*)mat->data; 453 shell->destroy = (PetscErrorCode (*)(Mat)) f; 454 } else mat->ops->destroy = (PetscErrorCode (*)(Mat)) f; 455 } 456 else if (op == MATOP_VIEW) mat->ops->view = (PetscErrorCode (*)(Mat,PetscViewer)) f; 457 else (((void(**)(void))mat->ops)[op]) = f; 458 459 PetscFunctionReturn(0); 460 } 461 462 #undef __FUNCT__ 463 #define __FUNCT__ "MatShellGetOperation" 464 /*@C 465 MatShellGetOperation - Gets a matrix function for a shell matrix. 466 467 Not Collective 468 469 Input Parameters: 470 + mat - the shell matrix 471 - op - the name of the operation 472 473 Output Parameter: 474 . f - the function that provides the operation. 475 476 Level: advanced 477 478 Notes: 479 See the file include/petscmat.h for a complete list of matrix 480 operations, which all have the form MATOP_<OPERATION>, where 481 <OPERATION> is the name (in all capital letters) of the 482 user interface routine (e.g., MatMult() -> MATOP_MULT). 483 484 All user-provided functions have the same calling 485 sequence as the usual matrix interface routines, since they 486 are intended to be accessed via the usual matrix interface 487 routines, e.g., 488 $ MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec) 489 490 Within each user-defined routine, the user should call 491 MatShellGetContext() to obtain the user-defined context that was 492 set by MatCreateShell(). 493 494 .keywords: matrix, shell, set, operation 495 496 .seealso: MatCreateShell(), MatShellGetContext(), MatShellSetOperation(), MatShellSetContext() 497 @*/ 498 PetscErrorCode MatShellGetOperation(Mat mat,MatOperation op,void(**f)(void)) 499 { 500 PetscErrorCode ierr; 501 PetscTruth flg; 502 503 PetscFunctionBegin; 504 PetscValidHeaderSpecific(mat,MAT_COOKIE,1); 505 if (op == MATOP_DESTROY) { 506 ierr = PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr); 507 if (flg) { 508 Mat_Shell *shell = (Mat_Shell*)mat->data; 509 *f = (void(*)(void))shell->destroy; 510 } else { 511 *f = (void(*)(void))mat->ops->destroy; 512 } 513 } else if (op == MATOP_VIEW) { 514 *f = (void(*)(void))mat->ops->view; 515 } else { 516 *f = (((void(**)(void))mat->ops)[op]); 517 } 518 519 PetscFunctionReturn(0); 520 } 521 522