1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2018 - 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 
17 #include <deal.II/distributed/cell_weights.h>
18 
19 #include <deal.II/dofs/dof_accessor.h>
20 
21 
22 DEAL_II_NAMESPACE_OPEN
23 
24 
25 namespace parallel
26 {
27   template <int dim, int spacedim>
CellWeights(const dealii::DoFHandler<dim,spacedim> & dof_handler,const WeightingFunction & weighting_function)28   CellWeights<dim, spacedim>::CellWeights(
29     const dealii::DoFHandler<dim, spacedim> &dof_handler,
30     const WeightingFunction &                weighting_function)
31   {
32     reinit(dof_handler, weighting_function);
33   }
34 
35 
36 
37   template <int dim, int spacedim>
~CellWeights()38   CellWeights<dim, spacedim>::~CellWeights()
39   {
40     connection.disconnect();
41   }
42 
43 
44 
45   template <int dim, int spacedim>
46   void
reinit(const DoFHandler<dim,spacedim> & dof_handler,const typename CellWeights<dim,spacedim>::WeightingFunction & weighting_function)47   CellWeights<dim, spacedim>::reinit(
48     const DoFHandler<dim, spacedim> &dof_handler,
49     const typename CellWeights<dim, spacedim>::WeightingFunction
50       &weighting_function)
51   {
52     connection.disconnect();
53     connection = dof_handler.get_triangulation().signals.cell_weight.connect(
54       make_weighting_callback(dof_handler, weighting_function));
55   }
56 
57 
58 
59   // ---------- static member functions ----------
60 
61   // ---------- selection of weighting functions ----------
62 
63   template <int dim, int spacedim>
64   typename CellWeights<dim, spacedim>::WeightingFunction
constant_weighting(const unsigned int factor)65   CellWeights<dim, spacedim>::constant_weighting(const unsigned int factor)
66   {
67     return [factor](const typename DoFHandler<dim, spacedim>::cell_iterator &,
68                     const FiniteElement<dim, spacedim> &) -> unsigned int {
69       return factor;
70     };
71   }
72 
73 
74 
75   template <int dim, int spacedim>
76   typename CellWeights<dim, spacedim>::WeightingFunction
ndofs_weighting(const std::pair<float,float> & coefficients)77   CellWeights<dim, spacedim>::ndofs_weighting(
78     const std::pair<float, float> &coefficients)
79   {
80     return [coefficients](
81              const typename DoFHandler<dim, spacedim>::cell_iterator &,
82              const FiniteElement<dim, spacedim> &future_fe) -> unsigned int {
83       const float result =
84         std::trunc(coefficients.first *
85                    std::pow(future_fe.n_dofs_per_cell(), coefficients.second));
86 
87       Assert(result >= 0. &&
88                result <=
89                  static_cast<float>(std::numeric_limits<unsigned int>::max()),
90              ExcMessage(
91                "Cannot cast determined weight for this cell to unsigned int!"));
92 
93       return static_cast<unsigned int>(result);
94     };
95   }
96 
97 
98 
99   template <int dim, int spacedim>
100   typename CellWeights<dim, spacedim>::WeightingFunction
ndofs_weighting(const std::vector<std::pair<float,float>> & coefficients)101   CellWeights<dim, spacedim>::ndofs_weighting(
102     const std::vector<std::pair<float, float>> &coefficients)
103   {
104     return [coefficients](
105              const typename DoFHandler<dim, spacedim>::cell_iterator &,
106              const FiniteElement<dim, spacedim> &future_fe) -> unsigned int {
107       float result = 0;
108       for (const auto &pair : coefficients)
109         result +=
110           pair.first * std::pow(future_fe.n_dofs_per_cell(), pair.second);
111       result = std::trunc(result);
112 
113       Assert(result >= 0. &&
114                result <=
115                  static_cast<float>(std::numeric_limits<unsigned int>::max()),
116              ExcMessage(
117                "Cannot cast determined weight for this cell to unsigned int!"));
118 
119       return static_cast<unsigned int>(result);
120     };
121   }
122 
123 
124 
125   // ---------- handling callback functions ----------
126 
127   template <int dim, int spacedim>
128   std::function<unsigned int(
129     const typename dealii::Triangulation<dim, spacedim>::cell_iterator &cell,
130     const typename dealii::Triangulation<dim, spacedim>::CellStatus     status)>
make_weighting_callback(const DoFHandler<dim,spacedim> & dof_handler,const typename CellWeights<dim,spacedim>::WeightingFunction & weighting_function)131   CellWeights<dim, spacedim>::make_weighting_callback(
132     const DoFHandler<dim, spacedim> &dof_handler,
133     const typename CellWeights<dim, spacedim>::WeightingFunction
134       &weighting_function)
135   {
136     const parallel::TriangulationBase<dim, spacedim> *tria =
137       dynamic_cast<const parallel::TriangulationBase<dim, spacedim> *>(
138         &(dof_handler.get_triangulation()));
139 
140     Assert(
141       tria != nullptr,
142       ExcMessage(
143         "parallel::CellWeights requires a parallel::TriangulationBase object."));
144 
145     return
146       [&dof_handler, tria, weighting_function](
147         const typename dealii::Triangulation<dim, spacedim>::cell_iterator
148           &                                                             cell,
149         const typename dealii::Triangulation<dim, spacedim>::CellStatus status)
150         -> unsigned int {
151         return CellWeights<dim, spacedim>::weighting_callback(
152           cell,
153           status,
154           std::cref(dof_handler),
155           std::cref(*tria),
156           weighting_function);
157       };
158   }
159 
160 
161 
162   template <int dim, int spacedim>
163   unsigned int
weighting_callback(const typename dealii::Triangulation<dim,spacedim>::cell_iterator & cell_,const typename dealii::Triangulation<dim,spacedim>::CellStatus status,const DoFHandler<dim,spacedim> & dof_handler,const parallel::TriangulationBase<dim,spacedim> & triangulation,const typename CellWeights<dim,spacedim>::WeightingFunction & weighting_function)164   CellWeights<dim, spacedim>::weighting_callback(
165     const typename dealii::Triangulation<dim, spacedim>::cell_iterator &cell_,
166     const typename dealii::Triangulation<dim, spacedim>::CellStatus     status,
167     const DoFHandler<dim, spacedim> &                 dof_handler,
168     const parallel::TriangulationBase<dim, spacedim> &triangulation,
169     const typename CellWeights<dim, spacedim>::WeightingFunction
170       &weighting_function)
171   {
172     // Check if we are still working with the correct combination of
173     // Triangulation and DoFHandler.
174     AssertThrow(&triangulation == &(dof_handler.get_triangulation()),
175                 ExcMessage(
176                   "Triangulation associated with the DoFHandler has changed!"));
177 
178     // Convert cell type from Triangulation to DoFHandler to be able
179     // to access the information about the degrees of freedom.
180     const typename DoFHandler<dim, spacedim>::cell_iterator cell(*cell_,
181                                                                  &dof_handler);
182 
183     // Determine which FiniteElement object will be present on this cell after
184     // refinement and will thus specify the number of degrees of freedom.
185     unsigned int fe_index = numbers::invalid_unsigned_int;
186     switch (status)
187       {
188         case Triangulation<dim, spacedim>::CELL_PERSIST:
189         case Triangulation<dim, spacedim>::CELL_REFINE:
190         case Triangulation<dim, spacedim>::CELL_INVALID:
191           fe_index = cell->future_fe_index();
192           break;
193 
194         case Triangulation<dim, spacedim>::CELL_COARSEN:
195           {
196             std::set<unsigned int> fe_indices_children;
197             for (unsigned int child_index = 0; child_index < cell->n_children();
198                  ++child_index)
199               {
200                 const auto &child = cell->child(child_index);
201                 Assert(child->is_active() && child->coarsen_flag_set(),
202                        typename dealii::Triangulation<
203                          dim>::ExcInconsistentCoarseningFlags());
204 
205                 fe_indices_children.insert(child->future_fe_index());
206               }
207             Assert(!fe_indices_children.empty(), ExcInternalError());
208 
209             fe_index =
210               dof_handler.get_fe_collection().find_dominated_fe_extended(
211                 fe_indices_children, /*codim=*/0);
212 
213             Assert(fe_index != numbers::invalid_unsigned_int,
214                    typename dealii::hp::FECollection<
215                      dim>::ExcNoDominatedFiniteElementAmongstChildren());
216           }
217           break;
218 
219         default:
220           Assert(false, ExcInternalError());
221           break;
222       }
223 
224     // Return the cell weight determined by the function of choice.
225     return weighting_function(cell, dof_handler.get_fe(fe_index));
226   }
227 
228 
229 
230   // ---------- deprecated functions ----------
231 
232   template <int dim, int spacedim>
CellWeights(const dealii::DoFHandler<dim,spacedim> & dof_handler)233   CellWeights<dim, spacedim>::CellWeights(
234     const dealii::DoFHandler<dim, spacedim> &dof_handler)
235     : dof_handler(&dof_handler)
236     , triangulation(
237         dynamic_cast<const parallel::TriangulationBase<dim, spacedim> *>(
238           &(dof_handler.get_triangulation())))
239   {
240     Assert(
241       triangulation != nullptr,
242       ExcMessage(
243         "parallel::CellWeights requires a parallel::TriangulationBase object."));
244 
245     register_constant_weighting();
246   }
247 
248 
249 
250   template <int dim, int spacedim>
251   void
register_constant_weighting(const unsigned int factor)252   CellWeights<dim, spacedim>::register_constant_weighting(
253     const unsigned int factor)
254   {
255     connection.disconnect();
256 
257     connection = triangulation->signals.cell_weight.connect(
258       [this,
259        factor](const typename Triangulation<dim, spacedim>::cell_iterator &cell,
260                const typename Triangulation<dim, spacedim>::CellStatus status)
261         -> unsigned int {
262         return this->weighting_callback(cell,
263                                         status,
264                                         std::cref(*(this->dof_handler)),
265                                         std::cref(*(this->triangulation)),
266                                         this->constant_weighting(factor));
267       });
268   }
269 
270 
271 
272   template <int dim, int spacedim>
273   void
register_ndofs_weighting(const unsigned int factor)274   CellWeights<dim, spacedim>::register_ndofs_weighting(
275     const unsigned int factor)
276   {
277     connection.disconnect();
278 
279     connection = triangulation->signals.cell_weight.connect(
280       [this,
281        factor](const typename Triangulation<dim, spacedim>::cell_iterator &cell,
282                const typename Triangulation<dim, spacedim>::CellStatus status)
283         -> unsigned int {
284         return this->weighting_callback(cell,
285                                         status,
286                                         std::cref(*(this->dof_handler)),
287                                         std::cref(*(this->triangulation)),
288                                         this->ndofs_weighting({factor, 1}));
289       });
290   }
291 
292 
293 
294   template <int dim, int spacedim>
295   void
register_ndofs_squared_weighting(const unsigned int factor)296   CellWeights<dim, spacedim>::register_ndofs_squared_weighting(
297     const unsigned int factor)
298   {
299     connection.disconnect();
300 
301     connection = triangulation->signals.cell_weight.connect(
302       [this,
303        factor](const typename Triangulation<dim, spacedim>::cell_iterator &cell,
304                const typename Triangulation<dim, spacedim>::CellStatus status)
305         -> unsigned int {
306         return this->weighting_callback(cell,
307                                         status,
308                                         std::cref(*(this->dof_handler)),
309                                         std::cref(*(this->triangulation)),
310                                         this->ndofs_weighting({factor, 2}));
311       });
312   }
313 
314 
315 
316   template <int dim, int spacedim>
317   void
register_custom_weighting(const std::function<unsigned int (const FiniteElement<dim,spacedim> &,const typename DoFHandler<dim,spacedim>::cell_iterator &)> custom_function)318   CellWeights<dim, spacedim>::register_custom_weighting(
319     const std::function<
320       unsigned int(const FiniteElement<dim, spacedim> &,
321                    const typename DoFHandler<dim, spacedim>::cell_iterator &)>
322       custom_function)
323   {
324     connection.disconnect();
325 
326     const std::function<
327       unsigned int(const typename DoFHandler<dim, spacedim>::cell_iterator &,
328                    const FiniteElement<dim, spacedim> &)>
329       converted_function =
330         [&custom_function](
331           const typename DoFHandler<dim, spacedim>::cell_iterator &cell,
332           const FiniteElement<dim, spacedim> &future_fe) -> unsigned int {
333       return custom_function(future_fe, cell);
334     };
335 
336     connection = triangulation->signals.cell_weight.connect(
337       [this, converted_function](
338         const typename Triangulation<dim, spacedim>::cell_iterator &cell,
339         const typename Triangulation<dim, spacedim>::CellStatus     status)
340         -> unsigned int {
341         return this->weighting_callback(cell,
342                                         status,
343                                         std::cref(*(this->dof_handler)),
344                                         std::cref(*(this->triangulation)),
345                                         converted_function);
346       });
347   }
348 } // namespace parallel
349 
350 
351 // explicit instantiations
352 #include "cell_weights.inst"
353 
354 DEAL_II_NAMESPACE_CLOSE
355