simple_cubic_tet_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_CUBIC_TET_MESH_TEMPLATE_HEADER
27#define OOMPH_SIMPLE_CUBIC_TET_MESH_TEMPLATE_HEADER
28
29#ifndef OOMPH_SIMPLE_CUBIC_TET_MESH_HEADER
30#error __FILE__ should only be included from simple_cubic_tet_mesh.h.
31#endif // OOMPH_SIMPLE_CUBIC_TET_MESH_HEADER
32
33#include <algorithm>
34
35// Simple 3D tetrahedral mesh class
36
37#include "generic/map_matrix.h"
38#include <algorithm>
39
40namespace oomph
41{
42 //====================================================================
43 /// Simple tetrahedral mesh - with 24 tet elements constructed within a
44 /// "brick" form for each element block.
45 //====================================================================
46 template<class ELEMENT>
48 TimeStepper* time_stepper_pt)
49 {
50 // Mesh can only be built with 3D Telements.
51 MeshChecker::assert_geometric_element<TElementGeometricBase, ELEMENT>(3);
52
53 // Create space for elements
54 unsigned nelem = Tmp_mesh_pt->nelement();
55 Element_pt.resize(nelem);
56
57 // Create space for nodes
58 unsigned nnode_scaffold = Tmp_mesh_pt->nnode();
60
61 // Set number of boundaries
62 unsigned nbound = Tmp_mesh_pt->nboundary();
63 set_nboundary(nbound);
64
65 // Loop over elements in scaffold mesh, visit their nodes
66 for (unsigned e = 0; e < nelem; e++)
67 {
68 Element_pt[e] = new ELEMENT;
69 }
70
71 // In the first instance build all nodes from within all the elements
72 unsigned nnod_el = Tmp_mesh_pt->finite_element_pt(0)->nnode();
73 // Loop over elements in scaffold mesh, visit their nodes
74 for (unsigned e = 0; e < nelem; e++)
75 {
76 // Loop over all nodes in element
77 for (unsigned j = 0; j < nnod_el; j++)
78 {
79 // Create new node, using the NEW element's construct_node
80 // member function
81 finite_element_pt(e)->construct_node(j, time_stepper_pt);
82 }
83 }
84
85 // Setup map to check the (pseudo-)global node number
86 // Nodes whose number is zero haven't been copied across
87 // into the mesh yet.
88 std::map<Node*, unsigned> global_number;
89 unsigned global_count = 0;
90 // Loop over elements in scaffold mesh, visit their nodes
91 for (unsigned e = 0; e < nelem; e++)
92 {
93 // Loop over all nodes in element
94 for (unsigned j = 0; j < nnod_el; j++)
95 {
96 // Pointer to node in the scaffold mesh
97 Node* scaffold_node_pt = Tmp_mesh_pt->finite_element_pt(e)->node_pt(j);
98
99 // Get the (pseudo-)global node number in scaffold mesh
100 // (It's zero [=default] if not visited this one yet)
102
103 // Haven't done this one yet
104 if (j_global == 0)
105 {
106 // Give it a number (not necessarily the global node
107 // number in the scaffold mesh -- we just need something
108 // to keep track...)
109 global_count++;
111
112 // Copy new node, created using the NEW element's construct_node
113 // function into global storage, using the same global
114 // node number that we've just associated with the
115 // corresponding node in the scaffold mesh
116 Node_pt[global_count - 1] = finite_element_pt(e)->node_pt(j);
117
118 // Assign coordinates
119 Node_pt[global_count - 1]->x(0) = scaffold_node_pt->x(0);
120 Node_pt[global_count - 1]->x(1) = scaffold_node_pt->x(1);
121 Node_pt[global_count - 1]->x(2) = scaffold_node_pt->x(2);
122
123 // Get pointer to set of mesh boundaries that this
124 // scaffold node occupies; NULL if the node is not on any boundary
125 std::set<unsigned>* boundaries_pt;
126 scaffold_node_pt->get_boundaries_pt(boundaries_pt);
127
128 // Loop over the mesh boundaries that the node in the scaffold mesh
129 // occupies and assign new node to the same ones.
130 if (boundaries_pt != 0)
131 {
132 this->convert_to_boundary_node(Node_pt[global_count - 1]);
133 for (std::set<unsigned>::iterator it = boundaries_pt->begin();
134 it != boundaries_pt->end();
135 ++it)
136 {
137 add_boundary_node(*it, Node_pt[global_count - 1]);
138 }
139 }
140 }
141 // This one has already been done: Kill it
142 else
143 {
144 // Kill it
145 delete finite_element_pt(e)->node_pt(j);
146
147 // Overwrite the element's pointer to local node by
148 // pointer to the already existing node -- identified by
149 // the number kept in the map
150 finite_element_pt(e)->node_pt(j) = Node_pt[j_global - 1];
151 }
152 }
153 }
154
155 // At this point we've created all the elements and
156 // created their vertex nodes. Now we need to create
157 // the additional (midside and internal) nodes!
158
159 // We'll first create all local nodes for all elements
160 // and then delete the superfluous ones that have
161 // a matching node in an adjacent element.
162
163 // Get number of nodes along element edge and dimension of element (3)
164 // from first element
165 unsigned nnode_1d = finite_element_pt(0)->nnode_1d();
166
167 // At the moment we're only able to deal with nnode_1d=2 or 3.
168 if ((nnode_1d != 2) && (nnode_1d != 3))
169 {
170 std::ostringstream error_message;
171 error_message << "Mesh generation currently only works\n";
172 error_message << "for nnode_1d = 2 or 3. You're trying to use it\n";
173 error_message << "for nnode_1d=" << nnode_1d << std::endl;
174
175 throw OomphLibError(
177 }
178
179 // Spatial dimension of element = number of local coordinates
180 unsigned dim = finite_element_pt(0)->dim();
181
182 // Storage for the local coordinate of the new node
184
185 // Get number of nodes in the element from first element
186 unsigned nnode = finite_element_pt(0)->nnode();
187
188 // Loop over all elements
189 for (unsigned e = 0; e < nelem; e++)
190 {
191 // Loop over the new nodes in the element and create them.
192 for (unsigned j = 4; j < nnode; j++)
193 {
194 // Create new node
196 finite_element_pt(e)->construct_node(j, time_stepper_pt);
197
198 // What are the node's local coordinates?
199 finite_element_pt(e)->local_coordinate_of_node(j, s);
200
201 // Find the coordinates of the new node from the existing
202 // and fully-functional element in the scaffold mesh
203 for (unsigned i = 0; i < dim; i++)
204 {
205 new_node_pt->x(i) =
206 Tmp_mesh_pt->finite_element_pt(e)->interpolated_x(s, i);
207 }
208 } // end of loop over new nodes
209 } // end of loop over elements
210
211 // Bracket this away so the edge map goes out of scope
212 // when we're done
213 {
214 // Storage for pointer to mid-edge node
216 Node* edge_node1_pt = 0;
217 Node* edge_node2_pt = 0;
218
219 // Loop over elements
220 for (unsigned e = 0; e < nelem; e++)
221 {
222 // Loop over new local nodes
223 for (unsigned j = 4; j < nnode; j++)
224 {
225 // Pointer to the element's local node
226 Node* node_pt = finite_element_pt(e)->node_pt(j);
227
228 // By default, we assume the node is not new
229 bool is_new = false;
230
231 // This will have to be changed for higher-order elements
232 //=======================================================
233
234 // Switch on local node number (all located on edges)
235 switch (j)
236 {
237 // Node 4 is located between nodes 0 and 1
238 case 4:
239
240 edge_node1_pt = finite_element_pt(e)->node_pt(0);
241 edge_node2_pt = finite_element_pt(e)->node_pt(1);
243 {
244 is_new = true;
247 }
248 break;
249
250 // Node 5 is located between nodes 0 and 2
251 case 5:
252
253 edge_node1_pt = finite_element_pt(e)->node_pt(0);
254 edge_node2_pt = finite_element_pt(e)->node_pt(2);
256 {
257 is_new = true;
260 }
261 break;
262
263 // Node 6 is located between nodes 0 and 3
264 case 6:
265
266 edge_node1_pt = finite_element_pt(e)->node_pt(0);
267 edge_node2_pt = finite_element_pt(e)->node_pt(3);
269 {
270 is_new = true;
273 }
274 break;
275
276 // Node 7 is located between nodes 1 and 2
277 case 7:
278
279 edge_node1_pt = finite_element_pt(e)->node_pt(1);
280 edge_node2_pt = finite_element_pt(e)->node_pt(2);
282 {
283 is_new = true;
286 }
287 break;
288
289 // Node 8 is located between nodes 2 and 3
290 case 8:
291
292 edge_node1_pt = finite_element_pt(e)->node_pt(2);
293 edge_node2_pt = finite_element_pt(e)->node_pt(3);
295 {
296 is_new = true;
299 }
300 break;
301
302 // Node 9 is located between nodes 1 and 3
303 case 9:
304
305 edge_node1_pt = finite_element_pt(e)->node_pt(1);
306 edge_node2_pt = finite_element_pt(e)->node_pt(3);
308 {
309 is_new = true;
312 }
313 break;
314
315 default:
316 throw OomphLibError("More than ten nodes in Tet Element",
319 }
320
321 if (is_new)
322 {
323 // New node: Add it to mesh
324 Node_pt.push_back(node_pt);
325 }
326 else
327 {
328 // Delete local node in element...
329 delete finite_element_pt(e)->node_pt(j);
330
331 // ... and reset pointer to the existing node
332 finite_element_pt(e)->node_pt(j) =
334 }
335 }
336 }
337 }
338
339 // Boundary conditions
340
341 // Matrix map to check if a node has already been added to
342 // the boundary number b (NOTE: Enumerated by pointer to ORIGINAL
343 // node before transfer to boundary node)
345
346 // Create lookup scheme for pointers to original local nodes
347 // in elements
349
350 // Loop over elements
351 for (unsigned e = 0; e < nelem; e++)
352 {
353 orig_node_pt[e].resize(nnode, 0);
354
355 // Loop over new local nodes
356 for (unsigned j = 4; j < nnode; j++)
357 {
358 // Pointer to the element's local node
359 orig_node_pt[e][j] = finite_element_pt(e)->node_pt(j);
360 }
361 }
362
363 // Loop over elements
364 for (unsigned e = 0; e < nelem; e++)
365 {
366 // Loop over new local nodes
367 for (unsigned j = 4; j < nnode; j++)
368 {
369 // Loop over the boundaries
370 for (unsigned bo = 0; bo < nbound; bo++)
371 {
372 // Pointer to the element's local node
373 Node* loc_node_pt = finite_element_pt(e)->node_pt(j);
374
375 // Pointer to original node
377
378 // value of the map for the node and boundary specified
380
381 if (bound_test == false)
382 {
384
385 // This will have to be changed for higher-order elements
386 //=======================================================
387
388 // Switch on local node number (all located on edges)
389 switch (j)
390 {
391 // Node 4 is located between nodes 0 and 1
392 case 4:
393
394 if (finite_element_pt(e)->node_pt(0)->is_on_boundary(bo) &&
395 finite_element_pt(e)->node_pt(1)->is_on_boundary(bo))
396 {
397 this->convert_to_boundary_node(loc_node_pt);
398 add_boundary_node(bo, loc_node_pt);
399 }
400 break;
401
402 // Node 5 is located between nodes 0 and 2
403 case 5:
404
405 if (finite_element_pt(e)->node_pt(0)->is_on_boundary(bo) &&
406 finite_element_pt(e)->node_pt(2)->is_on_boundary(bo))
407 {
408 this->convert_to_boundary_node(loc_node_pt);
409 add_boundary_node(bo, loc_node_pt);
410 }
411 break;
412
413 // Node 6 is located between nodes 0 and 3
414 case 6:
415
416 if (finite_element_pt(e)->node_pt(0)->is_on_boundary(bo) &&
417 finite_element_pt(e)->node_pt(3)->is_on_boundary(bo))
418 {
419 this->convert_to_boundary_node(loc_node_pt);
420 add_boundary_node(bo, loc_node_pt);
421 }
422 break;
423
424 // Node 7 is located between nodes 1 and 2
425 case 7:
426
427 if (finite_element_pt(e)->node_pt(1)->is_on_boundary(bo) &&
428 finite_element_pt(e)->node_pt(2)->is_on_boundary(bo))
429 {
430 this->convert_to_boundary_node(loc_node_pt);
431 add_boundary_node(bo, loc_node_pt);
432 }
433 break;
434
435 // Node 8 is located between nodes 2 and 3
436 case 8:
437
438 if (finite_element_pt(e)->node_pt(2)->is_on_boundary(bo) &&
439 finite_element_pt(e)->node_pt(3)->is_on_boundary(bo))
440 {
441 this->convert_to_boundary_node(loc_node_pt);
442 add_boundary_node(bo, loc_node_pt);
443 }
444 break;
445
446 // Node 9 is located between nodes 1 and 3
447 case 9:
448
449 if (finite_element_pt(e)->node_pt(1)->is_on_boundary(bo) &&
450 finite_element_pt(e)->node_pt(3)->is_on_boundary(bo))
451 {
452 this->convert_to_boundary_node(loc_node_pt);
453 add_boundary_node(bo, loc_node_pt);
454 }
455 break;
456
457 default:
458 throw OomphLibError("More than ten nodes in Tet Element",
461 }
462 }
463
464 } // end for bo
465 } // end for j
466 } // end for e
467 }
468
469} // namespace oomph
470
471#endif
e
Definition cfortran.h:571
static char t char * s
Definition cfortran.h:568
cstr elem_len * i
Definition cfortran.h:603
virtual void local_coordinate_of_node(const unsigned &j, Vector< double > &s) const
Get local coordinates of node j in the element; vector sets its own size (broken virtual)
Definition elements.h:1846
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
virtual double interpolated_x(const Vector< double > &s, const unsigned &i) const
Return FE interpolated coordinate x[i] at local coordinate s.
Definition elements.cc:3992
unsigned dim() const
Return the spatial dimension of the element, i.e. the number of local coordinates required to paramet...
Definition elements.h:2615
unsigned nnode() const
Return the number of nodes.
Definition elements.h:2214
Node ** Node_pt
Storage for pointers to the nodes in the element.
Definition elements.h:1323
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
TimeStepper *& time_stepper_pt()
Access function for pointer to time stepper: Null if object is not time-dependent.
Nodes are derived from Data, but, in addition, have a definite (Eulerian) position in a space of a gi...
Definition nodes.h:906
double & x(const unsigned &i)
Return the i-th nodal coordinate.
Definition nodes.h:1060
void resize(const unsigned &n_value)
Resize the number of equations.
Definition nodes.cc:2167
An OomphLibError object which should be thrown when an run-time error is encountered....
void build_from_scaffold(TimeStepper *time_stepper_pt)
Build mesh from scaffold mesh.
TAdvectionDiffusionReactionElement<NREAGENT,DIM,NNODE_1D> elements are isoparametric triangular DIM-d...
TAdvectionDiffusionReactionElement()
Constructor: Call constructors for TElement and AdvectionDiffusionReaction equations.
Base class for time-stepping schemes. Timestepper provides an approximation of the temporal derivativ...
DRAIG: Change all instances of (SPATIAL_DIM) to (DIM-1).