https://mooseframework.inl.gov
HorizonStabilizedFormIFiniteStrainMechanicsNOSPD.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 the Jacobian for Form I "
21  "of the horizon-stabilized peridynamic correspondence model under finite 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  : MechanicsFiniteStrainBaseNOSPD(parameters), _component(getParam<unsigned int>("component"))
33 {
34 }
35 
36 void
38 {
39  // For finite strain formulation, the _stress tensor gotten from material class is the
40  // Cauchy stress (Sigma). the first Piola-Kirchhoff stress (P) is then obtained as
41  // P = J * Sigma * inv(F)^T.
42  // Nodal force states are based on the first Piola-Kirchhoff stress tensors (P).
43  // i.e., T = (J * Sigma * inv(F)^T) * inv(Shape) * xi * multi.
44  // Cauchy stress is calculated as Sigma_n+1 = Sigma_n + R * (C * dt * D) * R^T
45 
46  for (unsigned int nd = 0; nd < _nnodes; ++nd)
47  for (unsigned int i = 0; i < _nnodes; ++i)
48  _local_re(i) += (i == 0 ? -1 : 1) * _multi[nd] *
49  ((_dgrad[nd].det() * _stress[nd] * _dgrad[nd].inverse().transpose()) *
50  _shape2[nd].inverse())
51  .row(_component) *
52  _origin_vec * _bond_status;
53 }
54 
55 void
57 {
58  // excludes dTi/dUj and dTj/dUi contribution which was considered as nonlocal contribution
59  std::vector<RankTwoTensor> dPxdUx(_nnodes);
60  for (unsigned int nd = 0; nd < _nnodes; ++nd)
61  dPxdUx[nd] = computeDJDU(_component, nd) * _stress[nd] * _dgrad[nd].inverse().transpose() +
62  _dgrad[nd].det() * computeDSDU(_component, nd) * _dgrad[nd].inverse().transpose() +
63  _dgrad[nd].det() * _stress[nd] * computeDinvFTDU(_component, nd);
64 
65  for (unsigned int i = 0; i < _nnodes; ++i)
66  for (unsigned int j = 0; j < _nnodes; ++j)
67  _local_ke(i, j) += (i == 0 ? -1 : 1) * _multi[j] *
68  (dPxdUx[j] * _shape2[j].inverse()).row(_component) * _origin_vec *
69  _bond_status;
70 }
71 
72 void
74 {
75  // includes dTi/dUj and dTj/dUi contributions
76  for (unsigned int nd = 0; nd < _nnodes; ++nd)
77  {
78  RankFourTensor dSdFhat = computeDSDFhat(nd);
79  RankTwoTensor invF = _dgrad[nd].inverse();
80  Real detF = _dgrad[nd].det();
81  // calculation of jacobian contribution to current_node's neighbors
82  std::vector<dof_id_type> ivardofs(_nnodes);
83  ivardofs[0] = _current_elem->node_ptr(nd)->dof_number(_sys.number(), _var.number(), 0);
84  std::vector<dof_id_type> neighbors = _pdmesh.getNeighbors(_current_elem->node_id(nd));
85  std::vector<dof_id_type> bonds = _pdmesh.getBonds(_current_elem->node_id(nd));
86 
87  dof_id_type nb_index =
88  std::find(neighbors.begin(), neighbors.end(), _current_elem->node_id(1 - nd)) -
89  neighbors.begin();
90  std::vector<dof_id_type> dg_neighbors =
91  _pdmesh.getBondDeformationGradientNeighbors(_current_elem->node_id(nd), nb_index);
92 
93  Real vol_nb, dJdU;
94  RealGradient origin_vec_nb;
95  RankTwoTensor dFdUk, dPxdUkx, dSdU, dinvFTdU;
96 
97  for (unsigned int nb = 0; nb < dg_neighbors.size(); ++nb)
98  if (_bond_status_var->getElementalValue(_pdmesh.elemPtr(bonds[dg_neighbors[nb]])) > 0.5)
99  {
100  ivardofs[1] = _pdmesh.nodePtr(neighbors[dg_neighbors[nb]])
101  ->dof_number(_sys.number(), _var.number(), 0);
102  vol_nb = _pdmesh.getNodeVolume(neighbors[dg_neighbors[nb]]);
103 
104  origin_vec_nb = _pdmesh.getNodeCoord(neighbors[dg_neighbors[nb]]) -
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  _horizon_radius[nd] / origin_vec_nb.norm() * origin_vec_nb(i) * vol_nb;
111 
112  dFdUk *= _shape2[nd].inverse();
113 
114  // calculate dJ/du
115  dJdU = 0.0;
116  for (unsigned int i = 0; i < 3; ++i)
117  for (unsigned int j = 0; j < 3; ++j)
118  dJdU += detF * invF(j, i) * dFdUk(i, j);
119 
120  // calculate dS/du
121  dSdU = dSdFhat * dFdUk * _dgrad_old[nd].inverse();
122 
123  // calculate dinv(F)Tdu
124  dinvFTdU.zero();
125  for (unsigned int i = 0; i < 3; ++i)
126  for (unsigned int J = 0; J < 3; ++J)
127  for (unsigned int k = 0; k < 3; ++k)
128  for (unsigned int L = 0; L < 3; ++L)
129  dinvFTdU(i, J) += -invF(J, k) * invF(L, i) * dFdUk(k, L);
130 
131  // calculate the derivative of first Piola-Kirchhoff stress w.r.t displacements
132  dPxdUkx = dJdU * _stress[nd] * invF.transpose() + detF * dSdU * invF.transpose() +
133  detF * _stress[nd] * dinvFTdU;
134 
135  for (unsigned int i = 0; i < _nnodes; ++i)
136  for (unsigned int j = 0; j < _nnodes; ++j)
137  _local_ke(i, j) = (i == 0 ? -1 : 1) * (j == 0 ? 0 : 1) * _multi[nd] *
138  (dPxdUkx * _shape2[nd].inverse()).row(_component) * _origin_vec *
139  _bond_status;
140 
141  addJacobian(_assembly, _local_ke, _ivardofs, ivardofs, _var.scalingFactor());
142 
143  if (_has_diag_save_in)
144  {
145  unsigned int rows = _nnodes;
146  DenseVector<Real> diag(rows);
147  for (unsigned int i = 0; i < rows; ++i)
148  diag(i) = _local_ke(i, i);
149 
150  Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
151  for (unsigned int i = 0; i < _diag_save_in.size(); ++i)
152  {
153  std::vector<dof_id_type> diag_save_in_dofs(2);
154  diag_save_in_dofs[0] = _current_elem->node_ptr(nd)->dof_number(
155  _diag_save_in[i]->sys().number(), _diag_save_in[i]->number(), 0);
156  diag_save_in_dofs[1] =
157  _pdmesh.nodePtr(neighbors[dg_neighbors[nb]])
158  ->dof_number(_diag_save_in[i]->sys().number(), _diag_save_in[i]->number(), 0);
159 
160  _diag_save_in[i]->sys().solution().add_vector(diag, diag_save_in_dofs);
161  }
162  }
163  }
164  }
165 }
166 
167 void
169  unsigned int jvar_num, unsigned int coupled_component)
170 {
171  _local_ke.zero();
172  if (_temp_coupled && jvar_num == _temp_var->number())
173  {
174  std::vector<RankTwoTensor> dSdT(_nnodes);
175  for (unsigned int nd = 0; nd < _nnodes; ++nd)
176  for (unsigned int es = 0; es < _deigenstrain_dT.size(); ++es)
177  dSdT[nd] = -_dgrad[nd].det() * _Jacobian_mult[nd] * (*_deigenstrain_dT[es])[nd] *
178  _dgrad[nd].inverse().transpose();
179 
180  for (unsigned int i = 0; i < _nnodes; ++i)
181  for (unsigned int j = 0; j < _nnodes; ++j)
182  _local_ke(i, j) += (i == 0 ? -1 : 1) * _multi[j] *
183  (dSdT[j] * _shape2[j].inverse()).row(_component) * _origin_vec *
184  _bond_status;
185  }
186  else if (_out_of_plane_strain_coupled &&
187  jvar_num == _out_of_plane_strain_var
188  ->number()) // weak plane stress case, out_of_plane_strain is coupled
189  {
190  std::vector<RankTwoTensor> dSdE33(_nnodes);
191  for (unsigned int nd = 0; nd < _nnodes; ++nd)
192  {
193  for (unsigned int i = 0; i < 3; ++i)
194  for (unsigned int j = 0; j < 3; ++j)
195  dSdE33[nd](i, j) = _Jacobian_mult[nd](i, j, 2, 2);
196 
197  dSdE33[nd] = _dgrad[nd].det() * dSdE33[nd] * _dgrad[nd].inverse().transpose();
198  }
199 
200  for (unsigned int i = 0; i < _nnodes; ++i)
201  for (unsigned int j = 0; j < _nnodes; ++j)
202  _local_ke(i, j) += (i == 0 ? -1 : 1) * _multi[j] *
203  (dSdE33[j] * _shape2[j].inverse()).row(_component) * _origin_vec *
204  _bond_status;
205  }
206  else
207  {
208  std::vector<RankTwoTensor> dPxdUy(_nnodes);
209  for (unsigned int nd = 0; nd < _nnodes; ++nd)
210  dPxdUy[nd] =
211  computeDJDU(coupled_component, nd) * _stress[nd] * _dgrad[nd].inverse().transpose() +
212  _dgrad[nd].det() * computeDSDU(coupled_component, nd) * _dgrad[nd].inverse().transpose() +
213  _dgrad[nd].det() * _stress[nd] * computeDinvFTDU(coupled_component, nd);
214 
215  for (unsigned int i = 0; i < _nnodes; ++i)
216  for (unsigned int j = 0; j < _nnodes; ++j)
217  _local_ke(i, j) += (i == 0 ? -1 : 1) * _multi[j] *
218  (dPxdUy[j] * _shape2[j].inverse()).row(_component) * _origin_vec *
219  _bond_status;
220  }
221 }
222 
223 void
225  unsigned int jvar_num, unsigned int coupled_component)
226 {
227  if (_temp_coupled && jvar_num == _temp_var->number())
228  {
229  // no nonlocal contribution from temperature
230  }
232  {
233  // no nonlocal contribution from out of plane strain
234  }
235  else
236  {
237  for (unsigned int nd = 0; nd < _nnodes; ++nd)
238  {
239  RankFourTensor dSdFhat = computeDSDFhat(nd);
240  RankTwoTensor invF = _dgrad[nd].inverse();
241  Real detF = _dgrad[nd].det();
242  // calculation of jacobian contribution to current_node's neighbors
243  std::vector<dof_id_type> jvardofs(_nnodes);
244  jvardofs[0] = _current_elem->node_ptr(nd)->dof_number(_sys.number(), jvar_num, 0);
245  std::vector<dof_id_type> neighbors = _pdmesh.getNeighbors(_current_elem->node_id(nd));
246  std::vector<dof_id_type> bonds = _pdmesh.getBonds(_current_elem->node_id(nd));
247 
248  dof_id_type nb_index =
249  std::find(neighbors.begin(), neighbors.end(), _current_elem->node_id(1 - nd)) -
250  neighbors.begin();
251  std::vector<dof_id_type> dg_neighbors =
252  _pdmesh.getBondDeformationGradientNeighbors(_current_elem->node_id(nd), nb_index);
253 
254  Real vol_nb, dJdU;
255  RealGradient origin_vec_nb;
256  RankTwoTensor dFdUk, dPxdUky, dSdU, dinvFTdU;
257 
258  for (unsigned int nb = 0; nb < dg_neighbors.size(); ++nb)
259  if (_bond_status_var->getElementalValue(_pdmesh.elemPtr(bonds[dg_neighbors[nb]])) > 0.5)
260  {
261  jvardofs[1] =
262  _pdmesh.nodePtr(neighbors[dg_neighbors[nb]])->dof_number(_sys.number(), jvar_num, 0);
263  vol_nb = _pdmesh.getNodeVolume(neighbors[dg_neighbors[nb]]);
264 
265  origin_vec_nb = _pdmesh.getNodeCoord(neighbors[dg_neighbors[nb]]) -
266  _pdmesh.getNodeCoord(_current_elem->node_id(nd));
267 
268  dFdUk.zero();
269  for (unsigned int i = 0; i < _dim; ++i)
270  dFdUk(coupled_component, i) =
271  _horizon_radius[nd] / origin_vec_nb.norm() * origin_vec_nb(i) * vol_nb;
272 
273  dFdUk *= _shape2[nd].inverse();
274 
275  // calculate dJ/du
276  dJdU = 0.0;
277  for (unsigned int i = 0; i < 3; ++i)
278  for (unsigned int j = 0; j < 3; ++j)
279  dJdU += detF * invF(j, i) * dFdUk(i, j);
280 
281  // calculate dS/du
282  dSdU = dSdFhat * dFdUk * _dgrad_old[nd].inverse();
283 
284  // calculate dinv(F)Tdu
285  dinvFTdU.zero();
286  for (unsigned int i = 0; i < 3; ++i)
287  for (unsigned int J = 0; J < 3; ++J)
288  for (unsigned int k = 0; k < 3; ++k)
289  for (unsigned int L = 0; L < 3; ++L)
290  dinvFTdU(i, J) += -invF(J, k) * invF(L, i) * dFdUk(k, L);
291 
292  // calculate the derivative of first Piola-Kirchhoff stress w.r.t displacements
293  dPxdUky = dJdU * _stress[nd] * invF.transpose() + detF * dSdU * invF.transpose() +
294  detF * _stress[nd] * dinvFTdU;
295 
296  for (unsigned int i = 0; i < _nnodes; ++i)
297  for (unsigned int j = 0; j < _nnodes; ++j)
298  _local_ke(i, j) = (i == 0 ? -1 : 1) * (j == 0 ? 0 : 1) * _multi[nd] *
299  (dPxdUky * _shape2[nd].inverse()).row(_component) * _origin_vec *
300  _bond_status;
301 
302  addJacobian(_assembly, _local_ke, _ivardofs, jvardofs, _var.scalingFactor());
303  }
304  }
305  }
306 }
RankFourTensor computeDSDFhat(unsigned int nd)
Function to compute derivative of stress with respect to derived deformation gradient.
Base kernel class for finite strain correspondence models.
registerMooseObject("PeridynamicsApp", HorizonStabilizedFormIFiniteStrainMechanicsNOSPD)
const bool _temp_coupled
Temperature variable.
auto norm() const -> decltype(std::norm(Real()))
RankTwoTensor computeDinvFTDU(unsigned int component, unsigned int nd)
Function to compute derivative of deformation gradient inverse with respect to displacements.
const MaterialProperty< RankFourTensor > & _Jacobian_mult
unsigned int number() const
const MaterialProperty< RankTwoTensor > & _stress
void inverse(const std::vector< std::vector< Real >> &m, std::vector< std::vector< Real >> &m_inv)
const bool _out_of_plane_strain_coupled
Parameters for out-of-plane strain in weak plane stress formulation.
void addRequiredParam(const std::string &name, const std::string &doc_string)
std::vector< const MaterialProperty< RankTwoTensor > * > _deigenstrain_dT
const MaterialProperty< RankTwoTensor > & _dgrad_old
Material point based material property.
virtual 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...
virtual RankTwoTensor computeDSDU(unsigned int component, unsigned int nd) override
Function to compute derivative of stress with respect to displacements for small strain problems...
Real computeDJDU(unsigned int component, unsigned int nd)
Function to compute derivative of determinant of deformation gradient with respect to displacements...
MooseVariable * _out_of_plane_strain_var
std::vector< dof_id_type > _ivardofs
Current variable dof numbers for nodes i and j.
Kernel class for Form I of the horizon-stabilized peridynamic correspondence model for finite strain...
const MaterialProperty< RankTwoTensor > & _shape2
const MaterialProperty< Real > & _multi
Material point based material properties.
const unsigned int _component
The index of displacement component.
RankTwoTensorTempl< Real > transpose() const
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
void addClassDescription(const std::string &doc_string)
virtual 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...
static const std::complex< double > j(0, 1)
Complex number "j" (also known as "i")
MooseVariable * _temp_var
static const std::string k
Definition: NS.h:130
void ErrorVector unsigned int
uint8_t dof_id_type
const MaterialProperty< RankTwoTensor > & _dgrad