1 /*$Id: snesmfj.c,v 1.131 2001/09/05 18:45:40 bsmith Exp $*/ 2 3 #include "src/mat/matimpl.h" 4 #include "src/snes/mf/snesmfj.h" /*I "petscsnes.h" I*/ 5 6 PetscFList MatSNESMPetscFList = 0; 7 PetscTruth MatSNESMFRegisterAllCalled = PETSC_FALSE; 8 9 #undef __FUNCT__ 10 #define __FUNCT__ "MatSNESMFSetType" 11 /*@C 12 MatSNESMFSetType - Sets the method that is used to compute the 13 differencing parameter for finite differene matrix-free formulations. 14 15 Input Parameters: 16 + mat - the "matrix-free" matrix created via MatCreateSNESMF(), 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,const 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 EXTERN_C_BEGIN 66 #undef __FUNCT__ 67 #define __FUNCT__ "MatSNESMFSetFunctioniBase_FD" 68 int MatSNESMFSetFunctioniBase_FD(Mat mat,int (*func)(Vec,void *)) 69 { 70 MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data; 71 72 PetscFunctionBegin; 73 ctx->funcisetbase = func; 74 PetscFunctionReturn(0); 75 } 76 EXTERN_C_END 77 78 EXTERN_C_BEGIN 79 #undef __FUNCT__ 80 #define __FUNCT__ "MatSNESMFSetFunctioni_FD" 81 int MatSNESMFSetFunctioni_FD(Mat mat,int (*funci)(int,Vec,PetscScalar*,void *)) 82 { 83 MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data; 84 85 PetscFunctionBegin; 86 ctx->funci = funci; 87 PetscFunctionReturn(0); 88 } 89 EXTERN_C_END 90 91 92 #undef __FUNCT__ 93 #define __FUNCT__ "MatSNESMFRegister" 94 int MatSNESMFRegister(const char sname[],const char path[],const char name[],int (*function)(MatSNESMFCtx)) 95 { 96 int ierr; 97 char fullname[256]; 98 99 PetscFunctionBegin; 100 ierr = PetscFListConcat(path,name,fullname);CHKERRQ(ierr); 101 ierr = PetscFListAdd(&MatSNESMPetscFList,sname,fullname,(void (*)(void))function);CHKERRQ(ierr); 102 PetscFunctionReturn(0); 103 } 104 105 106 #undef __FUNCT__ 107 #define __FUNCT__ "MatSNESMFRegisterDestroy" 108 /*@C 109 MatSNESMFRegisterDestroy - Frees the list of MatSNESMF methods that were 110 registered by MatSNESMFRegisterDynamic). 111 112 Not Collective 113 114 Level: developer 115 116 .keywords: MatSNESMF, register, destroy 117 118 .seealso: MatSNESMFRegisterDynamic), MatSNESMFRegisterAll() 119 @*/ 120 int MatSNESMFRegisterDestroy(void) 121 { 122 int ierr; 123 124 PetscFunctionBegin; 125 if (MatSNESMPetscFList) { 126 ierr = PetscFListDestroy(&MatSNESMPetscFList);CHKERRQ(ierr); 127 MatSNESMPetscFList = 0; 128 } 129 MatSNESMFRegisterAllCalled = PETSC_FALSE; 130 PetscFunctionReturn(0); 131 } 132 133 /* ----------------------------------------------------------------------------------------*/ 134 #undef __FUNCT__ 135 #define __FUNCT__ "MatDestroy_MFFD" 136 int MatDestroy_MFFD(Mat mat) 137 { 138 int ierr; 139 MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data; 140 141 PetscFunctionBegin; 142 if (ctx->w != PETSC_NULL) { 143 ierr = VecDestroy(ctx->w);CHKERRQ(ierr); 144 } 145 if (ctx->ops->destroy) {ierr = (*ctx->ops->destroy)(ctx);CHKERRQ(ierr);} 146 if (ctx->sp) {ierr = MatNullSpaceDestroy(ctx->sp);CHKERRQ(ierr);} 147 PetscHeaderDestroy(ctx); 148 PetscFunctionReturn(0); 149 } 150 151 #undef __FUNCT__ 152 #define __FUNCT__ "MatView_MFFD" 153 /* 154 MatSNESMFView_MFFD - Views matrix-free parameters. 155 156 */ 157 int MatView_MFFD(Mat J,PetscViewer viewer) 158 { 159 int ierr; 160 MatSNESMFCtx ctx = (MatSNESMFCtx)J->data; 161 PetscTruth isascii; 162 163 PetscFunctionBegin; 164 ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&isascii);CHKERRQ(ierr); 165 if (isascii) { 166 ierr = PetscViewerASCIIPrintf(viewer," SNES matrix-free approximation:\n");CHKERRQ(ierr); 167 ierr = PetscViewerASCIIPrintf(viewer," err=%g (relative error in function evaluation)\n",ctx->error_rel);CHKERRQ(ierr); 168 if (!ctx->type_name) { 169 ierr = PetscViewerASCIIPrintf(viewer," The compute h routine has not yet been set\n");CHKERRQ(ierr); 170 } else { 171 ierr = PetscViewerASCIIPrintf(viewer," Using %s compute h routine\n",ctx->type_name);CHKERRQ(ierr); 172 } 173 if (ctx->ops->view) { 174 ierr = (*ctx->ops->view)(ctx,viewer);CHKERRQ(ierr); 175 } 176 } else { 177 SETERRQ1(1,"Viewer type %s not supported for SNES matrix free matrix",((PetscObject)viewer)->type_name); 178 } 179 PetscFunctionReturn(0); 180 } 181 182 #undef __FUNCT__ 183 #define __FUNCT__ "MatAssemblyEnd_MFFD" 184 /* 185 MatSNESMFAssemblyEnd_Private - Resets the ctx->ncurrenth to zero. This 186 allows the user to indicate the beginning of a new linear solve by calling 187 MatAssemblyXXX() on the matrix free matrix. This then allows the 188 MatSNESMFCreate_WP() to properly compute ||U|| only the first time 189 in the linear solver rather than every time. 190 */ 191 int MatAssemblyEnd_MFFD(Mat J,MatAssemblyType mt) 192 { 193 int ierr; 194 MatSNESMFCtx j = (MatSNESMFCtx)J->data; 195 196 PetscFunctionBegin; 197 ierr = MatSNESMFResetHHistory(J);CHKERRQ(ierr); 198 if (j->usesnes) { 199 ierr = SNESGetSolution(j->snes,&j->current_u);CHKERRQ(ierr); 200 ierr = SNESGetFunction(j->snes,&j->current_f,PETSC_NULL,PETSC_NULL);CHKERRQ(ierr); 201 if (j->w == PETSC_NULL) { 202 ierr = VecDuplicate(j->current_u, &j->w);CHKERRQ(ierr); 203 } 204 } 205 j->vshift = 0.0; 206 j->vscale = 1.0; 207 PetscFunctionReturn(0); 208 } 209 210 #undef __FUNCT__ 211 #define __FUNCT__ "MatMult_MFFD" 212 /* 213 MatMult_MFFD - Default matrix-free form for Jacobian-vector product, y = F'(u)*a: 214 215 y ~= (F(u + ha) - F(u))/h, 216 where F = nonlinear function, as set by SNESSetFunction() 217 u = current iterate 218 h = difference interval 219 */ 220 int MatMult_MFFD(Mat mat,Vec a,Vec y) 221 { 222 MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data; 223 SNES snes; 224 PetscScalar h,mone = -1.0; 225 Vec w,U,F; 226 int ierr,(*eval_fct)(SNES,Vec,Vec)=0; 227 228 PetscFunctionBegin; 229 /* We log matrix-free matrix-vector products separately, so that we can 230 separate the performance monitoring from the cases that use conventional 231 storage. We may eventually modify event logging to associate events 232 with particular objects, hence alleviating the more general problem. */ 233 ierr = PetscLogEventBegin(MAT_MultMatrixFree,a,y,0,0);CHKERRQ(ierr); 234 235 snes = ctx->snes; 236 w = ctx->w; 237 U = ctx->current_u; 238 239 /* 240 Compute differencing parameter 241 */ 242 if (!ctx->ops->compute) { 243 ierr = MatSNESMFSetType(mat,MATSNESMF_WP);CHKERRQ(ierr); 244 ierr = MatSNESMFSetFromOptions(mat);CHKERRQ(ierr); 245 } 246 ierr = (*ctx->ops->compute)(ctx,U,a,&h);CHKERRQ(ierr); 247 248 if (ctx->checkh) { 249 ierr = (*ctx->checkh)(U,a,&h,ctx->checkhctx);CHKERRQ(ierr); 250 } 251 252 /* keep a record of the current differencing parameter h */ 253 ctx->currenth = h; 254 #if defined(PETSC_USE_COMPLEX) 255 PetscLogInfo(mat,"MatMult_MFFD:Current differencing parameter: %g + %g i\n",PetscRealPart(h),PetscImaginaryPart(h)); 256 #else 257 PetscLogInfo(mat,"MatMult_MFFD:Current differencing parameter: %15.12e\n",h); 258 #endif 259 if (ctx->historyh && ctx->ncurrenth < ctx->maxcurrenth) { 260 ctx->historyh[ctx->ncurrenth] = h; 261 } 262 ctx->ncurrenth++; 263 264 /* w = u + ha */ 265 ierr = VecWAXPY(&h,a,U,w);CHKERRQ(ierr); 266 267 if (ctx->usesnes) { 268 eval_fct = SNESComputeFunction; 269 F = ctx->current_f; 270 if (!F) SETERRQ(1,"You must call MatAssembly() even on matrix-free matrices"); 271 ierr = (*eval_fct)(snes,w,y);CHKERRQ(ierr); 272 } else { 273 F = ctx->funcvec; 274 /* compute func(U) as base for differencing */ 275 if (ctx->ncurrenth == 1) { 276 ierr = (*ctx->func)(snes,U,F,ctx->funcctx);CHKERRQ(ierr); 277 } 278 ierr = (*ctx->func)(snes,w,y,ctx->funcctx);CHKERRQ(ierr); 279 } 280 281 ierr = VecAXPY(&mone,F,y);CHKERRQ(ierr); 282 h = 1.0/h; 283 ierr = VecScale(&h,y);CHKERRQ(ierr); 284 285 286 if (ctx->vshift != 0.0 && ctx->vscale != 1.0) { 287 ierr = VecAXPBY(&ctx->vshift,&ctx->vscale,a,y);CHKERRQ(ierr); 288 } else if (ctx->vscale != 1.0) { 289 ierr = VecScale(&ctx->vscale,y);CHKERRQ(ierr); 290 } else if (ctx->vshift != 0.0) { 291 ierr = VecAXPY(&ctx->vshift,a,y);CHKERRQ(ierr); 292 } 293 294 if (ctx->sp) {ierr = MatNullSpaceRemove(ctx->sp,y,PETSC_NULL);CHKERRQ(ierr);} 295 296 ierr = PetscLogEventEnd(MAT_MultMatrixFree,a,y,0,0);CHKERRQ(ierr); 297 PetscFunctionReturn(0); 298 } 299 300 #undef __FUNCT__ 301 #define __FUNCT__ "MatGetDiagonal_MFFD" 302 /* 303 MatGetDiagonal_MFFD - 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 MatGetDiagonal_MFFD(Mat mat,Vec a) 311 { 312 MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data; 313 PetscScalar h,*aa,*ww,v; 314 PetscReal epsilon = PETSC_SQRT_MACHINE_EPSILON,umin = 100.0*PETSC_SQRT_MACHINE_EPSILON; 315 Vec w,U; 316 int i,ierr,rstart,rend; 317 318 PetscFunctionBegin; 319 if (!ctx->funci) { 320 SETERRQ(1,"Requirers calling MatSNESMFSetFunctioni() first"); 321 } 322 323 w = ctx->w; 324 U = ctx->current_u; 325 ierr = (*ctx->func)(0,U,a,ctx->funcctx);CHKERRQ(ierr); 326 ierr = (*ctx->funcisetbase)(U,ctx->funcctx);CHKERRQ(ierr); 327 ierr = VecCopy(U,w);CHKERRQ(ierr); 328 329 ierr = VecGetOwnershipRange(a,&rstart,&rend);CHKERRQ(ierr); 330 ierr = VecGetArray(a,&aa);CHKERRQ(ierr); 331 for (i=rstart; i<rend; i++) { 332 ierr = VecGetArray(w,&ww);CHKERRQ(ierr); 333 h = ww[i-rstart]; 334 if (h == 0.0) h = 1.0; 335 #if !defined(PETSC_USE_COMPLEX) 336 if (h < umin && h >= 0.0) h = umin; 337 else if (h < 0.0 && h > -umin) h = -umin; 338 #else 339 if (PetscAbsScalar(h) < umin && PetscRealPart(h) >= 0.0) h = umin; 340 else if (PetscRealPart(h) < 0.0 && PetscAbsScalar(h) < umin) h = -umin; 341 #endif 342 h *= epsilon; 343 344 ww[i-rstart] += h; 345 ierr = VecRestoreArray(w,&ww);CHKERRQ(ierr); 346 ierr = (*ctx->funci)(i,w,&v,ctx->funcctx);CHKERRQ(ierr); 347 aa[i-rstart] = (v - aa[i-rstart])/h; 348 349 /* possibly shift and scale result */ 350 aa[i - rstart] = ctx->vshift + ctx->vscale*aa[i-rstart]; 351 352 ierr = VecGetArray(w,&ww);CHKERRQ(ierr); 353 ww[i-rstart] -= h; 354 ierr = VecRestoreArray(w,&ww);CHKERRQ(ierr); 355 } 356 ierr = VecRestoreArray(a,&aa);CHKERRQ(ierr); 357 PetscFunctionReturn(0); 358 } 359 360 #undef __FUNCT__ 361 #define __FUNCT__ "MatShift_MFFD" 362 int MatShift_MFFD(const PetscScalar *a,Mat Y) 363 { 364 MatSNESMFCtx shell = (MatSNESMFCtx)Y->data; 365 PetscFunctionBegin; 366 shell->vshift += *a; 367 PetscFunctionReturn(0); 368 } 369 370 #undef __FUNCT__ 371 #define __FUNCT__ "MatScale_MFFD" 372 int MatScale_MFFD(const PetscScalar *a,Mat Y) 373 { 374 MatSNESMFCtx shell = (MatSNESMFCtx)Y->data; 375 PetscFunctionBegin; 376 shell->vscale *= *a; 377 PetscFunctionReturn(0); 378 } 379 380 381 #undef __FUNCT__ 382 #define __FUNCT__ "MatCreateSNESMF" 383 /*@C 384 MatCreateSNESMF - Creates a matrix-free matrix context for use with 385 a SNES solver. This matrix can be used as the Jacobian argument for 386 the routine SNESSetJacobian(). 387 388 Collective on SNES and Vec 389 390 Input Parameters: 391 + snes - the SNES context 392 - x - vector where SNES solution is to be stored. 393 394 Output Parameter: 395 . J - the matrix-free matrix 396 397 Level: advanced 398 399 Notes: 400 The matrix-free matrix context merely contains the function pointers 401 and work space for performing finite difference approximations of 402 Jacobian-vector products, F'(u)*a, 403 404 The default code uses the following approach to compute h 405 406 .vb 407 F'(u)*a = [F(u+h*a) - F(u)]/h where 408 h = error_rel*u'a/||a||^2 if |u'a| > umin*||a||_{1} 409 = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2 otherwise 410 where 411 error_rel = square root of relative error in function evaluation 412 umin = minimum iterate parameter 413 .ve 414 415 The user can set the error_rel via MatSNESMFSetFunctionError() and 416 umin via MatSNESMFDefaultSetUmin(); see the nonlinear solvers chapter 417 of the users manual for details. 418 419 The user should call MatDestroy() when finished with the matrix-free 420 matrix context. 421 422 Options Database Keys: 423 + -snes_mf_err <error_rel> - Sets error_rel 424 . -snes_mf_unim <umin> - Sets umin (for default PETSc routine that computes h only) 425 - -snes_mf_ksp_monitor - KSP monitor routine that prints differencing h 426 427 .keywords: SNES, default, matrix-free, create, matrix 428 429 .seealso: MatDestroy(), MatSNESMFSetFunctionError(), MatSNESMFDefaultSetUmin() 430 MatSNESMFSetHHistory(), MatSNESMFResetHHistory(), MatCreateMF(), 431 MatSNESMFGetH(),MatSNESMFKSPMonitor(), MatSNESMFRegisterDynamic), MatSNESMFComputeJacobian() 432 433 @*/ 434 int MatCreateSNESMF(SNES snes,Vec x,Mat *J) 435 { 436 MatSNESMFCtx mfctx; 437 int ierr; 438 439 PetscFunctionBegin; 440 ierr = MatCreateMF(x,J);CHKERRQ(ierr); 441 442 mfctx = (MatSNESMFCtx)(*J)->data; 443 mfctx->snes = snes; 444 mfctx->usesnes = PETSC_TRUE; 445 PetscLogObjectParent(snes,*J); 446 PetscFunctionReturn(0); 447 } 448 449 EXTERN_C_BEGIN 450 #undef __FUNCT__ 451 #define __FUNCT__ "MatSNESMFSetBase_FD" 452 int MatSNESMFSetBase_FD(Mat J,Vec U) 453 { 454 int ierr; 455 MatSNESMFCtx ctx = (MatSNESMFCtx)J->data; 456 457 PetscFunctionBegin; 458 ierr = MatSNESMFResetHHistory(J);CHKERRQ(ierr); 459 ctx->current_u = U; 460 ctx->usesnes = PETSC_FALSE; 461 if (ctx->w == PETSC_NULL) { 462 ierr = VecDuplicate(ctx->current_u, &ctx->w);CHKERRQ(ierr); 463 } 464 PetscFunctionReturn(0); 465 } 466 EXTERN_C_END 467 468 EXTERN_C_BEGIN 469 #undef __FUNCT__ 470 #define __FUNCT__ "MatSNESMFSetCheckh_FD" 471 int MatSNESMFSetCheckh_FD(Mat J,int (*fun)(Vec,Vec,PetscScalar*,void*),void*ectx) 472 { 473 MatSNESMFCtx ctx = (MatSNESMFCtx)J->data; 474 475 PetscFunctionBegin; 476 ctx->checkh = fun; 477 ctx->checkhctx = ectx; 478 PetscFunctionReturn(0); 479 } 480 EXTERN_C_END 481 482 #undef __FUNCT__ 483 #define __FUNCT__ "MatSNESMFSetFromOptions" 484 /*@ 485 MatSNESMFSetFromOptions - Sets the MatSNESMF options from the command line 486 parameter. 487 488 Collective on Mat 489 490 Input Parameters: 491 . mat - the matrix obtained with MatCreateSNESMF() 492 493 Options Database Keys: 494 + -snes_mf_type - <default,wp> 495 - -snes_mf_err - square root of estimated relative error in function evaluation 496 - -snes_mf_period - how often h is recomputed, defaults to 1, everytime 497 498 Level: advanced 499 500 .keywords: SNES, matrix-free, parameters 501 502 .seealso: MatCreateSNESMF(),MatSNESMFSetHHistory(), 503 MatSNESMFResetHHistory(), MatSNESMFKSPMonitor() 504 @*/ 505 int MatSNESMFSetFromOptions(Mat mat) 506 { 507 MatSNESMFCtx mfctx = (MatSNESMFCtx)mat->data; 508 int ierr; 509 PetscTruth flg; 510 char ftype[256]; 511 512 PetscFunctionBegin; 513 if (!MatSNESMFRegisterAllCalled) {ierr = MatSNESMFRegisterAll(PETSC_NULL);CHKERRQ(ierr);} 514 515 ierr = PetscOptionsBegin(mfctx->comm,mfctx->prefix,"Set matrix free computation parameters","MatSNESMF");CHKERRQ(ierr); 516 ierr = PetscOptionsList("-snes_mf_type","Matrix free type","MatSNESMFSetType",MatSNESMPetscFList,mfctx->type_name,ftype,256,&flg);CHKERRQ(ierr); 517 if (flg) { 518 ierr = MatSNESMFSetType(mat,ftype);CHKERRQ(ierr); 519 } 520 521 ierr = PetscOptionsReal("-snes_mf_err","set sqrt relative error in function","MatSNESMFSetFunctionError",mfctx->error_rel,&mfctx->error_rel,0);CHKERRQ(ierr); 522 ierr = PetscOptionsInt("-snes_mf_period","how often h is recomputed","MatSNESMFSetPeriod",mfctx->recomputeperiod,&mfctx->recomputeperiod,0);CHKERRQ(ierr); 523 if (mfctx->snes) { 524 ierr = PetscOptionsName("-snes_mf_ksp_monitor","Monitor matrix-free parameters","MatSNESMFKSPMonitor",&flg);CHKERRQ(ierr); 525 if (flg) { 526 KSP ksp; 527 ierr = SNESGetKSP(mfctx->snes,&ksp);CHKERRQ(ierr); 528 ierr = KSPSetMonitor(ksp,MatSNESMFKSPMonitor,PETSC_NULL,0);CHKERRQ(ierr); 529 } 530 } 531 ierr = PetscOptionsName("-snes_mf_check_positivity","Insure that U + h*a is nonnegative","MatSNESMFSetCheckh",&flg);CHKERRQ(ierr); 532 if (flg) { 533 ierr = MatSNESMFSetCheckh(mat,MatSNESMFCheckPositivity,0);CHKERRQ(ierr); 534 } 535 if (mfctx->ops->setfromoptions) { 536 ierr = (*mfctx->ops->setfromoptions)(mfctx);CHKERRQ(ierr); 537 } 538 ierr = PetscOptionsEnd();CHKERRQ(ierr); 539 PetscFunctionReturn(0); 540 } 541 542 EXTERN_C_BEGIN 543 /*MC 544 MATMFFD - MATMFFD = "mffd" - A matrix free matrix type. 545 546 Level: advanced 547 548 .seealso: MatCreateMF, MatCreateSNESMF 549 M*/ 550 551 #undef __FUNCT__ 552 #define __FUNCT__ "MatCreate_MFFD" 553 int MatCreate_MFFD(Mat A) 554 { 555 MatSNESMFCtx mfctx; 556 int ierr; 557 558 PetscFunctionBegin; 559 #ifndef PETSC_USE_DYNAMIC_LIBRARIES 560 ierr = SNESInitializePackage(PETSC_NULL); CHKERRQ(ierr); 561 #endif 562 563 PetscHeaderCreate(mfctx,_p_MatSNESMFCtx,struct _MFOps,MATSNESMFCTX_COOKIE,0,"SNESMF",A->comm,MatDestroy_MFFD,MatView_MFFD); 564 PetscLogObjectCreate(mfctx); 565 mfctx->sp = 0; 566 mfctx->snes = 0; 567 mfctx->error_rel = PETSC_SQRT_MACHINE_EPSILON; 568 mfctx->recomputeperiod = 1; 569 mfctx->count = 0; 570 mfctx->currenth = 0.0; 571 mfctx->historyh = PETSC_NULL; 572 mfctx->ncurrenth = 0; 573 mfctx->maxcurrenth = 0; 574 mfctx->type_name = 0; 575 mfctx->usesnes = PETSC_FALSE; 576 577 mfctx->vshift = 0.0; 578 mfctx->vscale = 1.0; 579 580 /* 581 Create the empty data structure to contain compute-h routines. 582 These will be filled in below from the command line options or 583 a later call with MatSNESMFSetType() or if that is not called 584 then it will default in the first use of MatMult_MFFD() 585 */ 586 mfctx->ops->compute = 0; 587 mfctx->ops->destroy = 0; 588 mfctx->ops->view = 0; 589 mfctx->ops->setfromoptions = 0; 590 mfctx->hctx = 0; 591 592 mfctx->func = 0; 593 mfctx->funcctx = 0; 594 mfctx->funcvec = 0; 595 mfctx->w = PETSC_NULL; 596 597 A->data = mfctx; 598 599 A->ops->mult = MatMult_MFFD; 600 A->ops->destroy = MatDestroy_MFFD; 601 A->ops->view = MatView_MFFD; 602 A->ops->assemblyend = MatAssemblyEnd_MFFD; 603 A->ops->getdiagonal = MatGetDiagonal_MFFD; 604 A->ops->scale = MatScale_MFFD; 605 A->ops->shift = MatShift_MFFD; 606 A->ops->setfromoptions = MatSNESMFSetFromOptions; 607 608 ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatSNESMFSetBase_C","MatSNESMFSetBase_FD",MatSNESMFSetBase_FD);CHKERRQ(ierr); 609 ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatSNESMFSetFunctioniBase_C","MatSNESMFSetFunctioniBase_FD",MatSNESMFSetFunctioniBase_FD);CHKERRQ(ierr); 610 ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatSNESMFSetFunctioni_C","MatSNESMFSetFunctioni_FD",MatSNESMFSetFunctioni_FD);CHKERRQ(ierr); 611 ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatSNESMFSetCheckh_C","MatSNESMFSetCheckh_FD",MatSNESMFSetCheckh_FD);CHKERRQ(ierr); 612 mfctx->mat = A; 613 614 PetscFunctionReturn(0); 615 } 616 EXTERN_C_END 617 618 #undef __FUNCT__ 619 #define __FUNCT__ "MatCreateMF" 620 /*@C 621 MatCreateMF - Creates a matrix-free matrix. See also MatCreateSNESMF() 622 623 Collective on Vec 624 625 Input Parameters: 626 . x - vector that defines layout of the vectors and matrices 627 628 Output Parameter: 629 . J - the matrix-free matrix 630 631 Level: advanced 632 633 Notes: 634 The matrix-free matrix context merely contains the function pointers 635 and work space for performing finite difference approximations of 636 Jacobian-vector products, F'(u)*a, 637 638 The default code uses the following approach to compute h 639 640 .vb 641 F'(u)*a = [F(u+h*a) - F(u)]/h where 642 h = error_rel*u'a/||a||^2 if |u'a| > umin*||a||_{1} 643 = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2 otherwise 644 where 645 error_rel = square root of relative error in function evaluation 646 umin = minimum iterate parameter 647 .ve 648 649 The user can set the error_rel via MatSNESMFSetFunctionError() and 650 umin via MatSNESMFDefaultSetUmin(); see the nonlinear solvers chapter 651 of the users manual for details. 652 653 The user should call MatDestroy() when finished with the matrix-free 654 matrix context. 655 656 Options Database Keys: 657 + -snes_mf_err <error_rel> - Sets error_rel 658 . -snes_mf_unim <umin> - Sets umin (for default PETSc routine that computes h only) 659 . -snes_mf_ksp_monitor - KSP monitor routine that prints differencing h 660 - -snes_mf_check_positivity 661 662 .keywords: default, matrix-free, create, matrix 663 664 .seealso: MatDestroy(), MatSNESMFSetFunctionError(), MatSNESMFDefaultSetUmin() 665 MatSNESMFSetHHistory(), MatSNESMFResetHHistory(), MatCreateSNESMF(), 666 MatSNESMFGetH(),MatSNESMFKSPMonitor(), MatSNESMFRegisterDynamic),, MatSNESMFComputeJacobian() 667 668 @*/ 669 int MatCreateMF(Vec x,Mat *J) 670 { 671 MPI_Comm comm; 672 int n,nloc,ierr; 673 674 PetscFunctionBegin; 675 ierr = PetscObjectGetComm((PetscObject)x,&comm);CHKERRQ(ierr); 676 ierr = VecGetSize(x,&n);CHKERRQ(ierr); 677 ierr = VecGetLocalSize(x,&nloc);CHKERRQ(ierr); 678 ierr = MatCreate(comm,nloc,nloc,n,n,J);CHKERRQ(ierr); 679 ierr = MatRegisterDynamic(MATMFFD,0,"MatCreate_MFFD",MatCreate_MFFD);CHKERRQ(ierr); 680 ierr = MatSetType(*J,MATMFFD);CHKERRQ(ierr); 681 PetscFunctionReturn(0); 682 } 683 684 685 #undef __FUNCT__ 686 #define __FUNCT__ "MatSNESMFGetH" 687 /*@ 688 MatSNESMFGetH - Gets the last value that was used as the differencing 689 parameter. 690 691 Not Collective 692 693 Input Parameters: 694 . mat - the matrix obtained with MatCreateSNESMF() 695 696 Output Paramter: 697 . h - the differencing step size 698 699 Level: advanced 700 701 .keywords: SNES, matrix-free, parameters 702 703 .seealso: MatCreateSNESMF(),MatSNESMFSetHHistory(), 704 MatSNESMFResetHHistory(),MatSNESMFKSPMonitor() 705 @*/ 706 int MatSNESMFGetH(Mat mat,PetscScalar *h) 707 { 708 MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data; 709 710 PetscFunctionBegin; 711 *h = ctx->currenth; 712 PetscFunctionReturn(0); 713 } 714 715 #undef __FUNCT__ 716 #define __FUNCT__ "MatSNESMFKSPMonitor" 717 /* 718 MatSNESMFKSPMonitor - A KSP monitor for use with the default PETSc 719 SNES matrix free routines. Prints the differencing parameter used at 720 each step. 721 */ 722 int MatSNESMFKSPMonitor(KSP ksp,int n,PetscReal rnorm,void *dummy) 723 { 724 PC pc; 725 MatSNESMFCtx ctx; 726 int ierr; 727 Mat mat; 728 MPI_Comm comm; 729 PetscTruth nonzeroinitialguess; 730 731 PetscFunctionBegin; 732 ierr = PetscObjectGetComm((PetscObject)ksp,&comm);CHKERRQ(ierr); 733 ierr = KSPGetPC(ksp,&pc);CHKERRQ(ierr); 734 ierr = KSPGetInitialGuessNonzero(ksp,&nonzeroinitialguess);CHKERRQ(ierr); 735 ierr = PCGetOperators(pc,&mat,PETSC_NULL,PETSC_NULL);CHKERRQ(ierr); 736 ctx = (MatSNESMFCtx)mat->data; 737 738 if (n > 0 || nonzeroinitialguess) { 739 #if defined(PETSC_USE_COMPLEX) 740 ierr = PetscPrintf(comm,"%d KSP Residual norm %14.12e h %g + %g i\n",n,rnorm, 741 PetscRealPart(ctx->currenth),PetscImaginaryPart(ctx->currenth));CHKERRQ(ierr); 742 #else 743 ierr = PetscPrintf(comm,"%d KSP Residual norm %14.12e h %g \n",n,rnorm,ctx->currenth);CHKERRQ(ierr); 744 #endif 745 } else { 746 ierr = PetscPrintf(comm,"%d KSP Residual norm %14.12e\n",n,rnorm);CHKERRQ(ierr); 747 } 748 PetscFunctionReturn(0); 749 } 750 751 EXTERN_C_BEGIN 752 #undef __FUNCT__ 753 #define __FUNCT__ "MatSNESMFSetFunction" 754 /*@C 755 MatSNESMFSetFunction - Sets the function used in applying the matrix free. 756 757 Collective on Mat 758 759 Input Parameters: 760 + mat - the matrix free matrix created via MatCreateSNESMF() 761 . v - workspace vector 762 . func - the function to use 763 - funcctx - optional function context passed to function 764 765 Level: advanced 766 767 Notes: 768 If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free 769 matrix inside your compute Jacobian routine 770 771 If this is not set then it will use the function set with SNESSetFunction() 772 773 .keywords: SNES, matrix-free, function 774 775 .seealso: MatCreateSNESMF(),MatSNESMFGetH(), 776 MatSNESMFSetHHistory(), MatSNESMFResetHHistory(), 777 MatSNESMFKSPMonitor(), SNESetFunction() 778 @*/ 779 int MatSNESMFSetFunction(Mat mat,Vec v,int (*func)(SNES,Vec,Vec,void *),void *funcctx) 780 { 781 MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data; 782 783 PetscFunctionBegin; 784 ctx->func = func; 785 ctx->funcctx = funcctx; 786 ctx->funcvec = v; 787 PetscFunctionReturn(0); 788 } 789 EXTERN_C_END 790 791 #undef __FUNCT__ 792 #define __FUNCT__ "MatSNESMFSetFunctioni" 793 /*@C 794 MatSNESMFSetFunctioni - Sets the function for a single component 795 796 Collective on Mat 797 798 Input Parameters: 799 + mat - the matrix free matrix created via MatCreateSNESMF() 800 - funci - the function to use 801 802 Level: advanced 803 804 Notes: 805 If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free 806 matrix inside your compute Jacobian routine 807 808 809 .keywords: SNES, matrix-free, function 810 811 .seealso: MatCreateSNESMF(),MatSNESMFGetH(), 812 MatSNESMFSetHHistory(), MatSNESMFResetHHistory(), 813 MatSNESMFKSPMonitor(), SNESetFunction() 814 @*/ 815 int MatSNESMFSetFunctioni(Mat mat,int (*funci)(int,Vec,PetscScalar*,void *)) 816 { 817 int ierr,(*f)(Mat,int (*)(int,Vec,PetscScalar*,void *)); 818 819 PetscFunctionBegin; 820 PetscValidHeaderSpecific(mat,MAT_COOKIE); 821 ierr = PetscObjectQueryFunction((PetscObject)mat,"MatSNESMFSetFunctioni_C",(void (**)(void))&f);CHKERRQ(ierr); 822 if (f) { 823 ierr = (*f)(mat,funci);CHKERRQ(ierr); 824 } 825 PetscFunctionReturn(0); 826 } 827 828 829 #undef __FUNCT__ 830 #define __FUNCT__ "MatSNESMFSetFunctioniBase" 831 /*@C 832 MatSNESMFSetFunctioniBase - Sets the base vector for a single component function evaluation 833 834 Collective on Mat 835 836 Input Parameters: 837 + mat - the matrix free matrix created via MatCreateSNESMF() 838 - func - the function to use 839 840 Level: advanced 841 842 Notes: 843 If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free 844 matrix inside your compute Jacobian routine 845 846 847 .keywords: SNES, matrix-free, function 848 849 .seealso: MatCreateSNESMF(),MatSNESMFGetH(), 850 MatSNESMFSetHHistory(), MatSNESMFResetHHistory(), 851 MatSNESMFKSPMonitor(), SNESetFunction() 852 @*/ 853 int MatSNESMFSetFunctioniBase(Mat mat,int (*func)(Vec,void *)) 854 { 855 int ierr,(*f)(Mat,int (*)(Vec,void *)); 856 857 PetscFunctionBegin; 858 PetscValidHeaderSpecific(mat,MAT_COOKIE); 859 ierr = PetscObjectQueryFunction((PetscObject)mat,"MatSNESMFSetFunctioniBase_C",(void (**)(void))&f);CHKERRQ(ierr); 860 if (f) { 861 ierr = (*f)(mat,func);CHKERRQ(ierr); 862 } 863 PetscFunctionReturn(0); 864 } 865 866 867 #undef __FUNCT__ 868 #define __FUNCT__ "MatSNESMFSetPeriod" 869 /*@ 870 MatSNESMFSetPeriod - Sets how often h is recomputed, by default it is everytime 871 872 Collective on Mat 873 874 Input Parameters: 875 + mat - the matrix free matrix created via MatCreateSNESMF() 876 - period - 1 for everytime, 2 for every second etc 877 878 Options Database Keys: 879 + -snes_mf_period <period> 880 881 Level: advanced 882 883 884 .keywords: SNES, matrix-free, parameters 885 886 .seealso: MatCreateSNESMF(),MatSNESMFGetH(), 887 MatSNESMFSetHHistory(), MatSNESMFResetHHistory(), 888 MatSNESMFKSPMonitor() 889 @*/ 890 int MatSNESMFSetPeriod(Mat mat,int period) 891 { 892 MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data; 893 894 PetscFunctionBegin; 895 ctx->recomputeperiod = period; 896 PetscFunctionReturn(0); 897 } 898 899 #undef __FUNCT__ 900 #define __FUNCT__ "MatSNESMFSetFunctionError" 901 /*@ 902 MatSNESMFSetFunctionError - Sets the error_rel for the approximation of 903 matrix-vector products using finite differences. 904 905 Collective on Mat 906 907 Input Parameters: 908 + mat - the matrix free matrix created via MatCreateSNESMF() 909 - error_rel - relative error (should be set to the square root of 910 the relative error in the function evaluations) 911 912 Options Database Keys: 913 + -snes_mf_err <error_rel> - Sets error_rel 914 915 Level: advanced 916 917 Notes: 918 The default matrix-free matrix-vector product routine computes 919 .vb 920 F'(u)*a = [F(u+h*a) - F(u)]/h where 921 h = error_rel*u'a/||a||^2 if |u'a| > umin*||a||_{1} 922 = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2 else 923 .ve 924 925 .keywords: SNES, matrix-free, parameters 926 927 .seealso: MatCreateSNESMF(),MatSNESMFGetH(), 928 MatSNESMFSetHHistory(), MatSNESMFResetHHistory(), 929 MatSNESMFKSPMonitor() 930 @*/ 931 int MatSNESMFSetFunctionError(Mat mat,PetscReal error) 932 { 933 MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data; 934 935 PetscFunctionBegin; 936 if (error != PETSC_DEFAULT) ctx->error_rel = error; 937 PetscFunctionReturn(0); 938 } 939 940 #undef __FUNCT__ 941 #define __FUNCT__ "MatSNESMFAddNullSpace" 942 /*@ 943 MatSNESMFAddNullSpace - Provides a null space that an operator is 944 supposed to have. Since roundoff will create a small component in 945 the null space, if you know the null space you may have it 946 automatically removed. 947 948 Collective on Mat 949 950 Input Parameters: 951 + J - the matrix-free matrix context 952 - nullsp - object created with MatNullSpaceCreate() 953 954 Level: advanced 955 956 .keywords: SNES, matrix-free, null space 957 958 .seealso: MatNullSpaceCreate(), MatSNESMFGetH(), MatCreateSNESMF(), 959 MatSNESMFSetHHistory(), MatSNESMFResetHHistory(), 960 MatSNESMFKSPMonitor(), MatSNESMFErrorRel() 961 @*/ 962 int MatSNESMFAddNullSpace(Mat J,MatNullSpace nullsp) 963 { 964 int ierr; 965 MatSNESMFCtx ctx = (MatSNESMFCtx)J->data; 966 MPI_Comm comm; 967 968 PetscFunctionBegin; 969 ierr = PetscObjectGetComm((PetscObject)J,&comm);CHKERRQ(ierr); 970 971 ctx->sp = nullsp; 972 ierr = PetscObjectReference((PetscObject)nullsp);CHKERRQ(ierr); 973 PetscFunctionReturn(0); 974 } 975 976 #undef __FUNCT__ 977 #define __FUNCT__ "MatSNESMFSetHHistory" 978 /*@ 979 MatSNESMFSetHHistory - Sets an array to collect a history of the 980 differencing values (h) computed for the matrix-free product. 981 982 Collective on Mat 983 984 Input Parameters: 985 + J - the matrix-free matrix context 986 . histroy - space to hold the history 987 - nhistory - number of entries in history, if more entries are generated than 988 nhistory, then the later ones are discarded 989 990 Level: advanced 991 992 Notes: 993 Use MatSNESMFResetHHistory() to reset the history counter and collect 994 a new batch of differencing parameters, h. 995 996 .keywords: SNES, matrix-free, h history, differencing history 997 998 .seealso: MatSNESMFGetH(), MatCreateSNESMF(), 999 MatSNESMFResetHHistory(), 1000 MatSNESMFKSPMonitor(), MatSNESMFSetFunctionError() 1001 1002 @*/ 1003 int MatSNESMFSetHHistory(Mat J,PetscScalar history[],int nhistory) 1004 { 1005 MatSNESMFCtx ctx = (MatSNESMFCtx)J->data; 1006 1007 PetscFunctionBegin; 1008 ctx->historyh = history; 1009 ctx->maxcurrenth = nhistory; 1010 ctx->currenth = 0; 1011 PetscFunctionReturn(0); 1012 } 1013 1014 #undef __FUNCT__ 1015 #define __FUNCT__ "MatSNESMFResetHHistory" 1016 /*@ 1017 MatSNESMFResetHHistory - Resets the counter to zero to begin 1018 collecting a new set of differencing histories. 1019 1020 Collective on Mat 1021 1022 Input Parameters: 1023 . J - the matrix-free matrix context 1024 1025 Level: advanced 1026 1027 Notes: 1028 Use MatSNESMFSetHHistory() to create the original history counter. 1029 1030 .keywords: SNES, matrix-free, h history, differencing history 1031 1032 .seealso: MatSNESMFGetH(), MatCreateSNESMF(), 1033 MatSNESMFSetHHistory(), 1034 MatSNESMFKSPMonitor(), MatSNESMFSetFunctionError() 1035 1036 @*/ 1037 int MatSNESMFResetHHistory(Mat J) 1038 { 1039 MatSNESMFCtx ctx = (MatSNESMFCtx)J->data; 1040 1041 PetscFunctionBegin; 1042 ctx->ncurrenth = 0; 1043 PetscFunctionReturn(0); 1044 } 1045 1046 #undef __FUNCT__ 1047 #define __FUNCT__ "MatSNESMFComputeJacobian" 1048 int MatSNESMFComputeJacobian(SNES snes,Vec x,Mat *jac,Mat *B,MatStructure *flag,void *dummy) 1049 { 1050 int ierr; 1051 PetscFunctionBegin; 1052 ierr = MatAssemblyBegin(*jac,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 1053 ierr = MatAssemblyEnd(*jac,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 1054 PetscFunctionReturn(0); 1055 } 1056 1057 #undef __FUNCT__ 1058 #define __FUNCT__ "MatSNESMFSetBase" 1059 /*@ 1060 MatSNESMFSetBase - Sets the vector U at which matrix vector products of the 1061 Jacobian are computed 1062 1063 Collective on Mat 1064 1065 Input Parameters: 1066 + J - the MatSNESMF matrix 1067 - U - the vector 1068 1069 Notes: This is rarely used directly 1070 1071 Level: advanced 1072 1073 @*/ 1074 int MatSNESMFSetBase(Mat J,Vec U) 1075 { 1076 int ierr,(*f)(Mat,Vec); 1077 1078 PetscFunctionBegin; 1079 PetscValidHeaderSpecific(J,MAT_COOKIE); 1080 PetscValidHeaderSpecific(U,VEC_COOKIE); 1081 ierr = PetscObjectQueryFunction((PetscObject)J,"MatSNESMFSetBase_C",(void (**)(void))&f);CHKERRQ(ierr); 1082 if (f) { 1083 ierr = (*f)(J,U);CHKERRQ(ierr); 1084 } 1085 PetscFunctionReturn(0); 1086 } 1087 1088 #undef __FUNCT__ 1089 #define __FUNCT__ "MatSNESMFSetCheckh" 1090 /*@C 1091 MatSNESMFSetCheckh - Sets a function that checks the computed h and adjusts 1092 it to satisfy some criteria 1093 1094 Collective on Mat 1095 1096 Input Parameters: 1097 + J - the MatSNESMF matrix 1098 . fun - the function that checks h 1099 - ctx - any context needed by the function 1100 1101 Options Database Keys: 1102 . -snes_mf_check_positivity 1103 1104 Level: advanced 1105 1106 Notes: For example, MatSNESMFSetCheckPositivity() insures that all entries 1107 of U + h*a are non-negative 1108 1109 .seealso: MatSNESMFSetCheckPositivity() 1110 @*/ 1111 int MatSNESMFSetCheckh(Mat J,int (*fun)(Vec,Vec,PetscScalar*,void*),void* ctx) 1112 { 1113 int ierr,(*f)(Mat,int (*)(Vec,Vec,PetscScalar*,void*),void*); 1114 1115 PetscFunctionBegin; 1116 PetscValidHeaderSpecific(J,MAT_COOKIE); 1117 ierr = PetscObjectQueryFunction((PetscObject)J,"MatSNESMFSetCheckh_C",(void (**)(void))&f);CHKERRQ(ierr); 1118 if (f) { 1119 ierr = (*f)(J,fun,ctx);CHKERRQ(ierr); 1120 } 1121 PetscFunctionReturn(0); 1122 } 1123 1124 #undef __FUNCT__ 1125 #define __FUNCT__ "MatSNESMFSetCheckPositivity" 1126 /*@ 1127 MatSNESMFCheckPositivity - Checks that all entries in U + h*a are positive or 1128 zero, decreases h until this is satisfied. 1129 1130 Collective on Vec 1131 1132 Input Parameters: 1133 + U - base vector that is added to 1134 . a - vector that is added 1135 . h - scaling factor on a 1136 - dummy - context variable (unused) 1137 1138 Options Database Keys: 1139 . -snes_mf_check_positivity 1140 1141 Level: advanced 1142 1143 Notes: This is rarely used directly, rather it is passed as an argument to 1144 MatSNESMFSetCheckh() 1145 1146 .seealso: MatSNESMFSetCheckh() 1147 @*/ 1148 int MatSNESMFCheckPositivity(Vec U,Vec a,PetscScalar *h,void *dummy) 1149 { 1150 PetscReal val, minval; 1151 PetscScalar *u_vec, *a_vec; 1152 int ierr, i, size; 1153 MPI_Comm comm; 1154 1155 PetscFunctionBegin; 1156 ierr = PetscObjectGetComm((PetscObject)U,&comm);CHKERRQ(ierr); 1157 ierr = VecGetArray(U,&u_vec);CHKERRQ(ierr); 1158 ierr = VecGetArray(a,&a_vec);CHKERRQ(ierr); 1159 ierr = VecGetLocalSize(U,&size);CHKERRQ(ierr); 1160 minval = PetscAbsScalar(*h*1.01); 1161 for(i=0;i<size;i++) { 1162 if (PetscRealPart(u_vec[i] + *h*a_vec[i]) <= 0.0) { 1163 val = PetscAbsScalar(u_vec[i]/a_vec[i]); 1164 if (val < minval) minval = val; 1165 } 1166 } 1167 ierr = VecRestoreArray(U,&u_vec);CHKERRQ(ierr); 1168 ierr = VecRestoreArray(a,&a_vec);CHKERRQ(ierr); 1169 ierr = PetscGlobalMin(&minval,&val,comm);CHKERRQ(ierr); 1170 if (val <= PetscAbsScalar(*h)) { 1171 PetscLogInfo(U,"MatSNESMFCheckPositivity: Scaling back h from %g to %g\n",PetscRealPart(*h),.99*val); 1172 if (PetscRealPart(*h) > 0.0) *h = 0.99*val; 1173 else *h = -0.99*val; 1174 } 1175 PetscFunctionReturn(0); 1176 } 1177 1178 1179 1180 1181 1182 1183 1184