1 #include <petsc/private/snesimpl.h> /*I "petscsnes.h" I*/ 2 #include <petsc/private/dmimpl.h> /*I "petscdm.h" I*/ 3 4 static PetscErrorCode DMSNESUnsetFunctionContext_DMSNES(DMSNES sdm) 5 { 6 PetscFunctionBegin; 7 PetscCall(PetscObjectCompose((PetscObject)sdm, "function ctx", NULL)); 8 sdm->functionctxcontainer = NULL; 9 PetscFunctionReturn(PETSC_SUCCESS); 10 } 11 12 static PetscErrorCode DMSNESUnsetJacobianContext_DMSNES(DMSNES sdm) 13 { 14 PetscFunctionBegin; 15 PetscCall(PetscObjectCompose((PetscObject)sdm, "jacobian ctx", NULL)); 16 sdm->jacobianctxcontainer = NULL; 17 PetscFunctionReturn(PETSC_SUCCESS); 18 } 19 20 static PetscErrorCode DMSNESDestroy(DMSNES *kdm) 21 { 22 PetscFunctionBegin; 23 if (!*kdm) PetscFunctionReturn(PETSC_SUCCESS); 24 PetscValidHeaderSpecific(*kdm, DMSNES_CLASSID, 1); 25 if (--((PetscObject)*kdm)->refct > 0) { 26 *kdm = NULL; 27 PetscFunctionReturn(PETSC_SUCCESS); 28 } 29 PetscCall(DMSNESUnsetFunctionContext_DMSNES(*kdm)); 30 PetscCall(DMSNESUnsetJacobianContext_DMSNES(*kdm)); 31 PetscTryTypeMethod(*kdm, destroy); 32 PetscCall(PetscHeaderDestroy(kdm)); 33 PetscFunctionReturn(PETSC_SUCCESS); 34 } 35 36 PetscErrorCode DMSNESLoad(DMSNES kdm, PetscViewer viewer) 37 { 38 PetscFunctionBegin; 39 PetscCall(PetscViewerBinaryRead(viewer, &kdm->ops->computefunction, 1, NULL, PETSC_FUNCTION)); 40 PetscCall(PetscViewerBinaryRead(viewer, &kdm->ops->computejacobian, 1, NULL, PETSC_FUNCTION)); 41 PetscFunctionReturn(PETSC_SUCCESS); 42 } 43 44 PetscErrorCode DMSNESView(DMSNES kdm, PetscViewer viewer) 45 { 46 PetscBool isascii, isbinary; 47 48 PetscFunctionBegin; 49 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii)); 50 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary)); 51 if (isascii) { 52 #if defined(PETSC_SERIALIZE_FUNCTIONS) 53 const char *fname; 54 55 PetscCall(PetscFPTFind(kdm->ops->computefunction, &fname)); 56 if (fname) PetscCall(PetscViewerASCIIPrintf(viewer, "Function used by SNES: %s\n", fname)); 57 PetscCall(PetscFPTFind(kdm->ops->computejacobian, &fname)); 58 if (fname) PetscCall(PetscViewerASCIIPrintf(viewer, "Jacobian function used by SNES: %s\n", fname)); 59 #endif 60 } else if (isbinary) { 61 struct { 62 SNESFunctionFn *func; 63 } funcstruct; 64 struct { 65 SNESJacobianFn *jac; 66 } jacstruct; 67 funcstruct.func = kdm->ops->computefunction; 68 jacstruct.jac = kdm->ops->computejacobian; 69 PetscCall(PetscViewerBinaryWrite(viewer, &funcstruct, 1, PETSC_FUNCTION)); 70 PetscCall(PetscViewerBinaryWrite(viewer, &jacstruct, 1, PETSC_FUNCTION)); 71 } 72 PetscFunctionReturn(PETSC_SUCCESS); 73 } 74 75 static PetscErrorCode DMSNESCreate(MPI_Comm comm, DMSNES *kdm) 76 { 77 PetscFunctionBegin; 78 PetscCall(SNESInitializePackage()); 79 PetscCall(PetscHeaderCreate(*kdm, DMSNES_CLASSID, "DMSNES", "DMSNES", "DMSNES", comm, DMSNESDestroy, DMSNESView)); 80 PetscFunctionReturn(PETSC_SUCCESS); 81 } 82 83 /* Attaches the DMSNES to the coarse level. 84 * Under what conditions should we copy versus duplicate? 85 */ 86 static PetscErrorCode DMCoarsenHook_DMSNES(DM dm, DM dmc, PetscCtx ctx) 87 { 88 PetscFunctionBegin; 89 PetscCall(DMCopyDMSNES(dm, dmc)); 90 PetscFunctionReturn(PETSC_SUCCESS); 91 } 92 93 /* This could restrict auxiliary information to the coarse level. 94 */ 95 static PetscErrorCode DMRestrictHook_DMSNES(DM dm, Mat Restrict, Vec rscale, Mat Inject, DM dmc, PetscCtx ctx) 96 { 97 PetscFunctionBegin; 98 PetscFunctionReturn(PETSC_SUCCESS); 99 } 100 101 /* Attaches the DMSNES to the subdomain. */ 102 static PetscErrorCode DMSubDomainHook_DMSNES(DM dm, DM subdm, PetscCtx ctx) 103 { 104 PetscFunctionBegin; 105 PetscCall(DMCopyDMSNES(dm, subdm)); 106 PetscFunctionReturn(PETSC_SUCCESS); 107 } 108 109 /* This could restrict auxiliary information to the coarse level. 110 */ 111 static PetscErrorCode DMSubDomainRestrictHook_DMSNES(DM dm, VecScatter gscat, VecScatter lscat, DM subdm, PetscCtx ctx) 112 { 113 PetscFunctionBegin; 114 PetscFunctionReturn(PETSC_SUCCESS); 115 } 116 117 static PetscErrorCode DMRefineHook_DMSNES(DM dm, DM dmf, PetscCtx ctx) 118 { 119 PetscFunctionBegin; 120 PetscCall(DMCopyDMSNES(dm, dmf)); 121 PetscFunctionReturn(PETSC_SUCCESS); 122 } 123 124 /* This could restrict auxiliary information to the coarse level. 125 */ 126 static PetscErrorCode DMInterpolateHook_DMSNES(DM dm, Mat Interp, DM dmf, PetscCtx ctx) 127 { 128 PetscFunctionBegin; 129 PetscFunctionReturn(PETSC_SUCCESS); 130 } 131 132 /* 133 DMSNESCopy - copies the information in a `DMSNES` to another `DMSNES` 134 135 Not Collective 136 137 Input Parameters: 138 + kdm - Original `DMSNES` 139 - nkdm - `DMSNES` to receive the data, should have been created with `DMSNESCreate()` 140 141 Level: developer 142 143 .seealso: [](ch_snes), `DMSNES`, `DMSNESCreate()`, `DMSNESDestroy()` 144 */ 145 static PetscErrorCode DMSNESCopy(DMSNES kdm, DMSNES nkdm) 146 { 147 PetscFunctionBegin; 148 PetscValidHeaderSpecific(kdm, DMSNES_CLASSID, 1); 149 PetscValidHeaderSpecific(nkdm, DMSNES_CLASSID, 2); 150 nkdm->ops->computefunction = kdm->ops->computefunction; 151 nkdm->ops->computejacobian = kdm->ops->computejacobian; 152 nkdm->ops->computegs = kdm->ops->computegs; 153 nkdm->ops->computeobjective = kdm->ops->computeobjective; 154 nkdm->ops->computepjacobian = kdm->ops->computepjacobian; 155 nkdm->ops->computepfunction = kdm->ops->computepfunction; 156 nkdm->ops->destroy = kdm->ops->destroy; 157 nkdm->ops->duplicate = kdm->ops->duplicate; 158 159 nkdm->gsctx = kdm->gsctx; 160 nkdm->pctx = kdm->pctx; 161 nkdm->objectivectx = kdm->objectivectx; 162 nkdm->originaldm = kdm->originaldm; 163 nkdm->functionctxcontainer = kdm->functionctxcontainer; 164 nkdm->jacobianctxcontainer = kdm->jacobianctxcontainer; 165 if (nkdm->functionctxcontainer) PetscCall(PetscObjectCompose((PetscObject)nkdm, "function ctx", (PetscObject)nkdm->functionctxcontainer)); 166 if (nkdm->jacobianctxcontainer) PetscCall(PetscObjectCompose((PetscObject)nkdm, "jacobian ctx", (PetscObject)nkdm->jacobianctxcontainer)); 167 168 /* 169 nkdm->fortran_func_pointers[0] = kdm->fortran_func_pointers[0]; 170 nkdm->fortran_func_pointers[1] = kdm->fortran_func_pointers[1]; 171 nkdm->fortran_func_pointers[2] = kdm->fortran_func_pointers[2]; 172 */ 173 174 /* implementation specific copy hooks */ 175 PetscTryTypeMethod(kdm, duplicate, nkdm); 176 PetscFunctionReturn(PETSC_SUCCESS); 177 } 178 179 /*@C 180 DMGetDMSNES - get read-only private `DMSNES` context from a `DM` 181 182 Not Collective 183 184 Input Parameter: 185 . dm - `DM` to be used with `SNES` 186 187 Output Parameter: 188 . snesdm - private `DMSNES` context 189 190 Level: developer 191 192 Note: 193 Use `DMGetDMSNESWrite()` if write access is needed. The DMSNESSetXXX API should be used wherever possible. 194 195 .seealso: [](ch_snes), `DMSNES`, `DMGetDMSNESWrite()` 196 @*/ 197 PetscErrorCode DMGetDMSNES(DM dm, DMSNES *snesdm) 198 { 199 PetscFunctionBegin; 200 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 201 *snesdm = (DMSNES)dm->dmsnes; 202 if (!*snesdm) { 203 PetscCall(PetscInfo(dm, "Creating new DMSNES\n")); 204 PetscCall(DMSNESCreate(PetscObjectComm((PetscObject)dm), snesdm)); 205 206 dm->dmsnes = (PetscObject)*snesdm; 207 (*snesdm)->originaldm = dm; 208 PetscCall(DMCoarsenHookAdd(dm, DMCoarsenHook_DMSNES, DMRestrictHook_DMSNES, NULL)); 209 PetscCall(DMRefineHookAdd(dm, DMRefineHook_DMSNES, DMInterpolateHook_DMSNES, NULL)); 210 PetscCall(DMSubDomainHookAdd(dm, DMSubDomainHook_DMSNES, DMSubDomainRestrictHook_DMSNES, NULL)); 211 } 212 PetscFunctionReturn(PETSC_SUCCESS); 213 } 214 215 /*@C 216 DMGetDMSNESWrite - get write access to private `DMSNES` context from a `DM` 217 218 Not Collective 219 220 Input Parameter: 221 . dm - `DM` to be used with `SNES` 222 223 Output Parameter: 224 . snesdm - private `DMSNES` context 225 226 Level: developer 227 228 .seealso: [](ch_snes), `DMSNES`, `DMGetDMSNES()` 229 @*/ 230 PetscErrorCode DMGetDMSNESWrite(DM dm, DMSNES *snesdm) 231 { 232 DMSNES sdm; 233 234 PetscFunctionBegin; 235 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 236 PetscCall(DMGetDMSNES(dm, &sdm)); 237 PetscCheck(sdm->originaldm, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DMSNES has a NULL originaldm"); 238 if (sdm->originaldm != dm) { /* Copy on write */ 239 DMSNES oldsdm = sdm; 240 PetscCall(PetscInfo(dm, "Copying DMSNES due to write\n")); 241 PetscCall(DMSNESCreate(PetscObjectComm((PetscObject)dm), &sdm)); 242 PetscCall(DMSNESCopy(oldsdm, sdm)); 243 PetscCall(DMSNESDestroy((DMSNES *)&dm->dmsnes)); 244 dm->dmsnes = (PetscObject)sdm; 245 sdm->originaldm = dm; 246 } 247 *snesdm = sdm; 248 PetscFunctionReturn(PETSC_SUCCESS); 249 } 250 251 /*@ 252 DMCopyDMSNES - copies a `DMSNES` context to a new `DM` 253 254 Logically Collective 255 256 Input Parameters: 257 + dmsrc - `DM` to obtain context from 258 - dmdest - `DM` to add context to 259 260 Level: developer 261 262 Note: 263 The context is copied by reference. This function does not ensure that a context exists. 264 265 .seealso: [](ch_snes), `DMSNES`, `DMGetDMSNES()`, `SNESSetDM()` 266 @*/ 267 PetscErrorCode DMCopyDMSNES(DM dmsrc, DM dmdest) 268 { 269 PetscFunctionBegin; 270 PetscValidHeaderSpecific(dmsrc, DM_CLASSID, 1); 271 PetscValidHeaderSpecific(dmdest, DM_CLASSID, 2); 272 if (!dmdest->dmsnes) PetscCall(DMSNESCreate(PetscObjectComm((PetscObject)dmdest), (DMSNES *)&dmdest->dmsnes)); 273 PetscCall(DMSNESCopy((DMSNES)dmsrc->dmsnes, (DMSNES)dmdest->dmsnes)); 274 PetscCall(DMCoarsenHookAdd(dmdest, DMCoarsenHook_DMSNES, NULL, NULL)); 275 PetscCall(DMRefineHookAdd(dmdest, DMRefineHook_DMSNES, NULL, NULL)); 276 PetscCall(DMSubDomainHookAdd(dmdest, DMSubDomainHook_DMSNES, DMSubDomainRestrictHook_DMSNES, NULL)); 277 PetscFunctionReturn(PETSC_SUCCESS); 278 } 279 280 /*@C 281 DMSNESSetFunction - set `SNES` residual evaluation function 282 283 Not Collective 284 285 Input Parameters: 286 + dm - DM to be used with `SNES` 287 . f - residual evaluation function; see `SNESFunctionFn` for calling sequence 288 - ctx - context for residual evaluation 289 290 Level: developer 291 292 Note: 293 `SNESSetFunction()` is normally used, but it calls this function internally because the user context is actually 294 associated with the `DM`. This makes the interface consistent regardless of whether the user interacts with a `DM` or 295 not. 296 297 Developer Note: 298 If `DM` took a more central role at some later date, this could become the primary method of setting the residual. 299 300 .seealso: [](ch_snes), `DMSNES`, `DMSNESSetContext()`, `SNESSetFunction()`, `DMSNESSetJacobian()`, `SNESFunctionFn` 301 @*/ 302 PetscErrorCode DMSNESSetFunction(DM dm, SNESFunctionFn *f, PetscCtx ctx) 303 { 304 DMSNES sdm; 305 306 PetscFunctionBegin; 307 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 308 PetscCall(DMGetDMSNESWrite(dm, &sdm)); 309 if (f) sdm->ops->computefunction = f; 310 if (ctx) { 311 PetscContainer ctxcontainer; 312 PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)sdm), &ctxcontainer)); 313 PetscCall(PetscContainerSetPointer(ctxcontainer, ctx)); 314 PetscCall(PetscObjectCompose((PetscObject)sdm, "function ctx", (PetscObject)ctxcontainer)); 315 sdm->functionctxcontainer = ctxcontainer; 316 PetscCall(PetscContainerDestroy(&ctxcontainer)); 317 } 318 PetscFunctionReturn(PETSC_SUCCESS); 319 } 320 321 /*@C 322 DMSNESSetFunctionContextDestroy - set `SNES` residual evaluation context destroy function 323 324 Not Collective 325 326 Input Parameters: 327 + dm - `DM` to be used with `SNES` 328 - f - residual evaluation context destroy function, see `PetscCtxDestroyFn` for its calling sequence 329 330 Level: developer 331 332 .seealso: [](ch_snes), `DMSNES`, `DMSNESSetFunction()`, `SNESSetFunction()`, `PetscCtxDestroyFn` 333 @*/ 334 PetscErrorCode DMSNESSetFunctionContextDestroy(DM dm, PetscCtxDestroyFn *f) 335 { 336 DMSNES sdm; 337 338 PetscFunctionBegin; 339 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 340 PetscCall(DMGetDMSNESWrite(dm, &sdm)); 341 if (sdm->functionctxcontainer) PetscCall(PetscContainerSetCtxDestroy(sdm->functionctxcontainer, f)); 342 PetscFunctionReturn(PETSC_SUCCESS); 343 } 344 345 PetscErrorCode DMSNESUnsetFunctionContext_Internal(DM dm) 346 { 347 DMSNES sdm; 348 349 PetscFunctionBegin; 350 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 351 PetscCall(DMGetDMSNESWrite(dm, &sdm)); 352 PetscCall(DMSNESUnsetFunctionContext_DMSNES(sdm)); 353 PetscFunctionReturn(PETSC_SUCCESS); 354 } 355 356 /*@C 357 DMSNESSetMFFunction - set `SNES` residual evaluation function used in applying the matrix-free Jacobian with `-snes_mf_operator` 358 359 Logically Collective 360 361 Input Parameters: 362 + dm - `DM` to be used with `SNES` 363 . func - residual evaluation function; see `SNESFunctionFn` for calling sequence 364 - ctx - optional function context 365 366 Level: developer 367 368 Note: 369 If not provided then the function provided with `SNESSetFunction()` is used 370 371 .seealso: [](ch_snes), `DMSNES`, `DMSNESSetContext()`, `SNESSetFunction()`, `DMSNESSetJacobian()`, `DMSNESSetFunction()`, `SNESFunctionFn` 372 @*/ 373 PetscErrorCode DMSNESSetMFFunction(DM dm, SNESFunctionFn *func, PetscCtx ctx) 374 { 375 DMSNES sdm; 376 377 PetscFunctionBegin; 378 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 379 if (func || ctx) PetscCall(DMGetDMSNESWrite(dm, &sdm)); 380 if (func) sdm->ops->computemffunction = func; 381 if (ctx) sdm->mffunctionctx = ctx; 382 PetscFunctionReturn(PETSC_SUCCESS); 383 } 384 385 /*@C 386 DMSNESGetFunction - get `SNES` residual evaluation function from a `DMSNES` object 387 388 Not Collective 389 390 Input Parameter: 391 . dm - `DM` to be used with `SNES` 392 393 Output Parameters: 394 + f - residual evaluation function; see `SNESFunctionFn` for calling sequence 395 - ctx - context for residual evaluation 396 397 Level: developer 398 399 Note: 400 `SNESGetFunction()` is normally used, but it calls this function internally because the user context is actually 401 associated with the `DM`. 402 403 .seealso: [](ch_snes), `DMSNES`, `DMSNESSetContext()`, `DMSNESSetFunction()`, `SNESSetFunction()`, `SNESFunctionFn` 404 @*/ 405 PetscErrorCode DMSNESGetFunction(DM dm, SNESFunctionFn **f, PetscCtxRt ctx) 406 { 407 DMSNES sdm; 408 409 PetscFunctionBegin; 410 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 411 PetscCall(DMGetDMSNES(dm, &sdm)); 412 if (f) *f = sdm->ops->computefunction; 413 if (ctx) { 414 if (sdm->functionctxcontainer) PetscCall(PetscContainerGetPointer(sdm->functionctxcontainer, ctx)); 415 else *(void **)ctx = NULL; 416 } 417 PetscFunctionReturn(PETSC_SUCCESS); 418 } 419 420 /*@C 421 DMSNESSetObjective - Sets the objective function minimized by some of the `SNES` linesearch methods into a `DMSNES` object, used instead of the 2-norm of the residual 422 423 Not Collective 424 425 Input Parameters: 426 + dm - `DM` to be used with `SNES` 427 . obj - objective evaluation routine; see `SNESObjectiveFn` for the calling sequence 428 - ctx - [optional] user-defined context for private data for the objective evaluation routine (may be `NULL`) 429 430 Level: developer 431 432 .seealso: [](ch_snes), `DMSNES`, `DMSNESSetContext()`, `SNESGetObjective()`, `DMSNESSetFunction()`, `SNESObjectiveFn` 433 @*/ 434 PetscErrorCode DMSNESSetObjective(DM dm, SNESObjectiveFn *obj, PetscCtx ctx) 435 { 436 DMSNES sdm; 437 438 PetscFunctionBegin; 439 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 440 if (obj || ctx) PetscCall(DMGetDMSNESWrite(dm, &sdm)); 441 if (obj) sdm->ops->computeobjective = obj; 442 if (ctx) sdm->objectivectx = ctx; 443 PetscFunctionReturn(PETSC_SUCCESS); 444 } 445 446 /*@C 447 DMSNESGetObjective - Returns the objective function set with `DMSNESSetObjective()` 448 449 Not Collective 450 451 Input Parameter: 452 . dm - `DM` to be used with `SNES` 453 454 Output Parameters: 455 + obj - objective evaluation routine (or `NULL`); see `SNESObjectiveFn` for the calling sequence 456 - ctx - the function context (or `NULL`) 457 458 Level: developer 459 460 Note: 461 `SNESGetFunction()` is normally used, but it calls this function internally because the user context is actually 462 associated with the `DM`. 463 464 .seealso: [](ch_snes), `DMSNES`, `DMSNESSetContext()`, `DMSNESSetObjective()`, `SNESSetFunction()`, `SNESObjectiveFn` 465 @*/ 466 PetscErrorCode DMSNESGetObjective(DM dm, SNESObjectiveFn **obj, PetscCtxRt ctx) 467 { 468 DMSNES sdm; 469 470 PetscFunctionBegin; 471 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 472 PetscCall(DMGetDMSNES(dm, &sdm)); 473 if (obj) *obj = sdm->ops->computeobjective; 474 if (ctx) *(void **)ctx = sdm->objectivectx; 475 PetscFunctionReturn(PETSC_SUCCESS); 476 } 477 478 /*@C 479 DMSNESSetNGS - set `SNES` Gauss-Seidel relaxation function into a `DMSNES` object 480 481 Not Collective 482 483 Input Parameters: 484 + dm - `DM` to be used with `SNES` 485 . f - relaxation function, see `SNESGSFunction` 486 - ctx - context for residual evaluation 487 488 Level: developer 489 490 Note: 491 `SNESSetNGS()` is normally used, but it calls this function internally because the user context is actually 492 associated with the `DM`. This makes the interface consistent regardless of whether the user interacts with a `DM` or 493 not. 494 495 Developer Note: 496 If `DM` took a more central role at some later date, this could become the primary method of supplying the smoother 497 498 .seealso: [](ch_snes), `DMSNES`, `DMSNESSetContext()`, `SNESSetFunction()`, `DMSNESSetJacobian()`, `DMSNESSetFunction()`, `SNESGSFunction` 499 @*/ 500 PetscErrorCode DMSNESSetNGS(DM dm, PetscErrorCode (*f)(SNES, Vec, Vec, void *), PetscCtx ctx) 501 { 502 DMSNES sdm; 503 504 PetscFunctionBegin; 505 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 506 if (f || ctx) PetscCall(DMGetDMSNESWrite(dm, &sdm)); 507 if (f) sdm->ops->computegs = f; 508 if (ctx) sdm->gsctx = ctx; 509 PetscFunctionReturn(PETSC_SUCCESS); 510 } 511 512 /*@C 513 DMSNESGetNGS - get `SNES` Gauss-Seidel relaxation function from a `DMSNES` object 514 515 Not Collective 516 517 Input Parameter: 518 . dm - `DM` to be used with `SNES` 519 520 Output Parameters: 521 + f - relaxation function which performs Gauss-Seidel sweeps, see `SNESSetNGS()` 522 - ctx - context for residual evaluation 523 524 Level: developer 525 526 Note: 527 `SNESGetNGS()` is normally used, but it calls this function internally because the user context is actually 528 associated with the `DM`. 529 530 Developer Note: 531 This makes the interface consistent regardless of whether the user interacts with a `DM` or 532 not. If `DM` took a more central role at some later date, this could become the primary method of setting the residual. 533 534 .seealso: [](ch_snes), `DMSNES`, `DMSNESSetContext()`, `SNESGetNGS()`, `DMSNESGetJacobian()`, `DMSNESGetFunction()` 535 @*/ 536 PetscErrorCode DMSNESGetNGS(DM dm, PetscErrorCode (**f)(SNES, Vec, Vec, void *), PetscCtxRt ctx) 537 { 538 DMSNES sdm; 539 540 PetscFunctionBegin; 541 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 542 PetscCall(DMGetDMSNES(dm, &sdm)); 543 if (f) *f = sdm->ops->computegs; 544 if (ctx) *(void **)ctx = sdm->gsctx; 545 PetscFunctionReturn(PETSC_SUCCESS); 546 } 547 548 /*@C 549 DMSNESSetJacobian - set `SNES` Jacobian evaluation function into a `DMSNES` object 550 551 Not Collective 552 553 Input Parameters: 554 + dm - `DM` to be used with `SNES` 555 . J - Jacobian evaluation function, see `SNESJacobianFn` 556 - ctx - context for Jacobian evaluation 557 558 Level: developer 559 560 Note: 561 `SNESSetJacobian()` is normally used, but it calls this function internally because the user context is actually 562 associated with the `DM`. 563 564 Developer Note: 565 This makes the interface consistent regardless of whether the user interacts with a `DM` or 566 not. If `DM` took a more central role at some later date, this could become the primary method of setting the Jacobian. 567 568 .seealso: [](ch_snes), `DMSNES`, `DMSNESSetContext()`, `SNESSetFunction()`, `DMSNESGetJacobian()`, `SNESSetJacobian()`, `SNESJacobianFn` 569 @*/ 570 PetscErrorCode DMSNESSetJacobian(DM dm, SNESJacobianFn *J, PetscCtx ctx) 571 { 572 DMSNES sdm; 573 574 PetscFunctionBegin; 575 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 576 if (J || ctx) PetscCall(DMGetDMSNESWrite(dm, &sdm)); 577 if (J) sdm->ops->computejacobian = J; 578 if (ctx) { 579 PetscContainer ctxcontainer; 580 PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)sdm), &ctxcontainer)); 581 PetscCall(PetscContainerSetPointer(ctxcontainer, ctx)); 582 PetscCall(PetscObjectCompose((PetscObject)sdm, "jacobian ctx", (PetscObject)ctxcontainer)); 583 sdm->jacobianctxcontainer = ctxcontainer; 584 PetscCall(PetscContainerDestroy(&ctxcontainer)); 585 } 586 PetscFunctionReturn(PETSC_SUCCESS); 587 } 588 589 /*@C 590 DMSNESSetJacobianContextDestroy - set `SNES` Jacobian evaluation context destroy function into a `DMSNES` object 591 592 Not Collective 593 594 Input Parameters: 595 + dm - `DM` to be used with `SNES` 596 - f - Jacobian evaluation context destroy function, see `PetscCtxDestroyFn` for its calling sequence 597 598 Level: developer 599 600 .seealso: [](ch_snes), `DMSNES`, `DMSNESSetJacobian()` 601 @*/ 602 PetscErrorCode DMSNESSetJacobianContextDestroy(DM dm, PetscCtxDestroyFn *f) 603 { 604 DMSNES sdm; 605 606 PetscFunctionBegin; 607 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 608 PetscCall(DMGetDMSNESWrite(dm, &sdm)); 609 if (sdm->jacobianctxcontainer) PetscCall(PetscContainerSetCtxDestroy(sdm->jacobianctxcontainer, f)); 610 PetscFunctionReturn(PETSC_SUCCESS); 611 } 612 613 PetscErrorCode DMSNESUnsetJacobianContext_Internal(DM dm) 614 { 615 DMSNES sdm; 616 617 PetscFunctionBegin; 618 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 619 PetscCall(DMGetDMSNESWrite(dm, &sdm)); 620 PetscCall(DMSNESUnsetJacobianContext_DMSNES(sdm)); 621 PetscFunctionReturn(PETSC_SUCCESS); 622 } 623 624 /*@C 625 DMSNESGetJacobian - get `SNES` Jacobian evaluation function from a `DMSNES` object 626 627 Not Collective 628 629 Input Parameter: 630 . dm - `DM` to be used with `SNES` 631 632 Output Parameters: 633 + J - Jacobian evaluation function; for all calling sequence see `SNESJacobianFn` 634 - ctx - context for residual evaluation 635 636 Level: developer 637 638 Note: 639 `SNESGetJacobian()` is normally used, but it calls this function internally because the user context is actually 640 associated with the `DM`. This makes the interface consistent regardless of whether the user interacts with a `DM` or 641 not. 642 643 Developer Note: 644 If `DM` took a more central role at some later date, this could become the primary method of setting the Jacobian. 645 646 .seealso: [](ch_snes), `DMSNES`, `DMSNESSetContext()`, `SNESSetFunction()`, `DMSNESSetJacobian()`, `SNESJacobianFn` 647 @*/ 648 PetscErrorCode DMSNESGetJacobian(DM dm, SNESJacobianFn **J, PetscCtxRt ctx) 649 { 650 DMSNES sdm; 651 652 PetscFunctionBegin; 653 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 654 PetscCall(DMGetDMSNES(dm, &sdm)); 655 if (J) *J = sdm->ops->computejacobian; 656 if (ctx) { 657 if (sdm->jacobianctxcontainer) PetscCall(PetscContainerGetPointer(sdm->jacobianctxcontainer, ctx)); 658 else *(void **)ctx = NULL; 659 } 660 PetscFunctionReturn(PETSC_SUCCESS); 661 } 662 663 /*@C 664 DMSNESSetPicard - set SNES Picard iteration matrix and RHS evaluation functions into a `DMSNES` object 665 666 Not Collective 667 668 Input Parameters: 669 + dm - `DM` to be used with `SNES` 670 . b - RHS evaluation function; see `SNESFunctionFn` for calling sequence 671 . J - Picard matrix evaluation function; see `SNESJacobianFn` for calling sequence 672 - ctx - context for residual and matrix evaluation 673 674 Level: developer 675 676 .seealso: [](ch_snes), `DMSNES`, `SNESSetPicard()`, `DMSNESSetFunction()`, `DMSNESSetJacobian()`, `SNESFunctionFn`, `SNESJacobianFn` 677 @*/ 678 PetscErrorCode DMSNESSetPicard(DM dm, SNESFunctionFn *b, SNESJacobianFn *J, PetscCtx ctx) 679 { 680 DMSNES sdm; 681 682 PetscFunctionBegin; 683 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 684 PetscCall(DMGetDMSNES(dm, &sdm)); 685 if (b) sdm->ops->computepfunction = b; 686 if (J) sdm->ops->computepjacobian = J; 687 if (ctx) sdm->pctx = ctx; 688 PetscFunctionReturn(PETSC_SUCCESS); 689 } 690 691 /*@C 692 DMSNESGetPicard - get `SNES` Picard iteration evaluation functions from a `DMSNES` object 693 694 Not Collective 695 696 Input Parameter: 697 . dm - `DM` to be used with `SNES` 698 699 Output Parameters: 700 + b - RHS evaluation function; see `SNESFunctionFn` for calling sequence 701 . J - Jacobian evaluation function; see `SNESJacobianFn` for calling sequence 702 - ctx - context for residual and matrix evaluation 703 704 Level: developer 705 706 .seealso: [](ch_snes), `DMSNES`, `DMSNESSetContext()`, `SNESSetFunction()`, `DMSNESSetJacobian()`, `SNESFunctionFn`, `SNESJacobianFn` 707 @*/ 708 PetscErrorCode DMSNESGetPicard(DM dm, SNESFunctionFn **b, SNESJacobianFn **J, PetscCtxRt ctx) 709 { 710 DMSNES sdm; 711 712 PetscFunctionBegin; 713 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 714 PetscCall(DMGetDMSNES(dm, &sdm)); 715 if (b) *b = sdm->ops->computepfunction; 716 if (J) *J = sdm->ops->computepjacobian; 717 if (ctx) *(void **)ctx = sdm->pctx; 718 PetscFunctionReturn(PETSC_SUCCESS); 719 } 720