TetrahedralMesh.cpp

00001 /*
00002 
00003 Copyright (C) University of Oxford, 2005-2009
00004 
00005 University of Oxford means the Chancellor, Masters and Scholars of the
00006 University of Oxford, having an administrative office at Wellington
00007 Square, Oxford OX1 2JD, UK.
00008 
00009 This file is part of Chaste.
00010 
00011 Chaste is free software: you can redistribute it and/or modify it
00012 under the terms of the GNU Lesser General Public License as published
00013 by the Free Software Foundation, either version 2.1 of the License, or
00014 (at your option) any later version.
00015 
00016 Chaste is distributed in the hope that it will be useful, but WITHOUT
00017 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00018 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
00019 License for more details. The offer of Chaste under the terms of the
00020 License is subject to the License being interpreted in accordance with
00021 English Law and subject to any action against the University of Oxford
00022 being under the jurisdiction of the English Courts.
00023 
00024 You should have received a copy of the GNU Lesser General Public License
00025 along with Chaste. If not, see <http://www.gnu.org/licenses/>.
00026 
00027 */
00028 
00029 #include "TetrahedralMesh.hpp"
00030 
00031 #include <iostream>
00032 #include <cassert>
00033 #include <sstream>
00034 #include <map>
00035 
00036 #include "BoundaryElement.hpp"
00037 #include "Element.hpp"
00038 #include "Exception.hpp"
00039 #include "Node.hpp"
00040 #include "OutputFileHandler.hpp"
00041 #include "PetscTools.hpp"
00042 #include "RandomNumberGenerator.hpp"
00043 
00045 //   IMPLEMENTATION
00047 
00048 
00049 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00050 TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::TetrahedralMesh()
00051 {
00052     Clear();
00053 }
00054 
00055 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00056 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ConstructFromMeshReader(
00057     AbstractMeshReader<ELEMENT_DIM, SPACE_DIM>& rMeshReader,
00058     bool cullInternalFaces)
00059 {
00060     if (ELEMENT_DIM==1)
00061     {
00062         cullInternalFaces = true;
00063     }
00064 
00065     this->mMeshFileBaseName = rMeshReader.GetMeshFileBaseName();
00066 
00067     // Record number of corner nodes
00068     unsigned num_nodes = rMeshReader.GetNumNodes();
00069 
00070     // Reserve memory for nodes, so we don't have problems with pointers stored in
00071     // elements becoming invalid.
00072     this->mNodes.reserve(num_nodes);
00073 
00074     rMeshReader.Reset();
00075 
00076     //typename std::map<std::pair<unsigned,unsigned>,unsigned>::const_iterator iterator;
00077     //std::map<std::pair<unsigned,unsigned>,unsigned> internal_nodes_map;
00078 
00079     // Add corner nodes
00080     std::vector<double> coords;
00081     for (unsigned i=0; i < num_nodes; i++)
00082     {
00083         coords = rMeshReader.GetNextNode();
00084         this->mNodes.push_back(new Node<SPACE_DIM>(i, coords, false));
00085     }
00086 
00087     //unsigned new_node_index = mNumCornerNodes;
00088 
00089     rMeshReader.Reset();
00090     // Add elements
00091     //new_node_index = mNumCornerNodes;
00092     this->mElements.reserve(rMeshReader.GetNumElements());
00093 
00094     for (unsigned element_index=0; element_index < (unsigned) rMeshReader.GetNumElements(); element_index++)
00095     {
00096         ElementData element_data = rMeshReader.GetNextElementData();
00097         std::vector<Node<SPACE_DIM>*> nodes;
00098 
00099         // NOTE: currently just reading element vertices from mesh reader - even if it
00100         // does contain information about internal nodes (ie for quadratics) this is
00101         // ignored here and used elsewhere: ie don't do this:
00102         //   unsigned nodes_size = node_indices.size();
00103 
00104         for (unsigned j=0; j<ELEMENT_DIM+1; j++) // num vertices=ELEMENT_DIM+1, may not be equal to nodes_size.
00105         {
00106             assert(element_data.NodeIndices[j] <  this->mNodes.size());
00107             nodes.push_back(this->mNodes[element_data.NodeIndices[j]]);
00108         }
00109 
00110         Element<ELEMENT_DIM,SPACE_DIM> *p_element = new Element<ELEMENT_DIM,SPACE_DIM>(element_index, nodes);
00111         this->mElements.push_back(p_element);
00112 
00113         if (rMeshReader.GetNumElementAttributes() > 0)
00114         {
00115             assert(rMeshReader.GetNumElementAttributes() == 1);
00116             unsigned attribute_value = element_data.AttributeValue;
00117             p_element->SetRegion(attribute_value);
00118         }
00119     }
00120 
00121     // Add boundary elements and nodes
00122     unsigned actual_face_index=0;
00123     for (unsigned face_index=0; face_index<(unsigned)rMeshReader.GetNumFaces(); face_index++)
00124     {
00125         ElementData face_data = rMeshReader.GetNextFaceData();
00126         std::vector<unsigned> node_indices = face_data.NodeIndices;
00127 
00128         // NOTE: as above just read boundary element *vertices* from mesh reader - even if
00129         // it is a quadratic mesh with internal elements, the extra nodes are ignored here 
00130         // and used elsewhere: ie, we don't do this:
00131         //   unsigned nodes_size = node_indices.size();
00132 
00133         bool is_boundary_face = true;
00134 
00135         // Determine if this is a boundary face
00136         std::set<unsigned> containing_element_indices; // Elements that contain this face
00137         std::vector<Node<SPACE_DIM>*> nodes;
00138         for (unsigned node_index=0; node_index<ELEMENT_DIM; node_index++) // node_index from 0 to DIM-1, not 0 to node.size()-1
00139         {
00140             assert(node_indices[node_index] < this->mNodes.size());
00141             // Add Node pointer to list for creating an element
00142             nodes.push_back(this->mNodes[node_indices[node_index]]);
00143 
00144             if (cullInternalFaces)
00145             {
00146                 // Work out what elements contain this face, by taking the intersection
00147                 // of the sets of elements containing each node in the face.
00148                 if (node_index == 0)
00149                 {
00150                     containing_element_indices = nodes[node_index]->rGetContainingElementIndices();
00151                 }
00152                 else
00153                 {
00154                     std::set<unsigned> temp;
00155                     std::set_intersection(nodes[node_index]->rGetContainingElementIndices().begin(),
00156                                           nodes[node_index]->rGetContainingElementIndices().end(),
00157                                           containing_element_indices.begin(), containing_element_indices.end(),
00158                                           std::inserter(temp, temp.begin()));
00159                     containing_element_indices = temp;
00160                 }
00161             }
00162         }
00163 
00164         if (cullInternalFaces)
00165         {
00166             // only if not 1D as this assertion does not apply to quadratic 1D meshes
00167             if (ELEMENT_DIM!=1)
00168             {
00169                 //If the following assertion is thrown, it means that the .edge/.face file does not
00170                 //match the .ele file -- they were generated at separate times.  Simply remove the internal
00171                 //edges/faces by hand.
00172                 assert(containing_element_indices.size() != 0);
00173             }
00174 
00175             // if num_containing_elements is greater than 1, it is not an boundary face
00176             if (containing_element_indices.size() > 1)
00177             {
00178                 is_boundary_face = false;
00179             }
00180 
00181             // in 1D QUADRATICS, all nodes are faces, so internal nodes which don't have any
00182             // containing elements must also be unmarked as a boundary face
00183             if ((ELEMENT_DIM==1) && (containing_element_indices.size()==0))
00184             {
00185                 is_boundary_face = false;
00186             }
00187         }
00188 
00189         if (is_boundary_face)
00190         {
00191             // This is a boundary face
00192             // Ensure all its nodes are marked as boundary nodes
00193             
00194             assert(nodes.size()==ELEMENT_DIM); // just taken vertices of boundary node from 
00195             for (unsigned j=0; j<nodes.size(); j++)
00196             {
00197                 if (!nodes[j]->IsBoundaryNode())
00198                 {
00199                     nodes[j]->SetAsBoundaryNode();
00200                     this->mBoundaryNodes.push_back(nodes[j]);
00201                 }
00202                 //Register the index that this bounday element will have
00203                 //with the node
00204                 nodes[j]->AddBoundaryElement(actual_face_index);
00205             }
00206 
00207             // The added elements will be deleted in our destructor
00208             BoundaryElement<ELEMENT_DIM-1,SPACE_DIM> *p_boundary_element = new BoundaryElement<ELEMENT_DIM-1,SPACE_DIM>(actual_face_index, nodes);
00209             this->mBoundaryElements.push_back(p_boundary_element);
00210 
00211             if (rMeshReader.GetNumFaceAttributes() > 0)
00212             {
00213                 assert(rMeshReader.GetNumFaceAttributes() == 1);
00214                 unsigned attribute_value = face_data.AttributeValue;
00215                 p_boundary_element->SetRegion(attribute_value);
00216             }
00217             actual_face_index++;
00218         }
00219     }
00220 
00221     RefreshJacobianCachedData();
00222 }
00223 
00224 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00225 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ReadNodesPerProcessorFile(const std::string& rNodesPerProcessorFile)
00226 {
00227     std::vector<unsigned> nodes_per_processor_vec;
00228 
00229     std::ifstream file_stream(rNodesPerProcessorFile.c_str());
00230     if (file_stream.is_open())
00231     {
00232         while (file_stream)
00233         {
00234             unsigned nodes_per_processor;
00235             file_stream >> nodes_per_processor;
00236 
00237             if (file_stream)
00238             {
00239                 nodes_per_processor_vec.push_back(nodes_per_processor);
00240             }
00241         }
00242     }
00243     else
00244     {
00245         EXCEPTION("Unable to read nodes per processor file " + rNodesPerProcessorFile);
00246     }
00247 
00248     unsigned sum = 0;
00249     for (unsigned i=0; i<nodes_per_processor_vec.size(); i++)
00250     {
00251         sum += nodes_per_processor_vec[i];
00252     }
00253 
00254     if (sum != this->GetNumNodes())
00255     {
00256         std::stringstream string_stream;
00257         string_stream << "Sum of nodes per processor, " << sum
00258                      << ", not equal to number of nodes in mesh, " << this->GetNumNodes();
00259         EXCEPTION(string_stream.str());
00260     }
00261     
00262     unsigned num_owned=nodes_per_processor_vec[PetscTools::GetMyRank()];
00263     
00264     if (nodes_per_processor_vec.size() != PetscTools::GetNumProcs())
00265     {
00266         EXCEPTION("Number of processes doesn't match the size of the nodes-per-processor file");
00267     }
00268     delete this->mpDistributedVectorFactory;
00269     this->mpDistributedVectorFactory=new DistributedVectorFactory(this->GetNumNodes(), num_owned);
00270 }
00271 
00272 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00273 double TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::GetVolume()
00274 {
00275     double mesh_volume = 0.0;
00276 
00277     for (typename AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ElementIterator iter = this->GetElementIteratorBegin();
00278          iter != this->GetElementIteratorEnd();
00279          ++iter)
00280     {
00281         mesh_volume += iter->GetVolume(mElementJacobianDeterminants[iter->GetIndex()]);
00282     }
00283 
00284     return mesh_volume;
00285 }
00286 
00287 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00288 double TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::GetSurfaceArea()
00289 {
00290     //ELEMENT_DIM-1 is the dimension of the boundary element
00291     assert(ELEMENT_DIM >= 1);
00292     const unsigned bound_element_dim = ELEMENT_DIM-1;
00293     assert(bound_element_dim < 3);
00294     if ( bound_element_dim == 0)
00295     {
00296         return 0.0;
00297     }
00298 
00299     double mesh_surface = 0.0;
00300     typename TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::BoundaryElementIterator it = this->GetBoundaryElementIteratorBegin();
00301 
00302     while (it != this->GetBoundaryElementIteratorEnd())
00303     {
00304         mesh_surface += mBoundaryElementJacobianDeterminants[(*it)->GetIndex()];
00305         it++;
00306     }
00307 
00308     if ( bound_element_dim == 2)
00309     {
00310         mesh_surface /= 2.0;
00311     }
00312 
00313     return mesh_surface;
00314 }
00315 
00316 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00317 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::Translate(
00318     const double xMovement,
00319     const double yMovement,
00320     const double zMovement)
00321 {
00322     c_vector<double, SPACE_DIM> displacement;
00323 
00324     switch (SPACE_DIM)
00325     {
00326         case 3:
00327             displacement[2] = zMovement;
00328         case 2:
00329             displacement[1] = yMovement;
00330         case 1:
00331             displacement[0] = xMovement;
00332     }
00333 
00334     Translate(displacement);
00335 }
00336 
00337 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00338 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::Translate(c_vector<double, SPACE_DIM> transVec)
00339 {
00340     unsigned num_nodes = this->GetNumAllNodes();
00341 
00342     for (unsigned i=0; i<num_nodes; i++)
00343     {
00344         c_vector<double, SPACE_DIM>& r_location = this->mNodes[i]->rGetModifiableLocation();
00345         r_location += transVec;
00346     }
00347 
00348     RefreshMesh();
00349 }
00350 
00351 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00352 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::Rotate(
00353     c_matrix<double , SPACE_DIM, SPACE_DIM> rotationMatrix)
00354 {
00355     unsigned num_nodes = this->GetNumAllNodes();
00356 
00357     for (unsigned i=0; i<num_nodes; i++)
00358     {
00359         c_vector<double, SPACE_DIM>& r_location = this->mNodes[i]->rGetModifiableLocation();
00360         r_location = prod(rotationMatrix, r_location);
00361     }
00362 
00363     RefreshMesh();
00364 }
00365 
00366 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00367 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::Rotate(c_vector<double,3> axis, double angle)
00368 {
00369     assert(SPACE_DIM == 3);
00370     double norm = norm_2(axis);
00371     c_vector<double,3> unit_axis=axis/norm;
00372 
00373     c_matrix<double, SPACE_DIM,SPACE_DIM> rotation_matrix;
00374 
00375     double c = cos(angle);
00376     double s = sin(angle);
00377 
00378     rotation_matrix(0,0) = unit_axis(0)*unit_axis(0)+c*(1-unit_axis(0)*unit_axis(0));
00379     rotation_matrix(0,1) = unit_axis(0)*unit_axis(1)*(1-c) - unit_axis(2)*s;
00380     rotation_matrix(1,0) = unit_axis(0)*unit_axis(1)*(1-c) + unit_axis(2)*s;
00381     rotation_matrix(1,1) = unit_axis(1)*unit_axis(1)+c*(1-unit_axis(1)*unit_axis(1));
00382     rotation_matrix(0,2) = unit_axis(0)*unit_axis(2)*(1-c)+unit_axis(1)*s;
00383     rotation_matrix(1,2) = unit_axis(1)*unit_axis(2)*(1-c)-unit_axis(0)*s;
00384     rotation_matrix(2,0) = unit_axis(0)*unit_axis(2)*(1-c)-unit_axis(1)*s;
00385     rotation_matrix(2,1) = unit_axis(1)*unit_axis(2)*(1-c)+unit_axis(0)*s;
00386     rotation_matrix(2,2) = unit_axis(2)*unit_axis(2)+c*(1-unit_axis(2)*unit_axis(2));
00387 
00388     Rotate(rotation_matrix);
00389 }
00390 
00391 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00392 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::RotateX(const double theta)
00393 {
00394     if (SPACE_DIM != 3)
00395     {
00396         EXCEPTION("This rotation is only valid in 3D");
00397     }
00398     c_matrix<double , SPACE_DIM, SPACE_DIM> x_rotation_matrix=identity_matrix<double>(SPACE_DIM);
00399 
00400     x_rotation_matrix(1,1) = cos(theta);
00401     x_rotation_matrix(1,2) = sin(theta);
00402     x_rotation_matrix(2,1) = -sin(theta);
00403     x_rotation_matrix(2,2) = cos(theta);
00404     Rotate(x_rotation_matrix);
00405 }
00406 
00407 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00408 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::RotateY(const double theta)
00409 {
00410     if (SPACE_DIM != 3)
00411     {
00412         EXCEPTION("This rotation is only valid in 3D");
00413     }
00414     c_matrix<double , SPACE_DIM, SPACE_DIM> y_rotation_matrix=identity_matrix<double>(SPACE_DIM);
00415 
00416     y_rotation_matrix(0,0) = cos(theta);
00417     y_rotation_matrix(0,2) = -sin(theta);
00418     y_rotation_matrix(2,0) = sin(theta);
00419     y_rotation_matrix(2,2) = cos(theta);
00420 
00421 
00422     Rotate(y_rotation_matrix);
00423 }
00424 
00425 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00426 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::RotateZ(const double theta)
00427 {
00428     if (SPACE_DIM < 2)
00429     {
00430         EXCEPTION("This rotation is not valid in less than 2D");
00431     }
00432     c_matrix<double , SPACE_DIM, SPACE_DIM> z_rotation_matrix=identity_matrix<double>(SPACE_DIM);
00433 
00434 
00435     z_rotation_matrix(0,0) = cos(theta);
00436     z_rotation_matrix(0,1) = sin(theta);
00437     z_rotation_matrix(1,0) = -sin(theta);
00438     z_rotation_matrix(1,1) = cos(theta);
00439 
00440     Rotate(z_rotation_matrix);
00441 }
00442 
00443 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00444 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::Rotate(double theta)
00445 {
00446     RotateZ(theta);
00447 }
00448 
00449 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00450 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::PermuteNodes()
00451 {
00452     RandomNumberGenerator *p_rng = RandomNumberGenerator::Instance();
00453 
00454     // Working from the back, each node is swapped with a random node that precedes it in the array
00455     for (unsigned index=this->mNodes.size()-1; index>0; index--)
00456     {
00457         unsigned  other=p_rng->randMod(index+1); //includes the possibility of rolling "index"
00458         // Swap index and other
00459         Node<SPACE_DIM> *temp=this->mNodes[index];
00460         this->mNodes[index]=this->mNodes[other];
00461         this->mNodes[other]=temp;
00462     }
00463 
00464     // Update indices
00465     for (unsigned index=0; index<this->mNodes.size(); index++)
00466     {
00467         this->mNodes[index]->SetIndex(index);
00468     }
00469 }
00470 
00471 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00472 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::PermuteNodes(std::vector<unsigned>& perm)
00473 {
00474     // Let's not do this if there are any deleted nodes
00475     assert( this->GetNumAllNodes() == this->GetNumNodes());
00476 
00477     assert(perm.size() == this->mNodes.size());
00478 
00479     // Copy the node pointers
00480     std::vector< Node<SPACE_DIM>* > copy_m_nodes;
00481     copy_m_nodes.assign(this->mNodes.begin(), this->mNodes.end());
00482 
00483     for (unsigned i=0; i<this->mNodes.size(); i++)
00484     {
00485         assert(perm[i] < this->mNodes.size());
00486         this->mNodes[ perm[i] ] = copy_m_nodes[i];
00487     }
00488 
00489     // Update indices
00490     for (unsigned index=0; index<this->mNodes.size(); index++)
00491     {
00492         this->mNodes[index]->SetIndex(index);
00493     }
00494 }
00495 
00496 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00497 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::PermuteNodesWithMetisBinaries(unsigned numProcs)
00498 {
00499     assert(ELEMENT_DIM==2 || ELEMENT_DIM==3);
00500     assert( this->GetNumAllElements() == this->GetNumElements());
00501     assert( this->GetNumAllNodes() == this->GetNumNodes());
00502 
00503     // Open a file for the elements
00504     OutputFileHandler handler("");
00505 
00506     // Filenames
00507     std::string basename = "metis.mesh";
00508     std::stringstream output_file;
00509     output_file << basename << ".npart." << numProcs;
00510     std::string nodes_per_proc_file = basename + ".nodesperproc";
00511 
00512     // Only the master process should do IO and call METIS
00513     if (handler.IsMaster())
00514     {
00515         out_stream metis_file = handler.OpenOutputFile(basename);
00516 
00517         (*metis_file)<<this->GetNumElements()<<"\t";
00518         if (ELEMENT_DIM==2)
00519         {
00520             (*metis_file)<<1<<"\n"; //1 is Metis speak for triangles
00521         }
00522         else
00523         {
00524             (*metis_file)<<2<<"\n"; //2 is Metis speak for tetrahedra
00525         }
00526 
00527         for (unsigned i=0; i<this->GetNumElements(); i++)
00528         {
00529             for (unsigned j=0; j<ELEMENT_DIM+1; j++)
00530             {
00531                 //Note the +1 since Metis wants meshes indexed from 1
00532                 (*metis_file)<<this->mElements[i]->GetNode(j)->GetIndex() + 1<<"\t";
00533             }
00534             (*metis_file)<<"\n";
00535         }
00536         metis_file->close();
00537 
00538         /*
00539          *  Call METIS binary to perform the partitioning.
00540          *  It will output a file called metis.mesh.npart.numProcs
00541          */
00542         std::stringstream permute_command;
00543         permute_command <<  "./bin/partdmesh "
00544                         <<  handler.GetOutputDirectoryFullPath("")
00545                         <<  basename << " "
00546                         <<  numProcs
00547                         <<  " > /dev/null";
00548 
00549         // METIS doesn't return 0 after a successful execution
00550         IGNORE_RET(system, permute_command.str());
00551 
00552         /*
00553          *  Create a file with the number of nodes per partition
00554          */
00555         // Make sure it doesn't exist, since values will be appended with >>
00556         std::stringstream clear_command;
00557         clear_command << "rm -f "
00558                       << handler.GetOutputDirectoryFullPath("")
00559                       << nodes_per_proc_file
00560                       << " > /dev/null";
00561         EXPECT0(system, clear_command.str());
00562 
00563         // Loop over the partition number (i.e. processor number) and count how many nodes
00564         for (unsigned proc_index=0; proc_index<numProcs; proc_index++)
00565         {
00566             std::stringstream count_command;
00567             count_command << "grep "
00568                           << proc_index << " "
00569                           << handler.GetOutputDirectoryFullPath("")
00570                           << output_file.str()
00571                           << " | wc -l >> "
00572                           << handler.GetOutputDirectoryFullPath("")
00573                           << nodes_per_proc_file;
00574 
00575             EXPECT0(system, count_command.str());
00576         }
00577 
00578     }
00579 
00580     // Wait for the permutation to be available
00581     PetscTools::Barrier();
00582 
00583     /*
00584      *  Read partition file back into a vector.
00585      */
00586     std::vector<unsigned> partition(this->GetNumNodes());
00587     std::vector<unsigned> offset(numProcs,0u);
00588 
00589     std::ifstream partition_stream;
00590     std::string full_path = handler.GetOutputDirectoryFullPath("")
00591                             + output_file.str();
00592 
00593     partition_stream.open(full_path.c_str());
00594     assert(partition_stream.is_open());
00595 
00596     for (unsigned node_index=0; node_index<this->GetNumNodes(); node_index++)
00597     {
00598         unsigned part_read;
00599 
00600         partition_stream >> part_read;
00601 
00602         partition[node_index] = part_read;
00603         for (unsigned proc=part_read+1; proc<numProcs; proc++)
00604         {
00605             offset[proc]++;
00606         }
00607     }
00608     partition_stream.close();
00609 
00610     /*
00611      *  Create the permutation vector based on Metis output
00612      */
00613     std::vector<unsigned> permutation(this->GetNumNodes(), UINT_MAX);
00614     std::vector<unsigned> count(numProcs,0u);
00615 
00616     for (unsigned node_index=0; node_index<this->GetNumNodes(); node_index++)
00617     {
00618         unsigned part = partition[node_index];
00619         // Permutation defined like: new index for node node_index is "offset[part] + count[part]"
00620         permutation [ node_index ] = offset[part] + count[part];
00621 
00622         count[part]++;
00623     }
00624 
00625     PermuteNodes(permutation);
00626 
00627 }
00628 
00629 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00630 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ConstructLinearMesh(unsigned width)
00631 {
00632     assert(SPACE_DIM == 1);
00633     assert(ELEMENT_DIM == 1);
00634 
00635     for (unsigned node_index=0; node_index<=width; node_index++)
00636     {
00637         Node<SPACE_DIM> *p_node = new Node<SPACE_DIM>(node_index, node_index==0 || node_index==width, node_index);
00638         this->mNodes.push_back(p_node); // create node
00639         if (node_index==0) // create left boundary node and boundary element
00640         {
00641             this->mBoundaryNodes.push_back(p_node);
00642             this->mBoundaryElements.push_back(new BoundaryElement<ELEMENT_DIM-1,SPACE_DIM>(0, p_node) );
00643         }
00644         if (node_index==width) // create right boundary node and boundary element
00645         {
00646             this->mBoundaryNodes.push_back(p_node);
00647             this->mBoundaryElements.push_back(new BoundaryElement<ELEMENT_DIM-1,SPACE_DIM>(1, p_node) );
00648         }
00649         if (node_index>0) // create element
00650         {
00651             std::vector<Node<SPACE_DIM>*> nodes;
00652             nodes.push_back(this->mNodes[node_index-1]);
00653             nodes.push_back(this->mNodes[node_index]);
00654             this->mElements.push_back(new Element<ELEMENT_DIM,SPACE_DIM>(node_index-1, nodes) );
00655         }
00656     }
00657 
00658     RefreshJacobianCachedData();
00659 }
00660 
00661 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00662 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ConstructRectangularMesh(unsigned width, unsigned height, bool stagger)
00663 {
00664     assert(SPACE_DIM == 2);
00665     assert(ELEMENT_DIM == 2);
00666 
00667     //Construct the nodes
00668     unsigned node_index=0;
00669     for (int j=(int)height; j>=0; j--) //j must be signed for this loop to terminate
00670     {
00671         for (unsigned i=0; i<width+1; i++)
00672         {
00673             bool is_boundary=false;
00674             if (i==0 || j==0 || i==width || j==(int)height)
00675             {
00676                 is_boundary=true;
00677             }
00678             Node<SPACE_DIM> *p_node = new Node<SPACE_DIM>(node_index++, is_boundary, i, j);
00679             this->mNodes.push_back(p_node);
00680             if (is_boundary)
00681             {
00682                 this->mBoundaryNodes.push_back(p_node);
00683             }
00684         }
00685     }
00686 
00687     //Construct the boundary elements
00688     unsigned belem_index=0;
00689     //Top
00690     for (unsigned i=0; i<width; i++)
00691     {
00692         std::vector<Node<SPACE_DIM>*> nodes;
00693         nodes.push_back(this->mNodes[i]);
00694         nodes.push_back(this->mNodes[i+1]);
00695         this->mBoundaryElements.push_back(new BoundaryElement<ELEMENT_DIM-1,SPACE_DIM>(belem_index++,nodes));
00696     }
00697     //Right
00698     for (unsigned i=1; i<height+1; i++)
00699     {
00700         std::vector<Node<SPACE_DIM>*> nodes;
00701         nodes.push_back(this->mNodes[(width+1)*i-1]);
00702         nodes.push_back(this->mNodes[(width+1)*(i+1)-1]);
00703         this->mBoundaryElements.push_back(new BoundaryElement<ELEMENT_DIM-1,SPACE_DIM>(belem_index++,nodes));
00704     }
00705     //Bottom
00706     for (unsigned i=0; i<width; i++)
00707     {
00708         std::vector<Node<SPACE_DIM>*> nodes;
00709         nodes.push_back(this->mNodes[height*(width+1)+i+1]);
00710         nodes.push_back(this->mNodes[height*(width+1)+i]);
00711         this->mBoundaryElements.push_back(new BoundaryElement<ELEMENT_DIM-1,SPACE_DIM>(belem_index++,nodes));
00712     }
00713     //Left
00714     for (unsigned i=0; i<height; i++)
00715     {
00716         std::vector<Node<SPACE_DIM>*> nodes;
00717         nodes.push_back(this->mNodes[(width+1)*(i+1)]);
00718         nodes.push_back(this->mNodes[(width+1)*(i)]);
00719         this->mBoundaryElements.push_back(new BoundaryElement<ELEMENT_DIM-1,SPACE_DIM>(belem_index++,nodes));
00720     }
00721 
00722     //Construct the elements
00723     unsigned elem_index = 0;
00724     for (unsigned j=0; j<height; j++)
00725     {
00726         for (unsigned i=0; i<width; i++)
00727         {
00728             unsigned parity=(i+j)%2;
00729             std::vector<Node<SPACE_DIM>*> upper_nodes;
00730             upper_nodes.push_back(this->mNodes[j*(width+1)+i]);
00731             upper_nodes.push_back(this->mNodes[j*(width+1)+i+1]);
00732             if (stagger==false  || parity == 0)
00733             {
00734                 upper_nodes.push_back(this->mNodes[(j+1)*(width+1)+i+1]);
00735             }
00736             else
00737             {
00738                 upper_nodes.push_back(this->mNodes[(j+1)*(width+1)+i]);
00739             }
00740             this->mElements.push_back(new Element<ELEMENT_DIM,SPACE_DIM>(elem_index++,upper_nodes));
00741             std::vector<Node<SPACE_DIM>*> lower_nodes;
00742             lower_nodes.push_back(this->mNodes[(j+1)*(width+1)+i+1]);
00743             lower_nodes.push_back(this->mNodes[(j+1)*(width+1)+i]);
00744             if (stagger==false  ||parity == 0)
00745             {
00746                 lower_nodes.push_back(this->mNodes[j*(width+1)+i]);
00747             }
00748             else
00749             {
00750                 lower_nodes.push_back(this->mNodes[j*(width+1)+i+1]);
00751             }
00752             this->mElements.push_back(new Element<ELEMENT_DIM,SPACE_DIM>(elem_index++,lower_nodes));
00753         }
00754     }
00755 
00756     RefreshJacobianCachedData();
00757 }
00758 
00759 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00760 unsigned TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::GetContainingElementIndex(ChastePoint<SPACE_DIM> testPoint, bool strict, std::set<unsigned> testElements)
00761 {
00762     for (std::set<unsigned>::iterator iter=testElements.begin(); iter!=testElements.end(); iter++)
00763     {
00764         assert(*iter<this->GetNumElements());
00766         if (this->mElements[*iter]->IncludesPoint(testPoint, strict))
00767         {
00768             return *iter;
00769         }
00770     }
00771 
00774     for (unsigned i=0; i<this->mElements.size(); i++)
00775     {
00777         if (this->mElements[i]->IncludesPoint(testPoint, strict))
00778         {
00779             return i;
00780         }
00781     }
00782 
00783     //If it's in none of the elements, then throw
00784     EXCEPTION("Point is not in mesh");
00785 }
00786 
00787 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00788 unsigned TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::GetNearestElementIndex(ChastePoint<SPACE_DIM> testPoint)
00789 {
00792 
00793     double max_min_weight = -INFINITY;
00794     unsigned closest_index = 0;
00795     for (unsigned i=0; i<this->mElements.size(); i++)
00796     {
00798         c_vector<double, ELEMENT_DIM+1> weight=this->mElements[i]->CalculateInterpolationWeights(testPoint);
00799         double neg_weight_sum=0.0;
00800         for (unsigned j=0; j<=ELEMENT_DIM; j++)
00801         {
00802             if (weight[j] < 0.0)
00803             {
00804                 neg_weight_sum += weight[j];
00805             }
00806         }
00807         if (neg_weight_sum > max_min_weight)
00808         {
00809             max_min_weight = neg_weight_sum;
00810             closest_index=i;
00811         }
00812 
00813     }
00814     return closest_index;
00815 }
00816 
00817 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00818 std::vector<unsigned> TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::GetContainingElementIndices(ChastePoint<SPACE_DIM> testPoint)
00819 {
00820     std::vector<unsigned> element_indices;
00821     for (unsigned i=0; i<this->mElements.size(); i++)
00822     {
00824         if (this->mElements[i]->IncludesPoint(testPoint))
00825         {
00826             element_indices.push_back(i);
00827         }
00828     }
00829     return element_indices;
00830 }
00831 
00832 //template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00833 //void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::SetElementOwnerships(unsigned lo, unsigned hi)
00834 //{
00835 //    assert(hi>=lo);
00836 //    for (unsigned element_index=0; element_index<this->mElements.size(); element_index++)
00837 //    {
00838 //        Element<ELEMENT_DIM, SPACE_DIM> *p_element=this->mElements[element_index];
00839 //        p_element->SetOwnership(false);
00840 //        for (unsigned local_node_index=0; local_node_index< p_element->GetNumNodes(); local_node_index++)
00841 //        {
00842 //            unsigned global_node_index = p_element->GetNodeGlobalIndex(local_node_index);
00843 //            if (lo<=global_node_index && global_node_index<hi)
00844 //            {
00845 //                p_element->SetOwnership(true);
00846 //                break;
00847 //            }
00848 //        }
00849 //
00850 //    }
00851 //}
00852 
00853 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00854 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ConstructCuboid(unsigned width,
00855         unsigned height,
00856         unsigned depth,
00857         bool stagger)
00858 {
00859     assert(SPACE_DIM == 3);
00860     assert(ELEMENT_DIM == 3);
00861     //Construct the nodes
00862 
00863     unsigned node_index = 0;
00864     for (unsigned k=0; k<depth+1; k++)
00865     {
00866         for (unsigned j=0; j<height+1; j++)
00867         {
00868             for (unsigned i=0; i<width+1; i++)
00869             {
00870                 bool is_boundary = false;
00871                 if (i==0 || j==0 || k==0 || i==width || j==height || k==depth)
00872                 {
00873                     is_boundary = true;
00874                 }
00875 
00876                 Node<SPACE_DIM> *p_node = new Node<SPACE_DIM>(node_index++, is_boundary, i, j, k);
00877 
00878                 this->mNodes.push_back(p_node);
00879                 if (is_boundary)
00880                 {
00881                     this->mBoundaryNodes.push_back(p_node);
00882                 }
00883             }
00884         }
00885     }
00886 
00887     // Construct the elements
00888 
00889     unsigned elem_index = 0;
00890     unsigned belem_index = 0;
00891     unsigned element_nodes[4][6][4] = {{{0, 1, 5, 7}, {0, 1, 3, 7},
00892                                         {0, 2, 3, 7}, {0, 2, 6, 7},
00893                                         {0, 4, 6, 7}, {0, 4, 5, 7}},
00894                                        {{1, 0, 2, 6}, {1, 0, 4, 6},
00895                                         {1, 5, 4, 6}, {1, 5, 7, 6},
00896                                         {1, 3, 2, 6}, {1, 3, 7, 6}},
00897                                        {{2, 0, 1, 5}, {2, 0, 4, 5},
00898                                         {2, 3, 1, 5}, {2, 3, 7, 5},
00899                                         {2, 6, 4, 5}, {2, 6, 7, 5}},
00900                                        {{3, 1, 0, 4}, {3, 1, 5, 4},
00901                                         {3, 2, 0, 4}, {3, 2, 6, 4},
00902                                         {3, 7, 5, 4}, {3, 7, 6, 4}}};
00903 
00904     std::vector<Node<SPACE_DIM>*> tetrahedra_nodes;
00905 
00906     for (unsigned k=0; k<depth; k++)
00907     {
00908         for (unsigned j=0; j<height; j++)
00909         {
00910             for (unsigned i=0; i<width; i++)
00911             {
00912                 // Compute the nodes' index
00913                 unsigned global_node_indices[8];
00914                 unsigned local_node_index = 0;
00915 
00916                 for (unsigned z = 0; z < 2; z++)
00917                 {
00918                     for (unsigned y = 0; y < 2; y++)
00919                     {
00920                         for (unsigned x = 0; x < 2; x++)
00921                         {
00922                             global_node_indices[local_node_index] = i+x+(width+1)*(j+y+(height+1)*(k+z));
00923 
00924                             local_node_index++;
00925                         }
00926                     }
00927                 }
00928 
00929                 for (unsigned m = 0; m < 6; m++)
00930                 {
00931                     // Tetrahedra #m
00932 
00933                     tetrahedra_nodes.clear();
00934 
00935                     for (unsigned n = 0; n < 4; n++)
00936                     {
00937                         if (stagger)
00938                         {
00939                             if (i%2==0)
00940                             {
00941                                 if (j%2==0)
00942                                 {
00943                                     if (k%2==0)
00944                                     {
00945                                         tetrahedra_nodes.push_back(this->mNodes[global_node_indices[element_nodes[0][m][n]]]);
00946                                     }
00947                                     else
00948                                     {
00949                                         tetrahedra_nodes.push_back(this->mNodes[global_node_indices[element_nodes[3][m][n]]]);
00950                                     }
00951                                 }
00952                                 else
00953                                 {
00954                                     if (k%2==0)
00955                                     {
00956                                         tetrahedra_nodes.push_back(this->mNodes[global_node_indices[element_nodes[2][m][n]]]);
00957                                     }
00958                                     else
00959                                     {
00960                                         tetrahedra_nodes.push_back(this->mNodes[global_node_indices[element_nodes[1][m][n]]]);
00961                                     }
00962                                 }
00963                             }
00964                             else
00965                             {
00966                                if (j%2==0)
00967                                {
00968                                     if (k%2==0)
00969                                     {
00970                                         tetrahedra_nodes.push_back(this->mNodes[global_node_indices[element_nodes[3][m][n]]]);
00971                                     }
00972                                     else
00973                                     {
00974                                         tetrahedra_nodes.push_back(this->mNodes[global_node_indices[element_nodes[1][m][n]]]);
00975                                     }
00976                                }
00977                                else
00978                                {
00979                                     if (k%2==0)
00980                                     {
00981                                         tetrahedra_nodes.push_back(this->mNodes[global_node_indices[element_nodes[2][m][n]]]);
00982                                     }
00983                                     else
00984                                     {
00985                                         tetrahedra_nodes.push_back(this->mNodes[global_node_indices[element_nodes[0][m][n]]]);
00986                                     }
00987                                 }
00988                             }
00989                         }
00990 
00991                         else
00992                         {
00993                             tetrahedra_nodes.push_back(this->mNodes[global_node_indices[element_nodes[0][m][n]]]);
00994                         }
00995                     }
00996 
00997                     this->mElements.push_back(new Element<ELEMENT_DIM,SPACE_DIM>(elem_index++, tetrahedra_nodes));
00998                 }
00999 
01000                 //Are we at a boundary?
01001                 std::vector<Node<SPACE_DIM>*> triangle_nodes;
01002                 if (i == 0) //low face at x==0
01003                 {
01004                     triangle_nodes.clear();
01005                     triangle_nodes.push_back(this->mNodes[global_node_indices[0]]);
01006                     triangle_nodes.push_back(this->mNodes[global_node_indices[2]]);
01007                     triangle_nodes.push_back(this->mNodes[global_node_indices[6]]);
01008                     this->mBoundaryElements.push_back(new BoundaryElement<ELEMENT_DIM-1,SPACE_DIM>(belem_index++,triangle_nodes));
01009                     triangle_nodes.clear();
01010                     triangle_nodes.push_back(this->mNodes[global_node_indices[0]]);
01011                     triangle_nodes.push_back(this->mNodes[global_node_indices[6]]);
01012                     triangle_nodes.push_back(this->mNodes[global_node_indices[4]]);
01013                     this->mBoundaryElements.push_back(new BoundaryElement<ELEMENT_DIM-1,SPACE_DIM>(belem_index++,triangle_nodes));
01014                 }
01015                 if (i == width-1) //high face at x=width
01016                 {
01017                     triangle_nodes.clear();
01018                     triangle_nodes.push_back(this->mNodes[global_node_indices[1]]);
01019                     triangle_nodes.push_back(this->mNodes[global_node_indices[5]]);
01020                     triangle_nodes.push_back(this->mNodes[global_node_indices[7]]);
01021                     this->mBoundaryElements.push_back(new BoundaryElement<ELEMENT_DIM-1,SPACE_DIM>(belem_index++,triangle_nodes));
01022                     triangle_nodes.clear();
01023                     triangle_nodes.push_back(this->mNodes[global_node_indices[1]]);
01024                     triangle_nodes.push_back(this->mNodes[global_node_indices[7]]);
01025                     triangle_nodes.push_back(this->mNodes[global_node_indices[3]]);
01026                     this->mBoundaryElements.push_back(new BoundaryElement<ELEMENT_DIM-1,SPACE_DIM>(belem_index++,triangle_nodes));
01027                 }
01028                 if (j == 0) //low face at y==0
01029                 {
01030                     triangle_nodes.clear();
01031                     triangle_nodes.push_back(this->mNodes[global_node_indices[0]]);
01032                     triangle_nodes.push_back(this->mNodes[global_node_indices[5]]);
01033                     triangle_nodes.push_back(this->mNodes[global_node_indices[1]]);
01034                     this->mBoundaryElements.push_back(new BoundaryElement<ELEMENT_DIM-1,SPACE_DIM>(belem_index++,triangle_nodes));
01035                     triangle_nodes.clear();
01036                     triangle_nodes.push_back(this->mNodes[global_node_indices[0]]);
01037                     triangle_nodes.push_back(this->mNodes[global_node_indices[4]]);
01038                     triangle_nodes.push_back(this->mNodes[global_node_indices[5]]);
01039                     this->mBoundaryElements.push_back(new BoundaryElement<ELEMENT_DIM-1,SPACE_DIM>(belem_index++,triangle_nodes));
01040                 }
01041                 if (j == height-1) //high face at y=height
01042                 {
01043                     triangle_nodes.clear();
01044                     triangle_nodes.push_back(this->mNodes[global_node_indices[2]]);
01045                     triangle_nodes.push_back(this->mNodes[global_node_indices[3]]);
01046                     triangle_nodes.push_back(this->mNodes[global_node_indices[7]]);
01047                     this->mBoundaryElements.push_back(new BoundaryElement<ELEMENT_DIM-1,SPACE_DIM>(belem_index++,triangle_nodes));
01048                     triangle_nodes.clear();
01049                     triangle_nodes.push_back(this->mNodes[global_node_indices[2]]);
01050                     triangle_nodes.push_back(this->mNodes[global_node_indices[7]]);
01051                     triangle_nodes.push_back(this->mNodes[global_node_indices[6]]);
01052                     this->mBoundaryElements.push_back(new BoundaryElement<ELEMENT_DIM-1,SPACE_DIM>(belem_index++,triangle_nodes));
01053                 }
01054                 if (k == 0) //low face at z==0
01055                 {
01056                     triangle_nodes.clear();
01057                     triangle_nodes.push_back(this->mNodes[global_node_indices[0]]);
01058                     triangle_nodes.push_back(this->mNodes[global_node_indices[3]]);
01059                     triangle_nodes.push_back(this->mNodes[global_node_indices[2]]);
01060                     this->mBoundaryElements.push_back(new BoundaryElement<ELEMENT_DIM-1,SPACE_DIM>(belem_index++,triangle_nodes));
01061                     triangle_nodes.clear();
01062                     triangle_nodes.push_back(this->mNodes[global_node_indices[0]]);
01063                     triangle_nodes.push_back(this->mNodes[global_node_indices[1]]);
01064                     triangle_nodes.push_back(this->mNodes[global_node_indices[3]]);
01065                     this->mBoundaryElements.push_back(new BoundaryElement<ELEMENT_DIM-1,SPACE_DIM>(belem_index++,triangle_nodes));
01066                 }
01067                 if (k == depth-1) //high face at z=depth
01068                 {
01069                     triangle_nodes.clear();
01070                     triangle_nodes.push_back(this->mNodes[global_node_indices[4]]);
01071                     triangle_nodes.push_back(this->mNodes[global_node_indices[7]]);
01072                     triangle_nodes.push_back(this->mNodes[global_node_indices[5]]);
01073                     this->mBoundaryElements.push_back(new BoundaryElement<ELEMENT_DIM-1,SPACE_DIM>(belem_index++,triangle_nodes));
01074                     triangle_nodes.clear();
01075                     triangle_nodes.push_back(this->mNodes[global_node_indices[4]]);
01076                     triangle_nodes.push_back(this->mNodes[global_node_indices[6]]);
01077                     triangle_nodes.push_back(this->mNodes[global_node_indices[7]]);
01078                     this->mBoundaryElements.push_back(new BoundaryElement<ELEMENT_DIM-1,SPACE_DIM>(belem_index++,triangle_nodes));
01079                 }
01080             }//i
01081         }//j
01082     }//k
01083 
01084     RefreshJacobianCachedData();
01085 }
01086 
01087 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
01088 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::Clear()
01089 {
01090     // three loops, just like the destructor. note we don't delete boundary nodes.
01091     for (unsigned i=0; i<this->mBoundaryElements.size(); i++)
01092     {
01093         delete this->mBoundaryElements[i];
01094     }
01095     for (unsigned i=0; i<this->mElements.size(); i++)
01096     {
01097         delete this->mElements[i];
01098     }
01099     for (unsigned i=0; i<this->mNodes.size(); i++)
01100     {
01101         delete this->mNodes[i];
01102     }
01103 
01104     this->mNodes.clear();
01105     this->mElements.clear();
01106     this->mBoundaryElements.clear();
01107     this->mBoundaryNodes.clear();
01108 }
01109 
01110 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
01111 std::set<unsigned> TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::CalculateBoundaryOfFlaggedRegion()
01112 {
01113     // A set of nodes which lie on the face, size 3 in 2D, size 4 in 3D
01114     typedef std::set<unsigned> FaceNodes;
01115 
01116     // Face maps to true the first time it is encountered, and false subsequent
01117     // times. Thus, faces mapping to true at the end are boundary faces
01118     std::map<FaceNodes,bool> face_on_boundary;
01119 
01120     // Loop over all elements
01121     for (typename AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ElementIterator iter = this->GetElementIteratorBegin();
01122          iter != this->GetElementIteratorEnd();
01123          ++iter)
01124     {
01125         if (iter->IsFlagged())
01126         {
01127             // To get faces, initially start with all nodes
01128             std::set<unsigned> all_nodes;
01129             for (unsigned i=0; i<ELEMENT_DIM+1; i++)
01130             {
01131                 all_nodes.insert(iter->GetNodeGlobalIndex(i));
01132             }
01133 
01134             // Remove one node in turn to obtain each face
01135             for (unsigned i=0; i<ELEMENT_DIM+1; i++)
01136             {
01137                 FaceNodes face_nodes = all_nodes;
01138                 face_nodes.erase(iter->GetNodeGlobalIndex(i));
01139 
01140                 // Search the map of faces to see if it contains this face
01141                 std::map<FaceNodes,bool>::iterator it = face_on_boundary.find(face_nodes);
01142 
01143                 if (it == face_on_boundary.end())
01144                 {
01145                     // Face not found, add and assume on boundary
01146                     face_on_boundary[face_nodes]=true;
01147                 }
01148                 else
01149                 {
01150                     // Face found in map, so not on boundary
01151                     it->second = false;
01152                 }
01153             }
01154         }
01155     }
01156 
01157     // Boundary nodes to be returned
01158     std::set<unsigned> boundary_of_flagged_region;
01159 
01160     // Get all faces in the map
01161     std::map<FaceNodes,bool>::iterator it=face_on_boundary.begin();
01162     while (it!=face_on_boundary.end())
01163     {
01164         // If the face maps to true it is on the boundary
01165         if (it->second==true)
01166         {
01167             // Get all nodes in the face and put in set to be returned
01168             boundary_of_flagged_region.insert(it->first.begin(),it->first.end());
01169         }
01170         it++;
01171     }
01172 
01173     return boundary_of_flagged_region;
01174 }
01175 
01176 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
01177 double TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::GetAngleBetweenNodes(unsigned indexA, unsigned indexB)
01178 {
01179     assert(SPACE_DIM == 2);
01180     assert(SPACE_DIM == ELEMENT_DIM);
01181 
01182     double x_diff = this->mNodes[indexB]->rGetLocation()[0] - this->mNodes[indexA]->rGetLocation()[0];
01183     double y_diff = this->mNodes[indexB]->rGetLocation()[1] - this->mNodes[indexA]->rGetLocation()[1];
01184 
01185     if (x_diff==0)
01186     {
01187         if (y_diff>0)
01188         {
01189             return M_PI/2.0;
01190         }
01191         else if (y_diff<0)
01192         {
01193             return -M_PI/2.0;
01194         }
01195         else
01196         {
01197             EXCEPTION("Tried to compute polar angle of (0,0)");
01198         }
01199     }
01200 
01201     double angle = atan2(y_diff,x_diff);
01202     return angle;
01203 }
01204 
01205 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
01206 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::UnflagAllElements()
01207 {
01208     for (typename AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ElementIterator iter = this->GetElementIteratorBegin();
01209          iter != this->GetElementIteratorEnd();
01210          ++iter)
01211     {
01212         iter->Unflag();
01213     }
01214 }
01215 
01216 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
01217 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::FlagElementsNotContainingNodes(std::set<unsigned> nodesList)
01218 {
01219     for (typename AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ElementIterator iter = this->GetElementIteratorBegin();
01220          iter != this->GetElementIteratorEnd();
01221          ++iter)
01222     {
01223         bool found_node = false;
01224 
01225         for (unsigned i=0; i<iter->GetNumNodes(); i++)
01226         {
01227             unsigned node_index = iter->GetNodeGlobalIndex(i);
01228 
01229             std::set<unsigned>::iterator set_iter = nodesList.find(node_index);
01230             if (set_iter != nodesList.end())
01231             {
01232                 found_node = true;
01233             }
01234         }
01235 
01236         if (!found_node)
01237         {
01238             iter->Flag();
01239         }
01240     }
01241 }
01242 
01243 
01245 //                          edge iterator class                             //
01247 
01248 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
01249 Node<SPACE_DIM>* TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::EdgeIterator::GetNodeA()
01250 {
01251     assert((*this) != mrMesh.EdgesEnd());
01252     Element<ELEMENT_DIM,SPACE_DIM> *p_element = mrMesh.GetElement(mElemIndex);
01253     return p_element->GetNode(mNodeALocalIndex);
01254 }
01255 
01256 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
01257 Node<SPACE_DIM>* TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::EdgeIterator::GetNodeB()
01258 {
01259     assert((*this) != mrMesh.EdgesEnd());
01260     Element<ELEMENT_DIM,SPACE_DIM> *p_element = mrMesh.GetElement(mElemIndex);
01261     return p_element->GetNode(mNodeBLocalIndex);
01262 }
01263 
01264 
01265 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
01266 bool TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::EdgeIterator::operator!=(const TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::EdgeIterator& rOther)
01267 {
01268     return (mElemIndex != rOther.mElemIndex ||
01269             mNodeALocalIndex != rOther.mNodeALocalIndex ||
01270             mNodeBLocalIndex != rOther.mNodeBLocalIndex);
01271 }
01272 
01273 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
01274 typename TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::EdgeIterator& TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::EdgeIterator::operator++()
01275 {
01276     std::set<unsigned> current_node_pair;
01277     std::set<std::set<unsigned> >::iterator set_iter;
01278 
01279     do
01280     {
01281         // Advance to the next edge in the mesh.
01282         // Node indices are incremented modulo #nodes_per_elem
01283         mNodeBLocalIndex = (mNodeBLocalIndex + 1) % (ELEMENT_DIM+1);
01284         if (mNodeBLocalIndex == mNodeALocalIndex)
01285         {
01286             mNodeALocalIndex = (mNodeALocalIndex + 1) % (ELEMENT_DIM+1);
01287             mNodeBLocalIndex = (mNodeALocalIndex + 1) % (ELEMENT_DIM+1);
01288         }
01289 
01290         if (mNodeALocalIndex == 0 && mNodeBLocalIndex == 1) // advance to next element...
01291         {
01292             mElemIndex++;
01293             // ...skipping deleted ones
01294             while (mElemIndex!=mrMesh.GetNumAllElements() && mrMesh.GetElement(mElemIndex)->IsDeleted())
01295             {
01296                 mElemIndex++;
01297             }
01298         }
01299 
01300         if (mElemIndex != mrMesh.GetNumAllElements())
01301         {
01302             unsigned node_a_global_index = mrMesh.GetElement(mElemIndex)->GetNodeGlobalIndex(mNodeALocalIndex);
01303             unsigned node_b_global_index = mrMesh.GetElement(mElemIndex)->GetNodeGlobalIndex(mNodeBLocalIndex);
01304 
01305             // Check we haven't seen it before
01306             current_node_pair.clear();
01307             current_node_pair.insert(node_a_global_index);
01308             current_node_pair.insert(node_b_global_index);
01309             set_iter = mEdgesVisited.find(current_node_pair);
01310         }
01311     }
01312     while (*this != mrMesh.EdgesEnd() && set_iter != mEdgesVisited.end());
01313     mEdgesVisited.insert(current_node_pair);
01314 
01315     return (*this);
01316 }
01317 
01318 
01319 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
01320 TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::EdgeIterator::EdgeIterator(TetrahedralMesh& rMesh, unsigned elemIndex)
01321     : mrMesh(rMesh),
01322       mElemIndex(elemIndex),
01323       mNodeALocalIndex(0),
01324       mNodeBLocalIndex(1)
01325 {
01326     if (elemIndex==mrMesh.GetNumAllElements())
01327     {
01328         return;
01329     }
01330 
01331     mEdgesVisited.clear();
01332 
01333     // add the current node pair to the store
01334     std::set<unsigned> current_node_pair;
01335     unsigned node_a_global_index = mrMesh.GetElement(mElemIndex)->GetNodeGlobalIndex(mNodeALocalIndex);
01336     unsigned node_b_global_index = mrMesh.GetElement(mElemIndex)->GetNodeGlobalIndex(mNodeBLocalIndex);
01337     current_node_pair.insert(node_a_global_index);
01338     current_node_pair.insert(node_b_global_index);
01339 
01340     mEdgesVisited.insert(current_node_pair);
01341 }
01342 
01343 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
01344 typename TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::EdgeIterator TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::EdgesBegin()
01345 {
01346     unsigned first_element_index=0;
01347     while (first_element_index!=this->GetNumAllElements() && this->GetElement(first_element_index)->IsDeleted())
01348     {
01349         first_element_index++;
01350     }
01351     return EdgeIterator(*this, first_element_index);
01352 }
01353 
01354 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
01355 typename TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::EdgeIterator TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::EdgesEnd()
01356 {
01357     return EdgeIterator(*this, this->GetNumAllElements());
01358 }
01359 
01360 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
01361 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::RefreshMesh()
01362 {
01363     RefreshJacobianCachedData();
01364 }
01365 
01366 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
01367 unsigned TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::SolveNodeMapping(unsigned index) const
01368 {
01369     assert(index < this->mNodes.size() );
01370     return index;
01371 }
01372 
01373 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
01374 unsigned TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::SolveElementMapping(unsigned index) const
01375 {
01376     assert(index < this->mElements.size() );
01377     return index;
01378 }
01379 
01380 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
01381 unsigned TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::SolveBoundaryElementMapping(unsigned index) const
01382 {
01383     assert(index < this->mBoundaryElements.size() );
01384     return index;
01385 }
01386 
01387 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
01388 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::RefreshJacobianCachedData()
01389 {
01390     // Make sure we have enough space
01391     this->mElementJacobians.resize(this->GetNumAllElements());
01392     this->mElementInverseJacobians.resize(this->GetNumAllElements());
01393     
01394     if (ELEMENT_DIM < SPACE_DIM)
01395     {
01396         this->mElementWeightedDirections.resize(this->GetNumAllElements());
01397     }
01398 
01399     this->mBoundaryElementWeightedDirections.resize(this->GetNumAllBoundaryElements());
01400 
01401     this->mElementJacobianDeterminants.resize(this->GetNumAllElements());
01402     this->mBoundaryElementJacobianDeterminants.resize(this->GetNumAllBoundaryElements());
01403 
01404     // Update caches
01405     for (typename AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ElementIterator iter = this->GetElementIteratorBegin();
01406          iter != this->GetElementIteratorEnd();
01407          ++iter)
01408     {
01409         unsigned index = iter->GetIndex();
01410         iter->CalculateInverseJacobian(this->mElementJacobians[index], this->mElementJacobianDeterminants[index], this->mElementInverseJacobians[index]);
01411     }
01412         
01413     if (ELEMENT_DIM < SPACE_DIM)
01414     {
01415         for (typename AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ElementIterator iter = this->GetElementIteratorBegin();
01416              iter != this->GetElementIteratorEnd();
01417              ++iter)
01418         {
01419              unsigned index = iter->GetIndex();
01420              iter->CalculateWeightedDirection(this->mElementWeightedDirections[index], this->mElementJacobianDeterminants[index]);
01421         }
01422     }
01423 
01424     for ( typename TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::BoundaryElementIterator itb = this->GetBoundaryElementIteratorBegin();
01425           itb != this->GetBoundaryElementIteratorEnd();
01426           itb++)
01427     {
01428         unsigned index = (*itb)->GetIndex();
01429         (*itb)->CalculateWeightedDirection(this->mBoundaryElementWeightedDirections[index], this->mBoundaryElementJacobianDeterminants[index]);
01430     }
01431 }
01432 
01433 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
01434 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::GetJacobianForElement(unsigned elementIndex, c_matrix<double, SPACE_DIM, SPACE_DIM>& rJacobian, double& rJacobianDeterminant) const
01435 {
01436     assert(ELEMENT_DIM <= SPACE_DIM);
01437     assert(elementIndex < this->mElementJacobians.size());
01438     rJacobian = this->mElementJacobians[elementIndex];
01439     rJacobianDeterminant = this->mElementJacobianDeterminants[elementIndex];
01440 }
01441 
01442 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
01443 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
01444 {
01445     assert(ELEMENT_DIM <= SPACE_DIM);
01446     assert(elementIndex < this->mElementInverseJacobians.size());
01447     rInverseJacobian = this->mElementInverseJacobians[elementIndex];
01448     rJacobian = this->mElementJacobians[elementIndex];
01449     rJacobianDeterminant = this->mElementJacobianDeterminants[elementIndex];
01450 }
01451 
01452 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
01453 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::GetWeightedDirectionForElement(unsigned elementIndex, c_vector<double, SPACE_DIM>& rWeightedDirection, double& rJacobianDeterminant) const
01454 {
01455     assert(ELEMENT_DIM < SPACE_DIM);
01456     assert(elementIndex < this->mElementWeightedDirections.size());
01457     rWeightedDirection = this->mElementWeightedDirections[elementIndex];
01458     rJacobianDeterminant = this->mElementJacobianDeterminants[elementIndex];
01459 }
01460 
01461 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
01462 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::GetWeightedDirectionForBoundaryElement(unsigned elementIndex, c_vector<double, SPACE_DIM>& rWeightedDirection, double& rJacobianDeterminant) const
01463 {
01464     assert(elementIndex < this->mBoundaryElementWeightedDirections.size());
01465     rWeightedDirection = this->mBoundaryElementWeightedDirections[elementIndex];
01466     rJacobianDeterminant = this->mBoundaryElementJacobianDeterminants[elementIndex];
01467 }
01468 
01470 // Explicit instantiation
01472 
01473 template class TetrahedralMesh<1,1>;
01474 template class TetrahedralMesh<1,2>;
01475 template class TetrahedralMesh<1,3>;
01476 template class TetrahedralMesh<2,2>;
01477 template class TetrahedralMesh<2,3>;
01478 template class TetrahedralMesh<3,3>;

Generated on Tue Aug 4 16:10:22 2009 for Chaste by  doxygen 1.5.5