full_circle_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-2022 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
27#ifndef OOMPH_FULL_CIRCLE_MESH_TEMPLATE_CC
28#define OOMPH_FULL_CIRCLE_MESH_TEMPLATE_CC
29
31
32namespace oomph
33{
34 //====================================================================
35 /// Constructor for deformable quarter tube mesh class.
36 /// The domain is specified by the GeomObject that
37 /// identifies the entire volume.
38 //====================================================================
39 template<class ELEMENT>
41 const Vector<double>& theta_positions,
42 const Vector<double>& radius_box,
43 TimeStepper* time_stepper_pt)
44 : Area_pt(area_pt)
45 {
46// Check that the vectors are the correct sizes.
47#ifdef PARANOID
48 if (radius_box.size() != 4 || theta_positions.size() != 4)
49 {
50 std::string err =
51 "This mesh is hard coded to only work for the case when there are 5 "
52 "elements: the central square and 4 surrounding elements, but you gave "
53 "vectors inconsistent with this.";
54 throw OomphLibError(
55 err, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
56 }
57#endif
58
59 // Mesh can only be built with 2D Qelements.
60 MeshChecker::assert_geometric_element<QElementGeometricBase, ELEMENT>(2);
61
62 // Build macro element-based domain
63 Domain_pt = new FullCircleDomain(area_pt, theta_positions, radius_box);
64
65 // Set the number of boundaries
67
68 // We have only bothered to parametrise the only boundary (boundary 0)
70
71 // Allocate the store for the elements
72 const unsigned nelem = 5;
73 Element_pt.resize(nelem);
74
75 // Create dummy element so we can determine the number of nodes
76 ELEMENT* dummy_el_pt = new ELEMENT;
77
78 // Read out the number of linear points in the element
79 unsigned n_p = dummy_el_pt->nnode_1d();
80
81 // Kill the element
82 delete dummy_el_pt;
83
84 // Can now allocate the store for the nodes
85 unsigned nnodes_total = (n_p * n_p + 4 * (n_p - 1) * (n_p - 1));
86 Node_pt.resize(nnodes_total);
87
89 Vector<double> r(2);
90
91 // Storage for the intrinsic boundary coordinate
92 Vector<double> zeta(1);
93
94 // Loop over elements and create all nodes
95 for (unsigned ielem = 0; ielem < nelem; ielem++)
96 {
97 // Create element
98 Element_pt[ielem] = new ELEMENT;
99
100 // Loop over rows in y/s_1-direction
101 for (unsigned i1 = 0; i1 < n_p; i1++)
102 {
103 // Loop over rows in x/s_0-direction
104 for (unsigned i0 = 0; i0 < n_p; i0++)
105 {
106 // Local node number
107 unsigned jnod_local = i0 + i1 * n_p;
108
109 // Create the node
111 jnod_local, time_stepper_pt);
112
113 // Set the position of the node from macro element mapping
114 s[0] = -1.0 + 2.0 * double(i0) / double(n_p - 1);
115 s[1] = -1.0 + 2.0 * double(i1) / double(n_p - 1);
117
118 node_pt->x(0) = r[0];
119 node_pt->x(1) = r[1];
120 }
121 }
122 }
123
124 // Initialise number of global nodes
125 unsigned node_count = 0;
126
127 // Tolerance for node killing:
128 double node_kill_tol = 1.0e-12;
129
130 // Check for error in node killing
131 bool stopit = false;
132
133 // Define pine
134 const double pi = MathematicalConstants::Pi;
135
136 // Loop over elements
137 for (unsigned ielem = 0; ielem < nelem; ielem++)
138 {
139 // Which macro element?
140 switch (ielem)
141 {
142 // Macro element 0: Central box, create all the nodes
143 //----------------------------------------------------
144 case 0:
145
146 // Loop over rows in y/s_1-direction
147 for (unsigned i1 = 0; i1 < n_p; i1++)
148 {
149 // Loop over rows in x/s_0-direction
150 for (unsigned i0 = 0; i0 < n_p; i0++)
151 {
152 // Local node number
153 unsigned jnod_local = i0 + i1 * n_p;
154
155 // Add the node to the mesh
156 Node_pt[node_count] =
157 finite_element_pt(ielem)->node_pt(jnod_local);
158
159 // Increment node counter
160 node_count++;
161 }
162 }
163
164 break;
165
166 // Macro element 1: Bottom
167 //---------------------------------
168 case 1:
169
170 // Loop over rows in y/s_1-direction
171 for (unsigned i1 = 0; i1 < n_p; i1++)
172 {
173 // Loop over rows in x/s_0-direction
174 for (unsigned i0 = 0; i0 < n_p; i0++)
175 {
176 // Local node number
177 unsigned jnod_local = i0 + i1 * n_p;
178
179 // Has the node been killed?
180 bool killed = false;
181
182 // Duplicate node: kill and set pointer to central element
183 if (i1 == (n_p - 1))
184 {
185 // Neighbour element
186 unsigned ielem_neigh = ielem - 1;
187
188 // Node in neighbour element
189 unsigned i0_neigh = i0;
190 unsigned i1_neigh = 0;
191 unsigned jnod_local_neigh = i0_neigh + i1_neigh * n_p;
192
193 // Check:
194 for (unsigned i = 0; i < 2; i++)
195 {
196 double error = std::fabs(
197 finite_element_pt(ielem)->node_pt(jnod_local)->x(i) -
198 finite_element_pt(ielem_neigh)
199 ->node_pt(jnod_local_neigh)
200 ->x(i));
201 if (error > node_kill_tol)
202 {
203 oomph_info << "Error in node killing for i " << i << " "
204 << error << std::endl;
205 stopit = true;
206 }
207 }
208
209 // Kill node
210 delete finite_element_pt(ielem)->node_pt(jnod_local);
211 killed = true;
212
213 // Set pointer to neighbour:
214 finite_element_pt(ielem)->node_pt(jnod_local) =
215 finite_element_pt(ielem_neigh)->node_pt(jnod_local_neigh);
216 }
217
218 // No duplicate node: Copy across to mesh
219 if (!killed)
220 {
221 Node_pt[node_count] =
222 finite_element_pt(ielem)->node_pt(jnod_local);
223
224 // Set boundaries:
225
226 // Bottom: outer boundary
227 if (i1 == 0)
228 {
229 this->convert_to_boundary_node(Node_pt[node_count]);
230 add_boundary_node(0, Node_pt[node_count]);
231
232 // Get azimuthal boundary coordinate
233 zeta[0] = theta_positions[0] +
234 double(i1) / double(n_p - 1) * 0.5 *
235 (theta_positions[1] - theta_positions[0]);
236
237 Node_pt[node_count]->set_coordinates_on_boundary(0, zeta);
238 }
239
240 // Increment node counter
241 node_count++;
242 }
243 }
244 } // End of loop over nodes
245
246 break;
247
248
249 // Macro element 2: Right element
250 //--------------------------------
251 case 2:
252
253 // Loop over rows in y/s_1-direction
254 for (unsigned i1 = 0; i1 < n_p; i1++)
255 {
256 // Loop over rows in x/s_0-direction
257 for (unsigned i0 = 0; i0 < n_p; i0++)
258 {
259 // Local node number
260 unsigned jnod_local = i0 + i1 * n_p;
261
262 // Has the node been killed?
263 bool killed = false;
264
265 // Duplicate node: kill and set pointer to previous element
266 if (i1 == 0)
267 {
268 // Neighbour element
269 unsigned ielem_neigh = ielem - 1;
270
271 // Node in neighbour element
272 unsigned i0_neigh = n_p - 1;
273 unsigned i1_neigh = n_p - 1 - i0;
274
275 unsigned jnod_local_neigh = i0_neigh + i1_neigh * n_p;
276
277 // Check:
278 for (unsigned i = 0; i < 2; i++)
279 {
280 double error = std::fabs(
281 finite_element_pt(ielem)->node_pt(jnod_local)->x(i) -
282 finite_element_pt(ielem_neigh)
283 ->node_pt(jnod_local_neigh)
284 ->x(i));
285 if (error > node_kill_tol)
286 {
287 oomph_info << "Error in node killing for i " << i << " "
288 << error << std::endl;
289 stopit = true;
290 }
291 }
292
293 // Kill node
294 delete finite_element_pt(ielem)->node_pt(jnod_local);
295 killed = true;
296
297 // Set pointer to neighbour:
298 finite_element_pt(ielem)->node_pt(jnod_local) =
299 finite_element_pt(ielem_neigh)->node_pt(jnod_local_neigh);
300 }
301
302
303 // Duplicate node: kill and set pointer to central element
304 if ((i0 == 0) && (i1 != 0))
305 {
306 // Neighbour element
307 unsigned ielem_neigh = ielem - 2;
308
309 // Node in neighbour element
310 unsigned i0_neigh = n_p - 1;
311 unsigned i1_neigh = i1;
312 unsigned jnod_local_neigh = i0_neigh + i1_neigh * n_p;
313
314 // Check:
315 for (unsigned i = 0; i < 2; i++)
316 {
317 double error = std::fabs(
318 finite_element_pt(ielem)->node_pt(jnod_local)->x(i) -
319 finite_element_pt(ielem_neigh)
320 ->node_pt(jnod_local_neigh)
321 ->x(i));
322 if (error > node_kill_tol)
323 {
324 oomph_info << "Error in node killing for i " << i << " "
325 << error << std::endl;
326 stopit = true;
327 }
328 }
329
330 // Kill node
331 delete finite_element_pt(ielem)->node_pt(jnod_local);
332 killed = true;
333
334 // Set pointer to neighbour:
335 finite_element_pt(ielem)->node_pt(jnod_local) =
336 finite_element_pt(ielem_neigh)->node_pt(jnod_local_neigh);
337 }
338
339 // No duplicate node: Copy across to mesh
340 if (!killed)
341 {
342 Node_pt[node_count] =
343 finite_element_pt(ielem)->node_pt(jnod_local);
344
345 // Set boundaries:
346
347 // FullCircle boundary
348 if (i0 == n_p - 1)
349 {
350 this->convert_to_boundary_node(Node_pt[node_count]);
351 add_boundary_node(0, Node_pt[node_count]);
352
353 // Get azimuthal boundary coordinate
354 zeta[0] = theta_positions[1] +
355 double(i1) / double(n_p - 1) * 0.5 *
356 (theta_positions[2] - theta_positions[1]);
357
358 Node_pt[node_count]->set_coordinates_on_boundary(0, zeta);
359 }
360
361 // Increment node counter
362 node_count++;
363 }
364 }
365 }
366
367
368 break;
369
370 // Macro element 3: Top element
371 //--------------------------------
372 case 3:
373
374 // Loop over rows in y/s_1-direction
375 for (unsigned i1 = 0; i1 < n_p; i1++)
376 {
377 // Loop over rows in x/s_0-direction
378 for (unsigned i0 = 0; i0 < n_p; i0++)
379 {
380 // Local node number
381 unsigned jnod_local = i0 + i1 * n_p;
382
383 // Has the node been killed?
384 bool killed = false;
385
386
387 // Duplicate node: kill and set pointer to previous element
388 if (i0 == n_p - 1)
389 {
390 // Neighbour element
391 unsigned ielem_neigh = ielem - 1;
392
393 // Node in neighbour element
394 unsigned i0_neigh = i1;
395 unsigned i1_neigh = n_p - 1;
396 unsigned jnod_local_neigh = i0_neigh + i1_neigh * n_p;
397
398 // Check:
399 for (unsigned i = 0; i < 2; i++)
400 {
401 double error = std::fabs(
402 finite_element_pt(ielem)->node_pt(jnod_local)->x(i) -
403 finite_element_pt(ielem_neigh)
404 ->node_pt(jnod_local_neigh)
405 ->x(i));
406 if (error > node_kill_tol)
407 {
408 oomph_info << "Error in node killing for i " << i << " "
409 << error << std::endl;
410 stopit = true;
411 }
412 }
413
414 // Kill node
415 delete finite_element_pt(ielem)->node_pt(jnod_local);
416 killed = true;
417
418 // Set pointer to neighbour:
419 finite_element_pt(ielem)->node_pt(jnod_local) =
420 finite_element_pt(ielem_neigh)->node_pt(jnod_local_neigh);
421 }
422
423 // Duplicate node: kill and set pointer to central element
424 if ((i1 == 0) && (i0 != n_p - 1))
425 {
426 // Neighbour element
427 unsigned ielem_neigh = ielem - 3;
428
429 // Node in neighbour element
430 unsigned i0_neigh = i0;
431 unsigned i1_neigh = n_p - 1;
432 unsigned jnod_local_neigh = i0_neigh + i1_neigh * n_p;
433
434 // Check:
435 for (unsigned i = 0; i < 2; i++)
436 {
437 double error = std::fabs(
438 finite_element_pt(ielem)->node_pt(jnod_local)->x(i) -
439 finite_element_pt(ielem_neigh)
440 ->node_pt(jnod_local_neigh)
441 ->x(i));
442 if (error > node_kill_tol)
443 {
444 oomph_info << "Error in node killing for i " << i << " "
445 << error << std::endl;
446 stopit = true;
447 }
448 }
449
450 // Kill node
451 delete finite_element_pt(ielem)->node_pt(jnod_local);
452 killed = true;
453
454 // Set pointer to neighbour:
455 finite_element_pt(ielem)->node_pt(jnod_local) =
456 finite_element_pt(ielem_neigh)->node_pt(jnod_local_neigh);
457 }
458
459 // No duplicate node: Copy across to mesh
460 if (!killed)
461 {
462 Node_pt[node_count] =
463 finite_element_pt(ielem)->node_pt(jnod_local);
464
465 // Set boundaries:
466
467 // FullCircle boundary
468 if (i1 == n_p - 1)
469 {
470 this->convert_to_boundary_node(Node_pt[node_count]);
471 add_boundary_node(0, Node_pt[node_count]);
472
473 // Get azimuthal boundary coordinate
474 zeta[0] = theta_positions[3] +
475 double(i0) / double(n_p - 1) * 0.5 *
476 (theta_positions[2] - theta_positions[3]);
477
478 Node_pt[node_count]->set_coordinates_on_boundary(0, zeta);
479 }
480
481 // Increment node counter
482 node_count++;
483 }
484 }
485 }
486 break;
487
488
489 // Macro element 4: Left element
490 //--------------------------------
491 case 4:
492
493 // Loop over rows in y/s_1-direction
494 for (unsigned i1 = 0; i1 < n_p; i1++)
495 {
496 // Loop over rows in x/s_0-direction
497 for (unsigned i0 = 0; i0 < n_p; i0++)
498 {
499 // Local node number
500 unsigned jnod_local = i0 + i1 * n_p;
501
502 // Has the node been killed?
503 bool killed = false;
504
505 // Duplicate node: kill and set pointer to previous element
506 if (i1 == n_p - 1)
507 {
508 // Neighbour element
509 unsigned ielem_neigh = ielem - 1;
510
511 // Node in neighbour element
512 unsigned i0_neigh = 0;
513 unsigned i1_neigh = n_p - 1 - i0;
514 unsigned jnod_local_neigh = i0_neigh + i1_neigh * n_p;
515
516 // Check:
517 for (unsigned i = 0; i < 2; i++)
518 {
519 double error = std::fabs(
520 finite_element_pt(ielem)->node_pt(jnod_local)->x(i) -
521 finite_element_pt(ielem_neigh)
522 ->node_pt(jnod_local_neigh)
523 ->x(i));
524 if (error > node_kill_tol)
525 {
526 oomph_info << "Error in node killing for i " << i << " "
527 << error << std::endl;
528 stopit = true;
529 }
530 }
531
532 // Kill node
533 delete finite_element_pt(ielem)->node_pt(jnod_local);
534 killed = true;
535
536 // Set pointer to neighbour:
537 finite_element_pt(ielem)->node_pt(jnod_local) =
538 finite_element_pt(ielem_neigh)->node_pt(jnod_local_neigh);
539 }
540
541 // Duplicate node: kill and set pointer to central element
542 if ((i0 == n_p - 1) && (i1 != n_p - 1))
543 {
544 // Neighbour element
545 unsigned ielem_neigh = ielem - 4;
546
547 // Node in neighbour element
548 unsigned i0_neigh = 0;
549 unsigned i1_neigh = i1;
550 unsigned jnod_local_neigh = i0_neigh + i1_neigh * n_p;
551
552 // Check:
553 for (unsigned i = 0; i < 2; i++)
554 {
555 double error = std::fabs(
556 finite_element_pt(ielem)->node_pt(jnod_local)->x(i) -
557 finite_element_pt(ielem_neigh)
558 ->node_pt(jnod_local_neigh)
559 ->x(i));
560 if (error > node_kill_tol)
561 {
562 oomph_info << "Error in node killing for i " << i << " "
563 << error << std::endl;
564 stopit = true;
565 }
566 }
567
568 // Kill node
569 delete finite_element_pt(ielem)->node_pt(jnod_local);
570 killed = true;
571
572 // Set pointer to neighbour:
573 finite_element_pt(ielem)->node_pt(jnod_local) =
574 finite_element_pt(ielem_neigh)->node_pt(jnod_local_neigh);
575 }
576
577 // Duplicate node: kill and set pointer to other ring element
578 if ((i1 == 0) && (i0 != n_p - 1))
579 {
580 // Neighbour element
581 unsigned ielem_neigh = ielem - 3;
582
583 // Node in neighbour element
584 unsigned i0_neigh = 0;
585 unsigned i1_neigh = i0;
586 unsigned jnod_local_neigh = i0_neigh + i1_neigh * n_p;
587
588 // Check:
589 for (unsigned i = 0; i < 2; i++)
590 {
591 double error = std::fabs(
592 finite_element_pt(ielem)->node_pt(jnod_local)->x(i) -
593 finite_element_pt(ielem_neigh)
594 ->node_pt(jnod_local_neigh)
595 ->x(i));
596 if (error > node_kill_tol)
597 {
598 oomph_info << "Error in node killing for i " << i << " "
599 << error << std::endl;
600 stopit = true;
601 }
602 }
603
604 // Kill node
605 delete finite_element_pt(ielem)->node_pt(jnod_local);
606 killed = true;
607
608 // Set pointer to neighbour:
609 finite_element_pt(ielem)->node_pt(jnod_local) =
610 finite_element_pt(ielem_neigh)->node_pt(jnod_local_neigh);
611 }
612
613
614 // No duplicate node: Copy across to mesh
615 if (!killed)
616 {
617 Node_pt[node_count] =
618 finite_element_pt(ielem)->node_pt(jnod_local);
619
620 // Set boundaries:
621
622 // FullCircle boundary
623 if (i0 == 0)
624 {
625 this->convert_to_boundary_node(Node_pt[node_count]);
626 add_boundary_node(0, Node_pt[node_count]);
627
628 // Get azimuthal boundary coordinate
629 zeta[0] =
630 theta_positions[0] + 2.0 * pi +
631 double(i1) / double(n_p - 1) * 0.5 *
632 (theta_positions[3] - theta_positions[0] + 2.0 * pi);
633
634 Node_pt[node_count]->set_coordinates_on_boundary(0, zeta);
635 }
636
637 // Increment node counter
638 node_count++;
639 }
640 }
641 }
642 break;
643 }
644 }
645
646 // Terminate if there's been an error
647 if (stopit)
648 {
649 std::ostringstream error_stream;
650 error_stream << "Error in killing nodes\n"
651 << "The most probable cause is that the domain is not\n"
652 << "compatible with the mesh.\n"
653 << "For the FullCircleMesh, the domain must be\n"
654 << "topologically consistent with a quarter tube with a\n"
655 << "non-curved centreline.\n";
656 throw OomphLibError(
657 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
658 }
659
660 // Setup boundary element lookup schemes
662 }
663
664} // namespace oomph
665#endif
static char t char * s
Definition: cfortran.h:568
cstr elem_len * i
Definition: cfortran.h:603
MacroElement * macro_element_pt(const unsigned &i)
Access to i-th macro element.
Definition: domain.h:116
virtual Node * construct_node(const unsigned &n)
Construct the local node n and return a pointer to the newly created node object.
Definition: elements.h:2509
Node *& node_pt(const unsigned &n)
Return a pointer to the local node n.
Definition: elements.h:2175
Topologically circular domain, e.g. a tube cross section. The entire domain must be defined by a Geom...
FullCircleDomain * Domain_pt
Pointer to domain.
GeomObject *& area_pt()
Access function to GeomObject representing wall.
FullCircleMesh(GeomObject *wall_pt, const Vector< double > &theta_positions, const Vector< double > &radius_box, TimeStepper *time_stepper_pt=&Mesh::Default_TimeStepper)
Constructor: Pass pointer to geometric object that specifies the area; values of theta at which divid...
/////////////////////////////////////////////////////////////////////
Definition: geom_objects.h:101
void macro_map(const Vector< double > &s, Vector< double > &r)
The mapping from local to global coordinates at the current time : r(s)
void add_boundary_node(const unsigned &b, Node *const &node_pt)
Add a (pointer to) a node to the b-th boundary.
Definition: mesh.cc:243
Vector< Node * > Node_pt
Vector of pointers to nodes.
Definition: mesh.h:183
std::vector< bool > Boundary_coordinate_exists
Vector of boolean data that indicates whether the boundary coordinates have been set for the boundary...
Definition: mesh.h:190
FiniteElement * finite_element_pt(const unsigned &e) const
Upcast (downcast?) to FiniteElement (needed to access FiniteElement member functions).
Definition: mesh.h:473
void set_nboundary(const unsigned &nbound)
Set the number of boundaries in the mesh.
Definition: mesh.h:505
Node *& node_pt(const unsigned long &n)
Return pointer to global node n.
Definition: mesh.h:436
void convert_to_boundary_node(Node *&node_pt, const Vector< FiniteElement * > &finite_element_pt)
A function that upgrades an ordinary node to a boundary node We shouldn't ever really use this,...
Definition: mesh.cc:2590
Vector< GeneralisedElement * > Element_pt
Vector of pointers to generalised elements.
Definition: mesh.h:186
Nodes are derived from Data, but, in addition, have a definite (Eulerian) position in a space of a gi...
Definition: nodes.h:906
double & x(const unsigned &i)
Return the i-th nodal coordinate.
Definition: nodes.h:1060
An OomphLibError object which should be thrown when an run-time error is encountered....
void setup_boundary_element_info()
Setup lookup schemes which establish whic elements are located next to mesh's boundaries (wrapper to ...
Definition: quad_mesh.h:73
////////////////////////////////////////////////////////////////////// //////////////////////////////...
Definition: timesteppers.h:231
std::string string(const unsigned &i)
Return the i-th string or "" if the relevant string hasn't been defined.
const double Pi
50 digits from maple
//////////////////////////////////////////////////////////////////// ////////////////////////////////...
OomphInfo oomph_info
Single (global) instantiation of the OomphInfo object – this is used throughout the library as a "rep...