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