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