LCOV - code coverage report
Current view: top level - src/materials - ComputeStrainBaseNOSPD.C (source / functions) Hit Total Coverage
Test: idaholab/moose peridynamics: #31405 (292dce) with base fef103 Lines: 139 144 96.5 %
Date: 2025-09-04 07:55:08 Functions: 8 8 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 "ComputeStrainBaseNOSPD.h"
      11             : #include "ElasticityTensorTools.h"
      12             : 
      13             : #include "libmesh/quadrature.h"
      14             : 
      15             : InputParameters
      16         564 : ComputeStrainBaseNOSPD::validParams()
      17             : {
      18         564 :   InputParameters params = MechanicsMaterialBasePD::validParams();
      19         564 :   params.addClassDescription(
      20             :       "Base material strain class for the peridynamic correspondence models");
      21             : 
      22        1128 :   MooseEnum stabilization_option("FORCE BOND_HORIZON_I BOND_HORIZON_II");
      23        1128 :   params.addRequiredParam<MooseEnum>(
      24             :       "stabilization",
      25             :       stabilization_option,
      26             :       "Stabilization techniques used for the peridynamic correspondence model");
      27        1128 :   params.addParam<bool>("plane_strain",
      28        1128 :                         false,
      29             :                         "Plane strain problem or not, this will affect the mechanical stretch "
      30             :                         "calculation for problem with eigenstrains");
      31        1128 :   params.addParam<std::vector<MaterialPropertyName>>(
      32             :       "eigenstrain_names", {}, "List of eigenstrains to be applied in this strain calculation");
      33             : 
      34         564 :   return params;
      35         564 : }
      36             : 
      37         444 : ComputeStrainBaseNOSPD::ComputeStrainBaseNOSPD(const InputParameters & parameters)
      38             :   : DerivativeMaterialInterface<MechanicsMaterialBasePD>(parameters),
      39         444 :     _stabilization(getParam<MooseEnum>("stabilization")),
      40         888 :     _plane_strain(getParam<bool>("plane_strain")),
      41         888 :     _Cijkl(getMaterialProperty<RankFourTensor>("elasticity_tensor")),
      42         888 :     _eigenstrain_names(getParam<std::vector<MaterialPropertyName>>("eigenstrain_names")),
      43         444 :     _eigenstrains(_eigenstrain_names.size()),
      44         444 :     _shape2(declareProperty<RankTwoTensor>("rank_two_shape_tensor")),
      45         444 :     _deformation_gradient(declareProperty<RankTwoTensor>("deformation_gradient")),
      46         444 :     _ddgraddu(declareProperty<RankTwoTensor>("ddeformation_gradient_du")),
      47         444 :     _ddgraddv(declareProperty<RankTwoTensor>("ddeformation_gradient_dv")),
      48         444 :     _ddgraddw(declareProperty<RankTwoTensor>("ddeformation_gradient_dw")),
      49         444 :     _total_strain(declareProperty<RankTwoTensor>("total_strain")),
      50         444 :     _mechanical_strain(declareProperty<RankTwoTensor>("mechanical_strain")),
      51         444 :     _multi(declareProperty<Real>("multi")),
      52         888 :     _sf_coeff(declareProperty<Real>("stabilization_force_coeff"))
      53             : {
      54         615 :   for (unsigned int i = 0; i < _eigenstrains.size(); ++i)
      55             :   {
      56             :     _eigenstrain_names[i] = _eigenstrain_names[i];
      57         171 :     _eigenstrains[i] = &getMaterialProperty<RankTwoTensor>(_eigenstrain_names[i]);
      58             :   }
      59         444 : }
      60             : 
      61             : void
      62        4896 : ComputeStrainBaseNOSPD::initQpStatefulProperties()
      63             : {
      64        4896 :   _mechanical_strain[_qp].zero();
      65        4896 :   _total_strain[_qp].zero();
      66        4896 :   _deformation_gradient[_qp].setToIdentity();
      67             : 
      68        4896 :   if (_qrule->n_points() < 2) // Gauss_Lobatto: order = 2n-3 (n is number of qp)
      69           0 :     mooseError(
      70             :         "NOSPD models require Gauss_Lobatto rule and a minimum of 2 quadrature points, i.e., "
      71             :         "order of FIRST");
      72        4896 : }
      73             : 
      74             : void
      75     2860812 : ComputeStrainBaseNOSPD::computeQpDeformationGradient()
      76             : {
      77     2860812 :   _shape2[_qp].zero();
      78     2860812 :   _deformation_gradient[_qp].zero();
      79     2860812 :   _ddgraddu[_qp].zero();
      80     2860812 :   _ddgraddv[_qp].zero();
      81     2860812 :   _ddgraddw[_qp].zero();
      82     2860812 :   _multi[_qp] = 0.0;
      83     2860812 :   _sf_coeff[_qp] = 0.0;
      84             : 
      85     2860812 :   if (_dim == 2)
      86     2574432 :     _shape2[_qp](2, 2) = _deformation_gradient[_qp](2, 2) = 1.0;
      87             : 
      88     2860812 :   if (_bond_status_var->getElementalValue(_current_elem) > 0.5)
      89             :   {
      90     2834100 :     if (_stabilization == "FORCE")
      91             :     {
      92      101520 :       computeConventionalQpDeformationGradient();
      93             : 
      94      101520 :       _sf_coeff[_qp] = ElasticityTensorTools::getIsotropicYoungsModulus(_Cijkl[_qp]) *
      95      101520 :                        _pdmesh.getNodeAverageSpacing(_current_elem->node_id(_qp)) *
      96      101520 :                        _horizon_radius[_qp] / _origin_vec.norm();
      97      101520 :       _multi[_qp] = _horizon_radius[_qp] / _origin_vec.norm() * _node_vol[0] * _node_vol[1];
      98             :     }
      99     2732580 :     else if (_stabilization == "BOND_HORIZON_I" || _stabilization == "BOND_HORIZON_II")
     100     2732580 :       computeBondHorizonQpDeformationGradient();
     101             :     else
     102           0 :       paramError("stabilization",
     103             :                  "Unknown stabilization scheme for peridynamic correspondence model!");
     104             :   }
     105             :   else
     106             :   {
     107       26712 :     _shape2[_qp].setToIdentity();
     108       26712 :     _deformation_gradient[_qp].setToIdentity();
     109             :   }
     110     2860812 : }
     111             : 
     112             : void
     113      101520 : ComputeStrainBaseNOSPD::computeConventionalQpDeformationGradient()
     114             : {
     115      101520 :   std::vector<dof_id_type> neighbors = _pdmesh.getNeighbors(_current_elem->node_id(_qp));
     116      101520 :   std::vector<dof_id_type> bonds = _pdmesh.getBonds(_current_elem->node_id(_qp));
     117             : 
     118             :   // calculate the shape tensor and prepare the deformation gradient tensor
     119             :   Real vol_nb, weight_nb;
     120             :   RealGradient origin_vec_nb, current_vec_nb;
     121             : 
     122     1376280 :   for (unsigned int nb = 0; nb < neighbors.size(); ++nb)
     123     1274760 :     if (_bond_status_var->getElementalValue(_pdmesh.elemPtr(bonds[nb])) > 0.5)
     124             :     {
     125     1247040 :       vol_nb = _pdmesh.getNodeVolume(neighbors[nb]);
     126     1247040 :       origin_vec_nb =
     127     1247040 :           _pdmesh.getNodeCoord(neighbors[nb]) - _pdmesh.getNodeCoord(_current_elem->node_id(_qp));
     128             : 
     129     3741120 :       for (unsigned int k = 0; k < _dim; ++k)
     130     2494080 :         current_vec_nb(k) = origin_vec_nb(k) +
     131     4988160 :                             _disp_var[k]->getNodalValue(*_pdmesh.nodePtr(neighbors[nb])) -
     132     2494080 :                             _disp_var[k]->getNodalValue(*_current_elem->node_ptr(_qp));
     133             : 
     134     1247040 :       weight_nb = _horizon_radius[_qp] / origin_vec_nb.norm();
     135     3741120 :       for (unsigned int k = 0; k < _dim; ++k)
     136             :       {
     137     7482240 :         for (unsigned int l = 0; l < _dim; ++l)
     138             :         {
     139     4988160 :           _shape2[_qp](k, l) += weight_nb * origin_vec_nb(k) * origin_vec_nb(l) * vol_nb;
     140     4988160 :           _deformation_gradient[_qp](k, l) +=
     141     4988160 :               weight_nb * current_vec_nb(k) * origin_vec_nb(l) * vol_nb;
     142             :         }
     143             :         // calculate derivatives of deformation_gradient w.r.t displacements of node nb
     144     2494080 :         _ddgraddu[_qp](0, k) += -weight_nb * origin_vec_nb(k) * vol_nb;
     145     2494080 :         _ddgraddv[_qp](1, k) += -weight_nb * origin_vec_nb(k) * vol_nb;
     146     2494080 :         if (_dim == 3)
     147           0 :           _ddgraddw[_qp](2, k) += -weight_nb * origin_vec_nb(k) * vol_nb;
     148             :       }
     149             :     }
     150             : 
     151             :   // finalize the deformation gradient tensor
     152      101520 :   if (_shape2[_qp].det() == 0.)
     153           0 :     mooseError("Singular shape tensor is detected in ComputeStrainBaseNOSPD! Use "
     154             :                "SingularShapeTensorEliminatorUserObjectPD to avoid singular shape tensor!");
     155             : 
     156      101520 :   _deformation_gradient[_qp] *= _shape2[_qp].inverse();
     157      101520 :   _ddgraddu[_qp] *= _shape2[_qp].inverse();
     158      101520 :   _ddgraddv[_qp] *= _shape2[_qp].inverse();
     159      101520 :   _ddgraddw[_qp] *= _shape2[_qp].inverse();
     160      101520 : }
     161             : 
     162             : void
     163     2732580 : ComputeStrainBaseNOSPD::computeBondHorizonQpDeformationGradient()
     164             : {
     165     2732580 :   std::vector<dof_id_type> neighbors = _pdmesh.getNeighbors(_current_elem->node_id(_qp));
     166     2732580 :   std::vector<dof_id_type> bonds = _pdmesh.getBonds(_current_elem->node_id(_qp));
     167             : 
     168             :   dof_id_type nb_index =
     169     2732580 :       std::find(neighbors.begin(), neighbors.end(), _current_elem->node_id(1 - _qp)) -
     170     2732580 :       neighbors.begin();
     171             :   std::vector<dof_id_type> dg_neighbors =
     172     2732580 :       _pdmesh.getBondDeformationGradientNeighbors(_current_elem->node_id(_qp), nb_index);
     173     2732580 :   Real dg_sub_vol = _pdmesh.getHorizonSubsetVolume(_current_elem->node_id(_qp), nb_index);
     174     2732580 :   Real dg_sub_vol_sum = _pdmesh.getHorizonSubsetVolumeSum(_current_elem->node_id(_qp));
     175             : 
     176             :   // calculate the shape tensor and prepare the deformation gradient tensor
     177             :   Real vol_nb, weight_nb;
     178             :   RealGradient origin_vec_nb, current_vec_nb;
     179             : 
     180    48914754 :   for (unsigned int nb = 0; nb < dg_neighbors.size(); ++nb)
     181    46182174 :     if (_bond_status_var->getElementalValue(_pdmesh.elemPtr(bonds[dg_neighbors[nb]])) > 0.5)
     182             :     {
     183    46035080 :       vol_nb = _pdmesh.getNodeVolume(neighbors[dg_neighbors[nb]]);
     184    46035080 :       origin_vec_nb = _pdmesh.getNodeCoord(neighbors[dg_neighbors[nb]]) -
     185    46035080 :                       _pdmesh.getNodeCoord(_current_elem->node_id(_qp));
     186             : 
     187   142210536 :       for (unsigned int k = 0; k < _dim; ++k)
     188    96175456 :         current_vec_nb(k) =
     189    96175456 :             origin_vec_nb(k) +
     190   192350912 :             _disp_var[k]->getNodalValue(*_pdmesh.nodePtr(neighbors[dg_neighbors[nb]])) -
     191    96175456 :             _disp_var[k]->getNodalValue(*_current_elem->node_ptr(_qp));
     192             : 
     193    46035080 :       weight_nb = _horizon_radius[_qp] / origin_vec_nb.norm();
     194   142210536 :       for (unsigned int k = 0; k < _dim; ++k)
     195             :       {
     196   300842256 :         for (unsigned int l = 0; l < _dim; ++l)
     197             :         {
     198   204666800 :           _shape2[_qp](k, l) += weight_nb * origin_vec_nb(k) * origin_vec_nb(l) * vol_nb;
     199   204666800 :           _deformation_gradient[_qp](k, l) +=
     200   204666800 :               weight_nb * current_vec_nb(k) * origin_vec_nb(l) * vol_nb;
     201             :         }
     202             :         // calculate derivatives of deformation_gradient w.r.t displacements of node i
     203    96175456 :         _ddgraddu[_qp](0, k) += -weight_nb * origin_vec_nb(k) * vol_nb;
     204    96175456 :         _ddgraddv[_qp](1, k) += -weight_nb * origin_vec_nb(k) * vol_nb;
     205    96175456 :         if (_dim == 3)
     206    12315888 :           _ddgraddw[_qp](2, k) += -weight_nb * origin_vec_nb(k) * vol_nb;
     207             :       }
     208             :     }
     209             :   // finalize the deformation gradient and its derivatives
     210     2732580 :   if (_shape2[_qp].det() == 0.)
     211           0 :     computeConventionalQpDeformationGradient(); // this will affect the corresponding jacobian
     212             :                                                 // calculation
     213             :   else
     214             :   {
     215     2732580 :     _deformation_gradient[_qp] *= _shape2[_qp].inverse();
     216     2732580 :     _ddgraddu[_qp] *= _shape2[_qp].inverse();
     217     2732580 :     _ddgraddv[_qp] *= _shape2[_qp].inverse();
     218     2732580 :     _ddgraddw[_qp] *= _shape2[_qp].inverse();
     219             :   }
     220             : 
     221             :   // force state multiplier
     222     2732580 :   if (_stabilization == "BOND_HORIZON_I")
     223     2584200 :     _multi[_qp] = _horizon_radius[_qp] / _origin_vec.norm() * _node_vol[0] * _node_vol[1] *
     224     2584200 :                   dg_sub_vol / _horizon_vol[_qp];
     225      148380 :   else if (_stabilization == "BOND_HORIZON_II")
     226      148380 :     _multi[_qp] = _node_vol[_qp] * dg_sub_vol / dg_sub_vol_sum;
     227     2732580 : }
     228             : 
     229             : void
     230     1430406 : ComputeStrainBaseNOSPD::computeProperties()
     231             : {
     232     1430406 :   setupMeshRelatedData();     // function from base class
     233     1430406 :   computeBondCurrentLength(); // current length of a bond from base class
     234     1430406 :   computeBondStretch();       // stretch of a bond
     235             : 
     236     4291218 :   for (_qp = 0; _qp < _nnodes; ++_qp)
     237     2860812 :     computeQpStrain();
     238     1430406 : }
     239             : 
     240             : void
     241     1430406 : ComputeStrainBaseNOSPD::computeBondStretch()
     242             : {
     243     1430406 :   _total_stretch[0] = _current_len / _origin_vec.norm() - 1.0;
     244     1430406 :   _total_stretch[1] = _total_stretch[0];
     245     1430406 :   _mechanical_stretch[0] = _total_stretch[0];
     246             : 
     247             :   Real factor = 1.0;
     248     1430406 :   if (_plane_strain)
     249      144738 :     factor = 1.0 + ElasticityTensorTools::getIsotropicPoissonsRatio(_Cijkl[0]);
     250             : 
     251     1793096 :   for (auto es : _eigenstrains)
     252      362690 :     _mechanical_stretch[0] -= 0.5 * factor * ((*es)[0](2, 2) + (*es)[1](2, 2));
     253             : 
     254     1430406 :   _mechanical_stretch[1] = _mechanical_stretch[0];
     255     1430406 : }

Generated by: LCOV version 1.14