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, 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,A);CHKERRQ(ierr); 370 ierr = MatSetSizes(*A,m,n,M,N);CHKERRQ(ierr); 371 ierr = MatSetType(*A,MATSHELL);CHKERRQ(ierr); 372 ierr = MatShellSetContext(*A,ctx);CHKERRQ(ierr); 373 PetscFunctionReturn(0); 374 } 375 376 #undef __FUNCT__ 377 #define __FUNCT__ "MatShellSetContext" 378 /*@C 379 MatShellSetContext - sets the context for a shell matrix 380 381 Collective on Mat 382 383 Input Parameters: 384 + mat - the shell matrix 385 - ctx - the context 386 387 Level: advanced 388 389 Fortran Notes: The context can only be an integer or a PetscObject 390 unfortunately it cannot be a Fortran array or derived type. 391 392 .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation() 393 @*/ 394 PetscErrorCode PETSCMAT_DLLEXPORT MatShellSetContext(Mat mat,void *ctx) 395 { 396 Mat_Shell *shell = (Mat_Shell*)mat->data; 397 PetscErrorCode ierr; 398 PetscTruth flg; 399 400 PetscFunctionBegin; 401 PetscValidHeaderSpecific(mat,MAT_COOKIE,1); 402 ierr = PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr); 403 if (flg) { 404 shell->ctx = ctx; 405 } 406 PetscFunctionReturn(0); 407 } 408 409 #undef __FUNCT__ 410 #define __FUNCT__ "MatShellSetOperation" 411 /*@C 412 MatShellSetOperation - Allows user to set a matrix operation for 413 a shell matrix. 414 415 Collective on Mat 416 417 Input Parameters: 418 + mat - the shell matrix 419 . op - the name of the operation 420 - f - the function that provides the operation. 421 422 Level: advanced 423 424 Usage: 425 $ extern int usermult(Mat,Vec,Vec); 426 $ ierr = MatCreateShell(comm,m,n,M,N,ctx,&A); 427 $ ierr = MatShellSetOperation(A,MATOP_MULT,(void(*)(void))usermult); 428 429 Notes: 430 See the file include/petscmat.h for a complete list of matrix 431 operations, which all have the form MATOP_<OPERATION>, where 432 <OPERATION> is the name (in all capital letters) of the 433 user interface routine (e.g., MatMult() -> MATOP_MULT). 434 435 All user-provided functions should have the same calling 436 sequence as the usual matrix interface routines, since they 437 are intended to be accessed via the usual matrix interface 438 routines, e.g., 439 $ MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec) 440 441 Within each user-defined routine, the user should call 442 MatShellGetContext() to obtain the user-defined context that was 443 set by MatCreateShell(). 444 445 .keywords: matrix, shell, set, operation 446 447 .seealso: MatCreateShell(), MatShellGetContext(), MatShellGetOperation(), MatShellSetContext() 448 @*/ 449 PetscErrorCode PETSCMAT_DLLEXPORT MatShellSetOperation(Mat mat,MatOperation op,void (*f)(void)) 450 { 451 PetscErrorCode ierr; 452 PetscTruth flg; 453 454 PetscFunctionBegin; 455 PetscValidHeaderSpecific(mat,MAT_COOKIE,1); 456 if (op == MATOP_DESTROY) { 457 ierr = PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr); 458 if (flg) { 459 Mat_Shell *shell = (Mat_Shell*)mat->data; 460 shell->destroy = (PetscErrorCode (*)(Mat)) f; 461 } else mat->ops->destroy = (PetscErrorCode (*)(Mat)) f; 462 } 463 else if (op == MATOP_VIEW) mat->ops->view = (PetscErrorCode (*)(Mat,PetscViewer)) f; 464 else (((void(**)(void))mat->ops)[op]) = f; 465 466 PetscFunctionReturn(0); 467 } 468 469 #undef __FUNCT__ 470 #define __FUNCT__ "MatShellGetOperation" 471 /*@C 472 MatShellGetOperation - Gets a matrix function for a shell matrix. 473 474 Not Collective 475 476 Input Parameters: 477 + mat - the shell matrix 478 - op - the name of the operation 479 480 Output Parameter: 481 . f - the function that provides the operation. 482 483 Level: advanced 484 485 Notes: 486 See the file include/petscmat.h for a complete list of matrix 487 operations, which all have the form MATOP_<OPERATION>, where 488 <OPERATION> is the name (in all capital letters) of the 489 user interface routine (e.g., MatMult() -> MATOP_MULT). 490 491 All user-provided functions have the same calling 492 sequence as the usual matrix interface routines, since they 493 are intended to be accessed via the usual matrix interface 494 routines, e.g., 495 $ MatMult(Mat,Vec,Vec) -> usermult(Mat,Vec,Vec) 496 497 Within each user-defined routine, the user should call 498 MatShellGetContext() to obtain the user-defined context that was 499 set by MatCreateShell(). 500 501 .keywords: matrix, shell, set, operation 502 503 .seealso: MatCreateShell(), MatShellGetContext(), MatShellSetOperation(), MatShellSetContext() 504 @*/ 505 PetscErrorCode PETSCMAT_DLLEXPORT MatShellGetOperation(Mat mat,MatOperation op,void(**f)(void)) 506 { 507 PetscErrorCode ierr; 508 PetscTruth flg; 509 510 PetscFunctionBegin; 511 PetscValidHeaderSpecific(mat,MAT_COOKIE,1); 512 if (op == MATOP_DESTROY) { 513 ierr = PetscTypeCompare((PetscObject)mat,MATSHELL,&flg);CHKERRQ(ierr); 514 if (flg) { 515 Mat_Shell *shell = (Mat_Shell*)mat->data; 516 *f = (void(*)(void))shell->destroy; 517 } else { 518 *f = (void(*)(void))mat->ops->destroy; 519 } 520 } else if (op == MATOP_VIEW) { 521 *f = (void(*)(void))mat->ops->view; 522 } else { 523 *f = (((void(**)(void))mat->ops)[op]); 524 } 525 526 PetscFunctionReturn(0); 527 } 528 529