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 A->data = (void*)b; 273 274 if (A->m == PETSC_DECIDE || A->n == PETSC_DECIDE) { 275 SETERRQ(PETSC_ERR_ARG_WRONG,"Must give local row and column count for matrix"); 276 } 277 278 ierr = PetscSplitOwnership(A->comm,&A->m,&A->M);CHKERRQ(ierr); 279 ierr = PetscSplitOwnership(A->comm,&A->n,&A->N);CHKERRQ(ierr); 280 281 ierr = PetscMapCreateMPI(A->comm,A->m,A->M,&A->rmap);CHKERRQ(ierr); 282 ierr = PetscMapCreateMPI(A->comm,A->n,A->N,&A->cmap);CHKERRQ(ierr); 283 284 b->ctx = 0; 285 b->scale = PETSC_FALSE; 286 b->shift = PETSC_FALSE; 287 b->vshift = 0.0; 288 b->vscale = 1.0; 289 b->mult = 0; 290 A->assembled = PETSC_TRUE; 291 A->preallocated = PETSC_TRUE; 292 PetscFunctionReturn(0); 293 } 294 EXTERN_C_END 295 296 #undef __FUNCT__ 297 #define __FUNCT__ "MatCreateShell" 298 /*@C 299 MatCreateShell - Creates a new matrix class for use with a user-defined 300 private data storage format. 301 302 Collective on MPI_Comm 303 304 Input Parameters: 305 + comm - MPI communicator 306 . m - number of local rows (must be given) 307 . n - number of local columns (must be given) 308 . M - number of global rows (may be PETSC_DETERMINE) 309 . N - number of global columns (may be PETSC_DETERMINE) 310 - ctx - pointer to data needed by the shell matrix routines 311 312 Output Parameter: 313 . A - the matrix 314 315 Level: advanced 316 317 Usage: 318 $ extern int mult(Mat,Vec,Vec); 319 $ MatCreateShell(comm,m,n,M,N,ctx,&mat); 320 $ MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult); 321 $ [ Use matrix for operations that have been set ] 322 $ MatDestroy(mat); 323 324 Notes: 325 The shell matrix type is intended to provide a simple class to use 326 with KSP (such as, for use with matrix-free methods). You should not 327 use the shell type if you plan to define a complete matrix class. 328 329 PETSc requires that matrices and vectors being used for certain 330 operations are partitioned accordingly. For example, when 331 creating a shell matrix, A, that supports parallel matrix-vector 332 products using MatMult(A,x,y) the user should set the number 333 of local matrix rows to be the number of local elements of the 334 corresponding result vector, y. Note that this is information is 335 required for use of the matrix interface routines, even though 336 the shell matrix may not actually be physically partitioned. 337 For example, 338 339 $ 340 $ Vec x, y 341 $ extern int mult(Mat,Vec,Vec); 342 $ Mat A 343 $ 344 $ VecCreateMPI(comm,PETSC_DECIDE,M,&y); 345 $ VecCreateMPI(comm,PETSC_DECIDE,N,&x); 346 $ VecGetLocalSize(y,&m); 347 $ VecGetLocalSize(x,&n); 348 $ MatCreateShell(comm,m,n,M,N,ctx,&A); 349 $ MatShellSetOperation(mat,MATOP_MULT,(void(*)(void))mult); 350 $ MatMult(A,x,y); 351 $ MatDestroy(A); 352 $ VecDestroy(y); VecDestroy(x); 353 $ 354 355 .keywords: matrix, shell, create 356 357 .seealso: MatShellSetOperation(), MatHasOperation(), MatShellGetContext(), MatShellSetContext() 358 @*/ 359 PetscErrorCode MatCreateShell(MPI_Comm comm,PetscInt m,PetscInt n,PetscInt M,PetscInt N,void *ctx,Mat *A) 360 { 361 PetscErrorCode ierr; 362 363 PetscFunctionBegin; 364 ierr = MatCreate(comm,m,n,M,N,A);CHKERRQ(ierr); 365 ierr = MatSetType(*A,MATSHELL);CHKERRQ(ierr); 366 ierr = MatShellSetContext(*A,ctx);CHKERRQ(ierr); 367 PetscFunctionReturn(0); 368 } 369 370 #undef __FUNCT__ 371 #define __FUNCT__ "MatShellSetContext" 372 /*@C 373 MatShellSetContext - sets the context for a shell matrix 374 375 Collective on Mat 376 377 Input Parameters: 378 + mat - the shell matrix 379 - ctx - the context 380 381 Level: advanced 382 383 384 .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation() 385 @*/ 386 PetscErrorCode MatShellSetContext(Mat mat,void *ctx) 387 { 388 Mat_Shell *shell = (Mat_Shell*)mat->data; 389 PetscErrorCode ierr; 390 PetscTruth flg; 391 392 PetscFunctionBegin; 393 PetscValidHeaderSpecific(mat,MAT_COOKIE,1); 394 ierr = PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr); 395 if (flg) { 396 shell->ctx = ctx; 397 } 398 PetscFunctionReturn(0); 399 } 400 401 #undef __FUNCT__ 402 #define __FUNCT__ "MatShellSetOperation" 403 /*@C 404 MatShellSetOperation - Allows user to set a matrix operation for 405 a shell matrix. 406 407 Collective on Mat 408 409 Input Parameters: 410 + mat - the shell matrix 411 . op - the name of the operation 412 - f - the function that provides the operation. 413 414 Level: advanced 415 416 Usage: 417 $ extern int usermult(Mat,Vec,Vec); 418 $ ierr = MatCreateShell(comm,m,n,M,N,ctx,&A); 419 $ ierr = MatShellSetOperation(A,MATOP_MULT,(void(*)(void))usermult); 420 421 Notes: 422 See the file include/petscmat.h for a complete list of matrix 423 operations, which all have the form MATOP_<OPERATION>, where 424 <OPERATION> is the name (in all capital letters) of the 425 user interface routine (e.g., MatMult() -> MATOP_MULT). 426 427 All user-provided functions should have the same calling 428 sequence as the usual matrix interface routines, since they 429 are intended to be accessed via the usual matrix interface 430 routines, e.g., 431 $ MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec) 432 433 Within each user-defined routine, the user should call 434 MatShellGetContext() to obtain the user-defined context that was 435 set by MatCreateShell(). 436 437 .keywords: matrix, shell, set, operation 438 439 .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellSetContext() 440 @*/ 441 PetscErrorCode MatShellSetOperation(Mat mat,MatOperation op,void (*f)(void)) 442 { 443 PetscErrorCode ierr; 444 PetscTruth flg; 445 446 PetscFunctionBegin; 447 PetscValidHeaderSpecific(mat,MAT_COOKIE,1); 448 if (op == MATOP_DESTROY) { 449 ierr = PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr); 450 if (flg) { 451 Mat_Shell *shell = (Mat_Shell*)mat->data; 452 shell->destroy = (PetscErrorCode (*)(Mat)) f; 453 } else mat->ops->destroy = (PetscErrorCode (*)(Mat)) f; 454 } 455 else if (op == MATOP_VIEW) mat->ops->view = (PetscErrorCode (*)(Mat,PetscViewer)) f; 456 else (((void(**)(void))mat->ops)[op]) = f; 457 458 PetscFunctionReturn(0); 459 } 460 461 #undef __FUNCT__ 462 #define __FUNCT__ "MatShellGetOperation" 463 /*@C 464 MatShellGetOperation - Gets a matrix function for a shell matrix. 465 466 Not Collective 467 468 Input Parameters: 469 + mat - the shell matrix 470 - op - the name of the operation 471 472 Output Parameter: 473 . f - the function that provides the operation. 474 475 Level: advanced 476 477 Notes: 478 See the file include/petscmat.h for a complete list of matrix 479 operations, which all have the form MATOP_<OPERATION>, where 480 <OPERATION> is the name (in all capital letters) of the 481 user interface routine (e.g., MatMult() -> MATOP_MULT). 482 483 All user-provided functions have the same calling 484 sequence as the usual matrix interface routines, since they 485 are intended to be accessed via the usual matrix interface 486 routines, e.g., 487 $ MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec) 488 489 Within each user-defined routine, the user should call 490 MatShellGetContext() to obtain the user-defined context that was 491 set by MatCreateShell(). 492 493 .keywords: matrix, shell, set, operation 494 495 .seealso: MatCreateShell(), MatShellGetContext(), MatShellSetOperation(), MatShellSetContext() 496 @*/ 497 PetscErrorCode MatShellGetOperation(Mat mat,MatOperation op,void(**f)(void)) 498 { 499 PetscErrorCode ierr; 500 PetscTruth flg; 501 502 PetscFunctionBegin; 503 PetscValidHeaderSpecific(mat,MAT_COOKIE,1); 504 if (op == MATOP_DESTROY) { 505 ierr = PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr); 506 if (flg) { 507 Mat_Shell *shell = (Mat_Shell*)mat->data; 508 *f = (void(*)(void))shell->destroy; 509 } else { 510 *f = (void(*)(void))mat->ops->destroy; 511 } 512 } else if (op == MATOP_VIEW) { 513 *f = (void(*)(void))mat->ops->view; 514 } else { 515 *f = (((void(**)(void))mat->ops)[op]); 516 } 517 518 PetscFunctionReturn(0); 519 } 520 521