00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #include "TetrahedralMesh.hpp"
00037
00038 #include <iostream>
00039 #include <cassert>
00040 #include <sstream>
00041 #include <map>
00042 #include <limits>
00043
00044 #include "BoundaryElement.hpp"
00045 #include "Element.hpp"
00046 #include "Exception.hpp"
00047 #include "Node.hpp"
00048 #include "OutputFileHandler.hpp"
00049 #include "PetscTools.hpp"
00050 #include "RandomNumberGenerator.hpp"
00051 #include "Warnings.hpp"
00052
00053
00054 #define REAL double
00055 #define VOID void
00056 #include "triangle.h"
00057 #include "tetgen.h"
00058 #undef REAL
00059 #undef VOID
00060
00061 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00062 TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::TetrahedralMesh()
00063 {
00064 Clear();
00065 }
00066
00067 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00068 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ConstructFromMeshReader(
00069 AbstractMeshReader<ELEMENT_DIM, SPACE_DIM>& rMeshReader)
00070 {
00071 assert(rMeshReader.HasNodePermutation() == false);
00072 this->mMeshFileBaseName = rMeshReader.GetMeshFileBaseName();
00073
00074
00075 unsigned num_nodes = rMeshReader.GetNumNodes();
00076
00077
00078
00079
00080
00081 this->mNodes.reserve(num_nodes);
00082
00083 rMeshReader.Reset();
00084
00085
00086
00087
00088
00089 std::vector<double> coords;
00090 for (unsigned node_index=0; node_index < num_nodes; node_index++)
00091 {
00092 coords = rMeshReader.GetNextNode();
00093 Node<SPACE_DIM>* p_node = new Node<SPACE_DIM>(node_index, coords, false);
00094
00095 for (unsigned i=0; i<rMeshReader.GetNodeAttributes().size(); i++)
00096 {
00097 double attribute = rMeshReader.GetNodeAttributes()[i];
00098 p_node->AddNodeAttribute(attribute);
00099 }
00100
00101 this->mNodes.push_back(p_node);
00102 }
00103
00104
00105
00106 rMeshReader.Reset();
00107
00108
00109 this->mElements.reserve(rMeshReader.GetNumElements());
00110
00111 for (unsigned element_index=0; element_index < (unsigned) rMeshReader.GetNumElements(); element_index++)
00112 {
00113 ElementData element_data = rMeshReader.GetNextElementData();
00114 std::vector<Node<SPACE_DIM>*> nodes;
00115
00116
00117
00118
00119
00120
00121
00122 for (unsigned j=0; j<ELEMENT_DIM+1; j++)
00123 {
00124 assert(element_data.NodeIndices[j] < this->mNodes.size());
00125 nodes.push_back(this->mNodes[element_data.NodeIndices[j]]);
00126 }
00127
00128 Element<ELEMENT_DIM,SPACE_DIM>* p_element = new Element<ELEMENT_DIM,SPACE_DIM>(element_index, nodes);
00129 this->mElements.push_back(p_element);
00130
00131 if (rMeshReader.GetNumElementAttributes() > 0)
00132 {
00133 assert(rMeshReader.GetNumElementAttributes() == 1);
00134 double attribute_value = element_data.AttributeValue;
00135 p_element->SetAttribute(attribute_value);
00136 }
00137 }
00138
00139
00140 for (unsigned face_index=0; face_index<(unsigned)rMeshReader.GetNumFaces(); face_index++)
00141 {
00142 ElementData face_data = rMeshReader.GetNextFaceData();
00143 std::vector<unsigned> node_indices = face_data.NodeIndices;
00144
00145
00146
00147
00148
00149
00150
00151 std::vector<Node<SPACE_DIM>*> nodes;
00152 for (unsigned node_index=0; node_index<node_indices.size(); node_index++)
00153 {
00154 assert(node_indices[node_index] < this->mNodes.size());
00155
00156 nodes.push_back(this->mNodes[node_indices[node_index]]);
00157 }
00158
00159
00160 for (unsigned j=0; j<nodes.size(); j++)
00161 {
00162 if (!nodes[j]->IsBoundaryNode())
00163 {
00164 nodes[j]->SetAsBoundaryNode();
00165 this->mBoundaryNodes.push_back(nodes[j]);
00166 }
00167
00168
00169 nodes[j]->AddBoundaryElement(face_index);
00170 }
00171
00172
00173 BoundaryElement<ELEMENT_DIM-1,SPACE_DIM>* p_boundary_element = new BoundaryElement<ELEMENT_DIM-1,SPACE_DIM>(face_index, nodes);
00174 this->mBoundaryElements.push_back(p_boundary_element);
00175
00176 if (rMeshReader.GetNumFaceAttributes() > 0)
00177 {
00178 assert(rMeshReader.GetNumFaceAttributes() == 1);
00179 double attribute_value = face_data.AttributeValue;
00180 p_boundary_element->SetAttribute(attribute_value);
00181 }
00182 }
00183
00184 RefreshJacobianCachedData();
00185 rMeshReader.Reset();
00186 }
00187
00188 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00189 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ReadNodesPerProcessorFile(const std::string& rNodesPerProcessorFile)
00190 {
00191 std::vector<unsigned> nodes_per_processor_vec;
00192
00193 std::ifstream file_stream(rNodesPerProcessorFile.c_str());
00194 if (file_stream.is_open())
00195 {
00196 while (file_stream)
00197 {
00198 unsigned nodes_per_processor;
00199 file_stream >> nodes_per_processor;
00200
00201 if (file_stream)
00202 {
00203 nodes_per_processor_vec.push_back(nodes_per_processor);
00204 }
00205 }
00206 }
00207 else
00208 {
00209 EXCEPTION("Unable to read nodes per processor file " + rNodesPerProcessorFile);
00210 }
00211
00212 unsigned sum = 0;
00213 for (unsigned i=0; i<nodes_per_processor_vec.size(); i++)
00214 {
00215 sum += nodes_per_processor_vec[i];
00216 }
00217
00218 if (sum != this->GetNumNodes())
00219 {
00220 EXCEPTION("Sum of nodes per processor, " << sum
00221 << ", not equal to number of nodes in mesh, " << this->GetNumNodes());
00222 }
00223
00224 unsigned num_owned=nodes_per_processor_vec[PetscTools::GetMyRank()];
00225
00226 if (nodes_per_processor_vec.size() != PetscTools::GetNumProcs())
00227 {
00228 EXCEPTION("Number of processes doesn't match the size of the nodes-per-processor file");
00229 }
00230 delete this->mpDistributedVectorFactory;
00231 this->mpDistributedVectorFactory = new DistributedVectorFactory(this->GetNumNodes(), num_owned);
00232 }
00233 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00234 bool TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::CheckIsConforming()
00235 {
00236
00237
00238
00239
00240
00241
00242
00243 std::set< std::set<unsigned> > odd_parity_faces;
00244
00245 for (typename AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ElementIterator iter = this->GetElementIteratorBegin();
00246 iter != this->GetElementIteratorEnd();
00247 ++iter)
00248 {
00249 for (unsigned face_index=0; face_index<=ELEMENT_DIM; face_index++)
00250 {
00251 std::set<unsigned> face_info;
00252 for (unsigned node_index=0; node_index<=ELEMENT_DIM; node_index++)
00253 {
00254
00255 if (node_index != face_index)
00256 {
00257 face_info.insert(iter->GetNodeGlobalIndex(node_index));
00258 }
00259 }
00260
00261 std::set< std::set<unsigned> >::iterator find_face=odd_parity_faces.find(face_info);
00262 if (find_face != odd_parity_faces.end())
00263 {
00264
00265
00266 odd_parity_faces.erase(find_face);
00267 }
00268 else
00269 {
00270
00271 odd_parity_faces.insert(face_info);
00272 }
00273
00274 }
00275 }
00276
00277
00278
00279
00280
00281
00282 return(odd_parity_faces.size() == this->GetNumBoundaryElements());
00283 }
00284
00285 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00286 double TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::GetVolume()
00287 {
00288 double mesh_volume = 0.0;
00289
00290 for (typename AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ElementIterator iter = this->GetElementIteratorBegin();
00291 iter != this->GetElementIteratorEnd();
00292 ++iter)
00293 {
00294 mesh_volume += iter->GetVolume(mElementJacobianDeterminants[iter->GetIndex()]);
00295 }
00296
00297 return mesh_volume;
00298 }
00299
00300 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00301 double TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::GetSurfaceArea()
00302 {
00303
00304 assert(ELEMENT_DIM >= 1);
00305 const unsigned bound_element_dim = ELEMENT_DIM-1;
00306 assert(bound_element_dim < 3);
00307 if ( bound_element_dim == 0)
00308 {
00309 return 0.0;
00310 }
00311
00312 double mesh_surface = 0.0;
00313 typename TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::BoundaryElementIterator it = this->GetBoundaryElementIteratorBegin();
00314
00315 while (it != this->GetBoundaryElementIteratorEnd())
00316 {
00317 mesh_surface += mBoundaryElementJacobianDeterminants[(*it)->GetIndex()];
00318 it++;
00319 }
00320
00321 if ( bound_element_dim == 2)
00322 {
00323 mesh_surface /= 2.0;
00324 }
00325
00326 return mesh_surface;
00327 }
00328
00329 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00330 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::PermuteNodes()
00331 {
00332
00333 RandomNumberGenerator* p_rng = RandomNumberGenerator::Instance();
00334 std::vector<unsigned> perm;
00335 p_rng->Shuffle(this->mNodes.size(), perm);
00336
00337
00338 PermuteNodes(perm);
00339 }
00340
00341 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00342 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::PermuteNodes(const std::vector<unsigned>& perm)
00343 {
00344
00345 assert( this->GetNumAllNodes() == this->GetNumNodes());
00346
00347 assert(perm.size() == this->mNodes.size());
00348
00349
00350 std::vector< Node<SPACE_DIM>* > copy_m_nodes;
00351 copy_m_nodes.assign(this->mNodes.begin(), this->mNodes.end());
00352
00353 for (unsigned original_index=0; original_index<this->mNodes.size(); original_index++)
00354 {
00355 assert(perm[original_index] < this->mNodes.size());
00356
00357 this->mNodes[ perm[original_index] ] = copy_m_nodes[original_index];
00358 }
00359
00360
00361 for (unsigned index=0; index<this->mNodes.size(); index++)
00362 {
00363 this->mNodes[index]->SetIndex(index);
00364 }
00365
00366
00367 this->mNodePermutation = perm;
00368 }
00369
00370 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00371 unsigned TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::GetContainingElementIndexWithInitialGuess(const ChastePoint<SPACE_DIM>& rTestPoint, unsigned startingElementGuess, bool strict)
00372 {
00373 assert(startingElementGuess<this->GetNumElements());
00374
00375
00376
00377
00378
00379 unsigned i = startingElementGuess;
00380 bool reached_end = false;
00381
00382 while (!reached_end)
00383 {
00384 if (this->mElements[i]->IncludesPoint(rTestPoint, strict))
00385 {
00386 assert(!this->mElements[i]->IsDeleted());
00387 return i;
00388 }
00389
00390
00391 i++;
00392 if (i==this->GetNumElements())
00393 {
00394 i=0;
00395 }
00396
00397
00398 if (i==startingElementGuess)
00399 {
00400 reached_end = true;
00401 }
00402 }
00403
00404
00405 std::stringstream ss;
00406 ss << "Point [";
00407 for (unsigned j=0; (int)j<(int)SPACE_DIM-1; j++)
00408 {
00409 ss << rTestPoint[j] << ",";
00410 }
00411 ss << rTestPoint[SPACE_DIM-1] << "] is not in mesh - all elements tested";
00412 EXCEPTION(ss.str());
00413 }
00414
00415
00416 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00417 unsigned TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::GetNearestElementIndex(const ChastePoint<SPACE_DIM>& rTestPoint)
00418 {
00419 double max_min_weight = -std::numeric_limits<double>::infinity();
00420 unsigned closest_index = 0;
00421 for (unsigned i=0; i<this->mElements.size(); i++)
00422 {
00423 c_vector<double, ELEMENT_DIM+1> weight=this->mElements[i]->CalculateInterpolationWeights(rTestPoint);
00424 double neg_weight_sum=0.0;
00425 for (unsigned j=0; j<=ELEMENT_DIM; j++)
00426 {
00427 if (weight[j] < 0.0)
00428 {
00429 neg_weight_sum += weight[j];
00430 }
00431 }
00432 if (neg_weight_sum > max_min_weight)
00433 {
00434 max_min_weight = neg_weight_sum;
00435 closest_index = i;
00436 }
00437 }
00438 assert(!this->mElements[closest_index]->IsDeleted());
00439 return closest_index;
00440 }
00441
00442 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00443 std::vector<unsigned> TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::GetContainingElementIndices(const ChastePoint<SPACE_DIM> &rTestPoint)
00444 {
00445 std::vector<unsigned> element_indices;
00446 for (unsigned i=0; i<this->mElements.size(); i++)
00447 {
00448 if (this->mElements[i]->IncludesPoint(rTestPoint))
00449 {
00450 assert(!this->mElements[i]->IsDeleted());
00451 element_indices.push_back(i);
00452 }
00453 }
00454 return element_indices;
00455 }
00456
00457 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00458 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::Clear()
00459 {
00460
00461 for (unsigned i=0; i<this->mBoundaryElements.size(); i++)
00462 {
00463 delete this->mBoundaryElements[i];
00464 }
00465 for (unsigned i=0; i<this->mElements.size(); i++)
00466 {
00467 delete this->mElements[i];
00468 }
00469 for (unsigned i=0; i<this->mNodes.size(); i++)
00470 {
00471 delete this->mNodes[i];
00472 }
00473
00474 this->mNodes.clear();
00475 this->mElements.clear();
00476 this->mBoundaryElements.clear();
00477 this->mBoundaryNodes.clear();
00478 }
00479
00480 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00481 std::set<unsigned> TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::CalculateBoundaryOfFlaggedRegion()
00482 {
00483
00484 typedef std::set<unsigned> FaceNodes;
00485
00486
00487
00488
00489
00490 std::map<FaceNodes,bool> face_on_boundary;
00491
00492
00493 for (typename AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ElementIterator iter = this->GetElementIteratorBegin();
00494 iter != this->GetElementIteratorEnd();
00495 ++iter)
00496 {
00497 if (iter->IsFlagged())
00498 {
00499
00500 std::set<unsigned> all_nodes;
00501 for (unsigned i=0; i<ELEMENT_DIM+1; i++)
00502 {
00503 all_nodes.insert(iter->GetNodeGlobalIndex(i));
00504 }
00505
00506
00507 for (unsigned i=0; i<ELEMENT_DIM+1; i++)
00508 {
00509 FaceNodes face_nodes = all_nodes;
00510 face_nodes.erase(iter->GetNodeGlobalIndex(i));
00511
00512
00513 std::map<FaceNodes,bool>::iterator it = face_on_boundary.find(face_nodes);
00514
00515 if (it == face_on_boundary.end())
00516 {
00517
00518 face_on_boundary[face_nodes]=true;
00519 }
00520 else
00521 {
00522
00523 it->second = false;
00524 }
00525 }
00526 }
00527 }
00528
00529
00530 std::set<unsigned> boundary_of_flagged_region;
00531
00532
00533 std::map<FaceNodes,bool>::iterator it=face_on_boundary.begin();
00534 while (it!=face_on_boundary.end())
00535 {
00536
00537 if (it->second==true)
00538 {
00539
00540 boundary_of_flagged_region.insert(it->first.begin(),it->first.end());
00541 }
00542 it++;
00543 }
00544
00545 return boundary_of_flagged_region;
00546 }
00547
00548 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00549 double TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::GetAngleBetweenNodes(unsigned indexA, unsigned indexB)
00550 {
00551 assert(SPACE_DIM == 2);
00552 assert(SPACE_DIM == ELEMENT_DIM);
00553
00554 double x_difference = this->mNodes[indexB]->rGetLocation()[0] - this->mNodes[indexA]->rGetLocation()[0];
00555 double y_difference = this->mNodes[indexB]->rGetLocation()[1] - this->mNodes[indexA]->rGetLocation()[1];
00556
00557 if (x_difference == 0)
00558 {
00559 if (y_difference > 0)
00560 {
00561 return M_PI/2.0;
00562 }
00563 else if (y_difference < 0)
00564 {
00565 return -M_PI/2.0;
00566 }
00567 else
00568 {
00569 EXCEPTION("Tried to compute polar angle of (0,0)");
00570 }
00571 }
00572
00573 double angle = atan2(y_difference,x_difference);
00574 return angle;
00575 }
00576
00577 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00578 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::UnflagAllElements()
00579 {
00580 for (typename AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ElementIterator iter = this->GetElementIteratorBegin();
00581 iter != this->GetElementIteratorEnd();
00582 ++iter)
00583 {
00584 iter->Unflag();
00585 }
00586 }
00587
00588 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00589 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::FlagElementsNotContainingNodes(const std::set<unsigned>& rNodes)
00590 {
00591 for (typename AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ElementIterator iter = this->GetElementIteratorBegin();
00592 iter != this->GetElementIteratorEnd();
00593 ++iter)
00594 {
00595 bool found_node = false;
00596
00597 for (unsigned i=0; i<iter->GetNumNodes(); i++)
00598 {
00599 unsigned node_index = iter->GetNodeGlobalIndex(i);
00600
00601 std::set<unsigned>::iterator set_iter = rNodes.find(node_index);
00602 if (set_iter != rNodes.end())
00603 {
00604 found_node = true;
00605 }
00606 }
00607
00608 if (!found_node)
00609 {
00610 iter->Flag();
00611 }
00612 }
00613 }
00614
00616
00618
00619 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00620 Node<SPACE_DIM>* TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::EdgeIterator::GetNodeA()
00621 {
00622 assert((*this) != mrMesh.EdgesEnd());
00623 Element<ELEMENT_DIM,SPACE_DIM>* p_element = mrMesh.GetElement(mElemIndex);
00624 return p_element->GetNode(mNodeALocalIndex);
00625 }
00626
00627 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00628 Node<SPACE_DIM>* TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::EdgeIterator::GetNodeB()
00629 {
00630 assert((*this) != mrMesh.EdgesEnd());
00631 Element<ELEMENT_DIM,SPACE_DIM>* p_element = mrMesh.GetElement(mElemIndex);
00632 return p_element->GetNode(mNodeBLocalIndex);
00633 }
00634
00635 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00636 bool TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::EdgeIterator::operator!=(const typename TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::EdgeIterator& rOther)
00637 {
00638 return (mElemIndex != rOther.mElemIndex ||
00639 mNodeALocalIndex != rOther.mNodeALocalIndex ||
00640 mNodeBLocalIndex != rOther.mNodeBLocalIndex);
00641 }
00642
00643 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00644 typename TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::EdgeIterator& TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::EdgeIterator::operator++()
00645 {
00646 bool already_seen_this_edge;
00647
00648 unsigned num_elements = mrMesh.GetNumAllElements();
00649 std::pair<unsigned, unsigned> current_node_pair;
00650 do
00651 {
00652
00653
00654
00655
00656 mNodeBLocalIndex = (mNodeBLocalIndex + 1) % (ELEMENT_DIM+1);
00657 if (mNodeBLocalIndex == mNodeALocalIndex)
00658 {
00659 mNodeALocalIndex = (mNodeALocalIndex + 1) % (ELEMENT_DIM+1);
00660 mNodeBLocalIndex = (mNodeALocalIndex + 1) % (ELEMENT_DIM+1);
00661 }
00662
00663 if (mNodeALocalIndex == 0 && mNodeBLocalIndex == 1)
00664 {
00665
00666 do
00667 {
00668 mElemIndex++;
00669 }
00670 while (mElemIndex!=num_elements && mrMesh.GetElement(mElemIndex)->IsDeleted());
00671 }
00672
00673 if (mElemIndex != num_elements)
00674 {
00675 Element<ELEMENT_DIM, SPACE_DIM>* p_element = mrMesh.GetElement(mElemIndex);
00676 unsigned node_a_global_index = p_element->GetNodeGlobalIndex(mNodeALocalIndex);
00677 unsigned node_b_global_index = p_element->GetNodeGlobalIndex(mNodeBLocalIndex);
00678 if (node_b_global_index < node_a_global_index)
00679 {
00680
00681 unsigned temp = node_a_global_index;
00682 node_a_global_index = node_b_global_index;
00683 node_b_global_index = temp;
00684 }
00685
00686
00687 current_node_pair = std::pair<unsigned, unsigned>(node_a_global_index, node_b_global_index);
00688 already_seen_this_edge = (mEdgesVisited.count(current_node_pair) != 0);
00689 }
00690 else
00691 {
00692 already_seen_this_edge = false;
00693 }
00694 }
00695
00696 while (already_seen_this_edge);
00697 mEdgesVisited.insert(current_node_pair);
00698
00699 return (*this);
00700 }
00701
00702 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00703 TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::EdgeIterator::EdgeIterator(TetrahedralMesh& rMesh, unsigned elemIndex)
00704 : mrMesh(rMesh),
00705 mElemIndex(elemIndex),
00706 mNodeALocalIndex(0),
00707 mNodeBLocalIndex(1)
00708 {
00709 if (elemIndex == mrMesh.GetNumAllElements())
00710 {
00711 return;
00712 }
00713
00714 mEdgesVisited.clear();
00715
00716
00717 unsigned node_a_global_index = mrMesh.GetElement(mElemIndex)->GetNodeGlobalIndex(mNodeALocalIndex);
00718 unsigned node_b_global_index = mrMesh.GetElement(mElemIndex)->GetNodeGlobalIndex(mNodeBLocalIndex);
00719 if (node_b_global_index < node_a_global_index)
00720 {
00721
00722 unsigned temp = node_a_global_index;
00723 node_a_global_index = node_b_global_index;
00724 node_b_global_index = temp;
00725 }
00726
00727
00728 std::pair<unsigned, unsigned> current_node_pair = std::pair<unsigned, unsigned>(node_a_global_index, node_b_global_index);
00729 mEdgesVisited.insert(current_node_pair);
00730 }
00731
00732 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00733 typename TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::EdgeIterator TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::EdgesBegin()
00734 {
00735 unsigned first_element_index = 0;
00736 while (first_element_index!=this->GetNumAllElements() && this->GetElement(first_element_index)->IsDeleted())
00737 {
00738 first_element_index++;
00739 }
00740 return EdgeIterator(*this, first_element_index);
00741 }
00742
00743 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00744 typename TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::EdgeIterator TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::EdgesEnd()
00745 {
00746 return EdgeIterator(*this, this->GetNumAllElements());
00747 }
00748
00749 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00750 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::RefreshMesh()
00751 {
00752 RefreshJacobianCachedData();
00753 }
00754
00755 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00756 unsigned TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::SolveNodeMapping(unsigned index) const
00757 {
00758 assert(index < this->mNodes.size() );
00759 return index;
00760 }
00761
00762 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00763 unsigned TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::SolveElementMapping(unsigned index) const
00764 {
00765 assert(index < this->mElements.size() );
00766 return index;
00767 }
00768
00769 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00770 unsigned TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::SolveBoundaryElementMapping(unsigned index) const
00771 {
00772 assert(index < this->mBoundaryElements.size() );
00773 return index;
00774 }
00775
00776 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00777 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::RefreshJacobianCachedData()
00778 {
00779 unsigned num_elements = this->GetNumAllElements();
00780 unsigned num_boundary_elements = this->GetNumAllBoundaryElements();
00781
00782
00783 this->mElementJacobians.resize(num_elements);
00784 this->mElementInverseJacobians.resize(num_elements);
00785
00786 if (ELEMENT_DIM < SPACE_DIM)
00787 {
00788 this->mElementWeightedDirections.resize(num_elements);
00789 }
00790
00791 this->mBoundaryElementWeightedDirections.resize(num_boundary_elements);
00792
00793 this->mElementJacobianDeterminants.resize(num_elements);
00794 this->mBoundaryElementJacobianDeterminants.resize(num_boundary_elements);
00795
00796
00797 for (typename AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ElementIterator iter = this->GetElementIteratorBegin();
00798 iter != this->GetElementIteratorEnd();
00799 ++iter)
00800 {
00801 unsigned index = iter->GetIndex();
00802 iter->CalculateInverseJacobian(this->mElementJacobians[index], this->mElementJacobianDeterminants[index], this->mElementInverseJacobians[index]);
00803 }
00804
00805 if (ELEMENT_DIM < SPACE_DIM)
00806 {
00807 for (typename AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ElementIterator iter = this->GetElementIteratorBegin();
00808 iter != this->GetElementIteratorEnd();
00809 ++iter)
00810 {
00811 unsigned index = iter->GetIndex();
00812 iter->CalculateWeightedDirection(this->mElementWeightedDirections[index], this->mElementJacobianDeterminants[index]);
00813 }
00814 }
00815
00816 for ( typename TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::BoundaryElementIterator itb = this->GetBoundaryElementIteratorBegin();
00817 itb != this->GetBoundaryElementIteratorEnd();
00818 itb++)
00819 {
00820 unsigned index = (*itb)->GetIndex();
00821 (*itb)->CalculateWeightedDirection(this->mBoundaryElementWeightedDirections[index], this->mBoundaryElementJacobianDeterminants[index]);
00822 }
00823 }
00824
00825 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00826 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::GetJacobianForElement(unsigned elementIndex, c_matrix<double, SPACE_DIM, SPACE_DIM>& rJacobian, double& rJacobianDeterminant) const
00827 {
00828 assert(ELEMENT_DIM <= SPACE_DIM);
00829 assert(elementIndex < this->mElementJacobians.size());
00830 rJacobian = this->mElementJacobians[elementIndex];
00831 rJacobianDeterminant = this->mElementJacobianDeterminants[elementIndex];
00832 }
00833
00834 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00835 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
00836 {
00837 assert(ELEMENT_DIM <= SPACE_DIM);
00838 assert(elementIndex < this->mElementInverseJacobians.size());
00839 rInverseJacobian = this->mElementInverseJacobians[elementIndex];
00840 rJacobian = this->mElementJacobians[elementIndex];
00841 rJacobianDeterminant = this->mElementJacobianDeterminants[elementIndex];
00842 }
00843
00844 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00845 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::GetWeightedDirectionForElement(unsigned elementIndex, c_vector<double, SPACE_DIM>& rWeightedDirection, double& rJacobianDeterminant) const
00846 {
00847 assert(ELEMENT_DIM < SPACE_DIM);
00848 assert(elementIndex < this->mElementWeightedDirections.size());
00849 rWeightedDirection = this->mElementWeightedDirections[elementIndex];
00850 rJacobianDeterminant = this->mElementJacobianDeterminants[elementIndex];
00851 }
00852
00853 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00854 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::GetWeightedDirectionForBoundaryElement(unsigned elementIndex, c_vector<double, SPACE_DIM>& rWeightedDirection, double& rJacobianDeterminant) const
00855 {
00856 assert(elementIndex < this->mBoundaryElementWeightedDirections.size());
00857 rWeightedDirection = this->mBoundaryElementWeightedDirections[elementIndex];
00858 rJacobianDeterminant = this->mBoundaryElementJacobianDeterminants[elementIndex];
00859 }
00860
00861 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00862 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::InitialiseTriangulateIo(triangulateio& mesherIo)
00863 {
00864 mesherIo.numberofpoints = 0;
00865 mesherIo.pointlist = NULL;
00866 mesherIo.numberofpointattributes = 0;
00867 mesherIo.pointattributelist = (double *) NULL;
00868 mesherIo.pointmarkerlist = (int *) NULL;
00869 mesherIo.numberofsegments = 0;
00870 mesherIo.numberofholes = 0;
00871 mesherIo.numberofregions = 0;
00872 mesherIo.trianglelist = (int *) NULL;
00873 mesherIo.triangleattributelist = (double *) NULL;
00874 mesherIo.numberoftriangleattributes = 0;
00875 mesherIo.edgelist = (int *) NULL;
00876 mesherIo.edgemarkerlist = (int *) NULL;
00877 }
00878
00879 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00880 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::FreeTriangulateIo(triangulateio& mesherIo)
00881 {
00882 if (mesherIo.numberofpoints != 0)
00883 {
00884 mesherIo.numberofpoints=0;
00885 free(mesherIo.pointlist);
00886 }
00887
00888
00889 free(mesherIo.pointattributelist);
00890 free(mesherIo.pointmarkerlist);
00891 free(mesherIo.trianglelist);
00892 free(mesherIo.triangleattributelist);
00893 free(mesherIo.edgelist);
00894 free(mesherIo.edgemarkerlist);
00895 }
00896
00897 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00898 template <class MESHER_IO>
00899 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ExportToMesher(NodeMap& map, MESHER_IO& mesherInput, int *elementList)
00900 {
00901 if (SPACE_DIM == 2)
00902 {
00903 mesherInput.pointlist = (double *) malloc(this->GetNumNodes() * SPACE_DIM * sizeof(double));
00904 }
00905 else
00906 {
00907 mesherInput.pointlist = new double[this->GetNumNodes() * SPACE_DIM];
00908 }
00909
00910 mesherInput.numberofpoints = this->GetNumNodes();
00911 unsigned new_index = 0;
00912 for (unsigned i=0; i<this->GetNumAllNodes(); i++)
00913 {
00914 if (this->mNodes[i]->IsDeleted())
00915 {
00916 map.SetDeleted(i);
00917 }
00918 else
00919 {
00920 map.SetNewIndex(i, new_index);
00921 for (unsigned j=0; j<SPACE_DIM; j++)
00922 {
00923 mesherInput.pointlist[SPACE_DIM*new_index + j] = this->mNodes[i]->rGetLocation()[j];
00924 }
00925 new_index++;
00926 }
00927 }
00928 if (elementList != NULL)
00929 {
00930 unsigned element_index = 0;
00931
00932
00933 mesherInput.numberofcorners=ELEMENT_DIM+1;
00934 for (typename TetrahedralMesh<ELEMENT_DIM,SPACE_DIM>::ElementIterator elem_iter = this->GetElementIteratorBegin();
00935 elem_iter != this->GetElementIteratorEnd();
00936 ++elem_iter)
00937 {
00938
00939 for (unsigned j=0; j<=ELEMENT_DIM; j++)
00940 {
00941 elementList[element_index*(ELEMENT_DIM+1) + j] = (*elem_iter).GetNodeGlobalIndex(j);
00942 }
00943 element_index++;
00944 }
00945 }
00946 }
00947
00948 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00949 template <class MESHER_IO>
00950 void TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ImportFromMesher(MESHER_IO& mesherOutput, unsigned numberOfElements, int *elementList, unsigned numberOfFaces, int *faceList, int *edgeMarkerList)
00951 {
00952 unsigned nodes_per_element = mesherOutput.numberofcorners;
00953
00954 assert( nodes_per_element == ELEMENT_DIM+1 || nodes_per_element == (ELEMENT_DIM+1)*(ELEMENT_DIM+2)/2 );
00955
00956 Clear();
00957
00958
00959 for (unsigned node_index=0; node_index<(unsigned)mesherOutput.numberofpoints; node_index++)
00960 {
00961 this->mNodes.push_back(new Node<SPACE_DIM>(node_index, &mesherOutput.pointlist[node_index * SPACE_DIM], false));
00962 }
00963
00964
00965 this->mElements.reserve(numberOfElements);
00966
00967 unsigned real_element_index=0;
00968 for (unsigned element_index=0; element_index<numberOfElements; element_index++)
00969 {
00970 std::vector<Node<SPACE_DIM>*> nodes;
00971 for (unsigned j=0; j<ELEMENT_DIM+1; j++)
00972 {
00973 unsigned global_node_index = elementList[element_index*(nodes_per_element) + j];
00974 assert(global_node_index < this->mNodes.size());
00975 nodes.push_back(this->mNodes[global_node_index]);
00976
00977 }
00978
00979
00980
00981
00982
00983 Element<ELEMENT_DIM, SPACE_DIM>* p_element;
00984 try
00985 {
00986 p_element = new Element<ELEMENT_DIM, SPACE_DIM>(real_element_index, nodes);
00987
00988
00989 this->mElements.push_back(p_element);
00990
00991
00992 for (unsigned j=ELEMENT_DIM+1; j<nodes_per_element; j++)
00993 {
00994 unsigned global_node_index = elementList[element_index*nodes_per_element + j];
00995 assert(global_node_index < this->mNodes.size());
00996 this->mElements[real_element_index]->AddNode( this->mNodes[global_node_index] );
00997 this->mNodes[global_node_index]->AddElement(real_element_index);
00998 this->mNodes[global_node_index]->MarkAsInternal();
00999 }
01000 real_element_index++;
01001 }
01002 catch (Exception &)
01003 {
01004 if (SPACE_DIM == 2)
01005 {
01006 WARNING("Triangle has produced a zero area (collinear) element");
01007 }
01008 else
01009 {
01010 WARNING("Tetgen has produced a zero volume (coplanar) element");
01011 }
01012 }
01013 }
01014
01015
01016 unsigned next_boundary_element_index = 0;
01017 for (unsigned boundary_element_index=0; boundary_element_index<numberOfFaces; boundary_element_index++)
01018 {
01019
01020
01021
01022
01023 if (edgeMarkerList == NULL || edgeMarkerList[boundary_element_index] == 1)
01024 {
01025 std::vector<Node<SPACE_DIM>*> nodes;
01026 for (unsigned j=0; j<ELEMENT_DIM; j++)
01027 {
01028 unsigned global_node_index = faceList[boundary_element_index*ELEMENT_DIM + j];
01029 assert(global_node_index < this->mNodes.size());
01030 nodes.push_back(this->mNodes[global_node_index]);
01031 if (!nodes[j]->IsBoundaryNode())
01032 {
01033 nodes[j]->SetAsBoundaryNode();
01034 this->mBoundaryNodes.push_back(nodes[j]);
01035 }
01036 }
01037
01038
01039
01040
01041
01042 BoundaryElement<ELEMENT_DIM-1, SPACE_DIM>* p_b_element;
01043 try
01044 {
01045 p_b_element = new BoundaryElement<ELEMENT_DIM-1, SPACE_DIM>(next_boundary_element_index, nodes);
01046 this->mBoundaryElements.push_back(p_b_element);
01047 next_boundary_element_index++;
01048 }
01049 catch (Exception &)
01050 {
01051
01052 assert(SPACE_DIM == 3);
01053 }
01054 }
01055 }
01056
01057 this->RefreshJacobianCachedData();
01058 }
01059
01061
01063
01064 template class TetrahedralMesh<1,1>;
01065 template class TetrahedralMesh<1,2>;
01066 template class TetrahedralMesh<1,3>;
01067 template class TetrahedralMesh<2,2>;
01068 template class TetrahedralMesh<2,3>;
01069 template class TetrahedralMesh<3,3>;
01070
01075 template void TetrahedralMesh<2,2>::ExportToMesher<triangulateio>(NodeMap&, triangulateio&, int*);
01076 template void TetrahedralMesh<2,2>::ImportFromMesher<triangulateio>(triangulateio&, unsigned, int *, unsigned, int *, int *);
01077
01078 template void TetrahedralMesh<3,3>::ExportToMesher<tetgen::tetgenio>(NodeMap&, tetgen::tetgenio&, int*);
01079 template void TetrahedralMesh<3,3>::ImportFromMesher<tetgen::tetgenio>(tetgen::tetgenio&, unsigned, int *, unsigned, int *, int *);
01080
01081
01082 template void TetrahedralMesh<1,2>::ExportToMesher<triangulateio>(NodeMap&, triangulateio&, int*);
01083 template void TetrahedralMesh<1,2>::ImportFromMesher<triangulateio>(triangulateio&, unsigned, int *, unsigned, int *, int *);
01084
01085 template void TetrahedralMesh<1,3>::ExportToMesher<tetgen::tetgenio>(NodeMap&, tetgen::tetgenio&, int*);
01086 template void TetrahedralMesh<1,3>::ImportFromMesher<tetgen::tetgenio>(tetgen::tetgenio&, unsigned, int *, unsigned, int *, int *);
01087 template void TetrahedralMesh<2,3>::ExportToMesher<tetgen::tetgenio>(NodeMap&, tetgen::tetgenio&, int*);
01088 template void TetrahedralMesh<2,3>::ImportFromMesher<tetgen::tetgenio>(tetgen::tetgenio&, unsigned, int *, unsigned, int *, int *);
01089
01090
01091 template void TetrahedralMesh<3u, 3u>::ImportFromMesher<triangulateio>(triangulateio&, unsigned int, int*, unsigned int, int*, int*);
01092 template void TetrahedralMesh<1u, 1u>::ImportFromMesher<triangulateio>(triangulateio&, unsigned int, int*, unsigned int, int*, int*);
01093 template void TetrahedralMesh<1u, 1u>::ImportFromMesher<tetgen::tetgenio>(tetgen::tetgenio&, unsigned int, int*, unsigned int, int*, int*);
01094 template void TetrahedralMesh<2u, 2u>::ImportFromMesher<tetgen::tetgenio>(tetgen::tetgenio&, unsigned int, int*, unsigned int, int*, int*);
01095 template void TetrahedralMesh<1u, 1u>::ExportToMesher<tetgen::tetgenio>(NodeMap&, tetgen::tetgenio&, int*);
01096
01097
01098
01099
01100
01101
01102
01103
01104
01105
01106
01107 #ifdef _MSC_VER
01108
01109 template void TetrahedralMesh<2,2>::ExportToMesher<tetgen::tetgenio>(NodeMap&, tetgen::tetgenio&, int*);
01110 template void TetrahedralMesh<3,3>::ExportToMesher<triangulateio>(NodeMap&, triangulateio&, int*);
01111 template void TetrahedralMesh<1,3>::ExportToMesher<triangulateio>(NodeMap&, triangulateio&, int*);
01112 template void TetrahedralMesh<1,1>::ExportToMesher<triangulateio>(NodeMap&, triangulateio&, int*);
01113 template void TetrahedralMesh<1,2>::ExportToMesher<tetgen::tetgenio>(NodeMap&, tetgen::tetgenio&, int*);
01114 template void TetrahedralMesh<2,3>::ExportToMesher<triangulateio>(NodeMap&, triangulateio&, int*);
01115 template void TetrahedralMesh<1,3>::ImportFromMesher<triangulateio>(triangulateio&, unsigned, int *, unsigned, int *, int *);
01116 template void TetrahedralMesh<2,3>::ImportFromMesher<triangulateio>(triangulateio&, unsigned, int *, unsigned, int *, int *);
01117 template void TetrahedralMesh<1,2>::ImportFromMesher<tetgen::tetgenio>(tetgen::tetgenio&, unsigned, int *, unsigned, int *, int *);
01118 #endif
01119
01124
01125 #define CHASTE_SERIALIZATION_CPP
01126 #include "SerializationExportWrapper.hpp"
01127 EXPORT_TEMPLATE_CLASS_ALL_DIMS(TetrahedralMesh)