xref: /petsc/src/snes/mf/snesmfj.c (revision 9371c9d470a9602b6d10a8bf50c9b2280a79e45a)
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 
36db781477SPatrick Sanan .seealso: `MatMFFDGetH()`, `MatCreateSNESMF()`, `MatCreateMFFD()`, `MATMFFD`,
37db781477SPatrick Sanan           `MatMFFDSetHHistory()`, `MatMFFDSetFunctionError()`, `MatCreateMFFD()`, `SNESSetJacobian()`
38e884886fSBarry Smith 
39e884886fSBarry Smith @*/
40*9371c9d4SSatish Balay PetscErrorCode MatMFFDComputeJacobian(SNES snes, Vec x, Mat jac, Mat B, void *dummy) {
41e884886fSBarry Smith   PetscFunctionBegin;
429566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(jac, MAT_FINAL_ASSEMBLY));
439566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(jac, MAT_FINAL_ASSEMBLY));
44e884886fSBarry Smith   PetscFunctionReturn(0);
45e884886fSBarry Smith }
46e884886fSBarry Smith 
47d8fa6a54SBarry Smith PETSC_EXTERN PetscErrorCode MatAssemblyEnd_MFFD(Mat, MatAssemblyType);
48d8fa6a54SBarry Smith PETSC_EXTERN PetscErrorCode MatMFFDSetBase_MFFD(Mat, Vec, Vec);
49563d23a3SJed Brown 
50bc13fc8dSBarry Smith /*@
51bc13fc8dSBarry Smith     MatSNESMFGetSNES - returns the SNES associated with a matrix created with MatCreateSNESMF()
52bc13fc8dSBarry Smith 
53bc13fc8dSBarry Smith     Not collective
54bc13fc8dSBarry Smith 
55bc13fc8dSBarry Smith     Input Parameter:
56bc13fc8dSBarry Smith .   J - the matrix
57bc13fc8dSBarry Smith 
58bc13fc8dSBarry Smith     Output Parameter:
59bc13fc8dSBarry Smith .   snes - the SNES object
60bc13fc8dSBarry Smith 
6106dd6b0eSSatish Balay     Level: advanced
6206dd6b0eSSatish Balay 
63db781477SPatrick Sanan .seealso: `MatCreateSNESMF()`
64bc13fc8dSBarry Smith @*/
65*9371c9d4SSatish Balay PetscErrorCode MatSNESMFGetSNES(Mat J, SNES *snes) {
66789d8953SBarry Smith   MatMFFD j;
67bc13fc8dSBarry Smith 
68bc13fc8dSBarry Smith   PetscFunctionBegin;
699566063dSJacob Faibussowitsch   PetscCall(MatShellGetContext(J, &j));
70bc13fc8dSBarry Smith   *snes = (SNES)j->ctx;
71bc13fc8dSBarry Smith   PetscFunctionReturn(0);
72bc13fc8dSBarry Smith }
73bc13fc8dSBarry Smith 
743ec795f1SBarry Smith /*
753ec795f1SBarry Smith    MatAssemblyEnd_SNESMF - Calls MatAssemblyEnd_MFFD() and then sets the
763ec795f1SBarry Smith     base from the SNES context
773ec795f1SBarry Smith 
783ec795f1SBarry Smith */
79*9371c9d4SSatish Balay static PetscErrorCode MatAssemblyEnd_SNESMF(Mat J, MatAssemblyType mt) {
80789d8953SBarry Smith   MatMFFD j;
81789d8953SBarry Smith   SNES    snes;
8209ffd372SDmitry Karpeev   Vec     u, f;
83bbc1464cSBarry Smith   DM      dm;
84bbc1464cSBarry Smith   DMSNES  dms;
853ec795f1SBarry Smith 
863ec795f1SBarry Smith   PetscFunctionBegin;
879566063dSJacob Faibussowitsch   PetscCall(MatShellGetContext(J, &j));
88789d8953SBarry Smith   snes = (SNES)j->ctx;
899566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd_MFFD(J, mt));
903ec795f1SBarry Smith 
919566063dSJacob Faibussowitsch   PetscCall(SNESGetSolution(snes, &u));
929566063dSJacob Faibussowitsch   PetscCall(SNESGetDM(snes, &dm));
939566063dSJacob Faibussowitsch   PetscCall(DMGetDMSNES(dm, &dms));
94bbc1464cSBarry Smith   if ((j->func == (PetscErrorCode(*)(void *, Vec, Vec))SNESComputeFunction) && !dms->ops->computemffunction) {
959566063dSJacob Faibussowitsch     PetscCall(SNESGetFunction(snes, &f, NULL, NULL));
969566063dSJacob Faibussowitsch     PetscCall(MatMFFDSetBase_MFFD(J, u, f));
975eb111a0SBarry Smith   } else {
985eb111a0SBarry Smith     /* f value known by SNES is not correct for other differencing function */
999566063dSJacob Faibussowitsch     PetscCall(MatMFFDSetBase_MFFD(J, u, NULL));
1005eb111a0SBarry Smith   }
1013ec795f1SBarry Smith   PetscFunctionReturn(0);
1023ec795f1SBarry Smith }
1033ec795f1SBarry Smith 
104174415d9SBarry Smith /*
105208be567SBarry Smith    MatAssemblyEnd_SNESMF_UseBase - Calls MatAssemblyEnd_MFFD() and then sets the
106208be567SBarry Smith     base from the SNES context. This version will cause the base to be used for differencing
107208be567SBarry Smith     even if the func is not SNESComputeFunction. See: MatSNESMFUseBase()
108208be567SBarry Smith 
109208be567SBarry Smith */
110*9371c9d4SSatish Balay static PetscErrorCode MatAssemblyEnd_SNESMF_UseBase(Mat J, MatAssemblyType mt) {
111789d8953SBarry Smith   MatMFFD j;
112789d8953SBarry Smith   SNES    snes;
113208be567SBarry Smith   Vec     u, f;
114208be567SBarry Smith 
115208be567SBarry Smith   PetscFunctionBegin;
1169566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd_MFFD(J, mt));
1179566063dSJacob Faibussowitsch   PetscCall(MatShellGetContext(J, &j));
118789d8953SBarry Smith   snes = (SNES)j->ctx;
1199566063dSJacob Faibussowitsch   PetscCall(SNESGetSolution(snes, &u));
1209566063dSJacob Faibussowitsch   PetscCall(SNESGetFunction(snes, &f, NULL, NULL));
1219566063dSJacob Faibussowitsch   PetscCall(MatMFFDSetBase_MFFD(J, u, f));
122208be567SBarry Smith   PetscFunctionReturn(0);
123208be567SBarry Smith }
124208be567SBarry Smith 
125208be567SBarry Smith /*
126174415d9SBarry Smith     This routine resets the MatAssemblyEnd() for the MatMFFD created from MatCreateSNESMF() so that it NO longer
127174415d9SBarry Smith   uses the solution in the SNES object to update the base. See the warning in MatCreateSNESMF().
128174415d9SBarry Smith */
129*9371c9d4SSatish Balay static PetscErrorCode MatMFFDSetBase_SNESMF(Mat J, Vec U, Vec F) {
130174415d9SBarry Smith   PetscFunctionBegin;
1319566063dSJacob Faibussowitsch   PetscCall(MatMFFDSetBase_MFFD(J, U, F));
132174415d9SBarry Smith   J->ops->assemblyend = MatAssemblyEnd_MFFD;
133174415d9SBarry Smith   PetscFunctionReturn(0);
134174415d9SBarry Smith }
135174415d9SBarry Smith 
136*9371c9d4SSatish Balay static PetscErrorCode MatSNESMFSetReuseBase_SNESMF(Mat J, PetscBool use) {
137208be567SBarry Smith   PetscFunctionBegin;
138208be567SBarry Smith   if (use) {
139208be567SBarry Smith     J->ops->assemblyend = MatAssemblyEnd_SNESMF_UseBase;
140208be567SBarry Smith   } else {
141208be567SBarry Smith     J->ops->assemblyend = MatAssemblyEnd_SNESMF;
142208be567SBarry Smith   }
143208be567SBarry Smith   PetscFunctionReturn(0);
144208be567SBarry Smith }
145208be567SBarry Smith 
146208be567SBarry Smith /*@
147208be567SBarry Smith     MatSNESMFSetReuseBase - Causes the base vector to be used for differencing even if the function provided to SNESSetFunction() is not the
148208be567SBarry Smith                        same as that provided to MatMFFDSetFunction().
149208be567SBarry Smith 
150208be567SBarry Smith     Logically Collective on Mat
151208be567SBarry Smith 
152208be567SBarry Smith     Input Parameters:
153208be567SBarry Smith +   J - the MatMFFD matrix
154208be567SBarry Smith -   use - if true always reuse the base vector instead of recomputing f(u) even if the function in the MatSNESMF is
155208be567SBarry Smith           not SNESComputeFunction()
156208be567SBarry Smith 
15795452b02SPatrick Sanan     Notes:
15895452b02SPatrick Sanan     Care must be taken when using this routine to insure that the function provided to MatMFFDSetFunction(), call it F_MF() is compatible with
159208be567SBarry 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
160208be567SBarry Smith 
16195452b02SPatrick Sanan     Developer Notes:
16295452b02SPatrick Sanan     This was provided for the MOOSE team who desired to have a SNESSetFunction() function that could change configurations due
163208be567SBarry Smith                      to contacts while the function provided to MatMFFDSetFunction() cannot. Except for the possibility of changing the configuration
164208be567SBarry Smith                      both functions compute the same mathematical function so the differencing makes sense.
165208be567SBarry Smith 
166208be567SBarry Smith     Level: advanced
167208be567SBarry Smith 
168db781477SPatrick Sanan .seealso: `MatCreateSNESMF()`, `MatSNESMFGetReuseBase()`
169208be567SBarry Smith @*/
170*9371c9d4SSatish Balay PetscErrorCode MatSNESMFSetReuseBase(Mat J, PetscBool use) {
171208be567SBarry Smith   PetscFunctionBegin;
172208be567SBarry Smith   PetscValidHeaderSpecific(J, MAT_CLASSID, 1);
173cac4c232SBarry Smith   PetscTryMethod(J, "MatSNESMFSetReuseBase_C", (Mat, PetscBool), (J, use));
174208be567SBarry Smith   PetscFunctionReturn(0);
175208be567SBarry Smith }
176208be567SBarry Smith 
177*9371c9d4SSatish Balay static PetscErrorCode MatSNESMFGetReuseBase_SNESMF(Mat J, PetscBool *use) {
178208be567SBarry Smith   PetscFunctionBegin;
179208be567SBarry Smith   if (J->ops->assemblyend == MatAssemblyEnd_SNESMF_UseBase) *use = PETSC_TRUE;
180208be567SBarry Smith   else *use = PETSC_FALSE;
181208be567SBarry Smith   PetscFunctionReturn(0);
182208be567SBarry Smith }
183208be567SBarry Smith 
184208be567SBarry Smith /*@
185208be567SBarry Smith     MatSNESMFGetReuseBase - Determines if the base vector is to be used for differencing even if the function provided to SNESSetFunction() is not the
186208be567SBarry Smith                        same as that provided to MatMFFDSetFunction().
187208be567SBarry Smith 
188208be567SBarry Smith     Logically Collective on Mat
189208be567SBarry Smith 
190208be567SBarry Smith     Input Parameter:
191208be567SBarry Smith .   J - the MatMFFD matrix
192208be567SBarry Smith 
193208be567SBarry Smith     Output Parameter:
194208be567SBarry Smith .   use - if true always reuse the base vector instead of recomputing f(u) even if the function in the MatSNESMF is
195208be567SBarry Smith           not SNESComputeFunction()
196208be567SBarry Smith 
19795452b02SPatrick Sanan     Notes:
19895452b02SPatrick Sanan     Care must be taken when using this routine to insure that the function provided to MatMFFDSetFunction(), call it F_MF() is compatible with
199208be567SBarry 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
200208be567SBarry Smith 
20195452b02SPatrick Sanan     Developer Notes:
20295452b02SPatrick Sanan     This was provided for the MOOSE team who desired to have a SNESSetFunction() function that could change configurations due
203208be567SBarry Smith                      to contacts while the function provided to MatMFFDSetFunction() cannot. Except for the possibility of changing the configuration
204208be567SBarry Smith                      both functions compute the same mathematical function so the differencing makes sense.
205208be567SBarry Smith 
206208be567SBarry Smith     Level: advanced
207208be567SBarry Smith 
208db781477SPatrick Sanan .seealso: `MatCreateSNESMF()`, `MatSNESMFSetReuseBase()`
209208be567SBarry Smith @*/
210*9371c9d4SSatish Balay PetscErrorCode MatSNESMFGetReuseBase(Mat J, PetscBool *use) {
211208be567SBarry Smith   PetscFunctionBegin;
212208be567SBarry Smith   PetscValidHeaderSpecific(J, MAT_CLASSID, 1);
213cac4c232SBarry Smith   PetscUseMethod(J, "MatSNESMFGetReuseBase_C", (Mat, PetscBool *), (J, use));
214208be567SBarry Smith   PetscFunctionReturn(0);
215208be567SBarry Smith }
216208be567SBarry Smith 
21752baeb72SSatish Balay /*@
21865f2ba5bSLois Curfman McInnes    MatCreateSNESMF - Creates a matrix-free matrix context for use with
21965f2ba5bSLois Curfman McInnes    a SNES solver.  This matrix can be used as the Jacobian argument for
220174415d9SBarry Smith    the routine SNESSetJacobian(). See MatCreateMFFD() for details on how
221174415d9SBarry Smith    the finite difference computation is done.
222a4d4d686SBarry Smith 
223d083f849SBarry Smith    Collective on SNES
224a4d4d686SBarry Smith 
225a4d4d686SBarry Smith    Input Parameters:
226fef1beadSBarry Smith .  snes - the SNES context
227a4d4d686SBarry Smith 
228a4d4d686SBarry Smith    Output Parameter:
229a4d4d686SBarry Smith .  J - the matrix-free matrix
230a4d4d686SBarry Smith 
23115091d37SBarry Smith    Level: advanced
23215091d37SBarry Smith 
2335eb111a0SBarry Smith    Notes:
2345eb111a0SBarry Smith      You can call SNESSetJacobian() with MatMFFDComputeJacobian() if you are using matrix and not a different
2355eb111a0SBarry Smith      preconditioner matrix
2365eb111a0SBarry Smith 
2375eb111a0SBarry Smith      If you wish to provide a different function to do differencing on to compute the matrix-free operator than
2385eb111a0SBarry Smith      that provided to SNESSetFunction() then call MatMFFDSetFunction() with your function after this call.
2395eb111a0SBarry Smith 
2405eb111a0SBarry Smith      The difference between this routine and MatCreateMFFD() is that this matrix
2415eb111a0SBarry Smith      automatically gets the current base vector from the SNES object and not from an
2425eb111a0SBarry Smith      explicit call to MatMFFDSetBase().
2435eb111a0SBarry Smith 
244174415d9SBarry Smith    Warning:
245174415d9SBarry Smith      If MatMFFDSetBase() is ever called on jac then this routine will NO longer get
246174415d9SBarry Smith      the x from the SNES object and MatMFFDSetBase() must from that point on be used to
247174415d9SBarry Smith      change the base vector x.
2489a6cb015SBarry Smith 
2495eb111a0SBarry Smith    Warning:
2505eb111a0SBarry Smith      Using a different function for the differencing will not work if you are using non-linear left preconditioning.
251ca93e954SBarry Smith 
252db781477SPatrick Sanan .seealso: `MatDestroy()`, `MatMFFDSetFunction()`, `MatMFFDSetFunctionError()`, `MatMFFDDSSetUmin()`
253db781477SPatrick Sanan           `MatMFFDSetHHistory()`, `MatMFFDResetHHistory()`, `MatCreateMFFD()`,
254db781477SPatrick Sanan           `MatMFFDGetH()`, `MatMFFDRegister()`, `MatMFFDComputeJacobian()`, `MatSNESMFSetReuseBase()`, `MatSNESMFGetReuseBase()`
255a4d4d686SBarry Smith 
256a4d4d686SBarry Smith @*/
257*9371c9d4SSatish Balay PetscErrorCode MatCreateSNESMF(SNES snes, Mat *J) {
258fef1beadSBarry Smith   PetscInt n, N;
2595eb111a0SBarry Smith   MatMFFD  mf;
2601d1367b7SBarry Smith 
2611d1367b7SBarry Smith   PetscFunctionBegin;
262a8248277SBarry Smith   if (snes->vec_func) {
2639566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(snes->vec_func, &n));
2649566063dSJacob Faibussowitsch     PetscCall(VecGetSize(snes->vec_func, &N));
265a8248277SBarry Smith   } else if (snes->dm) {
266a8248277SBarry Smith     Vec tmp;
2679566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalVector(snes->dm, &tmp));
2689566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(tmp, &n));
2699566063dSJacob Faibussowitsch     PetscCall(VecGetSize(tmp, &N));
2709566063dSJacob Faibussowitsch     PetscCall(DMRestoreGlobalVector(snes->dm, &tmp));
271ce94432eSBarry Smith   } else SETERRQ(PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_WRONGSTATE, "Must call SNESSetFunction() or SNESSetDM() first");
2729566063dSJacob Faibussowitsch   PetscCall(MatCreateMFFD(PetscObjectComm((PetscObject)snes), n, n, N, N, J));
2739566063dSJacob Faibussowitsch   PetscCall(MatShellGetContext(*J, &mf));
2745eb111a0SBarry Smith   mf->ctx = snes;
2755eb111a0SBarry Smith 
276efd4aadfSBarry Smith   if (snes->npc && snes->npcside == PC_LEFT) {
2779566063dSJacob Faibussowitsch     PetscCall(MatMFFDSetFunction(*J, (PetscErrorCode(*)(void *, Vec, Vec))SNESComputeFunctionDefaultNPC, snes));
278ed07d7d7SPeter Brune   } else {
279bbc1464cSBarry Smith     DM     dm;
280bbc1464cSBarry Smith     DMSNES dms;
2811aa26658SKarl Rupp 
2829566063dSJacob Faibussowitsch     PetscCall(SNESGetDM(snes, &dm));
2839566063dSJacob Faibussowitsch     PetscCall(DMGetDMSNES(dm, &dms));
2849566063dSJacob Faibussowitsch     PetscCall(MatMFFDSetFunction(*J, (PetscErrorCode(*)(void *, Vec, Vec))(dms->ops->computemffunction ? SNESComputeMFFunction : SNESComputeFunction), snes));
285bbc1464cSBarry Smith   }
2863ec795f1SBarry Smith   (*J)->ops->assemblyend = MatAssemblyEnd_SNESMF;
2871aa26658SKarl Rupp 
2889566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)*J, "MatMFFDSetBase_C", MatMFFDSetBase_SNESMF));
2899566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)*J, "MatSNESMFSetReuseBase_C", MatSNESMFSetReuseBase_SNESMF));
2909566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)*J, "MatSNESMFGetReuseBase_C", MatSNESMFGetReuseBase_SNESMF));
2911d1367b7SBarry Smith   PetscFunctionReturn(0);
2921d1367b7SBarry Smith }
293