fsi_osc_ring_compare_jacs.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 2D Navier Stokes flow interacting with an elastic ring
31 
32 // Oomph-lib include files
33 #include "generic.h"
34 #include "navier_stokes.h"
35 #include "beam.h"
36 
37 //Need to include templated meshes, so that all functions
38 //are instantiated for our particular element types.
39 #include "meshes/quarter_circle_sector_mesh.h"
40 #include "meshes/one_d_lagrangian_mesh.h"
41 
42 using namespace std;
43 
44 using namespace oomph;
45 
46 //===========================================================================
47 /// Namespace for physical parameters
48 //===========================================================================
50 {
51 
52  // Independent parameters:
53  //------------------------
54 
55  /// Square of Womersly number (a frequency parameter)
56  double Alpha_sq=50.0;
57 
58  /// Density ratio of the solid and the fluid
59  double Density_ratio=1.0;
60 
61  /// External Pressure
62  double Pext=0.0;
63 
64  /// Poisson ratio
65  double Nu=0.49;
66 
67  /// Nondimensional thickness of the beam
68  double H=0.05;
69 
70  /// Perturbation pressure
71  double Pcos=0.0;
72 
73 
74  // Dependent parameters:
75  //----------------------
76 
77  /// Reynolds number
78  double Re;
79 
80  /// Reynolds x Strouhal number
81  double ReSt;
82 
83  /// Timescale ratio (non-dimensation density)
84  double Lambda_sq;
85 
86  /// Stress ratio
87  double Q;
88 
89  /// \short Set the parameters that are used in the code as a function
90  /// of the Womersley number, the density ratio and H
91  void set_params()
92  {
93  cout << "\n\n======================================================" <<std::endl;
94  cout << "\nSetting parameters. \n\n";
95  cout << "Prescribed: Square of Womersley number: Alpha_sq = "
96  << Alpha_sq << std::endl;
97  cout << " Density ratio: Density_ratio = "
98  << Density_ratio << std::endl;
99  cout << " Wall thickness: H = "
100  << H << std::endl;
101  cout << " Poisson ratio: Nu = "
102  << Nu << std::endl;
103  cout << " Pressure perturbation: Pcos = "
104  << Pcos << std::endl;
105 
106 
107  Q=1.0/12.0*pow(H,3)/Alpha_sq;
108  cout << "\nDependent: Stress ratio: Q = "
109  << Q << std::endl;
110 
111  Lambda_sq=1.0/12.0*pow(H,3)*Density_ratio;
112  cout << " Timescale ratio: Lambda_sq = "
113  << Lambda_sq << std::endl;
114 
115  Re=Alpha_sq;
116  cout << " Reynolds number: Re = "
117  << Re << std::endl;
118 
119  ReSt=Re;
120  cout << " Womersley number: ReSt = "
121  << ReSt << std::endl;
122  cout << "\n======================================================\n\n"
123  <<std::endl;
124 
125  }
126 
127  /// Non-FSI load function, a constant external pressure plus
128  /// a (small) sinusoidal perturbation of wavenumber two.
129  void pcos_load(const Vector<double>& xi, const Vector<double> &x,
130  const Vector<double>& N, Vector<double>& load)
131  {
132  for(unsigned i=0;i<2;i++)
133  {load[i] = (Pext - Pcos*cos(2.0*xi[0]))*N[i];}
134  }
135 
136 }
137 
138 
139 //======================================================================
140 /// FSI Ring problem: a fluid-structure interaction problem in which
141 /// a viscous fluid bounded by an initially circular beam is set into motion
142 /// by a small sinusoidal perturbation of the beam (the domain boundary).
143 //======================================================================
144 class FSIRingProblem : public Problem
145 {
146  /// \short There are very few element types that will work for this problem.
147  /// Rather than passing the element type as a template parameter to the
148  /// problem, we choose instead to use a typedef to specify the
149  /// particular element fluid used.
150  typedef AlgebraicElement<RefineableQCrouzeixRaviartElement<2> > FLUID_ELEMENT;
151 
152  /// \short Typedef to specify the solid element used
153  typedef FSIHermiteBeamElement SOLID_ELEMENT;
154 
155 public:
156 
157  /// Constructor: Number of elements in wall mesh, amplitude of the
158  /// initial wall deformation, amplitude of pcos perturbation and its duration.
159  FSIRingProblem(const unsigned &nelement_wall,
160  const double& eps_ampl, const double& pcos_initial,
161  const double& pcos_duration, const unsigned& i_case);
162 
163  /// Update after solve (empty)
165 
166  /// \short Update before solve (empty)
168 
169  /// \short Update the problem specs before checking Newton
170  /// convergence
172  {
173  // Update the fluid mesh -- auxiliary update function for algebraic
174  // nodes automatically updates no slip condition.
175  Fluid_mesh_pt->node_update();
176  }
177 
178  /// \short Update the problem specs after adaptation:
180  {
181  // The functions used to update the no slip boundary conditions
182  // must be set on any new nodes that have been created during the
183  // mesh adaptation process.
184  // There is no mechanism by which auxiliary update functions
185  // are copied to newly created nodes.
186  // (because, unlike boundary conditions, they don't occur exclusively
187  // at boundaries)
188 
189  // The no-slip boundary is boundary 1 of the mesh
190  // Loop over the nodes on this boundary and reset the auxilliary
191  // node update function
192  unsigned n_node = Fluid_mesh_pt->nboundary_node(1);
193  for (unsigned n=0;n<n_node;n++)
194  {
195  Fluid_mesh_pt->boundary_node_pt(1,n)->set_auxiliary_node_update_fct_pt(
196  FSI_functions::apply_no_slip_on_moving_wall);
197  }
198 
199  // (Re-)setup fsi: Work out which fluid dofs affect wall elements
200  // the correspondance between wall dofs and fluid elements is handled
201  // during the remeshing, but the "reverse" association must be done
202  // separately.
203  // We need to set up the interaction every time because the fluid element
204  // adjacent to a given solid element's integration point may have changed
205  // We pass the boundary between the fluid and solid meshes and pointers
206  // to the meshes. The interaction boundary is boundary 1 of the 2D
207  // fluid mesh.
208  FSI_functions::setup_fluid_load_info_for_solid_elements<FLUID_ELEMENT,2>
209  (this,1,Fluid_mesh_pt,Wall_mesh_pt);
210  }
211 
212  /// \short Doc solution: Pass number of timestep, i (we append to tracefile
213  /// after every timestep but do a full doc only at certain intervals),
214  /// DocInfo object and tracefile
215  void doc_solution(const unsigned& i, DocInfo& doc_info, ofstream& trace_file,
216  const unsigned& i_case);
217 
218  /// Do dynamic run
219  void dynamic_run(const unsigned& i_case);
220 
221 private:
222 
223  /// Setup initial condition for both domains
224  void set_initial_condition();
225 
226  /// Setup initial condition for wall
227  void set_wall_initial_condition();
228 
229  /// Setup initial condition for fluid
230  void set_fluid_initial_condition();
231 
232  /// \short Element used for documenting displacement
233  SOLID_ELEMENT* Doc_displacement_elem_pt;
234 
235  /// Pointer to wall mesh
236  OneDLagrangianMesh<SOLID_ELEMENT> *Wall_mesh_pt;
237 
238  /// Pointer to fluid mesh
239  AlgebraicRefineableQuarterCircleSectorMesh<FLUID_ELEMENT> *Fluid_mesh_pt;
240 
241  /// Pointer to geometric object that represents the undeformed wall shape
242  GeomObject* Undef_geom_pt;
243 
244  /// Pointer to wall timestepper
245  Newmark<2>* Wall_time_stepper_pt;
246 
247  /// Pointer to fluid timestepper
248  BDF<2>* Fluid_time_stepper_pt;
249 
250  /// Pointer to node on coarsest mesh on which velocity is traced
251  Node* Veloc_trace_node_pt;
252 
253  /// Amplitude of initial deformation
254  double Eps_ampl;
255 
256  /// Initial pcos
257  double Pcos_initial;
258 
259  /// Duration of initial pcos
260  double Pcos_duration;
261 
262 };
263 
264 
265 //===============================================================
266 /// Setup initial condition: When we're done here, all variables
267 /// represent the state at the initial time.
268 //===============================================================
270 {
271 
272  cout << "Setting wall ic" << std::endl;
273  set_wall_initial_condition();
274 
275  cout << "Setting fluid ic" << std::endl;
276  set_fluid_initial_condition();
277 
278 }
279 
280 
281 //===============================================================
282 /// Setup initial condition for fluid: Impulsive start
283 //===============================================================
285 {
286 
287  // Update fluid domain: Careful!!! This also applies the no slip conditions
288  // on all nodes on the wall! Since the wall might have moved since
289  // we created the mesh; we're therefore imposing a nonzero
290  // velocity on these nodes. Must wipe this afterwards (done
291  // by setting *all* velocities to zero) otherwise we get
292  // an impulsive start from a very bizarre initial velocity
293  // field! [Yes, it took me a while to figure this out...]
294  Fluid_mesh_pt->node_update();
295 
296  // Assign initial values for the velocities;
297  // pressures don't carry a time history and can be left alone.
298 
299  //Find number of nodes in fluid mesh
300  unsigned n_node = Fluid_mesh_pt->nnode();
301 
302  // Loop over the nodes to set initial guess everywhere
303  for(unsigned n=0;n<n_node;n++)
304  {
305  // Loop over velocity directions: Impulsive initial start from
306  // zero velocity!
307  for(unsigned i=0;i<2;i++)
308  {
309  Fluid_mesh_pt->node_pt(n)->set_value(i,0.0);
310  }
311  }
312 
313  // Do an impulsive start with the assigned velocity field
314  Fluid_mesh_pt->assign_initial_values_impulsive();
315 
316 }
317 
318 
319 //===============================================================
320 /// Setup initial condition: Impulsive start either from
321 /// deformed or undeformed wall shape.
322 //===============================================================
324 {
325 
326  // Geometric object that specifies the initial conditions:
327  // A ring that is bucked in a 2-lobed mode
328  GeomObject* ic_geom_object_pt=
329  new PseudoBucklingRing(Eps_ampl,Global_Physical_Variables::H,2,2,
330  Wall_time_stepper_pt);
331 
332  // Assign period of oscillation of the geometric object
333  static_cast<PseudoBucklingRing*>(ic_geom_object_pt)->set_T(1.0);
334 
335  //Set initial time (to deform wall into max. amplitude)
336  double time=0.25;
337 
338  // Assign initial radius of the object
339  static_cast<PseudoBucklingRing*>(ic_geom_object_pt)->set_R_0(1.00);
340 
341  // Setup object that specifies the initial conditions:
342  SolidInitialCondition* IC_pt = new SolidInitialCondition(ic_geom_object_pt);
343 
344  // Assign values of positional data of all elements on wall mesh
345  // so that the wall deforms into the shape specified by IC object.
346  SolidMesh::Solid_IC_problem.set_static_initial_condition(
347  this,Wall_mesh_pt,IC_pt,time);
348 
349 }
350 
351 
352 //========================================================================
353 /// Document solution: Pass number of timestep, i; we append to trace file
354 /// at every timestep and do a full doc only after a certain number
355 /// of steps.
356 //========================================================================
357 void FSIRingProblem::doc_solution(const unsigned& i,
358  DocInfo& doc_info, ofstream& trace_file, const unsigned& i_case)
359 {
360 
361  // Full doc every nskip steps
362  unsigned nskip=1; // ADJUST
363 
364  // If we at an integer multiple of nskip, full documentation.
365  if (i%nskip==0)
366  {
367  doc_info.enable_doc();
368  cout << "Full doc step " << doc_info.number()
369  << " for time " << time_stepper_pt()->time_pt()->time() << std::endl;
370  }
371  //Otherwise, just output the trace file
372  else
373  {
374  doc_info.disable_doc();
375  cout << "Only trace for time "
376  << time_stepper_pt()->time_pt()->time() << std::endl;
377  }
378 
379 
380  // If we are at a full documentation step, output the fluid solution
381  if (doc_info.is_doc_enabled())
382  {
383  //Variables used in the output file.
384  ofstream some_file; char filename[100];
385  //Construct the output filename from the doc_info number and the
386  //output directory
387  sprintf(filename,"%s/soln%i_%i.dat",doc_info.directory().c_str(),
388  i_case,doc_info.number());
389  //Open the output file
390  some_file.open(filename);
391  ///Output the solution using 5x5 plot points
392  Fluid_mesh_pt->output(some_file,5);
393  //Close the output file
394  some_file.close();
395  }
396 
397  //Temporary vector to give the local coordinate at which to document
398  //the wall displacment
399  Vector<double> s(1,1.0);
400  // Write to the trace file:
401  trace_file << time_pt()->time()
402  //Document the displacement at the end of the the chosen element
403  << " " << Doc_displacement_elem_pt->interpolated_x(s,1)
404  << " " << Veloc_trace_node_pt->x(0)
405  << " " << Veloc_trace_node_pt->x(1)
406  << " " << Veloc_trace_node_pt->value(0)
407  << " " << Veloc_trace_node_pt->value(1)
408  << " " << Fluid_mesh_pt->nelement()
409  << " " << ndof()
410  << " " << Fluid_mesh_pt->nrefinement_overruled()
411  << " " << Fluid_mesh_pt->max_error()
412  << " " << Fluid_mesh_pt->min_error()
413  << " " << Fluid_mesh_pt->max_permitted_error()
414  << " " << Fluid_mesh_pt->min_permitted_error()
415  << " " << Fluid_mesh_pt->max_keep_unrefined();
416 
417  // Output the number of the corresponding full documentation
418  // file number (or -1 if no full doc was made)
419  if (doc_info.is_doc_enabled())
420  {trace_file << " " <<doc_info.number() << " ";}
421  else {trace_file << " " <<-1 << " ";}
422 
423  //End the trace file
424  trace_file << std::endl;
425 
426  // Increment counter for full doc
427  if (doc_info.is_doc_enabled()) {doc_info.number()++;}
428 }
429 
430 //======================================================================
431 /// Constructor for FSI ring problem. Pass number of wall elements
432 /// and length of wall (in Lagrangian coordinates) amplitude of
433 /// initial deformation, pcos perturbation and duration.
434 //======================================================================
436  const double& eps_ampl,
437  const double& pcos_initial,
438  const double& pcos_duration,
439  const unsigned& i_case) :
440  Eps_ampl(eps_ampl), Pcos_initial(pcos_initial),
441  Pcos_duration(pcos_duration)
442 {
443  //-----------------------------------------------------------
444  // Create timesteppers
445  //-----------------------------------------------------------
446 
447  // Allocate the wall timestepper and add it to the problem's vector
448  // of timesteppers
449  Wall_time_stepper_pt = new Newmark<2>;
450  add_time_stepper_pt(Wall_time_stepper_pt);
451 
452  // Allocate the fluid timestepper and add it to the problem's Vector
453  // of timesteppers
454  Fluid_time_stepper_pt = new BDF<2>;
455  add_time_stepper_pt(Fluid_time_stepper_pt);
456 
457  //----------------------------------------------------------
458  // Create the wall mesh
459  //----------------------------------------------------------
460 
461  // Undeformed wall is an elliptical ring
462  Undef_geom_pt = new Ellipse(1.0,1.0);
463 
464  //Length of wall in Lagrangian coordinates
465  double L = 2.0*atan(1.0);
466 
467  //Now create the (Lagrangian!) mesh
468  Wall_mesh_pt = new
469  OneDLagrangianMesh<SOLID_ELEMENT>(N,L,Undef_geom_pt,Wall_time_stepper_pt);
470 
471  //----------------------------------------------------------
472  // Set the boundary conditions for wall mesh (problem)
473  //----------------------------------------------------------
474 
475  // Bottom boundary: (Boundary 0)
476  // No vertical displacement
477  Wall_mesh_pt->boundary_node_pt(0,0)->pin_position(1);
478  // Zero slope: Pin type 1 dof for displacement direction 0
479  Wall_mesh_pt->boundary_node_pt(0,0)->pin_position(1,0);
480 
481  // Top boundary: (Boundary 1)
482  // No horizontal displacement
483  Wall_mesh_pt->boundary_node_pt(1,0)->pin_position(0);
484  // Zero slope: Pin type 1 dof for displacement direction 1
485  Wall_mesh_pt->boundary_node_pt(1,0)->pin_position(1,1);
486 
487 
488  //-----------------------------------------------------------
489  // Create the fluid mesh:
490  //-----------------------------------------------------------
491 
492  // Fluid mesh is suspended from wall between the following Lagrangian
493  // coordinates:
494  double xi_lo=0.0;
495  double xi_hi=L;
496 
497  // Fractional position of dividing line for two outer blocks in mesh
498  double fract_mid=0.5;
499 
500  //Create a geometric object that represents the wall geometry from the
501  //wall mesh (one Lagrangian, two Eulerian coordinates).
502  MeshAsGeomObject *wall_mesh_as_geometric_object_pt
503  = new MeshAsGeomObject(Wall_mesh_pt);
504 
505  // Build fluid mesh using the wall mesh as a geometric object
506  Fluid_mesh_pt = new AlgebraicRefineableQuarterCircleSectorMesh<FLUID_ELEMENT >
507  (wall_mesh_as_geometric_object_pt,
508  xi_lo,fract_mid,xi_hi,Fluid_time_stepper_pt);
509 
510  // Set the error estimator
511  Z2ErrorEstimator* error_estimator_pt=new Z2ErrorEstimator;
512  Fluid_mesh_pt->spatial_error_estimator_pt()=error_estimator_pt;
513 
514  // Extract pointer to node at center of mesh
515  unsigned nnode=Fluid_mesh_pt->finite_element_pt(0)->nnode();
516  Veloc_trace_node_pt=Fluid_mesh_pt->finite_element_pt(0)->node_pt(nnode-1);
517 
518  // Do some random refinement
519  Vector<unsigned> elements_to_be_refined;
520  elements_to_be_refined.push_back(2);
521  Fluid_mesh_pt->refine_selected_elements(elements_to_be_refined);
522  Fluid_mesh_pt->refine_selected_elements(elements_to_be_refined);
523 
524  //-------------------------------------------------------
525  // Set the fluid boundary conditions
526  //-------------------------------------------------------
527 
528  // Bottom boundary (boundary 0):
529  {
530  unsigned n_node = Fluid_mesh_pt->nboundary_node(0);
531  for (unsigned n=0;n<n_node;n++)
532  {
533  // Pin vertical velocity
534  Fluid_mesh_pt->boundary_node_pt(0,n)->pin(1);
535  }
536  }
537 
538  // Ring boundary (boundary 1):
539  // No slip; this also implies that the velocity needs
540  // to be updated in response to wall motion
541  {
542  unsigned n_node = Fluid_mesh_pt->nboundary_node(1);
543  for (unsigned n=0;n<n_node;n++)
544  {
545  // Which node are we dealing with?
546  Node* node_pt=Fluid_mesh_pt->boundary_node_pt(1,n);
547 
548  // Set auxiliary update function pointer
549  node_pt->set_auxiliary_node_update_fct_pt(
550  FSI_functions::apply_no_slip_on_moving_wall);
551 
552  // Pin both velocities
553  for(unsigned i=0;i<2;i++) {node_pt->pin(i);}
554  }
555  }
556 
557  // Left boundary (boundary 2):
558  {
559  unsigned n_node = Fluid_mesh_pt->nboundary_node(2);
560  for (unsigned n=0;n<n_node;n++)
561  {
562  // Pin horizontal velocity
563  Fluid_mesh_pt->boundary_node_pt(2,n)->pin(0);
564  }
565  }
566 
567 
568  //--------------------------------------------------------
569  // Add the submeshes and build global mesh
570  // -------------------------------------------------------
571 
572  // Wall mesh
573  add_sub_mesh(Wall_mesh_pt);
574 
575  //Fluid mesh
576  add_sub_mesh(Fluid_mesh_pt);
577 
578  // Combine all submeshes into a single Mesh
579  build_global_mesh();
580 
581 
582  //----------------------------------------------------------
583  // Finish problem setup
584  // ---------------------------------------------------------
585 
586  //Find number of elements in fluid mesh
587  unsigned n_element = Fluid_mesh_pt->nelement();
588 
589  bool done=false;
590 
591  // Loop over the fluid elements to set up element-specific
592  // things that cannot be handled by constructor
593  for(unsigned e=0;e<n_element;e++)
594  {
595  // Upcast from FiniteElement to the present element
596  FLUID_ELEMENT *el_pt
597  = dynamic_cast<FLUID_ELEMENT*>(Fluid_mesh_pt->element_pt(e));
598 
599  //Set the Reynolds number, etc
600  el_pt->re_pt() = &Global_Physical_Variables::Re;
601  el_pt->re_st_pt() = &Global_Physical_Variables::ReSt;
602 
603  // Choose evaluation of shape derivatives
604 
605  // Direct FD
606  if (i_case==0)
607  {
608  el_pt->evaluate_shape_derivs_by_direct_fd();
609  if (!done) std::cout << "\n\n [CR residuals] Direct FD" << std::endl;
610  }
611  // Chain rule with/without FD
612  else if ( (i_case==1) || (i_case==2) )
613  {
614  // It's broken but let's call it anyway to keep self-test alive
615  bool i_know_what_i_am_doing=true;
616  el_pt->evaluate_shape_derivs_by_chain_rule(i_know_what_i_am_doing);
617  if (i_case==1)
618  {
619  el_pt->enable_always_evaluate_dresidual_dnodal_coordinates_by_fd();
620  if (!done) std::cout << "\n\n [CR residuals] Chain rule and FD"
621  << std::endl;
622  }
623  else
624  {
625  el_pt->disable_always_evaluate_dresidual_dnodal_coordinates_by_fd();
626  if (!done) std::cout << "\n\n [CR residuals] Chain rule and analytic"
627  << std::endl;
628  }
629  }
630  // Fastest with/without FD
631  else if ( (i_case==3) || (i_case==4) )
632  {
633 
634  // It's broken but let's call it anyway to keep self-test alive
635  bool i_know_what_i_am_doing=true;
636  el_pt->evaluate_shape_derivs_by_fastest_method(i_know_what_i_am_doing);
637  if (i_case==3)
638  {
639  el_pt->enable_always_evaluate_dresidual_dnodal_coordinates_by_fd();
640  if (!done) std::cout << "\n\n [CR residuals] Fastest and FD"
641  << std::endl;
642  }
643  else
644  {
645  el_pt->disable_always_evaluate_dresidual_dnodal_coordinates_by_fd();
646  if (!done) std::cout << "\n\n [CR residuals] Fastest and analytic"
647  << std::endl;
648  }
649  }
650  done=true;
651 
652  }
653 
654 
655  //Loop over the solid elements to set physical parameters etc.
656  unsigned n_wall_element = Wall_mesh_pt->nelement();
657  for(unsigned e=0;e<n_wall_element;e++)
658  {
659  //Cast to proper element type
660  SOLID_ELEMENT *el_pt = dynamic_cast<SOLID_ELEMENT*>(
661  Wall_mesh_pt->element_pt(e));
662 
663  //Set physical parameters for each element:
664  el_pt->h_pt() = &Global_Physical_Variables::H;
665  el_pt->lambda_sq_pt() = &Global_Physical_Variables::Lambda_sq;
666 
667  //Function that specifies the external load Vector
668  el_pt->load_vector_fct_pt() = &Global_Physical_Variables::pcos_load;
669 
670  // Function that specifies the load ratios
671  el_pt->q_pt() = &Global_Physical_Variables::Q;
672 
673  //Assign the undeformed beam shape
674  el_pt->undeformed_beam_pt() = Undef_geom_pt;
675  }
676 
677  // Establish control displacment: (even if no displacement control is applied
678  // we still want to doc the displacement at the same point)
679 
680  // Choose element: (This is the last one)
681  Doc_displacement_elem_pt = dynamic_cast<SOLID_ELEMENT*>(
682  Wall_mesh_pt->element_pt(n_wall_element-1));
683 
684  // Setup fsi: Work out which fluid dofs affect the wall elements
685  // the correspondance between wall dofs and fluid elements is handled
686  // during the remeshing, but the "reverse" association must be done
687  // separately.
688  // We pass the boundary between the fluid and solid meshes and pointers
689  // to the meshes. The interaction boundary is boundary 1 of the
690  // 2D fluid mesh.
691  FSI_functions::setup_fluid_load_info_for_solid_elements<FLUID_ELEMENT,2>
692  (this,1,Fluid_mesh_pt,Wall_mesh_pt);
693 
694  // Do equation numbering
695  cout << "# of dofs " << assign_eqn_numbers() << std::endl;
696 
697 }
698 
699 
700 //=========================================================================
701 /// Solver loop to perform unsteady run
702 //=========================================================================
703 void FSIRingProblem::dynamic_run(const unsigned& i_case)
704 {
705  // Setup documentation
706  //---------------------------------------------------------------
707 
708  /// Label for output
709  DocInfo doc_info;
710 
711  // Output directory
712  doc_info.set_directory("RESLT");
713 
714  // Step number
715  doc_info.number()=0;
716 
717  //Open a trace file
718  ofstream trace_file("RESLT/trace_ring.dat");
719 
720  // Write header for trace file
721  trace_file << "VARIABLES=\"time\",\"V_c_t_r_l\"";
722  trace_file << ",\"x<sub>1</sub><sup>(track)</sup>\"";
723  trace_file << ",\"x<sub>2</sub><sup>(track)</sup>\"";
724  trace_file << ",\"u<sub>1</sub><sup>(track)</sup>\"";
725  trace_file << ",\"u<sub>2</sub><sup>(track)</sup>\"";
726  trace_file << ",\"N<sub>element</sub>\"";
727  trace_file << ",\"N<sub>dof</sub>\"";
728  trace_file << ",\"# of under-refined elements\"";
729  trace_file << ",\"max. error\"";
730  trace_file << ",\"min. error\"";
731  trace_file << ",\"max. permitted error\"";
732  trace_file << ",\"min. permitted error\"";
733  trace_file << ",\"max. permitted # of unrefined elements\"";
734  trace_file << ",\"doc number\"";
735  trace_file << std::endl;
736 
737 
738  // Initialise timestepping
739  // -------------------------------------------------------------
740 
741  // Number of steps
742  unsigned nstep=300;
743 
744  // Nontrivial command line input: validation: only do three steps
745  if (CommandLineArgs::Argc>1)
746  {
747  nstep=1;
748  cout << "Only doing nstep steps for validation: " << nstep << std::endl;
749  }
750 
751  // Set initial timestep
752  double dt=0.004;
753 
754  // Set initial value for dt -- also assigns weights to the timesteppers
755  initialise_dt(dt);
756 
757  // Set physical parameters
758  //---------------------------------------------------------
759  using namespace Global_Physical_Variables;
760 
761  // Set Womersley number
762  Alpha_sq=100.0; // 50.0; // ADJUST
763 
764  // Set density ratio
765  Density_ratio=10.0; // 0.0; ADJUST
766 
767  // Wall thickness
768  H=1.0/20.0;
769 
770  // Set external pressure
771  Pext=0.0;
772 
773  /// Perturbation pressure
774  Pcos=Pcos_initial;
775 
776  // Assign/doc corresponding computational parameters
777  set_params();
778 
779 
780  // Refine uniformly and assign initial conditions
781  //--------------------------------------------------------------
782 
783  // Refine the problem uniformly
784  //refine_uniformly();
785  //refine_uniformly();
786 
787  // This sets up the solution at the initial time
789 
790  // Set targets for spatial adptivity
791  //---------------------------------------------------------------
792 
793  // Max. and min. error for adaptive refinement/unrefinement
794  Fluid_mesh_pt->max_permitted_error()=1.0e-2;
795  Fluid_mesh_pt->min_permitted_error()=1.0e-3;
796 
797  // Don't allow refinement to drop under given level
798  Fluid_mesh_pt->min_refinement_level()=2;
799 
800  // Don't allow refinement beyond given level
801  Fluid_mesh_pt->max_refinement_level()=6;
802 
803  // Don't bother adapting the mesh if no refinement is required
804  // and if less than ... elements are to be merged.
805  Fluid_mesh_pt->max_keep_unrefined()=20;
806 
807  // Doc refinement targets
808  Fluid_mesh_pt->doc_adaptivity_targets(cout);
809 
810 
811  // Do the timestepping
812  //----------------------------------------------------------------
813 
814  // Reset initial conditions after refinement for first step only
815  bool first=true;
816 
817  //Output initial data
818  doc_solution(0,doc_info,trace_file,i_case);
819 
820 
821 // {
822 // unsigned nel=Fluid_mesh_pt->nelement();
823 // for (unsigned e=0;e<nel;e++)
824 // {
825 // std::cout << "\n\nEl: " << e << std::endl << std::endl;
826 // FiniteElement* el_pt=Fluid_mesh_pt->finite_element_pt(e);
827 // unsigned n_dof=el_pt->ndof();
828 // Vector<double> residuals(n_dof);
829 // DenseDoubleMatrix jacobian(n_dof,n_dof);
830 // el_pt->get_jacobian(residuals,jacobian);
831 // }
832 // exit(0);
833 // }
834 
835  // Time integration loop
836  for(unsigned i=1;i<=nstep;i++)
837  {
838  // Switch doc off during solve
839  doc_info.disable_doc();
840 
841  // Solve
842  unsigned max_adapt=1;
843  unsteady_newton_solve(dt,max_adapt,first);
844 
845  // Now we've done the first step
846  first=false;
847 
848  // Doc solution
849  doc_solution(i,doc_info,trace_file,i_case);
850 
851  /// Switch off perturbation pressure
852  if (time_pt()->time()>Pcos_duration) {Pcos=0.0;}
853 
854  }
855 
856 }
857 
858 
859 //=====================================================================
860 /// Driver for fsi ring test problem
861 //=====================================================================
862 int main(int argc, char* argv[])
863 {
864 
865  // Store command line arguments
866  CommandLineArgs::setup(argc,argv);
867 
868  // Number of elements
869  unsigned nelem = 13;
870 
871  /// Perturbation pressure
872  double pcos_initial=1.0e-6; // ADJUST
873 
874  /// Duration of initial pcos perturbation
875  double pcos_duration=0.3; // ADJUST
876 
877  /// Amplitude of initial deformation
878  double eps_ampl=0.0; // ADJUST
879 
880 
881 
882  // Loop over all cases
883  for (unsigned i_case=0;i_case<5;i_case++)
884  {
885  std::cout << "[CR residuals] " << std::endl;
886  std::cout << "[CR residuals]=================================================="
887  << std::endl;
888  std::cout << "[CR residuals] " << std::endl;
889 
890  //Set up the problem
891  FSIRingProblem problem(nelem,eps_ampl,pcos_initial,pcos_duration,i_case);
892 
893  // Do parameter study
894  problem.dynamic_run(i_case);
895  }
896 
897 }
898 
899 
900 
901 
902 
903 
void doc_solution(const unsigned &i, DocInfo &doc_info, ofstream &trace_file)
Doc solution: Pass number of timestep, i (we append to tracefile after every timestep but do a full d...
double Density_ratio
Density ratio of the solid and the fluid.
Definition: fsi_osc_ring.cc:59
void set_params()
Set the parameters that are used in the code as a function of the Womersley number, the density ratio and H.
Definition: fsi_osc_ring.cc:91
double Lambda_sq
Timescale ratio (non-dimensation density)
Definition: fsi_osc_ring.cc:84
double Pcos
Perturbation pressure.
Definition: fsi_osc_ring.cc:71
AlgebraicRefineableQuarterCircleSectorMesh< FLUID_ELEMENT > * Fluid_mesh_pt
Pointer to fluid mesh.
void set_fluid_initial_condition()
Setup initial condition for fluid.
double Pcos_initial
Initial pcos.
double Q
Stress ratio.
Definition: fsi_osc_ring.cc:87
void dynamic_run()
Do dynamic run.
double ReSt
Reynolds x Strouhal number.
Definition: fsi_osc_ring.cc:81
void set_initial_condition()
Setup initial condition for both domains.
double Pcos_duration
Duration of initial pcos.
double Pext
External Pressure.
Definition: fsi_osc_ring.cc:62
double Re
Reynolds number.
Definition: fsi_osc_ring.cc:78
BDF< 2 > * Fluid_time_stepper_pt
Pointer to fluid timestepper.
Namespace for physical parameters.
Definition: fsi_osc_ring.cc:49
double H
Nondimensional thickness of the beam.
Definition: fsi_osc_ring.cc:68
GeomObject * Undef_geom_pt
Pointer to geometric object that represents the undeformed wall shape.
SOLID_ELEMENT * Doc_displacement_elem_pt
Element used for documenting displacement.
Newmark< 2 > * Wall_time_stepper_pt
Pointer to wall timestepper.
FSIHermiteBeamElement SOLID_ELEMENT
Typedef to specify the solid element used.
void actions_after_adapt()
Update the problem specs after adaptation:
double Alpha_sq
Square of Womersly number (a frequency parameter)
Definition: fsi_osc_ring.cc:56
int main(int argc, char *argv[])
Driver for fsi ring test problem.
void actions_after_newton_solve()
Update after solve (empty)
FSIRingProblem(const unsigned &nelement_wall, const double &eps_ampl, const double &pcos_initial, const double &pcos_duration)
void pcos_load(const Vector< double > &xi, const Vector< double > &x, const Vector< double > &N, Vector< double > &load)
void set_wall_initial_condition()
Setup initial condition for wall.
AlgebraicElement< RefineableQCrouzeixRaviartElement< 2 > > FLUID_ELEMENT
There are very few element types that will work for this problem. Rather than passing the element typ...
OneDLagrangianMesh< SOLID_ELEMENT > * Wall_mesh_pt
Pointer to wall mesh.
double Nu
Poisson ratio.
Definition: fsi_osc_ring.cc:65
void actions_before_newton_solve()
Update before solve (empty)
Node * Veloc_trace_node_pt
Pointer to node on coarsest mesh on which velocity is traced.
void actions_before_newton_convergence_check()
Update the problem specs before checking Newton convergence.