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