xref: /petsc/src/snes/mf/snesmfj.c (revision 95452b02e12c0ee11232c7ff2b24b568a8e07e43)
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 
64bc13fc8dSBarry Smith .seealso: MatCreateSNESMF()
65bc13fc8dSBarry Smith @*/
66bc13fc8dSBarry Smith PetscErrorCode MatSNESMFGetSNES(Mat J,SNES *snes)
67bc13fc8dSBarry Smith {
68bc13fc8dSBarry Smith   MatMFFD        j    = (MatMFFD)J->data;
69bc13fc8dSBarry Smith 
70bc13fc8dSBarry Smith   PetscFunctionBegin;
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 */
80cc2e6a90SBarry Smith static PetscErrorCode MatAssemblyEnd_SNESMF(Mat J,MatAssemblyType mt)
813ec795f1SBarry Smith {
823ec795f1SBarry Smith   PetscErrorCode ierr;
833ec795f1SBarry Smith   MatMFFD        j    = (MatMFFD)J->data;
845eb111a0SBarry Smith   SNES           snes = (SNES)j->ctx;
8509ffd372SDmitry Karpeev   Vec            u,f;
863ec795f1SBarry Smith 
873ec795f1SBarry Smith   PetscFunctionBegin;
883ec795f1SBarry Smith   ierr = MatAssemblyEnd_MFFD(J,mt);CHKERRQ(ierr);
893ec795f1SBarry Smith 
90be4711e3SBarry Smith   ierr = SNESGetSolution(snes,&u);CHKERRQ(ierr);
915eb111a0SBarry Smith   if (j->func == (PetscErrorCode (*)(void*,Vec,Vec))SNESComputeFunction) {
920298fd71SBarry Smith     ierr = SNESGetFunction(snes,&f,NULL,NULL);CHKERRQ(ierr);
9309ffd372SDmitry Karpeev     ierr = MatMFFDSetBase_MFFD(J,u,f);CHKERRQ(ierr);
945eb111a0SBarry Smith   } else {
955eb111a0SBarry Smith     /* f value known by SNES is not correct for other differencing function */
965eb111a0SBarry Smith     ierr = MatMFFDSetBase_MFFD(J,u,NULL);CHKERRQ(ierr);
975eb111a0SBarry Smith   }
983ec795f1SBarry Smith   PetscFunctionReturn(0);
993ec795f1SBarry Smith }
1003ec795f1SBarry Smith 
101174415d9SBarry Smith /*
102208be567SBarry Smith    MatAssemblyEnd_SNESMF_UseBase - Calls MatAssemblyEnd_MFFD() and then sets the
103208be567SBarry Smith     base from the SNES context. This version will cause the base to be used for differencing
104208be567SBarry Smith     even if the func is not SNESComputeFunction. See: MatSNESMFUseBase()
105208be567SBarry Smith 
106208be567SBarry Smith 
107208be567SBarry Smith */
108208be567SBarry Smith static PetscErrorCode MatAssemblyEnd_SNESMF_UseBase(Mat J,MatAssemblyType mt)
109208be567SBarry Smith {
110208be567SBarry Smith   PetscErrorCode ierr;
111208be567SBarry Smith   MatMFFD        j    = (MatMFFD)J->data;
112208be567SBarry Smith   SNES           snes = (SNES)j->ctx;
113208be567SBarry Smith   Vec            u,f;
114208be567SBarry Smith 
115208be567SBarry Smith   PetscFunctionBegin;
116208be567SBarry Smith   ierr = MatAssemblyEnd_MFFD(J,mt);CHKERRQ(ierr);
117208be567SBarry Smith 
118208be567SBarry Smith   ierr = SNESGetSolution(snes,&u);CHKERRQ(ierr);
119208be567SBarry Smith   ierr = SNESGetFunction(snes,&f,NULL,NULL);CHKERRQ(ierr);
120208be567SBarry Smith   ierr = MatMFFDSetBase_MFFD(J,u,f);CHKERRQ(ierr);
121208be567SBarry Smith   PetscFunctionReturn(0);
122208be567SBarry Smith }
123208be567SBarry Smith 
124208be567SBarry Smith /*
125174415d9SBarry Smith     This routine resets the MatAssemblyEnd() for the MatMFFD created from MatCreateSNESMF() so that it NO longer
126174415d9SBarry Smith   uses the solution in the SNES object to update the base. See the warning in MatCreateSNESMF().
127174415d9SBarry Smith */
128cc2e6a90SBarry Smith static PetscErrorCode  MatMFFDSetBase_SNESMF(Mat J,Vec U,Vec F)
129174415d9SBarry Smith {
130174415d9SBarry Smith   PetscErrorCode ierr;
131174415d9SBarry Smith 
132174415d9SBarry Smith   PetscFunctionBegin;
133885877adSHong Zhang   ierr = MatMFFDSetBase_MFFD(J,U,F);CHKERRQ(ierr);
134174415d9SBarry Smith   J->ops->assemblyend = MatAssemblyEnd_MFFD;
135174415d9SBarry Smith   PetscFunctionReturn(0);
136174415d9SBarry Smith }
137174415d9SBarry Smith 
138208be567SBarry Smith static PetscErrorCode  MatSNESMFSetReuseBase_SNESMF(Mat J,PetscBool use)
139208be567SBarry Smith {
140208be567SBarry Smith   PetscFunctionBegin;
141208be567SBarry Smith   if (use) {
142208be567SBarry Smith     J->ops->assemblyend = MatAssemblyEnd_SNESMF_UseBase;
143208be567SBarry Smith   } else {
144208be567SBarry Smith     J->ops->assemblyend = MatAssemblyEnd_SNESMF;
145208be567SBarry Smith   }
146208be567SBarry Smith   PetscFunctionReturn(0);
147208be567SBarry Smith }
148208be567SBarry Smith 
149208be567SBarry Smith /*@
150208be567SBarry Smith     MatSNESMFSetReuseBase - Causes the base vector to be used for differencing even if the function provided to SNESSetFunction() is not the
151208be567SBarry Smith                        same as that provided to MatMFFDSetFunction().
152208be567SBarry Smith 
153208be567SBarry Smith     Logically Collective on Mat
154208be567SBarry Smith 
155208be567SBarry Smith     Input Parameters:
156208be567SBarry Smith +   J - the MatMFFD matrix
157208be567SBarry Smith -   use - if true always reuse the base vector instead of recomputing f(u) even if the function in the MatSNESMF is
158208be567SBarry Smith           not SNESComputeFunction()
159208be567SBarry Smith 
160*95452b02SPatrick Sanan     Notes:
161*95452b02SPatrick Sanan     Care must be taken when using this routine to insure that the function provided to MatMFFDSetFunction(), call it F_MF() is compatible with
162208be567SBarry 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
163208be567SBarry Smith 
164*95452b02SPatrick Sanan     Developer Notes:
165*95452b02SPatrick Sanan     This was provided for the MOOSE team who desired to have a SNESSetFunction() function that could change configurations due
166208be567SBarry Smith                      to contacts while the function provided to MatMFFDSetFunction() cannot. Except for the possibility of changing the configuration
167208be567SBarry Smith                      both functions compute the same mathematical function so the differencing makes sense.
168208be567SBarry Smith 
169208be567SBarry Smith     Level: advanced
170208be567SBarry Smith 
171208be567SBarry Smith .seealso: MatCreateSNESMF(), MatSNESMFGetReuseBase()
172208be567SBarry Smith @*/
173208be567SBarry Smith PetscErrorCode  MatSNESMFSetReuseBase(Mat J,PetscBool use)
174208be567SBarry Smith {
175208be567SBarry Smith   PetscErrorCode ierr;
176208be567SBarry Smith 
177208be567SBarry Smith   PetscFunctionBegin;
178208be567SBarry Smith   PetscValidHeaderSpecific(J,MAT_CLASSID,1);
179208be567SBarry Smith   ierr = PetscTryMethod(J,"MatSNESMFSetReuseBase_C",(Mat,PetscBool),(J,use));CHKERRQ(ierr);
180208be567SBarry Smith   PetscFunctionReturn(0);
181208be567SBarry Smith }
182208be567SBarry Smith 
183208be567SBarry Smith static PetscErrorCode  MatSNESMFGetReuseBase_SNESMF(Mat J,PetscBool *use)
184208be567SBarry Smith {
185208be567SBarry Smith   PetscFunctionBegin;
186208be567SBarry Smith   if (J->ops->assemblyend == MatAssemblyEnd_SNESMF_UseBase) *use = PETSC_TRUE;
187208be567SBarry Smith   else *use = PETSC_FALSE;
188208be567SBarry Smith   PetscFunctionReturn(0);
189208be567SBarry Smith }
190208be567SBarry Smith 
191208be567SBarry Smith /*@
192208be567SBarry Smith     MatSNESMFGetReuseBase - Determines if the base vector is to be used for differencing even if the function provided to SNESSetFunction() is not the
193208be567SBarry Smith                        same as that provided to MatMFFDSetFunction().
194208be567SBarry Smith 
195208be567SBarry Smith     Logically Collective on Mat
196208be567SBarry Smith 
197208be567SBarry Smith     Input Parameter:
198208be567SBarry Smith .   J - the MatMFFD matrix
199208be567SBarry Smith 
200208be567SBarry Smith     Output Parameter:
201208be567SBarry Smith .   use - if true always reuse the base vector instead of recomputing f(u) even if the function in the MatSNESMF is
202208be567SBarry Smith           not SNESComputeFunction()
203208be567SBarry Smith 
204*95452b02SPatrick Sanan     Notes:
205*95452b02SPatrick Sanan     Care must be taken when using this routine to insure that the function provided to MatMFFDSetFunction(), call it F_MF() is compatible with
206208be567SBarry 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
207208be567SBarry Smith 
208*95452b02SPatrick Sanan     Developer Notes:
209*95452b02SPatrick Sanan     This was provided for the MOOSE team who desired to have a SNESSetFunction() function that could change configurations due
210208be567SBarry Smith                      to contacts while the function provided to MatMFFDSetFunction() cannot. Except for the possibility of changing the configuration
211208be567SBarry Smith                      both functions compute the same mathematical function so the differencing makes sense.
212208be567SBarry Smith 
213208be567SBarry Smith     Level: advanced
214208be567SBarry Smith 
215208be567SBarry Smith .seealso: MatCreateSNESMF(), MatSNESMFSetReuseBase()
216208be567SBarry Smith @*/
217208be567SBarry Smith PetscErrorCode  MatSNESMFGetReuseBase(Mat J,PetscBool *use)
218208be567SBarry Smith {
219208be567SBarry Smith   PetscErrorCode ierr;
220208be567SBarry Smith 
221208be567SBarry Smith   PetscFunctionBegin;
222208be567SBarry Smith   PetscValidHeaderSpecific(J,MAT_CLASSID,1);
223208be567SBarry Smith   ierr = PetscUseMethod(J,"MatSNESMFGetReuseBase_C",(Mat,PetscBool*),(J,use));CHKERRQ(ierr);
224208be567SBarry Smith   PetscFunctionReturn(0);
225208be567SBarry Smith }
226208be567SBarry Smith 
22752baeb72SSatish Balay /*@
22865f2ba5bSLois Curfman McInnes    MatCreateSNESMF - Creates a matrix-free matrix context for use with
22965f2ba5bSLois Curfman McInnes    a SNES solver.  This matrix can be used as the Jacobian argument for
230174415d9SBarry Smith    the routine SNESSetJacobian(). See MatCreateMFFD() for details on how
231174415d9SBarry Smith    the finite difference computation is done.
232a4d4d686SBarry Smith 
233a4d4d686SBarry Smith    Collective on SNES and Vec
234a4d4d686SBarry Smith 
235a4d4d686SBarry Smith    Input Parameters:
236fef1beadSBarry Smith .  snes - the SNES context
237a4d4d686SBarry Smith 
238a4d4d686SBarry Smith    Output Parameter:
239a4d4d686SBarry Smith .  J - the matrix-free matrix
240a4d4d686SBarry Smith 
24115091d37SBarry Smith    Level: advanced
24215091d37SBarry Smith 
2435eb111a0SBarry Smith 
2445eb111a0SBarry Smith    Notes:
2455eb111a0SBarry Smith      You can call SNESSetJacobian() with MatMFFDComputeJacobian() if you are using matrix and not a different
2465eb111a0SBarry Smith      preconditioner matrix
2475eb111a0SBarry Smith 
2485eb111a0SBarry Smith      If you wish to provide a different function to do differencing on to compute the matrix-free operator than
2495eb111a0SBarry Smith      that provided to SNESSetFunction() then call MatMFFDSetFunction() with your function after this call.
2505eb111a0SBarry Smith 
2515eb111a0SBarry Smith      The difference between this routine and MatCreateMFFD() is that this matrix
2525eb111a0SBarry Smith      automatically gets the current base vector from the SNES object and not from an
2535eb111a0SBarry Smith      explicit call to MatMFFDSetBase().
2545eb111a0SBarry Smith 
255174415d9SBarry Smith    Warning:
256174415d9SBarry Smith      If MatMFFDSetBase() is ever called on jac then this routine will NO longer get
257174415d9SBarry Smith      the x from the SNES object and MatMFFDSetBase() must from that point on be used to
258174415d9SBarry Smith      change the base vector x.
2599a6cb015SBarry Smith 
2605eb111a0SBarry Smith    Warning:
2615eb111a0SBarry Smith      Using a different function for the differencing will not work if you are using non-linear left preconditioning.
262ca93e954SBarry Smith 
263ca93e954SBarry Smith 
264722329fbSBarry Smith .seealso: MatDestroy(), MatMFFDSetFunction(), MatMFFDSetFunctionError(), MatMFFDDSSetUmin()
265174415d9SBarry Smith           MatMFFDSetHHistory(), MatMFFDResetHHistory(), MatCreateMFFD(),
266208be567SBarry Smith           MatMFFDGetH(), MatMFFDRegister(), MatMFFDComputeJacobian(), MatSNESMFSetReuseBase(), MatSNESMFGetReuseBase()
267a4d4d686SBarry Smith 
268a4d4d686SBarry Smith @*/
2697087cfbeSBarry Smith PetscErrorCode  MatCreateSNESMF(SNES snes,Mat *J)
270a4d4d686SBarry Smith {
271dfbe8321SBarry Smith   PetscErrorCode ierr;
272fef1beadSBarry Smith   PetscInt       n,N;
2735eb111a0SBarry Smith   MatMFFD        mf;
2741d1367b7SBarry Smith 
2751d1367b7SBarry Smith   PetscFunctionBegin;
276a8248277SBarry Smith   if (snes->vec_func) {
277fef1beadSBarry Smith     ierr = VecGetLocalSize(snes->vec_func,&n);CHKERRQ(ierr);
278fef1beadSBarry Smith     ierr = VecGetSize(snes->vec_func,&N);CHKERRQ(ierr);
279a8248277SBarry Smith   } else if (snes->dm) {
280a8248277SBarry Smith     Vec tmp;
281a8248277SBarry Smith     ierr = DMGetGlobalVector(snes->dm,&tmp);CHKERRQ(ierr);
282a8248277SBarry Smith     ierr = VecGetLocalSize(tmp,&n);CHKERRQ(ierr);
283a8248277SBarry Smith     ierr = VecGetSize(tmp,&N);CHKERRQ(ierr);
284a8248277SBarry Smith     ierr = DMRestoreGlobalVector(snes->dm,&tmp);CHKERRQ(ierr);
285ce94432eSBarry Smith   } else SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE,"Must call SNESSetFunction() or SNESSetDM() first");
286ce94432eSBarry Smith   ierr = MatCreateMFFD(PetscObjectComm((PetscObject)snes),n,n,N,N,J);CHKERRQ(ierr);
28788b4c220SStefano Zampini 
2885eb111a0SBarry Smith   mf      = (MatMFFD)(*J)->data;
2895eb111a0SBarry Smith   mf->ctx = snes;
2905eb111a0SBarry Smith 
291efd4aadfSBarry Smith   if (snes->npc && snes->npcside== PC_LEFT) {
292be95d8f1SBarry Smith     ierr = MatMFFDSetFunction(*J,(PetscErrorCode (*)(void*,Vec,Vec))SNESComputeFunctionDefaultNPC,snes);CHKERRQ(ierr);
293ed07d7d7SPeter Brune   } else {
294ece7ea46SSatish Balay     ierr = MatMFFDSetFunction(*J,(PetscErrorCode (*)(void*,Vec,Vec))SNESComputeFunction,snes);CHKERRQ(ierr);
295ed07d7d7SPeter Brune   }
2961aa26658SKarl Rupp 
2973ec795f1SBarry Smith   (*J)->ops->assemblyend = MatAssemblyEnd_SNESMF;
2981aa26658SKarl Rupp 
299bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)*J,"MatMFFDSetBase_C",MatMFFDSetBase_SNESMF);CHKERRQ(ierr);
300208be567SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)*J,"MatSNESMFSetReuseBase_C",MatSNESMFSetReuseBase_SNESMF);CHKERRQ(ierr);
301208be567SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)*J,"MatSNESMFGetReuseBase_C",MatSNESMFGetReuseBase_SNESMF);CHKERRQ(ierr);
3021d1367b7SBarry Smith   PetscFunctionReturn(0);
3031d1367b7SBarry Smith }
304