unstructured_cylinder.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// Version 1.0; svn revision $LastChangedRevision$
7 //LIC//
8 //LIC// $LastChangedDate$
9 //LIC//
10 //LIC// Copyright (C) 2006-2016 Matthias Heil and Andrew Hazel
11 //LIC//
12 //LIC// This library is free software; you can redistribute it and/or
13 //LIC// modify it under the terms of the GNU Lesser General Public
14 //LIC// License as published by the Free Software Foundation; either
15 //LIC// version 2.1 of the License, or (at your option) any later version.
16 //LIC//
17 //LIC// This library is distributed in the hope that it will be useful,
18 //LIC// but WITHOUT ANY WARRANTY; without even the implied warranty of
19 //LIC// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 //LIC// Lesser General Public License for more details.
21 //LIC//
22 //LIC// You should have received a copy of the GNU Lesser General Public
23 //LIC// License along with this library; if not, write to the Free Software
24 //LIC// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 //LIC// 02110-1301 USA.
26 //LIC//
27 //LIC// The authors may be contacted at oomph-lib@maths.man.ac.uk.
28 //LIC//
29 //LIC//====================================================================
30 // Driver
31 
32 // The oomphlib headers
33 #include "generic.h"
34 #include "time_harmonic_fourier_decomposed_linear_elasticity.h"
35 
36 // The mesh
37 #include "meshes/triangle_mesh.h"
38 
39 using namespace std;
40 
41 using namespace oomph;
42 
43 
44 //===start_of_namespace=================================================
45 /// Namespace for global parameters
46 //======================================================================
47 namespace Global_Parameters
48 {
49  /// Define Poisson's ratio Nu
50  std::complex<double> Nu(0.3,0.05);
51 
52  /// Define the non-dimensional Young's modulus
53  std::complex<double> E(1.0,0.01);
54 
55  // Lame parameters
56  std::complex<double> lambda = E*Nu/(1.0+Nu)/(1.0-2.0*Nu);
57  std::complex<double> mu = E/2.0/(1.0+Nu);
58 
59  /// Define Fourier wavenumber
60  int Fourier_wavenumber = 3;
61 
62  /// \short Define the non-dimensional square angular frequency of
63  /// time-harmonic motion
64  std::complex<double> Omega_sq (10.0,5.0);
65 
66  /// Length of domain in r direction
67  double Lr = 1.0;
68 
69  /// Length of domain in z-direction
70  double Lz = 2.0;
71 
72  // Set up min & max (r,z) coordinates
73  double rmin = 0.1;
74  double zmin = 0.3;
75  double rmax = rmin+Lr;
76  double zmax = zmin+Lz;
77 
78  /// Define the imaginary unit
79  const std::complex<double> I(0.0,1.0);
80 
81  /// The traction function at r=rmin: (t_r, t_z, t_theta)
82  void boundary_traction(const Vector<double> &x,
83  const Vector<double> &n,
84  Vector<std::complex<double> > &result)
85  {
86  result[0] = -6.0*pow(x[0],2)*mu*cos(x[1])-
87  lambda*(I*double(Fourier_wavenumber)*pow(x[0],2)*pow(x[1],3)+
88  (4.0*pow(x[0],2)+pow(x[0],3))*cos(x[1]));
89  result[1] = -mu*(3.0*pow(x[0],2)-pow(x[0],3))*sin(x[1]);
90  result[2] = -mu*pow(x[0],2)*(2*pow(x[1],3)+I*double(Fourier_wavenumber)*
91  cos(x[1]));
92  }
93 
94 
95  /// \short The body force function; returns vector of complex doubles
96  /// in the order (b_r, b_z, b_theta)
97  void body_force(const Vector<double> &x,
98  Vector<std::complex<double> > &result)
99  {
100  result[0] =
101  x[0]*(-2.0*I*lambda*double(Fourier_wavenumber)*pow(x[1],3)-cos(x[1])*
102  (lambda*(8.0+3.0*x[0])-
103  mu*(pow(double(Fourier_wavenumber),2)
104  -16.0+x[0]*(x[0]-3.0))+pow(x[0],2)*Omega_sq));
105  result[1] =
106  x[0]*sin(x[1])*(mu*(pow(double(Fourier_wavenumber),2)-9.0)+
107  4.0*x[0]*(lambda+mu)+pow(x[0],2)*
108  (lambda+2.0*mu-Omega_sq))-
109  3.0*I*double(Fourier_wavenumber)*pow(x[0],2)*pow(x[1],2)*(lambda+mu);
110  result[2] =
111  -x[0]*(8.0*mu*pow(x[1],3)-pow(double(Fourier_wavenumber),2)*pow(x[1],3)*
112  (lambda+2.0*mu)+pow(x[0],2)*(pow(x[1],3)*Omega_sq+6.0*mu*x[1])+
113  I*cos(x[1])*double(Fourier_wavenumber)*
114  (lambda*(4.0+x[0])+mu*(6.0+x[0])));
115  }
116 
117  /// The exact solution in a flat-packed vector:
118  // 0: u_r[real], 1: u_z[real],..., 5: u_theta[imag]
119  void exact_solution(const Vector<double> &x,
120  Vector<double> &u)
121  {
122  u[0] = pow(x[0],3)*cos(x[1]);
123  u[1] = pow(x[0],3)*sin(x[1]);
124  u[2] = pow(x[0],3)*pow(x[1],3);
125  u[3] = 0.0;
126  u[4] = 0.0;
127  u[5] = 0.0;
128  }
129 
130 } // end_of_namespace
131 
132 
133 //===start_of_problem_class=============================================
134 /// Class to validate time harmonic linear elasticity (Fourier
135 /// decomposed)
136 //======================================================================
137 template<class ELEMENT>
139 {
140 public:
141 
142  /// \short Constructor: Pass boundary locations
144  const double& rmax,
145  const double &zmin,
146  const double& zmax);
147 
148  /// Update before solve is empty
150 
151  /// Update after solve is empty
153 
154 
155  /// Actions before adapt: Wipe the mesh of traction elements
157  {
158  // Kill the traction elements and wipe surface mesh
159  delete_traction_elements();
160 
161  // Rebuild the Problem's global mesh from its various sub-meshes
162  rebuild_global_mesh();
163  }
164 
165 
166  /// Actions after adapt: Rebuild the mesh of traction elements
168  {
169  // Create traction elements from all elements that are
170  // adjacent to FSI boundaries and add them to surface meshes
171  assign_traction_elements();
172 
173  // Rebuild the Problem's global mesh from its various sub-meshes
174  rebuild_global_mesh();
175 
176  // Complete problem setup
177  complete_problem_setup();
178  }
179 
180  /// Doc the solution
181  void doc_solution(DocInfo& doc_info);
182 
183 private:
184 
185  /// Allocate traction elements on the bottom surface
186  void assign_traction_elements();
187 
188  /// Delete traction elements
189  void delete_traction_elements();
190 
191  /// Helper function to complete problem setup
192  void complete_problem_setup();
193 
194 #ifdef ADAPTIVE
195 
196  /// Pointer to the bulk mesh
197  RefineableTriangleMesh<ELEMENT>* Bulk_mesh_pt;
198 
199 #else
200 
201  /// Pointer to the bulk mesh
202  Mesh* Bulk_mesh_pt;
203 
204 #endif
205 
206  /// Pointer to the mesh of traction elements
207  Mesh* Surface_mesh_pt;
208 
209 }; // end_of_problem_class
210 
211 
212 //===start_of_constructor=============================================
213 /// Problem constructor: Pass size of domain.
214 //====================================================================
215 template<class ELEMENT>
218 (const double& rmin, const double& rmax, const double &zmin, const double& zmax)
219 {
220 
221  // The boundary is bounded by four distinct boundaries, each
222  // represented by its own polyline
223  Vector<TriangleMeshCurveSection*> boundary_polyline_pt(4);
224 
225  // Vertex coordinates on boundary
226  Vector<Vector<double> > bound_coords(2);
227  bound_coords[0].resize(2);
228  bound_coords[1].resize(2);
229 
230  // Horizontal bottom boundary
231  bound_coords[0][0]=rmin;
232  bound_coords[0][1]=zmin;
233  bound_coords[1][0]=rmax;
234  bound_coords[1][1]=zmin;
235 
236  // Build the boundary polyline
237  unsigned boundary_id=0;
238  boundary_polyline_pt[0]=new TriangleMeshPolyLine(bound_coords,boundary_id);
239 
240  // Vertical outer boundary
241  bound_coords[0][0]=rmax;
242  bound_coords[0][1]=zmin;
243  bound_coords[1][0]=rmax;
244  bound_coords[1][1]=zmax;
245 
246  // Build the boundary polyline
247  boundary_id=1;
248  boundary_polyline_pt[1]=new TriangleMeshPolyLine(bound_coords,boundary_id);
249 
250 
251  // Horizontal top boundary
252  bound_coords[0][0]=rmax;
253  bound_coords[0][1]=zmax;
254  bound_coords[1][0]=rmin;
255  bound_coords[1][1]=zmax;
256 
257  // Build the boundary polyline
258  boundary_id=2;
259  boundary_polyline_pt[2]=new TriangleMeshPolyLine(bound_coords,boundary_id);
260 
261  // Vertical inner boundary
262  bound_coords[0][0]=rmin;
263  bound_coords[0][1]=zmax;
264  bound_coords[1][0]=rmin;
265  bound_coords[1][1]=zmin;
266 
267  // Build the boundary polyline
268  boundary_id=3;
269  boundary_polyline_pt[3]=new TriangleMeshPolyLine(bound_coords,boundary_id);
270 
271  // Pointer to the closed curve that defines the outer boundary
272  TriangleMeshClosedCurve* closed_curve_pt=
273  new TriangleMeshPolygon(boundary_polyline_pt);
274 
275  // Use the TriangleMeshParameters object for helping on the manage of the
276  // TriangleMesh parameters
277  TriangleMeshParameters triangle_mesh_parameters(closed_curve_pt);
278 
279  // Specify the maximum area element
280  double uniform_element_area=0.2;
281  triangle_mesh_parameters.element_area() = uniform_element_area;
282 
283 #ifdef ADAPTIVE
284 
285  // Create the mesh
286  Bulk_mesh_pt=new RefineableTriangleMesh<ELEMENT>(triangle_mesh_parameters);
287 
288  // Set error estimator
289  Bulk_mesh_pt->spatial_error_estimator_pt()=new Z2ErrorEstimator;
290 
291 #else
292 
293  // Create the mesh
294  Bulk_mesh_pt=new TriangleMesh<ELEMENT>(triangle_mesh_parameters);
295 
296 #endif
297 
298  //Create the surface mesh of traction elements
299  Surface_mesh_pt=new Mesh;
300  assign_traction_elements();
301 
302  // Complete problem setup
303  complete_problem_setup();
304 
305  // Add the submeshes to the problem
306  add_sub_mesh(Bulk_mesh_pt);
307  add_sub_mesh(Surface_mesh_pt);
308 
309  // Now build the global mesh
310  build_global_mesh();
311 
312  // Assign equation numbers
313  cout << assign_eqn_numbers() << " equations assigned" << std::endl;
314 
315 } // end of constructor
316 
317 
318 
319 //===start_of_complete_problem_setup=================================
320 /// Complete problem setup
321 //===================================================================
322 template<class ELEMENT>
325 {
326 
327  // Set the boundary conditions for this problem: All nodes are
328  // free by default -- just pin & set the ones that have Dirichlet
329  // conditions here
330 
331  // storage for nodal position
332  Vector<double> x(2);
333 
334  // Storage for prescribed displacements
335  Vector<double> u(6);
336 
337  // Now set displacements on boundaries 0 (z=zmin),
338  //------------------------------------------------
339  // 1 (r=rmax) and 2 (z=zmax)
340  //--------------------------
341  for (unsigned ibound=0;ibound<=2;ibound++)
342  {
343  unsigned num_nod=Bulk_mesh_pt->nboundary_node(ibound);
344  for (unsigned inod=0;inod<num_nod;inod++)
345  {
346  // Get pointer to node
347  Node* nod_pt=Bulk_mesh_pt->boundary_node_pt(ibound,inod);
348 
349  // get r and z coordinates
350  x[0]=nod_pt->x(0);
351  x[1]=nod_pt->x(1);
352 
353  // Pinned in r, z and theta
354  nod_pt->pin(0);nod_pt->pin(1);nod_pt->pin(2);
355  nod_pt->pin(3);nod_pt->pin(4);nod_pt->pin(5);
356 
357  // Compute the value of the exact solution at the nodal point
358  Vector<double> u(6);
360 
361  // Set the displacements
362  nod_pt->set_value(0,u[0]);
363  nod_pt->set_value(1,u[1]);
364  nod_pt->set_value(2,u[2]);
365  nod_pt->set_value(3,u[3]);
366  nod_pt->set_value(4,u[4]);
367  nod_pt->set_value(5,u[5]);
368  }
369  } // end_of_loop_over_boundary_nodes
370 
371 
372  // Complete the problem setup to make the elements fully functional
373 
374  // Loop over the elements
375  unsigned n_el = Bulk_mesh_pt->nelement();
376  for(unsigned e=0;e<n_el;e++)
377  {
378  // Cast to a bulk element
379  ELEMENT *el_pt = dynamic_cast<ELEMENT*>(Bulk_mesh_pt->element_pt(e));
380 
381  // Set the body force
382  el_pt->body_force_fct_pt() = &Global_Parameters::body_force;
383 
384  // Set the pointer to Poisson's ratio
385  el_pt->nu_pt() = &Global_Parameters::Nu;
386 
387  // Set the pointer to Fourier wavenumber
388  el_pt->fourier_wavenumber_pt() = &Global_Parameters::Fourier_wavenumber;
389 
390  // Set the pointer to non-dim Young's modulus
391  el_pt->youngs_modulus_pt() = &Global_Parameters::E;
392 
393  // Set the pointer to square of the angular frequency
394  el_pt->omega_sq_pt() = &Global_Parameters::Omega_sq;
395 
396  }// end loop over elements
397 
398  // Loop over the traction elements
399  unsigned n_traction = Surface_mesh_pt->nelement();
400  for(unsigned e=0;e<n_traction;e++)
401  {
402  // Cast to a surface element
403  TimeHarmonicFourierDecomposedLinearElasticityTractionElement<ELEMENT>*
404  el_pt =
405  dynamic_cast<TimeHarmonicFourierDecomposedLinearElasticityTractionElement
406  <ELEMENT>* >(Surface_mesh_pt->element_pt(e));
407 
408  // Set the applied traction
409  el_pt->traction_fct_pt() = &Global_Parameters::boundary_traction;
410 
411  }// end loop over traction elements
412 }
413 
414 //===start_of_traction===============================================
415 /// Make traction elements along the boundary r=rmin
416 //===================================================================
417 template<class ELEMENT>
420 {
421  unsigned bound, n_neigh;
422 
423  // How many bulk elements are next to boundary 3
424  bound=3;
425  n_neigh = Bulk_mesh_pt->nboundary_element(bound);
426 
427  // Now loop over bulk elements and create the face elements
428  for(unsigned n=0;n<n_neigh;n++)
429  {
430  // Create the face element
431  FiniteElement *traction_element_pt
432  = new TimeHarmonicFourierDecomposedLinearElasticityTractionElement<ELEMENT>
433  (Bulk_mesh_pt->boundary_element_pt(bound,n),
434  Bulk_mesh_pt->face_index_at_boundary(bound,n));
435 
436  // Add to mesh
437  Surface_mesh_pt->add_element_pt(traction_element_pt);
438  }
439 
440 } // end of assign_traction_elements
441 
442 
443 
444 //===start_of_delete_traction========================================
445 /// Delete traction elements
446 //===================================================================
447 template<class ELEMENT>
450 {
451  // How many surface elements are in the surface mesh
452  unsigned n_element = Surface_mesh_pt->nelement();
453 
454  // Loop over the surface elements
455  for(unsigned e=0;e<n_element;e++)
456  {
457  // Kill surface element
458  delete Surface_mesh_pt->element_pt(e);
459  }
460 
461  // Wipe the mesh
462  Surface_mesh_pt->flush_element_and_node_storage();
463 
464 } // end of delete_traction_elements
465 
466 
467 //==start_of_doc_solution=================================================
468 /// Doc the solution
469 //========================================================================
470 template<class ELEMENT>
472 doc_solution(DocInfo& doc_info)
473 {
474  ofstream some_file;
475  char filename[100];
476 
477  // Number of plot points
478  unsigned npts=10;
479 
480  // Output solution
481  sprintf(filename,"%s/soln.dat",doc_info.directory().c_str());
482  some_file.open(filename);
483  Bulk_mesh_pt->output(some_file,npts);
484  some_file.close();
485 
486  // Output exact solution
487  sprintf(filename,"%s/exact_soln.dat",doc_info.directory().c_str());
488  some_file.open(filename);
489  Bulk_mesh_pt->output_fct(some_file,npts,
491  some_file.close();
492 
493  // Doc error
494  double error=0.0;
495  double norm=0.0;
496  sprintf(filename,"%s/error.dat",doc_info.directory().c_str());
497  some_file.open(filename);
498  Bulk_mesh_pt->compute_error(some_file,
500  error,norm);
501  some_file.close();
502 
503  // Doc error norm:
504  cout << "\nNorm of error: " << sqrt(error) << std::endl;
505  cout << "Norm of solution: " << sqrt(norm) << std::endl << std::endl;
506  cout << std::endl;
507 
508  // Output norm of solution (to allow validation of solution even
509  // if triangle generates a slightly different mesh)
510  sprintf(filename,"%s/norm.dat",doc_info.directory().c_str());
511  some_file.open(filename);
512  some_file << norm << std::endl;
513  some_file.close();
514 
515 } // end_of_doc_solution
516 
517 
518 //===start_of_main======================================================
519 /// Driver code
520 //======================================================================
521 int main(int argc, char* argv[])
522 {
523 
524  // Set up doc info
525  DocInfo doc_info;
526 
527  // Set output directory
528  doc_info.set_directory("RESLT");
529 
530 #ifdef ADAPTIVE
531 
532  // Set up problem
534  <ProjectableTimeHarmonicFourierDecomposedLinearElasticityElement
535  <TTimeHarmonicFourierDecomposedLinearElasticityElement<3> > >
538 
539  // Solve
540  unsigned max_adapt=3;
541  problem.newton_solve(max_adapt);
542 
543 #else
544 
545  // Set up problem
547  <TTimeHarmonicFourierDecomposedLinearElasticityElement<3> >
550 
551  // Solve
552  problem.newton_solve();
553 
554 #endif
555 
556 
557  // Output the solution
558  problem.doc_solution(doc_info);
559 
560 } // end_of_main
const std::complex< double > I(0.0, 1.0)
Define the imaginary unit.
void complete_problem_setup()
Helper function to complete problem setup.
void boundary_traction(const Vector< double > &x, const Vector< double > &n, Vector< std::complex< double > > &result)
The traction function at r=rmin: (t_r, t_z, t_theta)
Definition: cylinder.cc:81
std::complex< double > lambda
Definition: cylinder.cc:55
std::complex< double > Nu(0.3, 0.05)
Define Poisson&#39;s ratio Nu.
int Fourier_wavenumber
Define Fourier wavenumber.
Definition: cylinder.cc:59
void doc_solution(DocInfo &doc_info)
Doc the solution.
Definition: cylinder.cc:322
void actions_after_adapt()
Actions after adapt: Rebuild the mesh of traction elements.
FourierDecomposedTimeHarmonicLinearElasticityProblem(const unsigned &nr, const unsigned &nz, const double &rmin, const double &rmax, const double &zmin, const double &zmax)
Constructor: Pass number of elements in r and z directions and boundary locations.
Definition: cylinder.cc:178
void body_force(const Vector< double > &x, Vector< std::complex< double > > &result)
The body force function; returns vector of complex doubles in the order (b_r, b_z, b_theta)
Definition: cylinder.cc:96
void actions_before_newton_solve()
Update before solve is empty.
Namespace for global parameters.
Definition: cylinder.cc:46
std::complex< double > E(1.0, 0.01)
Define the non-dimensional Young&#39;s modulus.
double Lr
Length of domain in r direction.
Definition: cylinder.cc:66
double Lz
Length of domain in z-direction.
Definition: cylinder.cc:69
void exact_solution(const Vector< double > &x, Vector< double > &u)
The exact solution in a flat-packed vector:
Definition: cylinder.cc:118
std::complex< double > mu
Definition: cylinder.cc:56
void actions_after_newton_solve()
Update after solve is empty.
void assign_traction_elements()
Allocate traction elements on the bottom surface.
Definition: cylinder.cc:293
std::complex< double > Omega_sq(10.0, 5.0)
Define the non-dimensional square angular frequency of time-harmonic motion.
void actions_before_adapt()
Actions before adapt: Wipe the mesh of traction elements.
int main(int argc, char *argv[])
Driver code.