collapsible_channel.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 #include <iostream>
31 
32 // Generic oomph-lib includes
33 #include "generic.h"
34 
35 // Generic oomph-lib includes
36 #include "navier_stokes.h"
37 
38 //Include the mesh
39 #include "meshes/collapsible_channel_mesh.h"
40 
41 using namespace std;
42 
43 using namespace oomph;
44 
45 //==========start_of_BL_Squash =========================================
46 /// Namespace to define the mapping [0,1] -> [0,1] that re-distributes
47 /// nodal points across the channel width.
48 //======================================================================
49 namespace BL_Squash
50 {
51 
52  /// Boundary layer width
53  double Delta=0.1;
54 
55  /// Fraction of points in boundary layer
56  double Fract_in_BL=0.5;
57 
58  /// \short Mapping [0,1] -> [0,1] that re-distributes
59  /// nodal points across the channel width
60  double squash_fct(const double& s)
61  {
62  // Default return
63  double y=s;
64  if (s<0.5*Fract_in_BL)
65  {
66  y=Delta*2.0*s/Fract_in_BL;
67  }
68  else if (s>1.0-0.5*Fract_in_BL)
69  {
70  y=2.0*Delta/Fract_in_BL*s+1.0-2.0*Delta/Fract_in_BL;
71  }
72  else
73  {
74  y=(1.0-2.0*Delta)/(1.0-Fract_in_BL)*s+
75  (Delta-0.5*Fract_in_BL)/(1.0-Fract_in_BL);
76  }
77 
78  return y;
79  }
80 }// end of BL_Squash
81 
82 
83 
84 
85 
86 //===============start_of_oscillating_wall=================================
87 /// Straight, horizontal channel wall at \f$ y=H \f$ deforms into an
88 /// oscillating parabola. The amplitude of the oscillation
89 /// \f$ A \f$ and its period is \f$ T \f$.
90 /// The position vector to a point on the wall, parametrised by
91 /// the Lagrangian coordinate \f$ \zeta \in [0,L]\f$, is therefore given by
92 /// \f[ {\bf R}(\zeta,t) =
93 /// \left(
94 /// \begin{array}{c}
95 /// L_{up} + \zeta \\ 1
96 /// \end{array}
97 /// \right)
98 /// + A
99 /// \left(
100 /// \begin{array}{l}
101 /// - B \sin\left(\frac{2\pi}{L_{collapsible}}\zeta\right) \\ \left(
102 /// \frac{2}{L_{collapsible}}\right)^2 \zeta \ (L-\zeta)
103 /// \end{array}
104 /// \right)
105 /// \ \sin\left(\frac{2\pi t}{T}\right)
106 /// \ {\cal R}(t)
107 /// \f]
108 /// The parameter \f$ B \f$ is zero by default. If it is set to a nonzero
109 /// value, the material particles on the wall also perform some
110 /// horizontal motion. The "ramp" function
111 /// \f[
112 /// {\cal R}(t) = \left\{
113 /// \begin{array}{ll}
114 /// \frac{1}{2}(1-\cos(\pi t/T)) & \mbox{for $t<T$} \\ 1 & \mbox{for $t \ge T$}
115 /// \end{array}
116 /// \right.
117 /// \f]
118 /// provides a "smooth" startup of the oscillation.
119 //=========================================================================
120 class OscillatingWall : public GeomObject
121 {
122 
123 public:
124 
125  /// \short Constructor : It's a 2D object, parametrised by
126  /// one Lagrangian coordinate. Arguments: height at ends, x-coordinate of
127  /// left end, length, amplitude of deflection, period of oscillation, and
128  /// pointer to time object
129  OscillatingWall(const double& h, const double& x_left, const double& l,
130  const double& a, const double& period, Time* time_pt) :
131  GeomObject(1,2), H(h), Length(l), X_left(x_left), A(a), B(0.0), T(period),
132  Time_pt(time_pt)
133  {}
134 
135  /// Destructor: Empty
137 
138 ///Access function to the amplitude
139  double& amplitude(){return A;}
140 
141 ///Access function to the period
142  double& period(){return T;}
143 
144  /// \short Position vector at Lagrangian coordinate zeta
145  /// at time level t.
146  void position(const unsigned& t, const Vector<double>&zeta,
147  Vector<double>& r) const
148  {
149  using namespace MathematicalConstants;
150 
151  // Smoothly ramp up the oscillation during the first period
152  double ramp=1.0;
153  if (Time_pt->time(t)<T)
154  {
155  ramp=0.5*(1.0-cos(Pi*Time_pt->time(t)/T));
156  }
157 
158  // Position vector
159  r[0] = zeta[0]+X_left
160  -B*A*sin(2.0*3.14159*zeta[0]/Length)*
161  sin(2.0*Pi*(Time_pt->time(t))/T)*ramp;
162 
163  r[1] = H+A*((Length-zeta[0])*zeta[0])/pow(0.5*Length,2)*
164  sin(2.0*Pi*(Time_pt->time(t))/T)*ramp;
165 
166  } // end of "unsteady" version
167 
168 
169  /// \short "Current" position vector at Lagrangian coordinate zeta
170  void position(const Vector<double>&zeta, Vector<double>& r) const
171  {
172  position (0, zeta, r);
173  }
174 
175  /// Number of geometric Data in GeomObject: None.
176  unsigned ngeom_data() const {return 0;}
177 
178 private:
179 
180  /// Height at ends
181  double H;
182 
183  /// Length
184  double Length;
185 
186  /// x-coordinate of left end
187  double X_left;
188 
189  /// Amplitude of oscillation
190  double A;
191 
192  /// Relative amplitude of horizontal wall motion
193  double B;
194 
195  ///Period of the oscillations
196  double T;
197 
198  ///Pointer to the global time object
199  Time* Time_pt;
200 
201 }; // end of oscillating wall
202 
203 
204 
205 
206 //====start_of_Global_Physical_Variables================
207 /// Namespace for phyical parameters
208 //======================================================
210 {
211  /// Reynolds number
212  double Re=50.0;
213 
214  /// Womersley = Reynolds times Strouhal
215  double ReSt=50.0;
216 
217  /// Default pressure on the left boundary
218  double P_up=0.0;
219 
220  /// Traction required at the left boundary
221  void prescribed_traction(const double& t,
222  const Vector<double>& x,
223  const Vector<double>& n,
224  Vector<double>& traction)
225  {
226  traction.resize(2);
227  traction[0]=P_up;
228  traction[1]=0.0;
229  }
230 
231 } // end of Global_Physical_Variables
232 
233 
234 
235 //=======start_of_problem_class=======================================
236 ///Problem class
237 //====================================================================
238 template <class ELEMENT>
239 class CollapsibleChannelProblem : public Problem
240 {
241 
242  public :
243 
244  /// \short Constructor : the arguments are the number of elements,
245  /// the length of the domain and the amplitude and period of
246  ///the oscillations
247  CollapsibleChannelProblem(const unsigned& nup,
248  const unsigned& ncollapsible,
249  const unsigned& ndown,
250  const unsigned& ny,
251  const double& lup,
252  const double& lcollapsible,
253  const double& ldown,
254  const double& ly,
255  const double& amplitude,
256  const double& period);
257 
258  /// Empty destructor
260 
261  /// Access function for the specific mesh
262  RefineableCollapsibleChannelMesh<ELEMENT>* bulk_mesh_pt()
263  {
264 
265  // Upcast from pointer to the Mesh base class to the specific
266  // element type that we're using here.
267  return dynamic_cast<RefineableCollapsibleChannelMesh<ELEMENT>*>
268  (Bulk_mesh_pt);
269 
270  } // end of access to bulk mesh
271 
272  /// \short Update the problem specs before solve (empty)
274 
275  /// Update the problem after solve (empty)
277 
278  /// Update the velocity boundary condition on the moving wall
279  void actions_before_implicit_timestep();
280 
281  /// Actions before adapt: Wipe the mesh of prescribed traction elements
282  void actions_before_adapt();
283 
284  /// Actions after adapt: Rebuild the mesh of prescribed traction elements
285  void actions_after_adapt();
286 
287  /// Apply initial conditions
288  void set_initial_condition();
289 
290  /// Doc the solution
291  void doc_solution(DocInfo& doc_info, ofstream& trace_file);
292 
293 private :
294 
295  /// Create the prescribed traction elements on boundary b
296  /// of the bulk mesh and stick them into the surface mesh.
297  void create_traction_elements(const unsigned &b,
298  Mesh* const &bulk_mesh_pt,
299  Mesh* const &surface_mesh_pt);
300 
301  /// Delete prescribed traction elements from the surface mesh
302  void delete_traction_elements(Mesh* const &surface_mesh_pt);
303 
304  ///Number of elements in the x direction in the upstream part of the channel
305  unsigned Nup;
306 
307  /// \short Number of elements in the x direction in the "collapsible"
308  /// part of the channel
309  unsigned Ncollapsible;
310 
311  ///Number of elements in the x direction in the downstream part of the channel
312  unsigned Ndown;
313 
314  ///Number of elements across the channel
315  unsigned Ny;
316 
317  ///x-length in the upstream part of the channel
318  double Lup;
319 
320  ///x-length in the "collapsible" part of the channel
321  double Lcollapsible;
322 
323  ///x-length in the downstream part of the channel
324  double Ldown;
325 
326  ///Transverse length
327  double Ly;
328 
329  ///Pointer to the geometric object that parametrises the "collapsible" wall
331 
332  /// Pointer to the "bulk" mesh
333  RefineableCollapsibleChannelMesh<ELEMENT>* Bulk_mesh_pt;
334 
335  /// \short Pointer to the "surface" mesh that contains the applied traction
336  /// elements
338 
339  /// Pointer to the left control node
341 
342  /// Pointer to right control node
344 
345 }; // end of problem class
346 
347 
348 
349 
350 //===start_of_constructor=======================================
351 /// Constructor for the collapsible channel problem
352 //===============================================================
353 template <class ELEMENT>
355  const unsigned& nup,
356  const unsigned& ncollapsible,
357  const unsigned& ndown,
358  const unsigned& ny,
359  const double& lup,
360  const double& lcollapsible,
361  const double& ldown,
362  const double& ly,
363  const double& amplitude,
364  const double& period)
365 {
366  // Number of elements
367  Nup=nup;
368  Ncollapsible=ncollapsible;
369  Ndown=ndown;
370  Ny=ny;
371 
372  // Lengths of domain
373  Lup=lup;
374  Lcollapsible=lcollapsible;
375  Ldown=ldown;
376  Ly=ly;
377 
378  // Overwrite maximum allowed residual to accomodate possibly
379  // poor initial guess for solution
380  Problem::Max_residuals=10000;
381 
382  // Allocate the timestepper -- this constructs the Problem's
383  // time object with a sufficient amount of storage to store the
384  // previous timsteps.
385  add_time_stepper_pt(new BDF<2>);
386 
387  // Parameters for wall object
388  double height=ly;
389  double length=lcollapsible;
390  double x_left=lup;
391 
392  //Create the geometric object that represents the wall
393  Wall_pt=new OscillatingWall(height, x_left, length, amplitude, period,
394  time_pt());
395 
396  //Build mesh
397  Bulk_mesh_pt = new RefineableCollapsibleChannelMesh<ELEMENT>(
398  nup, ncollapsible, ndown, ny,
399  lup, lcollapsible, ldown, ly,
400  Wall_pt,
401  time_stepper_pt());
402 
403 
404  // Enable boundary layer squash function?
405 #ifdef USE_BL_SQUASH_FCT
406 
407  // Set a non-trivial boundary-layer-squash function...
408  Bulk_mesh_pt->bl_squash_fct_pt() = &BL_Squash::squash_fct;
409 
410  // ... and update the nodal positions accordingly
411  Bulk_mesh_pt->node_update();
412 
413 #endif
414  // end of boundary layer squash function
415 
416 
417  // Create "surface mesh" that will contain only the prescribed-traction
418  // elements at the inflow. The default constructor just creates the mesh
419  // without giving it any elements, nodes, etc.
420  Surface_mesh_pt = new Mesh;
421 
422  // Create prescribed-traction elements from all elements that are
423  // adjacent to boundary 5 (inflow boundary), and add them to the surface mesh.
424  create_traction_elements(5,Bulk_mesh_pt,Surface_mesh_pt);
425 
426  // Add the two sub meshes to the problem
427  add_sub_mesh(Bulk_mesh_pt);
428  add_sub_mesh(Surface_mesh_pt);
429 
430  // Combine all submeshes added so far into a single Mesh
431  build_global_mesh();
432 
433  //Set errror estimator for bulk mesh
434  Z2ErrorEstimator* error_estimator_pt=new Z2ErrorEstimator;
435  dynamic_cast<RefineableCollapsibleChannelMesh<ELEMENT>*>
436  (Bulk_mesh_pt)->spatial_error_estimator_pt()=error_estimator_pt;
437 
438 
439  // Loop over the elements to set up element-specific
440  // things that cannot be handled by constructor
441  unsigned n_element=Bulk_mesh_pt->nelement();
442  for(unsigned e=0;e<n_element;e++)
443  {
444  // Upcast from GeneralisedElement to the present element
445  ELEMENT* el_pt = dynamic_cast<ELEMENT*>(Bulk_mesh_pt->element_pt(e));
446 
447  //Set the Reynolds number
448  el_pt->re_pt() = &Global_Physical_Variables::Re;
449 
450  // Set the Womersley number
451  el_pt->re_st_pt() = &Global_Physical_Variables::ReSt;
452 
453  } // end loop over bulk elements
454 
455 
456 
457  // Loop over the traction elements to pass pointer to prescribed
458  // traction function
459  unsigned n_el=Surface_mesh_pt->nelement();
460  for(unsigned e=0;e<n_el;e++)
461  {
462  // Upcast from GeneralisedElement to NavierStokes traction element
463  NavierStokesTractionElement<ELEMENT> *el_pt =
464  dynamic_cast< NavierStokesTractionElement<ELEMENT>*>(
465  Surface_mesh_pt->element_pt(e));
466 
467  // Set the pointer to the prescribed traction function
468  el_pt->traction_fct_pt() = &Global_Physical_Variables::prescribed_traction;
469 
470  } // end loop over applied traction elements
471 
472 
473 
474 
475  //Pin the velocity on the boundaries
476  //x and y-velocities pinned along boundary 0 (bottom boundary) :
477  unsigned ibound=0;
478  unsigned num_nod= bulk_mesh_pt()->nboundary_node(ibound);
479  for (unsigned inod=0;inod<num_nod;inod++)
480  {
481  for(unsigned i=0;i<2;i++)
482  {
483  bulk_mesh_pt()->boundary_node_pt(ibound, inod)->pin(i);
484  }
485  }
486 
487 
488  //x and y-velocities pinned along boundary 2, 3, 4 (top boundaries) :
489  for(unsigned ib=2;ib<5;ib++)
490  {
491  num_nod= bulk_mesh_pt()->nboundary_node(ib);
492  for (unsigned inod=0;inod<num_nod;inod++)
493  {
494  for(unsigned i=0;i<2;i++)
495  {
496  bulk_mesh_pt()->boundary_node_pt(ib, inod)->pin(i);
497  }
498  }
499  }
500 
501  //y-velocity pinned along boundary 1 (right boundary):
502  ibound=1;
503  num_nod= bulk_mesh_pt()->nboundary_node(ibound);
504  for (unsigned inod=0;inod<num_nod;inod++)
505  {
506  bulk_mesh_pt()->boundary_node_pt(ibound, inod)->pin(1);
507  }
508 
509 
510  //y-velocity pinned along boundary 5 (left boundary):
511  ibound=5;
512  num_nod= bulk_mesh_pt()->nboundary_node(ibound);
513  for (unsigned inod=0;inod<num_nod;inod++)
514  {
515  bulk_mesh_pt()->boundary_node_pt(ibound, inod)->pin(1);
516  }// end of pin_velocity
517 
518 
519 
520  //Select control nodes "half way" up the inflow/outflow cross-sections
521  //--------------------------------------------------------------------
522 
523  // Left boundary
524  ibound=5;
525  num_nod= bulk_mesh_pt()->nboundary_node(ibound);
526  unsigned control_nod=num_nod/2;
527  Left_node_pt= bulk_mesh_pt()->boundary_node_pt(ibound, control_nod);
528 
529  // Right boundary
530  ibound=1;
531  num_nod= bulk_mesh_pt()->nboundary_node(ibound);
532  control_nod=num_nod/2;
533  Right_node_pt= bulk_mesh_pt()->boundary_node_pt(ibound, control_nod);
534 
535  // Setup equation numbering scheme
536  cout <<"Number of equations: " << assign_eqn_numbers() << std::endl;
537 
538 } //end of constructor
539 
540 
541 
542 
543 //====start_of_doc_solution===================================================
544 /// Doc the solution
545 //============================================================================
546 template <class ELEMENT>
548  ofstream& trace_file)
549 {
550  ofstream some_file;
551  char filename[100];
552 
553  // Number of plot points
554  unsigned npts;
555  npts=5;
556 
557  // Output solution
558  sprintf(filename,"%s/soln%i.dat",doc_info.directory().c_str(),
559  doc_info.number());
560  some_file.open(filename);
561  bulk_mesh_pt()->output(some_file,npts);
562  some_file.close();
563 
564 
565  // Get the position of the midpoint on the geometric object
566  Vector<double> zeta(1);
567  zeta[0]=0.5*Lcollapsible;
568  Vector<double> wall_point(2);
569  Wall_pt->position(zeta,wall_point);
570 
571  // Write trace file
572  trace_file << time_pt()->time() << " "
573  << wall_point[1] << " "
574  << Left_node_pt->value(0) << " "
575  << Right_node_pt->value(0) << " "
576  << std::endl;
577 
578  // Output wall shape
579  sprintf(filename,"%s/wall%i.dat",doc_info.directory().c_str(),
580  doc_info.number());
581  some_file.open(filename);
582  unsigned nplot=100;
583  for (unsigned i=0;i<nplot;i++)
584  {
585  zeta[0]=double(i)/double(nplot-1)*Lcollapsible;
586  Wall_pt->position(zeta,wall_point);
587  some_file << wall_point[0] << " "
588  << wall_point[1] << std::endl;
589  }
590  some_file.close();
591 
592 } // end_of_doc_solution
593 
594 
595 
596 
597 //==========start_of_create_traction_elements==================================
598 /// Create the traction elements
599 //============================================================================
600 template <class ELEMENT>
602  const unsigned &b, Mesh* const &bulk_mesh_pt, Mesh* const &surface_mesh_pt)
603 {
604  // How many bulk elements are adjacent to boundary b?
605  unsigned n_element = bulk_mesh_pt->nboundary_element(b);
606 
607  // Loop over the bulk elements adjacent to boundary b
608  for(unsigned e=0;e<n_element;e++)
609  {
610  // Get pointer to the bulk element that is adjacent to boundary b
611  ELEMENT* bulk_elem_pt = dynamic_cast<ELEMENT*>
612  (bulk_mesh_pt->boundary_element_pt(b,e));
613 
614  //What is the index of the face of element e that lies along boundary b
615  int face_index = bulk_mesh_pt->face_index_at_boundary(b,e);
616 
617  // Build the corresponding prescribed-traction element
618  NavierStokesTractionElement<ELEMENT>* traction_element_pt =
619  new NavierStokesTractionElement<ELEMENT>(bulk_elem_pt,face_index);
620 
621  //Add the prescribed-flux element to the surface mesh
622  surface_mesh_pt->add_element_pt(traction_element_pt);
623 
624  } //end of loop over bulk elements adjacent to boundary b
625 
626 } // end of create_traction_elements
627 
628 
629 //============start_of_delete_traction_elements==============================
630 /// Delete traction elements and wipe the surface mesh
631 //=======================================================================
632 template<class ELEMENT>
634 delete_traction_elements(Mesh* const &surface_mesh_pt)
635 {
636  // How many surface elements are in the surface mesh
637  unsigned n_element = surface_mesh_pt->nelement();
638 
639  // Loop over the surface elements
640  for(unsigned e=0;e<n_element;e++)
641  {
642  // Kill surface element
643  delete surface_mesh_pt->element_pt(e);
644  }
645 
646  // Wipe the mesh
647  surface_mesh_pt->flush_element_and_node_storage();
648 
649 } // end of delete_traction_elements
650 
651 
652 
653 //=======start_of_apply_initial_conditions===================================
654 /// Apply initial conditions: Impulsive start from steady Poiseuille flow
655 //============================================================================
656 template <class ELEMENT>
658 {
659 
660  // Check that timestepper is from the BDF family
661  if (time_stepper_pt()->type()!="BDF")
662  {
663  std::ostringstream error_stream;
664  error_stream
665  << "Timestepper has to be from the BDF family!\n"
666  << "You have specified a timestepper from the "
667  << time_stepper_pt()->type() << " family" << std::endl;
668 
669  throw OomphLibError(error_stream.str(),
670  OOMPH_CURRENT_FUNCTION,
671  OOMPH_EXCEPTION_LOCATION);
672  }
673 
674  // Update the mesh
675  bulk_mesh_pt()->node_update();
676 
677  // Loop over the nodes to set initial guess everywhere
678  unsigned num_nod = bulk_mesh_pt()->nnode();
679  for (unsigned n=0;n<num_nod;n++)
680  {
681  // Get nodal coordinates
682  Vector<double> x(2);
683  x[0]=bulk_mesh_pt()->node_pt(n)->x(0);
684  x[1]=bulk_mesh_pt()->node_pt(n)->x(1);
685 
686  // Assign initial condition: Steady Poiseuille flow
687  bulk_mesh_pt()->node_pt(n)->set_value(0,6.0*(x[1]/Ly)*(1.0-(x[1]/Ly)));
688  bulk_mesh_pt()->node_pt(n)->set_value(1,0.0);
689  }
690 
691  // Assign initial values for an impulsive start
692  bulk_mesh_pt()->assign_initial_values_impulsive();
693 
694 
695 } // end of set_initial_condition
696 
697 
698 
699 //=====start_of_actions_before_implicit_timestep==============================
700 /// Execute the actions before timestep: Update the velocity
701 /// boundary condition on the moving wall
702 //============================================================================
703 template <class ELEMENT>
705 {
706  // Update the domain shape
707  bulk_mesh_pt()->node_update();
708 
709  // Moving wall: No slip; this implies that the velocity needs
710  // to be updated in response to wall motion
711  unsigned ibound=3;
712  unsigned num_nod=bulk_mesh_pt()->nboundary_node(ibound);
713  for (unsigned inod=0;inod<num_nod;inod++)
714  {
715  // Which node are we dealing with?
716  Node* node_pt=bulk_mesh_pt()->boundary_node_pt(ibound,inod);
717 
718  // Apply no slip
719  FSI_functions::apply_no_slip_on_moving_wall(node_pt);
720  }
721 } //end of actions_before_implicit_timestep
722 
723 
724 
725 
726 //=========start_of_actions_before_adapt==================================
727 /// Actions before adapt: Wipe the mesh of prescribed traction elements
728 //========================================================================
729 template<class ELEMENT>
731 {
732  // Kill the traction elements and wipe surface mesh
733  delete_traction_elements(Surface_mesh_pt);
734 
735  // Rebuild the global mesh.
736  rebuild_global_mesh();
737 
738 } // end of actions_before_adapt
739 
740 
741 //==========start_of_actions_after_adapt==================================
742 /// Actions after adapt: Rebuild the mesh of prescribed traction elements
743 //========================================================================
744 template<class ELEMENT>
746 {
747  // Create prescribed-flux elements from all elements that are
748  // adjacent to boundary 5 and add them to surface mesh
749  create_traction_elements(5,Bulk_mesh_pt,Surface_mesh_pt);
750 
751  // Rebuild the global mesh
752  rebuild_global_mesh();
753 
754  // Loop over the traction elements to pass pointer to prescribed traction function
755  unsigned n_element=Surface_mesh_pt->nelement();
756  for(unsigned e=0;e<n_element;e++)
757  {
758  // Upcast from GeneralisedElement to NavierStokesTractionElement element
759  NavierStokesTractionElement<ELEMENT> *el_pt =
760  dynamic_cast<NavierStokesTractionElement<ELEMENT>*>(
761  Surface_mesh_pt->element_pt(e));
762 
763  // Set the pointer to the prescribed traction function
764  el_pt->traction_fct_pt() = &Global_Physical_Variables::prescribed_traction;
765  }
766 } // end of actions_after_adapt
767 
768 
769 
770 //=======start_of_driver_code==================================================
771 /// Driver code for an unsteady adaptive collapsible channel problem
772 /// with prescribed wall motion. Presence of command line arguments
773 /// indicates validation run with coarse resolution and small number of
774 /// timesteps.
775 //=============================================================================
776 int main(int argc, char* argv[])
777 {
778 
779  // Store command line arguments
780  CommandLineArgs::setup(argc,argv);
781 
782  // Reduction in resolution for validation run?
783  unsigned coarsening_factor=1;
784  if (CommandLineArgs::Argc>1)
785  {
786  coarsening_factor=4;
787  }
788 
789  // Number of elements in the domain
790  unsigned nup=20/coarsening_factor;
791  unsigned ncollapsible=40/coarsening_factor;
792  unsigned ndown=40/coarsening_factor;
793  unsigned ny=16/coarsening_factor;
794 
795  // Length of the domain
796  double lup=5.0;
797  double lcollapsible=10.0;
798  double ldown=10.0;
799  double ly=1.0;
800 
801  // Initial amplitude of the wall deformation
802  double amplitude=1.0e-2; // ADJUST
803 
804  // Period of oscillation
805  double period=0.45;
806 
807  // Pressure/applied traction on the left boundary: This is consistent with
808  // steady Poiseuille flow
809  Global_Physical_Variables::P_up=12.0*(lup+lcollapsible+ldown);
810 
811 
812  //Set output directory
813  DocInfo doc_info;
814  doc_info.set_directory("RESLT");
815 
816  // Open a trace file
817  ofstream trace_file;
818  char filename[100];
819  sprintf(filename,"%s/trace.dat",doc_info.directory().c_str());
820  trace_file.open(filename);
821 
822  // Build the problem with Crouzeix Raviart Elements
824  problem(nup, ncollapsible, ndown, ny,
825  lup, lcollapsible, ldown, ly,
826  amplitude,period);
827 
828 
829  // Number of timesteps per period
830  unsigned nsteps_per_period=40;
831 
832  // Number of periods
833  unsigned nperiod=3;
834 
835  // Number of timesteps (reduced for validation)
836  unsigned nstep=nsteps_per_period*nperiod;
837  if (CommandLineArgs::Argc>1)
838  {
839  nstep=3;
840  }
841 
842  //Timestep:
843  double dt=period/double(nsteps_per_period);
844 
845  // Start time
846  double t_min=0.0;
847 
848  // Initialise timestep and set initial conditions
849  problem.time_pt()->time()=t_min;
850  problem.initialise_dt(dt);
851  problem.set_initial_condition();
852 
853  // Output the initial solution
854  problem.doc_solution(doc_info, trace_file);
855 
856  // Step number
857  doc_info.number()++;
858 
859 
860  // Set targets for spatial adaptivity
861  problem.bulk_mesh_pt()->max_permitted_error()=1.0e-3;
862  problem.bulk_mesh_pt()->min_permitted_error()=1.0e-5;
863 
864  // Overwrite with reduced targets for validation run to force
865  // some refinement during the first few timesteps
866  if (CommandLineArgs::Argc>1)
867  {
868  problem.bulk_mesh_pt()->max_permitted_error()=1.0e-4;
869  problem.bulk_mesh_pt()->min_permitted_error()=1.0e-6;
870  }
871 
872 
873  // First timestep: We may re-assign the initial condition
874  // following any mesh adaptation.
875  bool first=true;
876 
877  // Max. number of adaptations during first timestep
878  unsigned max_adapt=10;
879 
880  // Timestepping loop
881  for (unsigned istep=0;istep<nstep;istep++)
882  {
883  // Solve the problem
884  problem.unsteady_newton_solve(dt, max_adapt, first);
885 
886 
887  // Outpt the solution
888  problem.doc_solution(doc_info, trace_file);
889 
890  // Step number
891  doc_info.number()++;
892 
893  // We've done one step: Don't re-assign the initial conditions
894  // and limit the number of adaptive mesh refinements to one
895  // per timestep.
896  first=false;
897  max_adapt=1;
898  }
899 
900  trace_file.close();
901 
902 } //end of driver code
903 
904 
905 
906 // {
907 // unsigned n=100;
908 // for (unsigned i=0;i<n;i++)
909 // {
910 // double s=double(i)/double(n-1);
911 // cout << s << " " << BL_Squash::squash_fct(s) << std::endl;
912 // }
913 // pause("done");
914 // }
double Ly
Transverse length.
double Lcollapsible
x-length in the "collapsible" part of the channel
double T
Period of the oscillations.
void doc_solution(DocInfo &doc_info, ofstream &trace_file)
Doc the solution.
double & amplitude()
Access function to the amplitude.
Node * Right_node_pt
Pointer to right control node.
Node * Left_node_pt
Pointer to the left control node.
unsigned Ncollapsible
Number of elements in the x direction in the "collapsible" part of the channel.
double Length
Length.
OscillatingWall(const double &h, const double &x_left, const double &l, const double &a, const double &period, Time *time_pt)
Constructor : It&#39;s a 2D object, parametrised by one Lagrangian coordinate. Arguments: height at ends...
void delete_traction_elements(Mesh *const &surface_mesh_pt)
Delete prescribed traction elements from the surface mesh.
double P_up
Default pressure on the left boundary.
Mesh * Surface_mesh_pt
Pointer to the "surface" mesh that contains the applied traction elements.
void actions_after_adapt()
Actions after adapt: Rebuild the mesh of prescribed traction elements.
double ReSt
Womersley = Reynolds times Strouhal.
Time * Time_pt
Pointer to the global time object.
void actions_before_implicit_timestep()
Update the velocity boundary condition on the moving wall.
RefineableCollapsibleChannelMesh< ELEMENT > * bulk_mesh_pt()
Access function for the specific mesh.
double A
Amplitude of oscillation.
void set_initial_condition()
Apply initial conditions.
double Delta
Boundary layer width.
~OscillatingWall()
Destructor: Empty.
double Re
Reynolds number.
void actions_before_adapt()
Actions before adapt: Wipe the mesh of prescribed traction elements.
~CollapsibleChannelProblem()
Empty destructor.
unsigned Ndown
Number of elements in the x direction in the downstream part of the channel.
double Fract_in_BL
Fraction of points in boundary layer.
void prescribed_traction(const double &t, const Vector< double > &x, const Vector< double > &n, Vector< double > &traction)
Traction required at the left boundary.
void actions_before_newton_solve()
Update the problem specs before solve (empty)
Namespace for phyical parameters.
double X_left
x-coordinate of left end
void actions_after_newton_solve()
Update the problem after solve (empty)
void create_traction_elements(const unsigned &b, Mesh *const &bulk_mesh_pt, Mesh *const &surface_mesh_pt)
Create the traction elements.
void position(const unsigned &t, const Vector< double > &zeta, Vector< double > &r) const
Position vector at Lagrangian coordinate zeta at time level t.
double Lup
x-length in the upstream part of the channel
RefineableCollapsibleChannelMesh< ELEMENT > * Bulk_mesh_pt
Pointer to the "bulk" mesh.
double B
Relative amplitude of horizontal wall motion.
double Ldown
x-length in the downstream part of the channel
unsigned Ny
Number of elements across the channel.
OscillatingWall * Wall_pt
Pointer to the geometric object that parametrises the "collapsible" wall.
double squash_fct(const double &s)
Mapping [0,1] -> [0,1] that re-distributes nodal points across the channel width. ...
unsigned ngeom_data() const
Number of geometric Data in GeomObject: None.
CollapsibleChannelProblem(const unsigned &nup, const unsigned &ncollapsible, const unsigned &ndown, const unsigned &ny, const double &lup, const double &lcollapsible, const double &ldown, const double &ly, const double &amplitude, const double &period)
Constructor : the arguments are the number of elements, the length of the domain and the amplitude an...
int main(int argc, char *argv[])
unsigned Nup
Number of elements in the x direction in the upstream part of the channel.
double & period()
Access function to the period.
double H
Height at ends.
void position(const Vector< double > &zeta, Vector< double > &r) const
"Current" position vector at Lagrangian coordinate zeta