fsi_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 #include "beam.h"
33 #include "navier_stokes.h"
34 #include "multi_physics.h"
35 
36 //Include the mesh
37 #include "meshes/channel_with_leaflet_mesh.h"
38 
39 // The wall mesh
40 #include "meshes/one_d_lagrangian_mesh.h"
41 
42 
43 using namespace std;
44 using namespace oomph;
45 
46 
47 //==== start_of_global_parameters================================
48 /// Global parameters
49 //===============================================================
51 {
52  /// Reynolds number
53  double Re=50.0;
54 
55  /// Womersley number: Product of Reynolds and Strouhal numbers
56  double ReSt=50.0;
57 
58  /// Non-dimensional wall thickness.
59  double H=0.05;
60 
61  /// \short Fluid structure interaction parameter: Ratio of stresses used for
62  /// non-dimensionalisation of fluid to solid stresses.
63  double Q=1.0e-6;
64 
65  /// Period for fluctuations in flux
66  double Period=2.0;
67 
68  /// Min. flux
69  double Min_flux=1.0;
70 
71  /// Max. flux
72  double Max_flux=2.0;
73 
74  /// \short Flux: Pulsatile flow fluctuating between Min_flux and Max_flux
75  /// with period Period
76  double flux(const double& t)
77  {
78  return Min_flux+
79  (Max_flux-Min_flux)*0.5*(1.0-cos(2.0*MathematicalConstants::Pi*t/Period));
80  }
81 
82 } // end_of_namespace
83 
84 
85 
86 ///////////////////////////////////////////////////////////////////////
87 //////////////////////////////////////////////////////////////////////
88 ///////////////////////////////////////////////////////////////////////
89 
90 
91 //=====start_of_undeformed_leaflet=================================
92 ///GeomObject: Undeformed straight, vertical leaflet
93 //=================================================================
94 class UndeformedLeaflet : public GeomObject
95 {
96 
97 public:
98 
99  /// Constructor: argument is the x-coordinate of the leaflet
100  UndeformedLeaflet(const double& x0): GeomObject(1,2)
101  {
102  X0=x0;
103  }
104 
105  /// \short Position vector at Lagrangian coordinate zeta
106  void position(const Vector<double>& zeta, Vector<double>& r) const
107  {
108  // Position Vector
109  r[0] = X0;
110  r[1] = zeta[0];
111  }
112 
113 
114  /// \short Parametrised position on object: r(zeta). Evaluated at
115  /// previous timestep. t=0: current time; t>0: previous
116  /// timestep. Calls steady version.
117  void position(const unsigned& t, const Vector<double>& zeta,
118  Vector<double>& r) const
119  {
120  // Use the steady version
121  position(zeta,r);
122  } // end of position
123 
124 
125  /// \short Posn vector and its 1st & 2nd derivatives
126  /// w.r.t. to coordinates:
127  /// \f$ \frac{dR_i}{d \zeta_\alpha}\f$ = drdzeta(alpha,i).
128  /// \f$ \frac{d^2R_i}{d \zeta_\alpha d \zeta_\beta}\f$ =
129  /// ddrdzeta(alpha,beta,i). Evaluated at current time.
130  void d2position(const Vector<double>& zeta,
131  Vector<double>& r,
132  DenseMatrix<double> &drdzeta,
133  RankThreeTensor<double> &ddrdzeta) const
134  {
135  // Position vector
136  r[0] = X0;
137  r[1] = zeta[0];
138 
139  // Tangent vector
140  drdzeta(0,0)=0.0;
141  drdzeta(0,1)=1.0;
142 
143  // Derivative of tangent vector
144  ddrdzeta(0,0,0)=0.0;
145  ddrdzeta(0,0,1)=0.0;
146  } // end of d2position
147 
148  /// Number of geometric Data in GeomObject: None.
149  unsigned ngeom_data() const {return 0;}
150 
151  private :
152 
153  /// x position of the undeformed leaflet's origin.
154  double X0;
155 
156 }; //end_of_undeformed_wall
157 
158 
159 ///////////////////////////////////////////////////////////////////////
160 //////////////////////////////////////////////////////////////////////
161 ///////////////////////////////////////////////////////////////////////
162 
163 
164 //=====start_of_problem_class========================================
165 /// FSI leaflet in channel
166 //===================================================================
167 template<class ELEMENT>
168 class FSIChannelWithLeafletProblem : public Problem
169 {
170 
171 public:
172 
173  /// \short Constructor: Pass the lenght of the domain at the left
174  /// of the leaflet lleft,the lenght of the domain at the right of the
175  /// leaflet lright,the height of the leaflet hleaflet, the total height
176  /// of the domain htot, the number of macro-elements at the left of the
177  /// leaflet nleft, the number of macro-elements at the right of the
178  /// leaflet nright, the number of macro-elements under hleaflet ny1,
179  /// the number of macro-elements above hleaflet ny2, the abscissa
180  /// of the origin of the leaflet x_0.
181  FSIChannelWithLeafletProblem(const double& lleft,
182  const double& lright, const double& hleaflet,
183  const double& htot,
184  const unsigned& nleft, const unsigned& nright,
185  const unsigned& ny1, const unsigned& ny2,
186  const double& x_0);
187 
188  /// Destructor empty
190 
191  /// Actions after solve (empty)
193 
194  /// Actions before solve (empty)
196 
197  /// Actions after adaptation
198  void actions_after_adapt();
199 
200  /// Access function to the wall mesh
201  OneDLagrangianMesh<FSIHermiteBeamElement>* wall_mesh_pt()
202  {
203  return Wall_mesh_pt;
204  }
205 
206  /// Access function to fluid mesh
207  RefineableAlgebraicChannelWithLeafletMesh<ELEMENT>* fluid_mesh_pt()
208  {
209  return Fluid_mesh_pt;
210  }
211 
212  /// Doc the solution
213  void doc_solution(DocInfo& doc_info, ofstream& trace);
214 
215 
216 /// Update the inflow velocity
218  {
219  // Actual time
220  double t=time_pt()->time();
221 
222  // Amplitude of flow
223  double ampl=Global_Physical_Variables::flux(t);
224 
225  // Update parabolic flow along boundary 3
226  unsigned ibound=3;
227  unsigned num_nod= Fluid_mesh_pt->nboundary_node(ibound);
228  for (unsigned inod=0;inod<num_nod;inod++)
229  {
230  double ycoord = Fluid_mesh_pt->boundary_node_pt(ibound,inod)->x(1);
231  double uy = ampl*6.0*ycoord/Htot*(1.0-ycoord/Htot);
232  Fluid_mesh_pt->boundary_node_pt(ibound,inod)->set_value(0,uy);
233  Fluid_mesh_pt->boundary_node_pt(ibound,inod)->set_value(1,0.0);
234  }
235  } // end of actions_before_implicit_timestep
236 
237  /// \short Update before checking Newton convergence: Update the
238  /// nodal positions in the fluid mesh in response to possible
239  /// changes in the wall shape
241  {
242  Fluid_mesh_pt->node_update();
243  }
244 
245 private:
246 
247  /// Pointer to the fluid mesh
248  RefineableAlgebraicChannelWithLeafletMesh<ELEMENT>* Fluid_mesh_pt;
249 
250  /// Pointer to the "wall" mesh
251  OneDLagrangianMesh<FSIHermiteBeamElement>* Wall_mesh_pt;
252 
253  /// Pointer to the GeomObject that represents the wall
254  GeomObject* Leaflet_pt;
255 
256  /// Total height of the domain
257  double Htot;
258 
259 };
260 
261 
262 
263 
264 
265 //=====start_of_constructor==============================================
266 /// Constructor
267 //=======================================================================
268 template <class ELEMENT>
270  const double& lleft,
271  const double& lright,
272  const double& hleaflet,
273  const double& htot,
274  const unsigned& nleft,
275  const unsigned& nright,
276  const unsigned& ny1,
277  const unsigned& ny2,
278  const double& x_0) : Htot(htot)
279 {
280  // Timesteppers:
281  //--------------
282 
283  // Allocate the timestepper
284  BDF<2>* fluid_time_stepper_pt=new BDF<2>;
285  add_time_stepper_pt(fluid_time_stepper_pt);
286 
287  // Allocate the wall timestepper
288  Steady<2>* wall_time_stepper_pt=new Steady<2>;
289  add_time_stepper_pt(wall_time_stepper_pt);
290 
291 
292  // Discretise leaflet
293  //-------------------
294 
295  // Geometric object that represents the undeformed leaflet
296  UndeformedLeaflet* undeformed_wall_pt=new UndeformedLeaflet(x_0);
297 
298  //Create the "wall" mesh with FSI Hermite beam elements
299  unsigned n_wall_el=5;
300  Wall_mesh_pt = new OneDLagrangianMesh<FSIHermiteBeamElement>
301  (n_wall_el,hleaflet,undeformed_wall_pt,wall_time_stepper_pt);
302 
303 
304  // Provide GeomObject representation of leaflet mesh and build fluid mesh
305  //-----------------------------------------------------------------------
306 
307  // Build a geometric object (one Lagrangian, two Eulerian coordinates)
308  // from the wall mesh
309  MeshAsGeomObject* wall_geom_object_pt=
310  new MeshAsGeomObject(Wall_mesh_pt);
311 
312 //Build the mesh
313  Fluid_mesh_pt =new RefineableAlgebraicChannelWithLeafletMesh<ELEMENT>(
314  wall_geom_object_pt,
315  lleft, lright,
316  hleaflet,
317  htot,nleft,
318  nright,ny1,ny2,
319  fluid_time_stepper_pt);
320 
321  // Set error estimator
322  Z2ErrorEstimator* error_estimator_pt=new Z2ErrorEstimator;
323  Fluid_mesh_pt->spatial_error_estimator_pt()=error_estimator_pt;
324 
325 
326 
327  // Build global mesh
328  //------------------
329 
330  // Add the sub meshes to the problem
331  add_sub_mesh(Fluid_mesh_pt);
332  add_sub_mesh(Wall_mesh_pt);
333 
334  // Combine all submeshes into a single Mesh
335  build_global_mesh();
336 
337 
338 
339  // Fluid boundary conditions
340  //--------------------------
341 
342  //Pin the boundary nodes of the fluid mesh
343  unsigned num_bound = Fluid_mesh_pt->nboundary();
344  for(unsigned ibound=0;ibound<num_bound;ibound++)
345  {
346  unsigned num_nod= Fluid_mesh_pt->nboundary_node(ibound);
347  for (unsigned inod=0;inod<num_nod;inod++)
348  {
349  Fluid_mesh_pt->boundary_node_pt(ibound,inod)->pin(1);
350 
351  // Do not pin the x velocity of the outflow
352  if( ibound != 1)
353  {
354  Fluid_mesh_pt->boundary_node_pt(ibound,inod)->pin(0);
355  }
356  }
357  }
358  // end loop over boundaries
359 
360 
361  // Setup parabolic flow along boundary 3 (everything else that's
362  // pinned has homogenous boundary conditions so no action is required
363  // as that's the default assignment). Inflow profile is parabolic
364  // and this is interpolated correctly during mesh refinement so
365  // no re-assignment necessary after adaptation.
366  unsigned ibound=3;
367  unsigned num_nod= Fluid_mesh_pt->nboundary_node(ibound);
368  for (unsigned inod=0;inod<num_nod;inod++)
369  {
370  double ycoord = Fluid_mesh_pt->boundary_node_pt(ibound,inod)->x(1);
371  double uy = 6.0*ycoord/htot*(1.0-ycoord/htot);
372  Fluid_mesh_pt->boundary_node_pt(ibound,inod)->set_value(0,uy);
373  Fluid_mesh_pt->boundary_node_pt(ibound,inod)->set_value(1,0.0);
374  }// end of setup boundary condition
375 
376 
377 
378  // Boundary conditions for wall mesh
379  //----------------------------------
380 
381  // Set the boundary conditions: the lower end of the beam is fixed in space
382  unsigned b=0;
383 
384  // Pin displacements in both x and y directions
385  wall_mesh_pt()->boundary_node_pt(b,0)->pin_position(0);
386  wall_mesh_pt()->boundary_node_pt(b,0)->pin_position(1);
387 
388  // Infinite slope: Pin type 1 (slope) dof for displacement direction 0
389  wall_mesh_pt()->boundary_node_pt(b,0)->pin_position(1,0);
390 
391 
392 
393  // Complete build of fluid elements
394  //---------------------------------
395  unsigned n_element = Fluid_mesh_pt->nelement();
396 
397  // Loop over the elements to set up element-specific
398  // things that cannot be handled by constructor
399  for(unsigned e=0;e<n_element;e++)
400  {
401  // Upcast from GeneralisedElement to the present element
402  ELEMENT* el_pt = dynamic_cast<ELEMENT*>(Fluid_mesh_pt->element_pt(e));
403 
404  //Set the Reynolds number
405  el_pt->re_pt() = &Global_Physical_Variables::Re;
406 
407  //Set the Womersley number
408  el_pt->re_st_pt() = &Global_Physical_Variables::ReSt;
409 
410  }// end loop over elements
411 
412 
413  // Pin redudant pressure dofs
414  RefineableNavierStokesEquations<2>::
415  pin_redundant_nodal_pressures(Fluid_mesh_pt->element_pt());
416 
417 
418  // Complete build of wall elements
419  //--------------------------------
420  n_element = wall_mesh_pt()->nelement();
421  for(unsigned e=0;e<n_element;e++)
422  {
423  // Upcast to the specific element type
424  FSIHermiteBeamElement *elem_pt =
425  dynamic_cast<FSIHermiteBeamElement*>(wall_mesh_pt()->element_pt(e));
426 
427  // Set physical parameters for each element:
428  elem_pt->h_pt() = &Global_Physical_Variables::H;
429 
430  // Function that specifies the load ratios
431  elem_pt->q_pt() = &Global_Physical_Variables::Q;
432 
433  // Set the undeformed shape for each element
434  elem_pt->undeformed_beam_pt() = undeformed_wall_pt;
435 
436  // Leaflet is immersed and loaded by fluid on both sides
437  elem_pt->enable_fluid_loading_on_both_sides();
438 
439  // The normal to the leaflet, as computed by the
440  // FSIHermiteElements points away from the fluid rather than
441  // into the fluid (as assumed by default) when viewed from
442  // the "front" (face 0).
443  elem_pt->set_normal_pointing_out_of_fluid();
444 
445  } // end of loop over elements
446 
447 
448  // Setup FSI
449  //----------
450 
451  // The velocity of the fluid nodes on the wall (fluid mesh boundary 4,5)
452  // is set by the wall motion -- hence the no-slip condition must be
453  // re-applied whenever a node update is performed for these nodes.
454  // Such tasks may be performed automatically by the auxiliary node update
455  // function specified by a function pointer:
456  for(unsigned ibound=4;ibound<6;ibound++ )
457  {
458  unsigned num_nod= Fluid_mesh_pt->nboundary_node(ibound);
459  for (unsigned inod=0;inod<num_nod;inod++)
460  {
461  Fluid_mesh_pt->boundary_node_pt(ibound, inod)->
462  set_auxiliary_node_update_fct_pt(
463  FSI_functions::apply_no_slip_on_moving_wall);
464  }
465  }// aux node update fct has been set
466 
467  // Work out which fluid dofs affect the residuals of the wall elements:
468  // We pass the boundary between the fluid and solid meshes and
469  // pointers to the meshes. The interaction boundary is boundary 4 and 5
470  // of the 2D fluid mesh.
471 
472  // Front of leaflet: Set face=0 (which is also the default so this argument
473  // could be omitted)
474  unsigned face=0;
475  FSI_functions::setup_fluid_load_info_for_solid_elements<ELEMENT,2>
476  (this,4,Fluid_mesh_pt,Wall_mesh_pt,face);
477 
478  // Back of leaflet: face 1, needs to be specified explicitly
479  face=1;
480  FSI_functions::setup_fluid_load_info_for_solid_elements<ELEMENT,2>
481  (this,5,Fluid_mesh_pt,Wall_mesh_pt,face);
482 
483  // Setup equation numbering scheme
484  cout <<"Number of equations: " << assign_eqn_numbers() << std::endl;
485 
486 
487 
488  // Choose iterative solvers with FSI preconditioner (only if not test)
489  //====================================================================
490  if (CommandLineArgs::Argc==1)
491  {
492 
493  // Build iterative linear solver
494  //------------------------------
495  GMRES<CRDoubleMatrix>* iterative_linear_solver_pt =
496  new GMRES<CRDoubleMatrix>;
497 
498  // Set maximum number of iterations
499  iterative_linear_solver_pt->max_iter() = 200;
500 
501  // Pass solver to problem:
502  linear_solver_pt()=iterative_linear_solver_pt;
503 
504 
505  // Build preconditioner
506  //---------------------
507  FSIPreconditioner* prec_pt=new FSIPreconditioner(this);
508 
509  // Set Navier Stokes mesh:
510  prec_pt->set_navier_stokes_mesh(Fluid_mesh_pt);
511 
512  // Set solid mesh:
513  prec_pt->set_wall_mesh(Wall_mesh_pt);
514 
515  // By default, the Schur complement preconditioner uses SuperLU as
516  // an exact preconditioner (i.e. a solver) for the
517  // momentum and Schur complement blocks.
518  // Can overwrite this by passing pointers to
519  // other preconditioners that perform the (approximate)
520  // solves of these blocks
521 
522 
523 #ifdef OOMPH_HAS_HYPRE
524 
525  // Create internal preconditioner used on Schur block
526  //---------------------------------------------------
527  HyprePreconditioner* p_preconditioner_pt = new HyprePreconditioner;
528 
529  // Shut up!
530  p_preconditioner_pt->disable_doc_time();
531 
532  // Set defaults parameters for use as preconditioner on Poisson-type problem
533  Hypre_default_settings::
534  set_defaults_for_2D_poisson_problem(p_preconditioner_pt);
535 
536  // Pass to preconditioner
537  //prec_pt->set_p_preconditioner(p_preconditioner_pt);
538 
539 
540  // Create internal preconditioner used on momentum block
541  //------------------------------------------------------
542  HyprePreconditioner* f_preconditioner_pt = new HyprePreconditioner;
543 
544  // Shut up!
545  f_preconditioner_pt->disable_doc_time();
546 
547  // Set default parameters for use as preconditioner in for momentum
548  // block in Navier-Stokes problem
549  Hypre_default_settings::
550  set_defaults_for_navier_stokes_momentum_block(f_preconditioner_pt);
551 
552  // Use Hypre for momentum block
553  //prec_pt->set_f_preconditioner(f_preconditioner_pt);
554 
555 #endif
556 
557  // Retain fluid onto solid terms in FSI preconditioner
558  prec_pt->use_block_triangular_version_with_fluid_on_solid();
559 
560  // Pass preconditioner to iterative linear solver
561  iterative_linear_solver_pt->preconditioner_pt()= prec_pt;
562 
563  }
564 
565 
566 }//end of constructor
567 
568 
569 
570 
571 
572 //==== start_of_actions_after_adapt=================================
573 /// Actions_after_adapt()
574 //==================================================================
575 template<class ELEMENT>
577 {
578  // Unpin all pressure dofs
579  RefineableNavierStokesEquations<2>::
580  unpin_all_pressure_dofs(Fluid_mesh_pt->element_pt());
581 
582  // Pin redundant pressure dofs
583  RefineableNavierStokesEquations<2>::
584  pin_redundant_nodal_pressures(Fluid_mesh_pt->element_pt());
585 
586 
587  // (Re-)apply the no slip condition on the moving wall
588  //-----------------------------------------------------
589 
590  // The velocity of the fluid nodes on the wall (fluid mesh boundary 4,5)
591  // is set by the wall motion -- hence the no-slip condition must be
592  // re-applied whenever a node update is performed for these nodes.
593  // Such tasks may be performed automatically by the auxiliary node update
594  // function specified by a function pointer:
595  for(unsigned ibound=4;ibound<6;ibound++ )
596  {
597  unsigned num_nod= Fluid_mesh_pt->nboundary_node(ibound);
598  for (unsigned inod=0;inod<num_nod;inod++)
599  {
600  Fluid_mesh_pt->boundary_node_pt(ibound, inod)->
601  set_auxiliary_node_update_fct_pt(
602  FSI_functions::apply_no_slip_on_moving_wall);
603  }
604  } // aux node update fct has been (re-)set
605 
606 
607 
608  // Re-setup FSI
609  //-------------
610 
611  // Work out which fluid dofs affect the residuals of the wall elements:
612  // We pass the boundary between the fluid and solid meshes and
613  // pointers to the meshes. The interaction boundary is boundary 4 and 5
614  // of the 2D fluid mesh.
615 
616  // Front of leaflet: Set face=0 (which is also the default so this argument
617  // could be omitted)
618  unsigned face=0;
619  FSI_functions::setup_fluid_load_info_for_solid_elements<ELEMENT,2>
620  (this,4,Fluid_mesh_pt,Wall_mesh_pt,face);
621 
622  // Back of leaflet: face 1, needs to be specified explicitly
623  face=1;
624  FSI_functions::setup_fluid_load_info_for_solid_elements<ELEMENT,2>
625  (this,5,Fluid_mesh_pt,Wall_mesh_pt,face);
626 
627 } // end_of_actions_after_adapt
628 
629 
630 
631 
632 
633 //==start_of_doc_solution=================================================
634 /// Doc the solution
635 //========================================================================
636 template<class ELEMENT>
638  ofstream& trace)
639 {
640  ofstream some_file;
641  char filename[100];
642 
643  // Number of plot points
644  unsigned npts;
645  npts=5;
646 
647  // Output fluid solution
648  sprintf(filename,"%s/soln%i.dat",doc_info.directory().c_str(),
649  doc_info.number());
650  some_file.open(filename);
651  Fluid_mesh_pt->output(some_file,npts);
652  some_file.close();
653 
654  // Output wall solution
655  sprintf(filename,"%s/wall_soln%i.dat",doc_info.directory().c_str(),
656  doc_info.number());
657  some_file.open(filename);
658  Wall_mesh_pt->output(some_file,npts);
659  some_file.close();
660 
661  // Get node at tip of leaflet
662  unsigned n_el_wall=Wall_mesh_pt->nelement();
663  Node* tip_node_pt=Wall_mesh_pt->finite_element_pt(n_el_wall-1)->node_pt(1);
664 
665  // Get time:
666  double time=time_pt()->time();
667 
668  // Write trace file
669  trace << time << " "
670  << Global_Physical_Variables::flux(time) << " "
671  << tip_node_pt->x(0) << " "
672  << tip_node_pt->x(1) << " "
673  << tip_node_pt->dposition_dt(0) << " "
674  << tip_node_pt->dposition_dt(1) << " "
675  << doc_info.number() << " "
676  << std::endl;
677 
678 
679  // Help me figure out what the "front" and "back" faces of the leaflet are
680  //------------------------------------------------------------------------
681 
682  // Output fluid elements on fluid mesh boundary 4 (associated with
683  // the "front")
684  unsigned bound=4;
685  sprintf(filename,"%s/fluid_boundary_elements_front_%i.dat",
686  doc_info.directory().c_str(),
687  doc_info.number());
688  some_file.open(filename);
689  unsigned nel= Fluid_mesh_pt->nboundary_element(bound);
690  for (unsigned e=0;e<nel;e++)
691  {
692  dynamic_cast<ELEMENT*>(Fluid_mesh_pt->boundary_element_pt(bound,e))
693  ->output(some_file,npts);
694  }
695  some_file.close();
696 
697 
698  // Output fluid elements on fluid mesh boundary 5 (associated with
699  // the "back")
700  bound=5;
701  sprintf(filename,"%s/fluid_boundary_elements_back_%i.dat",
702  doc_info.directory().c_str(),
703  doc_info.number());
704  some_file.open(filename);
705  nel= Fluid_mesh_pt->nboundary_element(bound);
706  for (unsigned e=0;e<nel;e++)
707  {
708  dynamic_cast<ELEMENT*>(Fluid_mesh_pt->boundary_element_pt(bound,e))
709  ->output(some_file,npts);
710  }
711  some_file.close();
712 
713 
714  // Output normal vector on wall elements
715  sprintf(filename,"%s/wall_normal_%i.dat",
716  doc_info.directory().c_str(),
717  doc_info.number());
718  some_file.open(filename);
719  nel=Wall_mesh_pt->nelement();
720  Vector<double> s(1);
721  Vector<double> x(2);
722  Vector<double> xi(1);
723  Vector<double> N(2);
724  for (unsigned e=0;e<nel;e++)
725  {
726  // Get pointer to element
727  FSIHermiteBeamElement* el_pt=
728  dynamic_cast<FSIHermiteBeamElement*>(Wall_mesh_pt->element_pt(e));
729 
730  // Loop over plot points
731  for (unsigned i=0;i<npts;i++)
732  {
733  s[0]=-1.0+2.0*double(i)/double(npts-1);
734 
735  // Get Eulerian position
736  el_pt->interpolated_x(s,x);
737 
738  // Get unit normal
739  el_pt->get_normal(s,N);
740 
741  // Get Lagrangian coordinate
742  el_pt->interpolated_xi(s,xi);
743 
744  some_file << x[0] << " " << x[1] << " "
745  << N[0] << " " << N[1] << " "
746  << xi[0] << std::endl;
747  }
748  }
749  some_file.close();
750 
751 } // end_of_doc_solution
752 
753 
754 
755 
756 //======= start_of_main================================================
757 /// Driver code -- pass a command line argument if you want to run
758 /// the code in validation mode where it only performs a few steps
759 //=====================================================================
760 int main(int argc, char* argv[])
761 {
762  // Store command line arguments
763  CommandLineArgs::setup(argc,argv);
764 
765  //Parameters for the leaflet: x-position of root and height
766  double x_0 = 1.0;
767  double hleaflet=0.5;
768 
769  // Number of elements in various regions of mesh
770  unsigned nleft=6;
771  unsigned nright=18;
772  unsigned ny1=3;
773  unsigned ny2=3;
774 
775  // Dimensions of fluid mesh: length to the left and right of leaflet
776  // and total height
777  double lleft =1.0;
778  double lright=3.0;
779  double htot=1.0;
780 
781  //Build the problem
783  AlgebraicElement<RefineableQTaylorHoodElement<2> > >
784  problem(lleft,lright,hleaflet,
785  htot,nleft,nright,ny1,ny2,x_0);
786 
787  // Set up doc info
788  DocInfo doc_info;
789  doc_info.set_directory("RESLT");
790 
791  // Trace file
792  ofstream trace;
793  char filename[100];
794  sprintf(filename,"%s/trace.dat",doc_info.directory().c_str());
795  trace.open(filename);
796 
797 
798  // Number of timesteps (reduced for validation)
799  unsigned nstep=200;
800  if (CommandLineArgs::Argc>1)
801  {
802  nstep=2;
803  }
804 
805  //Timestep:
806  double dt=0.05;
807 
808  // Initialise timestep
809  problem.initialise_dt(dt);
810 
811  // Doc initial guess for steady solve
812  problem.doc_solution(doc_info,trace);
813  doc_info.number()++;
814 
815 
816  // Initial loop to increment the Reynolds number in sequence of steady solves
817  //---------------------------------------------------------------------------
818  unsigned n_increment=4;
819  // Just to one step for validation run
820  if (CommandLineArgs::Argc>1)
821  {
822  n_increment=1;
823  }
824 
825  // Set max. number of adaptations
826  unsigned max_adapt=3;
827 
829  for (unsigned i=0;i<n_increment;i++)
830  {
831  // Increase Re and ReSt (for St=1)
834 
835  // Solve the steady problem
836  std::cout << "Computing a steady solution for Re="
837  << Global_Physical_Variables::Re << std::endl;
838  problem.steady_newton_solve(max_adapt);
839  problem.doc_solution(doc_info,trace);
840  doc_info.number()++;
841  } // reached final Reynolds number
842 
843 
844 
845  // Proper time-dependent run
846  //--------------------------
847 
848  // Limit the number of adaptations during unsteady run to one per timestep
849  max_adapt=1;
850 
851  // Don't re-set the initial conditions when adapting the mesh
852  bool first = false;
853 
854  // Timestepping loop
855  for (unsigned istep=0;istep<nstep;istep++)
856  {
857  // Solve the problem
858  problem.unsteady_newton_solve(dt,max_adapt,first);
859 
860  // Output the solution
861  problem.doc_solution(doc_info,trace);
862 
863  // Step number
864  doc_info.number()++;
865 
866  }
867 
868 }//end of main
869 
870 
void position(const Vector< double > &zeta, Vector< double > &r) const
Position vector at Lagrangian coordinate zeta.
void actions_after_adapt()
Actions after adaptation.
double Period
Period for fluctuations in flux.
unsigned ngeom_data() const
Number of geometric Data in GeomObject: None.
FSIChannelWithLeafletProblem(const double &lleft, const double &lright, const double &hleaflet, const double &htot, const unsigned &nleft, const unsigned &nright, const unsigned &ny1, const unsigned &ny2, const double &x_0)
Constructor: Pass the lenght of the domain at the left of the leaflet lleft,the lenght of the domain ...
int main(int argc, char *argv[])
void actions_before_implicit_timestep()
Update the inflow velocity.
OneDLagrangianMesh< FSIHermiteBeamElement > * wall_mesh_pt()
Access function to the wall mesh.
void position(const unsigned &t, const Vector< double > &zeta, Vector< double > &r) const
Parametrised position on object: r(zeta). Evaluated at previous timestep. t=0: current time; t>0: pre...
double Q
Fluid structure interaction parameter: Ratio of stresses used for non-dimensionalisation of fluid to ...
~FSIChannelWithLeafletProblem()
Destructor empty.
double ReSt
Womersley number: Product of Reynolds and Strouhal numbers.
void actions_before_newton_solve()
Actions before solve (empty)
void doc_solution(DocInfo &doc_info, ofstream &trace)
Doc the solution.
UndeformedLeaflet(const double &x0)
Constructor: argument is the x-coordinate of the leaflet.
double Htot
Total height of the domain.
void actions_before_newton_convergence_check()
Update before checking Newton convergence: Update the nodal positions in the fluid mesh in response t...
double X0
x position of the undeformed leaflet&#39;s origin.
GeomObject: Undeformed straight, vertical leaflet.
double flux(const double &t)
Flux: Pulsatile flow fluctuating between Min_flux and Max_flux with period Period.
void actions_after_newton_solve()
Actions after solve (empty)
double H
Non-dimensional wall thickness.
void d2position(const Vector< double > &zeta, Vector< double > &r, DenseMatrix< double > &drdzeta, RankThreeTensor< double > &ddrdzeta) const
Posn vector and its 1st & 2nd derivatives w.r.t. to coordinates: = drdzeta(alpha,i). = ddrdzeta(alpha,beta,i). Evaluated at current time.
RefineableAlgebraicChannelWithLeafletMesh< ELEMENT > * Fluid_mesh_pt
Pointer to the fluid mesh.
OneDLagrangianMesh< FSIHermiteBeamElement > * Wall_mesh_pt
Pointer to the "wall" mesh.
RefineableAlgebraicChannelWithLeafletMesh< ELEMENT > * fluid_mesh_pt()
Access function to fluid mesh.
GeomObject * Leaflet_pt
Pointer to the GeomObject that represents the wall.