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