quarter_tube_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#ifndef OOMPH_QUARTER_TUBE_MESH_TEMPLATE_CC
27#define OOMPH_QUARTER_TUBE_MESH_TEMPLATE_CC
28
30
31
32namespace oomph
33{
34 //====================================================================
35 /// Constructor for deformable quarter tube mesh class.
36 /// The domain is specified by the GeomObject that
37 /// identifies boundary 3. Pass pointer to geometric object that
38 /// specifies the wall, start and end coordinates on the
39 /// geometric object, and the fraction along
40 /// which the dividing line is to be placed, and the timestepper.
41 /// Timestepper defaults to Static dummy timestepper.
42 //====================================================================
43 template<class ELEMENT>
45 const Vector<double>& xi_lo,
46 const double& fract_mid,
47 const Vector<double>& xi_hi,
48 const unsigned& nlayer,
49 TimeStepper* time_stepper_pt)
50 : Wall_pt(wall_pt), Xi_lo(xi_lo), Fract_mid(fract_mid), Xi_hi(xi_hi)
51 {
52 // Mesh can only be built with 3D Qelements.
53 MeshChecker::assert_geometric_element<QElementGeometricBase, ELEMENT>(3);
54
55 // Build macro element-based domain
56 Domain_pt = new QuarterTubeDomain(wall_pt, xi_lo, fract_mid, xi_hi, nlayer);
57
58 // Set the number of boundaries
60
61 // We have only bothered to parametrise boundary 3
63
64 // Allocate the store for the elements
65 unsigned nelem = 3 * nlayer;
66 Element_pt.resize(nelem);
67
68 // Create dummy element so we can determine the number of nodes
69 ELEMENT* dummy_el_pt = new ELEMENT;
70
71 // Read out the number of linear points in the element
72 unsigned n_p = dummy_el_pt->nnode_1d();
73
74 // Kill the element
75 delete dummy_el_pt;
76
77 // Can now allocate the store for the nodes
78 unsigned nnodes_total =
79 (n_p * n_p + (n_p - 1) * n_p + (n_p - 1) * (n_p - 1)) *
80 (1 + nlayer * (n_p - 1));
81 Node_pt.resize(nnodes_total);
82
83
85 Vector<double> r(3);
86
87 // Storage for the intrinsic boundary coordinate
88 Vector<double> zeta(2);
89
90 // Loop over elements and create all nodes
91 for (unsigned ielem = 0; ielem < nelem; ielem++)
92 {
93 // Create element
94 Element_pt[ielem] = new ELEMENT;
95
96 // Loop over rows in z/s_2-direction
97 for (unsigned i2 = 0; i2 < n_p; i2++)
98 {
99 // Loop over rows in y/s_1-direction
100 for (unsigned i1 = 0; i1 < n_p; i1++)
101 {
102 // Loop over rows in x/s_0-direction
103 for (unsigned i0 = 0; i0 < n_p; i0++)
104 {
105 // Local node number
106 unsigned jnod_local = i0 + i1 * n_p + i2 * n_p * n_p;
107
108 // Create the node
110 jnod_local, time_stepper_pt);
111
112 // Set the position of the node from macro element mapping
113 s[0] = -1.0 + 2.0 * double(i0) / double(n_p - 1);
114 s[1] = -1.0 + 2.0 * double(i1) / double(n_p - 1);
115 s[2] = -1.0 + 2.0 * double(i2) / double(n_p - 1);
117
118 node_pt->x(0) = r[0];
119 node_pt->x(1) = r[1];
120 node_pt->x(2) = r[2];
121 }
122 }
123 }
124 }
125
126 // Initialise number of global nodes
127 unsigned node_count = 0;
128
129 // Tolerance for node killing:
130 double node_kill_tol = 1.0e-12;
131
132 // Check for error in node killing
133 bool stopit = false;
134
135 // Loop over elements
136 for (unsigned ielem = 0; ielem < nelem; ielem++)
137 {
138 // Which layer?
139 unsigned ilayer = unsigned(ielem / 3);
140
141 // Which macro element?
142 switch (ielem % 3)
143 {
144 // Macro element 0: Central box
145 //-----------------------------
146 case 0:
147
148
149 // Loop over rows in z/s_2-direction
150 for (unsigned i2 = 0; i2 < n_p; i2++)
151 {
152 // Loop over rows in y/s_1-direction
153 for (unsigned i1 = 0; i1 < n_p; i1++)
154 {
155 // Loop over rows in x/s_0-direction
156 for (unsigned i0 = 0; i0 < n_p; i0++)
157 {
158 // Local node number
159 unsigned jnod_local = i0 + i1 * n_p + i2 * n_p * n_p;
160
161 // Has the node been killed?
162 bool killed = false;
163
164 // First layer of all nodes in s_2 direction gets killed
165 // and re-directed to nodes in previous element layer
166 if ((i2 == 0) && (ilayer > 0))
167 {
168 // Neighbour element
169 unsigned ielem_neigh = ielem - 3;
170
171 // Node in neighbour element
172 unsigned i0_neigh = i0;
173 unsigned i1_neigh = i1;
174 unsigned i2_neigh = n_p - 1;
175 unsigned jnod_local_neigh =
176 i0_neigh + i1_neigh * n_p + i2_neigh * n_p * n_p;
177
178 // Check:
179 for (unsigned i = 0; i < 3; i++)
180 {
181 double error = std::fabs(
182 finite_element_pt(ielem)->node_pt(jnod_local)->x(i) -
183 finite_element_pt(ielem_neigh)
184 ->node_pt(jnod_local_neigh)
185 ->x(i));
186 if (error > node_kill_tol)
187 {
188 oomph_info << "Error in node killing for i " << i << " "
189 << error << std::endl;
190 stopit = true;
191 }
192 }
193
194 // Kill node
195 delete finite_element_pt(ielem)->node_pt(jnod_local);
196 killed = true;
197
198 // Set pointer to neighbour:
199 finite_element_pt(ielem)->node_pt(jnod_local) =
200 finite_element_pt(ielem_neigh)->node_pt(jnod_local_neigh);
201 }
202
203 // No duplicate node: Copy across to mesh
204 if (!killed)
205 {
206 Node_pt[node_count] =
207 finite_element_pt(ielem)->node_pt(jnod_local);
208
209 // Set boundaries:
210
211 // Back: Boundary 0
212 if ((i2 == 0) && (ilayer == 0))
213 {
214 this->convert_to_boundary_node(Node_pt[node_count]);
215 add_boundary_node(0, Node_pt[node_count]);
216 }
217
218 // Front: Boundary 4
219 if ((i2 == n_p - 1) && (ilayer == nlayer - 1))
220 {
221 this->convert_to_boundary_node(Node_pt[node_count]);
222 add_boundary_node(4, Node_pt[node_count]);
223 }
224
225 // Left symmetry plane: Boundary 1
226 if (i0 == 0)
227 {
228 this->convert_to_boundary_node(Node_pt[node_count]);
229 add_boundary_node(1, Node_pt[node_count]);
230 }
231
232 // Bottom symmetry plane: Boundary 2
233 if (i1 == 0)
234 {
235 this->convert_to_boundary_node(Node_pt[node_count]);
236 add_boundary_node(2, Node_pt[node_count]);
237 }
238
239 // Increment node counter
240 node_count++;
241 }
242 }
243 }
244 }
245
246
247 break;
248
249 // Macro element 1: Lower right box
250 //---------------------------------
251 case 1:
252
253
254 // Loop over rows in z/s_2-direction
255 for (unsigned i2 = 0; i2 < n_p; i2++)
256 {
257 // Loop over rows in y/s_1-direction
258 for (unsigned i1 = 0; i1 < n_p; i1++)
259 {
260 // Loop over rows in x/s_0-direction
261 for (unsigned i0 = 0; i0 < n_p; i0++)
262 {
263 // Local node number
264 unsigned jnod_local = i0 + i1 * n_p + i2 * n_p * n_p;
265
266 // Has the node been killed?
267 bool killed = false;
268
269 // First layer of all nodes in s_2 direction gets killed
270 // and re-directed to nodes in previous element layer
271 if ((i2 == 0) && (ilayer > 0))
272 {
273 // Neighbour element
274 unsigned ielem_neigh = ielem - 3;
275
276 // Node in neighbour element
277 unsigned i0_neigh = i0;
278 unsigned i1_neigh = i1;
279 unsigned i2_neigh = n_p - 1;
280 unsigned jnod_local_neigh =
281 i0_neigh + i1_neigh * n_p + i2_neigh * n_p * n_p;
282
283
284 // Check:
285 for (unsigned i = 0; i < 3; i++)
286 {
287 double error = std::fabs(
288 finite_element_pt(ielem)->node_pt(jnod_local)->x(i) -
289 finite_element_pt(ielem_neigh)
290 ->node_pt(jnod_local_neigh)
291 ->x(i));
292 if (error > node_kill_tol)
293 {
294 oomph_info << "Error in node killing for i " << i << " "
295 << error << std::endl;
296 stopit = true;
297 }
298 }
299
300 // Kill node
301 delete finite_element_pt(ielem)->node_pt(jnod_local);
302 killed = true;
303
304 // Set pointer to neighbour:
305 finite_element_pt(ielem)->node_pt(jnod_local) =
306 finite_element_pt(ielem_neigh)->node_pt(jnod_local_neigh);
307 }
308 // Not in first layer:
309 else
310 {
311 // Duplicate node: kill and set pointer to central element
312 if (i0 == 0)
313 {
314 // Neighbour element
315 unsigned ielem_neigh = ielem - 1;
316
317 // Node in neighbour element
318 unsigned i0_neigh = n_p - 1;
319 unsigned i1_neigh = i1;
320 unsigned i2_neigh = i2;
321 unsigned jnod_local_neigh =
322 i0_neigh + i1_neigh * n_p + i2_neigh * n_p * n_p;
323
324
325 // Check:
326 for (unsigned i = 0; i < 3; i++)
327 {
328 double error = std::fabs(
329 finite_element_pt(ielem)->node_pt(jnod_local)->x(i) -
330 finite_element_pt(ielem_neigh)
331 ->node_pt(jnod_local_neigh)
332 ->x(i));
333 if (error > node_kill_tol)
334 {
335 oomph_info << "Error in node killing for i " << i << " "
336 << error << std::endl;
337 stopit = true;
338 }
339 }
340
341 // Kill node
342 delete finite_element_pt(ielem)->node_pt(jnod_local);
343 killed = true;
344
345 // Set pointer to neighbour:
346 finite_element_pt(ielem)->node_pt(jnod_local) =
347 finite_element_pt(ielem_neigh)->node_pt(jnod_local_neigh);
348 }
349 }
350
351 // No duplicate node: Copy across to mesh
352 if (!killed)
353 {
354 Node_pt[node_count] =
355 finite_element_pt(ielem)->node_pt(jnod_local);
356
357 // Set boundaries:
358
359 // Back: Boundary 0
360 if ((i2 == 0) && (ilayer == 0))
361 {
362 this->convert_to_boundary_node(Node_pt[node_count]);
363 add_boundary_node(0, Node_pt[node_count]);
364 }
365
366 // Front: Boundary 4
367 if ((i2 == n_p - 1) && (ilayer == nlayer - 1))
368 {
369 this->convert_to_boundary_node(Node_pt[node_count]);
370 add_boundary_node(4, Node_pt[node_count]);
371 }
372
373 // Bottom symmetry plane: Boundary 2
374 if (i1 == 0)
375 {
376 this->convert_to_boundary_node(Node_pt[node_count]);
377 add_boundary_node(2, Node_pt[node_count]);
378 }
379
380 // Tube wall: Boundary 3
381 if (i0 == n_p - 1)
382 {
383 this->convert_to_boundary_node(Node_pt[node_count]);
384 add_boundary_node(3, Node_pt[node_count]);
385
386
387 // Get axial boundary coordinate
388 zeta[0] = Xi_lo[0] +
389 (double(ilayer) + double(i2) / double(n_p - 1)) *
390 (Xi_hi[0] - Xi_lo[0]) / double(nlayer);
391
392 // Get azimuthal boundary coordinate
393 zeta[1] = Xi_lo[1] + double(i1) / double(n_p - 1) * 0.5 *
394 (Xi_hi[1] - Xi_lo[1]);
395
396 Node_pt[node_count]->set_coordinates_on_boundary(3, zeta);
397 }
398
399 // Increment node counter
400 node_count++;
401 }
402 }
403 }
404 }
405
406 break;
407
408
409 // Macro element 2: Top left box
410 //--------------------------------
411 case 2:
412
413 // Loop over rows in z/s_2-direction
414 for (unsigned i2 = 0; i2 < n_p; i2++)
415 {
416 // Loop over rows in y/s_1-direction
417 for (unsigned i1 = 0; i1 < n_p; i1++)
418 {
419 // Loop over rows in x/s_0-direction
420 for (unsigned i0 = 0; i0 < n_p; i0++)
421 {
422 // Local node number
423 unsigned jnod_local = i0 + i1 * n_p + i2 * n_p * n_p;
424
425 // Has the node been killed?
426 bool killed = false;
427
428 // First layer of all nodes in s_2 direction gets killed
429 // and re-directed to nodes in previous element layer
430 if ((i2 == 0) && (ilayer > 0))
431 {
432 // Neighbour element
433 unsigned ielem_neigh = ielem - 3;
434
435 // Node in neighbour element
436 unsigned i0_neigh = i0;
437 unsigned i1_neigh = i1;
438 unsigned i2_neigh = n_p - 1;
439 unsigned jnod_local_neigh =
440 i0_neigh + i1_neigh * n_p + i2_neigh * n_p * n_p;
441
442 // Check:
443 for (unsigned i = 0; i < 3; i++)
444 {
445 double error = std::fabs(
446 finite_element_pt(ielem)->node_pt(jnod_local)->x(i) -
447 finite_element_pt(ielem_neigh)
448 ->node_pt(jnod_local_neigh)
449 ->x(i));
450 if (error > node_kill_tol)
451 {
452 oomph_info << "Error in node killing for i " << i << " "
453 << error << std::endl;
454 stopit = true;
455 }
456 }
457
458 // Kill node
459 delete finite_element_pt(ielem)->node_pt(jnod_local);
460 killed = true;
461
462 // Set pointer to neighbour:
463 finite_element_pt(ielem)->node_pt(jnod_local) =
464 finite_element_pt(ielem_neigh)->node_pt(jnod_local_neigh);
465 }
466 // Not in first layer:
467 else
468 {
469 // Duplicate node: kill and set pointer to node in bottom
470 // right element
471 if (i0 == n_p - 1)
472 {
473 // Neighbour element
474 unsigned ielem_neigh = ielem - 1;
475
476 // Node in neighbour element
477 unsigned i0_neigh = i1;
478 unsigned i1_neigh = n_p - 1;
479 unsigned i2_neigh = i2;
480 unsigned jnod_local_neigh =
481 i0_neigh + i1_neigh * n_p + i2_neigh * n_p * n_p;
482
483 // Check:
484 for (unsigned i = 0; i < 3; i++)
485 {
486 double error = std::fabs(
487 finite_element_pt(ielem)->node_pt(jnod_local)->x(i) -
488 finite_element_pt(ielem_neigh)
489 ->node_pt(jnod_local_neigh)
490 ->x(i));
491 if (error > node_kill_tol)
492 {
493 oomph_info << "Error in node killing for i " << i << " "
494 << error << std::endl;
495 stopit = true;
496 }
497 }
498
499 // Kill node
500 delete finite_element_pt(ielem)->node_pt(jnod_local);
501 killed = true;
502
503 // Set pointer to neighbour:
504 finite_element_pt(ielem)->node_pt(jnod_local) =
505 finite_element_pt(ielem_neigh)->node_pt(jnod_local_neigh);
506 }
507
508
509 // Duplicate node: kill and set pointer to central element
510 if ((i1 == 0) && (i0 != n_p - 1))
511 {
512 // Neighbour element
513 unsigned ielem_neigh = ielem - 2;
514
515 // Node in neighbour element
516 unsigned i0_neigh = i0;
517 unsigned i1_neigh = n_p - 1;
518 unsigned i2_neigh = i2;
519 unsigned jnod_local_neigh =
520 i0_neigh + i1_neigh * n_p + i2_neigh * n_p * n_p;
521
522 // Check:
523 for (unsigned i = 0; i < 3; i++)
524 {
525 double error = std::fabs(
526 finite_element_pt(ielem)->node_pt(jnod_local)->x(i) -
527 finite_element_pt(ielem_neigh)
528 ->node_pt(jnod_local_neigh)
529 ->x(i));
530 if (error > node_kill_tol)
531 {
532 oomph_info << "Error in node killing for i " << i << " "
533 << error << std::endl;
534 stopit = true;
535 }
536 }
537
538 // Kill node
539 delete finite_element_pt(ielem)->node_pt(jnod_local);
540 killed = true;
541
542 // Set pointer to neighbour:
543 finite_element_pt(ielem)->node_pt(jnod_local) =
544 finite_element_pt(ielem_neigh)->node_pt(jnod_local_neigh);
545 }
546
547 // No duplicate node: Copy across to mesh
548 if (!killed)
549 {
550 Node_pt[node_count] =
551 finite_element_pt(ielem)->node_pt(jnod_local);
552
553 // Set boundaries:
554
555 // Back: Boundary 0
556 if ((i2 == 0) && (ilayer == 0))
557 {
558 this->convert_to_boundary_node(Node_pt[node_count]);
559 add_boundary_node(0, Node_pt[node_count]);
560 }
561
562 // Front: Boundary 4
563 if ((i2 == n_p - 1) && (ilayer == nlayer - 1))
564 {
565 this->convert_to_boundary_node(Node_pt[node_count]);
566 add_boundary_node(4, Node_pt[node_count]);
567 }
568
569 // Left symmetry plane: Boundary 1
570 if (i0 == 0)
571 {
572 this->convert_to_boundary_node(Node_pt[node_count]);
573 add_boundary_node(1, Node_pt[node_count]);
574 }
575
576
577 // Tube wall: Boundary 3
578 if (i1 == n_p - 1)
579 {
580 this->convert_to_boundary_node(Node_pt[node_count]);
581 add_boundary_node(3, Node_pt[node_count]);
582
583
584 // Get axial boundary coordinate
585 zeta[0] =
586 Xi_lo[0] +
587 (double(ilayer) + double(i2) / double(n_p - 1)) *
588 (Xi_hi[0] - Xi_lo[0]) / double(nlayer);
589
590 // Get azimuthal boundary coordinate
591 zeta[1] = Xi_hi[1] - double(i0) / double(n_p - 1) * 0.5 *
592 (Xi_hi[1] - Xi_lo[1]);
593
594 Node_pt[node_count]->set_coordinates_on_boundary(3, zeta);
595 }
596
597 // Increment node counter
598 node_count++;
599 }
600 }
601 }
602 }
603 }
604
605 break;
606 }
607 }
608
609 // Terminate if there's been an error
610 if (stopit)
611 {
612 std::ostringstream error_stream;
613 error_stream << "Error in killing nodes\n"
614 << "The most probable cause is that the domain is not\n"
615 << "compatible with the mesh.\n"
616 << "For the QuarterTubeMesh, the domain must be\n"
617 << "topologically consistent with a quarter tube with a\n"
618 << "non-curved centreline.\n";
619 throw OomphLibError(
620 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
621 }
622
623 // Setup boundary element lookup schemes
625 }
626
627 /// ////////////////////////////////////////////////////////////////////
628 /// ////////////////////////////////////////////////////////////////////
629 // Algebraic-mesh-version of RefineableQuarterTubeMesh
630 /// ////////////////////////////////////////////////////////////////////
631 /// ////////////////////////////////////////////////////////////////////
632
633
634 //======================================================================
635 /// Setup algebraic node update data, based on 3 regions, each
636 /// undergoing a different node update strategy. These regions are
637 /// defined by the three MacroElements in each of the nlayer slices
638 /// of the QuarterTubeDomain used to build the mesh.
639 /// The Mesh is suspended from the `wall' GeomObject pointed to
640 /// by wall_pt. The lower right edge of the mesh is located at the
641 /// wall's coordinate xi[1]==xi_lo[1], the upper left edge at
642 /// xi[1]=xi_hi[1], i.e. a view looking down the tube length.
643 /// The dividing line between the two outer regions is located
644 /// at the fraction fract_mid between these two coordinates.
645 /// Node updating strategy:
646 /// - the starting cross sectional shape along the tube length is
647 /// assumed to be uniform
648 /// - the cross sectional shape of the central region remains
649 /// rectangular; the position of its top right corner is located
650 /// at a fixed fraction of the starting width and height of the
651 /// domain measured at xi[1]==xi_lo[1] and xi[1]==xi_hi[1]
652 /// respectively. Nodes in this region are located at fixed
653 /// horizontal and vertical fractions of the region.
654 /// - Nodes in the two outer regions (bottom right and top left)
655 /// are located on straight lines running from the edges of the
656 /// central region to the outer wall.
657 //======================================================================
658 template<class ELEMENT>
660 ELEMENT>::setup_algebraic_node_update()
661 {
662#ifdef PARANOID
663 /// Pointer to first algebraic element in central region
664 AlgebraicElementBase* algebraic_element_pt =
665 dynamic_cast<AlgebraicElementBase*>(Mesh::element_pt(0));
666
667 if (algebraic_element_pt == 0)
668 {
669 std::ostringstream error_message;
670 error_message
671 << "Element in AlgebraicRefineableQuarterTubeMesh must be\n ";
672 error_message << "derived from AlgebraicElementBase\n";
673 error_message << "but it is of type: "
674 << typeid(Mesh::element_pt(0)).name() << std::endl;
675 std::string function_name = "AlgebraicRefineableQuarterTubeMesh::";
676 function_name += "setup_algebraic_node_update()";
677 throw OomphLibError(
678 error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
679 }
680#endif
681
682 // Find number of nodes in an element from the zeroth element
683 unsigned nnodes_3d = Mesh::finite_element_pt(0)->nnode();
684
685 // also find number of nodes in 1d line and 2d slice
686 unsigned nnodes_1d = Mesh::finite_element_pt(0)->nnode_1d();
687 unsigned nnodes_2d = nnodes_1d * nnodes_1d;
688
689 // find node number of a top-left and a bottom-right node in an element
690 // (orientation: looking down tube)
691 unsigned tl_node = nnodes_2d - nnodes_1d;
692 unsigned br_node = nnodes_1d - 1;
693
694 // find x & y distances to top-right node in element 0 - this is the same
695 // node as the top-left node of element 1
696 double x_c_element = Mesh::finite_element_pt(1)->node_pt(tl_node)->x(0);
697 double y_c_element = Mesh::finite_element_pt(1)->node_pt(tl_node)->x(1);
698
699 // Get x-distance to bottom-right edge of wall, i.e. coord of node
700 // at bottom-right of bottom-right of element 1
701 double x_wall = Mesh::finite_element_pt(1)->node_pt(br_node)->x(0);
702
703 // Get y-distance to top-left edge of wall, i.e. coord of node
704 // at top-left of element 2
705 double y_wall = Mesh::finite_element_pt(2)->node_pt(tl_node)->x(1);
706
707 // Establish fractional widths in central region
708 Lambda_x = Centre_box_size * x_c_element / x_wall;
709 Lambda_y = Centre_box_size * y_c_element / y_wall;
710
711 // how many elements are there?
712 unsigned nelements = Mesh::nelement();
713
714 // loop through the elements
715 for (unsigned e = 0; e < nelements; e++)
716 {
717 // get pointer to element
719
720 // set region id
721 unsigned region_id = e % 3;
722
723 // find the first node for which to set up node update info - must
724 // bypass the first nnodes_2d nodes after the first 3 elements
725 unsigned nstart = nnodes_2d;
726 if (e < 3)
727 {
728 nstart = 0;
729 }
730
731 // loop through the nodes,
732 for (unsigned n = nstart; n < nnodes_3d; n++)
733 {
734 // find z coordinate of node
735 // NOTE: to implement axial spacing replace z by z_spaced where
736 // z_spaced=axial_spacing_fct(z) when finding the GeomObjects
737 // and local coords below
738 // BUT store z as the third reference value since this is the value
739 // required by update_node_update()
740 double z = el_pt->node_pt(n)->x(2);
741
742 // Find wall GeomObject and the GeomObject local coordinates
743 // at bottom-right edge of wall
744 Vector<double> xi(2);
745 xi[0] = z;
747 GeomObject* obj_br_pt;
748 Vector<double> s_br(2);
749 this->Wall_pt->locate_zeta(xi, obj_br_pt, s_br);
750
751 // Find wall GeomObject/local coordinate
752 // at top-left edge of wall
754 GeomObject* obj_tl_pt;
755 Vector<double> s_tl(2);
756 this->Wall_pt->locate_zeta(xi, obj_tl_pt, s_tl);
757
758 // Element 0: central region
759 //--------------------------
760 if (region_id == 0)
761 {
762 // Nodal coordinates in x and y direction
763 double x = el_pt->node_pt(n)->x(0);
764 double y = el_pt->node_pt(n)->x(1);
765
766 // The update function requires two geometric objects
767 Vector<GeomObject*> geom_object_pt(2);
768
769 // Wall GeomObject at bottom right end of wall mesh:
770 geom_object_pt[0] = obj_br_pt;
771
772 // Wall GeomObject at top left end of wall mesh:
773 geom_object_pt[1] = obj_tl_pt;
774
775 // The update function requires seven parameters:
776 Vector<double> ref_value(7);
777
778 // First reference value: fractional x-position inside region
779 ref_value[0] = x / x_c_element;
780
781 // Second cfractional y-position inside region
782 ref_value[1] = y / y_c_element;
783
784 // Third reference value: initial z coordinate of node
785 ref_value[2] = z;
786
787 // Fourth and fifth reference values:
788 // local coordinate in GeomObject at bottom-right of wall.
789 // Note: must recompute this reference for new nodes
790 // since values interpolated from parent nodes will
791 // be wrong (this is true for all local coordinates
792 // within GeomObjects)
793 ref_value[3] = s_br[0];
794 ref_value[4] = s_br[1];
795
796 // Sixth and seventh reference values:
797 // local coordinate in GeomObject at top-left of wall.
798 ref_value[5] = s_tl[0];
799 ref_value[6] = s_tl[1];
800
801 // Setup algebraic update for node: Pass update information
802 static_cast<AlgebraicNode*>(el_pt->node_pt(n))
803 ->add_node_update_info(Central_region, // enumerated ID
804 this, // mesh
805 geom_object_pt, // vector of geom objects
806 ref_value); // vector of ref. values
807 }
808
809 // Element 1: Bottom right region
810 //-------------------------------
811 else if (region_id == 1)
812 {
813 // Fractional distance between nodes
814 double fract = 1.0 / double(nnodes_1d - 1);
815
816 // Fraction in the s_0-direction
817 double rho_0 = fract * double(n % nnodes_1d);
818
819 // Fraction in the s_1-direction
820 double rho_1 = fract * double((n / nnodes_1d) % nnodes_1d);
821
822 // Find coord of reference point on wall
827
828 // Identify wall GeomObject and local coordinate of
829 // reference point in GeomObject
830 GeomObject* obj_wall_pt;
831 Vector<double> s_wall(2);
832 this->Wall_pt->locate_zeta(xi, obj_wall_pt, s_wall);
833
834 // The update function requires three geometric objects
835 Vector<GeomObject*> geom_object_pt(3);
836
837 // Wall element at bottom-right end of wall mesh:
838 geom_object_pt[0] = obj_br_pt;
839
840 // Wall element at top left end of wall mesh:
841 geom_object_pt[1] = obj_tl_pt;
842
843 // Wall element at that contians reference point:
844 geom_object_pt[2] = obj_wall_pt;
845
846 // The update function requires nine parameters:
847 Vector<double> ref_value(9);
848
849 // First reference value: fractional s0-position inside region
850 ref_value[0] = rho_0;
851
852 // Second reference value: fractional s1-position inside region
853 ref_value[1] = rho_1;
854
855 // Thrid reference value: initial z coord of node
856 ref_value[2] = z;
857
858 // Fourth and fifth reference values:
859 // local coordinates at bottom-right of wall.
860 ref_value[3] = s_br[0];
861 ref_value[4] = s_br[1];
862
863 // Sixth and seventh reference values:
864 // local coordinates at top-left of wall.
865 ref_value[5] = s_tl[0];
866 ref_value[6] = s_tl[1];
867
868 // Eighth and ninth reference values:
869 // local coordinate of reference point.
870 ref_value[7] = s_wall[0];
871 ref_value[8] = s_wall[1];
872
873 // Setup algebraic update for node: Pass update information
874 static_cast<AlgebraicNode*>(el_pt->node_pt(n))
875 ->add_node_update_info(Lower_right_region, // enumerated ID
876 this, // mesh
877 geom_object_pt, // vector of geom objects
878 ref_value); // vector of ref. vals
879 }
880
881 // Element 2: Top left region
882 //---------------------------
883 else if (region_id == 2)
884 {
885 // Fractional distance between nodes
886 double fract = 1.0 / double(nnodes_1d - 1);
887
888 // Fraction in the s_0-direction
889 double rho_0 = fract * double(n % nnodes_1d);
890
891 // Fraction in the s_1-direction
892 double rho_1 = fract * double((n / nnodes_1d) % nnodes_1d);
893
894 // Find coord of reference point on wall
899
900 // Identify GeomObject and local coordinate at
901 // reference point on wall
902 GeomObject* obj_wall_pt;
903 Vector<double> s_wall(2);
904 this->Wall_pt->locate_zeta(xi, obj_wall_pt, s_wall);
905
906 // The update function requires three geometric objects
907 Vector<GeomObject*> geom_object_pt(3);
908
909 // Wall element at bottom-right of wall mesh:
910 geom_object_pt[0] = obj_br_pt;
911
912 // Wall element at top-left of wall mesh:
913 geom_object_pt[1] = obj_tl_pt;
914
915 // Wall element contianing reference point:
916 geom_object_pt[2] = obj_wall_pt;
917
918 // The update function requires nine parameters:
919 Vector<double> ref_value(9);
920
921 // First reference value: fractional s0-position inside region
922 ref_value[0] = rho_0;
923
924 // Second reference value: fractional s1-position inside region
925 ref_value[1] = rho_1;
926
927 // Third reference value: initial z coord
928 ref_value[2] = z;
929
930 // Fourth and fifth reference values:
931 // local coordinates in bottom-right GeomObject
932 ref_value[3] = s_br[0];
933 ref_value[4] = s_br[1];
934
935 // Sixth and seventh reference values:
936 // local coordinates in top-left GeomObject
937 ref_value[5] = s_tl[0];
938 ref_value[6] = s_tl[1];
939
940 // Eighth and ninth reference values:
941 // local coordinates at reference point
942 ref_value[7] = s_wall[0];
943 ref_value[8] = s_wall[1];
944
945 // Setup algebraic update for node: Pass update information
946 static_cast<AlgebraicNode*>(el_pt->node_pt(n))
947 ->add_node_update_info(Upper_left_region, // Enumerated ID
948 this, // mesh
949 geom_object_pt, // vector of geom objects
950 ref_value); // vector of ref. vals
951 }
952 }
953 }
954 }
955
956 //======================================================================
957 /// Algebraic update function: Update in central region according
958 /// to wall shape at time level t (t=0: present; t>0: previous)
959 //======================================================================
960 template<class ELEMENT>
962 const unsigned& t, AlgebraicNode*& node_pt)
963 {
964#ifdef PARANOID
965 // We're updating the nodal positions (!) at time level t
966 // and determine them by evaluating the wall GeomObject's
967 // position at that time level. I believe this only makes sense
968 // if the t-th history value in the positional timestepper
969 // actually represents previous values (rather than some
970 // generalised quantity). Hence if this function is called with
971 // t>nprev_values(), we issue a warning and terminate the execution.
972 // It *might* be possible that the code still works correctly
973 // even if this condition is violated (e.g. if the GeomObject's
974 // position() function returns the appropriate "generalised"
975 // position value that is required by the timestepping scheme but it's
976 // probably worth flagging this up and forcing the user to manually switch
977 // off this warning if he/she is 100% sure that this is kosher.
978 if (t > node_pt->position_time_stepper_pt()->nprev_values())
979 {
980 std::string error_message =
981 "Trying to update the nodal position at a time level\n";
982 error_message += "beyond the number of previous values in the nodes'\n";
983 error_message += "position timestepper. This seems highly suspect!\n";
984 error_message += "If you're sure the code behaves correctly\n";
985 error_message += "in your application, remove this warning \n";
986 error_message += "or recompile with PARNOID switched off.\n";
987
988 std::string function_name = "AlgebraicRefineableQuarterTubeMesh::";
989 function_name += "node_update_central_region()",
990 throw OomphLibError(
991 error_message, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
992 }
993#endif
994
995 // Extract references for update in central region by copy construction
996 Vector<double> ref_value(node_pt->vector_ref_value(Central_region));
997
998 // Extract geometric objects for update in central region by copy
999 // construction
1000 Vector<GeomObject*> geom_object_pt(
1001 node_pt->vector_geom_object_pt(Central_region));
1002
1003 // First reference value: fractional x-position of node inside region
1004 double rho_x = ref_value[0];
1005
1006 // Second reference value: fractional y-position of node inside region
1007 double rho_y = ref_value[1];
1008
1009 // Wall position in bottom right corner:
1010
1011 // Pointer to GeomObject
1012 GeomObject* obj_br_pt = geom_object_pt[0];
1013
1014 // Local coordinate at bottom-right reference point:
1015 Vector<double> s_br(2);
1016 s_br[0] = ref_value[3];
1017 s_br[1] = ref_value[4];
1018
1019 // Get wall position
1020 unsigned n_dim = obj_br_pt->ndim();
1021 Vector<double> r_br(n_dim);
1022 obj_br_pt->position(t, s_br, r_br);
1023
1024 // Wall position in top left corner:
1025
1026 // Pointer to GeomObject
1027 GeomObject* obj_tl_pt = geom_object_pt[1];
1028
1029 // Local coordinate:
1030 Vector<double> s_tl(2);
1031 s_tl[0] = ref_value[5];
1032 s_tl[1] = ref_value[6];
1033
1034 // Get wall position
1035 Vector<double> r_tl(n_dim);
1036 obj_tl_pt->position(t, s_tl, r_tl);
1037
1038 // Assign new nodal coordinate
1039 node_pt->x(t, 0) = r_br[0] * Lambda_x * rho_x;
1040 node_pt->x(t, 1) = r_tl[1] * Lambda_y * rho_y;
1041 node_pt->x(t, 2) = (r_br[2] + r_tl[2]) * 0.5;
1042 }
1043
1044
1045 //====================================================================
1046 /// Algebraic update function: Update in lower-right region according
1047 /// to wall shape at time level t (t=0: present; t>0: previous)
1048 //====================================================================
1049 template<class ELEMENT>
1051 ELEMENT>::node_update_lower_right_region(const unsigned& t,
1052 AlgebraicNode*& node_pt)
1053 {
1054#ifdef PARANOID
1055 // We're updating the nodal positions (!) at time level t
1056 // and determine them by evaluating the wall GeomObject's
1057 // position at that gime level. I believe this only makes sense
1058 // if the t-th history value in the positional timestepper
1059 // actually represents previous values (rather than some
1060 // generalised quantity). Hence if this function is called with
1061 // t>nprev_values(), we issue a warning and terminate the execution.
1062 // It *might* be possible that the code still works correctly
1063 // even if this condition is violated (e.g. if the GeomObject's
1064 // position() function returns the appropriate "generalised"
1065 // position value that is required by the timestepping scheme but it's
1066 // probably worth flagging this up and forcing the user to manually switch
1067 // off this warning if he/she is 100% sure that this is kosher.
1068 if (t > node_pt->position_time_stepper_pt()->nprev_values())
1069 {
1070 std::string error_message =
1071 "Trying to update the nodal position at a time level";
1072 error_message += "beyond the number of previous values in the nodes'";
1073 error_message += "position timestepper. This seems highly suspect!";
1074 error_message += "If you're sure the code behaves correctly";
1075 error_message += "in your application, remove this warning ";
1076 error_message += "or recompile with PARNOID switched off.";
1077
1078 std::string function_name = "AlgebraicRefineableQuarterTubeSectorMesh::";
1079 function_name += "node_update_lower_right_region()",
1080 throw OomphLibError(
1081 error_message, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
1082 }
1083#endif
1084
1085 // Extract references for update in lower-right region by copy construction
1086 Vector<double> ref_value(node_pt->vector_ref_value(Lower_right_region));
1087
1088 // Extract geometric objects for update in lower-right region
1089 // by copy construction
1090 Vector<GeomObject*> geom_object_pt(
1091 node_pt->vector_geom_object_pt(Lower_right_region));
1092
1093 // First reference value: fractional s0-position of node inside region
1094 double rho_0 = ref_value[0];
1095
1096 // Use s_squashed to modify fractional s0 position
1097 rho_0 = this->Domain_pt->s_squashed(rho_0);
1098
1099 // Second reference value: fractional s1-position of node inside region
1100 double rho_1 = ref_value[1];
1101
1102 // Wall position in bottom right corner:
1103
1104 // Pointer to GeomObject
1105 GeomObject* obj_br_pt = geom_object_pt[0];
1106
1107 // Local coordinate
1108 Vector<double> s_br(2);
1109 s_br[0] = ref_value[3];
1110 s_br[1] = ref_value[4];
1111
1112 // Eulerian dimension
1113 unsigned n_dim = obj_br_pt->ndim();
1114
1115 // Get wall position
1116 Vector<double> r_br(n_dim);
1117 obj_br_pt->position(t, s_br, r_br);
1118
1119 // Wall position in top left corner:
1120
1121 // Pointer to GeomObject
1122 GeomObject* obj_tl_pt = geom_object_pt[1];
1123
1124 // Local coordinate
1125 Vector<double> s_tl(2);
1126 s_tl[0] = ref_value[5];
1127 s_tl[1] = ref_value[6];
1128
1129 Vector<double> r_tl(n_dim);
1130 obj_tl_pt->position(t, s_tl, r_tl);
1131
1132 // Wall position at reference point:
1133
1134 // Pointer to GeomObject
1135 GeomObject* obj_wall_pt = geom_object_pt[2];
1136
1137 // Local coordinate
1138 Vector<double> s_wall(2);
1139 s_wall[0] = ref_value[7];
1140 s_wall[1] = ref_value[8];
1141
1142 Vector<double> r_wall(n_dim);
1143 obj_wall_pt->position(t, s_wall, r_wall);
1144
1145 // Position Vector to corner of the central region
1146 Vector<double> r_corner(n_dim);
1147 r_corner[0] = Lambda_x * r_br[0];
1148 r_corner[1] = Lambda_y * r_tl[1];
1149 r_corner[2] = (r_br[2] + r_tl[2]) * 0.5;
1150
1151 // Position Vector to left edge of region
1152 Vector<double> r_left(n_dim);
1153 r_left[0] = r_corner[0];
1154 r_left[1] = rho_1 * r_corner[1];
1155 r_left[2] = r_corner[2];
1156
1157 // Assign new nodal coordinate
1158 node_pt->x(t, 0) = r_left[0] + rho_0 * (r_wall[0] - r_left[0]);
1159 node_pt->x(t, 1) = r_left[1] + rho_0 * (r_wall[1] - r_left[1]);
1160 node_pt->x(t, 2) = r_left[2] + rho_0 * (r_wall[2] - r_left[2]);
1161 }
1162 //====================================================================
1163 /// Algebraic update function: Update in upper left region according
1164 /// to wall shape at time level t (t=0: present; t>0: previous)
1165 //====================================================================
1166 template<class ELEMENT>
1168 ELEMENT>::node_update_upper_left_region(const unsigned& t,
1169 AlgebraicNode*& node_pt)
1170 {
1171#ifdef PARANOID
1172 // We're updating the nodal positions (!) at time level t
1173 // and determine them by evaluating the wall GeomObject's
1174 // position at that gime level. I believe this only makes sense
1175 // if the t-th history value in the positional timestepper
1176 // actually represents previous values (rather than some
1177 // generalised quantity). Hence if this function is called with
1178 // t>nprev_values(), we issue a warning and terminate the execution.
1179 // It *might* be possible that the code still works correctly
1180 // even if this condition is violated (e.g. if the GeomObject's
1181 // position() function returns the appropriate "generalised"
1182 // position value that is required by the timestepping scheme but it's
1183 // probably worth flagging this up and forcing the user to manually switch
1184 // off this warning if he/she is 100% sure that this is kosher.
1185 if (t > node_pt->position_time_stepper_pt()->nprev_values())
1186 {
1187 std::string error_message =
1188 "Trying to update the nodal position at a time level";
1189 error_message += "beyond the number of previous values in the nodes'";
1190 error_message += "position timestepper. This seems highly suspect!";
1191 error_message += "If you're sure the code behaves correctly";
1192 error_message += "in your application, remove this warning ";
1193 error_message += "or recompile with PARNOID switched off.";
1194
1195 std::string function_name = "AlgebraicRefineableQuarterTubeMesh::";
1196 function_name += "node_update_upper_left_region()";
1197
1198 throw OomphLibError(
1199 error_message, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
1200 }
1201#endif
1202
1203 // Extract references for update in upper-left region by copy construction
1204 Vector<double> ref_value(node_pt->vector_ref_value(Upper_left_region));
1205
1206 // Extract geometric objects for update in upper-left region
1207 // by copy construction
1208 Vector<GeomObject*> geom_object_pt(
1209 node_pt->vector_geom_object_pt(Upper_left_region));
1210
1211 // First reference value: fractional s0-position of node inside region
1212 double rho_0 = ref_value[0];
1213
1214 // Second reference value: fractional s1-position of node inside region
1215 double rho_1 = ref_value[1];
1216
1217 // Use s_squashed to modify fractional s1 position
1218 rho_1 = this->Domain_pt->s_squashed(rho_1);
1219
1220 // Wall position in bottom right corner:
1221
1222 // Pointer to GeomObject
1223 GeomObject* obj_br_pt = geom_object_pt[0];
1224
1225 // Eulerian dimension
1226 unsigned n_dim = obj_br_pt->ndim();
1227
1228 // Local coordinate
1229 Vector<double> s_br(2);
1230 s_br[0] = ref_value[3];
1231 s_br[1] = ref_value[4];
1232
1233 // Get wall position
1234 Vector<double> r_br(n_dim);
1235 obj_br_pt->position(t, s_br, r_br);
1236
1237 // Wall position in top left corner:
1238
1239 // Pointer to GeomObject
1240 GeomObject* obj_tl_pt = node_pt->geom_object_pt(1);
1241
1242 // Local coordinate
1243 Vector<double> s_tl(2);
1244 s_tl[0] = ref_value[5];
1245 s_tl[1] = ref_value[6];
1246
1247 Vector<double> r_tl(n_dim);
1248 obj_tl_pt->position(t, s_tl, r_tl);
1249
1250 // Wall position at reference point:
1251
1252 // Pointer to GeomObject
1253 GeomObject* obj_wall_pt = node_pt->geom_object_pt(2);
1254
1255 // Local coordinate
1256 Vector<double> s_wall(2);
1257 s_wall[0] = ref_value[7];
1258 s_wall[1] = ref_value[8];
1259
1260 Vector<double> r_wall(n_dim);
1261 obj_wall_pt->position(t, s_wall, r_wall);
1262
1263 // Position vector to corner of the central region
1264 Vector<double> r_corner(n_dim);
1265 r_corner[0] = Lambda_x * r_br[0];
1266 r_corner[1] = Lambda_y * r_tl[1];
1267 r_corner[2] = (r_br[2] + r_tl[2]) * 0.5;
1268
1269 // Position Vector to top face of central region
1270 Vector<double> r_top(n_dim);
1271 r_top[0] = rho_0 * r_corner[0];
1272 r_top[1] = r_corner[1];
1273 r_top[2] = r_corner[2];
1274
1275 // Assign new nodal coordinate
1276 node_pt->x(t, 0) = r_top[0] + rho_1 * (r_wall[0] - r_top[0]);
1277 node_pt->x(t, 1) = r_top[1] + rho_1 * (r_wall[1] - r_top[1]);
1278 node_pt->x(t, 2) = r_top[2] + rho_1 * (r_wall[2] - r_top[2]);
1279 }
1280
1281
1282 //======================================================================
1283 /// Update algebraic update function for nodes in region defined by
1284 /// region_id.
1285 //======================================================================
1286 template<class ELEMENT>
1288 ELEMENT>::update_node_update_in_region(AlgebraicNode*& node_pt,
1289 int& region_id)
1290 {
1291 // Extract references by copy construction
1292 Vector<double> ref_value(node_pt->vector_ref_value(region_id));
1293
1294 // Extract geometric objects for update by copy construction
1295 Vector<GeomObject*> geom_object_pt(
1296 node_pt->vector_geom_object_pt(region_id));
1297
1298 // Now remove the update info to allow overwriting below
1299 node_pt->kill_node_update_info(region_id);
1300
1301 // Fixed reference value: Start coordinate on wall
1302 double xi_lo = QuarterTubeMesh<ELEMENT>::Xi_lo[1];
1303
1304 // Fixed reference value: Fractional position of dividing line
1305 double fract_mid = QuarterTubeMesh<ELEMENT>::Fract_mid;
1306
1307 // Fixed reference value: End coordinate on wall
1308 double xi_hi = QuarterTubeMesh<ELEMENT>::Xi_hi[1];
1309
1310 // get initial z-coordinate of node
1311 // NOTE: use modified z found using axial_spacing_fct()
1312 // to implement axial spacing
1313 double z = ref_value[2];
1314
1315 // Update reference to wall point in bottom right corner
1316 //------------------------------------------------------
1317
1318 // Wall position in bottom right corner:
1319 Vector<double> xi(2);
1320 xi[0] = z;
1321 xi[1] = xi_lo;
1322
1323 // Find corresponding wall element/local coordinate
1324 GeomObject* obj_br_pt;
1325 Vector<double> s_br(2);
1326 this->Wall_pt->locate_zeta(xi, obj_br_pt, s_br);
1327
1328 // Wall element at bottom right end of wall mesh:
1329 geom_object_pt[0] = obj_br_pt;
1330
1331 // Local coordinate in this wall element.
1332 ref_value[3] = s_br[0];
1333 ref_value[4] = s_br[1];
1334
1335
1336 // Update reference to wall point in upper left corner
1337 //----------------------------------------------------
1338
1339 // Wall position in top left corner
1340 xi[1] = xi_hi;
1341
1342 // Find corresponding wall element/local coordinate
1343 GeomObject* obj_tl_pt;
1344 Vector<double> s_tl(2);
1345 this->Wall_pt->locate_zeta(xi, obj_tl_pt, s_tl);
1346
1347 // Wall element at top left end of wall mesh:
1348 geom_object_pt[1] = obj_tl_pt;
1349
1350 // Local coordinate in this wall element.
1351 ref_value[5] = s_tl[0];
1352 ref_value[6] = s_tl[1];
1353
1354 if (region_id != Central_region)
1355 {
1356 // Update reference to reference point on wall
1357 //--------------------------------------------
1358
1359 // Reference point on wall
1360 if (region_id == Lower_right_region)
1361 {
1362 // Second reference value: fractional s1-position of node inside region
1363 double rho_1 = ref_value[1];
1364
1365 // position of reference point
1366 xi[1] = xi_lo + rho_1 * fract_mid * (xi_hi - xi_lo);
1367 }
1368 else // case of Upper_left region
1369 {
1370 // First reference value: fractional s0-position of node inside region
1371 double rho_0 = ref_value[0];
1372
1373 // position of reference point
1374 xi[1] = xi_hi - rho_0 * (1.0 - fract_mid) * (xi_hi - xi_lo);
1375 }
1376
1377 // Identify wall element number and local coordinate of
1378 // reference point on wall
1379 GeomObject* obj_wall_pt;
1380 Vector<double> s_wall(2);
1381 this->Wall_pt->locate_zeta(xi, obj_wall_pt, s_wall);
1382
1383 // Wall element at that contians reference point:
1384 geom_object_pt[2] = obj_wall_pt;
1385
1386 // Local coordinate in this wall element.
1387 ref_value[7] = s_wall[0];
1388 ref_value[8] = s_wall[1];
1389 }
1390
1391 // Setup algebraic update for node: Pass update information
1392 node_pt->add_node_update_info(region_id, // Enumerated ID
1393 this, // mesh
1394 geom_object_pt, // vector of geom objects
1395 ref_value); // vector of ref. vals
1396 }
1397
1398
1399} // namespace oomph
1400#endif
e
Definition: cfortran.h:571
static char t char * s
Definition: cfortran.h:568
cstr elem_len * i
Definition: cfortran.h:603
char t
Definition: cfortran.h:568
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
Vector< GeomObject * > & vector_geom_object_pt(const int &id)
Return vector of geometric objects involved in id-th update function.
GeomObject * geom_object_pt(const unsigned &i)
Return pointer to i-th geometric object involved in default (usually first) update function.
void kill_node_update_info(const int &id=0)
Erase algebraic node update information for id-th node update function. Id defaults to 0.
Vector< double > & vector_ref_value()
Return vector of reference values involved in default (usually first) update function.
void add_node_update_info(const int &id, AlgebraicMesh *mesh_pt, const Vector< GeomObject * > &geom_object_pt, const Vector< double > &ref_value, const bool &called_from_constructor=false)
Add algebraic update information for node: What's the ID of the mesh update function (typically used ...
AlgebraicMesh version of RefineableQuarterTubeMesh.
void node_update_central_region(const unsigned &t, AlgebraicNode *&node_pt)
Algebraic update function for a node that is located in the central region.
void setup_boundary_element_info()
Setup lookup schemes which establish whic elements are located next to mesh's boundaries (wrapper to ...
Definition: brick_mesh.h:195
MacroElement * macro_element_pt(const unsigned &i)
Access to i-th macro element.
Definition: domain.h:116
A general Finite Element class.
Definition: elements.h:1313
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
unsigned nnode() const
Return the number of nodes.
Definition: elements.h:2210
Node *& node_pt(const unsigned &n)
Return a pointer to the local node n.
Definition: elements.h:2175
virtual unsigned nnode_1d() const
Return the number of nodes along one edge of the element Default is to return zero — must be overload...
Definition: elements.h:2218
/////////////////////////////////////////////////////////////////////
Definition: geom_objects.h:101
unsigned ndim() const
Access function to # of Eulerian coordinates.
Definition: geom_objects.h:177
virtual void position(const Vector< double > &zeta, Vector< double > &r) const =0
Parametrised position on object at current time: r(zeta).
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
const Vector< GeneralisedElement * > & element_pt() const
Return reference to the Vector of elements.
Definition: mesh.h:460
Vector< GeneralisedElement * > Element_pt
Vector of pointers to generalised elements.
Definition: mesh.h:186
unsigned long nelement() const
Return number of elements in the mesh.
Definition: mesh.h:590
Nodes are derived from Data, but, in addition, have a definite (Eulerian) position in a space of a gi...
Definition: nodes.h:906
TimeStepper *& position_time_stepper_pt()
Return a pointer to the position timestepper.
Definition: nodes.h:1022
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....
Quarter tube as domain. Domain is bounded by curved boundary which is represented by a GeomObject....
3D quarter tube mesh class. The domain is specified by the GeomObject that identifies boundary 3....
GeomObject *& wall_pt()
Access function to GeomObject representing wall.
QuarterTubeDomain * Domain_pt
Pointer to domain.
Vector< double > Xi_lo
Lower limits for the coordinates along the wall.
QuarterTubeMesh(GeomObject *wall_pt, const Vector< double > &xi_lo, const double &fract_mid, const Vector< double > &xi_hi, const unsigned &nlayer, TimeStepper *time_stepper_pt=&Mesh::Default_TimeStepper)
Constructor: Pass pointer to geometric object that specifies the wall, start and end coordinates on t...
Vector< double > Xi_hi
Upper limits for the coordinates along the wall.
////////////////////////////////////////////////////////////////////// //////////////////////////////...
Definition: timesteppers.h:231
virtual unsigned nprev_values() const =0
Number of previous values available: 0 for static, 1 for BDF<1>,...
std::string string(const unsigned &i)
Return the i-th string or "" if the relevant string hasn't been defined.
//////////////////////////////////////////////////////////////////// ////////////////////////////////...
OomphInfo oomph_info
Single (global) instantiation of the OomphInfo object – this is used throughout the library as a "rep...