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 `MatMFFDSetType`(mfctx, "my_h")` or at runtime via the option 191 `-mat_mffd_type my_h` 192 193 .seealso: [](ch_matrices), `Mat`, `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(PETSC_SUCCESS); 201 } 202 203 static PetscErrorCode MatDestroy_MFFD(Mat mat) 204 { 205 MatMFFD ctx; 206 207 PetscFunctionBegin; 208 PetscCall(MatShellGetContext(mat, &ctx)); 209 PetscCall(VecDestroy(&ctx->w)); 210 PetscCall(VecDestroy(&ctx->current_u)); 211 if (ctx->current_f_allocated) PetscCall(VecDestroy(&ctx->current_f)); 212 PetscTryTypeMethod(ctx, destroy); 213 PetscCall(PetscHeaderDestroy(&ctx)); 214 215 PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatMFFDSetBase_C", NULL)); 216 PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatMFFDSetFunctioniBase_C", NULL)); 217 PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatMFFDSetFunctioni_C", NULL)); 218 PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatMFFDSetFunction_C", NULL)); 219 PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatMFFDSetFunctionError_C", NULL)); 220 PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatMFFDSetCheckh_C", NULL)); 221 PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatMFFDSetPeriod_C", NULL)); 222 PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatMFFDResetHHistory_C", NULL)); 223 PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatMFFDSetHHistory_C", NULL)); 224 PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatMFFDSetType_C", NULL)); 225 PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatMFFDGetH_C", NULL)); 226 PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatSNESMFSetReuseBase_C", NULL)); 227 PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatSNESMFGetReuseBase_C", NULL)); 228 PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatShellSetContext_C", NULL)); 229 PetscFunctionReturn(PETSC_SUCCESS); 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(PETSC_SUCCESS); 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(PETSC_SUCCESS); 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 MatAssemblyBegin/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(PETSC_SUCCESS); 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(PETSC_SUCCESS); 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 static 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(PETSC_SUCCESS); 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(PETSC_SUCCESS); 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(PETSC_SUCCESS); 464 } 465 466 /*@C 467 MatMFFDSetOptionsPrefix - Sets the prefix used for searching for all 468 MATMFFD` options in the database. 469 470 Collective 471 472 Input Parameters: 473 + mat - 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: [](ch_matrices), `Mat`, `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(PETSC_SUCCESS); 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(PETSC_SUCCESS); 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(PETSC_SUCCESS); 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(PETSC_SUCCESS); 542 } 543 544 static PetscErrorCode MatMFFDSetFunctionError_MFFD(Mat mat, PetscReal error) 545 { 546 PetscFunctionBegin; 547 if (error != (PetscReal)PETSC_DEFAULT) { 548 MatMFFD ctx; 549 550 PetscCall(MatShellGetContext(mat, &ctx)); 551 ctx->error_rel = error; 552 } 553 PetscFunctionReturn(PETSC_SUCCESS); 554 } 555 556 static PetscErrorCode MatMFFDSetHHistory_MFFD(Mat J, PetscScalar history[], PetscInt nhistory) 557 { 558 MatMFFD ctx; 559 560 PetscFunctionBegin; 561 PetscCall(MatShellGetContext(J, &ctx)); 562 ctx->historyh = history; 563 ctx->maxcurrenth = nhistory; 564 ctx->currenth = 0.; 565 PetscFunctionReturn(PETSC_SUCCESS); 566 } 567 568 /*MC 569 MATMFFD - "mffd" - A matrix-free matrix type. 570 571 Level: advanced 572 573 Developer Notes: 574 This is implemented on top of `MATSHELL` to get support for scaling and shifting without requiring duplicate code 575 576 Users should not MatShell... operations on this class, there is some error checking for that incorrect usage 577 578 .seealso: [](ch_matrices), `Mat`, `MatCreateMFFD()`, `MatCreateSNESMF()`, `MatMFFDSetFunction()`, `MatMFFDSetType()`, 579 `MatMFFDSetFunctionError()`, `MatMFFDDSSetUmin()`, `MatMFFDSetFunction()` 580 `MatMFFDSetHHistory()`, `MatMFFDResetHHistory()`, `MatCreateSNESMF()`, 581 `MatMFFDGetH()`, 582 M*/ 583 PETSC_EXTERN PetscErrorCode MatCreate_MFFD(Mat A) 584 { 585 MatMFFD mfctx; 586 587 PetscFunctionBegin; 588 PetscCall(MatMFFDInitializePackage()); 589 590 PetscCall(PetscHeaderCreate(mfctx, MATMFFD_CLASSID, "MatMFFD", "Matrix-free Finite Differencing", "Mat", PetscObjectComm((PetscObject)A), NULL, NULL)); 591 592 mfctx->error_rel = PETSC_SQRT_MACHINE_EPSILON; 593 mfctx->recomputeperiod = 1; 594 mfctx->count = 0; 595 mfctx->currenth = 0.0; 596 mfctx->historyh = NULL; 597 mfctx->ncurrenth = 0; 598 mfctx->maxcurrenth = 0; 599 ((PetscObject)mfctx)->type_name = NULL; 600 601 /* 602 Create the empty data structure to contain compute-h routines. 603 These will be filled in below from the command line options or 604 a later call with MatMFFDSetType() or if that is not called 605 then it will default in the first use of MatMult_MFFD() 606 */ 607 mfctx->ops->compute = NULL; 608 mfctx->ops->destroy = NULL; 609 mfctx->ops->view = NULL; 610 mfctx->ops->setfromoptions = NULL; 611 mfctx->hctx = NULL; 612 613 mfctx->func = NULL; 614 mfctx->funcctx = NULL; 615 mfctx->w = NULL; 616 mfctx->mat = A; 617 618 PetscCall(MatSetType(A, MATSHELL)); 619 PetscCall(MatShellSetContext(A, mfctx)); 620 PetscCall(MatShellSetOperation(A, MATOP_MULT, (void (*)(void))MatMult_MFFD)); 621 PetscCall(MatShellSetOperation(A, MATOP_DESTROY, (void (*)(void))MatDestroy_MFFD)); 622 PetscCall(MatShellSetOperation(A, MATOP_VIEW, (void (*)(void))MatView_MFFD)); 623 PetscCall(MatShellSetOperation(A, MATOP_ASSEMBLY_END, (void (*)(void))MatAssemblyEnd_MFFD)); 624 PetscCall(MatShellSetOperation(A, MATOP_SET_FROM_OPTIONS, (void (*)(void))MatSetFromOptions_MFFD)); 625 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetContext_C", MatShellSetContext_Immutable)); 626 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetContextDestroy_C", MatShellSetContextDestroy_Immutable)); 627 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatShellSetManageScalingShifts_C", MatShellSetManageScalingShifts_Immutable)); 628 629 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatMFFDSetBase_C", MatMFFDSetBase_MFFD)); 630 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatMFFDSetFunctioniBase_C", MatMFFDSetFunctioniBase_MFFD)); 631 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatMFFDSetFunctioni_C", MatMFFDSetFunctioni_MFFD)); 632 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatMFFDSetFunction_C", MatMFFDSetFunction_MFFD)); 633 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatMFFDSetCheckh_C", MatMFFDSetCheckh_MFFD)); 634 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatMFFDSetPeriod_C", MatMFFDSetPeriod_MFFD)); 635 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatMFFDSetFunctionError_C", MatMFFDSetFunctionError_MFFD)); 636 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatMFFDResetHHistory_C", MatMFFDResetHHistory_MFFD)); 637 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatMFFDSetHHistory_C", MatMFFDSetHHistory_MFFD)); 638 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatMFFDSetType_C", MatMFFDSetType_MFFD)); 639 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatMFFDGetH_C", MatMFFDGetH_MFFD)); 640 PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATMFFD)); 641 PetscFunctionReturn(PETSC_SUCCESS); 642 } 643 644 /*@ 645 MatCreateMFFD - Creates a matrix-free matrix of type `MATMFFD`. See also `MatCreateSNESMF()` 646 647 Collective 648 649 Input Parameters: 650 + comm - MPI communicator 651 . m - number of local rows (or `PETSC_DECIDE` to have calculated if `M` is given) 652 This value should be the same as the local size used in creating the 653 y vector for the matrix-vector product y = Ax. 654 . n - This value should be the same as the local size used in creating the 655 x vector for the matrix-vector product y = Ax. (or `PETSC_DECIDE` to have 656 calculated if `N` is given) For square matrices `n` is almost always `m`. 657 . M - number of global rows (or `PETSC_DETERMINE` to have calculated if `m` is given) 658 - N - number of global columns (or `PETSC_DETERMINE` to have calculated if `n` is given) 659 660 Output Parameter: 661 . J - the matrix-free matrix 662 663 Options Database Keys: 664 + -mat_mffd_type - wp or ds (see `MATMFFD_WP` or `MATMFFD_DS`) 665 . -mat_mffd_err - square root of estimated relative error in function evaluation 666 . -mat_mffd_period - how often h is recomputed, defaults to 1, every time 667 . -mat_mffd_check_positivity - possibly decrease `h` until U + h*a has only positive values 668 . -mat_mffd_umin <umin> - Sets umin (for default PETSc routine that computes h only) 669 - -mat_mffd_complex - use the Lyness trick with complex numbers to compute the matrix-vector product instead of differencing 670 (requires real valued functions but that PETSc be configured for complex numbers) 671 672 Level: advanced 673 674 Notes: 675 The matrix-free matrix context merely contains the function pointers 676 and work space for performing finite difference approximations of 677 Jacobian-vector products, F'(u)*a, 678 679 The default code uses the following approach to compute h 680 681 .vb 682 F'(u)*a = [F(u+h*a) - F(u)]/h where 683 h = error_rel*u'a/||a||^2 if |u'a| > umin*||a||_{1} 684 = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2 otherwise 685 where 686 error_rel = square root of relative error in function evaluation 687 umin = minimum iterate parameter 688 .ve 689 690 You can call `SNESSetJacobian()` with `MatMFFDComputeJacobian()` if you are using matrix and not a different 691 preconditioner matrix 692 693 The user can set the error_rel via `MatMFFDSetFunctionError()` and 694 umin via `MatMFFDDSSetUmin()`. 695 696 The user should call `MatDestroy()` when finished with the matrix-free 697 matrix context. 698 699 .seealso: [](ch_matrices), `Mat`, `MATMFFD`, `MatDestroy()`, `MatMFFDSetFunctionError()`, `MatMFFDDSSetUmin()`, `MatMFFDSetFunction()` 700 `MatMFFDSetHHistory()`, `MatMFFDResetHHistory()`, `MatCreateSNESMF()`, 701 `MatMFFDGetH()`, `MatMFFDRegister()`, `MatMFFDComputeJacobian()` 702 @*/ 703 PetscErrorCode MatCreateMFFD(MPI_Comm comm, PetscInt m, PetscInt n, PetscInt M, PetscInt N, Mat *J) 704 { 705 PetscFunctionBegin; 706 PetscCall(MatCreate(comm, J)); 707 PetscCall(MatSetSizes(*J, m, n, M, N)); 708 PetscCall(MatSetType(*J, MATMFFD)); 709 PetscCall(MatSetUp(*J)); 710 PetscFunctionReturn(PETSC_SUCCESS); 711 } 712 713 /*@ 714 MatMFFDGetH - Gets the last value that was used as the differencing for a `MATMFFD` matrix 715 parameter. 716 717 Not Collective 718 719 Input Parameters: 720 . mat - the `MATMFFD` matrix 721 722 Output Parameter: 723 . h - the differencing step size 724 725 Level: advanced 726 727 .seealso: [](ch_matrices), `Mat`, `MATMFFD`, `MatCreateSNESMF()`, `MatMFFDSetHHistory()`, `MatCreateMFFD()`, `MatMFFDResetHHistory()` 728 @*/ 729 PetscErrorCode MatMFFDGetH(Mat mat, PetscScalar *h) 730 { 731 PetscFunctionBegin; 732 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 733 PetscAssertPointer(h, 2); 734 PetscUseMethod(mat, "MatMFFDGetH_C", (Mat, PetscScalar *), (mat, h)); 735 PetscFunctionReturn(PETSC_SUCCESS); 736 } 737 738 /*@C 739 MatMFFDSetFunction - Sets the function used in applying the matrix-free `MATMFFD` matrix. 740 741 Logically Collective 742 743 Input Parameters: 744 + mat - the matrix-free matrix `MATMFFD` created via `MatCreateSNESMF()` or `MatCreateMFFD()` 745 . func - the function to use 746 - funcctx - optional function context passed to function 747 748 Calling sequence of `func`: 749 + funcctx - user provided context 750 . x - input vector 751 - f - computed output function 752 753 Level: advanced 754 755 Notes: 756 If you use this you MUST call `MatAssemblyBegin()` and `MatAssemblyEnd()` on the matrix-free 757 matrix inside your compute Jacobian routine 758 759 If this is not set then it will use the function set with `SNESSetFunction()` if `MatCreateSNESMF()` was used. 760 761 .seealso: [](ch_matrices), `Mat`, `MATMFFD`, `MatCreateSNESMF()`, `MatMFFDGetH()`, `MatCreateMFFD()`, 762 `MatMFFDSetHHistory()`, `MatMFFDResetHHistory()`, `SNESSetFunction()` 763 @*/ 764 PetscErrorCode MatMFFDSetFunction(Mat mat, PetscErrorCode (*func)(void *funcctx, Vec x, Vec f), void *funcctx) 765 { 766 PetscFunctionBegin; 767 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 768 PetscTryMethod(mat, "MatMFFDSetFunction_C", (Mat, PetscErrorCode(*)(void *, Vec, Vec), void *), (mat, func, funcctx)); 769 PetscFunctionReturn(PETSC_SUCCESS); 770 } 771 772 /*@C 773 MatMFFDSetFunctioni - Sets the function for a single component for a `MATMFFD` matrix 774 775 Logically Collective 776 777 Input Parameters: 778 + mat - the matrix-free matrix `MATMFFD` 779 - funci - the function to use 780 781 Level: advanced 782 783 Notes: 784 If you use this you MUST call `MatAssemblyBegin()` and `MatAssemblyEnd()` on the matrix-free 785 matrix inside your compute Jacobian routine. 786 787 This function is necessary to compute the diagonal of the matrix. 788 funci must not contain any MPI call as it is called inside a loop on the local portion of the vector. 789 790 .seealso: [](ch_matrices), `Mat`, `MATMFFD`, `MatCreateSNESMF()`, `MatMFFDGetH()`, `MatMFFDSetHHistory()`, `MatMFFDResetHHistory()`, `SNESetFunction()`, `MatGetDiagonal()` 791 @*/ 792 PetscErrorCode MatMFFDSetFunctioni(Mat mat, PetscErrorCode (*funci)(void *, PetscInt, Vec, PetscScalar *)) 793 { 794 PetscFunctionBegin; 795 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 796 PetscTryMethod(mat, "MatMFFDSetFunctioni_C", (Mat, PetscErrorCode(*)(void *, PetscInt, Vec, PetscScalar *)), (mat, funci)); 797 PetscFunctionReturn(PETSC_SUCCESS); 798 } 799 800 /*@C 801 MatMFFDSetFunctioniBase - Sets the base vector for a single component function evaluation for a `MATMFFD` matrix 802 803 Logically Collective 804 805 Input Parameters: 806 + mat - the `MATMFFD` matrix-free matrix 807 - func - the function to use 808 809 Level: advanced 810 811 Notes: 812 If you use this you MUST call `MatAssemblyBegin()` and `MatAssemblyEnd()` on the matrix-free 813 matrix inside your compute Jacobian routine. 814 815 This function is necessary to compute the diagonal of the matrix, used for example with `PCJACOBI` 816 817 .seealso: [](ch_matrices), `Mat`, `MATMFFD`, `MatCreateSNESMF()`, `MatMFFDGetH()`, `MatCreateMFFD()`, 818 `MatMFFDSetHHistory()`, `MatMFFDResetHHistory()`, `SNESetFunction()`, `MatGetDiagonal()` 819 @*/ 820 PetscErrorCode MatMFFDSetFunctioniBase(Mat mat, PetscErrorCode (*func)(void *, Vec)) 821 { 822 PetscFunctionBegin; 823 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 824 PetscTryMethod(mat, "MatMFFDSetFunctioniBase_C", (Mat, PetscErrorCode(*)(void *, Vec)), (mat, func)); 825 PetscFunctionReturn(PETSC_SUCCESS); 826 } 827 828 /*@ 829 MatMFFDSetPeriod - Sets how often h is recomputed for a `MATMFFD` matrix, by default it is every time 830 831 Logically Collective 832 833 Input Parameters: 834 + mat - the `MATMFFD` matrix-free matrix 835 - period - 1 for every time, 2 for every second etc 836 837 Options Database Key: 838 . -mat_mffd_period <period> - Sets how often `h` is recomputed 839 840 Level: advanced 841 842 .seealso: [](ch_matrices), `Mat`, `MATMFFD`, `MatCreateSNESMF()`, `MatMFFDGetH()`, 843 `MatMFFDSetHHistory()`, `MatMFFDResetHHistory()` 844 @*/ 845 PetscErrorCode MatMFFDSetPeriod(Mat mat, PetscInt period) 846 { 847 PetscFunctionBegin; 848 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 849 PetscValidLogicalCollectiveInt(mat, period, 2); 850 PetscTryMethod(mat, "MatMFFDSetPeriod_C", (Mat, PetscInt), (mat, period)); 851 PetscFunctionReturn(PETSC_SUCCESS); 852 } 853 854 /*@ 855 MatMFFDSetFunctionError - Sets the error_rel for the approximation of matrix-vector products using finite differences with the `MATMFFD` matrix 856 857 Logically Collective 858 859 Input Parameters: 860 + mat - the `MATMFFD` matrix-free matrix 861 - error - relative error (should be set to the square root of the relative error in the function evaluations) 862 863 Options Database Key: 864 . -mat_mffd_err <error_rel> - Sets error_rel 865 866 Level: advanced 867 868 Note: 869 The default matrix-free matrix-vector product routine computes 870 .vb 871 F'(u)*a = [F(u+h*a) - F(u)]/h where 872 h = error_rel*u'a/||a||^2 if |u'a| > umin*||a||_{1} 873 = error_rel*umin*sign(u'a)*||a||_{1}/||a||^2 else 874 .ve 875 876 .seealso: [](ch_matrices), `Mat`, `MATMFFD`, `MatCreateSNESMF()`, `MatMFFDGetH()`, `MatCreateMFFD()`, 877 `MatMFFDSetHHistory()`, `MatMFFDResetHHistory()` 878 @*/ 879 PetscErrorCode MatMFFDSetFunctionError(Mat mat, PetscReal error) 880 { 881 PetscFunctionBegin; 882 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 883 PetscValidLogicalCollectiveReal(mat, error, 2); 884 PetscTryMethod(mat, "MatMFFDSetFunctionError_C", (Mat, PetscReal), (mat, error)); 885 PetscFunctionReturn(PETSC_SUCCESS); 886 } 887 888 /*@ 889 MatMFFDSetHHistory - Sets an array to collect a history of the 890 differencing values (h) computed for the matrix-free product `MATMFFD` matrix 891 892 Logically Collective 893 894 Input Parameters: 895 + J - the `MATMFFD` matrix-free matrix 896 . history - space to hold the history 897 - nhistory - number of entries in history, if more entries are generated than 898 nhistory, then the later ones are discarded 899 900 Level: advanced 901 902 Note: 903 Use `MatMFFDResetHHistory()` to reset the history counter and collect 904 a new batch of differencing parameters, h. 905 906 .seealso: [](ch_matrices), `Mat`, `MATMFFD`, `MatMFFDGetH()`, `MatCreateSNESMF()`, 907 `MatMFFDResetHHistory()`, `MatMFFDSetFunctionError()` 908 @*/ 909 PetscErrorCode MatMFFDSetHHistory(Mat J, PetscScalar history[], PetscInt nhistory) 910 { 911 PetscFunctionBegin; 912 PetscValidHeaderSpecific(J, MAT_CLASSID, 1); 913 if (history) PetscAssertPointer(history, 2); 914 PetscValidLogicalCollectiveInt(J, nhistory, 3); 915 PetscUseMethod(J, "MatMFFDSetHHistory_C", (Mat, PetscScalar[], PetscInt), (J, history, nhistory)); 916 PetscFunctionReturn(PETSC_SUCCESS); 917 } 918 919 /*@ 920 MatMFFDResetHHistory - Resets the counter to zero to begin 921 collecting a new set of differencing histories for the `MATMFFD` matrix 922 923 Logically Collective 924 925 Input Parameter: 926 . J - the matrix-free matrix context 927 928 Level: advanced 929 930 Note: 931 Use `MatMFFDSetHHistory()` to create the original history counter. 932 933 .seealso: [](ch_matrices), `Mat`, `MATMFFD`, `MatMFFDGetH()`, `MatCreateSNESMF()`, 934 `MatMFFDSetHHistory()`, `MatMFFDSetFunctionError()` 935 @*/ 936 PetscErrorCode MatMFFDResetHHistory(Mat J) 937 { 938 PetscFunctionBegin; 939 PetscValidHeaderSpecific(J, MAT_CLASSID, 1); 940 PetscTryMethod(J, "MatMFFDResetHHistory_C", (Mat), (J)); 941 PetscFunctionReturn(PETSC_SUCCESS); 942 } 943 944 /*@ 945 MatMFFDSetBase - Sets the vector `U` at which matrix vector products of the 946 Jacobian are computed for the `MATMFFD` matrix 947 948 Logically Collective 949 950 Input Parameters: 951 + J - the `MATMFFD` matrix 952 . U - the vector 953 - F - (optional) vector that contains F(u) if it has been already computed 954 955 Level: advanced 956 957 Notes: 958 This is rarely used directly 959 960 If `F` is provided then it is not recomputed. Otherwise the function is evaluated at the base 961 point during the first `MatMult()` after each call to `MatMFFDSetBase()`. 962 963 .seealso: [](ch_matrices), `Mat`, `MATMFFD`, `MatMult()` 964 @*/ 965 PetscErrorCode MatMFFDSetBase(Mat J, Vec U, Vec F) 966 { 967 PetscFunctionBegin; 968 PetscValidHeaderSpecific(J, MAT_CLASSID, 1); 969 PetscValidHeaderSpecific(U, VEC_CLASSID, 2); 970 if (F) PetscValidHeaderSpecific(F, VEC_CLASSID, 3); 971 PetscTryMethod(J, "MatMFFDSetBase_C", (Mat, Vec, Vec), (J, U, F)); 972 PetscFunctionReturn(PETSC_SUCCESS); 973 } 974 975 /*@C 976 MatMFFDSetCheckh - Sets a function that checks the computed h and adjusts 977 it to satisfy some criteria for the `MATMFFD` matrix 978 979 Logically Collective 980 981 Input Parameters: 982 + J - the `MATMFFD` matrix 983 . fun - the function that checks `h` 984 - ctx - any context needed by the function 985 986 Options Database Keys: 987 . -mat_mffd_check_positivity <bool> - Insure that U + h*a is non-negative 988 989 Level: advanced 990 991 Notes: 992 For example, `MatMFFDCheckPositivity()` insures that all entries of U + h*a are non-negative 993 994 The function you provide is called after the default `h` has been computed and allows you to 995 modify it. 996 997 .seealso: [](ch_matrices), `Mat`, `MATMFFD`, `MatMFFDCheckPositivity()` 998 @*/ 999 PetscErrorCode MatMFFDSetCheckh(Mat J, PetscErrorCode (*fun)(void *, Vec, Vec, PetscScalar *), void *ctx) 1000 { 1001 PetscFunctionBegin; 1002 PetscValidHeaderSpecific(J, MAT_CLASSID, 1); 1003 PetscTryMethod(J, "MatMFFDSetCheckh_C", (Mat, PetscErrorCode(*)(void *, Vec, Vec, PetscScalar *), void *), (J, fun, ctx)); 1004 PetscFunctionReturn(PETSC_SUCCESS); 1005 } 1006 1007 /*@ 1008 MatMFFDCheckPositivity - Checks that all entries in U + h*a are positive or 1009 zero, decreases h until this is satisfied for a `MATMFFD` matrix 1010 1011 Logically Collective 1012 1013 Input Parameters: 1014 + U - base vector that is added to 1015 . a - vector that is added 1016 . h - scaling factor on a 1017 - dummy - context variable (unused) 1018 1019 Options Database Keys: 1020 . -mat_mffd_check_positivity <bool> - Insure that U + h*a is nonnegative 1021 1022 Level: advanced 1023 1024 Note: 1025 This is rarely used directly, rather it is passed as an argument to `MatMFFDSetCheckh()` 1026 1027 .seealso: [](ch_matrices), `Mat`, `MATMFFD`, `MatMFFDSetCheckh()` 1028 @*/ 1029 PetscErrorCode MatMFFDCheckPositivity(void *dummy, Vec U, Vec a, PetscScalar *h) 1030 { 1031 PetscReal val, minval; 1032 PetscScalar *u_vec, *a_vec; 1033 PetscInt i, n; 1034 MPI_Comm comm; 1035 1036 PetscFunctionBegin; 1037 PetscValidHeaderSpecific(U, VEC_CLASSID, 2); 1038 PetscValidHeaderSpecific(a, VEC_CLASSID, 3); 1039 PetscAssertPointer(h, 4); 1040 PetscCall(PetscObjectGetComm((PetscObject)U, &comm)); 1041 PetscCall(VecGetArray(U, &u_vec)); 1042 PetscCall(VecGetArray(a, &a_vec)); 1043 PetscCall(VecGetLocalSize(U, &n)); 1044 minval = PetscAbsScalar(*h) * PetscRealConstant(1.01); 1045 for (i = 0; i < n; i++) { 1046 if (PetscRealPart(u_vec[i] + *h * a_vec[i]) <= 0.0) { 1047 val = PetscAbsScalar(u_vec[i] / a_vec[i]); 1048 if (val < minval) minval = val; 1049 } 1050 } 1051 PetscCall(VecRestoreArray(U, &u_vec)); 1052 PetscCall(VecRestoreArray(a, &a_vec)); 1053 PetscCall(MPIU_Allreduce(&minval, &val, 1, MPIU_REAL, MPIU_MIN, comm)); 1054 if (val <= PetscAbsScalar(*h)) { 1055 PetscCall(PetscInfo(U, "Scaling back h from %g to %g\n", (double)PetscRealPart(*h), (double)(.99 * val))); 1056 if (PetscRealPart(*h) > 0.0) *h = 0.99 * val; 1057 else *h = -0.99 * val; 1058 } 1059 PetscFunctionReturn(PETSC_SUCCESS); 1060 } 1061