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,
50 TimeStepper* time_stepper_pt)
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
104
105 // Set the position of the ll node
106 s[0] = -1.0;
107 s[1] = -1.0;
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
128 jnod_local, time_stepper_pt);
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;
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
159 jnod_local, time_stepper_pt);
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 ;
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);
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
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
234 jnod_local, time_stepper_pt);
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;
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);
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
289 jnod_local, time_stepper_pt);
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;
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
321 jnod_local, time_stepper_pt);
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);
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
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
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
393 jnod_local, time_stepper_pt);
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 ;
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);
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
447 jnod_local, time_stepper_pt);
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;
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
479 jnod_local, time_stepper_pt);
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;
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
513 }
514
515 // Setup boundary element lookup schemes
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;
554 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
576 Vector<double> xi(1);
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
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;
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
618 Vector<GeomObject*> geom_object_pt(2);
619
620 // The update function requires four parameters:
621 Vector<double> ref_value(4);
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:
630 geom_object_pt[0] = obj_br_pt;
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:
638 geom_object_pt[1] = obj_tl_pt;
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;
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
680 Vector<GeomObject*> geom_object_pt(3);
681
682 // The update function requires five parameters:
683 Vector<double> ref_value(5);
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:
692 geom_object_pt[0] = obj_br_pt;
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:
701 geom_object_pt[1] = obj_tl_pt;
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:
723 geom_object_pt[2] = obj_wall_pt;
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;
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
765 Vector<GeomObject*> geom_object_pt(3);
766
767 // The update function requires five parameters:
768 Vector<double> ref_value(5);
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:
777 geom_object_pt[0] = obj_br_pt;
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:
786 geom_object_pt[1] = obj_tl_pt;
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:
809 geom_object_pt[2] = obj_wall_pt;
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,
835 AlgebraicNode*& node_pt)
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
873 Vector<GeomObject*> geom_object_pt(
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:
885 GeomObject* obj_br_pt = geom_object_pt[0];
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
897
898 // Wall position in top left corner:
899
900 // Pointer to wall element:
901 GeomObject* obj_tl_pt = geom_object_pt[1];
902
903 // Local coordinate:
905 s_tl[0] = ref_value[3];
906
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,
922 AlgebraicNode*& node_pt)
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
960 Vector<GeomObject*> geom_object_pt(
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:
972 GeomObject* obj_br_pt = geom_object_pt[0];
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
984
985 // Wall position in top left corner:
986
987 // Pointer to wall element:
988 GeomObject* obj_tl_pt = geom_object_pt[1];
989
990 // Local coordinate:
992 s_tl[0] = ref_value[3];
993
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:
1010 GeomObject* obj_wall_pt = geom_object_pt[2];
1011
1012 // Local coordinate:
1014 s_wall[0] = ref_value[4];
1015
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,
1030 AlgebraicNode*& node_pt)
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
1069 Vector<GeomObject*> geom_object_pt(
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:
1081 GeomObject* obj_br_pt = geom_object_pt[0];
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
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
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
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
1144 Vector<GeomObject*> geom_object_pt(
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:
1175 geom_object_pt[0] = obj_br_pt;
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:
1194 geom_object_pt[1] = obj_tl_pt;
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:
1215 geom_object_pt[2] = obj_wall_pt;
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
1240 Vector<GeomObject*> geom_object_pt(
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:
1271 geom_object_pt[0] = obj_br_pt;
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:
1290 geom_object_pt[1] = obj_tl_pt;
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:
1310 geom_object_pt[2] = obj_wall_pt;
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
e
Definition cfortran.h:571
static char t char * s
Definition cfortran.h:568
char t
Definition cfortran.h:568
Base class for algebraic elements.
Algebraic nodes are nodes with an algebraic positional update function.
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.
double ref_value(const unsigned &i)
Return i-th reference value 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 ...
Algebraic version of RefineableQuarterCircleSectorMesh.
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:1317
virtual void set_macro_elem_pt(MacroElement *macro_elem_pt)
Set pointer to macro element – can be overloaded in derived elements to perform additional tasks.
Definition elements.h:1876
void position(const Vector< double > &zeta, Vector< double > &r) const
Return the parametrised position of the FiniteElement in its incarnation as a GeomObject,...
Definition elements.h:2680
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:2513
unsigned nnode() const
Return the number of nodes.
Definition elements.h:2214
virtual Node * construct_boundary_node(const unsigned &n)
Construct the local node n as a boundary node; that is a node that MAY be placed on a mesh boundary a...
Definition elements.h:2542
Node *& node_pt(const unsigned &n)
Return a pointer to the local node n.
Definition elements.h:2179
A geometric object is an object that provides a parametrised description of its shape via the functio...
unsigned ndim() const
Access function to # of Eulerian coordinates.
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
FiniteElement * finite_element_pt(const unsigned &e) const
Upcast (downcast?) to FiniteElement (needed to access FiniteElement member functions).
Definition mesh.h:477
void set_nboundary(const unsigned &nbound)
Set the number of boundaries in the mesh.
Definition mesh.h:509
const Vector< GeneralisedElement * > & element_pt() const
Return reference to the Vector of elements.
Definition mesh.h:464
void set_boundary_coordinate_exists(const unsigned &i)
Set boundary coordinate on the i-th boundary to be existing.
Definition mesh.h:584
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:598
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....
void setup_boundary_element_info()
Setup lookup schemes which establish whic elements are located next to mesh's boundaries (wrapper to ...
Definition quad_mesh.h:73
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.
TAdvectionDiffusionReactionElement<NREAGENT,DIM,NNODE_1D> elements are isoparametric triangular DIM-d...
Base class for time-stepping schemes. Timestepper provides an approximation of the temporal derivativ...
virtual unsigned nprev_values() const =0
Number of previous values available: 0 for static, 1 for BDF<1>,...
DRAIG: Change all instances of (SPATIAL_DIM) to (DIM-1).