LCOV - code coverage report
Current view: top level - solvers - NewtonWithLineSearch.cxx (source / functions) Coverage Total Hit
Test: coverage.info Lines: 85.7 % 63 54
Test Date: 2025-10-02 16:03:03 Functions: 100.0 % 4 4

            Line data    Source code
       1              : // Copyright 2024, UChicago Argonne, LLC
       2              : // All Rights Reserved
       3              : // Software Name: NEML2 -- the New Engineering material Model Library, version 2
       4              : // By: Argonne National Laboratory
       5              : // OPEN SOURCE LICENSE (MIT)
       6              : //
       7              : // Permission is hereby granted, free of charge, to any person obtaining a copy
       8              : // of this software and associated documentation files (the "Software"), to deal
       9              : // in the Software without restriction, including without limitation the rights
      10              : // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      11              : // copies of the Software, and to permit persons to whom the Software is
      12              : // furnished to do so, subject to the following conditions:
      13              : //
      14              : // The above copyright notice and this permission notice shall be included in
      15              : // all copies or substantial portions of the Software.
      16              : //
      17              : // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      18              : // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      19              : // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      20              : // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      21              : // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      22              : // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      23              : // THE SOFTWARE.
      24              : 
      25              : #include <iostream>
      26              : #include <iomanip>
      27              : 
      28              : #include "neml2/solvers/NewtonWithLineSearch.h"
      29              : #include "neml2/tensors/functions/bvv.h"
      30              : #include "neml2/tensors/functions/sqrt.h"
      31              : #include "neml2/tensors/assertions.h"
      32              : 
      33              : namespace neml2
      34              : {
      35              : register_NEML2_object(NewtonWithLineSearch);
      36              : 
      37              : OptionSet
      38            5 : NewtonWithLineSearch::expected_options()
      39              : {
      40            5 :   OptionSet options = Newton::expected_options();
      41            5 :   options.doc() = "The Newton-Raphson solver with line search.";
      42              : 
      43           20 :   EnumSelection linesearch_type({"BACKTRACKING", "STRONG_WOLFE"}, "BACKTRACKING");
      44            5 :   options.set<EnumSelection>("linesearch_type") = linesearch_type;
      45           10 :   options.set("linesearch_type").doc() = "The type of linesearch used."
      46           10 :                                          "Default: BACKTRACKING. Options are " +
      47           15 :                                          linesearch_type.candidates_str();
      48              : 
      49           10 :   options.set<unsigned int>("max_linesearch_iterations") = 10;
      50           15 :   options.set("max_linesearch_iterations").doc() =
      51              :       "Maximum allowable linesearch iterations. No error is produced upon reaching the maximum "
      52            5 :       "number of iterations, and the scale factor in the last iteration is used to scale the step.";
      53              : 
      54           10 :   options.set<double>("linesearch_cutback") = 2.0;
      55           15 :   options.set("linesearch_cutback").doc() = "Linesearch cut-back factor when the current scale "
      56            5 :                                             "factor cannot sufficiently reduce the residual.";
      57              : 
      58           10 :   options.set<double>("linesearch_stopping_criteria") = 1.0e-3;
      59           15 :   options.set("linesearch_stopping_criteria").doc() =
      60            5 :       "The lineseach tolerance slightly relaxing the definition of residual decrease";
      61              : 
      62           10 :   options.set<bool>("check_negative_critertia_value") = false;
      63           10 :   options.set("check_negative_critertia_value").doc() =
      64            5 :       "Whether to check if the convergence criteria for line search becomes negative";
      65              : 
      66           10 :   return options;
      67            5 : }
      68              : 
      69            4 : NewtonWithLineSearch::NewtonWithLineSearch(const OptionSet & options)
      70              :   : Newton(options),
      71            8 :     _linesearch_miter(options.get<unsigned int>("max_linesearch_iterations")),
      72            8 :     _linesearch_sigma(options.get<double>("linesearch_cutback")),
      73            8 :     _linesearch_c(options.get<double>("linesearch_stopping_criteria")),
      74            8 :     _type(options.get<EnumSelection>("linesearch_type")),
      75            8 :     _check_crit(options.get<bool>("check_negative_critertia_value"))
      76              : {
      77            4 : }
      78              : 
      79              : void
      80           79 : NewtonWithLineSearch::update(NonlinearSystem & system,
      81              :                              NonlinearSystem::Sol<true> & x,
      82              :                              const NonlinearSystem::Res<true> & r,
      83              :                              const NonlinearSystem::Jac<true> & J)
      84              : {
      85           79 :   auto dx = solve_direction(r, J);
      86           79 :   auto alpha = linesearch(system, x, dx, r);
      87           79 :   x = NonlinearSystem::Sol<true>(x.variable_data() + alpha * Tensor(dx));
      88           79 : }
      89              : 
      90              : Scalar
      91           79 : NewtonWithLineSearch::linesearch(NonlinearSystem & system,
      92              :                                  const NonlinearSystem::Sol<true> & x,
      93              :                                  const NonlinearSystem::Sol<true> & dx,
      94              :                                  const NonlinearSystem::Res<true> & R0) const
      95              : {
      96           79 :   auto alpha = Scalar::ones(x.batch_sizes(), x.options());
      97           79 :   const auto nR02 = bvv(R0, R0);
      98           79 :   auto crit = nR02;
      99              : 
     100          192 :   for (std::size_t i = 1; i < _linesearch_miter; i++)
     101              :   {
     102          173 :     NonlinearSystem::Sol<true> xp(Tensor(x) + alpha * Tensor(dx));
     103          173 :     auto R = system.residual(xp);
     104          173 :     auto nR2 = bvv(R, R);
     105              : 
     106          346 :     if (_type == "BACKTRACKING")
     107          173 :       crit = nR02 + 2.0 * _linesearch_c * alpha * bvv(R0, dx);
     108            0 :     else if (_type == "STRONG_WOLFE")
     109            0 :       crit = (1.0 - _linesearch_c * alpha) * nR02;
     110              : 
     111          173 :     if (verbose)
     112            0 :       std::cout << "     LS ITERATION " << std::setw(3) << i << ", min(alpha) = " << std::scientific
     113            0 :                 << at::min(alpha).item<double>() << ", max(||R||) = " << std::scientific
     114            0 :                 << at::max(sqrt(nR2)).item<double>() << ", min(||Rc||) = " << std::scientific
     115            0 :                 << at::min(sqrt(crit)).item<double>() << std::endl;
     116              : 
     117          173 :     auto stop = at::logical_or(nR2 <= crit, nR2 <= std::pow(atol, 2));
     118              : 
     119          173 :     if (at::all(stop).item<bool>())
     120           60 :       break;
     121              : 
     122          226 :     alpha.batch_index_put_({at::logical_not(stop)},
     123          452 :                            alpha.batch_index({at::logical_not(stop)}) / _linesearch_sigma);
     124          353 :   }
     125              : 
     126           79 :   if (_check_crit)
     127            0 :     if (at::max(crit).item<double>() < 0)
     128              :       std::cerr << "WARNING: Line Search produces negative stopping "
     129              :                    "criteria, this could lead to convergence issue. Try with other "
     130              :                    "linesearch_type, increase linesearch_cutback "
     131            0 :                    "or reduce linesearch_stopping_criteria"
     132            0 :                 << std::endl;
     133              : 
     134          158 :   return alpha;
     135          305 : }
     136              : 
     137              : } // namespace neml2
        

Generated by: LCOV version 2.0-1