1 /*$Id: snesmfj.c,v 1.123 2001/06/21 21:18:42 bsmith Exp bsmith $*/ 2 3 #include "src/snes/snesimpl.h" 4 #include "src/snes/mf/snesmfj.h" /*I "petscsnes.h" I*/ 5 6 PetscFList MatSNESMPetscFList = 0; 7 PetscTruth MatSNESMFRegisterAllCalled = PETSC_FALSE; 8 9 #undef __FUNCT__ 10 #define __FUNCT__ "MatSNESMFSetType" 11 /*@C 12 MatSNESMFSetType - Sets the method that is used to compute the 13 differencing parameter for finite differene matrix-free formulations. 14 15 Input Parameters: 16 + mat - the "matrix-free" matrix created via MatCreateSNESMF() 17 - ftype - the type requested 18 19 Level: advanced 20 21 Notes: 22 For example, such routines can compute h for use in 23 Jacobian-vector products of the form 24 25 F(x+ha) - F(x) 26 F'(u)a ~= ---------------- 27 h 28 29 .seealso: MatCreateSNESMF(), MatSNESMFRegisterDynamic) 30 @*/ 31 int MatSNESMFSetType(Mat mat,MatSNESMFType ftype) 32 { 33 int ierr,(*r)(MatSNESMFCtx); 34 MatSNESMFCtx ctx; 35 PetscTruth match; 36 37 PetscFunctionBegin; 38 PetscValidHeaderSpecific(mat,MAT_COOKIE); 39 PetscValidCharPointer(ftype); 40 41 ierr = MatShellGetContext(mat,(void **)&ctx);CHKERRQ(ierr); 42 43 /* already set, so just return */ 44 ierr = PetscTypeCompare((PetscObject)ctx,ftype,&match);CHKERRQ(ierr); 45 if (match) PetscFunctionReturn(0); 46 47 /* destroy the old one if it exists */ 48 if (ctx->ops->destroy) { 49 ierr = (*ctx->ops->destroy)(ctx);CHKERRQ(ierr); 50 } 51 52 /* Get the function pointers for the requrested method */ 53 if (!MatSNESMFRegisterAllCalled) {ierr = MatSNESMFRegisterAll(PETSC_NULL);CHKERRQ(ierr);} 54 55 ierr = PetscFListFind(ctx->comm,MatSNESMPetscFList,ftype,(void (**)(void)) &r);CHKERRQ(ierr); 56 57 if (!r) SETERRQ(1,"Unknown MatSNESMF type given"); 58 59 ierr = (*r)(ctx);CHKERRQ(ierr); 60 61 ierr = PetscObjectChangeTypeName((PetscObject)ctx,ftype);CHKERRQ(ierr); 62 63 PetscFunctionReturn(0); 64 } 65 66 /*MC 67 MatSNESMFRegisterDynamic - Adds a method to the MatSNESMF registry. 68 69 Synopsis: 70 int MatSNESMFRegisterDynamic(char *name_solver,char *path,char *name_create,int (*routine_create)(MatSNESMF)) 71 72 Not Collective 73 74 Input Parameters: 75 + name_solver - name of a new user-defined compute-h module 76 . path - path (either absolute or relative) the library containing this solver 77 . name_create - name of routine to create method context 78 - routine_create - routine to create method context 79 80 Level: developer 81 82 Notes: 83 MatSNESMFRegisterDynamic) may be called multiple times to add several user-defined solvers. 84 85 If dynamic libraries are used, then the fourth input argument (routine_create) 86 is ignored. 87 88 Sample usage: 89 .vb 90 MatSNESMFRegisterDynamic"my_h",/home/username/my_lib/lib/libO/solaris/mylib.a, 91 "MyHCreate",MyHCreate); 92 .ve 93 94 Then, your solver can be chosen with the procedural interface via 95 $ MatSNESMFSetType(mfctx,"my_h") 96 or at runtime via the option 97 $ -snes_mf_type my_h 98 99 .keywords: MatSNESMF, register 100 101 .seealso: MatSNESMFRegisterAll(), MatSNESMFRegisterDestroy() 102 M*/ 103 104 #undef __FUNCT__ 105 #define __FUNCT__ "MatSNESMFRegister" 106 int MatSNESMFRegister(char *sname,char *path,char *name,int (*function)(MatSNESMFCtx)) 107 { 108 int ierr; 109 char fullname[256]; 110 111 PetscFunctionBegin; 112 ierr = PetscFListConcat(path,name,fullname);CHKERRQ(ierr); 113 ierr = PetscFListAdd(&MatSNESMPetscFList,sname,fullname,(void (*)())function);CHKERRQ(ierr); 114 PetscFunctionReturn(0); 115 } 116 117 118 #undef __FUNCT__ 119 #define __FUNCT__ "MatSNESMFRegisterDestroy" 120 /*@C 121 MatSNESMFRegisterDestroy - Frees the list of MatSNESMF methods that were 122 registered by MatSNESMFRegisterDynamic). 123 124 Not Collective 125 126 Level: developer 127 128 .keywords: MatSNESMF, register, destroy 129 130 .seealso: MatSNESMFRegisterDynamic), MatSNESMFRegisterAll() 131 @*/ 132 int MatSNESMFRegisterDestroy(void) 133 { 134 int ierr; 135 136 PetscFunctionBegin; 137 if (MatSNESMPetscFList) { 138 ierr = PetscFListDestroy(&MatSNESMPetscFList);CHKERRQ(ierr); 139 MatSNESMPetscFList = 0; 140 } 141 MatSNESMFRegisterAllCalled = PETSC_FALSE; 142 PetscFunctionReturn(0); 143 } 144 145 /* ----------------------------------------------------------------------------------------*/ 146 #undef __FUNCT__ 147 #define __FUNCT__ "MatSNESMFDestroy_Private" 148 int MatSNESMFDestroy_Private(Mat mat) 149 { 150 int ierr; 151 MatSNESMFCtx ctx; 152 153 PetscFunctionBegin; 154 ierr = MatShellGetContext(mat,(void **)&ctx);CHKERRQ(ierr); 155 ierr = VecDestroy(ctx->w);CHKERRQ(ierr); 156 if (ctx->ops->destroy) {ierr = (*ctx->ops->destroy)(ctx);CHKERRQ(ierr);} 157 if (ctx->sp) {ierr = MatNullSpaceDestroy(ctx->sp);CHKERRQ(ierr);} 158 PetscHeaderDestroy(ctx); 159 PetscFunctionReturn(0); 160 } 161 162 #undef __FUNCT__ 163 #define __FUNCT__ "MatSNESMFView_Private" 164 /* 165 MatSNESMFView_Private - Views matrix-free parameters. 166 167 */ 168 int MatSNESMFView_Private(Mat J,PetscViewer viewer) 169 { 170 int ierr; 171 MatSNESMFCtx ctx; 172 PetscTruth isascii; 173 174 PetscFunctionBegin; 175 ierr = MatShellGetContext(J,(void **)&ctx);CHKERRQ(ierr); 176 ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&isascii);CHKERRQ(ierr); 177 if (isascii) { 178 ierr = PetscViewerASCIIPrintf(viewer," SNES matrix-free approximation:\n");CHKERRQ(ierr); 179 ierr = PetscViewerASCIIPrintf(viewer," err=%g (relative error in function evaluation)\n",ctx->error_rel);CHKERRQ(ierr); 180 if (!ctx->type_name) { 181 ierr = PetscViewerASCIIPrintf(viewer," The compute h routine has not yet been set\n");CHKERRQ(ierr); 182 } else { 183 ierr = PetscViewerASCIIPrintf(viewer," Using %s compute h routine\n",ctx->type_name);CHKERRQ(ierr); 184 } 185 if (ctx->ops->view) { 186 ierr = (*ctx->ops->view)(ctx,viewer);CHKERRQ(ierr); 187 } 188 } else { 189 SETERRQ1(1,"Viewer type %s not supported for SNES matrix free matrix",((PetscObject)viewer)->type_name); 190 } 191 PetscFunctionReturn(0); 192 } 193 194 #undef __FUNCT__ 195 #define __FUNCT__ "MatSNESMFAssemblyEnd_Private" 196 /* 197 MatSNESMFAssemblyEnd_Private - Resets the ctx->ncurrenth to zero. This 198 allows the user to indicate the beginning of a new linear solve by calling 199 MatAssemblyXXX() on the matrix free matrix. This then allows the 200 MatSNESMFCreate_WP() to properly compute ||U|| only the first time 201 in the linear solver rather than every time. 202 */ 203 int MatSNESMFAssemblyEnd_Private(Mat J) 204 { 205 int ierr; 206 MatSNESMFCtx j; 207 208 PetscFunctionBegin; 209 ierr = MatSNESMFResetHHistory(J);CHKERRQ(ierr); 210 ierr = MatShellGetContext(J,(void **)&j);CHKERRQ(ierr); 211 if (j->usesnes) { 212 ierr = SNESGetSolution(j->snes,&j->current_u);CHKERRQ(ierr); 213 if (j->snes->method_class == SNES_NONLINEAR_EQUATIONS) { 214 ierr = SNESGetFunction(j->snes,&j->current_f,PETSC_NULL,PETSC_NULL);CHKERRQ(ierr); 215 } else if (j->snes->method_class == SNES_UNCONSTRAINED_MINIMIZATION) { 216 ierr = SNESGetGradient(j->snes,&j->current_f,PETSC_NULL);CHKERRQ(ierr); 217 } else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Invalid method class"); 218 } 219 PetscFunctionReturn(0); 220 } 221 222 #undef __FUNCT__ 223 #define __FUNCT__ "MatSNESMFMult_Private" 224 /* 225 MatSNESMFMult_Private - Default matrix-free form for Jacobian-vector 226 product, y = F'(u)*a: 227 228 y ~= (F(u + ha) - F(u))/h, 229 where F = nonlinear function, as set by SNESSetFunction() 230 u = current iterate 231 h = difference interval 232 */ 233 int MatSNESMFMult_Private(Mat mat,Vec a,Vec y) 234 { 235 MatSNESMFCtx ctx; 236 SNES snes; 237 Scalar h,mone = -1.0; 238 Vec w,U,F; 239 int ierr,(*eval_fct)(SNES,Vec,Vec)=0; 240 241 PetscFunctionBegin; 242 /* We log matrix-free matrix-vector products separately, so that we can 243 separate the performance monitoring from the cases that use conventional 244 storage. We may eventually modify event logging to associate events 245 with particular objects, hence alleviating the more general problem. */ 246 ierr = PetscLogEventBegin(MAT_MatrixFreeMult,a,y,0,0);CHKERRQ(ierr); 247 248 ierr = MatShellGetContext(mat,(void **)&ctx);CHKERRQ(ierr); 249 snes = ctx->snes; 250 w = ctx->w; 251 U = ctx->current_u; 252 253 /* 254 Compute differencing parameter 255 */ 256 if (!ctx->ops->compute) { 257 ierr = MatSNESMFSetType(mat,MATSNESMF_DEFAULT);CHKERRQ(ierr); 258 ierr = MatSNESMFSetFromOptions(mat);CHKERRQ(ierr); 259 } 260 ierr = (*ctx->ops->compute)(ctx,U,a,&h);CHKERRQ(ierr); 261 262 /* keep a record of the current differencing parameter h */ 263 ctx->currenth = h; 264 #if defined(PETSC_USE_COMPLEX) 265 PetscLogInfo(mat,"MatSNESMFMult_Private:Current differencing parameter: %g + %g i\n",PetscRealPart(h),PetscImaginaryPart(h)); 266 #else 267 PetscLogInfo(mat,"MatSNESMFMult_Private:Current differencing parameter: %15.12e\n",h); 268 #endif 269 if (ctx->historyh && ctx->ncurrenth < ctx->maxcurrenth) { 270 ctx->historyh[ctx->ncurrenth] = h; 271 } 272 ctx->ncurrenth++; 273 274 /* w = u + ha */ 275 ierr = VecWAXPY(&h,a,U,w);CHKERRQ(ierr); 276 277 if (ctx->usesnes) { 278 if (snes->method_class == SNES_NONLINEAR_EQUATIONS) { 279 eval_fct = SNESComputeFunction; 280 } else if (snes->method_class == SNES_UNCONSTRAINED_MINIMIZATION) { 281 eval_fct = SNESComputeGradient; 282 } else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Invalid method class"); 283 F = ctx->current_f; 284 if (!F) SETERRQ(1,"You must call MatAssembly() even on matrix-free matrices"); 285 ierr = (*eval_fct)(snes,w,y);CHKERRQ(ierr); 286 } else { 287 F = ctx->funcvec; 288 /* compute func(U) as base for differencing */ 289 if (ctx->ncurrenth == 1) { 290 ierr = (*ctx->func)(snes,U,F,ctx->funcctx);CHKERRQ(ierr); 291 } 292 ierr = (*ctx->func)(snes,w,y,ctx->funcctx);CHKERRQ(ierr); 293 } 294 295 ierr = VecAXPY(&mone,F,y);CHKERRQ(ierr); 296 h = 1.0/h; 297 ierr = VecScale(&h,y);CHKERRQ(ierr); 298 if (ctx->sp) {ierr = MatNullSpaceRemove(ctx->sp,y,PETSC_NULL);CHKERRQ(ierr);} 299 300 ierr = PetscLogEventEnd(MAT_MatrixFreeMult,a,y,0,0);CHKERRQ(ierr); 301 PetscFunctionReturn(0); 302 } 303 304 #undef __FUNCT__ 305 #define __FUNCT__ "MatSNESMFGetDiagonal_Private" 306 /* 307 MatSNESMFGetDiagonal_Private - Gets the diagonal for a matrix free matrix 308 309 y ~= (F(u + ha) - F(u))/h, 310 where F = nonlinear function, as set by SNESSetFunction() 311 u = current iterate 312 h = difference interval 313 */ 314 int MatSNESMFGetDiagonal_Private(Mat mat,Vec a) 315 { 316 MatSNESMFCtx ctx; 317 Scalar h,h1,mone = -1.0,*aa,*ww,v,epsilon = 1.e-8,umin = 1.e-6; 318 Vec w,U,F; 319 int i,ierr,rstart,rend; 320 321 PetscFunctionBegin; 322 ierr = MatShellGetContext(mat,(void **)&ctx);CHKERRQ(ierr); 323 if (!ctx->funci) { 324 SETERRQ(1,"Requirers calling MatSNESMFSetFunctioni() first"); 325 } 326 327 w = ctx->w; 328 U = ctx->current_u; 329 ierr = (*ctx->func)(0,U,a,ctx->funcctx);CHKERRQ(ierr); 330 ierr = (*ctx->funcisetbase)(U,ctx->funcctx);CHKERRQ(ierr); 331 ierr = VecCopy(U,w);CHKERRQ(ierr); 332 333 ierr = VecGetOwnershipRange(a,&rstart,&rend);CHKERRQ(ierr); 334 ierr = VecGetArray(a,&aa);CHKERRQ(ierr); 335 for (i=rstart; i<rend; i++) { 336 ierr = VecGetArray(w,&ww);CHKERRQ(ierr); 337 h = ww[i-rstart]; 338 if (h == 0.0) h = 1.0; 339 #if !defined(PETSC_USE_COMPLEX) 340 if (h < umin && h >= 0.0) h = umin; 341 else if (h < 0.0 && h > -umin) h = -umin; 342 #else 343 if (PetscAbsScalar(h) < umin && PetscRealPart(h) >= 0.0) h = umin; 344 else if (PetscRealPart(h) < 0.0 && PetscAbsScalar(h) < umin) h = -umin; 345 #endif 346 h *= epsilon; 347 348 ww[i-rstart] += h; 349 ierr = VecRestoreArray(w,&ww);CHKERRQ(ierr); 350 ierr = (*ctx->funci)(i,w,&v,ctx->funcctx);CHKERRQ(ierr); 351 aa[i-rstart] = (v - aa[i-rstart])/h; 352 ierr = VecGetArray(w,&ww);CHKERRQ(ierr); 353 ww[i-rstart] -= h; 354 ierr = VecRestoreArray(w,&ww);CHKERRQ(ierr); 355 } 356 ierr = VecRestoreArray(a,&aa);CHKERRQ(ierr); 357 PetscFunctionReturn(0); 358 } 359 360 #undef __FUNCT__ 361 #define __FUNCT__ "MatCreateSNESMF" 362 /*@C 363 MatCreateSNESMF - Creates a matrix-free matrix context for use with 364 a SNES solver. This matrix can be used as the Jacobian argument for 365 the routine SNESSetJacobian(). 366 367 Collective on SNES and Vec 368 369 Input Parameters: 370 + snes - the SNES context 371 - x - vector where SNES solution is to be stored. 372 373 Output Parameter: 374 . J - the matrix-free matrix 375 376 Level: advanced 377 378 Notes: 379 The matrix-free matrix context merely contains the function pointers 380 and work space for performing finite difference approximations of 381 Jacobian-vector products, F'(u)*a, 382 383 The default code uses the following approach to compute h 384 385 .vb 386 F'(u)*a = [F(u+h*a) - F(u)]/h where 387 h = error_rel*u'a/||a||^2 if |u'a| > umin*||a||_{1} 388 = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2 otherwise 389 where 390 error_rel = square root of relative error in function evaluation 391 umin = minimum iterate parameter 392 .ve 393 394 The user can set the error_rel via MatSNESMFSetFunctionError() and 395 umin via MatSNESMFDefaultSetUmin(); see the nonlinear solvers chapter 396 of the users manual for details. 397 398 The user should call MatDestroy() when finished with the matrix-free 399 matrix context. 400 401 Options Database Keys: 402 + -snes_mf_err <error_rel> - Sets error_rel 403 . -snes_mf_unim <umin> - Sets umin (for default PETSc routine that computes h only) 404 - -snes_mf_ksp_monitor - KSP monitor routine that prints differencing h 405 406 .keywords: SNES, default, matrix-free, create, matrix 407 408 .seealso: MatDestroy(), MatSNESMFSetFunctionError(), MatSNESMFDefaultSetUmin() 409 MatSNESMFSetHHistory(), MatSNESMFResetHHistory(), MatCreateMF(), 410 MatSNESMFGetH(),MatSNESMFKSPMonitor(), MatSNESMFRegisterDynamic), MatSNESMFComputeJacobian() 411 412 @*/ 413 int MatCreateSNESMF(SNES snes,Vec x,Mat *J) 414 { 415 MatSNESMFCtx mfctx; 416 int ierr; 417 418 PetscFunctionBegin; 419 ierr = MatCreateMF(x,J);CHKERRQ(ierr); 420 ierr = MatShellGetContext(*J,(void **)&mfctx);CHKERRQ(ierr); 421 mfctx->snes = snes; 422 mfctx->usesnes = PETSC_TRUE; 423 PetscLogObjectParent(snes,*J); 424 PetscFunctionReturn(0); 425 } 426 427 EXTERN_C_BEGIN 428 #undef __FUNCT__ 429 #define __FUNCT__ "MatSNESMFSetBase_FD" 430 int MatSNESMFSetBase_FD(Mat J,Vec U) 431 { 432 int ierr; 433 MatSNESMFCtx ctx; 434 435 PetscFunctionBegin; 436 ierr = MatSNESMFResetHHistory(J);CHKERRQ(ierr); 437 ierr = MatShellGetContext(J,(void **)&ctx);CHKERRQ(ierr); 438 ctx->current_u = U; 439 ctx->usesnes = PETSC_FALSE; 440 PetscFunctionReturn(0); 441 } 442 EXTERN_C_END 443 444 #undef __FUNCT__ 445 #define __FUNCT__ "MatCreateMF" 446 /*@C 447 MatCreateMF - Creates a matrix-free matrix. See also MatCreateSNESMF() 448 449 Collective on Vec 450 451 Input Parameters: 452 . x - vector that defines layout of the vectors and matrices 453 454 Output Parameter: 455 . J - the matrix-free matrix 456 457 Level: advanced 458 459 Notes: 460 The matrix-free matrix context merely contains the function pointers 461 and work space for performing finite difference approximations of 462 Jacobian-vector products, F'(u)*a, 463 464 The default code uses the following approach to compute h 465 466 .vb 467 F'(u)*a = [F(u+h*a) - F(u)]/h where 468 h = error_rel*u'a/||a||^2 if |u'a| > umin*||a||_{1} 469 = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2 otherwise 470 where 471 error_rel = square root of relative error in function evaluation 472 umin = minimum iterate parameter 473 .ve 474 475 The user can set the error_rel via MatSNESMFSetFunctionError() and 476 umin via MatSNESMFDefaultSetUmin(); see the nonlinear solvers chapter 477 of the users manual for details. 478 479 The user should call MatDestroy() when finished with the matrix-free 480 matrix context. 481 482 Options Database Keys: 483 + -snes_mf_err <error_rel> - Sets error_rel 484 . -snes_mf_unim <umin> - Sets umin (for default PETSc routine that computes h only) 485 - -snes_mf_ksp_monitor - KSP monitor routine that prints differencing h 486 487 .keywords: default, matrix-free, create, matrix 488 489 .seealso: MatDestroy(), MatSNESMFSetFunctionError(), MatSNESMFDefaultSetUmin() 490 MatSNESMFSetHHistory(), MatSNESMFResetHHistory(), MatCreateSNESMF(), 491 MatSNESMFGetH(),MatSNESMFKSPMonitor(), MatSNESMFRegisterDynamic),, MatSNESMFComputeJacobian() 492 493 @*/ 494 int MatCreateMF(Vec x,Mat *J) 495 { 496 MPI_Comm comm; 497 MatSNESMFCtx mfctx; 498 int n,nloc,ierr; 499 500 PetscFunctionBegin; 501 ierr = PetscObjectGetComm((PetscObject)x,&comm);CHKERRQ(ierr); 502 PetscHeaderCreate(mfctx,_p_MatSNESMFCtx,struct _MFOps,MATSNESMFCTX_COOKIE,0,"SNESMF",comm,MatSNESMFDestroy_Private,MatSNESMFView_Private); 503 PetscLogObjectCreate(mfctx); 504 mfctx->sp = 0; 505 mfctx->snes = 0; 506 mfctx->error_rel = 1.e-8; /* assumes PetscReal precision */ 507 mfctx->recomputeperiod = 1; 508 mfctx->count = 0; 509 mfctx->currenth = 0.0; 510 mfctx->historyh = PETSC_NULL; 511 mfctx->ncurrenth = 0; 512 mfctx->maxcurrenth = 0; 513 mfctx->type_name = 0; 514 mfctx->usesnes = PETSC_FALSE; 515 516 /* 517 Create the empty data structure to contain compute-h routines. 518 These will be filled in below from the command line options or 519 a later call with MatSNESMFSetType() or if that is not called 520 then it will default in the first use of MatSNESMFMult_private() 521 */ 522 mfctx->ops->compute = 0; 523 mfctx->ops->destroy = 0; 524 mfctx->ops->view = 0; 525 mfctx->ops->setfromoptions = 0; 526 mfctx->hctx = 0; 527 528 mfctx->func = 0; 529 mfctx->funcctx = 0; 530 mfctx->funcvec = 0; 531 532 ierr = VecDuplicate(x,&mfctx->w);CHKERRQ(ierr); 533 ierr = VecGetSize(mfctx->w,&n);CHKERRQ(ierr); 534 ierr = VecGetLocalSize(mfctx->w,&nloc);CHKERRQ(ierr); 535 ierr = MatCreateShell(comm,nloc,nloc,n,n,mfctx,J);CHKERRQ(ierr); 536 ierr = MatShellSetOperation(*J,MATOP_MULT,(void(*)())MatSNESMFMult_Private);CHKERRQ(ierr); 537 ierr = MatShellSetOperation(*J,MATOP_DESTROY,(void(*)())MatSNESMFDestroy_Private);CHKERRQ(ierr); 538 ierr = MatShellSetOperation(*J,MATOP_VIEW,(void(*)())MatSNESMFView_Private);CHKERRQ(ierr); 539 ierr = MatShellSetOperation(*J,MATOP_ASSEMBLY_END,(void(*)())MatSNESMFAssemblyEnd_Private);CHKERRQ(ierr); 540 ierr = MatShellSetOperation(*J,MATOP_GET_DIAGONAL,(void(*)())MatSNESMFGetDiagonal_Private);CHKERRQ(ierr); 541 ierr = PetscObjectComposeFunctionDynamic((PetscObject)*J,"MatSNESMFSetBase_C","MatSNESMFSetBase_FD",MatSNESMFSetBase_FD);CHKERRQ(ierr); 542 PetscLogObjectParent(*J,mfctx->w); 543 544 mfctx->mat = *J; 545 PetscFunctionReturn(0); 546 } 547 548 #undef __FUNCT__ 549 #define __FUNCT__ "MatSNESMFSetFromOptions" 550 /*@ 551 MatSNESMFSetFromOptions - Sets the MatSNESMF options from the command line 552 parameter. 553 554 Collective on Mat 555 556 Input Parameters: 557 . mat - the matrix obtained with MatCreateSNESMF() 558 559 Options Database Keys: 560 + -snes_mf_type - <default,wp> 561 - -snes_mf_err - square root of estimated relative error in function evaluation 562 - -snes_mf_period - how often h is recomputed, defaults to 1, everytime 563 564 Level: advanced 565 566 .keywords: SNES, matrix-free, parameters 567 568 .seealso: MatCreateSNESMF(),MatSNESMFSetHHistory(), 569 MatSNESMFResetHHistory(), MatSNESMFKSPMonitor() 570 @*/ 571 int MatSNESMFSetFromOptions(Mat mat) 572 { 573 MatSNESMFCtx mfctx; 574 int ierr; 575 PetscTruth flg; 576 char ftype[256]; 577 578 PetscFunctionBegin; 579 ierr = MatShellGetContext(mat,(void **)&mfctx);CHKERRQ(ierr); 580 if (mfctx) { 581 if (!MatSNESMFRegisterAllCalled) {ierr = MatSNESMFRegisterAll(PETSC_NULL);CHKERRQ(ierr);} 582 583 ierr = PetscOptionsBegin(mfctx->comm,mfctx->prefix,"Set matrix free computation parameters","MatSNESMF");CHKERRQ(ierr); 584 ierr = PetscOptionsList("-snes_mf_type","Matrix free type","MatSNESMFSetType",MatSNESMPetscFList,mfctx->type_name,ftype,256,&flg);CHKERRQ(ierr); 585 if (flg) { 586 ierr = MatSNESMFSetType(mat,ftype);CHKERRQ(ierr); 587 } 588 589 ierr = PetscOptionsDouble("-snes_mf_err","set sqrt relative error in function","MatSNESMFSetFunctionError",mfctx->error_rel,&mfctx->error_rel,0);CHKERRQ(ierr); 590 ierr = PetscOptionsInt("-snes_mf_period","how often h is recomputed","MatSNESMFSetPeriod",mfctx->recomputeperiod,&mfctx->recomputeperiod,0);CHKERRQ(ierr); 591 if (mfctx->snes) { 592 ierr = PetscOptionsName("-snes_mf_ksp_monitor","Monitor matrix-free parameters","MatSNESMFKSPMonitor",&flg);CHKERRQ(ierr); 593 if (flg) { 594 SLES sles; 595 KSP ksp; 596 ierr = SNESGetSLES(mfctx->snes,&sles);CHKERRQ(ierr); 597 ierr = SLESGetKSP(sles,&ksp);CHKERRQ(ierr); 598 ierr = KSPSetMonitor(ksp,MatSNESMFKSPMonitor,PETSC_NULL,0);CHKERRQ(ierr); 599 } 600 } 601 if (mfctx->ops->setfromoptions) { 602 ierr = (*mfctx->ops->setfromoptions)(mfctx);CHKERRQ(ierr); 603 } 604 ierr = PetscOptionsEnd();CHKERRQ(ierr); 605 606 } 607 PetscFunctionReturn(0); 608 } 609 610 #undef __FUNCT__ 611 #define __FUNCT__ "MatSNESMFGetH" 612 /*@ 613 MatSNESMFGetH - Gets the last value that was used as the differencing 614 parameter. 615 616 Not Collective 617 618 Input Parameters: 619 . mat - the matrix obtained with MatCreateSNESMF() 620 621 Output Paramter: 622 . h - the differencing step size 623 624 Level: advanced 625 626 .keywords: SNES, matrix-free, parameters 627 628 .seealso: MatCreateSNESMF(),MatSNESMFSetHHistory(), 629 MatSNESMFResetHHistory(),MatSNESMFKSPMonitor() 630 @*/ 631 int MatSNESMFGetH(Mat mat,Scalar *h) 632 { 633 MatSNESMFCtx ctx; 634 int ierr; 635 636 PetscFunctionBegin; 637 ierr = MatShellGetContext(mat,(void **)&ctx);CHKERRQ(ierr); 638 if (ctx) { 639 *h = ctx->currenth; 640 } 641 PetscFunctionReturn(0); 642 } 643 644 #undef __FUNCT__ 645 #define __FUNCT__ "MatSNESMFKSPMonitor" 646 /* 647 MatSNESMFKSPMonitor - A KSP monitor for use with the default PETSc 648 SNES matrix free routines. Prints the differencing parameter used at 649 each step. 650 */ 651 int MatSNESMFKSPMonitor(KSP ksp,int n,PetscReal rnorm,void *dummy) 652 { 653 PC pc; 654 MatSNESMFCtx ctx; 655 int ierr; 656 Mat mat; 657 MPI_Comm comm; 658 PetscTruth nonzeroinitialguess; 659 660 PetscFunctionBegin; 661 ierr = PetscObjectGetComm((PetscObject)ksp,&comm);CHKERRQ(ierr); 662 ierr = KSPGetPC(ksp,&pc);CHKERRQ(ierr); 663 ierr = KSPGetInitialGuessNonzero(ksp,&nonzeroinitialguess);CHKERRQ(ierr); 664 ierr = PCGetOperators(pc,&mat,PETSC_NULL,PETSC_NULL);CHKERRQ(ierr); 665 ierr = MatShellGetContext(mat,(void **)&ctx);CHKERRQ(ierr); 666 if (!ctx) { 667 SETERRQ(1,"Matrix is not a matrix free shell matrix"); 668 } 669 if (n > 0 || nonzeroinitialguess) { 670 #if defined(PETSC_USE_COMPLEX) 671 ierr = PetscPrintf(comm,"%d KSP Residual norm %14.12e h %g + %g i\n",n,rnorm, 672 PetscRealPart(ctx->currenth),PetscImaginaryPart(ctx->currenth));CHKERRQ(ierr); 673 #else 674 ierr = PetscPrintf(comm,"%d KSP Residual norm %14.12e h %g \n",n,rnorm,ctx->currenth);CHKERRQ(ierr); 675 #endif 676 } else { 677 ierr = PetscPrintf(comm,"%d KSP Residual norm %14.12e\n",n,rnorm);CHKERRQ(ierr); 678 } 679 PetscFunctionReturn(0); 680 } 681 682 #undef __FUNCT__ 683 #define __FUNCT__ "MatSNESMFSetFunction" 684 /*@C 685 MatSNESMFSetFunction - Sets the function used in applying the matrix free. 686 687 Collective on Mat 688 689 Input Parameters: 690 + mat - the matrix free matrix created via MatCreateSNESMF() 691 . v - workspace vector 692 . func - the function to use 693 - funcctx - optional function context passed to function 694 695 Level: advanced 696 697 Notes: 698 If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free 699 matrix inside your compute Jacobian routine 700 701 If this is not set then it will use the function set with SNESSetFunction() 702 703 .keywords: SNES, matrix-free, function 704 705 .seealso: MatCreateSNESMF(),MatSNESMFGetH(), 706 MatSNESMFSetHHistory(), MatSNESMFResetHHistory(), 707 MatSNESMFKSPMonitor(), SNESetFunction() 708 @*/ 709 int MatSNESMFSetFunction(Mat mat,Vec v,int (*func)(SNES,Vec,Vec,void *),void *funcctx) 710 { 711 MatSNESMFCtx ctx; 712 int ierr; 713 714 PetscFunctionBegin; 715 ierr = MatShellGetContext(mat,(void **)&ctx);CHKERRQ(ierr); 716 if (ctx) { 717 ctx->func = func; 718 ctx->funcctx = funcctx; 719 ctx->funcvec = v; 720 } 721 PetscFunctionReturn(0); 722 } 723 724 #undef __FUNCT__ 725 #define __FUNCT__ "MatSNESMFSetFunctioni" 726 /*@C 727 MatSNESMFSetFunctioni - Sets the function for a single component 728 729 Collective on Mat 730 731 Input Parameters: 732 + mat - the matrix free matrix created via MatCreateSNESMF() 733 - funci - the function to use 734 735 Level: advanced 736 737 Notes: 738 If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free 739 matrix inside your compute Jacobian routine 740 741 742 .keywords: SNES, matrix-free, function 743 744 .seealso: MatCreateSNESMF(),MatSNESMFGetH(), 745 MatSNESMFSetHHistory(), MatSNESMFResetHHistory(), 746 MatSNESMFKSPMonitor(), SNESetFunction() 747 @*/ 748 int MatSNESMFSetFunctioni(Mat mat,int (*funci)(int,Vec,Scalar*,void *)) 749 { 750 MatSNESMFCtx ctx; 751 int ierr; 752 753 PetscFunctionBegin; 754 ierr = MatShellGetContext(mat,(void **)&ctx);CHKERRQ(ierr); 755 if (ctx) { 756 ctx->funci = funci; 757 } 758 PetscFunctionReturn(0); 759 } 760 761 #undef __FUNCT__ 762 #define __FUNCT__ "MatSNESMFSetFunctioniBase" 763 /*@C 764 MatSNESMFSetFunctioniBase - Sets the base vector for a single component function evaluation 765 766 Collective on Mat 767 768 Input Parameters: 769 + mat - the matrix free matrix created via MatCreateSNESMF() 770 - func - the function to use 771 772 Level: advanced 773 774 Notes: 775 If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free 776 matrix inside your compute Jacobian routine 777 778 779 .keywords: SNES, matrix-free, function 780 781 .seealso: MatCreateSNESMF(),MatSNESMFGetH(), 782 MatSNESMFSetHHistory(), MatSNESMFResetHHistory(), 783 MatSNESMFKSPMonitor(), SNESetFunction() 784 @*/ 785 int MatSNESMFSetFunctioniBase(Mat mat,int (*func)(Vec,void *)) 786 { 787 MatSNESMFCtx ctx; 788 int ierr; 789 790 PetscFunctionBegin; 791 ierr = MatShellGetContext(mat,(void **)&ctx);CHKERRQ(ierr); 792 if (ctx) { 793 ctx->funcisetbase = func; 794 } 795 PetscFunctionReturn(0); 796 } 797 798 799 #undef __FUNCT__ 800 #define __FUNCT__ "MatSNESMFSetPeriod" 801 /*@ 802 MatSNESMFSetPeriod - Sets how often h is recomputed, by default it is everytime 803 804 Collective on Mat 805 806 Input Parameters: 807 + mat - the matrix free matrix created via MatCreateSNESMF() 808 - period - 1 for everytime, 2 for every second etc 809 810 Options Database Keys: 811 + -snes_mf_period <period> 812 813 Level: advanced 814 815 816 .keywords: SNES, matrix-free, parameters 817 818 .seealso: MatCreateSNESMF(),MatSNESMFGetH(), 819 MatSNESMFSetHHistory(), MatSNESMFResetHHistory(), 820 MatSNESMFKSPMonitor() 821 @*/ 822 int MatSNESMFSetPeriod(Mat mat,int period) 823 { 824 MatSNESMFCtx ctx; 825 int ierr; 826 827 PetscFunctionBegin; 828 ierr = MatShellGetContext(mat,(void **)&ctx);CHKERRQ(ierr); 829 if (ctx) { 830 ctx->recomputeperiod = period; 831 } 832 PetscFunctionReturn(0); 833 } 834 835 #undef __FUNCT__ 836 #define __FUNCT__ "MatSNESMFSetFunctionError" 837 /*@ 838 MatSNESMFSetFunctionError - Sets the error_rel for the approximation of 839 matrix-vector products using finite differences. 840 841 Collective on Mat 842 843 Input Parameters: 844 + mat - the matrix free matrix created via MatCreateSNESMF() 845 - error_rel - relative error (should be set to the square root of 846 the relative error in the function evaluations) 847 848 Options Database Keys: 849 + -snes_mf_err <error_rel> - Sets error_rel 850 851 Level: advanced 852 853 Notes: 854 The default matrix-free matrix-vector product routine computes 855 .vb 856 F'(u)*a = [F(u+h*a) - F(u)]/h where 857 h = error_rel*u'a/||a||^2 if |u'a| > umin*||a||_{1} 858 = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2 else 859 .ve 860 861 .keywords: SNES, matrix-free, parameters 862 863 .seealso: MatCreateSNESMF(),MatSNESMFGetH(), 864 MatSNESMFSetHHistory(), MatSNESMFResetHHistory(), 865 MatSNESMFKSPMonitor() 866 @*/ 867 int MatSNESMFSetFunctionError(Mat mat,PetscReal error) 868 { 869 MatSNESMFCtx ctx; 870 int ierr; 871 872 PetscFunctionBegin; 873 ierr = MatShellGetContext(mat,(void **)&ctx);CHKERRQ(ierr); 874 if (ctx) { 875 if (error != PETSC_DEFAULT) ctx->error_rel = error; 876 } 877 PetscFunctionReturn(0); 878 } 879 880 #undef __FUNCT__ 881 #define __FUNCT__ "MatSNESMFAddNullSpace" 882 /*@ 883 MatSNESMFAddNullSpace - Provides a null space that an operator is 884 supposed to have. Since roundoff will create a small component in 885 the null space, if you know the null space you may have it 886 automatically removed. 887 888 Collective on Mat 889 890 Input Parameters: 891 + J - the matrix-free matrix context 892 - nullsp - object created with MatNullSpaceCreate() 893 894 Level: advanced 895 896 .keywords: SNES, matrix-free, null space 897 898 .seealso: MatNullSpaceCreate(), MatSNESMFGetH(), MatCreateSNESMF(), 899 MatSNESMFSetHHistory(), MatSNESMFResetHHistory(), 900 MatSNESMFKSPMonitor(), MatSNESMFErrorRel() 901 @*/ 902 int MatSNESMFAddNullSpace(Mat J,MatNullSpace nullsp) 903 { 904 int ierr; 905 MatSNESMFCtx ctx; 906 MPI_Comm comm; 907 908 PetscFunctionBegin; 909 ierr = PetscObjectGetComm((PetscObject)J,&comm);CHKERRQ(ierr); 910 911 ierr = MatShellGetContext(J,(void **)&ctx);CHKERRQ(ierr); 912 /* no context indicates that it is not the "matrix free" matrix type */ 913 if (!ctx) PetscFunctionReturn(0); 914 ctx->sp = nullsp; 915 ierr = PetscObjectReference((PetscObject)nullsp);CHKERRQ(ierr); 916 PetscFunctionReturn(0); 917 } 918 919 #undef __FUNCT__ 920 #define __FUNCT__ "MatSNESMFSetHHistory" 921 /*@ 922 MatSNESMFSetHHistory - Sets an array to collect a history of the 923 differencing values (h) computed for the matrix-free product. 924 925 Collective on Mat 926 927 Input Parameters: 928 + J - the matrix-free matrix context 929 . histroy - space to hold the history 930 - nhistory - number of entries in history, if more entries are generated than 931 nhistory, then the later ones are discarded 932 933 Level: advanced 934 935 Notes: 936 Use MatSNESMFResetHHistory() to reset the history counter and collect 937 a new batch of differencing parameters, h. 938 939 .keywords: SNES, matrix-free, h history, differencing history 940 941 .seealso: MatSNESMFGetH(), MatCreateSNESMF(), 942 MatSNESMFResetHHistory(), 943 MatSNESMFKSPMonitor(), MatSNESMFSetFunctionError() 944 945 @*/ 946 int MatSNESMFSetHHistory(Mat J,Scalar *history,int nhistory) 947 { 948 int ierr; 949 MatSNESMFCtx ctx; 950 951 PetscFunctionBegin; 952 953 ierr = MatShellGetContext(J,(void **)&ctx);CHKERRQ(ierr); 954 /* no context indicates that it is not the "matrix free" matrix type */ 955 if (!ctx) PetscFunctionReturn(0); 956 ctx->historyh = history; 957 ctx->maxcurrenth = nhistory; 958 ctx->currenth = 0; 959 960 PetscFunctionReturn(0); 961 } 962 963 #undef __FUNCT__ 964 #define __FUNCT__ "MatSNESMFResetHHistory" 965 /*@ 966 MatSNESMFResetHHistory - Resets the counter to zero to begin 967 collecting a new set of differencing histories. 968 969 Collective on Mat 970 971 Input Parameters: 972 . J - the matrix-free matrix context 973 974 Level: advanced 975 976 Notes: 977 Use MatSNESMFSetHHistory() to create the original history counter. 978 979 .keywords: SNES, matrix-free, h history, differencing history 980 981 .seealso: MatSNESMFGetH(), MatCreateSNESMF(), 982 MatSNESMFSetHHistory(), 983 MatSNESMFKSPMonitor(), MatSNESMFSetFunctionError() 984 985 @*/ 986 int MatSNESMFResetHHistory(Mat J) 987 { 988 int ierr; 989 MatSNESMFCtx ctx; 990 991 PetscFunctionBegin; 992 993 ierr = MatShellGetContext(J,(void **)&ctx);CHKERRQ(ierr); 994 /* no context indicates that it is not the "matrix free" matrix type */ 995 if (!ctx) PetscFunctionReturn(0); 996 ctx->ncurrenth = 0; 997 998 PetscFunctionReturn(0); 999 } 1000 1001 #undef __FUNCT__ 1002 #define __FUNCT__ "MatSNESMFComputeJacobian" 1003 int MatSNESMFComputeJacobian(SNES snes,Vec x,Mat *jac,Mat *B,MatStructure *flag,void *dummy) 1004 { 1005 int ierr; 1006 PetscFunctionBegin; 1007 ierr = MatAssemblyBegin(*jac,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 1008 ierr = MatAssemblyEnd(*jac,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 1009 PetscFunctionReturn(0); 1010 } 1011 1012 #undef __FUNCT__ 1013 #define __FUNCT__ "MatSNESMFSetBase" 1014 int MatSNESMFSetBase(Mat J,Vec U) 1015 { 1016 int ierr,(*f)(Mat,Vec); 1017 1018 PetscFunctionBegin; 1019 PetscValidHeaderSpecific(J,MAT_COOKIE); 1020 PetscValidHeaderSpecific(U,VEC_COOKIE); 1021 ierr = PetscObjectQueryFunction((PetscObject)J,"MatSNESMFSetBase_C",(void (**)())&f);CHKERRQ(ierr); 1022 if (f) { 1023 ierr = (*f)(J,U);CHKERRQ(ierr); 1024 } 1025 PetscFunctionReturn(0); 1026 } 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036