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