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 -> decltype(std::norm(Real()))
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)