spine_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 two-dimensional two fluid interface problem, where
27// the mesh is deformed using a spine-based 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// The mesh
39#include "meshes/two_layer_spine_mesh.h"
40
41using namespace std;
42
43using namespace oomph;
44
45
46//==start_of_namespace====================================================
47/// Namespace for physical parameters
48//========================================================================
50{
51
52 /// Reynolds number
53 double Re = 5.0;
54
55 /// Strouhal number
56 double St = 1.0;
57
58 /// Womersley number (Reynolds x Strouhal, computed automatically)
59 double ReSt;
60
61 /// Product of Reynolds number and inverse of Froude number
62 double ReInvFr = 5.0; // (Fr = 1)
63
64 /// Ratio of viscosity in upper fluid to viscosity in lower
65 /// fluid. Reynolds number etc. is based on viscosity in lower fluid.
66 double Viscosity_Ratio = 0.1;
67
68 /// Ratio of density in upper fluid to density in lower
69 /// fluid. Reynolds number etc. is based on density in lower fluid.
70 double Density_Ratio = 0.5;
71
72 /// Capillary number
73 double Ca = 0.01;
74
75 /// Direction of gravity
77
78} // End of namespace
79
80
81/// ///////////////////////////////////////////////////////////////////////
82/// ///////////////////////////////////////////////////////////////////////
83/// ///////////////////////////////////////////////////////////////////////
84
85
86//==start_of_problem_class================================================
87/// Two fluid interface problem in a rectangular domain which is
88/// periodic in the x direction
89//========================================================================
90template <class ELEMENT, class TIMESTEPPER>
91class InterfaceProblem : public Problem
92{
93
94public:
95
96 /// Constructor: Pass the number of elements and the width of the
97 /// domain in the x direction. Also pass the number of elements in
98 /// the y direction of the bottom (fluid 1) and top (fluid 2) layers,
99 /// along with the heights of both layers.
100 InterfaceProblem(const unsigned &n_x, const unsigned &n_y1,
101 const unsigned &n_y2, const double &l_x,
102 const double &h1, const double &h2);
103
104 /// Destructor (empty)
106
107 /// Set initial conditions
109
110 /// Set boundary conditions
112
113 /// Doc the solution
115
116 /// Do unsteady run up to maximum time t_max with given timestep dt
117 void unsteady_run(const double &t_max, const double &dt);
118
119private:
120
121 /// Spine heights/lengths are unknowns in the problem so their
122 /// values get corrected during each Newton step. However, changing
123 /// their value does not automatically change the nodal positions, so
124 /// we need to update all of them here.
126 {
127 Bulk_mesh_pt->node_update();
128 }
129
130 /// No actions required before solve step
132
133 /// Update after solve can remain empty, because the update
134 /// is performed automatically after every Newton step.
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 /// Fix pressure in element e at pressure dof pdof and set to pvalue
141 void fix_pressure(const unsigned &e,
142 const unsigned &pdof,
143 const double &pvalue)
144 {
145 // Fix the pressure at that element
146 dynamic_cast<ELEMENT*>(Bulk_mesh_pt->element_pt(e))->
148 }
149
150 /// Width of domain
151 double Lx;
152
153 /// Trace file
155
156 /// Pointer to the specific bulk mesh
158
159 /// Pointer to the surface mesh
161
162}; // End of problem class
163
164
165
166//==start_of_constructor==================================================
167/// Constructor for two fluid interface problem
168//========================================================================
169template <class ELEMENT, class TIMESTEPPER>
171InterfaceProblem(const unsigned &n_x, const unsigned &n_y1,
172 const unsigned &n_y2, const double &l_x,
173 const double& h1, const double &h2) : Lx(l_x)
174{
175
176 // Allocate the timestepper (this constructs the time object as well)
178
179 // Build and assign mesh (the "true" boolean flag tells the mesh
180 // constructor that the domain is periodic in x)
183
184 Surface_mesh_pt = new Mesh;
185
186 //Loop over the horizontal elements
187 for(unsigned i=0;i<n_x;i++)
188 {
189 //Construct a new 1D line element on the face on which the local
190 //coordinate 1 is fixed at its max. value (1) -- Face 2
193 Bulk_mesh_pt->finite_element_pt(n_x*(n_y1-1)+i),2);
194
195 this->Surface_mesh_pt->add_element_pt(interface_element_pt);
196 }
197
198
199 // --------------------------------------------
200 // Set the boundary conditions for this problem
201 // --------------------------------------------
202
203 // All nodes are free by default -- just pin the ones that have
204 // Dirichlet conditions here
205
206 // Loop over mesh boundaries
207 for(unsigned b=0;b<5;b++)
208 {
209 // Determine number of nodes on boundary b
210 const unsigned n_node = Bulk_mesh_pt->nboundary_node(b);
211
212 // Loop over nodes on boundary b
213 for (unsigned n=0;n<n_node;n++)
214 {
215 // Pin x-component of velocity on all boundaries (no slip/penetration)
216 Bulk_mesh_pt->boundary_node_pt(b,n)->pin(0);
217
218 // Pin y-component of velocity on both solid boundaries (no penetration)
219 if(b==0 || b==3) { Bulk_mesh_pt->boundary_node_pt(b,n)->pin(1); }
220 }
221 }
222
223 // ----------------------------------------------------------------
224 // Complete the problem setup to make the elements fully functional
225 // ----------------------------------------------------------------
226
227 // Determine number of bulk elements in lower/upper fluids
228 const unsigned n_lower = Bulk_mesh_pt->nlower();
229 const unsigned n_upper = Bulk_mesh_pt->nupper();
230
231 // Loop over bulk elements in lower fluid
232 for(unsigned e=0;e<n_lower;e++)
233 {
234 // Upcast from GeneralisedElement to the present element
235 ELEMENT *el_pt = dynamic_cast<ELEMENT*>(Bulk_mesh_pt->
237
238 // Set the Reynolds number
240
241 // Set the Womersley number
243
244 // Set the product of the Reynolds number and the inverse of the
245 // Froude number
247
248 // Set the direction of gravity
250
251 } // End of loop over bulk elements in lower fluid
252
253 // Loop over bulk elements in upper fluid
254 for(unsigned e=0;e<n_upper;e++)
255 {
256 // Upcast from GeneralisedElement to the present element
257 ELEMENT *el_pt = dynamic_cast<ELEMENT*>(Bulk_mesh_pt->
259
260 // Set the Reynolds number
262
263 // Set the Womersley number
265
266 // Set the product of the Reynolds number and the inverse of the
267 // Froude number
269
270 // Set the viscosity ratio
271 el_pt->viscosity_ratio_pt() = &Global_Physical_Variables::Viscosity_Ratio;
272
273 // Set the density ratio
274 el_pt->density_ratio_pt() = &Global_Physical_Variables::Density_Ratio;
275
276 // Set the direction of gravity
278
279 } // End of loop over bulk elements in upper fluid
280
281 // Set the pressure in the first element at 'node' 0 to 0.0
282 fix_pressure(0,0,0.0);
283
284 // Determine number of 1D interface elements in mesh
285 unsigned n_interface_element = Surface_mesh_pt->nelement();
286
287 // Loop over interface elements
288 for(unsigned e=0;e<n_interface_element;e++)
289 {
290 // Upcast from GeneralisedElement to the present element
293 (Surface_mesh_pt->element_pt(e));
294
295 // Set the Strouhal number
297
298 // Set the Capillary number
300
301 } // End of loop over interface elements
302
303 // Apply the boundary conditions
305
308
309 this->build_global_mesh();
310
311
312 // Setup equation numbering scheme
313 cout << "Number of equations: " << assign_eqn_numbers() << std::endl;
314
315} // End of constructor
316
317
318
319//==start_of_set_initial_condition========================================
320/// Set initial conditions: Set all nodal velocities to zero and
321/// initialise the previous velocities and nodal positions to correspond
322/// to an impulsive start
323//========================================================================
324template <class ELEMENT, class TIMESTEPPER>
326{
327 // Determine number of nodes in mesh
328 const unsigned n_node = Bulk_mesh_pt->nnode();
329
330 // Loop over all nodes in mesh
331 for(unsigned n=0;n<n_node;n++)
332 {
333 // Loop over the two velocity components
334 for(unsigned i=0;i<2;i++)
335 {
336 // Set velocity component i of node n to zero
337 Bulk_mesh_pt->node_pt(n)->set_value(i,0.0);
338 }
339 }
340
341 // Initialise the previous velocity values for timestepping
342 // corresponding to an impulsive start
344
345} // End of set_initial_condition
346
347
348
349//==start_of_set_boundary_conditions======================================
350/// Set boundary conditions: Set both velocity components
351/// to zero on the top and bottom (solid) walls and the horizontal
352/// component only to zero on the side (periodic) boundaries
353//========================================================================
354template <class ELEMENT, class TIMESTEPPER>
356{
357
358 // Loop over mesh boundaries
359 for(unsigned b=0;b<5;b++)
360 {
361 // Determine number of nodes on boundary b
362 const unsigned n_node = Bulk_mesh_pt->nboundary_node(b);
363
364 // Loop over nodes on boundary b
365 for(unsigned n=0;n<n_node;n++)
366 {
367 // Set x-component of the velocity to zero on all boundaries
368 Bulk_mesh_pt->boundary_node_pt(b,n)->set_value(0,0.0);
369
370 // Set y-component of the velocity to zero on both solid
371 // boundaries (top and bottom)
372 if(b==0 || b==3)
373 {
374 Bulk_mesh_pt->boundary_node_pt(b,n)->set_value(1,0.0);
375 }
376 } // End of loop over nodes on boundary b
377 } // End of loop over mesh boundaries
378
379} // End of set_boundary_conditions
380
381
382
383//==start_of_deform_free_surface==========================================
384/// Deform the mesh/free surface to a prescribed function
385//========================================================================
386template <class ELEMENT, class TIMESTEPPER>
388deform_free_surface(const double &epsilon,const unsigned &n_periods)
389{
390 // Determine number of spines in mesh
391 const unsigned n_spine = Bulk_mesh_pt->nspine();
392
393 // Loop over spines in mesh
394 for(unsigned i=0;i<n_spine;i++)
395 {
396 // Determine x coordinate of spine
397 double x_value = Bulk_mesh_pt->boundary_node_pt(0,i)->x(0);
398
399 // Set spine height
400 Bulk_mesh_pt->spine_pt(i)->height() =
402 }
403
404 // Update nodes in bulk mesh
405 Bulk_mesh_pt->node_update();
406
407} // End of deform_free_surface
408
409
410
411//==start_of_doc_solution=================================================
412/// Doc the solution
413//========================================================================
414template <class ELEMENT, class TIMESTEPPER>
416{
417
418 // Output the time
419 cout << "Time is now " << time_pt()->time() << std::endl;
420
421 // Document time and vertical position of left hand side of interface
422 // in trace file
423 Trace_file << time_pt()->time() << " "
424 << Bulk_mesh_pt->spine_pt(0)->height() << " " << std::endl;
425
427 char filename[100];
428
429 // Set number of plot points (in each coordinate direction)
430 const unsigned npts = 5;
431
432 // Open solution output file
433 sprintf(filename,"%s/soln%i.dat",doc_info.directory().c_str(),
434 doc_info.number());
435 some_file.open(filename);
436
437 // Output solution to file
438 Bulk_mesh_pt->output(some_file,npts);
439 Surface_mesh_pt->output(some_file,npts);
440
441 // Close solution output file
442 some_file.close();
443
444} // End of doc_solution
445
446
447
448//==start_of_unsteady_run=================================================
449/// Perform run up to specified time t_max with given timestep dt
450//========================================================================
451template <class ELEMENT, class TIMESTEPPER>
453unsteady_run(const double &t_max, const double &dt)
454{
455
456 // Set value of epsilon
457 const double epsilon = 0.1;
458
459 // Set number of periods for cosine term
460 const unsigned n_periods = 1;
461
462 // Deform the mesh/free surface
463 deform_free_surface(epsilon,n_periods);
464
465 // Initialise DocInfo object
467
468 // Set output directory
469 doc_info.set_directory("RESLT");
470
471 // Initialise counter for solutions
472 doc_info.number()=0;
473
474 // Open trace file
475 char filename[100];
476 sprintf(filename,"%s/trace.dat",doc_info.directory().c_str());
477 Trace_file.open(filename);
478
479 // Initialise trace file
480 Trace_file << "time, free surface height" << std::endl;
481
482 // Initialise timestep
484
485 // Set initial conditions
486 set_initial_condition();
487
488 // Determine number of timesteps
489 const unsigned n_timestep = unsigned(t_max/dt);
490
491 // Doc initial solution
492 doc_solution(doc_info);
493
494 // Increment counter for solutions
495 doc_info.number()++;
496
497 // Timestepping loop
498 for(unsigned t=1;t<=n_timestep;t++)
499 {
500 // Output current timestep to screen
501 cout << "\nTimestep " << t << " of " << n_timestep << std::endl;
502
503 // Take one fixed timestep
505
506 // Doc solution
507 doc_solution(doc_info);
508
509 // Increment counter for solutions
510 doc_info.number()++;
511
512 } // End of timestepping loop
513
514} // End of unsteady_run
515
516
517/// ///////////////////////////////////////////////////////////////////////
518/// ///////////////////////////////////////////////////////////////////////
519/// ///////////////////////////////////////////////////////////////////////
520
521
522//==start_of_main======================================================
523/// Driver code for two-dimensional two fluid interface problem
524//=====================================================================
525int main(int argc, char* argv[])
526{
527 // Store command line arguments
529
530 // Compute the Womersley number
533
534 /// Maximum time
535 double t_max = 0.6;
536
537 /// Duration of timestep
538 const double dt = 0.0025;
539
540 // If we are doing validation run, use smaller number of timesteps
541 if(CommandLineArgs::Argc>1) { t_max = 0.005; }
542
543 // Number of elements in x direction
544 const unsigned n_x = 12;
545
546 // Number of elements in y direction in lower fluid (fluid 1)
547 const unsigned n_y1 = 12;
548
549 // Number of elements in y direction in upper fluid (fluid 2)
550 const unsigned n_y2 = 12;
551
552 // Width of domain
553 const double l_x = 1.0;
554
555 // Height of lower fluid layer
556 const double h1 = 1.0;
557
558 // Height of upper fluid layer
559 const double h2 = 1.0;
560
561 // Set direction of gravity (vertically downwards)
564
565 // Set up the spine test problem with QCrouzeixRaviartElements,
566 // using the BDF<2> timestepper
569
570 // Run the unsteady simulation
571 problem.unsteady_run(t_max,dt);
572
573} // 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.
TwoLayerSpineMesh< ELEMENT > * Bulk_mesh_pt
Pointer to the specific bulk mesh.
void deform_free_surface(const double &epsilon, const unsigned &n_periods)
Deform the mesh/free surface to a prescribed function.
void doc_solution(DocInfo &doc_info)
Doc the solution.
void set_boundary_conditions()
Set boundary conditions.
~InterfaceProblem()
Destructor (empty)
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 actions_before_newton_convergence_check()
Spine heights/lengths are unknowns in the problem so their values get corrected during each Newton st...
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_after_newton_solve()
Update after solve can remain empty, because the update is performed automatically after every Newton...
Namespace for physical parameters.
double ReSt
Womersley number (Reynolds x Strouhal)
Vector< double > G(2)
Direction of gravity.
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....
int main(int argc, char *argv[])
/////////////////////////////////////////////////////////////////////// /////////////////////////////...