1 #include <petsc/private/snesimpl.h> /*I "petscsnes.h" I*/ 2 3 /*@ 4 SNESApplyNPC - Calls `SNESSolve()` on the preconditioner for the `SNES` 5 6 Collective 7 8 Input Parameters: 9 + snes - the `SNES` context 10 . x - input vector 11 - f - optional; the function evaluation on `x` 12 13 Output Parameter: 14 . y - function vector, as set by `SNESSetFunction()` 15 16 Level: developer 17 18 Note: 19 `SNESComputeFunction()` should be called on `x` before `SNESApplyNPC()` is called, as it is 20 with `SNESComuteJacobian()`. 21 22 .seealso: [](ch_snes), `SNES`, `SNESGetNPC()`, `SNESSetNPC()`, `SNESComputeFunction()` 23 @*/ 24 PetscErrorCode SNESApplyNPC(SNES snes, Vec x, Vec f, Vec y) 25 { 26 PetscFunctionBegin; 27 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1); 28 PetscValidHeaderSpecific(x, VEC_CLASSID, 2); 29 PetscValidHeaderSpecific(y, VEC_CLASSID, 4); 30 PetscCheckSameComm(snes, 1, x, 2); 31 PetscCheckSameComm(snes, 1, y, 4); 32 PetscCall(VecValidValues_Internal(x, 2, PETSC_TRUE)); 33 if (snes->npc) { 34 if (f) PetscCall(SNESSetInitialFunction(snes->npc, f)); 35 PetscCall(VecCopy(x, y)); 36 PetscCall(PetscLogEventBegin(SNES_NPCSolve, snes->npc, x, y, 0)); 37 PetscCall(SNESSolve(snes->npc, snes->vec_rhs, y)); 38 PetscCall(PetscLogEventEnd(SNES_NPCSolve, snes->npc, x, y, 0)); 39 PetscCall(VecAYPX(y, -1.0, x)); 40 } 41 PetscFunctionReturn(PETSC_SUCCESS); 42 } 43 44 PetscErrorCode SNESComputeFunctionDefaultNPC(SNES snes, Vec X, Vec F) 45 { 46 /* This is to be used as an argument to SNESMF -- NOT as a "function" */ 47 SNESConvergedReason reason; 48 49 PetscFunctionBegin; 50 if (snes->npc) { 51 PetscCall(SNESApplyNPC(snes, X, NULL, F)); 52 PetscCall(SNESGetConvergedReason(snes->npc, &reason)); 53 if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) PetscCall(SNESSetFunctionDomainError(snes)); 54 } else { 55 PetscCall(SNESComputeFunction(snes, X, F)); 56 } 57 PetscFunctionReturn(PETSC_SUCCESS); 58 } 59 60 /*@ 61 SNESGetNPCFunction - Gets the current function value (for the callback function provided by `SNESSetFunction()`, 62 and its norm from a nonlinear preconditioner after `SNESSolve()` has been called on that `SNES` 63 64 Collective 65 66 Input Parameter: 67 . snes - the `SNES` context 68 69 Output Parameters: 70 + F - function vector 71 - fnorm - the norm of `F` 72 73 Level: developer 74 75 .seealso: [](ch_snes), `SNES`, `SNESGetNPC()`, `SNESSetNPC()`, `SNESComputeFunction()`, `SNESApplyNPC()`, `SNESSolve()` 76 @*/ 77 PetscErrorCode SNESGetNPCFunction(SNES snes, Vec F, PetscReal *fnorm) 78 { 79 PCSide npcside; 80 SNESFunctionType functype; 81 SNESNormSchedule normschedule; 82 Vec FPC, XPC; 83 84 PetscFunctionBegin; 85 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1); 86 if (fnorm) PetscAssertPointer(fnorm, 3); 87 PetscCheck(snes->npc, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "No nonlinear preconditioner set"); 88 PetscCall(SNESGetNPCSide(snes->npc, &npcside)); 89 PetscCall(SNESGetFunctionType(snes->npc, &functype)); 90 PetscCall(SNESGetNormSchedule(snes->npc, &normschedule)); 91 92 /* check if the function is valid based upon how the inner solver is preconditioned */ 93 if (normschedule != SNES_NORM_NONE && normschedule != SNES_NORM_INITIAL_ONLY && (npcside == PC_RIGHT || functype == SNES_FUNCTION_UNPRECONDITIONED)) { 94 PetscCall(SNESGetFunction(snes->npc, &FPC, NULL, NULL)); 95 PetscCheck(FPC, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Nonlinear preconditioner has no function"); 96 if (fnorm) PetscCall(VecNorm(FPC, NORM_2, fnorm)); 97 PetscCall(VecCopy(FPC, F)); 98 } else { 99 PetscCall(SNESGetSolution(snes->npc, &XPC)); 100 PetscCheck(XPC, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Nonlinear preconditioner has no solution"); 101 PetscCall(SNESComputeFunction(snes->npc, XPC, F)); 102 if (fnorm) PetscCall(VecNorm(F, NORM_2, fnorm)); 103 } 104 PetscFunctionReturn(PETSC_SUCCESS); 105 } 106