Actual source code: taosnes.c

  1: static char help[] = "Check TAOSNES convergence reasons on a quadratic problem.\n";

  3: #include <petsctao.h>

  5: static PetscErrorCode FormObjectiveGradient(Tao tao, Vec X, PetscReal *f, Vec G, PetscCtx ctx)
  6: {
  7:   PetscScalar dot;

  9:   PetscFunctionBeginUser;
 10:   PetscCall(VecDot(X, X, &dot));
 11:   *f = 0.5 * PetscRealPart(dot);
 12:   PetscCall(VecCopy(X, G));
 13:   PetscFunctionReturn(PETSC_SUCCESS);
 14: }

 16: static PetscErrorCode FormHessian(Tao tao, Vec X, Mat H, Mat P, PetscCtx ctx)
 17: {
 18:   PetscFunctionBeginUser;
 19:   PetscCall(MatZeroEntries(H));
 20:   PetscCall(MatShift(H, 1.0));
 21:   PetscFunctionReturn(PETSC_SUCCESS);
 22: }

 24: int main(int argc, char **argv)
 25: {
 26:   const SNESConvergedReason snes_reasons[] = {SNES_CONVERGED_FNORM_ABS, SNES_DIVERGED_MAX_IT, SNES_CONVERGED_FNORM_RELATIVE, SNES_DIVERGED_FUNCTION_COUNT, SNES_DIVERGED_LINEAR_SOLVE};
 27:   const TaoConvergedReason  tao_reasons[]  = {TAO_CONVERGED_GATOL, TAO_DIVERGED_MAXITS, TAO_CONVERGED_GTTOL, TAO_DIVERGED_MAXFCN, TAO_DIVERGED_USER};
 28:   Tao                       tao;
 29:   SNES                      snes;
 30:   KSP                       ksp;
 31:   PC                        pc;
 32:   Vec                       X;
 33:   Mat                       H;

 35:   PetscFunctionBeginUser;
 36:   PetscCall(PetscInitialize(&argc, &argv, NULL, help));
 37:   PetscCall(VecCreateSeq(PETSC_COMM_SELF, 2, &X));
 38:   PetscCall(MatCreateSeqAIJ(PETSC_COMM_SELF, 2, 2, 1, NULL, &H));
 39:   for (PetscInt i = 0; i < 2; ++i) PetscCall(MatSetValue(H, i, i, 1.0, INSERT_VALUES));
 40:   PetscCall(MatAssemblyBegin(H, MAT_FINAL_ASSEMBLY));
 41:   PetscCall(MatAssemblyEnd(H, MAT_FINAL_ASSEMBLY));
 42:   PetscCall(TaoCreate(PETSC_COMM_SELF, &tao));
 43:   PetscCall(TaoSetType(tao, TAOSNES));
 44:   PetscCall(TaoSetSolution(tao, X));
 45:   PetscCall(TaoSetObjectiveAndGradient(tao, NULL, FormObjectiveGradient, NULL));
 46:   PetscCall(TaoSetHessian(tao, H, H, FormHessian, NULL));
 47:   PetscCall(TaoSNESGetSNES(tao, &snes));
 48:   PetscCall(TaoSetFromOptions(tao));
 49:   PetscCall(TaoSetUp(tao));
 50:   PetscCall(SNESGetKSP(snes, &ksp));
 51:   PetscCall(KSPSetType(ksp, KSPCG));
 52:   PetscCall(KSPGetPC(ksp, &pc));
 53:   PetscCall(PCSetType(pc, PCNONE));
 54:   for (size_t test = 0; test < PETSC_STATIC_ARRAY_LENGTH(snes_reasons); ++test) {
 55:     SNESConvergedReason snes_reason;
 56:     TaoConvergedReason  tao_reason;
 57:     PetscInt            snes_its, tao_its;

 59:     PetscCall(VecSet(X, 1.0));
 60:     PetscCall(SNESSetTolerances(snes, test == 2 ? 0.0 : 1.e-12, test == 2 ? 0.5 : 0.0, 0.0, test == 1 ? 0 : 10, test == 3 ? 1 : 100));
 61:     PetscCall(KSPSetTolerances(ksp, 1.e-12, PETSC_CURRENT, PETSC_CURRENT, test == 4 ? 0 : 10));
 62:     PetscCall(TaoSolve(tao));
 63:     PetscCall(SNESGetConvergedReason(snes, &snes_reason));
 64:     PetscCall(TaoGetConvergedReason(tao, &tao_reason));
 65:     PetscCall(SNESGetIterationNumber(snes, &snes_its));
 66:     PetscCall(TaoGetIterationNumber(tao, &tao_its));
 67:     PetscCheck(snes_reason == snes_reasons[test], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected SNES reason %s", SNESConvergedReasons[snes_reason]);
 68:     PetscCheck(tao_reason == tao_reasons[test], PETSC_COMM_SELF, PETSC_ERR_PLIB, "SNES reason %s mapped to TAO reason %s", SNESConvergedReasons[snes_reason], TaoConvergedReasons[tao_reason]);
 69:     PetscCheck(tao_its == snes_its, PETSC_COMM_SELF, PETSC_ERR_PLIB, "TAO and SNES iteration counts differ");
 70:     PetscCall(PetscPrintf(PETSC_COMM_SELF, "SNES %s -> TAO %s\n", SNESConvergedReasons[snes_reason], TaoConvergedReasons[tao_reason]));
 71:   }
 72:   PetscCall(TaoDestroy(&tao));
 73:   PetscCall(MatDestroy(&H));
 74:   PetscCall(VecDestroy(&X));
 75:   PetscCall(PetscFinalize());
 76:   return 0;
 77: }

 79: /*TEST

 81:   test:
 82:     suffix: 1
 83:     requires: !single !complex
 84:     args: -snes_type {{newtonls newtontr}}

 86: TEST*/