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++)
101 this->mNodes.push_back(p_node);
114 std::vector<Node<SPACE_DIM>*> nodes;
122 for (
unsigned j=0; j<ELEMENT_DIM+1; j++)
124 assert(element_data.
NodeIndices[j] < this->mNodes.size());
125 nodes.push_back(this->mNodes[element_data.
NodeIndices[j]]);
130 this->mElements.push_back(p_element);
144 std::vector<unsigned> node_indices = face_data.
NodeIndices;
152 std::vector<Node<SPACE_DIM>*> nodes;
153 for (
unsigned node_index=0; node_index<node_indices.size(); node_index++)
155 assert(node_indices[node_index] < this->mNodes.size());
157 nodes.push_back(this->mNodes[node_indices[node_index]]);
161 for (
unsigned j=0; j<nodes.size(); j++)
163 if (!nodes[j]->IsBoundaryNode())
165 nodes[j]->SetAsBoundaryNode();
166 this->mBoundaryNodes.push_back(nodes[j]);
170 nodes[j]->AddBoundaryElement(face_index);
175 this->mBoundaryElements.push_back(p_boundary_element);
181 p_boundary_element->SetAttribute(attribute_value);
185 RefreshJacobianCachedData();
190 template<
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
193 std::vector<unsigned> nodes_per_processor_vec;
195 std::ifstream file_stream(rNodesPerProcessorFile.c_str());
196 if (file_stream.is_open())
200 unsigned nodes_per_processor;
201 file_stream >> nodes_per_processor;
205 nodes_per_processor_vec.push_back(nodes_per_processor);
211 EXCEPTION(
"Unable to read nodes per processor file " + rNodesPerProcessorFile);
215 for (
unsigned i=0; i<nodes_per_processor_vec.size(); i++)
217 sum += nodes_per_processor_vec[i];
220 if (sum != this->GetNumNodes())
222 EXCEPTION(
"Sum of nodes per processor, " << sum
223 <<
", not equal to number of nodes in mesh, " << this->GetNumNodes());
230 EXCEPTION(
"Number of processes doesn't match the size of the nodes-per-processor file");
232 delete this->mpDistributedVectorFactory;
236 template<
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
246 std::set< std::set<unsigned> > odd_parity_faces;
249 iter != this->GetElementIteratorEnd();
252 for (
unsigned face_index=0; face_index<=ELEMENT_DIM; face_index++)
254 std::set<unsigned> face_info;
255 for (
unsigned node_index=0; node_index<=ELEMENT_DIM; node_index++)
258 if (node_index != face_index)
260 face_info.insert(iter->GetNodeGlobalIndex(node_index));
264 std::set< std::set<unsigned> >::iterator find_face=odd_parity_faces.find(face_info);
265 if (find_face != odd_parity_faces.end())
269 odd_parity_faces.erase(find_face);
274 odd_parity_faces.insert(face_info);
285 return(odd_parity_faces.size() == this->GetNumBoundaryElements());
288 template<
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
291 double mesh_volume = 0.0;
294 iter != this->GetElementIteratorEnd();
297 mesh_volume += iter->GetVolume(mElementJacobianDeterminants[iter->GetIndex()]);
303 template<
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
307 assert(ELEMENT_DIM >= 1);
308 const unsigned bound_element_dim = ELEMENT_DIM-1;
309 assert(bound_element_dim < 3);
310 if (bound_element_dim == 0)
315 double mesh_surface = 0.0;
318 while (it != this->GetBoundaryElementIteratorEnd())
320 mesh_surface += mBoundaryElementJacobianDeterminants[(*it)->GetIndex()];
324 if (bound_element_dim == 2)
332 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
337 std::vector<unsigned> perm;
338 p_rng->
Shuffle(this->mNodes.size(), perm);
344 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
348 assert( this->GetNumAllNodes() == this->GetNumNodes());
350 assert(perm.size() == this->mNodes.size());
353 std::vector< Node<SPACE_DIM>* > copy_m_nodes;
354 copy_m_nodes.assign(this->mNodes.begin(), this->mNodes.end());
356 for (
unsigned original_index=0; original_index<this->mNodes.size(); original_index++)
358 assert(perm[original_index] < this->mNodes.size());
360 this->mNodes[ perm[original_index] ] = copy_m_nodes[original_index];
364 for (
unsigned index=0; index<this->mNodes.size(); index++)
366 this->mNodes[index]->SetIndex(index);
370 this->mNodePermutation = perm;
373 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
376 assert(startingElementGuess<this->GetNumElements());
382 unsigned i = startingElementGuess;
383 bool reached_end =
false;
387 if (this->mElements[i]->IncludesPoint(rTestPoint, strict))
389 assert(!this->mElements[i]->IsDeleted());
395 if (i==this->GetNumElements())
401 if (i==startingElementGuess)
408 std::stringstream ss;
410 for (
unsigned j=0; (int)j<(
int)SPACE_DIM-1; j++)
412 ss << rTestPoint[j] <<
",";
414 ss << rTestPoint[SPACE_DIM-1] <<
"] is not in mesh - all elements tested";
419 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
423 double max_min_weight = -std::numeric_limits<double>::infinity();
424 unsigned closest_index = 0;
425 for (
unsigned i=0; i<this->mElements.size(); i++)
427 c_vector<double, ELEMENT_DIM+1> weight = this->mElements[i]->CalculateInterpolationWeights(rTestPoint);
428 double neg_weight_sum = 0.0;
429 for (
unsigned j=0; j<=ELEMENT_DIM; j++)
433 neg_weight_sum += weight[j];
436 if (neg_weight_sum > max_min_weight)
438 max_min_weight = neg_weight_sum;
442 assert(!this->mElements[closest_index]->IsDeleted());
443 return closest_index;
446 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
449 std::vector<unsigned> element_indices;
450 for (
unsigned i=0; i<this->mElements.size(); i++)
452 if (this->mElements[i]->IncludesPoint(rTestPoint))
454 assert(!this->mElements[i]->IsDeleted());
455 element_indices.push_back(i);
458 return element_indices;
461 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
465 for (
unsigned i=0; i<this->mBoundaryElements.size(); i++)
467 delete this->mBoundaryElements[i];
469 for (
unsigned i=0; i<this->mElements.size(); i++)
471 delete this->mElements[i];
473 for (
unsigned i=0; i<this->mNodes.size(); i++)
475 delete this->mNodes[i];
478 this->mNodes.clear();
479 this->mElements.clear();
480 this->mBoundaryElements.clear();
481 this->mBoundaryNodes.clear();
485 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
488 assert(SPACE_DIM == 2);
489 assert(SPACE_DIM == ELEMENT_DIM);
491 double x_difference = this->mNodes[indexB]->rGetLocation()[0] - this->mNodes[indexA]->rGetLocation()[0];
492 double y_difference = this->mNodes[indexB]->rGetLocation()[1] - this->mNodes[indexA]->rGetLocation()[1];
494 if (x_difference == 0)
496 if (y_difference > 0)
500 else if (y_difference < 0)
506 EXCEPTION(
"Tried to compute polar angle of (0,0)");
510 double angle = atan2(y_difference,x_difference);
518 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
526 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
534 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
542 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
545 bool already_seen_this_edge;
548 std::pair<unsigned, unsigned> current_node_pair;
577 if (node_b_global_index < node_a_global_index)
580 unsigned temp = node_a_global_index;
581 node_a_global_index = node_b_global_index;
582 node_b_global_index = temp;
586 current_node_pair = std::pair<unsigned, unsigned>(node_a_global_index, node_b_global_index);
587 already_seen_this_edge = (
mEdgesVisited.count(current_node_pair) != 0);
591 already_seen_this_edge =
false;
595 while (already_seen_this_edge);
601 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
618 if (node_b_global_index < node_a_global_index)
621 unsigned temp = node_a_global_index;
622 node_a_global_index = node_b_global_index;
623 node_b_global_index = temp;
627 std::pair<unsigned, unsigned> current_node_pair = std::pair<unsigned, unsigned>(node_a_global_index, node_b_global_index);
631 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
634 unsigned first_element_index = 0;
637 first_element_index++;
642 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
648 template<
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
654 template<
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
657 assert(index < this->
mNodes.size() );
661 template<
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
668 template<
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
675 template<
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
685 if (ELEMENT_DIM < SPACE_DIM)
700 unsigned index = iter->GetIndex();
704 if (ELEMENT_DIM < SPACE_DIM)
710 unsigned index = iter->GetIndex();
719 unsigned index = (*itb)->GetIndex();
724 template<
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
727 assert(ELEMENT_DIM <= SPACE_DIM);
733 template<
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
736 assert(ELEMENT_DIM <= SPACE_DIM);
743 template<
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
746 assert(ELEMENT_DIM < SPACE_DIM);
752 template<
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
760 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
763 mesherIo.numberofpoints = 0;
764 mesherIo.pointlist =
nullptr;
765 mesherIo.numberofpointattributes = 0;
766 mesherIo.pointattributelist = (
double *)
nullptr;
767 mesherIo.pointmarkerlist = (
int *)
nullptr;
768 mesherIo.numberofsegments = 0;
769 mesherIo.numberofholes = 0;
770 mesherIo.numberofregions = 0;
771 mesherIo.trianglelist = (
int *)
nullptr;
772 mesherIo.triangleattributelist = (
double *)
nullptr;
773 mesherIo.numberoftriangleattributes = 0;
774 mesherIo.edgelist = (
int *)
nullptr;
775 mesherIo.edgemarkerlist = (
int *)
nullptr;
778 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
781 if (mesherIo.numberofpoints != 0)
783 mesherIo.numberofpoints=0;
784 free(mesherIo.pointlist);
788 free(mesherIo.pointattributelist);
789 free(mesherIo.pointmarkerlist);
790 free(mesherIo.trianglelist);
791 free(mesherIo.triangleattributelist);
792 free(mesherIo.edgelist);
793 free(mesherIo.edgemarkerlist);
796 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
797 template <
class MESHER_IO>
802 mesherInput.pointlist = (
double *) malloc(this->
GetNumNodes() * SPACE_DIM *
sizeof(
double));
806 mesherInput.pointlist =
new double[this->
GetNumNodes() * SPACE_DIM];
810 unsigned new_index = 0;
813 if (this->
mNodes[i]->IsDeleted())
820 for (
unsigned j=0; j<SPACE_DIM; j++)
822 mesherInput.pointlist[SPACE_DIM*new_index + j] = this->
mNodes[i]->rGetLocation()[j];
827 if (elementList !=
nullptr)
829 unsigned element_index = 0;
832 mesherInput.numberofcorners=ELEMENT_DIM+1;
838 for (
unsigned j=0; j<=ELEMENT_DIM; j++)
840 elementList[element_index*(ELEMENT_DIM+1) + j] = (*elem_iter).GetNodeGlobalIndex(j);
847 template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
848 template <
class MESHER_IO>
851 unsigned nodes_per_element = mesherOutput.numberofcorners;
853 assert( nodes_per_element == ELEMENT_DIM+1 || nodes_per_element == (ELEMENT_DIM+1)*(ELEMENT_DIM+2)/2 );
858 for (
unsigned node_index=0; node_index<(
unsigned)mesherOutput.numberofpoints; node_index++)
860 this->
mNodes.push_back(
new Node<SPACE_DIM>(node_index, &mesherOutput.pointlist[node_index * SPACE_DIM],
false));
864 this->
mElements.reserve(numberOfElements);
866 unsigned real_element_index=0;
867 for (
unsigned element_index=0; element_index<numberOfElements; element_index++)
869 std::vector<Node<SPACE_DIM>*> nodes;
870 for (
unsigned j=0; j<ELEMENT_DIM+1; j++)
872 unsigned global_node_index = elementList[element_index*(nodes_per_element) + j];
873 assert(global_node_index < this->
mNodes.size());
874 nodes.push_back(this->
mNodes[global_node_index]);
891 for (
unsigned j=ELEMENT_DIM+1; j<nodes_per_element; j++)
893 unsigned global_node_index = elementList[element_index*nodes_per_element + j];
894 assert(global_node_index < this->
mNodes.size());
895 this->
mElements[real_element_index]->AddNode( this->
mNodes[global_node_index] );
896 this->
mNodes[global_node_index]->AddElement(real_element_index);
897 this->
mNodes[global_node_index]->MarkAsInternal();
899 real_element_index++;
905 WARNING(
"Triangle has produced a zero area (collinear) element");
909 WARNING(
"Tetgen has produced a zero volume (coplanar) element");
915 unsigned next_boundary_element_index = 0;
916 for (
unsigned boundary_element_index=0; boundary_element_index<numberOfFaces; boundary_element_index++)
922 if (edgeMarkerList ==
nullptr || edgeMarkerList[boundary_element_index] == 1)
924 std::vector<Node<SPACE_DIM>*> nodes;
925 for (
unsigned j=0; j<ELEMENT_DIM; j++)
927 unsigned global_node_index = faceList[boundary_element_index*ELEMENT_DIM + j];
928 assert(global_node_index < this->
mNodes.size());
929 nodes.push_back(this->
mNodes[global_node_index]);
930 if (!nodes[j]->IsBoundaryNode())
932 nodes[j]->SetAsBoundaryNode();
944 p_b_element =
new BoundaryElement<ELEMENT_DIM-1, SPACE_DIM>(next_boundary_element_index, nodes);
946 next_boundary_element_index++;
956 assert(SPACE_DIM == 3);
1032 #define CHASTE_SERIALIZATION_CPP 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)
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
gcov doesn't like this file...
virtual unsigned GetNumNodes() const =0
void FreeTriangulateIo(triangulateio &mesherIo)
virtual std::vector< double > GetNodeAttributes()
virtual unsigned GetNumFaces() const =0
BoundaryElementIterator GetBoundaryElementIteratorEnd() const