36#include "VertexMesh.hpp"
37#include "MutableMesh.hpp"
38#include "RandomNumberGenerator.hpp"
40#include "Warnings.hpp"
42#include "VtkMeshWriter.hpp"
43#include "NodesOnlyMesh.hpp"
45template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
48 : mpDelaunayMesh(nullptr)
55 for (
unsigned node_index = 0; node_index < nodes.size(); node_index++)
58 this->
mNodes.push_back(p_temp_node);
60 for (
unsigned elem_index = 0; elem_index < vertexElements.size(); elem_index++)
63 mElements.push_back(p_temp_vertex_element);
70 std::set<unsigned> faces_counted;
73 for (
unsigned elem_index = 0; elem_index <
mElements.size(); elem_index++)
76 for (
unsigned face_index = 0; face_index <
mElements[elem_index]->GetNumFaces(); face_index++)
79 unsigned global_index = p_face->
GetIndex();
82 if (faces_counted.find(global_index) == faces_counted.end())
85 faces_counted.insert(global_index);
92 for (
unsigned index = 0; index <
mElements.size(); index++)
96 unsigned element_index = p_element->
GetIndex();
97 unsigned num_nodes_in_element = p_element->
GetNumNodes();
99 for (
unsigned node_index = 0; node_index < num_nodes_in_element; node_index++)
101 p_element->
GetNode(node_index)->AddElement(element_index);
110template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
114 : mpDelaunayMesh(nullptr)
120 for (
unsigned node_index = 0; node_index < nodes.size(); node_index++)
123 this->
mNodes.push_back(p_temp_node);
126 for (
unsigned face_index = 0; face_index < faces.size(); face_index++)
128 VertexElement<ELEMENT_DIM - 1, SPACE_DIM>* p_temp_face = faces[face_index];
129 mFaces.push_back(p_temp_face);
132 for (
unsigned elem_index = 0; elem_index < vertexElements.size(); elem_index++)
139 for (
unsigned index = 0; index <
mElements.size(); index++)
142 for (
unsigned node_index = 0; node_index < p_temp_vertex_element->
GetNumNodes(); node_index++)
160 bool scaleBoundByEdgeLength,
161 double maxDelaunayEdgeLength,
162 bool offsetNewBoundaryNodes)
163 : mpDelaunayMesh(&rMesh)
176 this->
mNodes.reserve(num_nodes);
180 for (
unsigned elem_index = 0; elem_index < num_elements; elem_index++)
190 for (
unsigned i = 0; i < num_nodes; i++)
194 for (
unsigned local_index = 0; local_index < 3; local_index++)
196 unsigned elem_index =
mpDelaunayMesh->GetElement(i)->GetNodeGlobalIndex(local_index);
197 unsigned num_nodes_in_elem =
mElements[elem_index]->GetNumNodes();
198 unsigned end_index = num_nodes_in_elem > 0 ? num_nodes_in_elem - 1 : 0;
207 std::vector<Node<2> *> nodes;
212 nodes.push_back(
new Node<2>(node_iter->GetIndex(), node_iter->rGetLocation(),node_iter->IsBoundaryNode()));
223 bool bad_element =
false;
225 for (
unsigned j=0; j<3; j++)
236 for (
unsigned j=0; j<3; j++)
244 std::set<unsigned> shared_elements;
245 std::set_intersection(node_a_element_indices.begin(),
246 node_a_element_indices.end(),
247 node_b_element_indices.begin(),
248 node_b_element_indices.end(),
249 std::inserter(shared_elements, shared_elements.begin()));
252 double edge_length = norm_2(edge);
259 bool is_boundary_edge =
false;
260 double direction_of_normal = 1.0;
261 if ((edge_length < maxDelaunayEdgeLength) && (shared_elements.size() == 1))
263 is_boundary_edge =
true;
265 if (bad_element && (edge_length < maxDelaunayEdgeLength))
271 assert(!is_boundary_edge);
272 is_boundary_edge =
true;
274 direction_of_normal = -1.0;
277 if (is_boundary_edge)
279 c_vector<double,2> normal_vector;
281 normal_vector[0]= edge[1];
282 normal_vector[1]= -edge[0];
284 double dij = norm_2(normal_vector);
286 normal_vector /= dij;
288 double new_node_distance = 1.0;
290 if (scaleBoundByEdgeLength)
292 new_node_distance = edge_length;
295 int num_sections = 1;
296 for (
int section=0; section<=num_sections; section++)
299 if (offsetNewBoundaryNodes)
310 c_vector<double,2> new_node_location = direction_of_normal * new_node_distance * normal_vector + ratio*p_node_a->
rGetLocation() + (1-ratio)*p_node_b->
rGetLocation();
313 double node_clearance = 0.01;
316 nodes.push_back(
new Node<2>(new_node_index, new_node_location));
333 unsigned num_nodes = extended_mesh.GetNumAllElements();
336 this->
mNodes.reserve(num_nodes);
340 for (
unsigned elem_index = 0; elem_index < num_elements; elem_index++)
350 for (
unsigned i = 0; i < num_nodes; i++)
354 for (
unsigned local_index = 0; local_index < 3; local_index++)
356 unsigned elem_index = extended_mesh.GetElement(i)->GetNodeGlobalIndex(local_index);
358 if (elem_index < num_elements)
360 unsigned num_nodes_in_elem =
mElements[elem_index]->GetNumNodes();
361 unsigned end_index = num_nodes_in_elem > 0 ? num_nodes_in_elem - 1 : 0;
370 for (
unsigned elem_index = 0; elem_index <
mElements.size(); elem_index++)
377 std::vector<std::pair<double, unsigned> > index_angle_list;
378 for (
unsigned local_index = 0; local_index <
mElements[elem_index]->GetNumNodes(); local_index++)
380 c_vector<double, 2> vectorA =
mpDelaunayMesh->GetNode(elem_index)->rGetLocation();
381 c_vector<double, 2> vectorB =
mElements[elem_index]->GetNodeLocation(local_index);
382 c_vector<double, 2> centre_to_vertex =
mpDelaunayMesh->GetVectorFromAtoB(vectorA, vectorB);
384 double angle = atan2(centre_to_vertex(1), centre_to_vertex(0));
385 unsigned global_index =
mElements[elem_index]->GetNodeGlobalIndex(local_index);
387 std::pair<double, unsigned> pair(angle, global_index);
388 index_angle_list.push_back(pair);
392 sort(index_angle_list.begin(), index_angle_list.end());
396 for (
unsigned count = 0; count < index_angle_list.size(); count++)
398 unsigned local_index = count > 1 ? count - 1 : 0;
399 p_new_element->
AddNode(
mNodes[index_angle_list[count].second], local_index);
421 : mpDelaunayMesh(&rMesh)
429 this->
mNodes.reserve(num_nodes);
434 std::map<unsigned, VertexElement<3, 3>*> index_element_map;
435 unsigned face_index = 0;
436 unsigned element_index = 0;
443 Node<3>* p_node_a = edge_iterator.GetNodeA();
444 Node<3>* p_node_b = edge_iterator.GetNodeB();
450 std::set<unsigned> edge_element_indices;
452 std::set_intersection(node_a_element_indices.begin(),
453 node_a_element_indices.end(),
454 node_b_element_indices.begin(),
455 node_b_element_indices.end(),
456 std::inserter(edge_element_indices, edge_element_indices.begin()));
458 c_vector<double, 3> edge_vector;
461 c_vector<double, 3> mid_edge;
462 mid_edge = edge_vector * 0.5 + p_node_a->
rGetLocation();
464 unsigned element0_index = *(edge_element_indices.begin());
466 c_vector<double, 3> basis_vector1;
467 basis_vector1 =
mNodes[element0_index]->rGetLocation() - mid_edge;
469 c_vector<double, 3> basis_vector2;
477 std::vector<std::pair<double, unsigned> > index_angle_list;
480 for (std::set<unsigned>::iterator index_iter = edge_element_indices.begin();
481 index_iter != edge_element_indices.end();
485 c_vector<double, 3> vertex_vector =
mNodes[*index_iter]->rGetLocation() - mid_edge;
487 double local_vertex_dot_basis_vector1 = inner_prod(vertex_vector, basis_vector1);
488 double local_vertex_dot_basis_vector2 = inner_prod(vertex_vector, basis_vector2);
490 double angle = atan2(local_vertex_dot_basis_vector2, local_vertex_dot_basis_vector1);
492 std::pair<double, unsigned> pair(angle, *index_iter);
493 index_angle_list.push_back(pair);
497 sort(index_angle_list.begin(), index_angle_list.end());
502 for (
unsigned count = 0; count < index_angle_list.size(); count++)
504 unsigned local_index = count > 1 ? count - 1 : 0;
505 p_face->
AddNode(
mNodes[index_angle_list[count].second], local_index);
514 unsigned node_a_index = p_node_a->
GetIndex();
515 if (index_element_map[node_a_index])
518 index_element_map[node_a_index]->AddFace(p_face);
527 index_element_map[node_a_index] = p_element;
532 unsigned node_b_index = p_node_b->
GetIndex();
533 if (index_element_map[node_b_index])
536 index_element_map[node_b_index]->AddFace(p_face);
545 index_element_map[node_b_index] = p_element;
552 unsigned elem_count = 0;
553 for (std::map<
unsigned,
VertexElement<3, 3>*>::iterator element_iter = index_element_map.begin();
554 element_iter != index_element_map.end();
557 mElements.push_back(element_iter->second);
569template<
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
574 for (
auto elem : rElements)
576 elem->SetEdgeHelper(&mEdgeHelper);
581template<
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
584 return mEdgeHelper.GetNumEdges();
587template<
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
590 return mEdgeHelper.GetEdge(index);
593template<
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
599template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
602 c_matrix<double, SPACE_DIM, ELEMENT_DIM> jacobian;
603 c_matrix<double, ELEMENT_DIM, SPACE_DIM> inverse_jacobian;
611 c_vector<double, SPACE_DIM + 1> circumsphere = rMesh.
GetElement(i)->CalculateCircumsphere(jacobian, inverse_jacobian);
613 c_vector<double, SPACE_DIM> circumcentre;
614 for (
unsigned j = 0; j < SPACE_DIM; j++)
616 circumcentre(j) = circumsphere(j);
624template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
627 assert(SPACE_DIM == 2);
629 std::set<unsigned> node_indices_1;
630 for (
unsigned i = 0; i < mElements[elementIndex1]->GetNumNodes(); i++)
632 node_indices_1.insert(mElements[elementIndex1]->GetNodeGlobalIndex(i));
634 std::set<unsigned> node_indices_2;
635 for (
unsigned i = 0; i < mElements[elementIndex2]->GetNumNodes(); i++)
637 node_indices_2.insert(mElements[elementIndex2]->GetNodeGlobalIndex(i));
640 std::set<unsigned> shared_nodes;
641 std::set_intersection(node_indices_1.begin(), node_indices_1.end(),
642 node_indices_2.begin(), node_indices_2.end(),
643 std::inserter(shared_nodes, shared_nodes.begin()));
645 if (shared_nodes.size() == 1)
648 EXCEPTION(
"Elements " << elementIndex1 <<
" and " << elementIndex2 <<
" share only one node.");
650 assert(shared_nodes.size() == 2);
652 unsigned index1 = *(shared_nodes.begin());
653 unsigned index2 = *(++(shared_nodes.begin()));
655 double edge_length = this->GetDistanceBetweenNodes(index1, index2);
659template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
662 if constexpr (SPACE_DIM == 2)
664 c_vector<double, 3> moments = CalculateMomentsOfElement(elementIndex);
666 const double discriminant = sqrt((moments(0) - moments(1)) * (moments(0) - moments(1)) + 4.0 * moments(2) * moments(2));
670 const double largest_eigenvalue = (moments(0) + moments(1) + discriminant) * 0.5;
671 const double smallest_eigenvalue = std::max(0.0, (moments(0) + moments(1) - discriminant) * 0.5);
674 if (smallest_eigenvalue == 0.0)
676 WARNING(
"Infinite elongation shape factor: element likely to be co-linear");
677 return std::numeric_limits<double>::infinity();
680 return sqrt(largest_eigenvalue / smallest_eigenvalue);
688template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
691 mpDelaunayMesh =
nullptr;
692 this->mMeshChangesDuringSimulation =
false;
696template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
702template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
705 assert(index < this->mNodes.size());
709template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
712 assert(index < this->mElements.size());
716template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
724template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
729 if (mVoronoiElementIndexMap.empty())
731 node_index = elementIndex;
735 for (std::map<unsigned, unsigned>::iterator iter = mVoronoiElementIndexMap.begin();
736 iter != mVoronoiElementIndexMap.end();
739 if (iter->second == elementIndex)
741 node_index = iter->first;
750template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
755 if (mVoronoiElementIndexMap.empty())
757 element_index = nodeIndex;
761 std::map<unsigned, unsigned>::iterator iter = mVoronoiElementIndexMap.find(nodeIndex);
763 if (iter == mVoronoiElementIndexMap.end())
765 EXCEPTION(
"This index does not correspond to a VertexElement");
769 element_index = iter->second;
773 return element_index;
776template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
779 assert(SPACE_DIM == 2 || SPACE_DIM == 3);
785 unsigned rosette_rank = 0;
786 for (
unsigned node_idx = 0; node_idx < p_element->
GetNumNodes(); node_idx++)
788 unsigned num_elems_this_node = p_element->
GetNode(node_idx)->rGetContainingElementIndices().size();
790 if (num_elems_this_node > rosette_rank)
792 rosette_rank = num_elems_this_node;
800template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
804 for (
unsigned i = 0; i < mElements.size(); i++)
811 for (
unsigned i = 0; i < mFaces.size(); i++)
819 for (
unsigned i = 0; i < this->mNodes.size(); i++)
821 delete this->mNodes[i];
823 this->mNodes.clear();
826template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
829 return this->mNodes.size();
832template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
835 return mElements.size();
838template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
841 return mElements.size();
844template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
847 return mFaces.size();
850template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
853 assert(index < mElements.size());
854 return mElements[index];
857template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
860 assert(index < mFaces.size());
861 return mFaces[index];
864template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
870 c_vector<double, SPACE_DIM> centroid = zero_vector<double>(SPACE_DIM);
881 double centroid_x = 0;
882 double centroid_y = 0;
885 double element_signed_area = 0.0;
888 c_vector<double, SPACE_DIM> first_node_location = p_element->
GetNodeLocation(0);
889 c_vector<double, SPACE_DIM> pos_1 = zero_vector<double>(SPACE_DIM);
892 for (
unsigned local_index = 0; local_index < num_nodes; local_index++)
894 c_vector<double, SPACE_DIM> next_node_location = p_element->
GetNodeLocation((local_index + 1) % num_nodes);
895 c_vector<double, SPACE_DIM> pos_2 = GetVectorFromAtoB(first_node_location, next_node_location);
897 double this_x = pos_1[0];
898 double this_y = pos_1[1];
899 double next_x = pos_2[0];
900 double next_y = pos_2[1];
902 double signed_area_term = this_x * next_y - this_y * next_x;
904 centroid_x += (this_x + next_x) * signed_area_term;
905 centroid_y += (this_y + next_y) * signed_area_term;
906 element_signed_area += 0.5 * signed_area_term;
911 assert(element_signed_area != 0.0);
914 centroid = first_node_location;
915 centroid(0) += centroid_x / (6.0 * element_signed_area);
916 centroid(1) += centroid_y / (6.0 * element_signed_area);
922 for (
unsigned local_index = 0; local_index < num_nodes; local_index++)
926 centroid /= ((
double)num_nodes);
935template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
939 std::set<unsigned> neighbouring_node_indices;
942 std::set<unsigned> containing_elem_indices = this->GetNode(nodeIndex)->rGetContainingElementIndices();
945 for (std::set<unsigned>::iterator elem_iter = containing_elem_indices.begin();
946 elem_iter != containing_elem_indices.end();
950 unsigned local_index = GetElement(*elem_iter)->GetNodeLocalIndex(nodeIndex);
953 unsigned num_nodes = GetElement(*elem_iter)->GetNumNodes();
954 unsigned previous_local_index = (local_index + num_nodes - 1) % num_nodes;
955 unsigned next_local_index = (local_index + 1) % num_nodes;
958 neighbouring_node_indices.insert(GetElement(*elem_iter)->GetNodeGlobalIndex(previous_local_index));
959 neighbouring_node_indices.insert(GetElement(*elem_iter)->GetNodeGlobalIndex(next_local_index));
962 return neighbouring_node_indices;
965template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
972 std::set<unsigned> node_indices_in_this_element;
973 for (
unsigned local_index = 0; local_index < p_element->
GetNumNodes(); local_index++)
976 node_indices_in_this_element.insert(global_index);
980 if (node_indices_in_this_element.find(nodeIndex) == node_indices_in_this_element.end())
982 EXCEPTION(
"The given node is not contained in the given element.");
986 std::set<unsigned> neighbouring_node_indices_not_in_this_element;
989 std::set<unsigned> node_neighbours = GetNeighbouringNodeIndices(nodeIndex);
992 for (std::set<unsigned>::iterator iter = node_neighbours.begin();
993 iter != node_neighbours.end();
996 if (node_indices_in_this_element.find(*iter) == node_indices_in_this_element.end())
998 neighbouring_node_indices_not_in_this_element.insert(*iter);
1002 return neighbouring_node_indices_not_in_this_element;
1005template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
1012 std::set<unsigned> neighbouring_element_indices;
1015 for (
unsigned local_index = 0; local_index < p_element->
GetNumNodes(); local_index++)
1024 std::set<unsigned> all_elements;
1025 std::set_union(neighbouring_element_indices.begin(), neighbouring_element_indices.end(),
1026 containing_elem_indices.begin(), containing_elem_indices.end(),
1027 std::inserter(all_elements, all_elements.begin()));
1030 neighbouring_element_indices = all_elements;
1034 neighbouring_element_indices.erase(elementIndex);
1036 return neighbouring_element_indices;
1039template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
1045template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
1048 bool node_near =
false;
1050 for (
unsigned i=0; i<nodesToCheck.size(); i++)
1052 double distance = norm_2(mpDelaunayMesh->GetVectorFromAtoB(nodesToCheck[i]->rGetLocation(), newNodeLocation));
1053 if (distance < minClearance)
650 assert(shared_nodes.size() == 2); {
…}
1068 EXCEPTION(
"VertexMesh<1,1>::ConstructFromMeshReader() is not implemented");
1076 EXCEPTION(
"VertexMesh<1,2>::ConstructFromMeshReader() is not implemented");
1084 EXCEPTION(
"VertexMesh<1,3>::ConstructFromMeshReader() is not implemented");
1092 EXCEPTION(
"VertexMesh<2,3>::ConstructFromMeshReader() is not implemented");
1106 this->mNodes.reserve(num_nodes);
1108 rMeshReader.
Reset();
1111 std::vector<double> node_data;
1112 for (
unsigned i = 0; i < num_nodes; i++)
1115 unsigned is_boundary_node = (
bool)node_data[2];
1116 node_data.pop_back();
1117 this->mNodes.push_back(
new Node<2>(i, node_data, is_boundary_node));
1120 rMeshReader.
Reset();
1126 for (
unsigned elem_index = 0; elem_index < num_elements; elem_index++)
1132 std::vector<Node<2>*> nodes;
1133 unsigned num_nodes_in_element = element_data.
NodeIndices.size();
1134 for (
unsigned j = 0; j < num_nodes_in_element; j++)
1136 assert(element_data.
NodeIndices[j] < this->mNodes.size());
1137 nodes.push_back(this->mNodes[element_data.
NodeIndices[j]]);
1142 mElements.push_back(p_element);
1151 GenerateEdgesFromElements(mElements);
1166 this->mNodes.reserve(num_nodes);
1168 rMeshReader.
Reset();
1171 std::vector<double> node_data;
1172 for (
unsigned i = 0; i < num_nodes; i++)
1175 unsigned is_boundary_node = (
bool)node_data[3];
1176 node_data.pop_back();
1177 this->mNodes.push_back(
new Node<3>(i, node_data, is_boundary_node));
1180 rMeshReader.
Reset();
1186 std::set<unsigned> faces_counted;
1189 for (
unsigned elem_index = 0; elem_index < num_elements; elem_index++)
1193 assert(
dynamic_cast<VERTEX_MESH_READER*
>(&rMeshReader) !=
nullptr);
1196 VertexElementData element_data =
static_cast<VERTEX_MESH_READER*
>(&rMeshReader)->GetNextElementDataWithFaces();
1199 std::vector<Node<3>*> nodes;
1200 unsigned num_nodes_in_element = element_data.
NodeIndices.size();
1201 for (
unsigned j = 0; j < num_nodes_in_element; j++)
1203 assert(element_data.
NodeIndices[j] < this->mNodes.size());
1204 nodes.push_back(this->mNodes[element_data.
NodeIndices[j]]);
1208 std::vector<VertexElement<2, 3>*> faces;
1209 unsigned num_faces_in_element = element_data.
Faces.size();
1210 for (
unsigned i = 0; i < num_faces_in_element; i++)
1219 std::vector<Node<3>*> nodes_in_face;
1220 unsigned num_nodes_in_face = face_data.NodeIndices.size();
1221 for (
unsigned j = 0; j < num_nodes_in_face; j++)
1223 assert(face_data.NodeIndices[j] < this->mNodes.size());
1224 nodes_in_face.push_back(this->mNodes[face_data.NodeIndices[j]]);
1228 if (faces_counted.find(face_index) == faces_counted.end())
1232 mFaces.push_back(p_face);
1233 faces_counted.insert(face_index);
1234 faces.push_back(p_face);
1239 bool face_added =
false;
1240 for (
unsigned k = 0; k < mFaces.size(); k++)
1242 if (mFaces[k]->GetIndex() == face_index)
1244 faces.push_back(mFaces[k]);
1250 assert(face_added ==
true);
1255 std::vector<bool> orientations = std::vector<bool>(num_faces_in_element,
true);
1259 mElements.push_back(p_element);
1270template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
1272 const c_vector<double, SPACE_DIM>& rLocationA,
const c_vector<double, SPACE_DIM>& rLocationB)
1274 c_vector<double, SPACE_DIM> vector {};
1277 vector = mpDelaunayMesh->GetVectorFromAtoB(rLocationA, rLocationB);
1286template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
1289 assert(SPACE_DIM == 2 || SPACE_DIM == 3);
1294 double element_volume = 0.0;
1298 c_vector<double, SPACE_DIM> first_node_location = p_element->
GetNodeLocation(0);
1299 c_vector<double, SPACE_DIM> pos_1 = zero_vector<double>(SPACE_DIM);
1302 for (
unsigned local_index = 0; local_index < num_nodes; local_index++)
1304 c_vector<double, SPACE_DIM> next_node_location = p_element->
GetNodeLocation((local_index + 1) % num_nodes);
1305 c_vector<double, SPACE_DIM> pos_2 = GetVectorFromAtoB(first_node_location, next_node_location);
1307 double this_x = pos_1[0];
1308 double this_y = pos_1[1];
1309 double next_x = pos_2[0];
1310 double next_y = pos_2[1];
1312 element_volume += 0.5 * (this_x * next_y - next_x * this_y);
1320 c_vector<double, SPACE_DIM> pyramid_apex = p_element->
GetNodeLocation(0);
1321 for (
unsigned face_index = 0; face_index < p_element->
GetNumFaces(); face_index++)
1327 c_vector<double, SPACE_DIM> unit_normal;
1328 double face_area = CalculateUnitNormalToFaceWithArea(p_face, unit_normal);
1331 c_vector<double, SPACE_DIM> base_to_apex = GetVectorFromAtoB(p_face->GetNodeLocation(0), pyramid_apex);
1332 double perpendicular_distance = fabs(inner_prod(base_to_apex, unit_normal));
1335 element_volume += face_area * perpendicular_distance / 3;
1340 return fabs(element_volume);
1343template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
1346 assert(SPACE_DIM == 2 || SPACE_DIM == 3);
1351 double surface_area = 0.0;
1356 for (
unsigned local_index = 0; local_index < num_nodes; local_index++)
1358 unsigned next_node_index = p_element->
GetNodeGlobalIndex((local_index + 1) % num_nodes);
1360 surface_area += this->GetDistanceBetweenNodes(this_node_index, next_node_index);
1361 this_node_index = next_node_index;
1367 for (
unsigned face_index = 0; face_index < p_element->
GetNumFaces(); face_index++)
1369 surface_area += CalculateAreaOfFace(p_element->
GetFace(face_index));
1372 return surface_area;
1378template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
1380 [[maybe_unused]]
const c_vector<double, SPACE_DIM>& rTestPoint, [[maybe_unused]]
unsigned elementIndex)
1382 if constexpr (ELEMENT_DIM == 2 && SPACE_DIM == 2)
1386 const unsigned num_nodes = p_element->
GetNumNodes();
1389 bool element_includes_point =
false;
1449 const c_vector<double, 2> first_vertex = p_element->
GetNodeLocation(0);
1450 c_vector<double, 2> test_point = GetVectorFromAtoB(first_vertex, rTestPoint);
1453 c_vector<double, 2> vertexA = zero_vector<double>(2);
1454 for (
unsigned local_index = 0; local_index < num_nodes; local_index++)
1457 c_vector<double, 2> vector_a_to_point = GetVectorFromAtoB(vertexA, test_point);
1461 if (norm_2(vector_a_to_point) < DBL_EPSILON)
1466 c_vector<double, 2> vertexB = GetVectorFromAtoB(first_vertex, p_element->
GetNodeLocation((local_index + 1) % num_nodes));
1467 c_vector<double, 2> vector_b_to_point = GetVectorFromAtoB(vertexB, test_point);
1468 c_vector<double, 2> vector_a_to_b = GetVectorFromAtoB(vertexA, vertexB);
1471 if ((fabs(vector_a_to_b[1]) < DBL_EPSILON) && (fabs(vector_a_to_point[1]) < DBL_EPSILON) && (fabs(vector_b_to_point[1]) < DBL_EPSILON))
1473 if ((vector_a_to_point[0] > 0) != (vector_b_to_point[0] > 0))
1481 if ((vertexA[1] > test_point[1]) != (vertexB[1] > test_point[1]))
1484 if (test_point[0] < vertexA[0] + vector_a_to_b[0] * vector_a_to_point[1] / vector_a_to_b[1])
1486 element_includes_point = !element_includes_point;
1492 return element_includes_point;
1500template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
1502 [[maybe_unused]]
const c_vector<double, SPACE_DIM>& rTestPoint, [[maybe_unused]]
unsigned elementIndex)
1504 if constexpr (ELEMENT_DIM == 2 && SPACE_DIM == 2)
1508 const unsigned num_nodes = p_element->
GetNumNodes();
1510 double min_squared_normal_distance = DBL_MAX;
1511 unsigned min_distance_edge_index = UINT_MAX;
1514 for (
unsigned local_index = 0; local_index < num_nodes; local_index++)
1517 const c_vector<double, 2> vertexA = p_element->
GetNodeLocation(local_index);
1518 const c_vector<double, 2> vertexB = p_element->
GetNodeLocation((local_index + 1) % num_nodes);
1520 const c_vector<double, 2> vector_a_to_point = this->GetVectorFromAtoB(vertexA, rTestPoint);
1521 const c_vector<double, 2> vector_a_to_b = this->GetVectorFromAtoB(vertexA, vertexB);
1522 const double distance_a_to_b = norm_2(vector_a_to_b);
1524 const c_vector<double, 2> edge_ab_unit_vector = vector_a_to_b / norm_2(vector_a_to_b);
1525 double distance_parallel_to_edge = inner_prod(vector_a_to_point, edge_ab_unit_vector);
1527 double squared_distance_normal_to_edge = SmallPow(norm_2(vector_a_to_point), 2) - SmallPow(distance_parallel_to_edge, 2);
1535 if (squared_distance_normal_to_edge < DBL_EPSILON)
1537 squared_distance_normal_to_edge = 0.0;
1540 if (fabs(distance_parallel_to_edge) < DBL_EPSILON)
1542 distance_parallel_to_edge = 0.0;
1544 else if (fabs(distance_parallel_to_edge - distance_a_to_b) < DBL_EPSILON)
1546 distance_parallel_to_edge = distance_a_to_b;
1550 if (squared_distance_normal_to_edge < min_squared_normal_distance && distance_parallel_to_edge >= 0 && distance_parallel_to_edge <= distance_a_to_b)
1552 min_squared_normal_distance = squared_distance_normal_to_edge;
1553 min_distance_edge_index = local_index;
1557 assert(min_distance_edge_index < num_nodes);
1558 return min_distance_edge_index;
1566template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
1569 if constexpr (SPACE_DIM == 2)
1574 c_vector<double, 3> moments = zero_vector<double>(3);
1577 c_vector<double, SPACE_DIM> centroid = GetCentroidOfElement(index);
1579 c_vector<double, SPACE_DIM> this_node_location = p_element->
GetNodeLocation(0);
1580 c_vector<double, SPACE_DIM> pos_1 = this->GetVectorFromAtoB(centroid, this_node_location);
1582 for (
unsigned local_index = 0; local_index < num_nodes; local_index++)
1584 unsigned next_index = (local_index + 1) % num_nodes;
1585 c_vector<double, SPACE_DIM> next_node_location = p_element->
GetNodeLocation(next_index);
1586 c_vector<double, SPACE_DIM> pos_2 = this->GetVectorFromAtoB(centroid, next_node_location);
1588 double signed_area_term = pos_1(0) * pos_2(1) - pos_2(0) * pos_1(1);
1590 moments(0) += (pos_1(1) * pos_1(1) + pos_1(1) * pos_2(1) + pos_2(1) * pos_2(1)) * signed_area_term;
1593 moments(1) += (pos_1(0) * pos_1(0) + pos_1(0) * pos_2(0) + pos_2(0) * pos_2(0)) * signed_area_term;
1596 moments(2) += (pos_1(0) * pos_2(1) + 2 * pos_1(0) * pos_1(1) + 2 * pos_2(0) * pos_2(1) + pos_2(0) * pos_1(1)) * signed_area_term;
1611 if (moments(0) < 0.0)
1613 moments(0) = -moments(0);
1614 moments(1) = -moments(1);
1615 moments(2) = -moments(2);
1625template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
1628 if constexpr (SPACE_DIM == 2)
1631 c_vector<double, SPACE_DIM> short_axis = zero_vector<double>(SPACE_DIM);
1634 c_vector<double, 3> moments = CalculateMomentsOfElement(index);
1637 moments /= norm_2(moments);
1640 double discriminant = (moments(0) - moments(1)) * (moments(0) - moments(1)) + 4.0 * moments(2) * moments(2);
1641 if (fabs(discriminant) < DBL_EPSILON)
1645 short_axis(1) = sqrt(1.0 - short_axis(0) * short_axis(0));
1650 if (fabs(moments(2)) < DBL_EPSILON)
1652 if (moments(0) < moments(1))
1654 short_axis(0) = 0.0;
1655 short_axis(1) = 1.0;
1659 short_axis(0) = 1.0;
1660 short_axis(1) = 0.0;
1666 double lambda = 0.5 * (moments(0) + moments(1) + sqrt(discriminant));
1668 short_axis(0) = 1.0;
1669 short_axis(1) = (moments(0) - lambda) / moments(2);
1672 short_axis /= norm_2(short_axis);
1684template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
1688 if constexpr (SPACE_DIM == 2)
1690 unsigned num_nodes_in_element = pElement->GetNumNodes();
1691 unsigned next_local_index = (localIndex + 1) % num_nodes_in_element;
1694 unsigned previous_local_index = (num_nodes_in_element + localIndex - 1) % num_nodes_in_element;
1696 c_vector<double, SPACE_DIM> previous_node_location = pElement->GetNodeLocation(previous_local_index);
1697 c_vector<double, SPACE_DIM> next_node_location = pElement->GetNodeLocation(next_local_index);
1698 c_vector<double, SPACE_DIM> difference_vector = this->GetVectorFromAtoB(previous_node_location, next_node_location);
1700 c_vector<double, SPACE_DIM> area_gradient;
1702 area_gradient[0] = 0.5 * difference_vector[1];
1703 area_gradient[1] = -0.5 * difference_vector[0];
1705 return area_gradient;
1713template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
1717 if constexpr (SPACE_DIM == 2)
1719 assert(SPACE_DIM == 2);
1721 const unsigned num_nodes_in_element = pElement->GetNumNodes();
1724 const unsigned previous_local_index = (num_nodes_in_element + localIndex - 1) % num_nodes_in_element;
1726 const unsigned this_global_index = pElement->GetNodeGlobalIndex(localIndex);
1727 const unsigned previous_global_index = pElement->GetNodeGlobalIndex(previous_local_index);
1729 const double previous_edge_length = this->GetDistanceBetweenNodes(this_global_index, previous_global_index);
1730 assert(previous_edge_length > DBL_EPSILON);
1732 const c_vector<double, SPACE_DIM> previous_edge_gradient = this->GetVectorFromAtoB(pElement->GetNodeLocation(previous_local_index), pElement->GetNodeLocation(localIndex)) / previous_edge_length;
1734 return previous_edge_gradient;
1742template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
1746 if constexpr (SPACE_DIM == 2)
1748 const unsigned next_local_index = (localIndex + 1) % (pElement->GetNumNodes());
1750 const unsigned this_global_index = pElement->GetNodeGlobalIndex(localIndex);
1751 const unsigned next_global_index = pElement->GetNodeGlobalIndex(next_local_index);
1753 const double next_edge_length = this->GetDistanceBetweenNodes(this_global_index, next_global_index);
1754 assert(next_edge_length > DBL_EPSILON);
1756 const c_vector<double, SPACE_DIM> next_edge_gradient = this->GetVectorFromAtoB(pElement->GetNodeLocation(next_local_index), pElement->GetNodeLocation(localIndex)) / next_edge_length;
1758 return next_edge_gradient;
1766template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
1770 if constexpr (SPACE_DIM == 2)
1773 c_vector<double, SPACE_DIM> previous_edge_gradient = GetPreviousEdgeGradientOfElementAtNode(pElement, localIndex);
1774 c_vector<double, SPACE_DIM> next_edge_gradient = GetNextEdgeGradientOfElementAtNode(pElement, localIndex);
1776 return previous_edge_gradient + next_edge_gradient;
1788template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
1791 [[maybe_unused]] c_vector<double, SPACE_DIM>& rNormal)
1793 if constexpr (SPACE_DIM == 3)
1795 assert(SPACE_DIM == 3);
1798 assert(pFace->GetNumNodes() >= 3u);
1801 rNormal = zero_vector<double>(SPACE_DIM);
1803 c_vector<double, SPACE_DIM> v_minus_v0 = this->GetVectorFromAtoB(pFace->GetNode(0)->rGetLocation(), pFace->GetNode(1)->rGetLocation());
1804 for (
unsigned local_index = 2; local_index < pFace->GetNumNodes(); local_index++)
1806 c_vector<double, SPACE_DIM> vnext_minus_v0 = this->GetVectorFromAtoB(pFace->GetNode(0)->rGetLocation(), pFace->GetNode(local_index)->rGetLocation());
1808 v_minus_v0 = vnext_minus_v0;
1810 double magnitude = norm_2(rNormal);
1811 if (magnitude != 0.0)
1814 rNormal /= magnitude;
1818 return magnitude / 2.0;
1826template <
unsigned ELEMENT_DIM,
unsigned SPACE_DIM>
1830 if constexpr (SPACE_DIM == 3)
1833 c_vector<double, SPACE_DIM> unit_normal;
1834 return CalculateUnitNormalToFaceWithArea(pFace, unit_normal);
527 index_element_map[node_a_index] = p_element; {
…}
485 c_vector<double, 3> vertex_vector =
mNodes[*index_iter]->rGetLocation() - mid_edge; {
…}
435 unsigned face_index = 0; {
…}
354 for (
unsigned local_index = 0; local_index < 3; local_index++) {
…}
340 for (
unsigned elem_index = 0; elem_index < num_elements; elem_index++) {
…}
295 int num_sections = 1; {
…}
244 std::set<unsigned> shared_elements; {
…}
126 for (
unsigned face_index = 0; face_index < faces.size(); face_index++) {
…}
#define EXCEPTION(message)
const unsigned UNSIGNED_UNSET
#define EXPORT_TEMPLATE_CLASS_ALL_DIMS(CLASS)
c_vector< T, 1 > VectorProduct(const c_vector< T, 1 > &rA, const c_vector< T, 1 > &rB)
void SetAttribute(double attribute)
Node< SPACE_DIM > * GetNode(unsigned localIndex) const
double GetNodeLocation(unsigned localIndex, unsigned dimension) const
unsigned GetNumNodes() const
unsigned GetNodeGlobalIndex(unsigned localIndex) const
unsigned GetIndex() const
virtual unsigned GetNumElements() const =0
virtual ElementData GetNextElementData()=0
virtual unsigned GetNumElementAttributes() const
virtual std::vector< double > GetNextNode()=0
virtual bool HasNodePermutation()
virtual unsigned GetNumNodes() const =0
bool mMeshChangesDuringSimulation
virtual c_vector< double, SPACE_DIM > GetVectorFromAtoB(const c_vector< double, SPACE_DIM > &rLocationA, const c_vector< double, SPACE_DIM > &rLocationB)
std::vector< Node< SPACE_DIM > * > mNodes
Element< ELEMENT_DIM, SPACE_DIM > * GetElement(unsigned index) const
virtual unsigned GetNumElements() const
void AddNode(Node< SPACE_DIM > *pNode, const unsigned &rIndex)
std::set< unsigned > & rGetContainingElementIndices()
void AddElement(unsigned index)
const c_vector< double, SPACE_DIM > & rGetLocation() const
bool IsBoundaryNode() const
unsigned GetIndex() const
static RandomNumberGenerator * Instance()
virtual void GetInverseJacobianForElement(unsigned elementIndex, c_matrix< double, SPACE_DIM, ELEMENT_DIM > &rJacobian, double &rJacobianDeterminant, c_matrix< double, ELEMENT_DIM, SPACE_DIM > &rInverseJacobian) const
VertexElement< ELEMENT_DIM-1, SPACE_DIM > * GetFace(unsigned index) const
void AddFace(VertexElement< ELEMENT_DIM-1, SPACE_DIM > *pFace)
unsigned GetNumFaces() const
std::vector< VertexElement< ELEMENT_DIM - 1, SPACE_DIM > * > mFaces
virtual c_vector< double, SPACE_DIM > GetVectorFromAtoB(const c_vector< double, SPACE_DIM > &rLocationA, const c_vector< double, SPACE_DIM > &rLocationB)
double CalculateUnitNormalToFaceWithArea(VertexElement< ELEMENT_DIM - 1, SPACE_DIM > *pFace, c_vector< double, SPACE_DIM > &rNormal)
VertexElement< ELEMENT_DIM - 1, SPACE_DIM > * GetFace(unsigned index) const
virtual unsigned GetNumNodes() const
virtual double GetSurfaceAreaOfElement(unsigned index)
std::set< unsigned > GetNeighbouringNodeIndices(unsigned nodeIndex)
std::set< unsigned > GetNeighbouringNodeNotAlsoInElement(unsigned nodeIndex, unsigned elemIndex)
void GenerateEdgesFromElements(std::vector< VertexElement< ELEMENT_DIM, SPACE_DIM > * > &rElements)
virtual double CalculateAreaOfFace(VertexElement< ELEMENT_DIM - 1, SPACE_DIM > *pFace)
const EdgeHelper< SPACE_DIM > & rGetEdgeHelper() const
c_vector< double, SPACE_DIM > GetNextEdgeGradientOfElementAtNode(VertexElement< ELEMENT_DIM, SPACE_DIM > *pElement, unsigned localIndex)
virtual unsigned GetNumFaces() const
VertexElement< ELEMENT_DIM, SPACE_DIM > * GetElement(unsigned index) const
unsigned GetLocalIndexForElementEdgeClosestToPoint(const c_vector< double, SPACE_DIM > &rTestPoint, unsigned elementIndex)
double GetElongationShapeFactorOfElement(unsigned elementIndex)
unsigned GetNumAllElements() const
unsigned SolveNodeMapping(unsigned index) const
TetrahedralMesh< ELEMENT_DIM, SPACE_DIM > * mpDelaunayMesh
bool ElementIncludesPoint(const c_vector< double, SPACE_DIM > &rTestPoint, unsigned elementIndex)
c_vector< double, SPACE_DIM > GetAreaGradientOfElementAtNode(VertexElement< ELEMENT_DIM, SPACE_DIM > *pElement, unsigned localIndex)
bool IsNearExistingNodes(c_vector< double, SPACE_DIM > newNodeLocation, std::vector< Node< SPACE_DIM > * > nodesToCheck, double minClearance)
std::set< unsigned > GetNeighbouringElementIndices(unsigned elementIndex)
c_vector< double, SPACE_DIM > GetPerimeterGradientOfElementAtNode(VertexElement< ELEMENT_DIM, SPACE_DIM > *pElement, unsigned localIndex)
double GetEdgeLength(unsigned elementIndex1, unsigned elementIndex2)
c_vector< double, SPACE_DIM > GetShortAxisOfElement(unsigned index)
unsigned GetRosetteRankOfElement(unsigned index)
Edge< SPACE_DIM > * GetEdge(unsigned index) const
unsigned SolveBoundaryElementMapping(unsigned index) const
unsigned SolveElementMapping(unsigned index) const
unsigned GetVoronoiElementIndexCorrespondingToDelaunayNodeIndex(unsigned nodeIndex)
virtual c_vector< double, SPACE_DIM > GetCentroidOfElement(unsigned index)
std::map< unsigned, unsigned > mVoronoiElementIndexMap
void ConstructFromMeshReader(AbstractMeshReader< ELEMENT_DIM, SPACE_DIM > &rMeshReader)
unsigned GetDelaunayNodeIndexCorrespondingToVoronoiElementIndex(unsigned elementIndex)
unsigned GetNumEdges() const
c_vector< double, SPACE_DIM > GetPreviousEdgeGradientOfElementAtNode(VertexElement< ELEMENT_DIM, SPACE_DIM > *pElement, unsigned localIndex)
std::vector< VertexElement< ELEMENT_DIM, SPACE_DIM > * > mElements
virtual c_vector< double, 3 > CalculateMomentsOfElement(unsigned index)
virtual VertexMesh< ELEMENT_DIM, SPACE_DIM > * GetMeshForVtk()
virtual double GetVolumeOfElement(unsigned index)
virtual unsigned GetNumElements() const
void GenerateVerticesFromElementCircumcentres(TetrahedralMesh< ELEMENT_DIM, SPACE_DIM > &rMesh)
std::vector< unsigned > NodeIndices
std::vector< ElementData > Faces
std::vector< unsigned > NodeIndices