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,1); 40 PetscValidCharPointer(ftype,2); 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 typedef int (*FCN1)(Vec,void*); /* force argument to next function to not be extern C*/ 66 EXTERN_C_BEGIN 67 #undef __FUNCT__ 68 #define __FUNCT__ "MatSNESMFSetFunctioniBase_FD" 69 int MatSNESMFSetFunctioniBase_FD(Mat mat,FCN1 func) 70 { 71 MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data; 72 73 PetscFunctionBegin; 74 ctx->funcisetbase = func; 75 PetscFunctionReturn(0); 76 } 77 EXTERN_C_END 78 79 typedef int (*FCN2)(int,Vec,PetscScalar*,void*); /* force argument to next function to not be extern C*/ 80 EXTERN_C_BEGIN 81 #undef __FUNCT__ 82 #define __FUNCT__ "MatSNESMFSetFunctioni_FD" 83 int MatSNESMFSetFunctioni_FD(Mat mat,FCN2 funci) 84 { 85 MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data; 86 87 PetscFunctionBegin; 88 ctx->funci = funci; 89 PetscFunctionReturn(0); 90 } 91 EXTERN_C_END 92 93 94 #undef __FUNCT__ 95 #define __FUNCT__ "MatSNESMFRegister" 96 int MatSNESMFRegister(const char sname[],const char path[],const char name[],int (*function)(MatSNESMFCtx)) 97 { 98 int ierr; 99 char fullname[256]; 100 101 PetscFunctionBegin; 102 ierr = PetscFListConcat(path,name,fullname);CHKERRQ(ierr); 103 ierr = PetscFListAdd(&MatSNESMPetscFList,sname,fullname,(void (*)(void))function);CHKERRQ(ierr); 104 PetscFunctionReturn(0); 105 } 106 107 108 #undef __FUNCT__ 109 #define __FUNCT__ "MatSNESMFRegisterDestroy" 110 /*@C 111 MatSNESMFRegisterDestroy - Frees the list of MatSNESMF methods that were 112 registered by MatSNESMFRegisterDynamic). 113 114 Not Collective 115 116 Level: developer 117 118 .keywords: MatSNESMF, register, destroy 119 120 .seealso: MatSNESMFRegisterDynamic), MatSNESMFRegisterAll() 121 @*/ 122 int MatSNESMFRegisterDestroy(void) 123 { 124 int ierr; 125 126 PetscFunctionBegin; 127 if (MatSNESMPetscFList) { 128 ierr = PetscFListDestroy(&MatSNESMPetscFList);CHKERRQ(ierr); 129 MatSNESMPetscFList = 0; 130 } 131 MatSNESMFRegisterAllCalled = PETSC_FALSE; 132 PetscFunctionReturn(0); 133 } 134 135 /* ----------------------------------------------------------------------------------------*/ 136 #undef __FUNCT__ 137 #define __FUNCT__ "MatDestroy_MFFD" 138 int MatDestroy_MFFD(Mat mat) 139 { 140 int ierr; 141 MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data; 142 143 PetscFunctionBegin; 144 if (ctx->w != PETSC_NULL) { 145 ierr = VecDestroy(ctx->w);CHKERRQ(ierr); 146 } 147 if (ctx->ops->destroy) {ierr = (*ctx->ops->destroy)(ctx);CHKERRQ(ierr);} 148 if (ctx->sp) {ierr = MatNullSpaceDestroy(ctx->sp);CHKERRQ(ierr);} 149 PetscHeaderDestroy(ctx); 150 PetscFunctionReturn(0); 151 } 152 153 #undef __FUNCT__ 154 #define __FUNCT__ "MatView_MFFD" 155 /* 156 MatSNESMFView_MFFD - Views matrix-free parameters. 157 158 */ 159 int MatView_MFFD(Mat J,PetscViewer viewer) 160 { 161 int ierr; 162 MatSNESMFCtx ctx = (MatSNESMFCtx)J->data; 163 PetscTruth isascii; 164 165 PetscFunctionBegin; 166 ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&isascii);CHKERRQ(ierr); 167 if (isascii) { 168 ierr = PetscViewerASCIIPrintf(viewer," SNES matrix-free approximation:\n");CHKERRQ(ierr); 169 ierr = PetscViewerASCIIPrintf(viewer," err=%g (relative error in function evaluation)\n",ctx->error_rel);CHKERRQ(ierr); 170 if (!ctx->type_name) { 171 ierr = PetscViewerASCIIPrintf(viewer," The compute h routine has not yet been set\n");CHKERRQ(ierr); 172 } else { 173 ierr = PetscViewerASCIIPrintf(viewer," Using %s compute h routine\n",ctx->type_name);CHKERRQ(ierr); 174 } 175 if (ctx->ops->view) { 176 ierr = (*ctx->ops->view)(ctx,viewer);CHKERRQ(ierr); 177 } 178 } else { 179 SETERRQ1(1,"Viewer type %s not supported for SNES matrix free matrix",((PetscObject)viewer)->type_name); 180 } 181 PetscFunctionReturn(0); 182 } 183 184 #undef __FUNCT__ 185 #define __FUNCT__ "MatAssemblyEnd_MFFD" 186 /* 187 MatSNESMFAssemblyEnd_Private - Resets the ctx->ncurrenth to zero. This 188 allows the user to indicate the beginning of a new linear solve by calling 189 MatAssemblyXXX() on the matrix free matrix. This then allows the 190 MatSNESMFCreate_WP() to properly compute ||U|| only the first time 191 in the linear solver rather than every time. 192 */ 193 int MatAssemblyEnd_MFFD(Mat J,MatAssemblyType mt) 194 { 195 int ierr; 196 MatSNESMFCtx j = (MatSNESMFCtx)J->data; 197 198 PetscFunctionBegin; 199 ierr = MatSNESMFResetHHistory(J);CHKERRQ(ierr); 200 if (j->usesnes) { 201 ierr = SNESGetSolution(j->snes,&j->current_u);CHKERRQ(ierr); 202 ierr = SNESGetFunction(j->snes,&j->current_f,PETSC_NULL,PETSC_NULL);CHKERRQ(ierr); 203 if (j->w == PETSC_NULL) { 204 ierr = VecDuplicate(j->current_u, &j->w);CHKERRQ(ierr); 205 } 206 } 207 j->vshift = 0.0; 208 j->vscale = 1.0; 209 PetscFunctionReturn(0); 210 } 211 212 #undef __FUNCT__ 213 #define __FUNCT__ "MatMult_MFFD" 214 /* 215 MatMult_MFFD - Default matrix-free form for Jacobian-vector product, y = F'(u)*a: 216 217 y ~= (F(u + ha) - F(u))/h, 218 where F = nonlinear function, as set by SNESSetFunction() 219 u = current iterate 220 h = difference interval 221 */ 222 int MatMult_MFFD(Mat mat,Vec a,Vec y) 223 { 224 MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data; 225 SNES snes; 226 PetscScalar h,mone = -1.0; 227 Vec w,U,F; 228 int ierr,(*eval_fct)(SNES,Vec,Vec)=0; 229 230 PetscFunctionBegin; 231 /* We log matrix-free matrix-vector products separately, so that we can 232 separate the performance monitoring from the cases that use conventional 233 storage. We may eventually modify event logging to associate events 234 with particular objects, hence alleviating the more general problem. */ 235 ierr = PetscLogEventBegin(MAT_MultMatrixFree,a,y,0,0);CHKERRQ(ierr); 236 237 snes = ctx->snes; 238 w = ctx->w; 239 U = ctx->current_u; 240 241 /* 242 Compute differencing parameter 243 */ 244 if (!ctx->ops->compute) { 245 ierr = MatSNESMFSetType(mat,MATSNESMF_WP);CHKERRQ(ierr); 246 ierr = MatSNESMFSetFromOptions(mat);CHKERRQ(ierr); 247 } 248 ierr = (*ctx->ops->compute)(ctx,U,a,&h);CHKERRQ(ierr); 249 250 if (ctx->checkh) { 251 ierr = (*ctx->checkh)(U,a,&h,ctx->checkhctx);CHKERRQ(ierr); 252 } 253 254 /* keep a record of the current differencing parameter h */ 255 ctx->currenth = h; 256 #if defined(PETSC_USE_COMPLEX) 257 PetscLogInfo(mat,"MatMult_MFFD:Current differencing parameter: %g + %g i\n",PetscRealPart(h),PetscImaginaryPart(h)); 258 #else 259 PetscLogInfo(mat,"MatMult_MFFD:Current differencing parameter: %15.12e\n",h); 260 #endif 261 if (ctx->historyh && ctx->ncurrenth < ctx->maxcurrenth) { 262 ctx->historyh[ctx->ncurrenth] = h; 263 } 264 ctx->ncurrenth++; 265 266 /* w = u + ha */ 267 ierr = VecWAXPY(&h,a,U,w);CHKERRQ(ierr); 268 269 if (ctx->usesnes) { 270 eval_fct = SNESComputeFunction; 271 F = ctx->current_f; 272 if (!F) SETERRQ(1,"You must call MatAssembly() even on matrix-free matrices"); 273 ierr = (*eval_fct)(snes,w,y);CHKERRQ(ierr); 274 } else { 275 F = ctx->funcvec; 276 /* compute func(U) as base for differencing */ 277 if (ctx->ncurrenth == 1) { 278 ierr = (*ctx->func)(snes,U,F,ctx->funcctx);CHKERRQ(ierr); 279 } 280 ierr = (*ctx->func)(snes,w,y,ctx->funcctx);CHKERRQ(ierr); 281 } 282 283 ierr = VecAXPY(&mone,F,y);CHKERRQ(ierr); 284 h = 1.0/h; 285 ierr = VecScale(&h,y);CHKERRQ(ierr); 286 287 288 if (ctx->vshift != 0.0 && ctx->vscale != 1.0) { 289 ierr = VecAXPBY(&ctx->vshift,&ctx->vscale,a,y);CHKERRQ(ierr); 290 } else if (ctx->vscale != 1.0) { 291 ierr = VecScale(&ctx->vscale,y);CHKERRQ(ierr); 292 } else if (ctx->vshift != 0.0) { 293 ierr = VecAXPY(&ctx->vshift,a,y);CHKERRQ(ierr); 294 } 295 296 if (ctx->sp) {ierr = MatNullSpaceRemove(ctx->sp,y,PETSC_NULL);CHKERRQ(ierr);} 297 298 ierr = PetscLogEventEnd(MAT_MultMatrixFree,a,y,0,0);CHKERRQ(ierr); 299 PetscFunctionReturn(0); 300 } 301 302 #undef __FUNCT__ 303 #define __FUNCT__ "MatGetDiagonal_MFFD" 304 /* 305 MatGetDiagonal_MFFD - Gets the diagonal for a matrix free matrix 306 307 y ~= (F(u + ha) - F(u))/h, 308 where F = nonlinear function, as set by SNESSetFunction() 309 u = current iterate 310 h = difference interval 311 */ 312 int MatGetDiagonal_MFFD(Mat mat,Vec a) 313 { 314 MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data; 315 PetscScalar h,*aa,*ww,v; 316 PetscReal epsilon = PETSC_SQRT_MACHINE_EPSILON,umin = 100.0*PETSC_SQRT_MACHINE_EPSILON; 317 Vec w,U; 318 int i,ierr,rstart,rend; 319 320 PetscFunctionBegin; 321 if (!ctx->funci) { 322 SETERRQ(1,"Requirers calling MatSNESMFSetFunctioni() first"); 323 } 324 325 w = ctx->w; 326 U = ctx->current_u; 327 ierr = (*ctx->func)(0,U,a,ctx->funcctx);CHKERRQ(ierr); 328 ierr = (*ctx->funcisetbase)(U,ctx->funcctx);CHKERRQ(ierr); 329 ierr = VecCopy(U,w);CHKERRQ(ierr); 330 331 ierr = VecGetOwnershipRange(a,&rstart,&rend);CHKERRQ(ierr); 332 ierr = VecGetArray(a,&aa);CHKERRQ(ierr); 333 for (i=rstart; i<rend; i++) { 334 ierr = VecGetArray(w,&ww);CHKERRQ(ierr); 335 h = ww[i-rstart]; 336 if (h == 0.0) h = 1.0; 337 #if !defined(PETSC_USE_COMPLEX) 338 if (h < umin && h >= 0.0) h = umin; 339 else if (h < 0.0 && h > -umin) h = -umin; 340 #else 341 if (PetscAbsScalar(h) < umin && PetscRealPart(h) >= 0.0) h = umin; 342 else if (PetscRealPart(h) < 0.0 && PetscAbsScalar(h) < umin) h = -umin; 343 #endif 344 h *= epsilon; 345 346 ww[i-rstart] += h; 347 ierr = VecRestoreArray(w,&ww);CHKERRQ(ierr); 348 ierr = (*ctx->funci)(i,w,&v,ctx->funcctx);CHKERRQ(ierr); 349 aa[i-rstart] = (v - aa[i-rstart])/h; 350 351 /* possibly shift and scale result */ 352 aa[i - rstart] = ctx->vshift + ctx->vscale*aa[i-rstart]; 353 354 ierr = VecGetArray(w,&ww);CHKERRQ(ierr); 355 ww[i-rstart] -= h; 356 ierr = VecRestoreArray(w,&ww);CHKERRQ(ierr); 357 } 358 ierr = VecRestoreArray(a,&aa);CHKERRQ(ierr); 359 PetscFunctionReturn(0); 360 } 361 362 #undef __FUNCT__ 363 #define __FUNCT__ "MatShift_MFFD" 364 int MatShift_MFFD(const PetscScalar *a,Mat Y) 365 { 366 MatSNESMFCtx shell = (MatSNESMFCtx)Y->data; 367 PetscFunctionBegin; 368 shell->vshift += *a; 369 PetscFunctionReturn(0); 370 } 371 372 #undef __FUNCT__ 373 #define __FUNCT__ "MatScale_MFFD" 374 int MatScale_MFFD(const PetscScalar *a,Mat Y) 375 { 376 MatSNESMFCtx shell = (MatSNESMFCtx)Y->data; 377 PetscFunctionBegin; 378 shell->vscale *= *a; 379 PetscFunctionReturn(0); 380 } 381 382 383 #undef __FUNCT__ 384 #define __FUNCT__ "MatCreateSNESMF" 385 /*@C 386 MatCreateSNESMF - Creates a matrix-free matrix context for use with 387 a SNES solver. This matrix can be used as the Jacobian argument for 388 the routine SNESSetJacobian(). 389 390 Collective on SNES and Vec 391 392 Input Parameters: 393 + snes - the SNES context 394 - x - vector where SNES solution is to be stored. 395 396 Output Parameter: 397 . J - the matrix-free matrix 398 399 Level: advanced 400 401 Notes: 402 The matrix-free matrix context merely contains the function pointers 403 and work space for performing finite difference approximations of 404 Jacobian-vector products, F'(u)*a, 405 406 The default code uses the following approach to compute h 407 408 .vb 409 F'(u)*a = [F(u+h*a) - F(u)]/h where 410 h = error_rel*u'a/||a||^2 if |u'a| > umin*||a||_{1} 411 = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2 otherwise 412 where 413 error_rel = square root of relative error in function evaluation 414 umin = minimum iterate parameter 415 .ve 416 417 The user can set the error_rel via MatSNESMFSetFunctionError() and 418 umin via MatSNESMFDefaultSetUmin(); see the nonlinear solvers chapter 419 of the users manual for details. 420 421 The user should call MatDestroy() when finished with the matrix-free 422 matrix context. 423 424 Options Database Keys: 425 + -snes_mf_err <error_rel> - Sets error_rel 426 . -snes_mf_unim <umin> - Sets umin (for default PETSc routine that computes h only) 427 - -snes_mf_ksp_monitor - KSP monitor routine that prints differencing h 428 429 .keywords: SNES, default, matrix-free, create, matrix 430 431 .seealso: MatDestroy(), MatSNESMFSetFunctionError(), MatSNESMFDefaultSetUmin() 432 MatSNESMFSetHHistory(), MatSNESMFResetHHistory(), MatCreateMF(), 433 MatSNESMFGetH(),MatSNESMFKSPMonitor(), MatSNESMFRegisterDynamic), MatSNESMFComputeJacobian() 434 435 @*/ 436 int MatCreateSNESMF(SNES snes,Vec x,Mat *J) 437 { 438 MatSNESMFCtx mfctx; 439 int ierr; 440 441 PetscFunctionBegin; 442 ierr = MatCreateMF(x,J);CHKERRQ(ierr); 443 444 mfctx = (MatSNESMFCtx)(*J)->data; 445 mfctx->snes = snes; 446 mfctx->usesnes = PETSC_TRUE; 447 PetscLogObjectParent(snes,*J); 448 PetscFunctionReturn(0); 449 } 450 451 EXTERN_C_BEGIN 452 #undef __FUNCT__ 453 #define __FUNCT__ "MatSNESMFSetBase_FD" 454 int MatSNESMFSetBase_FD(Mat J,Vec U) 455 { 456 int ierr; 457 MatSNESMFCtx ctx = (MatSNESMFCtx)J->data; 458 459 PetscFunctionBegin; 460 ierr = MatSNESMFResetHHistory(J);CHKERRQ(ierr); 461 ctx->current_u = U; 462 ctx->usesnes = PETSC_FALSE; 463 if (ctx->w == PETSC_NULL) { 464 ierr = VecDuplicate(ctx->current_u, &ctx->w);CHKERRQ(ierr); 465 } 466 PetscFunctionReturn(0); 467 } 468 EXTERN_C_END 469 470 typedef int (*FCN3)(Vec,Vec,PetscScalar*,void*); /* force argument to next function to not be extern C*/ 471 EXTERN_C_BEGIN 472 #undef __FUNCT__ 473 #define __FUNCT__ "MatSNESMFSetCheckh_FD" 474 int MatSNESMFSetCheckh_FD(Mat J,FCN3 fun,void*ectx) 475 { 476 MatSNESMFCtx ctx = (MatSNESMFCtx)J->data; 477 478 PetscFunctionBegin; 479 ctx->checkh = fun; 480 ctx->checkhctx = ectx; 481 PetscFunctionReturn(0); 482 } 483 EXTERN_C_END 484 485 #undef __FUNCT__ 486 #define __FUNCT__ "MatSNESMFSetFromOptions" 487 /*@ 488 MatSNESMFSetFromOptions - Sets the MatSNESMF options from the command line 489 parameter. 490 491 Collective on Mat 492 493 Input Parameters: 494 . mat - the matrix obtained with MatCreateSNESMF() 495 496 Options Database Keys: 497 + -snes_mf_type - <default,wp> 498 - -snes_mf_err - square root of estimated relative error in function evaluation 499 - -snes_mf_period - how often h is recomputed, defaults to 1, everytime 500 501 Level: advanced 502 503 .keywords: SNES, matrix-free, parameters 504 505 .seealso: MatCreateSNESMF(),MatSNESMFSetHHistory(), 506 MatSNESMFResetHHistory(), MatSNESMFKSPMonitor() 507 @*/ 508 int MatSNESMFSetFromOptions(Mat mat) 509 { 510 MatSNESMFCtx mfctx = (MatSNESMFCtx)mat->data; 511 int ierr; 512 PetscTruth flg; 513 char ftype[256]; 514 515 PetscFunctionBegin; 516 if (!MatSNESMFRegisterAllCalled) {ierr = MatSNESMFRegisterAll(PETSC_NULL);CHKERRQ(ierr);} 517 518 ierr = PetscOptionsBegin(mfctx->comm,mfctx->prefix,"Set matrix free computation parameters","MatSNESMF");CHKERRQ(ierr); 519 ierr = PetscOptionsList("-snes_mf_type","Matrix free type","MatSNESMFSetType",MatSNESMPetscFList,mfctx->type_name,ftype,256,&flg);CHKERRQ(ierr); 520 if (flg) { 521 ierr = MatSNESMFSetType(mat,ftype);CHKERRQ(ierr); 522 } 523 524 ierr = PetscOptionsReal("-snes_mf_err","set sqrt relative error in function","MatSNESMFSetFunctionError",mfctx->error_rel,&mfctx->error_rel,0);CHKERRQ(ierr); 525 ierr = PetscOptionsInt("-snes_mf_period","how often h is recomputed","MatSNESMFSetPeriod",mfctx->recomputeperiod,&mfctx->recomputeperiod,0);CHKERRQ(ierr); 526 if (mfctx->snes) { 527 ierr = PetscOptionsName("-snes_mf_ksp_monitor","Monitor matrix-free parameters","MatSNESMFKSPMonitor",&flg);CHKERRQ(ierr); 528 if (flg) { 529 KSP ksp; 530 ierr = SNESGetKSP(mfctx->snes,&ksp);CHKERRQ(ierr); 531 ierr = KSPSetMonitor(ksp,MatSNESMFKSPMonitor,PETSC_NULL,0);CHKERRQ(ierr); 532 } 533 } 534 ierr = PetscOptionsName("-snes_mf_check_positivity","Insure that U + h*a is nonnegative","MatSNESMFSetCheckh",&flg);CHKERRQ(ierr); 535 if (flg) { 536 ierr = MatSNESMFSetCheckh(mat,MatSNESMFCheckPositivity,0);CHKERRQ(ierr); 537 } 538 if (mfctx->ops->setfromoptions) { 539 ierr = (*mfctx->ops->setfromoptions)(mfctx);CHKERRQ(ierr); 540 } 541 ierr = PetscOptionsEnd();CHKERRQ(ierr); 542 PetscFunctionReturn(0); 543 } 544 545 /*MC 546 MATMFFD - MATMFFD = "mffd" - A matrix free matrix type. 547 548 Level: advanced 549 550 .seealso: MatCreateMF, MatCreateSNESMF 551 M*/ 552 EXTERN_C_BEGIN 553 #undef __FUNCT__ 554 #define __FUNCT__ "MatCreate_MFFD" 555 int MatCreate_MFFD(Mat A) 556 { 557 MatSNESMFCtx mfctx; 558 int ierr; 559 560 PetscFunctionBegin; 561 #ifndef PETSC_USE_DYNAMIC_LIBRARIES 562 ierr = SNESInitializePackage(PETSC_NULL); CHKERRQ(ierr); 563 #endif 564 565 PetscHeaderCreate(mfctx,_p_MatSNESMFCtx,struct _MFOps,MATSNESMFCTX_COOKIE,0,"SNESMF",A->comm,MatDestroy_MFFD,MatView_MFFD); 566 PetscLogObjectCreate(mfctx); 567 mfctx->sp = 0; 568 mfctx->snes = 0; 569 mfctx->error_rel = PETSC_SQRT_MACHINE_EPSILON; 570 mfctx->recomputeperiod = 1; 571 mfctx->count = 0; 572 mfctx->currenth = 0.0; 573 mfctx->historyh = PETSC_NULL; 574 mfctx->ncurrenth = 0; 575 mfctx->maxcurrenth = 0; 576 mfctx->type_name = 0; 577 mfctx->usesnes = PETSC_FALSE; 578 579 mfctx->vshift = 0.0; 580 mfctx->vscale = 1.0; 581 582 /* 583 Create the empty data structure to contain compute-h routines. 584 These will be filled in below from the command line options or 585 a later call with MatSNESMFSetType() or if that is not called 586 then it will default in the first use of MatMult_MFFD() 587 */ 588 mfctx->ops->compute = 0; 589 mfctx->ops->destroy = 0; 590 mfctx->ops->view = 0; 591 mfctx->ops->setfromoptions = 0; 592 mfctx->hctx = 0; 593 594 mfctx->func = 0; 595 mfctx->funcctx = 0; 596 mfctx->funcvec = 0; 597 mfctx->w = PETSC_NULL; 598 599 A->data = mfctx; 600 601 A->ops->mult = MatMult_MFFD; 602 A->ops->destroy = MatDestroy_MFFD; 603 A->ops->view = MatView_MFFD; 604 A->ops->assemblyend = MatAssemblyEnd_MFFD; 605 A->ops->getdiagonal = MatGetDiagonal_MFFD; 606 A->ops->scale = MatScale_MFFD; 607 A->ops->shift = MatShift_MFFD; 608 A->ops->setfromoptions = MatSNESMFSetFromOptions; 609 610 ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatSNESMFSetBase_C","MatSNESMFSetBase_FD",MatSNESMFSetBase_FD);CHKERRQ(ierr); 611 ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatSNESMFSetFunctioniBase_C","MatSNESMFSetFunctioniBase_FD",MatSNESMFSetFunctioniBase_FD);CHKERRQ(ierr); 612 ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatSNESMFSetFunctioni_C","MatSNESMFSetFunctioni_FD",MatSNESMFSetFunctioni_FD);CHKERRQ(ierr); 613 ierr = PetscObjectComposeFunctionDynamic((PetscObject)A,"MatSNESMFSetCheckh_C","MatSNESMFSetCheckh_FD",MatSNESMFSetCheckh_FD);CHKERRQ(ierr); 614 mfctx->mat = A; 615 616 PetscFunctionReturn(0); 617 } 618 EXTERN_C_END 619 620 #undef __FUNCT__ 621 #define __FUNCT__ "MatCreateMF" 622 /*@C 623 MatCreateMF - Creates a matrix-free matrix. See also MatCreateSNESMF() 624 625 Collective on Vec 626 627 Input Parameters: 628 . x - vector that defines layout of the vectors and matrices 629 630 Output Parameter: 631 . J - the matrix-free matrix 632 633 Level: advanced 634 635 Notes: 636 The matrix-free matrix context merely contains the function pointers 637 and work space for performing finite difference approximations of 638 Jacobian-vector products, F'(u)*a, 639 640 The default code uses the following approach to compute h 641 642 .vb 643 F'(u)*a = [F(u+h*a) - F(u)]/h where 644 h = error_rel*u'a/||a||^2 if |u'a| > umin*||a||_{1} 645 = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2 otherwise 646 where 647 error_rel = square root of relative error in function evaluation 648 umin = minimum iterate parameter 649 .ve 650 651 The user can set the error_rel via MatSNESMFSetFunctionError() and 652 umin via MatSNESMFDefaultSetUmin(); see the nonlinear solvers chapter 653 of the users manual for details. 654 655 The user should call MatDestroy() when finished with the matrix-free 656 matrix context. 657 658 Options Database Keys: 659 + -snes_mf_err <error_rel> - Sets error_rel 660 . -snes_mf_unim <umin> - Sets umin (for default PETSc routine that computes h only) 661 . -snes_mf_ksp_monitor - KSP monitor routine that prints differencing h 662 - -snes_mf_check_positivity 663 664 .keywords: default, matrix-free, create, matrix 665 666 .seealso: MatDestroy(), MatSNESMFSetFunctionError(), MatSNESMFDefaultSetUmin() 667 MatSNESMFSetHHistory(), MatSNESMFResetHHistory(), MatCreateSNESMF(), 668 MatSNESMFGetH(),MatSNESMFKSPMonitor(), MatSNESMFRegisterDynamic),, MatSNESMFComputeJacobian() 669 670 @*/ 671 int MatCreateMF(Vec x,Mat *J) 672 { 673 MPI_Comm comm; 674 int n,nloc,ierr; 675 676 PetscFunctionBegin; 677 ierr = PetscObjectGetComm((PetscObject)x,&comm);CHKERRQ(ierr); 678 ierr = VecGetSize(x,&n);CHKERRQ(ierr); 679 ierr = VecGetLocalSize(x,&nloc);CHKERRQ(ierr); 680 ierr = MatCreate(comm,nloc,nloc,n,n,J);CHKERRQ(ierr); 681 ierr = MatRegisterDynamic(MATMFFD,0,"MatCreate_MFFD",MatCreate_MFFD);CHKERRQ(ierr); 682 ierr = MatSetType(*J,MATMFFD);CHKERRQ(ierr); 683 PetscFunctionReturn(0); 684 } 685 686 687 #undef __FUNCT__ 688 #define __FUNCT__ "MatSNESMFGetH" 689 /*@ 690 MatSNESMFGetH - Gets the last value that was used as the differencing 691 parameter. 692 693 Not Collective 694 695 Input Parameters: 696 . mat - the matrix obtained with MatCreateSNESMF() 697 698 Output Paramter: 699 . h - the differencing step size 700 701 Level: advanced 702 703 .keywords: SNES, matrix-free, parameters 704 705 .seealso: MatCreateSNESMF(),MatSNESMFSetHHistory(), 706 MatSNESMFResetHHistory(),MatSNESMFKSPMonitor() 707 @*/ 708 int MatSNESMFGetH(Mat mat,PetscScalar *h) 709 { 710 MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data; 711 712 PetscFunctionBegin; 713 *h = ctx->currenth; 714 PetscFunctionReturn(0); 715 } 716 717 #undef __FUNCT__ 718 #define __FUNCT__ "MatSNESMFKSPMonitor" 719 /* 720 MatSNESMFKSPMonitor - A KSP monitor for use with the default PETSc 721 SNES matrix free routines. Prints the differencing parameter used at 722 each step. 723 */ 724 int MatSNESMFKSPMonitor(KSP ksp,int n,PetscReal rnorm,void *dummy) 725 { 726 PC pc; 727 MatSNESMFCtx ctx; 728 int ierr; 729 Mat mat; 730 MPI_Comm comm; 731 PetscTruth nonzeroinitialguess; 732 733 PetscFunctionBegin; 734 ierr = PetscObjectGetComm((PetscObject)ksp,&comm);CHKERRQ(ierr); 735 ierr = KSPGetPC(ksp,&pc);CHKERRQ(ierr); 736 ierr = KSPGetInitialGuessNonzero(ksp,&nonzeroinitialguess);CHKERRQ(ierr); 737 ierr = PCGetOperators(pc,&mat,PETSC_NULL,PETSC_NULL);CHKERRQ(ierr); 738 ctx = (MatSNESMFCtx)mat->data; 739 740 if (n > 0 || nonzeroinitialguess) { 741 #if defined(PETSC_USE_COMPLEX) 742 ierr = PetscPrintf(comm,"%d KSP Residual norm %14.12e h %g + %g i\n",n,rnorm, 743 PetscRealPart(ctx->currenth),PetscImaginaryPart(ctx->currenth));CHKERRQ(ierr); 744 #else 745 ierr = PetscPrintf(comm,"%d KSP Residual norm %14.12e h %g \n",n,rnorm,ctx->currenth);CHKERRQ(ierr); 746 #endif 747 } else { 748 ierr = PetscPrintf(comm,"%d KSP Residual norm %14.12e\n",n,rnorm);CHKERRQ(ierr); 749 } 750 PetscFunctionReturn(0); 751 } 752 753 #undef __FUNCT__ 754 #define __FUNCT__ "MatSNESMFSetFunction" 755 /*@C 756 MatSNESMFSetFunction - Sets the function used in applying the matrix free. 757 758 Collective on Mat 759 760 Input Parameters: 761 + mat - the matrix free matrix created via MatCreateSNESMF() 762 . v - workspace vector 763 . func - the function to use 764 - funcctx - optional function context passed to function 765 766 Level: advanced 767 768 Notes: 769 If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free 770 matrix inside your compute Jacobian routine 771 772 If this is not set then it will use the function set with SNESSetFunction() 773 774 .keywords: SNES, matrix-free, function 775 776 .seealso: MatCreateSNESMF(),MatSNESMFGetH(), 777 MatSNESMFSetHHistory(), MatSNESMFResetHHistory(), 778 MatSNESMFKSPMonitor(), SNESetFunction() 779 @*/ 780 int MatSNESMFSetFunction(Mat mat,Vec v,int (*func)(SNES,Vec,Vec,void *),void *funcctx) 781 { 782 MatSNESMFCtx ctx = (MatSNESMFCtx)mat->data; 783 784 PetscFunctionBegin; 785 ctx->func = func; 786 ctx->funcctx = funcctx; 787 ctx->funcvec = v; 788 PetscFunctionReturn(0); 789 } 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,1); 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,1); 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,1); 1080 PetscValidHeaderSpecific(U,VEC_COOKIE,2); 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,1); 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