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