elastic_two_layer_interface.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 an adaptive two-dimensional two fluid interface problem,
27 // where the 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)
65  double ReSt = 5.0;
66 
67  /// Product of Reynolds number and inverse of Froude number
68  double ReInvFr = 5.0;
69 
70  /// Ratio of viscosity in upper fluid to viscosity in lower
71  /// fluid. Reynolds number etc. is based on viscosity in lower fluid.
72  double Viscosity_Ratio = 0.1;
73 
74  /// Ratio of density in upper fluid to density in lower
75  /// fluid. Reynolds number etc. is based on density in lower fluid.
76  double Density_Ratio = 0.5;
77 
78  /// Capillary number
79  double Ca = 0.01;
80 
81  /// Direction of gravity
82  Vector<double> G(2);
83 
84  /// Pseudo-solid Poisson ratio
85  double Nu = 0.1;
86 
87 } // End of namespace
88 
89 
90 /// ///////////////////////////////////////////////////////////////////////
91 /// ///////////////////////////////////////////////////////////////////////
92 /// ///////////////////////////////////////////////////////////////////////
93 
94 
95 //==start_of_specific_mesh_class==========================================
96 /// Two layer mesh which employs a pseudo-solid node-update strategy.
97 /// This class is essentially a wrapper to an
98 /// ElasticRefineableRectangularQuadMesh, with an additional boundary
99 /// to represent the interface between the two fluid layers.
100 //========================================================================
101 template <class ELEMENT>
103  public virtual ElasticRefineableRectangularQuadMesh<ELEMENT>
104 {
105 
106 public:
107 
108  /// Constructor: Pass number of elements in x-direction, number of
109  /// elements in y-direction in bottom and top layer, respectively,
110  /// axial length and height of top and bottom layers, a boolean
111  /// flag to make the mesh periodic in the x-direction, and pointer
112  /// to timestepper (defaults to Steady timestepper)
113  ElasticRefineableTwoLayerMesh(const unsigned &nx,
114  const unsigned &ny1,
115  const unsigned &ny2,
116  const double &lx,
117  const double &h1,
118  const double &h2,
119  const bool& periodic_in_x,
120  TimeStepper* time_stepper_pt=
121  &Mesh::Default_TimeStepper)
122  : RectangularQuadMesh<ELEMENT>(nx,ny1+ny2,lx,h1+h2,
123  periodic_in_x,time_stepper_pt),
124  ElasticRectangularQuadMesh<ELEMENT>(nx,ny1+ny2,lx,h1+h2,
125  periodic_in_x,time_stepper_pt),
126  ElasticRefineableRectangularQuadMesh<ELEMENT>(nx,ny1+ny2,lx,h1+h2,
127  periodic_in_x,
128  time_stepper_pt)
129  {
130  // ----------------------------------------------------
131  // Convert all nodes on the interface to boundary nodes
132  // ----------------------------------------------------
133 
134  // Set the number of boundaries to 5
135  this->set_nboundary(5);
136 
137  // Loop over horizontal elements
138  for(unsigned e=0;e<nx;e++)
139  {
140  // Get pointer to element in lower fluid adjacent to interface
141  FiniteElement* el_pt = this->finite_element_pt(nx*(ny1-1)+e);
142 
143  // Determine number of nodes in this element
144  const unsigned n_node = el_pt->nnode();
145 
146  // The last three nodes in this element are those on the interface.
147  // Loop over these nodes and convert them to boundary nodes.
148  for(unsigned n=0;n<3;n++)
149  {
150  Node* nod_pt = el_pt->node_pt(n_node-3+n);
151  this->convert_to_boundary_node(nod_pt);
152  this->add_boundary_node(4,nod_pt);
153  }
154  } // End of loop over horizontal elements
155 
156  // Set up the boundary element information
157  this->setup_boundary_element_info();
158  }
159 
160 }; // End of specific mesh class
161 
162 
163 /// ///////////////////////////////////////////////////////////////////////
164 /// ///////////////////////////////////////////////////////////////////////
165 /// ///////////////////////////////////////////////////////////////////////
166 
167 
168 //==start_of_problem_class================================================
169 /// Two fluid interface problem in a rectangular domain which is
170 /// periodic in the x direction
171 //========================================================================
172 template <class ELEMENT, class TIMESTEPPER>
173 class InterfaceProblem : public Problem
174 {
175 
176 public:
177 
178  /// Constructor
180 
181  /// Destructor (empty)
183 
184  /// Set initial conditions
185  void set_initial_condition();
186 
187  /// Set boundary conditions
188  void set_boundary_conditions();
189 
190  /// Document the solution
191  void doc_solution(DocInfo &doc_info);
192 
193  /// Do unsteady run up to maximum time t_max with given timestep dt
194  void unsteady_run(const double &t_max, const double &dt);
195 
196 private:
197 
198  /// No actions required before solve step
200 
201  /// No actions required after solve step
203 
204  /// Actions before the timestep: For maximum stability, reset
205  /// the current nodal positions to be the "stress-free" ones.
207  {
208  Bulk_mesh_pt->set_lagrangian_nodal_coordinates();
209  }
210 
211  /// Strip off the interface elements before adapting the bulk mesh
212  void actions_before_adapt();
213 
214  /// Rebuild the mesh of interface elements after adapting the bulk mesh
215  void actions_after_adapt();
216 
217  /// Create the 1d interface elements
218  void create_interface_elements();
219 
220  /// Delete the 1d interface elements
221  void delete_interface_elements();
222 
223  /// Deform the mesh/free surface to a prescribed function
224  void deform_free_surface(const double &epsilon, const unsigned &n_periods);
225 
226  /// Fix pressure in element e at pressure dof pdof and set to pvalue
227  void fix_pressure(const unsigned &e,
228  const unsigned &pdof,
229  const double &pvalue)
230  {
231  // Fix the pressure at that element
232  dynamic_cast<ELEMENT*>(mesh_pt()->element_pt(e))->
233  fix_pressure(pdof,pvalue);
234  }
235 
236  /// Pointer to the (specific) "bulk" mesh
238 
239  /// Pointer to the "surface" mesh
241 
242  // Pointer to the constitutive law used to determine the mesh deformation
243  ConstitutiveLaw* Constitutive_law_pt;
244 
245  /// Width of domain
246  double Lx;
247 
248  /// Trace file
249  ofstream Trace_file;
250 
251 }; // End of problem class
252 
253 
254 
255 //==start_of_constructor==================================================
256 /// Constructor for two fluid interface problem
257 //========================================================================
258 template <class ELEMENT, class TIMESTEPPER>
261 {
262  // Allocate the timestepper (this constructs the time object as well)
263  add_time_stepper_pt(new TIMESTEPPER);
264 
265  // Define number of elements in x direction
266  const unsigned n_x = 3;
267 
268  // Define number of elements in y direction in lower fluid (fluid 1)
269  const unsigned n_y1 = 3;
270 
271  // Define number of elements in y direction in upper fluid (fluid 2)
272  const unsigned n_y2 = 3;
273 
274  // Define width of domain and store as class member data
275  const double l_x = 1.0;
276  this->Lx = l_x;
277 
278  // Define height of lower fluid layer
279  const double h1 = 1.0;
280 
281  // Define height of upper fluid layer
282  const double h2 = 1.0;
283 
284  // Build and assign the "bulk" mesh (the "true" boolean flag tells
285  // the mesh constructor that the domain is periodic in x)
286  Bulk_mesh_pt = new ElasticRefineableTwoLayerMesh<ELEMENT>
287  (n_x,n_y1,n_y2,l_x,h1,h2,true,time_stepper_pt());
288 
289  // Create and set the error estimator for spatial adaptivity
290  Bulk_mesh_pt->spatial_error_estimator_pt() = new Z2ErrorEstimator;
291 
292  // Set the maximum refinement level for the mesh to 4
293  Bulk_mesh_pt->max_refinement_level() = 4;
294 
295  // Create the "surface" mesh that will contain only the interface
296  // elements. The constructor just creates the mesh without giving
297  // it any elements, nodes, etc.
298  Surface_mesh_pt = new Mesh;
299 
300  // Create interface elements at the boundary between the two fluids,
301  // and add them to the surface mesh
302  create_interface_elements();
303 
304  // Add the two sub meshes to the problem
305  add_sub_mesh(Bulk_mesh_pt);
306  add_sub_mesh(Surface_mesh_pt);
307 
308  // Combine all sub-meshes into a single mesh
309  build_global_mesh();
310 
311  // --------------------------------------------
312  // Set the boundary conditions for this problem
313  // --------------------------------------------
314 
315  // All values are free by default -- just pin the ones that have
316  // Dirichlet conditions here
317 
318  // Determine number of mesh boundaries
319  const unsigned n_boundary = Bulk_mesh_pt->nboundary();
320 
321  // Loop over mesh boundaries
322  for(unsigned b=0;b<n_boundary;b++)
323  {
324  // Determine number of nodes on boundary b
325  const unsigned n_node = Bulk_mesh_pt->nboundary_node(b);
326 
327  // Loop over nodes on boundary b
328  for(unsigned n=0;n<n_node;n++)
329  {
330  // Fluid boundary conditions:
331  // --------------------------
332 
333  // Pin x-component of velocity (no slip/penetration)
334  // on all boundaries other than the interface (b=4)
335  if(b!=4) { Bulk_mesh_pt->boundary_node_pt(b,n)->pin(0); }
336 
337  // Pin y-component of velocity on both solid boundaries (no penetration)
338  if(b==0 || b==2) { Bulk_mesh_pt->boundary_node_pt(b,n)->pin(1); }
339 
340  // Solid boundary conditions:
341  // --------------------------
342 
343  // Pin vertical mesh position on both solid boundaries (no penetration)
344  if(b==0 || b==2) { Bulk_mesh_pt->boundary_node_pt(b,n)->pin_position(1); }
345 
346  } // End of loop over nodes on boundary b
347  } // End of loop over mesh boundaries
348 
349  // Pin horizontal position of all nodes
350  const unsigned n_node = Bulk_mesh_pt->nnode();
351  for(unsigned n=0;n<n_node;n++) { Bulk_mesh_pt->node_pt(n)->pin_position(0); }
352 
353  // Define a constitutive law for the solid equations: generalised Hookean
354  Constitutive_law_pt = new GeneralisedHookean(&Global_Physical_Variables::Nu);
355 
356  // ----------------------------------------------------------------
357  // Complete the problem setup to make the elements fully functional
358  // ----------------------------------------------------------------
359 
360  // Compute number of bulk elements in lower/upper fluids
361  const unsigned n_lower = n_x*n_y1;
362  const unsigned n_upper = n_x*n_y2;
363 
364  // Loop over bulk elements in lower fluid
365  for(unsigned e=0;e<n_lower;e++)
366  {
367  // Upcast from GeneralisedElement to the present element
368  ELEMENT *el_pt = dynamic_cast<ELEMENT*>(Bulk_mesh_pt->element_pt(e));
369 
370  // Set the Reynolds number
371  el_pt->re_pt() = &Global_Physical_Variables::Re;
372 
373  // Set the Womersley number
374  el_pt->re_st_pt() = &Global_Physical_Variables::ReSt;
375 
376  // Set the product of the Reynolds number and the inverse of the
377  // Froude number
378  el_pt->re_invfr_pt() = &Global_Physical_Variables::ReInvFr;
379 
380  // Set the direction of gravity
381  el_pt->g_pt() = &Global_Physical_Variables::G;
382 
383  // Set the constitutive law
384  el_pt->constitutive_law_pt() = Constitutive_law_pt;
385 
386  } // End of loop over bulk elements in lower fluid
387 
388  // Loop over bulk elements in upper fluid
389  for(unsigned e=n_lower;e<(n_lower+n_upper);e++)
390  {
391  // Upcast from GeneralisedElement to the present element
392  ELEMENT *el_pt = dynamic_cast<ELEMENT*>(Bulk_mesh_pt->element_pt(e));
393 
394  // Set the Reynolds number
395  el_pt->re_pt() = &Global_Physical_Variables::Re;
396 
397  // Set the Womersley number
398  el_pt->re_st_pt() = &Global_Physical_Variables::ReSt;
399 
400  // Set the product of the Reynolds number and the inverse of the
401  // Froude number
402  el_pt->re_invfr_pt() = &Global_Physical_Variables::ReInvFr;
403 
404  // Set the viscosity ratio
405  el_pt->viscosity_ratio_pt() = &Global_Physical_Variables::Viscosity_Ratio;
406 
407  // Set the density ratio
408  el_pt->density_ratio_pt() = &Global_Physical_Variables::Density_Ratio;
409 
410  // Set the direction of gravity
411  el_pt->g_pt() = &Global_Physical_Variables::G;
412 
413  // Set the constitutive law
414  el_pt->constitutive_law_pt() = Constitutive_law_pt;
415 
416  } // End of loop over bulk elements in upper fluid
417 
418  // Set the pressure in the first element at 'node' 0 to 0.0
419  fix_pressure(0,0,0.0);
420 
421  // Apply the boundary conditions
422  set_boundary_conditions();
423 
424  // Set up equation numbering scheme
425  cout << "Number of equations: " << assign_eqn_numbers() << std::endl;
426 
427 } // End of constructor
428 
429 
430 
431 //==start_of_set_initial_condition========================================
432 /// Set initial conditions: Set all nodal velocities to zero and
433 /// initialise the previous velocities and nodal positions to correspond
434 /// to an impulsive start
435 //========================================================================
436 template <class ELEMENT, class TIMESTEPPER>
438 {
439  // Determine number of nodes in mesh
440  const unsigned n_node = mesh_pt()->nnode();
441 
442  // Loop over all nodes in mesh
443  for(unsigned n=0;n<n_node;n++)
444  {
445  // Loop over the two velocity components
446  for(unsigned i=0;i<2;i++)
447  {
448  // Set velocity component i of node n to zero
449  mesh_pt()->node_pt(n)->set_value(i,0.0);
450  }
451  }
452 
453  // Initialise the previous velocity values and nodal positions
454  // for timestepping corresponding to an impulsive start
455  assign_initial_values_impulsive();
456 
457 } // End of set_initial_condition
458 
459 
460 
461 //==start_of_set_boundary_conditions======================================
462 /// Set boundary conditions: Set both velocity components
463 /// to zero on the top and bottom (solid) walls and the horizontal
464 /// component only to zero on the side (periodic) boundaries
465 //========================================================================
466 template <class ELEMENT, class TIMESTEPPER>
468 {
469  // Determine number of mesh boundaries
470  const unsigned n_boundary = Bulk_mesh_pt->nboundary();
471 
472  // Loop over mesh boundaries
473  for(unsigned b=0;b<n_boundary;b++)
474  {
475  // Determine number of nodes on boundary b
476  const unsigned n_node = Bulk_mesh_pt->nboundary_node(b);
477 
478  // Loop over nodes on boundary b
479  for(unsigned n=0;n<n_node;n++)
480  {
481  // Set x-component of the velocity to zero on all boundaries
482  // other than the interface (b=4)
483  if(b!=4) { Bulk_mesh_pt->boundary_node_pt(b,n)->set_value(0,0.0); }
484 
485  // Set y-component of the velocity to zero on both solid
486  // boundaries (top and bottom)
487  if(b==0 || b==2)
488  {
489  Bulk_mesh_pt->boundary_node_pt(b,n)->set_value(1,0.0);
490  }
491  } // End of loop over nodes on boundary b
492  } // End of loop over mesh boundaries
493 
494 } // End of set_boundary_conditions
495 
496 
497 
498 //==start_of_actions_before_adapt=========================================
499 /// Strip off the interface elements before adapting the bulk mesh
500 //========================================================================
501 template<class ELEMENT, class TIMESTEPPER>
503 {
504  // Delete the interface elements and wipe the surface mesh
505  delete_interface_elements();
506 
507  // Rebuild the Problem's global mesh from its various sub-meshes
508  rebuild_global_mesh();
509 
510 } // End of actions_before_adapt
511 
512 
513 
514 //==start_of_actions_after_adapt==========================================
515 /// Rebuild the mesh of interface elements after adapting the bulk mesh
516 //========================================================================
517 template<class ELEMENT, class TIMESTEPPER>
519 {
520  // Create the interface elements
521  this->create_interface_elements();
522 
523  // Rebuild the Problem's global mesh from its various sub-meshes
524  rebuild_global_mesh();
525 
526  // Pin horizontal displacement of all nodes
527  const unsigned n_node = Bulk_mesh_pt->nnode();
528  for(unsigned n=0;n<n_node;n++) { Bulk_mesh_pt->node_pt(n)->pin_position(0); }
529 
530  // Unpin all fluid pressure dofs
531  RefineableNavierStokesEquations<2>::
532  unpin_all_pressure_dofs(Bulk_mesh_pt->element_pt());
533 
534  // Pin redudant fluid pressure dofs
535  RefineableNavierStokesEquations<2>::
536  pin_redundant_nodal_pressures(Bulk_mesh_pt->element_pt());
537 
538  // Now set the pressure in the first element at 'node' 0 to 0.0
539  fix_pressure(0,0,0.0);
540 
541  // Pin the redundant solid pressures (if any)
542  PVDEquationsBase<2>::pin_redundant_nodal_solid_pressures(
543  Bulk_mesh_pt->element_pt());
544 
545  // Reset the boundary conditions
546  set_boundary_conditions();
547 
548 } // End of actions_after_adapt
549 
550 
551 
552 //==start_of_create_interface_elements====================================
553 /// Create interface elements between the two fluids in the mesh
554 /// pointed to by Bulk_mesh_pt and add the elements to the Mesh object
555 /// pointed to by Surface_mesh_pt.
556 //========================================================================
557 template <class ELEMENT, class TIMESTEPPER>
559 {
560  // Determine number of bulk elements adjacent to interface (boundary 4)
561  const unsigned n_element = this->Bulk_mesh_pt->nboundary_element(4);
562 
563  // Loop over those elements adjacent to the interface
564  for(unsigned e=0;e<n_element;e++)
565  {
566  // Get pointer to the bulk element that is adjacent to the interface
567  ELEMENT* bulk_elem_pt = dynamic_cast<ELEMENT*>(
568  this->Bulk_mesh_pt->boundary_element_pt(4,e));
569 
570  // We only want to attach interface elements to the bulk elements
571  // which are BELOW the interface, and so we filter out those above by
572  // referring to the viscosity_ratio_pt
573  if(bulk_elem_pt->viscosity_ratio_pt()
575  {
576  // Find index of the face of element e that corresponds to the interface
577  const int face_index = this->Bulk_mesh_pt->face_index_at_boundary(4,e);
578 
579  // Create the interface element
580  FiniteElement* interface_element_element_pt =
581  new ElasticLineFluidInterfaceElement<ELEMENT>(bulk_elem_pt,face_index);
582 
583  // Add the interface element to the surface mesh
584  this->Surface_mesh_pt->add_element_pt(interface_element_element_pt);
585  }
586  }
587 
588  // --------------------------------------------------------
589  // Complete the setup to make the elements fully functional
590  // --------------------------------------------------------
591 
592  // Determine number of 1D interface elements in mesh
593  const unsigned n_interface_element = this->Surface_mesh_pt->nelement();
594 
595  // Loop over the interface elements
596  for(unsigned e=0;e<n_interface_element;e++)
597  {
598  // Upcast from GeneralisedElement to the present element
599  ElasticLineFluidInterfaceElement<ELEMENT>* el_pt =
600  dynamic_cast<ElasticLineFluidInterfaceElement<ELEMENT>*>
601  (Surface_mesh_pt->element_pt(e));
602 
603  // Set the Strouhal number
604  el_pt->st_pt() = &Global_Physical_Variables::St;
605 
606  // Set the Capillary number
607  el_pt->ca_pt() = &Global_Physical_Variables::Ca;
608 
609  } // End of loop over interface elements
610 
611 } // End of create_interface_elements
612 
613 
614 
615 //==start_of_delete_interface_elements====================================
616 /// Delete the interface elements and wipe the surface mesh
617 //========================================================================
618 template <class ELEMENT, class TIMESTEPPER>
620 {
621  // Determine number of interface elements
622  const unsigned n_interface_element = Surface_mesh_pt->nelement();
623 
624  // Loop over interface elements and delete
625  for(unsigned e=0;e<n_interface_element;e++)
626  {
627  delete Surface_mesh_pt->element_pt(e);
628  }
629 
630  // Wipe the mesh
631  Surface_mesh_pt->flush_element_and_node_storage();
632 
633 } // End of delete_interface_elements
634 
635 
636 
637 //==start_of_deform_free_surface==========================================
638 /// Deform the mesh/free surface to a prescribed function
639 //========================================================================
640 template <class ELEMENT, class TIMESTEPPER>
642 deform_free_surface(const double &epsilon,const unsigned &n_periods)
643 {
644  // Determine number of nodes in the "bulk" mesh
645  const unsigned n_node = Bulk_mesh_pt->nnode();
646 
647  // Loop over all nodes in mesh
648  for(unsigned n=0;n<n_node;n++)
649  {
650  // Determine eulerian position of node
651  const double current_x_pos = Bulk_mesh_pt->node_pt(n)->x(0);
652  const double current_y_pos = Bulk_mesh_pt->node_pt(n)->x(1);
653 
654  // Determine new vertical position of node
655  const double new_y_pos = current_y_pos
656  + (1.0-fabs(1.0-current_y_pos))*epsilon
657  *(cos(2.0*n_periods*MathematicalConstants::Pi*current_x_pos/Lx));
658 
659  // Set new position
660  Bulk_mesh_pt->node_pt(n)->x(1) = new_y_pos;
661  }
662 } // End of deform_free_surface
663 
664 
665 
666 //==start_of_doc_solution=================================================
667 /// Doc the solution
668 //========================================================================
669 template <class ELEMENT, class TIMESTEPPER>
671 {
672 
673  // Output the time
674  cout << "Time is now " << time_pt()->time() << std::endl;
675 
676  // Upcast from GeneralisedElement to the present element
677  ElasticLineFluidInterfaceElement<ELEMENT>* el_pt =
678  dynamic_cast<ElasticLineFluidInterfaceElement<ELEMENT>*>
679  (Surface_mesh_pt->element_pt(0));
680 
681  // Document time and vertical position of left hand side of interface
682  // in trace file
683  Trace_file << time_pt()->time() << " "
684  << el_pt->node_pt(0)->x(1) << std::endl;
685 
686  ofstream some_file;
687  char filename[100];
688 
689  // Set number of plot points (in each coordinate direction)
690  const unsigned npts = 5;
691 
692  // Open solution output file
693  sprintf(filename,"%s/soln%i.dat",
694  doc_info.directory().c_str(),doc_info.number());
695  some_file.open(filename);
696 
697  // Output solution to file
698  Bulk_mesh_pt->output(some_file,npts);
699 
700  // Close solution output file
701  some_file.close();
702 
703  // Open interface solution output file
704  sprintf(filename,"%s/interface_soln%i.dat",
705  doc_info.directory().c_str(),doc_info.number());
706  some_file.open(filename);
707 
708  // Output solution to file
709  Surface_mesh_pt->output(some_file,npts);
710 
711  // Close solution output file
712  some_file.close();
713 
714 } // End of doc_solution
715 
716 
717 
718 //==start_of_unsteady_run=================================================
719 /// Perform run up to specified time t_max with given timestep dt
720 //========================================================================
721 template <class ELEMENT, class TIMESTEPPER>
723 unsteady_run(const double &t_max, const double &dt)
724 {
725 
726  // Set value of epsilon
727  const double epsilon = 0.1;
728 
729  // Set number of periods for cosine term
730  const unsigned n_periods = 1;
731 
732  // Deform the mesh/free surface
733  deform_free_surface(epsilon,n_periods);
734 
735  // Initialise DocInfo object
736  DocInfo doc_info;
737 
738  // Set output directory
739  doc_info.set_directory("RESLT");
740 
741  // Initialise counter for solutions
742  doc_info.number()=0;
743 
744  // Open trace file
745  char filename[100];
746  sprintf(filename,"%s/trace.dat",doc_info.directory().c_str());
747  Trace_file.open(filename);
748 
749  // Initialise trace file
750  Trace_file << "time, interface height" << std::endl;
751 
752  // Initialise timestep
753  initialise_dt(dt);
754 
755  // Set initial condition
756  set_initial_condition();
757 
758  // Maximum number of spatial adaptations per timestep
759  unsigned max_adapt = 2;
760 
761  // Call refine_uniformly twice
762  for(unsigned i=0;i<2;i++) { refine_uniformly(); }
763 
764  // Doc initial solution
765  doc_solution(doc_info);
766 
767  // Increment counter for solutions
768  doc_info.number()++;
769 
770  // Determine number of timesteps
771  const unsigned n_timestep = unsigned(t_max/dt);
772 
773  // Are we on the first timestep? At this point, yes!
774  bool first_timestep = true;
775 
776  // Timestepping loop
777  for(unsigned t=1;t<=n_timestep;t++)
778  {
779  // Output current timestep to screen
780  cout << "\nTimestep " << t << " of " << n_timestep << std::endl;
781 
782  // Take one fixed timestep with spatial adaptivity
783  unsteady_newton_solve(dt,max_adapt,first_timestep);
784 
785  // No longer on first timestep, so set first_timestep flag to false
786  first_timestep = false;
787 
788  // Reset maximum number of adaptations for all future timesteps
789  max_adapt = 1;
790 
791  // Doc solution
792  doc_solution(doc_info);
793 
794  // Increment counter for solutions
795  doc_info.number()++;
796 
797  } // End of timestepping loop
798 
799 } // End of unsteady_run
800 
801 
802 /// ///////////////////////////////////////////////////////////////////////
803 /// ///////////////////////////////////////////////////////////////////////
804 /// ///////////////////////////////////////////////////////////////////////
805 
806 
807 //==start_of_main=========================================================
808 /// Driver code for two-dimensional two fluid interface problem
809 //========================================================================
810 int main(int argc, char* argv[])
811 {
812  // Store command line arguments
813  CommandLineArgs::setup(argc,argv);
814 
815  // -----------------------------------------------------------------
816  // Define possible command line arguments and parse the ones that
817  // were actually specified
818  // -----------------------------------------------------------------
819 
820  // Are we performing a validation run?
821  CommandLineArgs::specify_command_line_flag("--validation");
822 
823  // Parse command line
824  CommandLineArgs::parse_and_assign();
825 
826  // Doc what has actually been specified on the command line
827  CommandLineArgs::doc_specified_flags();
828 
829  // Check that definition of Womersley number is consistent with those
830  // of the Reynolds and Strouhal numbers
833  {
834  std::ostringstream error_stream;
835  error_stream << "Definition of Global_Physical_Variables::ReSt is "
836  << "inconsistant with those\n"
837  << "of Global_Physical_Variables::Re and "
838  << "Global_Physical_Variables::St." << std::endl;
839  throw OomphLibError(error_stream.str(),
840  OOMPH_CURRENT_FUNCTION,OOMPH_EXCEPTION_LOCATION);
841  }
842 
843  /// Maximum time
844  double t_max = 0.6;
845 
846  /// Duration of timestep
847  const double dt = 0.0025;
848 
849  // If we are doing validation run, use smaller number of timesteps
850  if(CommandLineArgs::command_line_flag_has_been_set("--validation"))
851  {
852  t_max = 0.005;
853  }
854 
855  // Set direction of gravity (vertically downwards)
858 
859  // Set up the elastic test problem with QCrouzeixRaviartElements,
860  // using the BDF<2> timestepper
861  InterfaceProblem<RefineablePseudoSolidNodeUpdateElement<
862  RefineableQCrouzeixRaviartElement<2>,RefineableQPVDElement<2,3> >, BDF<2> >
863  problem;
864 
865  // Run the unsteady simulation
866  problem.unsteady_run(t_max,dt);
867 
868 } // End of main
/////////////////////////////////////////////////////////////////////// /////////////////////////////...
ElasticRefineableTwoLayerMesh(const unsigned &nx, const unsigned &ny1, const unsigned &ny2, const double &lx, const double &h1, const double &h2, const bool &periodic_in_x, TimeStepper *time_stepper_pt=&Mesh::Default_TimeStepper)
Constructor: Pass number of elements in x-direction, number of elements in y-direction in bottom and ...
/////////////////////////////////////////////////////////////////////// /////////////////////////////...
Mesh * Surface_mesh_pt
Pointer to the "surface" mesh.
void set_initial_condition()
Set initial conditions.
void actions_after_adapt()
Rebuild the mesh of interface elements after adapting the bulk mesh.
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
void set_boundary_conditions()
Set boundary conditions.
~InterfaceProblem()
Destructor (empty)
void actions_before_adapt()
Strip off the interface elements before adapting the bulk mesh.
void create_interface_elements()
Create the 1d interface elements.
double Lx
Width of domain.
void fix_pressure(const unsigned &e, const unsigned &pdof, const double &pvalue)
Fix pressure in element e at pressure dof pdof and set to pvalue.
void delete_interface_elements()
Delete the 1d interface elements.
ElasticRefineableTwoLayerMesh< ELEMENT > * Bulk_mesh_pt
Pointer to the (specific) "bulk" mesh.
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.
int main(int argc, char *argv[])
/////////////////////////////////////////////////////////////////////// /////////////////////////////...
Namespace for physical parameters.
double ReSt
Womersley number (Reynolds x Strouhal)
Vector< double > G(2)
Direction of gravity.
double Nu
Pseudo-solid Poisson ratio.
double Density_Ratio
Ratio of density in upper fluid to density in lower fluid. Reynolds number etc. is based on density i...
double ReInvFr
Product of Reynolds number and inverse of Froude number.
double Viscosity_Ratio
Ratio of viscosity in upper fluid to viscosity in lower fluid. Reynolds number etc....
ConstitutiveLaw * Constitutive_law_pt
Constitutive law used to determine the mesh deformation.