https://mooseframework.inl.gov
Loading...
Searching...
No Matches
HomogenizedTotalLagrangianStressDivergence.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
12// MOOSE includes
13#include "Function.h"
14#include "MooseVariableScalar.h"
15
17
20{
22 params.addClassDescription("Total Lagrangian stress equilibrium kernel with "
23 "homogenization constraint Jacobian terms");
24 params.renameCoupledVar(
25 "scalar_variable", "macro_var", "Optional scalar field with the macro gradient");
26
27 params.addParam<bool>(
28 "off_diagonal_jacobian", true, "Include the off diagonal parts of the constraint Jacobian");
29
30 return params;
31}
32
34 const InputParameters & parameters)
36 _use_off_diagonal(getParam<bool>("off_diagonal_jacobian"))
37{
38}
39
40std::set<std::string>
42{
43 // Add the scalar variable to the list of variables that this kernel contributes to
44 std::set<std::string> vars = TotalLagrangianStressDivergence::additionalROVariables();
45 vars.insert(_kappa_var_ptr->name());
46 return vars;
47}
48
49void
51{
52 if (_alpha != 0)
53 return;
54
55 std::vector<Real> scalar_residuals(_k_order);
56
57 // only assemble scalar residual once; i.e. when handling the first displacement component
58 for (_qp = 0; _qp < _qrule->n_points(); _qp++)
59 {
60 initScalarQpResidual();
61 const auto dV = _JxW[_qp] * _coord[_qp];
62
63 // index for residual vector
64 unsigned int h = 0;
65
66 for (const auto & [indices, constraint] : cmap())
67 {
68 const auto [i, j] = indices;
69 const auto [ctype, ctarget] = constraint;
70 const auto cval = ctarget->value(_t, _q_point[_qp]);
71
72 // value to be constrained
73 Real val;
75 {
77 val = _pk1[_qp](i, j);
79 val = _F[_qp](i, j) - (Real(i == j));
80 else
81 mooseError("Unknown constraint type in the integral!");
82 }
83 else
84 {
86 val = _pk1[_qp](i, j);
88 val = 0.5 * (_F[_qp](i, j) + _F[_qp](j, i)) - (Real(i == j));
89 else
90 mooseError("Unknown constraint type in the integral!");
91 }
92
93 scalar_residuals[h++] += (val - cval) * dV;
94 }
95 }
96
97 addResiduals(
98 _assembly, scalar_residuals, _kappa_var_ptr->dofIndices(), _kappa_var_ptr->scalingFactor());
99}
100
101void
103{
104 if (_alpha != 0)
105 return;
106
107 _local_ke.resize(_k_order, _k_order);
108
109 // only assemble scalar residual once; i.e. when handling the first displacement component
110 for (_qp = 0; _qp < _qrule->n_points(); _qp++)
111 {
112 initScalarQpJacobian(_kappa_var);
113 const auto dV = _JxW[_qp] * _coord[_qp];
114
115 // index for Jacobian row
116 unsigned int h = 0;
117
118 for (const auto & [indices1, constraint1] : cmap())
119 {
120 const auto [i, j] = indices1;
121 const auto ctype = constraint1.first;
122
123 // index for Jacobian col
124 unsigned int m = 0;
125
126 for (const auto & [indices2, constraint2] : cmap())
127 {
128 const auto [k, l] = indices2;
130 // Macro_grad <-> macro_grad: scalar perturbation bypasses F-bar (the
131 // homogenization material adds to `_F` AFTER F-bar runs), so use the
132 // bypass variant of pk1_jacobian.
133 _local_ke(h, m++) += dV * (_dpk1_bypass_fbar[_qp](i, j, k, l));
135 {
137 _local_ke(h, m++) += dV * (Real(i == k && j == l));
138 else
139 _local_ke(h, m++) += dV * (0.5 * Real(i == k && j == l) + 0.5 * Real(i == l && j == k));
140 }
141 else
142 mooseError("Unknown constraint type in Jacobian calculator!");
143 }
144 h++;
145 }
146 }
147
148 addJacobian(_assembly,
149 _local_ke,
150 _kappa_var_ptr->dofIndices(),
151 _kappa_var_ptr->dofIndices(),
152 _kappa_var_ptr->scalingFactor());
153}
154
155void
157 const unsigned int jvar_num)
158{
160 return;
161
162 // ONLY assemble the contribution from _alpha component, which is connected with _var
163 // The other components are handled by other kernel instances with other _alpha
164 if (jvar_num != _var.number())
165 return;
166
167 const auto & jvar = getVariable(jvar_num);
168 const auto jvar_size = jvar.phiSize();
169 _local_ke.resize(_k_order, jvar_size);
170
171 // The scalar<->disp Jacobian needs `_avg_grad_trial[_alpha]` populated (for the
172 // non-local F-bar chain via `_d_F_stab_d_F_avg * deltaF_avg`). The base
173 // `precalculateOffDiagJacobian` only does this when the off-diag jvar IS a
174 // displacement; for the scalar-driven path it must be triggered explicitly.
176 {
177 _fe_problem.prepareShapes(jvar_num, _tid);
178 _avg_grad_trial[_alpha].resize(_phi.size());
180 }
181
182 for (_qp = 0; _qp < _qrule->n_points(); _qp++)
183 {
184 const auto dV = _JxW[_qp] * _coord[_qp];
185
186 // index for Jacobian row
187 unsigned int h = 0;
188
189 for (const auto & [indices, constraint] : cmap())
190 {
191 std::tie(_m, _n) = indices;
192 _ctype = constraint.first;
193 initScalarQpOffDiagJacobian(jvar);
194 for (_j = 0; _j < jvar_size; _j++)
195 _local_ke(h, _j) += dV * computeScalarQpOffDiagJacobian(jvar_num);
196 h++;
197 }
198 }
199
200 addJacobian(_assembly,
201 _local_ke,
202 _kappa_var_ptr->dofIndices(),
203 jvar.dofIndices(),
204 _kappa_var_ptr->scalingFactor());
205}
206
207void
209 const unsigned int svar_num)
210{
212 return;
213
214 // Just in case, skip any other scalar variables
215 if (svar_num != _kappa_var)
216 return;
217
218 _local_ke.resize(_test.size(), _k_order);
219
220 for (_qp = 0; _qp < _qrule->n_points(); _qp++)
221 {
222 unsigned int l = 0;
223 const auto dV = _JxW[_qp] * _coord[_qp];
224 for (const auto & [indices, constraint] : cmap())
225 {
226 // copy constraint indices to protected variables to pass to Qp routine
227 std::tie(_m, _n) = indices;
228 _ctype = constraint.first;
229 initScalarQpJacobian(svar_num);
230 for (_i = 0; _i < _test.size(); _i++)
231 _local_ke(_i, l) += dV * computeQpOffDiagJacobianScalar(svar_num);
232 l++;
233 }
234 }
235
236 addJacobian(
237 _assembly, _local_ke, _var.dofIndices(), _kappa_var_ptr->dofIndices(), _var.scalingFactor());
238}
239
240Real
242 unsigned int /*svar_num*/)
243{
244 // d(disp residual) / d(scalar_{m,n}) = int gradTest_alpha : d(PK1)/d(scalar_{m,n}) dV.
245 // The macro_gradient adds to `_F` AFTER F-bar runs (in
246 // `ComputeLagrangianStrainBase::computeQpProperties`), so scalar perturbations
247 // bypass F-bar's chain -- use `_dpk1_bypass_fbar` (pk1_jacobian with the F-bar
248 // `_d_F_stab_d_F_ust` factor REPLACED by identity in the sigma chain).
249 return _dpk1_bypass_fbar[_qp].contractionKl(_m, _n, gradTest(_alpha));
250}
251
252Real
254 unsigned int /*jvar_num*/)
255{
257 {
258 // d(PK1_{m,n})/d(grad u_beta,j) -- local chain via _dpk1 (= dPK1/d(grad u) including
259 // local F-bar effect via the sigma-chain through `_d_F_stab_d_F_ust`).
260 Real J = _dpk1[_qp].contractionIj(_m, _n, gradTrial(_alpha));
261
262 // Non-local F-bar contribution to PK1 component (m, n) via the shared helper --
263 // same chain as the regular TL displacement Jacobian but contracted into the single
264 // (m, n) entry rather than doubled with gradTest. Guarded on `_stabilize_strain`
265 // because `_avg_grad_trial` is only populated when F-bar is on.
267 {
268 const RankTwoTensor delta_F_avg = _d_F_d_grad_u[_qp] * _avg_grad_trial[_alpha][_j];
269 J += deltaPK1NonLocalFBar(delta_F_avg)(_m, _n);
270 }
271 return J;
272 }
274 {
275 // d(F_stab_{m,n})/d(disp_alpha_j) -- for F-bar on, the F-bar chain couples F_stab to
276 // F_ust through both LOCAL (`_d_F_stab_d_F_ust`) and NON-LOCAL
277 // (`_d_F_stab_d_F_avg * deltaF_avg`) routes. The old `Real(_m == _alpha) *
278 // gradTrial(_m, _n)` form captured only the F-bar-off case correctly.
279 const RankTwoTensor delta_F_ust_local = _d_F_d_grad_u[_qp] * gradTrialUnstabilized(_alpha);
280 RankTwoTensor delta_F_stab = _d_F_stab_d_F_ust[_qp] * delta_F_ust_local;
282 {
283 const RankTwoTensor delta_F_avg = _d_F_d_grad_u[_qp] * _avg_grad_trial[_alpha][_j];
284 delta_F_stab += _d_F_stab_d_F_avg[_qp] * delta_F_avg;
285 }
287 return delta_F_stab(_m, _n);
288 else
289 return 0.5 * (delta_F_stab(_m, _n) + delta_F_stab(_n, _m));
290 }
291 else
292 mooseError("Unknown constraint type in kernel calculation!");
293}
registerMooseObject("SolidMechanicsApp", HomogenizedTotalLagrangianStressDivergence)
void mooseError(Args &&... args)
char ** vars
Interface for objects that use the homogenization constraint.
static InputParameters validParams()
const Homogenization::ConstraintMap & cmap() const
Get the constraint map.
Total Lagrangian formulation with all homogenization terms (one disp_xyz field and macro_gradient sca...
virtual void computeScalarOffDiagJacobian(const unsigned int jvar_num) override
Method for computing an off-diagonal jacobian component d-_kappa-residual / d-jvar.
virtual Real computeQpOffDiagJacobianScalar(const unsigned int svar_num) override
Method for computing d-_var-residual / d-svar at quadrature points.
const bool _use_off_diagonal
Whether to use the off diagonal term.
Homogenization::ConstraintType _ctype
Type of current homogenization constraint.
virtual Real computeScalarQpOffDiagJacobian(const unsigned int jvar_num) override
Method for computing an off-diagonal jacobian component at quadrature points.
virtual std::set< std::string > additionalROVariables() override
Inform moose that this kernel covers the constraint scalar variable.
virtual void computeScalarJacobian() override
Method for computing the scalar variable part of Jacobian for d-_kappa-residual / d-_kappa.
virtual void computeScalarResidual() override
Method for computing the scalar part of residual for _kappa.
virtual void computeOffDiagJacobianScalarLocal(const unsigned int svar_num) override
Method for computing an off-diagonal jacobian component d-_var-residual / d-svar.
unsigned int _m
Indices for off-diagonal Jacobian components.
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
void renameCoupledVar(const std::string &old_name, const std::string &new_name, const std::string &new_docstring)
void addClassDescription(const std::string &doc_string)
RankTwoTensor deltaPK1NonLocalFBar(const RankTwoTensor &delta_F_avg) const
Non-local F-bar contribution to deltaPK1 at the current _qp, given the perturbation delta_F_avg of th...
const MaterialProperty< RankTwoTensor > & _F
The actual (stabilized) deformation gradient.
const bool _stabilize_strain
If true calculate the deformation gradient derivatives for F_bar.
const unsigned int _alpha
Which component of the vector residual this kernel is responsible for.
bool _large_kinematics
If true use large deformation kinematics.
const MaterialProperty< RankFourTensor > & _d_F_stab_d_F_avg
const MaterialProperty< RankFourTensor > & _d_F_stab_d_F_ust
Partials of the F-bar-stabilized deformation gradient.
std::vector< std::vector< RankTwoTensor > > _avg_grad_trial
const MaterialProperty< RankFourTensor > & _d_F_d_grad_u
Derivative of F_{n+1} w.r.t. the displacement gradient.
Enforce equilibrium with a total Lagrangian formulation.
virtual RankTwoTensor gradTrial(unsigned int component) override
virtual RankTwoTensor gradTrialUnstabilized(unsigned int component)
The unstabilized trial function gradient.
virtual void precalculateJacobianDisplacement(unsigned int component) override
Prepare the average shape function gradients for stabilization.
virtual RankTwoTensor gradTest(unsigned int component) override
const MaterialProperty< RankTwoTensor > & _pk1
The 1st Piola-Kirchhoff stress.
const MaterialProperty< RankFourTensor > & _dpk1_bypass_fbar
Variant of _dpk1 (= pk1_jacobian) computed WITHOUT the F-bar chain factor _d_F_stab_d_F_ust in the si...
const MaterialProperty< RankFourTensor > & _dpk1
The derivative of the PK1 stress with respect to the deformation gradient (F that the stress material...