unstructured_three_d_fsi.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 // Driver code for a simple unstructured fsi problem using meshes
31 // generated from input files generated by the 3d mesh generator
32 // tetgen.
33 
34 //Generic libraries
35 #include "generic.h"
36 #include "solid.h"
37 #include "constitutive.h"
38 #include "navier_stokes.h"
39 
40 // Get the mesh
41 #include "meshes/tetgen_mesh.h"
42 
43 using namespace std;
44 using namespace oomph;
45 
46 
47 
48 //==========start_solid_mesh===============================================
49 /// Tetgen-based mesh upgraded to become a solid mesh
50 //=========================================================================
51 template<class ELEMENT>
52 class MySolidTetgenMesh : public virtual TetgenMesh<ELEMENT>,
53  public virtual SolidMesh
54 {
55 
56 public:
57 
58  /// Constructor:
59  MySolidTetgenMesh(const std::string& node_file_name,
60  const std::string& element_file_name,
61  const std::string& face_file_name,
62  TimeStepper* time_stepper_pt=
63  &Mesh::Default_TimeStepper) :
64  TetgenMesh<ELEMENT>(node_file_name, element_file_name,
65  face_file_name, time_stepper_pt)
66  {
67  //Assign the Lagrangian coordinates
68  set_lagrangian_nodal_coordinates();
69 
70  // Find elements next to boundaries
71  setup_boundary_element_info();
72 
73  // Setup boundary coordinates for all boundaries
74  char filename[100];
75  ofstream some_file;
76  unsigned nb=this->nboundary();
77  for (unsigned b=0;b<nb;b++)
78  {
79  sprintf(filename,"RESLT/solid_boundary_test%i.dat",b);
80  some_file.open(filename);
81  this->template setup_boundary_coordinates<ELEMENT>(b,some_file);
82  some_file.close();
83  }
84 
85  }
86 
87  /// Empty Destructor
88  virtual ~MySolidTetgenMesh() { }
89 
90 };
91 
92 ///////////////////////////////////////////////////////////////////////
93 ///////////////////////////////////////////////////////////////////////
94 ///////////////////////////////////////////////////////////////////////
95 
96 
97 
98 //==============start_fluid_mesh===========================================
99 /// Tetgen-based mesh upgraded to become a (pseudo-) solid mesh
100 //=========================================================================
101 template<class ELEMENT>
102 class FluidTetMesh : public virtual TetgenMesh<ELEMENT>,
103  public virtual SolidMesh
104 {
105 
106 public:
107 
108  /// \short Constructor:
109  FluidTetMesh(const std::string& node_file_name,
110  const std::string& element_file_name,
111  const std::string& face_file_name,
112  const bool& split_corner_elements,
113  TimeStepper* time_stepper_pt=
114  &Mesh::Default_TimeStepper) :
115  TetgenMesh<ELEMENT>(node_file_name, element_file_name,
116  face_file_name, split_corner_elements,
117  time_stepper_pt)
118  {
119  //Assign the Lagrangian coordinates
120  set_lagrangian_nodal_coordinates();
121 
122  // Find out elements next to boundary
123  setup_boundary_element_info();
124 
125  // Setup boundary coordinates for boundary.
126  // To be consistent with the boundary coordinates generated
127  // in the solid, we switch the direction of the normal.
128  // (Both meshes are generated from the same polygonal facets
129  // at the FSI interface).
130  bool switch_normal=true;
131 
132  // Setup boundary coordinates for all boundaries
133  char filename[100];
134  ofstream some_file;
135  unsigned nb=this->nboundary();
136  for (unsigned b=0;b<nb;b++)
137  {
138  sprintf(filename,"RESLT/fluid_boundary_test%i.dat",b);
139  some_file.open(filename);
140  this->template setup_boundary_coordinates<ELEMENT>(b,switch_normal,some_file);
141  some_file.close();
142  }
143 
144  }
145 
146  /// Empty Destructor
147  virtual ~FluidTetMesh() { }
148 
149 };
150 
151 
152 //////////////////////////////////////////////////////////////////
153 //////////////////////////////////////////////////////////////////
154 //////////////////////////////////////////////////////////////////
155 
156 
157 //=======start_of_namespace==========================================
158 /// Global variables
159 //================================================================
161 {
162 
163  /// Default Reynolds number
164  double Re=100.0;
165 
166  /// Default FSI parameter
167  double Q=0.0;
168 
169  /// Pointer to constitutive law
170  ConstitutiveLaw* Constitutive_law_pt=0;
171 
172  /// Poisson's ratio for generalised Hookean constitutive equation
173  double Nu=0.3;
174 
175  /// Fluid pressure on inflow boundary
176  double P_in=0.5;
177 
178  /// Applied traction on fluid at the inflow boundary
179  void prescribed_inflow_traction(const double& t,
180  const Vector<double>& x,
181  const Vector<double>& n,
182  Vector<double>& traction)
183  {
184  traction[0]=0.0;
185  traction[1]=0.0;
186  traction[2]=P_in;
187  }
188 
189 
190  /// Fluid pressure on outflow boundary
191  double P_out=-0.5;
192 
193  /// Applied traction on fluid at the inflow boundary
194  void prescribed_outflow_traction(const double& t,
195  const Vector<double>& x,
196  const Vector<double>& n,
197  Vector<double>& traction)
198  {
199  traction[0]=0.0;
200  traction[1]=0.0;
201  traction[2]=-P_out;
202  }
203 
204 
205 } //end_of_namespace
206 
207 
208 
209 
210 
211 
212 //===============start_of_problem_class===============================
213 /// Unstructured 3D FSI problem
214 //====================================================================
215 template<class FLUID_ELEMENT, class SOLID_ELEMENT>
216 class UnstructuredFSIProblem : public Problem
217 {
218 
219 public:
220 
221  /// Constructor:
223 
224  /// Destructor (empty)
226 
227  /// Doc the solution
228  void doc_solution(DocInfo& doc_info);
229 
230  /// Create fluid traction elements at inflow
231  void create_fluid_traction_elements();
232 
233  /// Create FSI traction elements
234  void create_fsi_traction_elements();
235 
236  /// \short Create elements that enforce prescribed boundary motion
237  /// for the pseudo-solid fluid mesh by Lagrange multipliers
238  void create_lagrange_multiplier_elements();
239 
240 
241 private:
242 
243  /// Sanity check: Doc boundary coordinates on i-th solid FSI interface
244  void doc_solid_boundary_coordinates(const unsigned& i);
245 
246  /// \short Return total number of mesh boundaries that make up the inflow
247  /// boundary
249  {return Inflow_boundary_id.size();}
250 
251  /// \short Return total number of mesh boundaries that make up the outflow
252  /// boundary
254  {return Outflow_boundary_id.size();}
255 
256  /// \short Return total number of mesh boundaries that make up the
257  /// in- and outflow boundaries where a traction has to be applied
259  {return Inflow_boundary_id.size()+Outflow_boundary_id.size();}
260 
261  /// \short Return total number of mesh boundaries in the solid mesh that
262  /// make up the FSI interface
264  {return Solid_fsi_boundary_id.size();}
265 
266  /// \short Return total number of mesh boundaries in the fluid mesh that
267  /// make up the FSI interface
269  {return Fluid_fsi_boundary_id.size();}
270 
271  /// \short Return total number of mesh boundaries in the solid mesh
272  /// where the position is pinned.
274  {return Pinned_solid_boundary_id.size();}
275  //end npinned_solid_boundary
276 
277 
278  /// Bulk solid mesh
280 
281  /// Meshes of FSI traction elements
282  Vector<SolidMesh*> Solid_fsi_traction_mesh_pt;
283 
284  /// Bulk fluid mesh
286 
287  /// Meshes of fluid traction elements that apply pressure at in/outflow
288  Vector<Mesh*> Fluid_traction_mesh_pt;
289 
290  /// Meshes of Lagrange multiplier elements
291  Vector<SolidMesh*> Lagrange_multiplier_mesh_pt;
292 
293  /// GeomObject incarnations of the FSI boundary in the solid mesh
294  Vector<MeshAsGeomObject*>
296 
297  /// IDs of solid mesh boundaries where displacements are pinned
298  Vector<unsigned> Pinned_solid_boundary_id;
299 
300  /// \short IDs of solid mesh boundaries which make up the FSI interface
301  Vector<unsigned> Solid_fsi_boundary_id;
302 
303  /// \short IDs of fluid mesh boundaries along which inflow boundary conditions
304  /// are applied
305  Vector<unsigned> Inflow_boundary_id;
306 
307  /// \short IDs of fluid mesh boundaries along which inflow boundary conditions
308  /// are applied
309  Vector<unsigned> Outflow_boundary_id;
310 
311  /// \short IDs of fluid mesh boundaries which make up the FSI interface
312  Vector<unsigned> Fluid_fsi_boundary_id;
313 
314 };
315 
316 
317 
318 //==========start_of_constructor==========================================
319 /// Constructor for unstructured 3D FSI problem
320 //========================================================================
321 template<class FLUID_ELEMENT, class SOLID_ELEMENT>
323 {
324  // Define fluid mesh and its distinguished boundaries
325  //---------------------------------------------------
326 
327  //Create fluid bulk mesh, sub-dividing "corner" elements
328  string node_file_name="fsi_bifurcation_fluid.1.node";
329  string element_file_name="fsi_bifurcation_fluid.1.ele";
330  string face_file_name="fsi_bifurcation_fluid.1.face";
331  bool split_corner_elements=true;
332  Fluid_mesh_pt = new FluidTetMesh<FLUID_ELEMENT>(node_file_name,
333  element_file_name,
334  face_file_name,
335  split_corner_elements);
336 
337 
338  // The following corresponds to the boundaries as specified by
339  // facets in the tetgen input:
340 
341  // Fluid mesh has one inflow boundary: Boundary 0
342  Inflow_boundary_id.resize(1);
343  Inflow_boundary_id[0]=0;
344 
345  // Fluid mesh has two outflow boundaries: Boundaries 1 and 2
346  Outflow_boundary_id.resize(2);
347  Outflow_boundary_id[0]=1;
348  Outflow_boundary_id[1]=2;
349 
350  // The remaining fluid boundaries are FSI boundaries.
351  // Note that their order (as indexed in this vector, not
352  // their actual numbers) have to match those in the corresponding
353  // lookup scheme for the solid.
354  Fluid_fsi_boundary_id.resize(12);
355  for (unsigned i=0;i<12;i++)
356  {
357  Fluid_fsi_boundary_id[i]=i+3;
358  }
359 
360 
361  // Define solid mesh and its distinguished boundaries
362  //---------------------------------------------------
363 
364  //Create solid bulk mesh
365  node_file_name="fsi_bifurcation_solid.1.node";
366  element_file_name="fsi_bifurcation_solid.1.ele";
367  face_file_name="fsi_bifurcation_solid.1.face";
368  Solid_mesh_pt = new MySolidTetgenMesh<SOLID_ELEMENT>(node_file_name,
369  element_file_name,
370  face_file_name);
371 
372  // The following corresponds to the boundaries as specified by
373  // facets in the tetgen input:
374 
375  /// IDs of solid mesh boundaries where displacements are pinned
376  Pinned_solid_boundary_id.resize(3);
377  Pinned_solid_boundary_id[0]=0;
378  Pinned_solid_boundary_id[1]=1;
379  Pinned_solid_boundary_id[2]=2;
380 
381  // The solid and fluid fsi boundaries are numbered int he same way.
382  Solid_fsi_boundary_id.resize(12);
383  for (unsigned i=0;i<12;i++)
384  {
385  Solid_fsi_boundary_id[i]=i+3;
386  }
387 
388 
389 
390  // Create (empty) meshes of fluid traction elements at inflow/outflow
391  //-----------------------------------------------------------
392 
393  // Create the meshes
394  unsigned n=nfluid_traction_boundary();
395  Fluid_traction_mesh_pt.resize(n);
396  for (unsigned i=0;i<n;i++)
397  {
398  Fluid_traction_mesh_pt[i]=new Mesh;
399  }
400 
401  // Populate them with elements
402  create_fluid_traction_elements();
403 
404 
405 // Create FSI Traction elements
406 //-----------------------------
407 
408 // Create (empty) meshes of FSI traction elements
409  n=nsolid_fsi_boundary();
410  Solid_fsi_traction_mesh_pt.resize(n);
411  for (unsigned i=0;i<n;i++)
412  {
413  Solid_fsi_traction_mesh_pt[i]=new SolidMesh;
414  }
415 
416  // Build the FSI traction elements
417  create_fsi_traction_elements();
418 
419 
420  // Create Lagrange multiplier mesh for boundary motion of fluid mesh
421  //------------------------------------------------------------------
422 
423  // Construct the mesh of elements that enforce prescribed boundary motion
424  // of pseudo-solid fluid mesh by Lagrange multipliers
425  n=nfluid_fsi_boundary();
426  Lagrange_multiplier_mesh_pt.resize(n);
427  for (unsigned i=0;i<n;i++)
428  {
429  Lagrange_multiplier_mesh_pt[i]=new SolidMesh;
430  }
431 
432  // Create elements
433  create_lagrange_multiplier_elements();
434 
435 
436  // Combine the lot
437  //----------------
438 
439  // Add sub meshes:
440 
441  // The solid bulk mesh
442  add_sub_mesh(Solid_mesh_pt);
443 
444  // Fluid bulk mesh
445  add_sub_mesh(Fluid_mesh_pt);
446 
447  // The fluid traction meshes
448  n=nfluid_traction_boundary();
449  for (unsigned i=0;i<n;i++)
450  {
451  add_sub_mesh(Fluid_traction_mesh_pt[i]);
452  }
453 
454  // The solid fsi traction meshes
455  n=nsolid_fsi_boundary();
456  for (unsigned i=0;i<n;i++)
457  {
458  add_sub_mesh(Solid_fsi_traction_mesh_pt[i]);
459  }
460 
461  // The Lagrange multiplier meshes for the fluid
462  n=nfluid_fsi_boundary();
463  for (unsigned i=0;i<n;i++)
464  {
465  add_sub_mesh(Lagrange_multiplier_mesh_pt[i]);
466  }
467 
468  // Build global mesh
469  build_global_mesh();
470 
471 
472 
473 
474  // Apply BCs for fluid
475  //--------------------
476 
477  // Doc position of pinned pseudo solid nodes
478  std::ofstream pseudo_solid_bc_file("RESLT/pinned_pseudo_solid_nodes.dat");
479 
480  // Loop over inflow/outflow boundaries to impose parallel flow
481  // and pin pseudo-solid displacements
482  for (unsigned in_out=0;in_out<2;in_out++)
483  {
484  // Loop over in/outflow boundaries
485  unsigned n=nfluid_inflow_traction_boundary();
486  if (in_out==1) n=nfluid_outflow_traction_boundary();
487  for (unsigned i=0;i<n;i++)
488  {
489 
490  // Get boundary ID
491  unsigned b=0;
492  if (in_out==0)
493  {
494  b=Inflow_boundary_id[i];
495  }
496  else
497  {
498  b=Outflow_boundary_id[i];
499  }
500 
501  // Number of nodes on that boundary
502  unsigned num_nod=Fluid_mesh_pt->nboundary_node(b);
503  for (unsigned inod=0;inod<num_nod;inod++)
504  {
505  // Get the node
506  SolidNode* nod_pt=Fluid_mesh_pt->boundary_node_pt(b,inod);
507 
508  // Pin transverse velocities
509  nod_pt->pin(0);
510  nod_pt->pin(1);
511 
512  // Pin the nodal (pseudo-solid) displacements
513  for(unsigned i=0;i<3;i++)
514  {
515  nod_pt->pin_position(i);
516 
517  // Doc it as pinned
518  pseudo_solid_bc_file << nod_pt->x(i) << " ";
519  }
520  }
521  }
522  }
523 
524  // Close
525  pseudo_solid_bc_file.close();
526 
527  // Doc bcs for Lagrange multipliers
528  ofstream pinned_file("RESLT/pinned_lagrange_multiplier_nodes.dat");
529 
530  // Loop over all fluid mesh boundaries and pin velocities
531  // of nodes that haven't been dealt with yet
532  unsigned nbound=nfluid_fsi_boundary();
533  for(unsigned i=0;i<nbound;i++)
534  {
535  //Get the mesh boundary
536  unsigned b = Fluid_fsi_boundary_id[i];
537 
538  unsigned num_nod=Fluid_mesh_pt->nboundary_node(b);
539  for (unsigned inod=0;inod<num_nod;inod++)
540  {
541  // Get node
542  Node* nod_pt= Fluid_mesh_pt->boundary_node_pt(b,inod);
543 
544  // Pin all velocities
545  nod_pt->pin(0);
546  nod_pt->pin(1);
547  nod_pt->pin(2);
548 
549  // Find out whether node is also on in/outflow
550  bool is_in_or_outflow_node=false;
551  unsigned n=nfluid_inflow_traction_boundary();
552  for (unsigned k=0;k<n;k++)
553  {
554  if (nod_pt->is_on_boundary(Inflow_boundary_id[k]))
555  {
556  is_in_or_outflow_node=true;
557  break;
558  }
559  }
560  if (!is_in_or_outflow_node)
561  {
562  unsigned n=nfluid_outflow_traction_boundary();
563  for (unsigned k=0;k<n;k++)
564  {
565  if (nod_pt->is_on_boundary(Outflow_boundary_id[k]))
566  {
567  is_in_or_outflow_node=true;
568  break;
569  }
570  }
571  }
572 
573  // Pin the Lagrange multipliers on the out/in-flow boundaries
574  if (is_in_or_outflow_node)
575  {
576  //Cast to a boundary node
577  BoundaryNode<SolidNode> *bnod_pt =
578  dynamic_cast<BoundaryNode<SolidNode>*>
579  ( Fluid_mesh_pt->boundary_node_pt(b,inod) );
580 
581  // Loop over the Lagrange multipliers
582  for (unsigned l=0;l<3;l++)
583  {
584  // Pin the Lagrange multipliers that impose the displacement
585  // because the positon of the fluid nodes at the in/outflow
586  // is already determined.
587  nod_pt->pin
588  (bnod_pt->index_of_first_value_assigned_by_face_element()+l);
589  }
590 
591  // Doc that we've pinned the Lagrange multipliers at this node
592  pinned_file << nod_pt->x(0) << " "
593  << nod_pt->x(1) << " "
594  << nod_pt->x(2) << endl;
595  }
596  }
597 
598  } // done no slip on fsi boundary
599 
600  // Done
601  pinned_file.close();
602 
603  // Complete the build of the fluid elements so they are fully functional
604  //----------------------------------------------------------------------
605  unsigned n_element = Fluid_mesh_pt->nelement();
606  for(unsigned e=0;e<n_element;e++)
607  {
608  // Upcast from GeneralisedElement to the present element
609  FLUID_ELEMENT* el_pt =
610  dynamic_cast<FLUID_ELEMENT*>(Fluid_mesh_pt->element_pt(e));
611 
612  //Set the Reynolds number
613  el_pt->re_pt() = &Global_Parameters::Re;
614 
615  // Set the constitutive law for pseudo-elastic mesh deformation
616  el_pt->constitutive_law_pt() =
618 
619  } // end loop over elements
620 
621 
622 
623  // Apply BCs for solid
624  //--------------------
625 
626  // Doc pinned solid nodes
627  std::ofstream bc_file("RESLT/pinned_solid_nodes.dat");
628 
629  // Pin positions at inflow boundary (boundaries 0 and 1)
630  n=npinned_solid_boundary();
631  for (unsigned i=0;i<n;i++)
632  {
633  // Get boundary ID
634  unsigned b=Pinned_solid_boundary_id[i];
635  unsigned num_nod= Solid_mesh_pt->nboundary_node(b);
636  for (unsigned inod=0;inod<num_nod;inod++)
637  {
638  // Get node
639  SolidNode* nod_pt=Solid_mesh_pt->boundary_node_pt(b,inod);
640 
641  // Pin all directions
642  for (unsigned i=0;i<3;i++)
643  {
644  nod_pt->pin_position(i);
645 
646  // ...and doc it as pinned
647  bc_file << nod_pt->x(i) << " ";
648  }
649 
650  bc_file << std::endl;
651  }
652  }
653  bc_file.close();
654 
655 
656 
657  // Complete the build of Solid elements so they are fully functional
658  //----------------------------------------------------------------
659  n_element = Solid_mesh_pt->nelement();
660  for(unsigned i=0;i<n_element;i++)
661  {
662  //Cast to a solid element
663  SOLID_ELEMENT *el_pt = dynamic_cast<SOLID_ELEMENT*>(
664  Solid_mesh_pt->element_pt(i));
665 
666  // Set the constitutive law
667  el_pt->constitutive_law_pt() =
669  }
670 
671 
672  // Setup FSI
673  //----------
674 
675  // Work out which fluid dofs affect the residuals of the wall elements:
676  // We pass the boundary between the fluid and solid meshes and
677  // pointers to the meshes.
678  n=nsolid_fsi_boundary();
679  for (unsigned i=0;i<n;i++)
680  {
681  // Sanity check: Doc boundary coordinates from solid side
682  doc_solid_boundary_coordinates(i);
683 
684  //Doc boundary coordinates in fluid
685  char filename[100];
686  sprintf(filename,"RESLT/fluid_boundary_coordinates%i.dat",i);
687  Multi_domain_functions::Doc_boundary_coordinate_file.open(filename);
688 
689  // Setup FSI: Pass ID of fluid FSI boundary and associated
690  // mesh of solid fsi traction elements.
691  FSI_functions::setup_fluid_load_info_for_solid_elements<FLUID_ELEMENT,3>
692  (this,Fluid_fsi_boundary_id[i],Fluid_mesh_pt,Solid_fsi_traction_mesh_pt[i]);
693 
694  // Close the doc file
695  Multi_domain_functions::Doc_boundary_coordinate_file.close();
696  }
697 
698  // Setup equation numbering scheme
699  std::cout <<"Number of equations: " << assign_eqn_numbers() << std::endl;
700 
701 }
702 
703 
704 //============start_of_create_fsi_traction_elements======================
705 /// Create FSI traction elements
706 //=======================================================================
707 template<class FLUID_ELEMENT,class SOLID_ELEMENT>
710 {
711 
712  // Loop over FSI boundaries in solid
713  unsigned n=nsolid_fsi_boundary();
714  for (unsigned i=0;i<n;i++)
715  {
716  // Get boundary ID
717  unsigned b=Solid_fsi_boundary_id[i];
718 
719  // How many bulk elements are adjacent to boundary b?
720  unsigned n_element = Solid_mesh_pt->nboundary_element(b);
721 
722  // Loop over the bulk elements adjacent to boundary b
723  for(unsigned e=0;e<n_element;e++)
724  {
725  // Get pointer to the bulk element that is adjacent to boundary b
726  SOLID_ELEMENT* bulk_elem_pt = dynamic_cast<SOLID_ELEMENT*>(
727  Solid_mesh_pt->boundary_element_pt(b,e));
728 
729  //What is the index of the face of the element e along boundary b
730  int face_index = Solid_mesh_pt->face_index_at_boundary(b,e);
731 
732  // Create new element
733  FSISolidTractionElement<SOLID_ELEMENT,3>* el_pt=
734  new FSISolidTractionElement<SOLID_ELEMENT,3>(bulk_elem_pt,face_index);
735 
736  // Add it to the mesh
737  Solid_fsi_traction_mesh_pt[i]->add_element_pt(el_pt);
738 
739  // Specify boundary number
740  el_pt->set_boundary_number_in_bulk_mesh(b);
741 
742  // Function that specifies the load ratios
743  el_pt->q_pt() = &Global_Parameters::Q;
744  }
745  }
746 
747 } // end of create_fsi_traction_elements
748 
749 
750 //============start_of_create_lagrange_multiplier_elements===============
751 /// Create elements that impose the prescribed boundary displacement
752 /// for the pseudo-solid fluid mesh
753 //=======================================================================
754 template<class FLUID_ELEMENT, class SOLID_ELEMENT>
757 {
758  // Make space
759  unsigned n=nfluid_fsi_boundary();
760  Solid_fsi_boundary_pt.resize(n);
761 
762  // Loop over FSI interfaces in fluid
763  for (unsigned i=0;i<n;i++)
764  {
765  // Get boundary ID
766  unsigned b=Fluid_fsi_boundary_id[i];
767 
768  // Create GeomObject incarnation of fsi boundary in solid mesh
769  Solid_fsi_boundary_pt[i]=
770  new MeshAsGeomObject
771  (Solid_fsi_traction_mesh_pt[i]);
772 
773  // How many bulk fluid elements are adjacent to boundary b?
774  unsigned n_element = Fluid_mesh_pt->nboundary_element(b);
775 
776  // Loop over the bulk fluid elements adjacent to boundary b?
777  for(unsigned e=0;e<n_element;e++)
778  {
779  // Get pointer to the bulk fluid element that is adjacent to boundary b
780  FLUID_ELEMENT* bulk_elem_pt = dynamic_cast<FLUID_ELEMENT*>(
781  Fluid_mesh_pt->boundary_element_pt(b,e));
782 
783  //Find the index of the face of element e along boundary b
784  int face_index = Fluid_mesh_pt->face_index_at_boundary(b,e);
785 
786  // Create new element
787  ImposeDisplacementByLagrangeMultiplierElement<FLUID_ELEMENT>* el_pt =
788  new ImposeDisplacementByLagrangeMultiplierElement<FLUID_ELEMENT>(
789  bulk_elem_pt,face_index);
790 
791  // Add it to the mesh
792  Lagrange_multiplier_mesh_pt[i]->add_element_pt(el_pt);
793 
794  // Set the GeomObject that defines the boundary shape and set
795  // which bulk boundary we are attached to (needed to extract
796  // the boundary coordinate from the bulk nodes)
797  el_pt->set_boundary_shape_geom_object_pt(Solid_fsi_boundary_pt[i],b);
798  }
799  }
800 
801 } // end of create_lagrange_multiplier_elements
802 
803 
804 
805 //============start_of_fluid_traction_elements==============================
806 /// Create fluid traction elements
807 //=======================================================================
808 template<class FLUID_ELEMENT,class SOLID_ELEMENT>
811 {
812 
813  // Counter for number of fluid traction meshes
814  unsigned count=0;
815 
816  // Loop over inflow/outflow boundaries
817  for (unsigned in_out=0;in_out<2;in_out++)
818  {
819  // Loop over boundaries with fluid traction elements
820  unsigned n=nfluid_inflow_traction_boundary();
821  if (in_out==1) n=nfluid_outflow_traction_boundary();
822  for (unsigned i=0;i<n;i++)
823  {
824 
825  // Get boundary ID
826  unsigned b=0;
827  if (in_out==0)
828  {
829  b=Inflow_boundary_id[i];
830  }
831  else
832  {
833  b=Outflow_boundary_id[i];
834  }
835 
836  // How many bulk elements are adjacent to boundary b?
837  unsigned n_element = Fluid_mesh_pt->nboundary_element(b);
838 
839  // Loop over the bulk elements adjacent to boundary b
840  for(unsigned e=0;e<n_element;e++)
841  {
842  // Get pointer to the bulk element that is adjacent to boundary b
843  FLUID_ELEMENT* bulk_elem_pt = dynamic_cast<FLUID_ELEMENT*>(
844  Fluid_mesh_pt->boundary_element_pt(b,e));
845 
846  //What is the index of the face of the element e along boundary b
847  int face_index = Fluid_mesh_pt->face_index_at_boundary(b,e);
848 
849  // Create new element
850  NavierStokesTractionElement<FLUID_ELEMENT>* el_pt=
851  new NavierStokesTractionElement<FLUID_ELEMENT>(bulk_elem_pt,
852  face_index);
853 
854  // Add it to the mesh
855  Fluid_traction_mesh_pt[count]->add_element_pt(el_pt);
856 
857  // Set the pointer to the prescribed traction function
858  if (in_out==0)
859  {
860  el_pt->traction_fct_pt() =
862  }
863  else
864  {
865  el_pt->traction_fct_pt() =
867  }
868  }
869  // Bump up counter
870  count++;
871  }
872  }
873 
874  } // end of create_traction_elements
875 
876 
877 //============start_doc_solid_zeta=======================================
878 /// Doc boundary coordinates of i-th solid FSI boundary.
879 //=======================================================================
880 template<class FLUID_ELEMENT,class SOLID_ELEMENT>
883 {
884 
885  //Doc boundary coordinates in fluid
886  char filename[100];
887  sprintf(filename,"RESLT/solid_boundary_coordinates%i.dat",i);
888  std::ofstream the_file(filename);
889 
890  // Loop over traction elements
891  unsigned n_face_element = Solid_fsi_traction_mesh_pt[i]->nelement();
892  for(unsigned e=0;e<n_face_element;e++)
893  {
894  //Cast the element pointer
895  FSISolidTractionElement<SOLID_ELEMENT,3>* el_pt=
896  dynamic_cast<FSISolidTractionElement<SOLID_ELEMENT,3>*>
897  (Solid_fsi_traction_mesh_pt[i]->element_pt(e));
898 
899  // Doc boundary coordinate
900  Vector<double> s(2);
901  Vector<double> zeta(2);
902  Vector<double> x(3);
903  unsigned n_plot=3;
904  the_file << el_pt->tecplot_zone_string(n_plot);
905 
906  // Loop over plot points
907  unsigned num_plot_points=el_pt->nplot_points(n_plot);
908  for (unsigned iplot=0;iplot<num_plot_points;iplot++)
909  {
910  // Get local coordinates of plot point
911  el_pt->get_s_plot(iplot,n_plot,s);
912  el_pt->interpolated_zeta(s,zeta);
913  el_pt->interpolated_x(s,x);
914  for (unsigned i=0;i<3;i++)
915  {
916  the_file << x[i] << " ";
917  }
918  for (unsigned i=0;i<2;i++)
919  {
920  the_file << zeta[i] << " ";
921  }
922 
923  the_file << std::endl;
924  }
925  el_pt->write_tecplot_zone_footer(the_file,n_plot);
926  }
927 
928  // Close doc file
929  the_file.close();
930 
931 } // end doc_solid_zeta
932 
933 
934 //========start_of_doc_solution===========================================
935 /// Doc the solution
936 //========================================================================
937 template<class FLUID_ELEMENT, class SOLID_ELEMENT>
939 doc_solution(DocInfo& doc_info)
940 {
941 
942  ofstream some_file;
943  char filename[100];
944 
945  // Number of plot points
946  unsigned npts;
947  npts=5;
948 
949  // Output solid boundaries
950  //------------------------
951  sprintf(filename,"%s/solid_boundaries%i.dat",doc_info.directory().c_str(),
952  doc_info.number());
953  some_file.open(filename);
954  Solid_mesh_pt->output_boundaries(some_file);
955  some_file.close();
956 
957 
958  // Output solid solution
959  //-----------------------
960  sprintf(filename,"%s/solid_soln%i.dat",doc_info.directory().c_str(),
961  doc_info.number());
962  some_file.open(filename);
963  Solid_mesh_pt->output(some_file,npts);
964  some_file.close();
965 
966 
967  // Output fluid boundaries
968  //------------------------
969  sprintf(filename,"%s/fluid_boundaries%i.dat",doc_info.directory().c_str(),
970  doc_info.number());
971  some_file.open(filename);
972  Fluid_mesh_pt->output_boundaries(some_file);
973  some_file.close();
974 
975 
976  // Output fluid solution
977  //-----------------------
978  sprintf(filename,"%s/fluid_soln%i.dat",doc_info.directory().c_str(),
979  doc_info.number());
980  some_file.open(filename);
981  Fluid_mesh_pt->output(some_file,npts);
982  some_file.close();
983 
984 
985  // Output fsi traction
986  //--------------------
987  sprintf(filename,"%s/fsi_traction%i.dat",doc_info.directory().c_str(),
988  doc_info.number());
989  some_file.open(filename);
990  unsigned n=nsolid_fsi_boundary();
991  for (unsigned i=0;i<n;i++)
992  {
993  Solid_fsi_traction_mesh_pt[i]->output(some_file,npts);
994  }
995  some_file.close();
996 
997 } // end_of_doc
998 
999 
1000 
1001 
1002 
1003 //========================= start_of_main=================================
1004 /// Demonstrate how to solve an unstructured 3D FSI problem
1005 //========================================================================
1006 int main(int argc, char **argv)
1007 {
1008  // Label for output
1009  DocInfo doc_info;
1010 
1011  // Output directory
1012  doc_info.set_directory("RESLT");
1013 
1014  // Create generalised Hookean constitutive equations
1016  new GeneralisedHookean(&Global_Parameters::Nu);
1017 
1018  //Set up the problem
1020  PseudoSolidNodeUpdateElement<TTaylorHoodElement<3>, TPVDElement<3,3> >,
1021  TPVDElement<3,3> > problem;
1022 
1023  //Output initial configuration
1024  problem.doc_solution(doc_info);
1025  doc_info.number()++;
1026 
1027  // Parameter study
1028  unsigned nstep=2;
1029 
1030  // Increment in FSI parameter
1031  double q_increment=5.0e-2;
1032 
1033  for (unsigned istep=0;istep<nstep;istep++)
1034  {
1035  // Solve the problem
1036  problem.newton_solve();
1037 
1038  //Output solution
1039  problem.doc_solution(doc_info);
1040  doc_info.number()++;
1041 
1042  // Bump up FSI parameter
1043  Global_Parameters::Q+=q_increment;
1044  }
1045 
1046 } // end_of_main
Vector< SolidMesh * > Lagrange_multiplier_mesh_pt
Meshes of Lagrange multiplier elements.
double Q
Default FSI parameter.
unsigned nsolid_fsi_boundary()
Return total number of mesh boundaries in the solid mesh that make up the FSI interface.
Vector< MeshAsGeomObject * > Solid_fsi_boundary_pt
GeomObject incarnations of the FSI boundary in the solid mesh.
MySolidTetgenMesh< SOLID_ELEMENT > * Solid_mesh_pt
Bulk solid mesh.
MySolidTetgenMesh(const std::string &node_file_name, const std::string &element_file_name, const std::string &face_file_name, TimeStepper *time_stepper_pt=&Mesh::Default_TimeStepper)
Constructor:
double P_in
Fluid pressure on inflow boundary.
void prescribed_inflow_traction(const double &t, const Vector< double > &x, const Vector< double > &n, Vector< double > &traction)
Applied traction on fluid at the inflow boundary.
Vector< SolidMesh * > Solid_fsi_traction_mesh_pt
Meshes of FSI traction elements.
void create_fluid_traction_elements()
Create fluid traction elements at inflow.
virtual ~MySolidTetgenMesh()
Empty Destructor.
void create_fsi_traction_elements()
Create FSI traction elements.
int main(int argc, char **argv)
Demonstrate how to solve an unstructured 3D FSI problem.
~UnstructuredFSIProblem()
Destructor (empty)
Vector< unsigned > Solid_fsi_boundary_id
IDs of solid mesh boundaries which make up the FSI interface.
unsigned nfluid_inflow_traction_boundary()
Return total number of mesh boundaries that make up the inflow boundary.
void doc_solution(DocInfo &doc_info)
Doc the solution.
Vector< unsigned > Fluid_fsi_boundary_id
IDs of fluid mesh boundaries which make up the FSI interface.
Unstructured 3D FSI problem.
virtual ~FluidTetMesh()
Empty Destructor.
void prescribed_outflow_traction(const double &t, const Vector< double > &x, const Vector< double > &n, Vector< double > &traction)
Applied traction on fluid at the inflow boundary.
double P_out
Fluid pressure on outflow boundary.
FluidTetMesh< FLUID_ELEMENT > * Fluid_mesh_pt
Bulk fluid mesh.
unsigned npinned_solid_boundary()
Return total number of mesh boundaries in the solid mesh where the position is pinned.
Vector< unsigned > Outflow_boundary_id
IDs of fluid mesh boundaries along which inflow boundary conditions are applied.
double Nu
Poisson&#39;s ratio for generalised Hookean constitutive equation.
Tetgen-based mesh upgraded to become a (pseudo-) solid mesh.
Vector< Mesh * > Fluid_traction_mesh_pt
Meshes of fluid traction elements that apply pressure at in/outflow.
unsigned nfluid_fsi_boundary()
Return total number of mesh boundaries in the fluid mesh that make up the FSI interface.
unsigned nfluid_traction_boundary()
Return total number of mesh boundaries that make up the in- and outflow boundaries where a traction h...
void create_lagrange_multiplier_elements()
Create elements that enforce prescribed boundary motion for the pseudo-solid fluid mesh by Lagrange m...
FluidTetMesh(const std::string &node_file_name, const std::string &element_file_name, const std::string &face_file_name, const bool &split_corner_elements, TimeStepper *time_stepper_pt=&Mesh::Default_TimeStepper)
Constructor:
Vector< unsigned > Inflow_boundary_id
IDs of fluid mesh boundaries along which inflow boundary conditions are applied.
Tetgen-based mesh upgraded to become a solid mesh.
ConstitutiveLaw * Constitutive_law_pt
Pointer to constitutive law.
double Re
Default Reynolds number.
void doc_solid_boundary_coordinates(const unsigned &i)
Sanity check: Doc boundary coordinates on i-th solid FSI interface.
Vector< unsigned > Pinned_solid_boundary_id
IDs of solid mesh boundaries where displacements are pinned.
unsigned nfluid_outflow_traction_boundary()
Return total number of mesh boundaries that make up the outflow boundary.