1 /** @file unittest_UAT.cpp
2
3 @brief Unit tests performs Uniaxial Tension Test for Neo-Hookean, Mooney-Rivlin and Ogden material models
4
5 This file tests the following classes and functions:
6 - gsMaterialMatrix (dim=2, mat=1,3,4, impl=1,2,3)
7 - gsMaterialMatrixIntegrate (dim=2)
8 - gsMaterialMatrixBase
9 - gsThinShellAssembler (dim=2)
10 - assemble(), assembleMatrix(), assembleVector()
11 - boundaryFoceVector(), getArea()
12 - constructSolution(), computePrincipalStretches()
13
14 This file is part of the G+Smo library.
15
16 This Source Code Form is subject to the terms of the Mozilla Public
17 License, v. 2.0. If a copy of the MPL was not distributed with this
18 file, You can obtain one at http://mozilla.org/MPL/2.0/.
19
20 Author(s): H.M.Verhelst (2019 - ..., TU Delft)
21 */
22
23 #include <gismo.h>
24
25 #include <gsKLShell/gsThinShellAssembler.h>
26 #include <gsKLShell/getMaterialMatrix.h>
27
28 using namespace gismo;
29
numerical(index_t material,index_t impl,bool Compressibility)30 std::pair<real_t,real_t> numerical(index_t material, index_t impl, bool Compressibility)
31 {
32 //! [Parse command line]
33 index_t numRefine = 1;
34 index_t numElevate = 1;
35
36 real_t E_modulus = 1.0;
37 real_t PoissonRatio;
38 real_t Density = 1.0;
39 real_t Ratio = 7.0;
40
41 real_t mu = 1.5e6;
42 real_t thickness = 0.001;
43
44 real_t alpha1,alpha2,alpha3,mu1,mu2,mu3;
45 alpha1 = 1.3;
46 mu1 = 6.3e5/4.225e5*mu;
47 alpha2 = 5.0;
48 mu2 = 0.012e5/4.225e5*mu;
49 alpha3 = -2.0;
50 mu3 = -0.1e5/4.225e5*mu;
51
52 if (!Compressibility)
53 PoissonRatio = 0.5;
54 else
55 PoissonRatio = 0.45;
56
57 E_modulus = 2*mu*(1+PoissonRatio);
58
59 //! [Parse command line]
60
61 //! [Read input file]
62 gsMultiPatch<> mp, mp_def;
63
64 mp.addPatch( gsNurbsCreator<>::BSplineSquare(1) ); // degree
65
66 if (numElevate!=0)
67 mp.degreeElevate(numElevate);
68
69 // h-refine
70 for (int r =0; r < numRefine; ++r)
71 mp.uniformRefine();
72
73 mp_def = mp;
74
75 //! [Refinement]
76 gsMultiBasis<> dbasis(mp);
77
78 gsBoundaryConditions<> bc;
79 bc.setGeoMap(mp);
80
81 gsPointLoads<real_t> pLoads = gsPointLoads<real_t>();
82
83 real_t lambda = 2.0;
84 gsConstantFunction<> displx(lambda-1.0,2);
85
86 GISMO_ASSERT(mp.targetDim()==2,"Geometry must be planar (targetDim=2)!");
87 bc.addCondition(boundary::west, condition_type::dirichlet, 0, 0, false, 0 );
88
89 bc.addCondition(boundary::east, condition_type::dirichlet, &displx, 0, false, 0 );
90
91 bc.addCondition(boundary::south, condition_type::dirichlet, 0, 0, false, 1 );
92
93 //! [Refinement]
94
95 // Linear isotropic material model
96 gsVector<> tmp(2);
97 tmp.setZero();
98 gsConstantFunction<> force(tmp,2);
99 gsFunctionExpr<> t(std::to_string(thickness),2);
100 gsFunctionExpr<> E(std::to_string(E_modulus),2);
101 gsFunctionExpr<> nu(std::to_string(PoissonRatio),2);
102 gsFunctionExpr<> rho(std::to_string(Density),2);
103 gsConstantFunction<> ratio(Ratio,2);
104
105 gsConstantFunction<> alpha1fun(alpha1,2);
106 gsConstantFunction<> mu1fun(mu1,2);
107 gsConstantFunction<> alpha2fun(alpha2,2);
108 gsConstantFunction<> mu2fun(mu2,2);
109 gsConstantFunction<> alpha3fun(alpha3,2);
110 gsConstantFunction<> mu3fun(mu3,2);
111
112 std::vector<gsFunction<>*> parameters(3);
113 parameters[0] = &E;
114 parameters[1] = ν
115 parameters[2] = ∶
116 gsMaterialMatrixBase<real_t>* materialMatrix;
117
118 if (material==4)
119 {
120 parameters.resize(8);
121 parameters[0] = &E;
122 parameters[1] = ν
123 parameters[2] = &mu1fun;
124 parameters[3] = &alpha1fun;
125 parameters[4] = &mu2fun;
126 parameters[5] = &alpha2fun;
127 parameters[6] = &mu3fun;
128 parameters[7] = &alpha3fun;
129 }
130
131 gsOptionList options;
132 if (material==0)
133 {
134 GISMO_ERROR("This test is not available for SvK models");
135 }
136 else
137 {
138 options.addInt("Material","Material model: (0): SvK | (1): NH | (2): NH_ext | (3): MR | (4): Ogden",material);
139 options.addSwitch("Compressibility","Compressibility: (false): Imcompressible | (true): Compressible",Compressibility);
140 options.addInt("Implementation","Implementation: (0): Composites | (1): Analytical | (2): Generalized | (3): Spectral",impl);
141 materialMatrix = getMaterialMatrix<2,real_t>(mp,t,parameters,rho,options);
142 }
143
144 gsThinShellAssemblerBase<real_t>* assembler;
145 assembler = new gsThinShellAssembler<2, real_t, false >(mp,dbasis,bc,force,materialMatrix);
146
147 assembler->setPointLoads(pLoads);
148
149 // Function for the Jacobian
150 typedef std::function<gsSparseMatrix<real_t> (gsVector<real_t> const &)> Jacobian_t;
151 typedef std::function<gsVector<real_t> (gsVector<real_t> const &) > Residual_t;
152 Jacobian_t Jacobian = [&assembler,&mp_def](gsVector<real_t> const &x)
153 {
154 assembler->constructSolution(x,mp_def);
155 assembler->assembleMatrix(mp_def);
156 gsSparseMatrix<real_t> m = assembler->matrix();
157 return m;
158 };
159 // Function for the Residual
160 Residual_t Residual = [&assembler,&mp_def](gsVector<real_t> const &x)
161 {
162 assembler->constructSolution(x,mp_def);
163 assembler->assembleVector(mp_def);
164 return assembler->rhs();
165 };
166
167 // Define Matrices
168 assembler->assemble();
169
170 gsSparseMatrix<> matrix = assembler->matrix();
171 gsVector<> vector = assembler->rhs();
172
173 // Solve linear problem
174 gsVector<> solVector;
175 gsSparseSolver<>::CGDiagonal solver;
176 solver.compute( matrix );
177 solVector = solver.solve(vector);
178
179 gsVector<real_t> updateVector = solVector;
180 gsVector<real_t> resVec = Residual(solVector);
181 gsSparseMatrix<real_t> jacMat;
182 for (index_t it = 0; it != 100; ++it)
183 {
184 jacMat = Jacobian(solVector);
185 solver.compute(jacMat);
186 updateVector = solver.solve(resVec); // this is the UPDATE
187 solVector += updateVector;
188
189 resVec = Residual(solVector);
190
191 if (updateVector.norm() < 1e-6)
192 break;
193 else if (it+1 == it)
194 gsWarn<<"Maximum iterations reached!\n";
195 }
196
197 mp_def = assembler->constructSolution(solVector);
198
199 gsMultiPatch<> deformation = mp_def;
200 for (size_t k = 0; k != mp_def.nPatches(); ++k)
201 deformation.patch(k).coefs() -= mp.patch(k).coefs();
202
203 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
204 // Check solutions
205 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
206 // NOTE: all analytical solutions for compressible materials are fixed for displ=1; (lambda=2)
207
208 // Compute stretches (should be the same everywhere)
209 // Ordering: lambda(0) < lambda(1); lambda(2) is ALWAYS the through-thickness stretch
210 gsVector<> pt(2);
211 pt<<1,0;
212 gsMatrix<> lambdas = assembler->computePrincipalStretches(pt,mp_def,0);
213
214 // Get the total force on the tension boundary
215 patchSide ps(0,boundary::east);
216 gsMatrix<> forceVector = assembler->boundaryForceVector(mp_def,ps,0);
217 real_t sideForce = forceVector.sum();
218 real_t S = -sideForce / (thickness*lambdas(0)*lambdas(2));
219 real_t L = lambdas(0);
220
221 std::pair<real_t,real_t> result;
222 result.first = L;
223 result.second = S;
224
225 delete materialMatrix;
226 delete assembler;
227
228 return result;
229 }
230
analytical(index_t material,index_t impl,bool Compressibility)231 std::pair<real_t,real_t> analytical(index_t material, index_t impl, bool Compressibility)
232 {
233 real_t PoissonRatio;
234 real_t Ratio = 7.0;
235
236 real_t mu = 1.5e6;
237
238 real_t alpha1,alpha2,alpha3,mu1,mu2,mu3;
239 alpha1 = 1.3;
240 mu1 = 6.3e5/4.225e5*mu;
241 alpha2 = 5.0;
242 mu2 = 0.012e5/4.225e5*mu;
243 alpha3 = -2.0;
244 mu3 = -0.1e5/4.225e5*mu;
245
246 if (!Compressibility)
247 PoissonRatio = 0.5;
248 else
249 PoissonRatio = 0.45;
250
251 real_t lambda = 2.0;
252
253 real_t San,J,K,Lan;
254 if (material==1 && Compressibility)
255 {
256 K = 2*mu*(1+PoissonRatio)/(3-6*PoissonRatio);
257 J = 1.105598565;// specific for lambda==2!!
258 San = lambda*(0.5*mu*(-(2*(math::pow(lambda,2)+2*J/lambda))/(3*math::pow(J,2./3.)*lambda)+2*lambda/math::pow(J,2./3.))+0.25*K*(2*math::pow(J,2)/lambda-2./lambda))/J;
259 Lan = math::pow(J/lambda,0.5);
260 }
261 else if (material==1 && !Compressibility)
262 {
263 San = mu * (lambda*lambda - 1/lambda);
264 Lan = math::pow(1./lambda,0.5);
265 }
266 else if (material==3 && Compressibility)
267 {
268 real_t c2 = 1.0 / (Ratio+1);
269 real_t c1 = 1.0 - c2;
270 K = 2*mu*(1+PoissonRatio)/(3-6*PoissonRatio);
271 J = 1.099905842;// specific for lambda==2!!
272 San = lambda*(0.5*c1*mu*(-(2*(math::pow(lambda,2)+2*J/lambda))/(3*math::pow(J,2./3.)*lambda)+2*lambda/math::pow(J,2./3.))+0.5*c2*mu*(-(4*(2*lambda*J+math::pow(J,2)/math::pow(lambda,2)))/(3*math::pow(J,4./3.)*lambda)+4/math::pow(J,1./3.))+0.25*K*(2*math::pow(J,2)/lambda-2/lambda))/J;
273 Lan = math::pow(J/lambda,0.5);
274 }
275 else if (material==3 && !Compressibility)
276 {
277 real_t c2 = 1.0 / (Ratio+1);
278 real_t c1 = 1.0 - c2;
279 San =-mu*(c2*lambda*lambda+c2/lambda+c1)/lambda+lambda*(c1*lambda*mu+2*c2*mu);
280 Lan = math::pow(1./lambda,0.5);
281 }
282 else if (material==4 && Compressibility)
283 {
284 K = 2*mu*(1+PoissonRatio)/(3-6*PoissonRatio);
285 J = 1.088778638;// specific for lambda==2!!
286 San = 1./J* (lambda *( mu1*(2*math::pow(lambda/math::pow(J,1./3.),alpha1)*alpha1/(3*lambda)-2*math::pow(math::pow(J/lambda,0.5)/math::pow(J,1./3.),alpha1)*alpha1/(3*lambda))/alpha1+mu2*(2*math::pow(lambda/math::pow(J,1./3.),alpha2)*alpha2/(3*lambda)-2*math::pow(math::pow(J/lambda,0.5)/math::pow(J,1./3.),alpha2)*alpha2/(3*lambda))/alpha2+mu3*(2*math::pow(lambda/math::pow(J,1./3.),alpha3)*alpha3/(3*lambda)-2*math::pow(math::pow(J/lambda,0.5)/math::pow(J,1./3.),alpha3)*alpha3/(3*lambda))/alpha3+0.25*K*(2*math::pow(J,2)/lambda-2/lambda) ) );
287 Lan = math::pow(J/lambda,0.5);
288 }
289 else if (material==4 && !Compressibility)
290 {
291 San =-mu1*math::pow((1./lambda),0.5*alpha1)-mu2*math::pow((1./lambda),0.5*alpha2)-mu3*math::pow((1./lambda),0.5*alpha3)+mu1*math::pow(lambda,alpha1)+mu2*math::pow(lambda,alpha2)+mu3*math::pow(lambda,alpha3);
292 Lan = math::pow(1./lambda,0.5);
293 }
294 else
295 GISMO_ERROR("Material not treated");
296
297 std::pair<real_t,real_t> result;
298 result.first = Lan;
299 result.second = San;
300 return result;
301 }
302
303 // Choose among various shell examples, default = Thin Plate
main(int argc,char * argv[])304 int main(int argc, char *argv[])
305 {
306
307 real_t S, San,L,Lan;
308
309 std::vector<index_t> materials{ 1,3,4 };
310 std::vector<index_t> implementations{ 1,2,3 };
311 std::vector<bool> compressibility{ true,false };
312
313 std::pair<real_t,real_t> num, an;
314 real_t tol = 1e-9;
315 for (std::vector<index_t>::iterator mat = materials.begin(); mat!=materials.end(); mat++)
316 {
317 for (std::vector<index_t>::iterator impl = implementations.begin(); impl!=implementations.end(); impl++)
318 {
319 for (std::vector<bool>::iterator comp = compressibility.begin(); comp!=compressibility.end(); comp++)
320 {
321 if (*mat==4 && *impl!=3) continue;
322 num = numerical(*mat,*impl,*comp);
323 L = num.first;
324 S = num.second;
325
326 an = analytical(*mat,*impl,*comp);
327 Lan = an.first;
328 San = an.second;
329
330
331 if ( (std::abs(L-Lan)/Lan < tol) && (std::abs(S-San)/San < tol) )
332 gsInfo<<"Passed\n";
333 else
334 gsInfo<<"Failed; L error = "<<std::abs(L-Lan)/Lan<<"\t S error = "<<std::abs(S-San)/San<<"\n";
335 }
336 }
337 }
338
339 return EXIT_SUCCESS;
340
341 }// end main