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