1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 1999 - 2020 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/memory_consumption.h>
17
18 #include <deal.II/distributed/tria.h>
19
20 #include <deal.II/dofs/dof_accessor.h>
21 #include <deal.II/dofs/dof_handler.h>
22
23 #include <deal.II/fe/fe.h>
24
25 #include <deal.II/grid/tria.h>
26 #include <deal.II/grid/tria_accessor.h>
27 #include <deal.II/grid/tria_iterator.h>
28
29 #include <deal.II/lac/block_vector.h>
30 #include <deal.II/lac/la_parallel_block_vector.h>
31 #include <deal.II/lac/la_parallel_vector.h>
32 #include <deal.II/lac/la_vector.h>
33 #include <deal.II/lac/petsc_block_vector.h>
34 #include <deal.II/lac/petsc_vector.h>
35 #include <deal.II/lac/trilinos_parallel_block_vector.h>
36 #include <deal.II/lac/trilinos_vector.h>
37 #include <deal.II/lac/vector.h>
38 #include <deal.II/lac/vector_element_access.h>
39
40 #include <deal.II/numerics/solution_transfer.h>
41
42 DEAL_II_NAMESPACE_OPEN
43
44 template <int dim, typename VectorType, typename DoFHandlerType>
SolutionTransfer(const DoFHandlerType & dof)45 SolutionTransfer<dim, VectorType, DoFHandlerType>::SolutionTransfer(
46 const DoFHandlerType &dof)
47 : dof_handler(&dof, typeid(*this).name())
48 , n_dofs_old(0)
49 , prepared_for(none)
50 {
51 Assert((dynamic_cast<const parallel::distributed::Triangulation<
52 DoFHandlerType::dimension,
53 DoFHandlerType::space_dimension> *>(
54 &dof_handler->get_triangulation()) == nullptr),
55 ExcMessage("You are calling the dealii::SolutionTransfer class "
56 "with a DoF handler that is built on a "
57 "parallel::distributed::Triangulation. This will not "
58 "work for parallel computations. You probably want to "
59 "use the parallel::distributed::SolutionTransfer class."));
60 }
61
62
63
64 template <int dim, typename VectorType, typename DoFHandlerType>
~SolutionTransfer()65 SolutionTransfer<dim, VectorType, DoFHandlerType>::~SolutionTransfer()
66 {
67 clear();
68 }
69
70
71
72 template <int dim, typename VectorType, typename DoFHandlerType>
73 void
clear()74 SolutionTransfer<dim, VectorType, DoFHandlerType>::clear()
75 {
76 indices_on_cell.clear();
77 dof_values_on_cell.clear();
78 cell_map.clear();
79
80 prepared_for = none;
81 }
82
83
84
85 template <int dim, typename VectorType, typename DoFHandlerType>
86 void
prepare_for_pure_refinement()87 SolutionTransfer<dim, VectorType, DoFHandlerType>::prepare_for_pure_refinement()
88 {
89 Assert(prepared_for != pure_refinement, ExcAlreadyPrepForRef());
90 Assert(prepared_for != coarsening_and_refinement,
91 ExcAlreadyPrepForCoarseAndRef());
92
93 clear();
94
95 const unsigned int n_active_cells =
96 dof_handler->get_triangulation().n_active_cells();
97 n_dofs_old = dof_handler->n_dofs();
98
99 // efficient reallocation of indices_on_cell
100 std::vector<std::vector<types::global_dof_index>>(n_active_cells)
101 .swap(indices_on_cell);
102
103 typename DoFHandlerType::active_cell_iterator cell =
104 dof_handler->begin_active(),
105 endc = dof_handler->end();
106
107 for (unsigned int i = 0; cell != endc; ++cell, ++i)
108 {
109 indices_on_cell[i].resize(cell->get_fe().n_dofs_per_cell());
110 // on each cell store the indices of the
111 // dofs. after refining we get the values
112 // on the children by taking these
113 // indices, getting the respective values
114 // out of the data vectors and prolonging
115 // them to the children
116 cell->get_dof_indices(indices_on_cell[i]);
117 cell_map[std::make_pair(cell->level(), cell->index())] =
118 Pointerstruct(&indices_on_cell[i], cell->active_fe_index());
119 }
120 prepared_for = pure_refinement;
121 }
122
123
124
125 template <int dim, typename VectorType, typename DoFHandlerType>
126 void
refine_interpolate(const VectorType & in,VectorType & out) const127 SolutionTransfer<dim, VectorType, DoFHandlerType>::refine_interpolate(
128 const VectorType &in,
129 VectorType & out) const
130 {
131 Assert(prepared_for == pure_refinement, ExcNotPrepared());
132 Assert(in.size() == n_dofs_old, ExcDimensionMismatch(in.size(), n_dofs_old));
133 Assert(out.size() == dof_handler->n_dofs(),
134 ExcDimensionMismatch(out.size(), dof_handler->n_dofs()));
135 Assert(&in != &out,
136 ExcMessage("Vectors cannot be used as input and output"
137 " at the same time!"));
138
139 Vector<typename VectorType::value_type> local_values(0);
140
141 typename DoFHandlerType::cell_iterator cell = dof_handler->begin(),
142 endc = dof_handler->end();
143
144 typename std::map<std::pair<unsigned int, unsigned int>,
145 Pointerstruct>::const_iterator pointerstruct,
146 cell_map_end = cell_map.end();
147
148 for (; cell != endc; ++cell)
149 {
150 pointerstruct =
151 cell_map.find(std::make_pair(cell->level(), cell->index()));
152
153 if (pointerstruct != cell_map_end)
154 // this cell was refined or not
155 // touched at all, so we can get
156 // the new values by just setting
157 // or interpolating to the children,
158 // which is both done by one
159 // function
160 {
161 const unsigned int this_fe_index =
162 pointerstruct->second.active_fe_index;
163 const unsigned int dofs_per_cell =
164 cell->get_dof_handler().get_fe(this_fe_index).n_dofs_per_cell();
165 local_values.reinit(dofs_per_cell, true);
166
167 // make sure that the size of the stored indices is the same as
168 // dofs_per_cell. since we store the desired fe_index, we know
169 // what this size should be
170 Assert(dofs_per_cell == (*pointerstruct->second.indices_ptr).size(),
171 ExcInternalError());
172 for (unsigned int i = 0; i < dofs_per_cell; ++i)
173 local_values(i) = internal::ElementAccess<VectorType>::get(
174 in, (*pointerstruct->second.indices_ptr)[i]);
175 cell->set_dof_values_by_interpolation(local_values,
176 out,
177 this_fe_index);
178 }
179 }
180 }
181
182
183
184 namespace internal
185 {
186 /**
187 * Generate a table that contains
188 * interpolation matrices between
189 * each combination of finite
190 * elements used in a DoFHandler of
191 * some kind. Since not all
192 * elements can be interpolated
193 * onto each other, the table may
194 * contain empty matrices for those
195 * combinations of elements for
196 * which no such interpolation is
197 * implemented.
198 */
199 template <int dim, int spacedim>
200 void
extract_interpolation_matrices(const dealii::DoFHandler<dim,spacedim> & dof,dealii::Table<2,FullMatrix<double>> & matrices)201 extract_interpolation_matrices(const dealii::DoFHandler<dim, spacedim> &dof,
202 dealii::Table<2, FullMatrix<double>> &matrices)
203 {
204 if (dof.hp_capability_enabled == false)
205 return;
206
207 const dealii::hp::FECollection<dim, spacedim> &fe = dof.get_fe_collection();
208 matrices.reinit(fe.size(), fe.size());
209 for (unsigned int i = 0; i < fe.size(); ++i)
210 for (unsigned int j = 0; j < fe.size(); ++j)
211 if (i != j)
212 {
213 matrices(i, j).reinit(fe[i].n_dofs_per_cell(),
214 fe[j].n_dofs_per_cell());
215
216 // see if we can get the interpolation matrices for this
217 // combination of elements. if not, reset the matrix sizes to zero
218 // to indicate that this particular combination isn't
219 // supported. this isn't an outright error right away since we may
220 // never need to actually interpolate between these two elements
221 // on actual cells; we simply have to trigger an error if someone
222 // actually tries
223 try
224 {
225 fe[i].get_interpolation_matrix(fe[j], matrices(i, j));
226 }
227 catch (const typename FiniteElement<dim, spacedim>::
228 ExcInterpolationNotImplemented &)
229 {
230 matrices(i, j).reinit(0, 0);
231 }
232 }
233 }
234
235
236 template <int dim, int spacedim>
237 void
restriction_additive(const FiniteElement<dim,spacedim> &,std::vector<std::vector<bool>> &)238 restriction_additive(const FiniteElement<dim, spacedim> &,
239 std::vector<std::vector<bool>> &)
240 {}
241
242 template <int dim, int spacedim>
243 void
restriction_additive(const dealii::hp::FECollection<dim,spacedim> & fe,std::vector<std::vector<bool>> & restriction_is_additive)244 restriction_additive(const dealii::hp::FECollection<dim, spacedim> &fe,
245 std::vector<std::vector<bool>> &restriction_is_additive)
246 {
247 restriction_is_additive.resize(fe.size());
248 for (unsigned int f = 0; f < fe.size(); ++f)
249 {
250 restriction_is_additive[f].resize(fe[f].n_dofs_per_cell());
251 for (unsigned int i = 0; i < fe[f].n_dofs_per_cell(); ++i)
252 restriction_is_additive[f][i] = fe[f].restriction_is_additive(i);
253 }
254 }
255 } // namespace internal
256
257
258
259 template <int dim, typename VectorType, typename DoFHandlerType>
260 void
261 SolutionTransfer<dim, VectorType, DoFHandlerType>::
prepare_for_coarsening_and_refinement(const std::vector<VectorType> & all_in)262 prepare_for_coarsening_and_refinement(const std::vector<VectorType> &all_in)
263 {
264 Assert(prepared_for != pure_refinement, ExcAlreadyPrepForRef());
265 Assert(prepared_for != coarsening_and_refinement,
266 ExcAlreadyPrepForCoarseAndRef());
267
268 const unsigned int in_size = all_in.size();
269 Assert(in_size != 0,
270 ExcMessage("The array of input vectors you pass to this "
271 "function has no elements. This is not useful."));
272
273 clear();
274
275 const unsigned int n_active_cells =
276 dof_handler->get_triangulation().n_active_cells();
277 (void)n_active_cells;
278 n_dofs_old = dof_handler->n_dofs();
279
280 for (unsigned int i = 0; i < in_size; ++i)
281 {
282 Assert(all_in[i].size() == n_dofs_old,
283 ExcDimensionMismatch(all_in[i].size(), n_dofs_old));
284 }
285
286 // first count the number
287 // of cells that will be coarsened
288 // and that'll stay or be refined
289 unsigned int n_cells_to_coarsen = 0;
290 unsigned int n_cells_to_stay_or_refine = 0;
291 for (const auto &act_cell : dof_handler->active_cell_iterators())
292 {
293 if (act_cell->coarsen_flag_set())
294 ++n_cells_to_coarsen;
295 else
296 ++n_cells_to_stay_or_refine;
297 }
298 Assert((n_cells_to_coarsen + n_cells_to_stay_or_refine) == n_active_cells,
299 ExcInternalError());
300
301 unsigned int n_coarsen_fathers = 0;
302 for (typename DoFHandlerType::cell_iterator cell = dof_handler->begin();
303 cell != dof_handler->end();
304 ++cell)
305 if (!cell->is_active() && cell->child(0)->coarsen_flag_set())
306 ++n_coarsen_fathers;
307 Assert(n_cells_to_coarsen >= 2 * n_coarsen_fathers, ExcInternalError());
308
309 // allocate the needed memory. initialize
310 // the following arrays in an efficient
311 // way, without copying much
312 std::vector<std::vector<types::global_dof_index>>(n_cells_to_stay_or_refine)
313 .swap(indices_on_cell);
314
315 std::vector<std::vector<Vector<typename VectorType::value_type>>>(
316 n_coarsen_fathers,
317 std::vector<Vector<typename VectorType::value_type>>(in_size))
318 .swap(dof_values_on_cell);
319
320 Table<2, FullMatrix<double>> interpolation_hp;
321 std::vector<std::vector<bool>> restriction_is_additive;
322
323 internal::extract_interpolation_matrices(*dof_handler, interpolation_hp);
324 internal::restriction_additive(dof_handler->get_fe_collection(),
325 restriction_is_additive);
326
327 // we need counters for
328 // the 'to_stay_or_refine' cells 'n_sr' and
329 // the 'coarsen_fathers' cells 'n_cf',
330 unsigned int n_sr = 0, n_cf = 0;
331 for (typename DoFHandlerType::cell_iterator cell = dof_handler->begin();
332 cell != dof_handler->end();
333 ++cell)
334 {
335 // CASE 1: active cell that remains as it is
336 if (cell->is_active() && !cell->coarsen_flag_set())
337 {
338 const unsigned int dofs_per_cell = cell->get_fe().n_dofs_per_cell();
339 indices_on_cell[n_sr].resize(dofs_per_cell);
340 // cell will not be coarsened,
341 // so we get away by storing the
342 // dof indices and later
343 // interpolating to the children
344 cell->get_dof_indices(indices_on_cell[n_sr]);
345 cell_map[std::make_pair(cell->level(), cell->index())] =
346 Pointerstruct(&indices_on_cell[n_sr], cell->active_fe_index());
347 ++n_sr;
348 }
349
350 // CASE 2: cell is inactive but will become active
351 else if (cell->has_children() && cell->child(0)->coarsen_flag_set())
352 {
353 // we will need to interpolate from the children of this cell
354 // to the current one. in the hp context, this also means
355 // we need to figure out which finite element space to interpolate
356 // to since that is not implied by the global FE as in the non-hp
357 // case. we choose the 'least dominant fe' on all children from
358 // the associated FECollection.
359 std::set<unsigned int> fe_indices_children;
360 for (unsigned int child_index = 0; child_index < cell->n_children();
361 ++child_index)
362 {
363 const auto &child = cell->child(child_index);
364 Assert(child->is_active() && child->coarsen_flag_set(),
365 typename dealii::Triangulation<
366 dim>::ExcInconsistentCoarseningFlags());
367
368 fe_indices_children.insert(child->active_fe_index());
369 }
370 Assert(!fe_indices_children.empty(), ExcInternalError());
371
372 const unsigned int target_fe_index =
373 dof_handler->get_fe_collection().find_dominated_fe_extended(
374 fe_indices_children, /*codim=*/0);
375
376 Assert(target_fe_index != numbers::invalid_unsigned_int,
377 typename dealii::hp::FECollection<
378 dim>::ExcNoDominatedFiniteElementAmongstChildren());
379
380 const unsigned int dofs_per_cell =
381 dof_handler->get_fe(target_fe_index).n_dofs_per_cell();
382
383 std::vector<Vector<typename VectorType::value_type>>(
384 in_size, Vector<typename VectorType::value_type>(dofs_per_cell))
385 .swap(dof_values_on_cell[n_cf]);
386
387
388 // store the data of each of the input vectors. get this data
389 // as interpolated onto a finite element space that encompasses
390 // that of all the children. note that
391 // cell->get_interpolated_dof_values already does all of the
392 // interpolations between spaces
393 for (unsigned int j = 0; j < in_size; ++j)
394 cell->get_interpolated_dof_values(all_in[j],
395 dof_values_on_cell[n_cf][j],
396 target_fe_index);
397 cell_map[std::make_pair(cell->level(), cell->index())] =
398 Pointerstruct(&dof_values_on_cell[n_cf], target_fe_index);
399 ++n_cf;
400 }
401 }
402 Assert(n_sr == n_cells_to_stay_or_refine, ExcInternalError());
403 Assert(n_cf == n_coarsen_fathers, ExcInternalError());
404
405 prepared_for = coarsening_and_refinement;
406 }
407
408
409
410 template <int dim, typename VectorType, typename DoFHandlerType>
411 void
412 SolutionTransfer<dim, VectorType, DoFHandlerType>::
prepare_for_coarsening_and_refinement(const VectorType & in)413 prepare_for_coarsening_and_refinement(const VectorType &in)
414 {
415 std::vector<VectorType> all_in(1, in);
416 prepare_for_coarsening_and_refinement(all_in);
417 }
418
419
420
421 template <int dim, typename VectorType, typename DoFHandlerType>
422 void
interpolate(const std::vector<VectorType> & all_in,std::vector<VectorType> & all_out) const423 SolutionTransfer<dim, VectorType, DoFHandlerType>::interpolate(
424 const std::vector<VectorType> &all_in,
425 std::vector<VectorType> & all_out) const
426 {
427 Assert(prepared_for == coarsening_and_refinement, ExcNotPrepared());
428 const unsigned int size = all_in.size();
429 Assert(all_out.size() == size, ExcDimensionMismatch(all_out.size(), size));
430 for (unsigned int i = 0; i < size; ++i)
431 Assert(all_in[i].size() == n_dofs_old,
432 ExcDimensionMismatch(all_in[i].size(), n_dofs_old));
433 for (unsigned int i = 0; i < all_out.size(); ++i)
434 Assert(all_out[i].size() == dof_handler->n_dofs(),
435 ExcDimensionMismatch(all_out[i].size(), dof_handler->n_dofs()));
436 for (unsigned int i = 0; i < size; ++i)
437 for (unsigned int j = 0; j < size; ++j)
438 Assert(&all_in[i] != &all_out[j],
439 ExcMessage("Vectors cannot be used as input and output"
440 " at the same time!"));
441
442 Vector<typename VectorType::value_type> local_values;
443 std::vector<types::global_dof_index> dofs;
444
445 typename std::map<std::pair<unsigned int, unsigned int>,
446 Pointerstruct>::const_iterator pointerstruct,
447 cell_map_end = cell_map.end();
448
449 Table<2, FullMatrix<double>> interpolation_hp;
450 internal::extract_interpolation_matrices(*dof_handler, interpolation_hp);
451 Vector<typename VectorType::value_type> tmp, tmp2;
452
453 for (const auto &cell : dof_handler->cell_iterators())
454 {
455 pointerstruct =
456 cell_map.find(std::make_pair(cell->level(), cell->index()));
457
458 if (pointerstruct != cell_map_end)
459 {
460 const std::vector<types::global_dof_index> *const indexptr =
461 pointerstruct->second.indices_ptr;
462
463 const std::vector<Vector<typename VectorType::value_type>>
464 *const valuesptr = pointerstruct->second.dof_values_ptr;
465
466 // cell stayed as it was or was refined
467 if (indexptr)
468 {
469 Assert(valuesptr == nullptr, ExcInternalError());
470
471 const unsigned int old_fe_index =
472 pointerstruct->second.active_fe_index;
473
474 // get the values of each of the input data vectors on this cell
475 // and prolong it to its children
476 unsigned int in_size = indexptr->size();
477 for (unsigned int j = 0; j < size; ++j)
478 {
479 tmp.reinit(in_size, true);
480 for (unsigned int i = 0; i < in_size; ++i)
481 tmp(i) =
482 internal::ElementAccess<VectorType>::get(all_in[j],
483 (*indexptr)[i]);
484
485 cell->set_dof_values_by_interpolation(tmp,
486 all_out[j],
487 old_fe_index);
488 }
489 }
490 else if (valuesptr)
491 // the children of this cell were deleted
492 {
493 Assert(!cell->has_children(), ExcInternalError());
494 Assert(indexptr == nullptr, ExcInternalError());
495
496 const unsigned int dofs_per_cell =
497 cell->get_fe().n_dofs_per_cell();
498 dofs.resize(dofs_per_cell);
499 // get the local
500 // indices
501 cell->get_dof_indices(dofs);
502
503 // distribute the stored data to the new vectors
504 for (unsigned int j = 0; j < size; ++j)
505 {
506 // make sure that the size of the stored indices is the same
507 // as dofs_per_cell. this is kind of a test if we use the same
508 // fe in the hp case. to really do that test we would have to
509 // store the fe_index of all cells
510 const Vector<typename VectorType::value_type> *data = nullptr;
511 const unsigned int active_fe_index = cell->active_fe_index();
512 if (active_fe_index != pointerstruct->second.active_fe_index)
513 {
514 const unsigned int old_index =
515 pointerstruct->second.active_fe_index;
516 const FullMatrix<double> &interpolation_matrix =
517 interpolation_hp(active_fe_index, old_index);
518 // The interpolation matrix might be empty when using
519 // FE_Nothing.
520 if (interpolation_matrix.empty())
521 tmp.reinit(dofs_per_cell, false);
522 else
523 {
524 tmp.reinit(dofs_per_cell, true);
525 AssertDimension((*valuesptr)[j].size(),
526 interpolation_matrix.n());
527 AssertDimension(tmp.size(), interpolation_matrix.m());
528 interpolation_matrix.vmult(tmp, (*valuesptr)[j]);
529 }
530 data = &tmp;
531 }
532 else
533 data = &(*valuesptr)[j];
534
535
536 for (unsigned int i = 0; i < dofs_per_cell; ++i)
537 internal::ElementAccess<VectorType>::set((*data)(i),
538 dofs[i],
539 all_out[j]);
540 }
541 }
542 // undefined status
543 else
544 Assert(false, ExcInternalError());
545 }
546 }
547 }
548
549
550
551 template <int dim, typename VectorType, typename DoFHandlerType>
552 void
interpolate(const VectorType & in,VectorType & out) const553 SolutionTransfer<dim, VectorType, DoFHandlerType>::interpolate(
554 const VectorType &in,
555 VectorType & out) const
556 {
557 Assert(in.size() == n_dofs_old, ExcDimensionMismatch(in.size(), n_dofs_old));
558 Assert(out.size() == dof_handler->n_dofs(),
559 ExcDimensionMismatch(out.size(), dof_handler->n_dofs()));
560
561 std::vector<VectorType> all_in(1);
562 all_in[0] = in;
563 std::vector<VectorType> all_out(1);
564 all_out[0] = out;
565 interpolate(all_in, all_out);
566 out = all_out[0];
567 }
568
569
570
571 template <int dim, typename VectorType, typename DoFHandlerType>
572 std::size_t
memory_consumption() const573 SolutionTransfer<dim, VectorType, DoFHandlerType>::memory_consumption() const
574 {
575 // at the moment we do not include the memory
576 // consumption of the cell_map as we have no
577 // real idea about memory consumption of a
578 // std::map
579 return (MemoryConsumption::memory_consumption(dof_handler) +
580 MemoryConsumption::memory_consumption(n_dofs_old) +
581 sizeof(prepared_for) +
582 MemoryConsumption::memory_consumption(indices_on_cell) +
583 MemoryConsumption::memory_consumption(dof_values_on_cell));
584 }
585
586
587
588 template <int dim, typename VectorType, typename DoFHandlerType>
589 std::size_t
590 SolutionTransfer<dim, VectorType, DoFHandlerType>::Pointerstruct::
memory_consumption() const591 memory_consumption() const
592 {
593 return sizeof(*this);
594 }
595
596
597 /*-------------- Explicit Instantiations -------------------------------*/
598 #define SPLIT_INSTANTIATIONS_COUNT 4
599 #ifndef SPLIT_INSTANTIATIONS_INDEX
600 # define SPLIT_INSTANTIATIONS_INDEX 0
601 #endif
602 #include "solution_transfer.inst"
603
604 DEAL_II_NAMESPACE_CLOSE
605