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