vmtk_fluid.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 routines
27#include "generic.h"
28#include "constitutive.h"
29#include "navier_stokes.h"
30#include "meshes/tetgen_mesh.h"
31
32
33using namespace std;
34using namespace oomph;
35
36
37/// ///////////////////////////////////////////////////////////////
38/// ///////////////////////////////////////////////////////////////
39/// ///////////////////////////////////////////////////////////////
40
41
42//=======start_namespace==========================================
43/// Global variables
44//================================================================
46{
47
48 /// Default Reynolds number
49 double Re=10.0;
50
51 /// Fluid pressure on inflow boundary
52 double P_in=0.5;
53
54
55 /// Fluid pressure on outflow boundary
56 double P_out=-0.5;
57
58} //end namespace
59
60
61
62
63
64//======start_problem_class===========================================
65/// Unstructured fluid problem
66//====================================================================
67template<class ELEMENT>
68class UnstructuredFluidProblem : public Problem
69{
70
71public:
72
73 /// Constructor:
75
76 /// Destructor (empty)
78
79 /// Update the problem specs before solve: empty
81
82 /// Update the problem specs before solve: empty
84
85 /// Doc the solution
86 void doc_solution(DocInfo& doc_info);
87
88 /// Return total number of fluid inflow traction boundaries
90 {
91 return Inflow_boundary_id.size();
92 }
93
94 /// Return total number of fluid outflow traction boundaries
96 {
97 return Outflow_boundary_id.size();
98 }
99
100 /// Return total number of fluid outflow traction boundaries
102 {
103 return Inflow_boundary_id.size()+Outflow_boundary_id.size();
104 }
105
106private:
107
108 /// Create Lagrange multiplier elements that enforce parallel outflow
110
111 /// Bulk fluid mesh
112 TetgenMesh<ELEMENT>* Fluid_mesh_pt;
113
114 /// Meshes of FaceElements imposing parallel outflow
115 /// and a pressure at the in/outflow
117
118 /// IDs of fluid mesh boundaries along which inflow boundary conditions
119 /// are applied
120 Vector<unsigned> Inflow_boundary_id;
121
122 /// IDs of fluid mesh boundaries along which inflow boundary conditions
123 /// are applied
124 Vector<unsigned> Outflow_boundary_id;
125
126};
127
128
129
130//==========start_constructor=============================================
131/// Constructor for unstructured 3D fluid problem
132//========================================================================
133template<class ELEMENT>
135{
136
137 //Create fluid bulk mesh, sub-dividing "corner" elements
138 string node_file_name="fluid_iliac.1.node";
139 string element_file_name="fluid_iliac.1.ele";
140 string face_file_name="fluid_iliac.1.face";
141 bool split_corner_elements=true;
142
143 Fluid_mesh_pt = new TetgenMesh<ELEMENT>(node_file_name,
144 element_file_name,
145 face_file_name,
146 split_corner_elements);
147
148 // Find elements next to boundaries
149 Fluid_mesh_pt->setup_boundary_element_info();
150
151 // The following corresponds to the boundaries as specified by
152 // facets in the '.poly' input file:
153
154 // Fluid mesh inflow boundaries
155 Inflow_boundary_id.resize(22);
156 for(unsigned i=0; i<22; i++)
157 {
158 Inflow_boundary_id[i]=215+i;
159 }
160
161 // Fluid mesh outflow boundaries
162 Outflow_boundary_id.resize(11);
163 for(unsigned i=0; i<11; i++)
164 {
165
166 Outflow_boundary_id[i]=237+i;
167
168 } // done outflow boundaries
169
170
171 // Create meshes of Lagrange multiplier elements at inflow/outflow
172 //----------------------------------------------------------------
173
174 // Create the meshes
175 unsigned n=nfluid_traction_boundary();
176 Parallel_outflow_lagrange_multiplier_mesh_pt.resize(n);
177 for (unsigned i=0;i<n;i++)
178 {
179 Parallel_outflow_lagrange_multiplier_mesh_pt[i]=new Mesh;
180 }
181
182 // Populate them with elements
183 create_parallel_outflow_lagrange_elements();
184
185
186 // Combine the lot
187 //----------------
188
189 // Add sub meshes:
190
191 // Fluid bulk mesh
192 add_sub_mesh(Fluid_mesh_pt);
193
194 // The fluid traction meshes
195 n=nfluid_traction_boundary();
196 for (unsigned i=0;i<n;i++)
197 {
198 add_sub_mesh(Parallel_outflow_lagrange_multiplier_mesh_pt[i]);
199 }
200
201 // Build global mesh
202 build_global_mesh();
203
204
205 // Apply BCs
206 //----------
207 unsigned nbound=Fluid_mesh_pt->nboundary();
208
209 // Vector indicating the boundaries where we have no slip
210 std::vector<bool> pin_velocity(nbound, true);
211
212 // Loop over inflow/outflow boundaries
213 for (unsigned in_out=0;in_out<2;in_out++)
214 {
215 // Loop over in/outflow boundaries
216 n=nfluid_inflow_traction_boundary();
217 if (in_out==1) n=nfluid_outflow_traction_boundary();
218 for (unsigned i=0;i<n;i++)
219 {
220 // Get boundary ID
221 unsigned b=0;
222 if (in_out==0)
223 {
224 b=Inflow_boundary_id[i];
225 }
226 else
227 {
228 b=Outflow_boundary_id[i];
229 }
230
231 pin_velocity[b]=false;
232 }
233
234 } // done identification of boundaries where velocities are pinned
235
236
237 // Loop over all boundaries to apply no slip where required
238 for(unsigned b=0;b<nbound;b++)
239 {
240 if(pin_velocity[b])
241 {
242 unsigned num_nod=Fluid_mesh_pt->nboundary_node(b);
243 for (unsigned inod=0;inod<num_nod;inod++)
244 {
245 Node* nod_pt=Fluid_mesh_pt->boundary_node_pt(b,inod);
246
247 // Pin all velocities
248 nod_pt->pin(0);
249 nod_pt->pin(1);
250 nod_pt->pin(2);
251
252 // Find out if the node is also located on an in- or outflow
253 // boundary
254 bool is_in_or_outflow_node=false;
255 for (unsigned in_out=0;in_out<2;in_out++)
256 {
257 // Loop over boundaries with Lagrange multiplier elements
258 n=nfluid_inflow_traction_boundary();
259 if (in_out==1) n=nfluid_outflow_traction_boundary();
260 for (unsigned i=0;i<n;i++)
261 {
262 // Get boundary ID
263 unsigned bb=0;
264 if (in_out==0)
265 {
266 bb=Inflow_boundary_id[i];
267 }
268 else
269 {
270 bb=Outflow_boundary_id[i];
271 }
272
273 if(nod_pt->is_on_boundary(bb))
274 {
275 is_in_or_outflow_node=true;
276 }
277 }
278 } // now we know if it's on the an in- or outflow boundary...
279
280
281 // If its on an in- or outflow boundary pin the Lagrange multipliers
282 if(is_in_or_outflow_node)
283 {
284 //Cast to a boundary node
285 BoundaryNodeBase *bnod_pt =
286 dynamic_cast<BoundaryNodeBase*>
287 (Fluid_mesh_pt->boundary_node_pt(b,inod) );
288
289 // What's the index of the first Lagrange multiplier
290 // in the node's values?
291 unsigned first_index=bnod_pt->index_of_first_value_assigned_by_face_element();
292
293 // Pin the lagrange multiplier components
294 // in the out/in_flow boundaries
295 for (unsigned l=0;l<2;l++)
296 {
297 nod_pt->pin(first_index+l);
298 }
299 }
300 }
301 }
302 } // end of BC
303
304 // Complete the build of the fluid elements so they are fully functional
305 //----------------------------------------------------------------------
306 unsigned n_element = Fluid_mesh_pt->nelement();
307 for(unsigned e=0;e<n_element;e++)
308 {
309
310 // Upcast from GeneralisedElement to the present element
311 ELEMENT* el_pt = dynamic_cast<ELEMENT*>(Fluid_mesh_pt->element_pt(e));
312
313 //Set the Reynolds number
314 el_pt->re_pt() = &Global_Parameters::Re;
315
316 }
317
318 // Setup equation numbering scheme
319 std::cout <<"Number of equations: " << assign_eqn_numbers() << std::endl;
320
321} // end constructor
322
323
324//============start_of_lagrange_multiplier_elements======================
325/// Create Lagrange multiplier elements that impose parallel outflow
326//=======================================================================
327template<class ELEMENT>
330{
331 // Counter for number of Lagrange multiplier meshes
332 unsigned count=0;
333
334 // Loop over inflow/outflow boundaries
335 for (unsigned in_out=0;in_out<2;in_out++)
336 {
337 // Loop over boundaries with Lagrange multiplier elements
338 unsigned n=nfluid_inflow_traction_boundary();
339 if (in_out==1) n=nfluid_outflow_traction_boundary();
340 for (unsigned i=0;i<n;i++)
341 {
342 // Get boundary ID
343 unsigned b=0;
344 if (in_out==0)
345 {
346 b=Inflow_boundary_id[i];
347 }
348 else
349 {
350 b=Outflow_boundary_id[i];
351 }
352
353 // How many bulk elements are adjacent to boundary b?
354 unsigned n_element = Fluid_mesh_pt->nboundary_element(b);
355
356 // Loop over the bulk elements adjacent to boundary b
357 for(unsigned e=0;e<n_element;e++)
358 {
359 // Get pointer to the bulk element that is adjacent to boundary b
360 ELEMENT* bulk_elem_pt = dynamic_cast<ELEMENT*>(
361 Fluid_mesh_pt->boundary_element_pt(b,e));
362
363 //What is the index of the face of the element e along boundary b
364 int face_index = Fluid_mesh_pt->face_index_at_boundary(b,e);
365
366 // Build the corresponding lagrange element
367 ImposeParallelOutflowElement<ELEMENT>* el_pt = new
368 ImposeParallelOutflowElement<ELEMENT>(bulk_elem_pt,face_index);
369
370 // Add it to the mesh
371 Parallel_outflow_lagrange_multiplier_mesh_pt[count]->
372 add_element_pt(el_pt);
373
374 // Set the pointer to the prescribed pressure
375 if (in_out==0)
376 {
377 el_pt->pressure_pt()= &Global_Parameters::P_in;
378 }
379 else
380 {
381 el_pt->pressure_pt()= &Global_Parameters::P_out;
382 }
383 }
384 // Bump up counter
385 count++;
386 }
387 }
388
389} // done
390
391
392//========================================================================
393/// Doc the solution
394//========================================================================
395template<class ELEMENT>
397{
398
399 ofstream some_file;
400 char filename[100];
401
402 // Number of plot points
403 unsigned npts;
404 npts=5;
405
406
407 // Output fluid solution
408 sprintf(filename,"%s/fluid_soln%i.dat",doc_info.directory().c_str(),
409 doc_info.number());
410 some_file.open(filename);
411 Fluid_mesh_pt->output(some_file,npts);
412 some_file.close();
413
414}
415
416
417
418
419
420//=============start_main=================================================
421/// Demonstrate how to solve an unstructured 3D fluids problem
422//========================================================================
423int main(int argc, char **argv)
424{
425 // Store command line arguments
426 CommandLineArgs::setup(argc,argv);
427
428 // Label for output
429 DocInfo doc_info;
430
431 // Output directory
432 doc_info.set_directory("RESLT");
433
434 //Set up the problem
436
437 //Output initial guess
438 problem.doc_solution(doc_info);
439 doc_info.number()++;
440
441 // Parameter study
442 double Re_increment=100.0;
443 unsigned nstep=2;
444
445 // Parameter study: Crank up the pressure drop along the vessel
446 for (unsigned istep=0;istep<nstep;istep++)
447 {
448 // Solve the problem
449 problem.newton_solve();
450
451 //Output solution
452 problem.doc_solution(doc_info);
453 doc_info.number()++;
454
455 // Bump up Reynolds number (equivalent to increasing the imposed pressure
456 // drop)
457 Global_Parameters::Re+=Re_increment;
458 }
459
460} // end_of_main
461
462
463
464
Unstructured fluid problem.
Definition vmtk_fluid.cc:69
Vector< unsigned > Inflow_boundary_id
IDs of fluid mesh boundaries along which inflow boundary conditions are applied.
void actions_before_newton_solve()
Update the problem specs before solve: empty.
Definition vmtk_fluid.cc:80
~UnstructuredFluidProblem()
Destructor (empty)
Definition vmtk_fluid.cc:77
Vector< Mesh * > Parallel_outflow_lagrange_multiplier_mesh_pt
Meshes of FaceElements imposing parallel outflow and a pressure at the in/outflow.
unsigned nfluid_inflow_traction_boundary()
Return total number of fluid inflow traction boundaries.
Definition vmtk_fluid.cc:89
UnstructuredFluidProblem()
Constructor:
Vector< unsigned > Outflow_boundary_id
IDs of fluid mesh boundaries along which inflow boundary conditions are applied.
unsigned nfluid_outflow_traction_boundary()
Return total number of fluid outflow traction boundaries.
Definition vmtk_fluid.cc:95
void doc_solution(DocInfo &doc_info)
Doc the solution.
TetgenMesh< ELEMENT > * Fluid_mesh_pt
Bulk fluid mesh.
unsigned nfluid_traction_boundary()
Return total number of fluid outflow traction boundaries.
void create_parallel_outflow_lagrange_elements()
Create Lagrange multiplier elements that enforce parallel outflow.
void actions_after_newton_solve()
Update the problem specs before solve: empty.
Definition vmtk_fluid.cc:83
/////////////////////////////////////////////////////////////// /////////////////////////////////////...
Definition vmtk_fluid.cc:46
double P_in
Fluid pressure on inflow boundary.
Definition vmtk_fluid.cc:52
double Re
Default Reynolds number.
Definition vmtk_fluid.cc:49
double P_out
Fluid pressure on outflow boundary.
Definition vmtk_fluid.cc:56
int main(int argc, char **argv)
Demonstrate how to solve an unstructured 3D fluids problem.