38class OneSidedCylindricalManifold :
public dealii::ChartManifold<dim, dim, dim>
41 OneSidedCylindricalManifold(dealii::Triangulation<dim>
const & tria_in,
42 typename dealii::Triangulation<dim>::cell_iterator
const & cell_in,
43 unsigned int const face_in,
44 dealii::Point<dim>
const & center_in)
45 : alpha(1.0), radius(1.0), tria(tria_in), cell(cell_in), face(face_in), center(center_in)
47 AssertThrow(tria.all_reference_cells_are_hyper_cube(),
48 dealii::ExcMessage(
"This class is only implemented for hypercube elements."));
50 AssertThrow(face <= 3,
52 "One sided spherical manifold can only be applied to face f=0,1,2,3."));
60 dealii::Point<dim> x_1, x_2;
61 x_1 = cell->vertex(get_vertex_id(0));
62 x_2 = cell->vertex(get_vertex_id(1));
64 dealii::Point<2> x_1_2d = dealii::Point<2>(x_1[0], x_1[1]);
65 dealii::Point<2> x_2_2d = dealii::Point<2>(x_2[0], x_2[1]);
67 initialize(x_1_2d, x_2_2d);
71 initialize(dealii::Point<2>
const & x_1, dealii::Point<2>
const & x_2)
73 double const tol = 1.e-12;
82 double radius_check = v_2.norm();
83 AssertThrow(std::abs(radius - radius_check) < tol * radius,
85 "Invalid geometry parameters. To apply a spherical manifold both "
86 "end points of the face must have the same distance from the center."));
93 alpha = std::acos(v_1 * v_2);
96 normal = v_2 - (v_2 * v_1) * v_1;
98 AssertThrow(normal.norm() > tol, dealii::ExcMessage(
"Vector must not have length 0."));
100 normal /= normal.norm();
108 push_forward(dealii::Point<dim>
const & xi)
const override
110 dealii::Point<dim> x;
113 for(
unsigned int const v : cell->vertex_indices())
115 double shape_function_value = cell->reference_cell().d_linear_shape_function(xi, v);
116 x += shape_function_value * cell->vertex(v);
123 unsigned int index_face = get_index_face();
124 unsigned int index_other = get_index_other();
125 double const xi_face = xi[index_face];
126 double const xi_other = xi[index_other];
129 double beta = xi_face * alpha;
131 dealii::Tensor<1, 2> direction;
132 direction = std::cos(beta) * v_1 + std::sin(beta) * normal;
134 Assert(std::abs(direction.norm() - 1.0) < 1.e-12,
135 dealii::ExcMessage(
"Vector must have length 1."));
138 dealii::Tensor<1, 2> x_S;
139 x_S = x_C + radius * direction;
143 dealii::Tensor<1, 2> displ, x_lin;
144 for(
unsigned int v : dealii::ReferenceCells::template get_hypercube<1>().vertex_indices())
146 double shape_function_value =
147 dealii::ReferenceCells::template get_hypercube<1>().d_linear_shape_function(
148 dealii::Point<1>(xi_face), v);
150 unsigned int vertex_id = get_vertex_id(v);
151 dealii::Point<dim> vertex = cell->vertex(vertex_id);
153 x_lin[0] += shape_function_value * vertex[0];
154 x_lin[1] += shape_function_value * vertex[1];
160 dealii::Point<1> xi_other_1d = dealii::Point<1>(xi_other);
161 unsigned int index_1d = get_index_1d();
162 double fading_value =
163 dealii::ReferenceCells::template get_hypercube<1>().d_linear_shape_function(xi_other_1d,
165 x[0] += fading_value * displ[0];
166 x[1] += fading_value * displ[1];
168 Assert(dealii::numbers::is_finite(x.norm_square()), dealii::ExcMessage(
"Invalid point found"));
178 get_vertex_id(
unsigned int vertex_id_1d)
const
180 unsigned int vertex_id = 0;
183 vertex_id = 2 * vertex_id_1d;
185 vertex_id = 1 + 2 * vertex_id_1d;
187 vertex_id = vertex_id_1d;
189 vertex_id = 2 + vertex_id_1d;
201 unsigned int index_1d = 0;
203 if(face == 0 or face == 2)
205 else if(face == 1 or face == 3)
208 Assert(
false, dealii::ExcMessage(
"Face ID is invalid."));
218 get_index_face()
const
220 unsigned int index_face = 0;
222 if(face == 0 or face == 1)
224 else if(face == 2 or face == 3)
227 Assert(
false, dealii::ExcMessage(
"Face ID is invalid."));
238 get_index_other()
const
240 return 1 - get_index_face();
249 dealii::Tensor<2, dim>
250 get_inverse_jacobian(dealii::Point<dim>
const & xi)
const
252 dealii::Tensor<2, dim> jacobian;
255 for(
unsigned int const v : cell->vertex_indices())
257 dealii::Tensor<1, dim> shape_function_gradient =
258 cell->reference_cell().d_linear_shape_function_gradient(xi, v);
259 jacobian += outer_product(cell->vertex(v), shape_function_gradient);
262 return invert(jacobian);
271 pull_back(dealii::Point<dim>
const & x)
const override
273 dealii::Point<dim> xi;
274 dealii::Tensor<1, dim> residual = push_forward(xi) - x;
275 dealii::Tensor<1, dim> delta_xi;
278 unsigned int n_iter = 0, MAX_ITER = 100;
279 double const TOL = 1.e-12;
280 while(residual.norm() > TOL and n_iter < MAX_ITER)
286 delta_xi = get_inverse_jacobian(xi) * residual;
303 residual = push_forward(xi) - x;
309 Assert(n_iter < MAX_ITER,
310 dealii::ExcMessage(
"Newton solver did not converge to given tolerance. "
311 "Maximum number of iterations exceeded."));
313 Assert(xi[0] >= 0.0 and xi[0] <= 1.0,
314 dealii::ExcMessage(
"Pull back operation generated invalid xi[0] values."));
316 Assert(xi[1] >= 0.0 and xi[1] <= 1.0,
317 dealii::ExcMessage(
"Pull back operation generated invalid xi[1] values."));
322 std::unique_ptr<dealii::Manifold<dim>>
323 clone()
const override
325 return std::make_unique<OneSidedCylindricalManifold<dim>>(tria, cell, face, center);
329 dealii::Point<2> x_C;
330 dealii::Tensor<1, 2> v_1;
331 dealii::Tensor<1, 2> v_2;
332 dealii::Tensor<1, 2> normal;
336 dealii::Triangulation<dim>
const & tria;
337 typename dealii::Triangulation<dim>::cell_iterator cell;
339 dealii::Point<dim> center;
351class OneSidedConicalManifold :
public dealii::ChartManifold<dim, dim, dim>
354 OneSidedConicalManifold(dealii::Triangulation<dim>
const & tria_in,
355 typename dealii::Triangulation<dim>::cell_iterator
const & cell_in,
356 unsigned int const face_in,
357 dealii::Point<dim>
const & center_in,
368 AssertThrow(tria.all_reference_cells_are_hyper_cube(),
369 dealii::ExcMessage(
"This class is only implemented for hypercube elements."));
371 AssertThrow(dim == 3,
372 dealii::ExcMessage(
"OneSidedConicalManifold can only be used for 3D problems."));
374 AssertThrow(face <= 3,
376 "One sided spherical manifold can only be applied to face f=0,1,2,3."));
384 dealii::Point<dim> x_1, x_2;
385 x_1 = cell->vertex(get_vertex_id(0));
386 x_2 = cell->vertex(get_vertex_id(1));
388 dealii::Point<2> x_1_2d = dealii::Point<2>(x_1[0], x_1[1]);
389 dealii::Point<2> x_2_2d = dealii::Point<2>(x_2[0], x_2[1]);
391 initialize(x_1_2d, x_2_2d);
395 initialize(dealii::Point<2>
const & x_1, dealii::Point<2>
const & x_2)
397 double const tol = 1.e-12;
406 double radius_check = v_2.norm();
408 AssertThrow(std::abs(r_0 - radius_check) < tol * r_0,
410 "Invalid geometry parameters. To apply a spherical manifold both "
411 "end points of the face must have the same distance from the center."));
418 alpha = std::acos(v_1 * v_2);
421 normal = v_2 - (v_2 * v_1) * v_1;
423 AssertThrow(normal.norm() > tol, dealii::ExcMessage(
"Vector must not have length 0."));
425 normal /= normal.norm();
433 push_forward(dealii::Point<dim>
const & xi)
const override
435 dealii::Point<dim> x;
438 for(
unsigned int const v : cell->vertex_indices())
440 double shape_function_value = cell->reference_cell().d_linear_shape_function(xi, v);
441 x += shape_function_value * cell->vertex(v);
448 unsigned int index_face = get_index_face();
449 unsigned int index_other = get_index_other();
450 double const xi_face = xi[index_face];
451 double const xi_other = xi[index_other];
454 double beta = xi_face * alpha;
456 dealii::Tensor<1, 2> direction;
457 direction = std::cos(beta) * v_1 + std::sin(beta) * normal;
459 Assert(std::abs(direction.norm() - 1.0) < 1.e-12,
460 dealii::ExcMessage(
"Vector must have length 1."));
463 dealii::Tensor<1, 2> x_S;
464 x_S = x_C + r_0 * direction;
468 dealii::Tensor<1, 2> displ, x_lin;
469 for(
unsigned int const v : dealii::ReferenceCells::template get_hypercube<1>().vertex_indices())
471 double shape_function_value =
472 dealii::ReferenceCells::template get_hypercube<1>().d_linear_shape_function(
473 dealii::Point<1>(xi_face), v);
475 unsigned int vertex_id = get_vertex_id(v);
476 dealii::Point<dim> vertex = cell->vertex(vertex_id);
478 x_lin[0] += shape_function_value * vertex[0];
479 x_lin[1] += shape_function_value * vertex[1];
485 displ *= (1 - xi[2] * (r_0 - r_1) / r_0);
488 dealii::Point<1> xi_other_1d = dealii::Point<1>(xi_other);
489 unsigned int index_1d = get_index_1d();
490 double fading_value =
491 dealii::ReferenceCells::template get_hypercube<1>().d_linear_shape_function(xi_other_1d,
493 x[0] += fading_value * displ[0];
494 x[1] += fading_value * displ[1];
496 Assert(dealii::numbers::is_finite(x.norm_square()), dealii::ExcMessage(
"Invalid point found"));
506 get_vertex_id(
unsigned int vertex_id_1d)
const
508 unsigned int vertex_id = 0;
511 vertex_id = 2 * vertex_id_1d;
513 vertex_id = 1 + 2 * vertex_id_1d;
515 vertex_id = vertex_id_1d;
517 vertex_id = 2 + vertex_id_1d;
529 unsigned int index_1d = 0;
531 if(face == 0 or face == 2)
533 else if(face == 1 or face == 3)
536 Assert(
false, dealii::ExcMessage(
"Face ID is invalid."));
546 get_index_face()
const
548 unsigned int index_face = 0;
550 if(face == 0 or face == 1)
552 else if(face == 2 or face == 3)
555 Assert(
false, dealii::ExcMessage(
"Face ID is invalid."));
566 get_index_other()
const
568 return 1 - get_index_face();
577 dealii::Tensor<2, dim>
578 get_inverse_jacobian(dealii::Point<dim>
const & xi)
const
580 dealii::Tensor<2, dim> jacobian;
583 for(
unsigned int const v : cell->vertex_indices())
585 dealii::Tensor<1, dim> shape_function_gradient =
586 cell->reference_cell().d_linear_shape_function_gradient(xi, v);
587 jacobian += outer_product(cell->vertex(v), shape_function_gradient);
590 return invert(jacobian);
599 pull_back(dealii::Point<dim>
const & x)
const override
601 dealii::Point<dim> xi;
602 dealii::Tensor<1, dim> residual = push_forward(xi) - x;
603 dealii::Tensor<1, dim> delta_xi;
606 unsigned int n_iter = 0, MAX_ITER = 100;
607 double const TOL = 1.e-12;
608 while(residual.norm() > TOL and n_iter < MAX_ITER)
614 delta_xi = get_inverse_jacobian(xi) * residual;
636 residual = push_forward(xi) - x;
642 Assert(n_iter < MAX_ITER,
643 dealii::ExcMessage(
"Newton solver did not converge to given tolerance. "
644 "Maximum number of iterations exceeded."));
646 Assert(xi[0] >= 0.0 and xi[0] <= 1.0,
647 dealii::ExcMessage(
"Pull back operation generated invalid xi[0] values."));
649 Assert(xi[1] >= 0.0 and xi[1] <= 1.0,
650 dealii::ExcMessage(
"Pull back operation generated invalid xi[1] values."));
652 Assert(xi[2] >= 0.0 and xi[2] <= 1.0,
653 dealii::ExcMessage(
"Pull back operation generated invalid xi[2] values."));
658 std::unique_ptr<dealii::Manifold<dim>>
659 clone()
const override
661 return std::make_unique<OneSidedConicalManifold<dim>>(tria, cell, face, center, r_0, r_1);
666 dealii::Point<2> x_C;
667 dealii::Tensor<1, 2> v_1;
668 dealii::Tensor<1, 2> v_2;
669 dealii::Tensor<1, 2> normal;
672 dealii::Triangulation<dim>
const & tria;
673 typename dealii::Triangulation<dim>::cell_iterator cell;
676 dealii::Point<dim> center;
688class MyCylindricalManifold :
public dealii::ChartManifold<dim, spacedim, spacedim>
691 MyCylindricalManifold(dealii::Point<spacedim>
const center_in)
692 : dealii::ChartManifold<dim, spacedim, spacedim>(
693 MyCylindricalManifold<dim, spacedim>::get_periodicity()),
698 dealii::Tensor<1, spacedim>
701 dealii::Tensor<1, spacedim> periodicity;
704 periodicity[1] = 2 * dealii::numbers::PI;
708 dealii::Point<spacedim>
709 push_forward(dealii::Point<spacedim>
const & ref_point)
const override
711 double const radius = ref_point[0];
712 double const theta = ref_point[1];
714 Assert(ref_point[0] >= 0.0, dealii::ExcMessage(
"Radius must be positive."));
716 dealii::Point<spacedim> space_point;
719 AssertThrow(spacedim == 2 or spacedim == 3,
720 dealii::ExcMessage(
"Only implemented for 2D and 3D case."));
722 space_point[0] = radius * cos(theta);
723 space_point[1] = radius * sin(theta);
726 space_point[2] = ref_point[2];
729 return space_point + center;
732 dealii::Point<spacedim>
733 pull_back(dealii::Point<spacedim>
const & space_point)
const override
735 dealii::Tensor<1, spacedim> vector;
736 vector[0] = space_point[0] - center[0];
737 vector[1] = space_point[1] - center[1];
740 double const radius = vector.norm();
742 dealii::Point<spacedim> ref_point;
743 ref_point[0] = radius;
744 ref_point[1] = atan2(vector[1], vector[0]);
746 ref_point[1] += 2.0 * dealii::numbers::PI;
748 ref_point[2] = space_point[2];
753 std::unique_ptr<dealii::Manifold<dim>>
754 clone()
const override
756 return std::make_unique<MyCylindricalManifold<dim, spacedim>>(center);
761 dealii::Point<dim> center;