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