191627157SBarry Smith 2af0996ceSBarry Smith #include <petsc/private/snesimpl.h> /*I "petscsnes.h" I*/ 31e25c274SJed Brown #include <petscdm.h> /*I "petscdm.h" I*/ 491627157SBarry Smith 562cd874fSBarry Smith /* 662cd874fSBarry Smith MatFDColoringSetFunction() takes a function with four arguments, we want to use SNESComputeFunction() 762cd874fSBarry Smith since it logs function computation information. 862cd874fSBarry Smith */ 9d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESComputeFunctionCtx(SNES snes, Vec x, Vec f, void *ctx) 10d71ae5a4SJacob Faibussowitsch { 1162cd874fSBarry Smith return SNESComputeFunction(snes, x, f); 1262cd874fSBarry Smith } 13d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESComputeMFFunctionCtx(SNES snes, Vec x, Vec f, void *ctx) 14d71ae5a4SJacob Faibussowitsch { 150df40c35SBarry Smith return SNESComputeMFFunction(snes, x, f); 160df40c35SBarry Smith } 1762cd874fSBarry Smith 1891627157SBarry Smith /*@C 198d359177SBarry Smith SNESComputeJacobianDefaultColor - Computes the Jacobian using 20b4fc646aSLois Curfman McInnes finite differences and coloring to exploit matrix sparsity. 2191627157SBarry Smith 22f6dfbefdSBarry Smith Collective on snes 23fee21e36SBarry Smith 24c7afd0dbSLois Curfman McInnes Input Parameters: 25c7afd0dbSLois Curfman McInnes + snes - nonlinear solver object 26c7afd0dbSLois Curfman McInnes . x1 - location at which to evaluate Jacobian 277fb41025SPeter Brune - ctx - MatFDColoring context or NULL 28c7afd0dbSLois Curfman McInnes 29c7afd0dbSLois Curfman McInnes Output Parameters: 30c7afd0dbSLois Curfman McInnes + J - Jacobian matrix (not altered in this routine) 3156744491SBarry Smith - B - newly computed Jacobian matrix to use with preconditioner (generally the same as J) 32c7afd0dbSLois Curfman McInnes 3336851e7fSLois Curfman McInnes Level: intermediate 3436851e7fSLois Curfman McInnes 35f6dfbefdSBarry Smith Options Database Keys: 365620d6dcSBarry Smith + -snes_fd_color_use_mat - use a matrix coloring from the explicit matrix nonzero pattern instead of from the DM providing the matrix 37f6dfbefdSBarry Smith . -snes_fd_color - Activates `SNESComputeJacobianDefaultColor()` in `SNESSetFromOptions()` 385620d6dcSBarry Smith . -mat_fd_coloring_err <err> - Sets <err> (square root of relative error in the function) 395620d6dcSBarry Smith . -mat_fd_coloring_umin <umin> - Sets umin, the minimum allowable u-value magnitude 40f6dfbefdSBarry Smith . -mat_fd_type - Either wp or ds (see `MATMFFD_WP` or `MATMFFD_DS`) 41ec5066bdSBarry Smith . -snes_mf_operator - Use matrix free application of Jacobian 42a5b23f4aSJose E. Roman - -snes_mf - Use matrix free Jacobian with no explicit Jacobian representation 435620d6dcSBarry Smith 4495452b02SPatrick Sanan Notes: 4595452b02SPatrick Sanan If the coloring is not provided through the context, this will first try to get the 46f6dfbefdSBarry Smith coloring from the `DM`. If the `DM` has no coloring routine, then it will try to 47f6dfbefdSBarry Smith get the coloring from the matrix. This requires that the matrix have its nonzero locations already provided. 48b0ae01b7SPeter Brune 49f6dfbefdSBarry Smith `SNES` supports three approaches for computing (approximate) Jacobians: user provided via `SNESSetJacobian()`, matrix-free via `SNESSetUseMatrixFree()`, 50f6dfbefdSBarry Smith and computing explicitly with finite differences and coloring using `MatFDColoring`. It is also possible to use automatic differentiation 51f6dfbefdSBarry Smith and the `MatFDColoring` object, see src/ts/tutorials/autodiff/ex16adj_tl.cxx 52ec5066bdSBarry Smith 53f6dfbefdSBarry Smith This function can be provided to `SNESSetJacobian()` along with an appropriate sparse matrix to hold the Jacobian 54f6dfbefdSBarry Smith 55f6dfbefdSBarry Smith .seealso: `SNES`, `SNESSetJacobian()`, `SNESTestJacobian()`, `SNESComputeJacobianDefault()`, `SNESSetUseMatrixFree()`, 56db781477SPatrick Sanan `MatFDColoringCreate()`, `MatFDColoringSetFunction()` 5791627157SBarry Smith @*/ 58d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESComputeJacobianDefaultColor(SNES snes, Vec x1, Mat J, Mat B, void *ctx) 59d71ae5a4SJacob Faibussowitsch { 607fb41025SPeter Brune MatFDColoring color = (MatFDColoring)ctx; 614e269d77SPeter Brune DM dm; 62335efc43SPeter Brune MatColoring mc; 634e269d77SPeter Brune ISColoring iscoloring; 64b0ae01b7SPeter Brune PetscBool hascolor; 65aa2f1b4eSJed Brown PetscBool solvec, matcolor = PETSC_FALSE; 660df40c35SBarry Smith DMSNES dms; 67dff777c9SBarry Smith 683a40ed3dSBarry Smith PetscFunctionBegin; 69064a246eSJacob Faibussowitsch if (color) PetscValidHeaderSpecific(color, MAT_FDCOLORING_CLASSID, 5); 709566063dSJacob Faibussowitsch if (!color) PetscCall(PetscObjectQuery((PetscObject)B, "SNESMatFDColoring", (PetscObject *)&color)); 7162cd874fSBarry Smith 724e269d77SPeter Brune if (!color) { 739566063dSJacob Faibussowitsch PetscCall(SNESGetDM(snes, &dm)); 749566063dSJacob Faibussowitsch PetscCall(DMHasColoring(dm, &hascolor)); 75924833adSPeter Brune matcolor = PETSC_FALSE; 769566063dSJacob Faibussowitsch PetscCall(PetscOptionsGetBool(((PetscObject)snes)->options, ((PetscObject)snes)->prefix, "-snes_fd_color_use_mat", &matcolor, NULL)); 77c3138ed3SPeter Brune if (hascolor && !matcolor) { 789566063dSJacob Faibussowitsch PetscCall(DMCreateColoring(dm, IS_COLORING_GLOBAL, &iscoloring)); 79b0ae01b7SPeter Brune } else { 809566063dSJacob Faibussowitsch PetscCall(MatColoringCreate(B, &mc)); 819566063dSJacob Faibussowitsch PetscCall(MatColoringSetDistance(mc, 2)); 829566063dSJacob Faibussowitsch PetscCall(MatColoringSetType(mc, MATCOLORINGSL)); 839566063dSJacob Faibussowitsch PetscCall(MatColoringSetFromOptions(mc)); 849566063dSJacob Faibussowitsch PetscCall(MatColoringApply(mc, &iscoloring)); 859566063dSJacob Faibussowitsch PetscCall(MatColoringDestroy(&mc)); 860df40c35SBarry Smith } 879566063dSJacob Faibussowitsch PetscCall(MatFDColoringCreate(B, iscoloring, &color)); 889566063dSJacob Faibussowitsch PetscCall(DMGetDMSNES(dm, &dms)); 890df40c35SBarry Smith if (dms->ops->computemffunction) { 909566063dSJacob Faibussowitsch PetscCall(MatFDColoringSetFunction(color, (PetscErrorCode(*)(void))SNESComputeMFFunctionCtx, NULL)); 910df40c35SBarry Smith } else { 929566063dSJacob Faibussowitsch PetscCall(MatFDColoringSetFunction(color, (PetscErrorCode(*)(void))SNESComputeFunctionCtx, NULL)); 930df40c35SBarry Smith } 949566063dSJacob Faibussowitsch PetscCall(MatFDColoringSetFromOptions(color)); 959566063dSJacob Faibussowitsch PetscCall(MatFDColoringSetUp(B, iscoloring, color)); 969566063dSJacob Faibussowitsch PetscCall(ISColoringDestroy(&iscoloring)); 979566063dSJacob Faibussowitsch PetscCall(PetscObjectCompose((PetscObject)B, "SNESMatFDColoring", (PetscObject)color)); 989566063dSJacob Faibussowitsch PetscCall(PetscObjectDereference((PetscObject)color)); 994a9d489dSBarry Smith } 10095862db2SPeter Brune 101c89319d2SPeter Brune /* F is only usable if there is no RHS on the SNES and the full solution corresponds to x1 */ 1029566063dSJacob Faibussowitsch PetscCall(VecEqual(x1, snes->vec_sol, &solvec)); 103c89319d2SPeter Brune if (!snes->vec_rhs && solvec) { 10462cd874fSBarry Smith Vec F; 1059566063dSJacob Faibussowitsch PetscCall(SNESGetFunction(snes, &F, NULL, NULL)); 1069566063dSJacob Faibussowitsch PetscCall(MatFDColoringSetF(color, F)); 10795862db2SPeter Brune } 1089566063dSJacob Faibussowitsch PetscCall(MatFDColoringApply(B, color, x1, snes)); 10994ab13aaSBarry Smith if (J != B) { 1109566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY)); 1119566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY)); 112194405b3SBarry Smith } 1133a40ed3dSBarry Smith PetscFunctionReturn(0); 11491627157SBarry Smith } 11578e7fe0eSHong Zhang 11678e7fe0eSHong Zhang /*@C 117*7b2dc123SHong Zhang SNESPruneJacobianColor - Remove nondiagonal zeros in the Jacobian matrix and update the `MatMFFD` coloring information. 11878e7fe0eSHong Zhang 11978e7fe0eSHong Zhang Collective on SNES 12078e7fe0eSHong Zhang 12178e7fe0eSHong Zhang Input Parameters: 12278e7fe0eSHong Zhang + snes - the SNES context 12378e7fe0eSHong Zhang . J - Jacobian matrix (not altered in this routine) 12478e7fe0eSHong Zhang - B - newly computed Jacobian matrix to use with preconditioner (generally the same as J) 12578e7fe0eSHong Zhang 12678e7fe0eSHong Zhang Level: intermediate 12778e7fe0eSHong Zhang 12878e7fe0eSHong Zhang Notes: 129*7b2dc123SHong Zhang This function improves the `MatMFFD` coloring performance when the Jacobian matrix is overallocated or contains 13078e7fe0eSHong Zhang many constant zeros entries, which is typically the case when the matrix is generated by a DM 13178e7fe0eSHong Zhang and multiple fields are involved. 13278e7fe0eSHong Zhang 13378e7fe0eSHong Zhang Users need to make sure that the Jacobian matrix is properly filled to reflect the sparsity 134*7b2dc123SHong Zhang structure. For `MatMFFD` coloring, the values of nonzero entries are not important. So one can 135*7b2dc123SHong Zhang usually call `SNESComputeJacobian()` with randomized input vectors to generate a dummy Jacobian. 136*7b2dc123SHong Zhang `SNESComputeJacobian()` should be called before `SNESSolve()` but after `SNESSetUp()`. 13778e7fe0eSHong Zhang 13878e7fe0eSHong Zhang .seealso: `SNESComputeJacobianDefaultColor()`, `MatEliminateZeros()`, `MatFDColoringCreate()`, `MatFDColoringSetFunction()` 13978e7fe0eSHong Zhang @*/ 14078e7fe0eSHong Zhang PetscErrorCode SNESPruneJacobianColor(SNES snes, Mat J, Mat B) 14178e7fe0eSHong Zhang { 14278e7fe0eSHong Zhang DM dm; 14378e7fe0eSHong Zhang DMSNES dms; 14478e7fe0eSHong Zhang MatColoring mc; 14578e7fe0eSHong Zhang ISColoring iscoloring; 14678e7fe0eSHong Zhang MatFDColoring matfdcoloring; 14778e7fe0eSHong Zhang 14878e7fe0eSHong Zhang PetscFunctionBegin; 14978e7fe0eSHong Zhang /* Generate new coloring after eliminating zeros in the matrix */ 15078e7fe0eSHong Zhang PetscCall(MatEliminateZeros(B)); 15178e7fe0eSHong Zhang PetscCall(MatColoringCreate(B, &mc)); 15278e7fe0eSHong Zhang PetscCall(MatColoringSetDistance(mc, 2)); 15378e7fe0eSHong Zhang PetscCall(MatColoringSetType(mc, MATCOLORINGSL)); 15478e7fe0eSHong Zhang PetscCall(MatColoringSetFromOptions(mc)); 15578e7fe0eSHong Zhang PetscCall(MatColoringApply(mc, &iscoloring)); 15678e7fe0eSHong Zhang PetscCall(MatColoringDestroy(&mc)); 15778e7fe0eSHong Zhang /* Replace the old coloring with the new one */ 15878e7fe0eSHong Zhang PetscCall(MatFDColoringCreate(B, iscoloring, &matfdcoloring)); 15978e7fe0eSHong Zhang PetscCall(SNESGetDM(snes, &dm)); 16078e7fe0eSHong Zhang PetscCall(DMGetDMSNES(dm, &dms)); 16178e7fe0eSHong Zhang // Comment out the following branch to bypass the coverage test. You can uncomment it when needed. 16278e7fe0eSHong Zhang //if (dms->ops->computemffunction) { 16378e7fe0eSHong Zhang // PetscCall(MatFDColoringSetFunction(matfdcoloring, (PetscErrorCode(*)(void))SNESComputeMFFunctionCtx, NULL)); 16478e7fe0eSHong Zhang //} else { 16578e7fe0eSHong Zhang PetscCall(MatFDColoringSetFunction(matfdcoloring, (PetscErrorCode(*)(void))SNESComputeFunctionCtx, NULL)); 16678e7fe0eSHong Zhang //} 16778e7fe0eSHong Zhang PetscCall(MatFDColoringSetFromOptions(matfdcoloring)); 16878e7fe0eSHong Zhang PetscCall(MatFDColoringSetUp(B, iscoloring, matfdcoloring)); 16978e7fe0eSHong Zhang PetscCall(PetscObjectCompose((PetscObject)B, "SNESMatFDColoring", (PetscObject)matfdcoloring)); 17078e7fe0eSHong Zhang PetscCall(PetscObjectDereference((PetscObject)matfdcoloring)); 17178e7fe0eSHong Zhang PetscCall(ISColoringDestroy(&iscoloring)); 17278e7fe0eSHong Zhang PetscFunctionReturn(0); 17378e7fe0eSHong Zhang } 174