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