xref: /petsc/src/snes/mf/snesmfj.c (revision bbc1464cf0515385cd819c96cf84160a770064ee)
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)
19e884886fSBarry Smith .   flag - not relevent 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   PetscErrorCode ierr;
435fd66863SKarl Rupp 
44e884886fSBarry Smith   PetscFunctionBegin;
4594ab13aaSBarry Smith   ierr = MatAssemblyBegin(jac,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
4694ab13aaSBarry Smith   ierr = MatAssemblyEnd(jac,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
47e884886fSBarry Smith   PetscFunctionReturn(0);
48e884886fSBarry Smith }
49e884886fSBarry Smith 
50d8fa6a54SBarry Smith PETSC_EXTERN PetscErrorCode MatAssemblyEnd_MFFD(Mat,MatAssemblyType);
51d8fa6a54SBarry Smith PETSC_EXTERN PetscErrorCode MatMFFDSetBase_MFFD(Mat,Vec,Vec);
52563d23a3SJed Brown 
53bc13fc8dSBarry Smith /*@
54bc13fc8dSBarry Smith     MatSNESMFGetSNES - returns the SNES associated with a matrix created with MatCreateSNESMF()
55bc13fc8dSBarry Smith 
56bc13fc8dSBarry Smith     Not collective
57bc13fc8dSBarry Smith 
58bc13fc8dSBarry Smith     Input Parameter:
59bc13fc8dSBarry Smith .   J - the matrix
60bc13fc8dSBarry Smith 
61bc13fc8dSBarry Smith     Output Parameter:
62bc13fc8dSBarry Smith .   snes - the SNES object
63bc13fc8dSBarry Smith 
6406dd6b0eSSatish Balay     Level: advanced
6506dd6b0eSSatish Balay 
66bc13fc8dSBarry Smith .seealso: MatCreateSNESMF()
67bc13fc8dSBarry Smith @*/
68bc13fc8dSBarry Smith PetscErrorCode MatSNESMFGetSNES(Mat J,SNES *snes)
69bc13fc8dSBarry Smith {
70789d8953SBarry Smith   MatMFFD        j;
71789d8953SBarry Smith   PetscErrorCode ierr;
72bc13fc8dSBarry Smith 
73bc13fc8dSBarry Smith   PetscFunctionBegin;
74789d8953SBarry Smith   ierr = MatShellGetContext(J,&j);CHKERRQ(ierr);
75bc13fc8dSBarry Smith   *snes = (SNES)j->ctx;
76bc13fc8dSBarry Smith   PetscFunctionReturn(0);
77bc13fc8dSBarry Smith }
78bc13fc8dSBarry Smith 
793ec795f1SBarry Smith /*
803ec795f1SBarry Smith    MatAssemblyEnd_SNESMF - Calls MatAssemblyEnd_MFFD() and then sets the
813ec795f1SBarry Smith     base from the SNES context
823ec795f1SBarry Smith 
833ec795f1SBarry Smith */
84cc2e6a90SBarry Smith static PetscErrorCode MatAssemblyEnd_SNESMF(Mat J,MatAssemblyType mt)
853ec795f1SBarry Smith {
863ec795f1SBarry Smith   PetscErrorCode ierr;
87789d8953SBarry Smith   MatMFFD        j;
88789d8953SBarry Smith   SNES           snes;
8909ffd372SDmitry Karpeev   Vec            u,f;
90*bbc1464cSBarry Smith   DM             dm;
91*bbc1464cSBarry Smith   DMSNES         dms;
923ec795f1SBarry Smith 
933ec795f1SBarry Smith   PetscFunctionBegin;
94789d8953SBarry Smith   ierr = MatShellGetContext(J,&j);CHKERRQ(ierr);
95789d8953SBarry Smith   snes = (SNES)j->ctx;
963ec795f1SBarry Smith   ierr = MatAssemblyEnd_MFFD(J,mt);CHKERRQ(ierr);
973ec795f1SBarry Smith 
98be4711e3SBarry Smith   ierr = SNESGetSolution(snes,&u);CHKERRQ(ierr);
99*bbc1464cSBarry Smith   ierr = SNESGetDM(snes,&dm);CHKERRQ(ierr);
100*bbc1464cSBarry Smith   ierr = DMGetDMSNES(dm,&dms);CHKERRQ(ierr);
101*bbc1464cSBarry Smith   if ((j->func == (PetscErrorCode (*)(void*,Vec,Vec))SNESComputeFunction) && !dms->ops->computemffunction) {
1020298fd71SBarry Smith     ierr = SNESGetFunction(snes,&f,NULL,NULL);CHKERRQ(ierr);
10309ffd372SDmitry Karpeev     ierr = MatMFFDSetBase_MFFD(J,u,f);CHKERRQ(ierr);
1045eb111a0SBarry Smith   } else {
1055eb111a0SBarry Smith     /* f value known by SNES is not correct for other differencing function */
1065eb111a0SBarry Smith     ierr = MatMFFDSetBase_MFFD(J,u,NULL);CHKERRQ(ierr);
1075eb111a0SBarry Smith   }
1083ec795f1SBarry Smith   PetscFunctionReturn(0);
1093ec795f1SBarry Smith }
1103ec795f1SBarry Smith 
111174415d9SBarry Smith /*
112208be567SBarry Smith    MatAssemblyEnd_SNESMF_UseBase - Calls MatAssemblyEnd_MFFD() and then sets the
113208be567SBarry Smith     base from the SNES context. This version will cause the base to be used for differencing
114208be567SBarry Smith     even if the func is not SNESComputeFunction. See: MatSNESMFUseBase()
115208be567SBarry Smith 
116208be567SBarry Smith 
117208be567SBarry Smith */
118208be567SBarry Smith static PetscErrorCode MatAssemblyEnd_SNESMF_UseBase(Mat J,MatAssemblyType mt)
119208be567SBarry Smith {
120208be567SBarry Smith   PetscErrorCode ierr;
121789d8953SBarry Smith   MatMFFD        j;
122789d8953SBarry Smith   SNES           snes;
123208be567SBarry Smith   Vec            u,f;
124208be567SBarry Smith 
125208be567SBarry Smith   PetscFunctionBegin;
126208be567SBarry Smith   ierr = MatAssemblyEnd_MFFD(J,mt);CHKERRQ(ierr);
127789d8953SBarry Smith   ierr = MatShellGetContext(J,&j);CHKERRQ(ierr);
128789d8953SBarry Smith   snes = (SNES)j->ctx;
129208be567SBarry Smith   ierr = SNESGetSolution(snes,&u);CHKERRQ(ierr);
130208be567SBarry Smith   ierr = SNESGetFunction(snes,&f,NULL,NULL);CHKERRQ(ierr);
131208be567SBarry Smith   ierr = MatMFFDSetBase_MFFD(J,u,f);CHKERRQ(ierr);
132208be567SBarry Smith   PetscFunctionReturn(0);
133208be567SBarry Smith }
134208be567SBarry Smith 
135208be567SBarry Smith /*
136174415d9SBarry Smith     This routine resets the MatAssemblyEnd() for the MatMFFD created from MatCreateSNESMF() so that it NO longer
137174415d9SBarry Smith   uses the solution in the SNES object to update the base. See the warning in MatCreateSNESMF().
138174415d9SBarry Smith */
139cc2e6a90SBarry Smith static PetscErrorCode  MatMFFDSetBase_SNESMF(Mat J,Vec U,Vec F)
140174415d9SBarry Smith {
141174415d9SBarry Smith   PetscErrorCode ierr;
142174415d9SBarry Smith 
143174415d9SBarry Smith   PetscFunctionBegin;
144885877adSHong Zhang   ierr = MatMFFDSetBase_MFFD(J,U,F);CHKERRQ(ierr);
145174415d9SBarry Smith   J->ops->assemblyend = MatAssemblyEnd_MFFD;
146174415d9SBarry Smith   PetscFunctionReturn(0);
147174415d9SBarry Smith }
148174415d9SBarry Smith 
149208be567SBarry Smith static PetscErrorCode  MatSNESMFSetReuseBase_SNESMF(Mat J,PetscBool use)
150208be567SBarry Smith {
151208be567SBarry Smith   PetscFunctionBegin;
152208be567SBarry Smith   if (use) {
153208be567SBarry Smith     J->ops->assemblyend = MatAssemblyEnd_SNESMF_UseBase;
154208be567SBarry Smith   } else {
155208be567SBarry Smith     J->ops->assemblyend = MatAssemblyEnd_SNESMF;
156208be567SBarry Smith   }
157208be567SBarry Smith   PetscFunctionReturn(0);
158208be567SBarry Smith }
159208be567SBarry Smith 
160208be567SBarry Smith /*@
161208be567SBarry Smith     MatSNESMFSetReuseBase - Causes the base vector to be used for differencing even if the function provided to SNESSetFunction() is not the
162208be567SBarry Smith                        same as that provided to MatMFFDSetFunction().
163208be567SBarry Smith 
164208be567SBarry Smith     Logically Collective on Mat
165208be567SBarry Smith 
166208be567SBarry Smith     Input Parameters:
167208be567SBarry Smith +   J - the MatMFFD matrix
168208be567SBarry Smith -   use - if true always reuse the base vector instead of recomputing f(u) even if the function in the MatSNESMF is
169208be567SBarry Smith           not SNESComputeFunction()
170208be567SBarry Smith 
17195452b02SPatrick Sanan     Notes:
17295452b02SPatrick Sanan     Care must be taken when using this routine to insure that the function provided to MatMFFDSetFunction(), call it F_MF() is compatible with
173208be567SBarry 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
174208be567SBarry Smith 
17595452b02SPatrick Sanan     Developer Notes:
17695452b02SPatrick Sanan     This was provided for the MOOSE team who desired to have a SNESSetFunction() function that could change configurations due
177208be567SBarry Smith                      to contacts while the function provided to MatMFFDSetFunction() cannot. Except for the possibility of changing the configuration
178208be567SBarry Smith                      both functions compute the same mathematical function so the differencing makes sense.
179208be567SBarry Smith 
180208be567SBarry Smith     Level: advanced
181208be567SBarry Smith 
182208be567SBarry Smith .seealso: MatCreateSNESMF(), MatSNESMFGetReuseBase()
183208be567SBarry Smith @*/
184208be567SBarry Smith PetscErrorCode  MatSNESMFSetReuseBase(Mat J,PetscBool use)
185208be567SBarry Smith {
186208be567SBarry Smith   PetscErrorCode ierr;
187208be567SBarry Smith 
188208be567SBarry Smith   PetscFunctionBegin;
189208be567SBarry Smith   PetscValidHeaderSpecific(J,MAT_CLASSID,1);
190208be567SBarry Smith   ierr = PetscTryMethod(J,"MatSNESMFSetReuseBase_C",(Mat,PetscBool),(J,use));CHKERRQ(ierr);
191208be567SBarry Smith   PetscFunctionReturn(0);
192208be567SBarry Smith }
193208be567SBarry Smith 
194208be567SBarry Smith static PetscErrorCode  MatSNESMFGetReuseBase_SNESMF(Mat J,PetscBool *use)
195208be567SBarry Smith {
196208be567SBarry Smith   PetscFunctionBegin;
197208be567SBarry Smith   if (J->ops->assemblyend == MatAssemblyEnd_SNESMF_UseBase) *use = PETSC_TRUE;
198208be567SBarry Smith   else *use = PETSC_FALSE;
199208be567SBarry Smith   PetscFunctionReturn(0);
200208be567SBarry Smith }
201208be567SBarry Smith 
202208be567SBarry Smith /*@
203208be567SBarry Smith     MatSNESMFGetReuseBase - Determines if the base vector is to be used for differencing even if the function provided to SNESSetFunction() is not the
204208be567SBarry Smith                        same as that provided to MatMFFDSetFunction().
205208be567SBarry Smith 
206208be567SBarry Smith     Logically Collective on Mat
207208be567SBarry Smith 
208208be567SBarry Smith     Input Parameter:
209208be567SBarry Smith .   J - the MatMFFD matrix
210208be567SBarry Smith 
211208be567SBarry Smith     Output Parameter:
212208be567SBarry Smith .   use - if true always reuse the base vector instead of recomputing f(u) even if the function in the MatSNESMF is
213208be567SBarry Smith           not SNESComputeFunction()
214208be567SBarry Smith 
21595452b02SPatrick Sanan     Notes:
21695452b02SPatrick Sanan     Care must be taken when using this routine to insure that the function provided to MatMFFDSetFunction(), call it F_MF() is compatible with
217208be567SBarry 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
218208be567SBarry Smith 
21995452b02SPatrick Sanan     Developer Notes:
22095452b02SPatrick Sanan     This was provided for the MOOSE team who desired to have a SNESSetFunction() function that could change configurations due
221208be567SBarry Smith                      to contacts while the function provided to MatMFFDSetFunction() cannot. Except for the possibility of changing the configuration
222208be567SBarry Smith                      both functions compute the same mathematical function so the differencing makes sense.
223208be567SBarry Smith 
224208be567SBarry Smith     Level: advanced
225208be567SBarry Smith 
226208be567SBarry Smith .seealso: MatCreateSNESMF(), MatSNESMFSetReuseBase()
227208be567SBarry Smith @*/
228208be567SBarry Smith PetscErrorCode  MatSNESMFGetReuseBase(Mat J,PetscBool *use)
229208be567SBarry Smith {
230208be567SBarry Smith   PetscErrorCode ierr;
231208be567SBarry Smith 
232208be567SBarry Smith   PetscFunctionBegin;
233208be567SBarry Smith   PetscValidHeaderSpecific(J,MAT_CLASSID,1);
234208be567SBarry Smith   ierr = PetscUseMethod(J,"MatSNESMFGetReuseBase_C",(Mat,PetscBool*),(J,use));CHKERRQ(ierr);
235208be567SBarry Smith   PetscFunctionReturn(0);
236208be567SBarry Smith }
237208be567SBarry Smith 
23852baeb72SSatish Balay /*@
23965f2ba5bSLois Curfman McInnes    MatCreateSNESMF - Creates a matrix-free matrix context for use with
24065f2ba5bSLois Curfman McInnes    a SNES solver.  This matrix can be used as the Jacobian argument for
241174415d9SBarry Smith    the routine SNESSetJacobian(). See MatCreateMFFD() for details on how
242174415d9SBarry Smith    the finite difference computation is done.
243a4d4d686SBarry Smith 
244d083f849SBarry Smith    Collective on SNES
245a4d4d686SBarry Smith 
246a4d4d686SBarry Smith    Input Parameters:
247fef1beadSBarry Smith .  snes - the SNES context
248a4d4d686SBarry Smith 
249a4d4d686SBarry Smith    Output Parameter:
250a4d4d686SBarry Smith .  J - the matrix-free matrix
251a4d4d686SBarry Smith 
25215091d37SBarry Smith    Level: advanced
25315091d37SBarry Smith 
2545eb111a0SBarry Smith 
2555eb111a0SBarry Smith    Notes:
2565eb111a0SBarry Smith      You can call SNESSetJacobian() with MatMFFDComputeJacobian() if you are using matrix and not a different
2575eb111a0SBarry Smith      preconditioner matrix
2585eb111a0SBarry Smith 
2595eb111a0SBarry Smith      If you wish to provide a different function to do differencing on to compute the matrix-free operator than
2605eb111a0SBarry Smith      that provided to SNESSetFunction() then call MatMFFDSetFunction() with your function after this call.
2615eb111a0SBarry Smith 
2625eb111a0SBarry Smith      The difference between this routine and MatCreateMFFD() is that this matrix
2635eb111a0SBarry Smith      automatically gets the current base vector from the SNES object and not from an
2645eb111a0SBarry Smith      explicit call to MatMFFDSetBase().
2655eb111a0SBarry Smith 
266174415d9SBarry Smith    Warning:
267174415d9SBarry Smith      If MatMFFDSetBase() is ever called on jac then this routine will NO longer get
268174415d9SBarry Smith      the x from the SNES object and MatMFFDSetBase() must from that point on be used to
269174415d9SBarry Smith      change the base vector x.
2709a6cb015SBarry Smith 
2715eb111a0SBarry Smith    Warning:
2725eb111a0SBarry Smith      Using a different function for the differencing will not work if you are using non-linear left preconditioning.
273ca93e954SBarry Smith 
274ca93e954SBarry Smith 
275722329fbSBarry Smith .seealso: MatDestroy(), MatMFFDSetFunction(), MatMFFDSetFunctionError(), MatMFFDDSSetUmin()
276174415d9SBarry Smith           MatMFFDSetHHistory(), MatMFFDResetHHistory(), MatCreateMFFD(),
277208be567SBarry Smith           MatMFFDGetH(), MatMFFDRegister(), MatMFFDComputeJacobian(), MatSNESMFSetReuseBase(), MatSNESMFGetReuseBase()
278a4d4d686SBarry Smith 
279a4d4d686SBarry Smith @*/
2807087cfbeSBarry Smith PetscErrorCode  MatCreateSNESMF(SNES snes,Mat *J)
281a4d4d686SBarry Smith {
282dfbe8321SBarry Smith   PetscErrorCode ierr;
283fef1beadSBarry Smith   PetscInt       n,N;
2845eb111a0SBarry Smith   MatMFFD        mf;
2851d1367b7SBarry Smith 
2861d1367b7SBarry Smith   PetscFunctionBegin;
287a8248277SBarry Smith   if (snes->vec_func) {
288fef1beadSBarry Smith     ierr = VecGetLocalSize(snes->vec_func,&n);CHKERRQ(ierr);
289fef1beadSBarry Smith     ierr = VecGetSize(snes->vec_func,&N);CHKERRQ(ierr);
290a8248277SBarry Smith   } else if (snes->dm) {
291a8248277SBarry Smith     Vec tmp;
292a8248277SBarry Smith     ierr = DMGetGlobalVector(snes->dm,&tmp);CHKERRQ(ierr);
293a8248277SBarry Smith     ierr = VecGetLocalSize(tmp,&n);CHKERRQ(ierr);
294a8248277SBarry Smith     ierr = VecGetSize(tmp,&N);CHKERRQ(ierr);
295a8248277SBarry Smith     ierr = DMRestoreGlobalVector(snes->dm,&tmp);CHKERRQ(ierr);
296ce94432eSBarry Smith   } else SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE,"Must call SNESSetFunction() or SNESSetDM() first");
297ce94432eSBarry Smith   ierr = MatCreateMFFD(PetscObjectComm((PetscObject)snes),n,n,N,N,J);CHKERRQ(ierr);
298789d8953SBarry Smith   ierr = MatShellGetContext(*J,&mf);CHKERRQ(ierr);
2995eb111a0SBarry Smith   mf->ctx = snes;
3005eb111a0SBarry Smith 
301efd4aadfSBarry Smith   if (snes->npc && snes->npcside== PC_LEFT) {
302be95d8f1SBarry Smith     ierr = MatMFFDSetFunction(*J,(PetscErrorCode (*)(void*,Vec,Vec))SNESComputeFunctionDefaultNPC,snes);CHKERRQ(ierr);
303ed07d7d7SPeter Brune   } else {
304*bbc1464cSBarry Smith     DM     dm;
305*bbc1464cSBarry Smith     DMSNES dms;
3061aa26658SKarl Rupp 
307*bbc1464cSBarry Smith     ierr = SNESGetDM(snes,&dm);CHKERRQ(ierr);
308*bbc1464cSBarry Smith     ierr = DMGetDMSNES(dm,&dms);CHKERRQ(ierr);
309*bbc1464cSBarry Smith     ierr = MatMFFDSetFunction(*J,(PetscErrorCode (*)(void*,Vec,Vec))(dms->ops->computemffunction ? SNESComputeMFFunction : SNESComputeFunction),snes);CHKERRQ(ierr);
310*bbc1464cSBarry Smith   }
3113ec795f1SBarry Smith   (*J)->ops->assemblyend = MatAssemblyEnd_SNESMF;
3121aa26658SKarl Rupp 
313bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)*J,"MatMFFDSetBase_C",MatMFFDSetBase_SNESMF);CHKERRQ(ierr);
314208be567SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)*J,"MatSNESMFSetReuseBase_C",MatSNESMFSetReuseBase_SNESMF);CHKERRQ(ierr);
315208be567SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)*J,"MatSNESMFGetReuseBase_C",MatSNESMFGetReuseBase_SNESMF);CHKERRQ(ierr);
3161d1367b7SBarry Smith   PetscFunctionReturn(0);
3171d1367b7SBarry Smith }
318