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