30#include <boost/container/small_vector.hpp>
53 const double theta = dir.
norm();
63 return tmp / tmp.
norm();
80 template <
int spacedim>
92 ExcMessage(
"The direction parameter must not be zero!"));
99 normal[0] = (vector[1] + vector[2]) / vector[0];
106 normal[1] = (vector[0] + vector[2]) / vector[1];
112 normal[2] = (vector[0] + vector[1]) / vector[2];
115 normal /= normal.
norm();
127template <
int dim,
int spacedim>
138template <
int dim,
int spacedim>
139std::unique_ptr<Manifold<dim, spacedim>>
142 return std::make_unique<PolarManifold<dim, spacedim>>(*this);
147template <
int dim,
int spacedim>
164template <
int dim,
int spacedim>
169 Assert(spherical_point[0] >= 0.0,
170 ExcMessage(
"Negative radius for given point."));
171 const double rho = spherical_point[0];
172 const double theta = spherical_point[1];
184 const double phi = spherical_point[2];
198template <
int dim,
int spacedim>
204 const double rho = R.
norm();
213 p[1] = std::atan2(R[1], R[0]);
221 const double z = R[2];
222 p[2] = std::atan2(R[1], R[0]);
225 p[1] = std::atan2(
std::sqrt(R[0] * R[0] + R[1] * R[1]), z);
237template <
int dim,
int spacedim>
242 Assert(spherical_point[0] >= 0.0,
243 ExcMessage(
"Negative radius for given point."));
244 const double rho = spherical_point[0];
245 const double theta = spherical_point[1];
262 const double phi = spherical_point[2];
287 template <
int dim,
int spacedim>
289 spherical_face_is_horizontal(
299 constexpr unsigned int n_vertices =
301 std::array<double, n_vertices> sqr_distances_to_center;
302 std::array<double, n_vertices - 1> sqr_distances_to_first_vertex;
303 sqr_distances_to_center[0] =
304 (face->vertex(0) - manifold_center).norm_square();
305 for (
unsigned int i = 1; i < n_vertices; ++i)
307 sqr_distances_to_center[i] =
308 (face->vertex(i) - manifold_center).norm_square();
309 sqr_distances_to_first_vertex[i - 1] =
310 (face->vertex(i) - face->vertex(0)).norm_square();
312 const auto minmax_sqr_distance =
313 std::minmax_element(sqr_distances_to_center.begin(),
314 sqr_distances_to_center.end());
315 const auto min_sqr_distance_to_first_vertex =
316 std::min_element(sqr_distances_to_first_vertex.begin(),
317 sqr_distances_to_first_vertex.end());
319 return (*minmax_sqr_distance.second - *minmax_sqr_distance.first <
320 1.e-10 * *min_sqr_distance_to_first_vertex);
326template <
int dim,
int spacedim>
336 if (spherical_face_is_horizontal<dim, spacedim>(face,
p_center))
343 unnormalized_spherical_normal / unnormalized_spherical_normal.
norm();
344 return normalized_spherical_normal;
361template <
int dim,
int spacedim>
372template <
int dim,
int spacedim>
373std::unique_ptr<Manifold<dim, spacedim>>
376 return std::make_unique<SphericalManifold<dim, spacedim>>(*this);
381template <
int dim,
int spacedim>
386 const double w)
const
388 const double tol = 1e-10;
390 if ((p1 - p2).norm_square() < tol * tol ||
std::abs(w) < tol)
402 const double r1 = v1.
norm();
403 const double r2 = v2.
norm();
405 Assert(r1 > tol && r2 > tol,
406 ExcMessage(
"p1 and p2 cannot coincide with the center."));
412 const double cosgamma = e1 * e2;
415 if (cosgamma < -1 + 8. * std::numeric_limits<double>::epsilon())
419 if (cosgamma > 1 - 8. * std::numeric_limits<double>::epsilon())
425 const double sigma = w *
std::acos(cosgamma);
430 const double n_norm = n.
norm();
433 "Probably, this means v1==v2 or v2==0."));
447template <
int dim,
int spacedim>
453 [[maybe_unused]]
const double tol = 1e-10;
459 const double r1 = v1.
norm();
460 const double r2 = v2.
norm();
470 const double cosgamma = e1 * e2;
472 Assert(cosgamma > -1 + 8. * std::numeric_limits<double>::epsilon(),
473 ExcMessage(
"p1 and p2 cannot lie on the same diameter and be opposite "
474 "respect to the center."));
476 if (cosgamma > 1 - 8. * std::numeric_limits<double>::epsilon())
482 const double n_norm = n.
norm();
485 "Probably, this means v1==v2 or v2==0."));
491 const double gamma =
std::acos(cosgamma);
492 return (r2 - r1) * e1 + r1 * gamma * n;
497template <
int dim,
int spacedim>
507 if (spherical_face_is_horizontal<dim, spacedim>(face,
p_center))
514 unnormalized_spherical_normal / unnormalized_spherical_normal.
norm();
515 return normalized_spherical_normal;
549template <
int dim,
int spacedim>
560 if (spherical_face_is_horizontal<dim, spacedim>(face,
p_center))
565 for (
unsigned int vertex = 0;
566 vertex < GeometryInfo<spacedim>::vertices_per_face;
568 face_vertex_normals[vertex] = face->vertex(vertex) -
p_center;
576template <
int dim,
int spacedim>
593template <
int dim,
int spacedim>
617 template <
int spacedim>
640 Point<3> candidate = candidate_point;
641 const unsigned int n_merged_points = directions.size();
642 const double tolerance = 1e-10;
643 const int max_iterations = 10;
648 for (
unsigned int i = 0; i < n_merged_points; ++i)
650 const double squared_distance =
651 (candidate - directions[i]).norm_square();
652 if (squared_distance < tolerance * tolerance)
658 if (n_merged_points == 2)
660 static const ::SphericalManifold<3, 3> unit_manifold;
664 unit_manifold.get_intermediate_point(
Point<3>(directions[0]),
677 for (
unsigned int i = 0; i < max_iterations; ++i)
691 for (
unsigned int i = 0; i < n_merged_points; ++i)
697 const double sintheta =
std::sqrt(sinthetaSq);
698 if (sintheta < tolerance)
700 Hessian[0][0] += weights[i];
701 Hessian[1][1] += weights[i];
705 const double costheta = (directions[i]) * candidate;
706 const double theta = std::atan2(sintheta, costheta);
707 const double sincthetaInv = theta / sintheta;
709 const double cosphi = vPerp * Clocalx;
710 const double sinphi = vPerp * Clocaly;
712 gradlocal[0] = cosphi;
713 gradlocal[1] = sinphi;
714 gradient += (weights[i] * sincthetaInv) * gradlocal;
716 const double wt = weights[i] / sinthetaSq;
717 const double sinphiSq = sinphi * sinphi;
718 const double cosphiSq = cosphi * cosphi;
719 const double tt = sincthetaInv * costheta;
720 const double offdiag =
721 cosphi * sinphi * wt * (1.0 - tt);
722 Hessian[0][0] += wt * (cosphiSq + tt * sinphiSq);
723 Hessian[0][1] += offdiag;
724 Hessian[1][0] += offdiag;
725 Hessian[1][1] += wt * (sinphiSq + tt * cosphiSq);
735 xDisplocal[0] * Clocalx + xDisplocal[1] * Clocaly;
739 const Point<3> candidateOld = candidate;
744 if ((candidate - candidateOld).norm_square() <
745 tolerance * tolerance)
757template <
int dim,
int spacedim>
765 new_points.size() * surrounding_points.size());
766 const unsigned int weight_rows = new_points.size();
767 const unsigned int weight_columns = surrounding_points.size();
769 if (surrounding_points.size() == 2)
771 for (
unsigned int row = 0; row < weight_rows; ++row)
774 surrounding_points[0],
775 surrounding_points[1],
776 weights[row * weight_columns + 1]);
780 boost::container::small_vector<std::pair<double, Tensor<1, spacedim>>, 100>
781 new_candidates(new_points.size());
782 boost::container::small_vector<Tensor<1, spacedim>, 100> directions(
784 boost::container::small_vector<double, 100> distances(
785 surrounding_points.size(), 0.0);
786 double max_distance = 0.;
787 for (
unsigned int i = 0; i < surrounding_points.size(); ++i)
789 directions[i] = surrounding_points[i] -
p_center;
790 distances[i] = directions[i].norm();
792 if (distances[i] != 0.)
793 directions[i] /= distances[i];
796 ExcMessage(
"One of the vertices coincides with the center. "
797 "This is not allowed!"));
801 for (
unsigned int k = 0; k < i; ++k)
803 const double squared_distance =
804 (directions[i] - directions[k]).norm_square();
805 max_distance =
std::max(max_distance, squared_distance);
811 const double tolerance = 1e-10;
812 boost::container::small_vector<bool, 100> accurate_point_was_found(
813 new_points.size(),
false);
818 for (
unsigned int row = 0; row < weight_rows; ++row)
820 new_candidates[row] =
828 if (new_candidates[row].first == 0.0)
831 accurate_point_was_found[row] =
true;
846 if constexpr (spacedim < 3)
854 if (max_distance < 2e-2)
856 for (
unsigned int row = 0; row < weight_rows; ++row)
858 p_center + new_candidates[row].first * new_candidates[row].second;
868 boost::container::small_vector<double, 1000> merged_weights(
870 boost::container::small_vector<Tensor<1, spacedim>, 100>
872 boost::container::small_vector<double, 100> merged_distances(
873 surrounding_points.size(), 0.0);
875 unsigned int n_unique_directions = 0;
876 for (
unsigned int i = 0; i < surrounding_points.size(); ++i)
878 bool found_duplicate =
false;
882 for (
unsigned int j = 0; j < n_unique_directions; ++j)
884 const double squared_distance =
885 (directions[i] - directions[j]).norm_square();
886 if (!found_duplicate && squared_distance < 1e-28)
888 found_duplicate =
true;
889 for (
unsigned int row = 0; row < weight_rows; ++row)
890 merged_weights[row * weight_columns + j] +=
891 weights[row * weight_columns + i];
895 if (found_duplicate ==
false)
897 merged_directions[n_unique_directions] = directions[i];
898 merged_distances[n_unique_directions] = distances[i];
899 for (
unsigned int row = 0; row < weight_rows; ++row)
900 merged_weights[row * weight_columns + n_unique_directions] =
901 weights[row * weight_columns + i];
903 ++n_unique_directions;
909 boost::container::small_vector<unsigned int, 100> merged_weights_index(
911 for (
unsigned int row = 0; row < weight_rows; ++row)
913 for (
unsigned int existing_row = 0; existing_row < row;
916 bool identical_weights =
true;
918 for (
unsigned int weight_index = 0;
919 weight_index < n_unique_directions;
922 merged_weights[row * weight_columns + weight_index] -
923 merged_weights[existing_row * weight_columns +
924 weight_index]) > tolerance)
926 identical_weights =
false;
930 if (identical_weights)
932 merged_weights_index[row] = existing_row;
942 merged_directions.begin() + n_unique_directions);
945 merged_distances.begin() + n_unique_directions);
947 for (
unsigned int row = 0; row < weight_rows; ++row)
948 if (!accurate_point_was_found[row])
953 &merged_weights[row * weight_columns], n_unique_directions);
954 new_candidates[row].second =
955 internal::SphericalManifold::do_get_new_point(
956 array_merged_directions,
957 array_merged_distances,
958 array_merged_weights,
962 new_candidates[row].second =
963 new_candidates[merged_weights_index[row]].second;
966 p_center + new_candidates[row].first * new_candidates[row].second;
973template <
int dim,
int spacedim>
974std::pair<double, Tensor<1, spacedim>>
980 const double tolerance = 1e-10;
985 double total_weights = 0.;
986 for (
unsigned int i = 0; i < directions.size(); ++i)
989 if (
std::abs(1 - weights[i]) < tolerance)
990 return std::make_pair(distances[i], directions[i]);
992 rho += distances[i] * weights[i];
993 candidate += directions[i] * weights[i];
994 total_weights += weights[i];
998 const double norm = candidate.
norm();
1002 rho /= total_weights;
1004 return std::make_pair(rho, candidate);
1012template <
int dim,
int spacedim>
1022 ExcMessage(
"CylindricalManifold can only be used for spacedim==3!"));
1027template <
int dim,
int spacedim>
1034 , direction(direction / direction.norm())
1035 , point_on_axis(point_on_axis)
1036 , tolerance(tolerance)
1042 ExcMessage(
"CylindricalManifold can only be used for spacedim==3!"));
1047template <
int dim,
int spacedim>
1048std::unique_ptr<Manifold<dim, spacedim>>
1051 return std::make_unique<CylindricalManifold<dim, spacedim>>(*this);
1056template <
int dim,
int spacedim>
1063 ExcMessage(
"CylindricalManifold can only be used for spacedim==3!"));
1067 double average_length = 0.;
1068 for (
unsigned int i = 0; i < surrounding_points.size(); ++i)
1070 middle += surrounding_points[i] * weights[i];
1071 average_length += surrounding_points[i].square() * weights[i];
1074 const double lambda = middle *
direction;
1085template <
int dim,
int spacedim>
1091 ExcMessage(
"CylindricalManifold can only be used for spacedim==3!"));
1095 const double lambda = normalized_point *
direction;
1111template <
int dim,
int spacedim>
1117 ExcMessage(
"CylindricalManifold can only be used for spacedim==3!"));
1120 const double sine_r =
std::sin(chart_point[1]) * chart_point[0];
1121 const double cosine_r =
std::cos(chart_point[1]) * chart_point[0];
1131template <
int dim,
int spacedim>
1137 ExcMessage(
"CylindricalManifold can only be used for spacedim==3!"));
1142 const double sine =
std::sin(chart_point[1]);
1143 const double cosine =
std::cos(chart_point[1]);
1148 constexpr int s0 = 0 % spacedim;
1149 constexpr int s1 = 1 % spacedim;
1150 constexpr int s2 = 2 % spacedim;
1153 derivatives[s0][s0] = intermediate[s0];
1154 derivatives[s1][s0] = intermediate[s1];
1155 derivatives[s2][s0] = intermediate[s2];
1178 const double norm = t.
norm();
1179 Assert(norm > 0.0,
ExcMessage(
"The major axis must have a positive norm."));
1189template <
int dim,
int spacedim>
1196 ,
direction(check_and_normalize(major_axis_direction))
1207 "Invalid eccentricity: It must satisfy 0 < eccentricity < 1."));
1212template <
int dim,
int spacedim>
1213std::unique_ptr<Manifold<dim, spacedim>>
1216 return std::make_unique<EllipticalManifold<dim, spacedim>>(*this);
1221template <
int dim,
int spacedim>
1234template <
int dim,
int spacedim>
1248 const double cs =
std::cos(chart_point[1]);
1249 const double sn =
std::sin(chart_point[1]);
1252 const double x = chart_point[0] *
cosh_u * cs;
1253 const double y = chart_point[0] *
sinh_u * sn;
1262template <
int dim,
int spacedim>
1277 const double x0 = space_point[0] -
center[0];
1278 const double y0 = space_point[1] -
center[1];
1288 double cos_eta = x / (pt0 *
cosh_u);
1298 const double pt1 = (std::signbit(y) ? 2.0 *
numbers::PI - eta : eta);
1304template <
int dim,
int spacedim>
1320 const double cs =
std::cos(chart_point[1]);
1321 const double sn =
std::sin(chart_point[1]);
1324 dX[0][1] = -chart_point[0] *
cosh_u * sn;
1326 dX[1][1] = chart_point[0] *
sinh_u * cs;
1340template <
int dim,
int spacedim,
int chartdim>
1360template <
int dim,
int spacedim,
int chartdim>
1380template <
int dim,
int spacedim,
int chartdim>
1410template <
int dim,
int spacedim,
int chartdim>
1427template <
int dim,
int spacedim,
int chartdim>
1428std::unique_ptr<Manifold<dim, spacedim>>
1445 return std::make_unique<FunctionManifold<dim, spacedim, chartdim>>(
1457 return std::make_unique<FunctionManifold<dim, spacedim, chartdim>>(
1467template <
int dim,
int spacedim,
int chartdim>
1475 for (
unsigned int i = 0; i < spacedim; ++i)
1482 for (
unsigned int i = 0; i < chartdim; ++i)
1485 (
std::abs(pb[i] - chart_point[i]) <
1489 "The push forward is not the inverse of the pull back! Bailing out."));
1497template <
int dim,
int spacedim,
int chartdim>
1503 for (
unsigned int i = 0; i < spacedim; ++i)
1506 for (
unsigned int j = 0; j < chartdim; ++j)
1507 DF[i][j] = gradient[j];
1514template <
int dim,
int spacedim,
int chartdim>
1522 for (
unsigned int i = 0; i < chartdim; ++i)
1539 double phi = std::atan2(y, x);
1546 return {phi, theta, w};
1555 double phi = chart_point[0];
1556 double theta = chart_point[1];
1557 double w = chart_point[2];
1576 ExcMessage(
"The centerline radius must be greater than the "
1584std::unique_ptr<Manifold<dim, 3>>
1598 double phi = chart_point[0];
1599 double theta = chart_point[1];
1600 double w = chart_point[2];
1624template <
int dim,
int spacedim>
1635template <
int dim,
int spacedim>
1645template <
int dim,
int spacedim>
1646std::unique_ptr<Manifold<dim, spacedim>>
1652 return std::unique_ptr<Manifold<dim, spacedim>>(ptr);
1657template <
int dim,
int spacedim>
1666 this->triangulation =
nullptr;
1681 const std::vector<Point<dim>> unit_points =
1683 std::vector<Point<spacedim>> real_points(unit_points.size());
1685 for (
const auto &cell :
triangulation.active_cell_iterators())
1687 bool cell_is_flat =
true;
1688 for (
const auto l : cell->line_indices())
1689 if (cell->line(l)->manifold_id() != cell->manifold_id() &&
1691 cell_is_flat =
false;
1692 if constexpr (dim > 2)
1693 for (
const auto q : cell->face_indices())
1694 if (cell->quad(q)->manifold_id() != cell->manifold_id() &&
1696 cell_is_flat =
false;
1702 for (
unsigned int i = 0; i < unit_points.size(); ++i)
1713 template <
typename AccessorType>
1715 compute_transfinite_interpolation(
const AccessorType &cell,
1719 return cell.vertex(0) * (1. - chart_point[0]) +
1720 cell.vertex(1) * chart_point[0];
1724 template <
typename AccessorType>
1726 compute_transfinite_interpolation(
const AccessorType &cell,
1728 const bool cell_is_flat)
1730 const unsigned int dim = AccessorType::dimension;
1731 const unsigned int spacedim = AccessorType::space_dimension;
1739 const std::array<Point<spacedim>, 4> vertices{
1740 {cell.vertex(0), cell.vertex(1), cell.vertex(2), cell.vertex(3)}};
1745 std::array<double, 4> weights_vertices{
1746 {(1. - chart_point[0]) * (1. - chart_point[1]),
1747 chart_point[0] * (1. - chart_point[1]),
1748 (1. - chart_point[0]) * chart_point[1],
1749 chart_point[0] * chart_point[1]}};
1754 new_point += weights_vertices[v] * vertices[v];
1766 std::array<double, GeometryInfo<2>::vertices_per_face> weights;
1769 const auto weights_view =
1771 const auto points_view =
make_array_view(points.begin(), points.end());
1773 for (
unsigned int line = 0; line < GeometryInfo<2>::lines_per_cell;
1776 const double my_weight =
1777 (line % 2) ? chart_point[line / 2] : 1 - chart_point[line / 2];
1778 const double line_point = chart_point[1 - line / 2];
1785 cell.line(line)->manifold_id();
1786 if (line_manifold_id == my_manifold_id ||
1791 my_weight * (1. - line_point);
1794 my_weight * line_point;
1802 weights[0] = 1. - line_point;
1803 weights[1] = line_point;
1812 new_point -= weights_vertices[v] * vertices[v];
1821 static constexpr unsigned int face_to_cell_vertices_3d[6][4] = {{0, 2, 4, 6},
1831 static constexpr unsigned int face_to_cell_lines_3d[6][4] = {{8, 10, 0, 4},
1839 template <
typename AccessorType>
1841 compute_transfinite_interpolation(
const AccessorType &cell,
1843 const bool cell_is_flat)
1845 const unsigned int dim = AccessorType::dimension;
1846 const unsigned int spacedim = AccessorType::space_dimension;
1852 const std::array<Point<spacedim>, 8> vertices{{cell.vertex(0),
1864 double linear_shapes[10];
1865 for (
unsigned int d = 0;
d < 3; ++
d)
1867 linear_shapes[2 *
d] = 1. - chart_point[
d];
1868 linear_shapes[2 *
d + 1] = chart_point[
d];
1872 for (
unsigned int d = 6;
d < 10; ++
d)
1873 linear_shapes[d] = linear_shapes[d - 6];
1875 std::array<double, 8> weights_vertices;
1876 for (
unsigned int i2 = 0, v = 0; i2 < 2; ++i2)
1877 for (
unsigned int i1 = 0; i1 < 2; ++i1)
1878 for (
unsigned int i0 = 0; i0 < 2; ++i0, ++v)
1879 weights_vertices[v] =
1880 (linear_shapes[4 + i2] * linear_shapes[2 + i1]) * linear_shapes[i0];
1884 for (
unsigned int v = 0; v < 8; ++v)
1885 new_point += weights_vertices[v] * vertices[v];
1891 std::array<double, GeometryInfo<3>::lines_per_cell> weights_lines;
1892 std::fill(weights_lines.begin(), weights_lines.end(), 0.0);
1895 std::array<double, GeometryInfo<2>::vertices_per_cell> weights;
1898 const auto weights_view =
1900 const auto points_view =
make_array_view(points.begin(), points.end());
1904 const double my_weight = linear_shapes[face];
1905 const unsigned int face_even = face - face % 2;
1913 cell.face(face)->manifold_id();
1914 if (face_manifold_id == my_manifold_id ||
1917 for (
unsigned int line = 0;
1918 line < GeometryInfo<2>::lines_per_cell;
1921 const double line_weight =
1922 linear_shapes[face_even + 2 + line];
1923 weights_lines[face_to_cell_lines_3d[face][line]] +=
1924 my_weight * line_weight;
1930 weights_vertices[face_to_cell_vertices_3d[face][0]] -=
1931 linear_shapes[face_even + 2] *
1932 (linear_shapes[face_even + 4] * my_weight);
1933 weights_vertices[face_to_cell_vertices_3d[face][1]] -=
1934 linear_shapes[face_even + 3] *
1935 (linear_shapes[face_even + 4] * my_weight);
1936 weights_vertices[face_to_cell_vertices_3d[face][2]] -=
1937 linear_shapes[face_even + 2] *
1938 (linear_shapes[face_even + 5] * my_weight);
1939 weights_vertices[face_to_cell_vertices_3d[face][3]] -=
1940 linear_shapes[face_even + 3] *
1941 (linear_shapes[face_even + 5] * my_weight);
1946 points[v] = vertices[face_to_cell_vertices_3d[face][v]];
1948 linear_shapes[face_even + 2] * linear_shapes[face_even + 4];
1950 linear_shapes[face_even + 3] * linear_shapes[face_even + 4];
1952 linear_shapes[face_even + 2] * linear_shapes[face_even + 5];
1954 linear_shapes[face_even + 3] * linear_shapes[face_even + 5];
1962 const auto weights_view_line =
1964 const auto points_view_line =
1966 for (
unsigned int line = 0; line < GeometryInfo<3>::lines_per_cell;
1969 const double line_point =
1970 (line < 8 ? chart_point[1 - (line % 4) / 2] : chart_point[2]);
1971 double my_weight = 0.;
1973 my_weight = linear_shapes[line % 4] * linear_shapes[4 + line / 4];
1976 const unsigned int subline = line - 8;
1978 linear_shapes[subline % 2] * linear_shapes[2 + subline / 2];
1980 my_weight -= weights_lines[line];
1986 cell.line(line)->manifold_id();
1987 if (line_manifold_id == my_manifold_id ||
1992 my_weight * (1. - line_point);
1995 my_weight * (line_point);
2003 weights[0] = 1. - line_point;
2004 weights[1] = line_point;
2005 new_point -= my_weight * tria.
get_manifold(line_manifold_id)
2013 new_point += weights_vertices[v] * vertices[v];
2021template <
int dim,
int spacedim>
2033 ExcMessage(
"chart_point is not in unit interval"));
2035 return compute_transfinite_interpolation(*cell,
2042template <
int dim,
int spacedim>
2051 for (
unsigned int d = 0; d < dim; ++d)
2054 const double step = chart_point[d] > 0.5 ? -1e-8 : 1e-8;
2057 modified[d] += step;
2059 compute_transfinite_interpolation(*cell,
2062 pushed_forward_chart_point;
2063 for (
unsigned int e = 0; e < spacedim; ++e)
2064 grad[e][d] = difference[e] / step;
2071template <
int dim,
int spacedim>
2079 for (
unsigned int d = 0; d < dim; ++d)
2092 compute_transfinite_interpolation(*cell,
2096 double residual_norm_square = residual.
norm_square();
2098 bool must_recompute_jacobian =
true;
2099 for (
unsigned int i = 0; i < 100; ++i)
2101 if (residual_norm_square < tolerance)
2108 for (
unsigned int d = 0; d < spacedim; ++d)
2109 for (
unsigned int e = 0; e < dim; ++e)
2110 update[e] += inv_grad[d][e] * residual[d];
2111 return chart_point + update;
2123 if (must_recompute_jacobian || i % 9 == 0)
2137 must_recompute_jacobian =
false;
2140 for (
unsigned int d = 0; d < spacedim; ++d)
2141 for (
unsigned int e = 0; e < dim; ++e)
2142 update[e] += inv_grad[d][e] * residual[d];
2156 while (alpha > 1e-4)
2158 Point<dim> guess = chart_point + alpha * update;
2160 point - compute_transfinite_interpolation(
2162 const double residual_norm_new = residual_guess.
norm_square();
2163 if (residual_norm_new < residual_norm_square)
2165 residual = residual_guess;
2166 residual_norm_square = residual_norm_new;
2167 chart_point += alpha * update;
2180 must_recompute_jacobian =
true;
2194 for (
unsigned int d = 0; d < spacedim; ++d)
2195 for (
unsigned int e = 0; e < dim; ++e)
2196 Jinv_deltaf[e] += inv_grad[d][e] * delta_f[d];
2203 if (
std::abs(delta_x * Jinv_deltaf) > 1e-12 && !must_recompute_jacobian)
2206 (delta_x - Jinv_deltaf) / (delta_x * Jinv_deltaf);
2208 for (
unsigned int d = 0; d < spacedim; ++d)
2209 for (
unsigned int e = 0; e < dim; ++e)
2210 jac_update[d] += delta_x[e] * inv_grad[d][e];
2211 for (
unsigned int d = 0; d < spacedim; ++d)
2212 for (
unsigned int e = 0; e < dim; ++e)
2213 inv_grad[d][e] += factor[e] * jac_update[d];
2221template <
int dim,
int spacedim>
2222std::array<unsigned int, 20>
2232 ExcMessage(
"The manifold was initialized with level " +
2234 "active cells on a lower level. Coarsening the mesh is " +
2235 "currently not supported"));
2245 boost::container::small_vector<std::pair<double, unsigned int>, 200>
2246 distances_and_cells;
2247 for (; cell != endc; ++cell)
2257 vertices[vertex_n] = cell->
vertex(vertex_n);
2265 center += vertices[v];
2267 double radius_square = 0.;
2270 std::max(radius_square, (center - vertices[v]).norm_square());
2271 bool inside_circle =
true;
2272 for (
unsigned int i = 0; i < points.size(); ++i)
2273 if ((center - points[i]).norm_square() > radius_square * 1.5)
2275 inside_circle =
false;
2278 if (inside_circle ==
false)
2282 double current_distance = 0;
2283 for (
unsigned int i = 0; i < points.size(); ++i)
2289 distances_and_cells.push_back(
2290 std::make_pair(current_distance, cell->
index()));
2295 std::sort(distances_and_cells.begin(), distances_and_cells.end());
2296 std::array<unsigned int, 20> cells;
2298 for (
unsigned int i = 0; i < distances_and_cells.size() && i < cells.size();
2300 cells[i] = distances_and_cells[i].second;
2307template <
int dim,
int spacedim>
2313 Assert(surrounding_points.size() == chart_points.size(),
2314 ExcMessage(
"The chart points array view must be as large as the "
2315 "surrounding points array view."));
2317 std::array<unsigned int, 20> nearby_cells =
2342 auto guess_chart_point_structdim_2 = [&](
const unsigned int i) ->
Point<dim> {
2343 Assert(surrounding_points.size() == 8 && 2 < i && i < 8,
2344 ExcMessage(
"This function assumes that there are eight surrounding "
2345 "points around a two-dimensional object. It also assumes "
2346 "that the first three chart points have already been "
2356 return chart_points[1] + (chart_points[2] - chart_points[0]);
2358 return 0.5 * (chart_points[0] + chart_points[2]);
2360 return 0.5 * (chart_points[1] + chart_points[3]);
2362 return 0.5 * (chart_points[0] + chart_points[1]);
2364 return 0.5 * (chart_points[2] + chart_points[3]);
2393 auto guess_chart_point_structdim_3 = [&](
const unsigned int i) ->
Point<dim> {
2394 Assert(surrounding_points.size() == 8 && 4 < i && i < 8,
2395 ExcMessage(
"This function assumes that there are eight surrounding "
2396 "points around a three-dimensional object. It also "
2397 "assumes that the first five chart points have already "
2399 return chart_points[i - 4] + (chart_points[4] - chart_points[0]);
2403 bool use_structdim_2_guesses =
false;
2404 bool use_structdim_3_guesses =
false;
2409 if (surrounding_points.size() == 8)
2412 surrounding_points[6] - surrounding_points[0];
2414 surrounding_points[7] - surrounding_points[2];
2422 use_structdim_2_guesses =
true;
2423 else if (spacedim == 3)
2426 use_structdim_3_guesses =
true;
2429 Assert((!use_structdim_2_guesses && !use_structdim_3_guesses) ||
2430 (use_structdim_2_guesses ^ use_structdim_3_guesses),
2435 auto compute_chart_point =
2437 const unsigned int point_index) {
2443 bool used_quadratic_approximation =
false;
2446 if (point_index == 3 && surrounding_points.size() >= 8)
2447 guess = chart_points[1] + (chart_points[2] - chart_points[0]);
2448 else if (use_structdim_2_guesses && 3 < point_index)
2449 guess = guess_chart_point_structdim_2(point_index);
2450 else if (use_structdim_3_guesses && 4 < point_index)
2451 guess = guess_chart_point_structdim_3(point_index);
2452 else if (dim == 3 && point_index > 7 && surrounding_points.size() == 26)
2454 if (point_index < 20)
2457 point_index - 8, 0)] +
2459 point_index - 8, 1)]);
2463 point_index - 20, 0)] +
2465 point_index - 20, 1)] +
2467 point_index - 20, 2)] +
2469 point_index - 20, 3)]);
2474 surrounding_points[point_index]);
2475 used_quadratic_approximation =
true;
2477 chart_points[point_index] =
2478 pull_back(cell, surrounding_points[point_index], guess);
2483 if (chart_points[point_index][0] ==
2485 !used_quadratic_approximation)
2488 surrounding_points[point_index]);
2489 chart_points[point_index] =
2490 pull_back(cell, surrounding_points[point_index], guess);
2493 if (chart_points[point_index][0] ==
2496 for (
unsigned int d = 0; d < dim; ++d)
2498 chart_points[point_index] =
2499 pull_back(cell, surrounding_points[point_index], guess);
2504 for (
unsigned int c = 0; c < nearby_cells.size(); ++c)
2508 bool inside_unit_cell =
true;
2509 for (
unsigned int i = 0; i < surrounding_points.size(); ++i)
2511 compute_chart_point(cell, i);
2518 inside_unit_cell =
false;
2522 if (inside_unit_cell ==
true)
2529 if (c == nearby_cells.size() - 1 ||
2534 std::ostringstream message;
2535 for (
unsigned int b = 0; b <= c; ++b)
2539 message <<
"Looking at cell " << cell->
id()
2540 <<
" with vertices: " << std::endl;
2542 message << cell->
vertex(v) <<
" ";
2543 message << std::endl;
2544 message <<
"Transformation to chart coordinates: " << std::endl;
2545 for (
unsigned int i = 0; i < surrounding_points.size(); ++i)
2547 compute_chart_point(cell, i);
2548 message << surrounding_points[i] <<
" -> " << chart_points[i]
2568template <
int dim,
int spacedim>
2574 boost::container::small_vector<Point<dim>, 100> chart_points(
2575 surrounding_points.size());
2588template <
int dim,
int spacedim>
2598 boost::container::small_vector<Point<dim>, 100> chart_points(
2599 surrounding_points.size());
2604 boost::container::small_vector<Point<dim>, 100> new_points_on_chart(
2609 new_points_on_chart.end()));
2611 for (
unsigned int row = 0; row < weights.size(0); ++row)
2612 new_points[row] =
push_forward(cell, new_points_on_chart[row]);
2618#include "grid/manifold_lib.inst"
ArrayView< std::remove_reference_t< typename std::iterator_traits< Iterator >::reference >, MemorySpaceType > make_array_view(const Iterator begin, const Iterator end)
double diameter(const Mapping< dim, spacedim > &mapping) const
ChartManifold(const Tensor< 1, chartdim > &periodicity=Tensor< 1, chartdim >())
const Tensor< 1, chartdim > & get_periodicity() const
virtual Point< spacedim > get_new_point(const ArrayView< const Point< spacedim > > &surrounding_points, const ArrayView< const double > &weights) const override
virtual Point< spacedim > push_forward(const Point< 3 > &chart_point) const override
const Tensor< 1, spacedim > dxn
virtual DerivativeForm< 1, 3, spacedim > push_forward_gradient(const Point< 3 > &chart_point) const override
virtual Point< spacedim > get_new_point(const ArrayView< const Point< spacedim > > &surrounding_points, const ArrayView< const double > &weights) const override
virtual std::unique_ptr< Manifold< dim, spacedim > > clone() const override
const Tensor< 1, spacedim > normal_direction
CylindricalManifold(const unsigned int axis=0, const double tolerance=1e-10)
const Point< spacedim > point_on_axis
const Tensor< 1, spacedim > direction
virtual Point< 3 > pull_back(const Point< spacedim > &space_point) const override
virtual std::unique_ptr< Manifold< dim, spacedim > > clone() const override
const Point< spacedim > center
const double eccentricity
virtual Point< spacedim > push_forward(const Point< spacedim > &chart_point) const override
EllipticalManifold(const Point< spacedim > ¢er, const Tensor< 1, spacedim > &major_axis_direction, const double eccentricity)
virtual DerivativeForm< 1, spacedim, spacedim > push_forward_gradient(const Point< spacedim > &chart_point) const override
virtual Point< spacedim > pull_back(const Point< spacedim > &space_point) const override
static Tensor< 1, spacedim > get_periodicity()
const Tensor< 1, spacedim > direction
const FunctionParser< spacedim >::ConstMap const_map
const std::string chart_vars
const std::string pull_back_expression
virtual DerivativeForm< 1, chartdim, spacedim > push_forward_gradient(const Point< chartdim > &chart_point) const override
const std::string space_vars
virtual Point< spacedim > push_forward(const Point< chartdim > &chart_point) const override
const double finite_difference_step
FunctionManifold(const Function< chartdim > &push_forward_function, const Function< spacedim > &pull_back_function, const Tensor< 1, chartdim > &periodicity=Tensor< 1, chartdim >(), const double tolerance=1e-10)
virtual std::unique_ptr< Manifold< dim, spacedim > > clone() const override
const std::string push_forward_expression
virtual Point< chartdim > pull_back(const Point< spacedim > &space_point) const override
ObserverPointer< const Function< chartdim >, FunctionManifold< dim, spacedim, chartdim > > push_forward_function
ObserverPointer< const Function< spacedim >, FunctionManifold< dim, spacedim, chartdim > > pull_back_function
virtual ~FunctionManifold() override
virtual void initialize(const std::string &vars, const std::vector< std::string > &expressions, const ConstMap &constants, const bool time_dependent=false) override
std::map< std::string, double > ConstMap
virtual void get_normals_at_vertices(const typename Triangulation< dim, spacedim >::face_iterator &face, FaceVertexNormals &face_vertex_normals) const
virtual Tensor< 1, spacedim > normal_vector(const typename Triangulation< dim, spacedim >::face_iterator &face, const Point< spacedim > &p) const
std::array< Tensor< 1, spacedim >, GeometryInfo< dim >::vertices_per_face > FaceVertexNormals
virtual Point< spacedim > get_new_point(const ArrayView< const Point< spacedim > > &surrounding_points, const ArrayView< const double > &weights) const
PolarManifold(const Point< spacedim > center=Point< spacedim >())
static Tensor< 1, spacedim > get_periodicity()
virtual std::unique_ptr< Manifold< dim, spacedim > > clone() const override
virtual DerivativeForm< 1, spacedim, spacedim > push_forward_gradient(const Point< spacedim > &chart_point) const override
const Point< spacedim > center
const Point< spacedim > p_center
virtual Tensor< 1, spacedim > normal_vector(const typename Triangulation< dim, spacedim >::face_iterator &face, const Point< spacedim > &p) const override
virtual Point< spacedim > push_forward(const Point< spacedim > &chart_point) const override
virtual Point< spacedim > pull_back(const Point< spacedim > &space_point) const override
Point< dim > closest_point(const Point< dim > &p) const
virtual Point< spacedim > get_new_point(const ArrayView< const Point< spacedim > > &vertices, const ArrayView< const double > &weights) const override
virtual std::unique_ptr< Manifold< dim, spacedim > > clone() const override
const Point< spacedim > p_center
const Point< spacedim > center
virtual Point< spacedim > get_intermediate_point(const Point< spacedim > &p1, const Point< spacedim > &p2, const double w) const override
const PolarManifold< spacedim > polar_manifold
virtual void get_normals_at_vertices(const typename Triangulation< dim, spacedim >::face_iterator &face, typename Manifold< dim, spacedim >::FaceVertexNormals &face_vertex_normals) const override
std::pair< double, Tensor< 1, spacedim > > guess_new_point(const ArrayView< const Tensor< 1, spacedim > > &directions, const ArrayView< const double > &distances, const ArrayView< const double > &weights) const
virtual void get_new_points(const ArrayView< const Point< spacedim > > &surrounding_points, const Table< 2, double > &weights, ArrayView< Point< spacedim > > new_points) const override
SphericalManifold(const Point< spacedim > center=Point< spacedim >())
virtual Tensor< 1, spacedim > get_tangent_vector(const Point< spacedim > &x1, const Point< spacedim > &x2) const override
virtual Tensor< 1, spacedim > normal_vector(const typename Triangulation< dim, spacedim >::face_iterator &face, const Point< spacedim > &p) const override
void do_get_new_points(const ArrayView< const Point< spacedim > > &surrounding_points, const ArrayView< const double > &weights, ArrayView< Point< spacedim > > new_points) const
numbers::NumberTraits< Number >::real_type norm() const
constexpr numbers::NumberTraits< Number >::real_type norm_square() const
virtual Point< 3 > pull_back(const Point< 3 > &p) const override
virtual DerivativeForm< 1, 3, 3 > push_forward_gradient(const Point< 3 > &chart_point) const override
virtual Point< 3 > push_forward(const Point< 3 > &chart_point) const override
TorusManifold(const double centerline_radius, const double inner_radius)
virtual std::unique_ptr< Manifold< dim, 3 > > clone() const override
const Triangulation< dim, spacedim > * triangulation
boost::signals2::connection clear_signal
DerivativeForm< 1, dim, spacedim > push_forward_gradient(const typename Triangulation< dim, spacedim >::cell_iterator &cell, const Point< dim > &chart_point, const Point< spacedim > &pushed_forward_chart_point) const
std::vector< internal::MappingQImplementation::InverseQuadraticApproximation< dim, spacedim > > quadratic_approximation
void initialize(const Triangulation< dim, spacedim > &triangulation)
Triangulation< dim, spacedim >::cell_iterator compute_chart_points(const ArrayView< const Point< spacedim > > &surrounding_points, ArrayView< Point< dim > > chart_points) const
virtual ~TransfiniteInterpolationManifold() override
std::array< unsigned int, 20 > get_possible_cells_around_points(const ArrayView< const Point< spacedim > > &surrounding_points) const
FlatManifold< dim > chart_manifold
Point< dim > pull_back(const typename Triangulation< dim, spacedim >::cell_iterator &cell, const Point< spacedim > &p, const Point< dim > &initial_guess) const
virtual void get_new_points(const ArrayView< const Point< spacedim > > &surrounding_points, const Table< 2, double > &weights, ArrayView< Point< spacedim > > new_points) const override
virtual Point< spacedim > get_new_point(const ArrayView< const Point< spacedim > > &surrounding_points, const ArrayView< const double > &weights) const override
TransfiniteInterpolationManifold()
std::vector< bool > coarse_cell_is_flat
Point< spacedim > push_forward(const typename Triangulation< dim, spacedim >::cell_iterator &cell, const Point< dim > &chart_point) const
virtual std::unique_ptr< Manifold< dim, spacedim > > clone() const override
const Manifold< dim, spacedim > & get_manifold() const
Point< spacedim > & vertex(const unsigned int i) const
ReferenceCell reference_cell() const
#define DEAL_II_NAMESPACE_OPEN
#define DEAL_II_DISABLE_EXTRA_DIAGNOSTICS
constexpr bool running_in_debug_mode()
#define DEAL_II_NAMESPACE_CLOSE
#define DEAL_II_ENABLE_EXTRA_DIAGNOSTICS
#define DEAL_II_ASSERT_UNREACHABLE()
#define DEAL_II_NOT_IMPLEMENTED()
static ::ExceptionBase & ExcTransformationFailed()
static ::ExceptionBase & ExcNotImplemented()
static ::ExceptionBase & ExcEmptyObject()
#define Assert(cond, exc)
static ::ExceptionBase & ExcImpossibleInDim(int arg1)
#define AssertDimension(dim1, dim2)
#define AssertIndexRange(index, range)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcNotInitialized()
static ::ExceptionBase & ExcMessage(std::string arg1)
#define AssertThrow(cond, exc)
TriaIterator< TriaAccessor< dim - 1, dim, spacedim > > face_iterator
TriaIterator< CellAccessor< dim, spacedim > > cell_iterator
const Manifold< dim, spacedim > & get_manifold(const types::manifold_id number) const
SymmetricTensor< 2, dim, Number > d(const Tensor< 2, dim, Number > &F, const Tensor< 2, dim, Number > &dF_dt)
Number signed_angle(const Tensor< 1, spacedim, Number > &a, const Tensor< 1, spacedim, Number > &b, const Tensor< 1, spacedim, Number > &axis)
constexpr T fixed_power(const T t)
Tensor< 1, 3 > projected_direction(const Tensor< 1, 3 > &u, const Tensor< 1, 3 > &v)
Tensor< 1, 3 > apply_exponential_map(const Tensor< 1, 3 > &u, const Tensor< 1, 3 > &dir)
static constexpr double invalid_pull_back_coordinate
Point< spacedim > compute_normal(const Tensor< 1, spacedim > &, bool=false)
constexpr unsigned int invalid_unsigned_int
constexpr types::manifold_id flat_manifold_id
::VectorizedArray< Number, width > max(const ::VectorizedArray< Number, width > &, const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > cos(const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > sin(const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > sqrt(const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > abs(const ::VectorizedArray< Number, width > &)
inline ::VectorizedArray< Number, width > acos(const ::VectorizedArray< Number, width > &x)
static double distance_to_unit_cell(const Point< dim > &p)
static unsigned int face_to_cell_vertices(const unsigned int face, const unsigned int vertex, const bool face_orientation=true, const bool face_flip=false, const bool face_rotation=false)
static constexpr unsigned int vertices_per_cell
static std_cxx20::ranges::iota_view< unsigned int, unsigned int > face_indices()
static constexpr unsigned int vertices_per_face
static unsigned int line_to_cell_vertices(const unsigned int line, const unsigned int vertex)
static std_cxx20::ranges::iota_view< unsigned int, unsigned int > vertex_indices()
static bool is_inside_unit_cell(const Point< dim > &p)
DEAL_II_HOST constexpr Number determinant(const SymmetricTensor< 2, dim, Number > &)
DEAL_II_HOST constexpr SymmetricTensor< 2, dim, Number > invert(const SymmetricTensor< 2, dim, Number > &)
constexpr ProductType< Number, OtherNumber >::type scalar_product(const Tensor< rank, dim, Number > &left, const Tensor< rank, dim, OtherNumber > &right)
constexpr Tensor< 1, dim, typename ProductType< Number1, Number2 >::type > cross_product_3d(const Tensor< 1, dim, Number1 > &src1, const Tensor< 1, dim, Number2 > &src2)