Toggle navigation
Documentation
Big picture
The finite element method
The data structure
Not-so-quick guide
Optimisation
Order of action functions
Example codes and tutorials
List of example codes and tutorials
Meshing
Solvers
MPI parallel processing
Post-processing/visualisation
Other
Change log
Creating documentation
Coding conventions
Index
FAQ
About
People
Contact/Get involved
Publications
Acknowledgements
Copyright
Picture show
Go
src
meshes
collapsible_channel_mesh.template.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-2025 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
#ifndef OOMPH_COLLAPSIBLE_CHANNEL_MESH_TEMPLATE_HEADER
27
#define OOMPH_COLLAPSIBLE_CHANNEL_MESH_TEMPLATE_HEADER
28
29
#ifndef OOMPH_COLLAPSIBLE_CHANNEL_MESH_HEADER
30
#error __FILE__ should only be included from collapsible_channel_mesh.h.
31
#endif
// OOMPH_COLLAPSIBLE_CHANNEL_MESH_HEADER
32
33
// Include the headers file for collapsible channel
34
35
namespace
oomph
36
{
37
//========================================================================
38
/// Constructor: Pass number of elements in upstream/collapsible/downstream
39
/// segment and across the channel; lengths of upstream/collapsible/downstream
40
/// segments and width of channel, pointer to GeomObject that defines
41
/// the collapsible segment and pointer to TimeStepper (defaults to the
42
/// default timestepper, Steady).
43
//========================================================================
44
template
<
class
ELEMENT>
45
CollapsibleChannelMesh<ELEMENT>::CollapsibleChannelMesh
(
46
const
unsigned
& nup,
47
const
unsigned
& ncollapsible,
48
const
unsigned
& ndown,
49
const
unsigned
& ny,
50
const
double
&
lup
,
51
const
double
&
lcollapsible
,
52
const
double
&
ldown
,
53
const
double
&
ly
,
54
GeomObject
* wall_pt,
55
TimeStepper
*
time_stepper_pt
)
56
:
SimpleRectangularQuadMesh
<
ELEMENT
>(nup + ncollapsible + ndown,
57
ny,
58
lup
+
lcollapsible
+
ldown
,
59
ly
,
60
time_stepper_pt
),
61
Nup(nup),
62
Ncollapsible(ncollapsible),
63
Ndown(ndown),
64
Ny(ny),
65
Wall_pt(wall_pt)
66
{
67
// Mesh can only be built with 2D Qelements.
68
MeshChecker::assert_geometric_element<QElementGeometricBase, ELEMENT>(2);
69
70
// Create the CollapsibleChannelDomain with the wall represented
71
// by the geometric object
72
Domain_pt
=
new
CollapsibleChannelDomain
(
73
nup, ncollapsible, ndown,
ny
,
lup
,
lcollapsible
,
ldown
,
ly
,
wall_pt
);
74
75
// Total number of (macro/finite)elements
76
unsigned
nmacro
= (nup + ncollapsible + ndown) *
ny
;
77
78
// Loop over all elements and set macro element pointer
79
for
(
unsigned
e
= 0;
e
<
nmacro
;
e
++)
80
{
81
// Get pointer to finite element
82
FiniteElement
*
el_pt
= this->
finite_element_pt
(
e
);
83
84
// Set pointer to macro element so the curvlinear boundaries
85
// of the mesh/domain can get picked up during adaptive
86
// mesh refinement
87
el_pt
->set_macro_elem_pt(this->
Domain_pt
->macro_element_pt(
e
));
88
}
89
90
// Update the nodal positions corresponding to their
91
// macro element representations.
92
this->node_update();
93
94
// Update the boundary numbering scheme and set boundary coordinate
95
//-----------------------------------------------------------------
96
97
// (Note: The original SimpleRectangularQuadMesh had four boundaries.
98
// We need to overwrite the boundary lookup scheme for the current
99
// mesh so that the collapsible segment becomes identifiable).
100
// While we're doing this, we're also setting up a boundary
101
// coordinate for the nodes located on the collapsible segment.
102
// The boundary coordinate can be used to setup FSI.
103
104
// How many boundaries does the mesh have now?
105
unsigned
nbound
= this->
nboundary
();
106
for
(
unsigned
b
= 0;
b
<
nbound
;
b
++)
107
{
108
// Remove all nodes on this boundary from the mesh's lookup scheme
109
// and also delete the reverse lookup scheme held by the nodes
110
this->
remove_boundary_nodes
(
b
);
111
}
112
113
#ifdef PARANOID
114
// Sanity check
115
unsigned
nnod
= this->
nnode
();
116
for
(
unsigned
j
= 0;
j
<
nnod
;
j
++)
117
{
118
if
(this->
node_pt
(
j
)->
is_on_boundary
())
119
{
120
std::ostringstream
error_message
;
121
error_message
<<
"Node "
<<
j
<<
"is still on boundary "
<< std::endl;
122
123
throw
OomphLibError
(
error_message
.str(),
124
OOMPH_CURRENT_FUNCTION
,
125
OOMPH_EXCEPTION_LOCATION
);
126
}
127
}
128
#endif
129
130
// Change the numbers of boundaries
131
this->
set_nboundary
(6);
132
133
// Get the number of nodes along the element edge from first element
134
unsigned
nnode_1d
= this->
finite_element_pt
(0)->nnode_1d();
135
136
// Vector of Lagrangian coordinates used as boundary coordinate
137
Vector<double>
zeta
(1);
138
139
// Index of first element underneath the collapsible bit
140
unsigned
first_collapsible
= (
ny
- 1) * (nup + ncollapsible + ndown) + nup;
141
142
// Zeta increment over elements (used for assignment of
143
// boundary coordinate)
144
double
dzeta
=
lcollapsible
/
double
(ncollapsible);
145
146
// Manually loop over the elements near the boundaries and
147
// assign nodes to boundaries. Also set up boundary coordinate
148
unsigned
nelem
= this->
nelement
();
149
for
(
unsigned
e
= 0;
e
<
nelem
;
e
++)
150
{
151
// Bottom row of elements
152
if
(
e
< nup + ncollapsible + ndown)
153
{
154
for
(
unsigned
i
= 0;
i
<
nnode_1d
;
i
++)
155
{
156
this->
add_boundary_node
(0, this->
finite_element_pt
(
e
)->
node_pt
(
i
));
157
}
158
}
159
// Upstream upper rigid bit
160
if
((
e
> (
ny
- 1) * (nup + ncollapsible + ndown) - 1) &&
161
(
e
< (
ny
- 1) * (nup + ncollapsible + ndown) + nup))
162
{
163
for
(
unsigned
i
= 0;
i
<
nnode_1d
;
i
++)
164
{
165
this->
add_boundary_node
(
166
4,
167
this->
finite_element_pt
(
e
)->
node_pt
((
nnode_1d
- 1) *
nnode_1d
+
i
));
168
}
169
}
170
// Collapsible bit
171
if
((
e
> (
ny
- 1) * (nup + ncollapsible + ndown) + nup - 1) &&
172
(
e
< (
ny
- 1) * (nup + ncollapsible + ndown) + nup + ncollapsible))
173
{
174
for
(
unsigned
i
= 0;
i
<
nnode_1d
;
i
++)
175
{
176
this->
add_boundary_node
(
177
3,
178
this->
finite_element_pt
(
e
)->
node_pt
((
nnode_1d
- 1) *
nnode_1d
+
i
));
179
180
// What column of elements are we in?
181
unsigned
ix
=
e
-
first_collapsible
;
182
183
// Zeta coordinate
184
zeta
[0] =
185
double
(
ix
) *
dzeta
+
double
(
i
) *
dzeta
/
double
(
nnode_1d
- 1);
186
187
// Set boundary coordinate
188
this->
finite_element_pt
(
e
)
189
->node_pt((
nnode_1d
- 1) *
nnode_1d
+
i
)
190
->set_coordinates_on_boundary(3,
zeta
);
191
}
192
}
193
// Downstream upper rigid bit
194
if
((
e
>
195
(
ny
- 1) * (nup + ncollapsible + ndown) + nup + ncollapsible - 1) &&
196
(
e
<
ny
* (nup + ncollapsible + ndown)))
197
{
198
for
(
unsigned
i
= 0;
i
<
nnode_1d
;
i
++)
199
{
200
this->
add_boundary_node
(
201
2,
202
this->
finite_element_pt
(
e
)->
node_pt
((
nnode_1d
- 1) *
nnode_1d
+
i
));
203
}
204
}
205
// Left end
206
if
(
e
% (nup + ncollapsible + ndown) == 0)
207
{
208
for
(
unsigned
i
= 0;
i
<
nnode_1d
;
i
++)
209
{
210
this->
add_boundary_node
(
211
5, this->
finite_element_pt
(
e
)->
node_pt
(
i
*
nnode_1d
));
212
}
213
}
214
// Right end
215
if
(
e
% (nup + ncollapsible + ndown) == (nup + ncollapsible + ndown) - 1)
216
{
217
for
(
unsigned
i
= 0;
i
<
nnode_1d
;
i
++)
218
{
219
this->
add_boundary_node
(
220
1, this->
finite_element_pt
(
e
)->
node_pt
((
i
+ 1) *
nnode_1d
- 1));
221
}
222
}
223
}
224
225
// Re-setup lookup scheme that establishes which elements are located
226
// on the mesh boundaries (doesn't need to be wiped)
227
this->setup_boundary_element_info();
228
229
// We have only bothered to parametrise boundary 3
230
this->
set_boundary_coordinate_exists
(3);
231
}
232
233
234
///////////////////////////////////////////////////////////////////////////
235
///////////////////////////////////////////////////////////////////////////
236
///////////////////////////////////////////////////////////////////////////
237
238
//=================================================================
239
/// Perform algebraic mesh update at time level t (t=0: present;
240
/// t>0: previous)
241
//=================================================================
242
template
<
class
ELEMENT>
243
void
AlgebraicCollapsibleChannelMesh<ELEMENT>::algebraic_node_update
(
244
const
unsigned
&
t
,
AlgebraicNode
*&
node_pt
)
245
{
246
#ifdef PARANOID
247
// We're updating the nodal positions (!) at time level t
248
// and determine them by evaluating the wall GeomObject's
249
// position at that gime level. I believe this only makes sense
250
// if the t-th history value in the positional timestepper
251
// actually represents previous values (rather than some
252
// generalised quantity). Hence if this function is called with
253
// t>nprev_values(), we issue a warning and terminate the execution.
254
// It *might* be possible that the code still works correctly
255
// even if this condition is violated (e.g. if the GeomObject's
256
// position() function returns the appropriate "generalised"
257
// position value that is required by the timestepping scheme but it's
258
// probably worth flagging this up and forcing the user to manually switch
259
// off this warning if he/she is 100% sure that this is kosher.
260
if
(
t
>
node_pt
->position_time_stepper_pt()->nprev_values())
261
{
262
std::string
error_message
=
263
"Trying to update the nodal position at a time level"
;
264
error_message
+=
"beyond the number of previous values in the nodes'"
;
265
error_message
+=
"position timestepper. This seems highly suspect!"
;
266
error_message
+=
"If you're sure the code behaves correctly"
;
267
error_message
+=
"in your application, remove this warning "
;
268
error_message
+=
"or recompile with PARNOID switched off."
;
269
270
std::string
function_name
=
"AlgebraicCollapsibleChannelMesh::"
;
271
function_name
+=
"algebraic_node_update()"
;
272
273
throw
OomphLibError
(
274
error_message
,
OOMPH_CURRENT_FUNCTION
,
OOMPH_EXCEPTION_LOCATION
);
275
}
276
#endif
277
278
// Extract references for update by copy construction
279
Vector<double>
ref_value
(
node_pt
->vector_ref_value());
280
281
// First reference value: Original x-position. Used as the start point
282
// for the lines connecting the nodes in the vertical direction
283
double
x_bottom
=
ref_value
[0];
284
285
// Second reference value: Fractional position along
286
// straight line from the bottom (at the original x position)
287
// to the reference point on the upper wall
288
double
fract
=
ref_value
[1];
289
290
// Third reference value: Reference local coordinate
291
// in GeomObject that represents the upper wall (local coordinate
292
// in finite element if the wall GeomObject is a finite element mesh)
293
Vector<double>
s
(1);
294
s
[0] =
ref_value
[2];
295
296
// Fourth reference value: zeta coordinate on the upper wall
297
// If the wall is a simple GeomObject, zeta[0]=s[0]
298
// but if it's a compound GeomObject (e.g. a finite element mesh)
299
// zeta scales during mesh refinement, whereas s[0] and the
300
// pointer to the geom object have to be re-computed.
301
// double zeta=ref_value[3]; // not needed here
302
303
// Extract geometric objects for update by copy construction
304
Vector<GeomObject*>
geom_object_pt
(
node_pt
->vector_geom_object_pt());
305
306
// Pointer to actual wall geom object (either the same as the wall object
307
// or the pointer to the actual finite element)
308
GeomObject
*
geom_obj_pt
=
geom_object_pt
[0];
309
310
// Get position vector to wall at previous timestep t!
311
Vector<double>
r_wall
(2);
312
geom_obj_pt
->position(
t
,
s
,
r_wall
);
313
314
// Assign new nodal coordinate
315
node_pt
->x(
t
, 0) =
x_bottom
+
fract
* (
r_wall
[0] -
x_bottom
);
316
node_pt
->x(
t
, 1) =
fract
*
r_wall
[1];
317
}
318
319
//=====start_setup=================================================
320
/// Setup algebraic mesh update -- assumes that mesh has
321
/// initially been set up with a flush upper wall
322
//=================================================================
323
template
<
class
ELEMENT>
324
void
AlgebraicCollapsibleChannelMesh<ELEMENT>::setup_algebraic_node_update
()
325
{
326
// Shorthand for some geometric data:
327
double
l_up = this->domain_pt()->l_up();
328
double
l_collapsible = this->domain_pt()->l_collapsible();
329
330
// Loop over all nodes in mesh
331
unsigned
nnod
= this->
nnode
();
332
for
(
unsigned
j
= 0;
j
<
nnod
;
j
++)
333
{
334
// Get pointer to node -- recall that that Mesh::node_pt(...) has been
335
// overloaded in the AlgebraicMesh class to return a pointer to
336
// an AlgebraicNode.
337
AlgebraicNode
*
nod_pt
=
node_pt
(
j
);
338
339
// Get coordinates
340
double
x =
nod_pt
->x(0);
341
double
y =
nod_pt
->x(1);
342
343
// Check if it's in the collapsible part:
344
if
((x >= l_up) && (x <= (l_up + l_collapsible)))
345
{
346
// Get zeta coordinate on the undeformed wall
347
Vector<double>
zeta
(1);
348
zeta
[0] = x - l_up;
349
350
// Get pointer to geometric (sub-)object and Lagrangian coordinate
351
// on that sub-object. For a wall that is represented by
352
// a single geom object, this simply returns the input.
353
// If the geom object consists of sub-objects (e.g.
354
// if it is a finite element mesh representing a wall,
355
// then we'll obtain the pointer to the finite element
356
// (in its incarnation as a GeomObject) and the
357
// local coordinate in that element.
358
GeomObject
*
geom_obj_pt
;
359
Vector<double>
s
(1);
360
this->Wall_pt->locate_zeta(
zeta
,
geom_obj_pt
,
s
);
361
362
// Get position vector to wall:
363
Vector<double>
r_wall
(2);
364
geom_obj_pt
->position(
s
,
r_wall
);
365
366
// Sanity check: Confirm that the wall is in its undeformed position
367
#ifdef PARANOID
368
if
((std::fabs(
r_wall
[0] - x) > 1.0e-15) &&
369
(std::fabs(
r_wall
[1] - y) > 1.0e-15))
370
{
371
std::ostringstream
error_stream
;
372
error_stream
<<
"Wall must be in its undeformed position when\n"
373
<<
"algebraic node update information is set up!\n "
374
<<
"x-discrepancy: "
<< std::fabs(
r_wall
[0] - x)
375
<< std::endl
376
<<
"y-discrepancy: "
<< std::fabs(
r_wall
[1] - y)
377
<< std::endl;
378
379
throw
OomphLibError
(
error_stream
.str(),
380
OOMPH_CURRENT_FUNCTION
,
381
OOMPH_EXCEPTION_LOCATION
);
382
}
383
#endif
384
385
// One geometric object is involved in update operation
386
Vector<GeomObject*>
geom_object_pt
(1);
387
388
// The actual geometric object (If the wall is simple GeomObject
389
// this is the same as Wall_pt; if it's a compound GeomObject
390
// this points to the sub-object)
391
geom_object_pt
[0] =
geom_obj_pt
;
392
393
// The update function requires four parameters:
394
Vector<double>
ref_value
(4);
395
396
// First reference value: Original x-position
397
ref_value
[0] =
r_wall
[0];
398
399
// Second reference value: fractional position along
400
// straight line from the bottom (at the original x position)
401
// to the point on the wall)
402
ref_value
[1] = y /
r_wall
[1];
403
404
// Third reference value: Reference local coordinate
405
// in wall element (local coordinate in FE if we're dealing
406
// with a wall mesh)
407
ref_value
[2] =
s
[0];
408
409
// Fourth reference value: zeta coordinate on wall
410
// If the wall is a simple GeomObject, zeta[0]=s[0]
411
// but if it's a compound GeomObject (e.g. a finite element mesh)
412
// zeta scales during mesh refinement, whereas s[0] and the
413
// pointer to the geom object have to be re-computed.
414
ref_value
[3] =
zeta
[0];
415
416
// Setup algebraic update for node: Pass update information
417
nod_pt
->add_node_update_info(
this
,
// mesh
418
geom_object_pt
,
// vector of geom objects
419
ref_value
);
// vector of ref. values
420
}
421
}
422
423
}
// end of setup_algebraic_node_update
424
425
426
////////////////////////////////////////////////////////////////////
427
////////////////////////////////////////////////////////////////////
428
////////////////////////////////////////////////////////////////////
429
430
//========start_update_node_update=================================
431
/// Update the geometric references that are used
432
/// to update node after mesh adaptation.
433
//=================================================================
434
template
<
class
ELEMENT>
435
void
RefineableAlgebraicCollapsibleChannelMesh<ELEMENT>::update_node_update
(
436
AlgebraicNode
*&
node_pt
)
437
{
438
// Extract reference values for node update by copy construction
439
Vector<double>
ref_value
(
node_pt
->vector_ref_value());
440
441
// First reference value: Original x-position
442
// double x_bottom=ref_value[0]; // not needed here
443
444
// Second reference value: fractional position along
445
// straight line from the bottom (at the original x position)
446
// to the point on the wall)
447
// double fract=ref_value[1]; // not needed here
448
449
// Third reference value: Reference local coordinate
450
// in GeomObject (local coordinate in finite element if the wall
451
// GeomObject is a finite element mesh)
452
// Vector<double> s(1);
453
// s[0]=ref_value[2]; // This needs to be re-computed!
454
455
// Fourth reference value: intrinsic coordinate on the (possibly
456
// compound) wall.
457
double
zeta
=
ref_value
[3];
458
459
// Extract geometric objects for update by copy construction
460
Vector<GeomObject*>
geom_object_pt
(
node_pt
->vector_geom_object_pt());
461
462
// Pointer to actual wall geom object (either the same as wall object
463
// or the pointer to the actual finite element)
464
// GeomObject* geom_obj_pt=geom_object_pt[0]; // This needs to be
465
// re-computed!
466
467
// Get zeta coordinate on wall (as vector)
468
Vector<double>
zeta_wall
(1);
469
zeta_wall
[0] =
zeta
;
470
471
// Get pointer to geometric (sub-)object and Lagrangian coordinate
472
// on that sub-object. For a wall that is represented by
473
// a single geom object, this simply returns the input.
474
// If the geom object consists of sub-objects (e.g.
475
// if it is a finite element mesh representing a wall,
476
// then we'll obtain the pointer to the finite element
477
// (in its incarnation as a GeomObject) and the
478
// local coordinate in that element.
479
Vector<double>
s
(1);
480
GeomObject
*
geom_obj_pt
;
481
this->Wall_pt->locate_zeta(
zeta_wall
,
geom_obj_pt
,
s
);
482
483
// Update the pointer to the (sub-)GeomObject within which the
484
// reference point is located. (If the wall is simple GeomObject
485
// this is the same as Wall_pt; if it's a compound GeomObject
486
// this points to the sub-object)
487
geom_object_pt
[0] =
geom_obj_pt
;
488
489
// First reference value: Original x-position
490
// ref_value[0]=r_wall[0]; // unchanged
491
492
// Second reference value: fractional position along
493
// straight line from the bottom (at the original x position)
494
// to the point on the wall)
495
// ref_value[1]=y/r_wall[1]; // unchanged
496
497
// Update third reference value: Reference local coordinate
498
// in wall element (local coordinate in FE if we're dealing
499
// with a wall mesh)
500
ref_value
[2] =
s
[0];
501
502
// Fourth reference value: zeta coordinate on wall
503
// If the wall is a simple GeomObject, zeta[0]=s[0]
504
// but if it's a compound GeomObject (e.g. a finite element mesh)
505
// zeta scales during mesh refinement, whereas s[0] and the
506
// pointer to the geom object have to be re-computed.
507
// ref_value[3]=zeta[0]; //unchanged
508
509
// Kill the existing node update info
510
node_pt
->kill_node_update_info();
511
512
// Setup algebraic update for node: Pass update information
513
node_pt
->add_node_update_info(
this
,
// mesh
514
geom_object_pt
,
// vector of geom objects
515
ref_value
);
// vector of ref. values
516
}
517
518
}
// namespace oomph
519
#endif
oomph::AlgebraicCollapsibleChannelMesh::setup_algebraic_node_update
void setup_algebraic_node_update()
Function to setup the algebraic node update.
Definition
collapsible_channel_mesh.template.cc:324
oomph::AlgebraicCollapsibleChannelMesh::algebraic_node_update
void algebraic_node_update(const unsigned &t, AlgebraicNode *&node_pt)
Update nodal position at time level t (t=0: present; t>0: previous)
Definition
collapsible_channel_mesh.template.cc:243
oomph::CollapsibleChannelDomain
Collapsible channel domain.
Definition
collapsible_channel_domain.h:41
oomph::CollapsibleChannelMesh::CollapsibleChannelMesh
CollapsibleChannelMesh(const unsigned &nup, const unsigned &ncollapsible, const unsigned &ndown, const unsigned &ny, const double &lup, const double &lcollapsible, const double &ldown, const double &ly, GeomObject *wall_pt, TimeStepper *time_stepper_pt=&Mesh::Default_TimeStepper)
Constructor: Pass number of elements in upstream/collapsible/ downstream segment and across the chann...
Definition
collapsible_channel_mesh.template.cc:45
oomph::CollapsibleChannelMesh::wall_pt
GeomObject *& wall_pt()
Access function to GeomObject representing wall.
Definition
collapsible_channel_mesh.h:90
oomph::CollapsibleChannelMesh::Domain_pt
CollapsibleChannelDomain * Domain_pt
Pointer to domain.
Definition
collapsible_channel_mesh.h:145
oomph::RefineableAlgebraicCollapsibleChannelMesh::update_node_update
void update_node_update(AlgebraicNode *&node_pt)
Update the node update data for specified node following any mesh adapation.
Definition
collapsible_channel_mesh.template.cc:435
oomph::RefineableTriangleMesh
Unstructured refineable Triangle Mesh.
Definition
triangle_mesh.h:2225
oomph::SimpleRectangularQuadMesh
Simple rectangular 2D Quad mesh class. Nx : number of elements in the x direction.
Definition
simple_rectangular_quadmesh.h:58
oomph::SimpleRectangularQuadMesh::ny
const unsigned & ny() const
Access function for number of elements in y directions.
Definition
simple_rectangular_quadmesh.h:77
oomph
Definition
annular_domain.h:35