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) 19*a5b23f4aSJose E. Roman . flag - not relevant 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; 90bbc1464cSBarry Smith DM dm; 91bbc1464cSBarry 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); 99bbc1464cSBarry Smith ierr = SNESGetDM(snes,&dm);CHKERRQ(ierr); 100bbc1464cSBarry Smith ierr = DMGetDMSNES(dm,&dms);CHKERRQ(ierr); 101bbc1464cSBarry 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 static PetscErrorCode MatAssemblyEnd_SNESMF_UseBase(Mat J,MatAssemblyType mt) 118208be567SBarry Smith { 119208be567SBarry Smith PetscErrorCode ierr; 120789d8953SBarry Smith MatMFFD j; 121789d8953SBarry Smith SNES snes; 122208be567SBarry Smith Vec u,f; 123208be567SBarry Smith 124208be567SBarry Smith PetscFunctionBegin; 125208be567SBarry Smith ierr = MatAssemblyEnd_MFFD(J,mt);CHKERRQ(ierr); 126789d8953SBarry Smith ierr = MatShellGetContext(J,&j);CHKERRQ(ierr); 127789d8953SBarry Smith snes = (SNES)j->ctx; 128208be567SBarry Smith ierr = SNESGetSolution(snes,&u);CHKERRQ(ierr); 129208be567SBarry Smith ierr = SNESGetFunction(snes,&f,NULL,NULL);CHKERRQ(ierr); 130208be567SBarry Smith ierr = MatMFFDSetBase_MFFD(J,u,f);CHKERRQ(ierr); 131208be567SBarry Smith PetscFunctionReturn(0); 132208be567SBarry Smith } 133208be567SBarry Smith 134208be567SBarry Smith /* 135174415d9SBarry Smith This routine resets the MatAssemblyEnd() for the MatMFFD created from MatCreateSNESMF() so that it NO longer 136174415d9SBarry Smith uses the solution in the SNES object to update the base. See the warning in MatCreateSNESMF(). 137174415d9SBarry Smith */ 138cc2e6a90SBarry Smith static PetscErrorCode MatMFFDSetBase_SNESMF(Mat J,Vec U,Vec F) 139174415d9SBarry Smith { 140174415d9SBarry Smith PetscErrorCode ierr; 141174415d9SBarry Smith 142174415d9SBarry Smith PetscFunctionBegin; 143885877adSHong Zhang ierr = MatMFFDSetBase_MFFD(J,U,F);CHKERRQ(ierr); 144174415d9SBarry Smith J->ops->assemblyend = MatAssemblyEnd_MFFD; 145174415d9SBarry Smith PetscFunctionReturn(0); 146174415d9SBarry Smith } 147174415d9SBarry Smith 148208be567SBarry Smith static PetscErrorCode MatSNESMFSetReuseBase_SNESMF(Mat J,PetscBool use) 149208be567SBarry Smith { 150208be567SBarry Smith PetscFunctionBegin; 151208be567SBarry Smith if (use) { 152208be567SBarry Smith J->ops->assemblyend = MatAssemblyEnd_SNESMF_UseBase; 153208be567SBarry Smith } else { 154208be567SBarry Smith J->ops->assemblyend = MatAssemblyEnd_SNESMF; 155208be567SBarry Smith } 156208be567SBarry Smith PetscFunctionReturn(0); 157208be567SBarry Smith } 158208be567SBarry Smith 159208be567SBarry Smith /*@ 160208be567SBarry Smith MatSNESMFSetReuseBase - Causes the base vector to be used for differencing even if the function provided to SNESSetFunction() is not the 161208be567SBarry Smith same as that provided to MatMFFDSetFunction(). 162208be567SBarry Smith 163208be567SBarry Smith Logically Collective on Mat 164208be567SBarry Smith 165208be567SBarry Smith Input Parameters: 166208be567SBarry Smith + J - the MatMFFD matrix 167208be567SBarry Smith - use - if true always reuse the base vector instead of recomputing f(u) even if the function in the MatSNESMF is 168208be567SBarry Smith not SNESComputeFunction() 169208be567SBarry Smith 17095452b02SPatrick Sanan Notes: 17195452b02SPatrick Sanan Care must be taken when using this routine to insure that the function provided to MatMFFDSetFunction(), call it F_MF() is compatible with 172208be567SBarry 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 173208be567SBarry Smith 17495452b02SPatrick Sanan Developer Notes: 17595452b02SPatrick Sanan This was provided for the MOOSE team who desired to have a SNESSetFunction() function that could change configurations due 176208be567SBarry Smith to contacts while the function provided to MatMFFDSetFunction() cannot. Except for the possibility of changing the configuration 177208be567SBarry Smith both functions compute the same mathematical function so the differencing makes sense. 178208be567SBarry Smith 179208be567SBarry Smith Level: advanced 180208be567SBarry Smith 181208be567SBarry Smith .seealso: MatCreateSNESMF(), MatSNESMFGetReuseBase() 182208be567SBarry Smith @*/ 183208be567SBarry Smith PetscErrorCode MatSNESMFSetReuseBase(Mat J,PetscBool use) 184208be567SBarry Smith { 185208be567SBarry Smith PetscErrorCode ierr; 186208be567SBarry Smith 187208be567SBarry Smith PetscFunctionBegin; 188208be567SBarry Smith PetscValidHeaderSpecific(J,MAT_CLASSID,1); 189208be567SBarry Smith ierr = PetscTryMethod(J,"MatSNESMFSetReuseBase_C",(Mat,PetscBool),(J,use));CHKERRQ(ierr); 190208be567SBarry Smith PetscFunctionReturn(0); 191208be567SBarry Smith } 192208be567SBarry Smith 193208be567SBarry Smith static PetscErrorCode MatSNESMFGetReuseBase_SNESMF(Mat J,PetscBool *use) 194208be567SBarry Smith { 195208be567SBarry Smith PetscFunctionBegin; 196208be567SBarry Smith if (J->ops->assemblyend == MatAssemblyEnd_SNESMF_UseBase) *use = PETSC_TRUE; 197208be567SBarry Smith else *use = PETSC_FALSE; 198208be567SBarry Smith PetscFunctionReturn(0); 199208be567SBarry Smith } 200208be567SBarry Smith 201208be567SBarry Smith /*@ 202208be567SBarry Smith MatSNESMFGetReuseBase - Determines if the base vector is to be used for differencing even if the function provided to SNESSetFunction() is not the 203208be567SBarry Smith same as that provided to MatMFFDSetFunction(). 204208be567SBarry Smith 205208be567SBarry Smith Logically Collective on Mat 206208be567SBarry Smith 207208be567SBarry Smith Input Parameter: 208208be567SBarry Smith . J - the MatMFFD matrix 209208be567SBarry Smith 210208be567SBarry Smith Output Parameter: 211208be567SBarry Smith . use - if true always reuse the base vector instead of recomputing f(u) even if the function in the MatSNESMF is 212208be567SBarry Smith not SNESComputeFunction() 213208be567SBarry Smith 21495452b02SPatrick Sanan Notes: 21595452b02SPatrick Sanan Care must be taken when using this routine to insure that the function provided to MatMFFDSetFunction(), call it F_MF() is compatible with 216208be567SBarry 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 217208be567SBarry Smith 21895452b02SPatrick Sanan Developer Notes: 21995452b02SPatrick Sanan This was provided for the MOOSE team who desired to have a SNESSetFunction() function that could change configurations due 220208be567SBarry Smith to contacts while the function provided to MatMFFDSetFunction() cannot. Except for the possibility of changing the configuration 221208be567SBarry Smith both functions compute the same mathematical function so the differencing makes sense. 222208be567SBarry Smith 223208be567SBarry Smith Level: advanced 224208be567SBarry Smith 225208be567SBarry Smith .seealso: MatCreateSNESMF(), MatSNESMFSetReuseBase() 226208be567SBarry Smith @*/ 227208be567SBarry Smith PetscErrorCode MatSNESMFGetReuseBase(Mat J,PetscBool *use) 228208be567SBarry Smith { 229208be567SBarry Smith PetscErrorCode ierr; 230208be567SBarry Smith 231208be567SBarry Smith PetscFunctionBegin; 232208be567SBarry Smith PetscValidHeaderSpecific(J,MAT_CLASSID,1); 233208be567SBarry Smith ierr = PetscUseMethod(J,"MatSNESMFGetReuseBase_C",(Mat,PetscBool*),(J,use));CHKERRQ(ierr); 234208be567SBarry Smith PetscFunctionReturn(0); 235208be567SBarry Smith } 236208be567SBarry Smith 23752baeb72SSatish Balay /*@ 23865f2ba5bSLois Curfman McInnes MatCreateSNESMF - Creates a matrix-free matrix context for use with 23965f2ba5bSLois Curfman McInnes a SNES solver. This matrix can be used as the Jacobian argument for 240174415d9SBarry Smith the routine SNESSetJacobian(). See MatCreateMFFD() for details on how 241174415d9SBarry Smith the finite difference computation is done. 242a4d4d686SBarry Smith 243d083f849SBarry Smith Collective on SNES 244a4d4d686SBarry Smith 245a4d4d686SBarry Smith Input Parameters: 246fef1beadSBarry Smith . snes - the SNES context 247a4d4d686SBarry Smith 248a4d4d686SBarry Smith Output Parameter: 249a4d4d686SBarry Smith . J - the matrix-free matrix 250a4d4d686SBarry Smith 25115091d37SBarry Smith Level: advanced 25215091d37SBarry Smith 2535eb111a0SBarry Smith Notes: 2545eb111a0SBarry Smith You can call SNESSetJacobian() with MatMFFDComputeJacobian() if you are using matrix and not a different 2555eb111a0SBarry Smith preconditioner matrix 2565eb111a0SBarry Smith 2575eb111a0SBarry Smith If you wish to provide a different function to do differencing on to compute the matrix-free operator than 2585eb111a0SBarry Smith that provided to SNESSetFunction() then call MatMFFDSetFunction() with your function after this call. 2595eb111a0SBarry Smith 2605eb111a0SBarry Smith The difference between this routine and MatCreateMFFD() is that this matrix 2615eb111a0SBarry Smith automatically gets the current base vector from the SNES object and not from an 2625eb111a0SBarry Smith explicit call to MatMFFDSetBase(). 2635eb111a0SBarry Smith 264174415d9SBarry Smith Warning: 265174415d9SBarry Smith If MatMFFDSetBase() is ever called on jac then this routine will NO longer get 266174415d9SBarry Smith the x from the SNES object and MatMFFDSetBase() must from that point on be used to 267174415d9SBarry Smith change the base vector x. 2689a6cb015SBarry Smith 2695eb111a0SBarry Smith Warning: 2705eb111a0SBarry Smith Using a different function for the differencing will not work if you are using non-linear left preconditioning. 271ca93e954SBarry Smith 272722329fbSBarry Smith .seealso: MatDestroy(), MatMFFDSetFunction(), MatMFFDSetFunctionError(), MatMFFDDSSetUmin() 273174415d9SBarry Smith MatMFFDSetHHistory(), MatMFFDResetHHistory(), MatCreateMFFD(), 274208be567SBarry Smith MatMFFDGetH(), MatMFFDRegister(), MatMFFDComputeJacobian(), MatSNESMFSetReuseBase(), MatSNESMFGetReuseBase() 275a4d4d686SBarry Smith 276a4d4d686SBarry Smith @*/ 2777087cfbeSBarry Smith PetscErrorCode MatCreateSNESMF(SNES snes,Mat *J) 278a4d4d686SBarry Smith { 279dfbe8321SBarry Smith PetscErrorCode ierr; 280fef1beadSBarry Smith PetscInt n,N; 2815eb111a0SBarry Smith MatMFFD mf; 2821d1367b7SBarry Smith 2831d1367b7SBarry Smith PetscFunctionBegin; 284a8248277SBarry Smith if (snes->vec_func) { 285fef1beadSBarry Smith ierr = VecGetLocalSize(snes->vec_func,&n);CHKERRQ(ierr); 286fef1beadSBarry Smith ierr = VecGetSize(snes->vec_func,&N);CHKERRQ(ierr); 287a8248277SBarry Smith } else if (snes->dm) { 288a8248277SBarry Smith Vec tmp; 289a8248277SBarry Smith ierr = DMGetGlobalVector(snes->dm,&tmp);CHKERRQ(ierr); 290a8248277SBarry Smith ierr = VecGetLocalSize(tmp,&n);CHKERRQ(ierr); 291a8248277SBarry Smith ierr = VecGetSize(tmp,&N);CHKERRQ(ierr); 292a8248277SBarry Smith ierr = DMRestoreGlobalVector(snes->dm,&tmp);CHKERRQ(ierr); 293ce94432eSBarry Smith } else SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE,"Must call SNESSetFunction() or SNESSetDM() first"); 294ce94432eSBarry Smith ierr = MatCreateMFFD(PetscObjectComm((PetscObject)snes),n,n,N,N,J);CHKERRQ(ierr); 295789d8953SBarry Smith ierr = MatShellGetContext(*J,&mf);CHKERRQ(ierr); 2965eb111a0SBarry Smith mf->ctx = snes; 2975eb111a0SBarry Smith 298efd4aadfSBarry Smith if (snes->npc && snes->npcside== PC_LEFT) { 299be95d8f1SBarry Smith ierr = MatMFFDSetFunction(*J,(PetscErrorCode (*)(void*,Vec,Vec))SNESComputeFunctionDefaultNPC,snes);CHKERRQ(ierr); 300ed07d7d7SPeter Brune } else { 301bbc1464cSBarry Smith DM dm; 302bbc1464cSBarry Smith DMSNES dms; 3031aa26658SKarl Rupp 304bbc1464cSBarry Smith ierr = SNESGetDM(snes,&dm);CHKERRQ(ierr); 305bbc1464cSBarry Smith ierr = DMGetDMSNES(dm,&dms);CHKERRQ(ierr); 306bbc1464cSBarry Smith ierr = MatMFFDSetFunction(*J,(PetscErrorCode (*)(void*,Vec,Vec))(dms->ops->computemffunction ? SNESComputeMFFunction : SNESComputeFunction),snes);CHKERRQ(ierr); 307bbc1464cSBarry Smith } 3083ec795f1SBarry Smith (*J)->ops->assemblyend = MatAssemblyEnd_SNESMF; 3091aa26658SKarl Rupp 310bdf89e91SBarry Smith ierr = PetscObjectComposeFunction((PetscObject)*J,"MatMFFDSetBase_C",MatMFFDSetBase_SNESMF);CHKERRQ(ierr); 311208be567SBarry Smith ierr = PetscObjectComposeFunction((PetscObject)*J,"MatSNESMFSetReuseBase_C",MatSNESMFSetReuseBase_SNESMF);CHKERRQ(ierr); 312208be567SBarry Smith ierr = PetscObjectComposeFunction((PetscObject)*J,"MatSNESMFGetReuseBase_C",MatSNESMFGetReuseBase_SNESMF);CHKERRQ(ierr); 3131d1367b7SBarry Smith PetscFunctionReturn(0); 3141d1367b7SBarry Smith } 315