tetgen_mesh.template.h
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// Version 1.0; svn revision $LastChangedRevision$
7 //LIC//
8 //LIC// $LastChangedDate$
9 //LIC//
10 //LIC// Copyright (C) 2006-2016 Matthias Heil and Andrew Hazel
11 //LIC//
12 //LIC// This library is free software; you can redistribute it and/or
13 //LIC// modify it under the terms of the GNU Lesser General Public
14 //LIC// License as published by the Free Software Foundation; either
15 //LIC// version 2.1 of the License, or (at your option) any later version.
16 //LIC//
17 //LIC// This library is distributed in the hope that it will be useful,
18 //LIC// but WITHOUT ANY WARRANTY; without even the implied warranty of
19 //LIC// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 //LIC// Lesser General Public License for more details.
21 //LIC//
22 //LIC// You should have received a copy of the GNU Lesser General Public
23 //LIC// License along with this library; if not, write to the Free Software
24 //LIC// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 //LIC// 02110-1301 USA.
26 //LIC//
27 //LIC// The authors may be contacted at oomph-lib@maths.man.ac.uk.
28 //LIC//
29 //LIC//====================================================================
30 
31 #ifndef OOMPH_TETGEN_MESH_HEADER
32 #define OOMPH_TETGEN_MESH_HEADER
33 
34 // Config header generated by autoconfig
35 #ifdef HAVE_CONFIG_H
36  #include <oomph-lib-config.h>
37 #endif
38 
39 
40 #ifdef OOMPH_HAS_MPI
41 //mpi headers
42 #include "mpi.h"
43 #endif
44 
45 #include "../generic/tetgen_scaffold_mesh.h"
46 #include "../generic/tet_mesh.h"
47 
48 namespace oomph
49 {
50 
51 //=========start of TetgenMesh class======================================
52 /// \short Unstructured tet mesh based on output from Tetgen:
53 /// http://wias-berlin.de/software/tetgen/
54 //========================================================================
55 template <class ELEMENT>
56 class TetgenMesh : public virtual TetMeshBase
57 {
58 
59 public:
60 
61  /// \short Empty constructor
63  {
64  // Mesh can only be built with 3D Telements.
65  MeshChecker::assert_geometric_element<TElementGeometricBase,ELEMENT>(3);
66  }
67 
68  /// \short Constructor with the input files
69  TetgenMesh(const std::string& node_file_name,
70  const std::string& element_file_name,
71  const std::string& face_file_name,
72  TimeStepper* time_stepper_pt=
73  &Mesh::Default_TimeStepper,
74  const bool &use_attributes=false)
75  : Tetgenio_exists(false),
76  Tetgenio_pt(0)
77  {
78  // Mesh can only be built with 3D Telements.
79  MeshChecker::assert_geometric_element<TElementGeometricBase,ELEMENT>(3);
80 
81  //Store the attributes
82  Use_attributes = use_attributes;
83 
84  // Store timestepper used to build elements
85  Time_stepper_pt = time_stepper_pt;
86 
87  // Build scaffold
88  Tmp_mesh_pt= new
89  TetgenScaffoldMesh(node_file_name,element_file_name,face_file_name);
90 
91  // Convert mesh from scaffold to actual mesh
92  build_from_scaffold(time_stepper_pt,use_attributes);
93 
94  // Kill the scaffold
95  delete Tmp_mesh_pt;
96  Tmp_mesh_pt=0;
97 
98  // Setup boundary coordinates
99  unsigned nb=nboundary();
100  for (unsigned b=0;b<nb;b++)
101  {
102  bool switch_normal=false;
103  setup_boundary_coordinates<ELEMENT>(b,switch_normal);
104  }
105  }
106 
107 
108  /// \short Constructor with tetgenio data structure
109  TetgenMesh(tetgenio& tetgen_data,
110  TimeStepper* time_stepper_pt=
111  &Mesh::Default_TimeStepper,
112  const bool &use_attributes=false)
113 
114  {
115  // Mesh can only be built with 3D Telements.
116  MeshChecker::assert_geometric_element<TElementGeometricBase,ELEMENT>(3);
117 
118  //Store the attributes
119  Use_attributes = use_attributes;
120 
121  // Store timestepper used to build elements
122  Time_stepper_pt = time_stepper_pt;
123 
124  //We do not have a tetgenio representation
125  Tetgenio_exists = false;
126  Tetgenio_pt = 0;
127 
128  // Build scaffold
129  Tmp_mesh_pt= new
130  TetgenScaffoldMesh(tetgen_data);
131 
132  // Convert mesh from scaffold to actual mesh
133  build_from_scaffold(time_stepper_pt,use_attributes);
134 
135  // Kill the scaffold
136  delete Tmp_mesh_pt;
137  Tmp_mesh_pt=0;
138 
139  // Setup boundary coordinates
140  unsigned nb=nboundary();
141  for (unsigned b=0;b<nb;b++)
142  {
143  bool switch_normal=false;
144  setup_boundary_coordinates<ELEMENT>(b,switch_normal);
145  }
146  }
147 
148 
149  /// \short Constructor with the input files. Setting the boolean
150  /// flag to true splits "corner" elements, i.e. elements that
151  /// that have at least three faces on a domain boundary. The
152  /// relevant elements are split without introducing hanging
153  /// nodes so the sons have a "worse" shape than their fathers.
154  /// However, this step avoids otherwise-hard-to-diagnose
155  /// problems in fluids problems where the application of
156  /// boundary conditions at such "corner" elements can
157  /// overconstrain the solution.
158  TetgenMesh(const std::string& node_file_name,
159  const std::string& element_file_name,
160  const std::string& face_file_name,
161  const bool& split_corner_elements,
162  TimeStepper* time_stepper_pt=
163  &Mesh::Default_TimeStepper,
164  const bool &use_attributes=false)
165 
166  {
167  // Mesh can only be built with 3D Telements.
168  MeshChecker::assert_geometric_element<TElementGeometricBase,ELEMENT>(3);
169 
170  //Store the attributes
171  Use_attributes = use_attributes;
172 
173  // Store timestepper used to build elements
174  Time_stepper_pt = time_stepper_pt;
175 
176  // We do not have a tetgenio representation
177  this->Tetgenio_exists = false;
178  this->Tetgenio_pt = 0;
179 
180  // Build scaffold
181  Tmp_mesh_pt= new
182  TetgenScaffoldMesh(node_file_name,element_file_name,face_file_name);
183 
184  // Convert mesh from scaffold to actual mesh
185  build_from_scaffold(time_stepper_pt,use_attributes);
186 
187  // Kill the scaffold
188  delete Tmp_mesh_pt;
189  Tmp_mesh_pt=0;
190 
191  // Split corner elements
192  if (split_corner_elements)
193  {
194  split_elements_in_corners<ELEMENT>();
195  }
196 
197  // Setup boundary coordinates
198  unsigned nb=nboundary();
199  for (unsigned b=0;b<nb;b++)
200  {
201  bool switch_normal=false;
202  setup_boundary_coordinates<ELEMENT>(b,switch_normal);
203  }
204  }
205 
206  /// \short Constructor with tetgen data structure Setting the boolean
207  /// flag to true splits "corner" elements, i.e. elements that
208  /// that have at least three faces on a domain boundary. The
209  /// relevant elements are split without introducing hanging
210  /// nodes so the sons have a "worse" shape than their fathers.
211  /// However, this step avoids otherwise-hard-to-diagnose
212  /// problems in fluids problems where the application of
213  /// boundary conditions at such "corner" elements can
214  /// overconstrain the solution.
215  TetgenMesh(tetgenio &tetgen_data,
216  const bool& split_corner_elements,
217  TimeStepper* time_stepper_pt=
218  &Mesh::Default_TimeStepper,
219  const bool &use_attributes=false)
220 
221  {
222  // Mesh can only be built with 3D Telements.
223  MeshChecker::assert_geometric_element<TElementGeometricBase,ELEMENT>(3);
224 
225  //Store the attributes
226  Use_attributes = use_attributes;
227 
228  // Store timestepper used to build elements
229  Time_stepper_pt = time_stepper_pt;
230 
231  // We do not have a tetgenio representation
232  this->Tetgenio_exists = false;;
233  this->Tetgenio_pt = 0;
234 
235  // Build scaffold
236  Tmp_mesh_pt= new TetgenScaffoldMesh(tetgen_data);
237 
238  // Convert mesh from scaffold to actual mesh
239  build_from_scaffold(time_stepper_pt,use_attributes);
240 
241  // Kill the scaffold
242  delete Tmp_mesh_pt;
243  Tmp_mesh_pt=0;
244 
245  // Split corner elements
246  if (split_corner_elements)
247  {
248  split_elements_in_corners<ELEMENT>();
249  }
250 
251  // Setup boundary coordinates
252  unsigned nb=nboundary();
253  for (unsigned b=0;b<nb;b++)
254  {
255  bool switch_normal=false;
256  setup_boundary_coordinates<ELEMENT>(b,switch_normal);
257  }
258  }
259 
260 
261  /// \short Build mesh, based on a TetgenMeshFactedClosedSurface that specifies
262  /// the outer boundary of the domain and any number of internal
263  /// boundaries, specified by TetMeshFacetedSurfaces.
264  /// Also specify target size for uniform element size.
265  TetgenMesh(TetMeshFacetedClosedSurface* const &outer_boundary_pt,
266  Vector<TetMeshFacetedSurface*>& internal_surface_pt,
267  const double &element_volume,
268  TimeStepper* time_stepper_pt=
269  &Mesh::Default_TimeStepper,
270  const bool &use_attributes=false,
271  const bool& split_corner_elements = false)
272  {
273  // Mesh can only be built with 3D Telements.
274  MeshChecker::assert_geometric_element<TElementGeometricBase,ELEMENT>(3);
275 
276  //Store the attributes
277  Use_attributes = use_attributes;
278 
279  // Store timestepper used to build elements
280  Time_stepper_pt = time_stepper_pt;
281 
282  // Copy across
283  Outer_boundary_pt=outer_boundary_pt;
284 
285  // Setup reverse lookup scheme
286  {
287  unsigned n_facet=Outer_boundary_pt->nfacet();
288  for (unsigned f=0;f<n_facet;f++)
289  {
290  unsigned b=Outer_boundary_pt->one_based_facet_boundary_id(f);
291  if (b!=0)
292  {
293  Tet_mesh_faceted_surface_pt[b-1]=Outer_boundary_pt;
294  Tet_mesh_facet_pt[b-1]=Outer_boundary_pt->facet_pt(f);
295  }
296  else
297  {
298  std::ostringstream error_message;
299  error_message << "Boundary IDs have to be one-based. Yours is "
300  << b << "\n";
301  throw OomphLibError(error_message.str(),
302  OOMPH_CURRENT_FUNCTION,
303  OOMPH_EXCEPTION_LOCATION);
304  }
305  }
306  }
307 
308 
309  //Store the internal boundary
310  Internal_surface_pt = internal_surface_pt;
311 
312  // Setup reverse lookup scheme
313  {
314  unsigned n=Internal_surface_pt.size();
315  for (unsigned i=0;i<n;i++)
316  {
317  unsigned n_facet=Internal_surface_pt[i]->nfacet();
318  for (unsigned f=0;f<n_facet;f++)
319  {
320  unsigned b=Internal_surface_pt[i]->one_based_facet_boundary_id(f);
321  if (b!=0)
322  {
323  Tet_mesh_faceted_surface_pt[b-1]=Internal_surface_pt[i];
324  Tet_mesh_facet_pt[b-1]=Internal_surface_pt[i]->facet_pt(f);
325  }
326  else
327  {
328  std::ostringstream error_message;
329  error_message << "Boundary IDs have to be one-based. Yours is "
330  << b << "\n";
331  throw OomphLibError(error_message.str(),
332  OOMPH_CURRENT_FUNCTION,
333  OOMPH_EXCEPTION_LOCATION);
334  }
335  }
336  }
337  }
338 
339 
340  //Tetgen data structure for the input and output
341  tetgenio in;
342  this->build_tetgenio(outer_boundary_pt,
343  internal_surface_pt,
344  in);
345 
346 
347  //Now tetrahedralise
348  std::stringstream input_string;
349  input_string << "pAa" << element_volume; // Andrew's parameters
350 
351  //input_string << "Vpq1.414Aa" << element_volume;
352  // << "Q"; // Q for quiet!
353  // << "V"; // V for verbose incl. quality output!
354 
355  //If any of the boundaries should not be split add the "Y" flag
356  bool can_boundaries_be_split =
357  outer_boundary_pt->boundaries_can_be_split_in_tetgen();
358  {
359  unsigned n_internal=internal_surface_pt.size();
360  for(unsigned i=0;i<n_internal;i++)
361  {
362  can_boundaries_be_split &=
363  internal_surface_pt[i]->boundaries_can_be_split_in_tetgen();
364  }
365  }
366 
367  //If we can't split the boundaries add the flag
368  if(can_boundaries_be_split==false) {input_string << "Y";}
369 
370  //Now convert to a C-style string
371  char tetswitches[100];
372  sprintf(tetswitches,"%s",input_string.str().c_str());
373 
374  //Make a new tetgen representation
375  this->Tetgenio_exists = true;
376  Tetgenio_pt = new tetgenio;
377  tetrahedralize(tetswitches, &in, this->Tetgenio_pt);
378 
379  // Build scaffold
380  Tmp_mesh_pt= new TetgenScaffoldMesh(*this->Tetgenio_pt);
381 
382  //If any of the objects are different regions then we need to use
383  //the atributes
384  bool regions_exist = false;
385  {
386  unsigned n_internal=internal_surface_pt.size();
387  for(unsigned i=0;i<n_internal;i++)
388  {
389  TetMeshFacetedClosedSurface* srf_pt=
390  dynamic_cast<TetMeshFacetedClosedSurface*>(internal_surface_pt[i]);
391  if (srf_pt!=0)
392  {
393  unsigned n_int_pts=srf_pt->ninternal_point_for_tetgen();
394  for (unsigned j=0;j<n_int_pts;j++)
395  {
396  regions_exist |=
397  srf_pt->internal_point_identifies_region_for_tetgen(j);
398  }
399  }
400  }
401  }
402 
403  //If there are regions, use the attributes
404  if(regions_exist) {Use_attributes=true;}
405 
406  // Convert mesh from scaffold to actual mesh
407  build_from_scaffold(time_stepper_pt,Use_attributes);
408 
409  // Kill the scaffold
410  delete Tmp_mesh_pt;
411  Tmp_mesh_pt=0;
412 
413  // Split corner elements
414  if (split_corner_elements)
415  {
416  split_elements_in_corners<ELEMENT>();
417  }
418 
419  // Setup boundary coordinates
420  unsigned nb=nboundary();
421  for (unsigned b=0;b<nb;b++)
422  {
423  bool switch_normal=false;
424  setup_boundary_coordinates<ELEMENT>(b,switch_normal);
425  }
426 
427  // Now snap onto geometric objects associated with triangular facets
428  // (if any!)
429  snap_nodes_onto_geometric_objects();
430 
431  }
432 
433  ///\short Build tetgenio object from the TetMeshFacetedSurfaces
434  void build_tetgenio(TetMeshFacetedSurface* const &outer_boundary_pt,
435  Vector<TetMeshFacetedSurface*>& internal_surface_pt,
436  tetgenio& tetgen_io)
437  {
438  //Pointer to Tetgen facet
439  tetgenio::facet *f;
440  //Pointer to Tetgen polygon
441  tetgenio::polygon *p;
442 
443  //Start all indices from 1 (it's a choice and we've made it
444  tetgen_io.firstnumber = 1;
445  ///ALH: This may not be needed
446  tetgen_io.useindex = true;
447 
448  //Find the number of internal surfaces
449  const unsigned n_internal = internal_surface_pt.size();
450 
451  //Find the number of points on the outer boundary
452  const unsigned n_outer_vertex = outer_boundary_pt->nvertex();
453  tetgen_io.numberofpoints = n_outer_vertex;
454 
455  //Find the number of points on the inner boundaries and add to the totals
456  Vector<unsigned> n_internal_vertex(n_internal);
457  Vector<unsigned> internal_vertex_offset(n_internal);
458  for(unsigned h=0;h<n_internal;++h)
459  {
460  n_internal_vertex[h] = internal_surface_pt[h]->nvertex();
461  internal_vertex_offset[h] = tetgen_io.numberofpoints;
462  tetgen_io.numberofpoints += n_internal_vertex[h];
463  }
464 
465  //Read the data into the point list
466  tetgen_io.pointlist = new double[tetgen_io.numberofpoints * 3];
467  tetgen_io.pointmarkerlist = new int[tetgen_io.numberofpoints];
468  unsigned counter=0;
469  for(unsigned n=0;n<n_outer_vertex;++n)
470  {
471  for(unsigned i=0;i<3;++i)
472  {
473  tetgen_io.pointlist[counter] =
474  outer_boundary_pt->vertex_coordinate(n,i);
475  ++counter;
476  }
477  }
478  for(unsigned h=0;h<n_internal;++h)
479  {
480  const unsigned n_inner = n_internal_vertex[h];
481  for(unsigned n=0;n<n_inner;++n)
482  {
483  for(unsigned i=0;i<3;++i)
484  {
485  tetgen_io.pointlist[counter] =
486  internal_surface_pt[h]->vertex_coordinate(n,i);
487  ++counter;
488  }
489  }
490  }
491 
492 
493  //Set up the pointmarkers
494  counter=0;
495  for(unsigned n=0;n<n_outer_vertex;++n)
496  {
497  tetgen_io.pointmarkerlist[counter] =
498  outer_boundary_pt->one_based_vertex_boundary_id(n);
499  ++counter;
500  }
501  for(unsigned h=0;h<n_internal;++h)
502  {
503  const unsigned n_inner = n_internal_vertex[h];
504  for(unsigned n=0;n<n_inner;++n)
505  {
506  tetgen_io.pointmarkerlist[counter] =
507  internal_surface_pt[h]->one_based_vertex_boundary_id(n);
508  ++counter;
509  }
510  }
511 
512 
513  //Now the facets
514  unsigned n_outer_facet = outer_boundary_pt->nfacet();
515  tetgen_io.numberoffacets = n_outer_facet;
516  Vector<unsigned> n_inner_facet(n_internal);
517  for(unsigned h=0;h<n_internal;++h)
518  {
519  n_inner_facet[h] = internal_surface_pt[h]->nfacet();
520  tetgen_io.numberoffacets += n_inner_facet[h];
521  }
522 
523  tetgen_io.facetlist = new tetgenio::facet[tetgen_io.numberoffacets];
524  tetgen_io.facetmarkerlist = new int[tetgen_io.numberoffacets];
525 
526 
527  counter=0;
528  for(unsigned n=0;n<n_outer_facet;++n)
529  {
530  //Set pointer to facet
531  f = &tetgen_io.facetlist[counter];
532  f->numberofpolygons = 1;
533  f->polygonlist = new tetgenio::polygon[f->numberofpolygons];
534  f->numberofholes = 0;
535  f->holelist = NULL;
536  p = &f->polygonlist[0];
537 
538  Vector<unsigned> facet = outer_boundary_pt->vertex_index_in_tetgen(n);
539 
540  p->numberofvertices = facet.size();
541  p->vertexlist = new int[p->numberofvertices];
542  for(int i=0;i<p->numberofvertices;++i)
543  {
544  //The offset here is because we have insisted on 1-based indexing
545  p->vertexlist[i] = facet[i] + 1;
546  }
547 
548  //Set up the boundary markers
549  tetgen_io.facetmarkerlist[counter] =
550  outer_boundary_pt->one_based_facet_boundary_id(n);
551  //Increase the counter
552  ++counter;
553  }
554 
555  //Initialise the number of holes
556  tetgen_io.numberofholes=0;
557  //and the number of regions
558  tetgen_io.numberofregions=0;
559 
560  //Loop over the internal stuff
561  for(unsigned h=0;h<n_internal;++h)
562  {
563  for(unsigned n=0;n<n_inner_facet[h];++n)
564  {
565  //Set pointer to facet
566  f = &tetgen_io.facetlist[counter];
567  f->numberofpolygons = 1;
568  f->polygonlist = new tetgenio::polygon[f->numberofpolygons];
569  f->numberofholes = 0;
570  f->holelist = NULL;
571  p = &f->polygonlist[0];
572 
573  Vector<unsigned> facet=internal_surface_pt[h]->vertex_index_in_tetgen(n);
574 
575  p->numberofvertices = facet.size();
576  p->vertexlist = new int[p->numberofvertices];
577  for(int i=0;i<p->numberofvertices;++i)
578  {
579  //Add the 1-based and vertex offsets to get these number correct
580  p->vertexlist[i] = facet[i] + internal_vertex_offset[h] + 1;
581  }
582  //Set up the boundary markers
583  tetgen_io.facetmarkerlist[counter] =
584  internal_surface_pt[h]->one_based_facet_boundary_id(n);
585  ++counter;
586  }
587 
588  //If it's a hole/region add it
589  TetMeshFacetedClosedSurface* srf_pt=
590  dynamic_cast<TetMeshFacetedClosedSurface*>(internal_surface_pt[h]);
591  if (srf_pt!=0)
592  {
593  unsigned n_int_pts=srf_pt->ninternal_point_for_tetgen();
594  for (unsigned j=0;j<n_int_pts;j++)
595  {
596  if (srf_pt->internal_point_identifies_hole_for_tetgen(j))
597  {
598  ++tetgen_io.numberofholes;
599  }
600  //Otherwise it may be region
601  else
602  {
603  if (srf_pt->internal_point_identifies_region_for_tetgen(j))
604  {
605  ++tetgen_io.numberofregions;
606  }
607  }
608  }
609  }
610  }
611 
612  //Set storage for the holes
613  tetgen_io.holelist = new double[3*tetgen_io.numberofholes];
614 
615  //Loop over all the internal boundaries again
616  counter=0;
617  for(unsigned h=0;h<n_internal;++h)
618  {
619  TetMeshFacetedClosedSurface* srf_pt=
620  dynamic_cast<TetMeshFacetedClosedSurface*>(internal_surface_pt[h]);
621  if (srf_pt!=0)
622  {
623  unsigned n_int_pts=srf_pt->ninternal_point_for_tetgen();
624  for (unsigned j=0;j<n_int_pts;j++)
625  {
626  if (srf_pt->internal_point_identifies_hole_for_tetgen(j))
627  {
628  for(unsigned i=0;i<3;++i)
629  {
630  tetgen_io.holelist[counter] =
631  srf_pt->internal_point_for_tetgen(j,i);
632  ++counter;
633  }
634  }
635  }
636  }
637  }
638 
639  //Set storage for the regions
640  tetgen_io.regionlist = new double[5*tetgen_io.numberofregions];
641  //Loop over all the internal boundaries again
642  counter=0;
643  for(unsigned h=0;h<n_internal;++h)
644  {
645  TetMeshFacetedClosedSurface* srf_pt=
646  dynamic_cast<TetMeshFacetedClosedSurface*>(internal_surface_pt[h]);
647  if (srf_pt!=0)
648  {
649  unsigned n_int_pts=srf_pt->ninternal_point_for_tetgen();
650  for (unsigned j=0;j<n_int_pts;j++)
651  {
652  if (srf_pt->internal_point_identifies_region_for_tetgen(j))
653  {
654  for(unsigned i=0;i<3;++i)
655  {
656  tetgen_io.regionlist[counter] =
657  srf_pt->internal_point_for_tetgen(j,i);
658  ++counter;
659  }
660  tetgen_io.regionlist[counter] =
661  static_cast<double>(srf_pt->region_id_for_tetgen(j));
662  ++counter;
663  //Area target
664  tetgen_io.regionlist[counter] = 0.0;
665  ++counter;
666  }
667  }
668  }
669  }
670  }
671 
672 
673  /// Empty destructor
675  {
676  if(Tetgenio_exists)
677  {
678  delete Tetgenio_pt;
679  }
680  }
681 
682 
683  /// \short Overload set_mesh_level_time_stepper so that the stored
684  /// time stepper now corresponds to the new timestepper
685  void set_mesh_level_time_stepper(TimeStepper* const &time_stepper_pt,
686  const bool &preserve_existing_data)
687  {this->Time_stepper_pt = time_stepper_pt;}
688 
689 
690 
691  /// Boolen defining whether tetgenio object has been built or not
692  bool tetgenio_exists() const {return Tetgenio_exists;}
693 
694 
695  /// Access to the triangulateio representation of the mesh
696  tetgenio* &tetgenio_pt() {return Tetgenio_pt;}
697 
698  /// Set the tetgen pointer by a deep copy
699  void set_deep_copy_tetgenio_pt(tetgenio* const &tetgenio_pt)
700  {
701  //Delete the existing data
702  if(Tetgenio_exists) {delete Tetgenio_pt;}
703  this->Tetgenio_pt= new tetgenio;
704  //Create a deep copy of tetgenio_pt and store the result in
705  //Tetgenio_pt
706  this->deep_copy_of_tetgenio(tetgenio_pt,this->Tetgenio_pt);
707  }
708 
709  /// Transfer tetgenio data from the input to the output
710  /// The output is assumed to have been constructed and "empty"
711  void deep_copy_of_tetgenio(tetgenio* const &input_pt,
712  tetgenio* &output_pt);
713 
714 
715 
716 
717  protected:
718 
719  /// Build mesh from scaffold
720  void build_from_scaffold(TimeStepper* time_stepper_pt,
721  const bool &use_attributes);
722 
723  /// Temporary scaffold mesh
724  TetgenScaffoldMesh* Tmp_mesh_pt;
725 
726  /// \short Boolean to indicate whether a tetgenio representation of the
727  /// mesh exists
729 
730  /// \short Tetgen representation of mesh
731  tetgenio* Tetgenio_pt;
732 
733  /// \short Boolean flag to indicate whether to use attributes or not
734  /// (required for multidomain meshes)
736 
737 }; //end class
738 
739 
740 
741 
742 //////////////////////////////////////////////////////////////////
743 //////////////////////////////////////////////////////////////////
744 //////////////////////////////////////////////////////////////////
745 
746 
747 //==============start_mesh=================================================
748 /// Tetgen-based mesh upgraded to become a solid mesh. Automatically
749 /// enumerates all boundaries.
750 //=========================================================================
751 template<class ELEMENT>
752  class SolidTetgenMesh : public virtual TetgenMesh<ELEMENT>,
753  public virtual SolidMesh
754 {
755 
756 public:
757 
758  /// \short Constructor. Boundary coordinates are setup
759  /// automatically.
760  SolidTetgenMesh(const std::string& node_file_name,
761  const std::string& element_file_name,
762  const std::string& face_file_name,
763  const bool& split_corner_elements,
764  TimeStepper* time_stepper_pt=
765  &Mesh::Default_TimeStepper,
766  const bool &use_attributes=false) :
767  TetgenMesh<ELEMENT>(node_file_name, element_file_name,
768  face_file_name, split_corner_elements,
769  time_stepper_pt, use_attributes)
770  {
771  //Assign the Lagrangian coordinates
772  set_lagrangian_nodal_coordinates();
773  }
774 
775  /// \short Constructor. Boundary coordinates are re-setup
776  /// automatically, with the orientation of the outer unit
777  /// normal determined by switch_normal.
778  SolidTetgenMesh(const std::string& node_file_name,
779  const std::string& element_file_name,
780  const std::string& face_file_name,
781  const bool& split_corner_elements,
782  const bool& switch_normal,
783  TimeStepper* time_stepper_pt=
784  &Mesh::Default_TimeStepper,
785  const bool &use_attributes=false) :
786  TetgenMesh<ELEMENT>(node_file_name, element_file_name,
787  face_file_name, split_corner_elements,
788  time_stepper_pt, use_attributes)
789  {
790  //Assign the Lagrangian coordinates
791  set_lagrangian_nodal_coordinates();
792 
793  // Re-setup boundary coordinates for all boundaries with specified
794  // orientation of nnormal
795  unsigned nb=this->nboundary();
796  for (unsigned b=0;b<nb;b++)
797  {
798  this->template setup_boundary_coordinates<ELEMENT>(b,switch_normal);
799  }
800 
801  }
802 
803  /// Empty Destructor
804  virtual ~SolidTetgenMesh() { }
805 
806 };
807 
808 
809 
810 
811 
812 }
813 
814 #endif
void build_from_scaffold(TimeStepper *time_stepper_pt, const bool &use_attributes)
Build mesh from scaffold.
void set_mesh_level_time_stepper(TimeStepper *const &time_stepper_pt, const bool &preserve_existing_data)
Overload set_mesh_level_time_stepper so that the stored time stepper now corresponds to the new times...
TetgenMesh()
Empty constructor.
TetgenScaffoldMesh * Tmp_mesh_pt
Temporary scaffold mesh.
bool Use_attributes
Boolean flag to indicate whether to use attributes or not (required for multidomain meshes) ...
SolidTetgenMesh(const std::string &node_file_name, const std::string &element_file_name, const std::string &face_file_name, const bool &split_corner_elements, TimeStepper *time_stepper_pt=&Mesh::Default_TimeStepper, const bool &use_attributes=false)
Constructor. Boundary coordinates are setup automatically.
~TetgenMesh()
Empty destructor.
TetgenMesh(tetgenio &tetgen_data, TimeStepper *time_stepper_pt=&Mesh::Default_TimeStepper, const bool &use_attributes=false)
Constructor with tetgenio data structure.
bool Tetgenio_exists
Boolean to indicate whether a tetgenio representation of the mesh exists.
Unstructured tet mesh based on output from Tetgen: http://wias-berlin.de/software/tetgen/.
TetgenMesh(const std::string &node_file_name, const std::string &element_file_name, const std::string &face_file_name, const bool &split_corner_elements, TimeStepper *time_stepper_pt=&Mesh::Default_TimeStepper, const bool &use_attributes=false)
Constructor with the input files. Setting the boolean flag to true splits "corner" elements...
void build_tetgenio(TetMeshFacetedSurface *const &outer_boundary_pt, Vector< TetMeshFacetedSurface *> &internal_surface_pt, tetgenio &tetgen_io)
Build tetgenio object from the TetMeshFacetedSurfaces.
SolidTetgenMesh(const std::string &node_file_name, const std::string &element_file_name, const std::string &face_file_name, const bool &split_corner_elements, const bool &switch_normal, TimeStepper *time_stepper_pt=&Mesh::Default_TimeStepper, const bool &use_attributes=false)
Constructor. Boundary coordinates are re-setup automatically, with the orientation of the outer unit ...
void deep_copy_of_tetgenio(tetgenio *const &input_pt, tetgenio *&output_pt)
TetgenMesh(tetgenio &tetgen_data, const bool &split_corner_elements, TimeStepper *time_stepper_pt=&Mesh::Default_TimeStepper, const bool &use_attributes=false)
Constructor with tetgen data structure Setting the boolean flag to true splits "corner" elements...
tetgenio *& tetgenio_pt()
Access to the triangulateio representation of the mesh.
bool tetgenio_exists() const
Boolen defining whether tetgenio object has been built or not.
virtual ~SolidTetgenMesh()
Empty Destructor.
TetgenMesh(const std::string &node_file_name, const std::string &element_file_name, const std::string &face_file_name, TimeStepper *time_stepper_pt=&Mesh::Default_TimeStepper, const bool &use_attributes=false)
Constructor with the input files.
void set_deep_copy_tetgenio_pt(tetgenio *const &tetgenio_pt)
Set the tetgen pointer by a deep copy.
TetgenMesh(TetMeshFacetedClosedSurface *const &outer_boundary_pt, Vector< TetMeshFacetedSurface *> &internal_surface_pt, const double &element_volume, TimeStepper *time_stepper_pt=&Mesh::Default_TimeStepper, const bool &use_attributes=false, const bool &split_corner_elements=false)
Build mesh, based on a TetgenMeshFactedClosedSurface that specifies the outer boundary of the domain ...
tetgenio * Tetgenio_pt
Tetgen representation of mesh.