Reference documentation for deal.II version 9.3.2
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
grid_generator.cc
Go to the documentation of this file.
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 1999 - 2021 by the deal.II authors
4 //
5 // This file is part of the deal.II library.
6 //
7 // The deal.II library is free software; you can use it, redistribute
8 // it, and/or modify it under the terms of the GNU Lesser General
9 // Public License as published by the Free Software Foundation; either
10 // version 2.1 of the License, or (at your option) any later version.
11 // The full text of the license can be found in the file LICENSE.md at
12 // the top level directory of deal.II.
13 //
14 // ---------------------------------------------------------------------
15 
16 #include <deal.II/base/ndarray.h>
17 
21 
27 #include <deal.II/grid/tria.h>
30 
31 #include <array>
32 #include <cmath>
33 #include <limits>
34 
35 
37 
38 // work around the problem that doxygen for some reason lists all template
39 // specializations in this file
40 #ifndef DOXYGEN
41 
42 namespace GridGenerator
43 {
44  namespace Airfoil
45  {
47  // airfoil configuration
48  : airfoil_type("NACA")
49  , naca_id("2412")
50  , joukowski_center(-0.1, 0.14)
51  , airfoil_length(1.0)
52  // far field
53  , height(30.0)
54  , length_b2(15.0)
55  // mesh
56  , incline_factor(0.35)
57  , bias_factor(2.5)
58  , refinements(2)
59  , n_subdivision_x_0(3)
60  , n_subdivision_x_1(2)
61  , n_subdivision_x_2(5)
62  , n_subdivision_y(3)
63  , airfoil_sampling_factor(2)
64  {
65  Assert(
66  airfoil_length <= height,
67  ExcMessage(
68  "Mesh is to small to enclose airfoil! Choose larger field or smaller"
69  " chord length!"));
70  Assert(incline_factor < 1.0 && incline_factor >= 0.0,
71  ExcMessage("incline_factor has to be in [0,1)!"));
72  }
73 
74 
75 
76  void
77  AdditionalData::add_parameters(ParameterHandler &prm)
78  {
79  prm.enter_subsection("FarField");
80  {
81  prm.add_parameter(
82  "Height",
83  height,
84  "Mesh height measured from airfoil nose to horizontal boundaries");
85  prm.add_parameter(
86  "LengthB2",
87  length_b2,
88  "Length measured from airfoil leading edge to vertical outlet boundary");
89  prm.add_parameter(
90  "InclineFactor",
91  incline_factor,
92  "Define obliqueness of the vertical mesh around the airfoil");
93  }
94  prm.leave_subsection();
95 
96  prm.enter_subsection("AirfoilType");
97  {
98  prm.add_parameter(
99  "Type",
100  airfoil_type,
101  "Type of airfoil geometry, either NACA or Joukowski airfoil",
102  Patterns::Selection("NACA|Joukowski"));
103  }
104  prm.leave_subsection();
105 
106  prm.enter_subsection("NACA");
107  {
108  prm.add_parameter("NacaId", naca_id, "Naca serial number");
109  }
110  prm.leave_subsection();
111 
112  prm.enter_subsection("Joukowski");
113  {
114  prm.add_parameter("Center",
115  joukowski_center,
116  "Joukowski circle center coordinates");
117  prm.add_parameter("AirfoilLength",
118  airfoil_length,
119  "Joukowski airfoil length leading to trailing edge");
120  }
121  prm.leave_subsection();
122 
123  prm.enter_subsection("Mesh");
124  {
125  prm.add_parameter("Refinements",
126  refinements,
127  "Number of global refinements");
128  prm.add_parameter(
129  "NumberSubdivisionX0",
130  n_subdivision_x_0,
131  "Number of subdivisions along the airfoil in blocks with material ID 1 and 4");
132  prm.add_parameter(
133  "NumberSubdivisionX1",
134  n_subdivision_x_1,
135  "Number of subdivisions along the airfoil in blocks with material ID 2 and 5");
136  prm.add_parameter(
137  "NumberSubdivisionX2",
138  n_subdivision_x_2,
139  "Number of subdivisions in horizontal direction on the right of the trailing edge, i.e., blocks with material ID 3 and 6");
140  prm.add_parameter("NumberSubdivisionY",
141  n_subdivision_y,
142  "Number of subdivisions normal to airfoil");
143  prm.add_parameter(
144  "BiasFactor",
145  bias_factor,
146  "Factor to obtain a finer mesh at the airfoil surface");
147  }
148  prm.leave_subsection();
149  }
150 
151 
152  namespace
153  {
157  class MeshGenerator
158  {
159  public:
160  // IDs of the mesh blocks
161  static const unsigned int id_block_1 = 1;
162  static const unsigned int id_block_2 = 2;
163  static const unsigned int id_block_3 = 3;
164  static const unsigned int id_block_4 = 4;
165  static const unsigned int id_block_5 = 5;
166  static const unsigned int id_block_6 = 6;
167 
171  MeshGenerator(const AdditionalData &data)
172  : refinements(data.refinements)
173  , n_subdivision_x_0(data.n_subdivision_x_0)
174  , n_subdivision_x_1(data.n_subdivision_x_1)
175  , n_subdivision_x_2(data.n_subdivision_x_2)
176  , n_subdivision_y(data.n_subdivision_y)
177  , height(data.height)
178  , length_b2(data.length_b2)
179  , incline_factor(data.incline_factor)
180  , bias_factor(data.bias_factor)
181  , edge_length(1.0)
182  , n_cells_x_0(Utilities::pow(2, refinements) * n_subdivision_x_0)
183  , n_cells_x_1(Utilities::pow(2, refinements) * n_subdivision_x_1)
184  , n_cells_x_2(Utilities::pow(2, refinements) * n_subdivision_x_2)
185  , n_cells_y(Utilities::pow(2, refinements) * n_subdivision_y)
186  , n_points_on_each_side(n_cells_x_0 + n_cells_x_1 + 1)
187  // create points on the airfoil
188  , airfoil_1D(set_airfoil_length(
189  // call either the 'joukowski' or 'naca' static member function
190  data.airfoil_type == "Joukowski" ?
191  joukowski(data.joukowski_center,
192  n_points_on_each_side,
193  data.airfoil_sampling_factor) :
194  (data.airfoil_type == "NACA" ?
195  naca(data.naca_id,
196  n_points_on_each_side,
197  data.airfoil_sampling_factor) :
198  std::array<std::vector<Point<2>>, 2>{
199  {std::vector<Point<2>>{Point<2>(0), Point<2>(1)},
200  std::vector<Point<2>>{
201  Point<2>(0),
202  Point<2>(
203  1)}}} /* dummy vector since we are asserting later*/),
204  data.airfoil_length))
205  , end_b0_x_u(airfoil_1D[0][n_cells_x_0](0))
206  , end_b0_x_l(airfoil_1D[1][n_cells_x_0](0))
207  , nose_x(airfoil_1D[0].front()(0))
208  , tail_x(airfoil_1D[0].back()(0))
209  , tail_y(airfoil_1D[0].back()(1))
210  , center_mesh(0.5 * std::abs(end_b0_x_u + end_b0_x_l))
211  , length_b1_x(tail_x - center_mesh)
212  , gamma(std::atan(height /
213  (edge_length + std::abs(nose_x - center_mesh))))
214  // points on coarse grid
215  // coarse grid has to be symmetric in respect to x-axis to allow
216  // periodic BC and make sure that interpolate() works
217  , A(nose_x - edge_length, 0)
218  , B(nose_x, 0)
219  , C(center_mesh, +std::abs(nose_x - center_mesh) * std::tan(gamma))
220  , D(center_mesh, height)
221  , E(center_mesh, -std::abs(nose_x - center_mesh) * std::tan(gamma))
222  , F(center_mesh, -height)
223  , G(tail_x, height)
224  , H(tail_x, 0)
225  , I(tail_x, -height)
226  , J(tail_x + length_b2, 0)
227  , K(J(0), G(1))
228  , L(J(0), I(1))
229  {
230  Assert(data.airfoil_type == "Joukowski" ||
231  data.airfoil_type == "NACA",
232  ExcMessage("Unknown airfoil type."));
233  }
234 
239  Triangulation<2> & tria_grid,
240  std::vector<GridTools::PeriodicFacePair<
241  typename Triangulation<2>::cell_iterator>> *periodic_faces) const
242  {
243  make_coarse_grid(tria_grid);
244 
245  set_boundary_ids(tria_grid);
246 
247  if (periodic_faces != nullptr)
248  {
250  tria_grid, 5, 4, 1, *periodic_faces);
251  tria_grid.add_periodicity(*periodic_faces);
252  }
253 
254  tria_grid.refine_global(refinements);
255  interpolate(tria_grid);
256  }
257 
263  std::vector<GridTools::PeriodicFacePair<
264  typename Triangulation<2>::cell_iterator>> *periodic_faces) const
265  {
266  (void)parallel_grid;
267  (void)periodic_faces;
268 
269  AssertThrow(false, ExcMessage("Not implemented, yet!")); // TODO [PM]
270  }
271 
272  private:
273  // number of global refinements
274  const unsigned int refinements;
275 
276  // number of subdivisions of coarse grid in blocks 1 and 4
277  const unsigned int n_subdivision_x_0;
278 
279  // number of subdivisions of coarse grid in blocks 2 and 5
280  const unsigned int n_subdivision_x_1;
281 
282  // number of subdivisions of coarse grid in blocks 3 and 6
283  const unsigned int n_subdivision_x_2;
284 
285  // number of subdivisions of coarse grid in all blocks (normal to
286  // airfoil or in y-direction, respectively)
287  const unsigned int n_subdivision_y;
288 
289  // height of mesh, i.e. length JK or JL and radius of semicircle
290  // (C-Mesh) that arises after interpolation in blocks 1 and 4
291  const double height;
292 
293  // length block 3 and 6
294  const double length_b2;
295 
296  // factor to move points G and I horizontal to the right, i.e. make
297  // faces HG and HI inclined instead of vertical
298  const double incline_factor;
299 
300  // bias factor (if factor goes to zero than equal y = x)
301  const double bias_factor;
302 
303  // x-distance between coarse grid vertices A and B, i.e. used only once;
304  const double edge_length;
305 
306  // number of cells (after refining) in block 1 and 4 along airfoil
307  const unsigned int n_cells_x_0;
308 
309  // number of cells (after refining) in block 2 and 5 along airfoil
310  const unsigned int n_cells_x_1;
311 
312  // number of cells (after refining) in block 3 and 6 in x-direction
313  const unsigned int n_cells_x_2;
314 
315  // number of cells (after refining) in all blocks normal to airfoil or
316  // in y-direction, respectively
317  const unsigned int n_cells_y;
318 
319  // number of airfoil points on each side
320  const unsigned int n_points_on_each_side;
321 
322  // vector containing upper/lower airfoil points. First and last point
323  // are identical
324  const std::array<std::vector<Point<2>>, 2> airfoil_1D;
325 
326  // x-coordinate of n-th airfoilpoint where n indicates number of cells
327  // in block 1. end_b0_x_u = end_b0_x_l for symmetric airfoils
328  const double end_b0_x_u;
329 
330  // x-coordinate of n-th airfoilpoint where n indicates number of cells
331  // in block 4. end_b0_x_u = end_b0_x_l for symmetric airfoils
332  const double end_b0_x_l;
333 
334  // x-coordinate of first airfoil point in airfoil_1D[0] and
335  // airfoil_1D[1]
336  const double nose_x;
337 
338  // x-coordinate of last airfoil point in airfoil_1D[0] and airfoil_1D[1]
339  const double tail_x;
340 
341  // y-coordinate of last airfoil point in airfoil_1D[0] and airfoil_1D[1]
342  const double tail_y;
343 
344  // x-coordinate of C,D,E,F indicating ending of blocks 1 and 4 or
345  // beginning of blocks 2 and 5, respectively
346  const double center_mesh;
347 
348  // length of blocks 2 and 5
349  const double length_b1_x;
350 
351  // angle enclosed between faces DAB and FAB
352  const double gamma;
353 
354 
355 
376  const Point<2> A, B, C, D, E, F, G, H, I, J, K, L;
377 
378 
379 
415  static std::array<std::vector<Point<2>>, 2>
416  joukowski(const Point<2> & centerpoint,
417  const unsigned int number_points,
418  const unsigned int factor)
419  {
420  std::array<std::vector<Point<2>>, 2> airfoil_1D;
421  const unsigned int total_points = 2 * number_points - 2;
422  const unsigned int n_airfoilpoints = factor * total_points;
423  // joukowski points on the entire airfoil, i.e. upper and lower side
424  const auto jouk_points =
425  joukowski_transform(joukowski_circle(centerpoint, n_airfoilpoints));
426 
427  // vectors to collect airfoil points on either upper or lower side
428  std::vector<Point<2>> upper_points;
429  std::vector<Point<2>> lower_points;
430 
431  {
432  // find point on nose and point on tail
433  unsigned int nose_index = 0;
434  unsigned int tail_index = 0;
435  double nose_x_coordinate = 0;
436  double tail_x_coordinate = 0;
437 
438 
439  // find index in vector to nose point (min) and tail point (max)
440  for (unsigned int i = 0; i < jouk_points.size(); i++)
441  {
442  if (jouk_points[i](0) < nose_x_coordinate)
443  {
444  nose_x_coordinate = jouk_points[i](0);
445  nose_index = i;
446  }
447  if (jouk_points[i](0) > tail_x_coordinate)
448  {
449  tail_x_coordinate = jouk_points[i](0);
450  tail_index = i;
451  }
452  }
453 
454  // copy point on upper side of airfoil
455  for (unsigned int i = tail_index; i < jouk_points.size(); i++)
456  upper_points.emplace_back(jouk_points[i]);
457  for (unsigned int i = 0; i <= nose_index; i++)
458  upper_points.emplace_back(jouk_points[i]);
459  std::reverse(upper_points.begin(), upper_points.end());
460 
461  // copy point on lower side of airfoil
462  lower_points.insert(lower_points.end(),
463  jouk_points.begin() + nose_index,
464  jouk_points.begin() + tail_index + 1);
465  }
466 
467  airfoil_1D[0] = make_points_equidistant(upper_points, number_points);
468  airfoil_1D[1] = make_points_equidistant(lower_points, number_points);
469 
470  // move nose to origin
471  auto move_nose_to_origin = [](std::vector<Point<2>> &vector) {
472  const double nose_x_pos = vector.front()(0);
473  for (auto &i : vector)
474  i(0) -= nose_x_pos;
475  };
476 
477  move_nose_to_origin(airfoil_1D[1]);
478  move_nose_to_origin(airfoil_1D[0]);
479 
480  return airfoil_1D;
481  }
482 
507  static std::vector<Point<2>>
508  joukowski_circle(const Point<2> & center,
509  const unsigned int number_points)
510  {
511  std::vector<Point<2>> circle_points;
512 
513  // Create Circle with number_points - points
514  // unsigned int number_points = 2 * points_per_side - 2;
515 
516  // Calculate radius so that point (x=1|y=0) is enclosed - requirement
517  // for Joukowski transform
518  const double radius = std::sqrt(center(1) * center(1) +
519  (1 - center(0)) * (1 - center(0)));
520  const double radius_test = std::sqrt(
521  center(1) * center(1) + (1 + center(0)) * (1 + center(0)));
522  // Make sure point (x=-1|y=0) is enclosed by the circle
523  (void)radius_test;
524  AssertThrow(
525  radius_test < radius,
526  ExcMessage(
527  "Error creating lower circle: Circle for Joukowski-transform does"
528  " not enclose point zeta = -1! Choose different center "
529  "coordinate."));
530  // Create a full circle with radius 'radius' around Point 'center' of
531  // (number_points) equidistant points.
532  const double theta = 2 * numbers::PI / number_points;
533  // first point is leading edge then counterclockwise
534  for (unsigned int i = 0; i < number_points; i++)
535  circle_points.emplace_back(center[0] - radius * cos(i * theta),
536  center[1] - radius * sin(i * theta));
537 
538  return circle_points;
539  }
540 
549  static std::vector<Point<2>>
550  joukowski_transform(const std::vector<Point<2>> &circle_points)
551  {
552  std::vector<Point<2>> joukowski_points(circle_points.size());
553 
554  // transform each point
555  for (unsigned int i = 0; i < circle_points.size(); i++)
556  {
557  const double chi = circle_points[i](0);
558  const double eta = circle_points[i](1);
559  const std::complex<double> zeta(chi, eta);
560  const std::complex<double> z = zeta + 1. / zeta;
561 
562  joukowski_points[i] = {real(z), imag(z)};
563  }
564  return joukowski_points;
565  }
566 
583  static std::array<std::vector<Point<2>>, 2>
584  naca(const std::string &serialnumber,
585  const unsigned int number_points,
586  const unsigned int factor)
587  {
588  // number of non_equidistant airfoilpoints among which will be
589  // interpolated
590  const unsigned int n_airfoilpoints = factor * number_points;
591 
592  // create equidistant airfoil points for upper and lower side
593  return {{make_points_equidistant(
594  naca_create_points(serialnumber, n_airfoilpoints, true),
595  number_points),
596  make_points_equidistant(
597  naca_create_points(serialnumber, n_airfoilpoints, false),
598  number_points)}};
599  }
600 
612  static std::vector<Point<2>>
613  naca_create_points(const std::string &serialnumber,
614  const unsigned int number_points,
615  const bool is_upper)
616  {
617  Assert(serialnumber.length() == 4,
618  ExcMessage("This NACA-serial number is not implemented!"));
619 
620  return naca_create_points_4_digits(serialnumber,
621  number_points,
622  is_upper);
623  }
624 
639  static std::vector<Point<2>>
640  naca_create_points_4_digits(const std::string &serialnumber,
641  const unsigned int number_points,
642  const bool is_upper)
643  {
644  // conversion string (char * ) to int
645  const unsigned int digit_0 = (serialnumber[0] - '0');
646  const unsigned int digit_1 = (serialnumber[1] - '0');
647  const unsigned int digit_2 = (serialnumber[2] - '0');
648  const unsigned int digit_3 = (serialnumber[3] - '0');
649 
650  const unsigned int digit_23 = 10 * digit_2 + digit_3;
651 
652  // maximum thickness in percentage of the cord
653  const double t = static_cast<double>(digit_23) / 100.0;
654 
655  std::vector<Point<2>> naca_points;
656 
657  if (digit_0 == 0 && digit_1 == 0) // is symmetric
658  for (unsigned int i = 0; i < number_points; i++)
659  {
660  const double x = i * 1 / (1.0 * number_points - 1);
661  const double y_t =
662  5 * t *
663  (0.2969 * std::pow(x, 0.5) - 0.126 * x -
664  0.3516 * std::pow(x, 2) + 0.2843 * std::pow(x, 3) -
665  0.1036 * std::pow(x, 4)); // half thickness at a position x
666 
667  if (is_upper)
668  naca_points.emplace_back(x, +y_t);
669  else
670  naca_points.emplace_back(x, -y_t);
671  }
672  else // is asymmetric
673  for (unsigned int i = 0; i < number_points; i++)
674  {
675  const double m = 1.0 * digit_0 / 100; // max. chamber
676  const double p = 1.0 * digit_1 / 10; // location of max. chamber
677  const double x = i * 1 / (1.0 * number_points - 1);
678 
679  const double y_c =
680  (x <= p) ? m / std::pow(p, 2) * (2 * p * x - std::pow(x, 2)) :
681  m / std::pow(1 - p, 2) *
682  ((1 - 2 * p) + 2 * p * x - std::pow(x, 2));
683 
684  const double dy_c = (x <= p) ?
685  2 * m / std::pow(p, 2) * (p - x) :
686  2 * m / std::pow(1 - p, 2) * (p - x);
687 
688  const double y_t =
689  5 * t *
690  (0.2969 * std::pow(x, 0.5) - 0.126 * x -
691  0.3516 * std::pow(x, 2) + 0.2843 * std::pow(x, 3) -
692  0.1036 * std::pow(x, 4)); // half thickness at a position x
693 
694  const double theta = std::atan(dy_c);
695 
696  if (is_upper)
697  naca_points.emplace_back(x - y_t * std::sin(theta),
698  y_c + y_t * std::cos(theta));
699  else
700  naca_points.emplace_back(x + y_t * std::sin(theta),
701  y_c - y_t * std::cos(theta));
702  }
703 
704  return naca_points;
705  }
706 
707 
708 
717  static std::array<std::vector<Point<2>>, 2>
718  set_airfoil_length(const std::array<std::vector<Point<2>>, 2> &input,
719  const double desired_len)
720  {
721  std::array<std::vector<Point<2>>, 2> output;
722  output[0] = set_airfoil_length(input[0], desired_len);
723  output[1] = set_airfoil_length(input[1], desired_len);
724 
725  return output;
726  }
727 
735  static std::vector<Point<2>>
736  set_airfoil_length(const std::vector<Point<2>> &input,
737  const double desired_len)
738  {
739  std::vector<Point<2>> output = input;
740 
741  const double scale =
742  desired_len / input.front().distance(input.back());
743 
744  for (auto &x : output)
745  x *= scale;
746 
747  return output;
748  }
749 
760  static std::vector<Point<2>>
761  make_points_equidistant(
762  const std::vector<Point<2>> &non_equidistant_points,
763  const unsigned int number_points)
764  {
765  const unsigned int n_points =
766  non_equidistant_points
767  .size(); // number provided airfoilpoints to interpolate
768 
769  // calculate arclength
770  std::vector<double> arclength_L(non_equidistant_points.size(), 0);
771  for (unsigned int i = 0; i < non_equidistant_points.size() - 1; i++)
772  arclength_L[i + 1] =
773  arclength_L[i] +
774  non_equidistant_points[i + 1].distance(non_equidistant_points[i]);
775 
776 
777  const auto airfoil_length =
778  arclength_L.back(); // arclength upper or lower side
779  const auto deltaX = airfoil_length / (number_points - 1);
780 
781  // Create equidistant points: keep the first (and last) point
782  // unchanged
783  std::vector<Point<2>> equidist(
784  number_points); // number_points is required points on each side for
785  // mesh
786  equidist[0] = non_equidistant_points[0];
787  equidist[number_points - 1] = non_equidistant_points[n_points - 1];
788 
789 
790  // loop over all subsections
791  for (unsigned int j = 0, i = 1; j < n_points - 1; j++)
792  {
793  // get reference left and right end of this section
794  const auto Lj = arclength_L[j];
795  const auto Ljp = arclength_L[j + 1];
796 
797  while (Lj <= i * deltaX && i * deltaX <= Ljp &&
798  i < number_points - 1)
799  {
800  equidist[i] = Point<2>((i * deltaX - Lj) / (Ljp - Lj) *
801  (non_equidistant_points[j + 1] -
802  non_equidistant_points[j]) +
803  non_equidistant_points[j]);
804  ++i;
805  }
806  }
807  return equidist;
808  }
809 
810 
811 
818  void make_coarse_grid(Triangulation<2> &tria) const
819  {
820  // create vector of serial triangulations for each block and
821  // temporary storage for merging them
822  std::vector<Triangulation<2>> trias(10);
823 
824  // helper function to create a subdivided quadrilateral
825  auto make = [](Triangulation<2> & tria,
826  const std::vector<Point<2>> & corner_vertices,
827  const std::vector<unsigned int> &repetitions,
828  const unsigned int material_id) {
829  // create subdivided rectangle with corner points (-1,-1)
830  // and (+1, +1). It serves as reference system
832  repetitions,
833  {-1, -1},
834  {+1, +1});
835 
836  // move all vertices to the correct position
837  for (auto it = tria.begin_vertex(); it < tria.end_vertex(); ++it)
838  {
839  auto & point = it->vertex();
840  const double xi = point(0);
841  const double eta = point(1);
842 
843  // bilinear mapping
844  point = 0.25 * ((1 - xi) * (1 - eta) * corner_vertices[0] +
845  (1 + xi) * (1 - eta) * corner_vertices[1] +
846  (1 - xi) * (1 + eta) * corner_vertices[2] +
847  (1 + xi) * (1 + eta) * corner_vertices[3]);
848  }
849 
850  // set material id of block
851  for (auto cell : tria.active_cell_iterators())
852  cell->set_material_id(material_id);
853  };
854 
855  // create a subdivided quadrilateral for each block (see last number
856  // of block id)
857  make(trias[0],
858  {A, B, D, C},
859  {n_subdivision_y, n_subdivision_x_0},
860  id_block_1);
861  make(trias[1],
862  {F, E, A, B},
863  {n_subdivision_y, n_subdivision_x_0},
864  id_block_4);
865  make(trias[2],
866  {C, H, D, G},
867  {n_subdivision_x_1, n_subdivision_y},
868  id_block_2);
869  make(trias[3],
870  {F, I, E, H},
871  {n_subdivision_x_1, n_subdivision_y},
872  id_block_5);
873  make(trias[4],
874  {H, J, G, K},
875  {n_subdivision_x_2, n_subdivision_y},
876  id_block_3);
877  make(trias[5],
878  {I, L, H, J},
879  {n_subdivision_x_2, n_subdivision_y},
880  id_block_6);
881 
882 
883  // merge triangulation (warning: do not change the order here since
884  // this might change the face ids)
885  GridGenerator::merge_triangulations(trias[0], trias[1], trias[6]);
886  GridGenerator::merge_triangulations(trias[2], trias[3], trias[7]);
887  GridGenerator::merge_triangulations(trias[4], trias[5], trias[8]);
888  GridGenerator::merge_triangulations(trias[6], trias[7], trias[9]);
889  GridGenerator::merge_triangulations(trias[8], trias[9], tria);
890  }
891 
892  /*
893  * Loop over all (cells and) boundary faces of a given triangulation
894  * and set the boundary_ids depending on the material_id of the cell and
895  * the face number. The resulting boundary_ids are:
896  * - 0: inlet
897  * - 1: outlet
898  * - 2: upper airfoil surface (aka. suction side)
899  * - 3, lower airfoil surface (aka. pressure side),
900  * - 4: upper far-field side
901  * - 5: lower far-field side
902  */
903  static void set_boundary_ids(Triangulation<2> &tria)
904  {
905  for (auto cell : tria.active_cell_iterators())
906  for (unsigned int f : GeometryInfo<2>::face_indices())
907  {
908  if (cell->face(f)->at_boundary() == false)
909  continue;
910 
911  const auto mid = cell->material_id();
912 
913  if ((mid == id_block_1 && f == 0) ||
914  (mid == id_block_4 && f == 0))
915  cell->face(f)->set_boundary_id(0); // inlet
916  else if ((mid == id_block_3 && f == 0) ||
917  (mid == id_block_6 && f == 2))
918  cell->face(f)->set_boundary_id(1); // outlet
919  else if ((mid == id_block_1 && f == 1) ||
920  (mid == id_block_2 && f == 1))
921  cell->face(f)->set_boundary_id(2); // upper airfoil side
922  else if ((mid == id_block_4 && f == 1) ||
923  (mid == id_block_5 && f == 3))
924  cell->face(f)->set_boundary_id(3); // lower airfoil side
925  else if ((mid == id_block_2 && f == 0) ||
926  (mid == id_block_3 && f == 2))
927  cell->face(f)->set_boundary_id(4); // upper far-field side
928  else if ((mid == id_block_5 && f == 2) ||
929  (mid == id_block_6 && f == 0))
930  cell->face(f)->set_boundary_id(5); // lower far-field side
931  else
932  Assert(false, ExcIndexRange(mid, id_block_1, id_block_6));
933  }
934  }
935 
936  /*
937  * Interpolate all vertices of the given triangulation onto the airfoil
938  * geometry, depending on the material_id of the block.
939  * Due to symmetry of coarse grid in respect to
940  * x-axis (by definition of points A-L), blocks 1&4, 2&4 and 3&6 can be
941  * interpolated with the same geometric computations Consider a
942  * bias_factor and incline_factor during interpolation to obtain a more
943  * dense mesh next to airfoil geometry and receive an inclined boundary
944  * between block 2&3 and 5&6, respectively
945  */
946  void interpolate(Triangulation<2> &tria) const
947  {
948  // array storing the information if a vertex was processed
949  std::vector<bool> vertex_processed(tria.n_vertices(), false);
950 
951  // rotation matrix for clockwise rotation of block 1 by angle gamma
952  Tensor<2, 2, double> rotation_matrix_1, rotation_matrix_2;
953 
954  rotation_matrix_1[0][0] = +std::cos(-gamma);
955  rotation_matrix_1[0][1] = -std::sin(-gamma);
956  rotation_matrix_1[1][0] = +std::sin(-gamma);
957  rotation_matrix_1[1][1] = +std::cos(-gamma);
958 
959  rotation_matrix_2 = transpose(rotation_matrix_1);
960 
961  // horizontal offset in order to place coarse-grid node A in the
962  // origin
963  const Point<2, double> horizontal_offset(A(0), 0.0);
964 
965  // Move block 1 so that face BC coincides the x-axis
966  const Point<2, double> trapeze_offset(0.0,
967  std::sin(gamma) * edge_length);
968 
969  // loop over vertices of all cells
970  for (auto &cell : tria)
971  for (const unsigned int v : GeometryInfo<2>::vertex_indices())
972  {
973  // vertex has been already processed: nothing to do
974  if (vertex_processed[cell.vertex_index(v)])
975  continue;
976 
977  // mark vertex as processed
978  vertex_processed[cell.vertex_index(v)] = true;
979 
980  auto &node = cell.vertex(v);
981 
982  // distinguish blocks
983  if (cell.material_id() == id_block_1 ||
984  cell.material_id() == id_block_4) // block 1 and 4
985  {
986  // step 1: rotate block 1 clockwise by gamma and move block
987  // 1 so that A(0) is on y-axis so that faces AD and BC are
988  // horizontal. This simplifies the computation of the
989  // required indices for interpolation (all x-nodes are
990  // positive) Move trapeze to be in first quadrant by adding
991  // trapeze_offset
992  Point<2, double> node_;
993  if (cell.material_id() == id_block_1)
994  {
995  node_ = Point<2, double>(rotation_matrix_1 *
996  (node - horizontal_offset) +
997  trapeze_offset);
998  }
999  // step 1: rotate block 4 counterclockwise and move down so
1000  // that trapeze is located in fourth quadrant (subtracting
1001  // trapeze_offset)
1002  else if (cell.material_id() == id_block_4)
1003  {
1004  node_ = Point<2, double>(rotation_matrix_2 *
1005  (node - horizontal_offset) -
1006  trapeze_offset);
1007  }
1008  // step 2: compute indices ix and iy and interpolate
1009  // trapezoid to a rectangle of length pi/2.
1010  {
1011  const double trapeze_height =
1012  std::sin(gamma) * edge_length;
1013  const double L = height / std::sin(gamma);
1014  const double l_a = std::cos(gamma) * edge_length;
1015  const double l_b = trapeze_height * std::tan(gamma);
1016  const double x1 = std::abs(node_(1)) / std::tan(gamma);
1017  const double x2 = L - l_a - l_b;
1018  const double x3 = std::abs(node_(1)) * std::tan(gamma);
1019  const double Dx = x1 + x2 + x3;
1020  const double deltax =
1021  (trapeze_height - std::abs(node_(1))) / std::tan(gamma);
1022  const double dx = Dx / n_cells_x_0;
1023  const double dy = trapeze_height / n_cells_y;
1024  const int ix =
1025  static_cast<int>(std::round((node_(0) - deltax) / dx));
1026  const int iy =
1027  static_cast<int>(std::round(std::abs(node_(1)) / dy));
1028 
1029  node_(0) = numbers::PI / 2 * (1.0 * ix) / n_cells_x_0;
1030  node_(1) = height * (1.0 * iy) / n_cells_y;
1031  }
1032 
1033  // step 3: Interpolation between semicircle (of C-Mesh) and
1034  // airfoil contour
1035  {
1036  const double dx = numbers::PI / 2 / n_cells_x_0;
1037  const double dy = height / n_cells_y;
1038  const int ix =
1039  static_cast<int>(std::round(node_(0) / dx));
1040  const int iy =
1041  static_cast<int>(std::round(node_(1) / dy));
1042  const double alpha =
1043  bias_alpha(1 - (1.0 * iy) / n_cells_y);
1044  const double theta = node_(0);
1045  const Point<2> p(-height * std::cos(theta) + center_mesh,
1046  ((cell.material_id() == id_block_1) ?
1047  (height) :
1048  (-height)) *
1049  std::sin(theta));
1050  node =
1051  airfoil_1D[(
1052  (cell.material_id() == id_block_1) ? (0) : (1))][ix] *
1053  alpha +
1054  p * (1 - alpha);
1055  }
1056  }
1057  else if (cell.material_id() == id_block_2 ||
1058  cell.material_id() == id_block_5) // block 2 and 5
1059  {
1060  // geometric parameters and indices for interpolation
1061  Assert(
1062  (std::abs(D(1) - C(1)) == std::abs(F(1) - E(1))) &&
1063  (std::abs(C(1)) == std::abs(E(1))) &&
1064  (std::abs(G(1)) == std::abs(I(1))),
1065  ExcMessage(
1066  "Points D,C,G and E,F,I are not defined symmetric to "
1067  "x-axis, which is required to interpolate block 2"
1068  " and 5 with same geometric computations."));
1069  const double l_y = D(1) - C(1);
1070  const double l_h = D(1) - l_y;
1071  const double by = -l_h / length_b1_x * (node(0) - H(0));
1072  const double dy = (height - by) / n_cells_y;
1073  const int iy = static_cast<int>(
1074  std::round((std::abs(node(1)) - by) / dy));
1075  const double dx = length_b1_x / n_cells_x_1;
1076  const int ix = static_cast<int>(
1077  std::round(std::abs(node(0) - center_mesh) / dx));
1078 
1079  const double alpha = bias_alpha(1 - (1.0 * iy) / n_cells_y);
1080  // define points on upper/lower horizontal far field side,
1081  // i.e. face DG or FI. Incline factor to move points G and I
1082  // to the right by distance incline_facor*lenght_b2
1083  const Point<2> p(ix * dx + center_mesh +
1084  incline_factor * length_b2 * ix /
1085  n_cells_x_1,
1086  ((cell.material_id() == id_block_2) ?
1087  (height) :
1088  (-height)));
1089  // interpolate between y = height and upper airfoil points
1090  // (block2) or y = -height and lower airfoil points (block5)
1091  node = airfoil_1D[(
1092  (cell.material_id() == id_block_2) ? (0) : (1))]
1093  [n_cells_x_0 + ix] *
1094  alpha +
1095  p * (1 - alpha);
1096  }
1097  else if (cell.material_id() == id_block_3 ||
1098  cell.material_id() == id_block_6) // block 3 and 6
1099  {
1100  // compute indices ix and iy
1101  const double dx = length_b2 / n_cells_x_2;
1102  const double dy = height / n_cells_y;
1103  const int ix = static_cast<int>(
1104  std::round(std::abs(node(0) - H(0)) / dx));
1105  const int iy =
1106  static_cast<int>(std::round(std::abs(node(1)) / dy));
1107 
1108  const double alpha_y = bias_alpha(1 - 1.0 * iy / n_cells_y);
1109  const double alpha_x =
1110  bias_alpha(1 - (static_cast<double>(ix)) / n_cells_x_2);
1111  // define on upper/lower horizontal far field side at y =
1112  // +/- height, i.e. face GK or IL incline factor to move
1113  // points G and H to the right
1114  const Point<2> p1(J(0) - (1 - incline_factor) * length_b2 *
1115  (alpha_x),
1116  ((cell.material_id() == id_block_3) ?
1117  (height) :
1118  (-height)));
1119  // define points on HJ but use tail_y as y-coordinate, in
1120  // case last airfoil point has y =/= 0
1121  const Point<2> p2(J(0) - alpha_x * length_b2, tail_y);
1122  node = p1 * (1 - alpha_y) + p2 * alpha_y;
1123  }
1124  else
1125  {
1126  Assert(false,
1127  ExcIndexRange(cell.material_id(),
1128  id_block_1,
1129  id_block_6));
1130  }
1131  }
1132  }
1133 
1134 
1135  /*
1136  * This function returns a bias factor 'alpha' which is used to make the
1137  * mesh more tight in close distance of the airfoil.
1138  * It is a bijective function mapping from [0,1] onto [0,1] where values
1139  * near 1 are made tighter.
1140  */
1141  double
1142  bias_alpha(double alpha) const
1143  {
1144  return std::tanh(bias_factor * alpha) / std::tanh(bias_factor);
1145  }
1146  };
1147  } // namespace
1148 
1149 
1150 
1151  void internal_create_triangulation(
1152  Triangulation<2, 2> & tria,
1153  std::vector<GridTools::PeriodicFacePair<
1154  typename Triangulation<2, 2>::cell_iterator>> *periodic_faces,
1155  const AdditionalData & additional_data)
1156  {
1157  MeshGenerator mesh_generator(additional_data);
1158  // Cast the the triangulation to the right type so that the right
1159  // specialization of the function create_triangulation is picked up.
1160  if (auto parallel_tria =
1162  &tria))
1163  mesh_generator.create_triangulation(*parallel_tria, periodic_faces);
1164  else if (auto parallel_tria = dynamic_cast<
1166  &tria))
1167  mesh_generator.create_triangulation(*parallel_tria, periodic_faces);
1168  else
1169  mesh_generator.create_triangulation(tria, periodic_faces);
1170  }
1171 
1172  template <>
1173  void create_triangulation(Triangulation<1, 1> &, const AdditionalData &)
1174  {
1175  Assert(false, ExcMessage("Airfoils only exist for 2D and 3D!"));
1176  }
1177 
1178 
1179 
1180  template <>
1182  std::vector<GridTools::PeriodicFacePair<
1184  const AdditionalData &)
1185  {
1186  Assert(false, ExcMessage("Airfoils only exist for 2D and 3D!"));
1187  }
1188 
1189 
1190 
1191  template <>
1193  const AdditionalData &additional_data)
1194  {
1195  internal_create_triangulation(tria, nullptr, additional_data);
1196  }
1197 
1198 
1199 
1200  template <>
1201  void create_triangulation(
1202  Triangulation<2, 2> & tria,
1203  std::vector<GridTools::PeriodicFacePair<
1204  typename Triangulation<2, 2>::cell_iterator>> &periodic_faces,
1205  const AdditionalData & additional_data)
1206  {
1207  internal_create_triangulation(tria, &periodic_faces, additional_data);
1208  }
1209 
1210 
1211 
1212  template <>
1213  void create_triangulation(
1214  Triangulation<3, 3> & tria,
1215  std::vector<GridTools::PeriodicFacePair<
1216  typename Triangulation<3, 3>::cell_iterator>> &periodic_faces,
1217  const AdditionalData & additional_data)
1218  {
1219  Assert(false, ExcMessage("3D airfoils are not implemented yet!"));
1220  (void)tria;
1221  (void)additional_data;
1222  (void)periodic_faces;
1223  }
1224  } // namespace Airfoil
1225 
1226 
1227  namespace
1228  {
1233  template <int dim, int spacedim>
1234  void
1235  colorize_hyper_rectangle(Triangulation<dim, spacedim> &tria)
1236  {
1237  // there is nothing to do in 1d
1238  if (dim > 1)
1239  {
1240  // there is only one cell, so
1241  // simple task
1242  const typename Triangulation<dim, spacedim>::cell_iterator cell =
1243  tria.begin();
1244  for (auto f : GeometryInfo<dim>::face_indices())
1245  cell->face(f)->set_boundary_id(f);
1246  }
1247  }
1248 
1249 
1250 
1251  template <int spacedim>
1252  void colorize_subdivided_hyper_rectangle(Triangulation<1, spacedim> &tria,
1253  const Point<spacedim> &,
1254  const Point<spacedim> &,
1255  const double)
1256  {
1257  for (typename Triangulation<1, spacedim>::cell_iterator cell =
1258  tria.begin();
1259  cell != tria.end();
1260  ++cell)
1261  if (cell->center()(0) > 0)
1262  cell->set_material_id(1);
1263  // boundary indicators are set to
1264  // 0 (left) and 1 (right) by default.
1265  }
1266 
1267 
1268 
1269  template <int dim, int spacedim>
1270  void
1271  colorize_subdivided_hyper_rectangle(Triangulation<dim, spacedim> &tria,
1272  const Point<spacedim> & p1,
1273  const Point<spacedim> & p2,
1274  const double epsilon)
1275  {
1276  // run through all faces and check
1277  // if one of their center coordinates matches
1278  // one of the corner points. Comparisons
1279  // are made using an epsilon which
1280  // should be smaller than the smallest cell
1281  // diameter.
1282 
1284  tria.begin_face(),
1285  endface =
1286  tria.end_face();
1287  for (; face != endface; ++face)
1288  if (face->at_boundary())
1289  if (face->boundary_id() == 0)
1290  {
1291  const Point<spacedim> center(face->center());
1292 
1293  if (std::abs(center(0) - p1[0]) < epsilon)
1294  face->set_boundary_id(0);
1295  else if (std::abs(center(0) - p2[0]) < epsilon)
1296  face->set_boundary_id(1);
1297  else if (dim > 1 && std::abs(center(1) - p1[1]) < epsilon)
1298  face->set_boundary_id(2);
1299  else if (dim > 1 && std::abs(center(1) - p2[1]) < epsilon)
1300  face->set_boundary_id(3);
1301  else if (dim > 2 && std::abs(center(2) - p1[2]) < epsilon)
1302  face->set_boundary_id(4);
1303  else if (dim > 2 && std::abs(center(2) - p2[2]) < epsilon)
1304  face->set_boundary_id(5);
1305  else
1306  // triangulation says it
1307  // is on the boundary,
1308  // but we could not find
1309  // on which boundary.
1310  Assert(false, ExcInternalError());
1311  }
1312 
1313  for (const auto &cell : tria.cell_iterators())
1314  {
1315  types::material_id id = 0;
1316  for (unsigned int d = 0; d < dim; ++d)
1317  if (cell->center()(d) > 0)
1318  id += (1 << d);
1319  cell->set_material_id(id);
1320  }
1321  }
1322 
1323 
1328  void colorize_hyper_shell(Triangulation<2> &tria,
1329  const Point<2> &,
1330  const double,
1331  const double)
1332  {
1333  // In spite of receiving geometrical
1334  // data, we do this only based on
1335  // topology.
1336 
1337  // For the mesh based on cube,
1338  // this is highly irregular
1339  for (Triangulation<2>::cell_iterator cell = tria.begin();
1340  cell != tria.end();
1341  ++cell)
1342  {
1343  Assert(cell->face(2)->at_boundary(), ExcInternalError());
1344  cell->face(2)->set_all_boundary_ids(1);
1345  }
1346  }
1347 
1348 
1353  void colorize_hyper_shell(Triangulation<3> &tria,
1354  const Point<3> &,
1355  const double,
1356  const double)
1357  {
1358  // the following uses a good amount
1359  // of knowledge about the
1360  // orientation of cells. this is
1361  // probably not good style...
1362  if (tria.n_cells() == 6)
1363  {
1364  Triangulation<3>::cell_iterator cell = tria.begin();
1365 
1366  Assert(cell->face(4)->at_boundary(), ExcInternalError());
1367  cell->face(4)->set_all_boundary_ids(1);
1368 
1369  ++cell;
1370  Assert(cell->face(2)->at_boundary(), ExcInternalError());
1371  cell->face(2)->set_all_boundary_ids(1);
1372 
1373  ++cell;
1374  Assert(cell->face(2)->at_boundary(), ExcInternalError());
1375  cell->face(2)->set_all_boundary_ids(1);
1376 
1377  ++cell;
1378  Assert(cell->face(0)->at_boundary(), ExcInternalError());
1379  cell->face(0)->set_all_boundary_ids(1);
1380 
1381  ++cell;
1382  Assert(cell->face(2)->at_boundary(), ExcInternalError());
1383  cell->face(2)->set_all_boundary_ids(1);
1384 
1385  ++cell;
1386  Assert(cell->face(0)->at_boundary(), ExcInternalError());
1387  cell->face(0)->set_all_boundary_ids(1);
1388  }
1389  else if (tria.n_cells() == 12)
1390  {
1391  // again use some internal
1392  // knowledge
1393  for (Triangulation<3>::cell_iterator cell = tria.begin();
1394  cell != tria.end();
1395  ++cell)
1396  {
1397  Assert(cell->face(5)->at_boundary(), ExcInternalError());
1398  cell->face(5)->set_all_boundary_ids(1);
1399  }
1400  }
1401  else if (tria.n_cells() == 96)
1402  {
1403  // the 96-cell hypershell is
1404  // based on a once refined
1405  // 12-cell mesh. consequently,
1406  // since the outer faces all
1407  // are face_no==5 above, so
1408  // they are here (unless they
1409  // are in the interior). Use
1410  // this to assign boundary
1411  // indicators, but also make
1412  // sure that we encounter
1413  // exactly 48 such faces
1414  unsigned int count = 0;
1415  for (Triangulation<3>::cell_iterator cell = tria.begin();
1416  cell != tria.end();
1417  ++cell)
1418  if (cell->face(5)->at_boundary())
1419  {
1420  cell->face(5)->set_all_boundary_ids(1);
1421  ++count;
1422  }
1423  Assert(count == 48, ExcInternalError());
1424  }
1425  else
1426  Assert(false, ExcNotImplemented());
1427  }
1428 
1429 
1430 
1436  void colorize_quarter_hyper_shell(Triangulation<3> &tria,
1437  const Point<3> & center,
1438  const double inner_radius,
1439  const double outer_radius)
1440  {
1441  if (tria.n_cells() != 3)
1442  AssertThrow(false, ExcNotImplemented());
1443 
1444  double middle = (outer_radius - inner_radius) / 2e0 + inner_radius;
1445  double eps = 1e-3 * middle;
1446  Triangulation<3>::cell_iterator cell = tria.begin();
1447 
1448  for (; cell != tria.end(); ++cell)
1449  for (unsigned int f : GeometryInfo<3>::face_indices())
1450  {
1451  if (!cell->face(f)->at_boundary())
1452  continue;
1453 
1454  double radius = cell->face(f)->center().norm() - center.norm();
1455  if (std::fabs(cell->face(f)->center()(0)) <
1456  eps) // x = 0 set boundary 2
1457  {
1458  cell->face(f)->set_boundary_id(2);
1459  for (unsigned int j = 0; j < GeometryInfo<3>::lines_per_face;
1460  ++j)
1461  if (cell->face(f)->line(j)->at_boundary())
1462  if (std::fabs(cell->face(f)->line(j)->vertex(0).norm() -
1463  cell->face(f)->line(j)->vertex(1).norm()) >
1464  eps)
1465  cell->face(f)->line(j)->set_boundary_id(2);
1466  }
1467  else if (std::fabs(cell->face(f)->center()(1)) <
1468  eps) // y = 0 set boundary 3
1469  {
1470  cell->face(f)->set_boundary_id(3);
1471  for (unsigned int j = 0; j < GeometryInfo<3>::lines_per_face;
1472  ++j)
1473  if (cell->face(f)->line(j)->at_boundary())
1474  if (std::fabs(cell->face(f)->line(j)->vertex(0).norm() -
1475  cell->face(f)->line(j)->vertex(1).norm()) >
1476  eps)
1477  cell->face(f)->line(j)->set_boundary_id(3);
1478  }
1479  else if (std::fabs(cell->face(f)->center()(2)) <
1480  eps) // z = 0 set boundary 4
1481  {
1482  cell->face(f)->set_boundary_id(4);
1483  for (unsigned int j = 0; j < GeometryInfo<3>::lines_per_face;
1484  ++j)
1485  if (cell->face(f)->line(j)->at_boundary())
1486  if (std::fabs(cell->face(f)->line(j)->vertex(0).norm() -
1487  cell->face(f)->line(j)->vertex(1).norm()) >
1488  eps)
1489  cell->face(f)->line(j)->set_boundary_id(4);
1490  }
1491  else if (radius < middle) // inner radius set boundary 0
1492  {
1493  cell->face(f)->set_boundary_id(0);
1494  for (unsigned int j = 0; j < GeometryInfo<3>::lines_per_face;
1495  ++j)
1496  if (cell->face(f)->line(j)->at_boundary())
1497  if (std::fabs(cell->face(f)->line(j)->vertex(0).norm() -
1498  cell->face(f)->line(j)->vertex(1).norm()) <
1499  eps)
1500  cell->face(f)->line(j)->set_boundary_id(0);
1501  }
1502  else if (radius > middle) // outer radius set boundary 1
1503  {
1504  cell->face(f)->set_boundary_id(1);
1505  for (unsigned int j = 0; j < GeometryInfo<3>::lines_per_face;
1506  ++j)
1507  if (cell->face(f)->line(j)->at_boundary())
1508  if (std::fabs(cell->face(f)->line(j)->vertex(0).norm() -
1509  cell->face(f)->line(j)->vertex(1).norm()) <
1510  eps)
1511  cell->face(f)->line(j)->set_boundary_id(1);
1512  }
1513  else
1514  Assert(false, ExcInternalError());
1515  }
1516  }
1517 
1518  } // namespace
1519 
1520 
1521  template <int dim, int spacedim>
1522  void
1524  const Point<dim> & p_1,
1525  const Point<dim> & p_2,
1526  const bool colorize)
1527  {
1528  // First, extend dimensions from dim to spacedim and
1529  // normalize such that p1 is lower in all coordinate
1530  // directions. Additional entries will be 0.
1531  Point<spacedim> p1, p2;
1532  for (unsigned int i = 0; i < dim; ++i)
1533  {
1534  p1(i) = std::min(p_1(i), p_2(i));
1535  p2(i) = std::max(p_1(i), p_2(i));
1536  }
1537 
1538  std::vector<Point<spacedim>> vertices(GeometryInfo<dim>::vertices_per_cell);
1539  switch (dim)
1540  {
1541  case 1:
1542  vertices[0] = p1;
1543  vertices[1] = p2;
1544  break;
1545  case 2:
1546  vertices[0] = vertices[1] = p1;
1547  vertices[2] = vertices[3] = p2;
1548 
1549  vertices[1](0) = p2(0);
1550  vertices[2](0) = p1(0);
1551  break;
1552  case 3:
1553  vertices[0] = vertices[1] = vertices[2] = vertices[3] = p1;
1554  vertices[4] = vertices[5] = vertices[6] = vertices[7] = p2;
1555 
1556  vertices[1](0) = p2(0);
1557  vertices[2](1) = p2(1);
1558  vertices[3](0) = p2(0);
1559  vertices[3](1) = p2(1);
1560 
1561  vertices[4](0) = p1(0);
1562  vertices[4](1) = p1(1);
1563  vertices[5](1) = p1(1);
1564  vertices[6](0) = p1(0);
1565 
1566  break;
1567  default:
1568  Assert(false, ExcNotImplemented());
1569  }
1570 
1571  // Prepare cell data
1572  std::vector<CellData<dim>> cells(1);
1573  for (const unsigned int i : GeometryInfo<dim>::vertex_indices())
1574  cells[0].vertices[i] = i;
1575  cells[0].material_id = 0;
1576 
1577  tria.create_triangulation(vertices, cells, SubCellData());
1578 
1579  // Assign boundary indicators
1580  if (colorize)
1581  colorize_hyper_rectangle(tria);
1582  }
1583 
1584 
1585 
1586  template <int dim, int spacedim>
1587  void
1589  const double left,
1590  const double right,
1591  const bool colorize)
1592  {
1593  Assert(left < right,
1594  ExcMessage("Invalid left-to-right bounds of hypercube"));
1595 
1596  Point<dim> p1, p2;
1597  for (unsigned int i = 0; i < dim; ++i)
1598  {
1599  p1(i) = left;
1600  p2(i) = right;
1601  }
1602  hyper_rectangle(tria, p1, p2, colorize);
1603  }
1604 
1605 
1606 
1607  template <int dim>
1608  void
1609  simplex(Triangulation<dim> &tria, const std::vector<Point<dim>> &vertices)
1610  {
1611  AssertDimension(vertices.size(), dim + 1);
1612  Assert(dim > 1, ExcNotImplemented());
1613  Assert(dim < 4, ExcNotImplemented());
1614 
1615 # ifdef DEBUG
1616  Tensor<2, dim> vector_matrix;
1617  for (unsigned int d = 0; d < dim; ++d)
1618  for (unsigned int c = 1; c <= dim; ++c)
1619  vector_matrix[c - 1][d] = vertices[c](d) - vertices[0](d);
1620  Assert(determinant(vector_matrix) > 0.,
1621  ExcMessage("Vertices of simplex must form a right handed system"));
1622 # endif
1623 
1624  // Set up the vertices by first copying into points.
1625  std::vector<Point<dim>> points = vertices;
1627  // Compute the edge midpoints and add up everything to compute the
1628  // center point.
1629  for (unsigned int i = 0; i <= dim; ++i)
1630  {
1631  points.push_back(0.5 * (points[i] + points[(i + 1) % (dim + 1)]));
1632  center += points[i];
1633  }
1634  if (dim > 2)
1635  {
1636  // In 3D, we have some more edges to deal with
1637  for (unsigned int i = 1; i < dim; ++i)
1638  points.push_back(0.5 * (points[i - 1] + points[i + 1]));
1639  // And we need face midpoints
1640  for (unsigned int i = 0; i <= dim; ++i)
1641  points.push_back(1. / 3. *
1642  (points[i] + points[(i + 1) % (dim + 1)] +
1643  points[(i + 2) % (dim + 1)]));
1644  }
1645  points.push_back((1. / (dim + 1)) * center);
1646 
1647  std::vector<CellData<dim>> cells(dim + 1);
1648  switch (dim)
1649  {
1650  case 2:
1651  AssertDimension(points.size(), 7);
1652  cells[0].vertices[0] = 0;
1653  cells[0].vertices[1] = 3;
1654  cells[0].vertices[2] = 5;
1655  cells[0].vertices[3] = 6;
1656  cells[0].material_id = 0;
1657 
1658  cells[1].vertices[0] = 3;
1659  cells[1].vertices[1] = 1;
1660  cells[1].vertices[2] = 6;
1661  cells[1].vertices[3] = 4;
1662  cells[1].material_id = 0;
1663 
1664  cells[2].vertices[0] = 5;
1665  cells[2].vertices[1] = 6;
1666  cells[2].vertices[2] = 2;
1667  cells[2].vertices[3] = 4;
1668  cells[2].material_id = 0;
1669  break;
1670  case 3:
1671  AssertDimension(points.size(), 15);
1672  cells[0].vertices[0] = 0;
1673  cells[0].vertices[1] = 4;
1674  cells[0].vertices[2] = 8;
1675  cells[0].vertices[3] = 10;
1676  cells[0].vertices[4] = 7;
1677  cells[0].vertices[5] = 13;
1678  cells[0].vertices[6] = 12;
1679  cells[0].vertices[7] = 14;
1680  cells[0].material_id = 0;
1681 
1682  cells[1].vertices[0] = 4;
1683  cells[1].vertices[1] = 1;
1684  cells[1].vertices[2] = 10;
1685  cells[1].vertices[3] = 5;
1686  cells[1].vertices[4] = 13;
1687  cells[1].vertices[5] = 9;
1688  cells[1].vertices[6] = 14;
1689  cells[1].vertices[7] = 11;
1690  cells[1].material_id = 0;
1691 
1692  cells[2].vertices[0] = 8;
1693  cells[2].vertices[1] = 10;
1694  cells[2].vertices[2] = 2;
1695  cells[2].vertices[3] = 5;
1696  cells[2].vertices[4] = 12;
1697  cells[2].vertices[5] = 14;
1698  cells[2].vertices[6] = 6;
1699  cells[2].vertices[7] = 11;
1700  cells[2].material_id = 0;
1701 
1702  cells[3].vertices[0] = 7;
1703  cells[3].vertices[1] = 13;
1704  cells[3].vertices[2] = 12;
1705  cells[3].vertices[3] = 14;
1706  cells[3].vertices[4] = 3;
1707  cells[3].vertices[5] = 9;
1708  cells[3].vertices[6] = 6;
1709  cells[3].vertices[7] = 11;
1710  cells[3].material_id = 0;
1711  break;
1712  default:
1713  Assert(false, ExcNotImplemented());
1714  }
1715  tria.create_triangulation(points, cells, SubCellData());
1716  }
1717 
1718 
1719 
1720  template <int dim, int spacedim>
1721  void
1723  const ReferenceCell & reference_cell)
1724  {
1725  AssertDimension(dim, reference_cell.get_dimension());
1726 
1727  if (reference_cell == ReferenceCells::get_hypercube<dim>())
1728  {
1729  GridGenerator::hyper_cube(tria, 0, 1);
1730  }
1731  else if ((dim == 2) && (reference_cell == ReferenceCells::Triangle))
1732  {
1733  const std::vector<Point<spacedim>> vertices = {
1734  Point<spacedim>(), // the origin
1735  Point<spacedim>::unit_vector(0), // unit point along x-axis
1736  Point<spacedim>::unit_vector(1) // unit point along y-axis
1737  };
1738 
1739  std::vector<CellData<dim>> cells(1);
1740  cells[0].vertices = {0, 1, 2};
1741 
1742  tria.create_triangulation(vertices, cells, {});
1743  }
1744  else if ((dim == 3) && (reference_cell == ReferenceCells::Tetrahedron))
1745  {
1746  AssertDimension(spacedim, 3);
1747 
1748  static const std::vector<Point<spacedim>> vertices = {
1749  {{0.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {0.0, 0.0, 1.0}}};
1750 
1751  std::vector<CellData<dim>> cells(1);
1752  cells[0].vertices = {0, 1, 2, 3};
1753 
1754  tria.create_triangulation(vertices, cells, {});
1755  }
1756  else if ((dim == 3) && (reference_cell == ReferenceCells::Pyramid))
1757  {
1758  AssertDimension(spacedim, 3);
1759 
1760  static const std::vector<Point<spacedim>> vertices = {
1761  {{-1.0, -1.0, 0.0},
1762  {+1.0, -1.0, 0.0},
1763  {-1.0, +1.0, 0.0},
1764  {+1.0, +1.0, 0.0},
1765  {+0.0, +0.0, 1.0}}};
1766 
1767  std::vector<CellData<dim>> cells(1);
1768  cells[0].vertices = {0, 1, 2, 3, 4};
1769 
1770  tria.create_triangulation(vertices, cells, {});
1771  }
1772  else if ((dim == 3) && (reference_cell == ReferenceCells::Wedge))
1773  {
1774  AssertDimension(spacedim, 3);
1775 
1776  static const std::vector<Point<spacedim>> vertices = {
1777  {{1.0, 0.0, 0.0},
1778  {0.0, 1.0, 0.0},
1779  {0.0, 0.0, 0.0},
1780  {1.0, 0.0, 1.0},
1781  {0.0, 1.0, 1.0},
1782  {0.0, 0.0, 1.0}}};
1783 
1784  std::vector<CellData<dim>> cells(1);
1785  cells[0].vertices = {0, 1, 2, 3, 4, 5};
1786 
1787  tria.create_triangulation(vertices, cells, {});
1788  }
1789  else
1790  {
1791  Assert(false, ExcNotImplemented());
1792  }
1793  }
1794 
1795  void moebius(Triangulation<3> & tria,
1796  const unsigned int n_cells,
1797  const unsigned int n_rotations,
1798  const double R,
1799  const double r)
1800  {
1801  const unsigned int dim = 3;
1802  Assert(n_cells > 4,
1803  ExcMessage(
1804  "More than 4 cells are needed to create a moebius grid."));
1805  Assert(r > 0 && R > 0,
1806  ExcMessage("Outer and inner radius must be positive."));
1807  Assert(R > r,
1808  ExcMessage("Outer radius must be greater than inner radius."));
1809 
1810 
1811  std::vector<Point<dim>> vertices(4 * n_cells);
1812  double beta_step = n_rotations * numbers::PI / 2.0 / n_cells;
1813  double alpha_step = 2.0 * numbers::PI / n_cells;
1814 
1815  for (unsigned int i = 0; i < n_cells; ++i)
1816  for (unsigned int j = 0; j < 4; ++j)
1817  {
1818  vertices[4 * i + j][0] =
1819  R * std::cos(i * alpha_step) +
1820  r * std::cos(i * beta_step + j * numbers::PI / 2.0) *
1821  std::cos(i * alpha_step);
1822  vertices[4 * i + j][1] =
1823  R * std::sin(i * alpha_step) +
1824  r * std::cos(i * beta_step + j * numbers::PI / 2.0) *
1825  std::sin(i * alpha_step);
1826  vertices[4 * i + j][2] =
1827  r * std::sin(i * beta_step + j * numbers::PI / 2.0);
1828  }
1829 
1830  unsigned int offset = 0;
1831 
1832  // This Triangulation is constructed using the UCD numbering scheme since,
1833  // in that numbering, the front face is first and the back face is second,
1834  // which is more convenient for creating a moebius
1835  std::vector<CellData<dim>> cells(n_cells);
1836  for (unsigned int i = 0; i < n_cells; ++i)
1837  {
1838  for (unsigned int j = 0; j < 2; ++j)
1839  {
1840  cells[i].vertices[GeometryInfo<3>::ucd_to_deal[0 + 4 * j]] =
1841  offset + 0 + 4 * j;
1842  cells[i].vertices[GeometryInfo<3>::ucd_to_deal[1 + 4 * j]] =
1843  offset + 3 + 4 * j;
1844  cells[i].vertices[GeometryInfo<3>::ucd_to_deal[2 + 4 * j]] =
1845  offset + 2 + 4 * j;
1846  cells[i].vertices[GeometryInfo<3>::ucd_to_deal[3 + 4 * j]] =
1847  offset + 1 + 4 * j;
1848  }
1849  offset += 4;
1850  cells[i].material_id = 0;
1851  }
1852 
1853  // now correct the last four vertices
1854  cells[n_cells - 1].vertices[GeometryInfo<3>::ucd_to_deal[4]] =
1855  (0 + n_rotations) % 4;
1856  cells[n_cells - 1].vertices[GeometryInfo<3>::ucd_to_deal[5]] =
1857  (3 + n_rotations) % 4;
1858  cells[n_cells - 1].vertices[GeometryInfo<3>::ucd_to_deal[6]] =
1859  (2 + n_rotations) % 4;
1860  cells[n_cells - 1].vertices[GeometryInfo<3>::ucd_to_deal[7]] =
1861  (1 + n_rotations) % 4;
1862 
1864  tria.create_triangulation(vertices, cells, SubCellData());
1865  }
1866 
1867 
1868 
1869  template <>
1870  void torus<2, 3>(Triangulation<2, 3> &tria,
1871  const double R,
1872  const double r,
1873  const unsigned int,
1874  const double)
1875  {
1876  Assert(R > r,
1877  ExcMessage("Outer radius R must be greater than the inner "
1878  "radius r."));
1879  Assert(r > 0.0, ExcMessage("The inner radius r must be positive."));
1880 
1881  const unsigned int dim = 2;
1882  const unsigned int spacedim = 3;
1883  std::vector<Point<spacedim>> vertices(16);
1884 
1885  vertices[0] = Point<spacedim>(R - r, 0, 0);
1886  vertices[1] = Point<spacedim>(R, -r, 0);
1887  vertices[2] = Point<spacedim>(R + r, 0, 0);
1888  vertices[3] = Point<spacedim>(R, r, 0);
1889  vertices[4] = Point<spacedim>(0, 0, R - r);
1890  vertices[5] = Point<spacedim>(0, -r, R);
1891  vertices[6] = Point<spacedim>(0, 0, R + r);
1892  vertices[7] = Point<spacedim>(0, r, R);
1893  vertices[8] = Point<spacedim>(-(R - r), 0, 0);
1894  vertices[9] = Point<spacedim>(-R, -r, 0);
1895  vertices[10] = Point<spacedim>(-(R + r), 0, 0);
1896  vertices[11] = Point<spacedim>(-R, r, 0);
1897  vertices[12] = Point<spacedim>(0, 0, -(R - r));
1898  vertices[13] = Point<spacedim>(0, -r, -R);
1899  vertices[14] = Point<spacedim>(0, 0, -(R + r));
1900  vertices[15] = Point<spacedim>(0, r, -R);
1901 
1902  std::vector<CellData<dim>> cells(16);
1903  // Right Hand Orientation
1904  cells[0].vertices[0] = 0;
1905  cells[0].vertices[1] = 4;
1906  cells[0].vertices[2] = 3;
1907  cells[0].vertices[3] = 7;
1908  cells[0].material_id = 0;
1909 
1910  cells[1].vertices[0] = 1;
1911  cells[1].vertices[1] = 5;
1912  cells[1].vertices[2] = 0;
1913  cells[1].vertices[3] = 4;
1914  cells[1].material_id = 0;
1915 
1916  cells[2].vertices[0] = 2;
1917  cells[2].vertices[1] = 6;
1918  cells[2].vertices[2] = 1;
1919  cells[2].vertices[3] = 5;
1920  cells[2].material_id = 0;
1921 
1922  cells[3].vertices[0] = 3;
1923  cells[3].vertices[1] = 7;
1924  cells[3].vertices[2] = 2;
1925  cells[3].vertices[3] = 6;
1926  cells[3].material_id = 0;
1927 
1928  cells[4].vertices[0] = 4;
1929  cells[4].vertices[1] = 8;
1930  cells[4].vertices[2] = 7;
1931  cells[4].vertices[3] = 11;
1932  cells[4].material_id = 0;
1933 
1934  cells[5].vertices[0] = 5;
1935  cells[5].vertices[1] = 9;
1936  cells[5].vertices[2] = 4;
1937  cells[5].vertices[3] = 8;
1938  cells[5].material_id = 0;
1939 
1940  cells[6].vertices[0] = 6;
1941  cells[6].vertices[1] = 10;
1942  cells[6].vertices[2] = 5;
1943  cells[6].vertices[3] = 9;
1944  cells[6].material_id = 0;
1945 
1946  cells[7].vertices[0] = 7;
1947  cells[7].vertices[1] = 11;
1948  cells[7].vertices[2] = 6;
1949  cells[7].vertices[3] = 10;
1950  cells[7].material_id = 0;
1951 
1952  cells[8].vertices[0] = 8;
1953  cells[8].vertices[1] = 12;
1954  cells[8].vertices[2] = 11;
1955  cells[8].vertices[3] = 15;
1956  cells[8].material_id = 0;
1957 
1958  cells[9].vertices[0] = 9;
1959  cells[9].vertices[1] = 13;
1960  cells[9].vertices[2] = 8;
1961  cells[9].vertices[3] = 12;
1962  cells[9].material_id = 0;
1963 
1964  cells[10].vertices[0] = 10;
1965  cells[10].vertices[1] = 14;
1966  cells[10].vertices[2] = 9;
1967  cells[10].vertices[3] = 13;
1968  cells[10].material_id = 0;
1969 
1970  cells[11].vertices[0] = 11;
1971  cells[11].vertices[1] = 15;
1972  cells[11].vertices[2] = 10;
1973  cells[11].vertices[3] = 14;
1974  cells[11].material_id = 0;
1975 
1976  cells[12].vertices[0] = 12;
1977  cells[12].vertices[1] = 0;
1978  cells[12].vertices[2] = 15;
1979  cells[12].vertices[3] = 3;
1980  cells[12].material_id = 0;
1981 
1982  cells[13].vertices[0] = 13;
1983  cells[13].vertices[1] = 1;
1984  cells[13].vertices[2] = 12;
1985  cells[13].vertices[3] = 0;
1986  cells[13].material_id = 0;
1987 
1988  cells[14].vertices[0] = 14;
1989  cells[14].vertices[1] = 2;
1990  cells[14].vertices[2] = 13;
1991  cells[14].vertices[3] = 1;
1992  cells[14].material_id = 0;
1993 
1994  cells[15].vertices[0] = 15;
1995  cells[15].vertices[1] = 3;
1996  cells[15].vertices[2] = 14;
1997  cells[15].vertices[3] = 2;
1998  cells[15].material_id = 0;
1999 
2001  tria.create_triangulation(vertices, cells, SubCellData());
2002 
2003  tria.set_all_manifold_ids(0);
2004  tria.set_manifold(0, TorusManifold<2>(R, r));
2005  }
2006 
2007 
2008 
2009  template <>
2010  void torus<3, 3>(Triangulation<3, 3> &tria,
2011  const double R,
2012  const double r,
2013  const unsigned int n_cells_toroidal,
2014  const double phi)
2015  {
2016  Assert(R > r,
2017  ExcMessage("Outer radius R must be greater than the inner "
2018  "radius r."));
2019  Assert(r > 0.0, ExcMessage("The inner radius r must be positive."));
2020  Assert(n_cells_toroidal > 2,
2021  ExcMessage("Number of cells in toroidal direction has "
2022  "to be at least 3."));
2023  AssertThrow(phi > 0.0 && phi < 2.0 * numbers::PI + 1.0e-15,
2024  ExcMessage("Invalid angle phi specified."));
2025 
2026  // the first 8 vertices are in the x-y-plane
2027  Point<3> const p = Point<3>(R, 0.0, 0.0);
2028  double const a = 1. / (1 + std::sqrt(2.0));
2029  // A value of 1 indicates "open" torus with angle < 2*pi, which
2030  // means that we need an additional layer of vertices
2031  const unsigned int additional_layer =
2032  (phi < 2.0 * numbers::PI - 1.0e-15) ?
2033  1 :
2034  0; // torus is closed (angle of 2*pi)
2035  const unsigned int n_point_layers_toroidal =
2036  n_cells_toroidal + additional_layer;
2037  std::vector<Point<3>> vertices(8 * n_point_layers_toroidal);
2038  vertices[0] = p + Point<3>(-1, -1, 0) * (r / std::sqrt(2.0)),
2039  vertices[1] = p + Point<3>(+1, -1, 0) * (r / std::sqrt(2.0)),
2040  vertices[2] = p + Point<3>(-1, -1, 0) * (r / std::sqrt(2.0) * a),
2041  vertices[3] = p + Point<3>(+1, -1, 0) * (r / std::sqrt(2.0) * a),
2042  vertices[4] = p + Point<3>(-1, +1, 0) * (r / std::sqrt(2.0) * a),
2043  vertices[5] = p + Point<3>(+1, +1, 0) * (r / std::sqrt(2.0) * a),
2044  vertices[6] = p + Point<3>(-1, +1, 0) * (r / std::sqrt(2.0)),
2045  vertices[7] = p + Point<3>(+1, +1, 0) * (r / std::sqrt(2.0));
2046 
2047  // create remaining vertices by rotating around negative y-axis (the
2048  // direction is to ensure positive cell measures)
2049  double const phi_cell = phi / n_cells_toroidal;
2050  for (unsigned int c = 1; c < n_point_layers_toroidal; ++c)
2051  {
2052  for (unsigned int v = 0; v < 8; ++v)
2053  {
2054  double const r_2d = vertices[v][0];
2055  vertices[8 * c + v][0] = r_2d * std::cos(phi_cell * c);
2056  vertices[8 * c + v][1] = vertices[v][1];
2057  vertices[8 * c + v][2] = r_2d * std::sin(phi_cell * c);
2058  }
2059  }
2060 
2061  // cell connectivity
2062  std::vector<CellData<3>> cells(5 * n_cells_toroidal);
2063  for (unsigned int c = 0; c < n_cells_toroidal; ++c)
2064  {
2065  for (unsigned int j = 0; j < 2; ++j)
2066  {
2067  const unsigned int offset =
2068  (8 * (c + j)) % (8 * n_point_layers_toroidal);
2069 
2070  // cell 0 in x-y-plane
2071  cells[5 * c].vertices[0 + j * 4] = offset + 0;
2072  cells[5 * c].vertices[1 + j * 4] = offset + 1;
2073  cells[5 * c].vertices[2 + j * 4] = offset + 2;
2074  cells[5 * c].vertices[3 + j * 4] = offset + 3;
2075  // cell 1 in x-y-plane (cell on torus centerline)
2076  cells[5 * c + 1].vertices[0 + j * 4] = offset + 2;
2077  cells[5 * c + 1].vertices[1 + j * 4] = offset + 3;
2078  cells[5 * c + 1].vertices[2 + j * 4] = offset + 4;
2079  cells[5 * c + 1].vertices[3 + j * 4] = offset + 5;
2080  // cell 2 in x-y-plane
2081  cells[5 * c + 2].vertices[0 + j * 4] = offset + 4;
2082  cells[5 * c + 2].vertices[1 + j * 4] = offset + 5;
2083  cells[5 * c + 2].vertices[2 + j * 4] = offset + 6;
2084  cells[5 * c + 2].vertices[3 + j * 4] = offset + 7;
2085  // cell 3 in x-y-plane
2086  cells[5 * c + 3].vertices[0 + j * 4] = offset + 0;
2087  cells[5 * c + 3].vertices[1 + j * 4] = offset + 2;
2088  cells[5 * c + 3].vertices[2 + j * 4] = offset + 6;
2089  cells[5 * c + 3].vertices[3 + j * 4] = offset + 4;
2090  // cell 4 in x-y-plane
2091  cells[5 * c + 4].vertices[0 + j * 4] = offset + 3;
2092  cells[5 * c + 4].vertices[1 + j * 4] = offset + 1;
2093  cells[5 * c + 4].vertices[2 + j * 4] = offset + 5;
2094  cells[5 * c + 4].vertices[3 + j * 4] = offset + 7;
2095  }
2096 
2097  cells[5 * c].material_id = 0;
2098  // mark cell on torus centerline
2099  cells[5 * c + 1].material_id = 1;
2100  cells[5 * c + 2].material_id = 0;
2101  cells[5 * c + 3].material_id = 0;
2102  cells[5 * c + 4].material_id = 0;
2103  }
2104 
2105  tria.create_triangulation(vertices, cells, SubCellData());
2106 
2107  tria.reset_all_manifolds();
2108  tria.set_all_manifold_ids(0);
2109 
2110  for (auto &cell : tria.cell_iterators())
2111  {
2112  // identify faces on torus surface and set manifold to 1
2113  for (unsigned int f : GeometryInfo<3>::face_indices())
2114  {
2115  // faces 4 and 5 are those with normal vector aligned with torus
2116  // centerline
2117  if (cell->face(f)->at_boundary() && f != 4 && f != 5)
2118  {
2119  cell->face(f)->set_all_manifold_ids(1);
2120  }
2121  }
2122 
2123  // set manifold id to 2 for those cells that are on the torus centerline
2124  if (cell->material_id() == 1)
2125  {
2126  cell->set_all_manifold_ids(2);
2127  // reset to 0
2128  cell->set_material_id(0);
2129  }
2130  }
2131 
2132  tria.set_manifold(1, TorusManifold<3>(R, r));
2133  tria.set_manifold(2,
2134  CylindricalManifold<3>(Tensor<1, 3>({0., 1., 0.}),
2135  Point<3>()));
2137  transfinite.initialize(tria);
2138  tria.set_manifold(0, transfinite);
2139  }
2140 
2141 
2142 
2143  template <int dim, int spacedim>
2144  void
2146  const std::vector<Point<spacedim>> &vertices,
2147  const bool colorize)
2148  {
2150  ExcMessage("Wrong number of vertices."));
2151 
2152  // First create a hyper_rectangle and then deform it.
2153  hyper_cube(tria, 0, 1, colorize);
2154 
2156  tria.begin_active();
2157  for (const unsigned int i : GeometryInfo<dim>::vertex_indices())
2158  cell->vertex(i) = vertices[i];
2159 
2160  // Check that the order of the vertices makes sense, i.e., the volume of the
2161  // cell is positive.
2163  ExcMessage(
2164  "The volume of the cell is not greater than zero. "
2165  "This could be due to the wrong ordering of the vertices."));
2166  }
2167 
2168 
2169 
2170  template <>
2172  const Point<3> (&/*corners*/)[3],
2173  const bool /*colorize*/)
2174  {
2175  Assert(false, ExcNotImplemented());
2176  }
2177 
2178  template <>
2180  const Point<1> (&/*corners*/)[1],
2181  const bool /*colorize*/)
2182  {
2183  Assert(false, ExcNotImplemented());
2184  }
2185 
2186  // Implementation for 2D only
2187  template <>
2188  void parallelogram(Triangulation<2> &tria,
2189  const Point<2> (&corners)[2],
2190  const bool colorize)
2191  {
2192  Point<2> origin;
2193  std::array<Tensor<1, 2>, 2> edges;
2194  edges[0] = corners[0];
2195  edges[1] = corners[1];
2196  std::vector<unsigned int> subdivisions;
2197  subdivided_parallelepiped<2, 2>(
2198  tria, origin, edges, subdivisions, colorize);
2199  }
2200 
2201 
2202 
2203  template <int dim>
2204  void
2206  const Point<dim> (&corners)[dim],
2207  const bool colorize)
2208  {
2209  unsigned int n_subdivisions[dim];
2210  for (unsigned int i = 0; i < dim; ++i)
2211  n_subdivisions[i] = 1;
2212 
2213  // and call the function below
2214  subdivided_parallelepiped(tria, n_subdivisions, corners, colorize);
2215  }
2216 
2217  template <int dim>
2218  void
2220  const unsigned int n_subdivisions,
2221  const Point<dim> (&corners)[dim],
2222  const bool colorize)
2223  {
2224  // Equalize number of subdivisions in each dim-direction, their
2225  // validity will be checked later
2226  unsigned int n_subdivisions_[dim];
2227  for (unsigned int i = 0; i < dim; ++i)
2228  n_subdivisions_[i] = n_subdivisions;
2229 
2230  // and call the function below
2231  subdivided_parallelepiped(tria, n_subdivisions_, corners, colorize);
2232  }
2233 
2234  template <int dim>
2235  void
2237 # ifndef _MSC_VER
2238  const unsigned int (&n_subdivisions)[dim],
2239 # else
2240  const unsigned int *n_subdivisions,
2241 # endif
2242  const Point<dim> (&corners)[dim],
2243  const bool colorize)
2244  {
2245  Point<dim> origin;
2246  std::vector<unsigned int> subdivisions;
2247  std::array<Tensor<1, dim>, dim> edges;
2248  for (unsigned int i = 0; i < dim; ++i)
2249  {
2250  subdivisions.push_back(n_subdivisions[i]);
2251  edges[i] = corners[i];
2252  }
2253 
2254  subdivided_parallelepiped<dim, dim>(
2255  tria, origin, edges, subdivisions, colorize);
2256  }
2257 
2258  // Parallelepiped implementation in 1d, 2d, and 3d. @note The
2259  // implementation in 1d is similar to hyper_rectangle(), and in 2d is
2260  // similar to parallelogram().
2261  template <int dim, int spacedim>
2262  void
2264  const Point<spacedim> & origin,
2265  const std::array<Tensor<1, spacedim>, dim> &edges,
2266  const std::vector<unsigned int> &subdivisions,
2267  const bool colorize)
2268  {
2269  std::vector<unsigned int> compute_subdivisions = subdivisions;
2270  if (compute_subdivisions.size() == 0)
2271  {
2272  compute_subdivisions.resize(dim, 1);
2273  }
2274 
2275  Assert(compute_subdivisions.size() == dim,
2276  ExcMessage("One subdivision must be provided for each dimension."));
2277  // check subdivisions
2278  for (unsigned int i = 0; i < dim; ++i)
2279  {
2280  Assert(compute_subdivisions[i] > 0,
2281  ExcInvalidRepetitions(subdivisions[i]));
2282  Assert(
2283  edges[i].norm() > 0,
2284  ExcMessage(
2285  "Edges in subdivided_parallelepiped() must not be degenerate."));
2286  }
2287 
2288  /*
2289  * Verify that the edge points to the right in 1D, vectors are oriented in
2290  * a counter clockwise direction in 2D, or form a right handed system in
2291  * 3D.
2292  */
2293  bool twisted_data = false;
2294  switch (dim)
2295  {
2296  case 1:
2297  {
2298  twisted_data = (edges[0][0] < 0);
2299  break;
2300  }
2301  case 2:
2302  {
2303  if (spacedim == 2) // this check does not make sense otherwise
2304  {
2305  const double plane_normal =
2306  edges[0][0] * edges[1][1] - edges[0][1] * edges[1][0];
2307  twisted_data = (plane_normal < 0.0);
2308  }
2309  break;
2310  }
2311  case 3:
2312  {
2313  // Check that the first two vectors are not linear combinations to
2314  // avoid zero division later on.
2315  Assert(std::abs(edges[0] * edges[1] /
2316  (edges[0].norm() * edges[1].norm()) -
2317  1.0) > 1.0e-15,
2318  ExcMessage(
2319  "Edges in subdivided_parallelepiped() must point in"
2320  " different directions."));
2321  const Tensor<1, spacedim> plane_normal =
2322  cross_product_3d(edges[0], edges[1]);
2323 
2324  /*
2325  * Ensure that edges 1, 2, and 3 form a right-handed set of
2326  * vectors. This works by applying the definition of the dot product
2327  *
2328  * cos(theta) = dot(x, y)/(norm(x)*norm(y))
2329  *
2330  * and then, since the normal vector and third edge should both
2331  * point away from the plane formed by the first two edges, the
2332  * angle between them must be between 0 and pi/2; hence we just need
2333  *
2334  * 0 < dot(x, y).
2335  */
2336  twisted_data = (plane_normal * edges[2] < 0.0);
2337  break;
2338  }
2339  default:
2340  Assert(false, ExcInternalError());
2341  }
2342  (void)twisted_data; // make the static analyzer happy
2343  Assert(
2344  !twisted_data,
2346  "The triangulation you are trying to create will consist of cells"
2347  " with negative measures. This is usually the result of input data"
2348  " that does not define a right-handed coordinate system. The usual"
2349  " fix for this is to ensure that in 1D the given point is to the"
2350  " right of the origin (or the given edge tensor is positive), in 2D"
2351  " that the two edges (and their cross product) obey the right-hand"
2352  " rule (which may usually be done by switching the order of the"
2353  " points or edge tensors), or in 3D that the edges form a"
2354  " right-handed coordinate system (which may also be accomplished by"
2355  " switching the order of the first two points or edge tensors)."));
2356 
2357  // Check corners do not overlap (unique)
2358  for (unsigned int i = 0; i < dim; ++i)
2359  for (unsigned int j = i + 1; j < dim; ++j)
2360  Assert((edges[i] != edges[j]),
2361  ExcMessage(
2362  "Degenerate edges of subdivided_parallelepiped encountered."));
2363 
2364  // Create a list of points
2365  std::vector<Point<spacedim>> points;
2366 
2367  switch (dim)
2368  {
2369  case 1:
2370  for (unsigned int x = 0; x <= compute_subdivisions[0]; ++x)
2371  points.push_back(origin + edges[0] / compute_subdivisions[0] * x);
2372  break;
2373 
2374  case 2:
2375  for (unsigned int y = 0; y <= compute_subdivisions[1]; ++y)
2376  for (unsigned int x = 0; x <= compute_subdivisions[0]; ++x)
2377  points.push_back(origin + edges[0] / compute_subdivisions[0] * x +
2378  edges[1] / compute_subdivisions[1] * y);
2379  break;
2380 
2381  case 3:
2382  for (unsigned int z = 0; z <= compute_subdivisions[2]; ++z)
2383  for (unsigned int y = 0; y <= compute_subdivisions[1]; ++y)
2384  for (unsigned int x = 0; x <= compute_subdivisions[0]; ++x)
2385  points.push_back(origin +
2386  edges[0] / compute_subdivisions[0] * x +
2387  edges[1] / compute_subdivisions[1] * y +
2388  edges[2] / compute_subdivisions[2] * z);
2389  break;
2390 
2391  default:
2392  Assert(false, ExcNotImplemented());
2393  }
2394 
2395  // Prepare cell data
2396  unsigned int n_cells = 1;
2397  for (unsigned int i = 0; i < dim; ++i)
2398  n_cells *= compute_subdivisions[i];
2399  std::vector<CellData<dim>> cells(n_cells);
2400 
2401  // Create fixed ordering of
2402  switch (dim)
2403  {
2404  case 1:
2405  for (unsigned int x = 0; x < compute_subdivisions[0]; ++x)
2406  {
2407  cells[x].vertices[0] = x;
2408  cells[x].vertices[1] = x + 1;
2409 
2410  // wipe material id
2411  cells[x].material_id = 0;
2412  }
2413  break;
2414 
2415  case 2:
2416  {
2417  // Shorthand
2418  const unsigned int n_dy = compute_subdivisions[1];
2419  const unsigned int n_dx = compute_subdivisions[0];
2420 
2421  for (unsigned int y = 0; y < n_dy; ++y)
2422  for (unsigned int x = 0; x < n_dx; ++x)
2423  {
2424  const unsigned int c = y * n_dx + x;
2425  cells[c].vertices[0] = y * (n_dx + 1) + x;
2426  cells[c].vertices[1] = y * (n_dx + 1) + x + 1;
2427  cells[c].vertices[2] = (y + 1) * (n_dx + 1) + x;
2428  cells[c].vertices[3] = (y + 1) * (n_dx + 1) + x + 1;
2429 
2430  // wipe material id
2431  cells[c].material_id = 0;
2432  }
2433  }
2434  break;
2435 
2436  case 3:
2437  {
2438  // Shorthand
2439  const unsigned int n_dz = compute_subdivisions[2];
2440  const unsigned int n_dy = compute_subdivisions[1];
2441  const unsigned int n_dx = compute_subdivisions[0];
2442 
2443  for (unsigned int z = 0; z < n_dz; ++z)
2444  for (unsigned int y = 0; y < n_dy; ++y)
2445  for (unsigned int x = 0; x < n_dx; ++x)
2446  {
2447  const unsigned int c = z * n_dy * n_dx + y * n_dx + x;
2448 
2449  cells[c].vertices[0] =
2450  z * (n_dy + 1) * (n_dx + 1) + y * (n_dx + 1) + x;
2451  cells[c].vertices[1] =
2452  z * (n_dy + 1) * (n_dx + 1) + y * (n_dx + 1) + x + 1;
2453  cells[c].vertices[2] =
2454  z * (n_dy + 1) * (n_dx + 1) + (y + 1) * (n_dx + 1) + x;
2455  cells[c].vertices[3] = z * (n_dy + 1) * (n_dx + 1) +
2456  (y + 1) * (n_dx + 1) + x + 1;
2457  cells[c].vertices[4] =
2458  (z + 1) * (n_dy + 1) * (n_dx + 1) + y * (n_dx + 1) + x;
2459  cells[c].vertices[5] = (z + 1) * (n_dy + 1) * (n_dx + 1) +
2460  y * (n_dx + 1) + x + 1;
2461  cells[c].vertices[6] = (z + 1) * (n_dy + 1) * (n_dx + 1) +
2462  (y + 1) * (n_dx + 1) + x;
2463  cells[c].vertices[7] = (z + 1) * (n_dy + 1) * (n_dx + 1) +
2464  (y + 1) * (n_dx + 1) + x + 1;
2465 
2466  // wipe material id
2467  cells[c].material_id = 0;
2468  }
2469  break;
2470  }
2471 
2472  default:
2473  Assert(false, ExcNotImplemented());
2474  }
2475 
2476  // Create triangulation
2477  // reorder the cells to ensure that they satisfy the convention for
2478  // edge and face directions
2480  tria.create_triangulation(points, cells, SubCellData());
2481 
2482  // Finally assign boundary indicators according to hyper_rectangle
2483  if (colorize)
2484  {
2486  tria.begin_active(),
2487  endc = tria.end();
2488  for (; cell != endc; ++cell)
2489  {
2490  for (const unsigned int face : GeometryInfo<dim>::face_indices())
2491  {
2492  if (cell->face(face)->at_boundary())
2493  cell->face(face)->set_boundary_id(face);
2494  }
2495  }
2496  }
2497  }
2498 
2499 
2500  template <int dim, int spacedim>
2501  void
2503  const unsigned int repetitions,
2504  const double left,
2505  const double right,
2506  const bool colorize)
2507  {
2508  Assert(repetitions >= 1, ExcInvalidRepetitions(repetitions));
2509  Assert(left < right,
2510  ExcMessage("Invalid left-to-right bounds of hypercube"));
2511 
2512  Point<dim> p0, p1;
2513  for (unsigned int i = 0; i < dim; ++i)
2514  {
2515  p0[i] = left;
2516  p1[i] = right;
2517  }
2518 
2519  std::vector<unsigned int> reps(dim, repetitions);
2520  subdivided_hyper_rectangle(tria, reps, p0, p1, colorize);
2521  }
2522 
2523 
2524 
2525  template <int dim, int spacedim>
2526  void
2528  const std::vector<unsigned int> &repetitions,
2529  const Point<dim> & p_1,
2530  const Point<dim> & p_2,
2531  const bool colorize)
2532  {
2533  Assert(repetitions.size() == dim, ExcInvalidRepetitionsDimension(dim));
2534 
2535  // First, extend dimensions from dim to spacedim and
2536  // normalize such that p1 is lower in all coordinate
2537  // directions. Additional entries will be 0.
2538  Point<spacedim> p1, p2;
2539  for (unsigned int i = 0; i < dim; ++i)
2540  {
2541  p1(i) = std::min(p_1(i), p_2(i));
2542  p2(i) = std::max(p_1(i), p_2(i));
2543  }
2544 
2545  // calculate deltas and validate input
2546  std::vector<Point<spacedim>> delta(dim);
2547  for (unsigned int i = 0; i < dim; ++i)
2548  {
2549  Assert(repetitions[i] >= 1, ExcInvalidRepetitions(repetitions[i]));
2550 
2551  delta[i][i] = (p2[i] - p1[i]) / repetitions[i];
2552  Assert(
2553  delta[i][i] > 0.0,
2554  ExcMessage(
2555  "The first dim entries of coordinates of p1 and p2 need to be different."));
2556  }
2557 
2558  // then generate the points
2559  std::vector<Point<spacedim>> points;
2560  switch (dim)
2561  {
2562  case 1:
2563  for (unsigned int x = 0; x <= repetitions[0]; ++x)
2564  points.push_back(p1 + x * delta[0]);
2565  break;
2566 
2567  case 2:
2568  for (unsigned int y = 0; y <= repetitions[1]; ++y)
2569  for (unsigned int x = 0; x <= repetitions[0]; ++x)
2570  points.push_back(p1 + x * delta[0] + y * delta[1]);
2571  break;
2572 
2573  case 3:
2574  for (unsigned int z = 0; z <= repetitions[2]; ++z)
2575  for (unsigned int y = 0; y <= repetitions[1]; ++y)
2576  for (unsigned int x = 0; x <= repetitions[0]; ++x)
2577  points.push_back(p1 + x * delta[0] + y * delta[1] +
2578  z * delta[2]);
2579  break;
2580 
2581  default:
2582  Assert(false, ExcNotImplemented());
2583  }
2584 
2585  // next create the cells
2586  std::vector<CellData<dim>> cells;
2587  switch (dim)
2588  {
2589  case 1:
2590  {
2591  cells.resize(repetitions[0]);
2592  for (unsigned int x = 0; x < repetitions[0]; ++x)
2593  {
2594  cells[x].vertices[0] = x;
2595  cells[x].vertices[1] = x + 1;
2596  cells[x].material_id = 0;
2597  }
2598  break;
2599  }
2600 
2601  case 2:
2602  {
2603  cells.resize(repetitions[1] * repetitions[0]);
2604  for (unsigned int y = 0; y < repetitions[1]; ++y)
2605  for (unsigned int x = 0; x < repetitions[0]; ++x)
2606  {
2607  const unsigned int c = x + y * repetitions[0];
2608  cells[c].vertices[0] = y * (repetitions[0] + 1) + x;
2609  cells[c].vertices[1] = y * (repetitions[0] + 1) + x + 1;
2610  cells[c].vertices[2] = (y + 1) * (repetitions[0] + 1) + x;
2611  cells[c].vertices[3] = (y + 1) * (repetitions[0] + 1) + x + 1;
2612  cells[c].material_id = 0;
2613  }
2614  break;
2615  }
2616 
2617  case 3:
2618  {
2619  const unsigned int n_x = (repetitions[0] + 1);
2620  const unsigned int n_xy =
2621  (repetitions[0] + 1) * (repetitions[1] + 1);
2622 
2623  cells.resize(repetitions[2] * repetitions[1] * repetitions[0]);
2624  for (unsigned int z = 0; z < repetitions[2]; ++z)
2625  for (unsigned int y = 0; y < repetitions[1]; ++y)
2626  for (unsigned int x = 0; x < repetitions[0]; ++x)
2627  {
2628  const unsigned int c = x + y * repetitions[0] +
2629  z * repetitions[0] * repetitions[1];
2630  cells[c].vertices[0] = z * n_xy + y * n_x + x;
2631  cells[c].vertices[1] = z * n_xy + y * n_x + x + 1;
2632  cells[c].vertices[2] = z * n_xy + (y + 1) * n_x + x;
2633  cells[c].vertices[3] = z * n_xy + (y + 1) * n_x + x + 1;
2634  cells[c].vertices[4] = (z + 1) * n_xy + y * n_x + x;
2635  cells[c].vertices[5] = (z + 1) * n_xy + y * n_x + x + 1;
2636  cells[c].vertices[6] = (z + 1) * n_xy + (y + 1) * n_x + x;
2637  cells[c].vertices[7] =
2638  (z + 1) * n_xy + (y + 1) * n_x + x + 1;
2639  cells[c].material_id = 0;
2640  }
2641  break;
2642  }
2643 
2644  default:
2645  Assert(false, ExcNotImplemented());
2646  }
2647 
2648  tria.create_triangulation(points, cells, SubCellData());
2649 
2650  if (colorize)
2651  {
2652  // to colorize, run through all
2653  // faces of all cells and set
2654  // boundary indicator to the
2655  // correct value if it was 0.
2656 
2657  // use a large epsilon to
2658  // compare numbers to avoid
2659  // roundoff problems.
2660  double epsilon = 10;
2661  for (unsigned int i = 0; i < dim; ++i)
2662  epsilon = std::min(epsilon, 0.01 * delta[i][i]);
2663  Assert(epsilon > 0,
2664  ExcMessage(
2665  "The distance between corner points must be positive."))
2666 
2667  // actual code is external since
2668  // 1-D is different from 2/3D.
2669  colorize_subdivided_hyper_rectangle(tria, p1, p2, epsilon);
2670  }
2671  }
2672 
2673 
2674 
2675  template <int dim>
2676  void
2678  const std::vector<std::vector<double>> &step_sz,
2679  const Point<dim> & p_1,
2680  const Point<dim> & p_2,
2681  const bool colorize)
2682  {
2683  Assert(step_sz.size() == dim, ExcInvalidRepetitionsDimension(dim));
2684 
2685  // First, normalize input such that
2686  // p1 is lower in all coordinate
2687  // directions and check the consistency of
2688  // step sizes, i.e. that they all
2689  // add up to the sizes specified by
2690  // p_1 and p_2
2691  Point<dim> p1(p_1);
2692  Point<dim> p2(p_2);
2693  std::vector<std::vector<double>> step_sizes(step_sz);
2694 
2695  for (unsigned int i = 0; i < dim; ++i)
2696  {
2697  if (p1(i) > p2(i))
2698  {
2699  std::swap(p1(i), p2(i));
2700  std::reverse(step_sizes[i].begin(), step_sizes[i].end());
2701  }
2702 
2703  double x = 0;
2704  for (unsigned int j = 0; j < step_sizes.at(i).size(); j++)
2705  x += step_sizes[i][j];
2706  Assert(std::fabs(x - (p2(i) - p1(i))) <= 1e-12 * std::fabs(x),
2707  ExcMessage(
2708  "The sequence of step sizes in coordinate direction " +
2710  " must be equal to the distance of the two given "
2711  "points in this coordinate direction."));
2712  }
2713 
2714 
2715  // then generate the necessary
2716  // points
2717  std::vector<Point<dim>> points;
2718  switch (dim)
2719  {
2720  case 1:
2721  {
2722  double x = 0;
2723  for (unsigned int i = 0;; ++i)
2724  {
2725  points.push_back(Point<dim>(p1[0] + x));
2726 
2727  // form partial sums. in
2728  // the last run through
2729  // avoid accessing
2730  // non-existent values
2731  // and exit early instead
2732  if (i == step_sizes[0].size())
2733  break;
2734 
2735  x += step_sizes[0][i];
2736  }
2737  break;
2738  }
2739 
2740  case 2:
2741  {
2742  double y = 0;
2743  for (unsigned int j = 0;; ++j)
2744  {
2745  double x = 0;
2746  for (unsigned int i = 0;; ++i)
2747  {
2748  points.push_back(Point<dim>(p1[0] + x, p1[1] + y));
2749  if (i == step_sizes[0].size())
2750  break;
2751 
2752  x += step_sizes[0][i];
2753  }
2754 
2755  if (j == step_sizes[1].size())
2756  break;
2757 
2758  y += step_sizes[1][j];
2759  }
2760  break;
2761  }
2762  case 3:
2763  {
2764  double z = 0;
2765  for (unsigned int k = 0;; ++k)
2766  {
2767  double y = 0;
2768  for (unsigned int j = 0;; ++j)
2769  {
2770  double x = 0;
2771  for (unsigned int i = 0;; ++i)
2772  {
2773  points.push_back(
2774  Point<dim>(p1[0] + x, p1[1] + y, p1[2] + z));
2775  if (i == step_sizes[0].size())
2776  break;
2777 
2778  x += step_sizes[0][i];
2779  }
2780 
2781  if (j == step_sizes[1].size())
2782  break;
2783 
2784  y += step_sizes[1][j];
2785  }
2786 
2787  if (k == step_sizes[2].size())
2788  break;
2789 
2790  z += step_sizes[2][k];
2791  }
2792  break;
2793  }
2794 
2795  default:
2796  Assert(false, ExcNotImplemented());
2797  }
2798 
2799  // next create the cells
2800  // Prepare cell data
2801  std::vector<CellData<dim>> cells;
2802  switch (dim)
2803  {
2804  case 1:
2805  {
2806  cells.resize(step_sizes[0].size());
2807  for (unsigned int x = 0; x < step_sizes[0].size(); ++x)
2808  {
2809  cells[x].vertices[0] = x;
2810  cells[x].vertices[1] = x + 1;
2811  cells[x].material_id = 0;
2812  }
2813  break;
2814  }
2815 
2816  case 2:
2817  {
2818  cells.resize(step_sizes[1].size() * step_sizes[0].size());
2819  for (unsigned int y = 0; y < step_sizes[1].size(); ++y)
2820  for (unsigned int x = 0; x < step_sizes[0].size(); ++x)
2821  {
2822  const unsigned int c = x + y * step_sizes[0].size();
2823  cells[c].vertices[0] = y * (step_sizes[0].size() + 1) + x;
2824  cells[c].vertices[1] = y * (step_sizes[0].size() + 1) + x + 1;
2825  cells[c].vertices[2] =
2826  (y + 1) * (step_sizes[0].size() + 1) + x;
2827  cells[c].vertices[3] =
2828  (y + 1) * (step_sizes[0].size() + 1) + x + 1;
2829  cells[c].material_id = 0;
2830  }
2831  break;
2832  }
2833 
2834  case 3:
2835  {
2836  const unsigned int n_x = (step_sizes[0].size() + 1);
2837  const unsigned int n_xy =
2838  (step_sizes[0].size() + 1) * (step_sizes[1].size() + 1);
2839 
2840  cells.resize(step_sizes[2].size() * step_sizes[1].size() *
2841  step_sizes[0].size());
2842  for (unsigned int z = 0; z < step_sizes[2].size(); ++z)
2843  for (unsigned int y = 0; y < step_sizes[1].size(); ++y)
2844  for (unsigned int x = 0; x < step_sizes[0].size(); ++x)
2845  {
2846  const unsigned int c =
2847  x + y * step_sizes[0].size() +
2848  z * step_sizes[0].size() * step_sizes[1].size();
2849  cells[c].vertices[0] = z * n_xy + y * n_x + x;
2850  cells[c].vertices[1] = z * n_xy + y * n_x + x + 1;
2851  cells[c].vertices[2] = z * n_xy + (y + 1) * n_x + x;
2852  cells[c].vertices[3] = z * n_xy + (y + 1) * n_x + x + 1;
2853  cells[c].vertices[4] = (z + 1) * n_xy + y * n_x + x;
2854  cells[c].vertices[5] = (z + 1) * n_xy + y * n_x + x + 1;
2855  cells[c].vertices[6] = (z + 1) * n_xy + (y + 1) * n_x + x;
2856  cells[c].vertices[7] =
2857  (z + 1) * n_xy + (y + 1) * n_x + x + 1;
2858  cells[c].material_id = 0;
2859  }
2860  break;
2861  }
2862 
2863  default:
2864  Assert(false, ExcNotImplemented());
2865  }
2866 
2867  tria.create_triangulation(points, cells, SubCellData());
2868 
2869  if (colorize)
2870  {
2871  // to colorize, run through all
2872  // faces of all cells and set
2873  // boundary indicator to the
2874  // correct value if it was 0.
2875 
2876  // use a large epsilon to
2877  // compare numbers to avoid
2878  // roundoff problems.
2879  double min_size =
2880  *std::min_element(step_sizes[0].begin(), step_sizes[0].end());
2881  for (unsigned int i = 1; i < dim; ++i)
2882  min_size = std::min(min_size,
2883  *std::min_element(step_sizes[i].begin(),
2884  step_sizes[i].end()));
2885  const double epsilon = 0.01 * min_size;
2886 
2887  // actual code is external since
2888  // 1-D is different from 2/3D.
2889  colorize_subdivided_hyper_rectangle(tria, p1, p2, epsilon);
2890  }
2891  }
2892 
2893 
2894 
2895  template <>
2896  void
2898  const std::vector<std::vector<double>> &spacing,
2899  const Point<1> & p,
2901  const bool colorize)
2902  {
2903  Assert(spacing.size() == 1, ExcInvalidRepetitionsDimension(1));
2904 
2905  const unsigned int n_cells = material_id.size(0);
2906 
2907  Assert(spacing[0].size() == n_cells, ExcInvalidRepetitionsDimension(1));
2908 
2909  double delta = std::numeric_limits<double>::max();
2910  for (unsigned int i = 0; i < n_cells; i++)
2911  {
2912  Assert(spacing[0][i] >= 0, ExcInvalidRepetitions(-1));
2913  delta = std::min(delta, spacing[0][i]);
2914  }
2915 
2916  // generate the necessary points
2917  std::vector<Point<1>> points;
2918  double ax = p[0];
2919  for (unsigned int x = 0; x <= n_cells; ++x)
2920  {
2921  points.emplace_back(ax);
2922  if (x < n_cells)
2923  ax += spacing[0][x];
2924  }
2925  // create the cells
2926  unsigned int n_val_cells = 0;
2927  for (unsigned int i = 0; i < n_cells; i++)
2929  n_val_cells++;
2930 
2931  std::vector<CellData<1>> cells(n_val_cells);
2932  unsigned int id = 0;
2933  for (unsigned int x = 0; x < n_cells; ++x)
2935  {
2936  cells[id].vertices[0] = x;
2937  cells[id].vertices[1] = x + 1;
2938  cells[id].material_id = material_id[x];
2939  id++;
2940  }
2941  // create triangulation
2942  SubCellData t;
2943  GridTools::delete_unused_vertices(points, cells, t);
2944 
2945  tria.create_triangulation(points, cells, t);
2946 
2947  // set boundary indicator
2948  if (colorize)
2949  Assert(false, ExcNotImplemented());
2950  }
2951 
2952 
2953  template <>
2954  void
2956  const std::vector<std::vector<double>> &spacing,
2957  const Point<2> & p,
2959  const bool colorize)
2960  {
2961  Assert(spacing.size() == 2, ExcInvalidRepetitionsDimension(2));
2962 
2963  std::vector<unsigned int> repetitions(2);
2964  unsigned int n_cells = 1;
2965  double delta = std::numeric_limits<double>::max();
2966  for (unsigned int i = 0; i < 2; i++)
2967  {
2968  repetitions[i] = spacing[i].size();
2969  n_cells *= repetitions[i];
2970  for (unsigned int j = 0; j < repetitions[i]; j++)
2971  {
2972  Assert(spacing[i][j] >= 0, ExcInvalidRepetitions(-1));
2973  delta = std::min(delta, spacing[i][j]);
2974  }
2975  Assert(material_id.size(i) == repetitions[i],
2977  }
2978 
2979  // generate the necessary points
2980  std::vector<Point<2>> points;
2981  double ay = p[1];
2982  for (unsigned int y = 0; y <= repetitions[1]; ++y)
2983  {
2984  double ax = p[0];
2985  for (unsigned int x = 0; x <= repetitions[0]; ++x)
2986  {
2987  points.emplace_back(ax, ay);
2988  if (x < repetitions[0])
2989  ax += spacing[0][x];
2990  }
2991  if (y < repetitions[1])
2992  ay += spacing[1][y];
2993  }
2994 
2995  // create the cells
2996  unsigned int n_val_cells = 0;
2997  for (unsigned int i = 0; i < material_id.size(0); i++)
2998  for (unsigned int j = 0; j < material_id.size(1); j++)
3000  n_val_cells++;
3001 
3002  std::vector<CellData<2>> cells(n_val_cells);
3003  unsigned int id = 0;
3004  for (unsigned int y = 0; y < repetitions[1]; ++y)
3005  for (unsigned int x = 0; x < repetitions[0]; ++x)
3007  {
3008  cells[id].vertices[0] = y * (repetitions[0] + 1) + x;
3009  cells[id].vertices[1] = y * (repetitions[0] + 1) + x + 1;
3010  cells[id].vertices[2] = (y + 1) * (repetitions[0] + 1) + x;
3011  cells[id].vertices[3] = (y + 1) * (repetitions[0] + 1) + x + 1;
3012  cells[id].material_id = material_id[x][y];
3013  id++;
3014  }
3015 
3016  // create triangulation
3017  SubCellData t;
3018  GridTools::delete_unused_vertices(points, cells, t);
3019 
3020  tria.create_triangulation(points, cells, t);
3021 
3022  // set boundary indicator
3023  if (colorize)
3024  {
3025  double eps = 0.01 * delta;
3026  Triangulation<2>::cell_iterator cell = tria.begin(), endc = tria.end();
3027  for (; cell != endc; ++cell)
3028  {
3029  Point<2> cell_center = cell->center();
3030  for (unsigned int f : GeometryInfo<2>::face_indices())
3031  if (cell->face(f)->boundary_id() == 0)
3032  {
3033  Point<2> face_center = cell->face(f)->center();
3034  for (unsigned int i = 0; i < 2; ++i)
3035  {
3036  if (face_center[i] < cell_center[i] - eps)
3037  cell->face(f)->set_boundary_id(i * 2);
3038  if (face_center[i] > cell_center[i] + eps)
3039  cell->face(f)->set_boundary_id(i * 2 + 1);
3040  }
3041  }
3042  }
3043  }
3044  }
3045 
3046 
3047  template <>
3048  void
3050  const std::vector<std::vector<double>> &spacing,
3051  const Point<3> & p,
3053  const bool colorize)
3054  {
3055  const unsigned int dim = 3;
3056 
3057  Assert(spacing.size() == dim, ExcInvalidRepetitionsDimension(dim));
3058 
3059  std::vector<unsigned int> repetitions(dim);
3060  unsigned int n_cells = 1;
3061  double delta = std::numeric_limits<double>::max();
3062  for (unsigned int i = 0; i < dim; i++)
3063  {
3064  repetitions[i] = spacing[i].size();
3065  n_cells *= repetitions[i];
3066  for (unsigned int j = 0; j < repetitions[i]; j++)
3067  {
3068  Assert(spacing[i][j] >= 0, ExcInvalidRepetitions(-1));
3069  delta = std::min(delta, spacing[i][j]);
3070  }
3071  Assert(material_id.size(i) == repetitions[i],
3073  }
3074 
3075  // generate the necessary points
3076  std::vector<Point<dim>> points;
3077  double az = p[2];
3078  for (unsigned int z = 0; z <= repetitions[2]; ++z)
3079  {
3080  double ay = p[1];
3081  for (unsigned int y = 0; y <= repetitions[1]; ++y)
3082  {
3083  double ax = p[0];
3084  for (unsigned int x = 0; x <= repetitions[0]; ++x)
3085  {
3086  points.emplace_back(ax, ay, az);
3087  if (x < repetitions[0])
3088  ax += spacing[0][x];
3089  }
3090  if (y < repetitions[1])
3091  ay += spacing[1][y];
3092  }
3093  if (z < repetitions[2])
3094  az += spacing[2][z];
3095  }
3096 
3097  // create the cells
3098  unsigned int n_val_cells = 0;
3099  for (unsigned int i = 0; i < material_id.size(0); i++)
3100  for (unsigned int j = 0; j < material_id.size(1); j++)
3101  for (unsigned int k = 0; k < material_id.size(2); k++)
3102  if (material_id[i][j][k] != numbers::invalid_material_id)
3103  n_val_cells++;
3104 
3105  std::vector<CellData<dim>> cells(n_val_cells);
3106  unsigned int id = 0;
3107  const unsigned int n_x = (repetitions[0] + 1);
3108  const unsigned int n_xy = (repetitions[0] + 1) * (repetitions[1] + 1);
3109  for (unsigned int z = 0; z < repetitions[2]; ++z)
3110  for (unsigned int y = 0; y < repetitions[1]; ++y)
3111  for (unsigned int x = 0; x < repetitions[0]; ++x)
3112  if (material_id[x][y][z] != numbers::invalid_material_id)
3113  {
3114  cells[id].vertices[0] = z * n_xy + y * n_x + x;
3115  cells[id].vertices[1] = z * n_xy + y * n_x + x + 1;
3116  cells[id].vertices[2] = z * n_xy + (y + 1) * n_x + x;
3117  cells[id].vertices[3] = z * n_xy + (y + 1) * n_x + x + 1;
3118  cells[id].vertices[4] = (z + 1) * n_xy + y * n_x + x;
3119  cells[id].vertices[5] = (z + 1) * n_xy + y * n_x + x + 1;
3120  cells[id].vertices[6] = (z + 1) * n_xy + (y + 1) * n_x + x;
3121  cells[id].vertices[7] = (z + 1) * n_xy + (y + 1) * n_x + x + 1;
3122  cells[id].material_id = material_id[x][y][z];
3123  id++;
3124  }
3125 
3126  // create triangulation
3127  SubCellData t;
3128  GridTools::delete_unused_vertices(points, cells, t);
3129 
3130  tria.create_triangulation(points, cells, t);
3131 
3132  // set boundary indicator
3133  if (colorize)
3134  {
3135  double eps = 0.01 * delta;
3137  endc = tria.end();
3138  for (; cell != endc; ++cell)
3139  {
3140  Point<dim> cell_center = cell->center();
3141  for (auto f : GeometryInfo<dim>::face_indices())
3142  if (cell->face(f)->boundary_id() == 0)
3143  {
3144  Point<dim> face_center = cell->face(f)->center();
3145  for (unsigned int i = 0; i < dim; ++i)
3146  {
3147  if (face_center[i] < cell_center[i] - eps)
3148  cell->face(f)->set_boundary_id(i * 2);
3149  if (face_center[i] > cell_center[i] + eps)
3150  cell->face(f)->set_boundary_id(i * 2 + 1);
3151  }
3152  }
3153  }
3154  }
3155  }
3156 
3157  template <int dim, int spacedim>
3158  void
3160  const std::vector<unsigned int> &holes)
3161  {
3162  AssertDimension(holes.size(), dim);
3163  // The corner points of the first cell. If there is a desire at
3164  // some point to change the geometry of the cells, they can be
3165  // made an argument to the function.
3166 
3167  Point<spacedim> p1;
3168  Point<spacedim> p2;
3169  for (unsigned int d = 0; d < dim; ++d)
3170  p2(d) = 1.;
3171 
3172  // then check that all repetitions
3173  // are >= 1, and calculate deltas
3174  // convert repetitions from double
3175  // to int by taking the ceiling.
3176  std::vector<Point<spacedim>> delta(dim);
3177  unsigned int repetitions[dim];
3178  for (unsigned int i = 0; i < dim; ++i)
3179  {
3180  Assert(holes[i] >= 1,
3181  ExcMessage("At least one hole needed in each direction"));
3182  repetitions[i] = 2 * holes[i] + 1;
3183  delta[i][i] = (p2[i] - p1[i]);
3184  }
3185 
3186  // then generate the necessary
3187  // points
3188  std::vector<Point<spacedim>> points;
3189  switch (dim)
3190  {
3191  case 1:
3192  for (unsigned int x = 0; x <= repetitions[0]; ++x)
3193  points.push_back(p1 + x * delta[0]);
3194  break;
3195 
3196  case 2:
3197  for (unsigned int y = 0; y <= repetitions[1]; ++y)
3198  for (unsigned int x = 0; x <= repetitions[0]; ++x)
3199  points.push_back(p1 + x * delta[0] + y * delta[1]);
3200  break;
3201 
3202  case 3:
3203  for (unsigned int z = 0; z <= repetitions[2]; ++z)
3204  for (unsigned int y = 0; y <= repetitions[1]; ++y)
3205  for (unsigned int x = 0; x <= repetitions[0]; ++x)
3206  points.push_back(p1 + x * delta[0] + y * delta[1] +
3207  z * delta[2]);
3208  break;
3209 
3210  default:
3211  Assert(false, ExcNotImplemented());
3212  }
3213 
3214  // next create the cells
3215  // Prepare cell data
3216  std::vector<CellData<dim>> cells;
3217  switch (dim)
3218  {
3219  case 2:
3220  {
3221  cells.resize(repetitions[1] * repetitions[0] - holes[1] * holes[0]);
3222  unsigned int c = 0;
3223  for (unsigned int y = 0; y < repetitions[1]; ++y)
3224  for (unsigned int x = 0; x < repetitions[0]; ++x)
3225  {
3226  if ((x % 2 == 1) && (y % 2 == 1))
3227  continue;
3228  Assert(c < cells.size(), ExcInternalError());
3229  cells[c].vertices[0] = y * (repetitions[0] + 1) + x;
3230  cells[c].vertices[1] = y * (repetitions[0] + 1) + x + 1;
3231  cells[c].vertices[2] = (y + 1) * (repetitions[0] + 1) + x;
3232  cells[c].vertices[3] = (y + 1) * (repetitions[0] + 1) + x + 1;
3233  cells[c].material_id = 0;
3234  ++c;
3235  }
3236  break;
3237  }
3238 
3239  case 3:
3240  {
3241  const unsigned int n_x = (repetitions[0] + 1);
3242  const unsigned int n_xy =
3243  (repetitions[0] + 1) * (repetitions[1] + 1);
3244 
3245  cells.resize(repetitions[2] * repetitions[1] * repetitions[0]);
3246 
3247  unsigned int c = 0;
3248  for (unsigned int z = 0; z < repetitions[2]; ++z)
3249  for (unsigned int y = 0; y < repetitions[1]; ++y)
3250  for (unsigned int x = 0; x < repetitions[0]; ++x)
3251  {
3252  Assert(c < cells.size(), ExcInternalError());
3253  cells[c].vertices[0] = z * n_xy + y * n_x + x;
3254  cells[c].vertices[1] = z * n_xy + y * n_x + x + 1;
3255  cells[c].vertices[2] = z * n_xy + (y + 1) * n_x + x;
3256  cells[c].vertices[3] = z * n_xy + (y + 1) * n_x + x + 1;
3257  cells[c].vertices[4] = (z + 1) * n_xy + y * n_x + x;
3258  cells[c].vertices[5] = (z + 1) * n_xy + y * n_x + x + 1;
3259  cells[c].vertices[6] = (z + 1) * n_xy + (y + 1) * n_x + x;
3260  cells[c].vertices[7] =
3261  (z + 1) * n_xy + (y + 1) * n_x + x + 1;
3262  cells[c].material_id = 0;
3263  ++c;
3264  }
3265  break;
3266  }
3267 
3268  default:
3269  Assert(false, ExcNotImplemented());
3270  }
3271 
3272  tria.create_triangulation(points, cells, SubCellData());
3273  }
3274 
3275 
3276 
3277  template <>
3278  void plate_with_a_hole(Triangulation<1> & /*tria*/,
3279  const double /*inner_radius*/,
3280  const double /*outer_radius*/,
3281  const double /*pad_bottom*/,
3282  const double /*pad_top*/,
3283  const double /*pad_left*/,
3284  const double /*pad_right*/,
3285  const Point<1> & /*center*/,
3286  const types::manifold_id /*polar_manifold_id*/,
3287  const types::manifold_id /*tfi_manifold_id*/,
3288  const double /*L*/,
3289  const unsigned int /*n_slices*/,
3290  const bool /*colorize*/)
3291  {
3292  Assert(false, ExcNotImplemented());
3293  }
3294 
3295 
3296 
3297  template <>
3298  void channel_with_cylinder(Triangulation<1> & /*tria*/,
3299  const double /*shell_region_width*/,
3300  const unsigned int /*n_shells*/,
3301  const double /*skewness*/,
3302  const bool /*colorize*/)
3303  {
3304  Assert(false, ExcNotImplemented());
3305  }
3306 
3307 
3308 
3309  namespace internal
3310  {
3311  // helper function to check if point is in 2D box
3312  bool inline point_in_2d_box(const Point<2> &p,
3313  const Point<2> &c,
3314  const double radius)
3315  {
3316  return (std::abs(p[0] - c[0]) < radius) &&
3317  (std::abs(p[1] - c[1]) < radius);
3318  }
3319 
3320 
3321 
3322  // Find the minimal distance between two vertices. This is useful for
3323  // computing a tolerance for merging vertices in
3324  // GridTools::merge_triangulations.
3325  template <int dim, int spacedim>
3326  double
3327  minimal_vertex_distance(const Triangulation<dim, spacedim> &triangulation)
3328  {
3329  double length = std::numeric_limits<double>::max();
3330  for (const auto &cell : triangulation.active_cell_iterators())
3331  for (unsigned int n = 0; n < GeometryInfo<dim>::lines_per_cell; ++n)
3332  length = std::min(length, cell->line(n)->diameter());
3333  return length;
3334  }
3335  } // namespace internal
3336 
3337 
3338 
3339  template <>
3340  void plate_with_a_hole(Triangulation<2> & tria,
3341  const double inner_radius,
3342  const double outer_radius,
3343  const double pad_bottom,
3344  const double pad_top,
3345  const double pad_left,
3346  const double pad_right,
3347  const Point<2> & new_center,
3348  const types::manifold_id polar_manifold_id,
3349  const types::manifold_id tfi_manifold_id,
3350  const double L,
3351  const unsigned int /*n_slices*/,
3352  const bool colorize)
3353  {
3354  const bool with_padding =
3355  pad_bottom > 0 || pad_top > 0 || pad_left > 0 || pad_right > 0;
3356 
3357  Assert(pad_bottom >= 0., ExcMessage("Negative bottom padding."));
3358  Assert(pad_top >= 0., ExcMessage("Negative top padding."));
3359  Assert(pad_left >= 0., ExcMessage("Negative left padding."));
3360  Assert(pad_right >= 0., ExcMessage("Negative right padding."));
3361 
3362  const Point<2> center;
3363 
3364  auto min_line_length = [](const Triangulation<2> &tria) -> double {
3365  double length = std::numeric_limits<double>::max();
3366  for (const auto &cell : tria.active_cell_iterators())
3367  for (unsigned int n = 0; n < GeometryInfo<2>::lines_per_cell; ++n)
3368  length = std::min(length, cell->line(n)->diameter());
3369  return length;
3370  };
3371 
3372  // start by setting up the cylinder triangulation
3373  Triangulation<2> cylinder_tria_maybe;
3374  Triangulation<2> &cylinder_tria = with_padding ? cylinder_tria_maybe : tria;
3376  inner_radius,
3377  outer_radius,
3378  L,
3379  /*repetitions*/ 1,
3380  colorize);
3381 
3382  // we will deal with face manifold ids after we merge triangulations
3383  for (const auto &cell : cylinder_tria.active_cell_iterators())
3384  cell->set_manifold_id(tfi_manifold_id);
3385 
3386  const Point<2> bl(-outer_radius - pad_left, -outer_radius - pad_bottom);
3387  const Point<2> tr(outer_radius + pad_right, outer_radius + pad_top);
3388  if (with_padding)
3389  {
3390  // hyper_cube_with_cylindrical_hole will have 2 cells along
3391  // each face, so the element size is outer_radius
3392 
3393  auto add_sizes = [](std::vector<double> &step_sizes,
3394  const double padding,
3395  const double h) -> void {
3396  // use std::round instead of std::ceil to improve aspect ratio
3397  // in case padding is only slightly larger than h.
3398  const auto rounded =
3399  static_cast<unsigned int>(std::round(padding / h));
3400  // in case padding is much smaller than h, make sure we
3401  // have at least 1 element
3402  const unsigned int num = (padding > 0. && rounded == 0) ? 1 : rounded;
3403  for (unsigned int i = 0; i < num; ++i)
3404  step_sizes.push_back(padding / num);
3405  };
3406 
3407  std::vector<std::vector<double>> step_sizes(2);
3408  // x-coord
3409  // left:
3410  add_sizes(step_sizes[0], pad_left, outer_radius);
3411  // center
3412  step_sizes[0].push_back(outer_radius);
3413  step_sizes[0].push_back(outer_radius);
3414  // right
3415  add_sizes(step_sizes[0], pad_right, outer_radius);
3416  // y-coord
3417  // bottom
3418  add_sizes(step_sizes[1], pad_bottom, outer_radius);
3419  // center
3420  step_sizes[1].push_back(outer_radius);
3421  step_sizes[1].push_back(outer_radius);
3422  // top
3423  add_sizes(step_sizes[1], pad_top, outer_radius);
3424 
3425  // now create bulk
3426  Triangulation<2> bulk_tria;
3428  bulk_tria, step_sizes, bl, tr, colorize);
3429 
3430  // now remove cells reserved from the cylindrical hole
3431  std::set<Triangulation<2>::active_cell_iterator> cells_to_remove;
3432  for (const auto &cell : bulk_tria.active_cell_iterators())
3433  if (internal::point_in_2d_box(cell->center(), center, outer_radius))
3434  cells_to_remove.insert(cell);
3435 
3436  Triangulation<2> tria_without_cylinder;
3438  bulk_tria, cells_to_remove, tria_without_cylinder);
3439 
3440  const double tolerance =
3441  std::min(min_line_length(tria_without_cylinder),
3442  min_line_length(cylinder_tria)) /
3443  2.0;
3444 
3445  GridGenerator::merge_triangulations(tria_without_cylinder,
3446  cylinder_tria,
3447  tria,
3448  tolerance);
3449  }
3450 
3451  // now set manifold ids:
3452  for (const auto &cell : tria.active_cell_iterators())
3453  {
3454  // set all non-boundary manifold ids on the cells that came from the
3455  // grid around the cylinder to the new TFI manifold id.
3456  if (cell->manifold_id() == tfi_manifold_id)
3457  {
3458  for (const unsigned int face_n : GeometryInfo<2>::face_indices())
3459  {
3460  const auto &face = cell->face(face_n);
3461  if (face->at_boundary() &&
3462  internal::point_in_2d_box(face->center(),
3463  center,
3464  outer_radius))
3465  face->set_manifold_id(polar_manifold_id);
3466  else
3467  face->set_manifold_id(tfi_manifold_id);
3468  }
3469  }
3470  else
3471  {
3472  // ensure that all other manifold ids (including the faces
3473  // opposite the cylinder) are set to the flat id
3474  cell->set_all_manifold_ids(numbers::flat_manifold_id);
3475  }
3476  }
3477 
3478  static constexpr double tol =
3480  if (colorize)
3481  for (const auto &cell : tria.active_cell_iterators())
3482  for (const unsigned int face_n : GeometryInfo<2>::face_indices())
3483  {
3484  const auto face = cell->face(face_n);
3485  if (face->at_boundary())
3486  {
3487  const Point<2> center = face->center();
3488  // left side
3489  if (std::abs(center[0] - bl[0]) < tol * std::abs(bl[0]))
3490  face->set_boundary_id(0);
3491  // right side
3492  else if (std::abs(center[0] - tr[0]) < tol * std::abs(tr[0]))
3493  face->set_boundary_id(1);
3494  // bottom
3495  else if (std::abs(center[1] - bl[1]) < tol * std::abs(bl[1]))
3496  face->set_boundary_id(2);
3497  // top
3498  else if (std::abs(center[1] - tr[1]) < tol * std::abs(tr[1]))
3499  face->set_boundary_id(3);
3500  // cylinder boundary
3501  else
3502  {
3503  Assert(cell->manifold_id() == tfi_manifold_id,
3504  ExcInternalError());
3505  face->set_boundary_id(4);
3506  }
3507  }
3508  }
3509 
3510  // move to the new center
3511  GridTools::shift(new_center, tria);
3512 
3513  PolarManifold<2> polar_manifold(new_center);
3514  tria.set_manifold(polar_manifold_id, polar_manifold);
3515  TransfiniteInterpolationManifold<2> inner_manifold;
3516  inner_manifold.initialize(tria);
3517  tria.set_manifold(tfi_manifold_id, inner_manifold);
3518  }
3519 
3520 
3521 
3522  template <>
3523  void plate_with_a_hole(Triangulation<3> & tria,
3524  const double inner_radius,
3525  const double outer_radius,
3526  const double pad_bottom,
3527  const double pad_top,
3528  const double pad_left,
3529  const double pad_right,
3530  const Point<3> & new_center,
3531  const types::manifold_id polar_manifold_id,
3532  const types::manifold_id tfi_manifold_id,
3533  const double L,
3534  const unsigned int n_slices,
3535  const bool colorize)
3536  {
3537  Triangulation<2> tria_2;
3538  plate_with_a_hole(tria_2,
3539  inner_radius,
3540  outer_radius,
3541  pad_bottom,
3542  pad_top,
3543  pad_left,
3544  pad_right,
3545  Point<2>(new_center[0], new_center[1]),
3546  polar_manifold_id,
3547  tfi_manifold_id,
3548  L,
3549  n_slices,
3550  colorize);
3551 
3552  // extrude to 3D
3553  extrude_triangulation(tria_2, n_slices, L, tria, true);
3554 
3555  // shift in Z direction to match specified center
3556  GridTools::shift(Point<3>(0, 0, new_center[2] - L / 2.), tria);
3557 
3558  // set up the new manifolds
3559  const Tensor<1, 3> direction{{0.0, 0.0, 1.0}};
3560  const CylindricalManifold<3> cylindrical_manifold(
3561  direction,
3562  /*axial_point*/ new_center);
3563  TransfiniteInterpolationManifold<3> inner_manifold;
3564  inner_manifold.initialize(tria);
3565  tria.set_manifold(polar_manifold_id, cylindrical_manifold);
3566  tria.set_manifold(tfi_manifold_id, inner_manifold);
3567  }
3568 
3569 
3570 
3571  template <>
3573  const double shell_region_width,
3574  const unsigned int n_shells,
3575  const double skewness,
3576  const bool colorize)
3577  {
3578  Assert(0.0 <= shell_region_width && shell_region_width < 0.05,
3579  ExcMessage("The width of the shell region must be less than 0.05 "
3580  "(and preferably close to 0.03)"));
3581  const types::manifold_id polar_manifold_id = 0;
3582  const types::manifold_id tfi_manifold_id = 1;
3583 
3584  // We begin by setting up a grid that is 4 by 22 cells. While not
3585  // squares, these have pretty good aspect ratios.
3586  Triangulation<2> bulk_tria;
3588  {22u, 4u},
3589  Point<2>(0.0, 0.0),
3590  Point<2>(2.2, 0.41));
3591  // bulk_tria now looks like this:
3592  //
3593  // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
3594  // | | | | | | | | | | | | | | | | | | | | | | |
3595  // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
3596  // | |XX|XX| | | | | | | | | | | | | | | | | | | |
3597  // +--+--O--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
3598  // | |XX|XX| | | | | | | | | | | | | | | | | | | |
3599  // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
3600  // | | | | | | | | | | | | | | | | | | | | | | |
3601  // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
3602  //
3603  // Note that these cells are not quite squares: they are all 0.1 by
3604  // 0.1025.
3605  //
3606  // The next step is to remove the cells marked with XXs: we will place
3607  // the grid around the cylinder there later. The next loop does two
3608  // things:
3609  // 1. Determines which cells need to be removed from the Triangulation
3610  // (i.e., find the cells marked with XX in the picture).
3611  // 2. Finds the location of the vertex marked with 'O' and uses that to
3612  // calculate the shift vector for aligning cylinder_tria with
3613  // tria_without_cylinder.
3614  std::set<Triangulation<2>::active_cell_iterator> cells_to_remove;
3615  Tensor<1, 2> cylinder_triangulation_offset;
3616  for (const auto &cell : bulk_tria.active_cell_iterators())
3617  {
3618  if ((cell->center() - Point<2>(0.2, 0.2)).norm() < 0.15)
3619  cells_to_remove.insert(cell);
3620 
3621  if (cylinder_triangulation_offset == Tensor<1, 2>())
3622  {
3623  for (const unsigned int vertex_n :
3625  if (cell->vertex(vertex_n) == Point<2>())
3626  {
3627  // cylinder_tria is centered at zero, so we need to
3628  // shift it up and to the right by two cells:
3629  cylinder_triangulation_offset =
3630  2.0 * (cell->vertex(3) - Point<2>());
3631  break;
3632  }
3633  }
3634  }
3635  Triangulation<2> tria_without_cylinder;
3637  bulk_tria, cells_to_remove, tria_without_cylinder);
3638 
3639  // set up the cylinder triangulation. Note that this function sets the
3640  // manifold ids of the interior boundary cells to 0
3641  // (polar_manifold_id).
3642  Triangulation<2> cylinder_tria;
3644  0.05 + shell_region_width,
3645  0.41 / 4.0);
3646  // The bulk cells are not quite squares, so we need to move the left
3647  // and right sides of cylinder_tria inwards so that it fits in
3648  // bulk_tria:
3649  for (const auto &cell : cylinder_tria.active_cell_iterators())
3650  for (const unsigned int vertex_n : GeometryInfo<2>::vertex_indices())
3651  {
3652  if (std::abs(cell->vertex(vertex_n)[0] - -0.41 / 4.0) < 1e-10)
3653  cell->vertex(vertex_n)[0] = -0.1;
3654  else if (std::abs(cell->vertex(vertex_n)[0] - 0.41 / 4.0) < 1e-10)
3655  cell->vertex(vertex_n)[0] = 0.1;
3656  }
3657 
3658  // Assign interior manifold ids to be the TFI id.
3659  for (const auto &cell : cylinder_tria.active_cell_iterators())
3660  {
3661  cell->set_manifold_id(tfi_manifold_id);
3662  for (const unsigned int face_n : GeometryInfo<2>::face_indices())
3663  if (!cell->face(face_n)->at_boundary())
3664  cell->face(face_n)->set_manifold_id(tfi_manifold_id);
3665  }
3666  if (0.0 < shell_region_width)
3667  {
3668  Assert(0 < n_shells,
3669  ExcMessage("If the shell region has positive width then "
3670  "there must be at least one shell."));
3671  Triangulation<2> shell_tria;
3673  Point<2>(),
3674  0.05,
3675  0.05 + shell_region_width,
3676  n_shells,
3677  skewness,
3678  8);
3679 
3680  // Make the tolerance as large as possible since these cells can
3681  // be quite close together
3682  const double vertex_tolerance =
3683  std::min(internal::minimal_vertex_distance(shell_tria),
3684  internal::minimal_vertex_distance(cylinder_tria)) *
3685  0.5;
3686 
3687  shell_tria.set_all_manifold_ids(polar_manifold_id);
3688  Triangulation<2> temp;
3690  shell_tria, cylinder_tria, temp, vertex_tolerance, true);
3691  cylinder_tria = std::move(temp);
3692  }
3693  GridTools::shift(cylinder_triangulation_offset, cylinder_tria);
3694 
3695  // Compute the tolerance again, since the shells may be very close to
3696  // each-other:
3697  const double vertex_tolerance =
3698  std::min(internal::minimal_vertex_distance(tria_without_cylinder),
3699  internal::minimal_vertex_distance(cylinder_tria)) /
3700  10;
3702  tria_without_cylinder, cylinder_tria, tria, vertex_tolerance, true);
3703 
3704  // Move the vertices in the middle of the faces of cylinder_tria slightly
3705  // to give a better mesh quality. We have to balance the quality of these
3706  // cells with the quality of the outer cells (initially rectangles). For
3707  // constant radial distance, we would place them at the distance 0.1 *
3708  // sqrt(2.) from the center. In case the shell region width is more than
3709  // 0.1/6., we choose to place them at 0.1 * 4./3. from the center, which
3710  // ensures that the shortest edge of the outer cells is 2./3. of the
3711  // original length. If the shell region width is less, we make the edge
3712  // length of the inner part and outer part (in the shorter x direction)
3713  // the same.
3714  {
3715  const double shift =
3716  std::min(0.125 + shell_region_width * 0.5, 0.1 * 4. / 3.);
3717  for (const auto &cell : tria.active_cell_iterators())
3718  for (const unsigned int v : GeometryInfo<2>::vertex_indices())
3719  if (cell->vertex(v).distance(Point<2>(0.1, 0.205)) < 1e-10)
3720  cell->vertex(v) = Point<2>(0.2 - shift, 0.205);
3721  else if (cell->vertex(v).distance(Point<2>(0.3, 0.205)) < 1e-10)
3722  cell->vertex(v) = Point<2>(0.2 + shift, 0.205);
3723  else if (cell->vertex(v).distance(Point<2>(0.2, 0.1025)) < 1e-10)
3724  cell->vertex(v) = Point<2>(0.2, 0.2 - shift);
3725  else if (cell->vertex(v).distance(Point<2>(0.2, 0.3075)) < 1e-10)
3726  cell->vertex(v) = Point<2>(0.2, 0.2 + shift);
3727  }
3728 
3729  // Ensure that all manifold ids on a polar cell really are set to the
3730  // polar manifold id:
3731  for (const auto &cell : tria.active_cell_iterators())
3732  if (cell->manifold_id() == polar_manifold_id)
3733  cell->set_all_manifold_ids(polar_manifold_id);
3734 
3735  // Ensure that all other manifold ids (including the interior faces
3736  // opposite the cylinder) are set to the flat manifold id:
3737  for (const auto &cell : tria.active_cell_iterators())
3738  if (cell->manifold_id() != polar_manifold_id &&
3739  cell->manifold_id() != tfi_manifold_id)
3740  cell->set_all_manifold_ids(numbers::flat_manifold_id);
3741 
3742  // We need to calculate the current center so that we can move it later:
3743  // to start get a unique list of (points to) vertices on the cylinder
3744  std::vector<Point<2> *> cylinder_pointers;
3745  for (const auto &face : tria.active_face_iterators())
3746  if (face->manifold_id() == polar_manifold_id)
3747  {
3748  cylinder_pointers.push_back(&face->vertex(0));
3749  cylinder_pointers.push_back(&face->vertex(1));
3750  }
3751  // de-duplicate
3752  std::sort(cylinder_pointers.begin(), cylinder_pointers.end());
3753  cylinder_pointers.erase(std::unique(cylinder_pointers.begin(),
3754  cylinder_pointers.end()),
3755  cylinder_pointers.end());
3756 
3757  // find the current center...
3758  Point<2> center;
3759  for (const Point<2> *const ptr : cylinder_pointers)
3760  center += *ptr / double(cylinder_pointers.size());
3761 
3762  // and recenter at (0.2, 0.2)
3763  for (Point<2> *const ptr : cylinder_pointers)
3764  *ptr += Point<2>(0.2, 0.2) - center;
3765 
3766  // attach manifolds
3767  PolarManifold<2> polar_manifold(Point<2>(0.2, 0.2));
3768  tria.set_manifold(polar_manifold_id, polar_manifold);
3769  TransfiniteInterpolationManifold<2> inner_manifold;
3770  inner_manifold.initialize(tria);
3771  tria.set_manifold(tfi_manifold_id, inner_manifold);
3772 
3773  if (colorize)
3774  for (const auto &face : tria.active_face_iterators())
3775  if (face->at_boundary())
3776  {
3777  const Point<2> center = face->center();
3778  // left side
3779  if (std::abs(center[0] - 0.0) < 1e-10)
3780  face->set_boundary_id(0);
3781  // right side
3782  else if (std::abs(center[0] - 2.2) < 1e-10)
3783  face->set_boundary_id(1);
3784  // cylinder boundary
3785  else if (face->manifold_id() == polar_manifold_id)
3786  face->set_boundary_id(2);
3787  // sides of channel
3788  else
3789  {
3790  Assert(std::abs(center[1] - 0.00) < 1.0e-10 ||
3791  std::abs(center[1] - 0.41) < 1.0e-10,
3792  ExcInternalError());
3793  face->set_boundary_id(3);
3794  }
3795  }
3796  }
3797 
3798 
3799 
3800  template <>
3802  const double shell_region_width,
3803  const unsigned int n_shells,
3804  const double skewness,
3805  const bool colorize)
3806  {
3807  Triangulation<2> tria_2;
3809  tria_2, shell_region_width, n_shells, skewness, colorize);
3810  extrude_triangulation(tria_2, 5, 0.41, tria, true);
3811 
3812  // set up the new 3D manifolds
3813  const types::manifold_id cylindrical_manifold_id = 0;
3814  const types::manifold_id tfi_manifold_id = 1;
3815  const PolarManifold<2> *const m_ptr =
3816  dynamic_cast<const PolarManifold<2> *>(
3817  &tria_2.get_manifold(cylindrical_manifold_id));
3818  Assert(m_ptr != nullptr, ExcInternalError());
3819  const Point<3> axial_point(m_ptr->center[0], m_ptr->center[1], 0.0);
3820  const Tensor<1, 3> direction{{0.0, 0.0, 1.0}};
3821 
3822  const CylindricalManifold<3> cylindrical_manifold(direction, axial_point);
3823  TransfiniteInterpolationManifold<3> inner_manifold;
3824  inner_manifold.initialize(tria);
3825  tria.set_manifold(cylindrical_manifold_id, cylindrical_manifold);
3826  tria.set_manifold(tfi_manifold_id, inner_manifold);
3827 
3828  // From extrude_triangulation: since the maximum boundary id of tria_2 was
3829  // 3, the bottom boundary id is 4 and the top is 5: both are walls, so set
3830  // them to 3
3831  if (colorize)
3832  for (const auto &face : tria.active_face_iterators())
3833  if (face->boundary_id() == 4 || face->boundary_id() == 5)
3834  face->set_boundary_id(3);
3835  }
3836 
3837 
3838 
3839  template <int dim, int spacedim>
3840  void
3842  const std::vector<unsigned int> &sizes,
3843  const bool colorize)
3844  {
3846  Assert(dim > 1, ExcNotImplemented());
3847  Assert(dim < 4, ExcNotImplemented());
3848 
3849  // If there is a desire at some point to change the geometry of
3850  // the cells, this tensor can be made an argument to the function.
3851  Tensor<1, dim> dimensions;
3852  for (unsigned int d = 0; d < dim; ++d)
3853  dimensions[d] = 1.;
3854 
3855  std::vector<Point<spacedim>> points;
3856  unsigned int n_cells = 1;
3857  for (unsigned int i : GeometryInfo<dim>::face_indices())
3858  n_cells += sizes[i];
3859 
3860  std::vector<CellData<dim>> cells(n_cells);
3861  // Vertices of the center cell
3862  for (const unsigned int i : GeometryInfo<dim>::vertex_indices())
3863  {
3864  Point<spacedim> p;
3865  for (unsigned int d = 0; d < dim; ++d)
3866  p(d) = 0.5 * dimensions[d] *
3869  points.push_back(p);
3870  cells[0].vertices[i] = i;
3871  }
3872  cells[0].material_id = 0;
3873 
3874  // The index of the first cell of the leg.
3875  unsigned int cell_index = 1;
3876  // The legs of the cross
3877  for (const unsigned int face : GeometryInfo<dim>::face_indices())
3878  {
3879  const unsigned int oface = GeometryInfo<dim>::opposite_face[face];
3880  const unsigned int dir = GeometryInfo<dim>::unit_normal_direction[face];
3881 
3882  // We are moving in the direction of face
3883  for (unsigned int j = 0; j < sizes[face]; ++j, ++cell_index)
3884  {
3885  const unsigned int last_cell = (j == 0) ? 0U : (cell_index - 1);
3886 
3887  for (unsigned int v = 0; v < GeometryInfo<dim>::vertices_per_face;
3888  ++v)
3889  {
3890  const unsigned int cellv =
3892  const unsigned int ocellv =
3894  // First the vertices which already exist
3895  cells[cell_index].vertices[ocellv] =
3896  cells[last_cell].vertices[cellv];
3897 
3898  // Now the new vertices
3899  cells[cell_index].vertices[cellv] = points.size();
3900 
3901  Point<spacedim> p = points[cells[cell_index].vertices[ocellv]];
3903  dimensions[dir];
3904  points.push_back(p);
3905  }
3906  cells[cell_index].material_id = (colorize) ? (face + 1U) : 0U;
3907  }
3908  }
3909  tria.create_triangulation(points, cells, SubCellData());
3910  }
3911 
3912 
3913  template <>
3914  void
3915  hyper_cube_slit(Triangulation<1> &, const double, const double, const bool)
3916  {
3917  Assert(false, ExcNotImplemented());
3918  }
3919 
3920 
3921 
3922  template <>
3924  const double,
3925  const double,
3926  const double,
3927  const bool)
3928  {
3929  Assert(false, ExcNotImplemented());
3930  }
3931 
3932 
3933 
3934  template <>
3935  void hyper_L(Triangulation<1> &, const double, const double, const bool)
3936  {
3937  Assert(false, ExcNotImplemented());
3938  }
3939 
3940 
3941 
3942  template <>
3943  void
3944  hyper_ball(Triangulation<1> &, const Point<1> &, const double, const bool)
3945  {
3946  Assert(false, ExcNotImplemented());
3947  }
3948 
3949 
3950 
3951  template <>
3952  void cylinder(Triangulation<1> &, const double, const double)
3953  {
3954  Assert(false, ExcNotImplemented());
3955  }
3956 
3957 
3958  template <>
3960  const unsigned int,
3961  const double,
3962  const double)
3963  {
3964  Assert(false, ExcNotImplemented());
3965  }
3966 
3967 
3968 
3969  template <>
3970  void
3971  truncated_cone(Triangulation<1> &, const double, const double, const double)
3972  {
3973  Assert(false, ExcNotImplemented());
3974  }
3975 
3976 
3977 
3978  template <>
3980  const Point<1> &,
3981  const double,
3982  const double,
3983  const unsigned int,
3984  const bool)
3985  {
3986  Assert(false, ExcNotImplemented());
3987  }
3988 
3989  template <>
3991  const double,
3992  const double,
3993  const double,
3994  const unsigned int,
3995  const unsigned int)
3996  {
3997  Assert(false, ExcNotImplemented());
3998  }
3999 
4000 
4001  template <>
4002  void quarter_hyper_ball(Triangulation<1> &, const Point<1> &, const double)
4003  {
4004  Assert(false, ExcNotImplemented());
4005  }
4006 
4007 
4008  template <>
4009  void half_hyper_ball(Triangulation<1> &, const Point<1> &, const double)
4010  {
4011  Assert(false, ExcNotImplemented());
4012  }
4013 
4014 
4015  template <>
4017  const Point<1> &,
4018  const double,
4019  const double,
4020  const unsigned int,
4021  const bool)
4022  {
4023  Assert(false, ExcNotImplemented());
4024  }
4025 
4026  template <>
4028  const Point<1> &,
4029  const double,
4030  const double,
4031  const unsigned int,
4032  const bool)
4033  {
4034  Assert(false, ExcNotImplemented());
4035  }
4036 
4037  template <>
4039  const double left,
4040  const double right,
4041  const double thickness,
4042  const bool colorize)
4043  {
4044  Assert(left < right,
4045  ExcMessage("Invalid left-to-right bounds of enclosed hypercube"));
4046 
4047  std::vector<Point<2>> vertices(16);
4048  double coords[4];
4049  coords[0] = left - thickness;
4050  coords[1] = left;
4051  coords[2] = right;
4052  coords[3] = right + thickness;
4053 
4054  unsigned int k = 0;
4055  for (const double y : coords)
4056  for (const double x : coords)
4057  vertices[k++] = Point<2>(x, y);
4058 
4059  const types::material_id materials[9] = {5, 4, 6, 1, 0, 2, 9, 8, 10};
4060 
4061  std::vector<CellData<2>> cells(9);
4062  k = 0;
4063  for (unsigned int i0 = 0; i0 < 3; ++i0)
4064  for (unsigned int i1 = 0; i1 < 3; ++i1)
4065  {
4066  cells[k].vertices[0] = i1 + 4 * i0;
4067  cells[k].vertices[1] = i1 + 4 * i0 + 1;
4068  cells[k].vertices[2] = i1 + 4 * i0 + 4;
4069  cells[k].vertices[3] = i1 + 4 * i0 + 5;
4070  if (colorize)
4071  cells[k].material_id = materials[k];
4072  ++k;
4073  }
4075  cells,
4076  SubCellData()); // no boundary information
4077  }
4078 
4079 
4080 
4081  // Implementation for 2D only
4082  template <>
4083  void hyper_cube_slit(Triangulation<2> &tria,
4084  const double left,
4085  const double right,
4086  const bool colorize)
4087  {
4088  const double rl2 = (right + left) / 2;
4089  const Point<2> vertices[10] = {Point<2>(left, left),
4090  Point<2>(rl2, left),
4091  Point<2>(rl2, rl2),
4092  Point<2>(left, rl2),
4093  Point<2>(right, left),
4094  Point<2>(right, rl2),
4095  Point<2>(rl2, right),
4096  Point<2>(left, right),
4097  Point<2>(right, right),
4098  Point<2>(rl2, left)};
4099  const int cell_vertices[4][4] = {{0, 1, 3, 2},
4100  {9, 4, 2, 5},
4101  {3, 2, 7, 6},
4102  {2, 5, 6, 8}};
4103  std::vector<CellData<2>> cells(4, CellData<2>());
4104  for (unsigned int i = 0; i < 4; ++i)
4105  {
4106  for (unsigned int j = 0; j < 4; ++j)
4107  cells[i].vertices[j] = cell_vertices[i][j];
4108  cells[i].material_id = 0;
4109  }
4110  tria.create_triangulation(std::vector<Point<2>>(std::begin(vertices),
4111  std::end(vertices)),
4112  cells,
4113  SubCellData()); // no boundary information
4114 
4115  if (colorize)
4116  {
4117  Triangulation<2>::cell_iterator cell = tria.begin();
4118  cell->face(1)->set_boundary_id(1);
4119  ++cell;
4120  cell->face(0)->set_boundary_id(2);
4121  }
4122  }
4123 
4124 
4125 
4126  template <>
4128  const double radius_0,
4129  const double radius_1,
4130  const double half_length)
4131  {
4132  Point<2> vertices_tmp[4];
4133 
4134  vertices_tmp[0] = Point<2>(-half_length, -radius_0);
4135  vertices_tmp[1] = Point<2>(half_length, -radius_1);
4136  vertices_tmp[2] = Point<2>(-half_length, radius_0);
4137  vertices_tmp[3] = Point<2>(half_length, radius_1);
4138 
4139  const std::vector<Point<2>> vertices(std::begin(vertices_tmp),
4140  std::end(vertices_tmp));
4141  unsigned int cell_vertices[1][GeometryInfo<2>::vertices_per_cell];
4142 
4143  for (const unsigned int i : GeometryInfo<2>::vertex_indices())
4144  cell_vertices[0][i] = i;
4145 
4146  std::vector<CellData<2>> cells(1, CellData<2>());
4147 
4148  for (const unsigned int i : GeometryInfo<2>::vertex_indices())
4149  cells[0].vertices[i] = cell_vertices[0][i];
4150 
4151  cells[0].material_id = 0;
4152  triangulation.create_triangulation(vertices, cells, SubCellData());
4153 
4155 
4156  cell->face(0)->set_boundary_id(1);
4157  cell->face(1)->set_boundary_id(2);
4158 
4159  for (unsigned int i = 2; i < 4; ++i)
4160  cell->face(i)->set_boundary_id(0);
4161  }
4162 
4163 
4164 
4165  // Implementation for 2D only
4166  template <>
4167  void hyper_L(Triangulation<2> &tria,
4168  const double a,
4169  const double b,
4170  const bool colorize)
4171  {
4172  const Point<2> vertices[8] = {Point<2>(a, a),
4173  Point<2>((a + b) / 2, a),
4174  Point<2>(b, a),
4175  Point<2>(a, (a + b) / 2),
4176  Point<2>((a + b) / 2, (a + b) / 2),
4177  Point<2>(b, (a + b) / 2),
4178  Point<2>(a, b),
4179  Point<2>((a + b) / 2, b)};
4180  const int cell_vertices[3][4] = {{0, 1, 3, 4}, {1, 2, 4, 5}, {3, 4, 6, 7}};
4181 
4182  std::vector<CellData<2>> cells(3, CellData<2>());
4183 
4184  for (unsigned int i = 0; i < 3; ++i)
4185  {
4186  for (unsigned int j = 0; j < 4; ++j)
4187  cells[i].vertices[j] = cell_vertices[i][j];
4188  cells[i].material_id = 0;
4189  }
4190 
4191  tria.create_triangulation(std::vector<Point<2>>(std::begin(vertices),
4192  std::end(vertices)),
4193  cells,
4194  SubCellData());
4195 
4196  if (colorize)
4197  {
4198  Triangulation<2>::cell_iterator cell = tria.begin();
4199 
4200  cell->face(0)->set_boundary_id(0);
4201  cell->face(2)->set_boundary_id(1);
4202  cell++;
4203 
4204  cell->face(1)->set_boundary_id(2);
4205  cell->face(2)->set_boundary_id(1);
4206  cell->face(3)->set_boundary_id(3);
4207  cell++;
4208 
4209  cell->face(0)->set_boundary_id(0);
4210  cell->face(1)->set_boundary_id(4);
4211  cell->face(3)->set_boundary_id(5);
4212  }
4213  }
4214 
4215 
4216 
4217  template <int dim, int spacedim>
4218  void
4220  const std::vector<unsigned int> &repetitions,
4221  const Point<dim> & bottom_left,
4222  const Point<dim> & top_right,
4223  const std::vector<int> & n_cells_to_remove)
4224  {
4225  Assert(dim > 1, ExcNotImplemented());
4226  // Check the consistency of the dimensions provided.
4227  AssertDimension(repetitions.size(), dim);
4228  AssertDimension(n_cells_to_remove.size(), dim);
4229  for (unsigned int d = 0; d < dim; ++d)
4230  {
4231  Assert(std::fabs(n_cells_to_remove[d]) <= repetitions[d],
4232  ExcMessage("Attempting to cut away too many cells."));
4233  }
4234  // Create the domain to be cut
4235  Triangulation<dim, spacedim> rectangle;
4237  repetitions,
4238  bottom_left,
4239  top_right);
4240  // compute the vertex of the cut step, we will cut according to the
4241  // location of the cartesian coordinates of the cell centers
4242  std::array<double, dim> h;
4243  Point<dim> cut_step;
4244  for (unsigned int d = 0; d < dim; ++d)
4245  {
4246  // mesh spacing in each direction in cartesian coordinates
4247  h[d] = (top_right[d] - bottom_left[d]) / repetitions[d];
4248  // left to right, bottom to top, front to back
4249  if (n_cells_to_remove[d] >= 0)
4250  {
4251  // cartesian coordinates of vertex location
4252  cut_step[d] =
4253  h[d] * std::fabs(n_cells_to_remove[d]) + bottom_left[d];
4254  }
4255  // right to left, top to bottom, back to front
4256  else
4257  {
4258  cut_step[d] = top_right[d] - h[d] * std::fabs(n_cells_to_remove[d]);
4259  }
4260  }
4261 
4262 
4263  // compute cells to remove
4264  std::set<typename Triangulation<dim, spacedim>::active_cell_iterator>
4265  cells_to_remove;
4266  std::copy_if(
4267  rectangle.active_cell_iterators().begin(),
4268  rectangle.active_cell_iterators().end(),
4269  std::inserter(cells_to_remove, cells_to_remove.end()),
4270  [&](
4272  -> bool {
4273  for (unsigned int d = 0; d < dim; ++d)
4274  if ((n_cells_to_remove[d] > 0 && cell->center()[d] >= cut_step[d]) ||
4275  (n_cells_to_remove[d] < 0 && cell->center()[d] <= cut_step[d]))
4276  return false;
4277 
4278  return true;
4279  });
4280 
4282  cells_to_remove,
4283  tria);
4284  }
4285 
4286 
4287 
4288  // Implementation for 2D only
4289  template <>
4290  void hyper_ball(Triangulation<2> &tria,
4291  const Point<2> & p,
4292  const double radius,
4293  const bool internal_manifolds)
4294  {
4295  // equilibrate cell sizes at
4296  // transition from the inner part
4297  // to the radial cells
4298  const double a = 1. / (1 + std::sqrt(2.0));
4299  const Point<2> vertices[8] = {
4300  p + Point<2>(-1, -1) * (radius / std::sqrt(2.0)),
4301  p + Point<2>(+1, -1) * (radius / std::sqrt(2.0)),
4302  p + Point<2>(-1, -1) * (radius / std::sqrt(2.0) * a),
4303  p + Point<2>(+1, -1) * (radius / std::sqrt(2.0) * a),
4304  p + Point<2>(-1, +1) * (radius / std::sqrt(2.0) * a),
4305  p + Point<2>(+1, +1) * (radius / std::sqrt(2.0) * a),
4306  p + Point<2>(-1, +1) * (radius / std::sqrt(2.0)),
4307  p + Point<2>(+1, +1) * (radius / std::sqrt(2.0))};
4308 
4309  const int cell_vertices[5][4] = {
4310  {0, 1, 2, 3}, {0, 2, 6, 4}, {2, 3, 4, 5}, {1, 7, 3, 5}, {6, 4, 7, 5}};
4311 
4312  std::vector<CellData<2>> cells(5, CellData<2>());
4313 
4314  for (unsigned int i = 0; i < 5; ++i)
4315  {
4316  for (unsigned int j = 0; j < 4; ++j)
4317  cells[i].vertices[j] = cell_vertices[i][j];
4318  cells[i].material_id = 0;
4319  cells[i].manifold_id = i == 2 ? numbers::flat_manifold_id : 1;
4320  }
4321 
4322  tria.create_triangulation(std::vector<Point<2>>(std::begin(vertices),
4323  std::end(vertices)),
4324  cells,
4325  SubCellData()); // no boundary information
4327  tria.set_manifold(0, SphericalManifold<2>(p));
4328  if (internal_manifolds)
4329  tria.set_manifold(1, SphericalManifold<2>(p));
4330  }
4331 
4332 
4333 
4334  template <>
4335  void hyper_shell(Triangulation<2> & tria,
4336  const Point<2> & center,
4337  const double inner_radius,
4338  const double outer_radius,
4339  const unsigned int n_cells,
4340  const bool colorize)
4341  {
4342  Assert((inner_radius > 0) && (inner_radius < outer_radius),
4343  ExcInvalidRadii());
4344 
4345  const double pi = numbers::PI;
4346 
4347  // determine the number of cells
4348  // for the grid. if not provided by
4349  // the user determine it such that
4350  // the length of each cell on the
4351  // median (in the middle between
4352  // the two circles) is equal to its
4353  // radial extent (which is the
4354  // difference between the two
4355  // radii)
4356  const unsigned int N =
4357  (n_cells == 0 ? static_cast<unsigned int>(
4358  std::ceil((2 * pi * (outer_radius + inner_radius) / 2) /
4359  (outer_radius - inner_radius))) :
4360  n_cells);
4361 
4362  // set up N vertices on the
4363  // outer and N vertices on
4364  // the inner circle. the
4365  // first N ones are on the
4366  // outer one, and all are
4367  // numbered counter-clockwise
4368  std::vector<Point<2>> vertices(2 * N);
4369  for (unsigned int i = 0; i < N; ++i)
4370  {
4371  vertices[i] =
4372  Point<2>(std::cos(2 * pi * i / N), std::sin(2 * pi * i / N)) *
4373  outer_radius;
4374  vertices[i + N] = vertices[i] * (inner_radius / outer_radius);
4375 
4376  vertices[i] += center;
4377  vertices[i + N] += center;
4378  }
4379 
4380  std::vector<CellData<2>> cells(N, CellData<2>());
4381 
4382  for (unsigned int i = 0; i < N; ++i)
4383  {
4384  cells[i].vertices[0] = i;
4385  cells[i].vertices[1] = (i + 1) % N;
4386  cells[i].vertices[2] = N + i;
4387  cells[i].vertices[3] = N + ((i + 1) % N);
4388 
4389  cells[i].material_id = 0;
4390  }
4391 
4392  tria.create_triangulation(vertices, cells, SubCellData());
4393 
4394  if (colorize)
4395  colorize_hyper_shell(tria, center, inner_radius, outer_radius);
4396 
4397  tria.set_all_manifold_ids(0);
4399  }
4400 
4401 
4402 
4403  template <int dim>
4404  void
4406  const Point<dim> & inner_center,
4407  const Point<dim> & outer_center,
4408  const double inner_radius,
4409  const double outer_radius,
4410  const unsigned int n_cells)
4411  {
4413  tria, outer_center, inner_radius, outer_radius, n_cells, true);
4414 
4415  // check the consistency of the dimensions provided
4416  Assert(
4417  outer_radius - inner_radius > outer_center.distance(inner_center),
4419  "The inner radius is greater than or equal to the outer radius plus eccentricity."));
4420 
4421  // shift nodes along the inner boundary according to the position of
4422  // inner_circle
4423  std::set<Point<dim> *> vertices_to_move;
4424 
4425  for (const auto &face : tria.active_face_iterators())
4426  if (face->boundary_id() == 0)
4427  for (unsigned int v = 0; v < GeometryInfo<dim>::vertices_per_face; ++v)
4428  vertices_to_move.insert(&face->vertex(v));
4429 
4430  const auto shift = inner_center - outer_center;
4431  for (const auto &p : vertices_to_move)
4432  (*p) += shift;
4433 
4434  // the original hyper_shell function assigns the same manifold id
4435  // to all cells and faces. Set all manifolds ids to a different
4436  // value (2), then use boundary ids to assign different manifolds to
4437  // the inner (0) and outer manifolds (1). Use a transfinite manifold
4438  // for all faces and cells aside from the boundaries.
4439  tria.set_all_manifold_ids(2);
4441 
4442  SphericalManifold<dim> inner_manifold(inner_center);
4443  SphericalManifold<dim> outer_manifold(outer_center);
4444 
4446  transfinite.initialize(tria);
4447 
4448  tria.set_manifold(0, inner_manifold);
4449  tria.set_manifold(1, outer_manifold);
4450  tria.set_manifold(2, transfinite);
4451  }
4452 
4453 
4454 
4455  // Implementation for 2D only
4456  template <>
4457  void cylinder(Triangulation<2> &tria,
4458  const double radius,
4459  const double half_length)
4460  {
4461  Point<2> p1(-half_length, -radius);
4462  Point<2> p2(half_length, radius);
4463 
4464  hyper_rectangle(tria, p1, p2, true);
4465 
4468  while (f != end)
4469  {
4470  switch (f->boundary_id())
4471  {
4472  case 0:
4473  f->set_boundary_id(1);
4474  break;
4475  case 1:
4476  f->set_boundary_id(2);
4477  break;
4478  default:
4479  f->set_boundary_id(0);
4480  break;
4481  }
4482  ++f;
4483  }
4484  }
4485 
4486  template <>
4488  const unsigned int,
4489  const double,
4490  const double)
4491  {
4492  Assert(false, ExcNotImplemented());
4493  }
4494 
4495 
4496 
4497  // Implementation for 2D only
4498  template <>
4500  const double,
4501  const double,
4502  const double,
4503  const unsigned int,
4504  const unsigned int)
4505  {
4506  Assert(false, ExcNotImplemented());
4507  }
4508 
4509 
4510  template <>
4512  const Point<2> & p,
4513  const double radius)
4514  {
4515  const unsigned int dim = 2;
4516 
4517  // the numbers 0.55647 and 0.42883 have been found by a search for the
4518  // best aspect ratio (defined as the maximal between the minimal singular
4519  // value of the Jacobian)
4520  const Point<dim> vertices[7] = {p + Point<dim>(0, 0) * radius,
4521  p + Point<dim>(+1, 0) * radius,
4522  p + Point<dim>(+1, 0) * (radius * 0.55647),
4523  p + Point<dim>(0, +1) * (radius * 0.55647),
4524  p + Point<dim>(+1, +1) * (radius * 0.42883),
4525  p + Point<dim>(0, +1) * radius,
4526  p + Point<dim>(+1, +1) *
4527  (radius / std::sqrt(2.0))};
4528 
4529  const int cell_vertices[3][4] = {{0, 2, 3, 4}, {1, 6, 2, 4}, {5, 3, 6, 4}};
4530 
4531  std::vector<CellData<dim>> cells(3, CellData<dim>());
4532 
4533  for (unsigned int i = 0; i < 3; ++i)
4534  {
4535  for (unsigned int j = 0; j < 4; ++j)
4536  cells[i].vertices[j] = cell_vertices[i][j];
4537  cells[i].material_id = 0;
4538  }
4539 
4541  std::end(vertices)),
4542  cells,
4543  SubCellData()); // no boundary information
4544 
4547 
4549 
4550  while (cell != end)
4551  {
4552  for (unsigned int i : GeometryInfo<dim>::face_indices())
4553  {
4554  if (cell->face(i)->boundary_id() ==
4556  continue;
4557 
4558  // If one the components is the same as the respective
4559  // component of the center, then this is part of the plane
4560  if (cell->face(i)->center()(0) < p(0) + 1.e-5 * radius ||
4561  cell->face(i)->center()(1) < p(1) + 1.e-5 * radius)
4562  {
4563  cell->face(i)->set_boundary_id(1);
4564  cell->face(i)->set_manifold_id(numbers::flat_manifold_id);
4565  }
4566  }
4567  ++cell;
4568  }
4569  tria.set_manifold(0, SphericalManifold<2>(p));
4570  }
4571 
4572 
4573  template <>
4574  void half_hyper_ball(Triangulation<2> &tria,
4575  const Point<2> & p,
4576  const double radius)
4577  {
4578  // equilibrate cell sizes at
4579  // transition from the inner part
4580  // to the radial cells
4581  const double a = 1. / (1 + std::sqrt(2.0));
4582  const Point<2> vertices[8] = {
4583  p + Point<2>(0, -1) * radius,
4584  p + Point<2>(+1, -1) * (radius / std::sqrt(2.0)),
4585  p + Point<2>(0, -1) * (radius / std::sqrt(2.0) * a),
4586  p + Point<2>(+1, -1) * (radius / std::sqrt(2.0) * a),
4587  p + Point<2>(0, +1) * (radius / std::sqrt(2.0) * a),
4588  p + Point<2>(+1, +1) * (radius / std::sqrt(2.0) * a),
4589  p + Point<2>(0, +1) * radius,
4590  p + Point<2>(+1, +1) * (radius / std::sqrt(2.0))};
4591 
4592  const int cell_vertices[5][4] = {{0, 1, 2, 3},
4593  {2, 3, 4, 5},
4594  {1, 7, 3, 5},
4595  {6, 4, 7, 5}};
4596 
4597  std::vector<CellData<2>> cells(4, CellData<2>());
4598 
4599  for (unsigned int i = 0; i < 4; ++i)
4600  {
4601  for (unsigned int j = 0; j < 4; ++j)
4602  cells[i].vertices[j] = cell_vertices[i][j];
4603  cells[i].material_id = 0;
4604  }
4605 
4606  tria.create_triangulation(std::vector<Point<2>>(std::begin(vertices),
4607  std::end(vertices)),
4608  cells,
4609  SubCellData()); // no boundary information
4610 
4611  Triangulation<2>::cell_iterator cell = tria.begin();
4613 
4615 
4616  while (cell != end)
4617  {
4618  for (unsigned int i : GeometryInfo<2>::face_indices())
4619  {
4620  if (cell->face(i)->boundary_id() ==
4622  continue;
4623 
4624  // If x is zero, then this is part of the plane
4625  if (cell->face(i)->center()(0) < p(0) + 1.e-5 * radius)
4626  {
4627  cell->face(i)->set_boundary_id(1);
4628  cell->face(i)->set_manifold_id(numbers::flat_manifold_id);
4629  }
4630  }
4631  ++cell;
4632  }
4633  tria.set_manifold(0, SphericalManifold<2>(p));
4634  }
4635 
4636 
4637 
4638  // Implementation for 2D only
4639  template <>
4640  void half_hyper_shell(Triangulation<2> & tria,
4641  const Point<2> & center,
4642  const double inner_radius,
4643  const double outer_radius,
4644  const unsigned int n_cells,
4645  const bool colorize)
4646  {
4647  Assert((inner_radius > 0) && (inner_radius < outer_radius),
4648  ExcInvalidRadii());
4649 
4650  const double pi = numbers::PI;
4651  // determine the number of cells
4652  // for the grid. if not provided by
4653  // the user determine it such that
4654  // the length of each cell on the
4655  // median (in the middle between
4656  // the two circles) is equal to its
4657  // radial extent (which is the
4658  // difference between the two
4659  // radii)
4660  const unsigned int N =
4661  (n_cells == 0 ? static_cast<unsigned int>(
4662  std::ceil((pi * (outer_radius + inner_radius) / 2) /
4663  (outer_radius - inner_radius))) :
4664  n_cells);
4665 
4666  // set up N+1 vertices on the
4667  // outer and N+1 vertices on
4668  // the inner circle. the
4669  // first N+1 ones are on the
4670  // outer one, and all are
4671  // numbered counter-clockwise
4672  std::vector<Point<2>> vertices(2 * (N + 1));
4673  for (unsigned int i = 0; i <= N; ++i)
4674  {
4675  // enforce that the x-coordinates
4676  // of the first and last point of
4677  // each half-circle are exactly
4678  // zero (contrary to what we may
4679  // compute using the imprecise
4680  // value of pi)
4681  vertices[i] =
4682  Point<2>(((i == 0) || (i == N) ? 0 : std::cos(pi * i / N - pi / 2)),
4683  std::sin(pi * i / N - pi / 2)) *
4684  outer_radius;
4685  vertices[i + N + 1] = vertices[i] * (inner_radius / outer_radius);
4686 
4687  vertices[i] += center;
4688  vertices[i + N + 1] += center;
4689  }
4690 
4691 
4692  std::vector<CellData<2>> cells(N, CellData<2>());
4693 
4694  for (unsigned int i = 0; i < N; ++i)
4695  {
4696  cells[i].vertices[0] = i;
4697  cells[i].vertices[1] = (i + 1) % (N + 1);
4698  cells[i].vertices[2] = N + 1 + i;
4699  cells[i].vertices[3] = N + 1 + ((i + 1) % (N + 1));
4700 
4701  cells[i].material_id = 0;
4702  }
4703 
4704  tria.create_triangulation(vertices, cells, SubCellData());
4705 
4706  if (colorize)
4707  {
4708  Triangulation<2>::cell_iterator cell = tria.begin();
4709  for (; cell != tria.end(); ++cell)
4710  {
4711  cell->face(2)->set_boundary_id(1);
4712  }
4713  tria.begin()->face(0)->set_boundary_id(3);
4714 
4715  tria.last()->face(1)->set_boundary_id(2);
4716  }
4717  tria.set_all_manifold_ids(0);
4719  }
4720 
4721 
4722  template <>
4724  const Point<2> & center,
4725  const double inner_radius,
4726  const double outer_radius,
4727  const unsigned int n_cells,
4728  const bool colorize)
4729  {
4730  Assert((inner_radius > 0) && (inner_radius < outer_radius),
4731  ExcInvalidRadii());
4732 
4733  const double pi = numbers::PI;
4734  // determine the number of cells
4735  // for the grid. if not provided by
4736  // the user determine it such that
4737  // the length of each cell on the
4738  // median (in the middle between
4739  // the two circles) is equal to its
4740  // radial extent (which is the
4741  // difference between the two
4742  // radii)
4743  const unsigned int N =
4744  (n_cells == 0 ? static_cast<unsigned int>(
4745  std::ceil((pi * (outer_radius + inner_radius) / 4) /
4746  (outer_radius - inner_radius))) :
4747  n_cells);
4748 
4749  // set up N+1 vertices on the
4750  // outer and N+1 vertices on
4751  // the inner circle. the
4752  // first N+1 ones are on the
4753  // outer one, and all are
4754  // numbered counter-clockwise
4755  std::vector<Point<2>> vertices(2 * (N + 1));
4756  for (unsigned int i = 0; i <= N; ++i)
4757  {
4758  // enforce that the x-coordinates
4759  // of the last point is exactly
4760  // zero (contrary to what we may
4761  // compute using the imprecise
4762  // value of pi)
4763  vertices[i] = Point<2>(((i == N) ? 0 : std::cos(pi * i / N / 2)),
4764  std::sin(pi * i / N / 2)) *
4765  outer_radius;
4766  vertices[i + N + 1] = vertices[i] * (inner_radius / outer_radius);
4767 
4768  vertices[i] += center;
4769  vertices[i + N + 1] += center;
4770  }
4771 
4772 
4773  std::vector<CellData<2>> cells(N, CellData<2>());
4774 
4775  for (unsigned int i = 0; i < N; ++i)
4776  {
4777  cells[i].vertices[0] = i;
4778  cells[i].vertices[1] = (i + 1) % (N + 1);
4779  cells[i].vertices[2] = N + 1 + i;
4780  cells[i].vertices[3] = N + 1 + ((i + 1) % (N + 1));
4781 
4782  cells[i].material_id = 0;
4783  }
4784 
4785  tria.create_triangulation(vertices, cells, SubCellData());
4786 
4787  if (colorize)
4788  {
4789  Triangulation<2>::cell_iterator cell = tria.begin();
4790  for (; cell != tria.end(); ++cell)
4791  {
4792  cell->face(2)->set_boundary_id(1);
4793  }
4794  tria.begin()->face(0)->set_boundary_id(3);
4795 
4796  tria.last()->face(1)->set_boundary_id(2);
4797  }
4798 
4799  tria.set_all_manifold_ids(0);
4801  }
4802 
4803 
4804 
4805  // Implementation for 3D only
4806  template <>
4807  void hyper_cube_slit(Triangulation<3> &tria,
4808  const double left,
4809  const double right,
4810  const bool colorize)
4811  {
4812  const double rl2 = (right + left) / 2;
4813  const double len = (right - left) / 2.;
4814 
4815  const Point<3> vertices[20] = {
4816  Point<3>(left, left, -len / 2.), Point<3>(rl2, left, -len / 2.),
4817  Point<3>(rl2, rl2, -len / 2.), Point<3>(left, rl2, -len / 2.),
4818  Point<3>(right, left, -len / 2.), Point<3>(right, rl2, -len / 2.),
4819  Point<3>(rl2, right, -len / 2.), Point<3>(left, right, -len / 2.),
4820  Point<3>(right, right, -len / 2.), Point<3>(rl2, left, -len / 2.),
4821  Point<3>(left, left, len / 2.), Point<3>(rl2, left, len / 2.),
4822  Point<3>(rl2, rl2, len / 2.), Point<3>(left, rl2, len / 2.),
4823  Point<3>(right, left, len / 2.), Point<3>(right, rl2, len / 2.),
4824  Point<3>(rl2, right, len / 2.), Point<3>(left, right, len / 2.),
4825  Point<3>(right, right, len / 2.), Point<3>(rl2, left, len / 2.)};
4826  const int cell_vertices[4][8] = {{0, 1, 3, 2, 10, 11, 13, 12},
4827  {9, 4, 2, 5, 19, 14, 12, 15},
4828  {3, 2, 7, 6, 13, 12, 17, 16},
4829  {2, 5, 6, 8, 12, 15, 16, 18}};
4830  std::vector<CellData<3>> cells(4, CellData<3>());
4831  for (unsigned int i = 0; i < 4; ++i)
4832  {
4833  for (unsigned int j = 0; j < 8; ++j)
4834  cells[i].vertices[j] = cell_vertices[i][j];
4835  cells[i].material_id = 0;
4836  }
4837  tria.create_triangulation(std::vector<Point<3>>(std::begin(vertices),
4838  std::end(vertices)),
4839  cells,
4840  SubCellData()); // no boundary information
4841 
4842  if (colorize)
4843  {
4844  Triangulation<3>::cell_iterator cell = tria.begin();
4845  cell->face(1)->set_boundary_id(1);
4846  ++cell;
4847  cell->face(0)->set_boundary_id(2);
4848  }
4849  }
4850 
4851 
4852 
4853  // Implementation for 3D only
4854  template <>
4856  const double left,
4857  const double right,
4858  const double thickness,
4859  const bool colorize)
4860  {
4861  Assert(left < right,
4862  ExcMessage("Invalid left-to-right bounds of enclosed hypercube"));
4863 
4864  std::vector<Point<3>> vertices(64);
4865  double coords[4];
4866  coords[0] = left - thickness;
4867  coords[1] = left;
4868  coords[2] = right;
4869  coords[3] = right + thickness;
4870 
4871  unsigned int k = 0;
4872  for (const double z : coords)
4873  for (const double y : coords)
4874  for (const double x : coords)
4875  vertices[k++] = Point<3>(x, y, z);
4876 
4877  const types::material_id materials[27] = {21, 20, 22, 17, 16, 18, 25,
4878  24, 26, 5, 4, 6, 1, 0,
4879  2, 9, 8, 10, 37, 36, 38,
4880  33, 32, 34, 41, 40, 42};
4881 
4882  std::vector<CellData<3>> cells(27);
4883  k = 0;
4884  for (unsigned int z = 0; z < 3; ++z)
4885  for (unsigned int y = 0; y < 3; ++y)
4886  for (unsigned int x = 0; x < 3; ++x)
4887  {
4888  cells[k].vertices[0] = x + 4 * y + 16 * z;
4889  cells[k].vertices[1] = x + 4 * y + 16 * z + 1;
4890  cells[k].vertices[2] = x + 4 * y + 16 * z + 4;
4891  cells[k].vertices[3] = x + 4 * y + 16 * z + 5;
4892  cells[k].vertices[4] = x + 4 * y + 16 * z + 16;
4893  cells[k].vertices[5] = x + 4 * y + 16 * z + 17;
4894  cells[k].vertices[6] = x + 4 * y + 16 * z + 20;
4895  cells[k].vertices[7] = x + 4 * y + 16 * z + 21;
4896  if (colorize)
4897  cells[k].material_id = materials[k];
4898  ++k;
4899  }
4901  cells,
4902  SubCellData()); // no boundary information
4903  }
4904 
4905 
4906 
4907  template <>
4909  const double radius_0,
4910  const double radius_1,
4911  const double half_length)
4912  {
4913  Assert(triangulation.n_cells() == 0,
4914  ExcMessage("The output triangulation object needs to be empty."));
4915  Assert(0 < radius_0, ExcMessage("The radii must be positive."));
4916  Assert(0 < radius_1, ExcMessage("The radii must be positive."));
4917  Assert(0 < half_length, ExcMessage("The half length must be positive."));
4918 
4919  const auto n_slices = 1 + static_cast<unsigned int>(std::ceil(
4920  half_length / std::max(radius_0, radius_1)));
4921 
4922  Triangulation<2> triangulation_2;
4923  GridGenerator::hyper_ball(triangulation_2, Point<2>(), radius_0);
4924  GridGenerator::extrude_triangulation(triangulation_2,
4925  n_slices,
4926  2 * half_length,
4927  triangulation);
4929  GridTools::shift(Tensor<1, 3>({-half_length, 0.0, 0.0}), triangulation);
4930  // At this point we have a cylinder. Multiply the y and z coordinates by a
4931  // factor that scales (with x) linearly between radius_0 and radius_1 to fix
4932  // the circle radii and interior points:
4933  auto shift_radii = [=](const Point<3> &p) {
4934  const double slope = (radius_1 / radius_0 - 1.0) / (2.0 * half_length);
4935  const double factor = slope * (p[0] - -half_length) + 1.0;
4936  return Point<3>(p[0], factor * p[1], factor * p[2]);
4937  };
4938  GridTools::transform(shift_radii, triangulation);
4939 
4940  // Set boundary ids at -half_length to 1 and at half_length to 2. Set the
4941  // manifold id on hull faces (i.e., faces not on either end) to 0.
4942  for (const auto &face : triangulation.active_face_iterators())
4943  if (face->at_boundary())
4944  {
4945  if (std::abs(face->center()[0] - -half_length) < 1e-8 * half_length)
4946  face->set_boundary_id(1);
4947  else if (std::abs(face->center()[0] - half_length) <
4948  1e-8 * half_length)
4949  face->set_boundary_id(2);
4950  else
4951  face->set_all_manifold_ids(0);
4952  }
4953 
4954  triangulation.set_manifold(0, CylindricalManifold<3>());
4955  }
4956 
4957 
4958  // Implementation for 3D only
4959  template <>
4960  void hyper_L(Triangulation<3> &tria,
4961  const double a,
4962  const double b,
4963  const bool colorize)
4964  {
4965  // we slice out the top back right
4966  // part of the cube
4967  const Point<3> vertices[26] = {
4968  // front face of the big cube
4969  Point<3>(a, a, a),
4970  Point<3>((a + b) / 2, a, a),
4971  Point<3>(b, a, a),
4972  Point<3>(a, a, (a + b) / 2),
4973  Point<3>((a + b) / 2, a, (a + b) / 2),
4974  Point<3>(b, a, (a + b) / 2),
4975  Point<3>(a, a, b),
4976  Point<3>((a + b) / 2, a, b),
4977  Point<3>(b, a, b),
4978  // middle face of the big cube
4979  Point<3>(a, (a + b) / 2, a),
4980  Point<3>((a + b) / 2, (a + b) / 2, a),
4981  Point<3>(b, (a + b) / 2, a),
4982  Point<3>(a, (a + b) / 2, (a + b) / 2),
4983  Point<3>((a + b) / 2, (a + b) / 2, (a + b) / 2),
4984  Point<3>(b, (a + b) / 2, (a + b) / 2),
4985  Point<3>(a, (a + b) / 2, b),
4986  Point<3>((a + b) / 2, (a + b) / 2, b),
4987  Point<3>(b, (a + b) / 2, b),
4988  // back face of the big cube
4989  // last (top right) point is missing
4990  Point<3>(a, b, a),
4991  Point<3>((a + b) / 2, b, a),
4992  Point<3>(b, b, a),
4993  Point<3>(a, b, (a + b) / 2),
4994  Point<3>((a + b) / 2, b, (a + b) / 2),
4995  Point<3>(b, b, (a + b) / 2),
4996  Point<3>(a, b, b),
4997  Point<3>((a + b) / 2, b, b)};
4998  const int cell_vertices[7][8] = {{0, 1, 9, 10, 3, 4, 12, 13},
4999  {1, 2, 10, 11, 4, 5, 13, 14},
5000  {3, 4, 12, 13, 6, 7, 15, 16},
5001  {4, 5, 13, 14, 7, 8, 16, 17},
5002  {9, 10, 18, 19, 12, 13, 21, 22},
5003  {10, 11, 19, 20, 13, 14, 22, 23},
5004  {12, 13, 21, 22, 15, 16, 24, 25}};
5005 
5006  std::vector<CellData<3>> cells(7, CellData<3>());
5007 
5008  for (unsigned int i = 0; i < 7; ++i)
5009  {
5010  for (unsigned int j = 0; j < 8; ++j)
5011  cells[i].vertices[j] = cell_vertices[i][j];
5012  cells[i].material_id = 0;
5013  }
5014 
5015  tria.create_triangulation(std::vector<Point<3>>(std::begin(vertices),
5016  std::end(vertices)),
5017  cells,
5018  SubCellData()); // no boundary information
5019 
5020  if (colorize)
5021  {
5022  Assert(false, ExcNotImplemented());
5023  }
5024  }
5025 
5026 
5027 
5028  // Implementation for 3D only
5029  template <>
5030  void hyper_ball(Triangulation<3> &tria,
5031  const Point<3> & p,
5032  const double radius,
5033  const bool internal_manifold)
5034  {
5035  const double a =
5036  1. / (1 + std::sqrt(3.0)); // equilibrate cell sizes at transition
5037  // from the inner part to the radial
5038  // cells
5039  const unsigned int n_vertices = 16;
5040  const Point<3> vertices[n_vertices] = {
5041  // first the vertices of the inner
5042  // cell
5043  p + Point<3>(-1, -1, -1) * (radius / std::sqrt(3.0) * a),
5044  p + Point<3>(+1, -1, -1) * (radius / std::sqrt(3.0) * a),
5045  p + Point<3>(+1, -1, +1) * (radius / std::sqrt(3.0) * a),
5046  p + Point<3>(-1, -1, +1) * (radius / std::sqrt(3.0) * a),
5047  p + Point<3>(-1, +1, -1) * (radius / std::sqrt(3.0) * a),
5048  p + Point<3>(+1, +1, -1) * (radius / std::sqrt(3.0) * a),
5049  p + Point<3>(+1, +1, +1) * (radius / std::sqrt(3.0) * a),
5050  p + Point<3>(-1, +1, +1) * (radius / std::sqrt(3.0) * a),
5051  // now the eight vertices at
5052  // the outer sphere
5053  p + Point<3>(-1, -1, -1) * (radius / std::sqrt(3.0)),
5054  p + Point<3>(+1, -1, -1) * (radius / std::sqrt(3.0)),
5055  p + Point<3>(+1, -1, +1) * (radius / std::sqrt(3.0)),
5056  p + Point<3>(-1, -1, +1) * (radius / std::sqrt(3.0)),
5057  p + Point<3>(-1, +1, -1) * (radius / std::sqrt(3.0)),
5058  p + Point<3>(+1, +1, -1) * (radius / std::sqrt(3.0)),
5059  p + Point<3>(+1, +1, +1) * (radius / std::sqrt(3.0)),
5060  p + Point<3>(-1, +1, +1) * (radius / std::sqrt(3.0)),
5061  };
5062 
5063  // one needs to draw the seven cubes to
5064  // understand what's going on here
5065  const unsigned int n_cells = 7;
5066  const int cell_vertices[n_cells][8] = {
5067  {0, 1, 4, 5, 3, 2, 7, 6}, // center
5068  {8, 9, 12, 13, 0, 1, 4, 5}, // bottom
5069  {9, 13, 1, 5, 10, 14, 2, 6}, // right
5070  {11, 10, 3, 2, 15, 14, 7, 6}, // top
5071  {8, 0, 12, 4, 11, 3, 15, 7}, // left
5072  {8, 9, 0, 1, 11, 10, 3, 2}, // front
5073  {12, 4, 13, 5, 15, 7, 14, 6}}; // back
5074 
5075  std::vector<CellData<3>> cells(n_cells, CellData<3>());
5076 
5077  for (unsigned int i = 0; i < n_cells; ++i)
5078  {
5079  for (const unsigned int j : GeometryInfo<3>::vertex_indices())
5080  cells[i].vertices[j] = cell_vertices[i][j];
5081  cells[i].material_id = 0;
5082  cells[i].manifold_id = i == 0 ? numbers::flat_manifold_id : 1;
5083  }
5084 
5085  tria.create_triangulation(std::vector<Point<3>>(std::begin(vertices),
5086  std::end(vertices)),
5087  cells,
5088  SubCellData()); // no boundary information
5090  tria.set_manifold(0, SphericalManifold<3>(p));
5091  if (internal_manifold)
5092  tria.set_manifold(1, SphericalManifold<3>(p));
5093  }
5094 
5095 
5097  const bool rotate_left_square,
5098  const bool rotate_right_square)
5099  {
5100  constexpr unsigned int dim = 2;
5101 
5102  const unsigned int n_cells = 2;
5103  std::vector<CellData<dim>> cells(n_cells);
5104 
5105  // Corner points of the cube [0,1]^2
5106  const std::vector<Point<dim>> vertices = {Point<dim>(0, 0), // 0
5107  Point<dim>(1, 0), // 1
5108  Point<dim>(0, 1), // 2
5109  Point<dim>(1, 1), // 3
5110  Point<dim>(2, 0), // 4
5111  Point<dim>(2, 1)}; // 5
5112 
5113 
5114  // consistent orientation
5115  unsigned int cell_vertices[n_cells][4] = {{0, 1, 2, 3}, // unit cube
5116  {1, 4, 3, 5}}; // shifted cube
5117 
5118  // all 4 true-false combinations of (rotate_left_square | rotate_right_square) to a number 0..3
5119  unsigned int this_case = 2 * rotate_left_square + rotate_right_square;
5120 
5121  switch (this_case)
5122  {
5123  case /* rotate only right square */ 1:
5124  {
5125  cell_vertices[1][0] = 4;
5126  cell_vertices[1][1] = 5;
5127  cell_vertices[1][2] = 1;
5128  cell_vertices[1][3] = 3;
5129  break;
5130  }
5131 
5132  case /* rotate only left square */ 2:
5133  {
5134  cell_vertices[0][0] = 1;
5135  cell_vertices[0][1] = 3;
5136  cell_vertices[0][2] = 0;
5137  cell_vertices[0][3] = 2;
5138  break;
5139  }
5140 
5141  case /* rotate both squares (again consistent orientation) */ 3:
5142  {
5143  cell_vertices[0][0] = 1;
5144  cell_vertices[0][1] = 3;
5145  cell_vertices[0][2] = 0;
5146  cell_vertices[0][3] = 2;
5147 
5148  cell_vertices[1][0] = 4;
5149  cell_vertices[1][1] = 5;
5150  cell_vertices[1][2] = 1;
5151  cell_vertices[1][3] = 3;
5152  break;
5153  }
5154 
5155  default /* 0 */:
5156  break;
5157  } // switch
5158 
5159  cells.resize(n_cells, CellData<dim>());
5160 
5161  for (unsigned int cell_index = 0; cell_index < n_cells; ++cell_index)
5162  {
5163  for (const unsigned int vertex_index :
5165  {
5166  cells[cell_index].vertices[vertex_index] =
5167  cell_vertices[cell_index][vertex_index];
5168  cells[cell_index].material_id = 0;
5169  }
5170  }
5171 
5172  tria.create_triangulation(vertices, cells, SubCellData());
5173  }
5174 
5175 
5177  const bool face_orientation,
5178  const bool face_flip,
5179  const bool face_rotation,
5180  const bool manipulate_left_cube)
5181  {
5182  constexpr unsigned int dim = 3;
5183 
5184  const unsigned int n_cells = 2;
5185  std::vector<CellData<dim>> cells(n_cells);
5186 
5187  // Corner points of the cube [0,1]^3
5188  const std::vector<Point<dim>> vertices = {Point<dim>(0, 0, 0), // 0
5189  Point<dim>(1, 0, 0), // 1
5190  Point<dim>(0, 1, 0), // 2
5191  Point<dim>(1, 1, 0), // 3
5192  Point<dim>(0, 0, 1), // 4
5193  Point<dim>(1, 0, 1), // 5
5194  Point<dim>(0, 1, 1), // 6
5195  Point<dim>(1, 1, 1), // 7
5196  Point<dim>(2, 0, 0), // 8
5197  Point<dim>(2, 1, 0), // 9
5198  Point<dim>(2, 0, 1), // 10
5199  Point<dim>(2, 1, 1)}; // 11
5200 
5201  unsigned int cell_vertices[n_cells][8] = {
5202  {0, 1, 2, 3, 4, 5, 6, 7}, // unit cube
5203  {1, 8, 3, 9, 5, 10, 7, 11}}; // shifted cube
5204 
5205  // binary to case number
5206  const unsigned int this_case =
5207  4 * face_orientation + 2 * face_flip + face_rotation;
5208 
5209  if (manipulate_left_cube)
5210  {
5211  switch (this_case)
5212  {
5213  case 0:
5214  {
5215  cell_vertices[0][0] = 1;
5216  cell_vertices[0][1] = 0;
5217  cell_vertices[0][2] = 5;
5218  cell_vertices[0][3] = 4;
5219  cell_vertices[0][4] = 3;
5220  cell_vertices[0][5] = 2;
5221  cell_vertices[0][6] = 7;
5222  cell_vertices[0][7] = 6;
5223  break;
5224  }
5225 
5226  case 1:
5227  {
5228  cell_vertices[0][0] = 5;
5229  cell_vertices[0][1] = 4;
5230  cell_vertices[0][2] = 7;
5231  cell_vertices[0][3] = 6;
5232  cell_vertices[0][4] = 1;
5233  cell_vertices[0][5] = 0;
5234  cell_vertices[0][6] = 3;
5235  cell_vertices[0][7] = 2;
5236  break;
5237  }
5238 
5239  case 2:
5240  {
5241  cell_vertices[0][0] = 7;
5242  cell_vertices[0][1] = 6;
5243  cell_vertices[0][2] = 3;
5244  cell_vertices[0][3] = 2;
5245  cell_vertices[0][4] = 5;
5246  cell_vertices[0][5] = 4;
5247  cell_vertices[0][6] = 1;
5248  cell_vertices[0][7] = 0;
5249  break;
5250  }
5251  case 3:
5252  {
5253  cell_vertices[0][0] = 3;
5254  cell_vertices[0][1] = 2;
5255  cell_vertices[0][2] = 1;
5256  cell_vertices[0][3] = 0;
5257  cell_vertices[0][4] = 7;
5258  cell_vertices[0][5] = 6;
5259  cell_vertices[0][6] = 5;
5260  cell_vertices[0][7] = 4;
5261  break;
5262  }
5263 
5264  case 4:
5265  {
5266  cell_vertices[0][0] = 0;
5267  cell_vertices[0][1] = 1;
5268  cell_vertices[0][2] = 2;
5269  cell_vertices[0][3] = 3;
5270  cell_vertices[0][4] = 4;
5271  cell_vertices[0][5] = 5;
5272  cell_vertices[0][6] = 6;
5273  cell_vertices[0][7] = 7;
5274  break;
5275  }
5276 
5277  case 5:
5278  {
5279  cell_vertices[0][0] = 2;
5280  cell_vertices[0][1] = 3;
5281  cell_vertices[0][2] = 6;
5282  cell_vertices[0][3] = 7;
5283  cell_vertices[0][4] = 0;
5284  cell_vertices[0][5] = 1;
5285  cell_vertices[0][6] = 4;
5286  cell_vertices[0][7] = 5;
5287  break;
5288  }
5289 
5290  case 6:
5291  {
5292  cell_vertices[0][0] = 6;
5293  cell_vertices[0][1] = 7;
5294  cell_vertices[0][2] = 4;
5295  cell_vertices[0][3] = 5;
5296  cell_vertices[0][4] = 2;
5297  cell_vertices[0][5] = 3;
5298  cell_vertices[0][6] = 0;
5299  cell_vertices[0][7] = 1;
5300  break;
5301  }
5302 
5303  case 7:
5304  {
5305  cell_vertices[0][0] = 4;
5306  cell_vertices[0][1] = 5;
5307  cell_vertices[0][2] = 0;
5308  cell_vertices[0][3] = 1;
5309  cell_vertices[0][4] = 6;
5310  cell_vertices[0][5] = 7;
5311  cell_vertices[0][6] = 2;
5312  cell_vertices[0][7] = 3;
5313  break;
5314  }
5315  } // switch
5316  }
5317  else
5318  {
5319  switch (this_case)
5320  {
5321  case 0:
5322  {
5323  cell_vertices[1][0] = 8;
5324  cell_vertices[1][1] = 1;
5325  cell_vertices[1][2] = 10;
5326  cell_vertices[1][3] = 5;
5327  cell_vertices[1][4] = 9;
5328  cell_vertices[1][5] = 3;
5329  cell_vertices[1][6] = 11;
5330  cell_vertices[1][7] = 7;
5331  break;
5332  }
5333 
5334  case 1:
5335  {
5336  cell_vertices[1][0] = 10;
5337  cell_vertices[1][1] = 5;
5338  cell_vertices[1][2] = 11;
5339  cell_vertices[1][3] = 7;
5340  cell_vertices[1][4] = 8;
5341  cell_vertices[1][5] = 1;
5342  cell_vertices[1][6] = 9;
5343  cell_vertices[1][7] = 3;
5344  break;
5345  }
5346 
5347  case 2:
5348  {
5349  cell_vertices[1][0] = 11;
5350  cell_vertices[1][1] = 7;
5351  cell_vertices[1][2] = 9;
5352  cell_vertices[1][3] = 3;
5353  cell_vertices[1][4] = 10;
5354  cell_vertices[1][5] = 5;
5355  cell_vertices[1][6] = 8;
5356  cell_vertices[1][7] = 1;
5357  break;
5358  }
5359 
5360  case 3:
5361  {
5362  cell_vertices[1][0] = 9;
5363  cell_vertices[1][1] = 3;
5364  cell_vertices[1][2] = 8;
5365  cell_vertices[1][3] = 1;
5366  cell_vertices[1][4] = 11;
5367  cell_vertices[1][5] = 7;
5368  cell_vertices[1][6] = 10;
5369  cell_vertices[1][7] = 5;
5370  break;
5371  }
5372 
5373  case 4:
5374  {
5375  cell_vertices[1][0] = 1;
5376  cell_vertices[1][1] = 8;
5377  cell_vertices[1][2] = 3;
5378  cell_vertices[1][3] = 9;
5379  cell_vertices[1][4] = 5;
5380  cell_vertices[1][5] = 10;
5381  cell_vertices[1][6] = 7;
5382  cell_vertices[1][7] = 11;
5383  break;
5384  }
5385 
5386  case 5:
5387  {
5388  cell_vertices[1][0] = 5;
5389  cell_vertices[1][1] = 10;
5390  cell_vertices[1][2] = 1;
5391  cell_vertices[1][3] = 8;
5392  cell_vertices[1][4] = 7;
5393  cell_vertices[1][5] = 11;
5394  cell_vertices[1][6] = 3;
5395  cell_vertices[1][7] = 9;
5396  break;
5397  }
5398 
5399  case 6:
5400  {
5401  cell_vertices[1][0] = 7;
5402  cell_vertices[1][1] = 11;
5403  cell_vertices[1][2] = 5;
5404  cell_vertices[1][3] = 10;
5405  cell_vertices[1][4] = 3;
5406  cell_vertices[1][5] = 9;
5407  cell_vertices[1][6] = 1;
5408  cell_vertices[1][7] = 8;
5409  break;
5410  }
5411 
5412  case 7:
5413  {
5414  cell_vertices[1][0] = 3;
5415  cell_vertices[1][1] = 9;
5416  cell_vertices[1][2] = 7;
5417  cell_vertices[1][3] = 11;
5418  cell_vertices[1][4] = 1;
5419  cell_vertices[1][5] = 8;
5420  cell_vertices[1][6] = 5;
5421  cell_vertices[1][7] = 10;
5422  break;
5423  }
5424  } // switch
5425  }
5426 
5427  cells.resize(n_cells, CellData<dim>());
5428 
5429  for (unsigned int cell_index = 0; cell_index < n_cells; ++cell_index)
5430  {
5431  for (const unsigned int vertex_index :
5433  {
5434  cells[cell_index].vertices[vertex_index] =
5435  cell_vertices[cell_index][vertex_index];
5436  cells[cell_index].material_id = 0;
5437  }
5438  }
5439 
5440  tria.create_triangulation(vertices, cells, SubCellData());
5441  }
5442 
5443 
5444 
5445  template <int spacedim>
5447  const Point<spacedim> & p,
5448  const double radius)
5449  {
5450  Triangulation<spacedim> volume_mesh;
5451  GridGenerator::hyper_ball(volume_mesh, p, radius);
5452  std::set<types::boundary_id> boundary_ids;
5453  boundary_ids.insert(0);
5454  GridGenerator::extract_boundary_mesh(volume_mesh, tria, boundary_ids);
5455  tria.set_all_manifold_ids(0);
5457  }
5458 
5459 
5460 
5461  // Implementation for 3D only
5462  template <>
5464  const unsigned int x_subdivisions,
5465  const double radius,
5466  const double half_length)
5467  {
5468  // Copy the base from hyper_ball<3>
5469  // and transform it to yz
5470  const double d = radius / std::sqrt(2.0);
5471  const double a = d / (1 + std::sqrt(2.0));
5472 
5473  std::vector<Point<3>> vertices;
5474  const double initial_height = -half_length;
5475  const double height_increment = 2. * half_length / x_subdivisions;
5476 
5477  for (unsigned int rep = 0; rep < (x_subdivisions + 1); ++rep)
5478  {
5479  const double height = initial_height + height_increment * rep;
5480 
5481  vertices.emplace_back(Point<3>(-d, height, -d));
5482  vertices.emplace_back(Point<3>(d, height, -d));
5483  vertices.emplace_back(Point<3>(-a, height, -a));
5484  vertices.emplace_back(Point<3>(a, height, -a));
5485  vertices.emplace_back(Point<3>(-a, height, a));
5486  vertices.emplace_back(Point<3>(a, height, a));
5487  vertices.emplace_back(Point<3>(-d, height, d));
5488  vertices.emplace_back(Point<3>(d, height, d));
5489  }
5490 
5491  // Turn cylinder such that y->x
5492  for (auto &vertex : vertices)
5493  {
5494  const double h = vertex(1);
5495  vertex(1) = -vertex(0);
5496  vertex(0) = h;
5497  }
5498 
5499  std::vector<std::vector<int>> cell_vertices;
5500  cell_vertices.push_back({0, 1, 8, 9, 2, 3, 10, 11});
5501  cell_vertices.push_back({0, 2, 8, 10, 6, 4, 14, 12});
5502  cell_vertices.push_back({2, 3, 10, 11, 4, 5, 12, 13});
5503  cell_vertices.push_back({1, 7, 9, 15, 3, 5, 11, 13});
5504  cell_vertices.push_back({6, 4, 14, 12, 7, 5, 15, 13});
5505 
5506  for (unsigned int rep = 1; rep < x_subdivisions; ++rep)
5507  {
5508  for (unsigned int i = 0; i < 5; ++i)
5509  {
5510  std::vector<int> new_cell_vertices(8);
5511  for (unsigned int j = 0; j < 8; ++j)
5512  new_cell_vertices[j] = cell_vertices[i][j] + 8 * rep;
5513  cell_vertices.push_back(new_cell_vertices);
5514  }
5515  }
5516 
5517  unsigned int n_cells = x_subdivisions * 5;
5518 
5519  std::vector<CellData<3>> cells(n_cells, CellData<3>());
5520 
5521  for (unsigned int i = 0; i < n_cells; ++i)
5522  {
5523  for (unsigned int j = 0; j < 8; ++j)
5524  cells[i].vertices[j] = cell_vertices[i][j];
5525  cells[i].material_id = 0;
5526  }
5527 
5528  tria.create_triangulation(std::vector<Point<3>>(std::begin(vertices),
5529  std::end(vertices)),
5530  cells,
5531  SubCellData()); // no boundary information
5532 
5533  // set boundary indicators for the
5534  // faces at the ends to 1 and 2,
5535  // respectively. note that we also
5536  // have to deal with those lines
5537  // that are purely in the interior
5538  // of the ends. we determine whether
5539  // an edge is purely in the
5540  // interior if one of its vertices
5541  // is at coordinates '+-a' as set
5542  // above
5544 
5545  for (const auto &cell : tria.cell_iterators())
5546  for (unsigned int i : GeometryInfo<3>::face_indices())
5547  if (cell->at_boundary(i))
5548  {
5549  if (cell->face(i)->center()(0) > half_length - 1.e-5)
5550  {
5551  cell->face(i)->set_boundary_id(2);
5552  cell->face(i)->set_manifold_id(numbers::flat_manifold_id);
5553 
5554  for (unsigned int e = 0; e < GeometryInfo<3>::lines_per_face;
5555  ++e)
5556  if ((std::fabs(cell->face(i)->line(e)->vertex(0)[1]) == a) ||
5557  (std::fabs(cell->face(i)->line(e)->vertex(0)[2]) == a) ||
5558  (std::fabs(cell->face(i)->line(e)->vertex(1)[1]) == a) ||
5559  (std::fabs(cell->face(i)->line(e)->vertex(1)[2]) == a))
5560  {
5561  cell->face(i)->line(e)->set_boundary_id(2);
5562  cell->face(i)->line(e)->set_manifold_id(
5564  }
5565  }
5566  else if (cell->face(i)->center()(0) < -half_length + 1.e-5)
5567  {
5568  cell->face(i)->set_boundary_id(1);
5569  cell->face(i)->set_manifold_id(numbers::flat_manifold_id);
5570 
5571  for (unsigned int e = 0; e < GeometryInfo<3>::lines_per_face;
5572  ++e)
5573  if ((std::fabs(cell->face(i)->line(e)->vertex(0)[1]) == a) ||
5574  (std::fabs(cell->face(i)->line(e)->vertex(0)[2]) == a) ||
5575  (std::fabs(cell->face(i)->line(e)->vertex(1)[1]) == a) ||
5576  (std::fabs(cell->face(i)->line(e)->vertex(1)[2]) == a))
5577  {
5578  cell->face(i)->line(e)->set_boundary_id(1);
5579  cell->face(i)->line(e)->set_manifold_id(
5581  }
5582  }
5583  }
5585  }
5586 
5587  // Implementation for 3D only
5588  template <>
5589  void cylinder(Triangulation<3> &tria,
5590  const double radius,
5591  const double half_length)
5592  {
5593  subdivided_cylinder(tria, 2, radius, half_length);
5594  }
5595 
5596  template <>
5598  const Point<3> & center,
5599  const double radius)
5600  {
5601  const unsigned int dim = 3;
5602 
5603  // the parameters a (intersection on the octant lines from center), b
5604  // (intersection within the octant faces) and c (position inside the
5605  // octant) have been derived by equilibrating the minimal singular value
5606  // of the Jacobian of the four cells around the center point c and, as a
5607  // secondary measure, to minimize the aspect ratios defined as the maximal
5608  // divided by the minimal singular values throughout cells
5609  const double a = 0.528;
5610  const double b = 0.4533;
5611  const double c = 0.3752;
5612  const Point<dim> vertices[15] = {
5613  center + Point<dim>(0, 0, 0) * radius,
5614  center + Point<dim>(+1, 0, 0) * radius,
5615  center + Point<dim>(+1, 0, 0) * (radius * a),
5616  center + Point<dim>(0, +1, 0) * (radius * a),
5617  center + Point<dim>(+1, +1, 0) * (radius * b),
5618  center + Point<dim>(0, +1, 0) * radius,
5619  center + Point<dim>(+1, +1, 0) * radius / std::sqrt(2.0),
5620  center + Point<dim>(0, 0, 1) * radius * a,
5621  center + Point<dim>(+1, 0, 1) * radius / std::sqrt(2.0),
5622  center + Point<dim>(+1, 0, 1) * (radius * b),
5623  center + Point<dim>(0, +1, 1) * (radius * b),
5624  center + Point<dim>(+1, +1, 1) * (radius * c),
5625  center + Point<dim>(0, +1, 1) * radius / std::sqrt(2.0),
5626  center + Point<dim>(+1, +1, 1) * (radius / (std::sqrt(3.0))),
5627  center + Point<dim>(0, 0, 1) * radius};
5628  const int cell_vertices[4][8] = {{0, 2, 3, 4, 7, 9, 10, 11},
5629  {1, 6, 2, 4, 8, 13, 9, 11},
5630  {5, 3, 6, 4, 12, 10, 13, 11},
5631  {7, 9, 10, 11, 14, 8, 12, 13}};
5632 
5633  std::vector<CellData<dim>> cells(4, CellData<dim>());
5634 
5635  for (unsigned int i = 0; i < 4; ++i)
5636  {
5637  for (unsigned int j = 0; j < 8; ++j)
5638  cells[i].vertices[j] = cell_vertices[i][j];
5639  cells[i].material_id = 0;
5640  }
5641 
5643  std::end(vertices)),
5644  cells,
5645  SubCellData()); // no boundary information
5646 
5649 
5651  while (cell != end)
5652  {
5653  for (unsigned int i : GeometryInfo<dim>::face_indices())
5654  {
5655  if (cell->face(i)->boundary_id() ==
5657  continue;
5658 
5659  // If x,y or z is zero, then this is part of the plane
5660  if (cell->face(i)->center()(0) < center(0) + 1.e-5 * radius ||
5661  cell->face(i)->center()(1) < center(1) + 1.e-5 * radius ||
5662  cell->face(i)->center()(2) < center(2) + 1.e-5 * radius)
5663  {
5664  cell->face(i)->set_boundary_id(1);
5665  cell->face(i)->set_manifold_id(numbers::flat_manifold_id);
5666  // also set the boundary indicators of the bounding lines,
5667  // unless both vertices are on the perimeter
5668  for (unsigned int j = 0; j < GeometryInfo<3>::lines_per_face;
5669  ++j)
5670  {
5671  const Point<3> line_vertices[2] = {
5672  cell->face(i)->line(j)->vertex(0),
5673  cell->face(i)->line(j)->vertex(1)};
5674  if ((std::fabs(line_vertices[0].distance(center) - radius) >
5675  1e-5 * radius) ||
5676  (std::fabs(line_vertices[1].distance(center) - radius) >
5677  1e-5 * radius))
5678  {
5679  cell->face(i)->line(j)->set_boundary_id(1);
5680  cell->face(i)->line(j)->set_manifold_id(
5682  }
5683  }
5684  }
5685  }
5686  ++cell;
5687  }
5689  }
5690 
5691 
5692 
5693  // Implementation for 3D only
5694  template <>
5695  void half_hyper_ball(Triangulation<3> &tria,
5696  const Point<3> & center,
5697  const double radius)
5698  {
5699  // These are for the two lower squares
5700  const double d = radius / std::sqrt(2.0);
5701  const double a = d / (1 + std::sqrt(2.0));
5702  // These are for the two upper square
5703  const double b = a / 2.0;
5704  const double c = d / 2.0;
5705  // And so are these
5706  const double hb = radius * std::sqrt(3.0) / 4.0;
5707  const double hc = radius * std::sqrt(3.0) / 2.0;
5708 
5709  Point<3> vertices[16] = {
5710  center + Point<3>(0, d, -d),
5711  center + Point<3>(0, -d, -d),
5712  center + Point<3>(0, a, -a),
5713  center + Point<3>(0, -a, -a),
5714  center + Point<3>(0, a, a),
5715  center + Point<3>(0, -a, a),
5716  center + Point<3>(0, d, d),
5717  center + Point<3>(0, -d, d),
5718 
5719  center + Point<3>(hc, c, -c),
5720  center + Point<3>(hc, -c, -c),
5721  center + Point<3>(hb, b, -b),
5722  center + Point<3>(hb, -b, -b),
5723  center + Point<3>(hb, b, b),
5724  center + Point<3>(hb, -b, b),
5725  center + Point<3>(hc, c, c),
5726  center + Point<3>(hc, -c, c),
5727  };
5728 
5729  int cell_vertices[6][8] = {{0, 1, 8, 9, 2, 3, 10, 11},
5730  {0, 2, 8, 10, 6, 4, 14, 12},
5731  {2, 3, 10, 11, 4, 5, 12, 13},
5732  {1, 7, 9, 15, 3, 5, 11, 13},
5733  {6, 4, 14, 12, 7, 5, 15, 13},
5734  {8, 10, 9, 11, 14, 12, 15, 13}};
5735 
5736  std::vector<CellData<3>> cells(6, CellData<3>());
5737 
5738  for (unsigned int i = 0; i < 6; ++i)
5739  {
5740  for (unsigned int j = 0; j < 8; ++j)
5741  cells[i].vertices[j] = cell_vertices[i][j];
5742  cells[i].material_id = 0;
5743  }
5744 
5745  tria.create_triangulation(std::vector<Point<3>>(std::begin(vertices),
5746  std::end(vertices)),
5747  cells,
5748  SubCellData()); // no boundary information
5749 
5750  Triangulation<3>::cell_iterator cell = tria.begin();
5752 
5754 
5755  // go over all faces. for the ones on the flat face, set boundary
5756  // indicator for face and edges to one; the rest will remain at
5757  // zero but we have to pay attention to those edges that are
5758  // at the perimeter of the flat face since they should not be
5759  // set to one
5760  while (cell != end)
5761  {
5762  for (unsigned int i : GeometryInfo<3>::face_indices())
5763  {
5764  if (!cell->at_boundary(i))
5765  continue;
5766 
5767  // If the center is on the plane x=0, this is a planar element. set
5768  // its boundary indicator. also set the boundary indicators of the
5769  // bounding faces unless both vertices are on the perimeter
5770  if (cell->face(i)->center()(0) < center(0) + 1.e-5 * radius)
5771  {
5772  cell->face(i)->set_boundary_id(1);
5773  cell->face(i)->set_manifold_id(numbers::flat_manifold_id);
5774  for (unsigned int j = 0; j < GeometryInfo<3>::lines_per_face;
5775  ++j)
5776  {
5777  const Point<3> line_vertices[2] = {
5778  cell->face(i)->line(j)->vertex(0),
5779  cell->face(i)->line(j)->vertex(1)};
5780  if ((std::fabs(line_vertices[0].distance(center) - radius) >
5781  1e-5 * radius) ||
5782  (std::fabs(line_vertices[1].distance(center) - radius) >
5783  1e-5 * radius))
5784  {
5785  cell->face(i)->line(j)->set_boundary_id(1);
5786  cell->face(i)->line(j)->set_manifold_id(
5788  }
5789  }
5790  }
5791  }
5792  ++cell;
5793  }
5795  }
5796 
5797 
5798 
5799  template <int dim>
5800  void
5802  const Point<dim> & p,
5803  const double radius)
5804  {
5805  // We create the ball by duplicating the information in each dimension at
5806  // a time by appropriate rotations, starting from the quarter ball. The
5807  // rotations make sure we do not generate inverted cells that would appear
5808  // if we tried the slightly simpler approach to simply mirror the cells.
5809 
5810  Triangulation<dim> tria_piece;
5811  GridGenerator::quarter_hyper_ball(tria_piece, p, radius);
5812 
5813  for (unsigned int round = 0; round < dim; ++round)
5814  {
5815  Triangulation<dim> tria_copy;
5816  tria_copy.copy_triangulation(tria_piece);
5817  tria_piece.clear();
5818  std::vector<Point<dim>> new_points(tria_copy.n_vertices());
5819  if (round == 0)
5820  for (unsigned int v = 0; v < tria_copy.n_vertices(); ++v)
5821  {
5822  // rotate by 90 degrees counterclockwise
5823  new_points[v][0] = -tria_copy.get_vertices()[v][1];
5824  new_points[v][1] = tria_copy.get_vertices()[v][0];
5825  if (dim == 3)
5826  new_points[v][2] = tria_copy.get_vertices()[v][2];
5827  }
5828  else if (round == 1)
5829  {
5830  for (unsigned int v = 0; v < tria_copy.n_vertices(); ++v)
5831  {
5832  // rotate by 180 degrees along the xy plane
5833  new_points[v][0] = -tria_copy.get_vertices()[v][0];
5834  new_points[v][1] = -tria_copy.get_vertices()[v][1];
5835  if (dim == 3)
5836  new_points[v][2] = tria_copy.get_vertices()[v][2];
5837  }
5838  }
5839  else if (round == 2)
5840  for (unsigned int v = 0; v < tria_copy.n_vertices(); ++v)
5841  {
5842  // rotate by 180 degrees along the xz plane
5843  Assert(dim == 3, ExcInternalError());
5844  new_points[v][0] = -tria_copy.get_vertices()[v][0];
5845  new_points[v][1] = tria_copy.get_vertices()[v][1];
5846  new_points[v][2] = -tria_copy.get_vertices()[v][2];
5847  }
5848  else
5849  Assert(false, ExcInternalError());
5850 
5851 
5852  // the cell data is exactly the same as before
5853  std::vector<CellData<dim>> cells;
5854  cells.reserve(tria_copy.n_cells());
5855  for (const auto &cell : tria_copy.cell_iterators())
5856  {
5857  CellData<dim> data;
5858  for (unsigned int v : GeometryInfo<dim>::vertex_indices())
5859  data.vertices[v] = cell->vertex_index(v);
5860  data.material_id = cell->material_id();
5861  data.manifold_id = cell->manifold_id();
5862  cells.push_back(data);
5863  }
5864 
5865  Triangulation<dim> rotated_tria;
5866  rotated_tria.create_triangulation(new_points, cells, SubCellData());
5867 
5868  // merge the triangulations - this will make sure that the duplicate
5869  // vertices in the interior are absorbed
5870  if (round == dim - 1)
5871  merge_triangulations(tria_copy, rotated_tria, tria, 1e-12 * radius);
5872  else
5873  merge_triangulations(tria_copy,
5874  rotated_tria,
5875  tria_piece,
5876  1e-12 * radius);
5877  }
5878 
5879  for (const auto &cell : tria.cell_iterators())
5880  if (cell->center().norm_square() > 0.4 * radius)
5881  cell->set_manifold_id(1);
5882  else
5883  cell->set_all_manifold_ids(numbers::flat_manifold_id);
5884 
5887  }
5888 
5889 
5890 
5891  template <>
5892  void hyper_shell(Triangulation<3> & tria,
5893  const Point<3> & p,
5894  const double inner_radius,
5895  const double outer_radius,
5896  const unsigned int n_cells,
5897  const bool colorize)
5898  {
5899  Assert((inner_radius > 0) && (inner_radius < outer_radius),
5900  ExcInvalidRadii());
5901 
5902  unsigned int n_refinement_steps = 0;
5903  unsigned int n_cells_coarsened = n_cells;
5904  if (n_cells != 96 && n_cells > 12)
5905  while (n_cells_coarsened > 12 && n_cells_coarsened % 4 == 0)
5906  {
5907  ++n_refinement_steps;
5908  n_cells_coarsened /= 4;
5909  }
5910  Assert(n_cells == 0 || n_cells == 6 || n_cells == 12 || n_cells == 96 ||
5911  (n_refinement_steps > 0 &&
5912  (n_cells_coarsened == 6 || n_cells_coarsened == 12)),
5913  ExcMessage("Invalid number of coarse mesh cells"));
5914 
5915  const unsigned int n = n_refinement_steps > 0 ?
5916  4 * n_cells_coarsened :
5917  ((n_cells == 0) ? 6 : n_cells);
5918 
5919  const double irad = inner_radius / std::sqrt(3.0);
5920  const double orad = outer_radius / std::sqrt(3.0);
5921  std::vector<Point<3>> vertices;
5922  std::vector<CellData<3>> cells;
5923 
5924  // Corner points of the cube [-1,1]^3
5925  static const std::array<Point<3>, 8> hexahedron = {{{-1, -1, -1}, //
5926  {+1, -1, -1}, //
5927  {-1, +1, -1}, //
5928  {+1, +1, -1}, //
5929  {-1, -1, +1}, //
5930  {+1, -1, +1}, //
5931  {-1, +1, +1}, //
5932  {+1, +1, +1}}};
5933 
5934  switch (n)
5935  {
5936  case 6:
5937  {
5938  // Start with the shell bounded by two nested cubes
5939  for (unsigned int i = 0; i < 8; ++i)
5940  vertices.push_back(p + hexahedron[i] * irad);
5941  for (unsigned int i = 0; i < 8; ++i)
5942  vertices.push_back(p + hexahedron[i] * orad);
5943 
5944  const unsigned int n_cells = 6;
5945  const int cell_vertices[n_cells][8] = {
5946  {8, 9, 10, 11, 0, 1, 2, 3}, // bottom
5947  {9, 11, 1, 3, 13, 15, 5, 7}, // right
5948  {12, 13, 4, 5, 14, 15, 6, 7}, // top
5949  {8, 0, 10, 2, 12, 4, 14, 6}, // left
5950  {8, 9, 0, 1, 12, 13, 4, 5}, // front
5951  {10, 2, 11, 3, 14, 6, 15, 7}}; // back
5952 
5953  cells.resize(n_cells, CellData<3>());
5954 
5955  for (unsigned int i = 0; i < n_cells; ++i)
5956  {
5957  for (const unsigned int j : GeometryInfo<3>::vertex_indices())
5958  cells[i].vertices[j] = cell_vertices[i][j];
5959  cells[i].material_id = 0;
5960  }
5961 
5962  tria.create_triangulation(vertices, cells, SubCellData());
5963  break;
5964  }
5965  case 12:
5966  {
5967  // A more regular subdivision can be obtained by two nested rhombic
5968  // dodecahedra
5969  //
5970  // Octahedron inscribed in the cube [-1,1]^3
5971  static const std::array<Point<3>, 6> octahedron = {{{-1, 0, 0}, //
5972  {1, 0, 0}, //
5973  {0, -1, 0}, //
5974  {0, 1, 0}, //
5975  {0, 0, -1}, //
5976  {0, 0, 1}}};
5977 
5978  for (unsigned int i = 0; i < 8; ++i)
5979  vertices.push_back(p + hexahedron[i] * irad);
5980  for (unsigned int i = 0; i < 6; ++i)
5981  vertices.push_back(p + octahedron[i] * inner_radius);
5982  for (unsigned int i = 0; i < 8; ++i)
5983  vertices.push_back(p + hexahedron[i] * orad);
5984  for (unsigned int i = 0; i < 6; ++i)
5985  vertices.push_back(p + octahedron[i] * outer_radius);
5986 
5987  const unsigned int n_cells = 12;
5988  const unsigned int rhombi[n_cells][4] = {{10, 4, 0, 8},
5989  {4, 13, 8, 6},
5990  {10, 5, 4, 13},
5991  {1, 9, 10, 5},
5992  {9, 7, 5, 13},
5993  {7, 11, 13, 6},
5994  {9, 3, 7, 11},
5995  {1, 12, 9, 3},
5996  {12, 2, 3, 11},
5997  {2, 8, 11, 6},
5998  {12, 0, 2, 8},
5999  {1, 10, 12, 0}};
6000 
6001  cells.resize(n_cells, CellData<3>());
6002 
6003  for (unsigned int i = 0; i < n_cells; ++i)
6004  {
6005  for (unsigned int j = 0; j < 4; ++j)
6006  {
6007  cells[i].vertices[j] = rhombi[i][j];
6008  cells[i].vertices[j + 4] = rhombi[i][j] + 14;
6009  }
6010  cells[i].material_id = 0;
6011  }
6012 
6013  tria.create_triangulation(vertices, cells, SubCellData());
6014  break;
6015  }
6016  case 24:
6017  case 48:
6018  {
6019  // These two meshes are created by first creating a mesh of the
6020  // 6-cell/12-cell version, refining globally, and removing the
6021  // outer half of the cells. For 192 and more cells, we do this
6022  // iteratively several times, always refining and removing the
6023  // outer half. Thus, the outer radius for the start is larger and
6024  // set as 2^n_refinement_steps such that it exactly gives the
6025  // desired radius in the end. It would have been slightly less
6026  // code to treat refinement steps recursively for 192 cells or
6027  // beyond, but unfortunately we could end up with the 96 cell case
6028  // which is not what we want. Thus, we need to implement a loop
6029  // manually here.
6030  Triangulation<3> tmp;
6031  const unsigned int outer_radius_factor = 1 << n_refinement_steps;
6032  hyper_shell(tmp,
6033  p,
6034  inner_radius,
6035  outer_radius_factor * outer_radius -
6036  (outer_radius_factor - 1) * inner_radius,
6037  n / 4);
6038  for (unsigned int r = 0; r < n_refinement_steps; ++r)
6039  {
6040  tmp.refine_global(1);
6041  std::set<Triangulation<3>::active_cell_iterator>
6042  cells_to_remove;
6043 
6044  // We remove all cells which do not have exactly four vertices
6045  // at the inner radius (plus some tolerance).
6046  for (const auto &cell : tmp.active_cell_iterators())
6047  {
6048  unsigned int n_vertices_inside = 0;
6049  for (const auto v : GeometryInfo<3>::vertex_indices())
6050  if ((cell->vertex(v) - p).norm_square() <
6051  inner_radius * inner_radius * (1 + 1e-12))
6052  ++n_vertices_inside;
6053  if (n_vertices_inside < 4)
6054  cells_to_remove.insert(cell);
6055  }
6056 
6057  AssertDimension(cells_to_remove.size(),
6058  tmp.n_active_cells() / 2);
6059  if (r == n_refinement_steps - 1)
6061  cells_to_remove,
6062  tria);
6063  else
6064  {
6067  cells_to_remove,
6068  copy);
6069  tmp = std::move(copy);
6070  tmp.set_all_manifold_ids(0);
6072  }
6073  }
6074  break;
6075  }
6076  case 96:
6077  {
6078  // create a triangulation based on the 12-cell version. This
6079  // function was needed before SphericalManifold was written: it
6080  // manually adjusted the interior vertices to lie along concentric
6081  // spheres. Nowadays we can just refine globally:
6082  Triangulation<3> tmp;
6083  hyper_shell(tmp, p, inner_radius, outer_radius, 12);
6084  tmp.refine_global(1);
6085  flatten_triangulation(tmp, tria);
6086  break;
6087  }
6088  default:
6089  {
6090  Assert(false, ExcMessage("Invalid number of coarse mesh cells."));
6091  }
6092  }
6093 
6094  if (n_cells > 0)
6096 
6097  if (colorize)
6098  colorize_hyper_shell(tria, p, inner_radius, outer_radius);
6099  tria.set_all_manifold_ids(0);
6100  tria.set_manifold(0, SphericalManifold<3>(p));
6101  }
6102 
6103 
6104 
6105  // Implementation for 3D only
6106  template <>
6108  const Point<3> & center,
6109  const double inner_radius,
6110  const double outer_radius,
6111  const unsigned int /*n_cells*/,
6112  const bool colorize)
6113  {
6114  Assert((inner_radius > 0) && (inner_radius < outer_radius),
6115  ExcInvalidRadii());
6116 
6117  // These are for the two lower squares
6118  const double d = outer_radius / std::sqrt(2.0);
6119  const double a = inner_radius / std::sqrt(2.0);
6120  // These are for the two upper square
6121  const double b = a / 2.0;
6122  const double c = d / 2.0;
6123  // And so are these
6124  const double hb = inner_radius * std::sqrt(3.0) / 2.0;
6125  const double hc = outer_radius * std::sqrt(3.0) / 2.0;
6126 
6127  Point<3> vertices[16] = {
6128  center + Point<3>(0, d, -d),
6129  center + Point<3>(0, -d, -d),
6130  center + Point<3>(0, a, -a),
6131  center + Point<3>(0, -a, -a),
6132  center + Point<3>(0, a, a),
6133  center + Point<3>(0, -a, a),
6134  center + Point<3>(0, d, d),
6135  center + Point<3>(0, -d, d),
6136 
6137  center + Point<3>(hc, c, -c),
6138  center + Point<3>(hc, -c, -c),
6139  center + Point<3>(hb, b, -b),
6140  center + Point<3>(hb, -b, -b),
6141  center + Point<3>(hb, b, b),
6142  center + Point<3>(hb, -b, b),
6143  center + Point<3>(hc, c, c),
6144  center + Point<3>(hc, -c, c),
6145  };
6146 
6147  int cell_vertices[5][8] = {{0, 1, 8, 9, 2, 3, 10, 11},
6148  {0, 2, 8, 10, 6, 4, 14, 12},
6149  {1, 7, 9, 15, 3, 5, 11, 13},
6150  {6, 4, 14, 12, 7, 5, 15, 13},
6151  {8, 10, 9, 11, 14, 12, 15, 13}};
6152 
6153  std::vector<CellData<3>> cells(5, CellData<3>());
6154 
6155  for (unsigned int i = 0; i < 5; ++i)
6156  {
6157  for (unsigned int j = 0; j < 8; ++j)
6158  cells[i].vertices[j] = cell_vertices[i][j];
6159  cells[i].material_id = 0;
6160  }
6161 
6162  tria.create_triangulation(std::vector<Point<3>>(std::begin(vertices),
6163  std::end(vertices)),
6164  cells,
6165  SubCellData()); // no boundary information
6166 
6167  if (colorize)
6168  {
6169  // We want to use a standard boundary description where
6170  // the boundary is not curved. Hence set boundary id 2 to
6171  // to all faces in a first step.
6172  Triangulation<3>::cell_iterator cell = tria.begin();
6173  for (; cell != tria.end(); ++cell)
6174  for (unsigned int i : GeometryInfo<3>::face_indices())
6175  if (cell->at_boundary(i))
6176  cell->face(i)->set_all_boundary_ids(2);
6177 
6178  // Next look for the curved boundaries. If the x value of the
6179  // center of the face is not equal to center(0), we're on a curved
6180  // boundary. Then decide whether the center is nearer to the inner
6181  // or outer boundary to set the correct boundary id.
6182  for (cell = tria.begin(); cell != tria.end(); ++cell)
6183  for (unsigned int i : GeometryInfo<3>::face_indices())
6184  if (cell->at_boundary(i))
6185  {
6186  const Triangulation<3>::face_iterator face = cell->face(i);
6187 
6188  const Point<3> face_center(face->center());
6189  if (std::abs(face_center(0) - center(0)) >
6190  1.e-6 * face_center.norm())
6191  {
6192  if (std::abs((face_center - center).norm() - inner_radius) <
6193  std::abs((face_center - center).norm() - outer_radius))
6194  face->set_all_boundary_ids(0);
6195  else
6196  face->set_all_boundary_ids(1);
6197  }
6198  }
6199  }
6200  tria.set_all_manifold_ids(0);
6202  }
6203 
6204 
6205  // Implementation for 3D only
6206  template <>
6208  const Point<3> & center,
6209  const double inner_radius,
6210  const double outer_radius,
6211  const unsigned int n,
6212  const bool colorize)
6213  {
6214  Assert((inner_radius > 0) && (inner_radius < outer_radius),
6215  ExcInvalidRadii());
6216  if (n == 0 || n == 3)
6217  {
6218  const double a = inner_radius * std::sqrt(2.0) / 2e0;
6219  const double b = outer_radius * std::sqrt(2.0) / 2e0;
6220  const double c = a * std::sqrt(3.0) / 2e0;
6221  const double d = b * std::sqrt(3.0) / 2e0;
6222  const double e = outer_radius / 2e0;
6223  const double h = inner_radius / 2e0;
6224 
6225  std::vector<Point<3>> vertices;
6226 
6227  vertices.push_back(center + Point<3>(0, inner_radius, 0)); // 0
6228  vertices.push_back(center + Point<3>(a, a, 0)); // 1
6229  vertices.push_back(center + Point<3>(b, b, 0)); // 2
6230  vertices.push_back(center + Point<3>(0, outer_radius, 0)); // 3
6231  vertices.push_back(center + Point<3>(0, a, a)); // 4
6232  vertices.push_back(center + Point<3>(c, c, h)); // 5
6233  vertices.push_back(center + Point<3>(d, d, e)); // 6
6234  vertices.push_back(center + Point<3>(0, b, b)); // 7
6235  vertices.push_back(center + Point<3>(inner_radius, 0, 0)); // 8
6236  vertices.push_back(center + Point<3>(outer_radius, 0, 0)); // 9
6237  vertices.push_back(center + Point<3>(a, 0, a)); // 10
6238  vertices.push_back(center + Point<3>(b, 0, b)); // 11
6239  vertices.push_back(center + Point<3>(0, 0, inner_radius)); // 12
6240  vertices.push_back(center + Point<3>(0, 0, outer_radius)); // 13
6241 
6242  const int cell_vertices[3][8] = {
6243  {0, 1, 3, 2, 4, 5, 7, 6},
6244  {1, 8, 2, 9, 5, 10, 6, 11},
6245  {4, 5, 7, 6, 12, 10, 13, 11},
6246  };
6247  std::vector<CellData<3>> cells(3);
6248 
6249  for (unsigned int i = 0; i < 3; ++i)
6250  {
6251  for (unsigned int j = 0; j < 8; ++j)
6252  cells[i].vertices[j] = cell_vertices[i][j];
6253  cells[i].material_id = 0;
6254  }
6255 
6257  cells,
6258  SubCellData()); // no boundary information
6259  }
6260  else
6261  {
6262  AssertThrow(false, ExcNotImplemented());
6263  }
6264 
6265  if (colorize)
6266  colorize_quarter_hyper_shell(tria, center, inner_radius, outer_radius);
6267 
6268  tria.set_all_manifold_ids(0);
6270  }
6271 
6272 
6273  // Implementation for 3D only
6274  template <>
6275  void cylinder_shell(Triangulation<3> & tria,
6276  const double length,
6277  const double inner_radius,
6278  const double outer_radius,
6279  const unsigned int n_radial_cells,
6280  const unsigned int n_axial_cells)
6281  {
6282  Assert((inner_radius > 0) && (inner_radius < outer_radius),
6283  ExcInvalidRadii());
6284 
6285  const double pi = numbers::PI;
6286 
6287  // determine the number of cells
6288  // for the grid. if not provided by
6289  // the user determine it such that
6290  // the length of each cell on the
6291  // median (in the middle between
6292  // the two circles) is equal to its
6293  // radial extent (which is the
6294  // difference between the two
6295  // radii)
6296  const unsigned int N_r =
6297  (n_radial_cells == 0 ? static_cast<unsigned int>(std::ceil(
6298  (2 * pi * (outer_radius + inner_radius) / 2) /
6299  (outer_radius - inner_radius))) :
6300  n_radial_cells);
6301  const unsigned int N_z =
6302  (n_axial_cells == 0 ?
6303  static_cast<unsigned int>(std::ceil(
6304  length / (2 * pi * (outer_radius + inner_radius) / 2 / N_r))) :
6305  n_axial_cells);
6306 
6307  // set up N vertices on the
6308  // outer and N vertices on
6309  // the inner circle. the
6310  // first N ones are on the
6311  // outer one, and all are
6312  // numbered counter-clockwise
6313  std::vector<Point<2>> vertices_2d(2 * N_r);
6314  for (unsigned int i = 0; i < N_r; ++i)
6315  {
6316  vertices_2d[i] =
6317  Point<2>(std::cos(2 * pi * i / N_r), std::sin(2 * pi * i / N_r)) *
6318  outer_radius;
6319  vertices_2d[i + N_r] = vertices_2d[i] * (inner_radius / outer_radius);
6320  }
6321 
6322  std::vector<Point<3>> vertices_3d;
6323  vertices_3d.reserve(2 * N_r * (N_z + 1));
6324  for (unsigned int j = 0; j <= N_z; ++j)
6325  for (unsigned int i = 0; i < 2 * N_r; ++i)
6326  {
6327  const Point<3> v(vertices_2d[i][0],
6328  vertices_2d[i][1],
6329  j * length / N_z);
6330  vertices_3d.push_back(v);
6331  }
6332 
6333  std::vector<CellData<3>> cells(N_r * N_z, CellData<3>());
6334 
6335  for (unsigned int j = 0; j < N_z; ++j)
6336  for (unsigned int i = 0; i < N_r; ++i)
6337  {
6338  cells[i + j * N_r].vertices[0] = i + (j + 1) * 2 * N_r;
6339  cells[i + j * N_r].vertices[1] = (i + 1) % N_r + (j + 1) * 2 * N_r;
6340  cells[i + j * N_r].vertices[2] = i + j * 2 * N_r;
6341  cells[i + j * N_r].vertices[3] = (i + 1) % N_r + j * 2 * N_r;
6342 
6343  cells[i + j * N_r].vertices[4] = N_r + i + (j + 1) * 2 * N_r;
6344  cells[i + j * N_r].vertices[5] =
6345  N_r + ((i + 1) % N_r) + (j + 1) * 2 * N_r;
6346  cells[i + j * N_r].vertices[6] = N_r + i + j * 2 * N_r;
6347  cells[i + j * N_r].vertices[7] = N_r + ((i + 1) % N_r) + j * 2 * N_r;
6348 
6349  cells[i + j * N_r].material_id = 0;
6350  }
6351 
6352  tria.create_triangulation(vertices_3d, cells, SubCellData());
6353  tria.set_all_manifold_ids(0);
6355  }
6356 
6357 
6358 
6359  template <int dim, int spacedim>
6360  void
6362  const std::vector<const Triangulation<dim, spacedim> *> &triangulations,
6364  const double duplicated_vertex_tolerance,
6365  const bool copy_manifold_ids)
6366  {
6367  std::vector<Point<spacedim>> vertices;
6368  std::vector<CellData<dim>> cells;
6369  SubCellData subcell_data;
6370 
6371  unsigned int n_accumulated_vertices = 0;
6372  for (const auto triangulation : triangulations)
6373  {
6374  Assert(triangulation->n_levels() == 1,
6375  ExcMessage("The input triangulations must be non-empty "
6376  "and must not be refined."));
6377 
6378  std::vector<Point<spacedim>> tria_vertices;
6379  std::vector<CellData<dim>> tria_cells;
6380  SubCellData tria_subcell_data;
6381  std::tie(tria_vertices, tria_cells, tria_subcell_data) =
6383 
6384  vertices.insert(vertices.end(),
6385  tria_vertices.begin(),
6386  tria_vertices.end());
6387  for (CellData<dim> &cell_data : tria_cells)
6388  {
6389  for (unsigned int &vertex_n : cell_data.vertices)
6390  vertex_n += n_accumulated_vertices;
6391  cells.push_back(cell_data);
6392  }
6393 
6394  // Skip copying lines with no manifold information.
6395  if (copy_manifold_ids)
6396  {
6397  for (CellData<1> &line_data : tria_subcell_data.boundary_lines)
6398  {
6399  if (line_data.manifold_id == numbers::flat_manifold_id)
6400  continue;
6401  for (unsigned int &vertex_n : line_data.vertices)
6402  vertex_n += n_accumulated_vertices;
6403  line_data.boundary_id =
6405  subcell_data.boundary_lines.push_back(line_data);
6406  }
6407 
6408  for (CellData<2> &quad_data : tria_subcell_data.boundary_quads)
6409  {
6410  if (quad_data.manifold_id == numbers::flat_manifold_id)
6411  continue;
6412  for (unsigned int &vertex_n : quad_data.vertices)
6413  vertex_n += n_accumulated_vertices;
6414  quad_data.boundary_id =
6416  subcell_data.boundary_quads.push_back(quad_data);
6417  }
6418  }
6419 
6420  n_accumulated_vertices += triangulation->n_vertices();
6421  }
6422 
6423  // throw out duplicated vertices
6424  std::vector<unsigned int> considered_vertices;
6426  cells,
6427  subcell_data,
6428  considered_vertices,
6429  duplicated_vertex_tolerance);
6430 
6431  // reorder the cells to ensure that they satisfy the convention for
6432  // edge and face directions
6434  result.clear();
6435  result.create_triangulation(vertices, cells, subcell_data);
6436  }
6437 
6438 
6439 
6440  template <int dim, int spacedim>
6441  void
6442  merge_triangulations(const Triangulation<dim, spacedim> &triangulation_1,
6443  const Triangulation<dim, spacedim> &triangulation_2,
6445  const double duplicated_vertex_tolerance,
6446  const bool copy_manifold_ids)
6447  {
6448  // if either Triangulation is empty then merging is just a copy.
6449  if (triangulation_1.n_cells() == 0)
6450  {
6451  result.copy_triangulation(triangulation_2);
6452  return;
6453  }
6454  if (triangulation_2.n_cells() == 0)
6455  {
6456  result.copy_triangulation(triangulation_1);
6457  return;
6458  }
6459  merge_triangulations({&triangulation_1, &triangulation_2},
6460  result,
6461  duplicated_vertex_tolerance,
6462  copy_manifold_ids);
6463  }
6464 
6465 
6466 
6467  namespace
6468  {
6490  template <int structdim>
6491  void
6492  delete_duplicated_objects(std::vector<CellData<structdim>> &subcell_data)
6493  {
6494  static_assert(structdim == 1 || structdim == 2,
6495  "This function is only implemented for lines and "
6496  "quadrilaterals.");
6497  // start by making sure that all objects representing the same vertices
6498  // are numbered in the same way by canonicalizing the numberings. This
6499  // makes it possible to detect duplicates.
6500  for (CellData<structdim> &cell_data : subcell_data)
6501  {
6502  if (structdim == 1)
6503  std::sort(std::begin(cell_data.vertices),
6504  std::end(cell_data.vertices));
6505  else if (structdim == 2)
6506  {
6507  // rotate the vertex numbers so that the lowest one is first
6508  std::array<unsigned int, 4> renumbering;
6509  std::copy(std::begin(cell_data.vertices),
6510  std::end(cell_data.vertices),
6511  renumbering.begin());
6512 
6513  // convert to old style vertex numbering. This makes the
6514  // permutations easy since the valid configurations are
6515  //
6516  // 3 2 2 1 1 0 0 3
6517  // 0 1 3 0 2 3 1 2
6518  // (0123) (3012) (2310) (1230)
6519  //
6520  // rather than the lexical ordering which is harder to permute
6521  // by rotation.
6522  std::swap(renumbering[2], renumbering[3]);
6523  std::rotate(renumbering.begin(),
6524  std::min_element(renumbering.begin(),
6525  renumbering.end()),
6526  renumbering.end());
6527  // convert to new style
6528  std::swap(renumbering[2], renumbering[3]);
6529  // deal with cases where we might have
6530  //
6531  // 3 2 1 2
6532  // 0 1 0 3
6533  //
6534  // by forcing the second vertex (in lexical ordering) to be
6535  // smaller than the third
6536  if (renumbering[1] > renumbering[2])
6537  std::swap(renumbering[1], renumbering[2]);
6538  std::copy(renumbering.begin(),
6539  renumbering.end(),
6540  std::begin(cell_data.vertices));
6541  }
6542  }
6543 
6544  // Now that all cell objects have been canonicalized they can be sorted:
6545  auto compare = [](const CellData<structdim> &a,
6546  const CellData<structdim> &b) {
6547  return std::lexicographical_compare(std::begin(a.vertices),
6548  std::end(a.vertices),
6549  std::begin(b.vertices),
6550  std::end(b.vertices));
6551  };
6552  std::sort(subcell_data.begin(), subcell_data.end(), compare);
6553 
6554  // Finally, determine which objects are duplicates. Duplicates are
6555  // assumed to be interior objects, so delete all but one and change the
6556  // boundary id:
6557  auto left = subcell_data.begin();
6558  while (left != subcell_data.end())
6559  {
6560  const auto right =
6561  std::upper_bound(left, subcell_data.end(), *left, compare);
6562  // if the range has more than one item, then there are duplicates -
6563  // set all boundary ids in the range to the internal boundary id
6564  if (left + 1 != right)
6565  for (auto it = left; it != right; ++it)
6566  {
6567  it->boundary_id = numbers::internal_face_boundary_id;
6568  Assert(it->manifold_id == left->manifold_id,
6569  ExcMessage(
6570  "In the process of grid generation a single "
6571  "line or quadrilateral has been assigned two "
6572  "different manifold ids. This can happen when "
6573  "a Triangulation is copied, e.g., via "
6574  "GridGenerator::replicate_triangulation() and "
6575  "not all external boundary faces have the same "
6576  "manifold id. Double check that all faces "
6577  "which you expect to be merged together have "
6578  "the same manifold id."));
6579  }
6580  left = right;
6581  }
6582 
6583  subcell_data.erase(std::unique(subcell_data.begin(), subcell_data.end()),
6584  subcell_data.end());
6585  }
6586  } // namespace
6587 
6588 
6589 
6590  template <int dim, int spacedim>
6591  void
6593  const std::vector<unsigned int> & extents,
6595  {
6596  AssertDimension(dim, extents.size());
6597 # ifdef DEBUG
6598  for (const auto &extent : extents)
6599  Assert(0 < extent,
6600  ExcMessage("The Triangulation must be copied at least one time in "
6601  "each coordinate dimension."));
6602 # endif
6603  const BoundingBox<spacedim> bbox(input.get_vertices());
6604  const auto & min = bbox.get_boundary_points().first;
6605  const auto & max = bbox.get_boundary_points().second;
6606 
6607  std::array<Tensor<1, spacedim>, dim> offsets;
6608  for (unsigned int d = 0; d < dim; ++d)
6609  offsets[d][d] = max[d] - min[d];
6610 
6611  Triangulation<dim, spacedim> tria_to_replicate;
6612  tria_to_replicate.copy_triangulation(input);
6613  for (unsigned int d = 0; d < dim; ++d)
6614  {
6615  std::vector<Point<spacedim>> input_vertices;
6616  std::vector<CellData<dim>> input_cell_data;
6617  SubCellData input_subcell_data;
6618  std::tie(input_vertices, input_cell_data, input_subcell_data) =
6619  GridTools::get_coarse_mesh_description(tria_to_replicate);
6620  std::vector<Point<spacedim>> output_vertices = input_vertices;
6621  std::vector<CellData<dim>> output_cell_data = input_cell_data;
6622  SubCellData output_subcell_data = input_subcell_data;
6623 
6624  for (unsigned int k = 1; k < extents[d]; ++k)
6625  {
6626  const std::size_t vertex_offset = k * input_vertices.size();
6627  // vertices
6628  for (const Point<spacedim> &point : input_vertices)
6629  output_vertices.push_back(point + double(k) * offsets[d]);
6630  // cell data
6631  for (const CellData<dim> &cell_data : input_cell_data)
6632  {
6633  output_cell_data.push_back(cell_data);
6634  for (unsigned int &vertex : output_cell_data.back().vertices)
6635  vertex += vertex_offset;
6636  }
6637  // subcell data
6638  for (const CellData<1> &boundary_line :
6639  input_subcell_data.boundary_lines)
6640  {
6641  output_subcell_data.boundary_lines.push_back(boundary_line);
6642  for (unsigned int &vertex :
6643  output_subcell_data.boundary_lines.back().vertices)
6644  vertex += vertex_offset;
6645  }
6646  for (const CellData<2> &boundary_quad :
6647  input_subcell_data.boundary_quads)
6648  {
6649  output_subcell_data.boundary_quads.push_back(boundary_quad);
6650  for (unsigned int &vertex :
6651  output_subcell_data.boundary_quads.back().vertices)
6652  vertex += vertex_offset;
6653  }
6654  }
6655  // check all vertices: since the grid is coarse, most will be on the
6656  // boundary anyway
6657  std::vector<unsigned int> boundary_vertices;
6659  output_vertices,
6660  output_cell_data,
6661  output_subcell_data,
6662  boundary_vertices,
6663  1e-6 * input.begin_active()->diameter());
6664  // delete_duplicated_vertices also deletes any unused vertices
6665  // deal with any reordering issues created by delete_duplicated_vertices
6666  GridTools::consistently_order_cells(output_cell_data);
6667  // clean up the boundary ids of the boundary objects: note that we
6668  // have to do this after delete_duplicated_vertices so that boundary
6669  // objects are actually duplicated at this point
6670  if (dim == 2)
6671  delete_duplicated_objects(output_subcell_data.boundary_lines);
6672  else if (dim == 3)
6673  {
6674  delete_duplicated_objects(output_subcell_data.boundary_quads);
6675  for (CellData<1> &boundary_line :
6676  output_subcell_data.boundary_lines)
6677  // set boundary lines to the default value - let
6678  // create_triangulation figure out the rest.
6680  }
6681 
6682  tria_to_replicate.clear();
6683  tria_to_replicate.create_triangulation(output_vertices,
6684  output_cell_data,
6685  output_subcell_data);
6686  }
6687 
6688  result.copy_triangulation(tria_to_replicate);
6689  }
6690 
6691 
6692 
6693  template <int dim, int spacedim>
6694  void
6696  const Triangulation<dim, spacedim> &triangulation_1,
6697  const Triangulation<dim, spacedim> &triangulation_2,
6699  {
6700  Assert(GridTools::have_same_coarse_mesh(triangulation_1, triangulation_2),
6701  ExcMessage("The two input triangulations are not derived from "
6702  "the same coarse mesh as required."));
6703  Assert((dynamic_cast<
6705  &triangulation_1) == nullptr) &&
6706  (dynamic_cast<
6708  &triangulation_2) == nullptr),
6709  ExcMessage("The source triangulations for this function must both "
6710  "be available entirely locally, and not be distributed "
6711  "triangulations."));
6712 
6713  // first copy triangulation_1, and
6714  // then do as many iterations as
6715  // there are levels in
6716  // triangulation_2 to refine
6717  // additional cells. since this is
6718  // the maximum number of
6719  // refinements to get from the
6720  // coarse grid to triangulation_2,
6721  // it is clear that this is also
6722  // the maximum number of
6723  // refinements to get from any cell
6724  // on triangulation_1 to
6725  // triangulation_2
6726  result.clear();
6727  result.copy_triangulation(triangulation_1);
6728  for (unsigned int iteration = 0; iteration < triangulation_2.n_levels();
6729  ++iteration)
6730  {
6732  intergrid_map.make_mapping(result, triangulation_2);
6733 
6734  bool any_cell_flagged = false;
6735  for (const auto &result_cell : result.active_cell_iterators())
6736  if (intergrid_map[result_cell]->has_children())
6737  {
6738  any_cell_flagged = true;
6739  result_cell->set_refine_flag();
6740  }
6741 
6742  if (any_cell_flagged == false)
6743  break;
6744  else
6746  }
6747  }
6748 
6749 
6750 
6751  template <int dim, int spacedim>
6752  void
6754  const Triangulation<dim, spacedim> &input_triangulation,
6756  & cells_to_remove,
6758  {
6759  // simply copy the vertices; we will later strip those
6760  // that turn out to be unused
6761  std::vector<Point<spacedim>> vertices = input_triangulation.get_vertices();
6762 
6763  // the loop through the cells and copy stuff, excluding
6764  // the ones we are to remove
6765  std::vector<CellData<dim>> cells;
6766  for (const auto &cell : input_triangulation.active_cell_iterators())
6767  if (cells_to_remove.find(cell) == cells_to_remove.end())
6768  {
6769  Assert(static_cast<unsigned int>(cell->level()) ==
6770  input_triangulation.n_levels() - 1,
6771  ExcMessage(
6772  "Your input triangulation appears to have "
6773  "adaptively refined cells. This is not allowed. You can "
6774  "only call this function on a triangulation in which "
6775  "all cells are on the same refinement level."));
6776 
6777  CellData<dim> this_cell;
6778  for (const unsigned int v : GeometryInfo<dim>::vertex_indices())
6779  this_cell.vertices[v] = cell->vertex_index(v);
6780  this_cell.material_id = cell->material_id();
6781  cells.push_back(this_cell);
6782  }
6783 
6784  // throw out duplicated vertices from the two meshes, reorder vertices as
6785  // necessary and create the triangulation
6786  SubCellData subcell_data;
6787  std::vector<unsigned int> considered_vertices;
6789  cells,
6790  subcell_data,
6791  considered_vertices);
6792 
6793  // then clear the old triangulation and create the new one
6794  result.clear();
6795  result.create_triangulation(vertices, cells, subcell_data);
6796  }
6797 
6798 
6799 
6800  void
6802  const Triangulation<2, 2> & input,
6803  const unsigned int n_slices,
6804  const double height,
6805  Triangulation<3, 3> & result,
6806  const bool copy_manifold_ids,
6807  const std::vector<types::manifold_id> &manifold_priorities)
6808  {
6809  Assert(input.n_levels() == 1,
6810  ExcMessage(
6811  "The input triangulation must be a coarse mesh, i.e., it must "
6812  "not have been refined."));
6813  Assert(result.n_cells() == 0,
6814  ExcMessage("The output triangulation object needs to be empty."));
6815  Assert(height > 0,
6816  ExcMessage("The given height for extrusion must be positive."));
6817  Assert(n_slices >= 2,
6818  ExcMessage(
6819  "The number of slices for extrusion must be at least 2."));
6820 
6821  const double delta_h = height / (n_slices - 1);
6822  std::vector<double> slices_z_values;
6823  for (unsigned int i = 0; i < n_slices; ++i)
6824  slices_z_values.push_back(i * delta_h);
6826  input, slices_z_values, result, copy_manifold_ids, manifold_priorities);
6827  }
6828 
6829 
6830 
6831  void
6833  const Triangulation<2, 2> & input,
6834  const unsigned int n_slices,
6835  const double height,
6836  Triangulation<2, 2> & result,
6837  const bool copy_manifold_ids,
6838  const std::vector<types::manifold_id> &manifold_priorities)
6839  {
6840  (void)input;
6841  (void)n_slices;
6842  (void)height;
6843  (void)result;
6844  (void)copy_manifold_ids;
6845  (void)manifold_priorities;
6846 
6847  AssertThrow(false,
6848  ExcMessage(
6849  "GridTools::extrude_triangulation() is only available "
6850  "for Triangulation<3, 3> as output triangulation."));
6851  }
6852 
6853 
6854 
6855  void
6857  const Triangulation<2, 2> & input,
6858  const std::vector<double> & slice_coordinates,
6859  Triangulation<3, 3> & result,
6860  const bool copy_manifold_ids,
6861  const std::vector<types::manifold_id> &manifold_priorities)
6862  {
6863  Assert(input.n_levels() == 1,
6864  ExcMessage(
6865  "The input triangulation must be a coarse mesh, i.e., it must "
6866  "not have been refined."));
6867  Assert(result.n_cells() == 0,
6868  ExcMessage("The output triangulation object needs to be empty."));
6869  Assert(slice_coordinates.size() >= 2,
6870  ExcMessage(
6871  "The number of slices for extrusion must be at least 2."));
6872  Assert(std::is_sorted(slice_coordinates.begin(), slice_coordinates.end()),
6873  ExcMessage("Slice z-coordinates should be in ascending order"));
6874 
6875  const auto priorities = [&]() -> std::vector<types::manifold_id> {
6876  // if a non-empty (i.e., not the default) vector is given for
6877  // manifold_priorities then use it (but check its validity in debug
6878  // mode)
6879  if (0 < manifold_priorities.size())
6880  {
6881 # ifdef DEBUG
6882  // check that the provided manifold_priorities is valid
6883  std::vector<types::manifold_id> sorted_manifold_priorities =
6884  manifold_priorities;
6885  std::sort(sorted_manifold_priorities.begin(),
6886  sorted_manifold_priorities.end());
6887  Assert(std::unique(sorted_manifold_priorities.begin(),
6888  sorted_manifold_priorities.end()) ==
6889  sorted_manifold_priorities.end(),
6890  ExcMessage(
6891  "The given vector of manifold ids may not contain any "
6892  "duplicated entries."));
6893  std::vector<types::manifold_id> sorted_manifold_ids =
6894  input.get_manifold_ids();
6895  std::sort(sorted_manifold_ids.begin(), sorted_manifold_ids.end());
6896  if (sorted_manifold_priorities != sorted_manifold_ids)
6897  {
6898  std::ostringstream message;
6899  message << "The given triangulation has manifold ids {";
6900  for (const types::manifold_id manifold_id : sorted_manifold_ids)
6901  if (manifold_id != sorted_manifold_ids.back())
6902  message << manifold_id << ", ";
6903  message << sorted_manifold_ids.back() << "}, but \n"
6904  << " the given vector of manifold ids is {";
6905  for (const types::manifold_id manifold_id : manifold_priorities)
6906  if (manifold_id != manifold_priorities.back())
6907  message << manifold_id << ", ";
6908  message
6909  << manifold_priorities.back() << "}.\n"
6910  << " These vectors should contain the same elements.\n";
6911  const std::string m = message.str();
6912  Assert(false, ExcMessage(m));
6913  }
6914 # endif
6915  return manifold_priorities;
6916  }
6917  // otherwise use the default ranking: ascending order, but TFI manifolds
6918  // are at the end.
6919  std::vector<types::manifold_id> default_priorities =
6920  input.get_manifold_ids();
6921  const auto first_tfi_it = std::partition(
6922  default_priorities.begin(),
6923  default_priorities.end(),
6924  [&input](const types::manifold_id &id) {
6925  return dynamic_cast<const TransfiniteInterpolationManifold<2, 2> *>(
6926  &input.get_manifold(id)) == nullptr;
6927  });
6928  std::sort(default_priorities.begin(), first_tfi_it);
6929  std::sort(first_tfi_it, default_priorities.end());
6930 
6931  return default_priorities;
6932  }();
6933 
6934  const std::size_t n_slices = slice_coordinates.size();
6935  std::vector<Point<3>> points(n_slices * input.n_vertices());
6936  std::vector<CellData<3>> cells;
6937  cells.reserve((n_slices - 1) * input.n_active_cells());
6938 
6939  // copy the array of points as many times as there will be slices,
6940  // one slice at a time. The z-axis value are defined in slices_coordinates
6941  for (std::size_t slice_n = 0; slice_n < n_slices; ++slice_n)
6942  {
6943  for (std::size_t vertex_n = 0; vertex_n < input.n_vertices();
6944  ++vertex_n)
6945  {
6946  const Point<2> vertex = input.get_vertices()[vertex_n];
6947  points[slice_n * input.n_vertices() + vertex_n] =
6948  Point<3>(vertex[0], vertex[1], slice_coordinates[slice_n]);
6949  }
6950  }
6951 
6952  // then create the cells of each of the slices, one stack at a
6953  // time
6954  for (const auto &cell : input.active_cell_iterators())
6955  {
6956  for (std::size_t slice_n = 0; slice_n < n_slices - 1; ++slice_n)
6957  {
6958  CellData<3> this_cell;
6959  for (const unsigned int vertex_n :
6961  {
6962  this_cell.vertices[vertex_n] =
6963  cell->vertex_index(vertex_n) + slice_n * input.n_vertices();
6964  this_cell
6966  cell->vertex_index(vertex_n) +
6967  (slice_n + 1) * input.n_vertices();
6968  }
6969 
6970  this_cell.material_id = cell->material_id();
6971  if (copy_manifold_ids)
6972  this_cell.manifold_id = cell->manifold_id();
6973  cells.push_back(this_cell);
6974  }
6975  }
6976 
6977  // Next, create face data for all faces that are orthogonal to the x-y
6978  // plane
6979  SubCellData subcell_data;
6980  std::vector<CellData<2>> &quads = subcell_data.boundary_quads;
6981  types::boundary_id max_boundary_id = 0;
6982  quads.reserve(input.n_active_lines() * (n_slices - 1) +
6983  input.n_active_cells() * 2);
6984  for (const auto &face : input.active_face_iterators())
6985  {
6986  CellData<2> quad;
6987  quad.boundary_id = face->boundary_id();
6988  if (face->at_boundary())
6989  max_boundary_id = std::max(max_boundary_id, quad.boundary_id);
6990  if (copy_manifold_ids)
6991  quad.manifold_id = face->manifold_id();
6992  for (std::size_t slice_n = 0; slice_n < n_slices - 1; ++slice_n)
6993  {
6994  quad.vertices[0] =
6995  face->vertex_index(0) + slice_n * input.n_vertices();
6996  quad.vertices[1] =
6997  face->vertex_index(1) + slice_n * input.n_vertices();
6998  quad.vertices[2] =
6999  face->vertex_index(0) + (slice_n + 1) * input.n_vertices();
7000  quad.vertices[3] =
7001  face->vertex_index(1) + (slice_n + 1) * input.n_vertices();
7002  quads.push_back(quad);
7003  }
7004  }
7005 
7006  // if necessary, create face data for faces parallel to the x-y
7007  // plane. This is only necessary if we need to set manifolds.
7008  if (copy_manifold_ids)
7009  for (const auto &cell : input.active_cell_iterators())
7010  {
7011  CellData<2> quad;
7013  quad.manifold_id = cell->manifold_id(); // check is outside loop
7014  for (std::size_t slice_n = 1; slice_n < n_slices - 1; ++slice_n)
7015  {
7016  quad.vertices[0] =
7017  cell->vertex_index(0) + slice_n * input.n_vertices();
7018  quad.vertices[1] =
7019  cell->vertex_index(1) + slice_n * input.n_vertices();
7020  quad.vertices[2] =
7021  cell->vertex_index(2) + slice_n * input.n_vertices();
7022  quad.vertices[3] =
7023  cell->vertex_index(3) + slice_n * input.n_vertices();
7024  quads.push_back(quad);
7025  }
7026  }
7027 
7028  // then mark the bottom and top boundaries of the extruded mesh
7029  // with max_boundary_id+1 and max_boundary_id+2. check that this
7030  // remains valid
7031  Assert((max_boundary_id != numbers::invalid_boundary_id) &&
7032  (max_boundary_id + 1 != numbers::invalid_boundary_id) &&
7033  (max_boundary_id + 2 != numbers::invalid_boundary_id),
7034  ExcMessage(
7035  "The input triangulation to this function is using boundary "
7036  "indicators in a range that do not allow using "
7037  "max_boundary_id+1 and max_boundary_id+2 as boundary "
7038  "indicators for the bottom and top faces of the "
7039  "extruded triangulation."));
7040  const types::boundary_id bottom_boundary_id = max_boundary_id + 1;
7041  const types::boundary_id top_boundary_id = max_boundary_id + 2;
7042  for (const auto &cell : input.active_cell_iterators())
7043  {
7044  CellData<2> quad;
7045  quad.boundary_id = bottom_boundary_id;
7046  quad.vertices[0] = cell->vertex_index(0);
7047  quad.vertices[1] = cell->vertex_index(1);
7048  quad.vertices[2] = cell->vertex_index(2);
7049  quad.vertices[3] = cell->vertex_index(3);
7050  if (copy_manifold_ids)
7051  quad.manifold_id = cell->manifold_id();
7052  quads.push_back(quad);
7053 
7054  quad.boundary_id = top_boundary_id;
7055  for (unsigned int &vertex : quad.vertices)
7056  vertex += (n_slices - 1) * input.n_vertices();
7057  if (copy_manifold_ids)
7058  quad.manifold_id = cell->manifold_id();
7059  quads.push_back(quad);
7060  }
7061 
7062  // use all of this to finally create the extruded 3d
7063  // triangulation. it is not necessary to call
7064  // GridTools::consistently_order_cells() because the cells we have
7065  // constructed above are automatically correctly oriented. this is
7066  // because the 2d base mesh is always correctly oriented, and
7067  // extruding it automatically yields a correctly oriented 3d mesh,
7068  // as discussed in the edge orientation paper mentioned in the
7069  // introduction to the @ref reordering "reordering module".
7070  result.create_triangulation(points, cells, subcell_data);
7071 
7072  for (auto manifold_id_it = priorities.rbegin();
7073  manifold_id_it != priorities.rend();
7074  ++manifold_id_it)
7075  for (const auto &face : result.active_face_iterators())
7076  if (face->manifold_id() == *manifold_id_it)
7077  for (unsigned int line_n = 0;
7078  line_n < GeometryInfo<3>::lines_per_face;
7079  ++line_n)
7080  face->line(line_n)->set_manifold_id(*manifold_id_it);
7081  }
7082 
7083 
7084 
7085  void
7087  const Triangulation<2, 2> & input,
7088  const std::vector<double> & slice_coordinates,
7089  Triangulation<2, 2> & result,
7090  const bool copy_manifold_ids,
7091  const std::vector<types::manifold_id> &manifold_priorities)
7092  {
7093  (void)input;
7094  (void)slice_coordinates;
7095  (void)result;
7096  (void)copy_manifold_ids;
7097  (void)manifold_priorities;
7098 
7099  AssertThrow(false,
7100  ExcMessage(
7101  "GridTools::extrude_triangulation() is only available "
7102  "for Triangulation<3, 3> as output triangulation."));
7103  }
7104 
7105 
7106 
7107  template <>
7109  const double,
7110  const double,
7111  const double,
7112  const unsigned int,
7113  const bool)
7114  {
7115  Assert(false, ExcNotImplemented());
7116  }
7117 
7118 
7119 
7120  template <>
7122  const double inner_radius,
7123  const double outer_radius,
7124  const double, // width,
7125  const unsigned int, // width_repetition,
7126  const bool colorize)
7127  {
7128  const int dim = 2;
7129 
7130  Assert(inner_radius < outer_radius,
7131  ExcMessage("outer_radius has to be bigger than inner_radius."));
7132 
7134  // We create an hyper_shell in two dimensions, and then we modify it.
7135  hyper_shell(triangulation, center, inner_radius, outer_radius, 8);
7136  triangulation.set_all_manifold_ids(numbers::flat_manifold_id);
7138  triangulation.begin_active(),
7139  endc = triangulation.end();
7140  std::vector<bool> treated_vertices(triangulation.n_vertices(), false);
7141  for (; cell != endc; ++cell)
7142  {
7143  for (auto f : GeometryInfo<dim>::face_indices())
7144  if (cell->face(f)->at_boundary())
7145  {
7146  for (unsigned int v = 0; v < GeometryInfo<dim>::vertices_per_face;
7147  ++v)
7148  {
7149  unsigned int vv = cell->face(f)->vertex_index(v);
7150  if (treated_vertices[vv] == false)
7151  {
7152  treated_vertices[vv] = true;
7153  switch (vv)
7154  {
7155  case 1:
7156  cell->face(f)->vertex(v) =
7157  center + Point<dim>(outer_radius, outer_radius);
7158  break;
7159  case 3:
7160  cell->face(f)->vertex(v) =
7161  center + Point<dim>(-outer_radius, outer_radius);
7162  break;
7163  case 5:
7164  cell->face(f)->vertex(v) =
7165  center + Point<dim>(-outer_radius, -outer_radius);
7166  break;
7167  case 7:
7168  cell->face(f)->vertex(v) =
7169  center + Point<dim>(outer_radius, -outer_radius);
7170  break;
7171  default:
7172  break;
7173  }
7174  }
7175  }
7176  }
7177  }
7178  double eps = 1e-3 * outer_radius;
7179  cell = triangulation.begin_active();
7180  for (; cell != endc; ++cell)
7181  {
7182  for (auto f : GeometryInfo<dim>::face_indices())
7183  if (cell->face(f)->at_boundary())
7184  {
7185  double dx = cell->face(f)->center()(0) - center(0);
7186  double dy = cell->face(f)->center()(1) - center(1);
7187  if (colorize)
7188  {
7189  if (std::abs(dx + outer_radius) < eps)
7190  cell->face(f)->set_boundary_id(0);
7191  else if (std::abs(dx - outer_radius) < eps)
7192  cell->face(f)->set_boundary_id(1);
7193  else if (std::abs(dy + outer_radius) < eps)
7194  cell->face(f)->set_boundary_id(2);
7195  else if (std::abs(dy - outer_radius) < eps)
7196  cell->face(f)->set_boundary_id(3);
7197  else
7198  {
7199  cell->face(f)->set_boundary_id(4);
7200  cell->face(f)->set_manifold_id(0);
7201  }
7202  }
7203  else
7204  {
7205  double d = (cell->face(f)->center() - center).norm();
7206  if (d - inner_radius < 0)
7207  {
7208  cell->face(f)->set_boundary_id(1);
7209  cell->face(f)->set_manifold_id(0);
7210  }
7211  else
7212  cell->face(f)->set_boundary_id(0);
7213  }
7214  }
7215  }
7216  triangulation.set_manifold(0, PolarManifold<2>(center));
7217  }
7218 
7219 
7220 
7221  template <int dim>
7222  void
7224  const Point<dim> & center,
7225  const double inner_radius,
7226  const double outer_radius,
7227  const unsigned int n_shells,
7228  const double skewness,
7229  const unsigned int n_cells,
7230  const bool colorize)
7231  {
7232  Assert(dim == 2 || dim == 3, ExcNotImplemented());
7233  (void)colorize;
7234  (void)n_cells;
7235  Assert(inner_radius < outer_radius,
7236  ExcMessage("outer_radius has to be bigger than inner_radius."));
7237  if (n_shells == 0)
7238  return; // empty Triangulation
7239 
7240  std::vector<double> radii;
7241  radii.push_back(inner_radius);
7242  for (unsigned int shell_n = 1; shell_n < n_shells; ++shell_n)
7243  if (skewness == 0.0)
7244  // same as below, but works in the limiting case of zero skewness
7245  radii.push_back(inner_radius +
7246  (outer_radius - inner_radius) *
7247  (1.0 - (1.0 - double(shell_n) / n_shells)));
7248  else
7249  radii.push_back(
7250  inner_radius +
7251  (outer_radius - inner_radius) *
7252  (1.0 - std::tanh(skewness * (1.0 - double(shell_n) / n_shells)) /
7253  std::tanh(skewness)));
7254  radii.push_back(outer_radius);
7255 
7256  double grid_vertex_tolerance = 0.0;
7257  for (unsigned int shell_n = 0; shell_n < radii.size() - 1; ++shell_n)
7258  {
7259  Triangulation<dim> current_shell;
7260  GridGenerator::hyper_shell(current_shell,
7261  center,
7262  radii[shell_n],
7263  radii[shell_n + 1],
7264  n_cells == 0 ? (dim == 2 ? 8 : 12) :
7265  n_cells);
7266 
7267  // The innermost shell has the smallest cells: use that to set the
7268  // vertex merging tolerance
7269  if (grid_vertex_tolerance == 0.0)
7270  grid_vertex_tolerance =
7271  0.5 * internal::minimal_vertex_distance(current_shell);
7272 
7273  Triangulation<dim> temp(std::move(triangulation));
7274  triangulation.clear();
7276  temp,
7277  triangulation,
7278  grid_vertex_tolerance);
7279  }
7280 
7281  const types::manifold_id manifold_id = 0;
7282  triangulation.set_all_manifold_ids(manifold_id);
7283  if (dim == 2)
7285  else if (dim == 3)
7287 
7288  // We use boundary vertex positions to see if things are on the inner or
7289  // outer boundary.
7290  constexpr double radial_vertex_tolerance =
7292  auto assert_vertex_distance_within_tolerance =
7293  [center, radial_vertex_tolerance](
7294  const TriaIterator<TriaAccessor<dim - 1, dim, dim>> face,
7295  const double radius) {
7296  (void)center;
7297  (void)radial_vertex_tolerance;
7298  (void)face;
7299  (void)radius;
7300  for (unsigned int vertex_n = 0;
7301  vertex_n < GeometryInfo<dim>::vertices_per_face;
7302  ++vertex_n)
7303  {
7304  Assert(std::abs((face->vertex(vertex_n) - center).norm() - radius) <
7305  (center.norm() + radius) * radial_vertex_tolerance,
7306  ExcInternalError());
7307  }
7308  };
7309  if (colorize)
7310  for (const auto &cell : triangulation.active_cell_iterators())
7311  for (const unsigned int face_n : GeometryInfo<dim>::face_indices())
7312  {
7313  auto face = cell->face(face_n);
7314  if (face->at_boundary())
7315  {
7316  if (((face->vertex(0) - center).norm() - inner_radius) <
7317  (center.norm() + inner_radius) * radial_vertex_tolerance)
7318  {
7319  // we must be at an inner face, but check
7320  assert_vertex_distance_within_tolerance(face, inner_radius);
7321  face->set_all_boundary_ids(0);
7322  }
7323  else
7324  {
7325  // we must be at an outer face, but check
7326  assert_vertex_distance_within_tolerance(face, outer_radius);
7327  face->set_all_boundary_ids(1);
7328  }
7329  }
7330  }
7331  }
7332 
7333 
7334 
7335  template <>
7337  const double inner_radius,
7338  const double outer_radius,
7339  const double L,
7340  const unsigned int Nz,
7341  const bool colorize)
7342  {
7343  const int dim = 3;
7344 
7345  Assert(inner_radius < outer_radius,
7346  ExcMessage("outer_radius has to be bigger than inner_radius."));
7347  Assert(L > 0, ExcMessage("Must give positive extension L"));
7348  Assert(Nz >= 1, ExcLowerRange(1, Nz));
7349 
7350  cylinder_shell(triangulation, L, inner_radius, outer_radius, 8, Nz);
7351  triangulation.set_all_manifold_ids(numbers::flat_manifold_id);
7352 
7354  triangulation.begin_active(),
7355  endc = triangulation.end();
7356  std::vector<bool> treated_vertices(triangulation.n_vertices(), false);
7357  for (; cell != endc; ++cell)
7358  {
7359  for (auto f : GeometryInfo<dim>::face_indices())
7360  if (cell->face(f)->at_boundary())
7361  {
7362  for (unsigned int v = 0; v < GeometryInfo<dim>::vertices_per_face;
7363  ++v)
7364  {
7365  unsigned int vv = cell->face(f)->vertex_index(v);
7366  if (treated_vertices[vv] == false)
7367  {
7368  treated_vertices[vv] = true;
7369  for (unsigned int i = 0; i <= Nz; ++i)
7370  {
7371  double d = i * L / Nz;
7372  switch (vv - i * 16)
7373  {
7374  case 1:
7375  cell->face(f)->vertex(v) =
7376  Point<dim>(outer_radius, outer_radius, d);
7377  break;
7378  case 3:
7379  cell->face(f)->vertex(v) =
7380  Point<dim>(-outer_radius, outer_radius, d);
7381  break;
7382  case 5:
7383  cell->face(f)->vertex(v) =
7384  Point<dim>(-outer_radius, -outer_radius, d);
7385  break;
7386  case 7:
7387  cell->face(f)->vertex(v) =
7388  Point<dim>(outer_radius, -outer_radius, d);
7389  break;
7390  default:
7391  break;
7392  }
7393  }
7394  }
7395  }
7396  }
7397  }
7398  double eps = 1e-3 * outer_radius;
7399  cell = triangulation.begin_active();
7400  for (; cell != endc; ++cell)
7401  {
7402  for (auto f : GeometryInfo<dim>::face_indices())
7403  if (cell->face(f)->at_boundary())
7404  {
7405  double dx = cell->face(f)->center()(0);
7406  double dy = cell->face(f)->center()(1);
7407  double dz = cell->face(f)->center()(2);
7408 
7409  if (colorize)
7410  {
7411  if (std::abs(dx + outer_radius) < eps)
7412  cell->face(f)->set_boundary_id(0);
7413 
7414  else if (std::abs(dx - outer_radius) < eps)
7415  cell->face(f)->set_boundary_id(1);
7416 
7417  else if (std::abs(dy + outer_radius) < eps)
7418  cell->face(f)->set_boundary_id(2);
7419 
7420  else if (std::abs(dy - outer_radius) < eps)
7421  cell->face(f)->set_boundary_id(3);
7422 
7423  else if (std::abs(dz) < eps)
7424  cell->face(f)->set_boundary_id(4);
7425 
7426  else if (std::abs(dz - L) < eps)
7427  cell->face(f)->set_boundary_id(5);
7428 
7429  else
7430  {
7431  cell->face(f)->set_all_boundary_ids(6);
7432  cell->face(f)->set_all_manifold_ids(0);
7433  }
7434  }
7435  else
7436  {
7437  Point<dim> c = cell->face(f)->center();
7438  c(2) = 0;
7439  double d = c.norm();
7440  if (d - inner_radius < 0)
7441  {
7442  cell->face(f)->set_all_boundary_ids(1);
7443  cell->face(f)->set_all_manifold_ids(0);
7444  }
7445  else
7446  cell->face(f)->set_boundary_id(0);
7447  }
7448  }
7449  }
7450  triangulation.set_manifold(0, CylindricalManifold<3>(2));
7451  }
7452 
7453  template <int dim, int spacedim1, int spacedim2>
7454  void
7456  Triangulation<dim, spacedim2> & out_tria)
7457  {
7459  dynamic_cast<
7461 
7462  (void)pt;
7463  Assert(
7464  pt == nullptr,
7465  ExcMessage(
7466  "Cannot use this function on parallel::distributed::Triangulation."));
7467 
7468  std::vector<Point<spacedim2>> v;
7469  std::vector<CellData<dim>> cells;
7470  SubCellData subcelldata;
7471 
7472  const unsigned int spacedim = std::min(spacedim1, spacedim2);
7473  const std::vector<Point<spacedim1>> &in_vertices = in_tria.get_vertices();
7474 
7475  v.resize(in_vertices.size());
7476  for (unsigned int i = 0; i < in_vertices.size(); ++i)
7477  for (unsigned int d = 0; d < spacedim; ++d)
7478  v[i][d] = in_vertices[i][d];
7479 
7480  cells.resize(in_tria.n_active_cells());
7482  cell = in_tria.begin_active(),
7483  endc = in_tria.end();
7484 
7485  for (unsigned int id = 0; cell != endc; ++cell, ++id)
7486  {
7487  cells[id].vertices.resize(cell->n_vertices());
7488  for (const auto i : cell->vertex_indices())
7489  cells[id].vertices[i] = cell->vertex_index(i);
7490  cells[id].material_id = cell->material_id();
7491  cells[id].manifold_id = cell->manifold_id();
7492  }
7493 
7494  if (dim > 1)
7495  {
7497  face = in_tria.begin_active_face(),
7498  endf = in_tria.end_face();
7499 
7500  // Face counter for both dim == 2 and dim == 3
7501  unsigned int f = 0;
7502  switch (dim)
7503  {
7504  case 2:
7505  {
7506  subcelldata.boundary_lines.resize(in_tria.n_active_faces());
7507  for (; face != endf; ++face)
7508  if (face->at_boundary())
7509  {
7510  subcelldata.boundary_lines[f].vertices.resize(
7511  face->n_vertices());
7512  for (const auto i : face->vertex_indices())
7513  subcelldata.boundary_lines[f].vertices[i] =
7514  face->vertex_index(i);
7515  subcelldata.boundary_lines[f].boundary_id =
7516  face->boundary_id();
7517  subcelldata.boundary_lines[f].manifold_id =
7518  face->manifold_id();
7519  ++f;
7520  }
7521  subcelldata.boundary_lines.resize(f);
7522  }
7523  break;
7524  case 3:
7525  {
7526  subcelldata.boundary_quads.resize(in_tria.n_active_faces());
7527  for (; face != endf; ++face)
7528  if (face->at_boundary())
7529  {
7530  subcelldata.boundary_quads[f].vertices.resize(
7531  face->n_vertices());
7532  for (const auto i : face->vertex_indices())
7533  subcelldata.boundary_quads[f].vertices[i] =
7534  face->vertex_index(i);
7535  subcelldata.boundary_quads[f].boundary_id =
7536  face->boundary_id();
7537  subcelldata.boundary_quads[f].manifold_id =
7538  face->manifold_id();
7539  ++f;
7540  }
7541  subcelldata.boundary_quads.resize(f);
7542  }
7543  break;
7544  default:
7545  Assert(false, ExcInternalError());
7546  }
7547  }
7548  out_tria.create_triangulation(v, cells, subcelldata);
7549  }
7550 
7551 
7552 
7553  template <int dim, int spacedim>
7554  void
7556  Triangulation<dim, spacedim> &out_tria)
7557  {
7558  Assert(in_tria.n_global_levels() == 1,
7559  ExcMessage("Number of global levels has to be 1."));
7560 
7561  Assert(dim > 1, ExcNotImplemented());
7562 
7563  /* static tables with the definitions of cells, faces and edges by its
7564  * vertices for 2D and 3D. For the inheritance of the manifold_id,
7565  * definitions of inner-faces and boundary-faces are required. In case of
7566  * 3D, also inner-edges and boundary-edges need to be defined.
7567  */
7568 
7569  /* Cell definition 2D:
7570  * A quadrilateral element is converted to 8 simplices elements. Each
7571  * triangle is defined by 3 vertices.
7572  */
7573  static const ndarray<unsigned int, 8, 3> table_2D_cell = {{{{0, 6, 4}},
7574  {{8, 4, 6}},
7575  {{8, 6, 5}},
7576  {{1, 5, 6}},
7577  {{2, 4, 7}},
7578  {{8, 7, 4}},
7579  {{8, 5, 7}},
7580  {{3, 7, 5}}}};
7581 
7582  /* Cell definition 3D:
7583  * A hexahedron element is converted to 24 tetrahedron elements. Each
7584  * tetrahedron is defined by 4 vertices.
7585  */
7586  static const ndarray<unsigned int, 24, 4> vertex_ids_for_cells_3d = {
7587  {{{0, 1, 12, 10}}, {{2, 3, 11, 12}}, {{7, 6, 11, 13}},
7588  {{5, 4, 13, 10}}, {{0, 2, 8, 12}}, {{4, 6, 13, 8}},
7589  {{5, 13, 7, 9}}, {{1, 9, 3, 12}}, {{0, 8, 4, 10}},
7590  {{1, 5, 9, 10}}, {{3, 7, 11, 9}}, {{2, 6, 8, 11}},
7591  {{12, 13, 10, 9}}, {{12, 13, 9, 11}}, {{12, 13, 11, 8}},
7592  {{12, 13, 8, 10}}, {{13, 8, 10, 4}}, {{13, 10, 9, 5}},
7593  {{13, 9, 11, 7}}, {{13, 11, 8, 6}}, {{10, 12, 9, 1}},
7594  {{9, 12, 11, 3}}, {{11, 12, 8, 2}}, {{8, 12, 10, 0}}}};
7595 
7596  /* Boundary-faces 2D:
7597  * After converting, each of the 4 quadrilateral faces is defined by faces
7598  * of 2 different triangles, i.e., lines. Note that lines are defined by 2
7599  * vertices.
7600  */
7601  static const ndarray<unsigned int, 4, 2, 2>
7602  vertex_ids_for_boundary_faces_2d = {{{{{{0, 4}}, {{4, 2}}}},
7603  {{{{1, 5}}, {{5, 3}}}},
7604  {{{{0, 6}}, {{6, 1}}}},
7605  {{{{2, 7}}, {{7, 3}}}}}};
7606 
7607  /* Boundary-faces 3D:
7608  * After converting, each of the 6 hexahedron faces corresponds to faces of
7609  * 4 different tetrahedron faces, i.e., triangles. Note that a triangle is
7610  * defined by 3 vertices.
7611  */
7612  static const ndarray<unsigned int, 6, 4, 3>
7613  vertex_ids_for_boundary_faces_3d = {
7614  {{{{{0, 4, 8}}, {{4, 8, 6}}, {{8, 6, 2}}, {{0, 2, 8}}}},
7615  {{{{1, 3, 9}}, {{3, 9, 7}}, {{9, 7, 5}}, {{1, 9, 5}}}},
7616  {{{{0, 1, 10}}, {{1, 10, 5}}, {{10, 5, 4}}, {{0, 10, 4}}}},
7617  {{{{2, 3, 11}}, {{3, 11, 7}}, {{11, 7, 6}}, {{2, 11, 6}}}},
7618  {{{{0, 1, 12}}, {{1, 12, 3}}, {{12, 3, 2}}, {{0, 12, 2}}}},
7619  {{{{4, 5, 13}}, {{5, 13, 7}}, {{13, 7, 6}}, {{4, 13, 6}}}}}};
7620 
7621  /* Inner-faces 2D:
7622  * The converted triangulation based on simplices has 8 faces that do not
7623  * form the boundary, i.e. inner-faces, each defined by 2 vertices.
7624  */
7625  static const ndarray<unsigned int, 8, 2> vertex_ids_for_inner_faces_2d = {
7626  {{{6, 4}},
7627  {{6, 8}},
7628  {{6, 5}},
7629  {{4, 8}},
7630  {{8, 5}},
7631  {{7, 4}},
7632  {{7, 8}},
7633  {{7, 5}}}};
7634 
7635  /* Inner-faces 3D:
7636  * The converted triangulation based on simplices has 72 faces that do not
7637  * form the boundary, i.e. inner-faces, each defined by 3 vertices.
7638  */
7639  static const ndarray<unsigned int, 72, 3> vertex_ids_for_inner_faces_3d = {
7640  {{{0, 12, 10}}, {{12, 1, 10}}, {{12, 1, 9}}, {{12, 3, 9}},
7641  {{12, 2, 11}}, {{12, 3, 11}}, {{12, 0, 8}}, {{12, 2, 8}},
7642  {{9, 13, 5}}, {{13, 7, 9}}, {{11, 7, 13}}, {{11, 6, 13}},
7643  {{4, 8, 13}}, {{6, 8, 13}}, {{4, 13, 10}}, {{13, 5, 10}},
7644  {{10, 9, 5}}, {{10, 9, 1}}, {{11, 9, 7}}, {{11, 9, 3}},
7645  {{8, 11, 2}}, {{8, 11, 6}}, {{8, 10, 0}}, {{8, 10, 4}},
7646  {{12, 3, 9}}, {{12, 9, 11}}, {{12, 3, 11}}, {{3, 9, 11}},
7647  {{2, 12, 8}}, {{2, 12, 11}}, {{2, 11, 8}}, {{8, 12, 11}},
7648  {{0, 12, 10}}, {{0, 12, 8}}, {{0, 8, 10}}, {{8, 10, 12}},
7649  {{12, 1, 10}}, {{12, 1, 9}}, {{1, 10, 9}}, {{10, 9, 12}},
7650  {{10, 8, 4}}, {{10, 8, 13}}, {{4, 13, 8}}, {{4, 13, 10}},
7651  {{10, 9, 13}}, {{10, 9, 5}}, {{13, 5, 10}}, {{13, 5, 9}},
7652  {{13, 7, 9}}, {{13, 7, 11}}, {{9, 11, 13}}, {{9, 11, 7}},
7653  {{8, 11, 13}}, {{8, 11, 6}}, {{6, 13, 8}}, {{6, 13, 11}},
7654  {{12, 13, 10}}, {{12, 13, 8}}, {{8, 10, 13}}, {{8, 10, 12}},
7655  {{12, 13, 10}}, {{12, 13, 9}}, {{10, 9, 13}}, {{10, 9, 12}},
7656  {{12, 13, 9}}, {{12, 13, 11}}, {{9, 11, 13}}, {{9, 11, 12}},
7657  {{12, 13, 11}}, {{12, 13, 8}}, {{8, 11, 13}}, {{8, 11, 12}}}};
7658 
7659  /* Inner-edges 3D:
7660  * The converted triangulation based on simplices has 60 edges that do not
7661  * coincide with the boundary, i.e. inner-edges, each defined by 2 vertices.
7662  */
7663  static const ndarray<unsigned int, 60, 2> vertex_ids_for_inner_edges_3d = {
7664  {{{12, 10}}, {{12, 9}}, {{12, 11}}, {{12, 8}}, {{9, 13}}, {{11, 13}},
7665  {{8, 13}}, {{10, 13}}, {{10, 9}}, {{9, 11}}, {{11, 8}}, {{8, 10}},
7666  {{12, 9}}, {{12, 11}}, {{11, 9}}, {{12, 8}}, {{12, 11}}, {{11, 8}},
7667  {{12, 8}}, {{12, 10}}, {{10, 8}}, {{12, 10}}, {{12, 9}}, {{9, 10}},
7668  {{13, 10}}, {{13, 8}}, {{8, 10}}, {{13, 10}}, {{13, 9}}, {{9, 10}},
7669  {{13, 11}}, {{13, 9}}, {{11, 9}}, {{13, 11}}, {{13, 8}}, {{11, 8}},
7670  {{12, 13}}, {{8, 10}}, {{8, 13}}, {{10, 13}}, {{8, 12}}, {{10, 12}},
7671  {{12, 13}}, {{10, 9}}, {{10, 13}}, {{9, 13}}, {{10, 12}}, {{9, 12}},
7672  {{12, 13}}, {{9, 11}}, {{9, 13}}, {{11, 13}}, {{9, 12}}, {{11, 12}},
7673  {{12, 13}}, {{11, 8}}, {{11, 13}}, {{8, 13}}, {{11, 12}}, {{8, 12}}}};
7674 
7675  /* Boundary-edges 3D:
7676  * For each of the 6 boundary-faces of the hexahedron, there are 8 edges (of
7677  * different tetrahedrons) that coincide with the boundary, i.e.
7678  * boundary-edges. Each boundary-edge is defined by 2 vertices.
7679  */
7680  static const ndarray<unsigned int, 6, 8, 2>
7681  vertex_ids_for_boundary_edges_3d = {{{{{{4, 6}},
7682  {{4, 8}},
7683  {{6, 8}},
7684  {{4, 0}},
7685  {{6, 2}},
7686  {{0, 8}},
7687  {{2, 8}},
7688  {{0, 2}}}},
7689  {{{{5, 7}},
7690  {{5, 9}},
7691  {{7, 9}},
7692  {{5, 1}},
7693  {{7, 3}},
7694  {{1, 9}},
7695  {{3, 9}},
7696  {{1, 3}}}},
7697  {{{{4, 5}},
7698  {{4, 10}},
7699  {{5, 10}},
7700  {{4, 0}},
7701  {{5, 1}},
7702  {{0, 10}},
7703  {{1, 10}},
7704  {{0, 1}}}},
7705  {{{{6, 7}},
7706  {{6, 11}},
7707  {{7, 11}},
7708  {{6, 2}},
7709  {{7, 3}},
7710  {{2, 11}},
7711  {{3, 11}},
7712  {{2, 3}}}},
7713  {{{{2, 3}},
7714  {{2, 12}},
7715  {{3, 12}},
7716  {{2, 0}},
7717  {{3, 1}},
7718  {{0, 12}},
7719  {{1, 12}},
7720  {{0, 1}}}},
7721  {{{{6, 7}},
7722  {{6, 13}},
7723  {{7, 13}},
7724  {{6, 4}},
7725  {{7, 5}},
7726  {{4, 13}},
7727  {{5, 14}},
7728  {{4, 5}}}}}};
7729 
7730 
7731  std::vector<Point<spacedim>> vertices;
7732  std::vector<CellData<dim>> cells;
7733  SubCellData subcell_data;
7734 
7735  // store for each vertex and face the assigned index so that we only
7736  // assign them a value once
7737  std::vector<unsigned int> old_to_new_vertex_indices(
7739  std::vector<unsigned int> face_to_new_vertex_indices(
7741 
7742  // We first have to create all of the new vertices. To do this, we loop over
7743  // all cells and on each cell
7744  // (i) copy the existing vertex locations (and record their new indices in
7745  // the 'old_to_new_vertex_indices' vector),
7746  // (ii) create new midpoint vertex locations for each face (and record their
7747  // new indices in the 'face_to_new_vertex_indices' vector),
7748  // (iii) create new midpoint vertex locations for each cell (dim = 2 only)
7749  for (const auto &cell : in_tria)
7750  {
7751  // temporary array storing the global indices of each cell entity in the
7752  // sequence: vertices, edges/faces, cell
7753  std::array<unsigned int, dim == 2 ? 9 : 14> local_vertex_indices;
7754 
7755  // (i) copy the existing vertex locations
7756  for (const auto v : cell.vertex_indices())
7757  {
7758  const auto v_global = cell.vertex_index(v);
7759 
7760  if (old_to_new_vertex_indices[v_global] ==
7762  {
7763  old_to_new_vertex_indices[v_global] = vertices.size();
7764  vertices.push_back(cell.vertex(v));
7765  }
7766 
7767  local_vertex_indices[v] = old_to_new_vertex_indices[v_global];
7768  }
7769 
7770  // (ii) create new midpoint vertex locations for each face
7771  for (const auto f : cell.face_indices())
7772  {
7773  const auto f_global = cell.face_index(f);
7774 
7775  if (face_to_new_vertex_indices[f_global] ==
7777  {
7778  face_to_new_vertex_indices[f_global] = vertices.size();
7779  vertices.push_back(
7780  cell.face(f)->center(/*respect_manifold*/ true));
7781  }
7782 
7783  local_vertex_indices[cell.n_vertices() + f] =
7784  face_to_new_vertex_indices[f_global];
7785  }
7786 
7787  // (iii) create new midpoint vertex locations for each cell
7788  if (dim == 2)
7789  {
7790  local_vertex_indices[cell.n_vertices() + cell.n_faces()] =
7791  vertices.size();
7792  vertices.push_back(cell.center(/*respect_manifold*/ true));
7793  }
7794 
7795  // helper function for creating cells and subcells
7796  const auto add_cell = [&](const unsigned int struct_dim,
7797  const auto & index_vertices,
7798  const unsigned int material_or_boundary_id,
7799  const unsigned int manifold_id = 0) {
7800  // sub-cell data only has to be stored if the information differs
7801  // from the default
7802  if (struct_dim < dim &&
7803  (material_or_boundary_id == numbers::internal_face_boundary_id &&
7805  return;
7806 
7807  if (struct_dim == dim) // cells
7808  {
7809  if (dim == 2)
7810  {
7811  AssertDimension(index_vertices.size(), 3);
7812  }
7813  else if (dim == 3)
7814  {
7815  AssertDimension(index_vertices.size(), 4);
7816  }
7817 
7818  CellData<dim> cell_data(index_vertices.size());
7819  for (unsigned int i = 0; i < index_vertices.size(); ++i)
7820  {
7821  cell_data.vertices[i] =
7822  local_vertex_indices[index_vertices[i]];
7823  cell_data.material_id =
7824  material_or_boundary_id; // inherit material id
7825  cell_data.manifold_id =
7826  manifold_id; // inherit cell-manifold id
7827  }
7828  cells.push_back(cell_data);
7829  }
7830  else if (dim == 2 && struct_dim == 1) // an edge of a simplex
7831  {
7832  Assert(index_vertices.size() == 2, ExcInternalError());
7833  CellData<1> boundary_line(2);
7834  boundary_line.boundary_id = material_or_boundary_id;
7835  boundary_line.manifold_id = manifold_id;
7836  for (unsigned int i = 0; i < index_vertices.size(); ++i)
7837  {
7838  boundary_line.vertices[i] =
7839  local_vertex_indices[index_vertices[i]];
7840  }
7841  subcell_data.boundary_lines.push_back(boundary_line);
7842  }
7843  else if (dim == 3 && struct_dim == 2) // a face of a tetrahedron
7844  {
7845  Assert(index_vertices.size() == 3, ExcInternalError());
7846  CellData<2> boundary_quad(3);
7847  boundary_quad.material_id = material_or_boundary_id;
7848  boundary_quad.manifold_id = manifold_id;
7849  for (unsigned int i = 0; i < index_vertices.size(); ++i)
7850  {
7851  boundary_quad.vertices[i] =
7852  local_vertex_indices[index_vertices[i]];
7853  }
7854  subcell_data.boundary_quads.push_back(boundary_quad);
7855  }
7856  else if (dim == 3 && struct_dim == 1) // an edge of a tetrahedron
7857  {
7858  Assert(index_vertices.size() == 2, ExcInternalError());
7859  CellData<1> boundary_line(2);
7860  boundary_line.manifold_id = manifold_id;
7861  for (unsigned int i = 0; i < index_vertices.size(); ++i)
7862  {
7863  boundary_line.vertices[i] =
7864  local_vertex_indices[index_vertices[i]];
7865  }
7866  subcell_data.boundary_lines.push_back(boundary_line);
7867  }
7868  else
7869  {
7870  Assert(false, ExcNotImplemented());
7871  }
7872  };
7873 
7874  const auto material_id_cell = cell.material_id();
7875 
7876  // create cells one by one
7877  if (dim == 2)
7878  {
7879  // get cell-manifold id from current quad cell
7880  const auto manifold_id_cell = cell.manifold_id();
7881  // inherit cell manifold
7882  for (const auto &cell_vertices : table_2D_cell)
7883  add_cell(dim, cell_vertices, material_id_cell, manifold_id_cell);
7884 
7885  // inherit inner manifold (faces)
7886  for (const auto &face_vertices : vertex_ids_for_inner_faces_2d)
7887  // set inner tri-faces according to cell-manifold of quad
7888  // element, set invalid b_id, since we do not want to modify
7889  // b_id inside
7890  add_cell(1,
7891  face_vertices,
7893  manifold_id_cell);
7894  }
7895  else if (dim == 3)
7896  {
7897  // get cell-manifold id from current quad cell
7898  const auto manifold_id_cell = cell.manifold_id();
7899  // inherit cell manifold
7900  for (const auto &cell_vertices : vertex_ids_for_cells_3d)
7901  add_cell(dim, cell_vertices, material_id_cell, manifold_id_cell);
7902 
7903  // set manifold of inner FACES of tets according to
7904  // hex-cell-manifold
7905  for (const auto &face_vertices : vertex_ids_for_inner_faces_3d)
7906  add_cell(2,
7907  face_vertices,
7909  manifold_id_cell);
7910 
7911  // set manifold of inner EDGES of tets according to
7912  // hex-cell-manifold
7913  for (const auto &edge_vertices : vertex_ids_for_inner_edges_3d)
7914  add_cell(1,
7915  edge_vertices,
7917  manifold_id_cell);
7918  }
7919  else
7920  Assert(false, ExcNotImplemented());
7921 
7922  // Set up sub-cell data.
7923  for (const auto f : cell.face_indices())
7924  {
7925  const auto bid = cell.face(f)->boundary_id();
7926  const auto mid = cell.face(f)->manifold_id();
7927 
7928  // process boundary-faces: set boundary and manifold ids
7929  if (dim == 2) // 2D boundary-faces
7930  for (const auto &face_vertices :
7931  vertex_ids_for_boundary_faces_2d[f])
7932  add_cell(1, face_vertices, bid, mid);
7933 
7934  else if (dim == 3) // 3D boundary-faces
7935  {
7936  // set manifold id of tet-boundary-faces according to
7937  // hex-boundary-faces
7938  for (const auto &face_vertices :
7939  vertex_ids_for_boundary_faces_3d[f])
7940  add_cell(2, face_vertices, bid, mid);
7941  // set manifold id of tet-boundary-edges according to
7942  // hex-boundary-faces
7943  for (const auto &edge_vertices :
7944  vertex_ids_for_boundary_edges_3d[f])
7945  add_cell(1, edge_vertices, bid, mid);
7946  }
7947 
7948  else
7949  Assert(false, ExcNotImplemented());
7950  }
7951  }
7952 
7953  out_tria.create_triangulation(vertices, cells, subcell_data);
7954  }
7955 
7956 
7957 
7958  template <int spacedim>
7959  void
7961  Triangulation<1, spacedim> & out_tria)
7962  {
7963  out_tria.copy_triangulation(in_tria);
7964  return;
7965  }
7966 
7967 
7968 
7969  template <template <int, int> class MeshType, int dim, int spacedim>
7970 # ifndef _MSC_VER
7971  std::map<typename MeshType<dim - 1, spacedim>::cell_iterator,
7972  typename MeshType<dim, spacedim>::face_iterator>
7973 # else
7974  typename ExtractBoundaryMesh<MeshType, dim, spacedim>::return_type
7975 # endif
7976  extract_boundary_mesh(const MeshType<dim, spacedim> & volume_mesh,
7977  MeshType<dim - 1, spacedim> & surface_mesh,
7978  const std::set<types::boundary_id> &boundary_ids)
7979  {
7980  Assert((dynamic_cast<
7982  &volume_mesh.get_triangulation()) == nullptr),
7983  ExcNotImplemented());
7984 
7985  // This function works using the following assumption:
7986  // Triangulation::create_triangulation(...) will create cells that
7987  // preserve the order of cells passed in using the CellData argument;
7988  // also, that it will not reorder the vertices.
7989 
7990  // dimension of the boundary mesh
7991  const unsigned int boundary_dim = dim - 1;
7992 
7993  // temporary map for level==0
7994  // iterator to face is stored along with face number
7995  // (this is required by the algorithm to adjust the normals of the
7996  // cells of the boundary mesh)
7997  std::vector<
7998  std::pair<typename MeshType<dim, spacedim>::face_iterator, unsigned int>>
7999  temporary_mapping_level0;
8000 
8001  // vector indicating whether a vertex of the volume mesh has
8002  // already been visited (necessary to avoid duplicate vertices in
8003  // boundary mesh)
8004  std::vector<bool> touched(volume_mesh.get_triangulation().n_vertices(),
8005  false);
8006 
8007  // data structures required for creation of boundary mesh
8008  std::vector<CellData<boundary_dim>> cells;
8009  SubCellData subcell_data;
8010  std::vector<Point<spacedim>> vertices;
8011 
8012  // volume vertex indices to surf ones
8013  std::map<unsigned int, unsigned int> map_vert_index;
8014 
8015  // define swapping of vertices to get proper normal orientation of boundary
8016  // mesh;
8017  // the entry (i,j) of swap_matrix stores the index of the vertex of
8018  // the boundary cell corresponding to the j-th vertex on the i-th face
8019  // of the underlying volume cell
8020  // if e.g. face 3 of a volume cell is considered and vertices 1 and 2 of the
8021  // corresponding boundary cell are swapped to get
8022  // proper normal orientation, swap_matrix[3]=( 0, 2, 1, 3 )
8023  Table<2, unsigned int> swap_matrix(
8026  for (unsigned int i1 = 0; i1 < GeometryInfo<spacedim>::faces_per_cell; i1++)
8027  {
8028  for (unsigned int i2 = 0; i2 < GeometryInfo<dim - 1>::vertices_per_cell;
8029  i2++)
8030  swap_matrix[i1][i2] = i2;
8031  }
8032  // vertex swapping such that normals on the surface mesh point out of the
8033  // underlying volume
8034  if (dim == 3)
8035  {
8036  std::swap(swap_matrix[0][1], swap_matrix[0][2]);
8037  std::swap(swap_matrix[2][1], swap_matrix[2][2]);
8038  std::swap(swap_matrix[4][1], swap_matrix[4][2]);
8039  }
8040  else if (dim == 2)
8041  {
8042  std::swap(swap_matrix[1][0], swap_matrix[1][1]);
8043  std::swap(swap_matrix[2][0], swap_matrix[2][1]);
8044  }
8045 
8046  // Create boundary mesh and mapping
8047  // from only level(0) cells of volume_mesh
8048  for (typename MeshType<dim, spacedim>::cell_iterator cell =
8049  volume_mesh.begin(0);
8050  cell != volume_mesh.end(0);
8051  ++cell)
8052  for (unsigned int i : GeometryInfo<dim>::face_indices())
8053  {
8054  const typename MeshType<dim, spacedim>::face_iterator face =
8055  cell->face(i);
8056 
8057  if (face->at_boundary() &&
8058  (boundary_ids.empty() ||
8059  (boundary_ids.find(face->boundary_id()) != boundary_ids.end())))
8060  {
8061  CellData<boundary_dim> c_data;
8062 
8063  for (const unsigned int j :
8065  {
8066  const unsigned int v_index = face->vertex_index(j);
8067 
8068  if (!touched[v_index])
8069  {
8070  vertices.push_back(face->vertex(j));
8071  map_vert_index[v_index] = vertices.size() - 1;
8072  touched[v_index] = true;
8073  }
8074 
8075  c_data.vertices[swap_matrix[i][j]] = map_vert_index[v_index];
8076  }
8077  c_data.material_id =
8078  static_cast<types::material_id>(face->boundary_id());
8079  c_data.manifold_id = face->manifold_id();
8080 
8081 
8082  // in 3d, we need to make sure we copy the manifold
8083  // indicators from the edges of the volume mesh to the
8084  // edges of the surface mesh
8085  //
8086  // we set default boundary ids for boundary lines
8087  // and numbers::internal_face_boundary_id for internal lines
8088  if (dim == 3)
8089  for (unsigned int e = 0; e < 4; ++e)
8090  {
8091  // see if we already saw this edge from a
8092  // neighboring face, either in this or the reverse
8093  // orientation. if so, skip it.
8094  {
8095  bool edge_found = false;
8096  for (auto &boundary_line : subcell_data.boundary_lines)
8097  if (((boundary_line.vertices[0] ==
8098  map_vert_index[face->line(e)->vertex_index(0)]) &&
8099  (boundary_line.vertices[1] ==
8100  map_vert_index[face->line(e)->vertex_index(
8101  1)])) ||
8102  ((boundary_line.vertices[0] ==
8103  map_vert_index[face->line(e)->vertex_index(1)]) &&
8104  (boundary_line.vertices[1] ==
8105  map_vert_index[face->line(e)->vertex_index(0)])))
8106  {
8107  boundary_line.boundary_id =
8109  edge_found = true;
8110  break;
8111  }
8112  if (edge_found == true)
8113  // try next edge of current face
8114  continue;
8115  }
8116 
8117  CellData<1> edge;
8118  edge.vertices[0] =
8119  map_vert_index[face->line(e)->vertex_index(0)];
8120  edge.vertices[1] =
8121  map_vert_index[face->line(e)->vertex_index(1)];
8122  edge.boundary_id = 0;
8123  edge.manifold_id = face->line(e)->manifold_id();
8124 
8125  subcell_data.boundary_lines.push_back(edge);
8126  }
8127 
8128  cells.push_back(c_data);
8129  temporary_mapping_level0.push_back(std::make_pair(face, i));
8130  }
8131  }
8132 
8133  // create level 0 surface triangulation
8134  Assert(cells.size() > 0, ExcMessage("No boundary faces selected"));
8135  const_cast<Triangulation<dim - 1, spacedim> &>(
8136  surface_mesh.get_triangulation())
8137  .create_triangulation(vertices, cells, subcell_data);
8138 
8139  // in 2d: set default boundary ids for "boundary vertices"
8140  if (dim == 2)
8141  {
8142  for (const auto &cell : surface_mesh.active_cell_iterators())
8143  for (unsigned int vertex = 0; vertex < 2; vertex++)
8144  if (cell->face(vertex)->at_boundary())
8145  cell->face(vertex)->set_boundary_id(0);
8146  }
8147 
8148  // Make mapping for level 0
8149 
8150  // temporary map between cells on the boundary and corresponding faces of
8151  // domain mesh (each face is characterized by an iterator to the face and
8152  // the face number within the underlying cell)
8153  std::vector<std::pair<
8154  const typename MeshType<dim - 1, spacedim>::cell_iterator,
8155  std::pair<typename MeshType<dim, spacedim>::face_iterator, unsigned int>>>
8156  temporary_map_boundary_cell_face;
8157  for (const auto &cell : surface_mesh.active_cell_iterators())
8158  temporary_map_boundary_cell_face.push_back(
8159  std::make_pair(cell, temporary_mapping_level0.at(cell->index())));
8160 
8161 
8162  // refine the boundary mesh according to the refinement of the underlying
8163  // volume mesh,
8164  // algorithm:
8165  // (1) check which cells on refinement level i need to be refined
8166  // (2) do refinement (yields cells on level i+1)
8167  // (3) repeat for the next level (i+1->i) until refinement is completed
8168 
8169  // stores the index into temporary_map_boundary_cell_face at which
8170  // presently deepest refinement level of boundary mesh begins
8171  unsigned int index_cells_deepest_level = 0;
8172  do
8173  {
8174  bool changed = false;
8175 
8176  // vector storing cells which have been marked for
8177  // refinement
8178  std::vector<unsigned int> cells_refined;
8179 
8180  // loop over cells of presently deepest level of boundary triangulation
8181  for (unsigned int cell_n = index_cells_deepest_level;
8182  cell_n < temporary_map_boundary_cell_face.size();
8183  cell_n++)
8184  {
8185  // mark boundary cell for refinement if underlying volume face has
8186  // children
8187  if (temporary_map_boundary_cell_face[cell_n]
8188  .second.first->has_children())
8189  {
8190  // algorithm only works for
8191  // isotropic refinement!
8192  Assert(temporary_map_boundary_cell_face[cell_n]
8193  .second.first->refinement_case() ==
8195  ExcNotImplemented());
8196  temporary_map_boundary_cell_face[cell_n]
8197  .first->set_refine_flag();
8198  cells_refined.push_back(cell_n);
8199  changed = true;
8200  }
8201  }
8202 
8203  // if cells have been marked for refinement (i.e., presently deepest
8204  // level is not the deepest level of the volume mesh)
8205  if (changed)
8206  {
8207  // do actual refinement
8208  const_cast<Triangulation<dim - 1, spacedim> &>(
8209  surface_mesh.get_triangulation())
8210  .execute_coarsening_and_refinement();
8211 
8212  // add new level of cells to temporary_map_boundary_cell_face
8213  index_cells_deepest_level = temporary_map_boundary_cell_face.size();
8214  for (const auto &refined_cell_n : cells_refined)
8215  {
8216  const typename MeshType<dim - 1, spacedim>::cell_iterator
8217  refined_cell =
8218  temporary_map_boundary_cell_face[refined_cell_n].first;
8219  const typename MeshType<dim,
8220  spacedim>::face_iterator refined_face =
8221  temporary_map_boundary_cell_face[refined_cell_n].second.first;
8222  const unsigned int refined_face_number =
8223  temporary_map_boundary_cell_face[refined_cell_n]
8224  .second.second;
8225  for (unsigned int child_n = 0;
8226  child_n < refined_cell->n_children();
8227  ++child_n)
8228  // at this point, the swapping of vertices done earlier must
8229  // be taken into account to get the right association between
8230  // volume faces and boundary cells!
8231  temporary_map_boundary_cell_face.push_back(
8232  std::make_pair(refined_cell->child(
8233  swap_matrix[refined_face_number][child_n]),
8234  std::make_pair(refined_face->child(child_n),
8235  refined_face_number)));
8236  }
8237  }
8238  // we are at the deepest level of refinement of the volume mesh
8239  else
8240  break;
8241  }
8242  while (true);
8243 
8244  // generate the final mapping from the temporary mapping
8245  std::map<typename MeshType<dim - 1, spacedim>::cell_iterator,
8246  typename MeshType<dim, spacedim>::face_iterator>
8247  surface_to_volume_mapping;
8248  for (unsigned int i = 0; i < temporary_map_boundary_cell_face.size(); i++)
8249  surface_to_volume_mapping[temporary_map_boundary_cell_face[i].first] =
8250  temporary_map_boundary_cell_face[i].second.first;
8251 
8252  return surface_to_volume_mapping;
8253  }
8254 
8255 
8256 
8257  template <int dim, int spacedim>
8258  void
8261  const std::vector<unsigned int> &repetitions,
8262  const Point<dim> & p1,
8263  const Point<dim> & p2,
8264  const bool colorize)
8265  {
8266  AssertDimension(dim, spacedim);
8267 
8268  AssertThrow(colorize == false, ExcNotImplemented());
8269 
8270  std::vector<Point<spacedim>> vertices;
8271  std::vector<CellData<dim>> cells;
8272 
8273  if (dim == 2)
8274  {
8275  // determine cell sizes
8276  const Point<dim> dx((p2[0] - p1[0]) / repetitions[0],
8277  (p2[1] - p1[1]) / repetitions[1]);
8278 
8279  // create vertices
8280  for (unsigned int j = 0; j <= repetitions[1]; ++j)
8281  for (unsigned int i = 0; i <= repetitions[0]; ++i)
8282  vertices.push_back(
8283  Point<spacedim>(p1[0] + dx[0] * i, p1[1] + dx[1] * j));
8284 
8285  // create cells
8286  for (unsigned int j = 0; j < repetitions[1]; ++j)
8287  for (unsigned int i = 0; i < repetitions[0]; ++i)
8288  {
8289  // create reference QUAD cell
8290  std::array<unsigned int, 4> quad{{
8291  (j + 0) * (repetitions[0] + 1) + i + 0, //
8292  (j + 0) * (repetitions[0] + 1) + i + 1, //
8293  (j + 1) * (repetitions[0] + 1) + i + 0, //
8294  (j + 1) * (repetitions[0] + 1) + i + 1 //
8295  }}; //
8296 
8297  // TRI cell 0
8298  {
8299  CellData<dim> tri;
8300  tri.vertices = {quad[0], quad[1], quad[2]};
8301  cells.push_back(tri);
8302  }
8303 
8304  // TRI cell 1
8305  {
8306  CellData<dim> tri;
8307  tri.vertices = {quad[3], quad[2], quad[1]};
8308  cells.push_back(tri);
8309  }
8310  }
8311  }
8312  else if (dim == 3)
8313  {
8314  // determine cell sizes
8315  const Point<dim> dx((p2[0] - p1[0]) / repetitions[0],
8316  (p2[1] - p1[1]) / repetitions[1],
8317  (p2[2] - p1[2]) / repetitions[2]);
8318 
8319  // create vertices
8320  for (unsigned int k = 0; k <= repetitions[2]; ++k)
8321  for (unsigned int j = 0; j <= repetitions[1]; ++j)
8322  for (unsigned int i = 0; i <= repetitions[0]; ++i)
8323  vertices.push_back(Point<spacedim>(p1[0] + dx[0] * i,
8324  p1[1] + dx[1] * j,
8325  p1[2] + dx[2] * k));
8326 
8327  // create cells
8328  for (unsigned int k = 0; k < repetitions[2]; ++k)
8329  for (unsigned int j = 0; j < repetitions[1]; ++j)
8330  for (unsigned int i = 0; i < repetitions[0]; ++i)
8331  {
8332  // create reference HEX cell
8333  std::array<unsigned int, 8> quad{
8334  {(k + 0) * (repetitions[0] + 1) * (repetitions[1] + 1) +
8335  (j + 0) * (repetitions[0] + 1) + i + 0,
8336  (k + 0) * (repetitions[0] + 1) * (repetitions[1] + 1) +
8337  (j + 0) * (repetitions[0] + 1) + i + 1,
8338  (k + 0) * (repetitions[0] + 1) * (repetitions[1] + 1) +
8339  (j + 1) * (repetitions[0] + 1) + i + 0,
8340  (k + 0) * (repetitions[0] + 1) * (repetitions[1] + 1) +
8341  (j + 1) * (repetitions[0] + 1) + i + 1,
8342  (k + 1) * (repetitions[0] + 1) * (repetitions[1] + 1) +
8343  (j + 0) * (repetitions[0] + 1) + i + 0,
8344  (k + 1) * (repetitions[0] + 1) * (repetitions[1] + 1) +
8345  (j + 0) * (repetitions[0] + 1) + i + 1,
8346  (k + 1) * (repetitions[0] + 1) * (repetitions[1] + 1) +
8347  (j + 1) * (repetitions[0] + 1) + i + 0,
8348  (k + 1) * (repetitions[0] + 1) * (repetitions[1] + 1) +
8349  (j + 1) * (repetitions[0] + 1) + i + 1}};
8350 
8351  // TET cell 0
8352  {
8353  CellData<dim> cell;
8354  if (((i % 2) + (j % 2) + (k % 2)) % 2 == 0)
8355  cell.vertices = {{quad[0], quad[1], quad[2], quad[4]}};
8356  else
8357  cell.vertices = {{quad[0], quad[1], quad[3], quad[5]}};
8358 
8359  cells.push_back(cell);
8360  }
8361 
8362  // TET cell 1
8363  {
8364  CellData<dim> cell;
8365  if (((i % 2) + (j % 2) + (k % 2)) % 2 == 0)
8366  cell.vertices = {{quad[2], quad[1], quad[3], quad[7]}};
8367  else
8368  cell.vertices = {{quad[0], quad[3], quad[2], quad[6]}};
8369  cells.push_back(cell);
8370  }
8371 
8372  // TET cell 2
8373  {
8374  CellData<dim> cell;
8375  if (((i % 2) + (j % 2) + (k % 2)) % 2 == 0)
8376  cell.vertices = {{quad[1], quad[4], quad[5], quad[7]}};
8377  else
8378  cell.vertices = {{quad[0], quad[4], quad[5], quad[6]}};
8379  cells.push_back(cell);
8380  }
8381 
8382  // TET cell 3
8383  {
8384  CellData<dim> cell;
8385  if (((i % 2) + (j % 2) + (k % 2)) % 2 == 0)
8386  cell.vertices = {{quad[2], quad[4], quad[7], quad[6]}};
8387  else
8388  cell.vertices = {{quad[3], quad[5], quad[7], quad[6]}};
8389  cells.push_back(cell);
8390  }
8391 
8392  // TET cell 4
8393  {
8394  CellData<dim> cell;
8395  if (((i % 2) + (j % 2) + (k % 2)) % 2 == 0)
8396  cell.vertices = {{quad[1], quad[2], quad[4], quad[7]}};
8397  else
8398  cell.vertices = {{quad[0], quad[3], quad[6], quad[5]}};
8399  cells.push_back(cell);
8400  }
8401  }
8402  }
8403  else
8404  {
8405  AssertThrow(colorize == false, ExcNotImplemented());
8406  }
8407 
8408  // actually create triangulation
8409  tria.create_triangulation(vertices, cells, SubCellData());
8410  }
8411 
8412 
8413 
8414  template <int dim, int spacedim>
8415  void
8417  const unsigned int repetitions,
8418  const double p1,
8419  const double p2,
8420  const bool colorize)
8421  {
8422  if (dim == 2)
8423  {
8425  tria, {{repetitions, repetitions}}, {p1, p1}, {p2, p2}, colorize);
8426  }
8427  else if (dim == 3)
8428  {
8430  tria,
8431  {{repetitions, repetitions, repetitions}},
8432  {p1, p1, p1},
8433  {p2, p2, p2},
8434  colorize);
8435  }
8436  else
8437  {
8438  AssertThrow(false, ExcNotImplemented())
8439  }
8440  }
8441 
8442 } // namespace GridGenerator
8443 
8444 // explicit instantiations
8445 # include "grid_generator.inst"
8446 
8447 #endif // DOXYGEN
8448 
void make_mapping(const MeshType &source_grid, const MeshType &destination_grid)
void add_parameter(const std::string &entry, ParameterType &parameter, const std::string &documentation="", const Patterns::PatternBase &pattern= *Patterns::Tools::Convert< ParameterType >::to_pattern(), const bool has_to_be_set=false)
void enter_subsection(const std::string &subsection)
Definition: point.h:111
numbers::NumberTraits< Number >::real_type distance(const Point< dim, Number > &p) const
static Point< dim, Number > unit_vector(const unsigned int i)
const Point< spacedim > center
Definition: manifold_lib.h:131
constexpr Number determinant(const SymmetricTensor< 2, dim, Number > &t)
Definition: tensor.h:472
constexpr Tensor< 1, dim, typename ProductType< Number1, Number2 >::type > cross_product_3d(const Tensor< 1, dim, Number1 > &src1, const Tensor< 1, dim, Number2 > &src2)
Definition: tensor.h:2564
numbers::NumberTraits< Number >::real_type norm() const
void initialize(const Triangulation< dim, spacedim > &triangulation)
virtual types::global_cell_index n_global_active_cells() const
virtual void clear()
virtual void create_triangulation(const std::vector< Point< spacedim >> &vertices, const std::vector< CellData< dim >> &cells, const SubCellData &subcelldata)
virtual void copy_triangulation(const Triangulation< dim, spacedim > &other_tria)
unsigned int n_faces() const
face_iterator end_face() const
cell_iterator begin(const unsigned int level=0) const
unsigned int n_active_faces() const
unsigned int n_active_cells() const
void refine_global(const unsigned int times=1)
virtual void add_periodicity(const std::vector< GridTools::PeriodicFacePair< cell_iterator >> &)
unsigned int n_active_lines() const
unsigned int n_levels() const
cell_iterator end() const
vertex_iterator begin_vertex() const
vertex_iterator end_vertex() const
virtual void execute_coarsening_and_refinement()
virtual unsigned int n_global_levels() const
cell_iterator last() const
face_iterator begin_face() const
unsigned int n_cells() const
unsigned int n_vertices() const
active_face_iterator begin_active_face() const
const std::vector< Point< spacedim > > & get_vertices() const
active_cell_iterator begin_active(const unsigned int level=0) const
VectorizedArray< Number, width > max(const ::VectorizedArray< Number, width > &x, const ::VectorizedArray< Number, width > &y)
VectorizedArray< Number, width > min(const ::VectorizedArray< Number, width > &x, const ::VectorizedArray< Number, width > &y)
#define DEAL_II_NAMESPACE_OPEN
Definition: config.h:396
#define DEAL_II_NAMESPACE_CLOSE
Definition: config.h:397
Point< 3 > center
Point< 3 > vertices[4]
DerivativeForm< 1, spacedim, dim, Number > transpose(const DerivativeForm< 1, dim, spacedim, Number > &DF)
Point< 2 > second
Definition: grid_out.cc:4588
bool colorize
Definition: grid_out.cc:4589
Point< 2 > first
Definition: grid_out.cc:4587
unsigned int cell_index
Definition: grid_tools.cc:1092
IteratorRange< active_cell_iterator > active_cell_iterators() const
IteratorRange< active_face_iterator > active_face_iterators() const
IteratorRange< cell_iterator > cell_iterators() const
__global__ void set(Number *val, const Number s, const size_type N)
static ::ExceptionBase & ExcIndexRange(int arg1, int arg2, int arg3)
static ::ExceptionBase & ExcLowerRange(int arg1, int arg2)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcInvalidInputOrientation()
static ::ExceptionBase & ExcInvalidRadii()
static ::ExceptionBase & ExcInvalidRepetitionsDimension(int arg1)
#define Assert(cond, exc)
Definition: exceptions.h:1465
static ::ExceptionBase & ExcNotImplemented()
#define AssertDimension(dim1, dim2)
Definition: exceptions.h:1622
static ::ExceptionBase & ExcInvalidRepetitions(int arg1)
static ::ExceptionBase & ExcMessage(std::string arg1)
#define AssertThrow(cond, exc)
Definition: exceptions.h:1575
virtual std::vector< types::manifold_id > get_manifold_ids() const
void set_all_manifold_ids_on_boundary(const types::manifold_id number)
void copy_boundary_to_manifold_id(Triangulation< dim, spacedim > &tria, const bool reset_boundary_ids=false)
Definition: grid_tools.cc:4808
void set_manifold(const types::manifold_id number, const Manifold< dim, spacedim > &manifold_object)
const Manifold< dim, spacedim > & get_manifold(const types::manifold_id number) const
void reset_all_manifolds()
void set_all_manifold_ids(const types::manifold_id number)
void subdivided_hyper_cube_with_simplices(Triangulation< dim, spacedim > &tria, const unsigned int repetitions, const double p1=0.0, const double p2=1.0, const bool colorize=false)
void subdivided_hyper_rectangle_with_simplices(Triangulation< dim, spacedim > &tria, const std::vector< unsigned int > &repetitions, const Point< dim > &p1, const Point< dim > &p2, const bool colorize=false)
const Mapping< dim, spacedim > & get_default_linear_mapping(const Triangulation< dim, spacedim > &triangulation)
Definition: mapping.cc:240
Expression fabs(const Expression &x)
Expression ceil(const Expression &x)
Expression atan(const Expression &x)
Expression tanh(const Expression &x)
void interpolate(const DoFHandler< dim, spacedim > &dof1, const InVector &u1, const DoFHandler< dim, spacedim > &dof2, OutVector &u2)
void create_triangulation(Triangulation< dim, dim > &tria, const AdditionalData &additional_data=AdditionalData())
void parallelepiped(Triangulation< dim > &tria, const Point< dim >(&corners)[dim], const bool colorize=false)
void hyper_cross(Triangulation< dim, spacedim > &tria, const std::vector< unsigned int > &sizes, const bool colorize_cells=false)
A center cell with stacks of cell protruding from each surface.
void hyper_ball_balanced(Triangulation< dim > &tria, const Point< dim > &center=Point< dim >(), const double radius=1.)
void plate_with_a_hole(Triangulation< dim > &tria, const double inner_radius=0.4, const double outer_radius=1., const double pad_bottom=2., const double pad_top=2., const double pad_left=1., const double pad_right=1., const Point< dim > &center=Point< dim >(), const types::manifold_id polar_manifold_id=0, const types::manifold_id tfi_manifold_id=1, const double L=1., const unsigned int n_slices=2, const bool colorize=false)
Rectangular plate with an (offset) cylindrical hole.
void general_cell(Triangulation< dim, spacedim > &tria, const std::vector< Point< spacedim >> &vertices, const bool colorize=false)
void enclosed_hyper_cube(Triangulation< dim > &tria, const double left=0., const double right=1., const double thickness=1., const bool colorize=false)
void replicate_triangulation(const Triangulation< dim, spacedim > &input, const std::vector< unsigned int > &extents, Triangulation< dim, spacedim > &result)
Replicate a given triangulation in multiple coordinate axes.
void parallelogram(Triangulation< dim > &tria, const Point< dim >(&corners)[dim], const bool colorize=false)
void subdivided_hyper_cube(Triangulation< dim, spacedim > &tria, const unsigned int repetitions, const double left=0., const double right=1., const bool colorize=false)
void hyper_L(Triangulation< dim > &tria, const double left=-1., const double right=1., const bool colorize=false)
std::map< typename MeshType< dim - 1, spacedim >::cell_iterator, typename MeshType< dim, spacedim >::face_iterator > extract_boundary_mesh(const MeshType< dim, spacedim > &volume_mesh, MeshType< dim - 1, spacedim > &surface_mesh, const std::set< types::boundary_id > &boundary_ids=std::set< types::boundary_id >())
void hyper_cube_slit(Triangulation< dim > &tria, const double left=0., const double right=1., const bool colorize=false)
void hyper_ball(Triangulation< dim > &tria, const Point< dim > &center=Point< dim >(), const double radius=1., const bool attach_spherical_manifold_on_boundary_cells=false)
void eccentric_hyper_shell(Triangulation< dim > &triangulation, const Point< dim > &inner_center, const Point< dim > &outer_center, const double inner_radius, const double outer_radius, const unsigned int n_cells)
void hyper_rectangle(Triangulation< dim, spacedim > &tria, const Point< dim > &p1, const Point< dim > &p2, const bool colorize=false)
void cylinder(Triangulation< dim > &tria, const double radius=1., const double half_length=1.)
void moebius(Triangulation< 3, 3 > &tria, const unsigned int n_cells, const unsigned int n_rotations, const double R, const double r)
void extrude_triangulation(const Triangulation< 2, 2 > &input, const unsigned int n_slices, const double height, Triangulation< 3, 3 > &result, const bool copy_manifold_ids=false, const std::vector< types::manifold_id > &manifold_priorities={})
void half_hyper_shell(Triangulation< dim > &tria, const Point< dim > &center, const double inner_radius, const double outer_radius, const unsigned int n_cells=0, const bool colorize=false)
void quarter_hyper_ball(Triangulation< dim > &tria, const Point< dim > &center=Point< dim >(), const double radius=1.)
void cylinder_shell(Triangulation< dim > &tria, const double length, const double inner_radius, const double outer_radius, const unsigned int n_radial_cells=0, const unsigned int n_axial_cells=0)
void cheese(Triangulation< dim, spacedim > &tria, const std::vector< unsigned int > &holes)
Rectangular domain with rectangular pattern of holes.
void simplex(Triangulation< dim, dim > &tria, const std::vector< Point< dim >> &vertices)
void merge_triangulations(const Triangulation< dim, spacedim > &triangulation_1, const Triangulation< dim, spacedim > &triangulation_2, Triangulation< dim, spacedim > &result, const double duplicated_vertex_tolerance=1.0e-12, const bool copy_manifold_ids=false)
void non_standard_orientation_mesh(Triangulation< 2 > &tria, const bool rotate_left_square, const bool rotate_right_square)
void create_union_triangulation(const Triangulation< dim, spacedim > &triangulation_1, const Triangulation< dim, spacedim > &triangulation_2, Triangulation< dim, spacedim > &result)
void subdivided_parallelepiped(Triangulation< dim > &tria, const unsigned int n_subdivisions, const Point< dim >(&corners)[dim], const bool colorize=false)
void subdivided_cylinder(Triangulation< dim > &tria, const unsigned int x_subdivisions, const double radius=1., const double half_length=1.)
void channel_with_cylinder(Triangulation< dim > &tria, const double shell_region_width=0.03, const unsigned int n_shells=2, const double skewness=2.0, const bool colorize=false)
void subdivided_hyper_L(Triangulation< dim, spacedim > &tria, const std::vector< unsigned int > &repetitions, const Point< dim > &bottom_left, const Point< dim > &top_right, const std::vector< int > &n_cells_to_remove)
void hyper_sphere(Triangulation< spacedim - 1, spacedim > &tria, const Point< spacedim > &center=Point< spacedim >(), const double radius=1.)
void concentric_hyper_shells(Triangulation< dim > &triangulation, const Point< dim > &center, const double inner_radius=0.125, const double outer_radius=0.25, const unsigned int n_shells=1, const double skewness=0.1, const unsigned int n_cells_per_shell=0, const bool colorize=false)
void convert_hypercube_to_simplex_mesh(const Triangulation< dim, spacedim > &in_tria, Triangulation< dim, spacedim > &out_tria)
void subdivided_hyper_rectangle(Triangulation< dim, spacedim > &tria, const std::vector< unsigned int > &repetitions, const Point< dim > &p1, const Point< dim > &p2, const bool colorize=false)
void quarter_hyper_shell(Triangulation< dim > &tria, const Point< dim > &center, const double inner_radius, const double outer_radius, const unsigned int n_cells=0, const bool colorize=false)
void hyper_cube(Triangulation< dim, spacedim > &tria, const double left=0., const double right=1., const bool colorize=false)
void hyper_shell(Triangulation< dim > &tria, const Point< dim > &center, const double inner_radius, const double outer_radius, const unsigned int n_cells=0, bool colorize=false)
void create_triangulation_with_removed_cells(const Triangulation< dim, spacedim > &input_triangulation, const std::set< typename Triangulation< dim, spacedim >::active_cell_iterator > &cells_to_remove, Triangulation< dim, spacedim > &result)
void hyper_cube_with_cylindrical_hole(Triangulation< dim > &triangulation, const double inner_radius=.25, const double outer_radius=.5, const double L=.5, const unsigned int repetitions=1, const bool colorize=false)
void truncated_cone(Triangulation< dim > &tria, const double radius_0=1.0, const double radius_1=0.5, const double half_length=1.0)
void reference_cell(Triangulation< dim, spacedim > &tria, const ReferenceCell &reference_cell)
void half_hyper_ball(Triangulation< dim > &tria, const Point< dim > &center=Point< dim >(), const double radius=1.)
void flatten_triangulation(const Triangulation< dim, spacedim1 > &in_tria, Triangulation< dim, spacedim2 > &out_tria)
void scale(const double scaling_factor, Triangulation< dim, spacedim > &triangulation)
Definition: grid_tools.cc:2042
void transform(const Transformation &transformation, Triangulation< dim, spacedim > &triangulation)
void invert_all_negative_measure_cells(const std::vector< Point< spacedim >> &all_vertices, std::vector< CellData< dim >> &cells)
Definition: grid_tools.cc:863
void delete_duplicated_vertices(std::vector< Point< spacedim >> &all_vertices, std::vector< CellData< dim >> &cells, SubCellData &subcelldata, std::vector< unsigned int > &considered_vertices, const double tol=1e-12)
Definition: grid_tools.cc:731
void shift(const Tensor< 1, spacedim > &shift_vector, Triangulation< dim, spacedim > &triangulation)
Definition: grid_tools.cc:2022
void consistently_order_cells(std::vector< CellData< dim >> &cells)
Definition: grid_tools.cc:1921
void rotate(const double angle, Triangulation< dim > &triangulation)
double volume(const Triangulation< dim, spacedim > &tria, const Mapping< dim, spacedim > &mapping=(ReferenceCells::get_hypercube< dim >() .template get_default_linear_mapping< dim, spacedim >()))
Definition: grid_tools.cc:137
void delete_unused_vertices(std::vector< Point< spacedim >> &vertices, std::vector< CellData< dim >> &cells, SubCellData &subcelldata)
Definition: grid_tools.cc:626
bool have_same_coarse_mesh(const Triangulation< dim, spacedim > &mesh_1, const Triangulation< dim, spacedim > &mesh_2)
void collect_periodic_faces(const MeshType &mesh, const types::boundary_id b_id1, const types::boundary_id b_id2, const int direction, std::vector< PeriodicFacePair< typename MeshType::cell_iterator >> &matched_pairs, const Tensor< 1, MeshType::space_dimension > &offset=::Tensor< 1, MeshType::space_dimension >(), const FullMatrix< double > &matrix=FullMatrix< double >())
std::tuple< std::vector< Point< spacedim > >, std::vector< CellData< dim > >, SubCellData > get_coarse_mesh_description(const Triangulation< dim, spacedim > &tria)
Definition: grid_tools.cc:534
static const char L
static const char U
static const char A
static const char N
double norm(const FEValuesBase< dim > &fe, const ArrayView< const std::vector< Tensor< 1, dim >>> &Du)
Definition: divergence.h:472
void swap(MemorySpaceData< Number, MemorySpace > &, MemorySpaceData< Number, MemorySpace > &)
Point< spacedim > point(const gp_Pnt &p, const double tolerance=1e-10)
Definition: utilities.cc:188
SymmetricTensor< 2, dim, Number > C(const Tensor< 2, dim, Number > &F)
SymmetricTensor< 2, dim, Number > d(const Tensor< 2, dim, Number > &F, const Tensor< 2, dim, Number > &dF_dt)
SymmetricTensor< 2, dim, Number > epsilon(const Tensor< 2, dim, Number > &Grad_u)
SymmetricTensor< 2, dim, Number > e(const Tensor< 2, dim, Number > &F)
Tensor< 2, dim, Number > F(const Tensor< 2, dim, Number > &Grad_u)
SymmetricTensor< 2, dim, Number > b(const Tensor< 2, dim, Number > &F)
constexpr const ReferenceCell Tetrahedron
constexpr const ReferenceCell Wedge
constexpr const ReferenceCell Pyramid
constexpr const ReferenceCell Triangle
void partition(const SparsityPattern &sparsity_pattern, const unsigned int n_partitions, std::vector< unsigned int > &partition_indices, const Partitioner partitioner=Partitioner::metis)
VectorType::value_type * begin(VectorType &V)
VectorType::value_type * end(VectorType &V)
std::string int_to_string(const unsigned int value, const unsigned int digits=numbers::invalid_unsigned_int)
Definition: utilities.cc:473
long double gamma(const unsigned int n)
unsigned int n_cells(const internal::TriangulationImplementation::NumberCache< 1 > &c)
Definition: tria.cc:12587
void copy(const T *begin, const T *end, U *dest)
const types::material_id invalid_material_id
Definition: types.h:228
const types::boundary_id invalid_boundary_id
Definition: types.h:239
static constexpr double E
Definition: numbers.h:206
static constexpr double PI
Definition: numbers.h:231
const types::boundary_id internal_face_boundary_id
Definition: types.h:255
static const unsigned int invalid_unsigned_int
Definition: types.h:196
const types::manifold_id flat_manifold_id
Definition: types.h:264
unsigned int manifold_id
Definition: types.h:141
unsigned int material_id
Definition: types.h:152
unsigned int boundary_id
Definition: types.h:129
typename internal::ndarray::HelperArray< T, Ns... >::type ndarray
Definition: ndarray.h:108
::VectorizedArray< Number, width > cos(const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > abs(const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > sin(const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > tan(const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > sqrt(const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > pow(const ::VectorizedArray< Number, width > &, const Number p)
const ::parallel::distributed::Triangulation< dim, spacedim > * triangulation
std::vector< unsigned int > vertices
types::manifold_id manifold_id
types::material_id material_id
types::boundary_id boundary_id
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)
std::vector< CellData< 2 > > boundary_quads
std::vector< CellData< 1 > > boundary_lines