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