1 /*$Id: snesmfj.c,v 1.115 2001/01/15 21:47:52 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 __FUNC__ 10 #define __FUNC__ "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,(int (**)(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 MatSNESMFRegisterDynamicchar *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 __FUNC__ 105 #define __FUNC__ "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,(int (*)(void*))function);CHKERRQ(ierr); 114 PetscFunctionReturn(0); 115 } 116 117 118 #undef __FUNC__ 119 #define __FUNC__ "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 __FUNC__ 147 #define __FUNC__ "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 __FUNC__ 163 #define __FUNC__ "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 __FUNC__ 195 #define __FUNC__ "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 223 #undef __FUNC__ 224 #define __FUNC__ "MatSNESMFMult_Private" 225 /* 226 MatSNESMFMult_Private - Default matrix-free form for Jacobian-vector 227 product, y = F'(u)*a: 228 229 y ~= (F(u + ha) - F(u))/h, 230 where F = nonlinear function, as set by SNESSetFunction() 231 u = current iterate 232 h = difference interval 233 */ 234 int MatSNESMFMult_Private(Mat mat,Vec a,Vec y) 235 { 236 MatSNESMFCtx ctx; 237 SNES snes; 238 Scalar h,mone = -1.0; 239 Vec w,U,F; 240 int ierr,(*eval_fct)(SNES,Vec,Vec)=0; 241 242 PetscFunctionBegin; 243 /* We log matrix-free matrix-vector products separately, so that we can 244 separate the performance monitoring from the cases that use conventional 245 storage. We may eventually modify event logging to associate events 246 with particular objects, hence alleviating the more general problem. */ 247 ierr = PetscLogEventBegin(MAT_MatrixFreeMult,a,y,0,0);CHKERRQ(ierr); 248 249 ierr = MatShellGetContext(mat,(void **)&ctx);CHKERRQ(ierr); 250 snes = ctx->snes; 251 w = ctx->w; 252 U = ctx->current_u; 253 254 /* 255 Compute differencing parameter 256 */ 257 if (!ctx->ops->compute) { 258 ierr = MatSNESMFSetType(mat,MATSNESMF_DEFAULT);CHKERRQ(ierr); 259 ierr = MatSNESMFSetFromOptions(mat);CHKERRQ(ierr); 260 } 261 ierr = (*ctx->ops->compute)(ctx,U,a,&h);CHKERRQ(ierr); 262 263 /* keep a record of the current differencing parameter h */ 264 ctx->currenth = h; 265 #if defined(PETSC_USE_COMPLEX) 266 PetscLogInfo(mat,"MatSNESMFMult_Private:Current differencing parameter: %g + %g i\n",PetscRealPart(h),PetscImaginaryPart(h)); 267 #else 268 PetscLogInfo(mat,"MatSNESMFMult_Private:Current differencing parameter: %15.12e\n",h); 269 #endif 270 if (ctx->historyh && ctx->ncurrenth < ctx->maxcurrenth) { 271 ctx->historyh[ctx->ncurrenth] = h; 272 } 273 ctx->ncurrenth++; 274 275 /* w = u + ha */ 276 ierr = VecWAXPY(&h,a,U,w);CHKERRQ(ierr); 277 278 if (ctx->usesnes) { 279 if (snes->method_class == SNES_NONLINEAR_EQUATIONS) { 280 eval_fct = SNESComputeFunction; 281 } else if (snes->method_class == SNES_UNCONSTRAINED_MINIMIZATION) { 282 eval_fct = SNESComputeGradient; 283 } else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Invalid method class"); 284 F = ctx->current_f; 285 if (!F) SETERRQ(1,"You must call MatAssembly() even on matrix-free matrices"); 286 ierr = (*eval_fct)(snes,w,y);CHKERRQ(ierr); 287 } else { 288 F = ctx->funcvec; 289 /* compute func(U) as base for differencing */ 290 if (ctx->ncurrenth == 1) { 291 ierr = (*ctx->func)(snes,U,F,ctx->funcctx);CHKERRQ(ierr); 292 } 293 ierr = (*ctx->func)(snes,w,y,ctx->funcctx);CHKERRQ(ierr); 294 } 295 296 ierr = VecAXPY(&mone,F,y);CHKERRQ(ierr); 297 h = 1.0/h; 298 ierr = VecScale(&h,y);CHKERRQ(ierr); 299 if (ctx->sp) {ierr = MatNullSpaceRemove(ctx->sp,y,PETSC_NULL);CHKERRQ(ierr);} 300 301 ierr = PetscLogEventEnd(MAT_MatrixFreeMult,a,y,0,0);CHKERRQ(ierr); 302 PetscFunctionReturn(0); 303 } 304 305 #undef __FUNC__ 306 #define __FUNC__ "MatCreateSNESMF" 307 /*@C 308 MatCreateSNESMF - Creates a matrix-free matrix context for use with 309 a SNES solver. This matrix can be used as the Jacobian argument for 310 the routine SNESSetJacobian(). 311 312 Collective on SNES and Vec 313 314 Input Parameters: 315 + snes - the SNES context 316 - x - vector where SNES solution is to be stored. 317 318 Output Parameter: 319 . J - the matrix-free matrix 320 321 Level: advanced 322 323 Notes: 324 The matrix-free matrix context merely contains the function pointers 325 and work space for performing finite difference approximations of 326 Jacobian-vector products, F'(u)*a, 327 328 The default code uses the following approach to compute h 329 330 .vb 331 F'(u)*a = [F(u+h*a) - F(u)]/h where 332 h = error_rel*u'a/||a||^2 if |u'a| > umin*||a||_{1} 333 = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2 otherwise 334 where 335 error_rel = square root of relative error in function evaluation 336 umin = minimum iterate parameter 337 .ve 338 339 The user can set the error_rel via MatSNESMFSetFunctionError() and 340 umin via MatSNESMFDefaultSetUmin(); see the nonlinear solvers chapter 341 of the users manual for details. 342 343 The user should call MatDestroy() when finished with the matrix-free 344 matrix context. 345 346 Options Database Keys: 347 + -snes_mf_err <error_rel> - Sets error_rel 348 . -snes_mf_unim <umin> - Sets umin (for default PETSc routine that computes h only) 349 - -snes_mf_ksp_monitor - KSP monitor routine that prints differencing h 350 351 .keywords: SNES, default, matrix-free, create, matrix 352 353 .seealso: MatDestroy(), MatSNESMFSetFunctionError(), MatSNESMFDefaultSetUmin() 354 MatSNESMFSetHHistory(), MatSNESMFResetHHistory(), MatCreateMF(), 355 MatSNESMFGetH(),MatSNESMFKSPMonitor(), MatSNESMFRegisterDynamic), MatSNESMFFormJacobian() 356 357 @*/ 358 int MatCreateSNESMF(SNES snes,Vec x,Mat *J) 359 { 360 MatSNESMFCtx mfctx; 361 int ierr; 362 363 PetscFunctionBegin; 364 ierr = MatCreateMF(x,J);CHKERRQ(ierr); 365 ierr = MatShellGetContext(*J,(void **)&mfctx);CHKERRQ(ierr); 366 mfctx->snes = snes; 367 mfctx->usesnes = PETSC_TRUE; 368 PetscLogObjectParent(snes,*J); 369 PetscFunctionReturn(0); 370 } 371 372 #undef __FUNC__ 373 #define __FUNC__ "MatCreateMF" 374 /*@C 375 MatCreateMF - Creates a matrix-free matrix. See also MatCreateSNESMF() 376 377 Collective on Vec 378 379 Input Parameters: 380 . x - vector that defines layout of the vectors and matrices 381 382 Output Parameter: 383 . J - the matrix-free matrix 384 385 Level: advanced 386 387 Notes: 388 The matrix-free matrix context merely contains the function pointers 389 and work space for performing finite difference approximations of 390 Jacobian-vector products, F'(u)*a, 391 392 The default code uses the following approach to compute h 393 394 .vb 395 F'(u)*a = [F(u+h*a) - F(u)]/h where 396 h = error_rel*u'a/||a||^2 if |u'a| > umin*||a||_{1} 397 = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2 otherwise 398 where 399 error_rel = square root of relative error in function evaluation 400 umin = minimum iterate parameter 401 .ve 402 403 The user can set the error_rel via MatSNESMFSetFunctionError() and 404 umin via MatSNESMFDefaultSetUmin(); see the nonlinear solvers chapter 405 of the users manual for details. 406 407 The user should call MatDestroy() when finished with the matrix-free 408 matrix context. 409 410 Options Database Keys: 411 + -snes_mf_err <error_rel> - Sets error_rel 412 . -snes_mf_unim <umin> - Sets umin (for default PETSc routine that computes h only) 413 - -snes_mf_ksp_monitor - KSP monitor routine that prints differencing h 414 415 .keywords: default, matrix-free, create, matrix 416 417 .seealso: MatDestroy(), MatSNESMFSetFunctionError(), MatSNESMFDefaultSetUmin() 418 MatSNESMFSetHHistory(), MatSNESMFResetHHistory(), MatCreateSNESMF(), 419 MatSNESMFGetH(),MatSNESMFKSPMonitor(), MatSNESMFRegisterDynamic),, MatSNESMFFormJacobian() 420 421 @*/ 422 int MatCreateMF(Vec x,Mat *J) 423 { 424 MPI_Comm comm; 425 MatSNESMFCtx mfctx; 426 int n,nloc,ierr; 427 428 PetscFunctionBegin; 429 ierr = PetscObjectGetComm((PetscObject)x,&comm);CHKERRQ(ierr); 430 PetscHeaderCreate(mfctx,_p_MatSNESMFCtx,struct _MFOps,MATSNESMFCTX_COOKIE,0,"SNESMF",comm,MatSNESMFDestroy_Private,MatSNESMFView_Private); 431 PetscLogObjectCreate(mfctx); 432 mfctx->sp = 0; 433 mfctx->snes = 0; 434 mfctx->error_rel = 1.e-8; /* assumes PetscReal precision */ 435 mfctx->recomputeperiod = 1; 436 mfctx->count = 0; 437 mfctx->currenth = 0.0; 438 mfctx->historyh = PETSC_NULL; 439 mfctx->ncurrenth = 0; 440 mfctx->maxcurrenth = 0; 441 mfctx->type_name = 0; 442 mfctx->usesnes = PETSC_FALSE; 443 444 /* 445 Create the empty data structure to contain compute-h routines. 446 These will be filled in below from the command line options or 447 a later call with MatSNESMFSetType() or if that is not called 448 then it will default in the first use of MatSNESMFMult_private() 449 */ 450 mfctx->ops->compute = 0; 451 mfctx->ops->destroy = 0; 452 mfctx->ops->view = 0; 453 mfctx->ops->setfromoptions = 0; 454 mfctx->hctx = 0; 455 456 mfctx->func = 0; 457 mfctx->funcctx = 0; 458 mfctx->funcvec = 0; 459 460 ierr = VecDuplicate(x,&mfctx->w);CHKERRQ(ierr); 461 ierr = VecGetSize(mfctx->w,&n);CHKERRQ(ierr); 462 ierr = VecGetLocalSize(mfctx->w,&nloc);CHKERRQ(ierr); 463 ierr = MatCreateShell(comm,nloc,nloc,n,n,mfctx,J);CHKERRQ(ierr); 464 ierr = MatShellSetOperation(*J,MATOP_MULT,(void*)MatSNESMFMult_Private);CHKERRQ(ierr); 465 ierr = MatShellSetOperation(*J,MATOP_DESTROY,(void *)MatSNESMFDestroy_Private);CHKERRQ(ierr); 466 ierr = MatShellSetOperation(*J,MATOP_VIEW,(void *)MatSNESMFView_Private);CHKERRQ(ierr); 467 ierr = MatShellSetOperation(*J,MATOP_ASSEMBLY_END,(void *)MatSNESMFAssemblyEnd_Private);CHKERRQ(ierr); 468 PetscLogObjectParent(*J,mfctx->w); 469 470 mfctx->mat = *J; 471 PetscFunctionReturn(0); 472 } 473 474 #undef __FUNC__ 475 #define __FUNC__ "MatSNESMFSetFromOptions" 476 /*@ 477 MatSNESMFSetFromOptions - Sets the MatSNESMF options from the command line 478 parameter. 479 480 Collective on Mat 481 482 Input Parameters: 483 . mat - the matrix obtained with MatCreateSNESMF() 484 485 Options Database Keys: 486 + -snes_mf_type - <default,wp> 487 - -snes_mf_err - square root of estimated relative error in function evaluation 488 - -snes_mf_period - how often h is recomputed, defaults to 1, everytime 489 490 Level: advanced 491 492 .keywords: SNES, matrix-free, parameters 493 494 .seealso: MatCreateSNESMF(),MatSNESMFSetHHistory(), 495 MatSNESMFResetHHistory(), MatSNESMFKSPMonitor() 496 @*/ 497 int MatSNESMFSetFromOptions(Mat mat) 498 { 499 MatSNESMFCtx mfctx; 500 int ierr; 501 PetscTruth flg; 502 char ftype[256]; 503 504 PetscFunctionBegin; 505 ierr = MatShellGetContext(mat,(void **)&mfctx);CHKERRQ(ierr); 506 if (mfctx) { 507 if (!MatSNESMFRegisterAllCalled) {ierr = MatSNESMFRegisterAll(PETSC_NULL);CHKERRQ(ierr);} 508 509 ierr = PetscOptionsBegin(mfctx->comm,mfctx->prefix,"Set matrix free computation parameters","MatSNESMF");CHKERRQ(ierr); 510 ierr = PetscOptionsList("-snes_mf_type","Matrix free type","MatSNESMFSetType",MatSNESMPetscFList,mfctx->type_name,ftype,256,&flg);CHKERRQ(ierr); 511 if (flg) { 512 ierr = MatSNESMFSetType(mat,ftype);CHKERRQ(ierr); 513 } 514 515 ierr = PetscOptionsDouble("-snes_mf_err","set sqrt relative error in function","MatSNESMFSetFunctionError",mfctx->error_rel,&mfctx->error_rel,0);CHKERRQ(ierr); 516 ierr = PetscOptionsInt("-snes_mf_period","how often h is recomputed","MatSNESMFSetPeriod",mfctx->recomputeperiod,&mfctx->recomputeperiod,0);CHKERRQ(ierr); 517 if (mfctx->snes) { 518 ierr = PetscOptionsName("-snes_mf_ksp_monitor","Monitor matrix-free parameters","MatSNESMFKSPMonitor",&flg);CHKERRQ(ierr); 519 if (flg) { 520 SLES sles; 521 KSP ksp; 522 ierr = SNESGetSLES(mfctx->snes,&sles);CHKERRQ(ierr); 523 ierr = SLESGetKSP(sles,&ksp);CHKERRQ(ierr); 524 ierr = KSPSetMonitor(ksp,MatSNESMFKSPMonitor,PETSC_NULL,0);CHKERRQ(ierr); 525 } 526 } 527 if (mfctx->ops->setfromoptions) { 528 ierr = (*mfctx->ops->setfromoptions)(mfctx);CHKERRQ(ierr); 529 } 530 ierr = PetscOptionsEnd();CHKERRQ(ierr); 531 532 } 533 PetscFunctionReturn(0); 534 } 535 536 #undef __FUNC__ 537 #define __FUNC__ "MatSNESMFGetH" 538 /*@ 539 MatSNESMFGetH - Gets the last value that was used as the differencing 540 parameter. 541 542 Not Collective 543 544 Input Parameters: 545 . mat - the matrix obtained with MatCreateSNESMF() 546 547 Output Paramter: 548 . h - the differencing step size 549 550 Level: advanced 551 552 .keywords: SNES, matrix-free, parameters 553 554 .seealso: MatCreateSNESMF(),MatSNESMFSetHHistory(), 555 MatSNESMFResetHHistory(),MatSNESMFKSPMonitor() 556 @*/ 557 int MatSNESMFGetH(Mat mat,Scalar *h) 558 { 559 MatSNESMFCtx ctx; 560 int ierr; 561 562 PetscFunctionBegin; 563 ierr = MatShellGetContext(mat,(void **)&ctx);CHKERRQ(ierr); 564 if (ctx) { 565 *h = ctx->currenth; 566 } 567 PetscFunctionReturn(0); 568 } 569 570 #undef __FUNC__ 571 #define __FUNC__ "MatSNESMFKSPMonitor" 572 /* 573 MatSNESMFKSPMonitor - A KSP monitor for use with the default PETSc 574 SNES matrix free routines. Prints the differencing parameter used at 575 each step. 576 */ 577 int MatSNESMFKSPMonitor(KSP ksp,int n,PetscReal rnorm,void *dummy) 578 { 579 PC pc; 580 MatSNESMFCtx ctx; 581 int ierr; 582 Mat mat; 583 MPI_Comm comm; 584 PetscTruth nonzeroinitialguess; 585 586 PetscFunctionBegin; 587 ierr = PetscObjectGetComm((PetscObject)ksp,&comm);CHKERRQ(ierr); 588 ierr = KSPGetPC(ksp,&pc);CHKERRQ(ierr); 589 ierr = KSPGetInitialGuessNonzero(ksp,&nonzeroinitialguess);CHKERRQ(ierr); 590 ierr = PCGetOperators(pc,&mat,PETSC_NULL,PETSC_NULL);CHKERRQ(ierr); 591 ierr = MatShellGetContext(mat,(void **)&ctx);CHKERRQ(ierr); 592 if (!ctx) { 593 SETERRQ(1,"Matrix is not a matrix free shell matrix"); 594 } 595 if (n > 0 || nonzeroinitialguess) { 596 #if defined(PETSC_USE_COMPLEX) 597 ierr = PetscPrintf(comm,"%d KSP Residual norm %14.12e h %g + %g i\n",n,rnorm, 598 PetscRealPart(ctx->currenth),PetscImaginaryPart(ctx->currenth));CHKERRQ(ierr); 599 #else 600 ierr = PetscPrintf(comm,"%d KSP Residual norm %14.12e h %g \n",n,rnorm,ctx->currenth);CHKERRQ(ierr); 601 #endif 602 } else { 603 ierr = PetscPrintf(comm,"%d KSP Residual norm %14.12e\n",n,rnorm);CHKERRQ(ierr); 604 } 605 PetscFunctionReturn(0); 606 } 607 608 #undef __FUNC__ 609 #define __FUNC__ "MatSNESMFSetFunction" 610 /*@C 611 MatSNESMFSetFunction - Sets the function used in applying the matrix free. 612 613 Collective on Mat 614 615 Input Parameters: 616 + mat - the matrix free matrix created via MatCreateSNESMF() 617 . v - workspace vector 618 . func - the function to use 619 - funcctx - optional function context passed to function 620 621 Level: advanced 622 623 Notes: 624 If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free 625 matrix inside your compute Jacobian routine 626 627 If this is not set then it will use the function set with SNESSetFunction() 628 629 .keywords: SNES, matrix-free, function 630 631 .seealso: MatCreateSNESMF(),MatSNESMFGetH(), 632 MatSNESMFSetHHistory(), MatSNESMFResetHHistory(), 633 MatSNESMFKSPMonitor(), SNESetFunction() 634 @*/ 635 int MatSNESMFSetFunction(Mat mat,Vec v,int (*func)(SNES,Vec,Vec,void *),void *funcctx) 636 { 637 MatSNESMFCtx ctx; 638 int ierr; 639 640 PetscFunctionBegin; 641 ierr = MatShellGetContext(mat,(void **)&ctx);CHKERRQ(ierr); 642 if (ctx) { 643 ctx->func = func; 644 ctx->funcctx = funcctx; 645 ctx->funcvec = v; 646 } 647 PetscFunctionReturn(0); 648 } 649 650 651 #undef __FUNC__ 652 #define __FUNC__ "MatSNESMFSetPeriod" 653 /*@ 654 MatSNESMFSetPeriod - Sets how often h is recomputed, by default it is everytime 655 656 Collective on Mat 657 658 Input Parameters: 659 + mat - the matrix free matrix created via MatCreateSNESMF() 660 - period - 1 for everytime, 2 for every second etc 661 662 Options Database Keys: 663 + -snes_mf_period <period> 664 665 Level: advanced 666 667 668 .keywords: SNES, matrix-free, parameters 669 670 .seealso: MatCreateSNESMF(),MatSNESMFGetH(), 671 MatSNESMFSetHHistory(), MatSNESMFResetHHistory(), 672 MatSNESMFKSPMonitor() 673 @*/ 674 int MatSNESMFSetPeriod(Mat mat,int period) 675 { 676 MatSNESMFCtx ctx; 677 int ierr; 678 679 PetscFunctionBegin; 680 ierr = MatShellGetContext(mat,(void **)&ctx);CHKERRQ(ierr); 681 if (ctx) { 682 ctx->recomputeperiod = period; 683 } 684 PetscFunctionReturn(0); 685 } 686 687 #undef __FUNC__ 688 #define __FUNC__ "MatSNESMFSetFunctionError" 689 /*@ 690 MatSNESMFSetFunctionError - Sets the error_rel for the approximation of 691 matrix-vector products using finite differences. 692 693 Collective on Mat 694 695 Input Parameters: 696 + mat - the matrix free matrix created via MatCreateSNESMF() 697 - error_rel - relative error (should be set to the square root of 698 the relative error in the function evaluations) 699 700 Options Database Keys: 701 + -snes_mf_err <error_rel> - Sets error_rel 702 703 Level: advanced 704 705 Notes: 706 The default matrix-free matrix-vector product routine computes 707 .vb 708 F'(u)*a = [F(u+h*a) - F(u)]/h where 709 h = error_rel*u'a/||a||^2 if |u'a| > umin*||a||_{1} 710 = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2 else 711 .ve 712 713 .keywords: SNES, matrix-free, parameters 714 715 .seealso: MatCreateSNESMF(),MatSNESMFGetH(), 716 MatSNESMFSetHHistory(), MatSNESMFResetHHistory(), 717 MatSNESMFKSPMonitor() 718 @*/ 719 int MatSNESMFSetFunctionError(Mat mat,PetscReal error) 720 { 721 MatSNESMFCtx ctx; 722 int ierr; 723 724 PetscFunctionBegin; 725 ierr = MatShellGetContext(mat,(void **)&ctx);CHKERRQ(ierr); 726 if (ctx) { 727 if (error != PETSC_DEFAULT) ctx->error_rel = error; 728 } 729 PetscFunctionReturn(0); 730 } 731 732 #undef __FUNC__ 733 #define __FUNC__ "MatSNESMFAddNullSpace" 734 /*@ 735 MatSNESMFAddNullSpace - Provides a null space that an operator is 736 supposed to have. Since roundoff will create a small component in 737 the null space, if you know the null space you may have it 738 automatically removed. 739 740 Collective on Mat 741 742 Input Parameters: 743 + J - the matrix-free matrix context 744 - nullsp - object created with MatNullSpaceCreate() 745 746 Level: advanced 747 748 .keywords: SNES, matrix-free, null space 749 750 .seealso: MatNullSpaceCreate(), MatSNESMFGetH(), MatCreateSNESMF(), 751 MatSNESMFSetHHistory(), MatSNESMFResetHHistory(), 752 MatSNESMFKSPMonitor(), MatSNESMFErrorRel() 753 @*/ 754 int MatSNESMFAddNullSpace(Mat J,MatNullSpace nullsp) 755 { 756 int ierr; 757 MatSNESMFCtx ctx; 758 MPI_Comm comm; 759 760 PetscFunctionBegin; 761 ierr = PetscObjectGetComm((PetscObject)J,&comm);CHKERRQ(ierr); 762 763 ierr = MatShellGetContext(J,(void **)&ctx);CHKERRQ(ierr); 764 /* no context indicates that it is not the "matrix free" matrix type */ 765 if (!ctx) PetscFunctionReturn(0); 766 ctx->sp = nullsp; 767 ierr = PetscObjectReference((PetscObject)nullsp);CHKERRQ(ierr); 768 PetscFunctionReturn(0); 769 } 770 771 #undef __FUNC__ 772 #define __FUNC__ "MatSNESMFSetHHistory" 773 /*@ 774 MatSNESMFSetHHistory - Sets an array to collect a history of the 775 differencing values (h) computed for the matrix-free product. 776 777 Collective on Mat 778 779 Input Parameters: 780 + J - the matrix-free matrix context 781 . histroy - space to hold the history 782 - nhistory - number of entries in history, if more entries are generated than 783 nhistory, then the later ones are discarded 784 785 Level: advanced 786 787 Notes: 788 Use MatSNESMFResetHHistory() to reset the history counter and collect 789 a new batch of differencing parameters, h. 790 791 .keywords: SNES, matrix-free, h history, differencing history 792 793 .seealso: MatSNESMFGetH(), MatCreateSNESMF(), 794 MatSNESMFResetHHistory(), 795 MatSNESMFKSPMonitor(), MatSNESMFSetFunctionError() 796 797 @*/ 798 int MatSNESMFSetHHistory(Mat J,Scalar *history,int nhistory) 799 { 800 int ierr; 801 MatSNESMFCtx ctx; 802 803 PetscFunctionBegin; 804 805 ierr = MatShellGetContext(J,(void **)&ctx);CHKERRQ(ierr); 806 /* no context indicates that it is not the "matrix free" matrix type */ 807 if (!ctx) PetscFunctionReturn(0); 808 ctx->historyh = history; 809 ctx->maxcurrenth = nhistory; 810 ctx->currenth = 0; 811 812 PetscFunctionReturn(0); 813 } 814 815 #undef __FUNC__ 816 #define __FUNC__ "MatSNESMFResetHHistory" 817 /*@ 818 MatSNESMFResetHHistory - Resets the counter to zero to begin 819 collecting a new set of differencing histories. 820 821 Collective on Mat 822 823 Input Parameters: 824 . J - the matrix-free matrix context 825 826 Level: advanced 827 828 Notes: 829 Use MatSNESMFSetHHistory() to create the original history counter. 830 831 .keywords: SNES, matrix-free, h history, differencing history 832 833 .seealso: MatSNESMFGetH(), MatCreateSNESMF(), 834 MatSNESMFSetHHistory(), 835 MatSNESMFKSPMonitor(), MatSNESMFSetFunctionError() 836 837 @*/ 838 int MatSNESMFResetHHistory(Mat J) 839 { 840 int ierr; 841 MatSNESMFCtx ctx; 842 843 PetscFunctionBegin; 844 845 ierr = MatShellGetContext(J,(void **)&ctx);CHKERRQ(ierr); 846 /* no context indicates that it is not the "matrix free" matrix type */ 847 if (!ctx) PetscFunctionReturn(0); 848 ctx->ncurrenth = 0; 849 850 PetscFunctionReturn(0); 851 } 852 853 #undef __FUNC__ 854 #define __FUNC__ "MatSNESMFFormJacobian" 855 int MatSNESMFFormJacobian(SNES snes,Vec x,Mat *jac,Mat *B,MatStructure *flag,void *dummy) 856 { 857 int ierr; 858 PetscFunctionBegin; 859 ierr = MatAssemblyBegin(*jac,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 860 ierr = MatAssemblyEnd(*jac,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 861 PetscFunctionReturn(0); 862 } 863 864 #undef __FUNC__ 865 #define __FUNC__ "MatSNESMFSetBase" 866 int MatSNESMFSetBase(Mat J,Vec U) 867 { 868 int ierr; 869 MatSNESMFCtx ctx; 870 871 PetscFunctionBegin; 872 PetscValidHeaderSpecific(J,MAT_COOKIE); 873 PetscValidHeaderSpecific(U,VEC_COOKIE); 874 875 ierr = MatShellGetContext(J,(void **)&ctx);CHKERRQ(ierr); 876 ctx->current_u = U; 877 ctx->usesnes = PETSC_FALSE; 878 PetscFunctionReturn(0); 879 } 880