xref: /petsc/src/snes/mf/snesmfj.c (revision 208be567e9ec6057f1d61e88379ecc0a3e9deb99)
181e6777dSBarry Smith 
2af0996ceSBarry Smith #include <petsc/private/snesimpl.h>  /*I  "petscsnes.h" I*/
31e25c274SJed Brown #include <petscdm.h>                 /*I  "petscdm.h"   I*/
4c6db04a5SJed Brown #include <../src/mat/impls/mffd/mffdimpl.h>
5af0996ceSBarry Smith #include <petsc/private/matimpl.h>
681e6777dSBarry Smith 
75fe378a3SBarry Smith /*@C
8e884886fSBarry Smith    MatMFFDComputeJacobian - Tells the matrix-free Jacobian object the new location at which
9174415d9SBarry Smith        Jacobian matrix vector products will be computed at, i.e. J(x) * a. The x is obtained
10174415d9SBarry Smith        from the SNES object (using SNESGetSolution()).
11e884886fSBarry Smith 
123f9fe445SBarry Smith    Logically Collective on SNES
13e884886fSBarry Smith 
14e884886fSBarry Smith    Input Parameters:
15e884886fSBarry Smith +   snes - the nonlinear solver context
16e884886fSBarry Smith .   x - the point at which the Jacobian vector products will be performed
17e884886fSBarry Smith .   jac - the matrix-free Jacobian object
18e884886fSBarry Smith .   B - either the same as jac or another matrix type (ignored)
19e884886fSBarry Smith .   flag - not relevent for matrix-free form
20e884886fSBarry Smith -   dummy - the user context (ignored)
21e884886fSBarry Smith 
22e884886fSBarry Smith    Level: developer
23e884886fSBarry Smith 
24174415d9SBarry Smith    Warning:
25174415d9SBarry Smith       If MatMFFDSetBase() is ever called on jac then this routine will NO longer get
26174415d9SBarry Smith     the x from the SNES object and MatMFFDSetBase() must from that point on be used to
27174415d9SBarry Smith     change the base vector x.
28174415d9SBarry Smith 
29e884886fSBarry Smith    Notes:
30ecaffddaSVictor Eijkhout      This can be passed into SNESSetJacobian() as the Jacobian evaluation function argument
31ecaffddaSVictor Eijkhout      when using a completely matrix-free solver,
32e884886fSBarry Smith      that is the B matrix is also the same matrix operator. This is used when you select
335fe378a3SBarry Smith      -snes_mf but rarely used directly by users. (All this routine does is call MatAssemblyBegin/End() on
3414f633e2SBarry Smith      the Mat jac.)
355fe378a3SBarry Smith 
360decc0a3SBarry Smith .seealso: MatMFFDGetH(), MatCreateSNESMF(), MatCreateMFFD(), MATMFFD,
371d0fab5eSBarry Smith           MatMFFDSetHHistory(), MatMFFDSetFunctionError(), MatCreateMFFD(), SNESSetJacobian()
38e884886fSBarry Smith 
39e884886fSBarry Smith @*/
40d1e9a80fSBarry Smith PetscErrorCode  MatMFFDComputeJacobian(SNES snes,Vec x,Mat jac,Mat B,void *dummy)
41e884886fSBarry Smith {
42e884886fSBarry Smith   PetscErrorCode ierr;
435fd66863SKarl Rupp 
44e884886fSBarry Smith   PetscFunctionBegin;
4594ab13aaSBarry Smith   ierr = MatAssemblyBegin(jac,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
4694ab13aaSBarry Smith   ierr = MatAssemblyEnd(jac,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
47e884886fSBarry Smith   PetscFunctionReturn(0);
48e884886fSBarry Smith }
49e884886fSBarry Smith 
50d8fa6a54SBarry Smith PETSC_EXTERN PetscErrorCode MatAssemblyEnd_MFFD(Mat,MatAssemblyType);
51d8fa6a54SBarry Smith PETSC_EXTERN PetscErrorCode MatMFFDSetBase_MFFD(Mat,Vec,Vec);
52563d23a3SJed Brown 
533ec795f1SBarry Smith /*
543ec795f1SBarry Smith    MatAssemblyEnd_SNESMF - Calls MatAssemblyEnd_MFFD() and then sets the
553ec795f1SBarry Smith     base from the SNES context
563ec795f1SBarry Smith 
573ec795f1SBarry Smith */
58cc2e6a90SBarry Smith static PetscErrorCode MatAssemblyEnd_SNESMF(Mat J,MatAssemblyType mt)
593ec795f1SBarry Smith {
603ec795f1SBarry Smith   PetscErrorCode ierr;
613ec795f1SBarry Smith   MatMFFD        j    = (MatMFFD)J->data;
625eb111a0SBarry Smith   SNES           snes = (SNES)j->ctx;
6309ffd372SDmitry Karpeev   Vec            u,f;
643ec795f1SBarry Smith 
653ec795f1SBarry Smith   PetscFunctionBegin;
663ec795f1SBarry Smith   ierr = MatAssemblyEnd_MFFD(J,mt);CHKERRQ(ierr);
673ec795f1SBarry Smith 
68be4711e3SBarry Smith   ierr = SNESGetSolution(snes,&u);CHKERRQ(ierr);
695eb111a0SBarry Smith   if (j->func == (PetscErrorCode (*)(void*,Vec,Vec))SNESComputeFunction) {
700298fd71SBarry Smith     ierr = SNESGetFunction(snes,&f,NULL,NULL);CHKERRQ(ierr);
7109ffd372SDmitry Karpeev     ierr = MatMFFDSetBase_MFFD(J,u,f);CHKERRQ(ierr);
725eb111a0SBarry Smith   } else {
735eb111a0SBarry Smith     /* f value known by SNES is not correct for other differencing function */
745eb111a0SBarry Smith     ierr = MatMFFDSetBase_MFFD(J,u,NULL);CHKERRQ(ierr);
755eb111a0SBarry Smith   }
763ec795f1SBarry Smith   PetscFunctionReturn(0);
773ec795f1SBarry Smith }
783ec795f1SBarry Smith 
79174415d9SBarry Smith /*
80*208be567SBarry Smith    MatAssemblyEnd_SNESMF_UseBase - Calls MatAssemblyEnd_MFFD() and then sets the
81*208be567SBarry Smith     base from the SNES context. This version will cause the base to be used for differencing
82*208be567SBarry Smith     even if the func is not SNESComputeFunction. See: MatSNESMFUseBase()
83*208be567SBarry Smith 
84*208be567SBarry Smith 
85*208be567SBarry Smith */
86*208be567SBarry Smith static PetscErrorCode MatAssemblyEnd_SNESMF_UseBase(Mat J,MatAssemblyType mt)
87*208be567SBarry Smith {
88*208be567SBarry Smith   PetscErrorCode ierr;
89*208be567SBarry Smith   MatMFFD        j    = (MatMFFD)J->data;
90*208be567SBarry Smith   SNES           snes = (SNES)j->ctx;
91*208be567SBarry Smith   Vec            u,f;
92*208be567SBarry Smith 
93*208be567SBarry Smith   PetscFunctionBegin;
94*208be567SBarry Smith   ierr = MatAssemblyEnd_MFFD(J,mt);CHKERRQ(ierr);
95*208be567SBarry Smith 
96*208be567SBarry Smith   ierr = SNESGetSolution(snes,&u);CHKERRQ(ierr);
97*208be567SBarry Smith   ierr = SNESGetFunction(snes,&f,NULL,NULL);CHKERRQ(ierr);
98*208be567SBarry Smith   ierr = MatMFFDSetBase_MFFD(J,u,f);CHKERRQ(ierr);
99*208be567SBarry Smith   PetscFunctionReturn(0);
100*208be567SBarry Smith }
101*208be567SBarry Smith 
102*208be567SBarry Smith /*
103174415d9SBarry Smith     This routine resets the MatAssemblyEnd() for the MatMFFD created from MatCreateSNESMF() so that it NO longer
104174415d9SBarry Smith   uses the solution in the SNES object to update the base. See the warning in MatCreateSNESMF().
105174415d9SBarry Smith */
106cc2e6a90SBarry Smith static PetscErrorCode  MatMFFDSetBase_SNESMF(Mat J,Vec U,Vec F)
107174415d9SBarry Smith {
108174415d9SBarry Smith   PetscErrorCode ierr;
109174415d9SBarry Smith 
110174415d9SBarry Smith   PetscFunctionBegin;
111885877adSHong Zhang   ierr = MatMFFDSetBase_MFFD(J,U,F);CHKERRQ(ierr);
112174415d9SBarry Smith   J->ops->assemblyend = MatAssemblyEnd_MFFD;
113174415d9SBarry Smith   PetscFunctionReturn(0);
114174415d9SBarry Smith }
115174415d9SBarry Smith 
116*208be567SBarry Smith static PetscErrorCode  MatSNESMFSetReuseBase_SNESMF(Mat J,PetscBool use)
117*208be567SBarry Smith {
118*208be567SBarry Smith   PetscFunctionBegin;
119*208be567SBarry Smith   if (use) {
120*208be567SBarry Smith     J->ops->assemblyend = MatAssemblyEnd_SNESMF_UseBase;
121*208be567SBarry Smith   } else {
122*208be567SBarry Smith     J->ops->assemblyend = MatAssemblyEnd_SNESMF;
123*208be567SBarry Smith   }
124*208be567SBarry Smith   PetscFunctionReturn(0);
125*208be567SBarry Smith }
126*208be567SBarry Smith 
127*208be567SBarry Smith /*@
128*208be567SBarry Smith     MatSNESMFSetReuseBase - Causes the base vector to be used for differencing even if the function provided to SNESSetFunction() is not the
129*208be567SBarry Smith                        same as that provided to MatMFFDSetFunction().
130*208be567SBarry Smith 
131*208be567SBarry Smith     Logically Collective on Mat
132*208be567SBarry Smith 
133*208be567SBarry Smith     Input Parameters:
134*208be567SBarry Smith +   J - the MatMFFD matrix
135*208be567SBarry Smith -   use - if true always reuse the base vector instead of recomputing f(u) even if the function in the MatSNESMF is
136*208be567SBarry Smith           not SNESComputeFunction()
137*208be567SBarry Smith 
138*208be567SBarry Smith     Notes: Care must be taken when using this routine to insure that the function provided to MatMFFDSetFunction(), call it F_MF() is compatible with
139*208be567SBarry Smith            with that provided to SNESSetFunction(), call it F_SNES(). That is, (F_MF(u + h*d) - F_SNES(u))/h has to approximate the derivative
140*208be567SBarry Smith 
141*208be567SBarry Smith     Developer Notes: This was provided for the MOOSE team who desired to have a SNESSetFunction() function that could change configurations due
142*208be567SBarry Smith                      to contacts while the function provided to MatMFFDSetFunction() cannot. Except for the possibility of changing the configuration
143*208be567SBarry Smith                      both functions compute the same mathematical function so the differencing makes sense.
144*208be567SBarry Smith 
145*208be567SBarry Smith     Level: advanced
146*208be567SBarry Smith 
147*208be567SBarry Smith .seealso: MatCreateSNESMF(), MatSNESMFGetReuseBase()
148*208be567SBarry Smith @*/
149*208be567SBarry Smith PetscErrorCode  MatSNESMFSetReuseBase(Mat J,PetscBool use)
150*208be567SBarry Smith {
151*208be567SBarry Smith   PetscErrorCode ierr;
152*208be567SBarry Smith 
153*208be567SBarry Smith   PetscFunctionBegin;
154*208be567SBarry Smith   PetscValidHeaderSpecific(J,MAT_CLASSID,1);
155*208be567SBarry Smith   ierr = PetscTryMethod(J,"MatSNESMFSetReuseBase_C",(Mat,PetscBool),(J,use));CHKERRQ(ierr);
156*208be567SBarry Smith   PetscFunctionReturn(0);
157*208be567SBarry Smith }
158*208be567SBarry Smith 
159*208be567SBarry Smith static PetscErrorCode  MatSNESMFGetReuseBase_SNESMF(Mat J,PetscBool *use)
160*208be567SBarry Smith {
161*208be567SBarry Smith   PetscFunctionBegin;
162*208be567SBarry Smith   if (J->ops->assemblyend == MatAssemblyEnd_SNESMF_UseBase) *use = PETSC_TRUE;
163*208be567SBarry Smith   else *use = PETSC_FALSE;
164*208be567SBarry Smith   PetscFunctionReturn(0);
165*208be567SBarry Smith }
166*208be567SBarry Smith 
167*208be567SBarry Smith /*@
168*208be567SBarry Smith     MatSNESMFGetReuseBase - Determines if the base vector is to be used for differencing even if the function provided to SNESSetFunction() is not the
169*208be567SBarry Smith                        same as that provided to MatMFFDSetFunction().
170*208be567SBarry Smith 
171*208be567SBarry Smith     Logically Collective on Mat
172*208be567SBarry Smith 
173*208be567SBarry Smith     Input Parameter:
174*208be567SBarry Smith .   J - the MatMFFD matrix
175*208be567SBarry Smith 
176*208be567SBarry Smith     Output Parameter:
177*208be567SBarry Smith .   use - if true always reuse the base vector instead of recomputing f(u) even if the function in the MatSNESMF is
178*208be567SBarry Smith           not SNESComputeFunction()
179*208be567SBarry Smith 
180*208be567SBarry Smith     Notes: Care must be taken when using this routine to insure that the function provided to MatMFFDSetFunction(), call it F_MF() is compatible with
181*208be567SBarry Smith            with that provided to SNESSetFunction(), call it F_SNES(). That is, (F_MF(u + h*d) - F_SNES(u))/h has to approximate the derivative
182*208be567SBarry Smith 
183*208be567SBarry Smith     Developer Notes: This was provided for the MOOSE team who desired to have a SNESSetFunction() function that could change configurations due
184*208be567SBarry Smith                      to contacts while the function provided to MatMFFDSetFunction() cannot. Except for the possibility of changing the configuration
185*208be567SBarry Smith                      both functions compute the same mathematical function so the differencing makes sense.
186*208be567SBarry Smith 
187*208be567SBarry Smith     Level: advanced
188*208be567SBarry Smith 
189*208be567SBarry Smith .seealso: MatCreateSNESMF(), MatSNESMFSetReuseBase()
190*208be567SBarry Smith @*/
191*208be567SBarry Smith PetscErrorCode  MatSNESMFGetReuseBase(Mat J,PetscBool *use)
192*208be567SBarry Smith {
193*208be567SBarry Smith   PetscErrorCode ierr;
194*208be567SBarry Smith 
195*208be567SBarry Smith   PetscFunctionBegin;
196*208be567SBarry Smith   PetscValidHeaderSpecific(J,MAT_CLASSID,1);
197*208be567SBarry Smith   ierr = PetscUseMethod(J,"MatSNESMFGetReuseBase_C",(Mat,PetscBool*),(J,use));CHKERRQ(ierr);
198*208be567SBarry Smith   PetscFunctionReturn(0);
199*208be567SBarry Smith }
200*208be567SBarry Smith 
20152baeb72SSatish Balay /*@
20265f2ba5bSLois Curfman McInnes    MatCreateSNESMF - Creates a matrix-free matrix context for use with
20365f2ba5bSLois Curfman McInnes    a SNES solver.  This matrix can be used as the Jacobian argument for
204174415d9SBarry Smith    the routine SNESSetJacobian(). See MatCreateMFFD() for details on how
205174415d9SBarry Smith    the finite difference computation is done.
206a4d4d686SBarry Smith 
207a4d4d686SBarry Smith    Collective on SNES and Vec
208a4d4d686SBarry Smith 
209a4d4d686SBarry Smith    Input Parameters:
210fef1beadSBarry Smith .  snes - the SNES context
211a4d4d686SBarry Smith 
212a4d4d686SBarry Smith    Output Parameter:
213a4d4d686SBarry Smith .  J - the matrix-free matrix
214a4d4d686SBarry Smith 
21515091d37SBarry Smith    Level: advanced
21615091d37SBarry Smith 
2175eb111a0SBarry Smith 
2185eb111a0SBarry Smith    Notes:
2195eb111a0SBarry Smith      You can call SNESSetJacobian() with MatMFFDComputeJacobian() if you are using matrix and not a different
2205eb111a0SBarry Smith      preconditioner matrix
2215eb111a0SBarry Smith 
2225eb111a0SBarry Smith      If you wish to provide a different function to do differencing on to compute the matrix-free operator than
2235eb111a0SBarry Smith      that provided to SNESSetFunction() then call MatMFFDSetFunction() with your function after this call.
2245eb111a0SBarry Smith 
2255eb111a0SBarry Smith      The difference between this routine and MatCreateMFFD() is that this matrix
2265eb111a0SBarry Smith      automatically gets the current base vector from the SNES object and not from an
2275eb111a0SBarry Smith      explicit call to MatMFFDSetBase().
2285eb111a0SBarry Smith 
229174415d9SBarry Smith    Warning:
230174415d9SBarry Smith      If MatMFFDSetBase() is ever called on jac then this routine will NO longer get
231174415d9SBarry Smith      the x from the SNES object and MatMFFDSetBase() must from that point on be used to
232174415d9SBarry Smith      change the base vector x.
2339a6cb015SBarry Smith 
2345eb111a0SBarry Smith    Warning:
2355eb111a0SBarry Smith      Using a different function for the differencing will not work if you are using non-linear left preconditioning.
236ca93e954SBarry Smith 
237ca93e954SBarry Smith 
238722329fbSBarry Smith .seealso: MatDestroy(), MatMFFDSetFunction(), MatMFFDSetFunctionError(), MatMFFDDSSetUmin()
239174415d9SBarry Smith           MatMFFDSetHHistory(), MatMFFDResetHHistory(), MatCreateMFFD(),
240*208be567SBarry Smith           MatMFFDGetH(), MatMFFDRegister(), MatMFFDComputeJacobian(), MatSNESMFSetReuseBase(), MatSNESMFGetReuseBase()
241a4d4d686SBarry Smith 
242a4d4d686SBarry Smith @*/
2437087cfbeSBarry Smith PetscErrorCode  MatCreateSNESMF(SNES snes,Mat *J)
244a4d4d686SBarry Smith {
245dfbe8321SBarry Smith   PetscErrorCode ierr;
246fef1beadSBarry Smith   PetscInt       n,N;
2475eb111a0SBarry Smith   MatMFFD        mf;
2481d1367b7SBarry Smith 
2491d1367b7SBarry Smith   PetscFunctionBegin;
250a8248277SBarry Smith   if (snes->vec_func) {
251fef1beadSBarry Smith     ierr = VecGetLocalSize(snes->vec_func,&n);CHKERRQ(ierr);
252fef1beadSBarry Smith     ierr = VecGetSize(snes->vec_func,&N);CHKERRQ(ierr);
253a8248277SBarry Smith   } else if (snes->dm) {
254a8248277SBarry Smith     Vec tmp;
255a8248277SBarry Smith     ierr = DMGetGlobalVector(snes->dm,&tmp);CHKERRQ(ierr);
256a8248277SBarry Smith     ierr = VecGetLocalSize(tmp,&n);CHKERRQ(ierr);
257a8248277SBarry Smith     ierr = VecGetSize(tmp,&N);CHKERRQ(ierr);
258a8248277SBarry Smith     ierr = DMRestoreGlobalVector(snes->dm,&tmp);CHKERRQ(ierr);
259ce94432eSBarry Smith   } else SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE,"Must call SNESSetFunction() or SNESSetDM() first");
260ce94432eSBarry Smith   ierr = MatCreateMFFD(PetscObjectComm((PetscObject)snes),n,n,N,N,J);CHKERRQ(ierr);
26188b4c220SStefano Zampini 
2625eb111a0SBarry Smith   mf      = (MatMFFD)(*J)->data;
2635eb111a0SBarry Smith   mf->ctx = snes;
2645eb111a0SBarry Smith 
265efd4aadfSBarry Smith   if (snes->npc && snes->npcside== PC_LEFT) {
266be95d8f1SBarry Smith     ierr = MatMFFDSetFunction(*J,(PetscErrorCode (*)(void*,Vec,Vec))SNESComputeFunctionDefaultNPC,snes);CHKERRQ(ierr);
267ed07d7d7SPeter Brune   } else {
268ece7ea46SSatish Balay     ierr = MatMFFDSetFunction(*J,(PetscErrorCode (*)(void*,Vec,Vec))SNESComputeFunction,snes);CHKERRQ(ierr);
269ed07d7d7SPeter Brune   }
2701aa26658SKarl Rupp 
2713ec795f1SBarry Smith   (*J)->ops->assemblyend = MatAssemblyEnd_SNESMF;
2721aa26658SKarl Rupp 
273bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)*J,"MatMFFDSetBase_C",MatMFFDSetBase_SNESMF);CHKERRQ(ierr);
274*208be567SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)*J,"MatSNESMFSetReuseBase_C",MatSNESMFSetReuseBase_SNESMF);CHKERRQ(ierr);
275*208be567SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)*J,"MatSNESMFGetReuseBase_C",MatSNESMFGetReuseBase_SNESMF);CHKERRQ(ierr);
2761d1367b7SBarry Smith   PetscFunctionReturn(0);
2771d1367b7SBarry Smith }
278