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