xref: /petsc/src/snes/mf/snesmfj.c (revision f6dfbefd03961ab3be6f06be75c96cbf27a49667)
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
10*f6dfbefdSBarry Smith        from the `SNES` object (using `SNESGetSolution()`).
11e884886fSBarry Smith 
12*f6dfbefdSBarry Smith    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
17*f6dfbefdSBarry Smith .   jac - the matrix-free Jacobian object of `MatType` `MATMFFD`, likely obtained with `MatCreateSNESMF()`
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 
22*f6dfbefdSBarry Smith    Option Database Key:
23*f6dfbefdSBarry Smith .  -snes_mf - use the matrix created with `MatSNESMFCreate()` to setup the Jacobian for each new solution in the Newton process
24*f6dfbefdSBarry Smith 
25e884886fSBarry Smith    Level: developer
26e884886fSBarry Smith 
27*f6dfbefdSBarry Smith    Notes:
28*f6dfbefdSBarry Smith       If `MatMFFDSetBase()` is ever called on jac then this routine will NO longer get
29*f6dfbefdSBarry Smith     the x from the `SNES` object and `MatMFFDSetBase()` must from that point on be used to
30174415d9SBarry Smith     change the base vector x.
31174415d9SBarry Smith 
32*f6dfbefdSBarry Smith      This can be passed into `SNESSetJacobian()` as the Jacobian evaluation function argument
33ecaffddaSVictor Eijkhout      when using a completely matrix-free solver,
34e884886fSBarry Smith      that is the B matrix is also the same matrix operator. This is used when you select
35*f6dfbefdSBarry Smith      -snes_mf but rarely used directly by users. (All this routine does is call `MatAssemblyBegin/End()` on
36*f6dfbefdSBarry Smith      the `Mat` jac.)
375fe378a3SBarry Smith 
38*f6dfbefdSBarry Smith .seealso: `MatMFFDGetH()`, `MatCreateSNESMF()`, `MatMFFDSetBase()`, `MatCreateMFFD()`, `MATMFFD`,
39db781477SPatrick Sanan           `MatMFFDSetHHistory()`, `MatMFFDSetFunctionError()`, `MatCreateMFFD()`, `SNESSetJacobian()`
40e884886fSBarry Smith @*/
419371c9d4SSatish Balay PetscErrorCode MatMFFDComputeJacobian(SNES snes, Vec x, Mat jac, Mat B, void *dummy) {
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 /*@
52*f6dfbefdSBarry 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:
60*f6dfbefdSBarry Smith .   snes - the `SNES` object
61bc13fc8dSBarry Smith 
6206dd6b0eSSatish Balay     Level: advanced
6306dd6b0eSSatish Balay 
64*f6dfbefdSBarry Smith .seealso: `Mat`, `SNES`, `MatCreateSNESMF()`
65bc13fc8dSBarry Smith @*/
669371c9d4SSatish Balay PetscErrorCode MatSNESMFGetSNES(Mat J, SNES *snes) {
67789d8953SBarry Smith   MatMFFD j;
68bc13fc8dSBarry Smith 
69bc13fc8dSBarry Smith   PetscFunctionBegin;
709566063dSJacob Faibussowitsch   PetscCall(MatShellGetContext(J, &j));
71bc13fc8dSBarry Smith   *snes = (SNES)j->ctx;
72bc13fc8dSBarry Smith   PetscFunctionReturn(0);
73bc13fc8dSBarry Smith }
74bc13fc8dSBarry Smith 
753ec795f1SBarry Smith /*
763ec795f1SBarry Smith    MatAssemblyEnd_SNESMF - Calls MatAssemblyEnd_MFFD() and then sets the
773ec795f1SBarry Smith     base from the SNES context
783ec795f1SBarry Smith 
793ec795f1SBarry Smith */
809371c9d4SSatish Balay static PetscErrorCode MatAssemblyEnd_SNESMF(Mat J, MatAssemblyType mt) {
81789d8953SBarry Smith   MatMFFD j;
82789d8953SBarry Smith   SNES    snes;
8309ffd372SDmitry Karpeev   Vec     u, f;
84bbc1464cSBarry Smith   DM      dm;
85bbc1464cSBarry Smith   DMSNES  dms;
863ec795f1SBarry Smith 
873ec795f1SBarry Smith   PetscFunctionBegin;
889566063dSJacob Faibussowitsch   PetscCall(MatShellGetContext(J, &j));
89789d8953SBarry Smith   snes = (SNES)j->ctx;
909566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd_MFFD(J, mt));
913ec795f1SBarry Smith 
929566063dSJacob Faibussowitsch   PetscCall(SNESGetSolution(snes, &u));
939566063dSJacob Faibussowitsch   PetscCall(SNESGetDM(snes, &dm));
949566063dSJacob Faibussowitsch   PetscCall(DMGetDMSNES(dm, &dms));
95bbc1464cSBarry Smith   if ((j->func == (PetscErrorCode(*)(void *, Vec, Vec))SNESComputeFunction) && !dms->ops->computemffunction) {
969566063dSJacob Faibussowitsch     PetscCall(SNESGetFunction(snes, &f, NULL, NULL));
979566063dSJacob Faibussowitsch     PetscCall(MatMFFDSetBase_MFFD(J, u, f));
985eb111a0SBarry Smith   } else {
995eb111a0SBarry Smith     /* f value known by SNES is not correct for other differencing function */
1009566063dSJacob Faibussowitsch     PetscCall(MatMFFDSetBase_MFFD(J, u, NULL));
1015eb111a0SBarry Smith   }
1023ec795f1SBarry Smith   PetscFunctionReturn(0);
1033ec795f1SBarry Smith }
1043ec795f1SBarry Smith 
105174415d9SBarry Smith /*
106208be567SBarry Smith    MatAssemblyEnd_SNESMF_UseBase - Calls MatAssemblyEnd_MFFD() and then sets the
107208be567SBarry Smith     base from the SNES context. This version will cause the base to be used for differencing
108208be567SBarry Smith     even if the func is not SNESComputeFunction. See: MatSNESMFUseBase()
109208be567SBarry Smith 
110208be567SBarry Smith */
1119371c9d4SSatish Balay static PetscErrorCode MatAssemblyEnd_SNESMF_UseBase(Mat J, MatAssemblyType mt) {
112789d8953SBarry Smith   MatMFFD j;
113789d8953SBarry Smith   SNES    snes;
114208be567SBarry Smith   Vec     u, f;
115208be567SBarry Smith 
116208be567SBarry Smith   PetscFunctionBegin;
1179566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd_MFFD(J, mt));
1189566063dSJacob Faibussowitsch   PetscCall(MatShellGetContext(J, &j));
119789d8953SBarry Smith   snes = (SNES)j->ctx;
1209566063dSJacob Faibussowitsch   PetscCall(SNESGetSolution(snes, &u));
1219566063dSJacob Faibussowitsch   PetscCall(SNESGetFunction(snes, &f, NULL, NULL));
1229566063dSJacob Faibussowitsch   PetscCall(MatMFFDSetBase_MFFD(J, u, f));
123208be567SBarry Smith   PetscFunctionReturn(0);
124208be567SBarry Smith }
125208be567SBarry Smith 
126208be567SBarry Smith /*
127174415d9SBarry Smith     This routine resets the MatAssemblyEnd() for the MatMFFD created from MatCreateSNESMF() so that it NO longer
128174415d9SBarry Smith   uses the solution in the SNES object to update the base. See the warning in MatCreateSNESMF().
129174415d9SBarry Smith */
1309371c9d4SSatish Balay static PetscErrorCode MatMFFDSetBase_SNESMF(Mat J, Vec U, Vec F) {
131174415d9SBarry Smith   PetscFunctionBegin;
1329566063dSJacob Faibussowitsch   PetscCall(MatMFFDSetBase_MFFD(J, U, F));
133174415d9SBarry Smith   J->ops->assemblyend = MatAssemblyEnd_MFFD;
134174415d9SBarry Smith   PetscFunctionReturn(0);
135174415d9SBarry Smith }
136174415d9SBarry Smith 
1379371c9d4SSatish Balay static PetscErrorCode MatSNESMFSetReuseBase_SNESMF(Mat J, PetscBool use) {
138208be567SBarry Smith   PetscFunctionBegin;
139208be567SBarry Smith   if (use) {
140208be567SBarry Smith     J->ops->assemblyend = MatAssemblyEnd_SNESMF_UseBase;
141208be567SBarry Smith   } else {
142208be567SBarry Smith     J->ops->assemblyend = MatAssemblyEnd_SNESMF;
143208be567SBarry Smith   }
144208be567SBarry Smith   PetscFunctionReturn(0);
145208be567SBarry Smith }
146208be567SBarry Smith 
147208be567SBarry Smith /*@
148*f6dfbefdSBarry Smith     MatSNESMFSetReuseBase - Causes the base vector to be used for differencing even if the function provided to `SNESSetFunction()` is not the
149*f6dfbefdSBarry Smith                        same as that provided to `MatMFFDSetFunction()`.
150208be567SBarry Smith 
151*f6dfbefdSBarry Smith     Logically Collective on J
152208be567SBarry Smith 
153208be567SBarry Smith     Input Parameters:
154*f6dfbefdSBarry Smith +   J - the `MATMFFD` matrix
155*f6dfbefdSBarry Smith -   use - if true always reuse the base vector instead of recomputing f(u) even if the function in the `MATMFFD` is
156*f6dfbefdSBarry Smith           not `SNESComputeFunction()`
157208be567SBarry Smith 
158*f6dfbefdSBarry Smith     Note:
159*f6dfbefdSBarry Smith     Care must be taken when using this routine to insure that the function provided to `MatMFFDSetFunction()`, call it F_MF() is compatible with
160*f6dfbefdSBarry 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
161208be567SBarry Smith 
162*f6dfbefdSBarry Smith     Developer Note:
163*f6dfbefdSBarry Smith     This was provided for the MOOSE team who desired to have a `SNESSetFunction()` function that could change configurations (similar to variable
164*f6dfbefdSBarry Smith     switching) to contacts while the function provided to `MatMFFDSetFunction()` cannot. Except for the possibility of changing the configuration
165208be567SBarry Smith     both functions compute the same mathematical function so the differencing makes sense.
166208be567SBarry Smith 
167208be567SBarry Smith     Level: advanced
168208be567SBarry Smith 
169*f6dfbefdSBarry Smith .seealso: `MATMFFD`, `MatMFFDSetFunction()`, `SNESSetFunction()`, `MatCreateSNESMF()`, `MatSNESMFGetReuseBase()`
170208be567SBarry Smith @*/
1719371c9d4SSatish Balay PetscErrorCode MatSNESMFSetReuseBase(Mat J, PetscBool use) {
172208be567SBarry Smith   PetscFunctionBegin;
173208be567SBarry Smith   PetscValidHeaderSpecific(J, MAT_CLASSID, 1);
174cac4c232SBarry Smith   PetscTryMethod(J, "MatSNESMFSetReuseBase_C", (Mat, PetscBool), (J, use));
175208be567SBarry Smith   PetscFunctionReturn(0);
176208be567SBarry Smith }
177208be567SBarry Smith 
1789371c9d4SSatish Balay static PetscErrorCode MatSNESMFGetReuseBase_SNESMF(Mat J, PetscBool *use) {
179208be567SBarry Smith   PetscFunctionBegin;
180208be567SBarry Smith   if (J->ops->assemblyend == MatAssemblyEnd_SNESMF_UseBase) *use = PETSC_TRUE;
181208be567SBarry Smith   else *use = PETSC_FALSE;
182208be567SBarry Smith   PetscFunctionReturn(0);
183208be567SBarry Smith }
184208be567SBarry Smith 
185208be567SBarry Smith /*@
186*f6dfbefdSBarry Smith     MatSNESMFGetReuseBase - Determines if the base vector is to be used for differencing even if the function provided to `SNESSetFunction()` is not the
187*f6dfbefdSBarry Smith                        same as that provided to `MatMFFDSetFunction()`.
188208be567SBarry Smith 
189*f6dfbefdSBarry Smith     Logically Collective on J
190208be567SBarry Smith 
191208be567SBarry Smith     Input Parameter:
192*f6dfbefdSBarry Smith .   J - the `MATMFFD` matrix
193208be567SBarry Smith 
194208be567SBarry Smith     Output Parameter:
195*f6dfbefdSBarry Smith .   use - if true always reuse the base vector instead of recomputing f(u) even if the function in the `MATMFFD` is
196*f6dfbefdSBarry Smith           not `SNESComputeFunction()`
197208be567SBarry Smith 
198208be567SBarry Smith     Level: advanced
199208be567SBarry Smith 
200*f6dfbefdSBarry Smith     Note:
201*f6dfbefdSBarry Smith     See `MatSNESMFSetReuseBase()`
202*f6dfbefdSBarry Smith 
203*f6dfbefdSBarry Smith .seealso: `MatSNESMFSetReuseBase()`, `MatCreateSNESMF()`, `MatSNESMFSetReuseBase()`
204208be567SBarry Smith @*/
2059371c9d4SSatish Balay PetscErrorCode MatSNESMFGetReuseBase(Mat J, PetscBool *use) {
206208be567SBarry Smith   PetscFunctionBegin;
207208be567SBarry Smith   PetscValidHeaderSpecific(J, MAT_CLASSID, 1);
208cac4c232SBarry Smith   PetscUseMethod(J, "MatSNESMFGetReuseBase_C", (Mat, PetscBool *), (J, use));
209208be567SBarry Smith   PetscFunctionReturn(0);
210208be567SBarry Smith }
211208be567SBarry Smith 
21252baeb72SSatish Balay /*@
21365f2ba5bSLois Curfman McInnes    MatCreateSNESMF - Creates a matrix-free matrix context for use with
214*f6dfbefdSBarry Smith    a `SNES` solver.  This matrix can be used as the Jacobian argument for
215*f6dfbefdSBarry Smith    the routine `SNESSetJacobian()`. See `MatCreateMFFD()` for details on how
216174415d9SBarry Smith    the finite difference computation is done.
217a4d4d686SBarry Smith 
218*f6dfbefdSBarry Smith    Collective on snes
219a4d4d686SBarry Smith 
220a4d4d686SBarry Smith    Input Parameters:
221*f6dfbefdSBarry Smith .  snes - the `SNES` context
222a4d4d686SBarry Smith 
223a4d4d686SBarry Smith    Output Parameter:
224*f6dfbefdSBarry Smith .  J - the matrix-free matrix which is of type `MATMFFD`
225a4d4d686SBarry Smith 
22615091d37SBarry Smith    Level: advanced
22715091d37SBarry Smith 
2285eb111a0SBarry Smith    Notes:
229*f6dfbefdSBarry Smith      You can call `SNESSetJacobian()` with `MatMFFDComputeJacobian()` if you are using matrix and not a different
2305eb111a0SBarry Smith      preconditioner matrix
2315eb111a0SBarry Smith 
2325eb111a0SBarry Smith      If you wish to provide a different function to do differencing on to compute the matrix-free operator than
233*f6dfbefdSBarry Smith      that provided to `SNESSetFunction()` then call `MatMFFDSetFunction()` with your function after this call.
2345eb111a0SBarry Smith 
235*f6dfbefdSBarry Smith      The difference between this routine and `MatCreateMFFD()` is that this matrix
236*f6dfbefdSBarry Smith      automatically gets the current base vector from the `SNES` object and not from an
237*f6dfbefdSBarry Smith      explicit call to `MatMFFDSetBase()`.
2385eb111a0SBarry Smith 
239*f6dfbefdSBarry Smith      If `MatMFFDSetBase()` is ever called on jac then this routine will NO longer get
240*f6dfbefdSBarry Smith      the x from the `SNES` object and `MatMFFDSetBase()` must from that point on be used to
241174415d9SBarry Smith      change the base vector x.
2429a6cb015SBarry Smith 
2435eb111a0SBarry Smith      Using a different function for the differencing will not work if you are using non-linear left preconditioning.
244ca93e954SBarry Smith 
245*f6dfbefdSBarry Smith .seealso: `MATMFFD, `MatDestroy()`, `MatMFFDSetFunction()`, `MatMFFDSetFunctionError()`, `MatMFFDDSSetUmin()`
246db781477SPatrick Sanan           `MatMFFDSetHHistory()`, `MatMFFDResetHHistory()`, `MatCreateMFFD()`,
247db781477SPatrick Sanan           `MatMFFDGetH()`, `MatMFFDRegister()`, `MatMFFDComputeJacobian()`, `MatSNESMFSetReuseBase()`, `MatSNESMFGetReuseBase()`
248a4d4d686SBarry Smith @*/
2499371c9d4SSatish Balay PetscErrorCode MatCreateSNESMF(SNES snes, Mat *J) {
250fef1beadSBarry Smith   PetscInt n, N;
2515eb111a0SBarry Smith   MatMFFD  mf;
2521d1367b7SBarry Smith 
2531d1367b7SBarry Smith   PetscFunctionBegin;
254a8248277SBarry Smith   if (snes->vec_func) {
2559566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(snes->vec_func, &n));
2569566063dSJacob Faibussowitsch     PetscCall(VecGetSize(snes->vec_func, &N));
257a8248277SBarry Smith   } else if (snes->dm) {
258a8248277SBarry Smith     Vec tmp;
2599566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalVector(snes->dm, &tmp));
2609566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(tmp, &n));
2619566063dSJacob Faibussowitsch     PetscCall(VecGetSize(tmp, &N));
2629566063dSJacob Faibussowitsch     PetscCall(DMRestoreGlobalVector(snes->dm, &tmp));
263ce94432eSBarry Smith   } else SETERRQ(PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_WRONGSTATE, "Must call SNESSetFunction() or SNESSetDM() first");
2649566063dSJacob Faibussowitsch   PetscCall(MatCreateMFFD(PetscObjectComm((PetscObject)snes), n, n, N, N, J));
2659566063dSJacob Faibussowitsch   PetscCall(MatShellGetContext(*J, &mf));
2665eb111a0SBarry Smith   mf->ctx = snes;
2675eb111a0SBarry Smith 
268efd4aadfSBarry Smith   if (snes->npc && snes->npcside == PC_LEFT) {
2699566063dSJacob Faibussowitsch     PetscCall(MatMFFDSetFunction(*J, (PetscErrorCode(*)(void *, Vec, Vec))SNESComputeFunctionDefaultNPC, snes));
270ed07d7d7SPeter Brune   } else {
271bbc1464cSBarry Smith     DM     dm;
272bbc1464cSBarry Smith     DMSNES dms;
2731aa26658SKarl Rupp 
2749566063dSJacob Faibussowitsch     PetscCall(SNESGetDM(snes, &dm));
2759566063dSJacob Faibussowitsch     PetscCall(DMGetDMSNES(dm, &dms));
2769566063dSJacob Faibussowitsch     PetscCall(MatMFFDSetFunction(*J, (PetscErrorCode(*)(void *, Vec, Vec))(dms->ops->computemffunction ? SNESComputeMFFunction : SNESComputeFunction), snes));
277bbc1464cSBarry Smith   }
2783ec795f1SBarry Smith   (*J)->ops->assemblyend = MatAssemblyEnd_SNESMF;
2791aa26658SKarl Rupp 
2809566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)*J, "MatMFFDSetBase_C", MatMFFDSetBase_SNESMF));
2819566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)*J, "MatSNESMFSetReuseBase_C", MatSNESMFSetReuseBase_SNESMF));
2829566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)*J, "MatSNESMFGetReuseBase_C", MatSNESMFGetReuseBase_SNESMF));
2831d1367b7SBarry Smith   PetscFunctionReturn(0);
2841d1367b7SBarry Smith }
285