16 #include <deal.II/base/tensor.h> 17 #include <deal.II/base/table.h> 18 #include <deal.II/base/std_cxx14/memory.h> 19 #include <deal.II/grid/tria.h> 20 #include <deal.II/grid/tria_iterator.h> 21 #include <deal.II/grid/tria_accessor.h> 22 #include <deal.II/grid/manifold_lib.h> 23 #include <deal.II/lac/vector.h> 24 #include <deal.II/fe/mapping.h> 27 DEAL_II_NAMESPACE_OPEN
36 static constexpr
double invalid_pull_back_coordinate = 20.0;
45 const double theta = dir.
norm();
53 const Tensor<1,3> tmp = cos(theta)*u + sin(theta)*dirUnit;
54 return tmp/tmp.
norm();
72 template <
int spacedim>
81 compute_normal(
const Tensor<1,3> &vector,
bool normalize=
false)
84 ExcMessage(
"The direction parameter must not be zero!"));
86 if (std::abs(vector[0]) >= std::abs(vector[1])
87 && std::abs(vector[0]) >= std::abs(vector[2]))
91 normal[0]=(vector[1]+vector[2])/vector[0];
93 else if (std::abs(vector[1]) >= std::abs(vector[0])
94 && std::abs(vector[1]) >= std::abs(vector[2]))
98 normal[1]=(vector[0]+vector[2])/vector[1];
104 normal[2]=(vector[0]+vector[1])/vector[2];
107 normal /= normal.
norm();
118 template <
int dim,
int spacedim>
126 template<
int dim,
int spacedim>
127 std::unique_ptr<Manifold<dim, spacedim> >
130 return std_cxx14::make_unique<PolarManifold<dim,spacedim> >(center);
135 template <
int dim,
int spacedim>
151 template <
int dim,
int spacedim>
155 Assert(spherical_point[0] >=0.0,
156 ExcMessage(
"Negative radius for given point."));
157 const double rho = spherical_point[0];
158 const double theta = spherical_point[1];
165 p[0] = rho*
cos(theta);
166 p[1] = rho*
sin(theta);
170 const double phi= spherical_point[2];
171 p[0] = rho*
sin(theta)*
cos(phi);
172 p[1] = rho*
sin(theta)*
sin(phi);
173 p[2] = rho*
cos(theta);
184 template <
int dim,
int spacedim>
189 const double rho = R.
norm();
198 p[1] = atan2(R[1],R[0]);
206 const double z = R[2];
207 p[2] = atan2(R[1],R[0]);
210 p[1] = atan2(
sqrt(R[0]*R[0]+R[1]*R[1]),z);
222 template <
int dim,
int spacedim>
226 Assert(spherical_point[0] >= 0.0,
227 ExcMessage(
"Negative radius for given point."));
228 const double rho = spherical_point[0];
229 const double theta = spherical_point[1];
237 DX[0][0] =
cos(theta);
238 DX[0][1] = -rho*
sin(theta);
239 DX[1][0] =
sin(theta);
240 DX[1][1] = rho*
cos(theta);
246 const double phi= spherical_point[2];
247 DX[0][0] =
sin(theta)*
cos(phi);
248 DX[0][1] = rho*
cos(theta)*
cos(phi);
249 DX[0][2] = -rho*
sin(theta)*
sin(phi);
251 DX[1][0] =
sin(theta)*
sin(phi);
252 DX[1][1] = rho*
cos(theta)*
sin(phi);
253 DX[1][2] = rho*
sin(theta)*
cos(phi);
255 DX[2][0] =
cos(theta);
256 DX[2][1] = -rho*
sin(theta);
273 template <
int dim,
int spacedim>
276 polar_manifold(center)
281 template<
int dim,
int spacedim>
282 std::unique_ptr<Manifold<dim, spacedim> >
285 return std_cxx14::make_unique<SphericalManifold<dim,spacedim> >(center);
290 template <
int dim,
int spacedim>
295 const double w)
const 297 const double tol = 1e-10;
299 if ( (p1-p2).norm_square() < tol*tol || std::abs(w) < tol)
301 else if (std::abs(w-1.0) < tol)
311 const double r1 = v1.
norm();
312 const double r2 = v2.
norm();
314 Assert(r1 > tol && r2 > tol,
315 ExcMessage(
"p1 and p2 cannot coincide with the center."));
321 const double cosgamma = e1*e2;
324 if (cosgamma < -1 + 8.*std::numeric_limits<double>::epsilon())
328 if (cosgamma > 1 - 8.*std::numeric_limits<double>::epsilon())
334 const double sigma = w * std::acos(cosgamma);
339 const double n_norm = n.
norm();
342 "Probably, this means v1==v2 or v2==0."));
356 template <
int dim,
int spacedim>
362 const double tol = 1e-10;
370 const double r1 = v1.
norm();
371 const double r2 = v2.
norm();
374 ExcMessage(
"p1 cannot coincide with the center."));
377 ExcMessage(
"p2 cannot coincide with the center."));
383 const double cosgamma = e1*e2;
385 Assert(cosgamma > -1 + 8.*std::numeric_limits<double>::epsilon(),
386 ExcMessage(
"p1 and p2 cannot lie on the same diameter and be opposite " 387 "respect to the center."));
389 if (cosgamma > 1 - 8.*std::numeric_limits<double>::epsilon())
395 const double n_norm = n.
norm();
398 "Probably, this means v1==v2 or v2==0."));
404 const double gamma = std::acos(cosgamma);
405 return (r2-r1)*e1 + r1*gamma*n;
410 template <
int dim,
int spacedim>
421 std::array<double, n_vertices> distances_to_center;
422 std::array<double, n_vertices-1> distances_to_first_vertex;
423 distances_to_center[0] = (face->vertex(0)-center).norm_square();
424 for (
unsigned int i=1; i<n_vertices; ++i)
426 distances_to_center[i] = (face->vertex(i)-center).norm_square();
427 distances_to_first_vertex[i-1] = (face->vertex(i)-face->vertex(0)).norm_square();
429 const auto minmax_distance = std::minmax_element(distances_to_center.begin(),
430 distances_to_center.end());
431 const auto min_distance_to_first_vertex = std::min_element(distances_to_first_vertex.begin(),
432 distances_to_first_vertex.end());
434 if (*minmax_distance.second-*minmax_distance.first<1.e-10 * *min_distance_to_first_vertex)
438 = unnormalized_spherical_normal/unnormalized_spherical_normal.
norm();
439 return normalized_spherical_normal;
468 template <
int dim,
int spacedim>
479 std::array<double, n_vertices> distances_to_center;
480 std::array<double, n_vertices-1> distances_to_first_vertex;
481 distances_to_center[0] = (face->vertex(0)-center).norm_square();
482 for (
unsigned int i=1; i<n_vertices; ++i)
484 distances_to_center[i] = (face->vertex(i)-center).norm_square();
485 distances_to_first_vertex[i-1] = (face->vertex(i)-face->vertex(0)).norm_square();
487 const auto minmax_distance = std::minmax_element(distances_to_center.begin(),
488 distances_to_center.end());
489 const auto min_distance_to_first_vertex = std::min_element(distances_to_first_vertex.begin(),
490 distances_to_first_vertex.end());
492 if (*minmax_distance.second-*minmax_distance.first<1.e-10 * *min_distance_to_first_vertex)
494 for (
unsigned int vertex=0; vertex<n_vertices; ++vertex)
495 face_vertex_normals[vertex] = face->vertex(vertex)-center;
503 template <
int dim,
int spacedim>
513 get_new_points(surrounding_points,
522 template <
int dim,
int spacedim>
531 get_new_points(vertices,
540 template <
int dim,
int spacedim>
548 const unsigned int weight_rows = new_points.size();
549 const unsigned int weight_columns = surrounding_points.size();
551 if (surrounding_points.size() == 2)
553 for (
unsigned int row=0; row<weight_rows; ++row)
554 new_points[row] = get_intermediate_point(surrounding_points[0], surrounding_points[1], weights[row * weight_columns + 1]);
558 boost::container::small_vector<std::pair<double,Tensor<1, spacedim>>, 100> new_candidates(new_points.size());
559 boost::container::small_vector<Tensor<1, spacedim>, 100> directions(surrounding_points.size(),
Point<spacedim>());
560 boost::container::small_vector<double, 100> distances(surrounding_points.size(),0.0);
561 double max_distance = 0.;
562 for (
unsigned int i = 0; i < surrounding_points.size(); ++i)
564 directions[i] = surrounding_points[i] - center;
565 distances[i] = directions[i].
norm();
567 if (distances[i] != 0.)
568 directions[i] /= distances[i];
571 ExcMessage(
"One of the vertices coincides with the center. " 572 "This is not allowed!"));
576 for (
unsigned int k = 0; k < i; ++k)
578 const double squared_distance = (directions[i] - directions[k]).norm_square();
579 max_distance = std::max(max_distance, squared_distance);
584 const double tolerance = 1e-10;
585 boost::container::small_vector<bool,100> accurate_point_was_found(new_points.size(),
false);
588 for (
unsigned int row=0; row<weight_rows; ++row)
590 new_candidates[row] = guess_new_point(array_directions,
596 if (new_candidates[row].first == 0.0)
598 new_points[row] = center;
599 accurate_point_was_found[row] =
true;
606 new_points[row] = polar_manifold.get_new_point(surrounding_points,
ArrayView<const double>(&weights[row*weight_columns],weight_columns));
618 if (max_distance < 2e-2)
620 for (
unsigned int row=0; row<weight_rows; ++row)
621 new_points[row] = center + new_candidates[row].first * new_candidates[row].second;
631 boost::container::small_vector<double, 1000> merged_weights(weights.
size());
632 boost::container::small_vector<Tensor<1, spacedim>, 100> merged_directions(surrounding_points.size(),
Point<spacedim>());
633 boost::container::small_vector<double, 100> merged_distances(surrounding_points.size(),0.0);
635 unsigned int n_unique_directions = 0;
636 for (
unsigned int i = 0; i < surrounding_points.size(); ++i)
638 bool found_duplicate =
false;
642 for (
unsigned int j = 0; j < n_unique_directions; ++j)
644 const double squared_distance = (directions[i] - directions[j]).norm_square();
645 if (!found_duplicate && squared_distance < 1e-28)
647 found_duplicate =
true;
648 for (
unsigned int row = 0; row < weight_rows; ++row)
649 merged_weights[row*weight_columns + j] += weights[row*weight_columns + i];
653 if (found_duplicate ==
false)
655 merged_directions[n_unique_directions] = directions[i];
656 merged_distances[n_unique_directions] = distances[i];
657 for (
unsigned int row = 0; row < weight_rows; ++row)
658 merged_weights[row*weight_columns + n_unique_directions] = weights[row*weight_columns + i];
660 ++n_unique_directions;
667 for (
unsigned int row = 0; row < weight_rows; ++row)
669 for (
unsigned int existing_row = 0; existing_row < row; ++existing_row)
671 bool identical_weights =
true;
673 for (
unsigned int weight_index = 0; weight_index < n_unique_directions; ++weight_index)
674 if (std::abs(merged_weights[row*weight_columns + weight_index] - merged_weights[existing_row*weight_columns + weight_index]) > tolerance)
676 identical_weights =
false;
680 if (identical_weights)
682 merged_weights_index[row] = existing_row;
690 merged_directions.begin()+n_unique_directions);
692 merged_distances.begin()+n_unique_directions);
694 for (
unsigned int row=0; row<weight_rows; ++row)
695 if (!accurate_point_was_found[row])
700 new_candidates[row].second = get_new_point(array_merged_directions,
701 array_merged_distances,
702 array_merged_weights,
706 new_candidates[row].second = new_candidates[merged_weights_index[row]].second;
708 new_points[row] = center + new_candidates[row].first * new_candidates[row].second;
714 template <
int dim,
int spacedim>
715 std::pair<double, Tensor<1,spacedim> >
721 const double tolerance = 1e-10;
726 double total_weights = 0.;
727 for (
unsigned int i = 0; i < directions.size(); i++)
730 if (std::abs(1-weights[i])<tolerance)
731 return std::make_pair(distances[i],directions[i]);
733 rho += distances[i] * weights[i];
734 candidate += directions[i] * weights[i];
735 total_weights += weights[i];
739 const double norm = candidate.
norm();
743 rho /= total_weights;
745 return std::make_pair(rho,candidate);
751 template <
int spacedim>
774 Point<3> candidate = candidate_point;
775 const unsigned int n_merged_points = directions.size();
776 const double tolerance = 1
e-10;
777 const int max_iterations = 10;
782 for (
unsigned int i=0; i<n_merged_points; ++i)
784 const double squared_distance = (candidate - directions[i]).norm_square();
785 if (squared_distance < tolerance*tolerance)
791 if (n_merged_points == 2)
794 Assert(std::abs(weights[0] + weights[1] - 1.0) < 1e-13,
808 for (
unsigned int i=0; i<max_iterations; ++i)
813 const Tensor<1,3> Clocalx = internal::compute_normal(candidate);
822 for (
unsigned int i=0; i<n_merged_points; ++i)
823 if (std::abs(weights[i])>1.e-15)
825 vPerp = internal::projected_direction(directions[i], candidate);
827 const double sintheta = std::sqrt(sinthetaSq);
828 if (sintheta<tolerance)
830 Hessian[0][0] += weights[i];
831 Hessian[1][1] += weights[i];
835 const double costheta = (directions[i])*candidate;
836 const double theta = atan2(sintheta, costheta);
837 const double sincthetaInv = theta/sintheta;
839 const double cosphi = vPerp*Clocalx;
840 const double sinphi = vPerp*Clocaly;
842 gradlocal[0] = cosphi;
843 gradlocal[1] = sinphi;
844 gradient += (weights[i]*sincthetaInv)*gradlocal;
846 const double wt = weights[i]/sinthetaSq;
847 const double sinphiSq = sinphi*sinphi;
848 const double cosphiSq = cosphi*cosphi;
849 const double tt = sincthetaInv*costheta;
850 const double offdiag = cosphi*sinphi*wt*(1.0-tt);
851 Hessian[0][0] += wt*(cosphiSq+tt*sinphiSq);
852 Hessian[0][1] += offdiag;
853 Hessian[1][0] += offdiag;
854 Hessian[1][1] += wt*(sinphiSq+tt*cosphiSq);
862 const Tensor<1,2> xDisplocal = inverse_Hessian*gradient;
863 const Tensor<1,3> xDisp = xDisplocal[0]*Clocalx + xDisplocal[1]*Clocaly;
866 const Point<3> candidateOld = candidate;
867 candidate =
Point<3>(internal::apply_exponential_map(candidate, xDisp));
870 if ((candidate-candidateOld).norm_square() < tolerance*tolerance)
880 template <
int dim,
int spacedim>
900 const Point<3> &candidate_point)
const 902 return do_get_new_point(directions,distances,weights,candidate_point);
913 const Point<3> &candidate_point)
const 915 return do_get_new_point(directions,distances,weights,candidate_point);
926 const Point<3> &candidate_point)
const 928 return do_get_new_point(directions,distances,weights,candidate_point);
936 template <
int dim,
int spacedim>
938 const double tolerance)
947 ExcMessage(
"CylindricalManifold can only be used for spacedim==3!"));
952 template <
int dim,
int spacedim>
955 const double tolerance) :
957 normal_direction(internal::compute_normal(direction,
true)),
958 direction (direction/direction.norm()),
959 point_on_axis (point_on_axis),
960 tolerance (tolerance)
965 ExcMessage(
"CylindricalManifold can only be used for spacedim==3!"));
970 template<
int dim,
int spacedim>
971 std::unique_ptr<Manifold<dim, spacedim> >
974 return std_cxx14::make_unique<CylindricalManifold<dim,spacedim> >(direction, point_on_axis, tolerance);
979 template <
int dim,
int spacedim>
986 ExcMessage(
"CylindricalManifold can only be used for spacedim==3!"));
990 double average_length = 0.;
991 for (
unsigned int i=0; i<surrounding_points.size(); ++i)
993 middle += surrounding_points[i]*weights[i];
994 average_length += surrounding_points[i].square()*weights[i];
996 middle -= point_on_axis;
997 const double lambda = middle*direction;
999 if ((middle-direction*lambda).square() < tolerance*average_length)
1008 template <
int dim,
int spacedim>
1013 ExcMessage(
"CylindricalManifold can only be used for spacedim==3!"));
1017 const double lambda = normalized_point*direction;
1023 const double dot = normal_direction*p_diff;
1025 const double phi = std::atan2(det, dot);
1028 return Point<3> (p_diff.norm(), phi, lambda);
1033 template <
int dim,
int spacedim>
1038 ExcMessage(
"CylindricalManifold can only be used for spacedim==3!"));
1045 const double sine_r = std::sin(chart_point(1))*chart_point(0);
1046 const double cosine_r = std::cos(chart_point(1))*chart_point(0);
1051 return point_on_axis+direction*chart_point(2)+intermediate;
1056 template <
int dim,
int spacedim>
1061 ExcMessage(
"CylindricalManifold can only be used for spacedim==3!"));
1070 const double sine = std::sin(chart_point(1));
1071 const double cosine = std::cos(chart_point(1));
1076 derivatives[0][0] = intermediate[0];
1077 derivatives[1][0] = intermediate[1];
1078 derivatives[2][0] = intermediate[2];
1081 derivatives[0][1] = -normal_direction[0]*sine + dxn[0]*cosine;
1082 derivatives[1][1] = -normal_direction[1]*sine + dxn[1]*cosine;
1083 derivatives[2][1] = -normal_direction[2]*sine + dxn[2]*cosine;
1086 derivatives[0][2] = direction[0];
1087 derivatives[1][2] = direction[1];
1088 derivatives[2][2] = direction[2];
1098 template <
int dim,
int spacedim,
int chartdim>
1103 const double tolerance):
1105 push_forward_function(&push_forward_function),
1106 pull_back_function(&pull_back_function),
1107 tolerance(tolerance),
1108 owns_pointers(
false),
1109 finite_difference_step(0)
1117 template <
int dim,
int spacedim,
int chartdim>
1119 (
const std::string push_forward_expression,
1120 const std::string pull_back_expression,
1123 const std::string chart_vars,
1124 const std::string space_vars,
1125 const double tolerance,
1128 const_map(const_map),
1129 tolerance(tolerance),
1130 owns_pointers(
true),
1131 push_forward_expression(push_forward_expression),
1132 pull_back_expression(pull_back_expression),
1133 chart_vars(chart_vars),
1134 space_vars(space_vars),
1135 finite_difference_step(h)
1139 pf->
initialize(chart_vars, push_forward_expression, const_map);
1140 pb->
initialize(space_vars, pull_back_expression, const_map);
1141 push_forward_function = pf;
1142 pull_back_function = pb;
1147 template <
int dim,
int spacedim,
int chartdim>
1150 if (owns_pointers ==
true)
1153 push_forward_function =
nullptr;
1157 pull_back_function =
nullptr;
1164 template<
int dim,
int spacedim,
int chartdim>
1165 std::unique_ptr<Manifold<dim, spacedim> >
1178 if (owns_pointers ==
true)
1180 return std_cxx14::make_unique<FunctionManifold<dim,spacedim,chartdim> >(push_forward_expression,
1181 pull_back_expression,
1182 this->get_periodicity(),
1187 finite_difference_step);
1190 return std_cxx14::make_unique<FunctionManifold<dim,spacedim,chartdim> >(*push_forward_function,
1191 *pull_back_function,
1192 this->get_periodicity(),
1198 template <
int dim,
int spacedim,
int chartdim>
1205 for (
unsigned int i=0; i<spacedim; ++i)
1211 for (
unsigned int i=0; i<chartdim; ++i)
1213 (std::abs(pb[i]-chart_point[i]) < tolerance*chart_point.
norm())) ||
1214 (std::abs(pb[i]-chart_point[i]) < tolerance),
1215 ExcMessage(
"The push forward is not the inverse of the pull back! Bailing out."));
1223 template <
int dim,
int spacedim,
int chartdim>
1228 for (
unsigned int i=0; i<spacedim; ++i)
1230 const auto gradient = push_forward_function->
gradient(chart_point, i);
1231 for (
unsigned int j=0; j<chartdim; ++j)
1232 DF[i][j] = gradient[j];
1239 template <
int dim,
int spacedim,
int chartdim>
1246 for (
unsigned int i=0; i<chartdim; ++i)
1263 double phi = atan2(y, x);
1264 double theta = atan2(z, std::sqrt(x*x+y*y)-R);
1265 double w = std::sqrt(
pow(y-
sin(phi)*R, 2.0)+
pow(x-
cos(phi)*R, 2.0)+z*z)/r;
1275 double phi = chart_point(0);
1276 double theta = chart_point(1);
1277 double w = chart_point(2);
1301 std::unique_ptr<Manifold<dim, 3> >
1304 return std_cxx14::make_unique<TorusManifold<dim> >(R,r);
1315 double phi = chart_point(0);
1316 double theta = chart_point(1);
1317 double w = chart_point(2);
1319 DX[0][0] = -
sin(phi)*R - r*w*
cos(theta)*
sin(phi);
1320 DX[0][1] = -r*w*
sin(theta)*
cos(phi);
1321 DX[0][2] = r*
cos(theta)*
cos(phi);
1324 DX[1][1] = r*w*
cos(theta);
1325 DX[1][2] = r*
sin(theta);
1327 DX[2][0] =
cos(phi)*R + r*w*
cos(theta)*
cos(phi);
1328 DX[2][1] = -r*w*
sin(theta)*
sin(phi);
1329 DX[2][2] = r*
cos(theta)*
sin(phi);
1339 template <
int dim,
int spacedim>
1342 triangulation(nullptr),
1350 template <
int dim,
int spacedim>
1353 if (clear_signal.connected())
1354 clear_signal.disconnect();
1359 template<
int dim,
int spacedim>
1360 std::unique_ptr<Manifold<dim, spacedim> >
1366 return std::unique_ptr<Manifold<dim,spacedim> >(ptr);
1371 template <
int dim,
int spacedim>
1376 this->triangulation = &triangulation;
1378 clear_signal = triangulation.signals.clear.connect
1379 ([&]() ->
void {this->triangulation =
nullptr; this->level_coarse = -1;});
1380 level_coarse = triangulation.last()->level();
1381 coarse_cell_is_flat.resize(triangulation.n_cells(level_coarse),
false);
1383 cell = triangulation.begin(level_coarse),
1384 endc = triangulation.end(level_coarse);
1385 for ( ; cell != endc; ++cell)
1387 bool cell_is_flat =
true;
1388 for (
unsigned int l=0; l<GeometryInfo<dim>::lines_per_cell; ++l)
1389 if (cell->line(l)->manifold_id() != cell->manifold_id() &&
1391 cell_is_flat =
false;
1393 for (
unsigned int q=0; q<GeometryInfo<dim>::quads_per_cell; ++q)
1394 if (cell->quad(q)->manifold_id() != cell->manifold_id() &&
1396 cell_is_flat =
false;
1398 coarse_cell_is_flat.size());
1399 coarse_cell_is_flat[cell->index()] = cell_is_flat;
1408 template <
typename AccessorType>
1410 compute_transfinite_interpolation(
const AccessorType &cell,
1414 return cell.vertex(0) * (1.-chart_point[0]) + cell.vertex(1) * chart_point[0];
1418 template <
typename AccessorType>
1420 compute_transfinite_interpolation(
const AccessorType &cell,
1422 const bool cell_is_flat)
1424 const unsigned int dim = AccessorType::dimension;
1425 const unsigned int spacedim = AccessorType::space_dimension;
1433 const std::array<Point<spacedim>, 4> vertices
1434 {{cell.vertex(0), cell.vertex(1), cell.vertex(2), cell.vertex(3)}};
1439 std::array<double,4> weights_vertices
1442 (1.-chart_point[0]) *(1.-chart_point[1]),
1443 chart_point[0] *(1.-chart_point[1]),
1444 (1.-chart_point[0]) *chart_point[1],
1445 chart_point[0] *chart_point[1]
1451 for (
unsigned int v=0; v<GeometryInfo<2>::vertices_per_cell; ++v)
1452 new_point += weights_vertices[v] * vertices[v];
1464 std::array<double, GeometryInfo<2>::vertices_per_face> weights;
1467 const auto weights_view =
make_array_view(weights.begin(), weights.end());
1468 const auto points_view =
make_array_view(points.begin(), points.end());
1470 for (
unsigned int line=0; line<GeometryInfo<2>::lines_per_cell; ++line)
1472 const double my_weight = (line%2) ? chart_point[line/2] : 1-chart_point[line/2];
1473 const double line_point = chart_point[1-line/2];
1480 if (line_manifold_id == my_manifold_id ||
1484 -= my_weight * (1.-line_point);
1486 -= my_weight * line_point;
1492 weights[0] = 1. - line_point;
1493 weights[1] = line_point;
1494 new_point += my_weight *
1495 tria.
get_manifold(line_manifold_id).get_new_point(points_view,
1501 for (
unsigned int v=0; v<GeometryInfo<2>::vertices_per_cell; ++v)
1502 new_point -= weights_vertices[v] * vertices[v];
1511 static constexpr
unsigned int 1512 face_to_cell_vertices_3d[6][4] =
1525 static constexpr
unsigned int 1526 face_to_cell_lines_3d[6][4] =
1537 template <
typename AccessorType>
1539 compute_transfinite_interpolation(
const AccessorType &cell,
1541 const bool cell_is_flat)
1543 const unsigned int dim = AccessorType::dimension;
1544 const unsigned int spacedim = AccessorType::space_dimension;
1550 const std::array<Point<spacedim>, 8> vertices
1553 cell.vertex(0), cell.vertex(1), cell.vertex(2), cell.vertex(3),
1554 cell.vertex(4), cell.vertex(5), cell.vertex(6), cell.vertex(7)
1561 double linear_shapes[10];
1562 for (
unsigned int d=0;
d<3; ++
d)
1564 linear_shapes[2*
d] = 1.-chart_point[
d];
1565 linear_shapes[2*
d+1] = chart_point[
d];
1569 for (
unsigned int d=6;
d<10; ++
d)
1570 linear_shapes[d] = linear_shapes[d-6];
1572 std::array<double,8> weights_vertices;
1573 for (
unsigned int i2=0, v=0; i2<2; ++i2)
1574 for (
unsigned int i1=0; i1<2; ++i1)
1575 for (
unsigned int i0=0; i0<2; ++i0, ++v)
1576 weights_vertices[v] = (linear_shapes[4+i2] * linear_shapes[2+i1]) *
1581 for (
unsigned int v=0; v<8; ++v)
1582 new_point += weights_vertices[v] * vertices[v];
1589 for (
unsigned int line=0; line<GeometryInfo<3>::lines_per_cell; ++line)
1590 weights_lines[line] = 0;
1593 std::array<double, GeometryInfo<2>::vertices_per_cell> weights;
1596 const auto weights_view =
make_array_view(weights.begin(), weights.end());
1597 const auto points_view =
make_array_view(points.begin(), points.end());
1599 for (
unsigned int face=0; face<GeometryInfo<3>::faces_per_cell; ++face)
1601 const double my_weight = linear_shapes[face];
1602 const unsigned int face_even = face - face%2;
1604 if (std::abs(my_weight) < 1
e-13)
1610 if (face_manifold_id == my_manifold_id ||
1613 for (
unsigned int line=0; line<GeometryInfo<2>::lines_per_cell; ++line)
1615 const double line_weight = linear_shapes[face_even+2+line];
1616 weights_lines[face_to_cell_lines_3d[face][line]] +=
1617 my_weight * line_weight;
1623 weights_vertices[face_to_cell_vertices_3d[face][0]] -=
1624 linear_shapes[face_even+2]*(linear_shapes[face_even+4]*my_weight);
1625 weights_vertices[face_to_cell_vertices_3d[face][1]] -=
1626 linear_shapes[face_even+3]*(linear_shapes[face_even+4]*my_weight);
1627 weights_vertices[face_to_cell_vertices_3d[face][2]] -=
1628 linear_shapes[face_even+2]*(linear_shapes[face_even+5]*my_weight);
1629 weights_vertices[face_to_cell_vertices_3d[face][3]] -=
1630 linear_shapes[face_even+3]*(linear_shapes[face_even+5]*my_weight);
1634 for (
unsigned int v=0; v<GeometryInfo<2>::vertices_per_cell; ++v)
1635 points[v] = vertices[face_to_cell_vertices_3d[face][v]];
1636 weights[0] = linear_shapes[face_even+2]*linear_shapes[face_even+4];
1637 weights[1] = linear_shapes[face_even+3]*linear_shapes[face_even+4];
1638 weights[2] = linear_shapes[face_even+2]*linear_shapes[face_even+5];
1639 weights[3] = linear_shapes[face_even+3]*linear_shapes[face_even+5];
1640 new_point += my_weight *
1641 tria.
get_manifold(face_manifold_id).get_new_point(points_view,
1647 const auto weights_view_line =
make_array_view(weights.begin(), weights.begin()+2);
1648 const auto points_view_line =
make_array_view(points.begin(), points.begin()+2);
1649 for (
unsigned int line=0; line<GeometryInfo<3>::lines_per_cell; ++line)
1651 const double line_point = (line < 8 ? chart_point[1-(line%4)/2] : chart_point[2]);
1652 double my_weight = 0.;
1654 my_weight = linear_shapes[line%4] * linear_shapes[4+line/4];
1657 const unsigned int subline = line-8;
1658 my_weight = linear_shapes[subline%2] * linear_shapes[2+subline/2];
1660 my_weight -= weights_lines[line];
1662 if (std::abs(my_weight) < 1
e-13)
1666 if (line_manifold_id == my_manifold_id ||
1670 -= my_weight * (1.-line_point);
1672 -= my_weight * (line_point);
1678 weights[0] = 1. - line_point;
1679 weights[1] = line_point;
1680 new_point -= my_weight *
1681 tria.
get_manifold(line_manifold_id).get_new_point(points_view_line,
1687 for (
unsigned int v=0; v<GeometryInfo<dim>::vertices_per_cell; ++v)
1688 new_point += weights_vertices[v] * vertices[v];
1696 template <
int dim,
int spacedim>
1708 ExcMessage(
"chart_point is not in unit interval"));
1710 return compute_transfinite_interpolation(*cell, chart_point,
1711 coarse_cell_is_flat[cell->index()]);
1716 template <
int dim,
int spacedim>
1725 for (
unsigned int d=0; d<dim; ++d)
1728 const double step = chart_point[d] > 0.5 ? -1e-8 : 1e-8;
1731 modified[d] += step;
1733 compute_transfinite_interpolation(*cell, modified,
1734 coarse_cell_is_flat[cell->index()]) -
1735 pushed_forward_chart_point;
1736 for (
unsigned int e=0; e<spacedim; ++e)
1737 grad[e][d] = difference[e] / step;
1744 template <
int dim,
int spacedim>
1752 for (
unsigned int d=0; d<dim; ++d)
1753 outside[d] = internal::invalid_pull_back_coordinate;
1763 Tensor<1,spacedim> residual = point - compute_transfinite_interpolation(*cell, chart_point,
1764 coarse_cell_is_flat[cell->index()]);
1765 const double tolerance = 1e-21 * Utilities::fixed_power<2>(cell->diameter());
1766 double residual_norm_square = residual.
norm_square();
1768 for (
unsigned int i=0; i<100; ++i)
1770 if (residual_norm_square < tolerance)
1777 for (
unsigned int d=0; d<spacedim; ++d)
1778 for (
unsigned int e=0; e<dim; ++e)
1779 update[e] += inv_grad[d][e] * residual[d];
1780 return chart_point + update;
1800 = push_forward_gradient(cell, chart_point,
1807 for (
unsigned int d=0; d<spacedim; ++d)
1808 for (
unsigned int e=0; e<dim; ++e)
1809 update[e] += inv_grad[d][e] * residual[d];
1822 while (alpha > 1e-7)
1824 Point<dim> guess = chart_point + alpha*update;
1825 residual = point - compute_transfinite_interpolation(*cell, guess,
1826 coarse_cell_is_flat[cell->index()]);
1827 const double residual_norm_new = residual.
norm_square();
1828 if (residual_norm_new < residual_norm_square)
1830 residual_norm_square = residual_norm_new;
1831 chart_point += alpha*update;
1851 for (
unsigned int d=0; d<spacedim; ++d)
1852 for (
unsigned int e=0; e<dim; ++e)
1853 Jinv_deltaf[e] += inv_grad[d][e] * delta_f[d];
1854 const Tensor<1,dim> factor = (delta_x - Jinv_deltaf)/(delta_x * Jinv_deltaf);
1856 for (
unsigned int d=0; d<spacedim; ++d)
1857 for (
unsigned int e=0; e<dim; ++e)
1858 jac_update[d] += delta_x[e] * inv_grad[d][e];
1859 for (
unsigned int d=0; d<spacedim; ++d)
1860 for (
unsigned int e=0; e<dim; ++e)
1861 inv_grad[d][e] += factor[e] * jac_update[d];
1868 template <
int dim,
int spacedim>
1869 std::array<unsigned int, 20>
1877 Assert(triangulation->begin_active()->level() >= level_coarse,
1878 ExcMessage(
"The manifold was initialized with level " +
1880 "active cells on a lower level. Coarsening the mesh is " +
1881 "currently not supported"));
1886 cell = triangulation->begin(level_coarse),
1887 endc = triangulation->end(level_coarse);
1888 boost::container::small_vector<std::pair<double, unsigned int>, 200> distances_and_cells;
1889 for ( ; cell != endc; ++cell)
1892 if (&cell->get_manifold() !=
this)
1896 for (
unsigned int vertex_n = 0; vertex_n < GeometryInfo<dim>::vertices_per_cell; ++vertex_n)
1898 vertices[vertex_n] = cell->vertex(vertex_n);
1905 for (
unsigned int v=0; v<GeometryInfo<dim>::vertices_per_cell; ++v)
1906 center += vertices[v];
1908 double radius_square = 0.;
1909 for (
unsigned int v=0; v<GeometryInfo<dim>::vertices_per_cell; ++v)
1910 radius_square = std::max(radius_square, (center-vertices[v]).norm_square());
1911 bool inside_circle =
true;
1912 for (
unsigned int i=0; i<points.size(); ++i)
1913 if ((center-points[i]).norm_square() > radius_square * 1.5)
1915 inside_circle =
false;
1918 if (inside_circle ==
false)
1922 double current_distance = 0;
1923 for (
unsigned int i=0; i<points.size(); ++i)
1925 Point<dim> point = cell->real_to_unit_cell_affine_approximation(points[i]);
1928 distances_and_cells.emplace_back(current_distance, cell->index());
1933 std::sort(distances_and_cells.begin(), distances_and_cells.end());
1934 std::array<unsigned int,20> cells;
1936 for (
unsigned int i=0; i<distances_and_cells.size() && i<cells.size(); ++i)
1937 cells[i] = distances_and_cells[i].second;
1944 template <
int dim,
int spacedim>
1950 Assert(surrounding_points.size() == chart_points.size(),
1951 ExcMessage(
"The chart points array view must be as large as the " 1952 "surrounding points array view."));
1954 std::array<unsigned int,20> nearby_cells =
1955 get_possible_cells_around_points(surrounding_points);
1979 auto guess_chart_point_structdim_2 = [&](
const unsigned int i) ->
Point<dim> 1981 Assert(surrounding_points.size() == 8 && 2 < i && i < 8,
1982 ExcMessage(
"This function assumes that there are eight surrounding " 1983 "points around a two-dimensional object. It also assumes " 1984 "that the first three chart points have already been " 1994 return chart_points[1] + (chart_points[2] - chart_points[0]);
1996 return 0.5*(chart_points[0] + chart_points[2]);
1998 return 0.5*(chart_points[1] + chart_points[3]);
2000 return 0.5*(chart_points[0] + chart_points[1]);
2002 return 0.5*(chart_points[2] + chart_points[3]);
2031 auto guess_chart_point_structdim_3 = [&](
const unsigned int i) ->
Point<dim> 2033 Assert(surrounding_points.size() == 8 && 4 < i && i < 8,
2034 ExcMessage(
"This function assumes that there are eight surrounding " 2035 "points around a three-dimensional object. It also " 2036 "assumes that the first five chart points have already " 2038 return chart_points[i - 4] + (chart_points[4] - chart_points[0]);
2042 bool use_structdim_2_guesses =
false;
2043 bool use_structdim_3_guesses =
false;
2048 if (surrounding_points.size() == 8)
2059 use_structdim_2_guesses =
true;
2060 else if (spacedim == 3)
2063 use_structdim_3_guesses =
true;
2066 Assert((!use_structdim_2_guesses && !use_structdim_3_guesses)
2067 || (use_structdim_2_guesses ^ use_structdim_3_guesses),
2071 for (
unsigned int c=0; c<nearby_cells.size(); ++c)
2076 bool inside_unit_cell =
true;
2077 for (
unsigned int i=0; i<surrounding_points.size(); ++i)
2084 bool used_affine_approximation =
false;
2087 if (i == 3 && surrounding_points.size() == 8)
2088 guess = chart_points[1] + (chart_points[2] - chart_points[0]);
2089 else if (use_structdim_2_guesses && 3 < i)
2090 guess = guess_chart_point_structdim_2(i);
2091 else if (use_structdim_3_guesses && 4 < i)
2092 guess = guess_chart_point_structdim_3(i);
2095 guess = cell->real_to_unit_cell_affine_approximation(surrounding_points[i]);
2096 used_affine_approximation =
true;
2098 chart_points[i] = pull_back(cell, surrounding_points[i], guess);
2103 if (chart_points[i][0] == internal::invalid_pull_back_coordinate &&
2104 !used_affine_approximation)
2106 guess = cell->real_to_unit_cell_affine_approximation(surrounding_points[i]);
2107 chart_points[i] = pull_back(cell, surrounding_points[i], guess);
2115 inside_unit_cell =
false;
2119 if (inside_unit_cell ==
true)
2126 if (c == nearby_cells.size()-1 ||
2131 std::ostringstream message;
2132 for (
unsigned int b=0; b<=c; ++b)
2137 message <<
"Looking at cell " 2138 << cell->id() <<
" with vertices: " << std::endl;
2139 for (
unsigned int v=0; v<GeometryInfo<dim>::vertices_per_cell; ++v)
2140 message << cell->vertex(v) <<
" ";
2141 message << std::endl;
2142 message <<
"Transformation to chart coordinates: " << std::endl;
2143 for (
unsigned int i=0; i<surrounding_points.size(); ++i)
2145 message << surrounding_points[i] <<
" -> " 2146 << pull_back(cell, surrounding_points[i],
2147 cell->real_to_unit_cell_affine_approximation(surrounding_points[i]))
2166 template <
int dim,
int spacedim>
2172 boost::container::small_vector<Point<dim>, 100> chart_points(surrounding_points.size());
2174 chart_points.end());
2175 const auto cell = compute_chart_points(surrounding_points, chart_points_view);
2177 const Point<dim> p_chart = chart_manifold.get_new_point (chart_points_view, weights);
2179 return push_forward(cell, p_chart);
2184 template <
int dim,
int spacedim>
2194 boost::container::small_vector<Point<dim>, 100> chart_points(surrounding_points.size());
2196 chart_points.end());
2197 const auto cell = compute_chart_points(surrounding_points, chart_points_view);
2199 boost::container::small_vector<Point<dim>, 100> new_points_on_chart(weights.
size(0));
2200 chart_manifold.get_new_points(chart_points_view,
2203 new_points_on_chart.end()));
2205 for (
unsigned int row=0; row<weights.
size(0); ++row)
2206 new_points[row] = push_forward(cell, new_points_on_chart[row]);
2212 #include "manifold_lib.inst" 2214 DEAL_II_NAMESPACE_CLOSE
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
static ::ExceptionBase & ExcTransformationFailed()
static const unsigned int invalid_unsigned_int
Triangulation< dim, spacedim >::cell_iterator compute_chart_points(const ArrayView< const Point< spacedim >> &surrounding_points, ArrayView< Point< dim >> chart_points) const
virtual Point< spacedim > push_forward(const Point< 3 > &chart_point) const override
#define AssertDimension(dim1, dim2)
const unsigned int n_components
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)
static Tensor< 1, spacedim > get_periodicity()
SymmetricTensor< 2, dim, Number > invert(const SymmetricTensor< 2, dim, Number > &t)
virtual Tensor< 1, dim, RangeNumberType > gradient(const Point< dim > &p, const unsigned int component=0) const
std::array< unsigned int, 20 > get_possible_cells_around_points(const ArrayView< const Point< spacedim >> &surrounding_points) const
SymmetricTensor< 2, dim, Number > e(const Tensor< 2, dim, Number > &F)
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, 3 > > clone() const override
static unsigned int line_to_cell_vertices(const unsigned int line, const unsigned int vertex)
virtual void get_new_points(const ArrayView< const Point< spacedim >> &surrounding_points, const Table< 2, double > &weights, ArrayView< Point< spacedim >> new_points) const override
#define AssertIndexRange(index, range)
virtual DerivativeForm< 1, 3, 3 > push_forward_gradient(const Point< 3 > &chart_point) const override
static ::ExceptionBase & ExcNotInitialized()
virtual Point< spacedim > get_new_point(const ArrayView< const Point< spacedim >> &vertices, const ArrayView< const double > &weights) const override
virtual Point< 3 > pull_back(const Point< 3 > &p) const override
#define AssertThrow(cond, exc)
numbers::NumberTraits< Number >::real_type norm() const
TorusManifold(const double R, const double r)
std::string to_string(const number value, const unsigned int digits=numbers::invalid_unsigned_int)
void initialize(const Triangulation< dim, spacedim > &triangulation)
virtual std::unique_ptr< Manifold< dim, spacedim > > clone() const override
static double distance_to_unit_cell(const Point< dim > &p)
ArrayView< typename std::remove_reference< typename std::iterator_traits< Iterator >::reference >::type > make_array_view(const Iterator begin, const Iterator end)
virtual Point< 3 > push_forward(const Point< 3 > &chart_point) const override
static ::ExceptionBase & ExcMessage(std::string arg1)
static ::ExceptionBase & ExcImpossibleInDim(int arg1)
virtual DerivativeForm< 1, 3, spacedim > push_forward_gradient(const Point< 3 > &chart_point) const override
CylindricalManifold(const unsigned int axis=0, const double tolerance=1e-10)
virtual std::unique_ptr< Manifold< dim, spacedim > > clone() const override
TriaIterator< CellAccessor< dim, spacedim > > cell_iterator
PolarManifold(const Point< spacedim > center=Point< spacedim >())
#define Assert(cond, exc)
virtual ~FunctionManifold() override
virtual Point< chartdim > pull_back(const Point< spacedim > &space_point) const override
Abstract base class for mapping classes.
virtual Point< 3 > pull_back(const Point< spacedim > &space_point) const override
virtual Tensor< 1, spacedim > get_tangent_vector(const Point< spacedim > &x1, const Point< spacedim > &x2) const override
Point< spacedim > push_forward(const typename Triangulation< dim, spacedim >::cell_iterator &cell, const Point< dim > &chart_point) const
virtual Point< spacedim > push_forward(const Point< spacedim > &chart_point) const override
virtual Point< spacedim > get_new_point(const ArrayView< const Point< spacedim >> &surrounding_points, const ArrayView< const double > &weights) const override
numbers::NumberTraits< Number >::real_type norm_square() const
VectorizedArray< Number > pow(const ::VectorizedArray< Number > &x, const Number p)
virtual std::unique_ptr< Manifold< dim, spacedim > > clone() const override
virtual void vector_value(const Point< dim > &p, Vector< RangeNumberType > &values) const
virtual void get_normals_at_vertices(const typename Triangulation< dim, spacedim >::face_iterator &face, typename Manifold< dim, spacedim >::FaceVertexNormals &face_vertex_normals) const override
SymmetricTensor< 2, dim, Number > d(const Tensor< 2, dim, Number > &F, const Tensor< 2, dim, Number > &dF_dt)
Tensor< 1, dim, Number > cross_product_3d(const Tensor< 1, dim, Number > &src1, const Tensor< 1, dim, Number > &src2)
ProductType< Number, OtherNumber >::type scalar_product(const SymmetricTensor< 2, dim, Number > &t1, const SymmetricTensor< 2, dim, OtherNumber > &t2)
virtual void get_new_points(const ArrayView< const Point< spacedim >> &surrounding_points, const Table< 2, double > &weights, ArrayView< Point< spacedim >> new_points) const override
static Point< dim > project_to_unit_cell(const Point< dim > &p)
Number determinant(const SymmetricTensor< 2, dim, Number > &t)
TransfiniteInterpolationManifold()
VectorizedArray< Number > sqrt(const ::VectorizedArray< Number > &x)
const types::manifold_id invalid_manifold_id
virtual ~TransfiniteInterpolationManifold() override
VectorizedArray< Number > sin(const ::VectorizedArray< Number > &x)
virtual Point< spacedim > push_forward(const Point< chartdim > &chart_point) const override
virtual Point< spacedim > pull_back(const Point< spacedim > &space_point) const override
size_type size(const unsigned int i) const
void initialize(const std::string &vars, const std::vector< std::string > &expressions, const ConstMap &constants, const bool time_dependent=false)
virtual DerivativeForm< 1, chartdim, spacedim > push_forward_gradient(const Point< chartdim > &chart_point) const override
Point< dim > pull_back(const typename Triangulation< dim, spacedim >::cell_iterator &cell, const Point< spacedim > &p, const Point< dim > &initial_guess) const
virtual Point< spacedim > get_new_point(const ArrayView< const Point< spacedim >> &surrounding_points, const ArrayView< const double > &weights) const override
static ::ExceptionBase & ExcEmptyObject()
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
static ::ExceptionBase & ExcNotImplemented()
virtual Tensor< 1, spacedim > normal_vector(const typename Triangulation< dim, spacedim >::face_iterator &face, const Point< spacedim > &p) const
virtual std::unique_ptr< Manifold< dim, spacedim > > clone() const override
SphericalManifold(const Point< spacedim > center=Point< spacedim >())
virtual Point< spacedim > get_intermediate_point(const Point< spacedim > &p1, const Point< spacedim > &p2, const double w) const override
virtual void get_normals_at_vertices(const typename Triangulation< dim, spacedim >::face_iterator &face, FaceVertexNormals &face_vertex_normals) const
const Manifold< dim, spacedim > & get_manifold(const types::manifold_id number) const
VectorizedArray< Number > cos(const ::VectorizedArray< Number > &x)
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
virtual Tensor< 1, spacedim > normal_vector(const typename Triangulation< dim, spacedim >::face_iterator &face, const Point< spacedim > &p) const override
static ::ExceptionBase & ExcInternalError()
Triangulation< dim, spacedim > & get_triangulation()