Chaste Release::3.1
TetrahedralMesh.cpp
00001 /*
00002 
00003 Copyright (c) 2005-2012, University of Oxford.
00004 All rights reserved.
00005 
00006 University of Oxford means the Chancellor, Masters and Scholars of the
00007 University of Oxford, having an administrative office at Wellington
00008 Square, Oxford OX1 2JD, UK.
00009 
00010 This file is part of Chaste.
00011 
00012 Redistribution and use in source and binary forms, with or without
00013 modification, are permitted provided that the following conditions are met:
00014  * Redistributions of source code must retain the above copyright notice,
00015    this list of conditions and the following disclaimer.
00016  * Redistributions in binary form must reproduce the above copyright notice,
00017    this list of conditions and the following disclaimer in the documentation
00018    and/or other materials provided with the distribution.
00019  * Neither the name of the University of Oxford nor the names of its
00020    contributors may be used to endorse or promote products derived from this
00021    software without specific prior written permission.
00022 
00023 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00024 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00025 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00026 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
00027 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00028 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
00029 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00030 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00031 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
00032 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00033 
00034 */
00035 
00036 #include "TetrahedralMesh.hpp"
00037 
00038 #include <iostream>
00039 #include <cassert>
00040 #include <sstream>
00041 #include <map>
00042 
00043 #include "BoundaryElement.hpp"
00044 #include "Element.hpp"
00045 #include "Exception.hpp"
00046 #include "Node.hpp"
00047 #include "OutputFileHandler.hpp"
00048 #include "PetscTools.hpp"
00049 #include "RandomNumberGenerator.hpp"
00050 #include "Warnings.hpp"
00051 
00052 // Jonathan Shewchuk's triangle and Hang Si's tetgen
00053 #define REAL double
00054 #define VOID void
00055 #include "triangle.h"
00056 #include "tetgen.h"
00057 #undef REAL
00058 #undef VOID
00059 
00060 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00061 TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::TetrahedralMesh()
00062 {
00063     Clear();
00064 }
00065 
00066 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00067 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ConstructFromMeshReader(
00068     AbstractMeshReader<ELEMENT_DIM, SPACE_DIM>& rMeshReader)
00069 {
00070     this->mMeshFileBaseName = rMeshReader.GetMeshFileBaseName();
00071 
00072     // Record number of corner nodes
00073     unsigned num_nodes = rMeshReader.GetNumNodes();
00074 
00075     /*
00076      * Reserve memory for nodes, so we don't have problems with
00077      * pointers stored in elements becoming invalid.
00078      */
00079     this->mNodes.reserve(num_nodes);
00080 
00081     rMeshReader.Reset();
00082 
00083     //typename std::map<std::pair<unsigned,unsigned>,unsigned>::const_iterator iterator;
00084     //std::map<std::pair<unsigned,unsigned>,unsigned> internal_nodes_map;
00085 
00086     // Add nodes
00087     std::vector<double> coords;
00088     for (unsigned i=0; i < num_nodes; i++)
00089     {
00090         coords = rMeshReader.GetNextNode();
00091         Node<SPACE_DIM>* p_node = new Node<SPACE_DIM>(i, coords, false);
00092 
00093         for (unsigned i=0; i<rMeshReader.GetNodeAttributes().size(); i++)
00094         {
00095             double attribute = rMeshReader.GetNodeAttributes()[i];
00096             p_node->AddNodeAttribute(attribute);
00097         }
00098 
00099         this->mNodes.push_back(p_node);
00100     }
00101 
00102     //unsigned new_node_index = mNumCornerNodes;
00103 
00104     rMeshReader.Reset();
00105     // Add elements
00106     //new_node_index = mNumCornerNodes;
00107     this->mElements.reserve(rMeshReader.GetNumElements());
00108 
00109     for (unsigned element_index=0; element_index < (unsigned) rMeshReader.GetNumElements(); element_index++)
00110     {
00111         ElementData element_data = rMeshReader.GetNextElementData();
00112         std::vector<Node<SPACE_DIM>*> nodes;
00113 
00114         /*
00115          * NOTE: currently just reading element vertices from mesh reader - even if it
00116          * does contain information about internal nodes (ie for quadratics) this is
00117          * ignored here and used elsewhere: ie don't do this:
00118          *   unsigned nodes_size = node_indices.size();
00119          */
00120         for (unsigned j=0; j<ELEMENT_DIM+1; j++) // num vertices=ELEMENT_DIM+1, may not be equal to nodes_size.
00121         {
00122             assert(element_data.NodeIndices[j] <  this->mNodes.size());
00123             nodes.push_back(this->mNodes[element_data.NodeIndices[j]]);
00124         }
00125 
00126         Element<ELEMENT_DIM,SPACE_DIM>* p_element = new Element<ELEMENT_DIM,SPACE_DIM>(element_index, nodes);
00127         this->mElements.push_back(p_element);
00128 
00129         if (rMeshReader.GetNumElementAttributes() > 0)
00130         {
00131             assert(rMeshReader.GetNumElementAttributes() == 1);
00132             double attribute_value = element_data.AttributeValue;
00133             p_element->SetAttribute(attribute_value);
00134         }
00135     }
00136 
00137     // Add boundary elements and nodes
00138     for (unsigned face_index=0; face_index<(unsigned)rMeshReader.GetNumFaces(); face_index++)
00139     {
00140         ElementData face_data = rMeshReader.GetNextFaceData();
00141         std::vector<unsigned> node_indices = face_data.NodeIndices;
00142 
00143         /*
00144          * NOTE: unlike the above where we just read element *vertices* from mesh reader, here we are
00145          * going to read a quadratic mesh with internal elements.
00146          * (There are only a few meshes with internals in the face file that we might as well use them.)
00147          *
00148          */
00149         std::vector<Node<SPACE_DIM>*> nodes;
00150         for (unsigned node_index=0; node_index<node_indices.size(); node_index++)
00151         {
00152             assert(node_indices[node_index] < this->mNodes.size());
00153             // Add Node pointer to list for creating an element
00154             nodes.push_back(this->mNodes[node_indices[node_index]]);
00155         }
00156 
00157         // This is a boundary face, so ensure all its nodes are marked as boundary nodes
00158         for (unsigned j=0; j<nodes.size(); j++)
00159         {
00160             if (!nodes[j]->IsBoundaryNode())
00161             {
00162                 nodes[j]->SetAsBoundaryNode();
00163                 this->mBoundaryNodes.push_back(nodes[j]);
00164             }
00165 
00166             // Register the index that this bounday element will have with the node
00167             nodes[j]->AddBoundaryElement(face_index);
00168         }
00169 
00170         // The added elements will be deleted in our destructor
00171         BoundaryElement<ELEMENT_DIM-1,SPACE_DIM>* p_boundary_element = new BoundaryElement<ELEMENT_DIM-1,SPACE_DIM>(face_index, nodes);
00172         this->mBoundaryElements.push_back(p_boundary_element);
00173 
00174         if (rMeshReader.GetNumFaceAttributes() > 0)
00175         {
00176             assert(rMeshReader.GetNumFaceAttributes() == 1);
00177             double attribute_value = face_data.AttributeValue;
00178             p_boundary_element->SetAttribute(attribute_value);
00179         }
00180     }
00181 
00182     RefreshJacobianCachedData();
00183     rMeshReader.Reset();
00184 }
00185 
00186 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00187 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ReadNodesPerProcessorFile(const std::string& rNodesPerProcessorFile)
00188 {
00189     std::vector<unsigned> nodes_per_processor_vec;
00190 
00191     std::ifstream file_stream(rNodesPerProcessorFile.c_str());
00192     if (file_stream.is_open())
00193     {
00194         while (file_stream)
00195         {
00196             unsigned nodes_per_processor;
00197             file_stream >> nodes_per_processor;
00198 
00199             if (file_stream)
00200             {
00201                 nodes_per_processor_vec.push_back(nodes_per_processor);
00202             }
00203         }
00204     }
00205     else
00206     {
00207         EXCEPTION("Unable to read nodes per processor file " + rNodesPerProcessorFile);
00208     }
00209 
00210     unsigned sum = 0;
00211     for (unsigned i=0; i<nodes_per_processor_vec.size(); i++)
00212     {
00213         sum += nodes_per_processor_vec[i];
00214     }
00215 
00216     if (sum != this->GetNumNodes())
00217     {
00218         EXCEPTION("Sum of nodes per processor, " << sum
00219                      << ", not equal to number of nodes in mesh, " << this->GetNumNodes());
00220     }
00221 
00222     unsigned num_owned=nodes_per_processor_vec[PetscTools::GetMyRank()];
00223 
00224     if (nodes_per_processor_vec.size() != PetscTools::GetNumProcs())
00225     {
00226         EXCEPTION("Number of processes doesn't match the size of the nodes-per-processor file");
00227     }
00228     delete this->mpDistributedVectorFactory;
00229     this->mpDistributedVectorFactory = new DistributedVectorFactory(this->GetNumNodes(), num_owned);
00230 }
00231 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00232 bool TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::CheckIsConforming()
00233 {
00234     /*
00235      * Each face of each element is a set of node indices.
00236      * We form a set of these in order to get their parity:
00237      *   all faces which appear once are inserted into the set;
00238      *   all faces which appear twice are inserted and then removed from the set;
00239      *   we're assuming that faces never appear more than twice.
00240      */
00241     std::set< std::set<unsigned> > odd_parity_faces;
00242 
00243     for (typename AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ElementIterator iter = this->GetElementIteratorBegin();
00244          iter != this->GetElementIteratorEnd();
00245          ++iter)
00246     {
00247         for (unsigned face_index=0; face_index<=ELEMENT_DIM; face_index++)
00248         {
00249             std::set<unsigned> face_info;
00250             for (unsigned node_index=0; node_index<=ELEMENT_DIM; node_index++)
00251             {
00252                 // Leave one index out each time
00253                 if (node_index != face_index)
00254                 {
00255                     face_info.insert(iter->GetNodeGlobalIndex(node_index));
00256                 }
00257             }
00258             // Face is now formed - attempt to find it
00259             std::set< std::set<unsigned> >::iterator find_face=odd_parity_faces.find(face_info);
00260             if (find_face != odd_parity_faces.end())
00261             {
00262                 // Face was in set, so it now has even parity.
00263                 // Remove it via the iterator
00264                 odd_parity_faces.erase(find_face);
00265             }
00266             else
00267             {
00268                 // Face is not in set so it now has odd parity. Insert it
00269                 odd_parity_faces.insert(face_info);
00270             }
00271 
00272         }
00273     }
00274 
00275     /*
00276      * At this point the odd parity faces should be the same as the
00277      * boundary elements. We could check this explicitly or we could
00278      * just count them.
00279      */
00280     return(odd_parity_faces.size() == this->GetNumBoundaryElements());
00281 }
00282 
00283 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00284 double TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::GetVolume()
00285 {
00286     double mesh_volume = 0.0;
00287 
00288     for (typename AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ElementIterator iter = this->GetElementIteratorBegin();
00289          iter != this->GetElementIteratorEnd();
00290          ++iter)
00291     {
00292         mesh_volume += iter->GetVolume(mElementJacobianDeterminants[iter->GetIndex()]);
00293     }
00294 
00295     return mesh_volume;
00296 }
00297 
00298 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00299 double TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::GetSurfaceArea()
00300 {
00301     // ELEMENT_DIM-1 is the dimension of the boundary element
00302     assert(ELEMENT_DIM >= 1);
00303     const unsigned bound_element_dim = ELEMENT_DIM-1;
00304     assert(bound_element_dim < 3);
00305     if ( bound_element_dim == 0)
00306     {
00307         return 0.0;
00308     }
00309 
00310     double mesh_surface = 0.0;
00311     typename TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::BoundaryElementIterator it = this->GetBoundaryElementIteratorBegin();
00312 
00313     while (it != this->GetBoundaryElementIteratorEnd())
00314     {
00315         mesh_surface += mBoundaryElementJacobianDeterminants[(*it)->GetIndex()];
00316         it++;
00317     }
00318 
00319     if ( bound_element_dim == 2)
00320     {
00321         mesh_surface /= 2.0;
00322     }
00323 
00324     return mesh_surface;
00325 }
00326 
00327 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00328 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::PermuteNodes()
00329 {
00330     // Make a permutation vector of the identity
00331     RandomNumberGenerator* p_rng = RandomNumberGenerator::Instance();
00332     std::vector<unsigned> perm;
00333     p_rng->Shuffle(this->mNodes.size(), perm);
00334 
00335     // Call the non-random version
00336     PermuteNodes(perm);
00337 }
00338 
00339 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00340 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::PermuteNodes(const std::vector<unsigned>& perm)
00341 {
00342     // Let's not do this if there are any deleted nodes
00343     assert( this->GetNumAllNodes() == this->GetNumNodes());
00344 
00345     assert(perm.size() == this->mNodes.size());
00346 
00347     // Copy the node pointers
00348     std::vector< Node<SPACE_DIM>* > copy_m_nodes;
00349     copy_m_nodes.assign(this->mNodes.begin(), this->mNodes.end());
00350 
00351     for (unsigned original_index=0; original_index<this->mNodes.size(); original_index++)
00352     {
00353         assert(perm[original_index] < this->mNodes.size());
00354         //perm[original_index] holds the new assigned index of that node
00355         this->mNodes[ perm[original_index] ] = copy_m_nodes[original_index];
00356     }
00357 
00358     // Update indices
00359     for (unsigned index=0; index<this->mNodes.size(); index++)
00360     {
00361         this->mNodes[index]->SetIndex(index);
00362     }
00363 
00364     // Copy the permutation vector into the mesh
00365     this->mNodesPermutation = perm;
00366 }
00367 
00368 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00369 unsigned TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::GetContainingElementIndex(const ChastePoint<SPACE_DIM>& rTestPoint,
00370                                                                             bool strict,
00371                                                                             std::set<unsigned> testElements,
00372                                                                             bool onlyTryWithTestElements)
00373 {
00374     for (std::set<unsigned>::iterator iter=testElements.begin(); iter!=testElements.end(); iter++)
00375     {
00376         assert(*iter<this->GetNumElements());
00377         if (this->mElements[*iter]->IncludesPoint(rTestPoint, strict))
00378         {
00379             assert(!this->mElements[*iter]->IsDeleted());
00380             return *iter;
00381         }
00382     }
00383 
00384     if (!onlyTryWithTestElements)
00385     {
00386         for (unsigned i=0; i<this->mElements.size(); i++)
00387         {
00388             if (this->mElements[i]->IncludesPoint(rTestPoint, strict))
00389             {
00390                 assert(!this->mElements[i]->IsDeleted());
00391                 return i;
00392             }
00393         }
00394     }
00395 
00396     // If it's in none of the elements, then throw
00397     std::stringstream ss;
00398     ss << "Point [";
00399     for (unsigned j=0; (int)j<(int)SPACE_DIM-1; j++)
00400     {
00401         ss << rTestPoint[j] << ",";
00402     }
00403     ss << rTestPoint[SPACE_DIM-1] << "] is not in ";
00404     if (!onlyTryWithTestElements)
00405     {
00406         ss << "mesh - all elements tested";
00407     }
00408     else
00409     {
00410         ss << "set of elements given";
00411     }
00412     EXCEPTION(ss.str());
00413 }
00414 
00415 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00416 unsigned TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::GetContainingElementIndexWithInitialGuess(const ChastePoint<SPACE_DIM>& rTestPoint, unsigned startingElementGuess, bool strict)
00417 {
00418     assert(startingElementGuess<this->GetNumElements());
00419 
00420     /*
00421      * Let m=startingElementGuess, N=num_elem-1.
00422      * We search from in this order: m, m+1, m+2, .. , N, 0, 1, .., m-1.
00423      */
00424     unsigned i = startingElementGuess;
00425     bool reached_end = false;
00426 
00427     while (!reached_end)
00428     {
00429         if (this->mElements[i]->IncludesPoint(rTestPoint, strict))
00430         {
00431             assert(!this->mElements[i]->IsDeleted());
00432             return i;
00433         }
00434 
00435         // Increment
00436         i++;
00437         if (i==this->GetNumElements())
00438         {
00439             i=0;
00440         }
00441 
00442         // Back to the beginning yet?
00443         if (i==startingElementGuess)
00444         {
00445             reached_end = true;
00446         }
00447     }
00448 
00449     // If it's in none of the elements, then throw
00450     std::stringstream ss;
00451     ss << "Point [";
00452     for (unsigned j=0; (int)j<(int)SPACE_DIM-1; j++)
00453     {
00454         ss << rTestPoint[j] << ",";
00455     }
00456     ss << rTestPoint[SPACE_DIM-1] << "] is not in mesh - all elements tested";
00457     EXCEPTION(ss.str());
00458 }
00459 
00460 
00461 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00462 unsigned TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::GetNearestElementIndex(const ChastePoint<SPACE_DIM>& rTestPoint)
00463 {
00464     double max_min_weight = -INFINITY;
00465     unsigned closest_index = 0;
00466     for (unsigned i=0; i<this->mElements.size(); i++)
00467     {
00468         c_vector<double, ELEMENT_DIM+1> weight=this->mElements[i]->CalculateInterpolationWeights(rTestPoint);
00469         double neg_weight_sum=0.0;
00470         for (unsigned j=0; j<=ELEMENT_DIM; j++)
00471         {
00472             if (weight[j] < 0.0)
00473             {
00474                 neg_weight_sum += weight[j];
00475             }
00476         }
00477         if (neg_weight_sum > max_min_weight)
00478         {
00479             max_min_weight = neg_weight_sum;
00480             closest_index = i;
00481         }
00482     }
00483     assert(!this->mElements[closest_index]->IsDeleted());
00484     return closest_index;
00485 }
00486 
00487 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00488 unsigned TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::GetNearestElementIndexFromTestElements(const ChastePoint<SPACE_DIM>& rTestPoint,
00489                                                                                          std::set<unsigned> testElements)
00490 {
00491     assert(testElements.size() > 0);
00492 
00493     double max_min_weight = -INFINITY;
00494     unsigned closest_index = 0;
00495     for (std::set<unsigned>::iterator iter = testElements.begin();
00496         iter != testElements.end();
00497         iter++)
00498     {
00499         c_vector<double, ELEMENT_DIM+1> weight=this->mElements[*iter]->CalculateInterpolationWeights(rTestPoint);
00500         double neg_weight_sum=0.0;
00501         for (unsigned j=0; j<=ELEMENT_DIM; j++)
00502         {
00503             if (weight[j] < 0.0)
00504             {
00505                 neg_weight_sum += weight[j];
00506             }
00507         }
00508         if (neg_weight_sum > max_min_weight)
00509         {
00510             max_min_weight = neg_weight_sum;
00511             closest_index = *iter;
00512         }
00513     }
00514     assert(!this->mElements[closest_index]->IsDeleted());
00515     return closest_index;
00516 }
00517 
00518 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00519 std::vector<unsigned> TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::GetContainingElementIndices(const ChastePoint<SPACE_DIM> &rTestPoint)
00520 {
00521     std::vector<unsigned> element_indices;
00522     for (unsigned i=0; i<this->mElements.size(); i++)
00523     {
00524         if (this->mElements[i]->IncludesPoint(rTestPoint))
00525         {
00526             assert(!this->mElements[i]->IsDeleted());
00527             element_indices.push_back(i);
00528         }
00529     }
00530     return element_indices;
00531 }
00532 
00533 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00534 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::Clear()
00535 {
00536     // Three loops, just like the destructor. note we don't delete boundary nodes.
00537     for (unsigned i=0; i<this->mBoundaryElements.size(); i++)
00538     {
00539         delete this->mBoundaryElements[i];
00540     }
00541     for (unsigned i=0; i<this->mElements.size(); i++)
00542     {
00543         delete this->mElements[i];
00544     }
00545     for (unsigned i=0; i<this->mNodes.size(); i++)
00546     {
00547         delete this->mNodes[i];
00548     }
00549 
00550     this->mNodes.clear();
00551     this->mElements.clear();
00552     this->mBoundaryElements.clear();
00553     this->mBoundaryNodes.clear();
00554 }
00555 
00556 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00557 std::set<unsigned> TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::CalculateBoundaryOfFlaggedRegion()
00558 {
00559     // A set of nodes which lie on the face, size 3 in 2D, size 4 in 3D
00560     typedef std::set<unsigned> FaceNodes;
00561 
00562     /*
00563      * Face maps to true the first time it is encountered, and false subsequent
00564      * times. Thus, faces mapping to true at the end are boundary faces.
00565      */
00566     std::map<FaceNodes,bool> face_on_boundary;
00567 
00568     // Loop over all elements
00569     for (typename AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ElementIterator iter = this->GetElementIteratorBegin();
00570          iter != this->GetElementIteratorEnd();
00571          ++iter)
00572     {
00573         if (iter->IsFlagged())
00574         {
00575             // To get faces, initially start with all nodes
00576             std::set<unsigned> all_nodes;
00577             for (unsigned i=0; i<ELEMENT_DIM+1; i++)
00578             {
00579                 all_nodes.insert(iter->GetNodeGlobalIndex(i));
00580             }
00581 
00582             // Remove one node in turn to obtain each face
00583             for (unsigned i=0; i<ELEMENT_DIM+1; i++)
00584             {
00585                 FaceNodes face_nodes = all_nodes;
00586                 face_nodes.erase(iter->GetNodeGlobalIndex(i));
00587 
00588                 // Search the map of faces to see if it contains this face
00589                 std::map<FaceNodes,bool>::iterator it = face_on_boundary.find(face_nodes);
00590 
00591                 if (it == face_on_boundary.end())
00592                 {
00593                     // Face not found, add and assume on boundary
00594                     face_on_boundary[face_nodes]=true;
00595                 }
00596                 else
00597                 {
00598                     // Face found in map, so not on boundary
00599                     it->second = false;
00600                 }
00601             }
00602         }
00603     }
00604 
00605     // Boundary nodes to be returned
00606     std::set<unsigned> boundary_of_flagged_region;
00607 
00608     // Get all faces in the map
00609     std::map<FaceNodes,bool>::iterator it=face_on_boundary.begin();
00610     while (it!=face_on_boundary.end())
00611     {
00612         // If the face maps to true it is on the boundary
00613         if (it->second==true)
00614         {
00615             // Get all nodes in the face and put in set to be returned
00616             boundary_of_flagged_region.insert(it->first.begin(),it->first.end());
00617         }
00618         it++;
00619     }
00620 
00621     return boundary_of_flagged_region;
00622 }
00623 
00624 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00625 double TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::GetAngleBetweenNodes(unsigned indexA, unsigned indexB)
00626 {
00627     assert(SPACE_DIM == 2);
00628     assert(SPACE_DIM == ELEMENT_DIM);
00629 
00630     double x_difference = this->mNodes[indexB]->rGetLocation()[0] - this->mNodes[indexA]->rGetLocation()[0];
00631     double y_difference = this->mNodes[indexB]->rGetLocation()[1] - this->mNodes[indexA]->rGetLocation()[1];
00632 
00633     if (x_difference == 0)
00634     {
00635         if (y_difference > 0)
00636         {
00637             return M_PI/2.0;
00638         }
00639         else if (y_difference < 0)
00640         {
00641             return -M_PI/2.0;
00642         }
00643         else
00644         {
00645             EXCEPTION("Tried to compute polar angle of (0,0)");
00646         }
00647     }
00648 
00649     double angle = atan2(y_difference,x_difference);
00650     return angle;
00651 }
00652 
00653 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00654 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::UnflagAllElements()
00655 {
00656     for (typename AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ElementIterator iter = this->GetElementIteratorBegin();
00657          iter != this->GetElementIteratorEnd();
00658          ++iter)
00659     {
00660         iter->Unflag();
00661     }
00662 }
00663 
00664 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00665 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::FlagElementsNotContainingNodes(std::set<unsigned> nodesList)
00666 {
00667     for (typename AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ElementIterator iter = this->GetElementIteratorBegin();
00668          iter != this->GetElementIteratorEnd();
00669          ++iter)
00670     {
00671         bool found_node = false;
00672 
00673         for (unsigned i=0; i<iter->GetNumNodes(); i++)
00674         {
00675             unsigned node_index = iter->GetNodeGlobalIndex(i);
00676 
00677             std::set<unsigned>::iterator set_iter = nodesList.find(node_index);
00678             if (set_iter != nodesList.end())
00679             {
00680                 found_node = true;
00681             }
00682         }
00683 
00684         if (!found_node)
00685         {
00686             iter->Flag();
00687         }
00688     }
00689 }
00690 
00692 //                          Edge iterator class                             //
00694 
00695 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00696 Node<SPACE_DIM>* TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::EdgeIterator::GetNodeA()
00697 {
00698     assert((*this) != mrMesh.EdgesEnd());
00699     Element<ELEMENT_DIM,SPACE_DIM>* p_element = mrMesh.GetElement(mElemIndex);
00700     return p_element->GetNode(mNodeALocalIndex);
00701 }
00702 
00703 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00704 Node<SPACE_DIM>* TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::EdgeIterator::GetNodeB()
00705 {
00706     assert((*this) != mrMesh.EdgesEnd());
00707     Element<ELEMENT_DIM,SPACE_DIM>* p_element = mrMesh.GetElement(mElemIndex);
00708     return p_element->GetNode(mNodeBLocalIndex);
00709 }
00710 
00711 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00712 bool TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::EdgeIterator::operator!=(const TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::EdgeIterator& rOther)
00713 {
00714     return (mElemIndex != rOther.mElemIndex ||
00715             mNodeALocalIndex != rOther.mNodeALocalIndex ||
00716             mNodeBLocalIndex != rOther.mNodeBLocalIndex);
00717 }
00718 
00719 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00720 typename TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::EdgeIterator& TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::EdgeIterator::operator++()
00721 {
00722     bool already_seen_this_edge;
00723 
00724     unsigned num_elements = mrMesh.GetNumAllElements();
00725     std::pair<unsigned, unsigned> current_node_pair;
00726     do
00727     {
00728         /*
00729          * Advance to the next edge in the mesh.
00730          * Node indices are incremented modulo #nodes_per_elem.
00731          */
00732         mNodeBLocalIndex = (mNodeBLocalIndex + 1) % (ELEMENT_DIM+1);
00733         if (mNodeBLocalIndex == mNodeALocalIndex)
00734         {
00735             mNodeALocalIndex = (mNodeALocalIndex + 1) % (ELEMENT_DIM+1);
00736             mNodeBLocalIndex = (mNodeALocalIndex + 1) % (ELEMENT_DIM+1);
00737         }
00738 
00739         if (mNodeALocalIndex == 0 && mNodeBLocalIndex == 1) // advance to next element...
00740         {
00741             // ...skipping deleted ones
00742             do
00743             {
00744                 mElemIndex++;
00745             }
00746             while (mElemIndex!=num_elements && mrMesh.GetElement(mElemIndex)->IsDeleted());
00747         }
00748 
00749         if (mElemIndex != num_elements)
00750         {
00751             Element<ELEMENT_DIM, SPACE_DIM>* p_element = mrMesh.GetElement(mElemIndex);
00752             unsigned node_a_global_index = p_element->GetNodeGlobalIndex(mNodeALocalIndex);
00753             unsigned node_b_global_index = p_element->GetNodeGlobalIndex(mNodeBLocalIndex);
00754             if (node_b_global_index < node_a_global_index)
00755             {
00756                 // Swap them over
00757                 unsigned temp = node_a_global_index;
00758                 node_a_global_index = node_b_global_index;
00759                 node_b_global_index = temp;
00760             }
00761 
00762             // Check we haven't seen it before
00763             current_node_pair = std::pair<unsigned, unsigned>(node_a_global_index, node_b_global_index);
00764             already_seen_this_edge = (mEdgesVisited.count(current_node_pair) != 0);
00765         }
00766         else
00767         {
00768             already_seen_this_edge = false;
00769         }
00770     }
00771 
00772     while (already_seen_this_edge);
00773     mEdgesVisited.insert(current_node_pair);
00774 
00775     return (*this);
00776 }
00777 
00778 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00779 TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::EdgeIterator::EdgeIterator(TetrahedralMesh& rMesh, unsigned elemIndex)
00780     : mrMesh(rMesh),
00781       mElemIndex(elemIndex),
00782       mNodeALocalIndex(0),
00783       mNodeBLocalIndex(1)
00784 {
00785     if (elemIndex == mrMesh.GetNumAllElements())
00786     {
00787         return;
00788     }
00789 
00790     mEdgesVisited.clear();
00791 
00792     // Add the current node pair to the store
00793     unsigned node_a_global_index = mrMesh.GetElement(mElemIndex)->GetNodeGlobalIndex(mNodeALocalIndex);
00794     unsigned node_b_global_index = mrMesh.GetElement(mElemIndex)->GetNodeGlobalIndex(mNodeBLocalIndex);
00795     if (node_b_global_index < node_a_global_index)
00796     {
00797         // Swap them over
00798         unsigned temp = node_a_global_index;
00799         node_a_global_index = node_b_global_index;
00800         node_b_global_index = temp;
00801     }
00802 
00803     // Check we haven't seen it before
00804     std::pair<unsigned, unsigned> current_node_pair = std::pair<unsigned, unsigned>(node_a_global_index, node_b_global_index);
00805     mEdgesVisited.insert(current_node_pair);
00806 }
00807 
00808 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00809 typename TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::EdgeIterator TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::EdgesBegin()
00810 {
00811     unsigned first_element_index=0;
00812     while (first_element_index!=this->GetNumAllElements() && this->GetElement(first_element_index)->IsDeleted())
00813     {
00814         first_element_index++;
00815     }
00816     return EdgeIterator(*this, first_element_index);
00817 }
00818 
00819 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00820 typename TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::EdgeIterator TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::EdgesEnd()
00821 {
00822     return EdgeIterator(*this, this->GetNumAllElements());
00823 }
00824 
00825 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00826 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::RefreshMesh()
00827 {
00828     RefreshJacobianCachedData();
00829 }
00830 
00831 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00832 unsigned TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::SolveNodeMapping(unsigned index) const
00833 {
00834     assert(index < this->mNodes.size() );
00835     return index;
00836 }
00837 
00838 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00839 unsigned TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::SolveElementMapping(unsigned index) const
00840 {
00841     assert(index < this->mElements.size() );
00842     return index;
00843 }
00844 
00845 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00846 unsigned TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::SolveBoundaryElementMapping(unsigned index) const
00847 {
00848     assert(index < this->mBoundaryElements.size() );
00849     return index;
00850 }
00851 
00852 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00853 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::RefreshJacobianCachedData()
00854 {
00855     unsigned num_elements = this->GetNumAllElements();
00856     unsigned num_boundary_elements = this->GetNumAllBoundaryElements();
00857 
00858     // Make sure we have enough space
00859     this->mElementJacobians.resize(num_elements);
00860     this->mElementInverseJacobians.resize(num_elements);
00861 
00862     if (ELEMENT_DIM < SPACE_DIM)
00863     {
00864         this->mElementWeightedDirections.resize(num_elements);
00865     }
00866 
00867     this->mBoundaryElementWeightedDirections.resize(num_boundary_elements);
00868 
00869     this->mElementJacobianDeterminants.resize(num_elements);
00870     this->mBoundaryElementJacobianDeterminants.resize(num_boundary_elements);
00871 
00872     // Update caches
00873     for (typename AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ElementIterator iter = this->GetElementIteratorBegin();
00874          iter != this->GetElementIteratorEnd();
00875          ++iter)
00876     {
00877         unsigned index = iter->GetIndex();
00878         iter->CalculateInverseJacobian(this->mElementJacobians[index], this->mElementJacobianDeterminants[index], this->mElementInverseJacobians[index]);
00879     }
00880 
00881     if (ELEMENT_DIM < SPACE_DIM)
00882     {
00883         for (typename AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ElementIterator iter = this->GetElementIteratorBegin();
00884              iter != this->GetElementIteratorEnd();
00885              ++iter)
00886         {
00887              unsigned index = iter->GetIndex();
00888              iter->CalculateWeightedDirection(this->mElementWeightedDirections[index], this->mElementJacobianDeterminants[index]);
00889         }
00890     }
00891 
00892     for ( typename TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::BoundaryElementIterator itb = this->GetBoundaryElementIteratorBegin();
00893           itb != this->GetBoundaryElementIteratorEnd();
00894           itb++)
00895     {
00896         unsigned index = (*itb)->GetIndex();
00897         (*itb)->CalculateWeightedDirection(this->mBoundaryElementWeightedDirections[index], this->mBoundaryElementJacobianDeterminants[index]);
00898     }
00899 }
00900 
00901 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00902 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::GetJacobianForElement(unsigned elementIndex, c_matrix<double, SPACE_DIM, SPACE_DIM>& rJacobian, double& rJacobianDeterminant) const
00903 {
00904     assert(ELEMENT_DIM <= SPACE_DIM);
00905     assert(elementIndex < this->mElementJacobians.size());
00906     rJacobian = this->mElementJacobians[elementIndex];
00907     rJacobianDeterminant = this->mElementJacobianDeterminants[elementIndex];
00908 }
00909 
00910 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00911 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::GetInverseJacobianForElement(unsigned elementIndex, c_matrix<double, SPACE_DIM, ELEMENT_DIM>& rJacobian, double& rJacobianDeterminant, c_matrix<double, ELEMENT_DIM, SPACE_DIM>& rInverseJacobian) const
00912 {
00913     assert(ELEMENT_DIM <= SPACE_DIM);
00914     assert(elementIndex < this->mElementInverseJacobians.size());
00915     rInverseJacobian = this->mElementInverseJacobians[elementIndex];
00916     rJacobian = this->mElementJacobians[elementIndex];
00917     rJacobianDeterminant = this->mElementJacobianDeterminants[elementIndex];
00918 }
00919 
00920 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00921 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::GetWeightedDirectionForElement(unsigned elementIndex, c_vector<double, SPACE_DIM>& rWeightedDirection, double& rJacobianDeterminant) const
00922 {
00923     assert(ELEMENT_DIM < SPACE_DIM);
00924     assert(elementIndex < this->mElementWeightedDirections.size());
00925     rWeightedDirection = this->mElementWeightedDirections[elementIndex];
00926     rJacobianDeterminant = this->mElementJacobianDeterminants[elementIndex];
00927 }
00928 
00929 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00930 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::GetWeightedDirectionForBoundaryElement(unsigned elementIndex, c_vector<double, SPACE_DIM>& rWeightedDirection, double& rJacobianDeterminant) const
00931 {
00932     assert(elementIndex < this->mBoundaryElementWeightedDirections.size());
00933     rWeightedDirection = this->mBoundaryElementWeightedDirections[elementIndex];
00934     rJacobianDeterminant = this->mBoundaryElementJacobianDeterminants[elementIndex];
00935 }
00936 
00937 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00938 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::InitialiseTriangulateIo(triangulateio& mesherIo)
00939 {
00940     mesherIo.numberofpoints = 0;
00941     mesherIo.pointlist = NULL;
00942     mesherIo.numberofpointattributes = 0;
00943     mesherIo.pointattributelist = (double *) NULL;
00944     mesherIo.pointmarkerlist = (int *) NULL;
00945     mesherIo.numberofsegments = 0;
00946     mesherIo.numberofholes = 0;
00947     mesherIo.numberofregions = 0;
00948     mesherIo.trianglelist = (int *) NULL;
00949     mesherIo.triangleattributelist = (double *) NULL;
00950     mesherIo.numberoftriangleattributes = 0;
00951     mesherIo.edgelist = (int *) NULL;
00952     mesherIo.edgemarkerlist = (int *) NULL;
00953 }
00954 
00955 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00956 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::FreeTriangulateIo(triangulateio& mesherIo)
00957 {
00958     if (mesherIo.numberofpoints != 0)
00959     {
00960         mesherIo.numberofpoints=0;
00961         free(mesherIo.pointlist);
00962     }
00963 
00964     // These (and the above) should actually be safe since we explicity set to NULL above
00965     free(mesherIo.pointattributelist);
00966     free(mesherIo.pointmarkerlist);
00967     free(mesherIo.trianglelist);
00968     free(mesherIo.triangleattributelist);
00969     free(mesherIo.edgelist);
00970     free(mesherIo.edgemarkerlist);
00971 }
00972 
00973 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00974 template <class MESHER_IO>
00975 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ExportToMesher(NodeMap& map, MESHER_IO& mesherInput, int *elementList)
00976 {
00977     if (SPACE_DIM == 2)
00978     {
00979         mesherInput.pointlist = (double *) malloc(this->GetNumNodes() * SPACE_DIM * sizeof(double));
00980     }
00981     else
00982     {
00983         mesherInput.pointlist = new double[this->GetNumNodes() * SPACE_DIM];
00984     }
00985 
00986     mesherInput.numberofpoints = this->GetNumNodes();
00987     unsigned new_index = 0;
00988     for (unsigned i=0; i<this->GetNumAllNodes(); i++)
00989     {
00990         if (this->mNodes[i]->IsDeleted())
00991         {
00992             map.SetDeleted(i);
00993         }
00994         else
00995         {
00996             map.SetNewIndex(i, new_index);
00997             for (unsigned j=0; j<SPACE_DIM; j++)
00998             {
00999                 mesherInput.pointlist[SPACE_DIM*new_index + j] = this->mNodes[i]->rGetLocation()[j];
01000             }
01001             new_index++;
01002         }
01003     }
01004     if (elementList != NULL)
01005     {
01006         unsigned element_index = 0;
01007 
01008         // Assume there is enough space for this
01009         mesherInput.numberofcorners=ELEMENT_DIM+1;
01010         for (typename TetrahedralMesh<ELEMENT_DIM,SPACE_DIM>::ElementIterator elem_iter = this->GetElementIteratorBegin();
01011              elem_iter != this->GetElementIteratorEnd();
01012              ++elem_iter)
01013         {
01014 
01015             for (unsigned j=0; j<=ELEMENT_DIM; j++)
01016             {
01017                 elementList[element_index*(ELEMENT_DIM+1) + j] = (*elem_iter).GetNodeGlobalIndex(j);
01018             }
01019             element_index++;
01020         }
01021     }
01022 }
01023 
01024 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
01025 template <class MESHER_IO>
01026 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ImportFromMesher(MESHER_IO& mesherOutput, unsigned numberOfElements, int *elementList, unsigned numberOfFaces, int *faceList, int *edgeMarkerList)
01027 {
01028     unsigned nodes_per_element = mesherOutput.numberofcorners;
01029 
01030     assert( nodes_per_element == ELEMENT_DIM+1 || nodes_per_element == (ELEMENT_DIM+1)*(ELEMENT_DIM+2)/2 );
01031 
01032     Clear();
01033 
01034     // Construct the nodes
01035     for (unsigned node_index=0; node_index<(unsigned)mesherOutput.numberofpoints; node_index++)
01036     {
01037         this->mNodes.push_back(new Node<SPACE_DIM>(node_index, &mesherOutput.pointlist[node_index * SPACE_DIM], false));
01038     }
01039 
01040     // Construct the elements
01041     this->mElements.reserve(numberOfElements);
01042 
01043     unsigned real_element_index=0;
01044     for (unsigned element_index=0; element_index<numberOfElements; element_index++)
01045     {
01046         std::vector<Node<SPACE_DIM>*> nodes;
01047         for (unsigned j=0; j<ELEMENT_DIM+1; j++)
01048         {
01049             unsigned global_node_index = elementList[element_index*(nodes_per_element) + j];
01050             assert(global_node_index < this->mNodes.size());
01051             nodes.push_back(this->mNodes[global_node_index]);
01052 
01053         }
01054 
01055         /*
01056          * For some reason, tetgen in library mode makes its initial Delaunay mesh
01057          * with very thin slivers. Hence we expect to ignore some of the elements!
01058          */
01059         Element<ELEMENT_DIM, SPACE_DIM>* p_element;
01060         try
01061         {
01062             p_element = new Element<ELEMENT_DIM, SPACE_DIM>(real_element_index, nodes);
01063 
01064             // Shouldn't throw after this point
01065             this->mElements.push_back(p_element);
01066 
01067             // Add the internals to quadratics
01068             for (unsigned j=ELEMENT_DIM+1; j<nodes_per_element; j++)
01069             {
01070                 unsigned global_node_index = elementList[element_index*nodes_per_element + j];
01071                 assert(global_node_index < this->mNodes.size());
01072                 this->mElements[real_element_index]->AddNode( this->mNodes[global_node_index] );
01073                 this->mNodes[global_node_index]->AddElement(real_element_index);
01074                 this->mNodes[global_node_index]->MarkAsInternal();
01075             }
01076             real_element_index++;
01077         }
01078         catch (Exception &e)
01079         {
01080             if (SPACE_DIM == 2)
01081             {
01082                 WARNING("Triangle has produced a zero area (collinear) element");
01083             }
01084             else
01085             {
01086                 WARNING("Tetgen has produced a zero volume (coplanar) element");
01087             }
01088         }
01089     }
01090 
01091     // Construct the BoundaryElements (and mark boundary nodes)
01092     unsigned next_boundary_element_index = 0;
01093     for (unsigned boundary_element_index=0; boundary_element_index<numberOfFaces; boundary_element_index++)
01094     {
01095         /*
01096          * Tetgen produces only boundary faces (set edgeMarkerList to NULL).
01097          * Triangle marks which edges are on the boundary.
01098          */
01099         if (edgeMarkerList == NULL || edgeMarkerList[boundary_element_index] == 1)
01100         {
01101             std::vector<Node<SPACE_DIM>*> nodes;
01102             for (unsigned j=0; j<ELEMENT_DIM; j++)
01103             {
01104                 unsigned global_node_index = faceList[boundary_element_index*ELEMENT_DIM + j];
01105                 assert(global_node_index < this->mNodes.size());
01106                 nodes.push_back(this->mNodes[global_node_index]);
01107                 if (!nodes[j]->IsBoundaryNode())
01108                 {
01109                     nodes[j]->SetAsBoundaryNode();
01110                     this->mBoundaryNodes.push_back(nodes[j]);
01111                 }
01112             }
01113 
01114             /*
01115              * For some reason, tetgen in library mode makes its initial Delaunay mesh
01116              * with very thin slivers. Hence we expect to ignore some of the elements!
01117              */
01118             BoundaryElement<ELEMENT_DIM-1, SPACE_DIM>* p_b_element;
01119             try
01120             {
01121                 p_b_element = new BoundaryElement<ELEMENT_DIM-1, SPACE_DIM>(next_boundary_element_index, nodes);
01122                 this->mBoundaryElements.push_back(p_b_element);
01123                 next_boundary_element_index++;
01124             }
01125             catch (Exception &e)
01126             {
01127                 // Tetgen is feeding us lies  //Watch this space for coverage
01128                 assert(SPACE_DIM == 3);
01129             }
01130         }
01131     }
01132 
01133     this->RefreshJacobianCachedData();
01134 }
01135 
01137 // Explicit instantiation
01139 
01140 template class TetrahedralMesh<1,1>;
01141 template class TetrahedralMesh<1,2>;
01142 template class TetrahedralMesh<1,3>;
01143 template class TetrahedralMesh<2,2>;
01144 template class TetrahedralMesh<2,3>;
01145 template class TetrahedralMesh<3,3>;
01146 
01151 template void TetrahedralMesh<2,2>::ExportToMesher<triangulateio>(NodeMap&, triangulateio&, int*);
01152 template void TetrahedralMesh<2,2>::ImportFromMesher<triangulateio>(triangulateio&, unsigned, int *, unsigned, int *, int *);
01153 
01154 template void TetrahedralMesh<3,3>::ExportToMesher<tetgen::tetgenio>(NodeMap&, tetgen::tetgenio&, int*);
01155 template void TetrahedralMesh<3,3>::ImportFromMesher<tetgen::tetgenio>(tetgen::tetgenio&, unsigned, int *, unsigned, int *, int *);
01156 
01157 //The following don't ever need to be instantiated, but are needed to keep some compilers happy
01158 template void TetrahedralMesh<1,2>::ExportToMesher<triangulateio>(NodeMap&, triangulateio&, int*);
01159 template void TetrahedralMesh<1,2>::ImportFromMesher<triangulateio>(triangulateio&, unsigned, int *, unsigned, int *, int *);
01160 
01161 template void TetrahedralMesh<1,3>::ExportToMesher<tetgen::tetgenio>(NodeMap&, tetgen::tetgenio&, int*);
01162 template void TetrahedralMesh<1,3>::ImportFromMesher<tetgen::tetgenio>(tetgen::tetgenio&, unsigned, int *, unsigned, int *, int *);
01163 template void TetrahedralMesh<2,3>::ExportToMesher<tetgen::tetgenio>(NodeMap&, tetgen::tetgenio&, int*);
01164 template void TetrahedralMesh<2,3>::ImportFromMesher<tetgen::tetgenio>(tetgen::tetgenio&, unsigned, int *, unsigned, int *, int *);
01165 
01166 //Intel compilation with IPO thinks that it's missing some bizarre instantiations
01167 template void TetrahedralMesh<3u, 3u>::ImportFromMesher<triangulateio>(triangulateio&, unsigned int, int*, unsigned int, int*, int*);
01168 template void TetrahedralMesh<1u, 1u>::ImportFromMesher<triangulateio>(triangulateio&, unsigned int, int*, unsigned int, int*, int*);
01169 template void TetrahedralMesh<1u, 1u>::ImportFromMesher<tetgen::tetgenio>(tetgen::tetgenio&, unsigned int, int*, unsigned int, int*, int*);
01170 template void TetrahedralMesh<2u, 2u>::ImportFromMesher<tetgen::tetgenio>(tetgen::tetgenio&, unsigned int, int*, unsigned int, int*, int*);
01171 template void TetrahedralMesh<1u, 1u>::ExportToMesher<tetgen::tetgenio>(NodeMap&, tetgen::tetgenio&, int*);
01172 
01173 // Intel v11 compilation thinks that it's missing even more bizarre instantiations
01174 //template void TetrahedralMesh<2,2>::ExportToMesher<tetgen::tetgenio>(NodeMap&, tetgen::tetgenio&, int*);
01175 //template void TetrahedralMesh<3,3>::ExportToMesher<triangulateio>(NodeMap&, triangulateio&, int*);
01176 //template void TetrahedralMesh<1,3>::ExportToMesher<triangulateio>(NodeMap&, triangulateio&, int*);
01177 //template void TetrahedralMesh<1,1>::ExportToMesher<triangulateio>(NodeMap&, triangulateio&, int*);
01178 //template void TetrahedralMesh<1,2>::ExportToMesher<tetgen::tetgenio>(NodeMap&, tetgen::tetgenio&, int*);
01179 //template void TetrahedralMesh<2,3>::ExportToMesher<triangulateio>(NodeMap&, triangulateio&, int*);
01180 //template void TetrahedralMesh<1,3>::ImportFromMesher<triangulateio>(triangulateio&, unsigned, int *, unsigned, int *, int *);
01181 //template void TetrahedralMesh<2,3>::ImportFromMesher<triangulateio>(triangulateio&, unsigned, int *, unsigned, int *, int *);
01182 //template void TetrahedralMesh<1,2>::ImportFromMesher<tetgen::tetgenio>(tetgen::tetgenio&, unsigned, int *, unsigned, int *, int *);
01188 // Serialization for Boost >= 1.36
01189 #define CHASTE_SERIALIZATION_CPP
01190 #include "SerializationExportWrapper.hpp"
01191 EXPORT_TEMPLATE_CLASS_ALL_DIMS(TetrahedralMesh)