https://mooseframework.inl.gov
ForceStabilizedSmallStrainMechanicsNOSPD.C
Go to the documentation of this file.
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 
11 #include "PeridynamicsMesh.h"
12 
14 
17 {
19  params.addClassDescription(
20  "Class for calculating the residual and Jacobian for the force-stabilized peridynamic "
21  "correspondence model under small strain assumptions");
22 
23  params.addRequiredParam<unsigned int>(
24  "component",
25  "An integer corresponding to the variable this kernel acts on (0 for x, 1 for y, 2 for z)");
26 
27  return params;
28 }
29 
31  const InputParameters & parameters)
32  : MechanicsBaseNOSPD(parameters),
33  _sf_coeff(getMaterialProperty<Real>("stabilization_force_coeff")),
34  _component(getParam<unsigned int>("component"))
35 {
36 }
37 
38 void
40 {
41  Real sforce = 0.5 * (_sf_coeff[0] + _sf_coeff[1]) *
42  (_disp_var[_component]->getNodalValue(*_current_elem->node_ptr(1)) -
43  _disp_var[_component]->getNodalValue(*_current_elem->node_ptr(0))) *
44  _bond_status;
45 
46  // For small strain assumptions, stress measures, i.e., Cauchy stress (Sigma), the first
47  // Piola-Kirchhoff stress (P), and the second Piola-Kirchhoff stress (S) are approximately the
48  // same. Thus, the nodal force state tensors are calculated using the Cauchy stresses,
49  // i.e., T = Sigma * inv(Shape) * xi * multi.
50  // Cauchy stress is calculated as Sigma = C * E.
51 
52  for (unsigned int nd = 0; nd < _nnodes; ++nd)
53  for (unsigned int i = 0; i < _nnodes; ++i)
54  _local_re(i) += (i == 0 ? -1 : 1) * _multi[nd] *
55  (_stress[nd] * _shape2[nd].inverse()).row(_component) * _origin_vec *
56  _bond_status;
57 
58  // add fictitious force for model stabilization
59  _local_re(0) += -sforce;
60  _local_re(1) += sforce;
61 }
62 
63 void
65 {
66  // excludes dTi/dUj and dTj/dUi contribution which was considered as nonlocal contribution
67  for (unsigned int i = 0; i < _nnodes; ++i)
68  for (unsigned int j = 0; j < _nnodes; ++j)
69  _local_ke(i, j) += (i == 0 ? -1 : 1) * _multi[j] *
70  (computeDSDU(_component, j) * _shape2[j].inverse()).row(_component) *
71  _origin_vec * _bond_status;
72 
73  // compute local stabilization force jacobian
74  Real diag = 0.5 * (_sf_coeff[0] + _sf_coeff[1]);
75  for (unsigned int i = 0; i < _nnodes; ++i)
76  for (unsigned int j = 0; j < _nnodes; ++j)
77  _local_ke(i, j) += (i == j ? 1 : -1) * diag * _bond_status;
78 }
79 
80 void
82 {
83  // includes dTi/dUj and dTj/dUi contributions
84  for (unsigned int nd = 0; nd < _nnodes; ++nd)
85  {
86  // calculation of jacobian contribution to current_node's neighbors
87  std::vector<dof_id_type> ivardofs(_nnodes);
88  ivardofs[0] = _current_elem->node_ptr(nd)->dof_number(_sys.number(), _var.number(), 0);
89  std::vector<dof_id_type> neighbors = _pdmesh.getNeighbors(_current_elem->node_id(nd));
90  std::vector<dof_id_type> bonds = _pdmesh.getBonds(_current_elem->node_id(nd));
91 
92  Real vol_nb;
93  RealGradient origin_vec_nb;
94  RankTwoTensor dFdUk, dSxdUkx;
95 
96  for (unsigned int nb = 0; nb < neighbors.size(); ++nb)
97  if (_bond_status_var->getElementalValue(_pdmesh.elemPtr(bonds[nb])) > 0.5)
98  {
99  Node * neighbor_nb = _pdmesh.nodePtr(neighbors[nb]);
100  ivardofs[1] = neighbor_nb->dof_number(_sys.number(), _var.number(), 0);
101  vol_nb = _pdmesh.getNodeVolume(neighbors[nb]);
102 
103  // obtain bond ndnb's origin vector
104  origin_vec_nb = _pdmesh.getNodeCoord(neighbor_nb->id()) -
105  _pdmesh.getNodeCoord(_current_elem->node_id(nd));
106 
107  dFdUk.zero();
108  for (unsigned int i = 0; i < _dim; ++i)
109  dFdUk(_component, i) =
110  vol_nb * _horizon_radius[nd] / origin_vec_nb.norm() * origin_vec_nb(i);
111 
112  dFdUk *= _shape2[nd].inverse();
113  dSxdUkx = _Jacobian_mult[nd] * 0.5 * (dFdUk.transpose() + dFdUk);
114 
115  _local_ke.zero();
116  for (unsigned int i = 0; i < _nnodes; ++i)
117  for (unsigned int j = 0; j < _nnodes; ++j)
118  _local_ke(i, j) = (i == 0 ? -1 : 1) * (j == 0 ? 0 : 1) * _multi[nd] *
119  (dSxdUkx * _shape2[nd].inverse()).row(_component) * _origin_vec *
120  _bond_status;
121 
122  addJacobian(_assembly, _local_ke, _ivardofs, ivardofs, _var.scalingFactor());
123 
124  if (_has_diag_save_in)
125  {
126  unsigned int rows = _nnodes;
127  DenseVector<Real> diag(rows);
128  for (unsigned int i = 0; i < rows; ++i)
129  diag(i) = _local_ke(i, i);
130 
131  Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
132  for (unsigned int i = 0; i < _diag_save_in.size(); ++i)
133  _diag_save_in[i]->sys().solution().add_vector(diag, _diag_save_in[i]->dofIndices());
134  }
135  }
136  }
137 }
138 
139 void
141  unsigned int jvar_num, unsigned int coupled_component)
142 {
143  _local_ke.zero();
144  if (_temp_coupled && jvar_num == _temp_var->number())
145  {
146  std::vector<RankTwoTensor> dSdT(_nnodes);
147  for (unsigned int nd = 0; nd < _nnodes; ++nd)
148  for (unsigned int es = 0; es < _deigenstrain_dT.size(); ++es)
149  dSdT[nd] = -(_Jacobian_mult[nd] * (*_deigenstrain_dT[es])[nd]);
150 
151  for (unsigned int i = 0; i < _nnodes; ++i)
152  for (unsigned int j = 0; j < _nnodes; ++j)
153  _local_ke(i, j) += (i == 0 ? -1 : 1) * _multi[j] *
154  (dSdT[j] * _shape2[j].inverse()).row(_component) * _origin_vec *
155  _bond_status;
156  }
157  else
158  {
159  for (unsigned int i = 0; i < _nnodes; ++i)
160  for (unsigned int j = 0; j < _nnodes; ++j)
161  _local_ke(i, j) +=
162  (i == 0 ? -1 : 1) * _multi[j] *
163  (computeDSDU(coupled_component, j) * _shape2[j].inverse()).row(_component) *
164  _origin_vec * _bond_status;
165  }
166 }
167 
168 void
170  unsigned int jvar_num, unsigned int coupled_component)
171 {
172  if (_temp_coupled && jvar_num == _temp_var->number())
173  {
174  // no nonlocal contribution from temperature
175  }
176  else
177  {
178  for (unsigned int nd = 0; nd < _nnodes; ++nd)
179  {
180  // calculation of jacobian contribution to current_node's neighbors
181  std::vector<dof_id_type> jvardofs(_nnodes);
182  jvardofs[0] = _current_elem->node_ptr(nd)->dof_number(_sys.number(), jvar_num, 0);
183  std::vector<dof_id_type> neighbors = _pdmesh.getNeighbors(_current_elem->node_id(nd));
184  std::vector<dof_id_type> bonds = _pdmesh.getBonds(_current_elem->node_id(nd));
185 
186  Real vol_nb;
187  RealGradient origin_vec_nb;
188  RankTwoTensor dFdUk, dSxdUky;
189 
190  for (unsigned int nb = 0; nb < neighbors.size(); ++nb)
191  if (_bond_status_var->getElementalValue(_pdmesh.elemPtr(bonds[nb])) > 0.5)
192 
193  {
194  Node * neighbor_nb = _pdmesh.nodePtr(neighbors[nb]);
195  jvardofs[1] = neighbor_nb->dof_number(_sys.number(), jvar_num, 0);
196  vol_nb = _pdmesh.getNodeVolume(neighbors[nb]);
197 
198  // obtain bond ndnb's origin vector
199  origin_vec_nb = _pdmesh.getNodeCoord(neighbor_nb->id()) -
200  _pdmesh.getNodeCoord(_current_elem->node_id(nd));
201 
202  dFdUk.zero();
203  for (unsigned int i = 0; i < _dim; ++i)
204  dFdUk(coupled_component, i) =
205  _horizon_radius[nd] / origin_vec_nb.norm() * origin_vec_nb(i) * vol_nb;
206 
207  dFdUk *= _shape2[nd].inverse();
208  dSxdUky = _Jacobian_mult[nd] * 0.5 * (dFdUk.transpose() + dFdUk);
209 
210  _local_ke.zero();
211  for (unsigned int i = 0; i < _nnodes; ++i)
212  for (unsigned int j = 0; j < _nnodes; ++j)
213  _local_ke(i, j) = (i == 0 ? -1 : 1) * (j == 0 ? 0 : 1) * _multi[nd] *
214  (dSxdUky * _shape2[nd].inverse()).row(_component) * _origin_vec *
215  _bond_status;
216 
217  addJacobian(_assembly, _local_ke, _ivardofs, jvardofs, _var.scalingFactor());
218  }
219  }
220  }
221 }
void computePDNonlocalOffDiagJacobian(unsigned int jvar_num, unsigned int coupled_component) override
Function to compute nonlocal contribution to the off-diagonal Jacobian at the current nodes...
const bool _temp_coupled
Temperature variable.
registerMooseObject("PeridynamicsApp", ForceStabilizedSmallStrainMechanicsNOSPD)
virtual RankTwoTensor computeDSDU(unsigned int component, unsigned int nd)
Function to compute derivative of stress with respect to displacements for small strain problems...
auto norm() const
const MaterialProperty< RankFourTensor > & _Jacobian_mult
unsigned int number() const
void computeLocalOffDiagJacobian(unsigned int jvar_num, unsigned int coupled_component) override
Function to compute local contribution to the off-diagonal Jacobian at the current nodes...
const MaterialProperty< RankTwoTensor > & _stress
void inverse(const std::vector< std::vector< Real >> &m, std::vector< std::vector< Real >> &m_inv)
void addRequiredParam(const std::string &name, const std::string &doc_string)
Kernel class for fictitious force stabilized peridynamic correspondence material model for small stra...
std::vector< const MaterialProperty< RankTwoTensor > * > _deigenstrain_dT
std::vector< MooseVariable * > _disp_var
displacement variables
static InputParameters validParams()
const unsigned int _component
The index of displacement component.
std::vector< dof_id_type > _ivardofs
Current variable dof numbers for nodes i and j.
const MaterialProperty< RankTwoTensor > & _shape2
const MaterialProperty< Real > & _multi
Material point based material properties.
RankTwoTensorTempl< Real > transpose() const
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
const MaterialProperty< Real > & _sf_coeff
Bond based material property for fictitious stabilization force.
void addClassDescription(const std::string &doc_string)
static const std::complex< double > j(0, 1)
Complex number "j" (also known as "i")
MooseVariable * _temp_var
void ErrorVector unsigned int
Base kernel class for bond-associated correspondence material models.
ForceStabilizedSmallStrainMechanicsNOSPD(const InputParameters &parameters)