simple_rectangular_tri_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_SIMPLE_RECTANGULAR_TRI_MESH_TEMPLATE_HEADER
27#define OOMPH_SIMPLE_RECTANGULAR_TRI_MESH_TEMPLATE_HEADER
28
29#ifndef OOMPH_SIMPLE_RECTANGULAR_TRI_MESH_HEADER
30#error __FILE__ should only be included from simple_rectangular_tri_mesh.h.
31#endif // OOMPH_SIMPLE_RECTANGULAR_TRI_MESH_HEADER
32
33#include <algorithm>
34
35#include "generic/Telements.h"
36
37// Simple 2D triangle mesh class
38
39namespace oomph
40{
41 //====================================================================
42 /// Constructor for simple 2D triangular mesh class:
43 ///
44 /// n_x : number of elements in the x direction
45 ///
46 /// n_y : number of elements in the y direction
47 ///
48 /// l_x : length in the x direction
49 ///
50 /// l_y : length in the y direction
51 ///
52 /// Ordering of elements: 'lower left' to 'lower right' then 'upwards'
53 //====================================================================
54 template<class ELEMENT>
56 const unsigned& n_x,
57 const unsigned& n_y,
58 const double& l_x,
59 const double& l_y,
60 TimeStepper* time_stepper_pt)
61 : Nx(n_x), Ny(n_y), Lx(l_x), Ly(l_y)
62 {
63 using namespace MathematicalConstants;
64
65 // Mesh can only be built with 2D Telements.
66 MeshChecker::assert_geometric_element<TElementGeometricBase, ELEMENT>(2);
67
68 // Set number of boundaries
69 this->set_nboundary(4);
70
71 // Allocate the store for the elements
72 unsigned n_element = (Nx) * (Ny) * 2;
73 Element_pt.resize(n_element, 0);
74
75 // Create first element
76 Element_pt[0] = new ELEMENT;
77
78 // Currently this mesh only works for 3 and 6 noded triangles
79 if ((finite_element_pt(0)->nnode_1d() != 2) &&
80 (finite_element_pt(0)->nnode_1d() != 3) &&
81 (finite_element_pt(0)->nnode_1d() != 4))
82 {
83 throw OomphLibError(
84 "Currently this mesh only works for 3, 6 & 10-noded triangles",
87 }
88
89 unsigned n_node = 0;
90 // Unless nnode_1d returned as !=2 default no extra nodes
91 unsigned additional_nnode = 0;
92
93 // Allocate storage if no extra nodes
94 if (finite_element_pt(0)->nnode_1d() == 2)
95 {
96 n_node = (Nx + 1) * (Ny + 1);
97 }
98
99 if (finite_element_pt(0)->nnode_1d() == 3)
100 {
102 // Allocate storage for nodes (including extra)
103 n_node = (2 * Nx + 1) * (2 * Ny + 1);
104 }
105
106 if (finite_element_pt(0)->nnode_1d() == 4)
107 {
109 // Allocate storage for notes (including extra)
110 n_node = (3 * Nx + 1) * (3 * Ny + 1);
111 }
112
113 Node_pt.resize(n_node);
114
115 // Set up geometrical data
116 //------------------------
117 unsigned long node_count = 0;
118 unsigned long element_count = 0;
119 double xinit = 0.0, yinit = 0.0;
120 // Set the values of the increments
121 double xstep = Lx / (Nx);
122 double ystep = Ly / (Ny);
123
124 // FIRST NODE (lower left corner)
125 //-------------------------------
126
127 // Set the corner node
128
129 // Allocate memory for the corner node of the first element
130 //(which is not created loop as all subsequent bottom corners already exist)
132 finite_element_pt(0)->construct_node(1, time_stepper_pt);
133
134 // Set the pointer from the element
136
137 // Don't increment node_count yet as we still need its containing box
138 //(position and boundaries for first node are allocated in the main loop)
139
140 // CREATE THE ELEMENTS (each has 3 local nodes)
141 //--------------------------------------------------
142 // Elements are created two at a time, the first being lower triangular
143 // and the second upper triangular, so that they form a containing box.
144 // Local nodes are numbered anti-clockwise with node_pt(1) being the
145 // right-angle corner of the triangle.
146 // The global node number, node_count, is considered to define
147 // a containing box, with node_count defined as the node number
148 // of the bottom left corner of the box.
149 for (unsigned j = 0; j < Ny + 1; ++j)
150 {
151 for (unsigned i = 0; i < Nx + 1; ++i)
152 {
153 // CURRENT BOX
154 //(nodes on RHS or top edge of domain do not define a box)
155 if (j < Ny && i < Nx)
156 {
157 // Create two elements
158 //------------------------------
159 if (element_count != 0) // 0th element already exists
160 {
161 Element_pt[element_count] = new ELEMENT;
162 }
163
164 Element_pt[element_count + 1] = new ELEMENT;
165
166 // Allocate memory for nodes in the current box
167 //--------------------------------------------
168 // If node on LHS of domain, allocate the top left corner node
169 if (i == 0)
170 {
171 Node_pt[node_count + Nx + 1] =
173 ->construct_node(0, time_stepper_pt);
174 }
175
176 // If on bottom row, allocate the bottom right corner node
177 if (j == 0)
178 {
180 ->construct_node(2, time_stepper_pt);
181 }
182
183 // Always need to allocate top right corner node
185 ->construct_node(1, time_stepper_pt);
186
187 // Bottom left corner node is already allocated
188
189 // Set the pointers from the elements
190 //----------------------------------
192 Node_pt[node_count + Nx + 1];
195 Node_pt[node_count + 1];
197 Node_pt[node_count + 1];
199 Node_pt[node_count + Nx + 2];
201 Node_pt[node_count + Nx + 1];
202
203 element_count += 2;
204 }
205
206 // CURRENT (GLOBAL) NODE
207 // Set the position
208 Node_pt[node_count]->x(0) = xinit + i * xstep;
209 Node_pt[node_count]->x(1) = yinit + j * ystep;
210
211 // Add node to any relevant boundaries
212 if (j == 0)
213 {
214 this->convert_to_boundary_node(Node_pt[node_count]);
216 }
217 if (j == Ny)
218 {
219 this->convert_to_boundary_node(Node_pt[node_count]);
221 }
222 if (i == 0)
223 {
224 this->convert_to_boundary_node(Node_pt[node_count]);
226 }
227 if (i == Nx)
228 {
229 this->convert_to_boundary_node(Node_pt[node_count]);
231 }
232
233 // Increment counter
234 node_count++;
235 }
236 }
237
238 if (additional_nnode == 3)
239 {
240 // Reset element counter to allow looping over existing elements
241 // to add extra nodes.
242 // Note that the node_count is not reset so no entries are overwritten
243 element_count = 0;
244 for (unsigned j = 0; j < Ny + 1; ++j)
245 {
246 // Note: i counter reduced by 1 since i axis runs through middle of
247 // elements on x-axis
248 for (unsigned i = 0; i < Nx; ++i)
249 {
250 // The additional nodes will be added in stages for ease of
251 // application. Note: local numbering follows the anti-clockwise
252 // pattern, node 3 halfway between nodes 0-1, 4 between 1-2 and the
253 // 5th local node between 2-0.
254
255 // Restricted to stop creation of additional nodes outside the mesh
256 if (j < Ny)
257 {
258 // If on the bottom row middle-node at bottom needs allocating
259 if (j == 0)
260 {
262 ->construct_node(4, time_stepper_pt);
263 }
264
265 // Due to directions of iteration node at middle of top box edge
266 // (in next element) always needs allocating
268 ->construct_node(4, time_stepper_pt);
269
270 // Set pointers to the top/bottom middle nodes
271 // Bottom node
273 // Top node
276
277 // Increase the element counter to add top/bottom nodes to
278 // next pair of element on next pass
279 element_count += 2;
280 } // End extra top/bottom node construction
281
282 // Set position of current (Global) Node
283 Node_pt[node_count]->x(0) = xinit + double(i + 0.5) * xstep;
284 Node_pt[node_count]->x(1) = yinit + j * ystep;
285
286 // Add node to any applicable boundaries (node 4's can only be top
287 // or bottom boundaries)
288 if (j == 0)
289 {
290 this->convert_to_boundary_node(Node_pt[node_count]);
292 }
293 if (j == Ny)
294 {
295 this->convert_to_boundary_node(Node_pt[node_count]);
297 }
298
299 // Update node_count
300 node_count++;
301 }
302 }
303
304 // Next stage of additional node implementation involes the middle left
305 // and right nodes (local number 3 on each triangle)
306
307 // Element counter reset for second loop over existing elements
308 element_count = 0;
309 // Note: j counter reduced by 1 since j axis runs through middle of
310 // elements on y-axis
311 for (unsigned j = 0; j < Ny; ++j)
312 {
313 for (unsigned i = 0; i < Nx + 1; ++i)
314 {
315 if (j < Ny && i < Nx)
316 {
317 // If on the left hand boundary the node at middle of the left
318 // side needs allocating
319 if (i == 0)
320 {
322 ->construct_node(3, time_stepper_pt);
323 }
324
325 // The mid node on the right hand side always needs constructing
326 // within the bounds of the mesh
328 ->construct_node(3, time_stepper_pt);
329
330 // Set pointers from the elements to new nodes
333 Node_pt[node_count + 1];
334
335 // Increase element_count by 2
336 element_count += 2;
337 } // End extra left/right node construction
338
339 // Set position of current (Global) Node
340 Node_pt[node_count]->x(0) = xinit + i * xstep;
341 Node_pt[node_count]->x(1) = yinit + double(j + 0.5) * ystep;
342
343 // Add node to any applicable boundaries again - only be left/right
344 if (i == 0)
345 {
346 this->convert_to_boundary_node(Node_pt[node_count]);
348 }
349 if (i == Nx)
350 {
351 this->convert_to_boundary_node(Node_pt[node_count]);
353 }
354
355 // Update node_count
356 node_count++;
357 }
358 }
359
360 // Final stage of inserting extra nodes - inclusion of the local
361 // number 5 (middle of hypot. edge)
362
363 element_count = 0;
364 // Note: both i,j counters reduced by 1 since j axis runs through middle
365 // of elements in both x,y
366 for (unsigned j = 0; j < Ny; ++j)
367 {
368 for (unsigned i = 0; i < Nx; ++i)
369 {
370 // The middle node always needs constructing
372 ->construct_node(5, time_stepper_pt);
373
374 // Set pointers from the elements to new nodes
378
379 // Increase element_count by 2
380 element_count += 2;
381 // End extra left/right node construction
382
383 // Set position of current (Global) Node
384 Node_pt[node_count]->x(0) = xinit + double(i + 0.5) * xstep;
385 Node_pt[node_count]->x(1) = yinit + double(j + 0.5) * ystep;
386
387 // All nodes are internal in this structure so no boundaries
388 // applicable
389
390 // Update node_count
391 node_count++;
392 }
393 }
394 }
395 // End of extra nodes for 6 noded trianglur elements
396
397 if (additional_nnode == 7)
398 {
399 // Reset element counter to allow looping over existing elements
400 // to add extra nodes.
401 // Note that the node_count is not reset so no entries are overwritten
402 element_count = 0;
403 for (unsigned j = 0; j < Ny + 1; ++j)
404 {
405 // Note: i counter reduced by 1 for implementation of lower element
406 // node 5 and upper element node 6's.
407 for (unsigned i = 0; i < Nx; ++i)
408 {
409 // The additional nodes will be added in stages for ease of
410 // application. Note: local numbering follows the anti-clockwise
411 // pattern, nodes 3 and 4 equidistant between nodes 0-1, 5 and 6
412 // between 1-2, 7 and 8 between 2-0 and last node 9 located
413 // (internally) at the centroid of the triangle.
414
415 // Restricted to stop creation of additional nodes outside the mesh
416 if (j < Ny)
417 {
418 // If on the bottom row middle-left-node at bottom needs allocating
419 if (j == 0)
420 {
422 ->construct_node(5, time_stepper_pt);
423 }
424
425 // Due to directions of iteration node at middle left of top box
426 // edge (in next element) always needs allocating
428 ->construct_node(6, time_stepper_pt);
429
430 // Set pointers to the top/bottom middle nodes
431 // Bottom node
433 // Top node
436
437 // Increase the element counter to add top/bottom nodes to
438 // next pair of element on next pass
439 element_count += 2;
440 } // End extra top/bottom node construction
441
442 // Set position of current (Global) Node
443 Node_pt[node_count]->x(0) = xinit + double(i + 1.0 / 3.0) * xstep;
444 Node_pt[node_count]->x(1) = yinit + j * ystep;
445
446 // Add node to any applicable boundaries (exactly as previous)
447 if (j == 0)
448 {
449 this->convert_to_boundary_node(Node_pt[node_count]);
451 }
452 if (j == Ny)
453 {
454 this->convert_to_boundary_node(Node_pt[node_count]);
456 }
457
458 // Update node_count
459 node_count++;
460 }
461 }
462
463 // Next stage: bottom-middle-right node (node 6 in lower tri.el.)
464 // and top-middle-right node (node 5 in upper tri.el.)
465
466 element_count = 0;
467 for (unsigned j = 0; j < Ny + 1; ++j)
468 {
469 // Note: i counter as for above 5/6's
470 for (unsigned i = 0; i < Nx; ++i)
471 {
472 // Restricted to stop creation of additional nodes outside the mesh
473 if (j < Ny)
474 {
475 // If on the bottom row middle-right-node at bottom needs allocating
476 if (j == 0)
477 {
479 ->construct_node(6, time_stepper_pt);
480 }
481
482 // Due to directions of iteration node at middle left of top box
483 // edge (in next element) always needs allocating
485 ->construct_node(5, time_stepper_pt);
486
487 // Set pointers to the top/bottom middle nodes
488 // Bottom node
490 // Top node
493
494 // Increase the element counter to add top/bottom nodes to
495 // next pair of element on next pass
496 element_count += 2;
497 } // End extra top/bottom node construction
498
499 // Set position of current (Global) Node
500 Node_pt[node_count]->x(0) = xinit + double(i + 2.0 / 3.0) * xstep;
501 Node_pt[node_count]->x(1) = yinit + j * ystep;
502
503 // Add node to any applicable boundaries (exactly as previous)
504 if (j == 0)
505 {
506 this->convert_to_boundary_node(Node_pt[node_count]);
508 }
509 if (j == Ny)
510 {
511 this->convert_to_boundary_node(Node_pt[node_count]);
513 }
514
515 // Update node_count
516 node_count++;
517 }
518 }
519
520 // Next stage of additional node implementation involes node 4 on lower
521 // tri. el. and node 3 on upper tri. el.
522
523 // Element counter reset for next loop over existing elements
524 element_count = 0;
525 // Note: j counter reduced by 1 similar to others above
526 for (unsigned j = 0; j < Ny; ++j)
527 {
528 for (unsigned i = 0; i < Nx + 1; ++i)
529 {
530 if (j < Ny && i < Nx)
531 {
532 // If on the left hand boundary the lower middle node of the left
533 // side needs allocating
534 if (i == 0)
535 {
537 ->construct_node(4, time_stepper_pt);
538 }
539
540 // The mid node on the right hand side always needs constructing
541 // within the bounds of the mesh
543 ->construct_node(3, time_stepper_pt);
544
545 // Set pointers from the elements to new nodes
548 Node_pt[node_count + 1];
549
550 // Increase element_count by 2
551 element_count += 2;
552 } // End extra left/right node construction
553
554 // Set position of current (Global) Node
555 Node_pt[node_count]->x(0) = xinit + i * xstep;
556 Node_pt[node_count]->x(1) = yinit + double(j + 1.0 / 3.0) * ystep;
557
558 // Add node to any applicable boundaries again - only be left/right
559 if (i == 0)
560 {
561 this->convert_to_boundary_node(Node_pt[node_count]);
563 }
564 if (i == Nx)
565 {
566 this->convert_to_boundary_node(Node_pt[node_count]);
568 }
569
570 // Update node_count
571 node_count++;
572 }
573 }
574
575 // Next stage of additional node implementation involes node 3 on lower
576 // tri. el. and node 4 on upper tri. el.
577
578 // Element counter reset for next loop over existing elements
579 element_count = 0;
580 // Note: j counter reduced by 1 similar to others above
581 for (unsigned j = 0; j < Ny; ++j)
582 {
583 for (unsigned i = 0; i < Nx + 1; ++i)
584 {
585 if (j < Ny && i < Nx)
586 {
587 // If on the left hand boundary the lower middle node of the left
588 // side needs allocating
589 if (i == 0)
590 {
592 ->construct_node(3, time_stepper_pt);
593 }
594
595 // The mid node on the right hand side always needs constructing
596 // within the bounds of the mesh
598 ->construct_node(4, time_stepper_pt);
599
600 // Set pointers from the elements to new nodes
603 Node_pt[node_count + 1];
604
605 // Increase element_count by 2
606 element_count += 2;
607 } // End extra left/right node construction
608
609 // Set position of current (Global) Node
610 Node_pt[node_count]->x(0) = xinit + i * xstep;
611 Node_pt[node_count]->x(1) = yinit + double(j + 2.0 / 3.0) * ystep;
612
613 // Add node to any applicable boundaries again - only be left/right
614 if (i == 0)
615 {
616 this->convert_to_boundary_node(Node_pt[node_count]);
618 }
619 if (i == Nx)
620 {
621 this->convert_to_boundary_node(Node_pt[node_count]);
623 }
624
625 // Update node_count
626 node_count++;
627 }
628 }
629
630 // Next is the lower tri. el. totally internal node with local number 9
631 element_count = 0;
632 // Note: both i,j counters reduced by 1
633 for (unsigned j = 0; j < Ny; ++j)
634 {
635 for (unsigned i = 0; i < Nx; ++i)
636 {
637 // The middle node always needs constructing
639 ->construct_node(9, time_stepper_pt);
640
641 // Set pointers from the elements to new nodes
643
644 // Increase element_count by 2
645 element_count += 2;
646
647 // Set position of current (Global) Node
648 Node_pt[node_count]->x(0) = xinit + double(i + 1.0 / 3.0) * xstep;
649 Node_pt[node_count]->x(1) = yinit + double(j + 1.0 / 3.0) * ystep;
650
651 // All nodes are internal in this structure so no boundaries
652 // applicable
653
654 // Update node_count
655 node_count++;
656 }
657 }
658
659 // Next is the bottom hyp. node -
660 // lower tri. el. number 7, upper tri. el. number 8
661 element_count = 0;
662 // Note: both i,j counters reduced by 1
663 for (unsigned j = 0; j < Ny; ++j)
664 {
665 for (unsigned i = 0; i < Nx; ++i)
666 {
667 // The node always needs constructing
669 ->construct_node(7, time_stepper_pt);
670
671 // Set pointers from the elements to new nodes
675
676 // Increase element_count by 2
677 element_count += 2;
678
679 // Set position of current (Global) Node
680 Node_pt[node_count]->x(0) = xinit + double(i + 2.0 / 3.0) * xstep;
681 Node_pt[node_count]->x(1) = yinit + double(j + 1.0 / 3.0) * ystep;
682
683 // All nodes are internal in this structure so no boundaries
684 // applicable
685
686 // Update node_count
687 node_count++;
688 }
689 }
690
691 // Next is the upper hyp. node -
692 // lower tri. el. number 8, upper tri. el. number 7
693 element_count = 0;
694 // Note: both i,j counters reduced by 1
695 for (unsigned j = 0; j < Ny; ++j)
696 {
697 for (unsigned i = 0; i < Nx; ++i)
698 {
699 // The node always needs constructing
701 ->construct_node(8, time_stepper_pt);
702
703 // Set pointers from the elements to new nodes
707
708 // Increase element_count by 2
709 element_count += 2;
710
711 // Set position of current (Global) Node
712 Node_pt[node_count]->x(0) = xinit + double(i + 1.0 / 3.0) * xstep;
713 Node_pt[node_count]->x(1) = yinit + double(j + 2.0 / 3.0) * ystep;
714
715 // All nodes are internal in this structure so no boundaries
716 // applicable
717
718 // Update node_count
719 node_count++;
720 }
721 }
722
723 // Next is the upper tri. el. totally internal node with local number 9
724 element_count = 0;
725 // Note: both i,j counters reduced by 1
726 for (unsigned j = 0; j < Ny; ++j)
727 {
728 for (unsigned i = 0; i < Nx; ++i)
729 {
730 // The middle node always needs constructing
732 ->construct_node(9, time_stepper_pt);
733
734 // Set pointers from the elements to new nodes
737
738 // Increase element_count by 2
739 element_count += 2;
740
741 // Set position of current (Global) Node
742 Node_pt[node_count]->x(0) = xinit + double(i + 2.0 / 3.0) * xstep;
743 Node_pt[node_count]->x(1) = yinit + double(j + 2.0 / 3.0) * ystep;
744
745 // All nodes are internal in this structure so no boundaries
746 // applicable
747
748 // Update node_count
749 node_count++;
750 }
751 }
752 }
753 }
754
755} // namespace oomph
756#endif
cstr elem_len * i
Definition cfortran.h:603
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
Node *& node_pt(const unsigned &n)
Return a pointer to the local node n.
Definition elements.h:2179
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:2222
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
void convert_to_boundary_node(Node *&node_pt, const Vector< FiniteElement * > &finite_element_pt)
A function that upgrades an ordinary node to a boundary node We shouldn't ever really use this,...
Definition mesh.cc:2590
Vector< GeneralisedElement * > Element_pt
Vector of pointers to generalised elements.
Definition mesh.h:186
An OomphLibError object which should be thrown when an run-time error is encountered....
SimpleRectangularTriMesh(const unsigned &n_x, const unsigned &n_y, const double &l_x, const double &l_y, TimeStepper *time_stepper_pt=&Mesh::Default_TimeStepper)
Constructor n_x : number of elements in the x direction; n_y : number of elements in the y direction;...
double Lx
Length of mesh in x-direction.
unsigned Ny
Number of elements in y directions.
unsigned Nx
Number of elements in x direction.
double Ly
Length of mesh in y-direction.
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...
DRAIG: Change all instances of (SPATIAL_DIM) to (DIM-1).