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 static struct _MatOps MatOps_Values = {0, 144 0, 145 0, 146 0, 147 /* 4*/ 0, 148 0, 149 0, 150 0, 151 0, 152 0, 153 /*10*/ 0, 154 0, 155 0, 156 0, 157 0, 158 /*15*/ 0, 159 0, 160 0, 161 0, 162 0, 163 /*20*/ 0, 164 MatAssemblyEnd_Shell, 165 0, 166 0, 167 0, 168 /*25*/ 0, 169 0, 170 0, 171 0, 172 0, 173 /*30*/ 0, 174 0, 175 0, 176 0, 177 0, 178 /*35*/ 0, 179 0, 180 0, 181 0, 182 0, 183 /*40*/ 0, 184 0, 185 0, 186 0, 187 0, 188 /*45*/ 0, 189 MatScale_Shell, 190 MatShift_Shell, 191 0, 192 0, 193 /*50*/ 0, 194 0, 195 0, 196 0, 197 0, 198 /*55*/ 0, 199 0, 200 0, 201 0, 202 0, 203 /*60*/ 0, 204 MatDestroy_Shell, 205 0, 206 MatGetPetscMaps_Petsc, 207 0, 208 /*65*/ 0, 209 0, 210 0, 211 0, 212 0, 213 /*70*/ 0, 214 MatConvert_Shell, 215 0, 216 0, 217 0, 218 /*75*/ 0, 219 0, 220 0, 221 0, 222 0, 223 /*80*/ 0, 224 0, 225 0, 226 0, 227 0, 228 /*85*/ 0, 229 0, 230 0, 231 0, 232 0, 233 /*90*/ 0, 234 0, 235 0, 236 0, 237 0, 238 /*95*/ 0, 239 0, 240 0, 241 0}; 242 243 /*MC 244 MATSHELL - MATSHELL = "shell" - A matrix type to be used to define your own matrix type -- perhaps matrix free. 245 246 Level: advanced 247 248 .seealso: MatCreateShell 249 M*/ 250 251 EXTERN_C_BEGIN 252 #undef __FUNCT__ 253 #define __FUNCT__ "MatCreate_Shell" 254 PetscErrorCode MatCreate_Shell(Mat A) 255 { 256 Mat_Shell *b; 257 PetscErrorCode ierr; 258 259 PetscFunctionBegin; 260 ierr = PetscMemcpy(A->ops,&MatOps_Values,sizeof(struct _MatOps));CHKERRQ(ierr); 261 262 ierr = PetscNew(Mat_Shell,&b);CHKERRQ(ierr); 263 PetscLogObjectMemory(A,sizeof(struct _p_Mat)+sizeof(Mat_Shell)); 264 ierr = PetscMemzero(b,sizeof(Mat_Shell));CHKERRQ(ierr); 265 A->data = (void*)b; 266 267 if (A->m == PETSC_DECIDE || A->n == PETSC_DECIDE) { 268 SETERRQ(PETSC_ERR_ARG_WRONG,"Must give local row and column count for matrix"); 269 } 270 271 ierr = PetscSplitOwnership(A->comm,&A->m,&A->M);CHKERRQ(ierr); 272 ierr = PetscSplitOwnership(A->comm,&A->n,&A->N);CHKERRQ(ierr); 273 274 ierr = PetscMapCreateMPI(A->comm,A->m,A->M,&A->rmap);CHKERRQ(ierr); 275 ierr = PetscMapCreateMPI(A->comm,A->n,A->N,&A->cmap);CHKERRQ(ierr); 276 277 b->ctx = 0; 278 b->scale = PETSC_FALSE; 279 b->shift = PETSC_FALSE; 280 b->vshift = 0.0; 281 b->vscale = 1.0; 282 b->mult = 0; 283 A->assembled = PETSC_TRUE; 284 A->preallocated = PETSC_TRUE; 285 PetscFunctionReturn(0); 286 } 287 EXTERN_C_END 288 289 #undef __FUNCT__ 290 #define __FUNCT__ "MatCreateShell" 291 /*@C 292 MatCreateShell - Creates a new matrix class for use with a user-defined 293 private data storage format. 294 295 Collective on MPI_Comm 296 297 Input Parameters: 298 + comm - MPI communicator 299 . m - number of local rows (must be given) 300 . n - number of local columns (must be given) 301 . M - number of global rows (may be PETSC_DETERMINE) 302 . N - number of global columns (may be PETSC_DETERMINE) 303 - ctx - pointer to data needed by the shell matrix routines 304 305 Output Parameter: 306 . A - the matrix 307 308 Level: advanced 309 310 Usage: 311 $ extern int mult(Mat,Vec,Vec); 312 $ MatCreateShell(comm,m,n,M,N,ctx,&mat); 313 $ MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult); 314 $ [ Use matrix for operations that have been set ] 315 $ MatDestroy(mat); 316 317 Notes: 318 The shell matrix type is intended to provide a simple class to use 319 with KSP (such as, for use with matrix-free methods). You should not 320 use the shell type if you plan to define a complete matrix class. 321 322 PETSc requires that matrices and vectors being used for certain 323 operations are partitioned accordingly. For example, when 324 creating a shell matrix, A, that supports parallel matrix-vector 325 products using MatMult(A,x,y) the user should set the number 326 of local matrix rows to be the number of local elements of the 327 corresponding result vector, y. Note that this is information is 328 required for use of the matrix interface routines, even though 329 the shell matrix may not actually be physically partitioned. 330 For example, 331 332 $ 333 $ Vec x, y 334 $ extern int mult(Mat,Vec,Vec); 335 $ Mat A 336 $ 337 $ VecCreateMPI(comm,PETSC_DECIDE,M,&y); 338 $ VecCreateMPI(comm,PETSC_DECIDE,N,&x); 339 $ VecGetLocalSize(y,&m); 340 $ VecGetLocalSize(x,&n); 341 $ MatCreateShell(comm,m,n,M,N,ctx,&A); 342 $ MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult); 343 $ MatMult(A,x,y); 344 $ MatDestroy(A); 345 $ VecDestroy(y); VecDestroy(x); 346 $ 347 348 .keywords: matrix, shell, create 349 350 .seealso: MatShellSetOperation(), MatHasOperation(), MatShellGetContext(), MatShellSetContext() 351 @*/ 352 PetscErrorCode MatCreateShell(MPI_Comm comm,PetscInt m,PetscInt n,PetscInt M,PetscInt N,void *ctx,Mat *A) 353 { 354 PetscErrorCode ierr; 355 356 PetscFunctionBegin; 357 ierr = MatCreate(comm,m,n,M,N,A);CHKERRQ(ierr); 358 ierr = MatSetType(*A,MATSHELL);CHKERRQ(ierr); 359 ierr = MatShellSetContext(*A,ctx);CHKERRQ(ierr); 360 PetscFunctionReturn(0); 361 } 362 363 #undef __FUNCT__ 364 #define __FUNCT__ "MatShellSetContext" 365 /*@C 366 MatShellSetContext - sets the context for a shell matrix 367 368 Collective on Mat 369 370 Input Parameters: 371 + mat - the shell matrix 372 - ctx - the context 373 374 Level: advanced 375 376 377 .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation() 378 @*/ 379 PetscErrorCode MatShellSetContext(Mat mat,void *ctx) 380 { 381 Mat_Shell *shell = (Mat_Shell*)mat->data; 382 PetscErrorCode ierr; 383 PetscTruth flg; 384 385 PetscFunctionBegin; 386 PetscValidHeaderSpecific(mat,MAT_COOKIE,1); 387 ierr = PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr); 388 if (flg) { 389 shell->ctx = ctx; 390 } 391 PetscFunctionReturn(0); 392 } 393 394 #undef __FUNCT__ 395 #define __FUNCT__ "MatShellSetOperation" 396 /*@C 397 MatShellSetOperation - Allows user to set a matrix operation for 398 a shell matrix. 399 400 Collective on Mat 401 402 Input Parameters: 403 + mat - the shell matrix 404 . op - the name of the operation 405 - f - the function that provides the operation. 406 407 Level: advanced 408 409 Usage: 410 $ extern int usermult(Mat,Vec,Vec); 411 $ ierr = MatCreateShell(comm,m,n,M,N,ctx,&A); 412 $ ierr = MatShellSetOperation(A,MATOP_MULT,(void(*)(void))usermult); 413 414 Notes: 415 See the file include/petscmat.h for a complete list of matrix 416 operations, which all have the form MATOP_<OPERATION>, where 417 <OPERATION> is the name (in all capital letters) of the 418 user interface routine (e.g., MatMult() -> MATOP_MULT). 419 420 All user-provided functions should have the same calling 421 sequence as the usual matrix interface routines, since they 422 are intended to be accessed via the usual matrix interface 423 routines, e.g., 424 $ MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec) 425 426 Within each user-defined routine, the user should call 427 MatShellGetContext() to obtain the user-defined context that was 428 set by MatCreateShell(). 429 430 .keywords: matrix, shell, set, operation 431 432 .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellSetContext() 433 @*/ 434 PetscErrorCode MatShellSetOperation(Mat mat,MatOperation op,void (*f)(void)) 435 { 436 PetscErrorCode ierr; 437 PetscTruth flg; 438 439 PetscFunctionBegin; 440 PetscValidHeaderSpecific(mat,MAT_COOKIE,1); 441 if (op == MATOP_DESTROY) { 442 ierr = PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr); 443 if (flg) { 444 Mat_Shell *shell = (Mat_Shell*)mat->data; 445 shell->destroy = (PetscErrorCode (*)(Mat)) f; 446 } else mat->ops->destroy = (PetscErrorCode (*)(Mat)) f; 447 } 448 else if (op == MATOP_VIEW) mat->ops->view = (PetscErrorCode (*)(Mat,PetscViewer)) f; 449 else (((void(**)(void))mat->ops)[op]) = f; 450 451 PetscFunctionReturn(0); 452 } 453 454 #undef __FUNCT__ 455 #define __FUNCT__ "MatShellGetOperation" 456 /*@C 457 MatShellGetOperation - Gets a matrix function for a shell matrix. 458 459 Not Collective 460 461 Input Parameters: 462 + mat - the shell matrix 463 - op - the name of the operation 464 465 Output Parameter: 466 . f - the function that provides the operation. 467 468 Level: advanced 469 470 Notes: 471 See the file include/petscmat.h for a complete list of matrix 472 operations, which all have the form MATOP_<OPERATION>, where 473 <OPERATION> is the name (in all capital letters) of the 474 user interface routine (e.g., MatMult() -> MATOP_MULT). 475 476 All user-provided functions have the same calling 477 sequence as the usual matrix interface routines, since they 478 are intended to be accessed via the usual matrix interface 479 routines, e.g., 480 $ MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec) 481 482 Within each user-defined routine, the user should call 483 MatShellGetContext() to obtain the user-defined context that was 484 set by MatCreateShell(). 485 486 .keywords: matrix, shell, set, operation 487 488 .seealso: MatCreateShell(), MatShellGetContext(), MatShellSetOperation(), MatShellSetContext() 489 @*/ 490 PetscErrorCode MatShellGetOperation(Mat mat,MatOperation op,void(**f)(void)) 491 { 492 PetscErrorCode ierr; 493 PetscTruth flg; 494 495 PetscFunctionBegin; 496 PetscValidHeaderSpecific(mat,MAT_COOKIE,1); 497 if (op == MATOP_DESTROY) { 498 ierr = PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr); 499 if (flg) { 500 Mat_Shell *shell = (Mat_Shell*)mat->data; 501 *f = (void(*)(void))shell->destroy; 502 } else { 503 *f = (void(*)(void))mat->ops->destroy; 504 } 505 } else if (op == MATOP_VIEW) { 506 *f = (void(*)(void))mat->ops->view; 507 } else { 508 *f = (((void(**)(void))mat->ops)[op]); 509 } 510 511 PetscFunctionReturn(0); 512 } 513 514