LCOV - code coverage report
Current view: top level - src/solvers - tao_optimization_solver.C (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4229 (6a9aeb) with base 727f46 Lines: 187 225 83.1 %
Date: 2025-08-19 19:27:09 Functions: 16 16 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // The libMesh Finite Element Library.
       2             : // Copyright (C) 2002-2025 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
       3             : 
       4             : // This library is free software; you can redistribute it and/or
       5             : // modify it under the terms of the GNU Lesser General Public
       6             : // License as published by the Free Software Foundation; either
       7             : // version 2.1 of the License, or (at your option) any later version.
       8             : 
       9             : // This library is distributed in the hope that it will be useful,
      10             : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12             : // Lesser General Public License for more details.
      13             : 
      14             : // You should have received a copy of the GNU Lesser General Public
      15             : // License along with this library; if not, write to the Free Software
      16             : // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
      17             : 
      18             : 
      19             : 
      20             : #include "libmesh/libmesh_common.h"
      21             : 
      22             : #if defined(LIBMESH_HAVE_PETSC_TAO) && !defined(LIBMESH_USE_COMPLEX_NUMBERS)
      23             : 
      24             : 
      25             : // C++ includes
      26             : 
      27             : // Local Includes
      28             : #include "libmesh/libmesh_logging.h"
      29             : #include "libmesh/petsc_vector.h"
      30             : #include "libmesh/petsc_matrix.h"
      31             : #include "libmesh/dof_map.h"
      32             : #include "libmesh/tao_optimization_solver.h"
      33             : #include "libmesh/equation_systems.h"
      34             : 
      35             : namespace libMesh
      36             : {
      37             : 
      38             : //--------------------------------------------------------------------
      39             : // Functions with C linkage to pass to Tao. Tao will call these
      40             : // methods as needed.
      41             : //
      42             : // Since they must have C linkage they have no knowledge of a namespace.
      43             : // Give them an obscure name to avoid namespace pollution.
      44             : extern "C"
      45             : {
      46             : 
      47             :   //---------------------------------------------------------------
      48             :   // This function is called by Tao to evaluate objective function at x
      49             :   PetscErrorCode
      50         990 :   __libmesh_tao_objective (Tao /*tao*/, Vec x, PetscReal * objective, void * ctx)
      51             :   {
      52             :     PetscFunctionBegin;
      53             : 
      54          44 :     LOG_SCOPE("objective()", "TaoOptimizationSolver");
      55             : 
      56          22 :     libmesh_assert(x);
      57          22 :     libmesh_assert(objective);
      58          22 :     libmesh_assert(ctx);
      59             : 
      60             :     // ctx should be a pointer to the solver (it was passed in as void *)
      61          22 :     TaoOptimizationSolver<Number> * solver =
      62             :       static_cast<TaoOptimizationSolver<Number> *> (ctx);
      63             : 
      64          44 :     OptimizationSystem & sys = solver->system();
      65             : 
      66             :     // We'll use current_local_solution below, so let's ensure that it's consistent
      67             :     // with the vector x that was passed in.
      68          22 :     PetscVector<Number> & X_sys = *cast_ptr<PetscVector<Number> *>(sys.solution.get());
      69         990 :     PetscVector<Number> X(x, sys.comm());
      70             : 
      71             :     // Perform a swap so that sys.solution points to the input vector
      72             :     // "x", update sys.current_local_solution based on "x", then swap
      73             :     // back.
      74         990 :     X.swap(X_sys);
      75         990 :     sys.update();
      76         990 :     X.swap(X_sys);
      77             : 
      78             :     // Enforce constraints (if any) exactly on the
      79             :     // current_local_solution.  This is the solution vector that is
      80             :     // actually used in the computation of the objective function
      81             :     // below, and is not locked by debug-enabled PETSc the way that
      82             :     // the solution vector is.
      83         990 :     sys.get_dof_map().enforce_constraints_exactly(sys, sys.current_local_solution.get());
      84             : 
      85         990 :     if (solver->objective_object != nullptr)
      86        1012 :       (*objective) = PS(solver->objective_object->objective(*(sys.current_local_solution), sys));
      87             :     else
      88           0 :       libmesh_error_msg("Objective function not defined in __libmesh_tao_objective");
      89             : 
      90        1012 :     PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
      91         946 :   }
      92             : 
      93             : 
      94             : 
      95             :   //---------------------------------------------------------------
      96             :   // This function is called by Tao to evaluate the gradient at x
      97             :   PetscErrorCode
      98         640 :   __libmesh_tao_gradient(Tao /*tao*/, Vec x, Vec g, void * ctx)
      99             :   {
     100             :     PetscFunctionBegin;
     101             : 
     102          24 :     LOG_SCOPE("gradient()", "TaoOptimizationSolver");
     103             : 
     104          12 :     libmesh_assert(x);
     105          12 :     libmesh_assert(g);
     106          12 :     libmesh_assert(ctx);
     107             : 
     108             :     // ctx should be a pointer to the solver (it was passed in as void *)
     109          12 :     TaoOptimizationSolver<Number> * solver =
     110             :       static_cast<TaoOptimizationSolver<Number> *> (ctx);
     111             : 
     112          24 :     OptimizationSystem & sys = solver->system();
     113             : 
     114             :     // We'll use current_local_solution below, so let's ensure that it's consistent
     115             :     // with the vector x that was passed in.
     116          12 :     PetscVector<Number> & X_sys = *cast_ptr<PetscVector<Number> *>(sys.solution.get());
     117         664 :     PetscVector<Number> X(x, sys.comm());
     118             : 
     119             :     // Perform a swap so that sys.solution points to the input vector
     120             :     // "x", update sys.current_local_solution based on "x", then swap
     121             :     // back.
     122         640 :     X.swap(X_sys);
     123         640 :     sys.update();
     124         640 :     X.swap(X_sys);
     125             : 
     126             :     // We'll also pass the gradient in to the assembly routine
     127             :     // so let's make a PETSc vector for that too.
     128         652 :     PetscVector<Number> gradient(g, sys.comm());
     129             : 
     130             :     // Clear the gradient prior to assembly
     131         640 :     gradient.zero();
     132             : 
     133             :     // Enforce constraints exactly on the current_local_solution.
     134         640 :     sys.get_dof_map().enforce_constraints_exactly(sys, sys.current_local_solution.get());
     135             : 
     136         640 :     if (solver->gradient_object != nullptr)
     137         652 :       solver->gradient_object->gradient(*(sys.current_local_solution), gradient, sys);
     138             :     else
     139           0 :       libmesh_error_msg("Gradient function not defined in __libmesh_tao_gradient");
     140             : 
     141         640 :     gradient.close();
     142             : 
     143         652 :     PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
     144         616 :   }
     145             : 
     146             :   //---------------------------------------------------------------
     147             :   // This function is called by Tao to evaluate the Hessian at x
     148             :   PetscErrorCode
     149         524 :   __libmesh_tao_hessian(Tao /*tao*/, Vec x, Mat h, Mat pc, void * ctx)
     150             :   {
     151             :     PetscFunctionBegin;
     152             : 
     153          20 :     LOG_SCOPE("hessian()", "TaoOptimizationSolver");
     154             : 
     155          10 :     libmesh_assert(x);
     156          10 :     libmesh_assert(h);
     157          10 :     libmesh_assert(pc);
     158          10 :     libmesh_assert(ctx);
     159             : 
     160             :     // ctx should be a pointer to the solver (it was passed in as void *)
     161          10 :     TaoOptimizationSolver<Number> * solver =
     162             :       static_cast<TaoOptimizationSolver<Number> *> (ctx);
     163             : 
     164          20 :     OptimizationSystem & sys = solver->system();
     165             : 
     166             :     // We'll use current_local_solution below, so let's ensure that it's consistent
     167             :     // with the vector x that was passed in.
     168          10 :     PetscVector<Number> & X_sys = *cast_ptr<PetscVector<Number> *>(sys.solution.get());
     169         544 :     PetscVector<Number> X(x, sys.comm());
     170             : 
     171             :     // Perform a swap so that sys.solution points to the input vector
     172             :     // "x", update sys.current_local_solution based on "x", then swap
     173             :     // back.
     174         524 :     X.swap(X_sys);
     175         524 :     sys.update();
     176         524 :     X.swap(X_sys);
     177             : 
     178             :     // Let's also wrap pc and h in PetscMatrix objects for convenience
     179         544 :     PetscMatrix<Number> PC(pc, sys.comm());
     180         534 :     PetscMatrix<Number> hessian(h, sys.comm());
     181         524 :     PC.attach_dof_map(sys.get_dof_map());
     182         524 :     hessian.attach_dof_map(sys.get_dof_map());
     183             : 
     184             :     // Enforce constraints exactly on the current_local_solution.
     185         524 :     sys.get_dof_map().enforce_constraints_exactly(sys, sys.current_local_solution.get());
     186             : 
     187         524 :     if (solver->hessian_object != nullptr)
     188             :       {
     189             :         // Following PetscNonlinearSolver by passing in PC. It's not clear
     190             :         // why we pass in PC and not hessian though?
     191        1038 :         solver->hessian_object->hessian(*(sys.current_local_solution), PC, sys);
     192             :       }
     193             :     else
     194           0 :       libmesh_error_msg("Hessian function not defined in __libmesh_tao_hessian");
     195             : 
     196         524 :     PC.close();
     197         524 :     hessian.close();
     198             : 
     199         534 :     PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
     200         504 :   }
     201             : 
     202             : 
     203             :   //---------------------------------------------------------------
     204             :   // This function is called by Tao to evaluate the equality constraints at x
     205             :   PetscErrorCode
     206         129 :   __libmesh_tao_equality_constraints(Tao /*tao*/, Vec x, Vec ce, void * ctx)
     207             :   {
     208             :     PetscFunctionBegin;
     209             : 
     210           0 :     LOG_SCOPE("equality_constraints()", "TaoOptimizationSolver");
     211             : 
     212           0 :     libmesh_assert(x);
     213           0 :     libmesh_assert(ce);
     214           0 :     libmesh_assert(ctx);
     215             : 
     216             :     // ctx should be a pointer to the solver (it was passed in as void *)
     217           0 :     TaoOptimizationSolver<Number> * solver =
     218             :       static_cast<TaoOptimizationSolver<Number> *> (ctx);
     219             : 
     220           0 :     OptimizationSystem & sys = solver->system();
     221             : 
     222             :     // We'll use current_local_solution below, so let's ensure that it's consistent
     223             :     // with the vector x that was passed in.
     224           0 :     PetscVector<Number> & X_sys = *cast_ptr<PetscVector<Number> *>(sys.solution.get());
     225         129 :     PetscVector<Number> X(x, sys.comm());
     226             : 
     227             :     // Perform a swap so that sys.solution points to the input vector
     228             :     // "x", update sys.current_local_solution based on "x", then swap
     229             :     // back.
     230         129 :     X.swap(X_sys);
     231         129 :     sys.update();
     232         129 :     X.swap(X_sys);
     233             : 
     234             :     // We'll also pass the constraints vector ce into the assembly routine
     235             :     // so let's make a PETSc vector for that too.
     236         129 :     PetscVector<Number> eq_constraints(ce, sys.comm());
     237             : 
     238             :     // Clear the gradient prior to assembly
     239         129 :     eq_constraints.zero();
     240             : 
     241             :     // Enforce constraints exactly on the current_local_solution.
     242         129 :     sys.get_dof_map().enforce_constraints_exactly(sys, sys.current_local_solution.get());
     243             : 
     244         129 :     if (solver->equality_constraints_object != nullptr)
     245         129 :       solver->equality_constraints_object->equality_constraints(*(sys.current_local_solution), eq_constraints, sys);
     246             :     else
     247           0 :       libmesh_error_msg("Constraints function not defined in __libmesh_tao_equality_constraints");
     248             : 
     249         129 :     eq_constraints.close();
     250             : 
     251         129 :     PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
     252         129 :   }
     253             : 
     254             :   //---------------------------------------------------------------
     255             :   // This function is called by Tao to evaluate the Jacobian of the
     256             :   // equality constraints at x
     257             :   PetscErrorCode
     258         129 :   __libmesh_tao_equality_constraints_jacobian(Tao /*tao*/, Vec x, Mat J, Mat Jpre, void * ctx)
     259             :   {
     260             :     PetscFunctionBegin;
     261             : 
     262           0 :     LOG_SCOPE("equality_constraints_jacobian()", "TaoOptimizationSolver");
     263             : 
     264           0 :     libmesh_assert(x);
     265           0 :     libmesh_assert(J);
     266           0 :     libmesh_assert(Jpre);
     267             : 
     268             :     // ctx should be a pointer to the solver (it was passed in as void *)
     269           0 :     TaoOptimizationSolver<Number> * solver =
     270             :       static_cast<TaoOptimizationSolver<Number> *> (ctx);
     271             : 
     272           0 :     OptimizationSystem & sys = solver->system();
     273             : 
     274             :     // We'll use current_local_solution below, so let's ensure that it's consistent
     275             :     // with the vector x that was passed in.
     276           0 :     PetscVector<Number> & X_sys = *cast_ptr<PetscVector<Number> *>(sys.solution.get());
     277         129 :     PetscVector<Number> X(x, sys.comm());
     278             : 
     279             :     // Perform a swap so that sys.solution points to the input vector
     280             :     // "x", update sys.current_local_solution based on "x", then swap
     281             :     // back.
     282         129 :     X.swap(X_sys);
     283         129 :     sys.update();
     284         129 :     X.swap(X_sys);
     285             : 
     286             :     // Let's also wrap J and Jpre in PetscMatrix objects for convenience
     287         129 :     PetscMatrix<Number> J_petsc(J, sys.comm());
     288         129 :     PetscMatrix<Number> Jpre_petsc(Jpre, sys.comm());
     289             : 
     290             :     // Enforce constraints exactly on the current_local_solution.
     291         129 :     sys.get_dof_map().enforce_constraints_exactly(sys, sys.current_local_solution.get());
     292             : 
     293         129 :     if (solver->equality_constraints_jacobian_object != nullptr)
     294         129 :       solver->equality_constraints_jacobian_object->equality_constraints_jacobian(*(sys.current_local_solution), J_petsc, sys);
     295             :     else
     296           0 :       libmesh_error_msg("Constraints function not defined in __libmesh_tao_equality_constraints_jacobian");
     297             : 
     298         129 :     J_petsc.close();
     299         129 :     Jpre_petsc.close();
     300             : 
     301         129 :     PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
     302         129 :   }
     303             : 
     304             :   //---------------------------------------------------------------
     305             :   // This function is called by Tao to evaluate the inequality constraints at x
     306             :   PetscErrorCode
     307         129 :   __libmesh_tao_inequality_constraints(Tao /*tao*/, Vec x, Vec cineq, void * ctx)
     308             :   {
     309             :     PetscFunctionBegin;
     310             : 
     311           0 :     LOG_SCOPE("inequality_constraints()", "TaoOptimizationSolver");
     312             : 
     313           0 :     libmesh_assert(x);
     314           0 :     libmesh_assert(cineq);
     315           0 :     libmesh_assert(ctx);
     316             : 
     317             :     // ctx should be a pointer to the solver (it was passed in as void *)
     318           0 :     TaoOptimizationSolver<Number> * solver =
     319             :       static_cast<TaoOptimizationSolver<Number> *> (ctx);
     320             : 
     321           0 :     OptimizationSystem & sys = solver->system();
     322             : 
     323             :     // We'll use current_local_solution below, so let's ensure that it's consistent
     324             :     // with the vector x that was passed in.
     325           0 :     PetscVector<Number> & X_sys = *cast_ptr<PetscVector<Number> *>(sys.solution.get());
     326         129 :     PetscVector<Number> X(x, sys.comm());
     327             : 
     328             :     // Perform a swap so that sys.solution points to the input vector
     329             :     // "x", update sys.current_local_solution based on "x", then swap
     330             :     // back.
     331         129 :     X.swap(X_sys);
     332         129 :     sys.update();
     333         129 :     X.swap(X_sys);
     334             : 
     335             :     // We'll also pass the constraints vector ce into the assembly routine
     336             :     // so let's make a PETSc vector for that too.
     337         129 :     PetscVector<Number> ineq_constraints(cineq, sys.comm());
     338             : 
     339             :     // Clear the gradient prior to assembly
     340         129 :     ineq_constraints.zero();
     341             : 
     342             :     // Enforce constraints exactly on the current_local_solution.
     343         129 :     sys.get_dof_map().enforce_constraints_exactly(sys, sys.current_local_solution.get());
     344             : 
     345         129 :     if (solver->inequality_constraints_object != nullptr)
     346         129 :       solver->inequality_constraints_object->inequality_constraints(*(sys.current_local_solution), ineq_constraints, sys);
     347             :     else
     348           0 :       libmesh_error_msg("Constraints function not defined in __libmesh_tao_inequality_constraints");
     349             : 
     350         129 :     ineq_constraints.close();
     351             : 
     352         129 :     PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
     353         129 :   }
     354             : 
     355             :   //---------------------------------------------------------------
     356             :   // This function is called by Tao to evaluate the Jacobian of the
     357             :   // equality constraints at x
     358             :   PetscErrorCode
     359         129 :   __libmesh_tao_inequality_constraints_jacobian(Tao /*tao*/, Vec x, Mat J, Mat Jpre, void * ctx)
     360             :   {
     361             :     PetscFunctionBegin;
     362             : 
     363           0 :     LOG_SCOPE("inequality_constraints_jacobian()", "TaoOptimizationSolver");
     364             : 
     365           0 :     libmesh_assert(x);
     366           0 :     libmesh_assert(J);
     367           0 :     libmesh_assert(Jpre);
     368             : 
     369             :     // ctx should be a pointer to the solver (it was passed in as void *)
     370           0 :     TaoOptimizationSolver<Number> * solver =
     371             :       static_cast<TaoOptimizationSolver<Number> *> (ctx);
     372             : 
     373           0 :     OptimizationSystem & sys = solver->system();
     374             : 
     375             :     // We'll use current_local_solution below, so let's ensure that it's consistent
     376             :     // with the vector x that was passed in.
     377           0 :     PetscVector<Number> & X_sys = *cast_ptr<PetscVector<Number> *>(sys.solution.get());
     378         129 :     PetscVector<Number> X(x, sys.comm());
     379             : 
     380             :     // Perform a swap so that sys.solution points to the input vector
     381             :     // "x", update sys.current_local_solution based on "x", then swap
     382             :     // back.
     383         129 :     X.swap(X_sys);
     384         129 :     sys.update();
     385         129 :     X.swap(X_sys);
     386             : 
     387             :     // Let's also wrap J and Jpre in PetscMatrix objects for convenience
     388         129 :     PetscMatrix<Number> J_petsc(J, sys.comm());
     389         129 :     PetscMatrix<Number> Jpre_petsc(Jpre, sys.comm());
     390             : 
     391             :     // Enforce constraints exactly on the current_local_solution.
     392         129 :     sys.get_dof_map().enforce_constraints_exactly(sys, sys.current_local_solution.get());
     393             : 
     394         129 :     if (solver->inequality_constraints_jacobian_object != nullptr)
     395         129 :       solver->inequality_constraints_jacobian_object->inequality_constraints_jacobian(*(sys.current_local_solution), J_petsc, sys);
     396             :     else
     397           0 :       libmesh_error_msg("Constraints function not defined in __libmesh_tao_inequality_constraints_jacobian");
     398             : 
     399         129 :     J_petsc.close();
     400         129 :     Jpre_petsc.close();
     401             : 
     402         129 :     PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
     403         129 :   }
     404             : 
     405             : } // end extern "C"
     406             : //---------------------------------------------------------------------
     407             : 
     408             : 
     409             : 
     410             : //---------------------------------------------------------------------
     411             : // TaoOptimizationSolver<> methods
     412             : template <typename T>
     413         142 : TaoOptimizationSolver<T>::TaoOptimizationSolver (OptimizationSystem & system_in) :
     414             :   OptimizationSolver<T>(system_in),
     415         142 :   _reason(TAO_CONVERGED_USER) // Arbitrary initial value...
     416             : {
     417         142 : }
     418             : 
     419             : 
     420             : 
     421             : template <typename T>
     422         284 : TaoOptimizationSolver<T>::~TaoOptimizationSolver ()
     423             : {
     424           8 :   this->TaoOptimizationSolver::clear ();
     425         351 : }
     426             : 
     427             : 
     428             : 
     429             : template <typename T>
     430          79 : void TaoOptimizationSolver<T>::clear () noexcept
     431             : {
     432         213 :   if (this->initialized())
     433             :     {
     434          71 :       this->_is_initialized = false;
     435             : 
     436          71 :       PetscErrorCode ierr = TaoDestroy(&_tao);
     437             :       if (ierr)
     438             :         libmesh_warning("Warning: TaoDestroy returned a non-zero error code which we ignored.");
     439             :     }
     440          79 : }
     441             : 
     442             : 
     443             : 
     444             : template <typename T>
     445         142 : void TaoOptimizationSolver<T>::init ()
     446             : {
     447             :   // Initialize the data structures if not done so already.
     448         142 :   if (!this->initialized())
     449             :     {
     450          71 :       this->_is_initialized = true;
     451             : 
     452          71 :       LibmeshPetscCall(TaoCreate(this->comm().get(),&_tao));
     453             :     }
     454         142 : }
     455             : 
     456             : template <typename T>
     457          71 : void TaoOptimizationSolver<T>::solve ()
     458             : {
     459           4 :   LOG_SCOPE("solve()", "TaoOptimizationSolver");
     460             : 
     461          71 :   this->init ();
     462             : 
     463          73 :   this->system().solution->zero();
     464             : 
     465          71 :   PetscMatrixBase<T> * hessian  = cast_ptr<PetscMatrixBase<T> *>(this->system().matrix);
     466             :   // PetscVector<T> * gradient = cast_ptr<PetscVector<T> *>(this->system().rhs);
     467           2 :   PetscVector<T> * x         = cast_ptr<PetscVector<T> *>(this->system().solution.get());
     468           2 :   PetscVector<T> * ceq       = cast_ptr<PetscVector<T> *>(this->system().C_eq.get());
     469           2 :   PetscMatrixBase<T> * ceq_jac   = cast_ptr<PetscMatrixBase<T> *>(this->system().C_eq_jac.get());
     470           2 :   PetscVector<T> * cineq     = cast_ptr<PetscVector<T> *>(this->system().C_ineq.get());
     471           2 :   PetscMatrixBase<T> * cineq_jac = cast_ptr<PetscMatrixBase<T> *>(this->system().C_ineq_jac.get());
     472          71 :   PetscVector<T> * lb        = cast_ptr<PetscVector<T> *>(&this->system().get_vector("lower_bounds"));
     473          71 :   PetscVector<T> * ub        = cast_ptr<PetscVector<T> *>(&this->system().get_vector("upper_bounds"));
     474             : 
     475             :   // Set the starting guess to zero.
     476          71 :   x->zero();
     477             : 
     478             :   // Workaround for bug where TaoSetFromOptions *reset*
     479             :   // programmatically set tolerance and max. function evaluation
     480             :   // values when "-tao_type ipm" was specified on the command line: we
     481             :   // call TaoSetFromOptions twice (both before and after setting
     482             :   // custom options programmatically)
     483          71 :   LibmeshPetscCall(TaoSetFromOptions(_tao));
     484             : 
     485             :   // Set convergence tolerances
     486             :   // f(X) - f(X*) (estimated)            <= fatol
     487             :   // |f(X) - f(X*)| (estimated) / |f(X)| <= frtol
     488             :   // ||g(X)||                            <= gatol
     489             :   // ||g(X)|| / |f(X)|                   <= grtol
     490             :   // ||g(X)|| / ||g(X0)||                <= gttol
     491             :   // Command line equivalents: -tao_fatol, -tao_frtol, -tao_gatol, -tao_grtol, -tao_gttol
     492             :   // Releases up to 3.7.0 had fatol and frtol, after that they were removed.
     493             : #if PETSC_VERSION_LESS_THAN(3,7,0)
     494             :   LibmeshPetscCall(TaoSetTolerances(_tao,
     495             :                                     /*fatol=*/PETSC_DEFAULT,
     496             :                                     /*frtol=*/PETSC_DEFAULT,
     497             :                                     /*gatol=*/PETSC_DEFAULT,
     498             :                                     /*grtol=*/this->objective_function_relative_tolerance,
     499             :                                     /*gttol=*/PETSC_DEFAULT));
     500             : #else
     501          71 :   LibmeshPetscCall(TaoSetTolerances(_tao,
     502             :                                     /*gatol=*/PETSC_DEFAULT,
     503             :                                     /*grtol=*/this->objective_function_relative_tolerance,
     504             :                                     /*gttol=*/PETSC_DEFAULT));
     505             : #endif
     506             : 
     507             :   // Set the max-allowed number of objective function evaluations
     508             :   // Command line equivalent: -tao_max_funcs
     509          71 :   LibmeshPetscCall(TaoSetMaximumFunctionEvaluations(_tao, this->max_objective_function_evaluations));
     510             : 
     511             :   // Set the max-allowed number of optimization iterations.
     512             :   // Command line equivalent: -tao_max_it
     513             :   // Not implemented for now as it seems fairly similar to
     514             :   // LibmeshPetscCall(TaoSetMaximumIterations(_tao, 4));
     515             : 
     516             :   // Set solution vec and an initial guess
     517             : #if PETSC_VERSION_LESS_THAN(3,17,0)
     518           4 :   LibmeshPetscCall(TaoSetInitialVector(_tao, x->vec()));
     519             : #else
     520          67 :   LibmeshPetscCall(TaoSetSolution(_tao, x->vec()));
     521             : #endif
     522             : 
     523             :   // We have to have an objective function
     524           2 :   libmesh_assert( this->objective_object );
     525             : 
     526             :   // Set routines for objective, gradient, hessian evaluation
     527             : #if PETSC_VERSION_LESS_THAN(3,17,0)
     528           4 :   LibmeshPetscCall(TaoSetObjectiveRoutine(_tao, __libmesh_tao_objective, this));
     529             : #else
     530          67 :   LibmeshPetscCall(TaoSetObjective(_tao, __libmesh_tao_objective, this));
     531             : #endif
     532             : 
     533          71 :   if (this->gradient_object)
     534             : #if PETSC_VERSION_LESS_THAN(3,17,0)
     535           4 :     LibmeshPetscCall(TaoSetGradientRoutine(_tao, __libmesh_tao_gradient, this));
     536             : #else
     537          67 :     LibmeshPetscCall(TaoSetGradient(_tao, NULL, __libmesh_tao_gradient, this));
     538             : #endif
     539             : 
     540          71 :   if (this->hessian_object)
     541             : #if PETSC_VERSION_LESS_THAN(3,17,0)
     542           4 :     LibmeshPetscCall(TaoSetHessianRoutine(_tao, hessian->mat(), hessian->mat(), __libmesh_tao_hessian, this));
     543             : #else
     544          67 :     LibmeshPetscCall(TaoSetHessian(_tao, hessian->mat(), hessian->mat(), __libmesh_tao_hessian, this));
     545             : #endif
     546             : 
     547          71 :   if (this->lower_and_upper_bounds_object)
     548             :     {
     549             :       // Need to actually compute the bounds vectors first
     550           1 :       this->lower_and_upper_bounds_object->lower_and_upper_bounds(this->system());
     551             : 
     552           1 :       LibmeshPetscCall(TaoSetVariableBounds(_tao,
     553             :                                             lb->vec(),
     554             :                                             ub->vec()));
     555             :     }
     556             : 
     557          71 :   if (this->equality_constraints_object)
     558           1 :     LibmeshPetscCall(TaoSetEqualityConstraintsRoutine(_tao, ceq->vec(), __libmesh_tao_equality_constraints, this));
     559             : 
     560          71 :   if (this->equality_constraints_jacobian_object)
     561           1 :     LibmeshPetscCall(TaoSetJacobianEqualityRoutine(_tao,
     562             :                                                    ceq_jac->mat(),
     563             :                                                    ceq_jac->mat(),
     564             :                                                    __libmesh_tao_equality_constraints_jacobian,
     565             :                                                    this));
     566             : 
     567             :   // Optionally set inequality constraints
     568          71 :   if (this->inequality_constraints_object)
     569           1 :     LibmeshPetscCall(TaoSetInequalityConstraintsRoutine(_tao, cineq->vec(), __libmesh_tao_inequality_constraints, this));
     570             : 
     571             :   // Optionally set inequality constraints Jacobian
     572          71 :   if (this->inequality_constraints_jacobian_object)
     573           1 :     LibmeshPetscCall(TaoSetJacobianInequalityRoutine(_tao,
     574             :                                                      cineq_jac->mat(),
     575             :                                                      cineq_jac->mat(),
     576             :                                                      __libmesh_tao_inequality_constraints_jacobian,
     577             :                                                      this));
     578             : 
     579             :   // Check for Tao command line options
     580          71 :   LibmeshPetscCall(TaoSetFromOptions(_tao));
     581             : 
     582             :   // Perform the optimization
     583          71 :   LibmeshPetscCall(TaoSolve(_tao));
     584             : 
     585             :   // Enforce constraints exactly now that the solve is done.  We have
     586             :   // been enforcing them on the current_local_solution during the
     587             :   // solve, but now need to be sure they are enforced on the parallel
     588             :   // solution vector as well.
     589          73 :   this->system().get_dof_map().enforce_constraints_exactly(this->system());
     590             : 
     591             :   // Store the convergence/divergence reason
     592          71 :   LibmeshPetscCall(TaoGetConvergedReason(_tao, &_reason));
     593          71 : }
     594             : 
     595             : 
     596             : template <typename T>
     597         129 : void TaoOptimizationSolver<T>::get_dual_variables()
     598             : {
     599           0 :   LOG_SCOPE("get_dual_variables()", "TaoOptimizationSolver");
     600             : 
     601             :   PetscVector<T> * lambda_eq_petsc =
     602           0 :     cast_ptr<PetscVector<T> *>(this->system().lambda_eq.get());
     603             :   PetscVector<T> * lambda_ineq_petsc =
     604           0 :     cast_ptr<PetscVector<T> *>(this->system().lambda_ineq.get());
     605             : 
     606         129 :   Vec lambda_eq_petsc_vec = lambda_eq_petsc->vec();
     607         129 :   Vec lambda_ineq_petsc_vec = lambda_ineq_petsc->vec();
     608             : 
     609         129 :   LibmeshPetscCall(TaoGetDualVariables(_tao,
     610             :                                        &lambda_eq_petsc_vec,
     611             :                                        &lambda_ineq_petsc_vec));
     612         129 : }
     613             : 
     614             : 
     615             : template <typename T>
     616          71 : void TaoOptimizationSolver<T>::print_converged_reason()
     617             : {
     618           2 :   libMesh::out << "Tao optimization solver convergence/divergence reason: "
     619          71 :                << TaoConvergedReasons[this->get_converged_reason()] << std::endl;
     620          71 : }
     621             : 
     622             : 
     623             : 
     624             : template <typename T>
     625          72 : int TaoOptimizationSolver<T>::get_converged_reason()
     626             : {
     627          72 :   if (this->initialized())
     628          72 :     LibmeshPetscCall(TaoGetConvergedReason(_tao, &_reason));
     629             : 
     630          72 :   return static_cast<int>(_reason);
     631             : }
     632             : 
     633             : 
     634             : //------------------------------------------------------------------
     635             : // Explicit instantiations
     636             : template class LIBMESH_EXPORT TaoOptimizationSolver<Number>;
     637             : 
     638             : } // namespace libMesh
     639             : 
     640             : 
     641             : 
     642             : #endif // #if defined(LIBMESH_HAVE_PETSC_TAO) && !defined(LIBMESH_USE_COMPLEX_NUMBERS)

Generated by: LCOV version 1.14