quarter_circle_sector_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_QUARTER_CIRCLE_SECTOR_MESH_TEMPLATE_HEADER
27#define OOMPH_QUARTER_CIRCLE_SECTOR_MESH_TEMPLATE_HEADER
28
29#ifndef OOMPH_QUARTER_CIRCLE_SECTOR_MESH_HEADER
30#error __FILE__ should only be included from quarter_circle_sector_mesh.h.
31#endif // OOMPH_QUARTER_CIRCLE_SECTOR_MESH_HEADER
32
33namespace oomph
34{
35 //====================================================================
36 /// Constructor for deformable 2D Ring mesh class. Pass pointer to
37 /// geometric object that specifies the wall, start and end coordinates on the
38 /// geometric object, and the fraction along
39 /// which the dividing line is to be placed, and the timestepper
40 /// (defaults to (Steady) default timestepper defined in Mesh).
41 /// Nodal positions are determined via macro-element-based representation
42 /// of the Domain (as a QuarterCircleSectorDomain).
43 //====================================================================
44 template<class ELEMENT>
46 GeomObject* wall_pt,
47 const double& xi_lo,
48 const double& fract_mid,
49 const double& xi_hi,
51 : Wall_pt(wall_pt), Xi_lo(xi_lo), Fract_mid(fract_mid), Xi_hi(xi_hi)
52 {
53 // Mesh can only be built with 2D Qelements.
54 MeshChecker::assert_geometric_element<QElementGeometricBase, ELEMENT>(2);
55
56 // Build macro element-based domain
58
59 // Set the number of boundaries
61
62 // We have only bothered to parametrise boundary 1
64
65 // Allocate the store for the elements
66 Element_pt.resize(3);
67
68 // Create first element
69 Element_pt[0] = new ELEMENT;
70
71 // Read out the number of linear points in the element
72 unsigned n_p = dynamic_cast<ELEMENT*>(finite_element_pt(0))->nnode_1d();
73
74 // Can now allocate the store for the nodes
75 Node_pt.resize(n_p * n_p + (n_p - 1) * n_p + (n_p - 1) * (n_p - 1));
76
79
80 // Storage for the intrinsic boundary coordinate
82
83 // Set up geometrical data
84 //------------------------
85
86 // Initialise node counter
87 unsigned long node_count = 0;
88
89 // Now assign the topology
90 // Boundaries are numbered 0 1 2 from the bottom proceeding anticlockwise
91
92 // FIRST ELEMENT (lower left corner)
93 //
94
95 // Set the corner node (on boundaries 0 and 2)
96 //-------------------------------------------
97
98 // Create the ll node
100 finite_element_pt(0)->construct_boundary_node(0, time_stepper_pt);
101
102 // Set the pointer from the element to the node
103 finite_element_pt(0)->node_pt(0) = Node_pt[node_count];
104
105 // Set the position of the ll node
106 s[0] = -1.0;
107 s[1] = -1.0;
108 Domain_pt->macro_element_pt(0)->macro_map(s, r);
109 Node_pt[node_count]->x(0) = r[0];
110 Node_pt[node_count]->x(1) = r[1];
111
112 // Add the node to the boundaries
115
116 // Increment the node number
117 node_count++;
118
119 // First row is on boundary 0:
120 //---------------------------
121 for (unsigned l1 = 1; l1 < n_p; l1++)
122 {
123 // Local node number
124 unsigned jnod_local = l1;
125
126 // Create the node
127 Node_pt[node_count] = finite_element_pt(0)->construct_boundary_node(
129
130 // Set the pointer from the element to the node
132
133 // Set the position of the node
134 s[0] = -1.0 + 2.0 * double(l1) / double(n_p - 1);
135 s[1] = -1.0;
136 Domain_pt->macro_element_pt(0)->macro_map(s, r);
137 Node_pt[node_count]->x(0) = r[0];
138 Node_pt[node_count]->x(1) = r[1];
139
140 // Add the node to the boundary
142
143 // Increment the node number
144 node_count++;
145 }
146
147 // Loop over the other rows of nodes
148 //------------------------------------
149 for (unsigned l2 = 1; l2 < n_p; l2++)
150 {
151 // First node in this row is on boundary 2:
152 //-----------------------------------------
153
154 // Local node number
155 unsigned jnod_local = n_p * l2;
156
157 // Create the node
158 Node_pt[node_count] = finite_element_pt(0)->construct_boundary_node(
160
161 // Set the pointer from the element to the node
163
164 // Set the position of the node
165 s[0] = -1.0;
166 s[1] = -1.0 + 2.0 * double(l2) / double(n_p - 1);
167 ;
168 Domain_pt->macro_element_pt(0)->macro_map(s, r);
169 Node_pt[node_count]->x(0) = r[0];
170 Node_pt[node_count]->x(1) = r[1];
171
172 // Add the node to the boundary
174
175 // Increment the node number
176 node_count++;
177
178 // The other nodes are in the interior
179 //------------------------------------
180 // Loop over the other node columns
181 for (unsigned l1 = 1; l1 < n_p; l1++)
182 {
183 // Local node number
184 unsigned jnod_local = l1 + n_p * l2;
185
186 // Create the node
188 finite_element_pt(0)->construct_node(jnod_local, time_stepper_pt);
189
190 // Set the pointer from the element to the node
192
193 // Set the position of the node
194 s[0] = -1.0 + 2.0 * double(l1) / double(n_p - 1);
195 s[1] = -1.0 + 2.0 * double(l2) / double(n_p - 1);
196 Domain_pt->macro_element_pt(0)->macro_map(s, r);
197 Node_pt[node_count]->x(0) = r[0];
198 Node_pt[node_count]->x(1) = r[1];
199
200 // Increment the node number
201 node_count++;
202 }
203 }
204
205 // SECOND ELEMENT (lower right corner)
206 //
207 // Create element
208 Element_pt[1] = new ELEMENT;
209
210 // Loop over the first column (already exists!)
211 //---------------------------------------------
212 for (unsigned l2 = 0; l2 < n_p; l2++)
213 {
214 // Node number in existing element
215 unsigned jnod_local_old = (n_p - 1) + l2 * n_p;
216
217 // Set the pointer from the element to the node
218 finite_element_pt(1)->node_pt(l2 * n_p) =
220 }
221
222 // Loop over the other node columns (apart from last one)
223 //------------------------------------------------------
224 for (unsigned l1 = 1; l1 < n_p - 1; l1++)
225 {
226 // First node is at the bottom (on boundary 0)
227 //--------------------------------------------
228
229 // Local node number
230 unsigned jnod_local = l1;
231
232 // Create the node
233 Node_pt[node_count] = finite_element_pt(1)->construct_boundary_node(
235
236 // Set the pointer from the element to the node
238
239 // Set the position of the node
240 s[0] = -1.0 + 2.0 * double(l1) / double(n_p - 1);
241 s[1] = -1.0;
242 Domain_pt->macro_element_pt(1)->macro_map(s, r);
243 Node_pt[node_count]->x(0) = r[0];
244 Node_pt[node_count]->x(1) = r[1];
245
246 // Add the node to the boundary
248
249 // Increment the node number
250 node_count++;
251
252 // Now loop over the interior nodes in this column
253 //-------------------------------------------------
254 for (unsigned l2 = 1; l2 < n_p; l2++)
255 {
256 // Local node number
257 unsigned jnod_local = l1 + l2 * n_p;
258
259 // Create the node
261 finite_element_pt(1)->construct_node(jnod_local, time_stepper_pt);
262
263 // Set the pointer from the element to the node
265
266 // Set the position of the node
267 s[0] = -1.0 + 2.0 * double(l1) / double(n_p - 1);
268 s[1] = -1.0 + 2.0 * double(l2) / double(n_p - 1);
269 Domain_pt->macro_element_pt(1)->macro_map(s, r);
270 Node_pt[node_count]->x(0) = r[0];
271 Node_pt[node_count]->x(1) = r[1];
272
273 // Increment the node number
274 node_count++;
275 }
276 }
277
278 // Last column (on boundary 1)
279 //----------------------------
280
281 // First node is at the bottom (and hence also on boundary 0)
282 //-----------------------------------------------------------
283
284 // Local node number
285 unsigned jnod_local = n_p - 1;
286
287 // Create the node
288 Node_pt[node_count] = finite_element_pt(1)->construct_boundary_node(
290
291 // Set the pointer from the element to the node
293
294 // Set the position of the node
295 s[0] = 1.0;
296 s[1] = -1.0;
297 Domain_pt->macro_element_pt(1)->macro_map(s, r);
298 Node_pt[node_count]->x(0) = r[0];
299 Node_pt[node_count]->x(1) = r[1];
300
301 // Add the node to the boundaries
304
305 // Set the intrinsic coordinate on the boundary 1
306 zeta[0] = Xi_lo + 0.5 * (1.0 + s[1]) * Fract_mid * (Xi_hi - Xi_lo);
307 Node_pt[node_count]->set_coordinates_on_boundary(1, zeta);
308
309 // Increment the node number
310 node_count++;
311
312 // Now do the remaining nodes in last column (only on boundary 1)
313 //---------------------------------------------------------------
314 for (unsigned l2 = 1; l2 < n_p; l2++)
315 {
316 // Local node number
317 unsigned jnod_local = (n_p - 1) + l2 * n_p;
318
319 // Create the node
320 Node_pt[node_count] = finite_element_pt(1)->construct_boundary_node(
322
323 // Set the pointer from the element to the node
325
326 // Set the position of the node
327 s[0] = 1.0;
328 s[1] = -1.0 + 2.0 * double(l2) / double(n_p - 1);
329 Domain_pt->macro_element_pt(1)->macro_map(s, r);
330 Node_pt[node_count]->x(0) = r[0];
331 Node_pt[node_count]->x(1) = r[1];
332
333 // Add the node to the boundary
335
336 // Set the intrinsic coordinate on the boundary 1
337 zeta[0] = Xi_lo + 0.5 * (1.0 + s[1]) * Fract_mid * (Xi_hi - Xi_lo);
338 Node_pt[node_count]->set_coordinates_on_boundary(1, zeta);
339
340 // Increment the node number
341 node_count++;
342 }
343
344 // THIRD ELEMENT (upper left corner)
345 //
346 // Create element
347 Element_pt[2] = new ELEMENT;
348
349 // Loop over the first row (has already been created via element 0)
350 //-----------------------------------------------------------------
351 for (unsigned l1 = 0; l1 < n_p; l1++)
352 {
353 // Node number in existing element
354 unsigned jnod_local_old = n_p * (n_p - 1) + l1;
355
356 // Local node number here
357 unsigned jnod_local = l1;
358
359 // Set the pointer from the element to the node
360 finite_element_pt(2)->node_pt(jnod_local) =
362 }
363
364 // Loop over the remaining nodes in the last column (has already
365 //--------------------------------------------------------------
366 // been created via element 1)
367 //----------------------------
368 for (unsigned l2 = 1; l2 < n_p; l2++)
369 {
370 // Node number in existing element
371 unsigned jnod_local_old = n_p * (n_p - 1) + l2;
372
373 // Local node number here
374 unsigned jnod_local = (n_p - 1) + l2 * n_p;
375
376 // Set the pointer from the element to the node
377 finite_element_pt(2)->node_pt(jnod_local) =
379 }
380
381 // Loop over the nodes in rows (apart from last one which is on boundary 1)
382 //-------------------------------------------------------------------------
383 for (unsigned l2 = 1; l2 < n_p - 1; l2++)
384 {
385 // First node in this row is on boundary 2:
386 //-----------------------------------------
387
388 // Local node number
389 unsigned jnod_local = n_p * l2;
390
391 // Create the node
392 Node_pt[node_count] = finite_element_pt(2)->construct_boundary_node(
394
395 // Set the pointer from the element to the node
397
398 // Set the position of the node
399 s[0] = -1.0;
400 s[1] = -1.0 + 2.0 * double(l2) / double(n_p - 1);
401 ;
402 Domain_pt->macro_element_pt(2)->macro_map(s, r);
403 Node_pt[node_count]->x(0) = r[0];
404 Node_pt[node_count]->x(1) = r[1];
405
406 // Add the node to the boundary
408
409 // Increment the node number
410 node_count++;
411
412 // The other nodes are in the interior
413 //------------------------------------
414 // Loop over the other node columns
415 for (unsigned l1 = 1; l1 < n_p - 1; l1++)
416 {
417 // Local node number
418 unsigned jnod_local = l1 + n_p * l2;
419
420 // Create the node
422 finite_element_pt(2)->construct_node(jnod_local, time_stepper_pt);
423
424 // Set the pointer from the element to the node
426
427 // Set the position of the node
428 s[0] = -1.0 + 2.0 * double(l1) / double(n_p - 1);
429 s[1] = -1.0 + 2.0 * double(l2) / double(n_p - 1);
430 Domain_pt->macro_element_pt(2)->macro_map(s, r);
431 Node_pt[node_count]->x(0) = r[0];
432 Node_pt[node_count]->x(1) = r[1];
433
434 // Increment the node number
435 node_count++;
436 }
437 }
438
439 // Top left corner is on boundaries 1 and 2:
440 //------------------------------------------
441
442 // Local node number
443 jnod_local = n_p * (n_p - 1);
444
445 // Create the node
446 Node_pt[node_count] = finite_element_pt(2)->construct_boundary_node(
448
449 // Set the pointer from the element to the node
451
452 // Set the position of the node
453 s[0] = -1.0;
454 s[1] = 1.0;
455 Domain_pt->macro_element_pt(2)->macro_map(s, r);
456 Node_pt[node_count]->x(0) = r[0];
457 Node_pt[node_count]->x(1) = r[1];
458
459 // Add the node to the boundaries
462
463 // Set the intrinsic coordinate on the boundary 1
464 zeta[0] = Xi_hi + 0.5 * (s[0] + 1.0) * (1.0 - Fract_mid) * (Xi_lo - Xi_hi);
465 Node_pt[node_count]->set_coordinates_on_boundary(1, zeta);
466
467 // Increment the node number
468 node_count++;
469
470 // Rest of top row is on boundary 1 only:
471 //---------------------------------------
472 for (unsigned l1 = 1; l1 < n_p - 1; l1++)
473 {
474 // Local node number
475 unsigned jnod_local = n_p * (n_p - 1) + l1;
476
477 // Create the node
478 Node_pt[node_count] = finite_element_pt(2)->construct_boundary_node(
480
481 // Set the pointer from the element to the node
483
484 // Set the position of the node
485 s[0] = -1.0 + 2.0 * double(l1) / double(n_p - 1);
486 s[1] = 1.0;
487 Domain_pt->macro_element_pt(2)->macro_map(s, r);
488 Node_pt[node_count]->x(0) = r[0];
489 Node_pt[node_count]->x(1) = r[1];
490
491 // Add the node to the boundary
493
494 // Set the intrinsic coordinate on the boundary 1
495 zeta[0] =
496 Xi_hi + 0.5 * (s[0] + 1.0) * (1.0 - Fract_mid) * (Xi_lo - Xi_hi);
497 Node_pt[node_count]->set_coordinates_on_boundary(1, zeta);
498
499 // Increment the node number
500 node_count++;
501 }
502
503 // Loop over all elements and set macro element pointer
504 // to enable MacroElement-based node update
505 unsigned n_element = this->nelement();
506 for (unsigned e = 0; e < n_element; e++)
507 {
508 // Get pointer to full element type
509 ELEMENT* el_pt = dynamic_cast<ELEMENT*>(this->element_pt(e));
510
511 // Set pointer to macro element
512 el_pt->set_macro_elem_pt(this->Domain_pt->macro_element_pt(e));
513 }
514
515 // Setup boundary element lookup schemes
516 setup_boundary_element_info();
517 }
518
519
520 ///////////////////////////////////////////////////////////////////////
521 ///////////////////////////////////////////////////////////////////////
522 // Algebraic-mesh-version of RefineableQuarterCircleSectorMesh
523 ///////////////////////////////////////////////////////////////////////
524 ///////////////////////////////////////////////////////////////////////
525
526 //======================================================================
527 /// Setup algebraic update operation, based on individual
528 /// blocks. Mesh is suspended from the `wall' GeomObject pointed to
529 /// by wall_pt. The lower right corner of the mesh is located at the
530 /// wall's coordinate xi_lo, the upper left corner at xi_hi;
531 /// The dividing line between the two blocks at the outer ring
532 /// is located at the fraction fract_mid between these two coordinates.
533 /// Node updating strategy:
534 /// - the shape of the central box remains rectangular; the position
535 /// of its top right corner is located at a fixed fraction
536 /// of the width and height of the domain. Nodes in this region
537 /// are located at fixed horizontal and vertical fractions of the box.
538 /// - Nodes in the two outer "ring" elements (bottom right and top left)
539 /// are located on straight lines running from the edges of the
540 /// central box to the outer wall.
541 //======================================================================
542 template<class ELEMENT>
544 ELEMENT>::setup_algebraic_node_update()
545 {
546#ifdef PARANOID
547 /// Pointer to algebraic element in central box
549 dynamic_cast<AlgebraicElementBase*>(Mesh::element_pt(0));
550
551 if (central_box_pt == 0)
552 {
553 std::ostringstream error_message;
555 << "Element in AlgebraicRefineableQuarterCircleSectorMesh must be\n ";
556 error_message << "derived from AlgebraicElementBase\n";
557 error_message << "but it is of type: "
558 << typeid(Mesh::element_pt(0)).name() << std::endl;
559 std::string function_name =
560 "AlgebraicRefineableQuarterCircleSectorMesh::";
561 function_name += "setup_algebraic_node_update()";
562 throw OomphLibError(
564 }
565#endif
566
567 // Number of nodes in elements
568 unsigned nnodes = Mesh::finite_element_pt(0)->nnode();
569
570 // Coordinates of central box
571 double x_box = Mesh::finite_element_pt(0)->node_pt(nnodes - 1)->x(0);
572 double y_box = Mesh::finite_element_pt(0)->node_pt(nnodes - 1)->x(1);
573
574 // Get wall position in bottom right corner
579
580 // Establish fractional width of central box
581 Lambda_x = x_box / r_br[0];
582
583 // Find corresponding wall element/local coordinate
586 this->Wall_pt->locate_zeta(xi, obj_br_pt, s_br);
587
588 obj_br_pt->position(s_br, r_br);
589
590 // Get wall position in top left corner
594
595 // Establish fractional height of central box
596 Lambda_y = y_box / r_tl[1];
597
598 // Find corresponding wall element/local coordinate
601 this->Wall_pt->locate_zeta(xi, obj_tl_pt, s_tl);
602
603 // Element 0: central box
604 //-----------------------
605 {
606 unsigned ielem = 0;
607 FiniteElement* el_pt = Mesh::finite_element_pt(ielem);
608
609 // Loop over all nodes in the element and give them the update
610 // info appropriate for the current element
611 for (unsigned jnod = 0; jnod < nnodes; jnod++)
612 {
613 // Nodal coordinates in undeformed mesh
614 double x = Mesh::finite_element_pt(ielem)->node_pt(jnod)->x(0);
615 double y = Mesh::finite_element_pt(ielem)->node_pt(jnod)->x(1);
616
617 // The update function requires two geometric objects
619
620 // The update function requires four parameters:
622
623 // First reference value: fractional x-position inside box
624 ref_value[0] = x / x_box;
625
626 // Second reference value: fractional y-position inside box
627 ref_value[1] = y / y_box;
628
629 // Wall element at bottom right end of wall mesh:
631
632 // Local coordinate in this wall element (Note:
633 // we'll have to recompute this reference
634 // when the mesh is refined as we might fall off the element otherwise)
635 ref_value[2] = s_br[0];
636
637 // Wall element at top left end of wall mesh:
639
640 // Local coordinate in this wall element. Note:
641 // we'll have to recompute this reference
642 // when the mesh is refined as we might fall off the element otherwise)
643 ref_value[3] = s_tl[0];
644
645 // Setup algebraic update for node: Pass update information
646 dynamic_cast<AlgebraicNode*>(el_pt->node_pt(jnod))
647 ->add_node_update_info(Central_box, // enumerated ID
648 this, // mesh
649 geom_object_pt, // vector of geom objects
650 ref_value); // vector of ref. values
651 }
652 }
653
654 // Element 1: Bottom right box
655 //----------------------------
656 {
657 unsigned ielem = 1;
658 FiniteElement* el_pt = Mesh::finite_element_pt(ielem);
659
660 // Loop over all nodes in the element and give them the update
661 // info appropriate for the current element
662
663 // Double loop over nodes
664 unsigned nnod_lin =
665 dynamic_cast<ELEMENT*>(Mesh::finite_element_pt(ielem))->nnode_1d();
666 for (unsigned i0 = 0; i0 < nnod_lin; i0++)
667 {
668 // Fraction in the s_0-direction
669 double rho_0 = double(i0) / double(nnod_lin - 1);
670
671 for (unsigned i1 = 0; i1 < nnod_lin; i1++)
672 {
673 // Fraction in the s_1-direction
674 double rho_1 = double(i1) / double(nnod_lin - 1);
675
676 // Node number
677 unsigned jnod = i0 + i1 * nnod_lin;
678
679 // The update function requires three geometric objects
681
682 // The update function requires five parameters:
684
685 // First reference value: fractional s0-position inside box
686 ref_value[0] = rho_0;
687
688 // Second reference value: fractional s1-position inside box
689 ref_value[1] = rho_1;
690
691 // Wall element at bottom right end of wall mesh:
693
694 // Local coordinate in this wall element. Note:
695 // We'll have to recompute this reference
696 // when the mesh is refined as we might fall off the element
697 // otherwise
698 ref_value[2] = s_br[0];
699
700 // Wall element at top left end of wall mesh:
702
703 // Local coordinate in this wall element. Note:
704 // We'll have to recompute this reference
705 // when the mesh is refined as we might fall off the element
706 // otherwise
707 ref_value[3] = s_tl[0];
708
709 // Reference point on wall
715
716 // Identify wall element number and local coordinate of
717 // reference point on wall
720 this->Wall_pt->locate_zeta(xi_wall, obj_wall_pt, s_wall);
721
722 // Wall element at that contians reference point:
724
725 // Local coordinate in this wall element. Note:
726 // We'll have to recompute this reference
727 // when the mesh is refined as we might fall off the element
728 // otherwise
729 ref_value[4] = s_wall[0];
730
731 // Setup algebraic update for node: Pass update information
732 dynamic_cast<AlgebraicNode*>(el_pt->node_pt(jnod))
733 ->add_node_update_info(Lower_right_box, // enumerated ID
734 this, // mesh
735 geom_object_pt, // vector of geom objects
736 ref_value); // vector of ref. vals
737 }
738 }
739 }
740
741 // Element 2: Top left box
742 //---------------------------
743 {
744 unsigned ielem = 2;
745 FiniteElement* el_pt = Mesh::finite_element_pt(ielem);
746
747 // Double loop over nodes
748 unsigned nnod_lin =
749 dynamic_cast<ELEMENT*>(Mesh::finite_element_pt(ielem))->nnode_1d();
750
751 for (unsigned i0 = 0; i0 < nnod_lin; i0++)
752 {
753 // Fraction in the s_0-direction
754 double rho_0 = double(i0) / double(nnod_lin - 1);
755
756 for (unsigned i1 = 0; i1 < nnod_lin; i1++)
757 {
758 // Fraction in the s_1-direction
759 double rho_1 = double(i1) / double(nnod_lin - 1);
760
761 // Node number
762 unsigned jnod = i0 + i1 * nnod_lin;
763
764 // The update function requires three geometric objects
766
767 // The update function requires five parameters:
769
770 // First reference value: fractional s0-position inside box
771 ref_value[0] = rho_0;
772
773 // Second reference value: fractional s1-position inside box
774 ref_value[1] = rho_1;
775
776 // Wall element at bottom right end of wall mesh:
778
779 // Local coordinate in this wall element. Note:
780 // We'll have to recompute this reference
781 // when the mesh is refined as we might fall off the element
782 // otherwise
783 ref_value[2] = s_br[0];
784
785 // Wall element at top left end of wall mesh:
787
788 // Local coordinate in this wall element. Note:
789 // We'll have to recompute this reference
790 // when the mesh is refined as we might fall off the element
791 // otherwise
792 ref_value[3] = s_tl[0];
793
794 // Reference point on wall
797 rho_0 *
801
802 // Identify wall element number and local coordinate of
803 // reference point on wall
806 this->Wall_pt->locate_zeta(xi_wall, obj_wall_pt, s_wall);
807
808 // Wall element at that contians reference point:
810
811 // Local coordinate in this wall element. Note:
812 // We'll have to recompute this reference
813 // when the mesh is refined as we might fall off the element
814 // otherwise
815 ref_value[4] = s_wall[0];
816
817 // Setup algebraic update for node: Pass update information
818 dynamic_cast<AlgebraicNode*>(el_pt->node_pt(jnod))
819 ->add_node_update_info(Upper_left_box, // Enumerated ID
820 this, // mesh
821 geom_object_pt, // vector of geom objects
822 ref_value); // vector of ref. vals
823 }
824 }
825 }
826 }
827
828 //======================================================================
829 /// Algebraic update function: Update in central box according
830 /// to wall shape at time level t (t=0: present; t>0: previous)
831 //======================================================================
832 template<class ELEMENT>
834 ELEMENT>::node_update_in_central_box(const unsigned& t,
836 {
837#ifdef PARANOID
838 // We're updating the nodal positions (!) at time level t
839 // and determine them by evaluating the wall GeomObject's
840 // position at that gime level. I believe this only makes sense
841 // if the t-th history value in the positional timestepper
842 // actually represents previous values (rather than some
843 // generalised quantity). Hence if this function is called with
844 // t>nprev_values(), we issue a warning and terminate the execution.
845 // It *might* be possible that the code still works correctly
846 // even if this condition is violated (e.g. if the GeomObject's
847 // position() function returns the appropriate "generalised"
848 // position value that is required by the timestepping scheme but it's
849 // probably worth flagging this up and forcing the user to manually switch
850 // off this warning if he/she is 100% sure that this is kosher.
851 if (t > node_pt->position_time_stepper_pt()->nprev_values())
852 {
853 std::string error_message =
854 "Trying to update the nodal position at a time level\n";
855 error_message += "beyond the number of previous values in the nodes'\n";
856 error_message += "position timestepper. This seems highly suspect!\n";
857 error_message += "If you're sure the code behaves correctly\n";
858 error_message += "in your application, remove this warning \n";
859 error_message += "or recompile with PARNOID switched off.\n";
860
861 std::string function_name =
862 "AlgebraicRefineableQuarterCircleSectorMesh::";
863 function_name += "node_update_in_central_box()",
864 throw OomphLibError(
866 }
867#endif
868
869 // Extract references for update in central box by copy construction
870 Vector<double> ref_value(node_pt->vector_ref_value(Central_box));
871
872 // Extract geometric objects for update in central box by copy construction
874 node_pt->vector_geom_object_pt(Central_box));
875
876 // First reference value: fractional x-position of node inside box
877 double rho_x = ref_value[0];
878
879 // Second reference value: fractional y-position of node inside box
880 double rho_y = ref_value[1];
881
882 // Wall position in bottom right corner:
883
884 // Pointer to wall element:
886
887 // Eulerian dimension
888 unsigned n_dim = obj_br_pt->ndim();
889
890 // Local coordinate:
892 s_br[0] = ref_value[2];
893
894 // Get wall position
896 obj_br_pt->position(t, s_br, r_br);
897
898 // Wall position in top left corner:
899
900 // Pointer to wall element:
902
903 // Local coordinate:
905 s_tl[0] = ref_value[3];
906
908 obj_tl_pt->position(t, s_tl, r_tl);
909
910 // Assign new nodal coordinate
911 node_pt->x(t, 0) = r_br[0] * Lambda_x * rho_x;
912 node_pt->x(t, 1) = r_tl[1] * Lambda_y * rho_y;
913 }
914
915 //====================================================================
916 /// Algebraic update function: Update in lower right box according
917 /// to wall shape at time level t (t=0: present; t>0: previous)
918 //====================================================================
919 template<class ELEMENT>
921 ELEMENT>::node_update_in_lower_right_box(const unsigned& t,
923 {
924#ifdef PARANOID
925 // We're updating the nodal positions (!) at time level t
926 // and determine them by evaluating the wall GeomObject's
927 // position at that gime level. I believe this only makes sense
928 // if the t-th history value in the positional timestepper
929 // actually represents previous values (rather than some
930 // generalised quantity). Hence if this function is called with
931 // t>nprev_values(), we issue a warning and terminate the execution.
932 // It *might* be possible that the code still works correctly
933 // even if this condition is violated (e.g. if the GeomObject's
934 // position() function returns the appropriate "generalised"
935 // position value that is required by the timestepping scheme but it's
936 // probably worth flagging this up and forcing the user to manually switch
937 // off this warning if he/she is 100% sure that this is kosher.
938 if (t > node_pt->position_time_stepper_pt()->nprev_values())
939 {
940 std::string error_message =
941 "Trying to update the nodal position at a time level";
942 error_message += "beyond the number of previous values in the nodes'";
943 error_message += "position timestepper. This seems highly suspect!";
944 error_message += "If you're sure the code behaves correctly";
945 error_message += "in your application, remove this warning ";
946 error_message += "or recompile with PARNOID switched off.";
947
948 std::string function_name =
949 "AlgebraicRefineableQuarterCircleSectorMesh::";
950 function_name += "node_update_in_lower_right_box()",
951 throw OomphLibError(
953 }
954#endif
955
956 // Extract references for update in central box by copy construction
957 Vector<double> ref_value(node_pt->vector_ref_value(Lower_right_box));
958
959 // Extract geometric objects for update in central box by copy construction
961 node_pt->vector_geom_object_pt(Lower_right_box));
962
963 // First reference value: fractional s0-position of node inside box
964 double rho_0 = ref_value[0];
965
966 // Second reference value: fractional s1-position of node inside box
967 double rho_1 = ref_value[1];
968
969 // Wall position in bottom right corner:
970
971 // Pointer to wall element:
973
974 // Eulerian dimension
975 unsigned n_dim = obj_br_pt->ndim();
976
977 // Local coordinate:
979 s_br[0] = ref_value[2];
980
981 // Get wall position
983 obj_br_pt->position(t, s_br, r_br);
984
985 // Wall position in top left corner:
986
987 // Pointer to wall element:
989
990 // Local coordinate:
992 s_tl[0] = ref_value[3];
993
995 obj_tl_pt->position(t, s_tl, r_tl);
996
997 // Position of the corner of the central box
999 r_box[0] = Lambda_x * r_br[0];
1000 r_box[1] = Lambda_y * r_tl[1];
1001
1002 // Position Vector to left end of box
1004 r_left[0] = Lambda_x * r_br[0] + rho_1 * (r_box[0] - Lambda_x * r_br[0]);
1005 r_left[1] = Lambda_x * r_br[1] + rho_1 * (r_box[1] - Lambda_x * r_br[1]);
1006
1007 // Wall position
1008
1009 // Pointer to wall element:
1011
1012 // Local coordinate:
1014 s_wall[0] = ref_value[4];
1015
1017 obj_wall_pt->position(t, s_wall, r_wall);
1018
1019 // Assign new nodal coordinate
1020 node_pt->x(t, 0) = r_left[0] + rho_0 * (r_wall[0] - r_left[0]);
1021 node_pt->x(t, 1) = r_left[1] + rho_0 * (r_wall[1] - r_left[1]);
1022 }
1023 //====================================================================
1024 /// Algebraic update function: Update in upper left box according
1025 /// to wall shape at time level t (t=0: present; t>0: previous)
1026 //====================================================================
1027 template<class ELEMENT>
1029 ELEMENT>::node_update_in_upper_left_box(const unsigned& t,
1031 {
1032#ifdef PARANOID
1033 // We're updating the nodal positions (!) at time level t
1034 // and determine them by evaluating the wall GeomObject's
1035 // position at that gime level. I believe this only makes sense
1036 // if the t-th history value in the positional timestepper
1037 // actually represents previous values (rather than some
1038 // generalised quantity). Hence if this function is called with
1039 // t>nprev_values(), we issue a warning and terminate the execution.
1040 // It *might* be possible that the code still works correctly
1041 // even if this condition is violated (e.g. if the GeomObject's
1042 // position() function returns the appropriate "generalised"
1043 // position value that is required by the timestepping scheme but it's
1044 // probably worth flagging this up and forcing the user to manually switch
1045 // off this warning if he/she is 100% sure that this is kosher.
1046 if (t > node_pt->position_time_stepper_pt()->nprev_values())
1047 {
1048 std::string error_message =
1049 "Trying to update the nodal position at a time level";
1050 error_message += "beyond the number of previous values in the nodes'";
1051 error_message += "position timestepper. This seems highly suspect!";
1052 error_message += "If you're sure the code behaves correctly";
1053 error_message += "in your application, remove this warning ";
1054 error_message += "or recompile with PARNOID switched off.";
1055
1056 std::string function_name =
1057 "AlgebraicRefineableQuarterCircleSectorMesh::";
1058 function_name += "node_update_in_upper_left_box()";
1059
1060 throw OomphLibError(
1062 }
1063#endif
1064
1065 // Extract references for update in central box by copy construction
1066 Vector<double> ref_value(node_pt->vector_ref_value(Upper_left_box));
1067
1068 // Extract geometric objects for update in central box by copy construction
1070 node_pt->vector_geom_object_pt(Upper_left_box));
1071
1072 // First reference value: fractional s0-position of node inside box
1073 double rho_0 = ref_value[0];
1074
1075 // Second reference value: fractional s1-position of node inside box
1076 double rho_1 = ref_value[1];
1077
1078 // Wall position in bottom right corner:
1079
1080 // Pointer to wall element:
1082
1083 // Eulerian dimension
1084 unsigned n_dim = obj_br_pt->ndim();
1085
1086 // Local coordinate:
1088 s_br[0] = ref_value[2];
1089
1090 // Get wall position
1092 obj_br_pt->position(t, s_br, r_br);
1093
1094 // Wall position in top left corner:
1095
1096 // Pointer to wall element:
1097 GeomObject* obj_tl_pt = node_pt->geom_object_pt(1);
1098
1099 // Local coordinate:
1101 s_tl[0] = node_pt->ref_value(3);
1102
1104 obj_tl_pt->position(t, s_tl, r_tl);
1105
1106 // Position of the corner of the central box
1108 r_box[0] = Lambda_x * r_br[0];
1109 r_box[1] = Lambda_y * r_tl[1];
1110
1111 // Position Vector to top face of central box
1113 r_top[0] = Lambda_y * r_tl[0] + rho_0 * (r_box[0] - Lambda_y * r_tl[0]);
1114 r_top[1] = Lambda_y * r_tl[1] + rho_0 * (r_box[1] - Lambda_y * r_tl[1]);
1115
1116 // Wall position
1117
1118 // Pointer to wall element:
1119 GeomObject* obj_wall_pt = node_pt->geom_object_pt(2);
1120
1121 // Local coordinate:
1123 s_wall[0] = node_pt->ref_value(4);
1124
1126 obj_wall_pt->position(t, s_wall, r_wall);
1127
1128 // Assign new nodal coordinate
1129 node_pt->x(t, 0) = r_top[0] + rho_1 * (r_wall[0] - r_top[0]);
1130 node_pt->x(t, 1) = r_top[1] + rho_1 * (r_wall[1] - r_top[1]);
1131 }
1132
1133 //======================================================================
1134 /// Update algebraic update function for nodes in lower right box.
1135 //======================================================================
1136 template<class ELEMENT>
1138 ELEMENT>::update_node_update_in_lower_right_box(AlgebraicNode*& node_pt)
1139 {
1140 // Extract references for update in central box by copy construction
1141 Vector<double> ref_value(node_pt->vector_ref_value(Lower_right_box));
1142
1143 // Extract geometric objects for updatein central box by copy construction
1145 node_pt->vector_geom_object_pt(Lower_right_box));
1146
1147 // Now remove the update info to allow overwriting below
1148 node_pt->kill_node_update_info(Lower_right_box);
1149
1150 // Fixed reference value: Start coordinate on wall
1152
1153 // Fixed reference value: Fractional position of dividing line
1155
1156 // Fixed reference value: End coordinate on wall
1158
1159 // Second reference value: fractional s1-position of node inside box
1160 double rho_1 = ref_value[1];
1161
1162 // Update reference to wall point in bottom right corner
1163 //------------------------------------------------------
1164
1165 // Wall position in bottom right corner:
1166 Vector<double> xi(1);
1167 xi[0] = xi_lo;
1168
1169 // Find corresponding wall element/local coordinate
1172 this->Wall_pt->locate_zeta(xi, obj_br_pt, s_br);
1173
1174 // Wall element at bottom right end of wall mesh:
1176
1177 // Local coordinate in this wall element. Note:
1178 // We'll have to recompute this reference
1179 // when the mesh is refined as we might fall off the element otherwise
1180 ref_value[2] = s_br[0];
1181
1182 // Update reference to wall point in upper left corner
1183 //----------------------------------------------------
1184
1185 // Wall position in top left corner
1186 xi[0] = xi_hi;
1187
1188 // Find corresponding wall element/local coordinate
1191 this->Wall_pt->locate_zeta(xi, obj_tl_pt, s_tl);
1192
1193 // Wall element at top left end of wall mesh:
1195
1196 // Local coordinate in this wall element. Note:
1197 // We'll have to recompute this reference
1198 // when the mesh is refined as we might fall off the element otherwise
1199 ref_value[3] = s_tl[0];
1200
1201 // Update reference to reference point on wall
1202 //--------------------------------------------
1203
1204 // Reference point on wall
1206 xi_wall[0] = xi_lo + rho_1 * fract_mid * (xi_hi - xi_lo);
1207
1208 // Identify wall element number and local coordinate of
1209 // reference point on wall
1212 this->Wall_pt->locate_zeta(xi_wall, obj_wall_pt, s_wall);
1213
1214 // Wall element at that contians reference point:
1216
1217 // Local coordinate in this wall element. Note:
1218 // We'll have to recompute this reference
1219 // when the mesh is refined as we might fall off the element otherwise
1220 ref_value[4] = s_wall[0];
1221
1222 // Setup algebraic update for node: Pass update information
1223 node_pt->add_node_update_info(Lower_right_box, // Enumerated ID
1224 this, // mesh
1225 geom_object_pt, // vector of geom objects
1226 ref_value); // vector of ref. vals
1227 }
1228
1229 //======================================================================
1230 /// Update algebraic update function for nodes in upper left box
1231 //======================================================================
1232 template<class ELEMENT>
1234 ELEMENT>::update_node_update_in_upper_left_box(AlgebraicNode*& node_pt)
1235 {
1236 // Extract references for update in central box by copy construction
1237 Vector<double> ref_value(node_pt->vector_ref_value(Upper_left_box));
1238
1239 // Extract geometric objects for update in central box by copy construction
1241 node_pt->vector_geom_object_pt(Upper_left_box));
1242
1243 // Now remove the update info to allow overwriting below
1244 node_pt->kill_node_update_info(Upper_left_box);
1245
1246 // Fixed reference value: Start coordinate on wall
1248
1249 // Fixed reference value: Fractional position of dividing line
1251
1252 // Fixed reference value: End coordinate on wall
1254
1255 // First reference value: fractional s0-position of node inside box
1256 double rho_0 = ref_value[0];
1257
1258 // Update reference to wall point in bottom right corner
1259 //------------------------------------------------------
1260
1261 // Wall position in bottom right corner:
1262 Vector<double> xi(1);
1263 xi[0] = xi_lo;
1264
1265 // Find corresponding wall element/local coordinate
1268 this->Wall_pt->locate_zeta(xi, obj_br_pt, s_br);
1269
1270 // Wall element at bottom right end of wall mesh:
1272
1273 // Local coordinate in this wall element. Note:
1274 // We'll have to recompute this reference
1275 // when the mesh is refined as we might fall off the element otherwise
1276 ref_value[2] = s_br[0];
1277
1278 // Update reference to wall point in upper left corner
1279 //----------------------------------------------------
1280
1281 // Wall position in top left corner
1282 xi[0] = xi_hi;
1283
1284 // Find corresponding wall element/local coordinate
1287 this->Wall_pt->locate_zeta(xi, obj_tl_pt, s_tl);
1288
1289 // Wall element at top left end of wall mesh:
1291
1292 // Local coordinate in this wall element. Note:
1293 // We'll have to recompute this reference
1294 // when the mesh is refined as we might fall off the element otherwise
1295 ref_value[3] = s_tl[0];
1296
1297 // Update reference to reference point on wall
1298 //--------------------------------------------
1299
1300 // Reference point on wall
1302 xi_wall[0] = xi_hi + rho_0 * (1.0 - fract_mid) * (xi_lo - xi_hi);
1303
1304 // Identify reference point on wall
1307 this->Wall_pt->locate_zeta(xi_wall, obj_wall_pt, s_wall);
1308
1309 // Wall element at that contians reference point:
1311
1312 // Local coordinate in this wall element. Note:
1313 // We'll have to recompute this reference
1314 // when the mesh is refined as we might fall off the element otherwise
1315 ref_value[4] = s_wall[0];
1316
1317 // Setup algebraic update for node: Pass update information
1318 node_pt->add_node_update_info(Upper_left_box, // Enumerated ID
1319 this, // mesh
1320 geom_object_pt, // vector of geom objects
1321 ref_value); // vector of ref. vals
1322 }
1323
1324} // namespace oomph
1325#endif
Algebraic version of RefineableQuarterCircleSectorMesh.
Circular sector as domain. Domain is bounded by curved boundary which is represented by a GeomObject....
2D quarter ring mesh class. The domain is specified by the GeomObject that identifies boundary 1.
double Fract_mid
Fraction along wall where outer ring is to be divided.
GeomObject *& wall_pt()
Access function to GeomObject representing wall.
double Xi_hi
Upper limit for the (1D) coordinates along the wall.
QuarterCircleSectorMesh(GeomObject *wall_pt, const double &xi_lo, const double &fract_mid, const double &xi_hi, TimeStepper *time_stepper_pt=&Mesh::Default_TimeStepper)
Constructor: Pass pointer to geometric object that specifies the wall, start and end coordinates on t...
QuarterCircleSectorDomain * Domain_pt
Pointer to Domain.
double Xi_lo
Lower limit for the (1D) coordinates along the wall.
Simple rectangular 2D Quad mesh class. Nx : number of elements in the x direction.