1 2 #include <petsc/private/matimpl.h> 3 #include <../src/mat/impls/mffd/mffdimpl.h> /*I "petscmat.h" I*/ 4 5 PetscFunctionList MatMFFDList = NULL; 6 PetscBool MatMFFDRegisterAllCalled = PETSC_FALSE; 7 8 PetscClassId MATMFFD_CLASSID; 9 PetscLogEvent MATMFFD_Mult; 10 11 static PetscBool MatMFFDPackageInitialized = PETSC_FALSE; 12 /*@C 13 MatMFFDFinalizePackage - This function destroys everything in the MatMFFD package. It is 14 called from PetscFinalize(). 15 16 Level: developer 17 18 .seealso: `PetscFinalize()`, `MatCreateMFFD()`, `MatCreateSNESMF()` 19 @*/ 20 PetscErrorCode MatMFFDFinalizePackage(void) 21 { 22 PetscFunctionBegin; 23 PetscCall(PetscFunctionListDestroy(&MatMFFDList)); 24 MatMFFDPackageInitialized = PETSC_FALSE; 25 MatMFFDRegisterAllCalled = PETSC_FALSE; 26 PetscFunctionReturn(0); 27 } 28 29 /*@C 30 MatMFFDInitializePackage - This function initializes everything in the MatMFFD package. It is called 31 from MatInitializePackage(). 32 33 Level: developer 34 35 .seealso: `PetscInitialize()` 36 @*/ 37 PetscErrorCode MatMFFDInitializePackage(void) 38 { 39 char logList[256]; 40 PetscBool opt,pkg; 41 42 PetscFunctionBegin; 43 if (MatMFFDPackageInitialized) PetscFunctionReturn(0); 44 MatMFFDPackageInitialized = PETSC_TRUE; 45 /* Register Classes */ 46 PetscCall(PetscClassIdRegister("MatMFFD",&MATMFFD_CLASSID)); 47 /* Register Constructors */ 48 PetscCall(MatMFFDRegisterAll()); 49 /* Register Events */ 50 PetscCall(PetscLogEventRegister("MatMult MF",MATMFFD_CLASSID,&MATMFFD_Mult)); 51 /* Process Info */ 52 { 53 PetscClassId classids[1]; 54 55 classids[0] = MATMFFD_CLASSID; 56 PetscCall(PetscInfoProcessClass("matmffd", 1, classids)); 57 } 58 /* Process summary exclusions */ 59 PetscCall(PetscOptionsGetString(NULL,NULL,"-log_exclude",logList,sizeof(logList),&opt)); 60 if (opt) { 61 PetscCall(PetscStrInList("matmffd",logList,',',&pkg)); 62 if (pkg) PetscCall(PetscLogEventExcludeClass(MATMFFD_CLASSID)); 63 } 64 /* Register package finalizer */ 65 PetscCall(PetscRegisterFinalize(MatMFFDFinalizePackage)); 66 PetscFunctionReturn(0); 67 } 68 69 static PetscErrorCode MatMFFDSetType_MFFD(Mat mat,MatMFFDType ftype) 70 { 71 MatMFFD ctx; 72 PetscBool match; 73 PetscErrorCode (*r)(MatMFFD); 74 75 PetscFunctionBegin; 76 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 77 PetscValidCharPointer(ftype,2); 78 PetscCall(MatShellGetContext(mat,&ctx)); 79 80 /* already set, so just return */ 81 PetscCall(PetscObjectTypeCompare((PetscObject)ctx,ftype,&match)); 82 if (match) PetscFunctionReturn(0); 83 84 /* destroy the old one if it exists */ 85 PetscTryTypeMethod(ctx,destroy); 86 87 PetscCall(PetscFunctionListFind(MatMFFDList,ftype,&r)); 88 PetscCheck(r,PETSC_COMM_SELF,PETSC_ERR_ARG_UNKNOWN_TYPE,"Unknown MatMFFD type %s given",ftype); 89 PetscCall((*r)(ctx)); 90 PetscCall(PetscObjectChangeTypeName((PetscObject)ctx,ftype)); 91 PetscFunctionReturn(0); 92 } 93 94 /*@C 95 MatMFFDSetType - Sets the method that is used to compute the 96 differencing parameter for finite differene matrix-free formulations. 97 98 Input Parameters: 99 + mat - the "matrix-free" matrix created via MatCreateSNESMF(), or MatCreateMFFD() 100 or MatSetType(mat,MATMFFD); 101 - ftype - the type requested, either MATMFFD_WP or MATMFFD_DS 102 103 Level: advanced 104 105 Notes: 106 For example, such routines can compute h for use in 107 Jacobian-vector products of the form 108 109 F(x+ha) - F(x) 110 F'(u)a ~= ---------------- 111 h 112 113 .seealso: `MatCreateSNESMF()`, `MatMFFDRegister()`, `MatMFFDSetFunction()`, `MatCreateMFFD()` 114 @*/ 115 PetscErrorCode MatMFFDSetType(Mat mat,MatMFFDType ftype) 116 { 117 PetscFunctionBegin; 118 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 119 PetscValidCharPointer(ftype,2); 120 PetscTryMethod(mat,"MatMFFDSetType_C",(Mat,MatMFFDType),(mat,ftype)); 121 PetscFunctionReturn(0); 122 } 123 124 static PetscErrorCode MatGetDiagonal_MFFD(Mat,Vec); 125 126 typedef PetscErrorCode (*FCN1)(void*,Vec); /* force argument to next function to not be extern C*/ 127 static PetscErrorCode MatMFFDSetFunctioniBase_MFFD(Mat mat,FCN1 func) 128 { 129 MatMFFD ctx; 130 131 PetscFunctionBegin; 132 PetscCall(MatShellGetContext(mat,&ctx)); 133 ctx->funcisetbase = func; 134 PetscFunctionReturn(0); 135 } 136 137 typedef PetscErrorCode (*FCN2)(void*,PetscInt,Vec,PetscScalar*); /* force argument to next function to not be extern C*/ 138 static PetscErrorCode MatMFFDSetFunctioni_MFFD(Mat mat,FCN2 funci) 139 { 140 MatMFFD ctx; 141 142 PetscFunctionBegin; 143 PetscCall(MatShellGetContext(mat,&ctx)); 144 ctx->funci = funci; 145 PetscCall(MatShellSetOperation(mat,MATOP_GET_DIAGONAL,(void (*)(void))MatGetDiagonal_MFFD)); 146 PetscFunctionReturn(0); 147 } 148 149 static PetscErrorCode MatMFFDGetH_MFFD(Mat mat,PetscScalar *h) 150 { 151 MatMFFD ctx; 152 153 PetscFunctionBegin; 154 PetscCall(MatShellGetContext(mat,&ctx)); 155 *h = ctx->currenth; 156 PetscFunctionReturn(0); 157 } 158 159 static PetscErrorCode MatMFFDResetHHistory_MFFD(Mat J) 160 { 161 MatMFFD ctx; 162 163 PetscFunctionBegin; 164 PetscCall(MatShellGetContext(J,&ctx)); 165 ctx->ncurrenth = 0; 166 PetscFunctionReturn(0); 167 } 168 169 /*@C 170 MatMFFDRegister - Adds a method to the MatMFFD registry. 171 172 Not Collective 173 174 Input Parameters: 175 + name_solver - name of a new user-defined compute-h module 176 - routine_create - routine to create method context 177 178 Level: developer 179 180 Notes: 181 MatMFFDRegister() may be called multiple times to add several user-defined solvers. 182 183 Sample usage: 184 .vb 185 MatMFFDRegister("my_h",MyHCreate); 186 .ve 187 188 Then, your solver can be chosen with the procedural interface via 189 $ MatMFFDSetType(mfctx,"my_h") 190 or at runtime via the option 191 $ -mat_mffd_type my_h 192 193 .seealso: `MatMFFDRegisterAll()`, `MatMFFDRegisterDestroy()` 194 @*/ 195 PetscErrorCode MatMFFDRegister(const char sname[],PetscErrorCode (*function)(MatMFFD)) 196 { 197 PetscFunctionBegin; 198 PetscCall(MatInitializePackage()); 199 PetscCall(PetscFunctionListAdd(&MatMFFDList,sname,function)); 200 PetscFunctionReturn(0); 201 } 202 203 /* ----------------------------------------------------------------------------------------*/ 204 static PetscErrorCode MatDestroy_MFFD(Mat mat) 205 { 206 MatMFFD ctx; 207 208 PetscFunctionBegin; 209 PetscCall(MatShellGetContext(mat,&ctx)); 210 PetscCall(VecDestroy(&ctx->w)); 211 PetscCall(VecDestroy(&ctx->current_u)); 212 if (ctx->current_f_allocated) { 213 PetscCall(VecDestroy(&ctx->current_f)); 214 } 215 PetscTryTypeMethod(ctx,destroy); 216 PetscCall(PetscHeaderDestroy(&ctx)); 217 218 PetscCall(PetscObjectComposeFunction((PetscObject)mat,"MatMFFDSetBase_C",NULL)); 219 PetscCall(PetscObjectComposeFunction((PetscObject)mat,"MatMFFDSetFunctioniBase_C",NULL)); 220 PetscCall(PetscObjectComposeFunction((PetscObject)mat,"MatMFFDSetFunctioni_C",NULL)); 221 PetscCall(PetscObjectComposeFunction((PetscObject)mat,"MatMFFDSetFunction_C",NULL)); 222 PetscCall(PetscObjectComposeFunction((PetscObject)mat,"MatMFFDSetFunctionError_C",NULL)); 223 PetscCall(PetscObjectComposeFunction((PetscObject)mat,"MatMFFDSetCheckh_C",NULL)); 224 PetscCall(PetscObjectComposeFunction((PetscObject)mat,"MatMFFDSetPeriod_C",NULL)); 225 PetscCall(PetscObjectComposeFunction((PetscObject)mat,"MatMFFDResetHHistory_C",NULL)); 226 PetscCall(PetscObjectComposeFunction((PetscObject)mat,"MatMFFDSetHHistory_C",NULL)); 227 PetscCall(PetscObjectComposeFunction((PetscObject)mat,"MatMFFDSetType_C",NULL)); 228 PetscCall(PetscObjectComposeFunction((PetscObject)mat,"MatMFFDGetH_C",NULL)); 229 PetscCall(PetscObjectComposeFunction((PetscObject)mat,"MatSNESMFSetReuseBase_C",NULL)); 230 PetscCall(PetscObjectComposeFunction((PetscObject)mat,"MatSNESMFGetReuseBase_C",NULL)); 231 PetscFunctionReturn(0); 232 } 233 234 /* 235 MatMFFDView_MFFD - Views matrix-free parameters. 236 237 */ 238 static PetscErrorCode MatView_MFFD(Mat J,PetscViewer viewer) 239 { 240 MatMFFD ctx; 241 PetscBool iascii, viewbase, viewfunction; 242 const char *prefix; 243 244 PetscFunctionBegin; 245 PetscCall(MatShellGetContext(J,&ctx)); 246 PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii)); 247 if (iascii) { 248 PetscCall(PetscViewerASCIIPrintf(viewer,"Matrix-free approximation:\n")); 249 PetscCall(PetscViewerASCIIPushTab(viewer)); 250 PetscCall(PetscViewerASCIIPrintf(viewer,"err=%g (relative error in function evaluation)\n",(double)ctx->error_rel)); 251 if (!((PetscObject)ctx)->type_name) { 252 PetscCall(PetscViewerASCIIPrintf(viewer,"The compute h routine has not yet been set\n")); 253 } else { 254 PetscCall(PetscViewerASCIIPrintf(viewer,"Using %s compute h routine\n",((PetscObject)ctx)->type_name)); 255 } 256 #if defined(PETSC_USE_COMPLEX) 257 if (ctx->usecomplex) { 258 PetscCall(PetscViewerASCIIPrintf(viewer,"Using Lyness complex number trick to compute the matrix-vector product\n")); 259 } 260 #endif 261 PetscTryTypeMethod(ctx,view,viewer); 262 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)J, &prefix)); 263 264 PetscCall(PetscOptionsHasName(((PetscObject)J)->options,prefix, "-mat_mffd_view_base", &viewbase)); 265 if (viewbase) { 266 PetscCall(PetscViewerASCIIPrintf(viewer, "Base:\n")); 267 PetscCall(VecView(ctx->current_u, viewer)); 268 } 269 PetscCall(PetscOptionsHasName(((PetscObject)J)->options,prefix, "-mat_mffd_view_function", &viewfunction)); 270 if (viewfunction) { 271 PetscCall(PetscViewerASCIIPrintf(viewer, "Function:\n")); 272 PetscCall(VecView(ctx->current_f, viewer)); 273 } 274 PetscCall(PetscViewerASCIIPopTab(viewer)); 275 } 276 PetscFunctionReturn(0); 277 } 278 279 /* 280 MatAssemblyEnd_MFFD - Resets the ctx->ncurrenth to zero. This 281 allows the user to indicate the beginning of a new linear solve by calling 282 MatAssemblyXXX() on the matrix free matrix. This then allows the 283 MatCreateMFFD_WP() to properly compute ||U|| only the first time 284 in the linear solver rather than every time. 285 286 This function is referenced directly from MatAssemblyEnd_SNESMF(), which may be in a different shared library hence 287 it must be labeled as PETSC_EXTERN 288 */ 289 PETSC_EXTERN PetscErrorCode MatAssemblyEnd_MFFD(Mat J,MatAssemblyType mt) 290 { 291 MatMFFD j; 292 293 PetscFunctionBegin; 294 PetscCall(MatShellGetContext(J,&j)); 295 PetscCall(MatMFFDResetHHistory(J)); 296 PetscFunctionReturn(0); 297 } 298 299 /* 300 MatMult_MFFD - Default matrix-free form for Jacobian-vector product, y = F'(u)*a: 301 302 y ~= (F(u + ha) - F(u))/h, 303 where F = nonlinear function, as set by SNESSetFunction() 304 u = current iterate 305 h = difference interval 306 */ 307 static PetscErrorCode MatMult_MFFD(Mat mat,Vec a,Vec y) 308 { 309 MatMFFD ctx; 310 PetscScalar h; 311 Vec w,U,F; 312 PetscBool zeroa; 313 314 PetscFunctionBegin; 315 PetscCall(MatShellGetContext(mat,&ctx)); 316 PetscCheck(ctx->current_u,PetscObjectComm((PetscObject)mat),PETSC_ERR_ARG_WRONGSTATE,"MatMFFDSetBase() has not been called, this is often caused by forgetting to call \n\t\tMatAssemblyBegin/End on the first Mat in the SNES compute function"); 317 /* We log matrix-free matrix-vector products separately, so that we can 318 separate the performance monitoring from the cases that use conventional 319 storage. We may eventually modify event logging to associate events 320 with particular objects, hence alleviating the more general problem. */ 321 PetscCall(PetscLogEventBegin(MATMFFD_Mult,a,y,0,0)); 322 323 w = ctx->w; 324 U = ctx->current_u; 325 F = ctx->current_f; 326 /* 327 Compute differencing parameter 328 */ 329 if (!((PetscObject)ctx)->type_name) { 330 PetscCall(MatMFFDSetType(mat,MATMFFD_WP)); 331 PetscCall(MatSetFromOptions(mat)); 332 } 333 PetscUseTypeMethod(ctx,compute ,U,a,&h,&zeroa); 334 if (zeroa) { 335 PetscCall(VecSet(y,0.0)); 336 PetscCall(PetscLogEventEnd(MATMFFD_Mult,a,y,0,0)); 337 PetscFunctionReturn(0); 338 } 339 340 PetscCheck(!mat->erroriffailure || !PetscIsInfOrNanScalar(h),PETSC_COMM_SELF,PETSC_ERR_PLIB,"Computed Nan differencing parameter h"); 341 if (ctx->checkh) { 342 PetscCall((*ctx->checkh)(ctx->checkhctx,U,a,&h)); 343 } 344 345 /* keep a record of the current differencing parameter h */ 346 ctx->currenth = h; 347 #if defined(PETSC_USE_COMPLEX) 348 PetscCall(PetscInfo(mat,"Current differencing parameter: %g + %g i\n",(double)PetscRealPart(h),(double)PetscImaginaryPart(h))); 349 #else 350 PetscCall(PetscInfo(mat,"Current differencing parameter: %15.12e\n",(double)PetscRealPart(h))); 351 #endif 352 if (ctx->historyh && ctx->ncurrenth < ctx->maxcurrenth) { 353 ctx->historyh[ctx->ncurrenth] = h; 354 } 355 ctx->ncurrenth++; 356 357 #if defined(PETSC_USE_COMPLEX) 358 if (ctx->usecomplex) h = PETSC_i*h; 359 #endif 360 361 /* w = u + ha */ 362 PetscCall(VecWAXPY(w,h,a,U)); 363 364 /* compute func(U) as base for differencing; only needed first time in and not when provided by user */ 365 if (ctx->ncurrenth == 1 && ctx->current_f_allocated) { 366 PetscCall((*ctx->func)(ctx->funcctx,U,F)); 367 } 368 PetscCall((*ctx->func)(ctx->funcctx,w,y)); 369 370 #if defined(PETSC_USE_COMPLEX) 371 if (ctx->usecomplex) { 372 PetscCall(VecImaginaryPart(y)); 373 h = PetscImaginaryPart(h); 374 } else { 375 PetscCall(VecAXPY(y,-1.0,F)); 376 } 377 #else 378 PetscCall(VecAXPY(y,-1.0,F)); 379 #endif 380 PetscCall(VecScale(y,1.0/h)); 381 if (mat->nullsp) PetscCall(MatNullSpaceRemove(mat->nullsp,y)); 382 383 PetscCall(PetscLogEventEnd(MATMFFD_Mult,a,y,0,0)); 384 PetscFunctionReturn(0); 385 } 386 387 /* 388 MatGetDiagonal_MFFD - Gets the diagonal for a matrix free matrix 389 390 y ~= (F(u + ha) - F(u))/h, 391 where F = nonlinear function, as set by SNESSetFunction() 392 u = current iterate 393 h = difference interval 394 */ 395 PetscErrorCode MatGetDiagonal_MFFD(Mat mat,Vec a) 396 { 397 MatMFFD ctx; 398 PetscScalar h,*aa,*ww,v; 399 PetscReal epsilon = PETSC_SQRT_MACHINE_EPSILON,umin = 100.0*PETSC_SQRT_MACHINE_EPSILON; 400 Vec w,U; 401 PetscInt i,rstart,rend; 402 403 PetscFunctionBegin; 404 PetscCall(MatShellGetContext(mat,&ctx)); 405 PetscCheck(ctx->func,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Requires calling MatMFFDSetFunction() first"); 406 PetscCheck(ctx->funci,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Requires calling MatMFFDSetFunctioni() first"); 407 w = ctx->w; 408 U = ctx->current_u; 409 PetscCall((*ctx->func)(ctx->funcctx,U,a)); 410 if (ctx->funcisetbase) PetscCall((*ctx->funcisetbase)(ctx->funcctx,U)); 411 PetscCall(VecCopy(U,w)); 412 413 PetscCall(VecGetOwnershipRange(a,&rstart,&rend)); 414 PetscCall(VecGetArray(a,&aa)); 415 for (i=rstart; i<rend; i++) { 416 PetscCall(VecGetArray(w,&ww)); 417 h = ww[i-rstart]; 418 if (h == 0.0) h = 1.0; 419 if (PetscAbsScalar(h) < umin && PetscRealPart(h) >= 0.0) h = umin; 420 else if (PetscRealPart(h) < 0.0 && PetscAbsScalar(h) < umin) h = -umin; 421 h *= epsilon; 422 423 ww[i-rstart] += h; 424 PetscCall(VecRestoreArray(w,&ww)); 425 PetscCall((*ctx->funci)(ctx->funcctx,i,w,&v)); 426 aa[i-rstart] = (v - aa[i-rstart])/h; 427 428 PetscCall(VecGetArray(w,&ww)); 429 ww[i-rstart] -= h; 430 PetscCall(VecRestoreArray(w,&ww)); 431 } 432 PetscCall(VecRestoreArray(a,&aa)); 433 PetscFunctionReturn(0); 434 } 435 436 PETSC_EXTERN PetscErrorCode MatMFFDSetBase_MFFD(Mat J,Vec U,Vec F) 437 { 438 MatMFFD ctx; 439 440 PetscFunctionBegin; 441 PetscCall(MatShellGetContext(J,&ctx)); 442 PetscCall(MatMFFDResetHHistory(J)); 443 if (!ctx->current_u) { 444 PetscCall(VecDuplicate(U,&ctx->current_u)); 445 PetscCall(VecLockReadPush(ctx->current_u)); 446 } 447 PetscCall(VecLockReadPop(ctx->current_u)); 448 PetscCall(VecCopy(U,ctx->current_u)); 449 PetscCall(VecLockReadPush(ctx->current_u)); 450 if (F) { 451 if (ctx->current_f_allocated) PetscCall(VecDestroy(&ctx->current_f)); 452 ctx->current_f = F; 453 ctx->current_f_allocated = PETSC_FALSE; 454 } else if (!ctx->current_f_allocated) { 455 PetscCall(MatCreateVecs(J,NULL,&ctx->current_f)); 456 ctx->current_f_allocated = PETSC_TRUE; 457 } 458 if (!ctx->w) { 459 PetscCall(VecDuplicate(ctx->current_u,&ctx->w)); 460 } 461 J->assembled = PETSC_TRUE; 462 PetscFunctionReturn(0); 463 } 464 465 typedef PetscErrorCode (*FCN3)(void*,Vec,Vec,PetscScalar*); /* force argument to next function to not be extern C*/ 466 467 static PetscErrorCode MatMFFDSetCheckh_MFFD(Mat J,FCN3 fun,void *ectx) 468 { 469 MatMFFD ctx; 470 471 PetscFunctionBegin; 472 PetscCall(MatShellGetContext(J,&ctx)); 473 ctx->checkh = fun; 474 ctx->checkhctx = ectx; 475 PetscFunctionReturn(0); 476 } 477 478 /*@C 479 MatMFFDSetOptionsPrefix - Sets the prefix used for searching for all 480 MatMFFD options in the database. 481 482 Collective on Mat 483 484 Input Parameters: 485 + A - the Mat context 486 - prefix - the prefix to prepend to all option names 487 488 Notes: 489 A hyphen (-) must NOT be given at the beginning of the prefix name. 490 The first character of all runtime options is AUTOMATICALLY the hyphen. 491 492 Level: advanced 493 494 .seealso: `MatSetFromOptions()`, `MatCreateSNESMF()`, `MatCreateMFFD()` 495 @*/ 496 PetscErrorCode MatMFFDSetOptionsPrefix(Mat mat,const char prefix[]) 497 { 498 MatMFFD mfctx; 499 500 PetscFunctionBegin; 501 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 502 PetscCall(MatShellGetContext(mat,&mfctx)); 503 PetscValidHeaderSpecific(mfctx,MATMFFD_CLASSID,1); 504 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)mfctx,prefix)); 505 PetscFunctionReturn(0); 506 } 507 508 static PetscErrorCode MatSetFromOptions_MFFD(Mat mat,PetscOptionItems *PetscOptionsObject) 509 { 510 MatMFFD mfctx; 511 PetscBool flg; 512 char ftype[256]; 513 514 PetscFunctionBegin; 515 PetscCall(MatShellGetContext(mat,&mfctx)); 516 PetscValidHeaderSpecific(mfctx,MATMFFD_CLASSID,1); 517 PetscObjectOptionsBegin((PetscObject)mfctx); 518 PetscCall(PetscOptionsFList("-mat_mffd_type","Matrix free type","MatMFFDSetType",MatMFFDList,((PetscObject)mfctx)->type_name,ftype,256,&flg)); 519 if (flg) PetscCall(MatMFFDSetType(mat,ftype)); 520 521 PetscCall(PetscOptionsReal("-mat_mffd_err","set sqrt relative error in function","MatMFFDSetFunctionError",mfctx->error_rel,&mfctx->error_rel,NULL)); 522 PetscCall(PetscOptionsInt("-mat_mffd_period","how often h is recomputed","MatMFFDSetPeriod",mfctx->recomputeperiod,&mfctx->recomputeperiod,NULL)); 523 524 flg = PETSC_FALSE; 525 PetscCall(PetscOptionsBool("-mat_mffd_check_positivity","Insure that U + h*a is nonnegative","MatMFFDSetCheckh",flg,&flg,NULL)); 526 if (flg) PetscCall(MatMFFDSetCheckh(mat,MatMFFDCheckPositivity,NULL)); 527 #if defined(PETSC_USE_COMPLEX) 528 PetscCall(PetscOptionsBool("-mat_mffd_complex","Use Lyness complex number trick to compute the matrix-vector product","None",mfctx->usecomplex,&mfctx->usecomplex,NULL)); 529 #endif 530 PetscTryTypeMethod(mfctx,setfromoptions,PetscOptionsObject); 531 PetscOptionsEnd(); 532 PetscFunctionReturn(0); 533 } 534 535 static PetscErrorCode MatMFFDSetPeriod_MFFD(Mat mat,PetscInt period) 536 { 537 MatMFFD ctx; 538 539 PetscFunctionBegin; 540 PetscCall(MatShellGetContext(mat,&ctx)); 541 ctx->recomputeperiod = period; 542 PetscFunctionReturn(0); 543 } 544 545 static PetscErrorCode MatMFFDSetFunction_MFFD(Mat mat,PetscErrorCode (*func)(void*,Vec,Vec),void *funcctx) 546 { 547 MatMFFD ctx; 548 549 PetscFunctionBegin; 550 PetscCall(MatShellGetContext(mat,&ctx)); 551 ctx->func = func; 552 ctx->funcctx = funcctx; 553 PetscFunctionReturn(0); 554 } 555 556 static PetscErrorCode MatMFFDSetFunctionError_MFFD(Mat mat,PetscReal error) 557 { 558 MatMFFD ctx; 559 560 PetscFunctionBegin; 561 PetscCall(MatShellGetContext(mat,&ctx)); 562 if (error != PETSC_DEFAULT) ctx->error_rel = error; 563 PetscFunctionReturn(0); 564 } 565 566 PetscErrorCode MatMFFDSetHHistory_MFFD(Mat J,PetscScalar history[],PetscInt nhistory) 567 { 568 MatMFFD ctx; 569 570 PetscFunctionBegin; 571 PetscCall(MatShellGetContext(J,&ctx)); 572 ctx->historyh = history; 573 ctx->maxcurrenth = nhistory; 574 ctx->currenth = 0.; 575 PetscFunctionReturn(0); 576 } 577 578 /*MC 579 MATMFFD - MATMFFD = "mffd" - A matrix free matrix type. 580 581 Level: advanced 582 583 Developers Note: This is implemented on top of MATSHELL to get support for scaling and shifting without requiring duplicate code 584 585 .seealso: `MatCreateMFFD()`, `MatCreateSNESMF()`, `MatMFFDSetFunction()`, `MatMFFDSetType()`, 586 `MatMFFDSetFunctionError()`, `MatMFFDDSSetUmin()`, `MatMFFDSetFunction()` 587 `MatMFFDSetHHistory()`, `MatMFFDResetHHistory()`, `MatCreateSNESMF()`, 588 `MatMFFDGetH()`, 589 M*/ 590 PETSC_EXTERN PetscErrorCode MatCreate_MFFD(Mat A) 591 { 592 MatMFFD mfctx; 593 594 PetscFunctionBegin; 595 PetscCall(MatMFFDInitializePackage()); 596 597 PetscCall(PetscHeaderCreate(mfctx,MATMFFD_CLASSID,"MatMFFD","Matrix-free Finite Differencing","Mat",PetscObjectComm((PetscObject)A),NULL,NULL)); 598 599 mfctx->error_rel = PETSC_SQRT_MACHINE_EPSILON; 600 mfctx->recomputeperiod = 1; 601 mfctx->count = 0; 602 mfctx->currenth = 0.0; 603 mfctx->historyh = NULL; 604 mfctx->ncurrenth = 0; 605 mfctx->maxcurrenth = 0; 606 ((PetscObject)mfctx)->type_name = NULL; 607 608 /* 609 Create the empty data structure to contain compute-h routines. 610 These will be filled in below from the command line options or 611 a later call with MatMFFDSetType() or if that is not called 612 then it will default in the first use of MatMult_MFFD() 613 */ 614 mfctx->ops->compute = NULL; 615 mfctx->ops->destroy = NULL; 616 mfctx->ops->view = NULL; 617 mfctx->ops->setfromoptions = NULL; 618 mfctx->hctx = NULL; 619 620 mfctx->func = NULL; 621 mfctx->funcctx = NULL; 622 mfctx->w = NULL; 623 mfctx->mat = A; 624 625 PetscCall(MatSetType(A,MATSHELL)); 626 PetscCall(MatShellSetContext(A,mfctx)); 627 PetscCall(MatShellSetOperation(A,MATOP_MULT,(void (*)(void))MatMult_MFFD)); 628 PetscCall(MatShellSetOperation(A,MATOP_DESTROY,(void (*)(void))MatDestroy_MFFD)); 629 PetscCall(MatShellSetOperation(A,MATOP_VIEW,(void (*)(void))MatView_MFFD)); 630 PetscCall(MatShellSetOperation(A,MATOP_ASSEMBLY_END,(void (*)(void))MatAssemblyEnd_MFFD)); 631 PetscCall(MatShellSetOperation(A,MATOP_SET_FROM_OPTIONS,(void (*)(void))MatSetFromOptions_MFFD)); 632 633 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatMFFDSetBase_C",MatMFFDSetBase_MFFD)); 634 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatMFFDSetFunctioniBase_C",MatMFFDSetFunctioniBase_MFFD)); 635 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatMFFDSetFunctioni_C",MatMFFDSetFunctioni_MFFD)); 636 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatMFFDSetFunction_C",MatMFFDSetFunction_MFFD)); 637 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatMFFDSetCheckh_C",MatMFFDSetCheckh_MFFD)); 638 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatMFFDSetPeriod_C",MatMFFDSetPeriod_MFFD)); 639 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatMFFDSetFunctionError_C",MatMFFDSetFunctionError_MFFD)); 640 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatMFFDResetHHistory_C",MatMFFDResetHHistory_MFFD)); 641 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatMFFDSetHHistory_C",MatMFFDSetHHistory_MFFD)); 642 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatMFFDSetType_C",MatMFFDSetType_MFFD)); 643 PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatMFFDGetH_C",MatMFFDGetH_MFFD)); 644 PetscCall(PetscObjectChangeTypeName((PetscObject)A,MATMFFD)); 645 PetscFunctionReturn(0); 646 } 647 648 /*@ 649 MatCreateMFFD - Creates a matrix-free matrix. See also MatCreateSNESMF() 650 651 Collective on Vec 652 653 Input Parameters: 654 + comm - MPI communicator 655 . m - number of local rows (or PETSC_DECIDE to have calculated if M is given) 656 This value should be the same as the local size used in creating the 657 y vector for the matrix-vector product y = Ax. 658 . n - This value should be the same as the local size used in creating the 659 x vector for the matrix-vector product y = Ax. (or PETSC_DECIDE to have 660 calculated if N is given) For square matrices n is almost always m. 661 . M - number of global rows (or PETSC_DETERMINE to have calculated if m is given) 662 - N - number of global columns (or PETSC_DETERMINE to have calculated if n is given) 663 664 Output Parameter: 665 . J - the matrix-free matrix 666 667 Options Database Keys: call MatSetFromOptions() to trigger these 668 + -mat_mffd_type - wp or ds (see MATMFFD_WP or MATMFFD_DS) 669 . -mat_mffd_err - square root of estimated relative error in function evaluation 670 . -mat_mffd_period - how often h is recomputed, defaults to 1, every time 671 . -mat_mffd_check_positivity - possibly decrease h until U + h*a has only positive values 672 - -mat_mffd_complex - use the Lyness trick with complex numbers to compute the matrix-vector product instead of differencing 673 (requires real valued functions but that PETSc be configured for complex numbers) 674 675 Level: advanced 676 677 Notes: 678 The matrix-free matrix context merely contains the function pointers 679 and work space for performing finite difference approximations of 680 Jacobian-vector products, F'(u)*a, 681 682 The default code uses the following approach to compute h 683 684 .vb 685 F'(u)*a = [F(u+h*a) - F(u)]/h where 686 h = error_rel*u'a/||a||^2 if |u'a| > umin*||a||_{1} 687 = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2 otherwise 688 where 689 error_rel = square root of relative error in function evaluation 690 umin = minimum iterate parameter 691 .ve 692 693 You can call SNESSetJacobian() with MatMFFDComputeJacobian() if you are using matrix and not a different 694 preconditioner matrix 695 696 The user can set the error_rel via MatMFFDSetFunctionError() and 697 umin via MatMFFDDSSetUmin(); see Users-Manual: ch_snes for details. 698 699 The user should call MatDestroy() when finished with the matrix-free 700 matrix context. 701 702 Options Database Keys: 703 + -mat_mffd_err <error_rel> - Sets error_rel 704 . -mat_mffd_umin <umin> - Sets umin (for default PETSc routine that computes h only) 705 - -mat_mffd_check_positivity - check positivity 706 707 .seealso: `MatDestroy()`, `MatMFFDSetFunctionError()`, `MatMFFDDSSetUmin()`, `MatMFFDSetFunction()` 708 `MatMFFDSetHHistory()`, `MatMFFDResetHHistory()`, `MatCreateSNESMF()`, 709 `MatMFFDGetH()`, `MatMFFDRegister()`, `MatMFFDComputeJacobian()` 710 711 @*/ 712 PetscErrorCode MatCreateMFFD(MPI_Comm comm,PetscInt m,PetscInt n,PetscInt M,PetscInt N,Mat *J) 713 { 714 PetscFunctionBegin; 715 PetscCall(MatCreate(comm,J)); 716 PetscCall(MatSetSizes(*J,m,n,M,N)); 717 PetscCall(MatSetType(*J,MATMFFD)); 718 PetscCall(MatSetUp(*J)); 719 PetscFunctionReturn(0); 720 } 721 722 /*@ 723 MatMFFDGetH - Gets the last value that was used as the differencing 724 parameter. 725 726 Not Collective 727 728 Input Parameters: 729 . mat - the matrix obtained with MatCreateSNESMF() 730 731 Output Parameter: 732 . h - the differencing step size 733 734 Level: advanced 735 736 .seealso: `MatCreateSNESMF()`, `MatMFFDSetHHistory()`, `MatCreateMFFD()`, `MATMFFD`, `MatMFFDResetHHistory()` 737 @*/ 738 PetscErrorCode MatMFFDGetH(Mat mat,PetscScalar *h) 739 { 740 PetscFunctionBegin; 741 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 742 PetscValidScalarPointer(h,2); 743 PetscUseMethod(mat,"MatMFFDGetH_C",(Mat,PetscScalar*),(mat,h)); 744 PetscFunctionReturn(0); 745 } 746 747 /*@C 748 MatMFFDSetFunction - Sets the function used in applying the matrix free. 749 750 Logically Collective on Mat 751 752 Input Parameters: 753 + mat - the matrix free matrix created via MatCreateSNESMF() or MatCreateMFFD() 754 . func - the function to use 755 - funcctx - optional function context passed to function 756 757 Calling Sequence of func: 758 $ func (void *funcctx, Vec x, Vec f) 759 760 + funcctx - user provided context 761 . x - input vector 762 - f - computed output function 763 764 Level: advanced 765 766 Notes: 767 If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free 768 matrix inside your compute Jacobian routine 769 770 If this is not set then it will use the function set with SNESSetFunction() if MatCreateSNESMF() was used. 771 772 .seealso: `MatCreateSNESMF()`, `MatMFFDGetH()`, `MatCreateMFFD()`, `MATMFFD`, 773 `MatMFFDSetHHistory()`, `MatMFFDResetHHistory()`, `SNESetFunction()` 774 @*/ 775 PetscErrorCode MatMFFDSetFunction(Mat mat,PetscErrorCode (*func)(void*,Vec,Vec),void *funcctx) 776 { 777 PetscFunctionBegin; 778 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 779 PetscTryMethod(mat,"MatMFFDSetFunction_C",(Mat,PetscErrorCode (*)(void*,Vec,Vec),void*),(mat,func,funcctx)); 780 PetscFunctionReturn(0); 781 } 782 783 /*@C 784 MatMFFDSetFunctioni - Sets the function for a single component 785 786 Logically Collective on Mat 787 788 Input Parameters: 789 + mat - the matrix free matrix created via MatCreateSNESMF() 790 - funci - the function to use 791 792 Level: advanced 793 794 Notes: 795 If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free 796 matrix inside your compute Jacobian routine. 797 This function is necessary to compute the diagonal of the matrix. 798 funci must not contain any MPI call as it is called inside a loop on the local portion of the vector. 799 800 .seealso: `MatCreateSNESMF()`, `MatMFFDGetH()`, `MatMFFDSetHHistory()`, `MatMFFDResetHHistory()`, `SNESetFunction()`, `MatGetDiagonal()` 801 802 @*/ 803 PetscErrorCode MatMFFDSetFunctioni(Mat mat,PetscErrorCode (*funci)(void*,PetscInt,Vec,PetscScalar*)) 804 { 805 PetscFunctionBegin; 806 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 807 PetscTryMethod(mat,"MatMFFDSetFunctioni_C",(Mat,PetscErrorCode (*)(void*,PetscInt,Vec,PetscScalar*)),(mat,funci)); 808 PetscFunctionReturn(0); 809 } 810 811 /*@C 812 MatMFFDSetFunctioniBase - Sets the base vector for a single component function evaluation 813 814 Logically Collective on Mat 815 816 Input Parameters: 817 + mat - the matrix free matrix created via MatCreateSNESMF() 818 - func - the function to use 819 820 Level: advanced 821 822 Notes: 823 If you use this you MUST call MatAssemblyBegin()/MatAssemblyEnd() on the matrix free 824 matrix inside your compute Jacobian routine. 825 This function is necessary to compute the diagonal of the matrix. 826 827 .seealso: `MatCreateSNESMF()`, `MatMFFDGetH()`, `MatCreateMFFD()`, `MATMFFD` 828 `MatMFFDSetHHistory()`, `MatMFFDResetHHistory()`, `SNESetFunction()`, `MatGetDiagonal()` 829 @*/ 830 PetscErrorCode MatMFFDSetFunctioniBase(Mat mat,PetscErrorCode (*func)(void*,Vec)) 831 { 832 PetscFunctionBegin; 833 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 834 PetscTryMethod(mat,"MatMFFDSetFunctioniBase_C",(Mat,PetscErrorCode (*)(void*,Vec)),(mat,func)); 835 PetscFunctionReturn(0); 836 } 837 838 /*@ 839 MatMFFDSetPeriod - Sets how often h is recomputed, by default it is every time 840 841 Logically Collective on Mat 842 843 Input Parameters: 844 + mat - the matrix free matrix created via MatCreateSNESMF() 845 - period - 1 for every time, 2 for every second etc 846 847 Options Database Keys: 848 . -mat_mffd_period <period> - Sets how often h is recomputed 849 850 Level: advanced 851 852 .seealso: `MatCreateSNESMF()`, `MatMFFDGetH()`, 853 `MatMFFDSetHHistory()`, `MatMFFDResetHHistory()` 854 @*/ 855 PetscErrorCode MatMFFDSetPeriod(Mat mat,PetscInt period) 856 { 857 PetscFunctionBegin; 858 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 859 PetscValidLogicalCollectiveInt(mat,period,2); 860 PetscTryMethod(mat,"MatMFFDSetPeriod_C",(Mat,PetscInt),(mat,period)); 861 PetscFunctionReturn(0); 862 } 863 864 /*@ 865 MatMFFDSetFunctionError - Sets the error_rel for the approximation of 866 matrix-vector products using finite differences. 867 868 Logically Collective on Mat 869 870 Input Parameters: 871 + mat - the matrix free matrix created via MatCreateMFFD() or MatCreateSNESMF() 872 - error_rel - relative error (should be set to the square root of 873 the relative error in the function evaluations) 874 875 Options Database Keys: 876 . -mat_mffd_err <error_rel> - Sets error_rel 877 878 Level: advanced 879 880 Notes: 881 The default matrix-free matrix-vector product routine computes 882 .vb 883 F'(u)*a = [F(u+h*a) - F(u)]/h where 884 h = error_rel*u'a/||a||^2 if |u'a| > umin*||a||_{1} 885 = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2 else 886 .ve 887 888 .seealso: `MatCreateSNESMF()`, `MatMFFDGetH()`, `MatCreateMFFD()`, `MATMFFD` 889 `MatMFFDSetHHistory()`, `MatMFFDResetHHistory()` 890 @*/ 891 PetscErrorCode MatMFFDSetFunctionError(Mat mat,PetscReal error) 892 { 893 PetscFunctionBegin; 894 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 895 PetscValidLogicalCollectiveReal(mat,error,2); 896 PetscTryMethod(mat,"MatMFFDSetFunctionError_C",(Mat,PetscReal),(mat,error)); 897 PetscFunctionReturn(0); 898 } 899 900 /*@ 901 MatMFFDSetHHistory - Sets an array to collect a history of the 902 differencing values (h) computed for the matrix-free product. 903 904 Logically Collective on Mat 905 906 Input Parameters: 907 + J - the matrix-free matrix context 908 . history - space to hold the history 909 - nhistory - number of entries in history, if more entries are generated than 910 nhistory, then the later ones are discarded 911 912 Level: advanced 913 914 Notes: 915 Use MatMFFDResetHHistory() to reset the history counter and collect 916 a new batch of differencing parameters, h. 917 918 .seealso: `MatMFFDGetH()`, `MatCreateSNESMF()`, 919 `MatMFFDResetHHistory()`, `MatMFFDSetFunctionError()` 920 921 @*/ 922 PetscErrorCode MatMFFDSetHHistory(Mat J,PetscScalar history[],PetscInt nhistory) 923 { 924 PetscFunctionBegin; 925 PetscValidHeaderSpecific(J,MAT_CLASSID,1); 926 if (history) PetscValidScalarPointer(history,2); 927 PetscValidLogicalCollectiveInt(J,nhistory,3); 928 PetscUseMethod(J,"MatMFFDSetHHistory_C",(Mat,PetscScalar[],PetscInt),(J,history,nhistory)); 929 PetscFunctionReturn(0); 930 } 931 932 /*@ 933 MatMFFDResetHHistory - Resets the counter to zero to begin 934 collecting a new set of differencing histories. 935 936 Logically Collective on Mat 937 938 Input Parameters: 939 . J - the matrix-free matrix context 940 941 Level: advanced 942 943 Notes: 944 Use MatMFFDSetHHistory() to create the original history counter. 945 946 .seealso: `MatMFFDGetH()`, `MatCreateSNESMF()`, 947 `MatMFFDSetHHistory()`, `MatMFFDSetFunctionError()` 948 949 @*/ 950 PetscErrorCode MatMFFDResetHHistory(Mat J) 951 { 952 PetscFunctionBegin; 953 PetscValidHeaderSpecific(J,MAT_CLASSID,1); 954 PetscTryMethod(J,"MatMFFDResetHHistory_C",(Mat),(J)); 955 PetscFunctionReturn(0); 956 } 957 958 /*@ 959 MatMFFDSetBase - Sets the vector U at which matrix vector products of the 960 Jacobian are computed 961 962 Logically Collective on Mat 963 964 Input Parameters: 965 + J - the MatMFFD matrix 966 . U - the vector 967 - F - (optional) vector that contains F(u) if it has been already computed 968 969 Notes: 970 This is rarely used directly 971 972 If F is provided then it is not recomputed. Otherwise the function is evaluated at the base 973 point during the first MatMult() after each call to MatMFFDSetBase(). 974 975 Level: advanced 976 977 @*/ 978 PetscErrorCode MatMFFDSetBase(Mat J,Vec U,Vec F) 979 { 980 PetscFunctionBegin; 981 PetscValidHeaderSpecific(J,MAT_CLASSID,1); 982 PetscValidHeaderSpecific(U,VEC_CLASSID,2); 983 if (F) PetscValidHeaderSpecific(F,VEC_CLASSID,3); 984 PetscTryMethod(J,"MatMFFDSetBase_C",(Mat,Vec,Vec),(J,U,F)); 985 PetscFunctionReturn(0); 986 } 987 988 /*@C 989 MatMFFDSetCheckh - Sets a function that checks the computed h and adjusts 990 it to satisfy some criteria 991 992 Logically Collective on Mat 993 994 Input Parameters: 995 + J - the MatMFFD matrix 996 . fun - the function that checks h 997 - ctx - any context needed by the function 998 999 Options Database Keys: 1000 . -mat_mffd_check_positivity <bool> - Insure that U + h*a is non-negative 1001 1002 Level: advanced 1003 1004 Notes: 1005 For example, MatMFFDCheckPositivity() insures that all entries 1006 of U + h*a are non-negative 1007 1008 The function you provide is called after the default h has been computed and allows you to 1009 modify it. 1010 1011 .seealso: `MatMFFDCheckPositivity()` 1012 @*/ 1013 PetscErrorCode MatMFFDSetCheckh(Mat J,PetscErrorCode (*fun)(void*,Vec,Vec,PetscScalar*),void *ctx) 1014 { 1015 PetscFunctionBegin; 1016 PetscValidHeaderSpecific(J,MAT_CLASSID,1); 1017 PetscTryMethod(J,"MatMFFDSetCheckh_C",(Mat,PetscErrorCode (*)(void*,Vec,Vec,PetscScalar*),void*),(J,fun,ctx)); 1018 PetscFunctionReturn(0); 1019 } 1020 1021 /*@ 1022 MatMFFDCheckPositivity - Checks that all entries in U + h*a are positive or 1023 zero, decreases h until this is satisfied. 1024 1025 Logically Collective on Vec 1026 1027 Input Parameters: 1028 + U - base vector that is added to 1029 . a - vector that is added 1030 . h - scaling factor on a 1031 - dummy - context variable (unused) 1032 1033 Options Database Keys: 1034 . -mat_mffd_check_positivity <bool> - Insure that U + h*a is nonnegative 1035 1036 Level: advanced 1037 1038 Notes: 1039 This is rarely used directly, rather it is passed as an argument to 1040 MatMFFDSetCheckh() 1041 1042 .seealso: `MatMFFDSetCheckh()` 1043 @*/ 1044 PetscErrorCode MatMFFDCheckPositivity(void *dummy,Vec U,Vec a,PetscScalar *h) 1045 { 1046 PetscReal val, minval; 1047 PetscScalar *u_vec, *a_vec; 1048 PetscInt i,n; 1049 MPI_Comm comm; 1050 1051 PetscFunctionBegin; 1052 PetscValidHeaderSpecific(U,VEC_CLASSID,2); 1053 PetscValidHeaderSpecific(a,VEC_CLASSID,3); 1054 PetscValidScalarPointer(h,4); 1055 PetscCall(PetscObjectGetComm((PetscObject)U,&comm)); 1056 PetscCall(VecGetArray(U,&u_vec)); 1057 PetscCall(VecGetArray(a,&a_vec)); 1058 PetscCall(VecGetLocalSize(U,&n)); 1059 minval = PetscAbsScalar(*h)*PetscRealConstant(1.01); 1060 for (i=0; i<n; i++) { 1061 if (PetscRealPart(u_vec[i] + *h*a_vec[i]) <= 0.0) { 1062 val = PetscAbsScalar(u_vec[i]/a_vec[i]); 1063 if (val < minval) minval = val; 1064 } 1065 } 1066 PetscCall(VecRestoreArray(U,&u_vec)); 1067 PetscCall(VecRestoreArray(a,&a_vec)); 1068 PetscCall(MPIU_Allreduce(&minval,&val,1,MPIU_REAL,MPIU_MIN,comm)); 1069 if (val <= PetscAbsScalar(*h)) { 1070 PetscCall(PetscInfo(U,"Scaling back h from %g to %g\n",(double)PetscRealPart(*h),(double)(.99*val))); 1071 if (PetscRealPart(*h) > 0.0) *h = 0.99*val; 1072 else *h = -0.99*val; 1073 } 1074 PetscFunctionReturn(0); 1075 } 1076