unstructured_two_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 for fsi on unstructured mesh
31 
32 //Generic includes
33 #include "generic.h"
34 #include "navier_stokes.h"
35 #include "solid.h"
36 #include "constitutive.h"
37 
38 // The meshes
39 #include "meshes/triangle_mesh.h"
40 
41 using namespace std;
42 using namespace oomph;
43 
44 //==start_of_namespace==============================
45 /// Namespace for physical parameters
46 //==================================================
48 {
49  /// Reynolds number
50  double Re=0.0;
51 
52  /// FSI parameter
53  double Q=0.0;
54 
55  /// Non-dim gravity
56  double Gravity=0.0;
57 
58  /// Non-dimensional gravity as body force
59  void gravity(const double& time,
60  const Vector<double> &xi,
61  Vector<double> &b)
62  {
63  b[0]=0.0;
64  b[1]=-Gravity;
65  }
66 
67  /// Pseudo-solid Poisson ratio
68  double Nu=0.3;
69 
70  /// Constitutive law for the solid (and pseudo-solid) mechanics
71  ConstitutiveLaw *Constitutive_law_pt=0;
72 
73  /// Boolean to identify if node is on fsi boundary
74  bool is_on_fsi_boundary(Node* nod_pt)
75  {
76  if (
77  (
78  // Is it a boundary node?
79  dynamic_cast<BoundaryNodeBase*>(nod_pt)!=0)&&
80  (
81  // Horizontal extent of main immersed obstacle
82  ( (nod_pt->x(0)>1.6)&&(nod_pt->x(0)<4.75)&&
83  // Vertical extent of main immersed obstacle
84  (nod_pt->x(1)>0.1125)&&(nod_pt->x(1)<2.8) ) ||
85  // Two nodes on the bottom wall are below y=0.3
86  ( (nod_pt->x(1)<0.3)&&
87  // ...and bracketed in these two x-ranges
88  ( ( (nod_pt->x(0)>3.0)&&(nod_pt->x(0)<3.1) ) ||
89  ( (nod_pt->x(0)<4.6)&&(nod_pt->x(0)>4.5) ) )
90  )
91  )
92  )
93  {
94  return true;
95  }
96  else
97  {
98  return false;
99  }
100  }
101 
102 
103 } // end_of_namespace
104 
105 
106 
107 ////////////////////////////////////////////////////////////////////////
108 ////////////////////////////////////////////////////////////////////////
109 ////////////////////////////////////////////////////////////////////////
110 
111 
112 //========start_solid_mesh=================================================
113 /// Triangle-based mesh upgraded to become a solid mesh
114 //=========================================================================
115 template<class ELEMENT>
116 class MySolidTriangleMesh : public virtual TriangleMesh<ELEMENT>,
117  public virtual SolidMesh
118 {
119 
120 public:
121 
122  /// Constructor:
123  MySolidTriangleMesh(const std::string& node_file_name,
124  const std::string& element_file_name,
125  const std::string& poly_file_name,
126  TimeStepper* time_stepper_pt=
127  &Mesh::Default_TimeStepper) :
128  TriangleMesh<ELEMENT>(node_file_name,element_file_name,
129  poly_file_name, time_stepper_pt)
130  {
131  //Assign the Lagrangian coordinates
132  set_lagrangian_nodal_coordinates();
133 
134  // Identify special boundaries
135  set_nboundary(3);
136 
137  unsigned n_node=this->nnode();
138  for (unsigned j=0;j<n_node;j++)
139  {
140  Node* nod_pt=this->node_pt(j);
141 
142  // Boundary 1 is lower boundary
143  if (nod_pt->x(1)<0.15)
144  {
145  this->remove_boundary_node(0,nod_pt);
146  this->add_boundary_node(1,nod_pt);
147  }
148 
149  // Boundary 2 is FSI interface
151  {
152  this->remove_boundary_node(0,nod_pt);
153  this->add_boundary_node(2,nod_pt);
154  }
155  }// done boundary assignment
156 
157  // Identify the elements next to the newly created boundaries
158  TriangleMesh<ELEMENT>::setup_boundary_element_info();
159 
160  // Setup boundary coordinates for boundaries 1 and 2
161  this->template setup_boundary_coordinates<ELEMENT>(1);
162  this->template setup_boundary_coordinates<ELEMENT>(2);
163  }
164 
165  /// Empty Destructor
166  virtual ~MySolidTriangleMesh() { }
167 
168 };
169 
170 
171 
172 ///////////////////////////////////////////////////////////////////////////
173 ///////////////////////////////////////////////////////////////////////////
174 ///////////////////////////////////////////////////////////////////////////
175 
176 
177 
178 //======================start_fluid_mesh===================================
179 /// Triangle-based mesh upgraded to become a pseudo-solid mesh
180 //=========================================================================
181 template<class ELEMENT>
182 class FluidTriangleMesh : public virtual TriangleMesh<ELEMENT>,
183  public virtual SolidMesh
184 {
185 
186 public:
187 
188  /// Constructor
189  FluidTriangleMesh(const std::string& node_file_name,
190  const std::string& element_file_name,
191  const std::string& poly_file_name,
192  TimeStepper* time_stepper_pt=
193  &Mesh::Default_TimeStepper) :
194  TriangleMesh<ELEMENT>(node_file_name,element_file_name,
195  poly_file_name, time_stepper_pt)
196  {
197  //Assign the Lagrangian coordinates
198  set_lagrangian_nodal_coordinates();
199 
200  // Identify special boundaries
201  this->set_nboundary(4);
202 
203  unsigned n_node=this->nnode();
204  for (unsigned j=0;j<n_node;j++)
205  {
206  Node* nod_pt=this->node_pt(j);
207 
208  // Boundary 1 is left (inflow) boundary
209  if (nod_pt->x(0)<0.226)
210  {
211  this->remove_boundary_node(0,nod_pt);
212  this->add_boundary_node(1,nod_pt);
213 
214  // Add overlapping nodes back to boundary 0
215  if (nod_pt->x(1)<0.2) this->add_boundary_node(0,nod_pt);
216  if (nod_pt->x(1)>4.06) this->add_boundary_node(0,nod_pt);
217  }
218 
219  // Boundary 2 is right (outflow) boundary
220  if (nod_pt->x(0)>8.28)
221  {
222  this->remove_boundary_node(0,nod_pt);
223  this->add_boundary_node(2,nod_pt);
224 
225  // Add overlapping nodes back to boundary 0
226  if (nod_pt->x(1)<0.2) this->add_boundary_node(0,nod_pt);
227  if (nod_pt->x(1)>4.06) this->add_boundary_node(0,nod_pt);
228 
229  }
230 
231  // Boundary 3 is FSI boundary
233  {
234  this->remove_boundary_node(0,nod_pt);
235  this->add_boundary_node(3,nod_pt);
236 
237  //If it's below y=0.2 it's also on boundary 0 so stick it back on
238  if (nod_pt->x(1)<0.2) this->add_boundary_node(0,nod_pt);
239  }
240  }
241  TriangleMesh<ELEMENT>::setup_boundary_element_info();
242 
243  // Open a file to doc the FaceElements that are used to
244  // create the boundary coordinates. The elements must
245  // form a simply-connected line. This may not work
246  // if the mesh is too coarse so that, e.g. an element
247  // that goes through the interior has endpoints that are
248  // both located on the same boundary. Outputting the
249  // FaceElements can help identify such cases.
250  ofstream some_file("RESLT/boundary_generation_test.dat");
251 
252  // Setup boundary coordinates for boundaries 1, 2 and 3
253  this->template setup_boundary_coordinates<ELEMENT>(1);
254  this->template setup_boundary_coordinates<ELEMENT>(2);
255  this->template setup_boundary_coordinates<ELEMENT>(3,some_file);
256 
257  // Close it again
258  some_file.close();
259  }
260 
261  /// Empty Destructor
262  virtual ~FluidTriangleMesh() { }
263 
264 };
265 
266 
267 
268 ///////////////////////////////////////////////////////////////////////////
269 ///////////////////////////////////////////////////////////////////////////
270 ///////////////////////////////////////////////////////////////////////////
271 
272 
273 //==start_of_problem_class============================================
274 /// Unstructured FSI Problem
275 //====================================================================
276 template<class FLUID_ELEMENT, class SOLID_ELEMENT>
277 class UnstructuredFSIProblem : public Problem
278 {
279 
280 public:
281 
282  /// Constructor
284 
285  /// Destructor (empty)
287 
288  /// Access function for the fluid mesh
290  {
291  return Fluid_mesh_pt;
292  }
293 
294  /// Access function for the solid mesh
296  {
297  return Solid_mesh_pt;
298  }
299 
300  /// Doc the solution
301  void doc_solution(DocInfo& doc_info);
302 
303 private:
304 
305  /// Create FSI traction elements
306  void create_fsi_traction_elements();
307 
308  /// \short Create elements that enforce prescribed boundary motion
309  /// for the pseudo-solid fluid mesh by Lagrange multipliers
310  void create_lagrange_multiplier_elements();
311 
312  /// Sanity check: Doc boundary coordinates from solid side
313  void doc_solid_boundary_coordinates();
314 
315  /// Fluid mesh
317 
318  /// Solid mesh
320 
321  /// Pointers to mesh of Lagrange multiplier elements
323 
324  /// Vector of pointers to mesh of FSI traction elements
325  SolidMesh* Traction_mesh_pt;
326 
327  /// GeomObject incarnation of fsi boundary in solid mesh
328  MeshAsGeomObject*
330 
331 };
332 
333 
334 
335 //==start_of_constructor==================================================
336 /// Constructor for unstructured FSI problem.
337 //========================================================================
338 template<class FLUID_ELEMENT, class SOLID_ELEMENT>
340 {
341 
342  // Fluid mesh
343  //-----------
344 
345  //Create fluid mesh
346  string fluid_node_file_name="fluid.fig.1.node";
347  string fluid_element_file_name="fluid.fig.1.ele";
348  string fluid_poly_file_name="fluid.fig.1.poly";
349  Fluid_mesh_pt = new FluidTriangleMesh<FLUID_ELEMENT>(fluid_node_file_name,
350  fluid_element_file_name,
351  fluid_poly_file_name);
352 
353  // Doc pinned solid nodes
354  std::ofstream pseudo_solid_bc_file("pinned_pseudo_solid_nodes.dat");
355 
356  // Set the boundary conditions for fluid problem: All nodes are
357  // free by default -- just pin the ones that have Dirichlet conditions
358  // here.
359  unsigned nbound=Fluid_mesh_pt->nboundary();
360  for(unsigned ibound=0;ibound<nbound;ibound++)
361  {
362  unsigned num_nod=Fluid_mesh_pt->nboundary_node(ibound);
363  for (unsigned inod=0;inod<num_nod;inod++)
364  {
365  // Pin velocity everywhere apart from outlet where we
366  // have parallel outflow
367  if (ibound!=2)
368  {
369  Fluid_mesh_pt->boundary_node_pt(ibound,inod)->pin(0);
370  }
371  Fluid_mesh_pt->boundary_node_pt(ibound,inod)->pin(1);
372 
373  // Pin pseudo-solid positions everywhere apart from boundary 3,
374  // the fsi boundary
375  if ((ibound==0)||(ibound==1)||(ibound==2))
376  {
377  for(unsigned i=0;i<2;i++)
378  {
379  // Pin the node
380  SolidNode* nod_pt=Fluid_mesh_pt->boundary_node_pt(ibound,inod);
381  nod_pt->pin_position(i);
382 
383  // Doc it as pinned
384  pseudo_solid_bc_file << nod_pt->x(i) << " ";
385  }
386  pseudo_solid_bc_file << std::endl;
387  }
388  }
389  } // end loop over boundaries
390 
391  // Close
392  pseudo_solid_bc_file.close();
393 
394 
395  // Complete the build of the fluid elements so they are fully functional
396  unsigned n_element = Fluid_mesh_pt->nelement();
397  for(unsigned e=0;e<n_element;e++)
398  {
399  // Upcast from GeneralisedElement to the present element
400  FLUID_ELEMENT* el_pt =
401  dynamic_cast<FLUID_ELEMENT*>(Fluid_mesh_pt->element_pt(e));
402 
403  //Set the Reynolds number
404  el_pt->re_pt() = &Global_Parameters::Re;
405 
406  // Set the constitutive law for pseudo-elastic mesh deformation
407  el_pt->constitutive_law_pt() =
409 
410  } // end loop over elements
411 
412 
413  // Apply fluid boundary conditions: Poiseuille at inflow
414 
415  // Find max. and min y-coordinate at inflow
416  unsigned ibound=1;
417  //Initialise both to the y-coordinate of the first boundary node
418  double y_min=fluid_mesh_pt()->boundary_node_pt(ibound,0)->x(1);;
419  double y_max=y_min;
420 
421  //Loop over the rest of the boundary nodes
422  unsigned num_nod= fluid_mesh_pt()->nboundary_node(ibound);
423  for (unsigned inod=1;inod<num_nod;inod++)
424  {
425  double y=fluid_mesh_pt()->boundary_node_pt(ibound,inod)->x(1);
426  if (y>y_max)
427  {
428  y_max=y;
429  }
430  if (y<y_min)
431  {
432  y_min=y;
433  }
434  }
435  double y_mid=0.5*(y_min+y_max);
436 
437  // Loop over all boundaries
438  const unsigned n_boundary = fluid_mesh_pt()->nboundary();
439  for (unsigned ibound=0;ibound<n_boundary;ibound++)
440  {
441  const unsigned num_nod= fluid_mesh_pt()->nboundary_node(ibound);
442  for (unsigned inod=0;inod<num_nod;inod++)
443  {
444  // Parabolic inflow at the left boundary (boundary 1)
445  if (ibound==1)
446  {
447  double y=fluid_mesh_pt()->boundary_node_pt(ibound,inod)->x(1);
448  double veloc=1.5/(y_max-y_min)*
449  (y-y_min)*(y_max-y)/((y_mid-y_min)*(y_max-y_mid));
450  fluid_mesh_pt()->boundary_node_pt(ibound,inod)->set_value(0,veloc);
451  fluid_mesh_pt()->boundary_node_pt(ibound,inod)->set_value(1,0.0);
452  }
453  // Zero flow elsewhere
454  else
455  {
456  fluid_mesh_pt()->boundary_node_pt(ibound,inod)->set_value(0,0.0);
457  fluid_mesh_pt()->boundary_node_pt(ibound,inod)->set_value(1,0.0);
458  }
459  }
460  } // end Poiseuille
461 
462 
463  // Solid mesh
464  //-----------
465 
466  //Create solid mesh
467  string solid_node_file_name="solid.fig.1.node";
468  string solid_element_file_name="solid.fig.1.ele";
469  string solid_poly_file_name="solid.fig.1.poly";
470  Solid_mesh_pt = new MySolidTriangleMesh<SOLID_ELEMENT>(solid_node_file_name,
471  solid_element_file_name,
472  solid_poly_file_name);
473 
474 
475  // Complete the build of all solid elements so they are fully functional
476  n_element = Solid_mesh_pt->nelement();
477  for(unsigned i=0;i<n_element;i++)
478  {
479  //Cast to a solid element
480  SOLID_ELEMENT *el_pt =
481  dynamic_cast<SOLID_ELEMENT*>(Solid_mesh_pt->element_pt(i));
482 
483  // Set the constitutive law
484  el_pt->constitutive_law_pt() =
486 
487  //Set the body force
488  el_pt->body_force_fct_pt() = Global_Parameters::gravity;
489  }
490 
491  // Pin both positions at lower boundary of solid mesh (boundary 1)
492  ibound=1;
493  num_nod=Solid_mesh_pt->nboundary_node(ibound);
494  for (unsigned inod=0;inod<num_nod;inod++)
495  {
496  Solid_mesh_pt->boundary_node_pt(ibound,inod)->pin_position(0);
497  Solid_mesh_pt->boundary_node_pt(ibound,inod)->pin_position(1);
498  }
499 
500 
501  // Create FSI Traction elements
502  //-----------------------------
503 
504  // Now construct the (empty) traction element mesh
505  Traction_mesh_pt=new SolidMesh;
506 
507  // Build the FSI traction elements and add them to the traction mesh
508  create_fsi_traction_elements();
509 
510  // Create Lagrange multiplier mesh for boundary motion
511  //----------------------------------------------------
512 
513  // Construct the mesh of elements that enforce prescribed boundary motion
514  // of pseudo-solid fluid mesh by Lagrange multipliers
515  Lagrange_multiplier_mesh_pt=new SolidMesh;
516  create_lagrange_multiplier_elements();
517 
518 
519  // Combine meshes
520  //---------------
521 
522  // Add sub meshes
523  add_sub_mesh(Fluid_mesh_pt);
524  add_sub_mesh(Solid_mesh_pt);
525  add_sub_mesh(Traction_mesh_pt);
526  add_sub_mesh(Lagrange_multiplier_mesh_pt);
527 
528  // Build global mesh
529  build_global_mesh();
530 
531 
532  // Setup FSI
533  //----------
534 
535  // Document the boundary coordinate along the FSI interface
536  // of the fluid mesh during call to
537  // setup_fluid_load_info_for_solid_elements()
538  Multi_domain_functions::Doc_boundary_coordinate_file.open(
539  "fluid_boundary_test.dat");
540 
541  // Work out which fluid dofs affect the residuals of the wall elements:
542  // We pass the boundary between the fluid and solid meshes and
543  // pointers to the meshes. The interaction boundary is boundary 3
544  // of the 2D fluid mesh.
545  FSI_functions::setup_fluid_load_info_for_solid_elements<FLUID_ELEMENT,2>
546  (this,3,Fluid_mesh_pt,Traction_mesh_pt);
547 
548  // Close the doc file
549  Multi_domain_functions::Doc_boundary_coordinate_file.close();
550 
551  // Sanity check: Doc boundary coordinates from solid side
552  doc_solid_boundary_coordinates();
553 
554  // Setup equation numbering scheme
555  cout <<"Number of equations: " << assign_eqn_numbers() << std::endl;
556 
557 } // end_of_constructor
558 
559 
560 
561 //============start_doc_solid_zeta=======================================
562 /// Doc boundary coordinates in solid and plot GeomObject representation
563 /// of FSI boundary.
564 //=======================================================================
565 template<class FLUID_ELEMENT,class SOLID_ELEMENT>
568 {
569 
570  // Doc boundary coordinates for fsi boundary in solid mesh
571  std::ofstream the_file("solid_boundary_test.dat");
572 
573  // Initialise max/min boundary coordinate
574  double zeta_min= 1.0e40;
575  double zeta_max=-1.0e40;
576 
577  // Loop over FSI traction elements
578  unsigned n_face_element = Traction_mesh_pt->nelement();
579  for(unsigned e=0;e<n_face_element;e++)
580  {
581  //Cast the element pointer
582  FSISolidTractionElement<SOLID_ELEMENT,2>* el_pt=
583  dynamic_cast<FSISolidTractionElement<SOLID_ELEMENT,2>*>
584  (Traction_mesh_pt->element_pt(e));
585 
586  // Doc boundary coordinate
587  Vector<double> s(1);
588  Vector<double> zeta(1);
589  Vector<double> x(2);
590  unsigned n_plot=5;
591  the_file << el_pt->tecplot_zone_string(n_plot);
592 
593  // Loop over plot points
594  unsigned num_plot_points=el_pt->nplot_points(n_plot);
595  for (unsigned iplot=0;iplot<num_plot_points;iplot++)
596  {
597  // Get local coordinates of plot point
598  el_pt->get_s_plot(iplot,n_plot,s);
599  el_pt->interpolated_zeta(s,zeta);
600  el_pt->interpolated_x(s,x);
601  for (unsigned i=0;i<2;i++)
602  {
603  the_file << x[i] << " ";
604  }
605  the_file << zeta[0] << " ";
606 
607  // Update max/min boundary coordinate
608  if (zeta[0]<zeta_min) zeta_min=zeta[0];
609  if (zeta[0]>zeta_max) zeta_max=zeta[0];
610 
611  the_file << std::endl;
612  }
613  }
614 
615  // Close doc file
616  the_file.close();
617 
618 
619  // Doc compound GeomObject
620  the_file.open("fsi_geom_object.dat");
621  unsigned nplot=10000;
622  Vector<double> zeta(1);
623  Vector<double> r(2);
624  for (unsigned i=0;i<nplot;i++)
625  {
626  zeta[0]=zeta_min+(zeta_max-zeta_min)*double(i)/double(nplot-1);
627  Solid_fsi_boundary_pt->position(zeta,r);
628  the_file << r[0] << " " << r[1] << std::endl;
629  }
630  the_file.close();
631 
632 } //end doc_solid_zeta
633 
634 
635 
636 
637 //============start_of_create_traction_elements==========================
638 /// Create FSI traction elements
639 //=======================================================================
640 template<class FLUID_ELEMENT,class SOLID_ELEMENT>
643 {
644  // Traction elements are located on boundary 2 of solid bulk mesh
645  unsigned b=2;
646 
647  // How many bulk elements are adjacent to boundary b?
648  unsigned n_element = solid_mesh_pt()->nboundary_element(b);
649 
650  // Loop over the bulk elements adjacent to boundary b
651  for(unsigned e=0;e<n_element;e++)
652  {
653  // Get pointer to the bulk element that is adjacent to boundary b
654  SOLID_ELEMENT* bulk_elem_pt = dynamic_cast<SOLID_ELEMENT*>(
655  solid_mesh_pt()->boundary_element_pt(b,e));
656 
657  //What is the index of the face of the element e along boundary b
658  int face_index = solid_mesh_pt()->face_index_at_boundary(b,e);
659 
660  // Create new element
661  FSISolidTractionElement<SOLID_ELEMENT,2>* el_pt=
662  new FSISolidTractionElement<SOLID_ELEMENT,2>(bulk_elem_pt,face_index);
663 
664  // Add it to the mesh
665  Traction_mesh_pt->add_element_pt(el_pt);
666 
667  // Specify boundary number
668  el_pt->set_boundary_number_in_bulk_mesh(b);
669 
670  // Function that specifies the load ratios
671  el_pt->q_pt() = &Global_Parameters::Q;
672  }
673 
674  } // end of create_traction_elements
675 
676 
677 
678 //============start_of_create_lagrange_multiplier_elements===============
679 /// Create elements that impose the prescribed boundary displacement
680 /// for the pseudo-solid fluid mesh
681 //=======================================================================
682 template<class FLUID_ELEMENT, class SOLID_ELEMENT>
685 {
686 
687  // Create GeomObject incarnation of fsi boundary in solid mesh
688  Solid_fsi_boundary_pt=
689  new MeshAsGeomObject
690  (Traction_mesh_pt);
691 
692  // Lagrange multiplier elements are located on boundary 3 of the fluid mesh
693  unsigned b=3;
694 
695  // How many bulk fluid elements are adjacent to boundary b?
696  unsigned n_element = Fluid_mesh_pt->nboundary_element(b);
697 
698  // Loop over the bulk fluid elements adjacent to boundary b?
699  for(unsigned e=0;e<n_element;e++)
700  {
701  // Get pointer to the bulk fluid element that is adjacent to boundary b
702  FLUID_ELEMENT* bulk_elem_pt = dynamic_cast<FLUID_ELEMENT*>(
703  Fluid_mesh_pt->boundary_element_pt(b,e));
704 
705  //Find the index of the face of element e along boundary b
706  int face_index = Fluid_mesh_pt->face_index_at_boundary(b,e);
707 
708  // Create new element
709  ImposeDisplacementByLagrangeMultiplierElement<FLUID_ELEMENT>* el_pt =
710  new ImposeDisplacementByLagrangeMultiplierElement<FLUID_ELEMENT>(
711  bulk_elem_pt,face_index);
712 
713  // Add it to the mesh
714  Lagrange_multiplier_mesh_pt->add_element_pt(el_pt);
715 
716  // Set the GeomObject that defines the boundary shape and set
717  // which bulk boundary we are attached to (needed to extract
718  // the boundary coordinate from the bulk nodes)
719  el_pt->set_boundary_shape_geom_object_pt(Solid_fsi_boundary_pt,b);
720 
721  // Loop over the nodes to apply boundary conditions
722  unsigned nnod=el_pt->nnode();
723  for (unsigned j=0;j<nnod;j++)
724  {
725  Node* nod_pt = el_pt->node_pt(j);
726 
727  // Is the node also on boundary 0?
728  if (nod_pt->is_on_boundary(0))
729  {
730  // How many nodal values were used by the "bulk" element
731  // that originally created this node?
732  unsigned n_bulk_value=el_pt->nbulk_value(j);
733 
734  // The remaining ones are Lagrange multipliers and we pin them.
735  unsigned nval=nod_pt->nvalue();
736  for (unsigned j=n_bulk_value;j<nval;j++)
737  {
738  nod_pt->pin(j);
739  }
740  }
741  }
742  }
743 
744 } // end of create_lagrange_multiplier_elements
745 
746 
747 //==start_of_doc_solution=================================================
748 /// Doc the solution
749 //========================================================================
750 template<class FLUID_ELEMENT, class SOLID_ELEMENT>
752 doc_solution(DocInfo& doc_info)
753 {
754  ofstream some_file;
755  char filename[100];
756 
757  // Number of plot points
758  unsigned npts;
759  npts=5;
760 
761  // Output fluid solution
762  sprintf(filename,"%s/fluid_soln%i.dat",doc_info.directory().c_str(),
763  doc_info.number());
764  some_file.open(filename);
765  Fluid_mesh_pt->output(some_file,npts);
766  some_file.close();
767 
768 
769  // Output solid solution
770  sprintf(filename,"%s/solid_soln%i.dat",doc_info.directory().c_str(),
771  doc_info.number());
772  some_file.open(filename);
773  Solid_mesh_pt->output(some_file,npts);
774  some_file.close();
775 
776 
777 } // end_of_doc_solution
778 
779 
780 
781 
782 ////////////////////////////////////////////////////////////////////////
783 ////////////////////////////////////////////////////////////////////////
784 ////////////////////////////////////////////////////////////////////////
785 
786 
787 //==start_of_main======================================================
788 /// Driver for unstructured fsi problem
789 //=====================================================================
790 int main()
791 {
792  // Label for output
793  DocInfo doc_info;
794 
795  // Set output directory
796  doc_info.set_directory("RESLT");
797 
798  //Create the constitutive law
799  Global_Parameters::Constitutive_law_pt = new GeneralisedHookean(
801 
802  // Build the problem with triangular Taylor Hood for fluid and solid
804  PseudoSolidNodeUpdateElement<TTaylorHoodElement<2>, TPVDElement<2,3> >,
805  TPVDElement<2,3> > problem;
806 
807  // Output boundaries
808  problem.fluid_mesh_pt()->output_boundaries("RESLT/fluid_boundaries.dat");
809  problem.solid_mesh_pt()->output_boundaries("RESLT/solid_boundaries.dat");
810 
811  // Output the initial guess for the solution
812  problem.doc_solution(doc_info);
813  doc_info.number()++;
814 
815  // Parameter study
817  double q_increment=1.0e-6;
818 
819  // Solve the problem at zero Re and Q
820  problem.newton_solve();
821 
822  // Output the solution
823  problem.doc_solution(doc_info);
824  doc_info.number()++;
825 
826  // Bump up Re
828 
829  // Now do proper parameter study with increase in Q
830  unsigned nstep=2; // 10;
831  for (unsigned i=0;i<nstep;i++)
832  {
833  // Solve the problem
834  problem.newton_solve();
835 
836  // Output the solution
837  problem.doc_solution(doc_info);
838  doc_info.number()++;
839 
840  // Bump up Q
841  Global_Parameters::Q+=q_increment;
842  }
843 
844 
845 } // end_of_main
846 
847 
848 
849 
850 
851 
852 
853 
854 
855 
FluidTriangleMesh(const std::string &node_file_name, const std::string &element_file_name, const std::string &poly_file_name, TimeStepper *time_stepper_pt=&Mesh::Default_TimeStepper)
Constructor.
SolidMesh * Traction_mesh_pt
Vector of pointers to mesh of FSI traction elements.
double Q
FSI parameter.
MySolidTriangleMesh< SOLID_ELEMENT > * Solid_mesh_pt
Solid mesh.
FluidTriangleMesh< FLUID_ELEMENT > *& fluid_mesh_pt()
Access function for the fluid mesh.
Triangle-based mesh upgraded to become a solid mesh.
virtual ~MySolidTriangleMesh()
Empty Destructor.
void create_fsi_traction_elements()
Create FSI traction elements.
int main()
Driver for unstructured fsi problem.
~UnstructuredFSIProblem()
Destructor (empty)
virtual ~FluidTriangleMesh()
Empty Destructor.
void doc_solution(DocInfo &doc_info)
Doc the solution.
double Gravity
Non-dim gravity.
SolidMesh * Lagrange_multiplier_mesh_pt
Pointers to mesh of Lagrange multiplier elements.
Unstructured FSI Problem.
Namespace for physical parameters.
FluidTriangleMesh< FLUID_ELEMENT > * Fluid_mesh_pt
Fluid mesh.
double Nu
Pseudo-solid Poisson ratio.
void gravity(const double &time, const Vector< double > &xi, Vector< double > &b)
Non-dimensional gravity as body force.
void create_lagrange_multiplier_elements()
Create elements that enforce prescribed boundary motion for the pseudo-solid fluid mesh by Lagrange m...
ConstitutiveLaw * Constitutive_law_pt
Constitutive law for the solid (and pseudo-solid) mechanics.
double Re
Reynolds number.
bool is_on_fsi_boundary(Node *nod_pt)
Boolean to identify if node is on fsi boundary.
Triangle-based mesh upgraded to become a pseudo-solid mesh.
MySolidTriangleMesh(const std::string &node_file_name, const std::string &element_file_name, const std::string &poly_file_name, TimeStepper *time_stepper_pt=&Mesh::Default_TimeStepper)
Constructor:
MySolidTriangleMesh< SOLID_ELEMENT > *& solid_mesh_pt()
Access function for the solid mesh.
void doc_solid_boundary_coordinates()
Sanity check: Doc boundary coordinates from solid side.
MeshAsGeomObject * Solid_fsi_boundary_pt
GeomObject incarnation of fsi boundary in solid mesh.