shell_unsteady.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// Constitutive laws
38#include "constitutive.h"
39
40// The mesh: annular
41#include "meshes/annular_mesh.h"
42// Line mesh for auxiliary 1D problem
43#include "meshes/one_d_mesh.h"
44
45using namespace std;
46using namespace oomph;
47
48//=======start_namespace==========================================
49/// Global physical variables
50//================================================================
52{
53 // Poisson ratio
54 double nu = 0.4;
55
56 // Coefficient amplitudes for the manufactured solution
57 double A0 = 0.05;
58 double B0 = 0.05;
59
60 // Oscillation frequency
61 double omega = 5.0;
62
63 // Get the principal stretches from the manufactured solution
64 Vector<double> get_principal_stretches(const double& time, const double& r)
65 {
66 Vector<double> lambda(2);
67 double A = A0 * sin(omega * time);
68 double B = B0 * sin(omega * time);
69 lambda[0] = 1.0 + A - 2.0 * B * pow(r, -3.0);
70 lambda[1] = 1.0 + A + B * pow(r, -3.0);
71 return lambda;
72 }
73
74 // Get derivatives of prinicipal stretches w.r.t. r
75 Vector<double> get_principal_stretch_derivatives(const double& time,
76 const double& r)
77 {
78 Vector<double> dlambda_dr(2);
79 double B = B0 * sin(omega * time);
80 dlambda_dr[0] = 6.0 * B / pow(r, 4.0);
81 dlambda_dr[1] = -3.0 * B / pow(r, 4.0);
82 return dlambda_dr;
83 }
84
85 // Evaluate the deformed position
86 void deformed_position_fct(const double& time,
87 const Vector<double>& xi,
88 Vector<double>& x)
89 {
90 double r = pow(xi[0] * xi[0] + xi[1] * xi[1], 0.5);
91 double theta = atan2(xi[1], xi[0]);
92 x[0] =
93 xi[0] + (A0 * r + B0 * pow(r, -2.0)) * sin(omega * time) * cos(theta);
94 x[1] =
95 xi[1] + (A0 * r + B0 * pow(r, -2.0)) * sin(omega * time) * sin(theta);
96 }
97
98 // Evaluate the deformed position
99 void deformed_velocity_fct(const double& time,
100 const Vector<double>& xi,
101 Vector<double>& x_dot)
102 {
103 double r = pow(xi[0] * xi[0] + xi[1] * xi[1], 0.5);
104 double theta = atan2(xi[1], xi[0]);
105 x_dot[0] =
106 omega * (A0 * r + B0 * pow(r, -2.0)) * cos(omega * time) * cos(theta);
107 x_dot[1] =
108 omega * (A0 * r + B0 * pow(r, -2.0)) * cos(omega * time) * sin(theta);
109 }
110
111 // Evaluate the deformed position
112 void deformed_accel_fct(const double& time,
113 const Vector<double>& xi,
114 Vector<double>& x_ddot)
115 {
116 double r = pow(xi[0] * xi[0] + xi[1] * xi[1], 0.5);
117 double theta = atan2(xi[1], xi[0]);
118 x_ddot[0] = -1.0 * omega * omega * (A0 * r + B0 * pow(r, -2.0)) *
119 sin(omega * time) * cos(theta);
120 x_ddot[1] = -1.0 * omega * omega * (A0 * r + B0 * pow(r, -2.0)) *
121 sin(omega * time) * sin(theta);
122 }
123
124 // Body force function
125 void body_force_fct(const double& time,
126 const Vector<double>& xi,
127 Vector<double>& b)
128 {
129 // Calculate the radial coordinate
130 double r = pow(xi[0] * xi[0] + xi[1] * xi[1], 0.5);
131 // Radial acceleration
132 double accel =
133 -1.0 * omega * omega * (A0 * r + B0 * pow(r, -2.0)) * sin(omega * time);
134 // Principal stretches
135 Vector<double> lambda = get_principal_stretches(time, r);
136 // Jacobian
137 double J = lambda[0] * lambda[1] * lambda[1];
138 // Derivative of radial principal stretch and Jacobian w.r.t. r
139 Vector<double> dlambda_dr = get_principal_stretch_derivatives(time, r);
140 double dJdr = dlambda_dr[0] * lambda[1] * lambda[1] +
141 2.0 * lambda[0] * lambda[1] * dlambda_dr[1];
142
143 // Dimensionless Lame parameters
144 double mu_L = 1.0 / (2.0 * (1.0 + nu));
145 double lambda_L = nu / ((1.0 + nu) * (1.0 - 2.0 * nu));
146
147 // Evaluate the body force
148 double b_spher =
149 accel - mu_L * (dlambda_dr[0] + (2.0 / r) * (lambda[0] - lambda[1])) -
150 lambda_L * dJdr / (J * lambda[0]) -
151 (dlambda_dr[0] / (lambda[0] * lambda[0]) +
152 (2.0 / r) * (1.0 / lambda[1] - 1.0 / lambda[0])) *
153 (mu_L - lambda_L * log(J));
154
155 double theta = atan2(xi[1], xi[0]);
156 b[0] = b_spher * cos(theta);
157 b[1] = b_spher * sin(theta);
158 }
159
160 // External traction force function
161 void traction_force_fct(const double& time,
162 const Vector<double>& xi,
163 const Vector<double>& x,
164 const Vector<double>& n,
165 Vector<double>& traction)
166 {
167 // Calculate the (undeformed) radial coordinate
168 double r = pow(xi[0] * xi[0] + xi[1] * xi[1], 0.5);
169 // Principal stretches
170 Vector<double> lambda = get_principal_stretches(time, r);
171 // Jacobian
172 double J = lambda[0] * lambda[1] * lambda[1];
173
174 // Dimensionless Lame parameters
175 double mu_L = 1.0 / (2.0 * (1.0 + nu));
176 double lambda_L = nu / ((1.0 + nu) * (1.0 - 2.0 * nu));
177
178 // Pressure required for the manufactured solution to work
179 double ext_pressure =
180 -1.0 * (mu_L * (lambda[0] * lambda[0] - 1.0) + lambda_L * log(J)) / J;
181
182 // Return the traction
183 traction[0] = -1.0 * ext_pressure * n[0];
184 traction[1] = -1.0 * ext_pressure * n[1];
185 }
186} // namespace GlobalPhysicalVariables
187
188
189//=======start_namespace==========================================
190/// Global simulation settings
191//================================================================
193{
194 // Folder for output
195 string result_folder = "RESLT";
196
197 /// Flag for using a pressure formulation
199
200 // Number of elements in radial direction
201 unsigned n_radial = 14;
202
203 // Number of elements in azimuthal direction
204 unsigned n_azimuthal = 14;
205
206 // Inner radius
207 double a = 1.0;
208
209 // Thickness
210 double h = 0.5;
211
212 // Number of timesteps
213 unsigned Nsteps = 120;
214
215 // Size of the timestep
216 double dt;
217} // namespace GlobalSimSettings
218
219//======================start_mesh================================
220/// Upgrade the mesh to a solidmesh.
221/// Quarter-annulus in quadrant r>0, z>0
222/// ntheta - no. elements in theta direction
223/// nr - no. elements in the radial direction
224/// a - Inner radius of annulus
225/// h - thickness of annulus
226//================================================================
227template<class ELEMENT>
228class ElasticTwoDAnnularMesh : public virtual TwoDAnnularMesh<ELEMENT>,
229 public virtual SolidMesh
230{
231public:
232 /// Constructor: Build mesh and copy Eulerian coords to Lagrangian
233 /// ones so that the initial configuration is the stress-free one.
235 const unsigned& ntheta,
236 const unsigned& nr,
237 const double& a,
238 const double& h,
241 ntheta, nr, 1.0, 1.0, false, time_stepper_pt),
243 0.25,
244 ntheta,
245 nr,
246 a,
247 h,
250 {
251 // Make the current configuration the undeformed one by
252 // setting the nodal Lagrangian coordinates to their current
253 // Eulerian ones
255 }
256};
257
258//==============start_problem=========================================
259/// Axisymmetric compression of a finite thickness shell in cylindrical
260/// polar coordiantes
261//====================================================================
262template<class ELEMENT>
263class ShellProblem : public Problem
264{
265public:
266 /// Constructor:
267 ShellProblem();
268
269 /// Destructor
271
272 /// Doc the solution
273 void doc_solution();
274
275 /// Set the initial condition
277
278 /// Run through the timesteps
279 void unsteady_run();
280
281private:
282 /// Complete the problem setup (attach function/physical parameter pointers)
284
285 /// Create the boundary elements
287
288 /// Delete boundary elements and wipe the associated mesh
290 {
291 // How many surface elements are in the surface mesh
292 unsigned n_element = Surface_mesh_pt->nelement();
293
294 // Loop over the surface elements
295 for (unsigned e = 0; e < n_element; e++)
296 {
297 // Kill surface element
298 delete Surface_mesh_pt->element_pt(e);
299 }
300
301 // Wipe the mesh
302 Surface_mesh_pt->flush_element_and_node_storage();
303 } // end of delete_boundary_elements
304
305 /// Bulk mesh
307
308 /// Surface mesh for traction force
310
311 /// Pointer to constitutive law
313
314 // DocInfo object
316};
317
318//===============start_constructor========================================
319/// Constructor for unstructured solid problem
320//========================================================================
321template<class ELEMENT>
323{
324 // Set output directory
325 Doc_info.set_directory(GlobalSimSettings::result_folder);
326
327 // Initialise counter for solutions
328 Doc_info.number() = 0;
329
330 // Allocate the timestepper
332
333 // Calculate the timestep size
337
338 // Create the mesh: Quarter-annulus in the quadrant r>0, z>0.
339 Bulk_mesh_pt =
345
346 // Create the surface mesh
347 Surface_mesh_pt = new Mesh;
348
349 // Create the boundary elements
350 create_boundary_elements();
351
352 // Add the two submeshes
353 add_sub_mesh(Bulk_mesh_pt);
354 add_sub_mesh(Surface_mesh_pt);
355
356 // Combine all sub-meshes into a single mesh
358
359 // Define a constitutive law from a strain energy density function.
360 // Compressible Neo-Hookean
363 Constitutive_law_pt =
365
366 // Complete the problem set up
367 complete_problem_setup();
368
369 // Set the initial condition consistently
370 set_initial_condition();
371
372 // Assign eqn numbers
373 oomph_info << "Number of equations: " << assign_eqn_numbers() << std::endl;
374} // end constructor
375
376//========start_of_complete_problem_setup==================================
377/// Assign function/parameter pointers, set boundary conditions etc.
378//=========================================================================
379template<class ELEMENT>
381{
382 // Determine number of bulk elements in mesh
383 const unsigned n_element_bulk = Bulk_mesh_pt->nelement();
384
385 // Loop over the bulk elements
386 for (unsigned e = 0; e < n_element_bulk; e++)
387 {
388 // Upcast from GeneralisedElement to the present element
389 ELEMENT* el_pt = dynamic_cast<ELEMENT*>(Bulk_mesh_pt->element_pt(e));
390
391 // Set the constitutive law
392 el_pt->constitutive_law_pt() = Constitutive_law_pt;
393
394 // Set the traction function for applying pressure
395 el_pt->body_force_fct_pt() = &GlobalPhysicalVariables::body_force_fct;
396 } // End of loop over bulk elements
397
398 // Determine number of 1D interface elements in mesh
399 const unsigned n_interface_element = Surface_mesh_pt->nelement();
400
401 // Loop over the interface elements
402 for (unsigned e = 0; e < n_interface_element; e++)
403 {
404 // Upcast from GeneralisedElement to the present element
407 Surface_mesh_pt->element_pt(e));
408
409 // Set the traction function for applying pressure
411
412 } // End of loop over interface elements
413
414 // Set Dirichlet boundary conditions
415 unsigned n_boundary_node = Bulk_mesh_pt->nboundary_node(1);
416 for (unsigned n = 0; n < n_boundary_node; n++)
417 {
418 // Pin radial position on symmetry axis only
419 Bulk_mesh_pt->boundary_node_pt(1, n)->pin_position(1);
420 }
421
422 n_boundary_node = Bulk_mesh_pt->nboundary_node(3);
423 // Loop over nodes on fixed boundary
424 for (unsigned n = 0; n < n_boundary_node; n++)
425 {
426 // Pin radial position on symmetry axis only
427 Bulk_mesh_pt->boundary_node_pt(3, n)->pin_position(0);
428 }
429} // end complete_problem_setup
430
431//============start_of_create_boundary_elements==========================
432/// Create boundary elements
433//=======================================================================
434template<class ELEMENT>
436{
437 // Loop over boundaries 0 and 2 (inner and outer surface of shell)
438 for (unsigned ibound : {0, 2})
439 {
440 // Loop over elements on boundaries 0 and 2
441 unsigned n_element = Bulk_mesh_pt->nboundary_element(ibound);
442 for (unsigned e = 0; e < n_element; e++)
443 {
444 // Set a pointer to the bulk element we wish to our interface
445 // element to
447 dynamic_cast<ELEMENT*>(Bulk_mesh_pt->boundary_element_pt(ibound, e));
448
449 // Find the index of the face of element e along boundary b
450 int face_index = Bulk_mesh_pt->face_index_at_boundary(ibound, e);
451
452 // Create the interface element
457
458 // Add the interface element to the surface mesh
459 this->Surface_mesh_pt->add_element_pt(interface_element_pt);
460 interface_element_pt->set_boundary_number_in_bulk_mesh(ibound);
461 }
462 }
463} // end of create_boundary_elements
464
465//============start_of_set_initial_condition==============================
466/// Given the form of the manufactured solution, this really only needs
467/// doing for the velocity
468//========================================================================
469template<class ELEMENT>
471{
472 // First initialize dt and set the weights
474
475 // Loop over nodes
476 unsigned n_node = Bulk_mesh_pt->nnode();
477 for (unsigned n = 0; n < n_node; n++)
478 {
479 // Container for position/velocity/acceleration
481
482 // Cast to (solid)node
483 SolidNode* nod_pt = dynamic_cast<SolidNode*>(Bulk_mesh_pt->node_pt(n));
484
485 // Get the undeformed position
486 Vector<double> xi(2), x(2);
487 xi[0] = nod_pt->lagrangian_position(0);
488 xi[1] = nod_pt->lagrangian_position(1);
489
490 // Set values of deformed position at the present and previous times
492 nod_pt->x(0, 0) = value[0];
493 nod_pt->x(0, 1) = value[1];
496 nod_pt->x(1, 0) = value[0];
497 nod_pt->x(1, 1) = value[1];
498
499 // Set the velocity at the previous time
502 nod_pt->x(2, 0) = value[0];
503 nod_pt->x(2, 1) = value[1];
504
505 // Set the acceleration at the previous time
508 nod_pt->x(3, 0) = value[0];
509 nod_pt->x(3, 1) = value[1];
510 }
511} // end set_initial_condition
512
513//========================================================================
514/// Run through the timesteps
515//========================================================================
516template<class ELEMENT>
518{
519 // Loop over timesteps
520 for (unsigned step = 0; step < GlobalSimSettings::Nsteps; step++)
521 {
522 // Perform the timestep
524
525 // Doc the solution
526 doc_solution();
527 }
528}
529
530//========================================================================
531/// Doc the solution
532//========================================================================
533template<class ELEMENT>
535{
537 char filename[100];
538
539 // Number of plot points
540 unsigned npts = 3;
541
543 "%s/bulk_soln%i.dat",
544 Doc_info.directory().c_str(),
545 Doc_info.number());
546 some_file.open(filename);
547 Bulk_mesh_pt->output(some_file, npts);
548 some_file.close();
549
551 "%s/bulk_soln%i.vtu",
552 Doc_info.directory().c_str(),
553 Doc_info.number());
554 some_file.open(filename);
555 Bulk_mesh_pt->output_paraview(some_file, npts);
556 some_file.close();
557
558 // Increment the counter
559 Doc_info.number()++;
560}
561
562//===========start_main===================================================
563/// Demonstrate how to solve an unstructured solid problem
564//========================================================================
565int main(int argc, char* argv[])
566{
567 // Store command line arguments
569
570 string str_temp;
572 "--use_solid_pressure", &str_temp, "Use solid pressure");
573
575 "--poisson", &GlobalPhysicalVariables::nu, "Poisson");
576
578 "--Nsteps", &GlobalSimSettings::Nsteps, "Number of Steps");
579
582
583 istringstream(str_temp) >> std::boolalpha >>
585
586 // Create the problem
588 {
589 // Build the problem with an additional degree of freedom for pressure
591
592 // Perform time integration and docs
593 problem.unsteady_run();
594 }
595 else
596 {
597 // Standard build
599
600 // Perform time integration and docs
601 problem.unsteady_run();
602 }
603} // end main
Upgrade the mesh to a solidmesh. Quarter-annulus in quadrant r>0, z>0 ntheta - no....
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...
Axisymmetric compression of a finite thickness shell in cylindrical polar coordiantes.
void create_boundary_elements()
Create the boundary elements.
void set_initial_condition()
Set the initial condition.
void complete_problem_setup()
Complete the problem setup (attach function/physical parameter pointers)
void delete_boundary_elements()
Delete boundary elements and wipe the associated mesh.
ElasticTwoDAnnularMesh< ELEMENT > * Bulk_mesh_pt
Bulk mesh.
void doc_solution()
Doc the solution.
void unsteady_run()
Run through the timesteps.
Mesh * Surface_mesh_pt
Surface mesh for traction force.
ShellProblem()
Constructor:
ConstitutiveLaw * Constitutive_law_pt
Pointer to constitutive law.
~ShellProblem()
Destructor.
Global physical variables.
Vector< double > get_principal_stretches(const double &time, const double &r)
Vector< double > get_principal_stretch_derivatives(const double &time, const double &r)
void deformed_accel_fct(const double &time, const Vector< double > &xi, Vector< double > &x_ddot)
void deformed_position_fct(const double &time, const Vector< double > &xi, Vector< double > &x)
void traction_force_fct(const double &time, const Vector< double > &xi, const Vector< double > &x, const Vector< double > &n, Vector< double > &traction)
void deformed_velocity_fct(const double &time, const Vector< double > &xi, Vector< double > &x_dot)
void body_force_fct(const double &time, const Vector< double > &xi, Vector< double > &b)
Global simulation settings.
bool use_pressure_formulation
Flag for using a pressure formulation.
int main(int argc, char *argv[])
Demonstrate how to solve an unstructured solid problem.