https://mooseframework.inl.gov
Loading...
Searching...
No Matches
LagrangianObjectiveRateTest.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
10#include "gtest/gtest.h"
11
13#include "RankTwoTensor.h"
14#include "RankFourTensor.h"
15
16// Unit tests for the objective-stress-rate free functions. These exercise the rate math in
17// isolation -- no host material, no assembly -- which is exactly what the free-function form
18// (vs the former host-coupled strategy hierarchy) enables.
19
20using namespace LagrangianObjectiveRates;
21
22namespace
23{
26isotropicC()
27{
29 C.fillFromInputVector({100.0, 60.0}, RankFourTensor::symmetric_isotropic); // {lambda, mu}
30 return C;
31}
32
34const RankTwoTensor kSigmaOld(30.0, -10.0, 15.0, 4.0, -3.0, 6.0);
35
41makeInputs(const RankFourTensor & C, const RankTwoTensor & dL)
42{
43 Inputs in;
44 in.small_jacobian = C;
45 in.cauchy_stress_old = kSigmaOld;
46 in.dL = dL;
47 in.dW = 0.5 * (dL - dL.transpose());
48 in.dS = C * (0.5 * (dL + dL.transpose()));
50 // d(skew(A))/dA = 1/2 (I^(4) - swap_ij), swap_ij = I^(4) with its first index pair transposed.
51 in.d_dW_d_F =
53 return in;
54}
55
57void
58checkJacobianFD(Outputs (*rate)(const Inputs &, bool),
59 const RankFourTensor & C,
60 const RankTwoTensor & dL)
61{
62 const RankFourTensor J = rate(makeInputs(C, dL), true).cauchy_jacobian;
63 const Real eps = 1.0e-6;
65 for (unsigned int k = 0; k < 3; ++k)
66 for (unsigned int l = 0; l < 3; ++l)
67 {
68 RankTwoTensor dLp = dL, dLm = dL;
69 dLp(k, l) += eps;
70 dLm(k, l) -= eps;
71 const RankTwoTensor d = (rate(makeInputs(C, dLp), false).cauchy_stress -
72 rate(makeInputs(C, dLm), false).cauchy_stress) /
73 (2.0 * eps);
74 for (unsigned int i = 0; i < 3; ++i)
75 for (unsigned int j = 0; j < 3; ++j)
76 Jfd(i, j, k, l) = d(i, j);
77 }
78 EXPECT_LT((Jfd - J).L2norm(), 1.0e-4 * J.L2norm());
79}
80}
81
82// With no kinematic increment every rate leaves the stress unadvected: sigma_{n+1} = sigma_n + dS.
83TEST(LagrangianObjectiveRateTest, zeroIncrement)
84{
85 Inputs in = makeInputs(isotropicC(), RankTwoTensor()); // dL = 0 -> dS = 0, dW = 0
90 const RankTwoTensor expected = in.cauchy_stress_old + in.dS;
91 EXPECT_LT((truesdell(in, false).cauchy_stress - expected).L2norm(), 1.0e-12);
92 EXPECT_LT((jaumann(in, false).cauchy_stress - expected).L2norm(), 1.0e-12);
93 EXPECT_LT((greenNaghdi(in, false).cauchy_stress - expected).L2norm(), 1.0e-12);
94 EXPECT_LT((rashid(in, false).cauchy_stress - expected).L2norm(), 1.0e-12);
95}
96
97// Consistent-tangent checks: the returned cauchy_jacobian must equal d(cauchy_stress)/d(dL).
98TEST(LagrangianObjectiveRateTest, truesdellJacobian)
99{
100 checkJacobianFD(&truesdell, isotropicC(), RankTwoTensor(0.03, -0.02, 0.01, 0.015, -0.01, 0.02));
101}
102
103TEST(LagrangianObjectiveRateTest, jaumannJacobian)
104{
105 checkJacobianFD(&jaumann, isotropicC(), RankTwoTensor(0.03, -0.02, 0.01, 0.015, -0.01, 0.02));
106}
107
108TEST(LagrangianObjectiveRateTest, rashidJacobian)
109{
110 // Add an antisymmetric part so r_hat = exp(skew(dL)) != I and the Rodrigues chain is exercised.
111 RankTwoTensor dL(0.03, -0.02, 0.01, 0.015, -0.01, 0.02);
112 dL(0, 1) += 0.02;
113 dL(1, 0) -= 0.02;
114 checkJacobianFD(&rashid, isotropicC(), dL);
115}
TEST(LagrangianObjectiveRateTest, zeroIncrement)
void fillFromInputVector(const std::vector< T > &input, FillMethod fill_method)
static RankFourTensorTempl< T > IdentityFour()
RankTwoTensorTempl< T > transpose() const
static RankTwoTensorTempl Identity()
Objective-stress-rate updates as stateless free functions.
Outputs jaumann(const Inputs &in, bool need_jacobian)
sigma_{n+1} = J(dW)^{-1} (sigma_n + Deltasigma). Jaumann rate.
Outputs greenNaghdi(const Inputs &in, bool need_jacobian)
sigma_{n+1} = J(dO)^{-1} (sigma_n + Deltasigma), with dO built from the polar rotation increment.
Outputs truesdell(const Inputs &in, bool need_jacobian)
sigma_{n+1} = J(dL)^{-1} (sigma_n + Deltasigma). Truesdell rate.
Outputs rashid(const Inputs &in, bool need_jacobian)
sigma_{n+1} = r_hat (sigma_n + Deltasigma) r_hat^T, r_hat = exp(Deltaw).
T L2norm(const RankTwoTensorTempl< T > &r2tensor)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
Per-qp quantities a rate reads.
RankFourTensor d_dL_d_F
d(dL)/dF and d(dW)/dF from the strain calculator.
RankTwoTensor dL
Spatial velocity gradient increment dL and its vorticity (skew) part dW.
RankTwoTensor rotation
Green-Naghdi only: polar-decomposition rotation R (n+1 and n), the inverse incremental deformation gr...
RankTwoTensor cauchy_stress_old
Cumulative Cauchy stress at step n.
RankTwoTensor dS
Constitutive small-stress increment (_small_stress - _small_stress_old).
RankFourTensor small_jacobian
Small-strain algorithmic tangent.
Per-qp outputs a rate produces.