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

Generated on Wed Mar 18 12:51:52 2009 for Chaste by  doxygen 1.5.5