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