36 #include "TetrahedralMesh.hpp"
44 #include "BoundaryElement.hpp"
45 #include "Element.hpp"
48 #include "OutputFileHandler.hpp"
50 #include "RandomNumberGenerator.hpp"
51 #include "Warnings.hpp"
61 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
67 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
81 this->mNodes.reserve(num_nodes);
89 std::vector<double> coords;
90 for (
unsigned node_index = 0; node_index < num_nodes; node_index++)
100 this->mNodes.push_back(p_node);
113 std::vector<Node<SPACE_DIM>*> nodes;
121 for (
unsigned j = 0; j < ELEMENT_DIM + 1; j++)
123 assert(element_data.
NodeIndices[j] < this->mNodes.size());
124 nodes.push_back(this->mNodes[element_data.
NodeIndices[j]]);
129 this->mElements.push_back(p_element);
140 for (
unsigned face_index = 0; face_index < (
unsigned)rMeshReader.
GetNumFaces(); face_index++)
143 std::vector<unsigned> node_indices = face_data.
NodeIndices;
151 std::vector<Node<SPACE_DIM>*> nodes;
152 for (
unsigned node_index = 0; node_index < node_indices.size(); node_index++)
154 assert(node_indices[node_index] < this->mNodes.size());
156 nodes.push_back(this->mNodes[node_indices[node_index]]);
160 for (
unsigned j = 0; j < nodes.size(); j++)
162 if (!nodes[j]->IsBoundaryNode())
164 nodes[j]->SetAsBoundaryNode();
165 this->mBoundaryNodes.push_back(nodes[j]);
169 nodes[j]->AddBoundaryElement(face_index);
174 this->mBoundaryElements.push_back(p_boundary_element);
180 p_boundary_element->SetAttribute(attribute_value);
184 RefreshJacobianCachedData();
189 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
192 std::vector<unsigned> nodes_per_processor_vec;
194 std::ifstream file_stream(rNodesPerProcessorFile.c_str());
195 if (file_stream.is_open())
199 unsigned nodes_per_processor;
200 file_stream >> nodes_per_processor;
204 nodes_per_processor_vec.push_back(nodes_per_processor);
210 EXCEPTION(
"Unable to read nodes per processor file " + rNodesPerProcessorFile);
214 for (
unsigned i = 0; i < nodes_per_processor_vec.size(); i++)
216 sum += nodes_per_processor_vec[i];
219 if (sum != this->GetNumNodes())
221 EXCEPTION(
"Sum of nodes per processor, " << sum
222 <<
", not equal to number of nodes in mesh, " << this->GetNumNodes());
229 EXCEPTION(
"Number of processes doesn't match the size of the nodes-per-processor file");
231 delete this->mpDistributedVectorFactory;
235 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
245 std::set<std::set<unsigned> > odd_parity_faces;
248 iter != this->GetElementIteratorEnd();
251 for (
unsigned face_index = 0; face_index <= ELEMENT_DIM; face_index++)
253 std::set<unsigned> face_info;
254 for (
unsigned node_index = 0; node_index <= ELEMENT_DIM; node_index++)
257 if (node_index != face_index)
259 face_info.insert(iter->GetNodeGlobalIndex(node_index));
263 std::set<std::set<unsigned> >::iterator find_face = odd_parity_faces.find(face_info);
264 if (find_face != odd_parity_faces.end())
268 odd_parity_faces.erase(find_face);
273 odd_parity_faces.insert(face_info);
283 return (odd_parity_faces.size() == this->GetNumBoundaryElements());
286 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
289 double mesh_volume = 0.0;
292 iter != this->GetElementIteratorEnd();
295 mesh_volume += iter->GetVolume(mElementJacobianDeterminants[iter->GetIndex()]);
301 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
305 assert(ELEMENT_DIM >= 1);
306 const unsigned bound_element_dim = ELEMENT_DIM - 1;
307 assert(bound_element_dim < 3);
308 if (bound_element_dim == 0)
313 double mesh_surface = 0.0;
316 while (it != this->GetBoundaryElementIteratorEnd())
318 mesh_surface += mBoundaryElementJacobianDeterminants[(*it)->GetIndex()];
322 if (bound_element_dim == 2)
330 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
335 std::vector<unsigned> perm;
336 p_rng->
Shuffle(this->mNodes.size(), perm);
342 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
346 assert(this->GetNumAllNodes() == this->GetNumNodes());
348 assert(perm.size() == this->mNodes.size());
351 std::vector<Node<SPACE_DIM>*> copy_m_nodes;
352 copy_m_nodes.assign(this->mNodes.begin(), this->mNodes.end());
354 for (
unsigned original_index = 0; original_index < this->mNodes.size(); original_index++)
356 assert(perm[original_index] < this->mNodes.size());
358 this->mNodes[perm[original_index]] = copy_m_nodes[original_index];
362 for (
unsigned index = 0; index < this->mNodes.size(); index++)
364 this->mNodes[index]->SetIndex(index);
368 this->mNodePermutation = perm;
371 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
374 assert(startingElementGuess < this->GetNumElements());
380 unsigned i = startingElementGuess;
381 bool reached_end =
false;
385 if (this->mElements[i]->IncludesPoint(rTestPoint, strict))
387 assert(!this->mElements[i]->IsDeleted());
393 if (i == this->GetNumElements())
399 if (i == startingElementGuess)
406 std::stringstream ss;
408 for (
unsigned j = 0; (int)j < (
int)SPACE_DIM - 1; j++)
410 ss << rTestPoint[j] <<
",";
412 ss << rTestPoint[SPACE_DIM - 1] <<
"] is not in mesh - all elements tested";
416 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
420 double max_min_weight = -std::numeric_limits<double>::infinity();
421 unsigned closest_index = 0;
422 for (
unsigned i = 0; i < this->mElements.size(); i++)
424 c_vector<double, ELEMENT_DIM + 1> weight = this->mElements[i]->CalculateInterpolationWeights(rTestPoint);
425 double neg_weight_sum = 0.0;
426 for (
unsigned j = 0; j <= ELEMENT_DIM; j++)
430 neg_weight_sum += weight[j];
433 if (neg_weight_sum > max_min_weight)
435 max_min_weight = neg_weight_sum;
439 assert(!this->mElements[closest_index]->IsDeleted());
440 return closest_index;
443 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
446 std::vector<unsigned> element_indices;
447 for (
unsigned i = 0; i < this->mElements.size(); i++)
449 if (this->mElements[i]->IncludesPoint(rTestPoint))
451 assert(!this->mElements[i]->IsDeleted());
452 element_indices.push_back(i);
455 return element_indices;
458 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
462 for (
unsigned i = 0; i < this->mBoundaryElements.size(); i++)
464 delete this->mBoundaryElements[i];
466 for (
unsigned i = 0; i < this->mElements.size(); i++)
468 delete this->mElements[i];
470 for (
unsigned i = 0; i < this->mNodes.size(); i++)
472 delete this->mNodes[i];
475 this->mNodes.clear();
476 this->mElements.clear();
477 this->mBoundaryElements.clear();
478 this->mBoundaryNodes.clear();
481 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
484 assert(SPACE_DIM == 2);
485 assert(SPACE_DIM == ELEMENT_DIM);
487 double x_difference = this->mNodes[indexB]->rGetLocation()[0] - this->mNodes[indexA]->rGetLocation()[0];
488 double y_difference = this->mNodes[indexB]->rGetLocation()[1] - this->mNodes[indexA]->rGetLocation()[1];
490 if (x_difference == 0)
492 if (y_difference > 0)
496 else if (y_difference < 0)
502 EXCEPTION(
"Tried to compute polar angle of (0,0)");
506 double angle = atan2(y_difference, x_difference);
514 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
522 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
525 assert((*
this) != mrMesh.EdgesEnd());
527 return p_element->
GetNode(mNodeBLocalIndex);
530 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
536 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
539 bool already_seen_this_edge;
541 unsigned num_elements = mrMesh.GetNumAllElements();
542 std::pair<unsigned, unsigned> current_node_pair;
549 mNodeBLocalIndex = (mNodeBLocalIndex + 1) % (ELEMENT_DIM + 1);
550 if (mNodeBLocalIndex == mNodeALocalIndex)
552 mNodeALocalIndex = (mNodeALocalIndex + 1) % (ELEMENT_DIM + 1);
553 mNodeBLocalIndex = (mNodeALocalIndex + 1) % (ELEMENT_DIM + 1);
556 if (mNodeALocalIndex == 0 && mNodeBLocalIndex == 1)
562 }
while (mElemIndex != num_elements && mrMesh.GetElement(mElemIndex)->IsDeleted());
565 if (mElemIndex != num_elements)
570 if (node_b_global_index < node_a_global_index)
573 unsigned temp = node_a_global_index;
574 node_a_global_index = node_b_global_index;
575 node_b_global_index = temp;
579 current_node_pair = std::pair<unsigned, unsigned>(node_a_global_index, node_b_global_index);
580 already_seen_this_edge = (mEdgesVisited.count(current_node_pair) != 0);
584 already_seen_this_edge =
false;
588 while (already_seen_this_edge);
589 mEdgesVisited.insert(current_node_pair);
594 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
597 mElemIndex(elemIndex),
611 if (node_b_global_index < node_a_global_index)
614 unsigned temp = node_a_global_index;
615 node_a_global_index = node_b_global_index;
616 node_b_global_index = temp;
620 std::pair<unsigned, unsigned> current_node_pair = std::pair<unsigned, unsigned>(node_a_global_index, node_b_global_index);
624 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
627 unsigned first_element_index = 0;
630 first_element_index++;
635 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
641 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
647 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
650 assert(index < this->
mNodes.size());
654 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
661 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
668 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
678 if (ELEMENT_DIM < SPACE_DIM)
693 unsigned index = iter->GetIndex();
697 if (ELEMENT_DIM < SPACE_DIM)
703 unsigned index = iter->GetIndex();
712 unsigned index = (*itb)->GetIndex();
717 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
720 assert(ELEMENT_DIM <= SPACE_DIM);
726 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
729 assert(ELEMENT_DIM <= SPACE_DIM);
736 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
739 assert(ELEMENT_DIM < SPACE_DIM);
745 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
753 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
756 mesherIo.numberofpoints = 0;
757 mesherIo.pointlist =
nullptr;
758 mesherIo.numberofpointattributes = 0;
759 mesherIo.pointattributelist = (
double*)
nullptr;
760 mesherIo.pointmarkerlist = (
int*)
nullptr;
761 mesherIo.numberofsegments = 0;
762 mesherIo.numberofholes = 0;
763 mesherIo.numberofregions = 0;
764 mesherIo.trianglelist = (
int*)
nullptr;
765 mesherIo.triangleattributelist = (
double*)
nullptr;
766 mesherIo.numberoftriangleattributes = 0;
767 mesherIo.edgelist = (
int*)
nullptr;
768 mesherIo.edgemarkerlist = (
int*)
nullptr;
771 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
774 if (mesherIo.numberofpoints != 0)
776 mesherIo.numberofpoints = 0;
777 free(mesherIo.pointlist);
781 free(mesherIo.pointattributelist);
782 free(mesherIo.pointmarkerlist);
783 free(mesherIo.trianglelist);
784 free(mesherIo.triangleattributelist);
785 free(mesherIo.edgelist);
786 free(mesherIo.edgemarkerlist);
789 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
790 template <
class MESHER_IO>
795 mesherInput.pointlist = (
double*)malloc(this->
GetNumNodes() * SPACE_DIM *
sizeof(
double));
799 mesherInput.pointlist =
new double[this->
GetNumNodes() * SPACE_DIM];
803 unsigned new_index = 0;
806 if (this->
mNodes[i]->IsDeleted())
813 for (
unsigned j = 0; j < SPACE_DIM; j++)
815 mesherInput.pointlist[SPACE_DIM * new_index + j] = this->
mNodes[i]->rGetLocation()[j];
820 if (elementList !=
nullptr)
822 unsigned element_index = 0;
825 mesherInput.numberofcorners = ELEMENT_DIM + 1;
831 for (
unsigned j = 0; j <= ELEMENT_DIM; j++)
833 elementList[element_index * (ELEMENT_DIM + 1) + j] = (*elem_iter).GetNodeGlobalIndex(j);
840 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
841 template <
class MESHER_IO>
844 unsigned nodes_per_element = mesherOutput.numberofcorners;
846 assert(nodes_per_element == ELEMENT_DIM + 1 || nodes_per_element == (ELEMENT_DIM + 1) * (ELEMENT_DIM + 2) / 2);
851 for (
unsigned node_index = 0; node_index < (
unsigned)mesherOutput.numberofpoints; node_index++)
853 this->
mNodes.push_back(
new Node<SPACE_DIM>(node_index, &mesherOutput.pointlist[node_index * SPACE_DIM],
false));
857 this->
mElements.reserve(numberOfElements);
859 unsigned real_element_index = 0;
860 for (
unsigned element_index = 0; element_index < numberOfElements; element_index++)
862 std::vector<Node<SPACE_DIM>*> nodes;
863 for (
unsigned j = 0; j < ELEMENT_DIM + 1; j++)
865 unsigned global_node_index = elementList[element_index * (nodes_per_element) + j];
866 assert(global_node_index < this->
mNodes.size());
867 nodes.push_back(this->
mNodes[global_node_index]);
883 for (
unsigned j = ELEMENT_DIM + 1; j < nodes_per_element; j++)
885 unsigned global_node_index = elementList[element_index * nodes_per_element + j];
886 assert(global_node_index < this->
mNodes.size());
887 this->
mElements[real_element_index]->AddNode(this->
mNodes[global_node_index]);
888 this->
mNodes[global_node_index]->AddElement(real_element_index);
889 this->
mNodes[global_node_index]->MarkAsInternal();
891 real_element_index++;
897 WARNING(
"Triangle has produced a zero area (collinear) element");
901 WARNING(
"Tetgen has produced a zero volume (coplanar) element");
907 unsigned next_boundary_element_index = 0;
908 for (
unsigned boundary_element_index = 0; boundary_element_index < numberOfFaces; boundary_element_index++)
914 if (edgeMarkerList ==
nullptr || edgeMarkerList[boundary_element_index] == 1)
916 std::vector<Node<SPACE_DIM>*> nodes;
917 for (
unsigned j = 0; j < ELEMENT_DIM; j++)
919 unsigned global_node_index = faceList[boundary_element_index * ELEMENT_DIM + j];
920 assert(global_node_index < this->
mNodes.size());
921 nodes.push_back(this->
mNodes[global_node_index]);
922 if (!nodes[j]->IsBoundaryNode())
924 nodes[j]->SetAsBoundaryNode();
936 p_b_element =
new BoundaryElement<ELEMENT_DIM - 1, SPACE_DIM>(next_boundary_element_index, nodes);
938 next_boundary_element_index++;
948 assert(SPACE_DIM == 3);
std::vector< c_matrix< double, SPACE_DIM, ELEMENT_DIM > > mElementJacobians
ElementIterator GetElementIteratorBegin(bool skipDeletedElements=true)
double GetAngleBetweenNodes(unsigned indexA, unsigned indexB)
std::vector< Element< ELEMENT_DIM, SPACE_DIM > * > mElements
void SetAttribute(double attribute)
std::vector< Node< SPACE_DIM > * > mBoundaryNodes
void ImportFromMesher(MESHER_IO &mesherOutput, unsigned numberOfElements, int *elementList, unsigned numberOfFaces, int *faceList, int *edgeMarkerList)
virtual ElementData GetNextElementData()=0
std::vector< unsigned > GetContainingElementIndices(const ChastePoint< SPACE_DIM > &rTestPoint)
BoundaryElementIterator GetBoundaryElementIteratorBegin() const
unsigned GetNodeGlobalIndex(unsigned localIndex) const
virtual void GetWeightedDirectionForBoundaryElement(unsigned elementIndex, c_vector< double, SPACE_DIM > &rWeightedDirection, double &rJacobianDeterminant) const
void AddNodeAttribute(double attribute)
unsigned GetContainingElementIndexWithInitialGuess(const ChastePoint< SPACE_DIM > &rTestPoint, unsigned startingElementGuess, bool strict=false)
ElementIterator GetElementIteratorEnd()
virtual void GetInverseJacobianForElement(unsigned elementIndex, c_matrix< double, SPACE_DIM, ELEMENT_DIM > &rJacobian, double &rJacobianDeterminant, c_matrix< double, ELEMENT_DIM, SPACE_DIM > &rInverseJacobian) const
#define EXCEPTION(message)
virtual void RefreshJacobianCachedData()
std::vector< c_matrix< double, ELEMENT_DIM, SPACE_DIM > > mElementInverseJacobians
Element< ELEMENT_DIM, SPACE_DIM > * GetElement(unsigned index) const
void ConstructFromMeshReader(AbstractMeshReader< ELEMENT_DIM, SPACE_DIM > &rMeshReader)
virtual unsigned GetNumNodes() const
virtual void GetJacobianForElement(unsigned elementIndex, c_matrix< double, SPACE_DIM, SPACE_DIM > &rJacobian, double &rJacobianDeterminant) const
virtual unsigned GetNumAllNodes() const
unsigned mNodeBLocalIndex
Node< SPACE_DIM > * GetNodeA()
void ExportToMesher(NodeMap &map, MESHER_IO &mesherInput, int *elementList=nullptr)
unsigned mNodeALocalIndex
void Shuffle(std::vector< boost::shared_ptr< T > > &rValues)
virtual ElementData GetNextFaceData()=0
std::vector< unsigned > NodeIndices
void SetNewIndex(unsigned oldIndex, unsigned newIndex)
EdgeIterator(TetrahedralMesh &rMesh, unsigned elemIndex)
Node< SPACE_DIM > * GetNode(unsigned localIndex) const
virtual bool HasNodePermutation()
Node< SPACE_DIM > * GetNodeB()
void ReadNodesPerProcessorFile(const std::string &rNodesPerProcessorFile)
unsigned SolveBoundaryElementMapping(unsigned index) const
std::vector< Node< SPACE_DIM > * > mNodes
virtual unsigned GetNumElements() const =0
void InitialiseTriangulateIo(triangulateio &mesherIo)
std::vector< BoundaryElement< ELEMENT_DIM-1, SPACE_DIM > * > mBoundaryElements
unsigned SolveElementMapping(unsigned index) const
void SetDeleted(unsigned index)
std::vector< double > mElementJacobianDeterminants
unsigned GetNearestElementIndex(const ChastePoint< SPACE_DIM > &rTestPoint)
std::vector< c_vector< double, SPACE_DIM > > mBoundaryElementWeightedDirections
#define EXCEPT_IF_NOT(test)
static RandomNumberGenerator * Instance()
#define EXPORT_TEMPLATE_CLASS_ALL_DIMS(CLASS)
virtual unsigned GetNumFaceAttributes() const
bool operator!=(const typename TetrahedralMesh< ELEMENT_DIM, SPACE_DIM >::EdgeIterator &rOther)
virtual unsigned GetNumElementAttributes() const
unsigned GetNumAllElements() const
EdgeIterator EdgesBegin()
unsigned SolveNodeMapping(unsigned index) const
std::vector< double > mBoundaryElementJacobianDeterminants
unsigned GetNumAllBoundaryElements() const
virtual void GetWeightedDirectionForElement(unsigned elementIndex, c_vector< double, SPACE_DIM > &rWeightedDirection, double &rJacobianDeterminant) const
virtual std::string GetMeshFileBaseName()
EdgeIterator & operator++()
virtual std::vector< double > GetNextNode()=0
std::vector< BoundaryElement< ELEMENT_DIM-1, SPACE_DIM > * >::const_iterator BoundaryElementIterator
std::vector< c_vector< double, SPACE_DIM > > mElementWeightedDirections
std::set< std::pair< unsigned, unsigned > > mEdgesVisited
virtual unsigned GetNumNodes() const =0
void FreeTriangulateIo(triangulateio &mesherIo)
virtual std::vector< double > GetNodeAttributes()
virtual unsigned GetNumFaces() const =0
BoundaryElementIterator GetBoundaryElementIteratorEnd() const