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