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