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