LCOV - code coverage report
Current view: top level - src/nodalkernels - NodalRotationalInertia.C (source / functions) Hit Total Coverage
Test: idaholab/moose solid_mechanics: f45d79 Lines: 139 162 85.8 %
Date: 2025-07-25 05:00:39 Functions: 5 5 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //* This file is part of the MOOSE framework
       2             : //* https://mooseframework.inl.gov
       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 "NodalRotationalInertia.h"
      11             : #include "MooseVariable.h"
      12             : #include "AuxiliarySystem.h"
      13             : #include "MooseMesh.h"
      14             : #include "TimeIntegrator.h"
      15             : #include "FEProblemBase.h"
      16             : 
      17             : registerMooseObject("SolidMechanicsApp", NodalRotationalInertia);
      18             : 
      19             : InputParameters
      20         126 : NodalRotationalInertia::validParams()
      21             : {
      22         126 :   InputParameters params = TimeNodalKernel::validParams();
      23         126 :   params.addClassDescription("Calculates the inertial torques and inertia proportional damping "
      24             :                              "corresponding to the nodal rotational inertia.");
      25         252 :   params.addCoupledVar("rotations", "rotational displacement variables");
      26         252 :   params.addCoupledVar("rotational_velocities", "rotational velocity variables");
      27         252 :   params.addCoupledVar("rotational_accelerations", "rotational acceleration variables");
      28         252 :   params.addRangeCheckedParam<Real>(
      29             :       "beta", "beta>0.0", "beta parameter for Newmark Time integration");
      30         252 :   params.addRangeCheckedParam<Real>(
      31             :       "gamma", "gamma>0.0", "gamma parameter for Newmark Time integration");
      32         378 :   params.addRangeCheckedParam<Real>("eta",
      33         252 :                                     0.0,
      34             :                                     "eta>=0.0",
      35             :                                     "Constant real number defining the eta parameter for"
      36             :                                     "Rayleigh damping.");
      37         378 :   params.addRangeCheckedParam<Real>("alpha",
      38         252 :                                     0.0,
      39             :                                     "alpha >= -0.3333 & alpha <= 0.0",
      40             :                                     "Alpha parameter for mass dependent numerical damping induced "
      41             :                                     "by HHT time integration scheme");
      42         252 :   params.addRequiredRangeCheckedParam<Real>(
      43             :       "Ixx", "Ixx>0.0", "Moment of inertia in the x direction.");
      44         252 :   params.addRequiredRangeCheckedParam<Real>(
      45             :       "Iyy", "Iyy>0.0", "Moment of inertia in the y direction.");
      46         252 :   params.addRequiredRangeCheckedParam<Real>(
      47             :       "Izz", "Izz>0.0", "Moment of inertia in the z direction.");
      48         252 :   params.addParam<Real>("Ixy", 0.0, "Moment of inertia in the xy direction.");
      49         252 :   params.addParam<Real>("Ixz", 0.0, "Moment of inertia in the xz direction.");
      50         252 :   params.addParam<Real>("Iyz", 0.0, "Moment of inertia in the yz direction.");
      51         252 :   params.addParam<RealGradient>(
      52             :       "x_orientation", "Unit vector along the x direction if different from global x direction.");
      53         252 :   params.addParam<RealGradient>(
      54             :       "y_orientation", "Unit vector along the y direction if different from global y direction.");
      55         252 :   params.addRequiredRangeCheckedParam<unsigned int>(
      56             :       "component",
      57             :       "component<3",
      58             :       "An integer corresponding to the direction "
      59             :       "the variable this nodalkernel acts in. (0 for rot_x, "
      60             :       "1 for rot_y, and 2 for rot_z).");
      61         126 :   return params;
      62           0 : }
      63             : 
      64          64 : NodalRotationalInertia::NodalRotationalInertia(const InputParameters & parameters)
      65             :   : TimeNodalKernel(parameters),
      66          64 :     _has_beta(isParamValid("beta")),
      67         128 :     _has_gamma(isParamValid("gamma")),
      68         128 :     _has_rot_velocities(isParamValid("rotational_velocities")),
      69         128 :     _has_rot_accelerations(isParamValid("rotational_accelerations")),
      70         128 :     _has_x_orientation(isParamValid("x_orientation")),
      71         128 :     _has_y_orientation(isParamValid("y_orientation")),
      72          64 :     _nrot(coupledComponents("rotations")),
      73          64 :     _rot(_nrot),
      74          64 :     _rot_old(_nrot),
      75          64 :     _rot_vel_num(_nrot),
      76          64 :     _rot_accel_num(_nrot),
      77          64 :     _rot_variables(_nrot),
      78          64 :     _rot_accel(_nrot),
      79          64 :     _rot_vel(_nrot),
      80          64 :     _rot_vel_old(_nrot),
      81         110 :     _beta(_has_beta ? getParam<Real>("beta") : 0.1),
      82         110 :     _gamma(_has_gamma ? getParam<Real>("gamma") : 0.1),
      83         128 :     _eta(getParam<Real>("eta")),
      84         128 :     _alpha(getParam<Real>("alpha")),
      85         128 :     _component(getParam<unsigned int>("component")),
      86          64 :     _rot_dot_residual(_nrot),
      87          64 :     _rot_vel_old_value(_nrot),
      88          64 :     _rot_dotdot_residual(_nrot),
      89         192 :     _time_integrator(_sys.getTimeIntegrator(_var.number()))
      90             : {
      91          64 :   if (_has_beta && _has_gamma && _has_rot_velocities && _has_rot_accelerations)
      92             :   {
      93          46 :     _aux_sys = &(_fe_problem.getAuxiliarySystem());
      94          92 :     if (coupledComponents("rotational_velocities") != _nrot ||
      95          90 :         coupledComponents("rotational_accelerations") != _nrot)
      96           2 :       mooseError(
      97             :           "NodalRotationalInertia: rotational_velocities and rotational_accelerations should "
      98             :           "be same size "
      99             :           "as rotations.");
     100             : 
     101         176 :     for (unsigned int i = 0; i < _nrot; ++i)
     102             :     {
     103         132 :       MooseVariable * rot_var = getVar("rotations", i);
     104         132 :       MooseVariable * rot_vel_var = getVar("rotational_velocities", i);
     105         132 :       MooseVariable * rot_accel_var = getVar("rotational_accelerations", i);
     106             : 
     107         132 :       _rot[i] = &rot_var->dofValues();
     108         132 :       _rot_old[i] = &rot_var->dofValuesOld();
     109             : 
     110         132 :       _rot_vel_num[i] = rot_vel_var->number();
     111         132 :       _rot_accel_num[i] = rot_accel_var->number();
     112             : 
     113         132 :       _rot_variables[i] = coupled("rotations", i);
     114             :     }
     115             :   }
     116          18 :   else if (!_has_beta && !_has_gamma && !_has_rot_velocities && !_has_rot_accelerations)
     117             :   {
     118          72 :     for (unsigned int i = 0; i < _nrot; ++i)
     119             :     {
     120          54 :       MooseVariable * rot_var = getVar("rotations", i);
     121          54 :       _rot_vel_old_value[i] = &rot_var->dofValuesDotOld();
     122          54 :       _rot_dot_residual[i] =
     123          54 :           &coupledVectorTagDofValue("rotations", _time_integrator.uDotFactorTag(), i);
     124          54 :       _rot_dotdot_residual[i] =
     125          54 :           &coupledVectorTagDofValue("rotations", _time_integrator.uDotDotFactorTag(), i);
     126             : 
     127          54 :       if (i == 0)
     128             :       {
     129          18 :         _du_dot_du = &rot_var->dofValuesDuDotDu();
     130          18 :         _du_dotdot_du = &rot_var->dofValuesDuDotDotDu();
     131             :       }
     132             :     }
     133             :   }
     134             :   else
     135           0 :     mooseError("NodalRotationalInertia: Either all or none of `beta`, `gamma`, "
     136             :                "`rotational_velocities` and `rotational_accelerations` should be provided as "
     137             :                "input.");
     138             : 
     139             :   // Store inertia values in inertia tensor
     140             :   _inertia.zero();
     141         124 :   _inertia(0, 0) = getParam<Real>("Ixx");
     142         124 :   _inertia(0, 1) = getParam<Real>("Ixy");
     143         124 :   _inertia(0, 2) = getParam<Real>("Ixz");
     144          62 :   _inertia(1, 0) = _inertia(0, 1);
     145         124 :   _inertia(1, 1) = getParam<Real>("Iyy");
     146         124 :   _inertia(1, 2) = getParam<Real>("Iyz");
     147          62 :   _inertia(2, 0) = _inertia(0, 2);
     148          62 :   _inertia(2, 1) = _inertia(1, 2);
     149         124 :   _inertia(2, 2) = getParam<Real>("Izz");
     150             : 
     151             :   // Check for positive definiteness of matrix using Sylvester's criterion.
     152          62 :   const Real det1 = _inertia(0, 0);
     153          62 :   const Real det2 = _inertia(0, 0) * _inertia(1, 1) - _inertia(0, 1) * _inertia(1, 0);
     154          62 :   const Real det3 = _inertia.det();
     155             : 
     156          62 :   if (det1 < 1e-6 || det2 < 1e-6 || det3 < 1e-6)
     157           2 :     mooseError("NodalRotationalInertia: The moment of inertia tensor should be positive definite.");
     158          60 :   if (_has_x_orientation && _has_y_orientation)
     159             :   {
     160           8 :     const RealGradient x_orientation = getParam<RealGradient>("x_orientation");
     161           8 :     const RealGradient y_orientation = getParam<RealGradient>("y_orientation");
     162             : 
     163           4 :     if (std::abs(x_orientation.norm() - 1.0) > 1e-6 || std::abs(y_orientation.norm() - 1.0) > 1e-6)
     164           2 :       mooseError("NodalRotationalInertia: x_orientation and y_orientation must be unit vectors.");
     165             : 
     166           2 :     Real sum = x_orientation(0) * y_orientation(0) + x_orientation(1) * y_orientation(1) +
     167           2 :                x_orientation(2) * y_orientation(2);
     168             : 
     169           2 :     if (std::abs(sum) > 1e-4)
     170           2 :       mooseError("NodalRotationalInertia: x_orientation and y_orientation should be perpendicular "
     171             :                  "to each other.");
     172             : 
     173             :     // Calculate z orientation as a cross product of the x and y orientations
     174             :     RealGradient z_orientation;
     175           0 :     z_orientation(0) = (x_orientation(1) * y_orientation(2) - x_orientation(2) * y_orientation(1));
     176           0 :     z_orientation(1) = (x_orientation(2) * y_orientation(0) - x_orientation(0) * y_orientation(2));
     177           0 :     z_orientation(2) = (x_orientation(0) * y_orientation(1) - x_orientation(1) * y_orientation(0));
     178             : 
     179             :     // Rotation matrix from global to original beam local configuration
     180           0 :     RankTwoTensor orientation;
     181           0 :     orientation(0, 0) = x_orientation(0);
     182           0 :     orientation(0, 1) = x_orientation(1);
     183           0 :     orientation(0, 2) = x_orientation(2);
     184           0 :     orientation(1, 0) = y_orientation(0);
     185           0 :     orientation(1, 1) = y_orientation(1);
     186           0 :     orientation(1, 2) = y_orientation(2);
     187           0 :     orientation(2, 0) = z_orientation(0);
     188           0 :     orientation(2, 1) = z_orientation(1);
     189           0 :     orientation(2, 2) = z_orientation(2);
     190             : 
     191           0 :     RankTwoTensor global_inertia = orientation.transpose() * _inertia * orientation;
     192           0 :     _inertia = global_inertia;
     193           0 :   }
     194          56 :   else if ((_has_x_orientation && !_has_y_orientation) ||
     195          54 :            (!_has_x_orientation && _has_y_orientation))
     196           2 :     mooseError("NodalRotationalInertia: Both x_orientation and y_orientation should be provided if "
     197             :                "x_orientation or "
     198             :                "y_orientation is different from global x or y direction, respectively.");
     199             : 
     200             :   // Check for Explicit and alpha parameter
     201          54 :   if (_alpha != 0 && _time_integrator.isExplicit())
     202           0 :     mooseError("NodalRotationalInertia: HHT time integration parameter can only be used with "
     203             :                "Newmark-Beta time integration.");
     204             : 
     205             :   // Check for Explicit and beta parameter
     206          54 :   if (_has_beta != 0 && _time_integrator.isExplicit())
     207           0 :     mooseError("NodalRotationalInertia: beta time integration parameter can only be used with "
     208             :                "Newmark-Beta time integrator.");
     209          54 : }
     210             : 
     211             : Real
     212        3606 : NodalRotationalInertia::computeQpResidual()
     213             : {
     214        3606 :   if (_dt == 0)
     215             :     return 0;
     216             :   else
     217             :   {
     218        3606 :     if (_has_beta)
     219             :     {
     220        2400 :       const NumericVector<Number> & aux_sol_old = _aux_sys->solutionOld();
     221             : 
     222        9600 :       for (unsigned int i = 0; i < _nrot; ++i)
     223             :       {
     224        7200 :         _rot_vel_old[i] =
     225        7200 :             aux_sol_old(_current_node->dof_number(_aux_sys->number(), _rot_vel_num[i], 0));
     226             :         const Real rot_accel_old =
     227        7200 :             aux_sol_old(_current_node->dof_number(_aux_sys->number(), _rot_accel_num[i], 0));
     228             : 
     229        7200 :         _rot_accel[i] = 1.0 / _beta *
     230        7200 :                         ((((*_rot[i])[_qp] - (*_rot_old[i])[_qp]) / (_dt * _dt)) -
     231        7200 :                          _rot_vel_old[i] / _dt - rot_accel_old * (0.5 - _beta));
     232        7200 :         _rot_vel[i] =
     233        7200 :             _rot_vel_old[i] + (_dt * (1.0 - _gamma)) * rot_accel_old + _gamma * _dt * _rot_accel[i];
     234             :       }
     235             : 
     236             :       Real res = 0.0;
     237        9600 :       for (unsigned int i = 0; i < _nrot; ++i)
     238        7200 :         res += _inertia(_component, i) * (_rot_accel[i] + _rot_vel[i] * _eta * (1.0 + _alpha) -
     239        7200 :                                           _alpha * _eta * _rot_vel_old[i]);
     240             : 
     241        2400 :       return res;
     242             :     }
     243             :     else
     244             :     {
     245             :       // All cases (Explicit, implicit and implicit with HHT)
     246             :       // Note that _alpha is ensured to be zero with explicit integration
     247             :       Real res = 0.0;
     248        4824 :       for (unsigned int i = 0; i < _nrot; ++i)
     249        3618 :         res += _inertia(_component, i) * ((*_rot_dotdot_residual[i])[_qp] +
     250        3618 :                                           (*_rot_dot_residual[i])[_qp] * _eta * (1.0 + _alpha) -
     251        3618 :                                           _alpha * _eta * (*_rot_vel_old_value[i])[_qp]);
     252        1206 :       return res;
     253             :     }
     254             :   }
     255             : }
     256             : 
     257             : Real
     258        1806 : NodalRotationalInertia::computeQpJacobian()
     259             : {
     260        1806 :   if (_dt == 0)
     261             :     return 0.0;
     262             :   else
     263             :   {
     264        1806 :     if (_has_beta)
     265        1200 :       return _inertia(_component, _component) / (_beta * _dt * _dt) +
     266        1200 :              _eta * (1.0 + _alpha) * _inertia(_component, _component) * _gamma / _beta / _dt;
     267         606 :     else if (_time_integrator.isExplicit())
     268             :       // for explicit central difference integration, _eta does not appear in the
     269             :       // Jacobian (mass matrix), and alpha is zero
     270           0 :       return _inertia(_component, _component) * (*_du_dotdot_du)[_qp];
     271             :     else
     272             :       // for NewmarkBeta time integrator
     273         606 :       return _inertia(_component, _component) * (*_du_dotdot_du)[_qp] +
     274         606 :              _eta * (1.0 + _alpha) * _inertia(_component, _component) * (*_du_dot_du)[_qp];
     275             :   }
     276             : }
     277             : 
     278             : Real
     279        3612 : NodalRotationalInertia::computeQpOffDiagJacobian(unsigned int jvar)
     280             : {
     281             :   unsigned int coupled_component = 0;
     282             :   bool rot_coupled = false;
     283             : 
     284        9648 :   for (unsigned int i = 0; i < _nrot; ++i)
     285             :   {
     286        8436 :     if (jvar == _rot_variables[i])
     287             :     {
     288             :       coupled_component = i;
     289             :       rot_coupled = true;
     290             :       break;
     291             :     }
     292             :   }
     293             : 
     294        3612 :   if (_dt == 0)
     295             :     return 0.0;
     296        3612 :   else if (rot_coupled)
     297             :   {
     298        2400 :     if (_has_beta)
     299        2400 :       return _inertia(_component, coupled_component) / (_beta * _dt * _dt) +
     300        2400 :              _eta * (1.0 + _alpha) * _inertia(_component, coupled_component) * _gamma / _beta / _dt;
     301             :     else
     302           0 :       return _inertia(_component, coupled_component) * (*_du_dotdot_du)[_qp] +
     303           0 :              _eta * (1.0 + _alpha) * _inertia(_component, coupled_component) * (*_du_dot_du)[_qp];
     304             :   }
     305             :   else
     306             :     return 0.0;
     307             : }

Generated by: LCOV version 1.14