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