Sorry, I wrote to quickly in my last email. You will need to create a SNESSHELL its solve simply calls your solver (for its one iteration) SNESNRICHARSON handles the rest.
On May 31, 2023, at 4:16 PM, Kenneth C Hall <kenneth.c.hall@duke.edu> wrote:Matt,Thanks for your quick reply. I think what you say makes sense.You asked what my code does. The MySolver program performs one iteration of a CFD iteration. The CFD scheme is an explicit scheme that uses multigrid, Mach number preconditioning, and residual smoothing. Typically, I have to call MySolver on the order of 40 to 100 times to get acceptable convergence.And in fact, I have another version of this Petsc code that uses SNESNGMRES to solve the problem with MySolver providing the residuals as R = N(x) - x. But I would like a version where I am using just MySolver, without any other operations applied to it. So I am trying to plug MySolver into the PETSc system to provide monitoring and other features, and for consistency and comparison to these other (more appropriate!) uses of PETSc.Thanks.KennethFrom: Matthew Knepley <knepley@gmail.com>
Date: Wednesday, May 31, 2023 at 3:48 PM
To: Kenneth C Hall <kenneth.c.hall@duke.edu>
Cc: petsc-users@mcs.anl.gov <petsc-users@mcs.anl.gov>
Subject: Re: [petsc-users] Using SNESSHELL as a wrapper for a CFD solver.Hi,I am doing a number of problems using PETSc/SLEPc, but I also work on some non-PETSc/SLEPc flow solvers. I would like to use PETSc as a wrapper for this non-PETSc flow solver for compatibility, so I can use the tolerance monitoring, options, viewers, and for direct comparison to PETSc methods I am using.Here is what I am trying to do… I have a CFD solver that iterates with a nonlinear iterator of the form x := N(x). This can be expressed in a fortran routine of the form,SUBROUTINE MySolver(x)orSUBROUTINE MySolver(x,y)In the first case, x is over written. In the second, y = N(x). In any event, I want to do something like what is shown in the subroutine at the bottom of this email.The code below “works” in the sense that MySolver is called, but it is called exactly *once*. But MyMonitor and MyConverged are *not* called. Again, I want to iterate so MySolver should be called many times, as should MyMonitor and MyConverged.The SNESolve() method is called once per nonlinear solve, just as KSPSolve() is called once per linear solve. There may be iteration inside the method, but that is handled inside the particular implementation. For example, both Newton's method and Nonlinear Conjugate Gradient iterate, but the iteration is internal to both, and they both call the monitor and convergence test at each internal iterate.So, if your nonlinear solver should iterate, it should happen inside the SNESSolve call for the SNESSHELL object. Does this make sense? What does your solver do?Thanks,MattThe SNESView before and after SNESSolve looks like this:SNES Object: 1 MPI process
type: shell
SNES has not been set up so information may be incomplete
maximum iterations=50, maximum function evaluations=10000
tolerances: relative=1e-50, absolute=1e-10, solution=1e+06
total number of function evaluations=0
norm schedule ALWAYS
SNES Object: 1 MPI process
type: shell
maximum iterations=50, maximum function evaluations=10000
tolerances: relative=1e-50, absolute=1e-10, solution=1e+06
total number of function evaluations=0
norm schedule ALWAYS
Any suggestions on how to do what I am trying to accomplish?Thanks.Kenneth Hall#include <petsc/finclude/petsc.h>#include "macros.h"
MODULE SolveWithSNESShell_moduleUSE MyPetscModuleCONTAINS!!====================================================================================================SUBROUTINE MySolver(snes, x, ierr)!====================================================================================================!!!!!====================================================================================================!USE MyPetscModuleIMPLICIT NONE!!.... declared passed variablesSNES :: snesVec :: xPetscErrorCode :: ierr!!.... code to find residual x := N(x)!.... (or alternatively y := N(x))
END SUBROUTINE MySolver!!====================================================================================================SUBROUTINE MyMonitor(snes, its, rnorm, ierr)!====================================================================================================!!!!!====================================================================================================!USE MyPetscModuleIMPLICIT NONE!!.... Declare passed variablesSNES :: snesPetscInt :: itsPetscReal :: rnormPetscErrorCode :: ierr!!.... Code to print out convergence history!.... Code to print out convergence history
END SUBROUTINE MyMonitor
!====================================================================================================SUBROUTINE MyConverged(snes, it, xnorm, ynorm, znorm, reason, ierr)USE MyPetscModuleIMPLICIT NONE
SNES :: snesPetscInt :: it,ctxPetscReal :: xnorm, ynorm, znormKSPConvergedReason :: reasonPetscErrorCode :: ierr
! ... add convergence test here ...! set reason to a positive value if convergence has been achieved
END SUBROUTINE MyConvergedEND MODULE SolveWithSNESShell_module!!====================================================================================================SUBROUTINE SolveWithSNESShell!====================================================================================================!!!!!====================================================================================================!USE SolveWithSNESShell_moduleIMPLICIT NONE!!.... Declare passed variablesINTEGER :: level_tmp!!.... Declare local variablesINTEGER :: izINTEGER :: imaxINTEGER :: jmaxINTEGER :: kmaxSNES :: snesKSP :: kspVec :: xVec :: yPetscViewer :: viewerPetscErrorCode :: ierrPetscReal :: rtol = 1.0D-10 !! relative tolerancePetscReal :: atol = 1.0D-50 !! absolute tolerancePetscReal :: dtol = 1.0D+06 !! divergence tolerancePetscInt :: maxits = 50PetscInt :: maxf = 10000character(len=1000):: args!!.... count the number of degrees of freedom.level = level_tmpn = 0DO iz = 1, hb(level)%nzoneimax = hb(level)%zone(iz)%imax - 1jmax = hb(level)%zone(iz)%jmax - 1kmax = hb(level)%zone(iz)%kmax - 1n = n + imax * jmax * kmaxEND DOn = n * neqn!!.... Initialize PETScPetscCall(PetscInitialize(PETSC_NULL_CHARACTER, ierr))!!.... LogPetscCall(PetscLogDefaultBegin(ierr))!!.... Hard-wired options.! PetscCall(PetscOptionsInsertString(PETSC_NULL_OPTIONS, "command line style option here" , ierr))!!.... Command line options.call GET_COMMAND(args)PetscCall(PetscOptionsInsertString(PETSC_NULL_OPTIONS, args, ierr))!!.... view command line tablePetscCall(PetscViewerASCIIOpen(PETSC_COMM_SELF, PETSC_VIEWER_STDOUT_SELF, viewer, ierr))PetscCall(PetscOptionsView(PETSC_NULL_OPTIONS, viewer, ierr))PetscCall(PetscViewerDestroy(viewer, ierr))!!.... Create PETSc vectorsPetscCall(VecCreateSeq(PETSC_COMM_SELF, n, x, ierr))PetscCall(VecCreateSeq(PETSC_COMM_SELF, n, y, ierr))PetscCall(VecSet(x, 0.0d0, ierr))PetscCall(VecSet(y, 0.0d0, ierr))
!.... SNES contextPetscCall(SNESCreate(PETSC_COMM_SELF, snes, ierr))PetscCall(SNESSetType(snes, SNESSHELL, ierr))PetscCall(SNESShellSetSolve(snes, MySolver, ierr))
!!!! PetscCall(SNESSetFunction(snes, x, MySolver, PETSC_NULL_INTEGER, ierr))!!!! this line causes a segmentation error if uncommented.
PetscCall(SNESSetConvergenceTest(snes, MyConverged, 0, PETSC_NULL_FUNCTION, ierr))!!.... Set SNES optionsPetscCall(SNESSetFromOptions(snes, ierr))
!.... Set tolerancesPetscCall(SNESSetTolerances(snes, rtol, atol, dtol, maxits, maxf, ierr))!!.... SNES montiorPetscCall(SNESMonitorSet(snes, MyMonitor, PETSC_NULL_INTEGER, PETSC_NULL_FUNCTION,ierr))!!.... Set the initial solutionCALL HBToVecX(x)!!.... View snes contextPetscCall(SNESView(snes, viewer, ierr))!!.... Solve SNES problemPetscCall(SNESSolve(snes, PETSC_NULL_VEC, x, ierr))!!.... View snes contextPetscCall(SNESView(snes, viewer, ierr))!!.... dump the logs! call PetscLogDump(ierr) ! Why does this cause error!!.... Destroy PETSc objectsPetscCall(SNESDestroy(snes, ierr))PetscCall(VecDestroy(x, ierr))PetscCall(VecDestroy(y, ierr))PetscCall(PetscViewerDestroy(viewer, ierr))!!.... FinishPetscCall(PetscFinalize(ierr))
END SUBROUTINE SolveWithSNESShell--What most experimenters take for granted before they begin their experiments is infinitely more interesting than any results to which their experiments lead.
-- Norbert Wiener