channel_with_leaflet.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 // Generic oomph-lib includes
31 #include "generic.h"
32 
33 // Generic oomph-lib includes
34 #include "navier_stokes.h"
35 
36 //Include the mesh
37 #include "meshes/channel_with_leaflet_mesh.h"
38 
39 using namespace std;
40 using namespace oomph;
41 
42 
43 //===start_of_leaflet_class===========================================
44 /// GeomObject representing a vertical leaflet that performs
45 /// bending and stretching oscillations.
46 //====================================================================
47 class Leaflet : public GeomObject
48 {
49 
50 public:
51 
52  /// \short Constructor: Pass length (in Lagrangian coordinates),
53  /// the amplitude of the horizontal and vertical deflection of the tip,
54  /// the x-coordinate of the origin and the period of the oscillation.
55  /// Passes the number of Lagrangian and Eulerian coordinates to the
56  /// constructor of the GeomObject base class.
57  Leaflet(const double& length, const double& d_x,const double& d_y,
58  const double& x_0, const double& period, Time* time_pt)
59  : GeomObject(1,2), Length(length), D_x(d_x), D_y(d_y), X_0(x_0),
60  T(period),Time_pt(time_pt) {}
61 
62 
63  /// Destructor -- emtpy
64  virtual ~Leaflet(){}
65 
66  /// \short Position vector, r, to the point identified by
67  /// its 1D Lagrangian coordinate, xi (passed as a 1D Vector) at discrete time
68  /// level t (t=0: present; t>0: previous).
69  void position(const unsigned& t, const Vector<double>& xi,
70  Vector<double>& r) const
71  {
72  using namespace MathematicalConstants;
73 
74  //Position
75  r[0] = X_0 + D_x*xi[0]*xi[0]/Length/Length*sin(2.0*Pi*Time_pt->time(t)/T);
76  r[1] = xi[0]*(1.0+D_y/Length*0.5*(1.0-cos(4.0*Pi*Time_pt->time(t)/T)));
77  }
78 
79  /// Steady version: Get current shape
80  void position(const Vector<double>& xi, Vector<double>& r) const
81  {
82  position(0,xi,r);
83  }
84 
85  /// Number of geometric Data in GeomObject: None.
86  unsigned ngeom_data() const {return 0;}
87 
88  /// Length of the leaflet
89  double length() { return Length; }
90 
91  /// Amplitude of horizontal tip displacement
92  double& d_x() {return D_x;}
93 
94  /// Amplitude of vertical tip displacement
95  double d_y() {return D_y;}
96 
97  /// x-coordinate of leaflet origin
98  double x_0() {return X_0;}
99 
100 private :
101 
102  /// Length in terms of Lagrangian coordinates
103  double Length;
104 
105  ///\short Horizontal displacement of tip
106  double D_x;
107 
108  ///\short Vertical displacement of tip
109  double D_y;
110 
111 ///\short Origin
112  double X_0;
113 
114  ///Period of the oscillations
115  double T;
116 
117  ///Pointer to the global time object
118  Time* Time_pt;
119 
120 }; //end_of_the_GeomObject
121 
122 
123 
124 ///////////////////////////////////////////////////////////////////////
125 //////////////////////////////////////////////////////////////////////
126 ///////////////////////////////////////////////////////////////////////
127 
128 
129 //==start_of_global_parameters=======================================
130 /// Global parameters
131 //===================================================================
133 {
134 
135  /// Reynolds number
136  double Re=20.0;
137 
138 } // end_of_namespace
139 
140 
141 
142 ///////////////////////////////////////////////////////////////////////
143 //////////////////////////////////////////////////////////////////////
144 ///////////////////////////////////////////////////////////////////////
145 
146 
147 //==start_of_problem_class===========================================
148 /// Problem class
149 //===================================================================
150 template<class ELEMENT>
151 class ChannelWithLeafletProblem : public Problem
152 {
153 
154 public:
155 
156  /// Constructor: Pass the length of the domain at the left
157  /// of the leaflet lleft,the length of the domain at the right of the
158  /// leaflet lright,the height of the leaflet hleaflet, the total height
159  /// of the domain htot, the number of macro-elements at the left of the
160  /// leaflet nleft, the number of macro-elements at the right of the
161  /// leaflet nright, the number of macro-elements under hleaflet ny1,
162  /// the number of macro-elements above hleaflet ny2,the x-displacement
163  /// of the leaflet d_x,the y-displacement of the leaflet d_y,the abscissa
164  /// of the origin of the leaflet x_0, the period of the moving leaflet.
165  ChannelWithLeafletProblem(const double& l_left,
166  const double& l_right, const double& h_leaflet,
167  const double& h_tot,
168  const unsigned& nleft, const unsigned& nright,
169  const unsigned& ny1, const unsigned& ny2,
170  const double& d_x,const double& d_y,
171  const double& x_0, const double& period);
172 
173  /// Destructor (empty)
175 
176  /// Overloaded access function to specific mesh
177  RefineableAlgebraicChannelWithLeafletMesh<ELEMENT>* mesh_pt()
178  {
179  // Upcast from pointer to the Mesh base class to the specific
180  // element type that we're using here.
181  return dynamic_cast<RefineableAlgebraicChannelWithLeafletMesh<ELEMENT>*>(
182  Problem::mesh_pt());
183  }
184 
185  /// Update after solve (empty)
187 
188  /// Update before solve (empty)
190 
191  /// Actions after adaptation: Pin redundant pressure dofs
192  void actions_after_adapt();
193 
194  /// Update the velocity boundary condition on the moving leaflet
195  void actions_before_implicit_timestep();
196 
197  /// Doc the solution
198  void doc_solution(DocInfo& doc_info);
199 
200 private:
201 
202  /// Pointer to the GeomObject
203  GeomObject* Leaflet_pt;
204 
205 };
206 
207 
208 
209 
210 //==start_of_constructor=================================================
211 /// Constructor
212 //=======================================================================
213 template <class ELEMENT>
215  const double& l_left,
216  const double& l_right, const double& h_leaflet,
217  const double& h_tot,
218  const unsigned& nleft, const unsigned& nright,
219  const unsigned& ny1, const unsigned& ny2,
220  const double& d_x,const double& d_y,
221  const double& x_0, const double& period)
222 {
223  // Allocate the timestepper
224  add_time_stepper_pt(new BDF<2>);
225 
226  //Create the geometric object that represents the leaflet
227  Leaflet_pt = new Leaflet(h_leaflet, d_x, d_y, x_0, period, time_pt()) ;
228 
229 //Build the mesh
230 Problem::mesh_pt()=new RefineableAlgebraicChannelWithLeafletMesh<ELEMENT>(
231  Leaflet_pt,
232  l_left, l_right,
233  h_leaflet,
234  h_tot,nleft,
235  nright,ny1,ny2,
236  time_stepper_pt());
237 
238 
239  // Set error estimator
240  Z2ErrorEstimator* error_estimator_pt=new Z2ErrorEstimator;
241  dynamic_cast<RefineableAlgebraicChannelWithLeafletMesh<ELEMENT>*>(mesh_pt())->
242  spatial_error_estimator_pt()=error_estimator_pt;
243 
244 
245  // Loop over the elements to set up element-specific
246  // things that cannot be handled by constructor
247  unsigned n_element = mesh_pt()->nelement();
248  for(unsigned e=0;e<n_element;e++)
249  {
250  // Upcast from GeneralisedElement to the present element
251  ELEMENT* el_pt = dynamic_cast<ELEMENT*>(mesh_pt()->element_pt(e));
252 
253  //Set the Reynolds number
254  el_pt->re_pt() = &Global_Physical_Variables::Re;
255 
256  // Set the Womersley number (product of Reynolds and Strouhal).
257  // We're assuming a Strouhal number of one, corresponding to
258  // a non-dimensionalisation of time on the flow's natural timescale.
259  el_pt->re_st_pt() = &Global_Physical_Variables::Re;
260 
261  } // end loop over elements
262 
263 
264  //Pin the boundary nodes
265  unsigned num_bound = mesh_pt()->nboundary();
266  for(unsigned ibound=0;ibound<num_bound;ibound++)
267  {
268  unsigned num_nod= mesh_pt()->nboundary_node(ibound);
269  for (unsigned inod=0;inod<num_nod;inod++)
270  {
271  mesh_pt()->boundary_node_pt(ibound,inod)->pin(1);
272  //do not pin the x velocity of the outflow
273  if( ibound != 1)
274  {
275  mesh_pt()->boundary_node_pt(ibound,inod)->pin(0);
276  }
277  }
278  }
279 
280  // Setup parabolic flow along the inflow boundary 3
281  unsigned ibound=3;
282  unsigned num_nod= mesh_pt()->nboundary_node(ibound);
283  for (unsigned inod=0;inod<num_nod;inod++)
284  {
285  double ycoord = mesh_pt()->boundary_node_pt(ibound,inod)->x(1);
286  double uy = 6.0*(ycoord/h_tot)*(1.0-(ycoord/h_tot));
287 
288  mesh_pt()->boundary_node_pt(ibound,inod)->set_value(0,uy);
289  mesh_pt()->boundary_node_pt(ibound,inod)->set_value(1,0.0);
290  }// end of setup boundary condition
291 
292  // Pin redudant pressure dofs
293  RefineableNavierStokesEquations<2>::
294  pin_redundant_nodal_pressures(Problem::mesh_pt()->element_pt());
295 
296  // Setup equation numbering scheme
297  cout << "Number of equations: " << assign_eqn_numbers() << std::endl;
298 
299 }//end of constructor
300 
301 
302 
303 
304 //=====start_of_actions_before_implicit_timestep=========================
305 /// Actions before implicit timestep: Update domain shape and
306 /// the velocity boundary conditions
307 //=======================================================================
308 template <class ELEMENT>
310 {
311  // Update the domain shape
312  mesh_pt()->node_update();
313 
314  // Moving leaflet: No slip; this implies that the velocity needs
315  // to be updated in response to leaflet motion
316  for( unsigned ibound=4;ibound<6;ibound++)
317  {
318  unsigned num_nod=mesh_pt()->nboundary_node(ibound);
319  for (unsigned inod=0;inod<num_nod;inod++)
320  {
321  // Which node are we dealing with?
322  Node* node_pt=mesh_pt()->boundary_node_pt(ibound,inod);
323 
324  // Apply no slip
325  FSI_functions::apply_no_slip_on_moving_wall(node_pt);
326  }
327  }
328 } //end_of_actions_before_implicit_timestep
329 
330 
331 
332 //==========start_of_actions_after_adaptation============================
333 // Actions after adaptation: Pin redundant pressure dofs
334 //=======================================================================
335 template<class ELEMENT>
337 {
338  // Unpin all pressure dofs
339  RefineableNavierStokesEquations<2>::
340  unpin_all_pressure_dofs(mesh_pt()->element_pt());
341 
342  // Pin redundant pressure dofs
343  RefineableNavierStokesEquations<2>::
344  pin_redundant_nodal_pressures(mesh_pt()->element_pt());
345 
346 } // end_of_actions_after_adapt
347 
348 
349 
350 //==start_of_doc_solution=================================================
351 /// Doc the solution
352 //========================================================================
353 template<class ELEMENT>
355 {
356 
357  ofstream some_file;
358  char filename[100];
359 
360  // Number of plot points
361  unsigned npts;
362  npts=5;
363 
364  // Output solution
365  sprintf(filename,"%s/soln%i.dat",doc_info.directory().c_str(),
366  doc_info.number());
367  some_file.open(filename);
368  mesh_pt()->output(some_file,npts);
369  some_file.close();
370 
371  // Output boundaries
372  sprintf(filename,"%s/boundaries%i.dat",doc_info.directory().c_str(),
373  doc_info.number());
374  some_file.open(filename);
375  mesh_pt()->output_boundaries(some_file);
376  some_file.close();
377 
378 } // end_of_doc_solution
379 
380 
381 ///////////////////////////////////////////////////////////////////////
382 //////////////////////////////////////////////////////////////////////
383 ///////////////////////////////////////////////////////////////////////
384 
385 
386 //======start_of_main==================================================
387 /// Driver code -- pass a command line argument if you want to run
388 /// the code in validation mode where it only performs a few steps
389 //=====================================================================
390 int main(int argc, char* argv[])
391 {
392 
393  // Store command line arguments
394  CommandLineArgs::setup(argc,argv);
395 
396  // Set up doc info
397  DocInfo doc_info;
398  doc_info.set_directory("RESLT");
399  doc_info.number()=0;
400 
401  // Parameters for the leaflet
402  //----------------------------
403 
404  // Height
405  double h_leaflet = 0.5;
406 
407 
408  // Tip deflection
409  double d_x = 0.25;
410  double d_y = -0.05;
411 
412  // x-positon of root
413  double x_0 = 3.0;
414 
415  // Period of the oscillation on the natural timescale of the flow
416  double period = 20.0;
417 
418 
419  //Parameters for the domain
420  //-------------------------
421 
422  // Length of the mesh to right and left of the leaflet
423  double l_left =2.0;
424  double l_right= 3.0;
425 
426  // Total height of domain (unity because lengths have been scaled on it)
427  double h_tot=1.0;
428 
429  // Initial number of element rows/columns in various mesh regions
430  unsigned nleft=8;
431  unsigned nright=12;
432  unsigned ny1=2;
433  unsigned ny2=2;
434 
435  //Build the problem
437  problem(l_left, l_right, h_leaflet,
438  h_tot,nleft, nright,ny1,ny2,
439  d_x, d_y, x_0,
440  period);
441 
442 
443  // Number of timesteps per period
444  unsigned nsteps_per_period=40;
445 
446  // Number of periods
447  unsigned nperiod=3;
448 
449  // Number of timesteps (reduced for validation)
450  unsigned nstep=nsteps_per_period*nperiod;
451  if (CommandLineArgs::Argc>1)
452  {
453  nstep=3;
454  }
455 
456  //Timestep:
457  double dt=period/double(nsteps_per_period);
458 
459  /// Initialise timestep
460  problem.initialise_dt(dt);
461 
462 
463  /// Set max. number of adaptations (reduced for validation)
464  unsigned max_adapt=5;
465  if (CommandLineArgs::Argc>1)
466  {
467  max_adapt=2;
468  }
469 
470  // Do steady solve first -- this also sets the history values
471  // to those corresponding to an impulsive start from the
472  // steady solution
473  problem.steady_newton_solve(max_adapt);
474 
475  /// Output steady solution
476  problem.doc_solution(doc_info);
477  doc_info.number()++;
478 
479 
480  /// Reduce the max number of adaptations for time-dependent simulation
481  max_adapt=1;
482 
483  // We don't want to re-assign the initial condition
484  bool first=false;
485 
486 // Timestepping loop
487  for (unsigned istep=0;istep<nstep;istep++)
488  {
489  // Solve the problem
490  problem.unsteady_newton_solve(dt,max_adapt,first);
491 
492  // Output the solution
493  problem.doc_solution(doc_info);
494 
495  // Step number
496  doc_info.number()++;
497 
498  }
499 
500 
501 }//end of main
502 
503 
void actions_before_implicit_timestep()
Update the velocity boundary condition on the moving leaflet.
void position(const Vector< double > &xi, Vector< double > &r) const
Steady version: Get current shape.
ChannelWithLeafletProblem(const double &l_left, const double &l_right, const double &h_leaflet, const double &h_tot, const unsigned &nleft, const unsigned &nright, const unsigned &ny1, const unsigned &ny2, const double &d_x, const double &d_y, const double &x_0, const double &period)
Constructor.
double D_x
Horizontal displacement of tip.
void actions_before_newton_solve()
Update before solve (empty)
double x_0()
x-coordinate of leaflet origin
double T
Period of the oscillations.
void doc_solution(DocInfo &doc_info)
Doc the solution.
Leaflet(const double &length, const double &d_x, const double &d_y, const double &x_0, const double &period, Time *time_pt)
Constructor: Pass length (in Lagrangian coordinates), the amplitude of the horizontal and vertical de...
int main(int argc, char *argv[])
double Length
Length in terms of Lagrangian coordinates.
double D_y
Vertical displacement of tip.
double & d_x()
Amplitude of horizontal tip displacement.
double Re
Reynolds number.
virtual ~Leaflet()
Destructor – emtpy.
double X_0
Origin.
void actions_after_newton_solve()
Update after solve (empty)
GeomObject * Leaflet_pt
Pointer to the GeomObject.
void actions_after_adapt()
Actions after adaptation: Pin redundant pressure dofs.
void position(const unsigned &t, const Vector< double > &xi, Vector< double > &r) const
Position vector, r, to the point identified by its 1D Lagrangian coordinate, xi (passed as a 1D Vecto...
~ChannelWithLeafletProblem()
Destructor (empty)
unsigned ngeom_data() const
Number of geometric Data in GeomObject: None.
RefineableAlgebraicChannelWithLeafletMesh< ELEMENT > * mesh_pt()
Overloaded access function to specific mesh.
double d_y()
Amplitude of vertical tip displacement.
Time * Time_pt
Pointer to the global time object.
double length()
Length of the leaflet.