LCOV - code coverage report
Current view: top level - solvers - NonlinearSystem.cxx (source / functions) Coverage Total Hit
Test: coverage.info Lines: 83.8 % 111 93
Test Date: 2025-06-29 01:25:44 Functions: 87.5 % 16 14

            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              : 
      27              : #include "neml2/solvers/NonlinearSystem.h"
      28              : #include "neml2/misc/assertions.h"
      29              : #include "neml2/tensors/functions/bmm.h"
      30              : #include "neml2/tensors/functions/diag_embed.h"
      31              : 
      32              : namespace neml2
      33              : {
      34              : bool &
      35         8426 : currently_solving_nonlinear_system()
      36              : {
      37              :   thread_local bool _solving_nl_sys = false;
      38         8426 :   return _solving_nl_sys;
      39              : }
      40              : 
      41          197 : SolvingNonlinearSystem::SolvingNonlinearSystem(bool solving)
      42          197 :   : prev_bool(currently_solving_nonlinear_system())
      43              : {
      44          197 :   currently_solving_nonlinear_system() = solving;
      45          197 : }
      46              : 
      47          197 : SolvingNonlinearSystem::~SolvingNonlinearSystem()
      48              : {
      49          197 :   currently_solving_nonlinear_system() = prev_bool;
      50          197 : }
      51              : 
      52              : OptionSet
      53          476 : NonlinearSystem::expected_options()
      54              : {
      55          476 :   OptionSet options;
      56              : 
      57          952 :   options.set<bool>("automatic_scaling") = false;
      58         1428 :   options.set("automatic_scaling").doc() =
      59              :       "Whether to perform automatic scaling. See neml2::NonlinearSystem::init_scaling for "
      60          476 :       "implementation details.";
      61              : 
      62          952 :   options.set<double>("automatic_scaling_tol") = 0.01;
      63         1428 :   options.set("automatic_scaling_tol").doc() =
      64          476 :       "Tolerance used in iteratively updating the scaling matrices.";
      65              : 
      66          952 :   options.set<unsigned int>("automatic_scaling_miter") = 20;
      67          952 :   options.set("automatic_scaling_miter").doc() =
      68              :       "Maximum number of automatic scaling iterations. No error is produced upon reaching the "
      69              :       "maximum number of scaling iterations, and the scaling matrices obtained at the last "
      70          476 :       "iteration are used to scale the nonlinear system.";
      71              : 
      72          476 :   return options;
      73            0 : }
      74              : 
      75              : void
      76          463 : NonlinearSystem::disable_automatic_scaling(OptionSet & options)
      77              : {
      78          926 :   options.set("automatic_scaling").suppressed() = true;
      79          926 :   options.set("automatic_scaling_tol").suppressed() = true;
      80          463 :   options.set("automatic_scaling_miter").suppressed() = true;
      81          463 : }
      82              : 
      83              : void
      84           12 : NonlinearSystem::enable_automatic_scaling(OptionSet & options)
      85              : {
      86           24 :   options.set("automatic_scaling").suppressed() = false;
      87           24 :   options.set("automatic_scaling_tol").suppressed() = false;
      88           12 :   options.set("automatic_scaling_miter").suppressed() = false;
      89           12 : }
      90              : 
      91          445 : NonlinearSystem::NonlinearSystem(const OptionSet & options)
      92          890 :   : _autoscale(options.get<bool>("automatic_scaling")),
      93          890 :     _autoscale_tol(options.get<double>("automatic_scaling_tol")),
      94         1335 :     _autoscale_miter(options.get<unsigned int>("automatic_scaling_miter"))
      95              : {
      96          445 : }
      97              : 
      98              : void
      99          193 : NonlinearSystem::init_scaling(const NonlinearSystem::Sol<false> & x, const bool verbose)
     100              : {
     101          193 :   if (!_autoscale)
     102          189 :     return;
     103              : 
     104            4 :   if (_scaling_matrices_initialized)
     105            0 :     return;
     106              : 
     107              :   // First compute the unscaled Jacobian
     108            4 :   auto J = Jacobian(x);
     109              : 
     110              :   // Initialize the scaling matrices
     111            4 :   auto Jp = J.clone();
     112            4 :   _row_scaling = Tensor::ones_like(x);
     113            4 :   _col_scaling = Tensor::ones_like(x);
     114              : 
     115            4 :   if (verbose)
     116            0 :     std::cout << "Before automatic scaling cond(J) = " << std::scientific
     117            0 :               << at::max(at::linalg_cond(Jp)).item<double>() << std::endl;
     118              : 
     119            4 :   const auto eps = machine_precision(x.scalar_type());
     120              : 
     121            8 :   for (unsigned int itr = 0; itr < _autoscale_miter; itr++)
     122              :   {
     123              :     // check for convergence
     124           16 :     auto rR = at::max(at::abs(1.0 - 1.0 / (at::sqrt(at::abs(std::get<0>(Jp.max(-1)))) + eps)))
     125            8 :                   .item<double>();
     126           16 :     auto rC = at::max(at::abs(1.0 - 1.0 / (at::sqrt(at::abs(std::get<0>(Jp.max(-2)))) + eps)))
     127            8 :                   .item<double>();
     128              : 
     129            8 :     if (verbose)
     130            0 :       std::cout << "ITERATION " << itr << ", ROW ILLNESS = " << std::scientific << rR
     131            0 :                 << ", COL ILLNESS = " << std::scientific << rC << std::endl;
     132            8 :     if (rR < _autoscale_tol && rC < _autoscale_tol)
     133            4 :       break;
     134              : 
     135              :     // scale rows and columns
     136           20 :     for (Size i = 0; i < x.base_size(-1); i++)
     137              :     {
     138           32 :       auto ar = 1.0 / (at::sqrt(at::max(at::abs(Jp.base_index({i})))) + eps);
     139           64 :       auto ac = 1.0 / (at::sqrt(at::max(at::abs(Jp.base_index({indexing::Slice(), i})))) + eps);
     140           32 :       _row_scaling.base_index({i}) *= ar;
     141           32 :       _col_scaling.base_index({i}) *= ac;
     142           32 :       Jp.base_index({i}) *= ar;
     143           64 :       Jp.base_index({indexing::Slice(), i}) *= ac;
     144           16 :     }
     145              :   }
     146              : 
     147            4 :   _scaling_matrices_initialized = true;
     148              : 
     149            4 :   if (verbose)
     150            0 :     std::cout << " After automatic scaling cond(J) = " << std::scientific
     151            0 :               << at::max(at::linalg_cond(Jp)).item<double>() << std::endl;
     152          132 : }
     153              : 
     154              : void
     155           98 : NonlinearSystem::ensure_scaling_matrices_initialized_dbg() const
     156              : {
     157           98 :   neml_assert_dbg(
     158           98 :       _autoscale == _scaling_matrices_initialized,
     159           98 :       _autoscale ? "Automatic scaling is requested but scaling matrices have not been initialized."
     160              :                  : "Automatic scaling is not requested but scaling matrices were initialized.");
     161           98 : }
     162              : 
     163              : NonlinearSystem::Res<true>
     164         1728 : NonlinearSystem::scale(const NonlinearSystem::Res<false> & r) const
     165              : {
     166         1728 :   if (!_autoscale)
     167         1693 :     return Res<true>(r);
     168              : 
     169           35 :   ensure_scaling_matrices_initialized_dbg();
     170           35 :   return Res<true>(_row_scaling * r);
     171              : }
     172              : 
     173              : NonlinearSystem::Res<false>
     174            0 : NonlinearSystem::unscale(const NonlinearSystem::Res<true> & r) const
     175              : {
     176            0 :   if (!_autoscale)
     177            0 :     return Res<false>(r);
     178              : 
     179            0 :   ensure_scaling_matrices_initialized_dbg();
     180            0 :   return Res<false>(1. / _row_scaling * r);
     181              : }
     182              : 
     183              : NonlinearSystem::Jac<true>
     184         1348 : NonlinearSystem::scale(const NonlinearSystem::Jac<false> & J) const
     185              : {
     186         1348 :   if (!_autoscale)
     187         1328 :     return Jac<true>(J);
     188              : 
     189           20 :   ensure_scaling_matrices_initialized_dbg();
     190           20 :   return Jac<true>(bmm(bmm(base_diag_embed(_row_scaling), J), base_diag_embed(_col_scaling)));
     191              : }
     192              : 
     193              : NonlinearSystem::Jac<false>
     194            0 : NonlinearSystem::unscale(const NonlinearSystem::Jac<true> & J) const
     195              : {
     196            0 :   if (!_autoscale)
     197            0 :     return Jac<false>(J);
     198              : 
     199            0 :   ensure_scaling_matrices_initialized_dbg();
     200              :   return Jac<false>(
     201            0 :       bmm(bmm(base_diag_embed(1.0 / _row_scaling), J), base_diag_embed(1.0 / _col_scaling)));
     202              : }
     203              : 
     204              : NonlinearSystem::Sol<true>
     205          217 : NonlinearSystem::scale(const NonlinearSystem::Sol<false> & u) const
     206              : {
     207          217 :   if (!_autoscale)
     208          213 :     return Sol<true>(u);
     209              : 
     210            4 :   ensure_scaling_matrices_initialized_dbg();
     211            4 :   return Sol<true>(1. / _col_scaling * u);
     212              : }
     213              : 
     214              : NonlinearSystem::Sol<false>
     215         1945 : NonlinearSystem::unscale(const NonlinearSystem::Sol<true> & u) const
     216              : {
     217         1945 :   if (!_autoscale)
     218         1906 :     return Sol<false>(u);
     219              : 
     220           39 :   ensure_scaling_matrices_initialized_dbg();
     221           39 :   return Sol<false>(_col_scaling * u);
     222              : }
     223              : 
     224              : void
     225         1729 : NonlinearSystem::set_guess(const NonlinearSystem::Sol<true> & x)
     226              : {
     227         1729 :   set_guess(unscale(x));
     228         1729 : }
     229              : } // namespace neml2
        

Generated by: LCOV version 2.0-1