LCOV - code coverage report
Current view: top level - models - SR2Invariant.cxx (source / functions) Coverage Total Hit
Test: coverage.info Lines: 92.6 % 81 75
Test Date: 2025-06-29 01:25:44 Functions: 100.0 % 3 3

            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 "neml2/models/SR2Invariant.h"
      26              : #include "neml2/tensors/Scalar.h"
      27              : #include "neml2/tensors/SR2.h"
      28              : #include "neml2/tensors/SSR4.h"
      29              : #include "neml2/base/EnumSelection.h"
      30              : 
      31              : namespace neml2
      32              : {
      33              : register_NEML2_object(SR2Invariant);
      34              : 
      35              : OptionSet
      36            2 : SR2Invariant::expected_options()
      37              : {
      38            2 :   OptionSet options = Model::expected_options();
      39            2 :   options.doc() = "Calculate the invariant of a symmetric second order tensor (of type SR2).";
      40              : 
      41            4 :   options.set<bool>("define_second_derivatives") = true;
      42              : 
      43            4 :   options.set_input("tensor");
      44            4 :   options.set("tensor").doc() = "SR2 which is used to calculate the invariant of";
      45              : 
      46            4 :   options.set_output("invariant");
      47            4 :   options.set("invariant").doc() = "Invariant";
      48              : 
      49              :   EnumSelection type_selection({"I1", "I2", "VONMISES", "EFFECTIVE_STRAIN", "INVALID"},
      50              :                                {static_cast<int>(SR2Invariant::IType::I1),
      51              :                                 static_cast<int>(SR2Invariant::IType::I2),
      52              :                                 static_cast<int>(SR2Invariant::IType::VONMISES),
      53              :                                 static_cast<int>(SR2Invariant::IType::EFFECTIVE_STRAIN),
      54              :                                 static_cast<int>(SR2Invariant::IType::INVALID)},
      55           12 :                                "INVALID");
      56            2 :   options.set<EnumSelection>("invariant_type") = type_selection;
      57            4 :   options.set("invariant_type").doc() =
      58            6 :       "Type of invariant. Options are: " + type_selection.candidates_str();
      59              : 
      60            4 :   return options;
      61            2 : }
      62              : 
      63           21 : SR2Invariant::SR2Invariant(const OptionSet & options)
      64              :   : Model(options),
      65           21 :     _type(options.get<EnumSelection>("invariant_type").as<IType>()),
      66           21 :     _A(declare_input_variable<SR2>("tensor")),
      67           42 :     _invariant(declare_output_variable<Scalar>("invariant"))
      68              : {
      69           21 : }
      70              : 
      71              : void
      72           52 : SR2Invariant::set_value(bool out, bool dout_din, bool d2out_din2)
      73              : {
      74           52 :   auto A = SR2(_A);
      75              : 
      76           52 :   if (_type == IType::I1)
      77              :   {
      78            8 :     if (out)
      79            6 :       _invariant = A.tr();
      80              : 
      81            8 :     if (!_A.is_dependent())
      82            0 :       return;
      83              : 
      84            8 :     if (dout_din)
      85            4 :       _invariant.d(_A) = SR2::identity(_A.options());
      86              : 
      87              :     if (d2out_din2)
      88              :     {
      89              :       // zero
      90              :     }
      91              :   }
      92           44 :   else if (_type == IType::I2)
      93              :   {
      94            3 :     if (out)
      95            1 :       _invariant = (A.tr() * A.tr() - A.inner(A)) / 2.0;
      96              : 
      97            3 :     if (!_A.is_dependent())
      98            0 :       return;
      99              : 
     100            3 :     if (dout_din || d2out_din2)
     101              :     {
     102            2 :       auto I2 = SR2::identity(_A.options());
     103              : 
     104            2 :       if (dout_din)
     105            1 :         _invariant.d(_A) = A.tr() * I2 - A;
     106              : 
     107            2 :       if (d2out_din2)
     108              :       {
     109            1 :         auto I2xI2 = SSR4::identity(_A.options());
     110            1 :         auto I4sym = SSR4::identity_sym(_A.options());
     111            1 :         _invariant.d(_A, _A) = I2xI2 - I4sym;
     112            1 :       }
     113            2 :     }
     114              :   }
     115           41 :   else if (_type == IType::VONMISES)
     116              :   {
     117           38 :     const auto eps = machine_precision(A.scalar_type());
     118           38 :     auto S = A.dev();
     119           38 :     Scalar vm = std::sqrt(3.0 / 2.0) * S.norm(eps);
     120              : 
     121           38 :     if (out)
     122           36 :       _invariant = vm;
     123              : 
     124           38 :     if (!_A.is_dependent())
     125            0 :       return;
     126              : 
     127           38 :     if (dout_din || d2out_din2)
     128              :     {
     129           27 :       auto dvm_dA = 3.0 / 2.0 * S / vm;
     130              : 
     131           27 :       if (dout_din)
     132           26 :         _invariant.d(_A) = dvm_dA;
     133              : 
     134           27 :       if (d2out_din2)
     135              :       {
     136           12 :         auto I = SSR4::identity_sym(_A.options());
     137           12 :         auto J = SSR4::identity_dev(_A.options());
     138           12 :         _invariant.d(_A, _A) = 3.0 / 2.0 * (I - 2.0 / 3.0 * dvm_dA.outer(dvm_dA)) * J / vm;
     139           12 :       }
     140           27 :     }
     141           38 :   }
     142            3 :   else if (_type == IType::EFFECTIVE_STRAIN)
     143              :   {
     144            3 :     const auto eps = machine_precision(A.scalar_type());
     145            3 :     Scalar r = std::sqrt(2.0 / 3.0) * A.norm(eps);
     146              : 
     147            3 :     if (out)
     148            1 :       _invariant = r;
     149              : 
     150            3 :     if (!_A.is_dependent())
     151            0 :       return;
     152              : 
     153            3 :     if (dout_din || d2out_din2)
     154              :     {
     155            2 :       auto d = 2.0 / 3.0 * A / r;
     156              : 
     157            2 :       if (dout_din)
     158            1 :         _invariant.d(_A) = 2.0 / 3.0 * A / r;
     159              : 
     160            2 :       if (d2out_din2)
     161            2 :         _invariant.d(_A, _A) =
     162            3 :             2.0 / 3.0 * (SSR4::identity_sym(_A.options()) - 3.0 / 2.0 * d.outer(d)) / r;
     163            2 :     }
     164            3 :   }
     165              :   else
     166            0 :     throw NEMLException("Unsupported invariant type: " +
     167            0 :                         std::string(input_options().get<EnumSelection>("invariant_type")));
     168           52 : }
     169              : } // namespace neml2
        

Generated by: LCOV version 2.0-1