ExaDG
Loading...
Searching...
No Matches
mapping_dof_vector.h
1/* ______________________________________________________________________
2 *
3 * ExaDG - High-Order Discontinuous Galerkin for the Exa-Scale
4 *
5 * Copyright (C) 2021 by the ExaDG authors
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 * ______________________________________________________________________
20 */
21
22#ifndef EXADG_GRID_MAPPING_DOF_VECTOR_H_
23#define EXADG_GRID_MAPPING_DOF_VECTOR_H_
24
25// deal.II
26#include <deal.II/base/conditional_ostream.h>
27#include <deal.II/base/mg_level_object.h>
28#include <deal.II/base/multithread_info.h>
29#include <deal.II/base/quadrature_lib.h>
30#include <deal.II/dofs/dof_tools.h>
31#include <deal.II/fe/fe_nothing.h>
32#include <deal.II/fe/fe_q.h>
33#include <deal.II/fe/fe_system.h>
34#include <deal.II/fe/fe_tools.h>
35#include <deal.II/fe/fe_values.h>
36#include <deal.II/fe/mapping_q_cache.h>
37#include <deal.II/lac/la_parallel_block_vector.h>
38#include <deal.II/multigrid/mg_transfer_matrix_free.h>
39
40// ExaDG
41#include <exadg/grid/grid_data.h>
42#include <exadg/solvers_and_preconditioners/multigrid/transfer.h>
43
44namespace ExaDG
45{
53template<int dim, typename Number>
55{
56public:
57 typedef dealii::LinearAlgebra::distributed::Vector<Number> VectorType;
58
62 MappingDoFVector(unsigned int const mapping_degree)
63 {
64 mapping_q_cache = std::make_shared<dealii::MappingQCache<dim>>(mapping_degree);
65
66 hierarchic_to_lexicographic_numbering =
67 dealii::FETools::hierarchic_to_lexicographic_numbering<dim>(mapping_degree);
68 lexicographic_to_hierarchic_numbering =
69 dealii::Utilities::invert_permutation(hierarchic_to_lexicographic_numbering);
70 }
71
76 {
77 }
78
82 std::shared_ptr<dealii::Mapping<dim> const>
84 {
85 AssertThrow(mapping_q_cache.get(),
86 dealii::ExcMessage("Mapping object mapping_q_cache is not initialized."));
87
88 return mapping_q_cache;
89 }
90
91 std::shared_ptr<dealii::MappingQCache<dim>>
92 get_mapping_q_cache() const
93 {
94 AssertThrow(mapping_q_cache.get(),
95 dealii::ExcMessage("Mapping object mapping_q_cache is not initialized."));
96
97 return mapping_q_cache;
98 }
99
105 void
106 fill_grid_coordinates_vector(VectorType & grid_coordinates,
107 dealii::DoFHandler<dim> const & dof_handler) const
108 {
109 AssertThrow(mapping_q_cache.get(),
110 dealii::ExcMessage("Mapping object mapping_q_cache is not initialized."));
111
112 // use the deformed state described by the dealii::MappingQCache object
113 fill_grid_coordinates_vector(*mapping_q_cache, grid_coordinates, dof_handler);
114 }
115
120 void
121 fill_grid_coordinates_vector(dealii::Mapping<dim> const & mapping,
122 VectorType & grid_coordinates,
123 dealii::DoFHandler<dim> const & dof_handler) const
124 {
125 if(grid_coordinates.size() != dof_handler.n_dofs())
126 {
127 dealii::IndexSet const relevant_dofs_grid =
128 dealii::DoFTools::extract_locally_relevant_dofs(dof_handler);
129 grid_coordinates.reinit(dof_handler.locally_owned_dofs(),
130 relevant_dofs_grid,
131 dof_handler.get_mpi_communicator());
132 }
133 else
134 {
135 grid_coordinates = 0;
136 }
137
138 AssertThrow(get_element_type(dof_handler.get_triangulation()) == ElementType::Hypercube,
139 dealii::ExcMessage("Only implemented for hypercube elements."));
140
141 dealii::FiniteElement<dim> const & fe = dof_handler.get_fe();
142
143 std::vector<std::array<unsigned int, dim>> component_to_system_index(
144 fe.base_element(0).dofs_per_cell);
145
146 if(fe.dofs_per_vertex > 0) // dealii::FE_Q
147 {
148 for(unsigned int i = 0; i < fe.dofs_per_cell; ++i)
149 {
150 component_to_system_index
151 [hierarchic_to_lexicographic_numbering[fe.system_to_component_index(i).second]]
152 [fe.system_to_component_index(i).first] = i;
153 }
154 }
155 else // dealii::FE_DGQ
156 {
157 for(unsigned int i = 0; i < fe.dofs_per_cell; ++i)
158 {
159 component_to_system_index[fe.system_to_component_index(i).second]
160 [fe.system_to_component_index(i).first] = i;
161 }
162 }
163
164 // Set up dealii::FEValues with FE_Nothing and the Gauss-Lobatto quadrature to
165 // reduce setup cost, as we only use the geometry information (this means
166 // we need to call fe_values.reinit(cell) with Triangulation::cell_iterator
167 // rather than dealii::DoFHandler::cell_iterator).
168 dealii::FE_Nothing<dim> fe_nothing;
169 dealii::FEValues<dim> fe_values(mapping,
170 fe_nothing,
171 dealii::QGaussLobatto<dim>(fe.degree + 1),
172 dealii::update_quadrature_points);
173
174 std::vector<dealii::types::global_dof_index> dof_indices(fe.dofs_per_cell);
175
176 for(auto const & cell : dof_handler.active_cell_iterators())
177 {
178 if(not cell->is_artificial())
179 {
180 fe_values.reinit(typename dealii::Triangulation<dim>::cell_iterator(cell));
181 cell->get_dof_indices(dof_indices);
182 for(unsigned int i = 0; i < fe_values.n_quadrature_points; ++i)
183 {
184 dealii::Point<dim> const point = fe_values.quadrature_point(i);
185 for(unsigned int d = 0; d < dim; ++d)
186 {
187 if(grid_coordinates.get_partitioner()->in_local_range(
188 dof_indices[component_to_system_index[i][d]]))
189 {
190 grid_coordinates(dof_indices[component_to_system_index[i][d]]) = point[d];
191 }
192 }
193 }
194 }
195 }
196
197 grid_coordinates.update_ghost_values();
198 }
199
212 void
213 initialize_mapping_from_dof_vector(std::shared_ptr<dealii::Mapping<dim> const> mapping,
214 VectorType const & displacement_vector,
215 dealii::DoFHandler<dim> const & dof_handler)
216 {
217 AssertThrow(dealii::MultithreadInfo::n_threads() == 1, dealii::ExcNotImplemented());
218
219 AssertThrow(mapping_q_cache.get(),
220 dealii::ExcMessage("Mapping object mapping_q_cache is not initialized."));
221
222 VectorType displacement_vector_ghosted;
223 if(dof_handler.n_dofs() > 0 and displacement_vector.size() == dof_handler.n_dofs())
224 {
225 dealii::IndexSet const locally_relevant_dofs =
226 dealii::DoFTools::extract_locally_relevant_dofs(dof_handler);
227 displacement_vector_ghosted.reinit(dof_handler.locally_owned_dofs(),
228 locally_relevant_dofs,
229 dof_handler.get_mpi_communicator());
230 displacement_vector_ghosted.copy_locally_owned_data_from(displacement_vector);
231 displacement_vector_ghosted.update_ghost_values();
232 }
233
234 AssertThrow(get_element_type(dof_handler.get_triangulation()) == ElementType::Hypercube,
235 dealii::ExcMessage("Only implemented for hypercube elements."));
236
237 std::shared_ptr<dealii::FEValues<dim>> fe_values;
238
239 // Set up dealii::FEValues with FE_Nothing and the Gauss-Lobatto quadrature to
240 // reduce setup cost, as we only use the geometry information (this means
241 // we need to call fe_values.reinit(cell) with Triangulation::cell_iterator
242 // rather than dealii::DoFHandler::cell_iterator).
243 dealii::FE_Nothing<dim> fe_nothing;
244
245 if(mapping.get() != 0)
246 {
247 fe_values = std::make_shared<dealii::FEValues<dim>>(*mapping,
248 fe_nothing,
249 dealii::QGaussLobatto<dim>(
250 mapping_q_cache->get_degree() + 1),
251 dealii::update_quadrature_points);
252 }
253
254 // take the grid coordinates described by mapping and add deformation described by displacement
255 // vector
256 mapping_q_cache->initialize(
257 dof_handler.get_triangulation(),
258 [&](const typename dealii::Triangulation<dim>::cell_iterator & cell_tria)
259 -> std::vector<dealii::Point<dim>> {
260 unsigned int const scalar_dofs_per_cell =
261 dealii::Utilities::pow(mapping_q_cache->get_degree() + 1, dim);
262
263 std::vector<dealii::Point<dim>> grid_coordinates(scalar_dofs_per_cell);
264
265 if(mapping.get() != 0)
266 {
267 fe_values->reinit(cell_tria);
268 // extract displacement and add to original position
269 for(unsigned int i = 0; i < scalar_dofs_per_cell; ++i)
270 {
271 grid_coordinates[i] =
272 fe_values->quadrature_point(this->hierarchic_to_lexicographic_numbering[i]);
273 }
274 }
275
276 // if this function is called with an empty dof-vector, this indicates that the
277 // displacements are zero and the points do not have to be moved
278 if(dof_handler.n_dofs() > 0 and displacement_vector.size() > 0 and
279 cell_tria->is_active() and not(cell_tria->is_artificial()))
280 {
281 typename dealii::DoFHandler<dim>::cell_iterator cell(&cell_tria->get_triangulation(),
282 cell_tria->level(),
283 cell_tria->index(),
284 &dof_handler);
285
286 dealii::FiniteElement<dim> const & fe = dof_handler.get_fe();
287 AssertThrow(fe.element_multiplicity(0) == dim,
288 dealii::ExcMessage("Expected finite element with dim components."));
289
290 std::vector<dealii::types::global_dof_index> dof_indices(fe.dofs_per_cell);
291 cell->get_dof_indices(dof_indices);
292
293 for(unsigned int i = 0; i < dof_indices.size(); ++i)
294 {
295 std::pair<unsigned int, unsigned int> const id = fe.system_to_component_index(i);
296
297 if(fe.dofs_per_vertex > 0) // dealii::FE_Q
298 {
299 grid_coordinates[id.second][id.first] += displacement_vector_ghosted(dof_indices[i]);
300 }
301 else // dealii::FE_DGQ
302 {
303 grid_coordinates[this->lexicographic_to_hierarchic_numbering[id.second]][id.first] +=
304 displacement_vector_ghosted(dof_indices[i]);
305 }
306 }
307 }
308
309 return grid_coordinates;
310 });
311 }
312
313 std::vector<unsigned int> hierarchic_to_lexicographic_numbering;
314 std::vector<unsigned int> lexicographic_to_hierarchic_numbering;
315
316protected:
317 std::shared_ptr<dealii::MappingQCache<dim>> mapping_q_cache;
318};
319
320
321namespace MappingTools
322{
336template<int dim, typename Number>
337void
338initialize_coarse_mappings_from_mapping_dof_vector(
339 std::vector<std::shared_ptr<MappingDoFVector<dim, Number>>> & coarse_mappings,
340 unsigned int const degree_coarse_mappings,
341 std::shared_ptr<MappingDoFVector<dim, Number> const> const & fine_mapping,
342 dealii::Triangulation<dim> const & triangulation)
343{
344 AssertThrow(dealii::MultithreadInfo::n_threads() == 1, dealii::ExcNotImplemented());
345
346 std::shared_ptr<dealii::MappingQCache<dim>> mapping_q_cache = fine_mapping->get_mapping_q_cache();
347 AssertThrow(mapping_q_cache.get(),
348 dealii::ExcMessage("Shared pointer mapping_q_cache is invalid."));
349
350 dealii::FESystem<dim> fe(dealii::FE_Q<dim>(degree_coarse_mappings), dim);
351 dealii::DoFHandler<dim> dof_handler(triangulation);
352 dof_handler.distribute_dofs(fe);
353 dof_handler.distribute_mg_dofs();
354
355 std::shared_ptr<MappingDoFVector<dim, Number>> mapping_dof_vector_all_levels =
356 std::make_shared<MappingDoFVector<dim, Number>>(degree_coarse_mappings);
357
358 // fill a dof vector with grid coordinates of the fine level using degree_coarse_mappings
359 typedef dealii::LinearAlgebra::distributed::Vector<Number> VectorType;
360 VectorType grid_coordinates_fine_level;
361
362 {
363 mapping_dof_vector_all_levels->fill_grid_coordinates_vector(*fine_mapping->get_mapping(),
364 grid_coordinates_fine_level,
365 dof_handler);
366 }
367
368 // project the solution onto all coarse levels of the triangulation using degree_coarse_mappings
369 dealii::MGLevelObject<VectorType> grid_coordinates_all_levels,
370 grid_coordinates_all_levels_ghosted;
371 unsigned int const n_levels = triangulation.n_global_levels();
372 grid_coordinates_all_levels.resize(0, n_levels - 1);
373 grid_coordinates_all_levels_ghosted.resize(0, n_levels - 1);
374
375 dealii::MGTransferMatrixFree<dim, Number> transfer;
376 transfer.build(dof_handler);
377 transfer.interpolate_to_mg(dof_handler, grid_coordinates_all_levels, grid_coordinates_fine_level);
378
379 // ghosting
380 for(unsigned int level = 0; level < n_levels; level++)
381 {
382 dealii::IndexSet const relevant_dofs =
383 dealii::DoFTools::extract_locally_relevant_level_dofs(dof_handler, level);
384
385 grid_coordinates_all_levels_ghosted[level].reinit(
386 dof_handler.locally_owned_mg_dofs(level),
387 relevant_dofs,
388 grid_coordinates_all_levels[level].get_mpi_communicator());
389
390 grid_coordinates_all_levels_ghosted[level].copy_locally_owned_data_from(
391 grid_coordinates_all_levels[level]);
392
393 grid_coordinates_all_levels_ghosted[level].update_ghost_values();
394 }
395
396 // Call the initialize() function of dealii::MappingQCache, which initializes the mapping for all
397 // levels according to grid_coordinates_all_levels_ghosted.
398 mapping_dof_vector_all_levels->get_mapping_q_cache()->initialize(
399 dof_handler.get_triangulation(),
400 [&](const typename dealii::Triangulation<dim>::cell_iterator & cell_tria)
401 -> std::vector<dealii::Point<dim>> {
402 unsigned int const level = cell_tria->level();
403
404 typename dealii::DoFHandler<dim>::cell_iterator cell(&cell_tria->get_triangulation(),
405 level,
406 cell_tria->index(),
407 &dof_handler);
408
409 AssertThrow(fe.element_multiplicity(0) == dim,
410 dealii::ExcMessage("Expected finite element with dim components."));
411
412 unsigned int const scalar_dofs_per_cell = dealii::Utilities::pow(fe.degree + 1, dim);
413
414 std::vector<dealii::Point<dim>> grid_coordinates(scalar_dofs_per_cell);
415
416 if(cell->level_subdomain_id() != dealii::numbers::artificial_subdomain_id)
417 {
418 std::vector<dealii::types::global_dof_index> dof_indices(fe.dofs_per_cell);
419 cell->get_mg_dof_indices(dof_indices);
420
421 for(unsigned int i = 0; i < dof_indices.size(); ++i)
422 {
423 std::pair<unsigned int, unsigned int> const id = fe.system_to_component_index(i);
424
425 if(fe.dofs_per_vertex > 0) // dealii::FE_Q
426 {
427 grid_coordinates[id.second][id.first] =
428 grid_coordinates_all_levels_ghosted[level](dof_indices[i]);
429 }
430 else // dealii::FE_DGQ
431 {
432 grid_coordinates[mapping_dof_vector_all_levels
433 ->lexicographic_to_hierarchic_numbering[id.second]][id.first] =
434 grid_coordinates_all_levels_ghosted[level](dof_indices[i]);
435 }
436 }
437 }
438
439 return grid_coordinates;
440 });
441
442
443 AssertThrow(
444 coarse_mappings.size() == n_levels - 1,
445 dealii::ExcMessage(
446 "coarse_mappings does not have correct size relative to the number of levels of the triangulation."));
447
448 // Finally, let all coarse grid mappings point to the same MappingDoFVector object. Using the
449 // same Mapping object for all multigrid h-levels is some form of legacy code. The class
450 // dealii::MatrixFree can internally extract the coarse-level mapping information (provided
451 // through the fine-level Mapping object).
452 for(unsigned int h_level = 0; h_level < coarse_mappings.size(); ++h_level)
453 {
454 coarse_mappings[h_level] = mapping_dof_vector_all_levels;
455 }
456}
457
473template<int dim, typename Number>
474void
475initialize_coarse_mappings_from_mapping_dof_vector(
476 std::vector<std::shared_ptr<MappingDoFVector<dim, Number>>> & coarse_mappings,
477 unsigned int const degree_coarse_mappings,
478 std::shared_ptr<MappingDoFVector<dim, Number> const> const & fine_mapping,
479 std::shared_ptr<dealii::Triangulation<dim> const> const & fine_triangulation,
480 std::vector<std::shared_ptr<dealii::Triangulation<dim> const>> const & coarse_triangulations)
481{
482 std::shared_ptr<dealii::MappingQCache<dim>> mapping_q_cache = fine_mapping->get_mapping_q_cache();
483 AssertThrow(mapping_q_cache.get(),
484 dealii::ExcMessage("Shared pointer mapping_q_cache is invalid."));
485
486 // setup dof-handlers and constraints for all levels using degree_coarse_mappings
487 dealii::FESystem<dim> fe(dealii::FE_Q<dim>(degree_coarse_mappings), dim);
488 unsigned int const n_h_levels = coarse_triangulations.size() + 1;
489 std::vector<dealii::DoFHandler<dim>> dof_handlers_all_levels(n_h_levels);
490 std::vector<dealii::AffineConstraints<Number>> constraints_all_levels(n_h_levels);
491 for(unsigned int h_level = 0; h_level < n_h_levels; ++h_level)
492 {
493 if(h_level == n_h_levels - 1)
494 dof_handlers_all_levels[h_level].reinit(*fine_triangulation);
495 else
496 dof_handlers_all_levels[h_level].reinit(*coarse_triangulations[h_level]);
497 dof_handlers_all_levels[h_level].distribute_dofs(fe);
498 // constraints are irrelevant for interpolation
499 constraints_all_levels[h_level].close();
500 }
501
502 // fill a dof vector with grid coordinates of the fine level using degree_coarse_mappings
503 typedef dealii::LinearAlgebra::distributed::Vector<Number> VectorType;
504 VectorType grid_coordinates_fine_level;
505
506 {
507 std::shared_ptr<MappingDoFVector<dim, Number>> mapping_dof_vector_fine_level =
508 std::make_shared<MappingDoFVector<dim, Number>>(degree_coarse_mappings);
509
510 auto const & dof_handler_fine_level = dof_handlers_all_levels[n_h_levels - 1];
511 mapping_dof_vector_fine_level->fill_grid_coordinates_vector(*fine_mapping->get_mapping(),
512 grid_coordinates_fine_level,
513 dof_handler_fine_level);
514 }
515
516 // create transfer objects
517 dealii::MGLevelObject<dealii::MGTwoLevelTransfer<dim, VectorType>> transfers(0, n_h_levels - 1);
518 for(unsigned int h_level = 1; h_level < n_h_levels; ++h_level)
519 {
520 transfers[h_level].reinit_geometric_transfer(dof_handlers_all_levels[h_level],
521 dof_handlers_all_levels[h_level - 1],
522 constraints_all_levels[h_level],
523 constraints_all_levels[h_level - 1]);
524 }
525
526 // a function that initializes the dof-vector for a given level and dof_handler
527 const std::function<void(unsigned int const, VectorType &)> initialize_dof_vector =
528 [&](unsigned int const h_level, VectorType & vector) {
529 dealii::IndexSet const locally_relevant_dofs =
530 dealii::DoFTools::extract_locally_relevant_dofs(dof_handlers_all_levels[h_level]);
531 vector.reinit(dof_handlers_all_levels[h_level].locally_owned_dofs(),
532 locally_relevant_dofs,
533 dof_handlers_all_levels[h_level].get_mpi_communicator());
534 };
535
536 dealii::MGTransferGlobalCoarsening<dim, VectorType> mg_transfer_global_coarsening(
537 transfers, initialize_dof_vector);
538
539 // Transfer grid coordinates to coarser h-levels.
540 // The dealii::DoFHandler object will not be used for global coarsening.
541 dealii::DoFHandler<dim> dof_handler_dummy;
542 dealii::MGLevelObject<VectorType> grid_coordinates_all_levels(0, n_h_levels - 1);
543 mg_transfer_global_coarsening.interpolate_to_mg(dof_handler_dummy,
544 grid_coordinates_all_levels,
545 grid_coordinates_fine_level);
546
547 // initialize mapping for all coarse h-levels using the dof-vectors with grid coordinates
548 AssertThrow(coarse_mappings.size() == n_h_levels - 1,
549 dealii::ExcMessage(
550 "coarse_mappings does not have correct size relative to coarse_triangulations."));
551
552 for(unsigned int h_level = 0; h_level < coarse_mappings.size(); ++h_level)
553 {
554 coarse_mappings[h_level] =
555 std::make_shared<MappingDoFVector<dim, Number>>(degree_coarse_mappings);
556
557 // grid_coordinates_all_levels describes absolute coordinates -> use an uninitialized mapping
558 // in order to interpret the grid coordinates vector as absolute coordinates and not as
559 // displacements.
560 std::shared_ptr<dealii::Mapping<dim> const> mapping_dummy;
561 coarse_mappings[h_level]->initialize_mapping_from_dof_vector(
562 mapping_dummy, grid_coordinates_all_levels[h_level], dof_handlers_all_levels[h_level]);
563 }
564}
565
581template<int dim, typename Number>
582void
583initialize_coarse_mappings(
584 std::vector<std::shared_ptr<MappingDoFVector<dim, Number>>> & coarse_mappings,
585 unsigned int const degree_coarse_mappings,
586 std::shared_ptr<MappingDoFVector<dim, Number> const> const & fine_mapping,
587 std::shared_ptr<dealii::Triangulation<dim> const> const & fine_triangulation,
588 std::vector<std::shared_ptr<dealii::Triangulation<dim> const>> const & coarse_triangulations)
589{
590 if(fine_mapping.get())
591 {
592 if(coarse_triangulations.size() > 0)
593 {
594 MappingTools::initialize_coarse_mappings_from_mapping_dof_vector<dim, Number>(
595 coarse_mappings,
596 degree_coarse_mappings,
597 fine_mapping,
598 fine_triangulation,
599 coarse_triangulations);
600 }
601 else
602 {
603 MappingTools::initialize_coarse_mappings_from_mapping_dof_vector<dim, Number>(
604 coarse_mappings, degree_coarse_mappings, fine_mapping, *fine_triangulation);
605 }
606 }
607}
608
609} // namespace MappingTools
610} // namespace ExaDG
611
612#endif /* EXADG_GRID_MAPPING_DOF_VECTOR_H_ */
MappingDoFVector(unsigned int const mapping_degree)
Definition mapping_dof_vector.h:62
void initialize_mapping_from_dof_vector(std::shared_ptr< dealii::Mapping< dim > const > mapping, VectorType const &displacement_vector, dealii::DoFHandler< dim > const &dof_handler)
Definition mapping_dof_vector.h:213
virtual ~MappingDoFVector()
Definition mapping_dof_vector.h:75
void fill_grid_coordinates_vector(dealii::Mapping< dim > const &mapping, VectorType &grid_coordinates, dealii::DoFHandler< dim > const &dof_handler) const
Definition mapping_dof_vector.h:121
void fill_grid_coordinates_vector(VectorType &grid_coordinates, dealii::DoFHandler< dim > const &dof_handler) const
Definition mapping_dof_vector.h:106
std::shared_ptr< dealii::Mapping< dim > const > get_mapping() const
Definition mapping_dof_vector.h:83
Definition driver.cpp:33
ElementType get_element_type(dealii::Triangulation< dim > const &tria)
Definition grid_data.h:70