simple_segregated_driver.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-2023 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 // Generic oomph-lib includes
27 #include "generic.h"
28 #include "navier_stokes.h"
29 #include "beam.h"
30 #include "multi_physics.h"
31 
32 // The wall mesh
33 #include "meshes/one_d_lagrangian_mesh.h"
34 
35 //Include the fluid mesh
36 #include "meshes/collapsible_channel_mesh.h"
37 
38 
39 using namespace std;
40 
41 using namespace oomph;
42 
43 
44 // Include the general-purpose fsi collapsible channel problem
45 #include "fsi_chan_problem.h"
46 
47 //====Namespace_for_flags================================
48 /// Extend namespace for control flags
49 //======================================================
50 namespace Flags
51 {
52 
53  /// Use Newton solver (0) or segregated solver (1)?
55 
56  /// Use pointwise Aitken extrapolation (1) or not (0)
58 
59  /// Under-relaxation parameter (1.0: no under-relaxation; 0.0: freeze)
60  double Omega_under_relax=1.0;
61 
62  /// Use Irons and Tuck extrapolation (1) or not (0)
64 
65  /// Convergence criterion: 0: global resmax; 1: abs. change; 2: rel. change
67 
68  /// Convergence tolerance
69  double Convergence_tolerance=1.0e-8;
70 
71 }
72 
73 
74 
75 /// ////////////////////////////////////////////////////////////////////
76 /// ////////////////////////////////////////////////////////////////////
77 /// ////////////////////////////////////////////////////////////////////
78 
79 
80 
81 //====start_of_problem_class==========================================
82 /// Problem class -- add segregated solver capability to an existing
83 /// problem.
84 //====================================================================
85 template <class ELEMENT>
87  public virtual FSICollapsibleChannelProblem<ELEMENT>,
88  public virtual SegregatableFSIProblem
89 {
90 
91 public :
92 
93  /// Constructor: The arguments are the same as the original
94  /// (non-segregated) problem, namely, numbers of elements and lengths
95  /// of different sections of the domain.
96  SegregatedFSICollapsibleChannelProblem(const unsigned& nup,
97  const unsigned& ncollapsible,
98  const unsigned& ndown,
99  const unsigned& ny,
100  const double& lup,
101  const double& lcollapsible,
102  const double& ldown,
103  const double& ly,
104  const bool& displ_control,
105  const bool& steady_flag);
106 
107  /// Empty Destructor
109 
110 
111  /// Identify the fluid and solid Data and meshes that
112  /// contain only elements involved in the respective sub-problems.
113  /// This is a specific implementation of a pure virtual function in the
114  /// SegregatableFSIProblem base class.
115  void identify_fluid_and_solid_dofs(Vector<Data*>& fluid_data_pt,
116  Vector<Data*>& solid_data_pt,
117  Mesh*& fluid_mesh_pt,
118  Mesh*& solid_mesh_pt);
119 
120  // start_of_convergence_checks
121 
122  /// Update nodal positions in the fluid mesh in
123  /// response to changes in the wall displacement field after every
124  /// Newton step in a monolithic or segregated solid solve. Note
125  /// the use of the (protected) flag Solve_type, which can take the
126  /// values Full_solve, Fluid_solve or Solid_solve. This flag is used
127  /// to allow specification of different actions depending on the
128  /// precise solve taking place.
130  {
131  //For a "true" segregated solver, we would not do this in fluid or solid
132  //solves, but adding the bulk node update to the solid solve phase aids
133  //convergence and makes it possible for larger values of Q. Of course,
134  //there is a small cost associated with doing this.
135  if(Solve_type!=Fluid_solve) {this->Bulk_mesh_pt->node_update();}
136  }
137 
138 
139  /// Update nodal positions in the fluid mesh
140  /// in response to any changes in the wall displacement field after every
141  /// segregated solve. This is not strictly necessary because we
142  /// do the solid solve last, which performs its own node update before the
143  /// convergence check of the sub problem. It remains here because if we
144  /// were solving in a completely segregated fashion a node update would be
145  /// required for the fluid mesh in the final converged solution to be
146  /// consistent with the solid positions.
148  {
149  this->Bulk_mesh_pt->node_update();
150  }
151 
152  // end_of_convergence_checks
153 
154  /// Document the solution
155  void doc_solution(DocInfo& doc_info);
156 
157  /// Perform a steady run
158  void steady_run();
159 
160 };
161 
162 
163 //=====start_of_constructor======================================
164 /// Constructor for the collapsible channel problem
165 //===============================================================
166 template <class ELEMENT>
168 SegregatedFSICollapsibleChannelProblem(const unsigned& nup,
169  const unsigned& ncollapsible,
170  const unsigned& ndown,
171  const unsigned& ny,
172  const double& lup,
173  const double& lcollapsible,
174  const double& ldown,
175  const double& ly,
176  const bool& displ_control,
177  const bool& steady_flag) :
178  FSICollapsibleChannelProblem<ELEMENT>(nup,
179  ncollapsible,
180  ndown,
181  ny,
182  lup,
183  lcollapsible,
184  ldown,
185  ly,
186  displ_control,
187  steady_flag)
188 {
189  // Choose convergence criterion based on Flag::Convergence criterion
190  // with tolerance given by Flag::Convergence_tolerance
192  {
193  assess_convergence_based_on_max_global_residual(
195  }
196  else if (Flags::Convergence_criterion==1)
197  {
198  assess_convergence_based_on_absolute_solid_change(
200  }
201  else if (Flags::Convergence_criterion==2)
202  {
203  assess_convergence_based_on_relative_solid_change(
205  }
206 
207  //Select a convergence-acceleration technique based on control flags
208 
209  // Pointwise Aitken extrapolation
211  {
212  this->enable_pointwise_aitken();
213  }
214  else
215  {
216  this->disable_pointwise_aitken();
217  }
218 
219  // Under-relaxation
220  this->enable_under_relaxation(Flags::Omega_under_relax);
221 
222  // Irons and Tuck's extrapolation
224  {
225  this->enable_irons_and_tuck_extrapolation();
226  }
227  else
228  {
229  this->disable_irons_and_tuck_extrapolation();
230  }
231 
232 } //end_of_constructor
233 
234 
235 
236 //=====start_of_identify_fluid_and_solid======================================
237 /// Identify the fluid and solid Data and the meshes that
238 /// contain only elements that are involved in the respective sub-problems.
239 /// This implements a pure virtual function in the
240 /// SegregatableFSIProblem base class.
241 //============================================================================
242 template <class ELEMENT>
244 identify_fluid_and_solid_dofs(Vector<Data*>& fluid_data_pt,
245  Vector<Data*>& solid_data_pt,
246  Mesh*& fluid_mesh_pt,
247  Mesh*& solid_mesh_pt)
248 {
249 
250  //FLUID DATA:
251  //All fluid elements are stored in the Mesh addressed by bulk_mesh_pt()
252 
253  //Reset the storage
254  fluid_data_pt.clear();
255 
256  //Find number of fluid elements
257  unsigned n_fluid_elem=this->bulk_mesh_pt()->nelement();
258  //Loop over fluid elements and add internal data to fluid_data_ptt
259  for(unsigned e=0;e<n_fluid_elem;e++)
260  {
261  GeneralisedElement* el_pt=this->bulk_mesh_pt()->element_pt(e);
262  unsigned n_internal=el_pt->ninternal_data();
263  for(unsigned i=0;i<n_internal;i++)
264  {
265  fluid_data_pt.push_back(el_pt->internal_data_pt(i));
266  }
267  }
268 
269  //Find number of nodes in fluid mesh
270  unsigned n_fluid_node=this->bulk_mesh_pt()->nnode();
271  //Loop over nodes and add the nodal data to fluid_data_pt
272  for (unsigned n=0;n<n_fluid_node;n++)
273  {
274  fluid_data_pt.push_back(this->bulk_mesh_pt()->node_pt(n));
275  }
276 
277  // The bulk_mesh_pt() is a mesh that contains only fluid elements
278  fluid_mesh_pt = this->bulk_mesh_pt();
279 
280 
281  //SOLID DATA
282  //All solid elements are stored in the Mesh addressed by wall_mesh_pt()
283 
284  //Reset the storage
285  solid_data_pt.clear();
286 
287  //Find number of nodes in the solid mesh
288  unsigned n_solid_node=this->wall_mesh_pt()->nnode();
289  //Loop over nodes and add nodal position data to solid_data_pt
290  for(unsigned n=0;n<n_solid_node;n++)
291  {
292  solid_data_pt.push_back(
293  this->wall_mesh_pt()->node_pt(n)->variable_position_pt());
294  }
295 
296  //If we are using displacement control then the displacement control element
297  //and external pressure degree of freedom should be treated as part
298  //of the solid problem
299 
300  //We will assemble a single solid mesh from a vector of pointers to meshes
301  Vector<Mesh*> s_mesh_pt(1);
302  //The wall_mesh_pt() contains all solid elements and is the first
303  //entry in our vector
304  s_mesh_pt[0]=this->wall_mesh_pt();
305 
306  //If we are using displacement control
307  if (this->Displ_control)
308  {
309  //Add the external pressure data to solid_data_pt
310  solid_data_pt.push_back(Global_Physical_Variables::P_ext_data_pt);
311  //Add a pointer to a Mesh containing the displacement control element
312  //to the vector of pointers to meshes
313  s_mesh_pt.push_back(this->Displ_control_mesh_pt);
314  }
315 
316  // Build "combined" mesh from our vector of solid meshes
317  solid_mesh_pt = new Mesh(s_mesh_pt);
318 
319 } //end_of_identify_fluid_and_solid
320 
321 
322 //====start_of_doc_solution============================================
323 /// Document the solution
324 //============================================================================
325 template <class ELEMENT>
327  DocInfo& doc_info)
328 {
329  //Output stream filenames
330  ofstream some_file;
331  char filename[100];
332 
333  // Number of plot points
334  unsigned npts=5;
335 
336  // Output fluid solution
337  sprintf(filename,"%s/soln%i.dat",doc_info.directory().c_str(),
338  doc_info.number());
339  some_file.open(filename);
340  this->bulk_mesh_pt()->output(some_file,npts);
341  some_file.close();
342 
343  // Document the wall shape
344  sprintf(filename,"%s/beam%i.dat",doc_info.directory().c_str(),
345  doc_info.number());
346  some_file.open(filename);
347  this->wall_mesh_pt()->output(some_file,npts);
348  some_file.close();
349 
350 } // end_of_doc_solution
351 
352 
353 
354 //====steady_run==============================================================
355 /// Perform a steady run in which the external pressure
356 /// (or presribed displacement) is varied causing the channel to collapse.
357 //============================================================================
358 template <class ELEMENT>
360 {
361 
362  // Set initial value for external pressure (on the wall stiffness scale).
363  // This can be overwritten in set_initial_condition.
365  set_value(0,Global_Physical_Variables::Pmin);
366 
367  // Apply initial condition
368  set_initial_condition();
369 
370  //Set output directory
371  DocInfo doc_info;
372  doc_info.set_directory("RESLT");
373 
374  // Output the initial solution
375  doc_solution(doc_info);
376 
377  // Increment step number
378  doc_info.number()++;
379 
380  // Increment for external pressure (on the wall stiffness scale)
381  double delta_p=(Global_Physical_Variables::Pmax-
383 
384  // Initial and final values for control position
386 
387  // Final value of prescribed displacement
388  double y_min=0.65;
389  //Change in y-coordinate to attain the minimum position in a given
390  //number of steps
391  double delta_y=(y_min-Global_Physical_Variables::Yprescr)/
392  double(Flags::Nsteps-1);
393 
394  // Parameter study (loop over the number of steps)
395  for (unsigned istep=0;istep<Flags::Nsteps;istep++)
396  {
397  // Setup segregated solver
398  //(Default behaviour will identify the fluid and solid dofs and
399  // allocate memory, etc every time. This is a bit inefficient in
400  // this case, but it is safe and will always work)
401  setup_segregated_solver();
402 
403  // SEGREGATED SOLVER
405  {
406  //Set the maximum number of Picard steps
407  Max_picard =50;
408 
409  // Solve ignoring return type (convergence data)
410  (void)steady_segregated_solve();
411  }
412  // NEWTON SOLVER
413  else
414  {
415  //Explit call to the steady Newton solve.
416  steady_newton_solve();
417  }
418 
419  // Output the solution
420  doc_solution(doc_info);
421 
422  //Increase the Step number
423  doc_info.number()++;
424 
425  // Adjust control parameters
426  //If displacment control increment position
427  if (this->Displ_control)
428  {
430  }
431  //Otherwise increment external pressure
432  else
433  {
434  double old_p=Global_Physical_Variables::P_ext_data_pt->value(0);
435  Global_Physical_Variables::P_ext_data_pt->set_value(0,old_p+delta_p);
436  }
437 
438  } // End of parameter study
439 
440 }
441 
442 //============start_of_main====================================================
443 /// Driver code for a segregated collapsible channel problem with FSI.
444 //=============================================================================
445 int main()
446 {
447  // Number of elements in the domain
448  unsigned nup=4*Flags::Resolution_factor;
449  unsigned ncollapsible=20*Flags::Resolution_factor;
450  unsigned ndown=40*Flags::Resolution_factor;
451  unsigned ny=4*Flags::Resolution_factor;
452 
453 
454  // Geometry of the domain
455  double lup=1.0;
456  double lcollapsible=5.0;
457  double ldown=10.0;
458  double ly=1.0;
459 
460  // Steady run by default
461  bool steady_flag=true;
462  // with displacement control
463  bool displ_control=true;
464 
465  // Build the problem with QTaylorHoodElements
467  <AlgebraicElement<QTaylorHoodElement<2> > >
468  problem(nup, ncollapsible, ndown, ny,
469  lup, lcollapsible, ldown, ly, displ_control,
470  steady_flag);
471 
472  //Perform a steady run
473  problem.steady_run();
474 
475 }//end of main
//////////////////////////////////////////////////////////////////// ////////////////////////////////...
void doc_solution(DocInfo &doc_info)
Document the solution.
void actions_before_newton_convergence_check()
Update nodal positions in the fluid mesh in response to changes in the wall displacement field after ...
void identify_fluid_and_solid_dofs(Vector< Data * > &fluid_data_pt, Vector< Data * > &solid_data_pt, Mesh *&fluid_mesh_pt, Mesh *&solid_mesh_pt)
Identify the fluid and solid Data and meshes that contain only elements involved in the respective su...
void actions_before_segregated_convergence_check()
Update nodal positions in the fluid mesh in response to any changes in the wall displacement field af...
SegregatedFSICollapsibleChannelProblem(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 bool &displ_control, const bool &steady_flag)
Constructor: The arguments are the same as the original (non-segregated) problem, namely,...
Extend namespace for control flags.
unsigned Use_segregated_solver
Use Newton solver (0) or segregated solver (1)?
double Convergence_tolerance
Convergence tolerance.
double Omega_under_relax
Under-relaxation parameter (1.0: no under-relaxation; 0.0: freeze)
unsigned Resolution_factor
Resolution factor (multiplier for number of elements across channel)
unsigned Nsteps
Number of steps in parameter study.
unsigned Use_irons_and_tuck_extrapolation
Use Irons and Tuck extrapolation (1) or not (0)
unsigned Use_pointwise_aitken
Use pointwise Aitken extrapolation (1) or not (0)
unsigned Convergence_criterion
Convergence criterion: 0: global resmax; 1: abs. change; 2: rel. change.
double Pmax
Max. pressure. Only used in steady runs during parameter incrementation. Use 2.0 for Re=250; 3....
Data * P_ext_data_pt
Pointer to Data object that stores external pressure.
double Pmin
Min. pressure. Only used in steady runs during parameter incrementation. Use 1.5 for values of Re to ...
double Yprescr
Current prescribed vertical position of control point (only used for displacement control)
int main()
Driver code for a segregated collapsible channel problem with FSI.