OGS
Lubby2.cpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright (c) OpenGeoSys Community (opengeosys.org)
2// SPDX-License-Identifier: BSD-3-Clause
3
4#include "Lubby2.h"
5
6#include <Eigen/LU>
7
9
10namespace MPL = MaterialPropertyLib;
11
12namespace MaterialLib
13{
14namespace Solids
15{
16namespace Lubby2
17{
20template <int DisplacementDim>
21Eigen::Matrix<double, Lubby2<DisplacementDim>::JacobianResidualSize,
24{
25 Eigen::Matrix<double, Lubby2<DisplacementDim>::JacobianResidualSize,
27 dGdE =
28 Eigen::Matrix<double, Lubby2<DisplacementDim>::JacobianResidualSize,
30 dGdE.template topLeftCorner<Lubby2<DisplacementDim>::KelvinVectorSize,
32 .diagonal()
33 .setConstant(-2.);
34 return dGdE;
35}
36
37template <int DisplacementDim, typename LinearSolver>
39 double const GM0, double const KM0, LinearSolver const& linear_solver)
40{
41 // Calculate dGdE for time step
42 auto const dGdE = calculatedGdEBurgers<DisplacementDim>();
43
44 // Consistent tangent from local Newton iteration of material
45 // functionals.
46 // Only the upper left block is relevant for the global tangent.
47 static int const KelvinVectorSize =
49 using KelvinMatrix =
51
52 KelvinMatrix const dzdE =
53 linear_solver.solve(-dGdE)
54 .template topLeftCorner<KelvinVectorSize, KelvinVectorSize>();
55
57 auto const& P_sph = Invariants::spherical_projection;
58 auto const& P_dev = Invariants::deviatoric_projection;
59
60 KelvinMatrix C = GM0 * dzdE * P_dev + 3. * KM0 * P_sph;
61 return C;
62};
63
64template <int DisplacementDim>
65std::optional<std::tuple<typename Lubby2<DisplacementDim>::KelvinVector,
66 std::unique_ptr<typename MechanicsBase<
67 DisplacementDim>::MaterialStateVariables>,
70 MaterialPropertyLib::VariableArray const& variable_array_prev,
71 MaterialPropertyLib::VariableArray const& variable_array, double const t,
72 ParameterLib::SpatialPosition const& x, double const dt,
74 material_state_variables) const
75{
76 auto const& eps_m = std::get<MPL::SymmetricTensor<DisplacementDim>>(
77 variable_array.mechanical_strain);
78 auto const& eps_m_prev = std::get<MPL::SymmetricTensor<DisplacementDim>>(
79 variable_array_prev.mechanical_strain);
80 auto const& sigma_prev = std::get<MPL::SymmetricTensor<DisplacementDim>>(
81 variable_array_prev.stress);
82
84
85 assert(dynamic_cast<MaterialStateVariables const*>(
86 &material_state_variables) != nullptr);
88 static_cast<MaterialStateVariables const&>(material_state_variables));
90
91 auto local_lubby2_properties =
93
94 // calculation of deviatoric parts
95 auto const& P_dev = Invariants::deviatoric_projection;
96 KelvinVector const eps_m_d_i = P_dev * eps_m;
97 KelvinVector const eps_m_d_t = P_dev * eps_m_prev;
98
99 // initial guess as elastic predictor.
100 KelvinVector sigd_j = 2.0 * (eps_m_d_i - state.eps_M_t - state.eps_K_t);
101 // Note: sigd_t contains dimensionless stresses!
102 KelvinVector sigd_t = P_dev * sigma_prev / local_lubby2_properties.GM0;
103
104 // Calculate effective stress and update material properties
105 double sig_eff = Invariants::equivalentStress(sigd_j);
106 local_lubby2_properties.update(sig_eff);
107
108 using LocalJacobianMatrix =
109 Eigen::Matrix<double, KelvinVectorSize * 3, KelvinVectorSize * 3,
110 Eigen::RowMajor>;
111
112 // Linear solver for the newton loop is required after the loop with the
113 // same matrix. This saves one decomposition.
114 Eigen::FullPivLU<LocalJacobianMatrix> linear_solver;
115
116 // Different solvers are available for the solution of the local system.
117 // TODO Make the following choice of linear solvers available from the
118 // input file configuration:
119 // K_loc.partialPivLu().solve(-res_loc);
120 // K_loc.fullPivLu().solve(-res_loc);
121 // K_loc.householderQr().solve(-res_loc);
122 // K_loc.colPivHouseholderQr().solve(res_loc);
123 // K_loc.fullPivHouseholderQr().solve(-res_loc);
124 // K_loc.llt().solve(-res_loc);
125 // K_loc.ldlt().solve(-res_loc);
126
127 LocalJacobianMatrix K_loc;
128 { // Local Newton solver
129 using LocalResidualVector =
130 Eigen::Matrix<double, KelvinVectorSize * 3, 1>;
131
132 auto const update_residual = [&](LocalResidualVector& residual)
133 {
134 calculateResidualBurgers(dt, eps_m_d_i, eps_m_d_t, sigd_j, sigd_t,
135 state.eps_K_j, state.eps_K_t,
136 state.eps_M_j, state.eps_M_t, residual,
137 local_lubby2_properties);
138 };
139
140 auto const update_jacobian = [&](LocalJacobianMatrix& jacobian)
141 {
143 t, x, dt, jacobian, sig_eff, sigd_j, state.eps_K_j,
144 local_lubby2_properties); // for solution dependent Jacobians
145 };
146
147 auto const update_solution = [&](LocalResidualVector const& increment)
148 {
149 // increment solution vectors
150 sigd_j.noalias() += increment.template segment<KelvinVectorSize>(
151 KelvinVectorSize * 0);
152 state.eps_K_j.noalias() +=
153 increment.template segment<KelvinVectorSize>(KelvinVectorSize *
154 1);
155 state.eps_M_j.noalias() +=
156 increment.template segment<KelvinVectorSize>(KelvinVectorSize *
157 2);
158
159 // Calculate effective stress and update material properties
161 KelvinVectorSize>::equivalentStress(sigd_j);
162 local_lubby2_properties.update(sig_eff);
163 };
164
165 auto newton_solver = NumLib::NewtonRaphson(
166 linear_solver, update_jacobian, update_residual, update_solution,
168
169 auto const success_iterations = newton_solver.solve(K_loc);
170
171 if (!success_iterations)
172 {
173 return {};
174 }
175
176 // If the Newton loop didn't run, the linear solver will not be
177 // initialized.
178 // This happens usually for the first iteration of the first timestep.
179 if (*success_iterations == 0)
180 {
181 linear_solver.compute(K_loc);
182 }
183 }
184
185 KelvinMatrix C =
186 tangentStiffnessA<DisplacementDim>(local_lubby2_properties.GM0,
187 local_lubby2_properties.KM0,
188 linear_solver);
189
190 // Hydrostatic part for the stress and the tangent.
191 double const delta_eps_m_trace = Invariants::trace(eps_m - eps_m_prev);
192 double const sigma_trace_prev = Invariants::trace(sigma_prev);
193 KelvinVector const sigma =
194 local_lubby2_properties.GM0 * sigd_j +
195 (local_lubby2_properties.KM0 * delta_eps_m_trace +
196 sigma_trace_prev / 3.) *
197 Invariants::identity2;
198 return {std::make_tuple(
199 sigma,
200 std::unique_ptr<
202 new MaterialStateVariables{state}},
203 C)};
204}
205
206template <int DisplacementDim>
208 const double dt,
209 const KelvinVector& strain_curr,
210 const KelvinVector& strain_t,
211 const KelvinVector& stress_curr,
212 const KelvinVector& stress_t,
213 const KelvinVector& strain_Kel_curr,
214 const KelvinVector& strain_Kel_t,
215 const KelvinVector& strain_Max_curr,
216 const KelvinVector& strain_Max_t,
217 ResidualVector& res,
219{
220 // calculate stress residual
221 res.template segment<KelvinVectorSize>(0).noalias() =
222 (stress_curr - stress_t) -
223 2. * ((strain_curr - strain_t) - (strain_Kel_curr - strain_Kel_t) -
224 (strain_Max_curr - strain_Max_t));
225
226 // calculate Kelvin strain residual
227 res.template segment<KelvinVectorSize>(KelvinVectorSize).noalias() =
228 (strain_Kel_curr - strain_Kel_t) -
229 dt / (2. * properties.etaK) *
230 (properties.GM0 * stress_curr -
231 2. * properties.GK * strain_Kel_curr);
232
233 // calculate Maxwell strain residual
234 res.template segment<KelvinVectorSize>(2 * KelvinVectorSize).noalias() =
235 (strain_Max_curr - strain_Max_t) -
236 dt * 0.5 * properties.GM0 / properties.etaM * stress_curr;
237}
238
239template <int DisplacementDim>
241 double const t,
243 const double dt,
244 JacobianMatrix& Jac,
245 double s_eff,
246 const KelvinVector& sig_i,
247 const KelvinVector& eps_K_i,
249{
250 Jac.setZero();
251
252 // build G_11
253 Jac.template block<KelvinVectorSize, KelvinVectorSize>(0, 0)
254 .diagonal()
255 .setConstant(1.);
256
257 // build G_12
258 Jac.template block<KelvinVectorSize, KelvinVectorSize>(0, KelvinVectorSize)
259 .diagonal()
260 .setConstant(2.);
261
262 // build G_13
263 Jac.template block<KelvinVectorSize, KelvinVectorSize>(0,
265 .diagonal()
266 .setConstant(2.);
267
268 // build G_21
269 Jac.template block<KelvinVectorSize, KelvinVectorSize>(KelvinVectorSize, 0)
270 .noalias() =
271 -0.5 * dt * properties.GM0 / properties.etaK * KelvinMatrix::Identity();
272 if (s_eff > 0.)
273 {
274 KelvinVector const eps_K_aid =
275 1. / (properties.etaK * properties.etaK) *
276 (properties.GM0 * sig_i - 2. * properties.GK * eps_K_i);
277
278 KelvinVector const dG_K = 1.5 * _mp.mK(t, x)[0] * properties.GK *
279 properties.GM0 / s_eff * sig_i;
280 KelvinVector const dmu_vK = 1.5 * _mp.mvK(t, x)[0] * properties.GM0 *
281 properties.etaK / s_eff * sig_i;
282 Jac.template block<KelvinVectorSize, KelvinVectorSize>(KelvinVectorSize,
283 0)
284 .noalias() += 0.5 * dt * eps_K_aid * dmu_vK.transpose() +
285 dt / properties.etaK * eps_K_i * dG_K.transpose();
286 }
287
288 // build G_22
289 Jac.template block<KelvinVectorSize, KelvinVectorSize>(KelvinVectorSize,
291 .diagonal()
292 .setConstant(1. + dt * properties.GK / properties.etaK);
293
294 // nothing to do for G_23
295
296 // build G_31
297 Jac.template block<KelvinVectorSize, KelvinVectorSize>(2 * KelvinVectorSize,
298 0)
299 .noalias() =
300 -0.5 * dt * properties.GM0 / properties.etaM * KelvinMatrix::Identity();
301 if (s_eff > 0.)
302 {
303 KelvinVector const dmu_vM = 1.5 * _mp.mvM(t, x)[0] * properties.GM0 *
304 properties.etaM / s_eff * sig_i;
305 Jac.template block<KelvinVectorSize, KelvinVectorSize>(
306 2 * KelvinVectorSize, 0)
307 .noalias() += 0.5 * dt * properties.GM0 /
308 (properties.etaM * properties.etaM) * sig_i *
309 dmu_vM.transpose();
310 }
311
312 // nothing to do for G_32
313
314 // build G_33
315 Jac.template block<KelvinVectorSize, KelvinVectorSize>(2 * KelvinVectorSize,
317 .diagonal()
318 .setConstant(1.);
319}
320
321template class Lubby2<2>;
322template class Lubby2<3>;
323
324} // namespace Lubby2
325} // namespace Solids
326} // namespace MaterialLib
std::optional< std::tuple< KelvinVector, std::unique_ptr< typename MechanicsBase< DisplacementDim >::MaterialStateVariables >, KelvinMatrix > > integrateStress(MaterialPropertyLib::VariableArray const &variable_array_prev, MaterialPropertyLib::VariableArray const &variable_array, double const t, ParameterLib::SpatialPosition const &x, double const dt, typename MechanicsBase< DisplacementDim >::MaterialStateVariables const &material_state_variables) const override
Definition Lubby2.cpp:69
NumLib::NewtonRaphsonSolverParameters const _nonlinear_solver_parameters
Definition Lubby2.h:265
MathLib::KelvinVector::KelvinMatrixType< DisplacementDim > KelvinMatrix
Definition Lubby2.h:157
Eigen::Matrix< double, JacobianResidualSize, 1 > ResidualVector
Definition Lubby2.h:163
Lubby2MaterialProperties _mp
Definition Lubby2.h:266
Eigen::Matrix< double, JacobianResidualSize, JacobianResidualSize, Eigen::RowMajor > JacobianMatrix
Definition Lubby2.h:164
static int const KelvinVectorSize
Definition Lubby2.h:153
MathLib::KelvinVector::KelvinVectorType< DisplacementDim > KelvinVector
Definition Lubby2.h:155
void calculateJacobianBurgers(double const t, ParameterLib::SpatialPosition const &x, double const dt, JacobianMatrix &Jac, double s_eff, const KelvinVector &sig_i, const KelvinVector &eps_K_i, detail::LocalLubby2Properties< DisplacementDim > const &properties) const
Calculates the 18x18 Jacobian.
Definition Lubby2.cpp:240
void calculateResidualBurgers(double const dt, const KelvinVector &strain_curr, const KelvinVector &strain_t, const KelvinVector &stress_curr, const KelvinVector &stress_t, const KelvinVector &strain_Kel_curr, const KelvinVector &strain_Kel_t, const KelvinVector &strain_Max_curr, const KelvinVector &strain_Max_t, ResidualVector &res, detail::LocalLubby2Properties< DisplacementDim > const &properties) const
Calculates the 18x1 residual vector.
Definition Lubby2.cpp:207
MathLib::KelvinVector::KelvinMatrixType< DisplacementDim > tangentStiffnessA(double const GM0, double const KM0, LinearSolver const &linear_solver)
Definition Lubby2.cpp:38
Eigen::Matrix< double, Lubby2< DisplacementDim >::JacobianResidualSize, Lubby2< DisplacementDim >::KelvinVectorSize > calculatedGdEBurgers()
Definition Lubby2.cpp:23
constexpr int kelvin_vector_dimensions(int const displacement_dim)
Kelvin vector dimensions for given displacement dimension.
Eigen::Matrix< double, kelvin_vector_dimensions(DisplacementDim), kelvin_vector_dimensions(DisplacementDim), Eigen::RowMajor > KelvinMatrixType