780 [[maybe_unused]]
unsigned index)
783 if constexpr (SPACE_DIM == 2)
788 c_vector<double, SPACE_DIM> centroid = zero_vector<double>(SPACE_DIM);
790 double centroid_x = 0;
791 double centroid_y = 0;
794 double element_signed_area = 0.0;
797 c_vector<double, SPACE_DIM> first_node_location = p_element->
GetNodeLocation(0);
798 c_vector<double, SPACE_DIM> pos_1 = zero_vector<double>(SPACE_DIM);
801 for (
unsigned local_index = 0; local_index < num_nodes; local_index++)
803 c_vector<double, SPACE_DIM> next_node_location = p_element->
GetNodeLocation((local_index + 1) % num_nodes);
804 c_vector<double, SPACE_DIM> pos_2 = GetVectorFromAtoB(first_node_location, next_node_location);
806 double this_x = pos_1[0];
807 double this_y = pos_1[1];
808 double next_x = pos_2[0];
809 double next_y = pos_2[1];
811 double signed_area_term = this_x * next_y - this_y * next_x;
813 centroid_x += (this_x + next_x) * signed_area_term;
814 centroid_y += (this_y + next_y) * signed_area_term;
815 element_signed_area += 0.5 * signed_area_term;
820 assert(element_signed_area != 0.0);
823 centroid = first_node_location;
824 centroid[0] += centroid_x / (6.0 * element_signed_area);
825 centroid[1] += centroid_y / (6.0 * element_signed_area);
827 centroid[0] = centroid[0] < 0 ? centroid[0] + 1.0 : fmod(centroid[0], 1.0);
828 centroid[1] = centroid[1] < 0 ? centroid[1] + 1.0 : fmod(centroid[1], 1.0);
1357 unsigned nodeAIndex,
1358 unsigned nodeBIndex,
1359 c_vector<double, SPACE_DIM> centroid,
1360 c_vector<double, SPACE_DIM> axisOfDivision)
1362 if constexpr (SPACE_DIM == 2 && ELEMENT_DIM == 2)
1366 EXCEPTION(
"The value of mElementDivisionSpacing has not been set.");
1382 double half_spacing = 0.5 * mElementDivisionSpacing;
1385 c_vector<double, SPACE_DIM> unit_axis = axisOfDivision / norm_2(axisOfDivision);
1386 c_vector<double, SPACE_DIM> unit_perp;
1387 unit_perp[0] = -unit_axis[1];
1388 unit_perp[1] = unit_axis[0];
1402 unsigned start_a = (nodeAIndex + 1) % num_nodes;
1403 unsigned end_a = nodeBIndex;
1405 unsigned start_b = (nodeBIndex + 1) % num_nodes;
1406 unsigned end_b = nodeAIndex;
1409 bool no_node_satisfied_condition_1 =
true;
1410 for (
unsigned i = start_a; i != end_a;)
1412 c_vector<double, SPACE_DIM> centroid_to_i = this->GetVectorFromAtoB(centroid, pElement->
GetNode(i)->rGetLocation());
1413 double perpendicular_dist = inner_prod(centroid_to_i, unit_perp);
1415 if (fabs(perpendicular_dist) >= half_spacing)
1417 no_node_satisfied_condition_1 =
false;
1421 c_vector<double, SPACE_DIM> new_location = pElement->
GetNode(i)->rGetLocation();
1422 new_location -= unit_perp * copysign(fabs(perpendicular_dist) - half_spacing, perpendicular_dist);
1429 i = (i + 1) % num_nodes;
1433 bool no_node_satisfied_condition_2 =
true;
1434 for (
unsigned i = end_a; i != start_a;)
1436 c_vector<double, SPACE_DIM> centroid_to_i = this->GetVectorFromAtoB(centroid, pElement->
GetNode(i)->rGetLocation());
1437 double perpendicular_dist = inner_prod(centroid_to_i, unit_perp);
1439 if (fabs(perpendicular_dist) >= half_spacing)
1441 no_node_satisfied_condition_2 =
false;
1445 c_vector<double, SPACE_DIM> new_location = pElement->
GetNode(i)->rGetLocation();
1446 new_location -= unit_perp * copysign(fabs(perpendicular_dist) - half_spacing, perpendicular_dist);
1453 i = (i + num_nodes - 1) % num_nodes;
1457 bool no_node_satisfied_condition_3 =
true;
1458 for (
unsigned i = start_b; i != end_b;)
1460 c_vector<double, SPACE_DIM> centroid_to_i = this->GetVectorFromAtoB(centroid, pElement->
GetNode(i)->rGetLocation());
1461 double perpendicular_dist = inner_prod(centroid_to_i, unit_perp);
1463 if (fabs(perpendicular_dist) >= half_spacing)
1465 no_node_satisfied_condition_3 =
false;
1469 c_vector<double, SPACE_DIM> new_location = pElement->
GetNode(i)->rGetLocation();
1470 new_location -= unit_perp * copysign(fabs(perpendicular_dist) - half_spacing, perpendicular_dist);
1477 i = (i + 1) % num_nodes;
1481 bool no_node_satisfied_condition_4 =
true;
1482 for (
unsigned i = end_b; i != start_b;)
1484 c_vector<double, SPACE_DIM> centroid_to_i = this->GetVectorFromAtoB(centroid, pElement->
GetNode(i)->rGetLocation());
1485 double perpendicular_dist = inner_prod(centroid_to_i, unit_perp);
1487 if (fabs(perpendicular_dist) >= half_spacing)
1489 no_node_satisfied_condition_4 =
false;
1493 c_vector<double, SPACE_DIM> new_location = pElement->
GetNode(i)->rGetLocation();
1494 new_location -= unit_perp * copysign(fabs(perpendicular_dist) - half_spacing, perpendicular_dist);
1501 i = (i + num_nodes - 1) % num_nodes;
1504 if (no_node_satisfied_condition_1 || no_node_satisfied_condition_2 || no_node_satisfied_condition_3 || no_node_satisfied_condition_4)
1506 EXCEPTION(
"Could not space elements far enough apart during cell division. Cannot currently handle this case");
1512 std::vector<c_vector<double, SPACE_DIM> > daughter_a_location_stencil;
1513 for (
unsigned node_idx = start_a; node_idx != (end_a + 1) % num_nodes;)
1515 daughter_a_location_stencil.push_back(c_vector<double, SPACE_DIM>(pElement->
GetNode(node_idx)->rGetLocation()));
1518 node_idx = (node_idx + 1) % num_nodes;
1521 std::vector<c_vector<double, SPACE_DIM> > daughter_b_location_stencil;
1522 for (
unsigned node_idx = start_b; node_idx != (end_b + 1) % num_nodes;)
1524 daughter_b_location_stencil.push_back(c_vector<double, SPACE_DIM>(pElement->
GetNode(node_idx)->rGetLocation()));
1527 node_idx = (node_idx + 1) % num_nodes;
1530 assert(daughter_a_location_stencil.size() > 1);
1531 assert(daughter_b_location_stencil.size() > 1);
1534 daughter_a_location_stencil.push_back(daughter_a_location_stencil[0]);
1535 daughter_b_location_stencil.push_back(daughter_b_location_stencil[0]);
1538 std::vector<double> cumulative_distances_a;
1539 std::vector<double> cumulative_distances_b;
1540 cumulative_distances_a.push_back(0.0);
1541 cumulative_distances_b.push_back(0.0);
1542 for (
unsigned loc_idx = 1; loc_idx < daughter_a_location_stencil.size(); loc_idx++)
1544 cumulative_distances_a.push_back(cumulative_distances_a.back() + norm_2(this->GetVectorFromAtoB(daughter_a_location_stencil[loc_idx - 1], daughter_a_location_stencil[loc_idx])));
1546 for (
unsigned loc_idx = 1; loc_idx < daughter_b_location_stencil.size(); loc_idx++)
1548 cumulative_distances_b.push_back(cumulative_distances_b.back() + norm_2(this->GetVectorFromAtoB(daughter_b_location_stencil[loc_idx - 1], daughter_b_location_stencil[loc_idx])));
1552 double target_spacing_a = cumulative_distances_a.back() / (
double)num_nodes;
1553 double target_spacing_b = cumulative_distances_b.back() / (
double)num_nodes;
1556 unsigned last_idx_used = 0;
1557 for (
unsigned node_idx = 0; node_idx < num_nodes; node_idx++)
1559 double location_along_arc = (
double)node_idx * target_spacing_a;
1561 while (location_along_arc > cumulative_distances_a[last_idx_used + 1])
1567 double interpolant = (location_along_arc - cumulative_distances_a[last_idx_used]) / (cumulative_distances_a[last_idx_used + 1] - cumulative_distances_a[last_idx_used]);
1569 c_vector<double, SPACE_DIM> this_to_next = this->GetVectorFromAtoB(daughter_a_location_stencil[last_idx_used],
1570 daughter_a_location_stencil[last_idx_used + 1]);
1572 c_vector<double, SPACE_DIM> new_location_a = daughter_a_location_stencil[last_idx_used] + interpolant * this_to_next;
1579 std::vector<Node<SPACE_DIM>*> new_nodes_vec;
1580 for (
unsigned node_idx = 0; node_idx < num_nodes; node_idx++)
1582 double location_along_arc = (
double)node_idx * target_spacing_b;
1584 while (location_along_arc > cumulative_distances_b[last_idx_used + 1])
1590 double interpolant = (location_along_arc - cumulative_distances_b[last_idx_used]) / (cumulative_distances_b[last_idx_used + 1] - cumulative_distances_b[last_idx_used]);
1592 c_vector<double, SPACE_DIM> this_to_next = this->GetVectorFromAtoB(daughter_b_location_stencil[last_idx_used],
1593 daughter_b_location_stencil[last_idx_used + 1]);
1595 c_vector<double, SPACE_DIM> new_location_b = daughter_b_location_stencil[last_idx_used] + interpolant * this_to_next;
1597 unsigned new_node_idx = this->mNodes.size();
1598 this->mNodes.push_back(
new Node<SPACE_DIM>(new_node_idx, new_location_b,
true));
1599 new_nodes_vec.push_back(this->mNodes.back());
1603 for (
unsigned node_idx = 0; node_idx < num_nodes; node_idx++)
1605 new_nodes_vec[node_idx]->SetRegion(pElement->
GetNode(node_idx)->GetRegion());
1607 for (
unsigned node_attribute = 0; node_attribute < pElement->
GetNode(node_idx)->GetNumNodeAttributes(); node_attribute++)
1609 new_nodes_vec[node_idx]->AddNodeAttribute(pElement->
GetNode(node_idx)->rGetNodeAttributes()[node_attribute]);
1614 unsigned new_elem_idx = this->mElements.size();
1616 this->mElements.back()->RegisterWithNodes();
1625 for (
unsigned corner = 0; corner < pElement->
rGetCornerNodes().size(); corner++)
1627 this->mElements.back()->rGetCornerNodes().push_back(pElement->
rGetCornerNodes()[corner]);
1634 c_vector<double, SPACE_DIM> new_centroid = this->GetCentroidOfElement(new_elem_idx);
1638 mElementFluidSources.back()->SetAssociatedElementIndex(new_elem_idx);
1639 mElementFluidSources.back()->SetStrength(0.0);
1642 mElements[new_elem_idx]->SetFluidSource(mElementFluidSources.back());
1644 return new_elem_idx;
1678 if constexpr (SPACE_DIM == 2)
1680 const unsigned num_nodes = pElement->
GetNumNodes();
1686 std::vector<c_vector<double, SPACE_DIM>> locations_straightened;
1687 locations_straightened.reserve(num_nodes);
1689 locations_straightened.emplace_back(pElement->
GetNodeLocation(start_idx));
1691 for (
unsigned node_idx = 1; node_idx < num_nodes; ++node_idx)
1693 const unsigned prev_idx = AdvanceMod(start_idx, node_idx - 1, num_nodes);
1694 const unsigned this_idx = AdvanceMod(start_idx, node_idx, num_nodes);
1696 const c_vector<double, SPACE_DIM>& r_last_location_added = locations_straightened.back();
1698 const c_vector<double, SPACE_DIM>& r_prev_location = pElement->
GetNodeLocation(prev_idx);
1699 const c_vector<double, SPACE_DIM>& r_this_location = pElement->
GetNodeLocation(this_idx);
1701 locations_straightened.emplace_back(r_last_location_added +
1702 this->GetVectorFromAtoB(r_prev_location, r_this_location));
1705 assert(locations_straightened.size() == num_nodes);
1707 const bool closed_path =
true;
1708 const bool permute_order =
false;
1709 const std::size_t num_pts_to_place = num_nodes;
1711 std::vector<c_vector<double, SPACE_DIM>> evenly_spaced_locations = EvenlySpaceAlongPath(
1712 locations_straightened,
1718 assert(evenly_spaced_locations.size() == num_nodes);
1721 for (c_vector<double, SPACE_DIM>& r_loc : evenly_spaced_locations)
1723 ConformToGeometry(r_loc);
1727 for (
unsigned node_idx = 0; node_idx < num_nodes; ++node_idx)
1729 const unsigned this_idx = AdvanceMod(node_idx, start_idx, num_nodes);
1730 pElement->
GetNode(this_idx)->rGetModifiableLocation() = evenly_spaced_locations[node_idx];
1743 if constexpr (SPACE_DIM == 2)
1745 const unsigned num_nodes = pLamina->
GetNumNodes();
1751 std::vector<c_vector<double, SPACE_DIM>> locations_straightened;
1752 locations_straightened.reserve(1 + num_nodes);
1754 locations_straightened.emplace_back(pLamina->
GetNodeLocation(start_idx));
1757 for (
unsigned node_idx = 1; node_idx < 1 + num_nodes; ++node_idx)
1759 const unsigned prev_idx = AdvanceMod(start_idx, node_idx - 1, num_nodes);
1760 const unsigned this_idx = AdvanceMod(start_idx, node_idx, num_nodes);
1762 const c_vector<double, SPACE_DIM>& r_last_location_added = locations_straightened.back();
1764 const c_vector<double, SPACE_DIM>& r_prev_location = pLamina->
GetNodeLocation(prev_idx);
1765 const c_vector<double, SPACE_DIM>& r_this_location = pLamina->
GetNodeLocation(this_idx);
1767 locations_straightened.emplace_back(r_last_location_added +
1768 this->GetVectorFromAtoB(r_prev_location, r_this_location));
1771 assert(locations_straightened.size() == 1 + num_nodes);
1773 const bool closed_path =
false;
1774 const bool permute_order =
false;
1775 const std::size_t num_pts_to_place = 1 + num_nodes;
1777 std::vector<c_vector<double, SPACE_DIM>> evenly_spaced_locations = EvenlySpaceAlongPath(
1778 locations_straightened,
1784 assert(evenly_spaced_locations.size() == 1 + num_nodes);
1787 for (c_vector<double, SPACE_DIM>& r_loc : evenly_spaced_locations)
1789 ConformToGeometry(r_loc);
1793 for (
unsigned node_idx = 0; node_idx < num_nodes; ++node_idx)
1795 const unsigned this_idx = AdvanceMod(start_idx, node_idx, num_nodes);
1796 pLamina->
GetNode(this_idx)->rGetModifiableLocation() = evenly_spaced_locations[node_idx];
1994 if (!mLaminas.empty())
1996 EXCEPTION(
"This method does not yet work in the presence of laminas");
2000 const double LARGE_DOUBLE = 1e6;
2010 UpdateNodeLocationsVoronoiDiagramIfOutOfDate();
2013 const unsigned max_elem_idx = GetMaxElementIndex();
2017 std::vector<double> max_shared_lengths(1 + max_elem_idx, 0.0);
2018 std::vector<double> voronoi_perimeter(1 + max_elem_idx, 0.0);
2021 for (
const auto& p_node : this->mNodes)
2023 const unsigned this_node_idx = p_node->GetIndex();
2024 const unsigned this_elem_idx = *p_node->ContainingElementsBegin();
2027 const unsigned voronoi_cell_id = mVoronoiCellIdsIndexedByNodeIndex[this_node_idx];
2028 const auto& voronoi_cell = mNodeLocationsVoronoiDiagram.cells()[voronoi_cell_id];
2031 auto p_edge = voronoi_cell.incident_edge();
2037 if (p_edge->is_infinite())
2039 max_shared_lengths[this_elem_idx] = LARGE_DOUBLE;
2040 voronoi_perimeter[this_elem_idx] += LARGE_DOUBLE;
2045 const unsigned twin_node_idx = p_edge->twin()->cell()->color();
2046 const unsigned twin_elem_idx = *this->GetNode(twin_node_idx)->ContainingElementsBegin();
2049 if (this_elem_idx != twin_elem_idx)
2051 const double edge_length = CalculateLengthOfVoronoiEdge(*p_edge);
2052 max_shared_lengths[this_elem_idx] = std::max(max_shared_lengths[this_elem_idx], edge_length);
2053 voronoi_perimeter[this_elem_idx] += edge_length;
2056 p_edge = p_edge->next();
2057 }
while (p_edge != voronoi_cell.incident_edge());
2061 std::vector<double> perimeter_multiples(voronoi_perimeter.size());
2062 for (
const auto& p_elem : this->mElements)
2064 const unsigned idx = p_elem->
GetIndex();
2065 perimeter_multiples[idx] = voronoi_perimeter[idx] / this->GetSurfaceAreaOfElement(idx);
2069 std::vector<double> copy_max_shared_lengths;
2070 std::vector<double> copy_perimeter_multiples;
2072 for (
const auto& p_elem : this->mElements)
2074 const unsigned idx = p_elem->
GetIndex();
2075 copy_max_shared_lengths.emplace_back(max_shared_lengths[idx]);
2076 copy_perimeter_multiples.emplace_back(perimeter_multiples[idx]);
2079 const std::size_t half_way = copy_max_shared_lengths.size() / 2;
2080 assert(half_way == copy_perimeter_multiples.size() / 2);
2082 std::nth_element(copy_max_shared_lengths.begin(), copy_max_shared_lengths.begin() + half_way, copy_max_shared_lengths.end());
2083 std::nth_element(copy_perimeter_multiples.begin(), copy_perimeter_multiples.begin() + half_way, copy_perimeter_multiples.end());
2085 double median_max_edge_length = copy_max_shared_lengths[half_way];
2086 double median_perimeter_multiple = copy_perimeter_multiples[half_way];
2090 if (median_max_edge_length == LARGE_DOUBLE || median_perimeter_multiple >= LARGE_DOUBLE)
2092 median_max_edge_length = 0.5 * LARGE_DOUBLE;
2093 median_perimeter_multiple = 0.5 * LARGE_DOUBLE;
2097 for (
const auto& p_elem : this->mElements)
2099 const unsigned idx = p_elem->
GetIndex();
2101 const bool large_shared_edge = max_shared_lengths[idx] > 1.1 * median_max_edge_length;
2102 const bool large_perimeter = perimeter_multiples[idx] > 1.1 * median_perimeter_multiple;
2111 if constexpr (SPACE_DIM == 2)
2113 using boost_point = boost::polygon::point_data<int>;
2120 double new_location_summary = this->mNodes.front()->rGetLocation()[0] +
2121 this->mNodes.front()->rGetLocation()[1] +
2122 this->mNodes.back()->rGetLocation()[0] +
2123 this->mNodes.back()->rGetLocation()[1];
2125 bool voronoi_needs_updating = std::fabs(mSummaryOfNodeLocations - new_location_summary) > DBL_EPSILON;
2137 if (voronoi_needs_updating)
2139 mSummaryOfNodeLocations = new_location_summary;
2142 const c_vector<double, SPACE_DIM> halo_up = Create_c_vector(0.0, 1.0);
2143 const c_vector<double, SPACE_DIM> halo_down = Create_c_vector(0.0, -1.0);
2144 const c_vector<double, SPACE_DIM> halo_left = Create_c_vector(-1.0, 0.0);
2145 const c_vector<double, SPACE_DIM> halo_right = Create_c_vector(1.0, 0.0);
2147 std::vector<std::pair<unsigned, c_vector<double, SPACE_DIM>>> halo_ids_and_locations;
2148 std::vector<unsigned> node_ids_in_source_idx_order;
2151 std::vector<boost_point> points;
2154 for (
const auto& p_node : this->mNodes)
2156 const double x_pos = p_node->rGetLocation()[0];
2157 const double y_pos = p_node->rGetLocation()[1];
2160 points.emplace_back(boost_point(ScaleUpToVoronoiCoordinate(x_pos), ScaleUpToVoronoiCoordinate(y_pos)));
2161 node_ids_in_source_idx_order.emplace_back(p_node->GetIndex());
2164 const bool needed_up = y_pos < mVoronoiHalo;
2165 const bool needed_down = y_pos > 1.0 - mVoronoiHalo;
2166 const bool needed_left = x_pos > 1.0 - mVoronoiHalo;
2167 const bool needed_right = x_pos < mVoronoiHalo;
2171 halo_ids_and_locations.emplace_back(std::make_pair(p_node->GetIndex(),
2172 p_node->rGetLocation() + halo_up));
2176 halo_ids_and_locations.emplace_back(std::make_pair(p_node->GetIndex(),
2177 p_node->rGetLocation() + halo_down));
2181 halo_ids_and_locations.emplace_back(std::make_pair(p_node->GetIndex(),
2182 p_node->rGetLocation() + halo_left));
2186 halo_ids_and_locations.emplace_back(std::make_pair(p_node->GetIndex(),
2187 p_node->rGetLocation() + halo_right));
2189 if (needed_up && needed_left)
2191 halo_ids_and_locations.emplace_back(std::make_pair(p_node->GetIndex(),
2192 p_node->rGetLocation() + halo_up + halo_left));
2194 if (needed_up && needed_right)
2196 halo_ids_and_locations.emplace_back(std::make_pair(p_node->GetIndex(),
2197 p_node->rGetLocation() + halo_up + halo_right));
2199 if (needed_down && needed_left)
2201 halo_ids_and_locations.emplace_back(std::make_pair(p_node->GetIndex(),
2202 p_node->rGetLocation() + halo_down + halo_left));
2204 if (needed_down && needed_right)
2206 halo_ids_and_locations.emplace_back(std::make_pair(p_node->GetIndex(),
2207 p_node->rGetLocation() + halo_down + halo_right));
2212 for (
const auto& pair : halo_ids_and_locations)
2214 const unsigned node_idx = pair.first;
2215 c_vector<double, SPACE_DIM> location = pair.second;
2217 const int x_coord = ScaleUpToVoronoiCoordinate(location[0]);
2218 const int y_coord = ScaleUpToVoronoiCoordinate(location[1]);
2220 points.emplace_back(boost_point(x_coord, y_coord));
2221 node_ids_in_source_idx_order.emplace_back(node_idx);
2225 mNodeLocationsVoronoiDiagram.clear();
2226 construct_voronoi(std::begin(points), std::end(points), &mNodeLocationsVoronoiDiagram);
2230 const unsigned max_node_idx = GetMaxNodeIndex();
2232 mVoronoiCellIdsIndexedByNodeIndex.resize(1 + max_node_idx);
2234 for (
unsigned vor_cell_id = 0; vor_cell_id < mNodeLocationsVoronoiDiagram.cells().size(); ++vor_cell_id)
2239 auto& r_this_cell = mNodeLocationsVoronoiDiagram.cells()[vor_cell_id];
2240 const auto source_idx = r_this_cell.source_index();
2241 const unsigned node_idx = node_ids_in_source_idx_order[source_idx];
2243 r_this_cell.color(node_idx);
2245 if (source_idx < this->mNodes.size())
2247 mVoronoiCellIdsIndexedByNodeIndex[node_idx] = vor_cell_id;
2252 this->TagBoundaryElements();