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 if ((*kdm)->ops->destroy) PetscCall(((*kdm)->ops->destroy)(*kdm)); 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 PetscErrorCode (*func)(SNES, Vec, Vec, void *); 63 } funcstruct; 64 struct { 65 PetscErrorCode (*jac)(SNES, Vec, Mat, Mat, void *); 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, void *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, void *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, void *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, void *ctx) 112 { 113 PetscFunctionBegin; 114 PetscFunctionReturn(PETSC_SUCCESS); 115 } 116 117 static PetscErrorCode DMRefineHook_DMSNES(DM dm, DM dmf, void *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, void *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 /*@C 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 `SNESFunction` for details 288 - ctx - context for residual evaluation 289 290 Level: advanced 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()`, `SNESFunction` 301 @*/ 302 PetscErrorCode DMSNESSetFunction(DM dm, PetscErrorCode (*f)(SNES, Vec, Vec, void *), void *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 329 330 Level: advanced 331 332 .seealso: [](ch_snes), `DMSNES`, `DMSNESSetFunction()`, `SNESSetFunction()` 333 @*/ 334 PetscErrorCode DMSNESSetFunctionContextDestroy(DM dm, PetscErrorCode (*f)(void *)) 335 { 336 DMSNES sdm; 337 338 PetscFunctionBegin; 339 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 340 PetscCall(DMGetDMSNESWrite(dm, &sdm)); 341 if (sdm->functionctxcontainer) PetscCall(PetscContainerSetUserDestroy(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 `SNESFunction` for details 364 - ctx - optional function context 365 366 Calling sequence of `func`: 367 + snes - the solver object 368 . x - the input vector 369 . f - the output vector 370 - ctx - the optional function context 371 372 Level: advanced 373 374 .seealso: [](ch_snes), `DMSNES`, `DMSNESSetContext()`, `SNESSetFunction()`, `DMSNESSetJacobian()`, `SNESFunction`, `DMSNESSetFunction()` 375 @*/ 376 PetscErrorCode DMSNESSetMFFunction(DM dm, PetscErrorCode (*func)(SNES snes, Vec x, Vec f, void *ctx), void *ctx) 377 { 378 DMSNES sdm; 379 380 PetscFunctionBegin; 381 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 382 if (func || ctx) PetscCall(DMGetDMSNESWrite(dm, &sdm)); 383 if (func) sdm->ops->computemffunction = func; 384 if (ctx) sdm->mffunctionctx = ctx; 385 PetscFunctionReturn(PETSC_SUCCESS); 386 } 387 388 /*@C 389 DMSNESGetFunction - get `SNES` residual evaluation function 390 391 Not Collective 392 393 Input Parameter: 394 . dm - `DM` to be used with `SNES` 395 396 Output Parameters: 397 + f - residual evaluation function; see `SNESFunction` for details 398 - ctx - context for residual evaluation 399 400 Level: advanced 401 402 Note: 403 `SNESGetFunction()` is normally used, but it calls this function internally because the user context is actually 404 associated with the `DM`. 405 406 .seealso: [](ch_snes), `DMSNES`, `DMSNESSetContext()`, `DMSNESSetFunction()`, `SNESSetFunction()`, `SNESFunction` 407 @*/ 408 PetscErrorCode DMSNESGetFunction(DM dm, PetscErrorCode (**f)(SNES, Vec, Vec, void *), void **ctx) 409 { 410 DMSNES sdm; 411 412 PetscFunctionBegin; 413 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 414 PetscCall(DMGetDMSNES(dm, &sdm)); 415 if (f) *f = sdm->ops->computefunction; 416 if (ctx) { 417 if (sdm->functionctxcontainer) PetscCall(PetscContainerGetPointer(sdm->functionctxcontainer, ctx)); 418 else *ctx = NULL; 419 } 420 PetscFunctionReturn(PETSC_SUCCESS); 421 } 422 423 /*@C 424 DMSNESSetObjective - set `SNES` objective evaluation function 425 426 Not Collective 427 428 Input Parameters: 429 + dm - `DM` to be used with `SNES` 430 . obj - objective evaluation function; see `SNESObjectiveFunction` for details 431 - ctx - context for residual evaluation 432 433 Level: advanced 434 435 .seealso: [](ch_snes), `DMSNES`, `DMSNESSetContext()`, `SNESGetObjective()`, `DMSNESSetFunction()` 436 @*/ 437 PetscErrorCode DMSNESSetObjective(DM dm, PetscErrorCode (*obj)(SNES, Vec, PetscReal *, void *), void *ctx) 438 { 439 DMSNES sdm; 440 441 PetscFunctionBegin; 442 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 443 if (obj || ctx) PetscCall(DMGetDMSNESWrite(dm, &sdm)); 444 if (obj) sdm->ops->computeobjective = obj; 445 if (ctx) sdm->objectivectx = ctx; 446 PetscFunctionReturn(PETSC_SUCCESS); 447 } 448 449 /*@C 450 DMSNESGetObjective - get `SNES` objective evaluation function 451 452 Not Collective 453 454 Input Parameter: 455 . dm - `DM` to be used with `SNES` 456 457 Output Parameters: 458 + obj - residual evaluation function; see `SNESObjectiveFunction` for details 459 - ctx - context for residual evaluation 460 461 Level: advanced 462 463 Note: 464 `SNESGetFunction()` is normally used, but it calls this function internally because the user context is actually 465 associated with the `DM`. 466 467 .seealso: [](ch_snes), `DMSNES`, `DMSNESSetContext()`, `DMSNESSetObjective()`, `SNESSetFunction()` 468 @*/ 469 PetscErrorCode DMSNESGetObjective(DM dm, PetscErrorCode (**obj)(SNES, Vec, PetscReal *, void *), void **ctx) 470 { 471 DMSNES sdm; 472 473 PetscFunctionBegin; 474 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 475 PetscCall(DMGetDMSNES(dm, &sdm)); 476 if (obj) *obj = sdm->ops->computeobjective; 477 if (ctx) *ctx = sdm->objectivectx; 478 PetscFunctionReturn(PETSC_SUCCESS); 479 } 480 481 /*@C 482 DMSNESSetNGS - set `SNES` Gauss-Seidel relaxation function 483 484 Not Collective 485 486 Input Parameters: 487 + dm - `DM` to be used with `SNES` 488 . f - relaxation function, see `SNESGSFunction` 489 - ctx - context for residual evaluation 490 491 Level: advanced 492 493 Note: 494 `SNESSetNGS()` is normally used, but it calls this function internally because the user context is actually 495 associated with the `DM`. This makes the interface consistent regardless of whether the user interacts with a `DM` or 496 not. 497 498 Developer Note: 499 If `DM` took a more central role at some later date, this could become the primary method of supplying the smoother 500 501 .seealso: [](ch_snes), `DMSNES`, `DMSNESSetContext()`, `SNESSetFunction()`, `DMSNESSetJacobian()`, `DMSNESSetFunction()`, `SNESGSFunction` 502 @*/ 503 PetscErrorCode DMSNESSetNGS(DM dm, PetscErrorCode (*f)(SNES, Vec, Vec, void *), void *ctx) 504 { 505 DMSNES sdm; 506 507 PetscFunctionBegin; 508 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 509 if (f || ctx) PetscCall(DMGetDMSNESWrite(dm, &sdm)); 510 if (f) sdm->ops->computegs = f; 511 if (ctx) sdm->gsctx = ctx; 512 PetscFunctionReturn(PETSC_SUCCESS); 513 } 514 515 /*@C 516 DMSNESGetNGS - get `SNES` Gauss-Seidel relaxation function 517 518 Not Collective 519 520 Input Parameter: 521 . dm - `DM` to be used with `SNES` 522 523 Output Parameters: 524 + f - relaxation function which performs Gauss-Seidel sweeps, see `SNESSetNGS()` 525 - ctx - context for residual evaluation 526 527 Level: advanced 528 529 Note: 530 `SNESGetNGS()` is normally used, but it calls this function internally because the user context is actually 531 associated with the `DM`. 532 533 Developer Note: 534 This makes the interface consistent regardless of whether the user interacts with a `DM` or 535 not. If `DM` took a more central role at some later date, this could become the primary method of setting the residual. 536 537 .seealso: [](ch_snes), `DMSNES`, `DMSNESSetContext()`, `SNESGetNGS()`, `DMSNESGetJacobian()`, `DMSNESGetFunction()` 538 @*/ 539 PetscErrorCode DMSNESGetNGS(DM dm, PetscErrorCode (**f)(SNES, Vec, Vec, void *), void **ctx) 540 { 541 DMSNES sdm; 542 543 PetscFunctionBegin; 544 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 545 PetscCall(DMGetDMSNES(dm, &sdm)); 546 if (f) *f = sdm->ops->computegs; 547 if (ctx) *ctx = sdm->gsctx; 548 PetscFunctionReturn(PETSC_SUCCESS); 549 } 550 551 /*@C 552 DMSNESSetJacobian - set `SNES` Jacobian evaluation function 553 554 Not Collective 555 556 Input Parameters: 557 + dm - `DM` to be used with `SNES` 558 . J - Jacobian evaluation function 559 - ctx - context for residual evaluation 560 561 Level: advanced 562 563 Note: 564 `SNESSetJacobian()` is normally used, but it calls this function internally because the user context is actually 565 associated with the `DM`. 566 567 Developer Note: 568 This makes the interface consistent regardless of whether the user interacts with a `DM` or 569 not. If `DM` took a more central role at some later date, this could become the primary method of setting the Jacobian. 570 571 .seealso: [](ch_snes), `DMSNES`, `DMSNESSetContext()`, `SNESSetFunction()`, `DMSNESGetJacobian()`, `SNESSetJacobian()`, `SNESJacobianFunction` 572 @*/ 573 PetscErrorCode DMSNESSetJacobian(DM dm, PetscErrorCode (*J)(SNES, Vec, Mat, Mat, void *), void *ctx) 574 { 575 DMSNES sdm; 576 577 PetscFunctionBegin; 578 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 579 if (J || ctx) PetscCall(DMGetDMSNESWrite(dm, &sdm)); 580 if (J) sdm->ops->computejacobian = J; 581 if (ctx) { 582 PetscContainer ctxcontainer; 583 PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)sdm), &ctxcontainer)); 584 PetscCall(PetscContainerSetPointer(ctxcontainer, ctx)); 585 PetscCall(PetscObjectCompose((PetscObject)sdm, "jacobian ctx", (PetscObject)ctxcontainer)); 586 sdm->jacobianctxcontainer = ctxcontainer; 587 PetscCall(PetscContainerDestroy(&ctxcontainer)); 588 } 589 PetscFunctionReturn(PETSC_SUCCESS); 590 } 591 592 /*@C 593 DMSNESSetJacobianContextDestroy - set `SNES` Jacobian evaluation context destroy function 594 595 Not Collective 596 597 Input Parameters: 598 + dm - `DM` to be used with `SNES` 599 - f - Jacobian evaluation context destroy function 600 601 Level: advanced 602 603 .seealso: [](ch_snes), `DMSNES`, `DMSNESSetJacobian()` 604 @*/ 605 PetscErrorCode DMSNESSetJacobianContextDestroy(DM dm, PetscErrorCode (*f)(void *)) 606 { 607 DMSNES sdm; 608 609 PetscFunctionBegin; 610 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 611 PetscCall(DMGetDMSNESWrite(dm, &sdm)); 612 if (sdm->jacobianctxcontainer) PetscCall(PetscContainerSetUserDestroy(sdm->jacobianctxcontainer, f)); 613 PetscFunctionReturn(PETSC_SUCCESS); 614 } 615 616 PetscErrorCode DMSNESUnsetJacobianContext_Internal(DM dm) 617 { 618 DMSNES sdm; 619 620 PetscFunctionBegin; 621 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 622 PetscCall(DMGetDMSNESWrite(dm, &sdm)); 623 PetscCall(DMSNESUnsetJacobianContext_DMSNES(sdm)); 624 PetscFunctionReturn(PETSC_SUCCESS); 625 } 626 627 /*@C 628 DMSNESGetJacobian - get `SNES` Jacobian evaluation function 629 630 Not Collective 631 632 Input Parameter: 633 . dm - `DM` to be used with `SNES` 634 635 Output Parameters: 636 + J - Jacobian evaluation function; for all calling sequence see `SNESJacobianFunction` 637 - ctx - context for residual evaluation 638 639 Level: advanced 640 641 Note: 642 `SNESGetJacobian()` is normally used, but it calls this function internally because the user context is actually 643 associated with the `DM`. This makes the interface consistent regardless of whether the user interacts with a `DM` or 644 not. 645 646 Developer Note: 647 If `DM` took a more central role at some later date, this could become the primary method of setting the Jacobian. 648 649 .seealso: [](ch_snes), `DMSNES`, `DMSNESSetContext()`, `SNESSetFunction()`, `DMSNESSetJacobian()`, `SNESJacobianFunction` 650 @*/ 651 PetscErrorCode DMSNESGetJacobian(DM dm, PetscErrorCode (**J)(SNES, Vec, Mat, Mat, void *), void **ctx) 652 { 653 DMSNES sdm; 654 655 PetscFunctionBegin; 656 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 657 PetscCall(DMGetDMSNES(dm, &sdm)); 658 if (J) *J = sdm->ops->computejacobian; 659 if (ctx) { 660 if (sdm->jacobianctxcontainer) PetscCall(PetscContainerGetPointer(sdm->jacobianctxcontainer, ctx)); 661 else *ctx = NULL; 662 } 663 PetscFunctionReturn(PETSC_SUCCESS); 664 } 665 666 /*@C 667 DMSNESSetPicard - set SNES Picard iteration matrix and RHS evaluation functions. 668 669 Not Collective 670 671 Input Parameters: 672 + dm - `DM` to be used with `SNES` 673 . b - RHS evaluation function; see `SNESFunction` for calling sequence 674 . J - Picard matrix evaluation function; see `SNESJacobianFunction` for calling sequence 675 - ctx - context for residual and matrix evaluation 676 677 Level: advanced 678 679 .seealso: [](ch_snes), `DMSNES`, `SNESSetPicard()`, `DMSNESSetFunction()`, `DMSNESSetJacobian()` 680 @*/ 681 PetscErrorCode DMSNESSetPicard(DM dm, PetscErrorCode (*b)(SNES, Vec, Vec, void *), PetscErrorCode (*J)(SNES, Vec, Mat, Mat, void *), void *ctx) 682 { 683 DMSNES sdm; 684 685 PetscFunctionBegin; 686 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 687 PetscCall(DMGetDMSNES(dm, &sdm)); 688 if (b) sdm->ops->computepfunction = b; 689 if (J) sdm->ops->computepjacobian = J; 690 if (ctx) sdm->pctx = ctx; 691 PetscFunctionReturn(PETSC_SUCCESS); 692 } 693 694 /*@C 695 DMSNESGetPicard - get `SNES` Picard iteration evaluation functions 696 697 Not Collective 698 699 Input Parameter: 700 . dm - `DM` to be used with `SNES` 701 702 Output Parameters: 703 + b - RHS evaluation function; see `SNESFunction` for calling sequence 704 . J - Jacobian evaluation function; see `SNESJacobianFunction` for calling sequence 705 - ctx - context for residual and matrix evaluation 706 707 Level: advanced 708 709 .seealso: [](ch_snes), `DMSNES`, `DMSNESSetContext()`, `SNESSetFunction()`, `DMSNESSetJacobian()` 710 @*/ 711 PetscErrorCode DMSNESGetPicard(DM dm, PetscErrorCode (**b)(SNES, Vec, Vec, void *), PetscErrorCode (**J)(SNES, Vec, Mat, Mat, void *), void **ctx) 712 { 713 DMSNES sdm; 714 715 PetscFunctionBegin; 716 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 717 PetscCall(DMGetDMSNES(dm, &sdm)); 718 if (b) *b = sdm->ops->computepfunction; 719 if (J) *J = sdm->ops->computepjacobian; 720 if (ctx) *ctx = sdm->pctx; 721 PetscFunctionReturn(PETSC_SUCCESS); 722 } 723