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