deal.II version GIT relicensing-2173-gae8fc9d14b 2024-11-24 06:40:00+00:00
\(\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\}}\)
Loading...
Searching...
No Matches
step-45.h
Go to the documentation of this file.
1 0,
107 /*b_id2*/ 1,
108 /*direction*/ 0,
109 matched_pairs);
110@endcode
111would yield periodicity constraints such that @f$u(0,y)=u(1,y)@f$ for all
112@f$y\in[0,1]@f$.
113
114If we instead consider the parallelogram given by the convex hull of
115@f$(0,0)@f$, @f$(1,1)@f$, @f$(1,2)@f$, @f$(0,1)@f$ we can achieve the constraints
116@f$u(0,y)=u(1,y+1)@f$ by specifying an @p offset:
117@code
119 /*b_id1*/ 0,
120 /*b_id2*/ 1,
121 /*direction*/ 0,
122 matched_pairs,
123 Tensor<1, 2>(0.,1.));
124@endcode
125or
126@code
128 /*b_id1*/ 0,
129 /*b_id2*/ 1,
130 /*arbitrary direction*/ 0,
131 matched_pairs,
132 Tensor<1, 2>(1.,1.));
133@endcode
134Here, again, the assignment of boundary indicators 0 and 1 stems from
135what GridGenerator::parallelogram() documents.
136
137The resulting @p matched_pairs can be used in
138DoFTools::make_periodicity_constraints for populating an AffineConstraints
139object with periodicity constraints:
140@code
141DoFTools::make_periodicity_constraints(matched_pairs, constraints);
142@endcode
143
144Apart from this high level interface there are also variants of
145DoFTools::make_periodicity_constraints available that combine those two
146steps (see the variants of DofTools::make_periodicity_constraints).
147
148There is also a low level interface to
149DoFTools::make_periodicity_constraints if more flexibility is needed. The
150low level variant allows to directly specify two faces that shall be
151constrained:
152@code
153using namespace DoFTools;
154make_periodicity_constraints(face_1,
155 face_2,
156 affine_constraints,
157 component_mask = <default value>;
158 face_orientation = <default value>,
159 face_flip = <default value>,
160 face_rotation = <default value>,
161 matrix = <default value>);
162@endcode
163Here, we need to specify the orientation of the two faces using
164@p face_orientation, @p face_flip and @p face_orientation. For a closer description
165have a look at the documentation of DoFTools::make_periodicity_constraints.
166The remaining parameters are the same as for the high level interface apart
167from the self-explaining @p component_mask and @p affine_constraints.
168
169
170<a name="step-45-problem"></a>
171<a name="step_45-Apracticalexample"></a><h1>A practical example</h1>
172
173
174In the following, we show how to use the above functions in a more involved
175example. The task is to enforce rotated periodicity constraints for the
176velocity component of a Stokes flow.
177
178On a quarter-circle defined by @f$\Omega=\{{\bf x}\in(0,1)^2:\|{\bf x}\|\in (0.5,1)\}@f$ we are
179going to solve the Stokes problem
180@f{eqnarray*}{
181 -\Delta \; \textbf{u} + \nabla p &=& (\exp(-100\|{\bf x}-(.75,0.1)^T\|^2),0)^T, \\
182 -\textrm{div}\; \textbf{u}&=&0,\\
183 \textbf{u}|_{\Gamma_1}&=&{\bf 0},
184@f}
185where the boundary @f$\Gamma_1@f$ is defined as @f$\Gamma_1 \dealcoloneq \{x\in \partial\Omega: \|x\|\in\{0.5,1\}\}@f$.
186For the remaining parts of the boundary we are going to use periodic boundary conditions, i.e.
187@f{align*}{
188 u_x(0,\nu)&=-u_y(\nu,0)&\nu&\in[0,1]\\
189 u_y(0,\nu)&=u_x(\nu,0)&\nu&\in[0,1].
190@f}
191
192The mesh will be generated by GridGenerator::quarter_hyper_shell(),
193which also documents how it assigns boundary indicators to its various
194boundaries if its `colorize` argument is set to `true`.
195 *
196 *
197 * <a name="step_45-CommProg"></a>
198 * <h1> The commented program</h1>
199 *
200 * This example program is a slight modification of @ref step_22 "step-22" running in parallel
201 * using Trilinos to demonstrate the usage of periodic boundary conditions in
202 * deal.II. We thus omit to discuss the majority of the source code and only
203 * comment on the parts that deal with periodicity constraints. For the rest
204 * have a look at @ref step_22 "step-22" and the full source code at the bottom.
205 *
206
207 *
208 * In order to implement periodic boundary conditions only two functions
209 * have to be modified:
210 * - <code>StokesProblem<dim>::setup_dofs()</code>:
211 * To populate an AffineConstraints object with periodicity constraints
212 * - <code>StokesProblem<dim>::create_mesh()</code>:
213 * To supply a distributed triangulation with periodicity information.
214 *
215
216 *
217 * The rest of the program is identical to @ref step_22 "step-22", so let us skip this part
218 * and only show these two functions in the following. (The full program can be
219 * found in the "Plain program" section below, though.)
220 *
221
222 *
223 *
224
225 *
226 *
227
228 *
229 *
230 * <a name="step_45-Settingupperiodicityconstraintsondistributedtriangulations"></a>
231 * <h3>Setting up periodicity constraints on distributed triangulations</h3>
232 *
233 * @code
234 *   template <int dim>
235 *   void StokesProblem<dim>::create_mesh()
236 *   {
237 *   Point<dim> center;
238 *   const double inner_radius = .5;
239 *   const double outer_radius = 1.;
240 *  
242 *   triangulation, center, inner_radius, outer_radius, 0, true);
243 *  
244 * @endcode
245 *
246 * Before we can prescribe periodicity constraints, we need to ensure that
247 * cells on opposite sides of the domain but connected by periodic faces are
248 * part of the ghost layer if one of them is stored on the local processor.
249 * At this point we need to think about how we want to prescribe
250 * periodicity. The vertices @f$\text{vertices}_2@f$ of a face on the left
251 * boundary should be matched to the vertices @f$\text{vertices}_1@f$ of a face
252 * on the lower boundary given by @f$\text{vertices}_2=R\cdot
253 * \text{vertices}_1+b@f$ where the rotation matrix @f$R@f$ and the offset @f$b@f$ are
254 * given by
255 * @f{align*}{
256 * R=\begin{pmatrix}
257 * 0&1\\-1&0
258 * \end{pmatrix},
259 * \quad
260 * b=\begin{pmatrix}0&0\end{pmatrix}.
261 * @f}
262 * The data structure we are saving the resulting information into is here
263 * based on the Triangulation.
264 *
265 * @code
266 *   std::vector<GridTools::PeriodicFacePair<
268 *   periodicity_vector;
269 *  
270 *   FullMatrix<double> rotation_matrix(dim);
271 *   rotation_matrix[0][1] = 1.;
272 *   rotation_matrix[1][0] = -1.;
273 *  
275 *   2,
276 *   3,
277 *   1,
278 *   periodicity_vector,
279 *   Tensor<1, dim>(),
280 *   rotation_matrix);
281 *  
282 * @endcode
283 *
284 * Now telling the triangulation about the desired periodicity is
285 * particularly easy by just calling
287 *
288 * @code
289 *   triangulation.add_periodicity(periodicity_vector);
290 *  
291 *   triangulation.refine_global(4 - dim);
292 *   }
293 *  
294 *  
295 *   template <int dim>
296 *   void StokesProblem<dim>::setup_dofs()
297 *   {
298 *   dof_handler.distribute_dofs(fe);
299 *  
300 *   std::vector<unsigned int> block_component(dim + 1, 0);
301 *   block_component[dim] = 1;
302 *   DoFRenumbering::component_wise(dof_handler, block_component);
303 *  
304 *   const std::vector<types::global_dof_index> dofs_per_block =
305 *   DoFTools::count_dofs_per_fe_block(dof_handler, block_component);
306 *   const unsigned int n_u = dofs_per_block[0], n_p = dofs_per_block[1];
307 *  
308 *   {
309 *   owned_partitioning.clear();
310 *   const IndexSet &locally_owned_dofs = dof_handler.locally_owned_dofs();
311 *   owned_partitioning.push_back(locally_owned_dofs.get_view(0, n_u));
312 *   owned_partitioning.push_back(locally_owned_dofs.get_view(n_u, n_u + n_p));
313 *  
314 *   relevant_partitioning.clear();
315 *   const IndexSet locally_relevant_dofs =
317 *   relevant_partitioning.push_back(locally_relevant_dofs.get_view(0, n_u));
318 *   relevant_partitioning.push_back(
319 *   locally_relevant_dofs.get_view(n_u, n_u + n_p));
320 *  
321 *   constraints.clear();
322 *   constraints.reinit(locally_owned_dofs, locally_relevant_dofs);
323 *  
324 *   const FEValuesExtractors::Vector velocities(0);
325 *  
326 *   DoFTools::make_hanging_node_constraints(dof_handler, constraints);
328 *   dof_handler,
329 *   0,
330 *   BoundaryValues<dim>(),
331 *   constraints,
332 *   fe.component_mask(velocities));
334 *   dof_handler,
335 *   1,
336 *   BoundaryValues<dim>(),
337 *   constraints,
338 *   fe.component_mask(velocities));
339 *  
340 * @endcode
341 *
342 * After we provided the mesh with the necessary information for the
343 * periodicity constraints, we are now able to actual create them. For
344 * describing the matching we are using the same approach as before, i.e.,
345 * the @f$\text{vertices}_2@f$ of a face on the left boundary should be
346 * matched to the vertices
347 * @f$\text{vertices}_1@f$ of a face on the lower boundary given by
348 * @f$\text{vertices}_2=R\cdot \text{vertices}_1+b@f$ where the rotation
349 * matrix @f$R@f$ and the offset @f$b@f$ are given by
350 * @f{align*}{
351 * R=\begin{pmatrix}
352 * 0&1\\-1&0
353 * \end{pmatrix},
354 * \quad
355 * b=\begin{pmatrix}0&0\end{pmatrix}.
356 * @f}
357 * These two objects not only describe how faces should be matched but
358 * also in which sense the solution should be transformed from
359 * @f$\text{face}_2@f$ to
360 * @f$\text{face}_1@f$.
361 *
362 * @code
363 *   FullMatrix<double> rotation_matrix(dim);
364 *   rotation_matrix[0][1] = 1.;
365 *   rotation_matrix[1][0] = -1.;
366 *  
367 *   Tensor<1, dim> offset;
368 *  
369 * @endcode
370 *
371 * For setting up the constraints, we first store the periodicity
372 * information in an auxiliary object of type
373 * <code>std::vector@<GridTools::PeriodicFacePair<typename
374 * DoFHandler@<dim@>::%cell_iterator@> </code>. The periodic boundaries
375 * have the boundary indicators 2 (x=0) and 3 (y=0). All the other
376 * parameters we have set up before. In this case the direction does not
377 * matter. Due to @f$\text{vertices}_2=R\cdot \text{vertices}_1+b@f$ this is
378 * exactly what we want.
379 *
380 * @code
381 *   std::vector<
383 *   periodicity_vector;
384 *  
385 *   const unsigned int direction = 1;
386 *  
387 *   GridTools::collect_periodic_faces(dof_handler,
388 *   2,
389 *   3,
390 *   direction,
391 *   periodicity_vector,
392 *   offset,
393 *   rotation_matrix);
394 *  
395 * @endcode
396 *
397 * Next, we need to provide information on which vector valued components
398 * of the solution should be rotated. Since we choose here to just
399 * constraint the velocity and this starts at the first component of the
400 * solution vector, we simply insert a 0:
401 *
402 * @code
403 *   std::vector<unsigned int> first_vector_components;
404 *   first_vector_components.push_back(0);
405 *  
406 * @endcode
407 *
408 * After setting up all the information in periodicity_vector all we have
409 * to do is to tell make_periodicity_constraints to create the desired
410 * constraints.
411 *
412 * @code
413 *   DoFTools::make_periodicity_constraints<dim, dim>(periodicity_vector,
414 *   constraints,
415 *   fe.component_mask(
416 *   velocities),
417 *   first_vector_components);
418 *   }
419 *  
420 *   constraints.close();
421 *  
422 *   {
423 *   TrilinosWrappers::BlockSparsityPattern bsp(owned_partitioning,
424 *   owned_partitioning,
425 *   relevant_partitioning,
426 *   mpi_communicator);
427 *  
428 *   Table<2, DoFTools::Coupling> coupling(dim + 1, dim + 1);
429 *   for (unsigned int c = 0; c < dim + 1; ++c)
430 *   for (unsigned int d = 0; d < dim + 1; ++d)
431 *   if (!((c == dim) && (d == dim)))
432 *   coupling[c][d] = DoFTools::always;
433 *   else
434 *   coupling[c][d] = DoFTools::none;
435 *  
436 *   DoFTools::make_sparsity_pattern(dof_handler,
437 *   coupling,
438 *   bsp,
439 *   constraints,
440 *   false,
442 *   mpi_communicator));
443 *  
444 *   bsp.compress();
445 *  
446 *   system_matrix.reinit(bsp);
447 *   }
448 *  
449 *   {
450 *   TrilinosWrappers::BlockSparsityPattern preconditioner_bsp(
451 *   owned_partitioning,
452 *   owned_partitioning,
453 *   relevant_partitioning,
454 *   mpi_communicator);
455 *  
456 *   Table<2, DoFTools::Coupling> preconditioner_coupling(dim + 1, dim + 1);
457 *   for (unsigned int c = 0; c < dim + 1; ++c)
458 *   for (unsigned int d = 0; d < dim + 1; ++d)
459 *   if ((c == dim) && (d == dim))
460 *   preconditioner_coupling[c][d] = DoFTools::always;
461 *   else
462 *   preconditioner_coupling[c][d] = DoFTools::none;
463 *  
464 *   DoFTools::make_sparsity_pattern(dof_handler,
465 *   preconditioner_coupling,
466 *   preconditioner_bsp,
467 *   constraints,
468 *   false,
470 *   mpi_communicator));
471 *  
472 *   preconditioner_bsp.compress();
473 *  
474 *   preconditioner_matrix.reinit(preconditioner_bsp);
475 *   }
476 *  
477 *   system_rhs.reinit(owned_partitioning, mpi_communicator);
478 *   solution.reinit(owned_partitioning,
479 *   relevant_partitioning,
480 *   mpi_communicator);
481 *   }
482 *  
483 * @endcode
484 *
485 * The rest of the program is then again identical to @ref step_22 "step-22". We will omit
486 * it here now, but as before, you can find these parts in the "Plain program"
487 * section below.
488 *
489
490 *
491<a name="step_45-Results"></a><h1>Results</h1>
492
493
494The created output is not very surprising. We simply see that the solution is
495periodic with respect to the left and lower boundary:
496
497<img src="https://www.dealii.org/images/steps/developer/step-45.periodic.png" alt="">
498
499Without the periodicity constraints we would have ended up with the following solution:
500
501<img src="https://www.dealii.org/images/steps/developer/step-45.non_periodic.png" alt="">
502 *
503 *
504<a name="step_45-PlainProg"></a>
505<h1> The plain program</h1>
506@include "step-45.cc"
507*/
void clear()
Definition index_set.h:1752
Definition point.h:111
virtual void add_periodicity(const std::vector<::GridTools::PeriodicFacePair< cell_iterator > > &) override
Definition tria.cc:3768
bool colorize
Definition grid_out.cc:4625
Point< 2 > first
Definition grid_out.cc:4623
unsigned int level
Definition grid_out.cc:4626
typename ::Triangulation< dim, spacedim >::cell_iterator cell_iterator
Definition tria.h:324
void make_hanging_node_constraints(const DoFHandler< dim, spacedim > &dof_handler, AffineConstraints< number > &constraints)
void make_sparsity_pattern(const DoFHandler< dim, spacedim > &dof_handler, SparsityPatternBase &sparsity_pattern, const AffineConstraints< number > &constraints={}, const bool keep_constrained_dofs=true, const types::subdomain_id subdomain_id=numbers::invalid_subdomain_id)
std::vector< index_type > data
Definition mpi.cc:735
void component_wise(DoFHandler< dim, spacedim > &dof_handler, const std::vector< unsigned int > &target_component=std::vector< unsigned int >())
void make_periodicity_constraints(const FaceIterator &face_1, const std_cxx20::type_identity_t< FaceIterator > &face_2, AffineConstraints< number > &constraints, const ComponentMask &component_mask={}, const unsigned char combined_orientation=ReferenceCell::default_combined_face_orientation(), const FullMatrix< double > &matrix=FullMatrix< double >(), const std::vector< unsigned int > &first_vector_components=std::vector< unsigned int >(), const number periodicity_factor=1.)
IndexSet extract_locally_relevant_dofs(const DoFHandler< dim, spacedim > &dof_handler)
std::vector< types::global_dof_index > count_dofs_per_fe_block(const DoFHandler< dim, spacedim > &dof, const std::vector< unsigned int > &target_block=std::vector< unsigned int >())
void parallelogram(Triangulation< dim > &tria, const Point< dim >(&corners)[dim], 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 collect_periodic_faces(const MeshType &mesh, const types::boundary_id b_id1, const types::boundary_id b_id2, const unsigned 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 >())
@ matrix
Contents is actually a matrix.
Point< spacedim > point(const gp_Pnt &p, const double tolerance=1e-10)
Definition utilities.cc:191
SymmetricTensor< 2, dim, Number > b(const Tensor< 2, dim, Number > &F)
SymmetricTensor< 2, dim, Number > d(const Tensor< 2, dim, Number > &F, const Tensor< 2, dim, Number > &dF_dt)
VectorType::value_type * end(VectorType &V)
VectorType::value_type * begin(VectorType &V)
unsigned int this_mpi_process(const MPI_Comm mpi_communicator)
Definition mpi.cc:107
void interpolate_boundary_values(const Mapping< dim, spacedim > &mapping, const DoFHandler< dim, spacedim > &dof, const std::map< types::boundary_id, const Function< spacedim, number > * > &function_map, std::map< types::global_dof_index, number > &boundary_values, const ComponentMask &component_mask={})
int(&) functions(const void *v1, const void *v2)
const ::parallel::distributed::Triangulation< dim, spacedim > * triangulation