shell.cc
Go to the documentation of this file.
1// LIC// ====================================================================
2// LIC// This file forms part of oomph-lib, the object-oriented,
3// LIC// multi-physics finite-element library, available
4// LIC// at http://www.oomph-lib.org.
5// LIC//
6// LIC// Copyright (C) 2006-2026 Matthias Heil and Andrew Hazel
7// LIC//
8// LIC// This library is free software; you can redistribute it and/or
9// LIC// modify it under the terms of the GNU Lesser General Public
10// LIC// License as published by the Free Software Foundation; either
11// LIC// version 2.1 of the License, or (at your option) any later version.
12// LIC//
13// LIC// This library is distributed in the hope that it will be useful,
14// LIC// but WITHOUT ANY WARRANTY; without even the implied warranty of
15// LIC// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16// LIC// Lesser General Public License for more details.
17// LIC//
18// LIC// You should have received a copy of the GNU Lesser General Public
19// LIC// License along with this library; if not, write to the Free Software
20// LIC// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21// LIC// 02110-1301 USA.
22// LIC//
23// LIC// The authors may be contacted at oomph-lib@maths.man.ac.uk.
24// LIC//
25// LIC//====================================================================
26
27// Driver code for benchmark of axisym non-linear solid equations
28// in cylindrical coordinates: Thick spherical shell with external pressure
29// Compare against analytical solution for an incompressible material
30
31// Generic routines
32#include "generic.h"
33
34// Axisymmetric non-linear solid equations in cylindrical coords
35#include "axisym_solid.h"
36
37// Elements used to solve an auxillary problem for benchmarking
38#include "benchmark_elements.h"
39
40// Constitutive laws
41#include "constitutive.h"
42
43// The mesh: annular
44#include "meshes/annular_mesh.h"
45// Line mesh for auxiliary 1D problem
46#include "meshes/one_d_mesh.h"
47
48using namespace std;
49using namespace oomph;
50
51//=======start_namespace==========================================
52/// Global physical variables
53//================================================================
55{
56 // Poisson ratio - only used in the compressible case
57 // (nu = 0.5 for incompressible material)
58 double nu = 0.4;
59
60 // The external pressure
61 double ext_pressure = 0.05;
62
63 // Traction function for appyling a pressure on the outer surface
64 void external_pressure_fct(const double& time,
65 const Vector<double>& xi,
66 const Vector<double>& x,
67 const Vector<double>& n,
68 Vector<double>& traction)
69 {
70 traction[0] = -1.0 * ext_pressure * n[0];
71 traction[1] = -1.0 * ext_pressure * n[1];
72 }
73} // namespace GlobalPhysicalVariables
74
75//=======start_namespace==========================================
76/// Global simulation settings
77//================================================================
79{
80 // Folder for output
81 string result_folder = "RESLT";
82
83 /// Flag for using a pressure formulation
85
86 /// If using a pressure formulation, is the solid incompressible?
87 bool incompressible = false;
88
89 // Number of elements in radial direction
90 unsigned n_radial = 10;
91
92 // Number of elements in azimuthal direction
93 unsigned n_azimuthal = 10;
94
95 // Inner radius
96 double a = 1.0;
97
98 // Thickness
99 double h = 0.5;
100} // namespace GlobalSimSettings
101
102//======================start_mesh================================
103/// Upgrade the mesh to a solidmesh.
104/// Quarter-annulus in quadrant r>0, z>0
105/// ntheta - no. elements in theta direction
106/// nr - no. elements in the radial direction
107/// a - Inner radius of annulus
108/// h - thickness of annulus
109//================================================================
110template<class ELEMENT>
111class ElasticTwoDAnnularMesh : public virtual TwoDAnnularMesh<ELEMENT>,
112 public virtual SolidMesh
113{
114public:
115 /// Constructor: Build mesh and copy Eulerian coords to Lagrangian
116 /// ones so that the initial configuration is the stress-free one.
118 const unsigned& ntheta,
119 const unsigned& nr,
120 const double& a,
121 const double& h,
124 ntheta, nr, 1.0, 1.0, false, time_stepper_pt),
126 0.25,
127 ntheta,
128 nr,
129 a,
130 h,
133 {
134 // Make the current configuration the undeformed one by
135 // setting the nodal Lagrangian coordinates to their current
136 // Eulerian ones
138 }
139}; // End mesh
140
141//==============start_problem=========================================
142/// Axisymmetric compression of a finite thickness shell in cylindrical
143/// polar coordiantes
144//====================================================================
145template<class ELEMENT>
146class ShellProblem : public Problem
147{
148public:
149 /// Constructor:
150 ShellProblem();
151
152 /// Destructor
154
155 /// Doc the solution
156 void doc_solution();
157
158private:
159 /// Create the boundary elements
161
162 /// Delete boundary elements and wipe the associated mesh
164 {
165 // How many surface elements are in the surface mesh
166 unsigned n_element = Surface_mesh_pt->nelement();
167
168 // Loop over the surface elements
169 for (unsigned e = 0; e < n_element; e++)
170 {
171 // Kill surface element
172 delete Surface_mesh_pt->element_pt(e);
173 }
174
175 // Wipe the mesh
176 Surface_mesh_pt->flush_element_and_node_storage();
177 } // end of delete_boundary_elements
178
179 /// Complete the problem setup (attach function/physical parameter pointers)
181
182 /// Bulk mesh
184
185 /// Pointer to the "surface" mesh
187
188 /// Pointer to constitutive law
190
191 // DocInfo object
193};
194
195//===============start_constructor========================================
196/// Constructor for unstructured solid problem
197//========================================================================
198template<class ELEMENT>
200{
201 // Set output directory
202 Doc_info.set_directory(GlobalSimSettings::result_folder);
203
204 // Initialise counter for solutions
205 Doc_info.number() = 0;
206
207 // Create the mesh: Quarter-annulus in the quadrant r>0, z>0.
208 Bulk_mesh_pt =
213
214 // Create the "surface mesh" that will contain only the interface
215 // elements. The constructor just creates the mesh without giving
216 // it any elements, nodes, etc.
217 Surface_mesh_pt = new Mesh;
218
219 // Create the boundary elements
220 create_boundary_elements();
221
222 // Add the two submeshes
223 add_sub_mesh(Bulk_mesh_pt);
224 add_sub_mesh(Surface_mesh_pt);
225
226 // Combine all sub-meshes into a single mesh
228
229 // Define a constitutive law from a strain energy density function.
230 // Version depends on the incompressibility flag
233 {
235 }
236 else
237 {
239 }
240 Constitutive_law_pt =
242
243 // Complete the problem set up
244 complete_problem_setup();
245
246 // Assign eqn numbers
247 oomph_info << "Number of equations: " << assign_eqn_numbers() << std::endl;
248
249} // end constructor
250
251//========start_of_complete_problem_setup==================================
252/// Assign function/parameter pointers, set boundary conditions etc.
253//=========================================================================
254template<class ELEMENT>
256{
257 // Determine number of bulk elements in mesh
258 const unsigned n_element_bulk = Bulk_mesh_pt->nelement();
259
260 // Loop over the bulk elements
261 for (unsigned e = 0; e < n_element_bulk; e++)
262 {
263 // Upcast from GeneralisedElement to the present element
264 ELEMENT* el_pt = dynamic_cast<ELEMENT*>(Bulk_mesh_pt->element_pt(e));
265
266 // Set the constitutive law
267 el_pt->constitutive_law_pt() = Constitutive_law_pt;
268
269 // Cast to element with pressure dofs
272
273 // Can set compressible/incompressible condition here
274 if (el_with_pres_pt != 0)
275 {
277 {
278 el_with_pres_pt->set_incompressible();
279 }
280 else
281 {
282 el_with_pres_pt->set_compressible();
283 }
284 }
285 } // End of loop over bulk elements
286
287 // Determine number of 1D interface elements in mesh
288 const unsigned n_interface_element = Surface_mesh_pt->nelement();
289
290 // Loop over the interface elements
291 for (unsigned e = 0; e < n_interface_element; e++)
292 {
293 // Upcast from GeneralisedElement to the present element
296 Surface_mesh_pt->element_pt(e));
297
298 // Set the traction function for applying pressure
300
301 } // End of loop over interface elements
302
303 // Set the Dirichlet boundary conditions for this problem
304 // Find number of nodes on boundary 3
305 unsigned n_boundary_node = Bulk_mesh_pt->nboundary_node(3);
306 // Loop over nodes on fixed boundary
307 for (unsigned n = 0; n < n_boundary_node; n++)
308 {
309 // Pin radial position on symmetry axis only
310 Bulk_mesh_pt->boundary_node_pt(3, n)->pin_position(0);
311 }
312 n_boundary_node = Bulk_mesh_pt->nboundary_node(1);
313 // Loop over nodes on fixed boundary
314 for (unsigned n = 0; n < n_boundary_node; n++)
315 {
316 // Pin radial position on symmetry axis only
317 Bulk_mesh_pt->boundary_node_pt(1, n)->pin_position(1);
318 }
319} // End complete_problem_setup
320
321//============start_of_create_boundary_elements==========================
322/// Create boundary elements
323//=======================================================================
324template<class ELEMENT>
326{
327 // Loop over elements on boundary 2
328 unsigned n_element = Bulk_mesh_pt->nboundary_element(2);
329 for (unsigned e = 0; e < n_element; e++)
330 {
331 // Set a pointer to the bulk element we wish to our interface
332 // element to
334 dynamic_cast<ELEMENT*>(Bulk_mesh_pt->boundary_element_pt(2, e));
335
336 // Find the index of the face of element e along boundary b
337 int face_index = Bulk_mesh_pt->face_index_at_boundary(2, e);
338
339 // Create the interface element
342 face_index);
343
344 // Add the interface element to the surface mesh
345 this->Surface_mesh_pt->add_element_pt(interface_element_pt);
346 interface_element_pt->set_boundary_number_in_bulk_mesh(2);
347 }
348} // end of create_boundary_elements
349
350
351//========================================================================
352/// Doc the solution
353//========================================================================
354template<class ELEMENT>
356{
358 char filename[100];
359
360 // Number of plot points
361 unsigned npts = 3;
362
364 "%s/bulk_soln_nu_%g_pres_%g.dat",
365 Doc_info.directory().c_str(),
368 some_file.open(filename);
369 Bulk_mesh_pt->output(some_file, npts);
370 some_file.close();
371
373 "%s/bulk_soln_nu_%g_pres_%g.vtu",
374 Doc_info.directory().c_str(),
377 some_file.open(filename);
378 Bulk_mesh_pt->output_paraview(some_file, npts);
379 some_file.close();
380
381 // Increment the counter
382 Doc_info.number()++;
383}
384
385
386//==============start_auxillary_problem===============================
387/// Axisymmetric compression of a finite thickness shell in cylindrical
388/// polar coordiantes
389//====================================================================
390class AuxiliaryShellProblem : public Problem
391{
392public:
393 /// Constructor:
395
396 /// Destructor
398
399 /// Doc the solution
400 void doc_solution();
401
402 /// Solve the auxiliary problem
404
405private:
406 /// Bulk mesh
408
409 /// Pointer to the "surface" mesh
411
412 // DocInfo object
414};
415
416
417//===============start_constructor========================================
418/// Constructor for auxiliary 1D problem
419//========================================================================
421{
422 // Set output directory
424
425 // Initialise counter for solutions
426 Doc_info.number() = 0;
427
428 // Create the mesh: use n_radial elements to match the 2D problem
432
433 // Only complete the setup if the material is compressible. Otherwise,
434 // an analytical solution will be used.
436 {
437 // Set the Poisson ratio in each element
438 unsigned n_el = Bulk_mesh_pt->nelement();
439 for (unsigned e = 0; e < n_el; e++)
440 {
441 // Cast to element
443 dynamic_cast<ShellBenchmarkElement<3>*>(Bulk_mesh_pt->element_pt(e));
444
445 // Set the Poisson ratio
447 }
448
449 // Loop over nodes and set the initial guess in each node: r=R
450 unsigned n_node = Bulk_mesh_pt->nnode();
451 for (unsigned n = 0; n < n_node; n++)
452 {
453 double r = Bulk_mesh_pt->node_pt(n)->x(0);
454 Bulk_mesh_pt->node_pt(n)->set_value(0, r);
455 }
456
457 // Create the "surface mesh" for application of boundary pressure
458 Surface_mesh_pt = new Mesh;
459
460 // Cast to the right-most element in the mesh
462 dynamic_cast<ShellBenchmarkElement<3>*>(
464
465 // Find the index of the face of element e (0) along boundary b (1)
466 int face_index = 1; // Bulk_mesh_pt->face_index_at_boundary(1, 0);
467
468 // Create the interface element
471
472 // Add the interface element to the surface mesh
473 this->Surface_mesh_pt->add_element_pt(interface_element_pt);
474 interface_element_pt->set_boundary_number_in_bulk_mesh(1);
475
476 // Set the pressure in the element
477 interface_element_pt->pressure_pt() =
479
480 // Add the two submeshes
483
484 // Combine all sub-meshes into a single mesh
486
487 // Assign eqn numbers
488 oomph_info << "Number of equations for auxiliary problem: "
489 << assign_eqn_numbers() << std::endl;
490 }
491} // end constructor
492
493//========================================================================
494/// Solve the auxiliary problem
495//========================================================================
497{
498 // If the material is incompressible, the problem can be solved
499 // analytically, but yields an algebriac equation which must still be
500 // solved numerically. This is done using a manual newton solve.
502 {
503 // Storage for residual and Jacobian
504 double residual, jacobian;
505
506 // Containers for undeformed and deformed inner/outer radii.
507 Vector<double> xi(2), r(2);
510
511 // Set the initial guess
512 r[0] = xi[0];
513 r[1] = xi[1];
514
515 // Derivative of outer coord. w.r.t. inner coord.
516 double dr1_dr0;
517
518 // Poisson ratio in incompressible case
519 const double nu = 0.5;
520
521 // Residual from the initial guess
522 r[1] = pow(pow(r[0], 3.0) + pow(xi[1], 3.0) - pow(xi[0], 3.0), 1.0 / 3.0);
523 residual =
524 (1.0 / (1.0 + nu)) * (0.25 * pow(xi[0] / r[0], 4.0) + xi[0] / r[0] -
525 0.25 * pow(xi[1] / r[1], 4.0) - xi[1] / r[1]) -
527
528 // Newton iteration loop
529 while (std::fabs(residual) > 1.0e-8)
530 {
531 // Calculate the Jacobian
532 dr1_dr0 =
533 pow(pow(r[0], 3.0) + pow(xi[1], 3.0) - pow(xi[0], 3.0), -2.0 / 3.0) *
534 r[0] * r[0];
535 jacobian = (1.0 / (1.0 + nu)) *
536 (-1.0 * (pow(xi[0] / r[0], 4.0) + xi[0] / r[0]) / r[0] +
537 (pow(xi[1] / r[1], 4.0) + xi[1] / r[1]) * dr1_dr0 / r[1]);
538 // Take a Newton step
539 r[0] = r[0] - residual / jacobian;
540
541 // Calculate the new residual
542 r[1] = pow(pow(r[0], 3.0) + pow(xi[1], 3.0) - pow(xi[0], 3.0), 1.0 / 3.0);
543 residual =
544 (1 / (1.0 + nu)) * (0.25 * pow(xi[0] / r[0], 4.0) + xi[0] / r[0] -
545 0.25 * pow(xi[1] / r[1], 4.0) - xi[1] / r[1]) -
547 }
548
549 // With the solution obtained, set nodal values from the analytic solution
550 unsigned n_node = Bulk_mesh_pt->nnode();
551 for (unsigned n = 0; n < n_node; n++)
552 {
553 double xi_tmp = Bulk_mesh_pt->node_pt(n)->x(0);
554 Bulk_mesh_pt->node_pt(n)->set_value(
555 0, pow(pow(r[0], 3.0) + pow(xi_tmp, 3.0) - pow(xi[0], 3.0), 1.0 / 3.0));
556 }
557 }
558 // Otherwise, perform a standard Newton solve using the benchmark elements.
559 else
560 {
561 newton_solve();
562 }
563}
564
565//========================================================================
566/// Doc the solution
567//========================================================================
569{
571 char filename[100];
572
573 // Number of plot points
574 unsigned npts = 3;
575
577 "%s/aux_soln_nu_%g_pres_%g.dat",
578 Doc_info.directory().c_str(),
581 some_file.open(filename);
582 Bulk_mesh_pt->output(some_file, npts);
583 some_file.close();
584
585 // Increment the counter
586 Doc_info.number()++;
587}
588
589//===========start_main===================================================
590/// Demonstrate how to solve an unstructured solid problem
591//========================================================================
592int main(int argc, char* argv[])
593{
594 // Store command line arguments
596
599 "--use_solid_pressure", &str_temp_solid_pressure, "Use solid pressure");
600
603 "--incompressible", &str_temp_incompressible, "Incompressible");
604
606 "--poisson", &GlobalPhysicalVariables::nu, "Poisson");
607
609 "--pressure", &GlobalPhysicalVariables::ext_pressure, "External pressure");
610
613
614 istringstream(str_temp_solid_pressure) >> std::boolalpha >>
616 istringstream(str_temp_incompressible) >> std::boolalpha >>
618
619 // If the Poisson ratio has been set to 0.5, but the
620 // use_pressure_formulation and/or incompressible flags are false, set them to
621 // true
622 if (std::fabs(GlobalPhysicalVariables::nu - 0.5) < 1.0e-10 &&
625 {
626 std::string warning_message =
627 "Inconsistency: Poisson ratio has been set to 0.5 but the \n"
628 "use_pressure_formulation and/or incompressible flags are false. \n"
629 "Setting both of these to true to proceed.";
634 }
635
636 // If the incompressibility flag has been set, we must use the solid
637 // pressure formulation. The Poisson ratio will not be used in this case.
640 {
641 std::string warning_message =
642 "Inconsistency: The incompressibility flag is true but we are not using "
643 "\n"
644 "the solid pressure formulation. Setting use_solid_pressure to true to "
645 "proceed. \n";
649 }
650
651 // Set the Poisson ratio to 0.5 if incompressibility has been specified. This
652 // is solely for the purpose of output
654 {
656 }
657
658 // End consistency checks
659
660 // Create the problem
662 {
663 // Build the problem with an additional degree of freedom for pressure
665
666 problem.newton_solve();
667 problem.doc_solution();
668 }
669 else
670 {
671 // Standard build
673
674 problem.newton_solve();
675 problem.doc_solution();
676 }
677
678 // Build and solve the auxiliary problem
680 aux_problem.solve_auxiliary_problem();
681 aux_problem.doc_solution();
682} // end main
Axisymmetric compression of a finite thickness shell in cylindrical polar coordiantes.
Definition shell.cc:391
~AuxiliaryShellProblem()
Destructor.
Definition shell.cc:397
Mesh * Surface_mesh_pt
Pointer to the "surface" mesh.
Definition shell.cc:410
AuxiliaryShellProblem()
Constructor:
Definition shell.cc:420
OneDMesh< ShellBenchmarkElement< 3 > > * Bulk_mesh_pt
Bulk mesh.
Definition shell.cc:407
void doc_solution()
Doc the solution.
Definition shell.cc:568
void solve_auxiliary_problem()
Solve the auxiliary problem.
Definition shell.cc:496
Upgrade the mesh to a solidmesh. Quarter-annulus in quadrant r>0, z>0 ntheta - no....
Definition shell.cc:113
ElasticTwoDAnnularMesh(const unsigned &ntheta, const unsigned &nr, const double &a, const double &h, TimeStepper *time_stepper_pt=&Mesh::Default_TimeStepper)
Constructor: Build mesh and copy Eulerian coords to Lagrangian ones so that the initial configuration...
Definition shell.cc:117
Axisymmetric compression of a finite thickness shell in cylindrical polar coordiantes.
Definition shell.cc:147
void create_boundary_elements()
Create the boundary elements.
Definition shell.cc:325
DocInfo Doc_info
Definition shell.cc:192
void complete_problem_setup()
Complete the problem setup (attach function/physical parameter pointers)
Definition shell.cc:255
Mesh * Surface_mesh_pt
Pointer to the "surface" mesh.
Definition shell.cc:186
void delete_boundary_elements()
Delete boundary elements and wipe the associated mesh.
Definition shell.cc:163
ElasticTwoDAnnularMesh< ELEMENT > * Bulk_mesh_pt
Bulk mesh.
Definition shell.cc:183
ConstitutiveLaw * Constitutive_law_pt
Pointer to constitutive law.
Definition shell.cc:189
void doc_solution()
Doc the solution.
Definition shell.cc:355
ShellProblem()
Constructor:
Definition shell.cc:199
~ShellProblem()
Destructor.
Definition shell.cc:153
Face elements for the application of an external pressure.
Global physical variables.
Definition shell.cc:55
void external_pressure_fct(const double &time, const Vector< double > &xi, const Vector< double > &x, const Vector< double > &n, Vector< double > &traction)
Definition shell.cc:64
Global simulation settings.
Definition shell.cc:79
unsigned n_azimuthal
Definition shell.cc:93
bool incompressible
If using a pressure formulation, is the solid incompressible?
Definition shell.cc:87
unsigned n_radial
Definition shell.cc:90
bool use_pressure_formulation
Flag for using a pressure formulation.
Definition shell.cc:84
string result_folder
Definition shell.cc:81
int main(int argc, char *argv[])
Demonstrate how to solve an unstructured solid problem.
Definition shell.cc:592