xref: /petsc/src/snes/mf/snesmfj.c (revision e4094ef18e7e53fda86cf35f3a47fda48a8e77d8)
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
10f6dfbefdSBarry Smith   from the `SNES` object (using `SNESGetSolution()`).
11e884886fSBarry Smith 
12c3339decSBarry Smith   Collective
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
17f6dfbefdSBarry 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 
222fe279fdSBarry Smith   Options Database Key:
23f6dfbefdSBarry Smith . -snes_mf - use the matrix created with `MatSNESMFCreate()` to setup the Jacobian for each new solution in the Newton process
24f6dfbefdSBarry Smith 
25e884886fSBarry Smith   Level: developer
26e884886fSBarry Smith 
27f6dfbefdSBarry Smith   Notes:
28f6dfbefdSBarry Smith   If `MatMFFDSetBase()` is ever called on jac then this routine will NO longer get
29f6dfbefdSBarry 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 
32f6dfbefdSBarry 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
35f6dfbefdSBarry Smith   -snes_mf but rarely used directly by users. (All this routine does is call `MatAssemblyBegin/End()` on
36f6dfbefdSBarry Smith   the `Mat` jac.)
375fe378a3SBarry Smith 
38f6dfbefdSBarry Smith .seealso: `MatMFFDGetH()`, `MatCreateSNESMF()`, `MatMFFDSetBase()`, `MatCreateMFFD()`, `MATMFFD`,
39*e4094ef1SJacob Faibussowitsch           `MatMFFDSetHHistory()`, `MatMFFDSetFunctionError()`, `SNESSetJacobian()`
40e884886fSBarry Smith @*/
41d71ae5a4SJacob Faibussowitsch PetscErrorCode MatMFFDComputeJacobian(SNES snes, Vec x, Mat jac, Mat B, void *dummy)
42d71ae5a4SJacob Faibussowitsch {
43e884886fSBarry Smith   PetscFunctionBegin;
449566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(jac, MAT_FINAL_ASSEMBLY));
459566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(jac, MAT_FINAL_ASSEMBLY));
463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
47e884886fSBarry Smith }
48e884886fSBarry Smith 
49d8fa6a54SBarry Smith PETSC_EXTERN PetscErrorCode MatAssemblyEnd_MFFD(Mat, MatAssemblyType);
50d8fa6a54SBarry Smith PETSC_EXTERN PetscErrorCode MatMFFDSetBase_MFFD(Mat, Vec, Vec);
51563d23a3SJed Brown 
52bc13fc8dSBarry Smith /*@
53f6dfbefdSBarry Smith   MatSNESMFGetSNES - returns the `SNES` associated with a matrix created with `MatCreateSNESMF()`
54bc13fc8dSBarry Smith 
5520f4b53cSBarry Smith   Not Collective
56bc13fc8dSBarry Smith 
57bc13fc8dSBarry Smith   Input Parameter:
58bc13fc8dSBarry Smith . J - the matrix
59bc13fc8dSBarry Smith 
60bc13fc8dSBarry Smith   Output Parameter:
61f6dfbefdSBarry Smith . snes - the `SNES` object
62bc13fc8dSBarry Smith 
6306dd6b0eSSatish Balay   Level: advanced
6406dd6b0eSSatish Balay 
65f6dfbefdSBarry Smith .seealso: `Mat`, `SNES`, `MatCreateSNESMF()`
66bc13fc8dSBarry Smith @*/
67d71ae5a4SJacob Faibussowitsch PetscErrorCode MatSNESMFGetSNES(Mat J, SNES *snes)
68d71ae5a4SJacob Faibussowitsch {
69789d8953SBarry Smith   MatMFFD j;
70bc13fc8dSBarry Smith 
71bc13fc8dSBarry Smith   PetscFunctionBegin;
729566063dSJacob Faibussowitsch   PetscCall(MatShellGetContext(J, &j));
73bc13fc8dSBarry Smith   *snes = (SNES)j->ctx;
743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
75bc13fc8dSBarry Smith }
76bc13fc8dSBarry Smith 
773ec795f1SBarry Smith /*
783ec795f1SBarry Smith    MatAssemblyEnd_SNESMF - Calls MatAssemblyEnd_MFFD() and then sets the
793ec795f1SBarry Smith     base from the SNES context
803ec795f1SBarry Smith 
813ec795f1SBarry Smith */
82d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAssemblyEnd_SNESMF(Mat J, MatAssemblyType mt)
83d71ae5a4SJacob Faibussowitsch {
84789d8953SBarry Smith   MatMFFD j;
85789d8953SBarry Smith   SNES    snes;
8609ffd372SDmitry Karpeev   Vec     u, f;
87bbc1464cSBarry Smith   DM      dm;
88bbc1464cSBarry Smith   DMSNES  dms;
893ec795f1SBarry Smith 
903ec795f1SBarry Smith   PetscFunctionBegin;
919566063dSJacob Faibussowitsch   PetscCall(MatShellGetContext(J, &j));
92789d8953SBarry Smith   snes = (SNES)j->ctx;
939566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd_MFFD(J, mt));
943ec795f1SBarry Smith 
959566063dSJacob Faibussowitsch   PetscCall(SNESGetSolution(snes, &u));
969566063dSJacob Faibussowitsch   PetscCall(SNESGetDM(snes, &dm));
979566063dSJacob Faibussowitsch   PetscCall(DMGetDMSNES(dm, &dms));
98bbc1464cSBarry Smith   if ((j->func == (PetscErrorCode(*)(void *, Vec, Vec))SNESComputeFunction) && !dms->ops->computemffunction) {
999566063dSJacob Faibussowitsch     PetscCall(SNESGetFunction(snes, &f, NULL, NULL));
1009566063dSJacob Faibussowitsch     PetscCall(MatMFFDSetBase_MFFD(J, u, f));
1015eb111a0SBarry Smith   } else {
1025eb111a0SBarry Smith     /* f value known by SNES is not correct for other differencing function */
1039566063dSJacob Faibussowitsch     PetscCall(MatMFFDSetBase_MFFD(J, u, NULL));
1045eb111a0SBarry Smith   }
1053ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1063ec795f1SBarry Smith }
1073ec795f1SBarry Smith 
108174415d9SBarry Smith /*
109208be567SBarry Smith    MatAssemblyEnd_SNESMF_UseBase - Calls MatAssemblyEnd_MFFD() and then sets the
110208be567SBarry Smith     base from the SNES context. This version will cause the base to be used for differencing
111208be567SBarry Smith     even if the func is not SNESComputeFunction. See: MatSNESMFUseBase()
112208be567SBarry Smith 
113208be567SBarry Smith */
114d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAssemblyEnd_SNESMF_UseBase(Mat J, MatAssemblyType mt)
115d71ae5a4SJacob Faibussowitsch {
116789d8953SBarry Smith   MatMFFD j;
117789d8953SBarry Smith   SNES    snes;
118208be567SBarry Smith   Vec     u, f;
119208be567SBarry Smith 
120208be567SBarry Smith   PetscFunctionBegin;
1219566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd_MFFD(J, mt));
1229566063dSJacob Faibussowitsch   PetscCall(MatShellGetContext(J, &j));
123789d8953SBarry Smith   snes = (SNES)j->ctx;
1249566063dSJacob Faibussowitsch   PetscCall(SNESGetSolution(snes, &u));
1259566063dSJacob Faibussowitsch   PetscCall(SNESGetFunction(snes, &f, NULL, NULL));
1269566063dSJacob Faibussowitsch   PetscCall(MatMFFDSetBase_MFFD(J, u, f));
1273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
128208be567SBarry Smith }
129208be567SBarry Smith 
130208be567SBarry Smith /*
131174415d9SBarry Smith     This routine resets the MatAssemblyEnd() for the MatMFFD created from MatCreateSNESMF() so that it NO longer
132174415d9SBarry Smith   uses the solution in the SNES object to update the base. See the warning in MatCreateSNESMF().
133174415d9SBarry Smith */
134d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMFFDSetBase_SNESMF(Mat J, Vec U, Vec F)
135d71ae5a4SJacob Faibussowitsch {
136174415d9SBarry Smith   PetscFunctionBegin;
1379566063dSJacob Faibussowitsch   PetscCall(MatMFFDSetBase_MFFD(J, U, F));
138174415d9SBarry Smith   J->ops->assemblyend = MatAssemblyEnd_MFFD;
1393ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
140174415d9SBarry Smith }
141174415d9SBarry Smith 
142d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSNESMFSetReuseBase_SNESMF(Mat J, PetscBool use)
143d71ae5a4SJacob Faibussowitsch {
144208be567SBarry Smith   PetscFunctionBegin;
145208be567SBarry Smith   if (use) {
146208be567SBarry Smith     J->ops->assemblyend = MatAssemblyEnd_SNESMF_UseBase;
147208be567SBarry Smith   } else {
148208be567SBarry Smith     J->ops->assemblyend = MatAssemblyEnd_SNESMF;
149208be567SBarry Smith   }
1503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
151208be567SBarry Smith }
152208be567SBarry Smith 
153208be567SBarry Smith /*@
154f6dfbefdSBarry Smith   MatSNESMFSetReuseBase - Causes the base vector to be used for differencing even if the function provided to `SNESSetFunction()` is not the
155f6dfbefdSBarry Smith   same as that provided to `MatMFFDSetFunction()`.
156208be567SBarry Smith 
157c3339decSBarry Smith   Logically Collective
158208be567SBarry Smith 
159208be567SBarry Smith   Input Parameters:
160f6dfbefdSBarry Smith + J   - the `MATMFFD` matrix
161f6dfbefdSBarry Smith - use - if true always reuse the base vector instead of recomputing f(u) even if the function in the `MATMFFD` is
162f6dfbefdSBarry Smith           not `SNESComputeFunction()`
163208be567SBarry Smith 
16420f4b53cSBarry Smith   Level: advanced
16520f4b53cSBarry Smith 
166f6dfbefdSBarry Smith   Note:
167f6dfbefdSBarry Smith   Care must be taken when using this routine to insure that the function provided to `MatMFFDSetFunction()`, call it F_MF() is compatible with
168f6dfbefdSBarry 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
169208be567SBarry Smith 
170*e4094ef1SJacob Faibussowitsch   Developer Notes:
171f6dfbefdSBarry Smith   This was provided for the MOOSE team who desired to have a `SNESSetFunction()` function that could change configurations (similar to variable
172f6dfbefdSBarry Smith   switching) to contacts while the function provided to `MatMFFDSetFunction()` cannot. Except for the possibility of changing the configuration
173208be567SBarry Smith   both functions compute the same mathematical function so the differencing makes sense.
174208be567SBarry Smith 
175f6dfbefdSBarry Smith .seealso: `MATMFFD`, `MatMFFDSetFunction()`, `SNESSetFunction()`, `MatCreateSNESMF()`, `MatSNESMFGetReuseBase()`
176208be567SBarry Smith @*/
177d71ae5a4SJacob Faibussowitsch PetscErrorCode MatSNESMFSetReuseBase(Mat J, PetscBool use)
178d71ae5a4SJacob Faibussowitsch {
179208be567SBarry Smith   PetscFunctionBegin;
180208be567SBarry Smith   PetscValidHeaderSpecific(J, MAT_CLASSID, 1);
181cac4c232SBarry Smith   PetscTryMethod(J, "MatSNESMFSetReuseBase_C", (Mat, PetscBool), (J, use));
1823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
183208be567SBarry Smith }
184208be567SBarry Smith 
185d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSNESMFGetReuseBase_SNESMF(Mat J, PetscBool *use)
186d71ae5a4SJacob Faibussowitsch {
187208be567SBarry Smith   PetscFunctionBegin;
188208be567SBarry Smith   if (J->ops->assemblyend == MatAssemblyEnd_SNESMF_UseBase) *use = PETSC_TRUE;
189208be567SBarry Smith   else *use = PETSC_FALSE;
1903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
191208be567SBarry Smith }
192208be567SBarry Smith 
193208be567SBarry Smith /*@
194f6dfbefdSBarry Smith   MatSNESMFGetReuseBase - Determines if the base vector is to be used for differencing even if the function provided to `SNESSetFunction()` is not the
195f6dfbefdSBarry Smith   same as that provided to `MatMFFDSetFunction()`.
196208be567SBarry Smith 
197c3339decSBarry Smith   Logically Collective
198208be567SBarry Smith 
199208be567SBarry Smith   Input Parameter:
200f6dfbefdSBarry Smith . J - the `MATMFFD` matrix
201208be567SBarry Smith 
202208be567SBarry Smith   Output Parameter:
203f6dfbefdSBarry Smith . use - if true always reuse the base vector instead of recomputing f(u) even if the function in the `MATMFFD` is
204f6dfbefdSBarry Smith           not `SNESComputeFunction()`
205208be567SBarry Smith 
206208be567SBarry Smith   Level: advanced
207208be567SBarry Smith 
208f6dfbefdSBarry Smith   Note:
209f6dfbefdSBarry Smith   See `MatSNESMFSetReuseBase()`
210f6dfbefdSBarry Smith 
211*e4094ef1SJacob Faibussowitsch .seealso: `MatSNESMFSetReuseBase()`, `MatCreateSNESMF()`
212208be567SBarry Smith @*/
213d71ae5a4SJacob Faibussowitsch PetscErrorCode MatSNESMFGetReuseBase(Mat J, PetscBool *use)
214d71ae5a4SJacob Faibussowitsch {
215208be567SBarry Smith   PetscFunctionBegin;
216208be567SBarry Smith   PetscValidHeaderSpecific(J, MAT_CLASSID, 1);
217cac4c232SBarry Smith   PetscUseMethod(J, "MatSNESMFGetReuseBase_C", (Mat, PetscBool *), (J, use));
2183ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
219208be567SBarry Smith }
220208be567SBarry Smith 
22152baeb72SSatish Balay /*@
22265f2ba5bSLois Curfman McInnes   MatCreateSNESMF - Creates a matrix-free matrix context for use with
223f6dfbefdSBarry Smith   a `SNES` solver.  This matrix can be used as the Jacobian argument for
224f6dfbefdSBarry Smith   the routine `SNESSetJacobian()`. See `MatCreateMFFD()` for details on how
225174415d9SBarry Smith   the finite difference computation is done.
226a4d4d686SBarry Smith 
227c3339decSBarry Smith   Collective
228a4d4d686SBarry Smith 
229a4d4d686SBarry Smith   Input Parameters:
230f6dfbefdSBarry Smith . snes - the `SNES` context
231a4d4d686SBarry Smith 
232a4d4d686SBarry Smith   Output Parameter:
233f6dfbefdSBarry Smith . J - the matrix-free matrix which is of type `MATMFFD`
234a4d4d686SBarry Smith 
23515091d37SBarry Smith   Level: advanced
23615091d37SBarry Smith 
2375eb111a0SBarry Smith   Notes:
238f6dfbefdSBarry Smith   You can call `SNESSetJacobian()` with `MatMFFDComputeJacobian()` if you are using matrix and not a different
2395eb111a0SBarry Smith   preconditioner matrix
2405eb111a0SBarry Smith 
2415eb111a0SBarry Smith   If you wish to provide a different function to do differencing on to compute the matrix-free operator than
242f6dfbefdSBarry Smith   that provided to `SNESSetFunction()` then call `MatMFFDSetFunction()` with your function after this call.
2435eb111a0SBarry Smith 
244f6dfbefdSBarry Smith   The difference between this routine and `MatCreateMFFD()` is that this matrix
245f6dfbefdSBarry Smith   automatically gets the current base vector from the `SNES` object and not from an
246f6dfbefdSBarry Smith   explicit call to `MatMFFDSetBase()`.
2475eb111a0SBarry Smith 
248f6dfbefdSBarry Smith   If `MatMFFDSetBase()` is ever called on jac then this routine will NO longer get
249f6dfbefdSBarry Smith   the x from the `SNES` object and `MatMFFDSetBase()` must from that point on be used to
250174415d9SBarry Smith   change the base vector x.
2519a6cb015SBarry Smith 
2525eb111a0SBarry Smith   Using a different function for the differencing will not work if you are using non-linear left preconditioning.
253ca93e954SBarry Smith 
254*e4094ef1SJacob Faibussowitsch .seealso: `MATMFFD`, `MatDestroy()`, `MatMFFDSetFunction()`, `MatMFFDSetFunctionError()`, `MatMFFDDSSetUmin()`
255db781477SPatrick Sanan           `MatMFFDSetHHistory()`, `MatMFFDResetHHistory()`, `MatCreateMFFD()`,
256db781477SPatrick Sanan           `MatMFFDGetH()`, `MatMFFDRegister()`, `MatMFFDComputeJacobian()`, `MatSNESMFSetReuseBase()`, `MatSNESMFGetReuseBase()`
257a4d4d686SBarry Smith @*/
258d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCreateSNESMF(SNES snes, Mat *J)
259d71ae5a4SJacob Faibussowitsch {
260fef1beadSBarry Smith   PetscInt n, N;
2615eb111a0SBarry Smith   MatMFFD  mf;
2621d1367b7SBarry Smith 
2631d1367b7SBarry Smith   PetscFunctionBegin;
264a8248277SBarry Smith   if (snes->vec_func) {
2659566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(snes->vec_func, &n));
2669566063dSJacob Faibussowitsch     PetscCall(VecGetSize(snes->vec_func, &N));
267a8248277SBarry Smith   } else if (snes->dm) {
268a8248277SBarry Smith     Vec tmp;
2699566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalVector(snes->dm, &tmp));
2709566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(tmp, &n));
2719566063dSJacob Faibussowitsch     PetscCall(VecGetSize(tmp, &N));
2729566063dSJacob Faibussowitsch     PetscCall(DMRestoreGlobalVector(snes->dm, &tmp));
273ce94432eSBarry Smith   } else SETERRQ(PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_WRONGSTATE, "Must call SNESSetFunction() or SNESSetDM() first");
2749566063dSJacob Faibussowitsch   PetscCall(MatCreateMFFD(PetscObjectComm((PetscObject)snes), n, n, N, N, J));
2759566063dSJacob Faibussowitsch   PetscCall(MatShellGetContext(*J, &mf));
2765eb111a0SBarry Smith   mf->ctx = snes;
2775eb111a0SBarry Smith 
278efd4aadfSBarry Smith   if (snes->npc && snes->npcside == PC_LEFT) {
2799566063dSJacob Faibussowitsch     PetscCall(MatMFFDSetFunction(*J, (PetscErrorCode(*)(void *, Vec, Vec))SNESComputeFunctionDefaultNPC, snes));
280ed07d7d7SPeter Brune   } else {
281bbc1464cSBarry Smith     DM     dm;
282bbc1464cSBarry Smith     DMSNES dms;
2831aa26658SKarl Rupp 
2849566063dSJacob Faibussowitsch     PetscCall(SNESGetDM(snes, &dm));
2859566063dSJacob Faibussowitsch     PetscCall(DMGetDMSNES(dm, &dms));
2869566063dSJacob Faibussowitsch     PetscCall(MatMFFDSetFunction(*J, (PetscErrorCode(*)(void *, Vec, Vec))(dms->ops->computemffunction ? SNESComputeMFFunction : SNESComputeFunction), snes));
287bbc1464cSBarry Smith   }
2883ec795f1SBarry Smith   (*J)->ops->assemblyend = MatAssemblyEnd_SNESMF;
2891aa26658SKarl Rupp 
2909566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)*J, "MatMFFDSetBase_C", MatMFFDSetBase_SNESMF));
2919566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)*J, "MatSNESMFSetReuseBase_C", MatSNESMFSetReuseBase_SNESMF));
2929566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)*J, "MatSNESMFGetReuseBase_C", MatSNESMFGetReuseBase_SNESMF));
2933ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2941d1367b7SBarry Smith }
295