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 65d83a8b1SBarry Smith /*@ 7e884886fSBarry Smith MatMFFDComputeJacobian - Tells the matrix-free Jacobian object the new location at which 8420bcc1bSBarry 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 15420bcc1bSBarry 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()` 17420bcc1bSBarry 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: 26420bcc1bSBarry Smith If `MatMFFDSetBase()` is ever called on `jac` then this routine will NO longer get 27420bcc1bSBarry Smith the `x` from the `SNES` object and `MatMFFDSetBase()` must from that point on be used to 28420bcc1bSBarry 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 34420bcc1bSBarry Smith the `Mat` `jac`.) 355fe378a3SBarry Smith 36420bcc1bSBarry 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 47d6acfc2dSPierre Jolivet PETSC_SINGLE_LIBRARY_VISIBILITY_INTERNAL PetscErrorCode MatAssemblyEnd_MFFD(Mat, MatAssemblyType); 48d6acfc2dSPierre Jolivet PETSC_SINGLE_LIBRARY_VISIBILITY_INTERNAL 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 63420bcc1bSBarry 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 173420bcc1bSBarry 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 209420bcc1bSBarry 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 /*@ 220c118d280SBarry Smith MatCreateSNESMF - Creates a finite differencing based 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: 236420bcc1bSBarry Smith You can call `SNESSetJacobian()` with `MatMFFDComputeJacobian()` if you are not using a different 237*7addb90fSBarry Smith matrix to construct the preconditioner. 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 246420bcc1bSBarry 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 248420bcc1bSBarry 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 252c118d280SBarry Smith This uses finite-differencing to apply the operator. To create a matrix-free `Mat` whose matrix-vector operator you 253c118d280SBarry Smith provide with your own function use `MatCreateShell()`. 254c118d280SBarry Smith 255c118d280SBarry Smith Developer Note: 256c118d280SBarry Smith This function should really be called `MatCreateSNESMFFD()` in correspondence to `MatCreateMFFD()` to clearly indicate 257c118d280SBarry Smith that this is for using finite differences to apply the operator matrix-free. 258c118d280SBarry Smith 259420bcc1bSBarry Smith .seealso: [](ch_snes), `SNES`, `MATMFFD`, `MatDestroy()`, `MatMFFDSetFunction()`, `MatMFFDSetFunctionError()`, `MatMFFDDSSetUmin()` 260c118d280SBarry Smith `MatMFFDSetHHistory()`, `MatMFFDResetHHistory()`, `MatCreateMFFD()`, `MatCreateShell()`, 261db781477SPatrick Sanan `MatMFFDGetH()`, `MatMFFDRegister()`, `MatMFFDComputeJacobian()`, `MatSNESMFSetReuseBase()`, `MatSNESMFGetReuseBase()` 262a4d4d686SBarry Smith @*/ 263d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCreateSNESMF(SNES snes, Mat *J) 264d71ae5a4SJacob Faibussowitsch { 265fef1beadSBarry Smith PetscInt n, N; 2665eb111a0SBarry Smith MatMFFD mf; 2671d1367b7SBarry Smith 2681d1367b7SBarry Smith PetscFunctionBegin; 269a8248277SBarry Smith if (snes->vec_func) { 2709566063dSJacob Faibussowitsch PetscCall(VecGetLocalSize(snes->vec_func, &n)); 2719566063dSJacob Faibussowitsch PetscCall(VecGetSize(snes->vec_func, &N)); 272a8248277SBarry Smith } else if (snes->dm) { 273a8248277SBarry Smith Vec tmp; 2749566063dSJacob Faibussowitsch PetscCall(DMGetGlobalVector(snes->dm, &tmp)); 2759566063dSJacob Faibussowitsch PetscCall(VecGetLocalSize(tmp, &n)); 2769566063dSJacob Faibussowitsch PetscCall(VecGetSize(tmp, &N)); 2779566063dSJacob Faibussowitsch PetscCall(DMRestoreGlobalVector(snes->dm, &tmp)); 278ce94432eSBarry Smith } else SETERRQ(PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_WRONGSTATE, "Must call SNESSetFunction() or SNESSetDM() first"); 2799566063dSJacob Faibussowitsch PetscCall(MatCreateMFFD(PetscObjectComm((PetscObject)snes), n, n, N, N, J)); 2809566063dSJacob Faibussowitsch PetscCall(MatShellGetContext(*J, &mf)); 2815eb111a0SBarry Smith mf->ctx = snes; 2825eb111a0SBarry Smith 283efd4aadfSBarry Smith if (snes->npc && snes->npcside == PC_LEFT) { 2849566063dSJacob Faibussowitsch PetscCall(MatMFFDSetFunction(*J, (PetscErrorCode (*)(void *, Vec, Vec))SNESComputeFunctionDefaultNPC, snes)); 285ed07d7d7SPeter Brune } else { 286bbc1464cSBarry Smith DM dm; 287bbc1464cSBarry Smith DMSNES dms; 2881aa26658SKarl Rupp 2899566063dSJacob Faibussowitsch PetscCall(SNESGetDM(snes, &dm)); 2909566063dSJacob Faibussowitsch PetscCall(DMGetDMSNES(dm, &dms)); 2919566063dSJacob Faibussowitsch PetscCall(MatMFFDSetFunction(*J, (PetscErrorCode (*)(void *, Vec, Vec))(dms->ops->computemffunction ? SNESComputeMFFunction : SNESComputeFunction), snes)); 292bbc1464cSBarry Smith } 2933ec795f1SBarry Smith (*J)->ops->assemblyend = MatAssemblyEnd_SNESMF; 2941aa26658SKarl Rupp 2959566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)*J, "MatMFFDSetBase_C", MatMFFDSetBase_SNESMF)); 2969566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)*J, "MatSNESMFSetReuseBase_C", MatSNESMFSetReuseBase_SNESMF)); 2979566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)*J, "MatSNESMFGetReuseBase_C", MatSNESMFGetReuseBase_SNESMF)); 2983ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2991d1367b7SBarry Smith } 300