xref: /petsc/src/snes/mf/snesmfj.c (revision 420bcc1b905230dede3c88f397d1a4e60493adde)
1af0996ceSBarry Smith #include <petsc/private/snesimpl.h> /*I  "petscsnes.h" I*/
21e25c274SJed Brown #include <petscdm.h>                /*I  "petscdm.h"   I*/
3c6db04a5SJed Brown #include <../src/mat/impls/mffd/mffdimpl.h>
4af0996ceSBarry Smith #include <petsc/private/matimpl.h>
581e6777dSBarry Smith 
65fe378a3SBarry Smith /*@C
7e884886fSBarry Smith   MatMFFDComputeJacobian - Tells the matrix-free Jacobian object the new location at which
8*420bcc1bSBarry Smith   Jacobian matrix-vector products will be computed at, i.e. J(x) * a. The x is obtained
9f6dfbefdSBarry Smith   from the `SNES` object (using `SNESGetSolution()`).
10e884886fSBarry Smith 
11c3339decSBarry Smith   Collective
12e884886fSBarry Smith 
13e884886fSBarry Smith   Input Parameters:
14e884886fSBarry Smith + snes  - the nonlinear solver context
15*420bcc1bSBarry Smith . x     - the point at which the Jacobian-vector products will be performed
16f6dfbefdSBarry Smith . jac   - the matrix-free Jacobian object of `MatType` `MATMFFD`, likely obtained with `MatCreateSNESMF()`
17*420bcc1bSBarry Smith . B     - either the same as `jac` or another matrix type (ignored)
18e884886fSBarry Smith - dummy - the user context (ignored)
19e884886fSBarry Smith 
202fe279fdSBarry Smith   Options Database Key:
21f6dfbefdSBarry Smith . -snes_mf - use the matrix created with `MatSNESMFCreate()` to setup the Jacobian for each new solution in the Newton process
22f6dfbefdSBarry Smith 
23e884886fSBarry Smith   Level: developer
24e884886fSBarry Smith 
25f6dfbefdSBarry Smith   Notes:
26*420bcc1bSBarry Smith   If `MatMFFDSetBase()` is ever called on `jac` then this routine will NO longer get
27*420bcc1bSBarry Smith   the `x` from the `SNES` object and `MatMFFDSetBase()` must from that point on be used to
28*420bcc1bSBarry Smith   change the base vector `x`.
29174415d9SBarry Smith 
30f6dfbefdSBarry Smith   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
33f6dfbefdSBarry Smith   -snes_mf but rarely used directly by users. (All this routine does is call `MatAssemblyBegin/End()` on
34*420bcc1bSBarry Smith   the `Mat` `jac`.)
355fe378a3SBarry Smith 
36*420bcc1bSBarry Smith .seealso: [](ch_snes), `MatMFFDGetH()`, `MatCreateSNESMF()`, `MatMFFDSetBase()`, `MatCreateMFFD()`, `MATMFFD`,
37e4094ef1SJacob Faibussowitsch           `MatMFFDSetHHistory()`, `MatMFFDSetFunctionError()`, `SNESSetJacobian()`
38e884886fSBarry Smith @*/
39d71ae5a4SJacob Faibussowitsch PetscErrorCode MatMFFDComputeJacobian(SNES snes, Vec x, Mat jac, Mat B, void *dummy)
40d71ae5a4SJacob Faibussowitsch {
41e884886fSBarry Smith   PetscFunctionBegin;
429566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(jac, MAT_FINAL_ASSEMBLY));
439566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(jac, MAT_FINAL_ASSEMBLY));
443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
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 /*@
51f6dfbefdSBarry Smith   MatSNESMFGetSNES - returns the `SNES` associated with a matrix created with `MatCreateSNESMF()`
52bc13fc8dSBarry Smith 
5320f4b53cSBarry Smith   Not Collective
54bc13fc8dSBarry Smith 
55bc13fc8dSBarry Smith   Input Parameter:
56bc13fc8dSBarry Smith . J - the matrix
57bc13fc8dSBarry Smith 
58bc13fc8dSBarry Smith   Output Parameter:
59f6dfbefdSBarry Smith . snes - the `SNES` object
60bc13fc8dSBarry Smith 
6106dd6b0eSSatish Balay   Level: advanced
6206dd6b0eSSatish Balay 
63*420bcc1bSBarry Smith .seealso: [](ch_snes), `Mat`, `SNES`, `MatCreateSNESMF()`
64bc13fc8dSBarry Smith @*/
65d71ae5a4SJacob Faibussowitsch PetscErrorCode MatSNESMFGetSNES(Mat J, SNES *snes)
66d71ae5a4SJacob Faibussowitsch {
67789d8953SBarry Smith   MatMFFD j;
68bc13fc8dSBarry Smith 
69bc13fc8dSBarry Smith   PetscFunctionBegin;
709566063dSJacob Faibussowitsch   PetscCall(MatShellGetContext(J, &j));
71bc13fc8dSBarry Smith   *snes = (SNES)j->ctx;
723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
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 */
80d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAssemblyEnd_SNESMF(Mat J, MatAssemblyType mt)
81d71ae5a4SJacob Faibussowitsch {
82789d8953SBarry Smith   MatMFFD j;
83789d8953SBarry Smith   SNES    snes;
8409ffd372SDmitry Karpeev   Vec     u, f;
85bbc1464cSBarry Smith   DM      dm;
86bbc1464cSBarry Smith   DMSNES  dms;
873ec795f1SBarry Smith 
883ec795f1SBarry Smith   PetscFunctionBegin;
899566063dSJacob Faibussowitsch   PetscCall(MatShellGetContext(J, &j));
90789d8953SBarry Smith   snes = (SNES)j->ctx;
919566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd_MFFD(J, mt));
923ec795f1SBarry Smith 
939566063dSJacob Faibussowitsch   PetscCall(SNESGetSolution(snes, &u));
949566063dSJacob Faibussowitsch   PetscCall(SNESGetDM(snes, &dm));
959566063dSJacob Faibussowitsch   PetscCall(DMGetDMSNES(dm, &dms));
96bbc1464cSBarry Smith   if ((j->func == (PetscErrorCode(*)(void *, Vec, Vec))SNESComputeFunction) && !dms->ops->computemffunction) {
979566063dSJacob Faibussowitsch     PetscCall(SNESGetFunction(snes, &f, NULL, NULL));
989566063dSJacob Faibussowitsch     PetscCall(MatMFFDSetBase_MFFD(J, u, f));
995eb111a0SBarry Smith   } else {
1005eb111a0SBarry Smith     /* f value known by SNES is not correct for other differencing function */
1019566063dSJacob Faibussowitsch     PetscCall(MatMFFDSetBase_MFFD(J, u, NULL));
1025eb111a0SBarry Smith   }
1033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1043ec795f1SBarry Smith }
1053ec795f1SBarry Smith 
106174415d9SBarry Smith /*
107208be567SBarry Smith    MatAssemblyEnd_SNESMF_UseBase - Calls MatAssemblyEnd_MFFD() and then sets the
108208be567SBarry Smith     base from the SNES context. This version will cause the base to be used for differencing
109208be567SBarry Smith     even if the func is not SNESComputeFunction. See: MatSNESMFUseBase()
110208be567SBarry Smith 
111208be567SBarry Smith */
112d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAssemblyEnd_SNESMF_UseBase(Mat J, MatAssemblyType mt)
113d71ae5a4SJacob Faibussowitsch {
114789d8953SBarry Smith   MatMFFD j;
115789d8953SBarry Smith   SNES    snes;
116208be567SBarry Smith   Vec     u, f;
117208be567SBarry Smith 
118208be567SBarry Smith   PetscFunctionBegin;
1199566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd_MFFD(J, mt));
1209566063dSJacob Faibussowitsch   PetscCall(MatShellGetContext(J, &j));
121789d8953SBarry Smith   snes = (SNES)j->ctx;
1229566063dSJacob Faibussowitsch   PetscCall(SNESGetSolution(snes, &u));
1239566063dSJacob Faibussowitsch   PetscCall(SNESGetFunction(snes, &f, NULL, NULL));
1249566063dSJacob Faibussowitsch   PetscCall(MatMFFDSetBase_MFFD(J, u, f));
1253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
126208be567SBarry Smith }
127208be567SBarry Smith 
128208be567SBarry Smith /*
129174415d9SBarry Smith     This routine resets the MatAssemblyEnd() for the MatMFFD created from MatCreateSNESMF() so that it NO longer
130174415d9SBarry Smith   uses the solution in the SNES object to update the base. See the warning in MatCreateSNESMF().
131174415d9SBarry Smith */
132d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMFFDSetBase_SNESMF(Mat J, Vec U, Vec F)
133d71ae5a4SJacob Faibussowitsch {
134174415d9SBarry Smith   PetscFunctionBegin;
1359566063dSJacob Faibussowitsch   PetscCall(MatMFFDSetBase_MFFD(J, U, F));
136174415d9SBarry Smith   J->ops->assemblyend = MatAssemblyEnd_MFFD;
1373ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
138174415d9SBarry Smith }
139174415d9SBarry Smith 
140d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSNESMFSetReuseBase_SNESMF(Mat J, PetscBool use)
141d71ae5a4SJacob Faibussowitsch {
142208be567SBarry Smith   PetscFunctionBegin;
143208be567SBarry Smith   if (use) {
144208be567SBarry Smith     J->ops->assemblyend = MatAssemblyEnd_SNESMF_UseBase;
145208be567SBarry Smith   } else {
146208be567SBarry Smith     J->ops->assemblyend = MatAssemblyEnd_SNESMF;
147208be567SBarry Smith   }
1483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
149208be567SBarry Smith }
150208be567SBarry Smith 
151208be567SBarry Smith /*@
152f6dfbefdSBarry Smith   MatSNESMFSetReuseBase - Causes the base vector to be used for differencing even if the function provided to `SNESSetFunction()` is not the
153f6dfbefdSBarry Smith   same as that provided to `MatMFFDSetFunction()`.
154208be567SBarry Smith 
155c3339decSBarry Smith   Logically Collective
156208be567SBarry Smith 
157208be567SBarry Smith   Input Parameters:
158f6dfbefdSBarry Smith + J   - the `MATMFFD` matrix
159f6dfbefdSBarry Smith - use - if true always reuse the base vector instead of recomputing f(u) even if the function in the `MATMFFD` is
160f6dfbefdSBarry Smith           not `SNESComputeFunction()`
161208be567SBarry Smith 
16220f4b53cSBarry Smith   Level: advanced
16320f4b53cSBarry Smith 
164f6dfbefdSBarry Smith   Note:
165f6dfbefdSBarry Smith   Care must be taken when using this routine to insure that the function provided to `MatMFFDSetFunction()`, call it F_MF() is compatible with
166f6dfbefdSBarry 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
167208be567SBarry Smith 
168e4094ef1SJacob Faibussowitsch   Developer Notes:
169f6dfbefdSBarry Smith   This was provided for the MOOSE team who desired to have a `SNESSetFunction()` function that could change configurations (similar to variable
170f6dfbefdSBarry Smith   switching) to contacts while the function provided to `MatMFFDSetFunction()` cannot. Except for the possibility of changing the configuration
171208be567SBarry Smith   both functions compute the same mathematical function so the differencing makes sense.
172208be567SBarry Smith 
173*420bcc1bSBarry Smith .seealso: [](ch_snes), `SNES`, `MATMFFD`, `MatMFFDSetFunction()`, `SNESSetFunction()`, `MatCreateSNESMF()`, `MatSNESMFGetReuseBase()`
174208be567SBarry Smith @*/
175d71ae5a4SJacob Faibussowitsch PetscErrorCode MatSNESMFSetReuseBase(Mat J, PetscBool use)
176d71ae5a4SJacob Faibussowitsch {
177208be567SBarry Smith   PetscFunctionBegin;
178208be567SBarry Smith   PetscValidHeaderSpecific(J, MAT_CLASSID, 1);
179cac4c232SBarry Smith   PetscTryMethod(J, "MatSNESMFSetReuseBase_C", (Mat, PetscBool), (J, use));
1803ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
181208be567SBarry Smith }
182208be567SBarry Smith 
183d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSNESMFGetReuseBase_SNESMF(Mat J, PetscBool *use)
184d71ae5a4SJacob Faibussowitsch {
185208be567SBarry Smith   PetscFunctionBegin;
186208be567SBarry Smith   if (J->ops->assemblyend == MatAssemblyEnd_SNESMF_UseBase) *use = PETSC_TRUE;
187208be567SBarry Smith   else *use = PETSC_FALSE;
1883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
189208be567SBarry Smith }
190208be567SBarry Smith 
191208be567SBarry Smith /*@
192f6dfbefdSBarry Smith   MatSNESMFGetReuseBase - Determines if the base vector is to be used for differencing even if the function provided to `SNESSetFunction()` is not the
193f6dfbefdSBarry Smith   same as that provided to `MatMFFDSetFunction()`.
194208be567SBarry Smith 
195c3339decSBarry Smith   Logically Collective
196208be567SBarry Smith 
197208be567SBarry Smith   Input Parameter:
198f6dfbefdSBarry Smith . J - the `MATMFFD` matrix
199208be567SBarry Smith 
200208be567SBarry Smith   Output Parameter:
201f6dfbefdSBarry Smith . use - if true always reuse the base vector instead of recomputing f(u) even if the function in the `MATMFFD` is
202f6dfbefdSBarry Smith           not `SNESComputeFunction()`
203208be567SBarry Smith 
204208be567SBarry Smith   Level: advanced
205208be567SBarry Smith 
206f6dfbefdSBarry Smith   Note:
207f6dfbefdSBarry Smith   See `MatSNESMFSetReuseBase()`
208f6dfbefdSBarry Smith 
209*420bcc1bSBarry Smith .seealso: [](ch_snes), `Mat`, `SNES`, `MatSNESMFSetReuseBase()`, `MatCreateSNESMF()`
210208be567SBarry Smith @*/
211d71ae5a4SJacob Faibussowitsch PetscErrorCode MatSNESMFGetReuseBase(Mat J, PetscBool *use)
212d71ae5a4SJacob Faibussowitsch {
213208be567SBarry Smith   PetscFunctionBegin;
214208be567SBarry Smith   PetscValidHeaderSpecific(J, MAT_CLASSID, 1);
215cac4c232SBarry Smith   PetscUseMethod(J, "MatSNESMFGetReuseBase_C", (Mat, PetscBool *), (J, use));
2163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
217208be567SBarry Smith }
218208be567SBarry Smith 
21952baeb72SSatish Balay /*@
22065f2ba5bSLois Curfman McInnes   MatCreateSNESMF - Creates a matrix-free matrix context for use with
221f6dfbefdSBarry Smith   a `SNES` solver.  This matrix can be used as the Jacobian argument for
222f6dfbefdSBarry Smith   the routine `SNESSetJacobian()`. See `MatCreateMFFD()` for details on how
223174415d9SBarry Smith   the finite difference computation is done.
224a4d4d686SBarry Smith 
225c3339decSBarry Smith   Collective
226a4d4d686SBarry Smith 
227a4d4d686SBarry Smith   Input Parameters:
228f6dfbefdSBarry Smith . snes - the `SNES` context
229a4d4d686SBarry Smith 
230a4d4d686SBarry Smith   Output Parameter:
231f6dfbefdSBarry Smith . J - the matrix-free matrix which is of type `MATMFFD`
232a4d4d686SBarry Smith 
23315091d37SBarry Smith   Level: advanced
23415091d37SBarry Smith 
2355eb111a0SBarry Smith   Notes:
236*420bcc1bSBarry Smith   You can call `SNESSetJacobian()` with `MatMFFDComputeJacobian()` if you are not using a different
2375eb111a0SBarry Smith   preconditioner matrix
2385eb111a0SBarry Smith 
2395eb111a0SBarry Smith   If you wish to provide a different function to do differencing on to compute the matrix-free operator than
240f6dfbefdSBarry Smith   that provided to `SNESSetFunction()` then call `MatMFFDSetFunction()` with your function after this call.
2415eb111a0SBarry Smith 
242f6dfbefdSBarry Smith   The difference between this routine and `MatCreateMFFD()` is that this matrix
243f6dfbefdSBarry Smith   automatically gets the current base vector from the `SNES` object and not from an
244f6dfbefdSBarry Smith   explicit call to `MatMFFDSetBase()`.
2455eb111a0SBarry Smith 
246*420bcc1bSBarry Smith   If `MatMFFDSetBase()` is ever called on `jac` then this routine will NO longer get
247f6dfbefdSBarry Smith   the x from the `SNES` object and `MatMFFDSetBase()` must from that point on be used to
248*420bcc1bSBarry Smith   change the base vector `x`.
2499a6cb015SBarry Smith 
2505eb111a0SBarry Smith   Using a different function for the differencing will not work if you are using non-linear left preconditioning.
251ca93e954SBarry Smith 
252*420bcc1bSBarry Smith .seealso: [](ch_snes), `SNES`, `MATMFFD`, `MatDestroy()`, `MatMFFDSetFunction()`, `MatMFFDSetFunctionError()`, `MatMFFDDSSetUmin()`
253db781477SPatrick Sanan           `MatMFFDSetHHistory()`, `MatMFFDResetHHistory()`, `MatCreateMFFD()`,
254db781477SPatrick Sanan           `MatMFFDGetH()`, `MatMFFDRegister()`, `MatMFFDComputeJacobian()`, `MatSNESMFSetReuseBase()`, `MatSNESMFGetReuseBase()`
255a4d4d686SBarry Smith @*/
256d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCreateSNESMF(SNES snes, Mat *J)
257d71ae5a4SJacob Faibussowitsch {
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));
2913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2921d1367b7SBarry Smith }
293