xref: /petsc/src/snes/mf/snesmfj.c (revision cac4c232dc4f93991e342196e27ef7b0655dac7b)
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)
19a5b23f4aSJose E. Roman .   flag - not relevant 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   PetscFunctionBegin;
439566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(jac,MAT_FINAL_ASSEMBLY));
449566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(jac,MAT_FINAL_ASSEMBLY));
45e884886fSBarry Smith   PetscFunctionReturn(0);
46e884886fSBarry Smith }
47e884886fSBarry Smith 
48d8fa6a54SBarry Smith PETSC_EXTERN PetscErrorCode MatAssemblyEnd_MFFD(Mat,MatAssemblyType);
49d8fa6a54SBarry Smith PETSC_EXTERN PetscErrorCode MatMFFDSetBase_MFFD(Mat,Vec,Vec);
50563d23a3SJed Brown 
51bc13fc8dSBarry Smith /*@
52bc13fc8dSBarry Smith     MatSNESMFGetSNES - returns the SNES associated with a matrix created with MatCreateSNESMF()
53bc13fc8dSBarry Smith 
54bc13fc8dSBarry Smith     Not collective
55bc13fc8dSBarry Smith 
56bc13fc8dSBarry Smith     Input Parameter:
57bc13fc8dSBarry Smith .   J - the matrix
58bc13fc8dSBarry Smith 
59bc13fc8dSBarry Smith     Output Parameter:
60bc13fc8dSBarry Smith .   snes - the SNES object
61bc13fc8dSBarry Smith 
6206dd6b0eSSatish Balay     Level: advanced
6306dd6b0eSSatish Balay 
64bc13fc8dSBarry Smith .seealso: MatCreateSNESMF()
65bc13fc8dSBarry Smith @*/
66bc13fc8dSBarry Smith PetscErrorCode MatSNESMFGetSNES(Mat J,SNES *snes)
67bc13fc8dSBarry Smith {
68789d8953SBarry Smith   MatMFFD        j;
69bc13fc8dSBarry Smith 
70bc13fc8dSBarry Smith   PetscFunctionBegin;
719566063dSJacob Faibussowitsch   PetscCall(MatShellGetContext(J,&j));
72bc13fc8dSBarry Smith   *snes = (SNES)j->ctx;
73bc13fc8dSBarry Smith   PetscFunctionReturn(0);
74bc13fc8dSBarry Smith }
75bc13fc8dSBarry Smith 
763ec795f1SBarry Smith /*
773ec795f1SBarry Smith    MatAssemblyEnd_SNESMF - Calls MatAssemblyEnd_MFFD() and then sets the
783ec795f1SBarry Smith     base from the SNES context
793ec795f1SBarry Smith 
803ec795f1SBarry Smith */
81cc2e6a90SBarry Smith static PetscErrorCode MatAssemblyEnd_SNESMF(Mat J,MatAssemblyType mt)
823ec795f1SBarry Smith {
83789d8953SBarry Smith   MatMFFD        j;
84789d8953SBarry Smith   SNES           snes;
8509ffd372SDmitry Karpeev   Vec            u,f;
86bbc1464cSBarry Smith   DM             dm;
87bbc1464cSBarry Smith   DMSNES         dms;
883ec795f1SBarry Smith 
893ec795f1SBarry Smith   PetscFunctionBegin;
909566063dSJacob Faibussowitsch   PetscCall(MatShellGetContext(J,&j));
91789d8953SBarry Smith   snes = (SNES)j->ctx;
929566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd_MFFD(J,mt));
933ec795f1SBarry Smith 
949566063dSJacob Faibussowitsch   PetscCall(SNESGetSolution(snes,&u));
959566063dSJacob Faibussowitsch   PetscCall(SNESGetDM(snes,&dm));
969566063dSJacob Faibussowitsch   PetscCall(DMGetDMSNES(dm,&dms));
97bbc1464cSBarry Smith   if ((j->func == (PetscErrorCode (*)(void*,Vec,Vec))SNESComputeFunction) && !dms->ops->computemffunction) {
989566063dSJacob Faibussowitsch     PetscCall(SNESGetFunction(snes,&f,NULL,NULL));
999566063dSJacob Faibussowitsch     PetscCall(MatMFFDSetBase_MFFD(J,u,f));
1005eb111a0SBarry Smith   } else {
1015eb111a0SBarry Smith     /* f value known by SNES is not correct for other differencing function */
1029566063dSJacob Faibussowitsch     PetscCall(MatMFFDSetBase_MFFD(J,u,NULL));
1035eb111a0SBarry Smith   }
1043ec795f1SBarry Smith   PetscFunctionReturn(0);
1053ec795f1SBarry Smith }
1063ec795f1SBarry Smith 
107174415d9SBarry Smith /*
108208be567SBarry Smith    MatAssemblyEnd_SNESMF_UseBase - Calls MatAssemblyEnd_MFFD() and then sets the
109208be567SBarry Smith     base from the SNES context. This version will cause the base to be used for differencing
110208be567SBarry Smith     even if the func is not SNESComputeFunction. See: MatSNESMFUseBase()
111208be567SBarry Smith 
112208be567SBarry Smith */
113208be567SBarry Smith static PetscErrorCode MatAssemblyEnd_SNESMF_UseBase(Mat J,MatAssemblyType mt)
114208be567SBarry Smith {
115789d8953SBarry Smith   MatMFFD        j;
116789d8953SBarry Smith   SNES           snes;
117208be567SBarry Smith   Vec            u,f;
118208be567SBarry Smith 
119208be567SBarry Smith   PetscFunctionBegin;
1209566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd_MFFD(J,mt));
1219566063dSJacob Faibussowitsch   PetscCall(MatShellGetContext(J,&j));
122789d8953SBarry Smith   snes = (SNES)j->ctx;
1239566063dSJacob Faibussowitsch   PetscCall(SNESGetSolution(snes,&u));
1249566063dSJacob Faibussowitsch   PetscCall(SNESGetFunction(snes,&f,NULL,NULL));
1259566063dSJacob Faibussowitsch   PetscCall(MatMFFDSetBase_MFFD(J,u,f));
126208be567SBarry Smith   PetscFunctionReturn(0);
127208be567SBarry Smith }
128208be567SBarry Smith 
129208be567SBarry Smith /*
130174415d9SBarry Smith     This routine resets the MatAssemblyEnd() for the MatMFFD created from MatCreateSNESMF() so that it NO longer
131174415d9SBarry Smith   uses the solution in the SNES object to update the base. See the warning in MatCreateSNESMF().
132174415d9SBarry Smith */
133cc2e6a90SBarry Smith static PetscErrorCode  MatMFFDSetBase_SNESMF(Mat J,Vec U,Vec F)
134174415d9SBarry Smith {
135174415d9SBarry Smith   PetscFunctionBegin;
1369566063dSJacob Faibussowitsch   PetscCall(MatMFFDSetBase_MFFD(J,U,F));
137174415d9SBarry Smith   J->ops->assemblyend = MatAssemblyEnd_MFFD;
138174415d9SBarry Smith   PetscFunctionReturn(0);
139174415d9SBarry Smith }
140174415d9SBarry Smith 
141208be567SBarry Smith static PetscErrorCode  MatSNESMFSetReuseBase_SNESMF(Mat J,PetscBool use)
142208be567SBarry Smith {
143208be567SBarry Smith   PetscFunctionBegin;
144208be567SBarry Smith   if (use) {
145208be567SBarry Smith     J->ops->assemblyend = MatAssemblyEnd_SNESMF_UseBase;
146208be567SBarry Smith   } else {
147208be567SBarry Smith     J->ops->assemblyend = MatAssemblyEnd_SNESMF;
148208be567SBarry Smith   }
149208be567SBarry Smith   PetscFunctionReturn(0);
150208be567SBarry Smith }
151208be567SBarry Smith 
152208be567SBarry Smith /*@
153208be567SBarry Smith     MatSNESMFSetReuseBase - Causes the base vector to be used for differencing even if the function provided to SNESSetFunction() is not the
154208be567SBarry Smith                        same as that provided to MatMFFDSetFunction().
155208be567SBarry Smith 
156208be567SBarry Smith     Logically Collective on Mat
157208be567SBarry Smith 
158208be567SBarry Smith     Input Parameters:
159208be567SBarry Smith +   J - the MatMFFD matrix
160208be567SBarry Smith -   use - if true always reuse the base vector instead of recomputing f(u) even if the function in the MatSNESMF is
161208be567SBarry Smith           not SNESComputeFunction()
162208be567SBarry Smith 
16395452b02SPatrick Sanan     Notes:
16495452b02SPatrick Sanan     Care must be taken when using this routine to insure that the function provided to MatMFFDSetFunction(), call it F_MF() is compatible with
165208be567SBarry 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
166208be567SBarry Smith 
16795452b02SPatrick Sanan     Developer Notes:
16895452b02SPatrick Sanan     This was provided for the MOOSE team who desired to have a SNESSetFunction() function that could change configurations due
169208be567SBarry Smith                      to contacts while the function provided to MatMFFDSetFunction() cannot. Except for the possibility of changing the configuration
170208be567SBarry Smith                      both functions compute the same mathematical function so the differencing makes sense.
171208be567SBarry Smith 
172208be567SBarry Smith     Level: advanced
173208be567SBarry Smith 
174208be567SBarry Smith .seealso: MatCreateSNESMF(), MatSNESMFGetReuseBase()
175208be567SBarry Smith @*/
176208be567SBarry Smith PetscErrorCode  MatSNESMFSetReuseBase(Mat J,PetscBool use)
177208be567SBarry Smith {
178208be567SBarry Smith   PetscFunctionBegin;
179208be567SBarry Smith   PetscValidHeaderSpecific(J,MAT_CLASSID,1);
180*cac4c232SBarry Smith   PetscTryMethod(J,"MatSNESMFSetReuseBase_C",(Mat,PetscBool),(J,use));
181208be567SBarry Smith   PetscFunctionReturn(0);
182208be567SBarry Smith }
183208be567SBarry Smith 
184208be567SBarry Smith static PetscErrorCode  MatSNESMFGetReuseBase_SNESMF(Mat J,PetscBool *use)
185208be567SBarry Smith {
186208be567SBarry Smith   PetscFunctionBegin;
187208be567SBarry Smith   if (J->ops->assemblyend == MatAssemblyEnd_SNESMF_UseBase) *use = PETSC_TRUE;
188208be567SBarry Smith   else *use = PETSC_FALSE;
189208be567SBarry Smith   PetscFunctionReturn(0);
190208be567SBarry Smith }
191208be567SBarry Smith 
192208be567SBarry Smith /*@
193208be567SBarry Smith     MatSNESMFGetReuseBase - Determines if the base vector is to be used for differencing even if the function provided to SNESSetFunction() is not the
194208be567SBarry Smith                        same as that provided to MatMFFDSetFunction().
195208be567SBarry Smith 
196208be567SBarry Smith     Logically Collective on Mat
197208be567SBarry Smith 
198208be567SBarry Smith     Input Parameter:
199208be567SBarry Smith .   J - the MatMFFD matrix
200208be567SBarry Smith 
201208be567SBarry Smith     Output Parameter:
202208be567SBarry Smith .   use - if true always reuse the base vector instead of recomputing f(u) even if the function in the MatSNESMF is
203208be567SBarry Smith           not SNESComputeFunction()
204208be567SBarry Smith 
20595452b02SPatrick Sanan     Notes:
20695452b02SPatrick Sanan     Care must be taken when using this routine to insure that the function provided to MatMFFDSetFunction(), call it F_MF() is compatible with
207208be567SBarry 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
208208be567SBarry Smith 
20995452b02SPatrick Sanan     Developer Notes:
21095452b02SPatrick Sanan     This was provided for the MOOSE team who desired to have a SNESSetFunction() function that could change configurations due
211208be567SBarry Smith                      to contacts while the function provided to MatMFFDSetFunction() cannot. Except for the possibility of changing the configuration
212208be567SBarry Smith                      both functions compute the same mathematical function so the differencing makes sense.
213208be567SBarry Smith 
214208be567SBarry Smith     Level: advanced
215208be567SBarry Smith 
216208be567SBarry Smith .seealso: MatCreateSNESMF(), MatSNESMFSetReuseBase()
217208be567SBarry Smith @*/
218208be567SBarry Smith PetscErrorCode  MatSNESMFGetReuseBase(Mat J,PetscBool *use)
219208be567SBarry Smith {
220208be567SBarry Smith   PetscFunctionBegin;
221208be567SBarry Smith   PetscValidHeaderSpecific(J,MAT_CLASSID,1);
222*cac4c232SBarry Smith   PetscUseMethod(J,"MatSNESMFGetReuseBase_C",(Mat,PetscBool*),(J,use));
223208be567SBarry Smith   PetscFunctionReturn(0);
224208be567SBarry Smith }
225208be567SBarry Smith 
22652baeb72SSatish Balay /*@
22765f2ba5bSLois Curfman McInnes    MatCreateSNESMF - Creates a matrix-free matrix context for use with
22865f2ba5bSLois Curfman McInnes    a SNES solver.  This matrix can be used as the Jacobian argument for
229174415d9SBarry Smith    the routine SNESSetJacobian(). See MatCreateMFFD() for details on how
230174415d9SBarry Smith    the finite difference computation is done.
231a4d4d686SBarry Smith 
232d083f849SBarry Smith    Collective on SNES
233a4d4d686SBarry Smith 
234a4d4d686SBarry Smith    Input Parameters:
235fef1beadSBarry Smith .  snes - the SNES context
236a4d4d686SBarry Smith 
237a4d4d686SBarry Smith    Output Parameter:
238a4d4d686SBarry Smith .  J - the matrix-free matrix
239a4d4d686SBarry Smith 
24015091d37SBarry Smith    Level: advanced
24115091d37SBarry Smith 
2425eb111a0SBarry Smith    Notes:
2435eb111a0SBarry Smith      You can call SNESSetJacobian() with MatMFFDComputeJacobian() if you are using matrix and not a different
2445eb111a0SBarry Smith      preconditioner matrix
2455eb111a0SBarry Smith 
2465eb111a0SBarry Smith      If you wish to provide a different function to do differencing on to compute the matrix-free operator than
2475eb111a0SBarry Smith      that provided to SNESSetFunction() then call MatMFFDSetFunction() with your function after this call.
2485eb111a0SBarry Smith 
2495eb111a0SBarry Smith      The difference between this routine and MatCreateMFFD() is that this matrix
2505eb111a0SBarry Smith      automatically gets the current base vector from the SNES object and not from an
2515eb111a0SBarry Smith      explicit call to MatMFFDSetBase().
2525eb111a0SBarry Smith 
253174415d9SBarry Smith    Warning:
254174415d9SBarry Smith      If MatMFFDSetBase() is ever called on jac then this routine will NO longer get
255174415d9SBarry Smith      the x from the SNES object and MatMFFDSetBase() must from that point on be used to
256174415d9SBarry Smith      change the base vector x.
2579a6cb015SBarry Smith 
2585eb111a0SBarry Smith    Warning:
2595eb111a0SBarry Smith      Using a different function for the differencing will not work if you are using non-linear left preconditioning.
260ca93e954SBarry Smith 
261722329fbSBarry Smith .seealso: MatDestroy(), MatMFFDSetFunction(), MatMFFDSetFunctionError(), MatMFFDDSSetUmin()
262174415d9SBarry Smith           MatMFFDSetHHistory(), MatMFFDResetHHistory(), MatCreateMFFD(),
263208be567SBarry Smith           MatMFFDGetH(), MatMFFDRegister(), MatMFFDComputeJacobian(), MatSNESMFSetReuseBase(), MatSNESMFGetReuseBase()
264a4d4d686SBarry Smith 
265a4d4d686SBarry Smith @*/
2667087cfbeSBarry Smith PetscErrorCode  MatCreateSNESMF(SNES snes,Mat *J)
267a4d4d686SBarry Smith {
268fef1beadSBarry Smith   PetscInt       n,N;
2695eb111a0SBarry Smith   MatMFFD        mf;
2701d1367b7SBarry Smith 
2711d1367b7SBarry Smith   PetscFunctionBegin;
272a8248277SBarry Smith   if (snes->vec_func) {
2739566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(snes->vec_func,&n));
2749566063dSJacob Faibussowitsch     PetscCall(VecGetSize(snes->vec_func,&N));
275a8248277SBarry Smith   } else if (snes->dm) {
276a8248277SBarry Smith     Vec tmp;
2779566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalVector(snes->dm,&tmp));
2789566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(tmp,&n));
2799566063dSJacob Faibussowitsch     PetscCall(VecGetSize(tmp,&N));
2809566063dSJacob Faibussowitsch     PetscCall(DMRestoreGlobalVector(snes->dm,&tmp));
281ce94432eSBarry Smith   } else SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE,"Must call SNESSetFunction() or SNESSetDM() first");
2829566063dSJacob Faibussowitsch   PetscCall(MatCreateMFFD(PetscObjectComm((PetscObject)snes),n,n,N,N,J));
2839566063dSJacob Faibussowitsch   PetscCall(MatShellGetContext(*J,&mf));
2845eb111a0SBarry Smith   mf->ctx = snes;
2855eb111a0SBarry Smith 
286efd4aadfSBarry Smith   if (snes->npc && snes->npcside== PC_LEFT) {
2879566063dSJacob Faibussowitsch     PetscCall(MatMFFDSetFunction(*J,(PetscErrorCode (*)(void*,Vec,Vec))SNESComputeFunctionDefaultNPC,snes));
288ed07d7d7SPeter Brune   } else {
289bbc1464cSBarry Smith     DM     dm;
290bbc1464cSBarry Smith     DMSNES dms;
2911aa26658SKarl Rupp 
2929566063dSJacob Faibussowitsch     PetscCall(SNESGetDM(snes,&dm));
2939566063dSJacob Faibussowitsch     PetscCall(DMGetDMSNES(dm,&dms));
2949566063dSJacob Faibussowitsch     PetscCall(MatMFFDSetFunction(*J,(PetscErrorCode (*)(void*,Vec,Vec))(dms->ops->computemffunction ? SNESComputeMFFunction : SNESComputeFunction),snes));
295bbc1464cSBarry Smith   }
2963ec795f1SBarry Smith   (*J)->ops->assemblyend = MatAssemblyEnd_SNESMF;
2971aa26658SKarl Rupp 
2989566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)*J,"MatMFFDSetBase_C",MatMFFDSetBase_SNESMF));
2999566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)*J,"MatSNESMFSetReuseBase_C",MatSNESMFSetReuseBase_SNESMF));
3009566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)*J,"MatSNESMFGetReuseBase_C",MatSNESMFGetReuseBase_SNESMF));
3011d1367b7SBarry Smith   PetscFunctionReturn(0);
3021d1367b7SBarry Smith }
303