LCOV - code coverage report
Current view: top level - src/neml2/materials - CauchyStressFromNEML2.C (source / functions) Hit Total Coverage
Test: idaholab/moose tensor_mechanics: d6b47a Lines: 0 10 0.0 %
Date: 2024-02-27 11:53:14 Functions: 0 2 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //* This file is part of the MOOSE framework
       2             : //* https://www.mooseframework.org
       3             : //*
       4             : //* All rights reserved, see COPYRIGHT for full restrictions
       5             : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
       6             : //*
       7             : //* Licensed under LGPL 2.1, please see LICENSE for details
       8             : //* https://www.gnu.org/licenses/lgpl-2.1.html
       9             : 
      10             : #include "CauchyStressFromNEML2.h"
      11             : #include "NEML2Utils.h"
      12             : #include "NonlinearSystem.h"
      13             : #include "libmesh/nonlinear_solver.h"
      14             : 
      15             : InputParameters
      16           0 : CauchyStressFromNEML2::validParams()
      17             : {
      18             :   InputParameters params =
      19           0 :       NEML2SolidMechanicsInterface<ComputeLagrangianObjectiveStress>::validParams();
      20           0 :   NEML2Utils::addClassDescription(
      21             :       params, "Perform the objective stress update using a NEML2 material model");
      22           0 :   params.addCoupledVar("temperature", "Coupled temperature");
      23           0 :   return params;
      24           0 : }
      25             : 
      26             : #ifndef NEML2_ENABLED
      27           0 : CauchyStressFromNEML2::CauchyStressFromNEML2(const InputParameters & parameters)
      28           0 :   : NEML2SolidMechanicsInterface<ComputeLagrangianObjectiveStress>(parameters)
      29             : {
      30           0 :   NEML2Utils::libraryNotEnabledError(parameters);
      31           0 : }
      32             : #endif
      33             : 
      34             : registerMooseObject("TensorMechanicsApp", CauchyStressFromNEML2);
      35             : 
      36             : #ifdef NEML2_ENABLED
      37             : 
      38             : CauchyStressFromNEML2::CauchyStressFromNEML2(const InputParameters & parameters)
      39             :   : NEML2SolidMechanicsInterface<ComputeLagrangianObjectiveStress>(parameters),
      40             :     // Inputs to the constitutive model
      41             :     _mechanical_strain_old(nullptr),
      42             :     _temperature(nullptr),
      43             :     _temperature_old(nullptr)
      44             : {
      45             :   validateModel();
      46             : 
      47             :   // Get the old mechanical strain if the NEML2 model need it
      48             :   _mechanical_strain_old =
      49             :       model().input().has_variable(strainOld())
      50             :           ? &getMaterialPropertyOld<RankTwoTensor>(_base_name + "mechanical_strain")
      51             :           : nullptr;
      52             : 
      53             :   // Get the temperature if the NEML2 model need it
      54             :   _temperature =
      55             :       model().input().has_variable(temperature()) ? &coupledValue("temperature") : nullptr;
      56             : 
      57             :   // Get the old temperature if the NEML2 model need it
      58             :   _temperature =
      59             :       model().input().has_variable(temperatureOld()) ? &coupledValueOld("temperature") : nullptr;
      60             : 
      61             :   // Find the stateful state variables.
      62             :   // A state variable is said to be stateful if it exists on the input's old_state axis as well as
      63             :   // on the output's state axis.
      64             :   if (model().input().has_subaxis("old_state"))
      65             :     for (auto var : model().input().subaxis("old_state").variable_accessors(/*recursive=*/true))
      66             :     {
      67             :       _state_vars[var.on("state")] = &declareProperty<std::vector<Real>>(Moose::stringify(var));
      68             :       _state_vars_old[var.on("old_state")] =
      69             :           &getMaterialPropertyOld<std::vector<Real>>(Moose::stringify(var));
      70             :     }
      71             : }
      72             : 
      73             : void
      74             : CauchyStressFromNEML2::initialSetup()
      75             : {
      76             :   auto solver = _fe_problem.getNonlinearSystem(/*nl_sys_num=*/0).nonlinearSolver();
      77             :   if (solver->residual_object || solver->jacobian || !solver->residual_and_jacobian_object)
      78             :     mooseWarning("NEML2 material models are designed to be used together with "
      79             :                  "residual_and_jacobian_together = true.");
      80             : }
      81             : 
      82             : void
      83             : CauchyStressFromNEML2::initQpStatefulProperties()
      84             : {
      85             :   ComputeLagrangianObjectiveStress::initQpStatefulProperties();
      86             : 
      87             :   // TODO: provide a mechanism to initialize the internal variables to non-zeros
      88             :   for (auto && [var, prop] : _state_vars)
      89             :     (*prop)[_qp] = std::vector<Real>(model().output().storage_size(var), 0);
      90             : }
      91             : 
      92             : void
      93             : CauchyStressFromNEML2::computeProperties()
      94             : {
      95             :   try
      96             :   {
      97             :     // Allocate input
      98             :     _in = neml2::LabeledVector::zeros(_qrule->n_points(), {&model().input()});
      99             : 
     100             :     advanceStep();
     101             : 
     102             :     updateForces();
     103             : 
     104             :     if (model().implicit())
     105             :       applyPredictor();
     106             : 
     107             :     solve();
     108             :   }
     109             :   catch (neml2::NEMLException & e)
     110             :   {
     111             :     mooseException("An error occurred during the evaluation of a NEML2 model:\n",
     112             :                    e.what(),
     113             :                    NEML2Utils::NEML2_help_message);
     114             :   }
     115             :   catch (std::runtime_error & e)
     116             :   {
     117             :     mooseException("An unknown error occurred during the evaluation of a NEML2 model:\n",
     118             :                    e.what(),
     119             :                    "\nIt is possible that this error is related to NEML2.",
     120             :                    NEML2Utils::NEML2_help_message);
     121             :   }
     122             : 
     123             :   ComputeLagrangianObjectiveStress::computeProperties();
     124             : }
     125             : 
     126             : void
     127             : CauchyStressFromNEML2::computeQpSmallStress()
     128             : {
     129             :   neml2::TorchSize qp = _qp;
     130             : 
     131             :   // Set the results into the corresponding MOOSE material properties
     132             :   _small_stress[_qp] =
     133             :       NEML2Utils::toMOOSE<SymmetricRankTwoTensor>(_out(stress()).batch_index({qp}));
     134             : 
     135             :   _small_jacobian[_qp] = RankFourTensor(NEML2Utils::toMOOSE<SymmetricRankFourTensor>(
     136             :       _dout_din(stress(), strain()).batch_index({qp})));
     137             : 
     138             :   for (auto && [var, prop] : _state_vars)
     139             :     (*prop)[_qp] = NEML2Utils::toMOOSE<std::vector<Real>>(_out(var).batch_index({qp}));
     140             : }
     141             : 
     142             : void
     143             : CauchyStressFromNEML2::advanceStep()
     144             : {
     145             :   // Set old state variables
     146             :   for (auto && [var, prop] : _state_vars_old)
     147             :     NEML2Utils::setBatched(_in, {var}, prop);
     148             : 
     149             :   // Set old forces
     150             :   NEML2Utils::setBatched(
     151             :       // The input LabeledVector
     152             :       _in,
     153             :       // NEML2 variable accessors
     154             :       {strainOld(), temperatureOld()},
     155             :       // Pointer to the batched data
     156             :       _mechanical_strain_old,
     157             :       _temperature_old);
     158             : 
     159             :   // TransientInterface doesn't provide _t_old...
     160             :   auto t_old = _t - _dt;
     161             :   NEML2Utils::set(
     162             :       // The input LabeledVector
     163             :       _in,
     164             :       // NEML2 variable accessors
     165             :       {timeOld()},
     166             :       // Pointer to the unbatched data
     167             :       model().input().has_variable(timeOld()) ? &t_old : nullptr);
     168             : }
     169             : 
     170             : void
     171             : CauchyStressFromNEML2::updateForces()
     172             : {
     173             :   NEML2Utils::setBatched(
     174             :       // The input LabeledVector
     175             :       _in,
     176             :       // NEML2 variable accessors
     177             :       {strain(), temperature()},
     178             :       // Pointer to the batched data
     179             :       &_mechanical_strain,
     180             :       _temperature);
     181             : 
     182             :   NEML2Utils::set(
     183             :       // The input LabeledVector
     184             :       _in,
     185             :       // NEML2 variable accessors
     186             :       {time()},
     187             :       // Pointer to the unbatched data
     188             :       model().input().has_variable(time()) ? &_t : nullptr);
     189             : }
     190             : 
     191             : void
     192             : CauchyStressFromNEML2::applyPredictor()
     193             : {
     194             :   // Set trial state variables (i.e., initial guesses).
     195             :   // Right now we hard-code to use the old state as the trial state.
     196             :   // TODO: implement other predictors
     197             :   _in.slice("state").fill(_in.slice("old_state"));
     198             : }
     199             : 
     200             : void
     201             : CauchyStressFromNEML2::solve()
     202             : {
     203             :   // 1. Sync input onto the model's device
     204             :   // 2. Evaluate the NEML2 material model
     205             :   // 3. Sync output back onto CPU
     206             :   auto res = model().value_and_dvalue(_in.to(device()));
     207             :   _out = std::get<0>(res).to(torch::kCPU);
     208             :   _dout_din = std::get<1>(res).to(torch::kCPU);
     209             : }
     210             : 
     211             : #endif // NEML2_ENABLED

Generated by: LCOV version 1.14