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 "CauchyStressFromNEML2UO.h" 11 : #include "NEML2Utils.h" 12 : 13 : registerMooseObject("TensorMechanicsApp", CauchyStressFromNEML2UO); 14 : 15 : InputParameters 16 0 : CauchyStressFromNEML2UO::validParams() 17 : { 18 0 : auto params = NEML2SolidMechanicsInterface<CauchyStressFromNEML2UOParent>::validParams(); 19 0 : NEML2Utils::addClassDescription( 20 : params, 21 : "Gather input variables required for an objective stress integration " 22 : "from all quadrature points. The batched input vector is sent through " 23 : "a NEML2 material model to perform the constitutive update."); 24 0 : params.addCoupledVar("temperature", "The temperature"); 25 : 26 : // Since we use the NEML2 model to evaluate the residual AND the Jacobian at the same time, we 27 : // want to execute this user object only at execute_on = LINEAR (i.e. during residual evaluation). 28 0 : ExecFlagEnum execute_options = MooseUtils::getDefaultExecFlagEnum(); 29 0 : execute_options = {EXEC_INITIAL, EXEC_LINEAR}; 30 0 : params.set<ExecFlagEnum>("execute_on") = execute_options; 31 : 32 0 : return params; 33 0 : } 34 : 35 : #ifndef NEML2_ENABLED 36 : 37 0 : CauchyStressFromNEML2UO::CauchyStressFromNEML2UO(const InputParameters & params) 38 : : NEML2SolidMechanicsInterface<CauchyStressFromNEML2UOParent>( 39 0 : params, "mechanical_strain", "temperature") 40 : { 41 0 : NEML2Utils::libraryNotEnabledError(params); 42 0 : } 43 : 44 : #else 45 : 46 : CauchyStressFromNEML2UO::CauchyStressFromNEML2UO(const InputParameters & params) 47 : : NEML2SolidMechanicsInterface<CauchyStressFromNEML2UOParent>( 48 : params, "mechanical_strain", "temperature") 49 : { 50 : validateModel(); 51 : } 52 : 53 : void 54 : CauchyStressFromNEML2UO::batchCompute() 55 : { 56 : try 57 : { 58 : // Allocate the input and output 59 : if (_t_step == 0) 60 : { 61 : _in = neml2::LabeledVector::zeros(_input_data.size(), {&model().input()}); 62 : _out = neml2::LabeledVector::zeros(_input_data.size(), {&model().output()}); 63 : } 64 : 65 : updateForces(); 66 : 67 : if (_t_step > 0) 68 : { 69 : if (model().implicit()) 70 : applyPredictor(); 71 : 72 : solve(); 73 : 74 : // Fill the NEML2 output back into the MOOSE output data 75 : for (const neml2::TorchSize i : index_range(_output_data)) 76 : { 77 : std::get<0>(_output_data[i]) = 78 : NEML2Utils::toMOOSE<SymmetricRankTwoTensor>(_out(stress()).batch_index({i})); 79 : std::get<1>(_output_data[i]) = RankFourTensor(NEML2Utils::toMOOSE<SymmetricRankFourTensor>( 80 : _dout_din(stress(), strain()).batch_index({i}))); 81 : } 82 : } 83 : } 84 : catch (neml2::NEMLException & e) 85 : { 86 : mooseException("An error occurred during the evaluation of a NEML2 model:\n", 87 : e.what(), 88 : NEML2Utils::NEML2_help_message); 89 : } 90 : catch (std::runtime_error & e) 91 : { 92 : mooseException("An unknown error occurred during the evaluation of a NEML2 model:\n", 93 : e.what(), 94 : "\nIt is possible that this error is related to NEML2.", 95 : NEML2Utils::NEML2_help_message); 96 : } 97 : } 98 : 99 : void 100 : CauchyStressFromNEML2UO::timestepSetup() 101 : { 102 : if (_t_step > 0) 103 : advanceStep(); 104 : } 105 : 106 : void 107 : CauchyStressFromNEML2UO::advanceStep() 108 : { 109 : // Set old state variables and old forces 110 : if (model().input().has_subaxis("old_state") && model().output().has_subaxis("state")) 111 : _in.slice("old_state").fill(_out.slice("state")); 112 : if (model().input().has_subaxis("old_forces") && model().input().has_subaxis("forces")) 113 : _in.slice("old_forces").fill(_in.slice("forces")); 114 : } 115 : 116 : void 117 : CauchyStressFromNEML2UO::updateForces() 118 : { 119 : // Homogenize the input data 120 : auto input = NEML2Utils::homogenizeBatchedTuple(_input_data); 121 : 122 : // Update forces 123 : NEML2Utils::setBatched( 124 : // The input LabeledVector 125 : _in, 126 : // NEML2 variable accessors 127 : {strain(), temperature()}, 128 : // Pointer to the batched data 129 : model().input().has_variable(strain()) ? &std::get<0>(input) : nullptr, 130 : model().input().has_variable(temperature()) ? &std::get<1>(input) : nullptr); 131 : 132 : NEML2Utils::set( 133 : // The input LabeledVector 134 : _in, 135 : // NEML2 variable accessors 136 : {time()}, 137 : // Pointer to the unbatched data 138 : model().input().has_variable(time()) ? &_t : nullptr); 139 : } 140 : 141 : void 142 : CauchyStressFromNEML2UO::applyPredictor() 143 : { 144 : // Set trial state variables (i.e., initial guesses). 145 : // Right now we hard-code to use the old state as the trial state. 146 : // TODO: implement other predictors 147 : _in.slice("state").fill(_in.slice("old_state")); 148 : } 149 : 150 : void 151 : CauchyStressFromNEML2UO::solve() 152 : { 153 : // 1. Sync input onto the model's device 154 : // 2. Evaluate the NEML2 material model 155 : // 3. Sync output back onto CPU 156 : auto res = model().value_and_dvalue(_in.to(device())); 157 : _out = std::get<0>(res).to(torch::kCPU); 158 : _dout_din = std::get<1>(res).to(torch::kCPU); 159 : } 160 : 161 : #endif // NEML2_ENABLED