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