turek_flag.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 stuff
31 #include "generic.h"
32 
33 // Solid mechanics
34 #include "solid.h"
35 
36 // Navier Stokes
37 #include "navier_stokes.h"
38 
39 // Multiphysics for FSI preconditioner
40 #include "multi_physics.h"
41 
42 // The meshes
43 #include "meshes/cylinder_with_flag_mesh.h"
44 #include "meshes/rectangular_quadmesh.h"
45 
46 
47 using namespace std;
48 
49 using namespace oomph;
50 
51 
52 //=====start_of_global_parameters=================================
53 /// Global variables
54 //================================================================
56 {
57 
58  /// Default case ID
59  string Case_ID="FSI1";
60 
61  /// Reynolds number (default assignment for FSI1 test case)
62  double Re=20.0;
63 
64  /// Strouhal number (default assignment for FSI1 test case)
65  double St=0.5;
66 
67  /// \short Product of Reynolds and Strouhal numbers (default
68  /// assignment for FSI1 test case)
69  double ReSt=10.0;
70 
71  /// FSI parameter (default assignment for FSI1 test case)
72  double Q=1.429e-6;
73 
74  /// \short Density ratio (solid to fluid; default assignment for FSI1
75  /// test case)
76  double Density_ratio=1.0;
77 
78  /// Height of flag
79  double H=0.2;
80 
81  /// x position of centre of cylinder
82  double Centre_x=2.0;
83 
84  /// y position of centre of cylinder
85  double Centre_y=2.0;
86 
87  /// Radius of cylinder
88  double Radius=0.5;
89 
90  /// Pointer to constitutive law
91  ConstitutiveLaw* Constitutive_law_pt=0;
92 
93  /// \short Timescale ratio for solid (dependent parameter
94  /// assigned in set_parameters())
95  double Lambda_sq=0.0;
96 
97  /// Timestep
98  double Dt=0.1;
99 
100  /// Ignore fluid (default assignment for FSI1 test case)
102 
103  /// Elastic modulus
104  double E=1.0;
105 
106  /// Poisson's ratio
107  double Nu=0.4;
108 
109  /// Non-dim gravity (default assignment for FSI1 test case)
110  double Gravity=0.0;
111 
112  /// Non-dimensional gravity as body force
113  void gravity(const double& time,
114  const Vector<double> &xi,
115  Vector<double> &b)
116  {
117  b[0]=0.0;
118  b[1]=-Gravity;
119  }
120 
121  /// Period for ramping up in flux
122  double Ramp_period=2.0;
123 
124  /// Min. flux
125  double Min_flux=0.0;
126 
127  /// Max. flux
128  double Max_flux=1.0;
129 
130  /// \short Flux increases between Min_flux and Max_flux over
131  /// period Ramp_period
132  double flux(const double& t)
133  {
134  if (t<Ramp_period)
135  {
136  return Min_flux+(Max_flux-Min_flux)*
137  0.5*(1.0-cos(MathematicalConstants::Pi*t/Ramp_period));
138  }
139  else
140  {
141  return Max_flux;
142  }
143  } // end of specification of ramped influx
144 
145 
146  /// Set parameters for the various test cases
147  void set_parameters(const string& case_id)
148  {
149 
150  // Remember which case we're dealing with
151  Case_ID=case_id;
152 
153  // Setup independent parameters depending on test case
154  if (case_id=="FSI1")
155  {
156  // Reynolds number based on diameter of cylinder
157  Re=20.0;
158 
159  // Strouhal number based on timescale of one second
160  St=0.5;
161 
162  // Womersley number
163  ReSt=Re*St;
164 
165  // FSI parameter
166  Q=1.429e-6;
167 
168  // Timestep -- aiming for about 40 steps per period
169  Dt=0.1;
170 
171  // Density ratio
172  Density_ratio=1.0;
173 
174  // Gravity
175  Gravity=0.0;
176 
177  // Max. flux
178  Max_flux=1.0;
179 
180  // Ignore fluid
181  Ignore_fluid_loading=false;
182 
183  // Compute dependent parameters
184 
185  // Timescale ratio for solid
186  Lambda_sq=Re*Q*Density_ratio*St*St;
187  }
188  else if (case_id=="FSI2")
189  {
190  // Reynolds number based on diameter of cylinder
191  Re=100.0;
192 
193  // Strouhal number based on timescale of one second
194  St=0.1;
195 
196  // Womersley number
197  ReSt=Re*St;
198 
199  // FSI parameter
200  Q=7.143e-6;
201 
202  // Timestep -- aiming for about 40 steps per period
203  Dt=0.01;
204 
205  // Density ratio
206  Density_ratio=10.0;
207 
208  // Gravity
209  Gravity=0.0;
210 
211  // Max. flux
212  Max_flux=1.0;
213 
214  // Ignore fluid
215  Ignore_fluid_loading=false;
216 
217  // Compute dependent parameters
218 
219  // Timescale ratio for solid
220  Lambda_sq=Re*Q*Density_ratio*St*St;
221  }
222  else if (case_id=="FSI3")
223  {
224  // Reynolds number based on diameter of cylinder
225  Re=200.0;
226 
227  // Strouhal number based on timescale of one second
228  St=0.05;
229 
230  // Womersley number
231  ReSt=Re*St;
232 
233  // FSI parameter
234  Q=3.571e-6;
235 
236  // Timestep -- aiming for about 40 steps per period
237  Dt=0.005;
238 
239  // Density ratio
240  Density_ratio=1.0;
241 
242  // Gravity
243  Gravity=0.0;
244 
245  // Max. flux
246  Max_flux=1.0;
247 
248  // Ignore fluid
249  Ignore_fluid_loading=false;
250 
251  // Compute dependent parameters
252 
253  // Timescale ratio for solid
254  Lambda_sq=Re*Q*Density_ratio*St*St;
255  }
256  else if (case_id=="CSM1")
257  {
258  // Reynolds number based on diameter of cylinder
259  Re=0.0;
260 
261  // Strouhal number based on timescale of one second
262  // (irrelevant here)
263  St=0.0;
264 
265  // Womersley number
266  ReSt=Re*St;
267 
268  // FSI parameter
269  Q=0.0;
270 
271  // Timestep -- irrelevant here
272  Dt=0.005;
273 
274  // Density ratio (switch off wall inertia)
275  Density_ratio=0.0;
276 
277  // Gravity
278  Gravity=1.429e-4;
279 
280  // Max. flux
281  Max_flux=0.0;
282 
283  // Ignore fluid
284  Ignore_fluid_loading=true;
285 
286  // Compute dependent parameters
287 
288  // Timescale ratio for solid
289  Lambda_sq=0.0;
290  }
291  else if (case_id=="CSM3")
292  {
293  // Reynolds number based on diameter of cylinder
294  Re=0.0;
295 
296  // Strouhal number based on timescale of one second
297  // (irrelevant here)
298  St=0.0;
299 
300  // Womersley number
301  ReSt=Re*St;
302 
303  // Timestep -- aiming for about 40 steps per period
304  Dt=0.025;
305 
306  // FSI parameter
307  Q=0.0;
308 
309  // Density ratio (not used here)
310  Density_ratio=0.0;
311 
312  // Gravity
313  Gravity=1.429e-4;
314 
315  // Max. flux
316  Max_flux=0.0;
317 
318  // Ignore fluid
319  Ignore_fluid_loading=true;
320 
321  // Compute dependent parameters
322 
323  // Set timescale ratio for solid based on the
324  // observed period of oscillation of about 1 sec)
325  Lambda_sq=7.143e-6;
326  }
327  else
328  {
329  std::cout << "Wrong case_id: " << case_id << std::endl;
330  exit(0);
331  }
332 
333 
334  // Ramp period (20 timesteps)
335  Ramp_period=Dt*20.0;
336 
337  // "Big G" Linear constitutive equations:
338  Constitutive_law_pt = new GeneralisedHookean(&Nu,&E);
339 
340  // Doc
341  oomph_info << std::endl;
342  oomph_info << "-------------------------------------------"
343  << std::endl;
344  oomph_info << "Case: " << case_id << std::endl;
345  oomph_info << "Re = " << Re << std::endl;
346  oomph_info << "St = " << St << std::endl;
347  oomph_info << "ReSt = " << ReSt << std::endl;
348  oomph_info << "Q = " << Q << std::endl;
349  oomph_info << "Dt = " << Dt << std::endl;
350  oomph_info << "Ramp_period = " << Ramp_period << std::endl;
351  oomph_info << "Max_flux = " << Max_flux << std::endl;
352  oomph_info << "Density_ratio = " << Density_ratio << std::endl;
353  oomph_info << "Lambda_sq = " << Lambda_sq << std::endl;
354  oomph_info << "Gravity = " << Gravity << std::endl;
355  oomph_info << "Ignore fluid = " << Ignore_fluid_loading<< std::endl;
356  oomph_info << "-------------------------------------------"
357  << std::endl << std::endl;
358  }
359 
360 }// end_of_namespace
361 
362 
363 
364 ///////////////////////////////////////////////////////////////////////
365 ///////////////////////////////////////////////////////////////////////
366 ///////////////////////////////////////////////////////////////////////
367 
368 
369 
370 //====start_of_problem_class===========================================
371 /// Problem class
372 //======================================================================
373 template< class FLUID_ELEMENT,class SOLID_ELEMENT >
374 class TurekProblem : public Problem
375 {
376 
377 public:
378 
379  /// \short Constructor: Pass length and height of domain
380  TurekProblem(const double &length, const double &height);
381 
382  /// Access function for the fluid mesh
383  RefineableAlgebraicCylinderWithFlagMesh<FLUID_ELEMENT>* fluid_mesh_pt()
384  { return Fluid_mesh_pt;}
385 
386  /// Access function for the solid mesh
387  ElasticRefineableRectangularQuadMesh<SOLID_ELEMENT>*& solid_mesh_pt()
388  {return Solid_mesh_pt;}
389 
390  /// Access function for the i-th mesh of FSI traction elements
391  SolidMesh*& traction_mesh_pt(const unsigned& i)
392  {return Traction_mesh_pt[i];}
393 
394  /// Actions after adapt: Re-setup the fsi lookup scheme
395  void actions_after_adapt();
396 
397  /// Doc the solution
398  void doc_solution(DocInfo& doc_info, ofstream& trace_file);
399 
400  /// Update function (empty)
402 
403  /// Update function (empty)
405 
406  /// \short Update the (enslaved) fluid node positions following the
407  /// update of the solid variables before performing Newton convergence
408  /// check
409  void actions_before_newton_convergence_check();
410 
411  /// Update the time-dependent influx
412  void actions_before_implicit_timestep();
413 
414 private:
415 
416  /// Create FSI traction elements
417  void create_fsi_traction_elements();
418 
419  /// Pointer to solid mesh
420  ElasticRefineableRectangularQuadMesh<SOLID_ELEMENT>* Solid_mesh_pt;
421 
422  ///Pointer to fluid mesh
423  RefineableAlgebraicCylinderWithFlagMesh<FLUID_ELEMENT>* Fluid_mesh_pt;
424 
425  /// Vector of pointers to mesh of FSI traction elements
426  Vector<SolidMesh*> Traction_mesh_pt;
427 
428  /// Combined mesh of traction elements -- only used for documentation
430 
431  /// Overall height of domain
433 
434  /// Overall length of domain
436 
437  /// Pointer to solid control node
439 
440  /// Pointer to fluid control node
442 
443 };// end_of_problem_class
444 
445 
446 //=====start_of_constructor=============================================
447 /// Constructor: Pass length and height of domain
448 //======================================================================
449 template< class FLUID_ELEMENT,class SOLID_ELEMENT >
451 TurekProblem(const double &length,
452  const double &height) : Domain_height(height),
453  Domain_length(length)
454 
455 {
456  // Increase max. number of iterations in Newton solver to
457  // accomodate possible poor initial guesses
458  Max_newton_iterations=20;
459  Max_residuals=1.0e4;
460 
461  // Build solid mesh
462  //------------------
463 
464  // # of elements in x-direction
465  unsigned n_x=20;
466 
467  // # of elements in y-direction
468  unsigned n_y=2;
469 
470  // Domain length in y-direction
471  double l_y=Global_Parameters::H;
472 
473  // Create the flag timestepper (consistent with BDF<2> for fluid)
474  Newmark<2>* flag_time_stepper_pt=new Newmark<2>;
475  add_time_stepper_pt(flag_time_stepper_pt);
476 
477  /// Left point on centreline of flag so that the top and bottom
478  /// vertices merge with the cylinder.
479  Vector<double> origin(2);
480  origin[0]=Global_Parameters::Centre_x+
484  origin[1]=Global_Parameters::Centre_y-0.5*l_y;
485 
486  // Set length of flag so that endpoint actually stretches all the
487  // way to x=6:
488  double l_x=6.0-origin[0];
489 
490  //Now create the mesh
491  solid_mesh_pt() = new ElasticRefineableRectangularQuadMesh<SOLID_ELEMENT>(
492  n_x,n_y,l_x,l_y,origin,flag_time_stepper_pt);
493 
494  // Set error estimator for the solid mesh
495  Z2ErrorEstimator* solid_error_estimator_pt=new Z2ErrorEstimator;
496  solid_mesh_pt()->spatial_error_estimator_pt()=solid_error_estimator_pt;
497 
498 
499  // Element that contains the control point
500  FiniteElement* el_pt=solid_mesh_pt()->finite_element_pt(n_x*n_y/2-1);
501 
502  // How many nodes does it have?
503  unsigned nnod=el_pt->nnode();
504 
505  // Get the control node
506  Solid_control_node_pt=el_pt->node_pt(nnod-1);
507 
508  std::cout << "Coordinates of solid control point "
509  << Solid_control_node_pt->x(0) << " "
510  << Solid_control_node_pt->x(1) << " " << std::endl;
511 
512  // Refine the mesh uniformly
513  solid_mesh_pt()->refine_uniformly();
514 
515  //Do not allow the solid mesh to be refined again
516  solid_mesh_pt()->disable_adaptation();
517 
518 
519  // Build mesh of solid traction elements that apply the fluid
520  //------------------------------------------------------------
521  // traction to the solid elements
522  //-------------------------------
523 
524  // Create storage for Meshes of FSI traction elements at the bottom
525  // top and left boundaries of the flag
526  Traction_mesh_pt.resize(3);
527 
528  // Now construct the traction element meshes
529  Traction_mesh_pt[0]=new SolidMesh;
530  Traction_mesh_pt[1]=new SolidMesh;
531  Traction_mesh_pt[2]=new SolidMesh;
532 
533  // Build the FSI traction elements
535 
536  // Loop over traction elements, pass the FSI parameter and tell them
537  // the boundary number in the bulk solid mesh -- this is required so
538  // they can get access to the boundary coordinates!
539  for (unsigned bound=0;bound<3;bound++)
540  {
541  unsigned n_face_element = Traction_mesh_pt[bound]->nelement();
542  for(unsigned e=0;e<n_face_element;e++)
543  {
544  //Cast the element pointer and specify boundary number
545  FSISolidTractionElement<SOLID_ELEMENT,2>* elem_pt=
546  dynamic_cast<FSISolidTractionElement<SOLID_ELEMENT,2>*>
547  (Traction_mesh_pt[bound]->element_pt(e));
548 
549  // Specify boundary number
550  elem_pt->set_boundary_number_in_bulk_mesh(bound);
551 
552  // Function that specifies the load ratios
553  elem_pt->q_pt() = &Global_Parameters::Q;
554 
555  }
556  } // build of FSISolidTractionElements is complete
557 
558 
559  // Turn the three meshes of FSI traction elements into compound
560  // geometric objects (one Lagrangian, two Eulerian coordinates)
561  // that determine the boundary of the fluid mesh
562  MeshAsGeomObject*
563  bottom_flag_pt=
564  new MeshAsGeomObject
565  (Traction_mesh_pt[0]);
566 
567  MeshAsGeomObject* tip_flag_pt=
568  new MeshAsGeomObject
569  (Traction_mesh_pt[1]);
570 
571  MeshAsGeomObject* top_flag_pt=
572  new MeshAsGeomObject
573  (Traction_mesh_pt[2]);
574 
575 
576  // Build fluid mesh
577  //-----------------
578 
579  //Create a new Circle object as the central cylinder
580  Circle* cylinder_pt = new Circle(Global_Parameters::Centre_x,
582  Global_Parameters::Radius);
583 
584  // Allocate the fluid timestepper
585  BDF<2>* fluid_time_stepper_pt=new BDF<2>;
586  add_time_stepper_pt(fluid_time_stepper_pt);
587 
588  // Build fluid mesh
590  new RefineableAlgebraicCylinderWithFlagMesh<FLUID_ELEMENT>
591  (cylinder_pt,
592  top_flag_pt,
593  bottom_flag_pt,
594  tip_flag_pt,
595  length, height,
600  fluid_time_stepper_pt);
601 
602 
603  // I happen to have found out by inspection that
604  // node 5 in the hand-coded fluid mesh is at the
605  // upstream tip of the cylinder
607 
608  // Set error estimator for the fluid mesh
609  Z2ErrorEstimator* fluid_error_estimator_pt=new Z2ErrorEstimator;
610  fluid_mesh_pt()->spatial_error_estimator_pt()=fluid_error_estimator_pt;
611 
612  // Refine uniformly
613  Fluid_mesh_pt->refine_uniformly();
614 
615 
616  // Build combined global mesh
617  //---------------------------
618 
619  // Add Solid mesh the problem's collection of submeshes
620  add_sub_mesh(solid_mesh_pt());
621 
622  // Add traction sub-meshes
623  for (unsigned i=0;i<3;i++)
624  {
625  add_sub_mesh(traction_mesh_pt(i));
626  }
627 
628  // Add fluid mesh
629  add_sub_mesh(fluid_mesh_pt());
630 
631  // Build combined "global" mesh
632  build_global_mesh();
633 
634 
635 
636  // Apply solid boundary conditons
637  //-------------------------------
638 
639  //Solid mesh: Pin the left boundary (boundary 3) in both directions
640  unsigned n_side = mesh_pt()->nboundary_node(3);
641 
642  //Loop over the nodes
643  for(unsigned i=0;i<n_side;i++)
644  {
645  solid_mesh_pt()->boundary_node_pt(3,i)->pin_position(0);
646  solid_mesh_pt()->boundary_node_pt(3,i)->pin_position(1);
647  }
648 
649  // Pin the redundant solid pressures (if any)
650  PVDEquationsBase<2>::pin_redundant_nodal_solid_pressures(
651  solid_mesh_pt()->element_pt());
652 
653  // Apply fluid boundary conditions
654  //--------------------------------
655 
656  //Fluid mesh: Horizontal, traction-free outflow; pinned elsewhere
657  unsigned num_bound = fluid_mesh_pt()->nboundary();
658  for(unsigned ibound=0;ibound<num_bound;ibound++)
659  {
660  unsigned num_nod= fluid_mesh_pt()->nboundary_node(ibound);
661  for (unsigned inod=0;inod<num_nod;inod++)
662  {
663  // Parallel, axially traction free outflow at downstream end
664  if (ibound != 1)
665  {
666  fluid_mesh_pt()->boundary_node_pt(ibound,inod)->pin(0);
667  fluid_mesh_pt()->boundary_node_pt(ibound,inod)->pin(1);
668  }
669  else
670  {
671  fluid_mesh_pt()->boundary_node_pt(ibound,inod)->pin(1);
672  }
673  }
674  }//end_of_pin
675 
676  // Pin redundant pressure dofs in fluid mesh
677  RefineableNavierStokesEquations<2>::
678  pin_redundant_nodal_pressures(fluid_mesh_pt()->element_pt());
679 
680 
681  // Apply boundary conditions for fluid
682  //-------------------------------------
683 
684  // Impose parabolic flow along boundary 3
685  // Current flow rate
686  double t=0.0;
687  double ampl=Global_Parameters::flux(t);
688  unsigned ibound=3;
689  unsigned num_nod= Fluid_mesh_pt->nboundary_node(ibound);
690  for (unsigned inod=0;inod<num_nod;inod++)
691  {
692  double ycoord = Fluid_mesh_pt->boundary_node_pt(ibound,inod)->x(1);
693  double uy = ampl*6.0*ycoord/Domain_height*(1.0-ycoord/Domain_height);
694  Fluid_mesh_pt->boundary_node_pt(ibound,inod)->set_value(0,uy);
695  Fluid_mesh_pt->boundary_node_pt(ibound,inod)->set_value(1,0.0);
696  }
697 
698 
699  // Complete build of solid elements
700  //---------------------------------
701 
702  //Pass problem parameters to solid elements
703  unsigned n_element =solid_mesh_pt()->nelement();
704  for(unsigned i=0;i<n_element;i++)
705  {
706  //Cast to a solid element
707  SOLID_ELEMENT *el_pt = dynamic_cast<SOLID_ELEMENT*>(
708  solid_mesh_pt()->element_pt(i));
709 
710  // Set the constitutive law
711  el_pt->constitutive_law_pt() =
713 
714  //Set the body force
715  el_pt->body_force_fct_pt() = Global_Parameters::gravity;
716 
717  // Timescale ratio for solid
718  el_pt->lambda_sq_pt() = &Global_Parameters::Lambda_sq;
719  }
720 
721 
722 
723  // Complete build of fluid elements
724  //---------------------------------
725 
726  // Set physical parameters in the fluid mesh
727  unsigned nelem=fluid_mesh_pt()->nelement();
728  for (unsigned e=0;e<nelem;e++)
729  {
730  // Upcast from GeneralisedElement to the present element
731  FLUID_ELEMENT* el_pt = dynamic_cast<FLUID_ELEMENT*>
732  (fluid_mesh_pt()->element_pt(e));
733 
734  //Set the Reynolds number
735  el_pt->re_pt() = &Global_Parameters::Re;
736 
737  //Set the Womersley number
738  el_pt->re_st_pt() = &Global_Parameters::ReSt;
739 
740  }//end_of_loop
741 
742 
743 
744  // Setup FSI
745  //----------
746 
747  // Pass Strouhal number to the helper function that automatically applies
748  // the no-slip condition
749  FSI_functions::Strouhal_for_no_slip=Global_Parameters::St;
750 
751  // The velocity of the fluid nodes on the wall (fluid mesh boundary 5,6,7)
752  // is set by the wall motion -- hence the no-slip condition must be
753  // re-applied whenever a node update is performed for these nodes.
754  // Such tasks may be performed automatically by the auxiliary node update
755  // function specified by a function pointer:
757  {
758  for(unsigned ibound=5;ibound<8;ibound++ )
759  {
760  unsigned num_nod= Fluid_mesh_pt->nboundary_node(ibound);
761  for (unsigned inod=0;inod<num_nod;inod++)
762  {
763  Fluid_mesh_pt->boundary_node_pt(ibound, inod)->
764  set_auxiliary_node_update_fct_pt(
765  FSI_functions::apply_no_slip_on_moving_wall);
766  }
767  } // done automatic application of no-slip
768 
769  // Work out which fluid dofs affect the residuals of the wall elements:
770  // We pass the boundary between the fluid and solid meshes and
771  // pointers to the meshes. The interaction boundary are boundaries 5,6,7
772  // of the 2D fluid mesh.
773  FSI_functions::setup_fluid_load_info_for_solid_elements<FLUID_ELEMENT,2>
774  (this,5,Fluid_mesh_pt,Traction_mesh_pt[0]);
775 
776  FSI_functions::setup_fluid_load_info_for_solid_elements<FLUID_ELEMENT,2>
777  (this,6,Fluid_mesh_pt,Traction_mesh_pt[2]);
778 
779  FSI_functions::setup_fluid_load_info_for_solid_elements<FLUID_ELEMENT,2>
780  (this,7,Fluid_mesh_pt,Traction_mesh_pt[1]);
781  }
782 
783 
784  // Build solver/preconditioner
785  //----------------------------
786 
787  // Build iterative linear solver
788  GMRES<CRDoubleMatrix>* iterative_linear_solver_pt =
789  new GMRES<CRDoubleMatrix>;
790 
791  // Set maximum number of iterations
792  iterative_linear_solver_pt->max_iter() = 100;
793 
794  // Set tolerance
795  iterative_linear_solver_pt->tolerance() = 1.0e-10;
796 
797  // Assign solver
798  linear_solver_pt()=iterative_linear_solver_pt;
799 
800  // Build preconditioner
801  FSIPreconditioner* prec_pt=new FSIPreconditioner(this);
802 
803  // Set Navier Stokes mesh:
804  prec_pt->set_navier_stokes_mesh(Fluid_mesh_pt);
805 
806  // Set solid mesh:
807  prec_pt->set_wall_mesh(solid_mesh_pt());
808 
809  // Retain fluid onto solid terms
810  prec_pt->use_block_triangular_version_with_fluid_on_solid();
811 
812  // Set preconditioner
813  iterative_linear_solver_pt->preconditioner_pt()= prec_pt;
814 
815  // By default, the LSC Preconditioner uses SuperLU as
816  // an exact preconditioner (i.e. a solver) for the
817  // momentum and Schur complement blocks.
818  // Can overwrite this by passing pointers to
819  // other preconditioners that perform the (approximate)
820  // solves of these blocks.
821 
822 #ifdef OOMPH_HAS_HYPRE
823 //Only use HYPRE if we don't have MPI enabled
824 #ifndef OOMPH_HAS_MPI
825 
826  // Create internal preconditioners used on Schur block
827  Preconditioner* P_matrix_preconditioner_pt = new HyprePreconditioner;
828 
829  HyprePreconditioner* P_hypre_solver_pt =
830  static_cast<HyprePreconditioner*>(P_matrix_preconditioner_pt);
831 
832  // Set defaults parameters for use as preconditioner on Poisson-type
833  // problem
834  Hypre_default_settings::
835  set_defaults_for_2D_poisson_problem(P_hypre_solver_pt);
836 
837  // Use Hypre for the Schur complement block
838  prec_pt->navier_stokes_preconditioner_pt()->
839  set_p_preconditioner(P_matrix_preconditioner_pt);
840 
841  // Shut up
842  P_hypre_solver_pt->disable_doc_time();
843 
844 #endif
845 #endif
846 
847  // Assign equation numbers
848  cout << assign_eqn_numbers() << std::endl;
849 
850 
851 }//end_of_constructor
852 
853 
854 
855 //====start_of_actions_before_newton_convergence_check===================
856 /// Update the (enslaved) fluid node positions following the
857 /// update of the solid variables
858 //=======================================================================
859 template <class FLUID_ELEMENT,class SOLID_ELEMENT>
862 {
863  fluid_mesh_pt()->node_update();
864 }
865 
866 
867 
868 //===== start_of_actions_before_implicit_timestep=========================
869 /// Actions before implicit timestep: Update inflow profile
870 //========================================================================
871 template <class FLUID_ELEMENT,class SOLID_ELEMENT>
874 {
875  // Current time
876  double t=time_pt()->time();
877 
878  // Amplitude of flow
879  double ampl=Global_Parameters::flux(t);
880 
881  // Update parabolic flow along boundary 3
882  unsigned ibound=3;
883  unsigned num_nod= Fluid_mesh_pt->nboundary_node(ibound);
884  for (unsigned inod=0;inod<num_nod;inod++)
885  {
886  double ycoord = Fluid_mesh_pt->boundary_node_pt(ibound,inod)->x(1);
887  double uy = ampl*6.0*ycoord/Domain_height*(1.0-ycoord/Domain_height);
888  Fluid_mesh_pt->boundary_node_pt(ibound,inod)->set_value(0,uy);
889  Fluid_mesh_pt->boundary_node_pt(ibound,inod)->set_value(1,0.0);
890  }
891 
892 } //end_of_actions_before_implicit_timestep
893 
894 
895 //=====================start_of_actions_after_adapt=======================
896 /// Actions after adapt: Re-setup FSI
897 //========================================================================
898 template<class FLUID_ELEMENT,class SOLID_ELEMENT >
900 {
901  // Unpin all pressure dofs
902  RefineableNavierStokesEquations<2>::
903  unpin_all_pressure_dofs(fluid_mesh_pt()->element_pt());
904 
905  // Pin redundant pressure dofs
906  RefineableNavierStokesEquations<2>::
907  pin_redundant_nodal_pressures(fluid_mesh_pt()->element_pt());
908 
909  // Unpin all solid pressure dofs
910  PVDEquationsBase<2>::
911  unpin_all_solid_pressure_dofs(solid_mesh_pt()->element_pt());
912 
913  // Pin the redundant solid pressures (if any)
914  PVDEquationsBase<2>::pin_redundant_nodal_solid_pressures(
915  solid_mesh_pt()->element_pt());
916 
917 
918  // The velocity of the fluid nodes on the wall (fluid mesh boundary 5,6,7)
919  // is set by the wall motion -- hence the no-slip condition must be
920  // re-applied whenever a node update is performed for these nodes.
921  // Such tasks may be performed automatically by the auxiliary node update
922  // function specified by a function pointer:
924  {
925  for(unsigned ibound=5;ibound<8;ibound++ )
926  {
927  unsigned num_nod= Fluid_mesh_pt->nboundary_node(ibound);
928  for (unsigned inod=0;inod<num_nod;inod++)
929  {
930  Fluid_mesh_pt->boundary_node_pt(ibound, inod)->
931  set_auxiliary_node_update_fct_pt(
932  FSI_functions::apply_no_slip_on_moving_wall);
933  }
934  }
935 
936 
937  // Re-setup the fluid load information for fsi solid traction elements
938  FSI_functions::setup_fluid_load_info_for_solid_elements<FLUID_ELEMENT,2>
939  (this,5,Fluid_mesh_pt,Traction_mesh_pt[0]);
940 
941  FSI_functions::setup_fluid_load_info_for_solid_elements<FLUID_ELEMENT,2>
942  (this,6,Fluid_mesh_pt,Traction_mesh_pt[2]);
943 
944  FSI_functions::setup_fluid_load_info_for_solid_elements<FLUID_ELEMENT,2>
945  (this,7,Fluid_mesh_pt,Traction_mesh_pt[1]);
946  }
947 
948 
949 }// end of actions_after_adapt
950 
951 
952 
953 //============start_of_create_traction_elements==============================
954 /// Create FSI traction elements
955 //=======================================================================
956 template<class FLUID_ELEMENT,class SOLID_ELEMENT >
958 {
959 
960  // Container to collect all nodes in the traction meshes
961  std::set<SolidNode*> all_nodes;
962 
963  // Traction elements are located on boundaries 0-2:
964  for (unsigned b=0;b<3;b++)
965  {
966  // How many bulk elements are adjacent to boundary b?
967  unsigned n_element = solid_mesh_pt()->nboundary_element(b);
968 
969  // Loop over the bulk elements adjacent to boundary b?
970  for(unsigned e=0;e<n_element;e++)
971  {
972  // Get pointer to the bulk element that is adjacent to boundary b
973  SOLID_ELEMENT* bulk_elem_pt = dynamic_cast<SOLID_ELEMENT*>(
974  solid_mesh_pt()->boundary_element_pt(b,e));
975 
976  //What is the index of the face of the element e along boundary b
977  int face_index = solid_mesh_pt()->face_index_at_boundary(b,e);
978 
979  // Create new element and add to mesh
980  Traction_mesh_pt[b]->add_element_pt(
981  new FSISolidTractionElement<SOLID_ELEMENT,2>(bulk_elem_pt,face_index));
982 
983  } //end of loop over bulk elements adjacent to boundary b
984 
985  // Identify unique nodes
986  unsigned nnod=solid_mesh_pt()->nboundary_node(b);
987  for (unsigned j=0;j<nnod;j++)
988  {
989  all_nodes.insert(solid_mesh_pt()->boundary_node_pt(b,j));
990  }
991  }
992 
993  // Build combined mesh of fsi traction elements
995 
996  // Stick nodes into combined traction mesh
997  for (std::set<SolidNode*>::iterator it=all_nodes.begin();
998  it!=all_nodes.end();it++)
999  {
1000  Combined_traction_mesh_pt->add_node_pt(*it);
1001  }
1002 
1003 } // end of create_traction_elements
1004 
1005 
1006 
1007 
1008 //=====start_of_doc_solution========================================
1009 /// Doc the solution
1010 //==================================================================
1011 template<class FLUID_ELEMENT,class SOLID_ELEMENT >
1013  DocInfo& doc_info, ofstream& trace_file)
1014 {
1015 
1016 // FSI_functions::doc_fsi<AlgebraicNode>(Fluid_mesh_pt,
1017 // Combined_traction_mesh_pt,
1018 // doc_info);
1019 
1020 // pause("done");
1021 
1022  ofstream some_file;
1023  char filename[100];
1024 
1025  // Number of plot points
1026  unsigned n_plot = 5;
1027 
1028  // Output solid solution
1029  sprintf(filename,"%s/solid_soln%i.dat",doc_info.directory().c_str(),
1030  doc_info.number());
1031  some_file.open(filename);
1032  solid_mesh_pt()->output(some_file,n_plot);
1033  some_file.close();
1034 
1035  // Output fluid solution
1036  sprintf(filename,"%s/soln%i.dat",doc_info.directory().c_str(),
1037  doc_info.number());
1038  some_file.open(filename);
1039  fluid_mesh_pt()->output(some_file,n_plot);
1040  some_file.close();
1041 
1042 
1043 //Output the traction
1044  sprintf(filename,"%s/traction%i.dat",doc_info.directory().c_str(),
1045  doc_info.number());
1046  some_file.open(filename);
1047 // Loop over the traction meshes
1048  for(unsigned i=0;i<3;i++)
1049  {
1050  // Loop over the element in traction_mesh_pt
1051  unsigned n_element = Traction_mesh_pt[i]->nelement();
1052  for(unsigned e=0;e<n_element;e++)
1053  {
1054  FSISolidTractionElement<SOLID_ELEMENT,2>* el_pt =
1055  dynamic_cast<FSISolidTractionElement<SOLID_ELEMENT,2>* > (
1056  Traction_mesh_pt[i]->element_pt(e) );
1057 
1058  el_pt->output(some_file,5);
1059  }
1060  }
1061  some_file.close();
1062 
1063 
1064  // Write trace (we're only using Taylor Hood elements so we know that
1065  // the pressure is the third value at the fluid control node...
1066  trace_file << time_pt()->time() << " "
1067  << Solid_control_node_pt->x(0) << " "
1068  << Solid_control_node_pt->x(1) << " "
1069  << Fluid_control_node_pt->value(2) << " "
1070  << Global_Parameters::flux(time_pt()->time()) << " "
1071  << std::endl;
1072 
1073  cout << "Doced solution for step "
1074  << doc_info.number()
1075  << std::endl << std::endl << std::endl;
1076 
1077 }//end_of_doc_solution
1078 
1079 
1080 
1081 //=======start_of_main==================================================
1082 /// Driver
1083 //======================================================================
1084 int main(int argc, char* argv[])
1085 {
1086  // Store command line arguments
1087  CommandLineArgs::setup(argc,argv);
1088 
1089  // Get case id as string
1090  string case_id="FSI1";
1091  if (CommandLineArgs::Argc==1)
1092  {
1093  oomph_info << "No command line arguments; running self-test FSI1"
1094  << std::endl;
1095  }
1096  else if (CommandLineArgs::Argc==2)
1097  {
1098  case_id=CommandLineArgs::Argv[1];
1099  }
1100  else
1101  {
1102  oomph_info << "Wrong number of command line arguments" << std::endl;
1103  oomph_info << "Enter none (for default) or one (namely the case id"
1104  << std::endl;
1105  oomph_info << "which should be one of: FSI1, FSI2, FSI3, CSM1"
1106  << std::endl;
1107  }
1108  std::cout << "Running case " << case_id << std::endl;
1109 
1110  // Setup parameters for case identified by command line
1111  // argument
1113 
1114  // Prepare output
1115  DocInfo doc_info;
1116  ofstream trace_file;
1117  doc_info.set_directory("RESLT");
1118  trace_file.open("RESLT/trace.dat");
1119 
1120  // Length and height of domain
1121  double length=25.0;
1122  double height=4.1;
1123 
1124  //Set up the problem
1126  RefineableQPVDElement<2,3> > problem(length, height);
1127 
1128  // Default number of timesteps
1129  unsigned nstep=4000;
1130  if (Global_Parameters::Case_ID=="FSI1")
1131  {
1132  std::cout << "Reducing number of steps for FSI1 " << std::endl;
1133  nstep=400;
1134  }
1135 
1136  if (CommandLineArgs::Argc==1)
1137  {
1138  std::cout << "Reducing number of steps for validation " << std::endl;
1139  nstep=2;
1140  }
1141 
1142  //Timestep:
1143  double dt=Global_Parameters::Dt;
1144 
1145  // Initialise timestep
1146  problem.initialise_dt(dt);
1147 
1148  // Impulsive start
1149  problem.assign_initial_values_impulsive(dt);
1150 
1151  // Doc the initial condition
1152  problem.doc_solution(doc_info,trace_file);
1153  doc_info.number()++;
1154 
1155  // Don't re-set the initial conditions when adapting during first
1156  // timestep
1157  bool first = false;
1158 
1159  // Max number of adaptation for time-stepping
1160  unsigned max_adapt=1;
1161 
1162  for(unsigned i=0;i<nstep;i++)
1163  {
1164  // Solve the problem
1165  problem.unsteady_newton_solve(dt,max_adapt,first);
1166 
1167  // Output the solution
1168  problem.doc_solution(doc_info,trace_file);
1169 
1170  // Step number
1171  doc_info.number()++;
1172  }
1173 
1174  trace_file.close();
1175 
1176 }//end of main
1177 
1178 
1179 
1180 
1181 
1182 
1183 
1184 
double Centre_x
x position of centre of cylinder
Definition: turek_flag.cc:82
Node * Solid_control_node_pt
Pointer to solid control node.
Definition: turek_flag.cc:438
double Q
FSI parameter (default assignment for FSI1 test case)
Definition: turek_flag.cc:72
SolidMesh *& traction_mesh_pt(const unsigned &i)
Access function for the i-th mesh of FSI traction elements.
Definition: turek_flag.cc:391
ElasticRefineableRectangularQuadMesh< SOLID_ELEMENT > *& solid_mesh_pt()
Access function for the solid mesh.
Definition: turek_flag.cc:387
void actions_before_implicit_timestep()
Update the time-dependent influx.
Definition: turek_flag.cc:873
double Min_flux
Min. flux.
Definition: turek_flag.cc:125
double Centre_y
y position of centre of cylinder
Definition: turek_flag.cc:85
void actions_before_newton_solve()
Update function (empty)
Definition: turek_flag.cc:404
double Ramp_period
Period for ramping up in flux.
Definition: turek_flag.cc:122
Node * Fluid_control_node_pt
Pointer to fluid control node.
Definition: turek_flag.cc:441
Vector< SolidMesh * > Traction_mesh_pt
Vector of pointers to mesh of FSI traction elements.
Definition: turek_flag.cc:426
void actions_after_newton_solve()
Update function (empty)
Definition: turek_flag.cc:401
double Density_ratio
Density ratio (solid to fluid; default assignment for FSI1 test case)
Definition: turek_flag.cc:76
int main(int argc, char *argv[])
Driver.
Definition: turek_flag.cc:1084
double flux(const double &t)
Flux increases between Min_flux and Max_flux over period Ramp_period.
Definition: turek_flag.cc:132
string Case_ID
Default case ID.
Definition: turek_flag.cc:59
double Domain_height
Overall height of domain.
Definition: turek_flag.cc:432
double St
Strouhal number (default assignment for FSI1 test case)
Definition: turek_flag.cc:65
double E
Elastic modulus.
Definition: turek_flag.cc:104
double Gravity
Non-dim gravity (default assignment for FSI1 test case)
Definition: turek_flag.cc:110
void set_parameters(const string &case_id)
Set parameters for the various test cases.
Definition: turek_flag.cc:147
ElasticRefineableRectangularQuadMesh< SOLID_ELEMENT > * Solid_mesh_pt
Pointer to solid mesh.
Definition: turek_flag.cc:420
Global variables.
Definition: turek_flag.cc:55
double Lambda_sq
Timescale ratio for solid (dependent parameter assigned in set_parameters())
Definition: turek_flag.cc:95
RefineableAlgebraicCylinderWithFlagMesh< FLUID_ELEMENT > * Fluid_mesh_pt
Pointer to fluid mesh.
Definition: turek_flag.cc:423
void create_fsi_traction_elements()
Create FSI traction elements.
Definition: turek_flag.cc:957
void doc_solution(DocInfo &doc_info, ofstream &trace_file)
Doc the solution.
Definition: turek_flag.cc:1012
void actions_before_newton_convergence_check()
Update the (enslaved) fluid node positions following the update of the solid variables before perform...
Definition: turek_flag.cc:861
double Nu
Poisson&#39;s ratio.
Definition: turek_flag.cc:107
double ReSt
Product of Reynolds and Strouhal numbers (default assignment for FSI1 test case)
Definition: turek_flag.cc:69
bool Ignore_fluid_loading
Ignore fluid (default assignment for FSI1 test case)
Definition: turek_flag.cc:101
double Domain_length
Overall length of domain.
Definition: turek_flag.cc:435
RefineableAlgebraicCylinderWithFlagMesh< FLUID_ELEMENT > * fluid_mesh_pt()
Access function for the fluid mesh.
Definition: turek_flag.cc:383
void gravity(const double &time, const Vector< double > &xi, Vector< double > &b)
Non-dimensional gravity as body force.
Definition: turek_flag.cc:113
double H
Height of flag.
Definition: turek_flag.cc:79
double Max_flux
Max. flux.
Definition: turek_flag.cc:128
TurekProblem(const double &length, const double &height)
Constructor: Pass length and height of domain.
Definition: turek_flag.cc:451
SolidMesh * Combined_traction_mesh_pt
Combined mesh of traction elements – only used for documentation.
Definition: turek_flag.cc:429
void actions_after_adapt()
Actions after adapt: Re-setup the fsi lookup scheme.
Definition: turek_flag.cc:899
ConstitutiveLaw * Constitutive_law_pt
Pointer to constitutive law.
Definition: turek_flag.cc:91
double Radius
Radius of cylinder.
Definition: turek_flag.cc:88
double Re
Reynolds number (default assignment for FSI1 test case)
Definition: turek_flag.cc:62
Problem class.
Definition: turek_flag.cc:374
double Dt
Timestep.
Definition: turek_flag.cc:98