tetgen_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_TETGEN_MESH_TEMPLATE_HEADER
27#define OOMPH_TETGEN_MESH_TEMPLATE_HEADER
28
29#ifndef OOMPH_TETGEN_MESH_HEADER
30#error __FILE__ should only be included from tetgen_mesh.h.
31#endif // OOMPH_TETGEN_MESH_HEADER
32
33#include <algorithm>
34
35#include "generic/Telements.h"
36#include "generic/map_matrix.h"
37
38namespace oomph
39{
40 ///////////////////////////////////////////////////////////////////////
41 ///////////////////////////////////////////////////////////////////////
42 ///////////////////////////////////////////////////////////////////////
43
44 //========================================================================
45 /// Build unstructured tet mesh based on output from scaffold
46 //========================================================================
47 template<class ELEMENT>
49 const bool& use_attributes)
50 {
51 // Mesh can only be built with 3D Telements.
52 MeshChecker::assert_geometric_element<TElementGeometricBase, ELEMENT>(3);
53
54 // Create space for elements
55 unsigned nelem = Tmp_mesh_pt->nelement();
56 Element_pt.resize(nelem);
57
58 // Create space for nodes
59 unsigned nnode_scaffold = Tmp_mesh_pt->nnode();
61
62 // Set number of boundaries
63 unsigned nbound = Tmp_mesh_pt->nboundary();
64 set_nboundary(nbound);
65 Boundary_element_pt.resize(nbound);
66 Face_index_at_boundary.resize(nbound);
67
68 // If we have different regions, then resize the region
69 // information
71 {
72 Boundary_region_element_pt.resize(nbound);
73 Face_index_region_at_boundary.resize(nbound);
74 }
75
76 // Build elements
77 for (unsigned e = 0; e < nelem; e++)
78 {
79 Element_pt[e] = new ELEMENT;
80 }
81
82 // Number of nodes per element
83 unsigned nnod_el = Tmp_mesh_pt->finite_element_pt(0)->nnode();
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
91 // Map of element attribute pairs
92 std::map<double, Vector<FiniteElement*>> element_attribute_map;
93
94 // Loop over elements in scaffold mesh, visit their nodes
95 for (unsigned e = 0; e < nelem; e++)
96 {
97 // Loop over all nodes in element
98 for (unsigned j = 0; j < nnod_el; j++)
99 {
100 // Pointer to node in the scaffold mesh
101 Node* scaffold_node_pt = Tmp_mesh_pt->finite_element_pt(e)->node_pt(j);
102
103 // Get the (pseudo-)global node number in scaffold mesh
104 // (It's zero [=default] if not visited this one yet)
106
107 // Haven't done this one yet
108 if (j_global == 0)
109 {
110 // Get pointer to set of mesh boundaries that this
111 // scaffold node occupies; NULL if the node is not on any boundary
112 std::set<unsigned>* boundaries_pt;
113 scaffold_node_pt->get_boundaries_pt(boundaries_pt);
114
115 // Is it on boundaries?
116 if (boundaries_pt != 0)
117 {
118 // Create new boundary node
120 finite_element_pt(e)->construct_boundary_node(j, time_stepper_pt);
121
122 // Give it a number (not necessarily the global node
123 // number in the scaffold mesh -- we just need something
124 // to keep track...)
125 global_count++;
127
128 // Add to boundaries
129 for (std::set<unsigned>::iterator it = boundaries_pt->begin();
130 it != boundaries_pt->end();
131 ++it)
132 {
133 add_boundary_node(*it, new_node_pt);
134 }
135 }
136 // Build normal node
137 else
138 {
139 // Create new normal node
140 finite_element_pt(e)->construct_node(j, time_stepper_pt);
141
142 // Give it a number (not necessarily the global node
143 // number in the scaffold mesh -- we just need something
144 // to keep track...)
145 global_count++;
147 }
148
149 // Copy new node, created using the NEW element's construct_node
150 // function into global storage, using the same global
151 // node number that we've just associated with the
152 // corresponding node in the scaffold mesh
153 Node_pt[global_count - 1] = finite_element_pt(e)->node_pt(j);
154
155 // Assign coordinates
156 Node_pt[global_count - 1]->x(0) = scaffold_node_pt->x(0);
157 Node_pt[global_count - 1]->x(1) = scaffold_node_pt->x(1);
158 Node_pt[global_count - 1]->x(2) = scaffold_node_pt->x(2);
159 }
160 // This one has already been done: Copy across
161 else
162 {
163 finite_element_pt(e)->node_pt(j) = Node_pt[j_global - 1];
164 }
165 }
166
167 // Store the attributes in the map
168 if (use_attributes)
169 {
170 element_attribute_map[Tmp_mesh_pt->element_attribute(e)].push_back(
171 finite_element_pt(e));
172 }
173 }
174
175 // Now let's construct lists
176 // Find the number of attributes
177 if (use_attributes)
178 {
180 // There are n_attribute different regions
181 Region_element_pt.resize(n_attribute);
182 Region_attribute.resize(n_attribute);
183 // Copy the vectors in the map over to our internal storage
184 unsigned count = 0;
185 for (std::map<double, Vector<FiniteElement*>>::iterator it =
186 element_attribute_map.begin();
187 it != element_attribute_map.end();
188 ++it)
189 {
190 Region_attribute[count] = it->first;
191 Region_element_pt[count] = it->second;
192 ++count;
193 }
194 }
195
196 // At this point we've created all the elements and
197 // created their vertex nodes. Now we need to create
198 // the additional (midside and internal) nodes!
199 unsigned boundary_id;
200
201 // Get number of nodes along element edge and dimension of element (3)
202 // from first element
203 unsigned n_node_1d = finite_element_pt(0)->nnode_1d();
204
205 // At the moment we're only able to deal with nnode_1d=2 or 3.
206 if ((n_node_1d != 2) && (n_node_1d != 3))
207 {
208 std::ostringstream error_message;
209 error_message << "Mesh generation from tetgen currently only works\n";
210 error_message << "for nnode_1d = 2 or 3. You're trying to use it\n";
211 error_message << "for nnode_1d=" << n_node_1d << std::endl;
212
213 throw OomphLibError(
215 }
216
217 // Spatial dimension of element = number of local coordinates
218 unsigned dim = finite_element_pt(0)->dim();
219
220 // Storage for the local coordinate of the new node
222
223 // Get number of nodes in the element from first element
224 unsigned n_node = finite_element_pt(0)->nnode();
225
226 // Storage for each global edge of the mesh
227 unsigned n_global_edge = Tmp_mesh_pt->nglobal_edge();
229
230 // Storage for each global face of the mesh
231 unsigned n_global_face = Tmp_mesh_pt->nglobal_face();
233
234 // Map storing the mid-side of an edge; edge identified by
235 // pointers to vertex nodes in scaffold mesh
236 // MapMatrix<Node*,Node*> central_edge_node_pt;
237 // Node* edge_node1_pt=0;
238 // Node* edge_node2_pt=0;
239
240 // Map storing the mid point of a face; face identified by
241 // set of pointers to vertex nodes in scaffold mesh
242 // std::map<std::set<Node*>,Node*> central_face_node_pt;
243 // std::set<Node*> face_nodes_pt;
244
245 // Mapping of Tetgen faces to face nodes in the enriched element
246 unsigned face_map[4] = {1, 0, 2, 3};
247
248 // Storage for the faces shared by the edges
249 const unsigned faces_on_edge[6][2] = {
250 {0, 1}, {0, 2}, {1, 2}, {0, 3}, {2, 3}, {1, 3}};
251
252 // Loop over all elements
253 for (unsigned e = 0; e < nelem; e++)
254 {
255 // Cache pointers to the elements
256 FiniteElement* const elem_pt = this->finite_element_pt(e);
257 FiniteElement* const tmp_elem_pt = Tmp_mesh_pt->finite_element_pt(e);
258
259 // The number of edge nodes is 4 + 6*(n_node1d-2)
260 unsigned n_edge_node = 4 + 6 * (n_node_1d - 2);
261
262 // Now loop over the edge nodes
263 // assuming that the numbering scheme is the same as the triangles
264 // which puts edge nodes in ascending order.
265 // We don't have any higher than quadratic at the moment, so it's
266 // a bit academic really.
267
268 // Only bother if we actually have some edge nodes
269 if (n_edge_node > 4)
270 {
271 // Start from node number 4
272 unsigned n = 4;
273
274 // Loop over the edges
275 for (unsigned j = 0; j < 6; ++j)
276 {
277 // Find the global edge index
278 unsigned edge_index = Tmp_mesh_pt->edge_index(e, j);
279
280 // Use the intersection of the appropriate faces to determine
281 // whether the boundaries on which an edge lies
282 std::set<unsigned> edge_boundaries;
283 for (unsigned i = 0; i < 2; ++i)
284 {
285 unsigned face_boundary_id =
286 Tmp_mesh_pt->face_boundary(e, faces_on_edge[j][i]);
287 if (face_boundary_id > 0)
288 {
290 }
291 }
292
293 // If the nodes on the edge have not been allocated, construct them
294 if (nodes_on_global_edge[edge_index].size() == 0)
295 {
296 // Now loop over the nodes on the edge
297 for (unsigned j2 = 0; j2 < n_node_1d - 2; ++j2)
298 {
299 // Storage for the new node
300 Node* new_node_pt = 0;
301
302 // If the edge is on a boundary, determined from the
303 // scaffold mesh, construct a boundary node
304 // The use of the scaffold mesh's edge_boundary data structure
305 // ensures that a boundary node is created, even if the faces of
306 // the current element do not lie on boundaries
307 if (Tmp_mesh_pt->edge_boundary(edge_index) == true)
308 {
311 // Add it to the boundaries in the set,
312 // remembering to subtract one to get to the oomph-lib numbering
313 // scheme
314 for (std::set<unsigned>::iterator it = edge_boundaries.begin();
315 it != edge_boundaries.end();
316 ++it)
317 {
318 this->add_boundary_node((*it) - 1, new_node_pt);
319 }
320 }
321 // Otherwise construct a normal node
322 else
323 {
325 }
326
327 // Find the local coordinates of the node
329
330 // Find the coordinates of the new node from the exiting and
331 // fully-functional element in the scaffold mesh
332 for (unsigned i = 0; i < dim; ++i)
333 {
335 }
336
337 // Add the newly created node to the global node list
338 Node_pt.push_back(new_node_pt);
339 // Add to the edge index
340 nodes_on_global_edge[edge_index].push_back(new_node_pt);
341 // Increment the local node number
342 ++n;
343 } // end of loop over edge nodes
344 }
345 // Otherwise just set the pointers (orientation assumed the same)
346 else
347 {
348 for (unsigned j2 = 0; j2 < n_node_1d - 2; ++j2)
349 {
350 elem_pt->node_pt(n) = nodes_on_global_edge[edge_index][j2];
351 // It is possible that the edge may be on additional boundaries
352 // through another element
353 // So add again (note that this function will not add to
354 // boundaries twice)
355 for (std::set<unsigned>::iterator it = edge_boundaries.begin();
356 it != edge_boundaries.end();
357 ++it)
358 {
359 this->add_boundary_node((*it) - 1, elem_pt->node_pt(n));
360 }
361 ++n;
362 }
363 }
364 } // End of loop over edges
365
366 // Deal with enriched elements
367 if (n_node == 15)
368 {
369 // Now loop over the faces
370 for (unsigned j = 0; j < 4; ++j)
371 {
372 // Find the boundary id of the face (need to map between node
373 // numbers and the face)
374 boundary_id = Tmp_mesh_pt->face_boundary(e, face_map[j]);
375
376 // Find the global face index (need to map between node numbers and
377 // the face)
378 unsigned face_index = Tmp_mesh_pt->face_index(e, face_map[j]);
379
380 // If the nodes on the face have not been allocated
381 if (nodes_on_global_face[face_index].size() == 0)
382 {
383 // Storage for the new node
384 Node* new_node_pt = 0;
385
386 // If the face is on a boundary, construct a boundary node
387 if (boundary_id > 0)
388 {
391 // Add it to the boundary
392 this->add_boundary_node(boundary_id - 1, new_node_pt);
393 }
394 // Otherwise construct a normal node
395 else
396 {
398 }
399
400 // Find the local coordinates of the node
402
403 // Find the coordinates of the new node from the exiting and
404 // fully-functional element in the scaffold mesh
405 for (unsigned i = 0; i < dim; ++i)
406 {
408 }
409
410 // Add the newly created node to the global node list
411 Node_pt.push_back(new_node_pt);
412 // Add to the face index
413 nodes_on_global_face[face_index].push_back(new_node_pt);
414 // Increment the local node number
415 ++n;
416 }
417 // Otherwise just set the single node from the face element
418 else
419 {
420 elem_pt->node_pt(n) = nodes_on_global_face[face_index][0];
421 ++n;
422 }
423 } // end of loop over faces
424
425 // Construct the element's central node, which is not on a boundary
426 {
428 finite_element_pt(e)->construct_node(n, time_stepper_pt);
429 Node_pt.push_back(new_node_pt);
430
431 // Find the local coordinates of the node
433
434 // Find the coordinates of the new node from the existing
435 // and fully-functional element in the scaffold mesh
436 for (unsigned i = 0; i < dim; i++)
437 {
439 }
440 }
441 } // End of enriched case
442
443 } // End of case for edge nodes
444
445 // Now loop over the faces to setup the information about elements
446 // adjacent to the boundary
447 for (unsigned j = 0; j < 4; ++j)
448 {
449 // Find the boundary id of the face
450 boundary_id = Tmp_mesh_pt->face_boundary(e, j);
451
452 if (boundary_id > 0)
453 {
454 Boundary_element_pt[boundary_id - 1].push_back(elem_pt);
455 // Need to put a shift in here because of an inconsistent naming
456 // convention between tetgen and our faces
457 // Tetgen Face 0 is our Face 3
458 // Tetgen Face 1 is our Face 2
459 // Tetgen Face 2 is our Face 1
460 // Tetgen Face 3 is our Face 0
461 Face_index_at_boundary[boundary_id - 1].push_back(3 - j);
462
463 // If using regions set up the boundary information
464 if (use_attributes)
465 {
466 // Element adjacent to boundary
467 Boundary_region_element_pt[boundary_id - 1]
468 [static_cast<unsigned>(
469 Tmp_mesh_pt->element_attribute(e))]
471 // Need to put a shift in here because of an inconsistent naming
472 // convention between triangle and face elements
473 Face_index_region_at_boundary[boundary_id - 1]
474 [static_cast<unsigned>(
475 Tmp_mesh_pt->element_attribute(e))]
476 .push_back(3 - j);
477 }
478 }
479 } // End of loop over faces
480
481 // Lookup scheme has now been setup
482 Lookup_for_elements_next_boundary_is_setup = true;
483
484 // /*
485
486 // //For standard quadratic elements all nodes are edge nodes
487 // unsigned n_vertex_and_edge_node = n_node;
488 // //If we have enriched elements, there are only 10 vertex and edge
489 // nodes if(n_node==15)
490 // {
491 // //There are only 10 vertex and edge nodes
492 // n_vertex_and_edge_node = 10;
493 // }
494
495 // // Loop over the new (edge) nodes in the element and create them.
496 // for(unsigned j=4;j<n_vertex_and_edge_node;j++)
497 // {
498
499 // // Figure out edge nodes
500 // switch(j)
501 // {
502
503 // // Node 4 is between nodes 0 and 1
504 // case 4:
505
506 // edge_node1_pt=Tmp_mesh_pt->finite_element_pt(e)->node_pt(0);
507 // edge_node2_pt=Tmp_mesh_pt->finite_element_pt(e)->node_pt(1);
508 // break;
509
510 // // Node 5 is between nodes 0 and 2
511 // case 5:
512
513 // edge_node1_pt=Tmp_mesh_pt->finite_element_pt(e)->node_pt(0);
514 // edge_node2_pt=Tmp_mesh_pt->finite_element_pt(e)->node_pt(2);
515 // break;
516
517 // // Node 6 is between nodes 0 and 3
518 // case 6:
519
520 // edge_node1_pt=Tmp_mesh_pt->finite_element_pt(e)->node_pt(0);
521 // edge_node2_pt=Tmp_mesh_pt->finite_element_pt(e)->node_pt(3);
522 // break;
523
524 // // Node 7 is between nodes 1 and 2
525 // case 7:
526
527 // edge_node1_pt=Tmp_mesh_pt->finite_element_pt(e)->node_pt(1);
528 // edge_node2_pt=Tmp_mesh_pt->finite_element_pt(e)->node_pt(2);
529 // break;
530
531 // // Node 8 is between nodes 2 and 3
532 // case 8:
533
534 // edge_node1_pt=Tmp_mesh_pt->finite_element_pt(e)->node_pt(2);
535 // edge_node2_pt=Tmp_mesh_pt->finite_element_pt(e)->node_pt(3);
536 // break;
537
538 // // Node 9 is between nodes 1 and 3
539 // case 9:
540
541 // edge_node1_pt=Tmp_mesh_pt->finite_element_pt(e)->node_pt(1);
542 // edge_node2_pt=Tmp_mesh_pt->finite_element_pt(e)->node_pt(3);
543 // break;
544
545 // break;
546
547 // //Error
548 // default:
549
550 // throw OomphLibError("More than ten edge nodes in Tet Element",
551 // OOMPH_CURRENT_FUNCTION,
552 // OOMPH_EXCEPTION_LOCATION);
553 // }
554
555 // // Do we need a boundary node?
556 // bool need_boundary_node=false;
557
558 // // hierher At some point fine tune via intersection of boundary
559 // sets if
560 // (edge_node1_pt->is_on_boundary()&&edge_node2_pt->is_on_boundary())
561 // {
562 // need_boundary_node=true;
563 // }
564
565 // // Do we need a new node?
566 // if (central_edge_node_pt(edge_node1_pt,edge_node2_pt)==0)
567 // {
568 // Node* new_node_pt=0;
569
570 // // Create new boundary node
571 // if (need_boundary_node)
572 // {
573 // new_node_pt=finite_element_pt(e)->
574 // construct_boundary_node(j,time_stepper_pt);
575 // }
576 // // Create new normal node
577 // else
578 // {
579 // new_node_pt=finite_element_pt(e)->
580 // construct_node(j,time_stepper_pt);
581 // }
582 // Node_pt.push_back(new_node_pt);
583
584 // // Now indicate existence of newly created mideside node in map
585 // central_edge_node_pt(edge_node1_pt,edge_node2_pt)=new_node_pt;
586 // central_edge_node_pt(edge_node2_pt,edge_node1_pt)=new_node_pt;
587
588 // // What are the node's local coordinates?
589 // finite_element_pt(e)->local_coordinate_of_node(j,s);
590
591 // // Find the coordinates of the new node from the existing
592 // // and fully-functional element in the scaffold mesh
593 // for(unsigned i=0;i<dim;i++)
594 // {
595 // new_node_pt->x(i)=
596 // Tmp_mesh_pt->finite_element_pt(e)->interpolated_x(s,i);
597 // }
598 // }
599 // else
600 // {
601 // // Set pointer to the existing node
602 // finite_element_pt(e)->node_pt(j)=
603 // central_edge_node_pt(edge_node1_pt,edge_node2_pt);
604 // }
605
606 // } // end of loop over new nodes
607
608 // //Need to sort out the face nodes
609 // if(n_node==15)
610 // {
611 // // Loop over the new (face) nodes in the element and create them.
612 // for(unsigned j=10;j<14;j++)
613 // {
614 // //Empty the set of face nodes
615 // face_nodes_pt.clear();
616 // // Figure out face nodes
617 // switch(j)
618 // {
619
620 // // Node 10 is between nodes 0 and 1 and 3
621 // case 10:
622
623 // face_nodes_pt.insert(Tmp_mesh_pt->finite_element_pt(e)->node_pt(0));
624 // face_nodes_pt.insert(Tmp_mesh_pt->finite_element_pt(e)->node_pt(1));
625 // face_nodes_pt.insert(Tmp_mesh_pt->finite_element_pt(e)->node_pt(3));
626 // break;
627
628 // // Node 11 is between nodes 0 and 1 and 2
629 // case 11:
630
631 // face_nodes_pt.insert(Tmp_mesh_pt->finite_element_pt(e)->node_pt(0));
632 // face_nodes_pt.insert(Tmp_mesh_pt->finite_element_pt(e)->node_pt(1));
633 // face_nodes_pt.insert(Tmp_mesh_pt->finite_element_pt(e)->node_pt(2));
634 // break;
635
636 // // Node 12 is between nodes 0 and 2 and 3
637 // case 12:
638
639 // face_nodes_pt.insert(Tmp_mesh_pt->finite_element_pt(e)->node_pt(0));
640 // face_nodes_pt.insert(Tmp_mesh_pt->finite_element_pt(e)->node_pt(2));
641 // face_nodes_pt.insert(Tmp_mesh_pt->finite_element_pt(e)->node_pt(3));
642 // break;
643
644 // // Node 13 is between nodes 1 and 2 and 3
645 // case 13:
646
647 // face_nodes_pt.insert(Tmp_mesh_pt->finite_element_pt(e)->node_pt(1));
648 // face_nodes_pt.insert(Tmp_mesh_pt->finite_element_pt(e)->node_pt(2));
649 // face_nodes_pt.insert(Tmp_mesh_pt->finite_element_pt(e)->node_pt(3));
650 // break;
651
652 // //Error
653 // default:
654
655 // throw OomphLibError("More than four face nodes in Tet Element",
656 // OOMPH_CURRENT_FUNCTION,
657 // OOMPH_EXCEPTION_LOCATION);
658 // }
659
660 // // Do we need a boundary node?
661 // bool need_boundary_node=false;
662
663 // //Work it out from the face boundary
664 // boundary_id = Tmp_mesh_pt->face_boundary(e,face_map[j-10]);
665 // //If it's non-zero then we do need to create a boundary node
666 // if(boundary_id!=0) {need_boundary_node=true;}
667
668 // // Do we need a new node?
669 // if (central_face_node_pt[face_nodes_pt]==0)
670 // {
671 // Node* new_node_pt=0;
672
673 // // Create a new boundary node
674 // if (need_boundary_node)
675 // {
676 // new_node_pt=finite_element_pt(e)->
677 // construct_boundary_node(j,time_stepper_pt);
678 // //Add it to the boundary
679 // add_boundary_node(boundary_id-1,new_node_pt);
680 // }
681 // // Create new normal node
682 // else
683 // {
684 // new_node_pt=finite_element_pt(e)->
685 // construct_node(j,time_stepper_pt);
686 // }
687 // Node_pt.push_back(new_node_pt);
688
689 // // Now indicate existence of newly created mideside node in map
690 // central_face_node_pt[face_nodes_pt]=new_node_pt;
691
692 // // What are the node's local coordinates?
693 // finite_element_pt(e)->local_coordinate_of_node(j,s);
694
695 // // Find the coordinates of the new node from the existing
696 // // and fully-functional element in the scaffold mesh
697 // for(unsigned i=0;i<dim;i++)
698 // {
699 // new_node_pt->x(i)=
700 // Tmp_mesh_pt->finite_element_pt(e)->interpolated_x(s,i);
701 // }
702 // }
703 // else
704 // {
705 // // Set pointer to the existing node
706 // finite_element_pt(e)->node_pt(j)=
707 // central_face_node_pt[face_nodes_pt];
708 // }
709 // } //End of loop over face nodes
710
711 // //Construct the element's central node, which is not on a boundary
712 // {
713 // Node* new_node_pt=
714 // finite_element_pt(e)->construct_node(14,time_stepper_pt);
715 // Node_pt.push_back(new_node_pt);
716
717 // // What are the node's local coordinates?
718 // finite_element_pt(e)->local_coordinate_of_node(14,s);
719 // // Find the coordinates of the new node from the existing
720 // // and fully-functional element in the scaffold mesh
721 // for(unsigned i=0;i<dim;i++)
722 // {
723 // new_node_pt->x(i)=
724 // Tmp_mesh_pt->finite_element_pt(e)->interpolated_x(s,i);
725 // }
726 // }
727 // } //End of enriched case
728
729 // } //end of loop over elements
730
731 // //Boundary conditions
732
733 // // Matrix map to check if a node has already been added to
734 // // the boundary number b
735 // MapMatrixMixed<Node*,unsigned,bool> bound_node_done;
736
737 // // Loop over elements
738 // for (unsigned e=0;e<nelem;e++)
739 // {
740 // // Loop over new local nodes
741 // for(unsigned j=4;j<n_node;j++)
742 // {
743 // // Pointer to the element's local node
744 // Node* loc_node_pt=finite_element_pt(e)->node_pt(j);
745
746 // // This will have to be changed for higher-order elements
747 // //=======================================================
748
749 // // These are the face nodes on the element's face 0:
750 // if ( (j==4) || (j==5) || (j==7) )
751 // {
752 // boundary_id=Tmp_mesh_pt->face_boundary(e,0);
753 // if (boundary_id!=0)
754 // {
755 // if (!bound_node_done(loc_node_pt,boundary_id-1))
756 // {
757 // add_boundary_node(boundary_id-1,loc_node_pt);
758 // bound_node_done(loc_node_pt,boundary_id-1)=true;
759 // }
760 // }
761 // }
762
763 // // These are the face nodes on the element's face 1:
764 // if ( (j==4) || (j==6) || (j==9) )
765 // {
766 // boundary_id=Tmp_mesh_pt->face_boundary(e,1);
767 // if (boundary_id!=0)
768 // {
769 // if (!bound_node_done(loc_node_pt,boundary_id-1))
770 // {
771 // add_boundary_node(boundary_id-1,loc_node_pt);
772 // bound_node_done(loc_node_pt,boundary_id-1)=true;
773 // }
774 // }
775 // }
776
777 // // These are the face nodes on the element's face 2:
778 // if ( (j==5) || (j==6) || (j==8) )
779 // {
780 // boundary_id=Tmp_mesh_pt->face_boundary(e,2);
781 // if (boundary_id!=0)
782 // {
783 // if (!bound_node_done(loc_node_pt,boundary_id-1))
784 // {
785 // add_boundary_node(boundary_id-1,loc_node_pt);
786 // bound_node_done(loc_node_pt,boundary_id-1)=true;
787 // }
788 // }
789 // }
790
791 // // These are the face nodes on the element's face 3:
792 // if ( (j==7) || (j==8) || (j==9) )
793 // {
794 // boundary_id=Tmp_mesh_pt->face_boundary(e,3);
795 // if (boundary_id!=0)
796 // {
797 // if (!bound_node_done(loc_node_pt,boundary_id-1))
798 // {
799 // add_boundary_node(boundary_id-1,loc_node_pt);
800 // bound_node_done(loc_node_pt,boundary_id-1)=true;
801 // }
802 // }
803 // }
804
805 // } //end for j
806
807 // */
808
809 } // end for e
810
811 } // end function
812
813 //=====================================================================
814 /// Helper function to set up the reverse look up scheme for facets.
815 /// This is used to set up boundary coordinates.
816 //=====================================================================
817 template<class ELEMENT>
820 {
821 // Set up reverse lookup scheme for a given faceted surface
822 // Assumption is that there there is one boundary ID per facet.
823 unsigned n_facet = faceted_surface_pt->nfacet();
824 for (unsigned f = 0; f < n_facet; f++)
825 {
826 unsigned b = faceted_surface_pt->one_based_facet_boundary_id(f);
827 if (b != 0)
828 {
829 this->Tet_mesh_faceted_surface_pt[b - 1] = faceted_surface_pt;
830 this->Tet_mesh_facet_pt[b - 1] = faceted_surface_pt->facet_pt(f);
831 }
832 else
833 {
834 std::ostringstream error_message;
835 error_message << "Boundary IDs have to be one-based. Yours is " << b
836 << "\n";
837 throw OomphLibError(error_message.str(),
840 }
841 }
842 }
843
844
845 ///////////////////////////////////////////////////////////////////////
846 ///////////////////////////////////////////////////////////////////////
847 ///////////////////////////////////////////////////////////////////////
848
849 //=========================================================================
850 /// Transfer tetgenio data from the input to the output
851 /// The output is assumed to have been constructed and "empty"
852 //=========================================================================
853 template<class ELEMENT>
856 {
857 // Copy data values
858 output_pt->firstnumber = input_pt->firstnumber;
859 output_pt->mesh_dim = input_pt->mesh_dim;
860 output_pt->useindex = input_pt->useindex;
861
862 // Copy the number of points
863 output_pt->numberofpoints = input_pt->numberofpoints;
864 output_pt->numberofpointattributes = input_pt->numberofpointattributes;
865 output_pt->numberofpointmtrs = input_pt->numberofpointmtrs;
866
867 const int n_point = output_pt->numberofpoints;
868 if (n_point > 0)
869 {
870 output_pt->pointlist = new double[n_point * 3];
871 // Copy the values
872 for (int n = 0; n < (n_point * 3); ++n)
873 {
874 output_pt->pointlist[n] = input_pt->pointlist[n];
875 }
876
877 // If there are point markers copy as well
878 if (input_pt->pointmarkerlist != (int*)NULL)
879 {
880 output_pt->pointmarkerlist = new int[n_point];
881 for (int n = 0; n < n_point; ++n)
882 {
883 output_pt->pointmarkerlist[n] = input_pt->pointmarkerlist[n];
884 }
885 }
886
887 const int n_attr = output_pt->numberofpointattributes;
888 if (n_attr > 0)
889 {
890 output_pt->pointattributelist = new double[n_point * n_attr];
891 for (int n = 0; n < (n_point * n_attr); ++n)
892 {
893 output_pt->pointattributelist[n] = input_pt->pointattributelist[n];
894 }
895 }
896 } // End of point case
897
898 // Now add in metric tensors (if there are any)
899 const int n_point_mtr = output_pt->numberofpointmtrs;
900 if (n_point_mtr > 0)
901 {
902 output_pt->pointmtrlist = new double[n_point * n_point_mtr];
903 for (int n = 0; n < (n_point * n_point_mtr); ++n)
904 {
905 output_pt->pointmtrlist[n] = input_pt->pointmtrlist[n];
906 }
907 }
908
909 // Next tetrahedrons
910 output_pt->numberoftetrahedra = input_pt->numberoftetrahedra;
911 output_pt->numberofcorners = input_pt->numberofcorners;
912 output_pt->numberoftetrahedronattributes =
913 input_pt->numberoftetrahedronattributes;
914
915 const int n_tetra = output_pt->numberoftetrahedra;
916 const int n_corner = output_pt->numberofcorners;
917 if (n_tetra > 0)
918 {
919 output_pt->tetrahedronlist = new int[n_tetra * n_corner];
920 for (int n = 0; n < (n_tetra * n_corner); ++n)
921 {
922 output_pt->tetrahedronlist[n] = input_pt->tetrahedronlist[n];
923 }
924
925 // Add in the volume constriants
926 if (input_pt->tetrahedronvolumelist != (double*)NULL)
927 {
928 output_pt->tetrahedronvolumelist = new double[n_tetra];
929 for (int n = 0; n < n_tetra; ++n)
930 {
931 output_pt->tetrahedronvolumelist[n] =
932 input_pt->tetrahedronvolumelist[n];
933 }
934 }
935
936 // Add in the attributes
937 const int n_tetra_attr = output_pt->numberoftetrahedronattributes;
938 if (n_tetra_attr > 0)
939 {
940 output_pt->tetrahedronattributelist =
941 new double[n_tetra * n_tetra_attr];
942 for (int n = 0; n < (n_tetra * n_tetra_attr); ++n)
943 {
944 output_pt->tetrahedronattributelist[n] =
945 input_pt->tetrahedronattributelist[n];
946 }
947 }
948
949 // Add in the neighbour list
950 if (input_pt->neighborlist != (int*)NULL)
951 {
952 output_pt->neighborlist = new int[n_tetra * 4];
953 for (int n = 0; n < (n_tetra * 4); ++n)
954 {
955 output_pt->neighborlist = input_pt->neighborlist;
956 }
957 }
958 } // End of tetrahedron section
959
960 // Now arrange the facet list
961 output_pt->numberoffacets = input_pt->numberoffacets;
962 const int n_facet = output_pt->numberoffacets;
963 if (n_facet > 0)
964 {
965 output_pt->facetlist = new tetgenio::facet[n_facet];
966 for (int n = 0; n < n_facet; ++n)
967 {
968 tetgenio::facet* input_f_pt = &input_pt->facetlist[n];
969 tetgenio::facet* output_f_pt = &output_pt->facetlist[n];
970
971 // Copy polygons and holes from the facets
972 output_f_pt->numberofpolygons = input_f_pt->numberofpolygons;
973
974 // Loop over polygons
975 const int n_poly = output_f_pt->numberofpolygons;
976 if (n_poly > 0)
977 {
978 output_f_pt->polygonlist = new tetgenio::polygon[n_poly];
979 for (int p = 0; p < n_poly; ++p)
980 {
981 tetgenio::polygon* output_p_pt = &output_f_pt->polygonlist[p];
982 tetgenio::polygon* input_p_pt = &input_f_pt->polygonlist[p];
983 // Find out how many vertices each polygon has
984 output_p_pt->numberofvertices = input_p_pt->numberofvertices;
985 // Now copy of the vertices
986 const int n_vertex = output_p_pt->numberofvertices;
987 if (n_vertex > 0)
988 {
989 output_p_pt->vertexlist = new int[n_vertex];
990 for (int v = 0; v < n_vertex; ++v)
991 {
992 output_p_pt->vertexlist[v] = input_p_pt->vertexlist[v];
993 }
994 }
995 }
996 }
997
998 // Hole information
999 output_f_pt->numberofholes = input_f_pt->numberofholes;
1000 const int n_hole = output_f_pt->numberofholes;
1001 if (n_hole > 0)
1002 {
1003 throw OomphLibError("Don't know how to handle holes yet\n",
1006 }
1007 } // end of loop over facets
1008
1009 // Add the facetmarkers if there are any
1010 if (input_pt->facetmarkerlist != (int*)NULL)
1011 {
1012 output_pt->facetmarkerlist = new int[n_facet];
1013 for (int n = 0; n < n_facet; ++n)
1014 {
1015 output_pt->facetmarkerlist[n] = input_pt->facetmarkerlist[n];
1016 }
1017 }
1018 }
1019
1020 // Now the holes
1021 output_pt->numberofholes = input_pt->numberofholes;
1022 const int n_hole = output_pt->numberofholes;
1023 if (n_hole > 0)
1024 {
1025 output_pt->holelist = new double[n_hole * 3];
1026 for (int n = 0; n < (n_hole * 3); ++n)
1027 {
1028 output_pt->holelist[n] = input_pt->holelist[n];
1029 }
1030 }
1031
1032 // Now the regions
1033 output_pt->numberofregions = input_pt->numberofregions;
1034 const int n_region = output_pt->numberofregions;
1035 if (n_region > 0)
1036 {
1037 output_pt->regionlist = new double[n_region * 5];
1038 for (int n = 0; n < (n_region * 5); ++n)
1039 {
1040 output_pt->regionlist[n] = input_pt->regionlist[n];
1041 }
1042 }
1043
1044 // Now the facet constraints
1045 output_pt->numberoffacetconstraints = input_pt->numberoffacetconstraints;
1046 const int n_facet_const = output_pt->numberoffacetconstraints;
1047 if (n_facet_const > 0)
1048 {
1049 output_pt->facetconstraintlist = new double[n_facet_const * 2];
1050 for (int n = 0; n < (n_facet_const * 2); ++n)
1051 {
1052 output_pt->facetconstraintlist[n] = input_pt->facetconstraintlist[n];
1053 }
1054 }
1055
1056 // Now the segment constraints
1057 output_pt->numberofsegmentconstraints =
1058 input_pt->numberofsegmentconstraints;
1059 const int n_seg_const = output_pt->numberofsegmentconstraints;
1060 if (n_seg_const > 0)
1061 {
1062 output_pt->segmentconstraintlist = new double[n_seg_const * 2];
1063 for (int n = 0; n < (n_seg_const * 2); ++n)
1064 {
1065 output_pt->segmentconstraintlist[n] =
1066 input_pt->segmentconstraintlist[n];
1067 }
1068 }
1069
1070 // Now the face list
1071 output_pt->numberoftrifaces = input_pt->numberoftrifaces;
1072 const int n_tri_face = output_pt->numberoftrifaces;
1073 if (n_tri_face > 0)
1074 {
1075 output_pt->trifacelist = new int[n_tri_face * 3];
1076 for (int n = 0; n < (n_tri_face * 3); ++n)
1077 {
1078 output_pt->trifacelist[n] = input_pt->trifacelist[n];
1079 }
1080
1081 output_pt->trifacemarkerlist = new int[n_tri_face];
1082 for (int n = 0; n < n_tri_face; ++n)
1083 {
1084 output_pt->trifacemarkerlist[n] = input_pt->trifacemarkerlist[n];
1085 }
1086 }
1087
1088 // Now the edge list
1089 output_pt->numberofedges = input_pt->numberofedges;
1090 const int n_edge = output_pt->numberofedges;
1091 if (n_edge > 0)
1092 {
1093 output_pt->edgelist = new int[n_edge * 2];
1094 for (int n = 0; n < (n_edge * 2); ++n)
1095 {
1096 output_pt->edgelist[n] = input_pt->edgelist[n];
1097 }
1098
1099 output_pt->edgemarkerlist = new int[n_edge];
1100 for (int n = 0; n < n_edge; ++n)
1101 {
1102 output_pt->edgemarkerlist[n] = input_pt->edgemarkerlist[n];
1103 }
1104 }
1105 }
1106
1107} // namespace oomph
1108#endif
e
Definition cfortran.h:571
static char t char * s
Definition cfortran.h:568
cstr elem_len * i
Definition cfortran.h:603
A general Finite Element class.
Definition elements.h:1317
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
double size() const
Calculate the size of the element (length, area, volume,...) in Eulerian computational coordinates....
Definition elements.cc:4320
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
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
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....
TAdvectionDiffusionReactionElement<NREAGENT,DIM,NNODE_1D> elements are isoparametric triangular DIM-d...
TAdvectionDiffusionReactionElement()
Constructor: Call constructors for TElement and AdvectionDiffusionReaction equations.
Base class for tet mesh boundary defined by polygonal planar facets.
Definition tet_mesh.h:306
void build_from_scaffold(TimeStepper *time_stepper_pt, const bool &use_attributes)
Build mesh from scaffold.
void setup_reverse_lookup_schemes_for_faceted_surface(TetMeshFacetedSurface *const &faceted_surface_pt)
Function to setup the reverse look-up schemes.
void deep_copy_of_tetgenio(tetgenio *const &input_pt, tetgenio *&output_pt)
Transfer tetgenio data from the input to the output The output is assumed to have been constructed an...
Base class for time-stepping schemes. Timestepper provides an approximation of the temporal derivativ...
DRAIG: Change all instances of (SPATIAL_DIM) to (DIM-1).