39class OneSidedCylindricalManifold :
public dealii::ChartManifold<dim, dim, dim>
42 OneSidedCylindricalManifold(dealii::Triangulation<dim>
const & tria_in,
43 typename dealii::Triangulation<dim>::cell_iterator
const & cell_in,
44 unsigned int const face_in,
45 dealii::Point<dim>
const & center_in)
46 : alpha(1.0), radius(1.0), tria(tria_in), cell(cell_in), face(face_in), center(center_in)
48 AssertThrow(tria.all_reference_cells_are_hyper_cube(),
49 dealii::ExcMessage(
"This class is only implemented for hypercube elements."));
51 AssertThrow(face <= 3,
53 "One sided spherical manifold can only be applied to face f=0,1,2,3."));
61 dealii::Point<dim> x_1, x_2;
62 x_1 = cell->vertex(get_vertex_id(0));
63 x_2 = cell->vertex(get_vertex_id(1));
65 dealii::Point<2> x_1_2d = dealii::Point<2>(x_1[0], x_1[1]);
66 dealii::Point<2> x_2_2d = dealii::Point<2>(x_2[0], x_2[1]);
68 initialize(x_1_2d, x_2_2d);
72 initialize(dealii::Point<2>
const & x_1, dealii::Point<2>
const & x_2)
74 double const tol = 1.e-12;
83 double radius_check = v_2.norm();
84 AssertThrow(std::abs(radius - radius_check) < tol * radius,
86 "Invalid geometry parameters. To apply a spherical manifold both "
87 "end points of the face must have the same distance from the center."));
94 alpha = std::acos(v_1 * v_2);
97 normal = v_2 - (v_2 * v_1) * v_1;
99 AssertThrow(normal.norm() > tol, dealii::ExcMessage(
"Vector must not have length 0."));
101 normal /= normal.norm();
109 push_forward(dealii::Point<dim>
const & xi)
const override
111 dealii::Point<dim> x;
114 for(
unsigned int const v : cell->vertex_indices())
116 double shape_function_value = cell->reference_cell().d_linear_shape_function(xi, v);
117 x += shape_function_value * cell->vertex(v);
124 unsigned int index_face = get_index_face();
125 unsigned int index_other = get_index_other();
126 double const xi_face = xi[index_face];
127 double const xi_other = xi[index_other];
130 double beta = xi_face * alpha;
132 dealii::Tensor<1, 2> direction;
133 direction = std::cos(beta) * v_1 + std::sin(beta) * normal;
135 Assert(std::abs(direction.norm() - 1.0) < 1.e-12,
136 dealii::ExcMessage(
"Vector must have length 1."));
139 dealii::Tensor<1, 2> x_S;
140 x_S = x_C + radius * direction;
144 dealii::Tensor<1, 2> displ, x_lin;
145 for(
unsigned int v : dealii::ReferenceCells::template get_hypercube<1>().vertex_indices())
147 double shape_function_value =
148 dealii::ReferenceCells::template get_hypercube<1>().d_linear_shape_function(
149 dealii::Point<1>(xi_face), v);
151 unsigned int vertex_id = get_vertex_id(v);
152 dealii::Point<dim> vertex = cell->vertex(vertex_id);
154 x_lin[0] += shape_function_value * vertex[0];
155 x_lin[1] += shape_function_value * vertex[1];
161 dealii::Point<1> xi_other_1d = dealii::Point<1>(xi_other);
162 unsigned int index_1d = get_index_1d();
163 double fading_value =
164 dealii::ReferenceCells::template get_hypercube<1>().d_linear_shape_function(xi_other_1d,
166 x[0] += fading_value * displ[0];
167 x[1] += fading_value * displ[1];
169 Assert(dealii::numbers::is_finite(x.norm_square()), dealii::ExcMessage(
"Invalid point found"));
179 get_vertex_id(
unsigned int vertex_id_1d)
const
181 unsigned int vertex_id = 0;
184 vertex_id = 2 * vertex_id_1d;
186 vertex_id = 1 + 2 * vertex_id_1d;
188 vertex_id = vertex_id_1d;
190 vertex_id = 2 + vertex_id_1d;
202 unsigned int index_1d = 0;
204 if(face == 0 or face == 2)
206 else if(face == 1 or face == 3)
209 Assert(
false, dealii::ExcMessage(
"Face ID is invalid."));
219 get_index_face()
const
221 unsigned int index_face = 0;
223 if(face == 0 or face == 1)
225 else if(face == 2 or face == 3)
228 Assert(
false, dealii::ExcMessage(
"Face ID is invalid."));
239 get_index_other()
const
241 return 1 - get_index_face();
250 dealii::Tensor<2, dim>
251 get_inverse_jacobian(dealii::Point<dim>
const & xi)
const
253 dealii::Tensor<2, dim> jacobian;
256 for(
unsigned int const v : cell->vertex_indices())
258 dealii::Tensor<1, dim> shape_function_gradient =
259 cell->reference_cell().d_linear_shape_function_gradient(xi, v);
260 jacobian += outer_product(cell->vertex(v), shape_function_gradient);
263 return invert(jacobian);
272 pull_back(dealii::Point<dim>
const & x)
const override
274 dealii::Point<dim> xi;
275 dealii::Tensor<1, dim> residual = push_forward(xi) - x;
276 dealii::Tensor<1, dim> delta_xi;
279 unsigned int n_iter = 0, MAX_ITER = 100;
280 double const TOL = 1.e-12;
281 while(residual.norm() > TOL and n_iter < MAX_ITER)
287 delta_xi = get_inverse_jacobian(xi) * residual;
304 residual = push_forward(xi) - x;
310 Assert(n_iter < MAX_ITER,
311 dealii::ExcMessage(
"Newton solver did not converge to given tolerance. "
312 "Maximum number of iterations exceeded."));
314 Assert(xi[0] >= 0.0 and xi[0] <= 1.0,
315 dealii::ExcMessage(
"Pull back operation generated invalid xi[0] values."));
317 Assert(xi[1] >= 0.0 and xi[1] <= 1.0,
318 dealii::ExcMessage(
"Pull back operation generated invalid xi[1] values."));
323 std::unique_ptr<dealii::Manifold<dim>>
324 clone()
const override
326 return std::make_unique<OneSidedCylindricalManifold<dim>>(tria, cell, face, center);
330 dealii::Point<2> x_C;
331 dealii::Tensor<1, 2> v_1;
332 dealii::Tensor<1, 2> v_2;
333 dealii::Tensor<1, 2> normal;
337 dealii::Triangulation<dim>
const & tria;
338 typename dealii::Triangulation<dim>::cell_iterator cell;
340 dealii::Point<dim> center;
352class OneSidedConicalManifold :
public dealii::ChartManifold<dim, dim, dim>
355 OneSidedConicalManifold(dealii::Triangulation<dim>
const & tria_in,
356 typename dealii::Triangulation<dim>::cell_iterator
const & cell_in,
357 unsigned int const face_in,
358 dealii::Point<dim>
const & center_in,
369 AssertThrow(tria.all_reference_cells_are_hyper_cube(),
370 dealii::ExcMessage(
"This class is only implemented for hypercube elements."));
372 AssertThrow(dim == 3,
373 dealii::ExcMessage(
"OneSidedConicalManifold can only be used for 3D problems."));
375 AssertThrow(face <= 3,
377 "One sided spherical manifold can only be applied to face f=0,1,2,3."));
385 dealii::Point<dim> x_1, x_2;
386 x_1 = cell->vertex(get_vertex_id(0));
387 x_2 = cell->vertex(get_vertex_id(1));
389 dealii::Point<2> x_1_2d = dealii::Point<2>(x_1[0], x_1[1]);
390 dealii::Point<2> x_2_2d = dealii::Point<2>(x_2[0], x_2[1]);
392 initialize(x_1_2d, x_2_2d);
396 initialize(dealii::Point<2>
const & x_1, dealii::Point<2>
const & x_2)
398 double const tol = 1.e-12;
407 double radius_check = v_2.norm();
409 AssertThrow(std::abs(r_0 - radius_check) < tol * r_0,
411 "Invalid geometry parameters. To apply a spherical manifold both "
412 "end points of the face must have the same distance from the center."));
419 alpha = std::acos(v_1 * v_2);
422 normal = v_2 - (v_2 * v_1) * v_1;
424 AssertThrow(normal.norm() > tol, dealii::ExcMessage(
"Vector must not have length 0."));
426 normal /= normal.norm();
434 push_forward(dealii::Point<dim>
const & xi)
const override
436 dealii::Point<dim> x;
439 for(
unsigned int const v : cell->vertex_indices())
441 double shape_function_value = cell->reference_cell().d_linear_shape_function(xi, v);
442 x += shape_function_value * cell->vertex(v);
449 unsigned int index_face = get_index_face();
450 unsigned int index_other = get_index_other();
451 double const xi_face = xi[index_face];
452 double const xi_other = xi[index_other];
455 double beta = xi_face * alpha;
457 dealii::Tensor<1, 2> direction;
458 direction = std::cos(beta) * v_1 + std::sin(beta) * normal;
460 Assert(std::abs(direction.norm() - 1.0) < 1.e-12,
461 dealii::ExcMessage(
"Vector must have length 1."));
464 dealii::Tensor<1, 2> x_S;
465 x_S = x_C + r_0 * direction;
469 dealii::Tensor<1, 2> displ, x_lin;
470 for(
unsigned int const v : dealii::ReferenceCells::template get_hypercube<1>().vertex_indices())
472 double shape_function_value =
473 dealii::ReferenceCells::template get_hypercube<1>().d_linear_shape_function(
474 dealii::Point<1>(xi_face), v);
476 unsigned int vertex_id = get_vertex_id(v);
477 dealii::Point<dim> vertex = cell->vertex(vertex_id);
479 x_lin[0] += shape_function_value * vertex[0];
480 x_lin[1] += shape_function_value * vertex[1];
486 displ *= (1 - xi[2] * (r_0 - r_1) / r_0);
489 dealii::Point<1> xi_other_1d = dealii::Point<1>(xi_other);
490 unsigned int index_1d = get_index_1d();
491 double fading_value =
492 dealii::ReferenceCells::template get_hypercube<1>().d_linear_shape_function(xi_other_1d,
494 x[0] += fading_value * displ[0];
495 x[1] += fading_value * displ[1];
497 Assert(dealii::numbers::is_finite(x.norm_square()), dealii::ExcMessage(
"Invalid point found"));
507 get_vertex_id(
unsigned int vertex_id_1d)
const
509 unsigned int vertex_id = 0;
512 vertex_id = 2 * vertex_id_1d;
514 vertex_id = 1 + 2 * vertex_id_1d;
516 vertex_id = vertex_id_1d;
518 vertex_id = 2 + vertex_id_1d;
530 unsigned int index_1d = 0;
532 if(face == 0 or face == 2)
534 else if(face == 1 or face == 3)
537 Assert(
false, dealii::ExcMessage(
"Face ID is invalid."));
547 get_index_face()
const
549 unsigned int index_face = 0;
551 if(face == 0 or face == 1)
553 else if(face == 2 or face == 3)
556 Assert(
false, dealii::ExcMessage(
"Face ID is invalid."));
567 get_index_other()
const
569 return 1 - get_index_face();
578 dealii::Tensor<2, dim>
579 get_inverse_jacobian(dealii::Point<dim>
const & xi)
const
581 dealii::Tensor<2, dim> jacobian;
584 for(
unsigned int const v : cell->vertex_indices())
586 dealii::Tensor<1, dim> shape_function_gradient =
587 cell->reference_cell().d_linear_shape_function_gradient(xi, v);
588 jacobian += outer_product(cell->vertex(v), shape_function_gradient);
591 return invert(jacobian);
600 pull_back(dealii::Point<dim>
const & x)
const override
602 dealii::Point<dim> xi;
603 dealii::Tensor<1, dim> residual = push_forward(xi) - x;
604 dealii::Tensor<1, dim> delta_xi;
607 unsigned int n_iter = 0, MAX_ITER = 100;
608 double const TOL = 1.e-12;
609 while(residual.norm() > TOL and n_iter < MAX_ITER)
615 delta_xi = get_inverse_jacobian(xi) * residual;
637 residual = push_forward(xi) - x;
643 Assert(n_iter < MAX_ITER,
644 dealii::ExcMessage(
"Newton solver did not converge to given tolerance. "
645 "Maximum number of iterations exceeded."));
647 Assert(xi[0] >= 0.0 and xi[0] <= 1.0,
648 dealii::ExcMessage(
"Pull back operation generated invalid xi[0] values."));
650 Assert(xi[1] >= 0.0 and xi[1] <= 1.0,
651 dealii::ExcMessage(
"Pull back operation generated invalid xi[1] values."));
653 Assert(xi[2] >= 0.0 and xi[2] <= 1.0,
654 dealii::ExcMessage(
"Pull back operation generated invalid xi[2] values."));
659 std::unique_ptr<dealii::Manifold<dim>>
660 clone()
const override
662 return std::make_unique<OneSidedConicalManifold<dim>>(tria, cell, face, center, r_0, r_1);
667 dealii::Point<2> x_C;
668 dealii::Tensor<1, 2> v_1;
669 dealii::Tensor<1, 2> v_2;
670 dealii::Tensor<1, 2> normal;
673 dealii::Triangulation<dim>
const & tria;
674 typename dealii::Triangulation<dim>::cell_iterator cell;
677 dealii::Point<dim> center;
689class MyCylindricalManifold :
public dealii::ChartManifold<dim, spacedim, spacedim>
692 MyCylindricalManifold(dealii::Point<spacedim>
const center_in)
693 : dealii::ChartManifold<dim, spacedim, spacedim>(
694 MyCylindricalManifold<dim, spacedim>::get_periodicity()),
699 dealii::Tensor<1, spacedim>
702 dealii::Tensor<1, spacedim> periodicity;
705 periodicity[1] = 2 * dealii::numbers::PI;
709 dealii::Point<spacedim>
710 push_forward(dealii::Point<spacedim>
const & ref_point)
const override
712 double const radius = ref_point[0];
713 double const theta = ref_point[1];
715 Assert(ref_point[0] >= 0.0, dealii::ExcMessage(
"Radius must be positive."));
717 dealii::Point<spacedim> space_point;
720 AssertThrow(spacedim == 2 or spacedim == 3,
721 dealii::ExcMessage(
"Only implemented for 2D and 3D case."));
723 space_point[0] = radius * cos(theta);
724 space_point[1] = radius * sin(theta);
727 space_point[2] = ref_point[2];
730 return space_point + center;
733 dealii::Point<spacedim>
734 pull_back(dealii::Point<spacedim>
const & space_point)
const override
736 dealii::Tensor<1, spacedim> vector;
737 vector[0] = space_point[0] - center[0];
738 vector[1] = space_point[1] - center[1];
741 double const radius = vector.norm();
743 dealii::Point<spacedim> ref_point;
744 ref_point[0] = radius;
745 ref_point[1] = atan2(vector[1], vector[0]);
747 ref_point[1] += 2.0 * dealii::numbers::PI;
749 ref_point[2] = space_point[2];
754 std::unique_ptr<dealii::Manifold<dim>>
755 clone()
const override
757 return std::make_unique<MyCylindricalManifold<dim, spacedim>>(center);
762 dealii::Point<dim> center;