elastic_single_layer.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 for two-dimensional single fluid free surface problem, where the
31 // mesh is deformed using a pseudo-solid node-update strategy
32 
33 // Generic oomph-lib header
34 #include "generic.h"
35 
36 // Navier-Stokes headers
37 #include "navier_stokes.h"
38 
39 // Interface headers
40 #include "fluid_interface.h"
41 
42 // Constitutive law headers
43 #include "constitutive.h"
44 
45 // Solid headers
46 #include "solid.h"
47 
48 // The mesh
49 #include "meshes/rectangular_quadmesh.h"
50 
51 using namespace std;
52 
53 using namespace oomph;
54 
55 
56 //==start_of_namespace====================================================
57 /// Namespace for physical parameters
58 //========================================================================
60 {
61 
62  /// Reynolds number
63  double Re = 5.0;
64 
65  /// Strouhal number
66  double St = 1.0;
67 
68  /// Womersley number (Reynolds x Strouhal, computed automatically)
69  double ReSt;
70 
71  /// Product of Reynolds number and inverse of Froude number
72  double ReInvFr = 5.0; // (Fr = 1)
73 
74  /// Capillary number
75  double Ca = 0.01;
76 
77  /// Direction of gravity
78  Vector<double> G(2);
79 
80  /// Pseudo-solid Poisson ratio
81  double Nu = 0.1;
82 
83 } // End of namespace
84 
85 
86 //////////////////////////////////////////////////////////////////////////
87 //////////////////////////////////////////////////////////////////////////
88 //////////////////////////////////////////////////////////////////////////
89 
90 
91 //==start_of_problem_class================================================
92 /// Single fluid free surface problem in a rectangular domain which is
93 /// periodic in the x direction
94 //========================================================================
95 template <class ELEMENT, class TIMESTEPPER>
96 class InterfaceProblem : public Problem
97 {
98 
99 public:
100 
101  /// Constructor: Pass the number of elements and the lengths of the
102  /// domain in the x and y directions (h is the height of the fluid layer
103  /// i.e. the length of the domain in the y direction)
104  InterfaceProblem(const unsigned &n_x, const unsigned &n_y,
105  const double &l_x, const double &h);
106 
107  /// Destructor (empty)
109 
110  /// Set initial conditions
111  void set_initial_condition();
112 
113  /// Set boundary conditions
114  void set_boundary_conditions();
115 
116  /// Document the solution
117  void doc_solution(DocInfo &doc_info);
118 
119  /// Do unsteady run up to maximum time t_max with given timestep dt
120  void unsteady_run(const double &t_max, const double &dt);
121 
122 private:
123 
124  /// No actions required before solve step
126 
127  /// No actions required after solve step
129 
130  /// \short Actions before the timestep: For maximum stability, reset
131  /// the current nodal positions to be the "stress-free" ones.
133  {
134  Bulk_mesh_pt->set_lagrangian_nodal_coordinates();
135  }
136 
137  /// Deform the mesh/free surface to a prescribed function
138  void deform_free_surface(const double &epsilon, const unsigned &n_periods);
139 
140  /// Pointer to the (specific) "bulk" mesh
141  ElasticRectangularQuadMesh<ELEMENT>* Bulk_mesh_pt;
142 
143  /// Pointer to the "surface" mesh
145 
146  // Pointer to the constitutive law used to determine the mesh deformation
147  ConstitutiveLaw* Constitutive_law_pt;
148 
149  /// Width of domain
150  double Lx;
151 
152  /// Trace file
153  ofstream Trace_file;
154 
155 }; // End of problem class
156 
157 
158 
159 //==start_of_constructor==================================================
160 /// Constructor for single fluid free surface problem
161 //========================================================================
162 template <class ELEMENT, class TIMESTEPPER>
164 InterfaceProblem(const unsigned &n_x, const unsigned &n_y,
165  const double &l_x, const double& h) : Lx(l_x)
166 {
167 
168  // Allocate the timestepper (this constructs the time object as well)
169  add_time_stepper_pt(new TIMESTEPPER);
170 
171  // Build and assign the "bulk" mesh (the "true" boolean flag tells
172  // the mesh constructor that the domain is periodic in x)
173  Bulk_mesh_pt = new ElasticRectangularQuadMesh<ELEMENT>
174  (n_x,n_y,l_x,h,true,time_stepper_pt());
175 
176  // Create the "surface mesh" that will contain only the interface
177  // elements. The constructor just creates the mesh without giving
178  // it any elements, nodes, etc.
179  Surface_mesh_pt = new Mesh;
180 
181  // -----------------------------
182  // Create the interface elements
183  // -----------------------------
184 
185  // Loop over those elements adjacent to the free surface
186  for(unsigned e=0;e<n_x;e++)
187  {
188  // Set a pointer to the bulk element we wish to our interface
189  // element to
190  FiniteElement* bulk_element_pt =
191  Bulk_mesh_pt->finite_element_pt(n_x*(n_y-1)+e);
192 
193  // Create the interface element (on face 2 of the bulk element)
194  FiniteElement* interface_element_pt =
195  new ElasticLineFluidInterfaceElement<ELEMENT>(bulk_element_pt,2);
196 
197  // Add the interface element to the surface mesh
198  this->Surface_mesh_pt->add_element_pt(interface_element_pt);
199  }
200 
201  // Add the two sub-meshes to the problem
202  add_sub_mesh(Bulk_mesh_pt);
203  add_sub_mesh(Surface_mesh_pt);
204 
205  // Combine all sub-meshes into a single mesh
206  build_global_mesh();
207 
208  // --------------------------------------------
209  // Set the boundary conditions for this problem
210  // --------------------------------------------
211 
212  // All nodes are free by default -- just pin the ones that have
213  // Dirichlet conditions here
214 
215  // Determine number of mesh boundaries
216  const unsigned n_boundary = Bulk_mesh_pt->nboundary();
217 
218  // Loop over mesh boundaries
219  for(unsigned b=0;b<n_boundary;b++)
220  {
221  // Determine number of nodes on boundary b
222  const unsigned n_node = Bulk_mesh_pt->nboundary_node(b);
223 
224  // Loop over nodes on boundary b
225  for(unsigned n=0;n<n_node;n++)
226  {
227  // Fluid boundary conditions:
228  // --------------------------
229 
230  // On lower boundary (solid wall), pin x and y components of
231  // the velocity (no slip/penetration)
232  if(b==0)
233  {
234  Bulk_mesh_pt->boundary_node_pt(b,n)->pin(0);
235  Bulk_mesh_pt->boundary_node_pt(b,n)->pin(1);
236  }
237 
238  // On left and right boundaries, pin x-component of the velocity
239  // (no penetration of the periodic boundaries)
240  if(b==1 || b==3)
241  {
242  Bulk_mesh_pt->boundary_node_pt(b,n)->pin(0);
243  }
244 
245  // Solid boundary conditions:
246  // --------------------------
247 
248  // On lower boundary (solid wall), pin vertical displacement
249  // (no penetration)
250  if(b==0)
251  {
252  Bulk_mesh_pt->boundary_node_pt(b,n)->pin_position(1);
253  }
254  } // End of loop over nodes on boundary b
255  } // End of loop over mesh boundaries
256 
257  // Pin horizontal displacement of all nodes
258  const unsigned n_node = Bulk_mesh_pt->nnode();
259  for(unsigned n=0;n<n_node;n++) { Bulk_mesh_pt->node_pt(n)->pin_position(0); }
260 
261  // Define a constitutive law for the solid equations: generalised Hookean
262  Constitutive_law_pt = new GeneralisedHookean(&Global_Physical_Variables::Nu);
263 
264  // ----------------------------------------------------------------
265  // Complete the problem setup to make the elements fully functional
266  // ----------------------------------------------------------------
267 
268  // Determine number of bulk elements in mesh
269  const unsigned n_element_bulk = Bulk_mesh_pt->nelement();
270 
271  // Loop over the bulk elements
272  for(unsigned e=0;e<n_element_bulk;e++)
273  {
274  // Upcast from GeneralisedElement to the present element
275  ELEMENT *el_pt = dynamic_cast<ELEMENT*>(Bulk_mesh_pt->element_pt(e));
276 
277  // Set the Reynolds number
278  el_pt->re_pt() = &Global_Physical_Variables::Re;
279 
280  // Set the Womersley number
281  el_pt->re_st_pt() = &Global_Physical_Variables::ReSt;
282 
283  // Set the product of the Reynolds number and the inverse of the
284  // Froude number
285  el_pt->re_invfr_pt() = &Global_Physical_Variables::ReInvFr;
286 
287  // Set the direction of gravity
288  el_pt->g_pt() = &Global_Physical_Variables::G;
289 
290  // Set the constitutive law
291  el_pt->constitutive_law_pt() = Constitutive_law_pt;
292 
293  } // End of loop over bulk elements
294 
295  // Create a Data object whose single value stores the external pressure
296  Data* external_pressure_data_pt = new Data(1);
297 
298  // Pin and set the external pressure to some arbitrary value
299  external_pressure_data_pt->pin(0);
300  external_pressure_data_pt->set_value(0,1.31);
301 
302  // Determine number of 1D interface elements in mesh
303  const unsigned n_interface_element = Surface_mesh_pt->nelement();
304 
305  // Loop over the interface elements
306  for(unsigned e=0;e<n_interface_element;e++)
307  {
308  // Upcast from GeneralisedElement to the present element
309  ElasticLineFluidInterfaceElement<ELEMENT>* el_pt =
310  dynamic_cast<ElasticLineFluidInterfaceElement<ELEMENT>*>
311  (Surface_mesh_pt->element_pt(e));
312 
313  // Set the Strouhal number
314  el_pt->st_pt() = &Global_Physical_Variables::St;
315 
316  // Set the Capillary number
317  el_pt->ca_pt() = &Global_Physical_Variables::Ca;
318 
319  // Pass the Data item that contains the single external pressure value
320  el_pt->set_external_pressure_data(external_pressure_data_pt);
321 
322  } // End of loop over interface elements
323 
324  // Apply the boundary conditions
326 
327  // Setup equation numbering scheme
328  cout << "Number of equations: " << assign_eqn_numbers() << std::endl;
329 
330 } // End of constructor
331 
332 
333 
334 //==start_of_set_initial_condition========================================
335 /// \short Set initial conditions: Set all nodal velocities to zero and
336 /// initialise the previous velocities and nodal positions to correspond
337 /// to an impulsive start
338 //========================================================================
339 template <class ELEMENT, class TIMESTEPPER>
341 {
342  // Determine number of nodes in mesh
343  const unsigned n_node = mesh_pt()->nnode();
344 
345  // Loop over all nodes in mesh
346  for(unsigned n=0;n<n_node;n++)
347  {
348  // Loop over the two velocity components
349  for(unsigned i=0;i<2;i++)
350  {
351  // Set velocity component i of node n to zero
352  mesh_pt()->node_pt(n)->set_value(i,0.0);
353  }
354  }
355 
356  // Initialise the previous velocity values and nodal positions
357  // for timestepping corresponding to an impulsive start
358  assign_initial_values_impulsive();
359 
360 } // End of set_initial_condition
361 
362 
363 
364 //==start_of_set_boundary_conditions======================================
365 /// \short Set boundary conditions: Set both velocity components to zero
366 /// on the bottom (solid) wall and the horizontal component only to zero
367 /// on the side (periodic) boundaries
368 //========================================================================
369 template <class ELEMENT, class TIMESTEPPER>
371 {
372  // Determine number of mesh boundaries
373  const unsigned n_boundary = Bulk_mesh_pt->nboundary();
374 
375  // Loop over mesh boundaries
376  for(unsigned b=0;b<n_boundary;b++)
377  {
378  // Determine number of nodes on boundary b
379  const unsigned n_node = Bulk_mesh_pt->nboundary_node(b);
380 
381  // Loop over nodes on boundary b
382  for(unsigned n=0;n<n_node;n++)
383  {
384  // Set x-component of the velocity to zero on all boundaries
385  // other than the free surface
386  if(b!=2)
387  {
388  Bulk_mesh_pt->boundary_node_pt(b,n)->set_value(0,0.0);
389  }
390 
391  // Set y-component of the velocity to zero on the bottom wall
392  if(b==0)
393  {
394  Bulk_mesh_pt->boundary_node_pt(b,n)->set_value(1,0.0);
395  }
396  } // End of loop over nodes on boundary b
397  } // End of loop over mesh boundaries
398 
399 } // End of set_boundary_conditions
400 
401 
402 
403 //==start_of_deform_free_surface==========================================
404 /// Deform the mesh/free surface to a prescribed function
405 //========================================================================
406 template <class ELEMENT, class TIMESTEPPER>
408 deform_free_surface(const double &epsilon,const unsigned &n_periods)
409 {
410  // Determine number of nodes in the "bulk" mesh
411  const unsigned n_node = Bulk_mesh_pt->nnode();
412 
413  // Loop over all nodes in mesh
414  for(unsigned n=0;n<n_node;n++)
415  {
416  // Determine eulerian position of node
417  const double current_x_pos = Bulk_mesh_pt->node_pt(n)->x(0);
418  const double current_y_pos = Bulk_mesh_pt->node_pt(n)->x(1);
419 
420  // Determine new vertical position of node
421  const double new_y_pos = current_y_pos
422  + (1.0-fabs(1.0-current_y_pos))*epsilon
423  *(cos(2.0*n_periods*MathematicalConstants::Pi*current_x_pos/Lx));
424 
425  // Set new position
426  Bulk_mesh_pt->node_pt(n)->x(1) = new_y_pos;
427  }
428 } // End of deform_free_surface
429 
430 
431 
432 //==start_of_doc_solution=================================================
433 /// Document the solution
434 //========================================================================
435 template <class ELEMENT, class TIMESTEPPER>
437 {
438 
439  // Output the time
440  cout << "Time is now " << time_pt()->time() << std::endl;
441 
442  // Upcast from GeneralisedElement to the present element
443  ElasticLineFluidInterfaceElement<ELEMENT>* el_pt =
444  dynamic_cast<ElasticLineFluidInterfaceElement<ELEMENT>*>
445  (Surface_mesh_pt->element_pt(0));
446 
447  // Document time and vertical position of left hand side of interface
448  // in trace file
449  Trace_file << time_pt()->time() << " "
450  << el_pt->node_pt(0)->x(1) << std::endl;
451 
452  ofstream some_file;
453  char filename[100];
454 
455  // Set number of plot points (in each coordinate direction)
456  const unsigned npts = 5;
457 
458  // Open solution output file
459  sprintf(filename,"%s/soln%i.dat",
460  doc_info.directory().c_str(),doc_info.number());
461  some_file.open(filename);
462 
463  // Output solution to file
464  Bulk_mesh_pt->output(some_file,npts);
465 
466  // Close solution output file
467  some_file.close();
468 
469  // Open interface solution output file
470  sprintf(filename,"%s/interface_soln%i.dat",
471  doc_info.directory().c_str(),doc_info.number());
472  some_file.open(filename);
473 
474  // Output solution to file
475  Surface_mesh_pt->output(some_file,npts);
476 
477  // Close solution output file
478  some_file.close();
479 
480 } // End of doc_solution
481 
482 
483 
484 //==start_of_unsteady_run=================================================
485 /// Perform run up to specified time t_max with given timestep dt
486 //========================================================================
487 template <class ELEMENT, class TIMESTEPPER>
489 unsteady_run(const double &t_max, const double &dt)
490 {
491 
492  // Set value of epsilon
493  const double epsilon = 0.1;
494 
495  // Set number of periods for cosine term
496  const unsigned n_periods = 1;
497 
498  // Deform the mesh/free surface
499  deform_free_surface(epsilon,n_periods);
500 
501  // Initialise DocInfo object
502  DocInfo doc_info;
503 
504  // Set output directory
505  doc_info.set_directory("RESLT");
506 
507  // Initialise counter for solutions
508  doc_info.number()=0;
509 
510  // Open trace file
511  char filename[100];
512  sprintf(filename,"%s/trace.dat",doc_info.directory().c_str());
513  Trace_file.open(filename);
514 
515  // Initialise trace file
516  Trace_file << "time, free surface height" << std::endl;
517 
518  // Initialise timestep
519  initialise_dt(dt);
520 
521  // Set initial conditions
523 
524  // Determine number of timesteps
525  const unsigned n_timestep = unsigned(t_max/dt);
526 
527  // Doc initial solution
528  doc_solution(doc_info);
529 
530  // Increment counter for solutions
531  doc_info.number()++;
532 
533  // Timestepping loop
534  for(unsigned t=1;t<=n_timestep;t++)
535  {
536  // Output current timestep to screen
537  cout << "\nTimestep " << t << " of " << n_timestep << std::endl;
538 
539  // Take one fixed timestep
540  unsteady_newton_solve(dt);
541 
542  // Doc solution
543  doc_solution(doc_info);
544 
545  // Increment counter for solutions
546  doc_info.number()++;
547 
548  } // End of timestepping loop
549 
550 } // End of unsteady_run
551 
552 
553 //////////////////////////////////////////////////////////////////////////
554 //////////////////////////////////////////////////////////////////////////
555 //////////////////////////////////////////////////////////////////////////
556 
557 
558 //==start_of_main=========================================================
559 /// Driver code for two-dimensional single fluid free surface problem
560 //========================================================================
561 int main(int argc, char* argv[])
562 {
563  // Store command line arguments
564  CommandLineArgs::setup(argc,argv);
565 
566  // Compute the Womersley number
569 
570  /// Maximum time
571  double t_max = 0.6;
572 
573  /// Duration of timestep
574  const double dt = 0.0025;
575 
576  // If we are doing validation run, use smaller number of timesteps
577  if(CommandLineArgs::Argc>1) { t_max = 0.005; }
578 
579  // Number of elements in x direction
580  const unsigned n_x = 12;
581 
582  // Number of elements in y direction
583  const unsigned n_y = 12;
584 
585  // Width of domain
586  const double l_x = 1.0;
587 
588  // Height of fluid layer
589  const double h = 1.0;
590 
591  // Set direction of gravity (vertically downwards)
594 
595  // Set up the elastic test problem with QCrouzeixRaviartElements,
596  // using the BDF<2> timestepper
598  QPVDElement<2,3> > , BDF<2> >
599  problem(n_x,n_y,l_x,h);
600 
601  // Run the unsteady simulation
602  problem.unsteady_run(t_max,dt);
603 
604 } // End of main
double Lx
Width of domain.
Vector< double > G(2)
Direction of gravity.
Mesh * Surface_mesh_pt
Pointer to the "surface" mesh.
double St
Strouhal number.
ofstream Trace_file
Trace file.
void actions_before_newton_solve()
No actions required before solve step.
double ReSt
Womersley number (Reynolds x Strouhal, computed automatically)
~InterfaceProblem()
Destructor (empty)
ElasticRectangularQuadMesh< ELEMENT > * Bulk_mesh_pt
Pointer to the (specific) "bulk" mesh.
double Re
Reynolds number.
void actions_after_newton_solve()
No actions required after solve step.
void set_boundary_conditions()
Set boundary conditions.
void set_initial_condition()
Set initial conditions.
InterfaceProblem(const unsigned &n_x, const unsigned &n_y, const double &l_x, const double &h)
Constructor for single fluid free surface problem.
void unsteady_run(const double &t_max, const double &dt)
Do unsteady run up to maximum time t_max with given timestep dt.
Namespace for physical parameters.
void deform_free_surface(const double &epsilon, const unsigned &n_periods)
Deform the mesh/free surface to a prescribed function.
double ReInvFr
Product of Reynolds number and inverse of Froude number.
void actions_before_implicit_timestep()
Actions before the timestep: For maximum stability, reset the current nodal positions to be the "stre...
void doc_solution(DocInfo &doc_info)
Document the solution.
ConstitutiveLaw * Constitutive_law_pt
double Nu
Pseudo-solid Poisson ratio.
double Ca
Capillary number.
int main(int argc, char *argv[])
Driver code for two-dimensional single fluid free surface problem.