fsi_chan_problem.h
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 
31 
32 
33 //====start_of_physical_parameters=====================
34 /// Namespace for phyical parameters
35 //======================================================
37 {
38 
39  /// Reynolds number
40  double Re=250.0;
41 
42  /// Womersley = Reynolds times Strouhal
43  double ReSt=250.0;
44 
45  /// Non-dimensional wall thickness. As in Heil (2004) paper.
46  double H=1.0e-2;
47 
48  /// 2nd Piola Kirchhoff pre-stress. As in Heil (2004) paper.
49  double Sigma0=1.0e3;
50 
51  /// Pointer to Data object that stores external pressure
52  Data* P_ext_data_pt=0;
53 
54  /// \short Min. pressure. Only used in steady runs during parameter
55  /// incrementation. Use 1.5 for values of Re to
56  /// span the range in Heil (2004) paper.
57  double Pmin=1.5;
58 
59  /// \short Max. pressure. Only used in steady runs during parameter
60  /// incrementation. Use 2.0 for Re=250; 3.7 for Re=0 to
61  /// span the range in Heil (2004) paper.
62  double Pmax=2.0;
63 
64  /// \short Jump in pressure after a restart -- used to give a steady
65  /// solution a kick before starting a time-dependent run
66  double P_step=0.0;
67 
68  /// \short Current prescribed vertical position of control point
69  /// (only used for displacement control)
70  double Yprescr = 1.0;
71 
72  /// Min. of prescribed vertical position of conrol point
73  /// (only used during parameter study with displacement control).
74  /// 0.6 corresponds to the value in Heil (2004) paper for static runs.
75  double Yprescr_min=0.6;
76 
77  /// \short Load function: Apply a constant external pressure to the wall.
78  /// Note: This is the load without the fluid contribution!
79  /// Fluid load gets added on by FSIWallElement.
80  void load(const Vector<double>& xi, const Vector<double>& x,
81  const Vector<double>& N, Vector<double>& load)
82  {
83  for(unsigned i=0;i<2;i++)
84  {
85  load[i] = -P_ext_data_pt->value(0)*N[i];
86  }
87  } //end of load
88 
89 
90  /// \short Fluid structure interaction parameter: Ratio of stresses used for
91  /// non-dimensionalisation of fluid to solid stresses. As in Heil (2004)
92  /// paper
93  double Q=1.0e-2;
94 
95 
96 } // end of namespace
97 
98 
99 
100 ////////////////////////////////////////////////////////////////////////
101 ////////////////////////////////////////////////////////////////////////
102 ////////////////////////////////////////////////////////////////////////
103 
104 
105 
106 
107 //==========start_of_BL_Squash =========================================
108 /// Namespace to define the mapping [0,1] -> [0,1] that re-distributes
109 /// nodal points across the channel width.
110 //======================================================================
111 namespace BL_Squash
112 {
113 
114  /// Boundary layer width
115  double Delta=0.1;
116 
117  /// Fraction of points in boundary layer
118  double Fract_in_BL=0.5;
119 
120  /// \short Mapping [0,1] -> [0,1] that re-distributes
121  /// nodal points across the channel width
122  double squash_fct(const double& s)
123  {
124  // Default return
125  double y=s;
126  if (s<0.5*Fract_in_BL)
127  {
128  y=Delta*2.0*s/Fract_in_BL;
129  }
130  else if (s>1.0-0.5*Fract_in_BL)
131  {
132  y=2.0*Delta/Fract_in_BL*s+1.0-2.0*Delta/Fract_in_BL;
133  }
134  else
135  {
136  y=(1.0-2.0*Delta)/(1.0-Fract_in_BL)*s+
137  (Delta-0.5*Fract_in_BL)/(1.0-Fract_in_BL);
138  }
139 
140  return y;
141  }
142 }// end of BL_Squash
143 
144 
145 
146 
147 
148 
149 //////////////////////////////////////////////////////////////////////////
150 //////////////////////////////////////////////////////////////////////////
151 //////////////////////////////////////////////////////////////////////////
152 
153 
154 //====start_of_underformed_wall============================================
155 /// Undeformed wall is a steady, straight 1D line in 2D space
156 /// \f[ x = X_0 + \zeta \f]
157 /// \f[ y = H \f]
158 //=========================================================================
159 class UndeformedWall : public GeomObject
160 {
161 
162 public:
163 
164  /// \short Constructor: arguments are the starting point and the height
165  /// above y=0.
166  UndeformedWall(const double& x0, const double& h): GeomObject(1,2)
167  {
168  X0=x0;
169  H=h;
170  }
171 
172 
173  /// \short Position vector at Lagrangian coordinate zeta
174  void position(const Vector<double>& zeta, Vector<double>& r) const
175  {
176  // Position Vector
177  r[0] = zeta[0]+X0;
178  r[1] = H;
179  }
180 
181 
182  /// \short Parametrised position on object: r(zeta). Evaluated at
183  /// previous timestep. t=0: current time; t>0: previous
184  /// timestep. Calls steady version.
185  void position(const unsigned& t, const Vector<double>& zeta,
186  Vector<double>& r) const
187  {
188  // Use the steady version
189  position(zeta,r);
190 
191  } // end of position
192 
193 
194  /// \short Posn vector and its 1st & 2nd derivatives
195  /// w.r.t. to coordinates:
196  /// \f$ \frac{dR_i}{d \zeta_\alpha}\f$ = drdzeta(alpha,i).
197  /// \f$ \frac{d^2R_i}{d \zeta_\alpha d \zeta_\beta}\f$ =
198  /// ddrdzeta(alpha,beta,i). Evaluated at current time.
199  virtual void d2position(const Vector<double>& zeta,
200  Vector<double>& r,
201  DenseMatrix<double> &drdzeta,
202  RankThreeTensor<double> &ddrdzeta) const
203  {
204  // Position vector
205  r[0] = zeta[0]+X0;
206  r[1] = H;
207 
208  // Tangent vector
209  drdzeta(0,0)=1.0;
210  drdzeta(0,1)=0.0;
211 
212  // Derivative of tangent vector
213  ddrdzeta(0,0,0)=0.0;
214  ddrdzeta(0,0,1)=0.0;
215 
216  } // end of d2position
217 
218 private :
219 
220  /// x position of the undeformed beam's left end.
221  double X0;
222 
223  /// Height of the undeformed wall above y=0.
224  double H;
225 
226 }; //end_of_undeformed_wall
227 
228 
229 
230 
231 
232 
233 //====Namespace_for_flags================================
234 /// Namespace for flags
235 //======================================================
236 namespace Flags
237 {
238 
239  /// Resolution factor (multiplier for number of elements across channel)
240  unsigned Resolution_factor=1;
241 
242  /// Use displacement control (1) or not (0)
243  unsigned Use_displ_control=1;
244 
245  /// Steady run (1) or unsteady run (0)
246  unsigned Steady_flag=1;
247 
248  /// \short Number of steps in parameter study
249  unsigned Nsteps=5;
250 
251  /// String to identify the run type in trace file
253 
254  /// Name of restart file
255  string Restart_file_name="";
256 
257  /// Doc flags
258  void doc_flags()
259  {
260 
261  std::cout << "\nFlags:\n"
262  << "======\n";
263 
264  std::cout << "-- Resolution factor: " << Resolution_factor << std::endl;
265 
266  if (Steady_flag)
267  {
268  std::cout << "-- Steady run " << std::endl;
269  if (Use_displ_control)
270  {
271  std::cout << "-- Using displacement control " << std::endl;
272  }
273  else
274  {
275  std::cout << "-- Not using displacement control " << std::endl;
276  }
277  }
278  else
279  {
280  std::cout << "-- Unsteady run " << std::endl;
281  if (Use_displ_control)
282  {
283  std::cout << "-- Not using displacement control (command line flag\n"
284  << " overwritten because it's an unsteady run!) "
285  << std::endl;
286  }
287  }
288 
289  std::cout << "-- Reynolds number: "
290  << Global_Physical_Variables::Re << std::endl;
291 
292  std::cout << "-- FSI parameter Q: "
293  << Global_Physical_Variables::Q << std::endl;
294 
295 
296  if (Restart_file_name!="")
297  {
298  std::cout << "-- Performing restart from: " << Restart_file_name
299  << std::endl;
300  std::cout << "-- Jump in pressure: " << Global_Physical_Variables::P_step
301  << std::endl;
302  }
303  else
304  {
305  std::cout << "-- No restart " << std::endl;
306  }
307  std::cout << std::endl;
308  }
309 
310 }
311 
312 
313 
314 //====start_of_problem_class==========================================
315 ///Problem class
316 //====================================================================
317 template <class ELEMENT>
318 class FSICollapsibleChannelProblem : public virtual Problem
319 {
320 
321 public :
322 
323 /// \short Constructor: The arguments are the number of elements and
324 /// the lengths of the domain.
325  FSICollapsibleChannelProblem(const unsigned& nup,
326  const unsigned& ncollapsible,
327  const unsigned& ndown,
328  const unsigned& ny,
329  const double& lup,
330  const double& lcollapsible,
331  const double& ldown,
332  const double& ly,
333  const bool& displ_control,
334  const bool& steady_flag);
335 
336  /// Destructor
338  {
339  // Mesh gets killed in general problem destructor
340  }
341 
342  /// Steady run; virtual so it can be overloaded in derived problem
343  /// classes
344  virtual void steady_run();
345 
346  /// \short Unsteady run; virtual so it can be overloaded in derived problem
347  /// classes. Specify timestep or use default of 0.1
348  virtual void unsteady_run(const double& dt=0.1);
349 
350  /// Access function for the specific bulk (fluid) mesh
351  AlgebraicCollapsibleChannelMesh<ELEMENT>* bulk_mesh_pt()
352  {
353  // Upcast from pointer to the Mesh base class to the specific
354  // element type that we're using here.
355  return dynamic_cast<
356  AlgebraicCollapsibleChannelMesh<ELEMENT>*>
357  (Bulk_mesh_pt);
358  }
359 
360  /// Access function for the wall mesh
361  OneDLagrangianMesh<FSIHermiteBeamElement>* wall_mesh_pt()
362  {
363  return Wall_mesh_pt;
364 
365  } // end of access to wall mesh
366 
367 
368  /// Actions before solve. Reset counter for number of Newton iterations
370  {
371  Newton_iter=0;
372  }
373 
374  /// Update the problem after solve (empty)
376 
377 
378  /// \short Update before checking Newton convergence: Update the
379  /// nodal positions in the fluid mesh in response to possible
380  /// changes in the wall shape.
382  {
383  // Update mesh
384  Bulk_mesh_pt->node_update();
385 
386  // Increment counter
387  Newton_iter++;
388  }
389 
390 
391  /// Doc the steady solution
392  virtual void doc_solution_steady(DocInfo& doc_info, ofstream& trace_file,
393  const double& cpu, const unsigned &niter);
394 
395  /// Doc the unsteady solution
396  virtual void doc_solution_unsteady(DocInfo& doc_info, ofstream& trace_file,
397  const double& cpu, const unsigned &niter);
398 
399  /// Apply initial conditions
400  void set_initial_condition();
401 
402 
403  protected:
404 
405  /// \short Dump problem to disk to allow for restart.
406  void dump_it(ofstream& dump_file);
407 
408  /// \short Read problem for restart from specified restart file.
409  void restart(ifstream& restart_file);
410 
411  ///Number of elements in the x direction in the upstream part of the channel
412  unsigned Nup;
413 
414  /// \short Number of elements in the x direction in the collapsible part of
415  /// the channel
416  unsigned Ncollapsible;
417 
418  ///Number of elements in the x direction in the downstream part of the channel
419  unsigned Ndown;
420 
421  ///Number of elements across the channel
422  unsigned Ny;
423 
424  ///x-length in the upstream part of the channel
425  double Lup;
426 
427  ///x-length in the collapsible part of the channel
428  double Lcollapsible;
429 
430  ///x-length in the downstream part of the channel
431  double Ldown;
432 
433  ///Transverse length
434  double Ly;
435 
436  /// Pointer to the "bulk" mesh
437  AlgebraicCollapsibleChannelMesh<ELEMENT>* Bulk_mesh_pt;
438 
439  /// \short Pointer to the mesh that contains the displacement control element
441 
442  /// Use displacement control?
444 
445  /// Pointer to the "wall" mesh
446  OneDLagrangianMesh<FSIHermiteBeamElement>* Wall_mesh_pt;
447 
448  ///Pointer to the left control node
450 
451  ///Pointer to right control node
453 
454  /// Pointer to control node on the wall
456 
457  /// Flag for steady run
459 
460  /// Pointer to GeomObject at which displacement control is applied
461  /// (or at which wall displacement is monitored in unsteady runs)
462  GeomObject* Ctrl_geom_obj_pt;
463 
464  /// \short Vector of local coordinates of displacement control point
465  /// in Ctrl_geom_obj_pt
466  Vector<double> S_displ_ctrl;
467 
468  ///\short Pointer to geometric object (one Lagrangian, two Eulerian
469  /// coordinates) that will be built from the wall mesh
470  MeshAsGeomObject* Wall_geom_object_pt;
471 
472  /// Counter for Newton iterations
473  unsigned Newton_iter;
474 
475  /// DocInfo object
476  DocInfo Doc_info;
477 
478 };//end of problem class
479 
480 
481 
482 
483 //=====start_of_constructor======================================
484 /// Constructor for the collapsible channel problem
485 //===============================================================
486 template <class ELEMENT>
488  const unsigned& nup,
489  const unsigned& ncollapsible,
490  const unsigned& ndown,
491  const unsigned& ny,
492  const double& lup,
493  const double& lcollapsible,
494  const double& ldown,
495  const double& ly,
496  const bool& displ_control,
497  const bool& steady_flag)
498 {
499 
500 
501  // Initialise number of Newton iterations
502  Newton_iter=0;
503 
504  // Store problem parameters
505  Nup=nup;
506  Ncollapsible=ncollapsible;
507  Ndown=ndown;
508  Ny=ny;
509  Lup=lup;
510  Lcollapsible=lcollapsible;
511  Ldown=ldown;
512  Ly=ly;
513  Steady_flag=steady_flag;
514 
515  // Displacement control only makes sense for steady problems
516  if (Steady_flag)
517  {
518  Displ_control=displ_control;
519  }
520  else
521  {
522  Displ_control=false;
523  if (displ_control)
524  {
525  std::cout << "Switched off displacement control for unsteady run!"
526  << std::endl;
527  }
528  }
529 
530 
531  // Overwrite maximum allowed residual to accomodate bad initial guesses
532  Problem::Max_residuals=1000.0;
533 
534  // Allocate the timestepper -- this constructs the Problem's
535  // time object with a sufficient amount of storage to store the
536  // previous timsteps. Note: This is appropriate even for
537  // the steady problem as we'll explicitly call the *steady*
538  // Newton solver which disables the timesteppers
539  // during the solve.
540  add_time_stepper_pt(new BDF<2>);
541 
542  // Create a dummy Steady timestepper that stores two history values
543  Steady<2>* wall_time_stepper_pt = new Steady<2>;
544 
545  // Add the wall timestepper to the Problem's collection of timesteppers.
546  add_time_stepper_pt(wall_time_stepper_pt);
547 
548  // Geometric object that represents the undeformed wall:
549  // A straight line at height y=ly; starting at x=lup.
550  UndeformedWall* undeformed_wall_pt=new UndeformedWall(lup,ly);
551 
552  //Create the "wall" mesh with FSI Hermite elements
553  Wall_mesh_pt = new OneDLagrangianMesh<FSIHermiteBeamElement>
554  (Ncollapsible,Lcollapsible,undeformed_wall_pt,wall_time_stepper_pt);
555 
556  // Build a geometric object (one Lagrangian, two Eulerian coordinates)
557  // from the wall mesh
558  Wall_geom_object_pt=
559  new MeshAsGeomObject(Wall_mesh_pt);
560 
561  // Get pointer to/local coordinate in wall geom object that contains
562  // control node -- adjusted for different values of Q, so that
563  // the point is located near the point of strongest collapse.
564  Vector<double> zeta_displ_ctrl(1);
565  zeta_displ_ctrl[0]=3.5;
566  if (std::abs(Global_Physical_Variables::Q-1.0e-3)<1.0e-10)
567  {
568  zeta_displ_ctrl[0]=3.0;
569  }
570  //if (std::abs(Global_Physical_Variables::Q-1.0e-4)<1.0e-10)
571  if (Global_Physical_Variables::Q<=1.0e-4)
572  {
573  zeta_displ_ctrl[0]=2.5;
574  }
575  std::cout << "Wall control point located at zeta=" <<zeta_displ_ctrl[0]
576  << std::endl;
577  S_displ_ctrl.resize(1);
578 
579  // Locate control point (pointer to GeomObject and local coordinate in it)
580  Wall_geom_object_pt->locate_zeta(zeta_displ_ctrl,
581  Ctrl_geom_obj_pt,
582  S_displ_ctrl);
583 
584 
585  // Normal load incrementation or unsteady run
586  //===========================================
587  Displ_control_mesh_pt=new Mesh;
588 
589  // Choose element in which displacement control is applied:
590  SolidFiniteElement* controlled_element_pt=
591  dynamic_cast<SolidFiniteElement*>(Ctrl_geom_obj_pt);
592 
593  // Fix the displacement in the vertical (1) direction...
594  unsigned controlled_direction=1;
595 
596  // Pointer to displacement control element
597  DisplacementControlElement* displ_control_el_pt;
598 
599  // Build displacement control element
600  displ_control_el_pt=
601  new DisplacementControlElement(controlled_element_pt,
602  S_displ_ctrl,
603  controlled_direction,
605 
606  // The constructor of the DisplacementControlElement has created
607  // a new Data object whose one-and-only value contains the
608  // adjustable load: Use this Data object in the load function:
609  Global_Physical_Variables::P_ext_data_pt=displ_control_el_pt->
610  displacement_control_load_pt();
611 
612  // Add the displacement-control element to its own mesh
613  Displ_control_mesh_pt->add_element_pt(displ_control_el_pt);
614 
615 
616  if (!Displ_control)
617  {
618  // Create Data object whose one-and-only value contains the
619  // (in principle) adjustable load
621 
622  //Pin the external pressure because it isn't actually adjustable.
624  }
625 
626  //Build bulk (fluid) mesh
627  Bulk_mesh_pt =
628  new AlgebraicCollapsibleChannelMesh<ELEMENT>
629  (nup, ncollapsible, ndown, ny,
630  lup, lcollapsible, ldown, ly,
631  Wall_geom_object_pt,
632  time_stepper_pt());
633 
634 
635  // Add the sub meshes to the problem
636  add_sub_mesh(Bulk_mesh_pt);
637  add_sub_mesh(Wall_mesh_pt);
638  add_sub_mesh(Displ_control_mesh_pt);
639 
640  // Combine all submeshes into a single Mesh
641  build_global_mesh();
642 
643 
644  // Complete build of fluid mesh
645  //-----------------------------
646 
647  // Loop over the elements to set up element-specific
648  // things that cannot be handled by constructor
649  unsigned n_element=Bulk_mesh_pt->nelement();
650  for(unsigned e=0;e<n_element;e++)
651  {
652  // Upcast from GeneralisedElement to the present element
653  ELEMENT* el_pt = dynamic_cast<ELEMENT*>(Bulk_mesh_pt->element_pt(e));
654 
655  //Set the Reynolds number
656  el_pt->re_pt() = &Global_Physical_Variables::Re;
657 
658  // Set the Womersley number
659  el_pt->re_st_pt() = &Global_Physical_Variables::ReSt;
660 
661  // Switch off mesh velocity in steady runs
662  if (Flags::Steady_flag)
663  {
664  el_pt->disable_ALE();
665  }
666  else
667  {
668  // Is element in rigid part?
669  bool is_in_rigid_part=true;
670 
671  // Number of nodes
672  unsigned nnod=el_pt->nnode();
673  for (unsigned j=0;j<nnod;j++)
674  {
675  double x=el_pt->node_pt(j)->x(0);
676  if ((x>=Lup)&&(x<=(Lup+Lcollapsible)))
677  {
678  is_in_rigid_part=false;
679  break;
680  }
681  }
682  if (is_in_rigid_part)
683  {
684  el_pt->disable_ALE();
685  }
686  }
687 
688  } // end loop over elements
689 
690 
691 
692  // Apply boundary conditions for fluid
693  //------------------------------------
694 
695  //Pin the velocity on the boundaries
696  //x and y-velocities pinned along boundary 0 (bottom boundary) :
697  unsigned ibound=0;
698  unsigned num_nod= bulk_mesh_pt()->nboundary_node(ibound);
699  for (unsigned inod=0;inod<num_nod;inod++)
700  {
701  for(unsigned i=0;i<2;i++)
702  {
703  bulk_mesh_pt()->boundary_node_pt(ibound, inod)->pin(i);
704  }
705  }
706 
707  //x and y-velocities pinned along boundaries 2, 3, 4 (top boundaries) :
708  for(ibound=2;ibound<5;ibound++)
709  {
710  num_nod= bulk_mesh_pt()->nboundary_node(ibound);
711  for (unsigned inod=0;inod<num_nod;inod++)
712  {
713  for(unsigned i=0;i<2;i++)
714  {
715  bulk_mesh_pt()->boundary_node_pt(ibound, inod)->pin(i);
716  }
717  }
718  }
719 
720  //y-velocity pinned along boundary 1 (right boundary):
721  ibound=1;
722  num_nod= bulk_mesh_pt()->nboundary_node(ibound);
723  for (unsigned inod=0;inod<num_nod;inod++)
724  {
725  bulk_mesh_pt()->boundary_node_pt(ibound, inod)->pin(1);
726  }
727 
728 
729  //Both velocities pinned along boundary 5 (left boundary):
730  ibound=5;
731  num_nod= bulk_mesh_pt()->nboundary_node(ibound);
732  for (unsigned inod=0;inod<num_nod;inod++)
733  {
734  bulk_mesh_pt()->boundary_node_pt(ibound, inod)->pin(0);
735  bulk_mesh_pt()->boundary_node_pt(ibound, inod)->pin(1);
736  }
737 //end of pin_velocity
738 
739 
740  // Complete build of wall elements
741  //--------------------------------
742 
743  //Loop over the elements to set physical parameters etc.
744  n_element = wall_mesh_pt()->nelement();
745  for(unsigned e=0;e<n_element;e++)
746  {
747  // Upcast to the specific element type
748  FSIHermiteBeamElement *elem_pt =
749  dynamic_cast<FSIHermiteBeamElement*>(wall_mesh_pt()->element_pt(e));
750 
751  // Set physical parameters for each element:
752  elem_pt->sigma0_pt() = &Global_Physical_Variables::Sigma0;
753  elem_pt->h_pt() = &Global_Physical_Variables::H;
754 
755  // Set the load vector for each element
756  elem_pt->load_vector_fct_pt() = &Global_Physical_Variables::load;
757 
758  // Function that specifies the load ratios
759  elem_pt->q_pt() = &Global_Physical_Variables::Q;
760 
761  // Set the undeformed shape for each element
762  elem_pt->undeformed_beam_pt() = undeformed_wall_pt;
763 
764  // The normal on the wall elements as computed by the FSIHermiteElements
765  // points away from the fluid rather than into the fluid (as assumed
766  // by default)
767  elem_pt->set_normal_pointing_out_of_fluid();
768 
769  // Displacement control? If so, the load on *all* elements
770  // is affected by an unknown -- the external pressure, stored
771  // as the one-and-only value in a Data object: Add it to the
772  // elements' external Data.
773  if (Displ_control)
774  {
775  //The external pressure is external data for all elements
776  elem_pt->add_external_data(Global_Physical_Variables::P_ext_data_pt);
777  }
778 
779 
780  } // end of loop over elements
781 
782 
783 
784  // Boundary conditions for wall mesh
785  //----------------------------------
786 
787  // Set the boundary conditions: Each end of the beam is fixed in space
788  // Loop over the boundaries (ends of the beam)
789  for(unsigned b=0;b<2;b++)
790  {
791  // Pin displacements in both x and y directions
792  wall_mesh_pt()->boundary_node_pt(b,0)->pin_position(0);
793  wall_mesh_pt()->boundary_node_pt(b,0)->pin_position(1);
794  }
795 
796 
797 
798  //Choose control nodes
799  //---------------------
800 
801  // Left boundary
802  ibound=5;
803  num_nod= bulk_mesh_pt()->nboundary_node(ibound);
804  unsigned control_nod=num_nod/2;
805  Left_node_pt= bulk_mesh_pt()->boundary_node_pt(ibound, control_nod);
806 
807  // Right boundary
808  ibound=1;
809  num_nod= bulk_mesh_pt()->nboundary_node(ibound);
810  control_nod=num_nod/2;
811  Right_node_pt= bulk_mesh_pt()->boundary_node_pt(ibound, control_nod);
812 
813 
814  // Set the pointer to the control node on the wall
815  num_nod= wall_mesh_pt()->nnode();
816  Wall_node_pt=wall_mesh_pt()->node_pt(Ncollapsible/2);
817 
818 
819 
820  // Setup FSI
821  //----------
822 
823  // The velocity of the fluid nodes on the wall (fluid mesh boundary 3)
824  // is set by the wall motion -- hence the no-slip condition must be
825  // re-applied whenever a node update is performed for these nodes.
826  // Such tasks may be performed automatically by the auxiliary node update
827  // function specified by a function pointer:
828  ibound=3;
829  num_nod= bulk_mesh_pt()->nboundary_node(ibound);
830  for (unsigned inod=0;inod<num_nod;inod++)
831  {
832  static_cast<AlgebraicNode*>(
833  bulk_mesh_pt()->boundary_node_pt(ibound, inod))->
834  set_auxiliary_node_update_fct_pt(
835  FSI_functions::apply_no_slip_on_moving_wall);
836  }
837 
838  // Work out which fluid dofs affect the residuals of the wall elements:
839  // We pass the boundary between the fluid and solid meshes and
840  // pointers to the meshes. The interaction boundary is boundary 3 of the
841  // 2D fluid mesh.
842  FSI_functions::setup_fluid_load_info_for_solid_elements<ELEMENT,2>
843  (this,3,Bulk_mesh_pt,Wall_mesh_pt);
844 
845  // Setup equation numbering scheme
846  cout <<"Total number of equations: " << assign_eqn_numbers() << std::endl;
847 
848 }//end of constructor
849 
850 
851 
852 //====start_of_doc_solution_steady============================================
853 /// Doc the solution for a steady run
854 //============================================================================
855 template <class ELEMENT>
858  DocInfo &doc_info,
859  ofstream& trace_file,
860  const double& cpu, const unsigned &niter)
861 {
862 
863  ofstream some_file;
864  char filename[100];
865 
866  // Number of plot points
867  unsigned npts;
868  npts=5;
869 
870  // Output fluid solution
871  sprintf(filename,"%s/soln%i.dat",Doc_info.directory().c_str(),
872  Doc_info.number());
873  some_file.open(filename);
874  bulk_mesh_pt()->output(some_file,npts);
875  some_file.close();
876 
877  // Document the wall shape
878  sprintf(filename,"%s/beam%i.dat",Doc_info.directory().c_str(),
879  Doc_info.number());
880  some_file.open(filename);
881  wall_mesh_pt()->output(some_file,npts);
882  some_file.close();
883 
884 // Write restart file
885  sprintf(filename,"%s/restart%i.dat",Doc_info.directory().c_str(),
886  Doc_info.number());
887  some_file.open(filename);
888  some_file.precision(16);
889  dump_it(some_file);
890  some_file.close();
891 
892  // Write trace file
893  trace_file << Global_Physical_Variables::P_ext_data_pt->value(0) << " ";
894  trace_file << Global_Physical_Variables::Yprescr << " ";
895 
896  // Write trace file
897  trace_file << Left_node_pt->value(0) << " "
898  << Right_node_pt->value(0) << " "
899  << cpu << " "
900  << Newton_iter << " "
901  << std::endl;
902 
903 
904 } // end_of_doc_solution_steady
905 
906 
907 
908 
909 
910 
911 
912 
913 //====start_of_doc_solution_unsteady==========================================
914 /// Doc the solution for an unstady run
915 //============================================================================
916 template <class ELEMENT>
919  DocInfo& doc_info,
920  ofstream& trace_file,
921  const double& cpu,
922  const unsigned &niter)
923 {
924 
925  ofstream some_file;
926  char filename[100];
927 
928  // Number of plot points
929  unsigned npts;
930  npts=5;
931 
932  // Output fluid solution
933  sprintf(filename,"%s/soln%i.dat",Doc_info.directory().c_str(),
934  Doc_info.number());
935  some_file.open(filename);
936  bulk_mesh_pt()->output(some_file,npts);
937  some_file.close();
938 
939  // Document the wall shape
940  sprintf(filename,"%s/beam%i.dat",Doc_info.directory().c_str(),
941  Doc_info.number());
942  some_file.open(filename);
943  wall_mesh_pt()->output(some_file,npts);
944  some_file.close();
945 
946 // Write restart file
947  sprintf(filename,"%s/restart%i.dat",Doc_info.directory().c_str(),
948  Doc_info.number());
949  some_file.open(filename);
950  dump_it(some_file);
951  some_file.close();
952 
953  // Write trace file
954  trace_file << time_pt()->time() << " ";
955 
956  // Get/doc y-coordinate of control point
957  Vector<double> r(2);
958  Ctrl_geom_obj_pt->position(S_displ_ctrl,r);
959  trace_file << r[1] << " ";
960 
961  // Write trace file
962  trace_file << Left_node_pt->value(0) << " "
963  << Right_node_pt->value(0) << " "
964  << cpu << " "
965  << Newton_iter << " "
966  << std::endl;
967 
968 
969 } // end_of_doc_solution_steady
970 
971 
972 
973 
974 //=====start_of_dump_it===================================================
975 /// Dump the solution to disk to allow for restart
976 //========================================================================
977 template <class ELEMENT>
979 {
980 
981  // Number of submeshes must agree when dumping/restarting so
982  // temporarily add displacement control mesh back in before dumping...
983  if (!Displ_control)
984  {
985  flush_sub_meshes();
986  add_sub_mesh(Bulk_mesh_pt);
987  add_sub_mesh(Wall_mesh_pt);
988  add_sub_mesh(Displ_control_mesh_pt);
989  rebuild_global_mesh();
990  assign_eqn_numbers();
991  }
992 
993  // Write current external pressure
994  dump_file << Global_Physical_Variables::P_ext_data_pt->value(0)
995  << " # external pressure" << std::endl;
996 
997  // Call generic dump()
998  Problem::dump(dump_file);
999 
1000  // ...strip displacement control mesh back out after dumping if
1001  // we don't actually need it
1002  if (!Displ_control)
1003  {
1004  flush_sub_meshes();
1005  add_sub_mesh(Bulk_mesh_pt);
1006  add_sub_mesh(Wall_mesh_pt);
1007  rebuild_global_mesh();
1008  assign_eqn_numbers();
1009  }
1010 
1011 
1012 } // end of dump_it
1013 
1014 
1015 
1016 //=================start_of_restart=======================================
1017 /// Read solution from disk for restart
1018 //========================================================================
1019 template <class ELEMENT>
1021 {
1022 
1023 
1024 
1025 // Read external pressure
1026 
1027 // Read line up to termination sign
1028  string input_string;
1029  getline(restart_file,input_string,'#');
1030  restart_file.ignore(80,'\n');
1031 
1033  {
1034  std::cout
1035  << "Increasing external pressure from "
1036  << double(atof(input_string.c_str())) << " to "
1037  << double(atof(input_string.c_str()))+Global_Physical_Variables::P_step
1038  << std::endl;
1039  }
1040  else
1041  {
1042  std::cout << "Running with unchanged external pressure of "
1043  << double(atof(input_string.c_str())) << std::endl;
1044  }
1045 
1046  // Set external pressure
1048  set_value(0,double(atof(input_string.c_str()))+
1050 
1051  // Read the generic problem data from restart file
1052  Problem::read(restart_file);
1053 
1054  //Now update the position of the nodes to be consistent with
1055  //the possible precision loss caused by reading in the data from disk
1056  this->Bulk_mesh_pt->node_update();
1057 
1058  // Strip out displacement control mesh if we don't need it
1059  if (!Displ_control)
1060  {
1061  flush_sub_meshes();
1062  add_sub_mesh(Bulk_mesh_pt);
1063  add_sub_mesh(Wall_mesh_pt);
1064  rebuild_global_mesh();
1065  assign_eqn_numbers();
1066  }
1067 
1068 
1069 } // end of restart
1070 
1071 
1072 
1073 //====start_of_apply_initial_condition========================================
1074 /// Apply initial conditions
1075 //============================================================================
1076 template <class ELEMENT>
1078 {
1079 
1080  // Check that timestepper is from the BDF family
1081  if (!Steady_flag)
1082  {
1083  if (time_stepper_pt()->type()!="BDF")
1084  {
1085  std::ostringstream error_stream;
1086  error_stream << "Timestepper has to be from the BDF family!\n"
1087  << "You have specified a timestepper from the "
1088  << time_stepper_pt()->type() << " family" << std::endl;
1089 
1090  throw OomphLibError(error_stream.str(),
1091  OOMPH_CURRENT_FUNCTION,
1092  OOMPH_EXCEPTION_LOCATION);
1093  }
1094  }
1095 
1096 
1097  // Pointer to restart file
1098  ifstream* restart_file_pt=0;
1099 
1100  // Restart?
1101  //---------
1102 
1103  if (Flags::Restart_file_name!="")
1104  {
1105  // Open restart file
1106  restart_file_pt= new ifstream(Flags::Restart_file_name.c_str(),
1107  ios_base::in);
1108  if (restart_file_pt!=0)
1109  {
1110  cout << "Have opened " << Flags::Restart_file_name <<
1111  " for restart. " << std::endl;
1112  restart(*restart_file_pt);
1113  return;
1114  }
1115  else
1116  {
1117  std::ostringstream error_stream;
1118  error_stream
1119  << "ERROR while trying to open " << Flags::Restart_file_name <<
1120  " for restart." << std::endl;
1121 
1122  throw OomphLibError(
1123  error_stream.str(),
1124  OOMPH_CURRENT_FUNCTION,
1125  OOMPH_EXCEPTION_LOCATION);
1126  }
1127  }
1128 
1129 
1130  // No restart
1131  else
1132  {
1133  // Update the mesh
1134  bulk_mesh_pt()->node_update();
1135 
1136  // Loop over the nodes to set initial guess everywhere
1137  unsigned num_nod = bulk_mesh_pt()->nnode();
1138  for (unsigned n=0;n<num_nod;n++)
1139  {
1140  // Get nodal coordinates
1141  Vector<double> x(2);
1142  x[0]=bulk_mesh_pt()->node_pt(n)->x(0);
1143  x[1]=bulk_mesh_pt()->node_pt(n)->x(1);
1144 
1145  // Assign initial condition: Steady Poiseuille flow
1146  bulk_mesh_pt()->node_pt(n)->set_value(0,6.0*(x[1]/Ly)*(1.0-(x[1]/Ly)));
1147  bulk_mesh_pt()->node_pt(n)->set_value(1,0.0);
1148  }
1149 
1150  // Assign initial values for an impulsive start
1151  bulk_mesh_pt()->assign_initial_values_impulsive();
1152  }
1153 
1154 
1155 } // end of set_initial_condition
1156 
1157 
1158 
1159 
1160 //====steady_run==============================================================
1161 /// Steady run
1162 //============================================================================
1163 template <class ELEMENT>
1165 {
1166 
1167  // Set initial value for external pressure (on the wall stiffness scale).
1168  // This can be overwritten in set_initial_condition.
1170  set_value(0,Global_Physical_Variables::Pmin);
1171 
1172  // Apply initial condition
1173  set_initial_condition();
1174 
1175  //Set output directory
1176  Doc_info.set_directory("RESLT");
1177 
1178  // Open a trace file
1179  ofstream trace_file;
1180  char filename[100];
1181  sprintf(filename,"%s/trace.dat",Doc_info.directory().c_str());
1182  trace_file.open(filename);
1183 
1184  // Write trace file header
1185  trace_file << "VARIABLES=\"p<sub>ext</sub>\","
1186  << "\"y<sub>ctrl</sub>\",";
1187  trace_file << "\"u_1\","
1188  << "\"u_2\","
1189  << "\"CPU time for solve\","
1190  << "\"Number of Newton iterations\","
1191  << std::endl;
1192 
1193  trace_file << "ZONE T=\"";
1194  trace_file << "Re=" << Global_Physical_Variables::Re << ", ";
1195  trace_file << "Q=" << Global_Physical_Variables::Q << ", ";
1196  trace_file << "resolution factor: " << Flags::Resolution_factor << ". ";
1197  trace_file << Flags::Run_identifier_string << "\" ";
1198  trace_file << std::endl;
1199 
1200  // Output the initial solution (dummy for CPU time)
1201  doc_solution_steady(Doc_info,trace_file,0.0,0);
1202 
1203  // Increment step number
1204  Doc_info.number()++;
1205 
1206 
1207  // Increment for external pressure (on the wall stiffness scale)
1208  double delta_p=(Global_Physical_Variables::Pmax-
1210 
1211  // Initial and final values for control position
1213 
1214  // Steady run
1215  double delta_y=
1217  double(Flags::Nsteps-1);
1218 
1219 
1220  // Parameter study
1221  //----------------
1222  for (unsigned istep=0;istep<Flags::Nsteps;istep++)
1223  {
1224 
1225  // Displacement control?
1226  if (Displ_control)
1227  {
1228  std::cout << "Solving for control displ = "
1230  << std::endl;
1231  }
1232  else
1233  {
1234  std::cout << "Solving for p_ext = "
1236  << std::endl;
1237  }
1238 
1239  // Solve the problem
1240  //------------------
1241  clock_t t_start = clock();
1242 
1243  // Explit call to the steady Newton solve.
1244  steady_newton_solve();
1245 
1246  clock_t t_end= clock();
1247  double cpu=double(t_end-t_start)/CLOCKS_PER_SEC;
1248 
1249 
1250  // Outpt the solution
1251  //-------------------
1252  doc_solution_steady(Doc_info,trace_file,cpu,0);
1253 
1254  // Step number
1255  Doc_info.number()++;
1256 
1257  // Adjust control parameter
1258  if (Displ_control)
1259  {
1260  // Increment control position
1262  }
1263  else
1264  {
1265  // Increment external pressure
1266  double old_p=Global_Physical_Variables::P_ext_data_pt->value(0);
1267  Global_Physical_Variables::P_ext_data_pt->set_value(0,old_p+delta_p);
1268  }
1269 
1270  }
1271 
1272  // Close trace file.
1273  trace_file.close();
1274 
1275 }
1276 
1277 
1278 
1279 
1280 
1281 
1282 //====unsteady_run============================================================
1283 /// Unsteady run. Specify timestep or use default of 0.1.
1284 //============================================================================
1285 template <class ELEMENT>
1287 {
1288 
1289  // Set initial value for external pressure (on the wall stiffness scale).
1290  // Will be overwritten by restart data if a restart file (and pressure
1291  // jump) are specified
1293  set_value(0,Global_Physical_Variables::Pmax);
1294 
1295  // Initialise timestep -- also sets the weights for all timesteppers
1296  // in the problem.
1297  initialise_dt(dt);
1298 
1299  std::cout << "Pressure before set initial: "
1301  << std::endl;
1302 
1303  // Apply initial condition
1304  set_initial_condition();
1305 
1306  std::cout << "Pressure after set initial: "
1308  << std::endl;
1309 
1310  //Set output directory
1311  Doc_info.set_directory("RESLT");
1312 
1313  // Open a trace file
1314  ofstream trace_file;
1315  char filename[100];
1316  sprintf(filename,"%s/trace.dat",Doc_info.directory().c_str());
1317  trace_file.open(filename);
1318 
1319 
1320  // Write trace file header
1321  trace_file << "VARIABLES=\"time\","
1322  << "\"y<sub>ctrl</sub>\",";
1323  trace_file << "\"u_1\","
1324  << "\"u_2\","
1325  << "\"CPU time for solve\","
1326  << "\"Number of Newton iterations\""
1327  << std::endl;
1328 
1329  trace_file << "ZONE T=\"";
1330  trace_file << "Re=" << Global_Physical_Variables::Re << ", ";
1331  trace_file << "Q=" << Global_Physical_Variables::Q << ", ";
1332  trace_file << "resolution factor: " << Flags::Resolution_factor << ". ";
1333  trace_file << Flags::Run_identifier_string << "\" ";
1334  trace_file << std::endl;
1335 
1336  // Output the initial solution (dummy for CPU time)
1337  doc_solution_unsteady(Doc_info,trace_file,0.0,0);
1338 
1339  // Increment step number
1340  Doc_info.number()++;
1341 
1342  // Timestepping loop
1343  //------------------
1344  for (unsigned istep=0;istep<Flags::Nsteps;istep++)
1345  {
1346 
1347  // Solve the problem
1348  //------------------
1349  clock_t t_start = clock();
1350 
1351  // Explit call to the unsteady Newton solve.
1352  unsteady_newton_solve(dt);
1353 
1354  clock_t t_end= clock();
1355  double cpu=double(t_end-t_start)/CLOCKS_PER_SEC;
1356 
1357 
1358  // Output the solution
1359  //--------------------
1360  doc_solution_unsteady(Doc_info,trace_file,cpu,0);
1361 
1362  // Step number
1363  Doc_info.number()++;
1364 
1365  }
1366 
1367  // Close trace file.
1368  trace_file.close();
1369 
1370 }
1371 
1372 
string Run_identifier_string
String to identify the run type in trace file.
Extend namespace for control flags.
unsigned Nsteps
Number of steps in parameter study.
void actions_before_newton_convergence_check()
Update before checking Newton convergence: Update the nodal positions in the fluid mesh in response t...
void position(const Vector< double > &zeta, Vector< double > &r) const
Position vector at Lagrangian coordinate zeta.
OneDLagrangianMesh< FSIHermiteBeamElement > * wall_mesh_pt()
Access function for the wall mesh.
void actions_before_newton_solve()
Actions before solve. Reset counter for number of Newton iterations.
~FSICollapsibleChannelProblem()
Destructor.
DocInfo Doc_info
DocInfo object.
double H
Height of the undeformed wall above y=0.
AlgebraicCollapsibleChannelMesh< ELEMENT > * Bulk_mesh_pt
Pointer to the "bulk" mesh.
double X0
x position of the undeformed beam&#39;s left end.
double Yprescr
Current prescribed vertical position of control point (only used for displacement control) ...
double Ly
Transverse length.
void set_initial_condition()
Apply initial conditions.
void load(const Vector< double > &xi, const Vector< double > &x, const Vector< double > &N, Vector< double > &load)
Load function: Apply a constant external pressure to the wall. Note: This is the load without the flu...
FSICollapsibleChannelProblem(const unsigned &nup, const unsigned &ncollapsible, const unsigned &ndown, const unsigned &ny, const double &lup, const double &lcollapsible, const double &ldown, const double &ly, const bool &displ_control, const bool &steady_flag)
Constructor: The arguments are the number of elements and the lengths of the domain.
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...
unsigned Steady_flag
Steady run (1) or unsteady run (0)
double Pmax
Max. pressure. Only used in steady runs during parameter incrementation. Use 2.0 for Re=250; 3...
AlgebraicCollapsibleChannelMesh< ELEMENT > * bulk_mesh_pt()
Access function for the specific bulk (fluid) mesh.
void restart(ifstream &restart_file)
Read problem for restart from specified restart file.
void doc_flags()
Doc flags.
OneDLagrangianMesh< FSIHermiteBeamElement > * Wall_mesh_pt
Pointer to the "wall" mesh.
double Sigma0
2nd Piola Kirchhoff pre-stress. As in Heil (2004) paper.
virtual 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.
double Q
Fluid structure interaction parameter: Ratio of stresses used for non-dimensionalisation of fluid to ...
Node * Wall_node_pt
Pointer to control node on the wall.
unsigned Nup
Number of elements in the x direction in the upstream part of the channel.
MeshAsGeomObject * Wall_geom_object_pt
Pointer to geometric object (one Lagrangian, two Eulerian coordinates) that will be built from the wa...
unsigned Newton_iter
Counter for Newton iterations.
double Pmin
Min. pressure. Only used in steady runs during parameter incrementation. Use 1.5 for values of Re to ...
unsigned Resolution_factor
Resolution factor (multiplier for number of elements across channel)
double Lcollapsible
x-length in the collapsible part of the channel
double ReSt
Womersley = Reynolds times Strouhal.
unsigned Ncollapsible
Number of elements in the x direction in the collapsible part of the channel.
Data * P_ext_data_pt
Pointer to Data object that stores external pressure.
virtual void doc_solution_steady(DocInfo &doc_info, ofstream &trace_file, const double &cpu, const unsigned &niter)
Doc the steady solution.
double Delta
Boundary layer width.
void dump_it(ofstream &dump_file)
Dump problem to disk to allow for restart.
double Re
Reynolds number.
void actions_after_newton_solve()
Update the problem after solve (empty)
double Fract_in_BL
Fraction of points in boundary layer.
Node * Left_node_pt
Pointer to the left control node.
bool Steady_flag
Flag for steady run.
UndeformedWall(const double &x0, const double &h)
Constructor: arguments are the starting point and the height above y=0.
Namespace for phyical parameters.
double H
Non-dimensional wall thickness. As in Heil (2004) paper.
virtual void doc_solution_unsteady(DocInfo &doc_info, ofstream &trace_file, const double &cpu, const unsigned &niter)
Doc the unsteady solution.
Mesh * Displ_control_mesh_pt
Pointer to the mesh that contains the displacement control element.
unsigned Use_displ_control
Use displacement control (1) or not (0)
Node * Right_node_pt
Pointer to right control node.
double Ldown
x-length in the downstream part of the channel
string Restart_file_name
Name of restart file.
Vector< double > S_displ_ctrl
Vector of local coordinates of displacement control point in Ctrl_geom_obj_pt.
double Lup
x-length in the upstream part of the channel
virtual void steady_run()
Steady run.
bool Displ_control
Use displacement control?
double P_step
Jump in pressure after a restart – used to give a steady solution a kick before starting a time-depe...
double squash_fct(const double &s)
Mapping [0,1] -> [0,1] that re-distributes nodal points across the channel width. ...
unsigned Ndown
Number of elements in the x direction in the downstream part of the channel.
unsigned Ny
Number of elements across the channel.
virtual void unsteady_run(const double &dt=0.1)
Unsteady run; virtual so it can be overloaded in derived problem classes. Specify timestep or use def...