LCOV - code coverage report
Current view: top level - src/materials - CauchyStressFromNEML.C (source / functions) Hit Total Coverage
Test: idaholab/blackbear: 75f23c Lines: 97 106 91.5 %
Date: 2025-07-17 04:05:57 Functions: 8 8 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /****************************************************************/
       2             : /*               DO NOT MODIFY THIS HEADER                      */
       3             : /*                       BlackBear                              */
       4             : /*                                                              */
       5             : /*           (c) 2017 Battelle Energy Alliance, LLC             */
       6             : /*                   ALL RIGHTS RESERVED                        */
       7             : /*                                                              */
       8             : /*          Prepared by Battelle Energy Alliance, LLC           */
       9             : /*            Under Contract No. DE-AC07-05ID14517              */
      10             : /*            With the U. S. Department of Energy               */
      11             : /*                                                              */
      12             : /*            See COPYRIGHT for full restrictions               */
      13             : /****************************************************************/
      14             : 
      15             : #ifdef NEML_ENABLED
      16             : 
      17             : #include "CauchyStressFromNEML.h"
      18             : 
      19             : #include "NEMLStressBase.h"
      20             : 
      21             : registerMooseObject("BlackBearApp", CauchyStressFromNEML);
      22             : 
      23             : InputParameters
      24        1174 : CauchyStressFromNEML::validParams()
      25             : {
      26        1174 :   InputParameters params = ComputeLagrangianStressCauchy::validParams();
      27             : 
      28        2348 :   params.addRequiredParam<FileName>("database", "Path to NEML XML database.");
      29        2348 :   params.addRequiredParam<std::string>("model", "Model name in NEML database.");
      30        2348 :   params.addCoupledVar("temperature", 0.0, "Coupled temperature");
      31             : 
      32        1174 :   return params;
      33           0 : }
      34             : 
      35         900 : CauchyStressFromNEML::CauchyStressFromNEML(const InputParameters & parameters)
      36             :   : ComputeLagrangianStressCauchy(parameters),
      37        1800 :     _fname(getParam<FileName>("database")),
      38        1800 :     _mname(getParam<std::string>("model")),
      39         900 :     _temperature(coupledValue("temperature")),
      40         900 :     _temperature_old(coupledValueOld("temperature")),
      41         900 :     _history(declareProperty<std::vector<Real>>(_base_name + "history")),
      42        1800 :     _history_old(getMaterialPropertyOld<std::vector<Real>>(_base_name + "history")),
      43         900 :     _energy(declareProperty<Real>(_base_name + "energy")),
      44        1800 :     _energy_old(getMaterialPropertyOld<Real>(_base_name + "energy")),
      45         900 :     _dissipation(declareProperty<Real>(_base_name + "dissipation")),
      46         900 :     _dissipation_old(declareProperty<Real>(_base_name + "dissipation_old")),
      47         900 :     _linear_rotation(declareProperty<RankTwoTensor>(_base_name + "linear_rotation")),
      48        1800 :     _linear_rotation_old(getMaterialPropertyOld<RankTwoTensor>(_base_name + "linear_rotation")),
      49        1800 :     _cauchy_stress_old(getMaterialPropertyOld<RankTwoTensor>(_base_name + "cauchy_stress")),
      50        1800 :     _mechanical_strain(getMaterialProperty<RankTwoTensor>(_base_name + "mechanical_strain")),
      51        1800 :     _mechanical_strain_old(getMaterialPropertyOld<RankTwoTensor>(_base_name + "mechanical_strain")),
      52         900 :     _inelastic_strain(declareProperty<RankTwoTensor>(_base_name + "inelastic_strain")),
      53         900 :     _elastic_strain(declareProperty<RankTwoTensor>(_base_name + "elastic_strain")),
      54        2700 :     _dissipation_rate(declareProperty<Real>(_base_name + "dissipation_rate"))
      55             : {
      56             :   // Check that the file is readable
      57         900 :   MooseUtils::checkFileReadable(_fname);
      58             : 
      59             :   // Will throw an exception if it doesn't succeed
      60             :   try
      61             :   {
      62        2700 :     _model = neml::parse_xml_unique(_fname, _mname);
      63             :   }
      64           0 :   catch (const neml::NEMLError & e)
      65             :   {
      66           0 :     paramError("Unable to load NEML model " + _mname + " from file " + _fname);
      67           0 :   }
      68         900 : }
      69             : 
      70             : void
      71         280 : CauchyStressFromNEML::reset_state(const std::vector<unsigned int> & indices, unsigned int qp)
      72             : {
      73             :   // Guard from zero, just for MOOSE...
      74         280 :   if (_model->nstore() == 0)
      75           0 :     return;
      76             : 
      77             :   // Form a NEML history object with the initial state
      78         280 :   std::vector<Real> init(_model->nstore(), 0);
      79         280 :   _model->init_store(&init.front());
      80             : 
      81             :   // Reset!
      82         560 :   for (auto i : indices)
      83         280 :     _history[qp][i] = init[i];
      84             : }
      85             : 
      86             : std::vector<unsigned int>
      87          14 : CauchyStressFromNEML::provide_indices(const std::vector<std::string> & to_reset)
      88             : {
      89             :   std::vector<unsigned int> indices;
      90             : 
      91             :   // Grab the state names...
      92          14 :   auto names = _model->report_internal_variable_names();
      93             : 
      94             :   // Iterate through names resetting each if found,
      95             :   // raise an error if you don't find it
      96          28 :   for (auto name : to_reset)
      97             :   {
      98          14 :     auto loc = std::find(names.begin(), names.end(), name);
      99          14 :     if (loc == names.end())
     100           0 :       mooseError("One of the state variables in the list "
     101             :                  "requested for resetting does not exist "
     102             :                  "in the NEML material model");
     103          14 :     unsigned int i = loc - names.begin();
     104          14 :     indices.push_back(i);
     105             :   }
     106             : 
     107          14 :   return indices;
     108          14 : }
     109             : 
     110             : void
     111     4041681 : CauchyStressFromNEML::computeQpCauchyStress()
     112             : {
     113             :   // Setup all the Mandel notation things we need
     114             :   double s_np1[6];
     115             :   double s_n[6];
     116     4041681 :   NEMLStressBase::rankTwoTensorToNeml(_cauchy_stress_old[_qp], s_n);
     117             : 
     118             :   // Strain
     119             :   double e_np1[6];
     120     4041681 :   NEMLStressBase::rankTwoTensorToNeml(_mechanical_strain[_qp], e_np1);
     121             :   double e_n[6];
     122     4041681 :   NEMLStressBase::rankTwoTensorToNeml(_mechanical_strain_old[_qp], e_n);
     123             : 
     124             :   // Vorticity
     125     4041681 :   RankTwoTensor L;
     126     4041681 :   if (_large_kinematics)
     127             :   {
     128     1461176 :     L = RankTwoTensor::Identity() - _inv_df[_qp];
     129             :   }
     130             :   else
     131             :   {
     132             :     L.zero();
     133             :   }
     134     4041681 :   _linear_rotation[_qp] = _linear_rotation_old[_qp] + (L - L.transpose()) / 2.0;
     135             : 
     136             :   double w_np1[3];
     137     4041681 :   rankTwoSkewToNEML(_linear_rotation[_qp], w_np1);
     138             :   double w_n[3];
     139     4041681 :   rankTwoSkewToNEML(_linear_rotation_old[_qp], w_n);
     140             : 
     141             :   // Time
     142     4041681 :   double t_np1 = _t;
     143     4041681 :   double t_n = _t - _dt;
     144             : 
     145             :   // Temperature
     146     4041681 :   double T_np1 = _temperature[_qp];
     147     4041681 :   double T_n = _temperature_old[_qp];
     148             : 
     149             :   // Internal state
     150             :   double * h_np1;
     151             :   const double * h_n;
     152             : 
     153             :   // Just to keep MOOSE debug happy
     154     4041681 :   if (_model->nstore() > 0)
     155             :   {
     156     4041681 :     h_np1 = &(_history[_qp][0]);
     157     4041681 :     h_n = &(_history_old[_qp][0]);
     158             :   }
     159             :   else
     160             :   {
     161             :     h_np1 = nullptr;
     162             :     h_n = nullptr;
     163             :   }
     164             : 
     165             :   // Energy
     166             :   double u_np1;
     167     4041681 :   double u_n = _energy_old[_qp];
     168             : 
     169             :   // Dissipation
     170             :   double p_np1;
     171     4041681 :   double p_n = _dissipation_old[_qp];
     172             : 
     173             :   // Tangent
     174             :   double A_np1[36];
     175             :   double B_np1[18];
     176             : 
     177             :   try
     178             :   {
     179             :     // Call NEML!
     180     4041681 :     if (_large_kinematics)
     181             :     {
     182     1461176 :       _model->update_ld_inc(e_np1,
     183             :                             e_n,
     184             :                             w_np1,
     185             :                             w_n,
     186             :                             T_np1,
     187             :                             T_n,
     188             :                             t_np1,
     189             :                             t_n,
     190             :                             s_np1,
     191             :                             s_n,
     192             :                             h_np1,
     193             :                             h_n,
     194             :                             A_np1,
     195             :                             B_np1,
     196             :                             u_np1,
     197             :                             u_n,
     198             :                             p_np1,
     199             :                             p_n);
     200             :     }
     201             :     else
     202             :     {
     203     2580505 :       _model->update_sd(e_np1,
     204             :                         e_n,
     205             :                         T_np1,
     206             :                         T_n,
     207             :                         t_np1,
     208             :                         t_n,
     209             :                         s_np1,
     210             :                         s_n,
     211             :                         h_np1,
     212             :                         h_n,
     213             :                         A_np1,
     214             :                         u_np1,
     215             :                         u_n,
     216             :                         p_np1,
     217             :                         p_n);
     218             :       std::fill(B_np1, B_np1 + 18, 0.0);
     219             :     }
     220             : 
     221             :     double estrain[6];
     222     4041636 :     _model->elastic_strains(s_np1, T_np1, h_np1, estrain);
     223             : 
     224             :     // Translate back from Mandel notation
     225     4041636 :     NEMLStressBase::nemlToRankTwoTensor(s_np1, _cauchy_stress[_qp]);
     226     4041636 :     recombineTangentNEML(A_np1, B_np1, _cauchy_jacobian[_qp]);
     227     4041636 :     _energy[_qp] = u_np1;
     228     4041636 :     _dissipation[_qp] = p_np1;
     229     4041636 :     _dissipation_rate[_qp] = (p_np1 - p_n) / (t_np1 - t_n);
     230             : 
     231     4041636 :     NEMLStressBase::nemlToRankTwoTensor(estrain, _elastic_strain[_qp]);
     232     4041636 :     _inelastic_strain[_qp] = _mechanical_strain[_qp] - _elastic_strain[_qp];
     233             :   }
     234          45 :   catch (const neml::NEMLError & e)
     235             :   {
     236          90 :     throw MooseException("NEML error: " + e.message());
     237          45 :   }
     238     4041636 : }
     239             : 
     240             : void
     241       20984 : CauchyStressFromNEML::initQpStatefulProperties()
     242             : {
     243       20984 :   ComputeLagrangianStressCauchy::initQpStatefulProperties();
     244             : 
     245       20984 :   _history[_qp].resize(_model->nstore());
     246             :   try
     247             :   {
     248             :     // This is only needed because MOOSE whines about zero sized vectors
     249             :     // that are not initialized
     250       20984 :     if (_history[_qp].size() > 0)
     251       20984 :       _model->init_store(&_history[_qp].front());
     252             :   }
     253           0 :   catch (const neml::NEMLError & e)
     254             :   {
     255           0 :     throw MooseException("NEML error: " + e.message());
     256           0 :   }
     257             : 
     258       20984 :   _linear_rotation[_qp].zero();
     259             : 
     260       20984 :   _energy[_qp] = 0.0;
     261       20984 :   _dissipation[_qp] = 0.0;
     262       20984 :   _dissipation_rate[_qp] = 0.0;
     263       20984 : }
     264             : 
     265             : void
     266     8083362 : rankTwoSkewToNEML(const RankTwoTensor & in, double * const out)
     267             : {
     268     8083362 :   out[0] = -in(1, 2);
     269     8083362 :   out[1] = in(0, 2);
     270     8083362 :   out[2] = -in(0, 1);
     271     8083362 : }
     272             : 
     273             : void
     274     4041636 : recombineTangentNEML(const double * const Dpart, const double * const Wpart, RankFourTensor & out)
     275             : {
     276     4041636 :   std::vector<double> data(81);
     277     4041636 :   neml::transform_fourth(Dpart, Wpart, &data[0]);
     278     4041636 :   out.fillFromInputVector(data, RankFourTensor::FillMethod::general);
     279     4041636 : }
     280             : 
     281             : #endif // NEML_ENABLED

Generated by: LCOV version 1.14