https://mooseframework.inl.gov
Loading...
Searching...
No Matches
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{
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
38void
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
63void
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] *
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
80void
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
139void
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
168void
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}
registerMooseObject("PeridynamicsApp", ForceStabilizedSmallStrainMechanicsNOSPD)
void ErrorVector unsigned int
Kernel class for fictitious force stabilized peridynamic correspondence material model for small stra...
const MaterialProperty< Real > & _sf_coeff
Bond based material property for fictitious stabilization force.
const unsigned int _component
The index of displacement component.
ForceStabilizedSmallStrainMechanicsNOSPD(const InputParameters &parameters)
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.
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.
void addRequiredParam(const std::string &name, const std::string &doc_string)
void addClassDescription(const std::string &doc_string)
Base kernel class for bond-associated correspondence material models.
const MaterialProperty< RankTwoTensor > & _shape2
const MaterialProperty< RankTwoTensor > & _stress
std::vector< const MaterialProperty< RankTwoTensor > * > _deigenstrain_dT
const MaterialProperty< Real > & _multi
Material point based material properties.
virtual RankTwoTensor computeDSDU(unsigned int component, unsigned int nd)
Function to compute derivative of stress with respect to displacements for small strain problems.
const MaterialProperty< RankFourTensor > & _Jacobian_mult
static InputParameters validParams()
MooseVariable * _temp_var
std::vector< dof_id_type > _ivardofs
Current variable dof numbers for nodes i and j.
const bool _temp_coupled
Temperature variable.
std::vector< MooseVariable * > _disp_var
displacement variables
unsigned int number() const
RankTwoTensorTempl< T > inverse() const
RankTwoTensorTempl< T > transpose() const