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