1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 1998 - 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 #ifndef dealii_error_estimator_templates_h
17 #define dealii_error_estimator_templates_h
18 
19 #include <deal.II/base/config.h>
20 
21 #include <deal.II/base/geometry_info.h>
22 #include <deal.II/base/numbers.h>
23 #include <deal.II/base/quadrature.h>
24 #include <deal.II/base/quadrature_lib.h>
25 #include <deal.II/base/work_stream.h>
26 
27 #include <deal.II/distributed/tria.h>
28 
29 #include <deal.II/dofs/dof_accessor.h>
30 #include <deal.II/dofs/dof_handler.h>
31 
32 #include <deal.II/fe/fe.h>
33 #include <deal.II/fe/fe_update_flags.h>
34 #include <deal.II/fe/fe_values.h>
35 #include <deal.II/fe/mapping_q1.h>
36 
37 #include <deal.II/grid/tria_iterator.h>
38 
39 #include <deal.II/hp/fe_values.h>
40 #include <deal.II/hp/mapping_collection.h>
41 #include <deal.II/hp/q_collection.h>
42 
43 #include <deal.II/lac/block_vector.h>
44 #include <deal.II/lac/la_parallel_block_vector.h>
45 #include <deal.II/lac/la_parallel_vector.h>
46 #include <deal.II/lac/la_vector.h>
47 #include <deal.II/lac/petsc_block_vector.h>
48 #include <deal.II/lac/petsc_vector.h>
49 #include <deal.II/lac/trilinos_parallel_block_vector.h>
50 #include <deal.II/lac/trilinos_vector.h>
51 #include <deal.II/lac/vector.h>
52 
53 #include <deal.II/numerics/error_estimator.h>
54 
55 #include <algorithm>
56 #include <cmath>
57 #include <functional>
58 #include <numeric>
59 #include <vector>
60 
61 DEAL_II_NAMESPACE_OPEN
62 
63 namespace internal
64 {
65   /**
66    * All small temporary data objects that are needed once per thread by the
67    * several functions of the error estimator are gathered in this struct.
68    * The reason for this structure is mainly that we have a number of
69    * functions that operate on cells or faces and need a number of small
70    * temporary data objects. Since these functions may run in parallel, we
71    * cannot make these objects member variables of the enclosing class. On
72    * the other hand, declaring them locally in each of these functions would
73    * require their reallocating every time we visit the next cell or face,
74    * which we found can take a significant amount of time if it happens
75    * often even in the single threaded case (10-20 per cent in our
76    * measurements); however, most importantly, memory allocation requires
77    * synchronization in multithreaded mode. While that is done by the C++
78    * library and has not to be handcoded, it nevertheless seriously damages
79    * the ability to efficiently run the functions of this class in parallel,
80    * since they are quite often blocked by these synchronization points,
81    * slowing everything down by a factor of two or three.
82    *
83    * Thus, every thread gets an instance of this class to work with and
84    * needs not allocate memory itself, or synchronize with other threads.
85    *
86    * The sizes of the arrays are initialized with the maximal number of
87    * entries necessary for the hp case. Within the loop over individual
88    * cells, we then resize the arrays as necessary. Since for std::vector
89    * resizing to a smaller size doesn't imply memory allocation, this is
90    * fast.
91    */
92   template <int dim, int spacedim, typename number>
93   struct ParallelData
94   {
95     /**
96      * The finite element to be used.
97      */
98     const dealii::hp::FECollection<dim, spacedim> finite_element;
99 
100     /**
101      * The quadrature formulas to be used for the faces.
102      */
103     const dealii::hp::QCollection<dim - 1> face_quadratures;
104 
105     /**
106      * FEFaceValues objects to integrate over the faces of the current and
107      * potentially of neighbor cells.
108      */
109     dealii::hp::FEFaceValues<dim, spacedim>    fe_face_values_cell;
110     dealii::hp::FEFaceValues<dim, spacedim>    fe_face_values_neighbor;
111     dealii::hp::FESubfaceValues<dim, spacedim> fe_subface_values;
112 
113     /**
114      * A vector to store the jump of the normal vectors in the quadrature
115      * points for each of the solution vectors (i.e. a temporary value).
116      * This vector is not allocated inside the functions that use it, but
117      * rather globally, since memory allocation is slow, in particular in
118      * presence of multiple threads where synchronization makes things even
119      * slower.
120      */
121     std::vector<std::vector<std::vector<number>>> phi;
122 
123     /**
124      * A vector for the gradients of the finite element function on one cell
125      *
126      * Let psi be a short name for <tt>a grad u_h</tt>, where the third
127      * index be the component of the finite element, and the second index
128      * the number of the quadrature point. The first index denotes the index
129      * of the solution vector.
130      */
131     std::vector<std::vector<std::vector<Tensor<1, spacedim, number>>>> psi;
132 
133     /**
134      * The same vector for a neighbor cell
135      */
136     std::vector<std::vector<std::vector<Tensor<1, spacedim, number>>>>
137       neighbor_psi;
138 
139     /**
140      * The normal vectors of the finite element function on one face
141      */
142     std::vector<Tensor<1, spacedim>> normal_vectors;
143 
144     /**
145      * Normal vectors of the opposing face.
146      */
147     std::vector<Tensor<1, spacedim>> neighbor_normal_vectors;
148 
149     /**
150      * Two arrays needed for the values of coefficients in the jumps, if
151      * they are given.
152      */
153     std::vector<double>                 coefficient_values1;
154     std::vector<dealii::Vector<double>> coefficient_values;
155 
156     /**
157      * Array for the products of Jacobian determinants and weights of
158      * quadraturs points.
159      */
160     std::vector<double> JxW_values;
161 
162     /**
163      * The subdomain id we are to care for.
164      */
165     const types::subdomain_id subdomain_id;
166     /**
167      * The material id we are to care for.
168      */
169     const types::material_id material_id;
170 
171     /**
172      * Some more references to input data to the
173      * KellyErrorEstimator::estimate() function.
174      */
175     const std::map<types::boundary_id, const Function<spacedim, number> *>
176       *                       neumann_bc;
177     const ComponentMask       component_mask;
178     const Function<spacedim> *coefficients;
179 
180     /**
181      * Constructor.
182      */
183     template <class FE>
184     ParallelData(const FE &                              fe,
185                  const dealii::hp::QCollection<dim - 1> &face_quadratures,
186                  const dealii::hp::MappingCollection<dim, spacedim> &mapping,
187                  const bool                need_quadrature_points,
188                  const unsigned int        n_solution_vectors,
189                  const types::subdomain_id subdomain_id,
190                  const types::material_id  material_id,
191                  const std::map<types::boundary_id,
192                                 const Function<spacedim, number> *> *neumann_bc,
193                  const ComponentMask &     component_mask,
194                  const Function<spacedim> *coefficients);
195 
196     /**
197      * Resize the arrays so that they fit the number of quadrature points
198      * associated with the given finite element index into the hp
199      * collections.
200      */
201     void
202     resize(const unsigned int active_fe_index);
203   };
204 
205 
206   template <int dim, int spacedim, typename number>
207   template <class FE>
ParallelData(const FE & fe,const dealii::hp::QCollection<dim-1> & face_quadratures,const dealii::hp::MappingCollection<dim,spacedim> & mapping,const bool need_quadrature_points,const unsigned int n_solution_vectors,const types::subdomain_id subdomain_id,const types::material_id material_id,const std::map<types::boundary_id,const Function<spacedim,number> * > * neumann_bc,const ComponentMask & component_mask,const Function<spacedim> * coefficients)208   ParallelData<dim, spacedim, number>::ParallelData(
209     const FE &                                          fe,
210     const dealii::hp::QCollection<dim - 1> &            face_quadratures,
211     const dealii::hp::MappingCollection<dim, spacedim> &mapping,
212     const bool                                          need_quadrature_points,
213     const unsigned int                                  n_solution_vectors,
214     const types::subdomain_id                           subdomain_id,
215     const types::material_id                            material_id,
216     const std::map<types::boundary_id, const Function<spacedim, number> *>
217       *                       neumann_bc,
218     const ComponentMask &     component_mask,
219     const Function<spacedim> *coefficients)
220     : finite_element(fe)
221     , face_quadratures(face_quadratures)
222     , fe_face_values_cell(mapping,
223                           finite_element,
224                           face_quadratures,
225                           update_gradients | update_JxW_values |
226                             (need_quadrature_points ? update_quadrature_points :
227                                                       UpdateFlags()) |
228                             update_normal_vectors)
229     , fe_face_values_neighbor(mapping,
230                               finite_element,
231                               face_quadratures,
232                               update_gradients | update_normal_vectors)
233     , fe_subface_values(mapping,
234                         finite_element,
235                         face_quadratures,
236                         update_gradients | update_normal_vectors)
237     , phi(n_solution_vectors,
238           std::vector<std::vector<number>>(
239             face_quadratures.max_n_quadrature_points(),
240             std::vector<number>(fe.n_components())))
241     , psi(n_solution_vectors,
242           std::vector<std::vector<Tensor<1, spacedim, number>>>(
243             face_quadratures.max_n_quadrature_points(),
244             std::vector<Tensor<1, spacedim, number>>(fe.n_components())))
245     , neighbor_psi(n_solution_vectors,
246                    std::vector<std::vector<Tensor<1, spacedim, number>>>(
247                      face_quadratures.max_n_quadrature_points(),
248                      std::vector<Tensor<1, spacedim, number>>(
249                        fe.n_components())))
250     , normal_vectors(face_quadratures.max_n_quadrature_points())
251     , neighbor_normal_vectors(face_quadratures.max_n_quadrature_points())
252     , coefficient_values1(face_quadratures.max_n_quadrature_points())
253     , coefficient_values(face_quadratures.max_n_quadrature_points(),
254                          dealii::Vector<double>(fe.n_components()))
255     , JxW_values(face_quadratures.max_n_quadrature_points())
256     , subdomain_id(subdomain_id)
257     , material_id(material_id)
258     , neumann_bc(neumann_bc)
259     , component_mask(component_mask)
260     , coefficients(coefficients)
261   {}
262 
263 
264 
265   template <int dim, int spacedim, typename number>
266   void
resize(const unsigned int active_fe_index)267   ParallelData<dim, spacedim, number>::resize(
268     const unsigned int active_fe_index)
269   {
270     const unsigned int n_q_points   = face_quadratures[active_fe_index].size();
271     const unsigned int n_components = finite_element.n_components();
272 
273     normal_vectors.resize(n_q_points);
274     neighbor_normal_vectors.resize(n_q_points);
275     coefficient_values1.resize(n_q_points);
276     coefficient_values.resize(n_q_points);
277     JxW_values.resize(n_q_points);
278 
279     for (unsigned int i = 0; i < phi.size(); ++i)
280       {
281         phi[i].resize(n_q_points);
282         psi[i].resize(n_q_points);
283         neighbor_psi[i].resize(n_q_points);
284 
285         for (unsigned int qp = 0; qp < n_q_points; ++qp)
286           {
287             phi[i][qp].resize(n_components);
288             psi[i][qp].resize(n_components);
289             neighbor_psi[i][qp].resize(n_components);
290           }
291       }
292 
293     for (unsigned int qp = 0; qp < n_q_points; ++qp)
294       coefficient_values[qp].reinit(n_components);
295   }
296 
297 
298 
299   /**
300    * Copy data from the local_face_integrals map of a single ParallelData
301    * object into a global such map. This is the copier stage of a WorkStream
302    * pipeline.
303    */
304   template <int dim, int spacedim>
305   void
copy_local_to_global(const std::map<typename DoFHandler<dim,spacedim>::face_iterator,std::vector<double>> & local_face_integrals,std::map<typename DoFHandler<dim,spacedim>::face_iterator,std::vector<double>> & face_integrals)306   copy_local_to_global(
307     const std::map<typename DoFHandler<dim, spacedim>::face_iterator,
308                    std::vector<double>> &local_face_integrals,
309     std::map<typename DoFHandler<dim, spacedim>::face_iterator,
310              std::vector<double>> &      face_integrals)
311   {
312     // now copy locally computed elements into the global map
313     for (typename std::map<typename DoFHandler<dim, spacedim>::face_iterator,
314                            std::vector<double>>::const_iterator p =
315            local_face_integrals.begin();
316          p != local_face_integrals.end();
317          ++p)
318       {
319         // double check that the element does not already exists in the
320         // global map
321         Assert(face_integrals.find(p->first) == face_integrals.end(),
322                ExcInternalError());
323 
324         for (unsigned int i = 0; i < p->second.size(); ++i)
325           {
326             Assert(numbers::is_finite(p->second[i]), ExcInternalError());
327             Assert(p->second[i] >= 0, ExcInternalError());
328           }
329 
330         face_integrals[p->first] = p->second;
331       }
332   }
333 
334 
335   /**
336    * Actually do the computation based on the evaluated gradients in
337    * ParallelData.
338    */
339   template <int dim, int spacedim, typename number>
340   std::vector<double>
integrate_over_face(ParallelData<dim,spacedim,number> & parallel_data,const typename DoFHandler<dim,spacedim>::face_iterator & face,dealii::hp::FEFaceValues<dim,spacedim> & fe_face_values_cell)341   integrate_over_face(
342     ParallelData<dim, spacedim, number> &                    parallel_data,
343     const typename DoFHandler<dim, spacedim>::face_iterator &face,
344     dealii::hp::FEFaceValues<dim, spacedim> &fe_face_values_cell)
345   {
346     const unsigned int n_q_points = parallel_data.psi[0].size(),
347                        n_components =
348                          parallel_data.finite_element.n_components(),
349                        n_solution_vectors = parallel_data.psi.size();
350 
351     // now psi contains the following:
352     // - for an internal face, psi=[grad u]
353     // - for a neumann boundary face, psi=grad u
354     // each component being the mentioned value at one of the quadrature
355     // points
356 
357     // next we have to multiply this with the normal vector. Since we have
358     // taken the difference of gradients for internal faces, we may chose
359     // the normal vector of one cell, taking that of the neighbor would only
360     // change the sign. We take the outward normal.
361 
362     parallel_data.normal_vectors =
363       fe_face_values_cell.get_present_fe_values().get_normal_vectors();
364 
365     for (unsigned int n = 0; n < n_solution_vectors; ++n)
366       for (unsigned int component = 0; component < n_components; ++component)
367         for (unsigned int point = 0; point < n_q_points; ++point)
368           parallel_data.phi[n][point][component] =
369             (parallel_data.psi[n][point][component] *
370              parallel_data.normal_vectors[point]);
371 
372     if (face->at_boundary() == false)
373       {
374         // compute the jump in the gradients
375 
376         for (unsigned int n = 0; n < n_solution_vectors; ++n)
377           for (unsigned int component = 0; component < n_components;
378                ++component)
379             for (unsigned int p = 0; p < n_q_points; ++p)
380               parallel_data.phi[n][p][component] +=
381                 (parallel_data.neighbor_psi[n][p][component] *
382                  parallel_data.neighbor_normal_vectors[p]);
383       }
384 
385     // if a coefficient was given: use that to scale the jump in the
386     // gradient
387     if (parallel_data.coefficients != nullptr)
388       {
389         // scalar coefficient
390         if (parallel_data.coefficients->n_components == 1)
391           {
392             parallel_data.coefficients->value_list(
393               fe_face_values_cell.get_present_fe_values()
394                 .get_quadrature_points(),
395               parallel_data.coefficient_values1);
396             for (unsigned int n = 0; n < n_solution_vectors; ++n)
397               for (unsigned int component = 0; component < n_components;
398                    ++component)
399                 for (unsigned int point = 0; point < n_q_points; ++point)
400                   parallel_data.phi[n][point][component] *=
401                     parallel_data.coefficient_values1[point];
402           }
403         else
404           // vector-valued coefficient
405           {
406             parallel_data.coefficients->vector_value_list(
407               fe_face_values_cell.get_present_fe_values()
408                 .get_quadrature_points(),
409               parallel_data.coefficient_values);
410             for (unsigned int n = 0; n < n_solution_vectors; ++n)
411               for (unsigned int component = 0; component < n_components;
412                    ++component)
413                 for (unsigned int point = 0; point < n_q_points; ++point)
414                   parallel_data.phi[n][point][component] *=
415                     parallel_data.coefficient_values[point](component);
416           }
417       }
418 
419 
420     if (face->at_boundary() == true)
421       // neumann boundary face. compute difference between normal derivative
422       // and boundary function
423       {
424         const types::boundary_id boundary_id = face->boundary_id();
425 
426         Assert(parallel_data.neumann_bc->find(boundary_id) !=
427                  parallel_data.neumann_bc->end(),
428                ExcInternalError());
429         // get the values of the boundary function at the quadrature points
430         if (n_components == 1)
431           {
432             std::vector<number> g(n_q_points);
433             parallel_data.neumann_bc->find(boundary_id)
434               ->second->value_list(fe_face_values_cell.get_present_fe_values()
435                                      .get_quadrature_points(),
436                                    g);
437 
438             for (unsigned int n = 0; n < n_solution_vectors; ++n)
439               for (unsigned int point = 0; point < n_q_points; ++point)
440                 parallel_data.phi[n][point][0] -= g[point];
441           }
442         else
443           {
444             std::vector<dealii::Vector<number>> g(
445               n_q_points, dealii::Vector<number>(n_components));
446             parallel_data.neumann_bc->find(boundary_id)
447               ->second->vector_value_list(fe_face_values_cell
448                                             .get_present_fe_values()
449                                             .get_quadrature_points(),
450                                           g);
451 
452             for (unsigned int n = 0; n < n_solution_vectors; ++n)
453               for (unsigned int component = 0; component < n_components;
454                    ++component)
455                 for (unsigned int point = 0; point < n_q_points; ++point)
456                   parallel_data.phi[n][point][component] -= g[point](component);
457           }
458       }
459 
460 
461 
462     // now phi contains the following:
463     // - for an internal face, phi=[a du/dn]
464     // - for a neumann boundary face, phi=a du/dn-g
465     // each component being the mentioned value at one of the quadrature
466     // points
467 
468     parallel_data.JxW_values =
469       fe_face_values_cell.get_present_fe_values().get_JxW_values();
470 
471     // take the square of the phi[i] for integration, and sum up
472     std::vector<double> face_integral(n_solution_vectors, 0);
473     for (unsigned int n = 0; n < n_solution_vectors; ++n)
474       for (unsigned int component = 0; component < n_components; ++component)
475         if (parallel_data.component_mask[component] == true)
476           for (unsigned int p = 0; p < n_q_points; ++p)
477             face_integral[n] += numbers::NumberTraits<number>::abs_square(
478                                   parallel_data.phi[n][p][component]) *
479                                 parallel_data.JxW_values[p];
480 
481     return face_integral;
482   }
483 
484   /**
485    * A factor to scale the integral for the face at the boundary. Used for
486    * Neumann BC.
487    */
488   template <int dim, int spacedim>
489   double
boundary_face_factor(const typename DoFHandler<dim,spacedim>::active_cell_iterator & cell,const unsigned int face_no,const dealii::hp::FEFaceValues<dim,spacedim> & fe_face_values_cell,const typename KellyErrorEstimator<dim,spacedim>::Strategy strategy)490   boundary_face_factor(
491     const typename DoFHandler<dim, spacedim>::active_cell_iterator &cell,
492     const unsigned int                                              face_no,
493     const dealii::hp::FEFaceValues<dim, spacedim> &fe_face_values_cell,
494     const typename KellyErrorEstimator<dim, spacedim>::Strategy strategy)
495   {
496     switch (strategy)
497       {
498         case KellyErrorEstimator<dim, spacedim>::cell_diameter_over_24:
499           {
500             return 1.0;
501           }
502         case KellyErrorEstimator<dim, spacedim>::cell_diameter:
503           {
504             return 1.0;
505           }
506         case KellyErrorEstimator<dim,
507                                  spacedim>::face_diameter_over_twice_max_degree:
508           {
509             const double cell_degree =
510               fe_face_values_cell.get_fe_collection()[cell->active_fe_index()]
511                 .degree;
512             return cell->face(face_no)->diameter() / cell_degree;
513           }
514         default:
515           {
516             Assert(false, ExcNotImplemented());
517             return -std::numeric_limits<double>::max();
518           }
519       }
520   }
521 
522 
523   /**
524    * A factor to scale the integral for the regular face.
525    */
526   template <int dim, int spacedim>
527   double
regular_face_factor(const typename DoFHandler<dim,spacedim>::active_cell_iterator & cell,const unsigned int face_no,const dealii::hp::FEFaceValues<dim,spacedim> & fe_face_values_cell,const dealii::hp::FEFaceValues<dim,spacedim> & fe_face_values_neighbor,const typename KellyErrorEstimator<dim,spacedim>::Strategy strategy)528   regular_face_factor(
529     const typename DoFHandler<dim, spacedim>::active_cell_iterator &cell,
530     const unsigned int                                              face_no,
531     const dealii::hp::FEFaceValues<dim, spacedim> &fe_face_values_cell,
532     const dealii::hp::FEFaceValues<dim, spacedim> &fe_face_values_neighbor,
533     const typename KellyErrorEstimator<dim, spacedim>::Strategy strategy)
534   {
535     switch (strategy)
536       {
537         case KellyErrorEstimator<dim, spacedim>::cell_diameter_over_24:
538           {
539             return 1.0;
540           }
541         case KellyErrorEstimator<dim, spacedim>::cell_diameter:
542           {
543             return 1.0;
544           }
545         case KellyErrorEstimator<dim,
546                                  spacedim>::face_diameter_over_twice_max_degree:
547           {
548             const double cell_degree =
549               fe_face_values_cell.get_fe_collection()[cell->active_fe_index()]
550                 .degree;
551             const double neighbor_degree =
552               fe_face_values_neighbor
553                 .get_fe_collection()[cell->neighbor(face_no)->active_fe_index()]
554                 .degree;
555             return cell->face(face_no)->diameter() /
556                    std::max(cell_degree, neighbor_degree) / 2.0;
557           }
558         default:
559           {
560             Assert(false, ExcNotImplemented());
561             return -std::numeric_limits<double>::max();
562           }
563       }
564   }
565 
566   /**
567    * A factor to scale the integral for the irregular face.
568    */
569   template <int dim, int spacedim>
570   double
irregular_face_factor(const typename DoFHandler<dim,spacedim>::active_cell_iterator & cell,const typename DoFHandler<dim,spacedim>::active_cell_iterator & neighbor_child,const unsigned int face_no,const unsigned int subface_no,const dealii::hp::FEFaceValues<dim,spacedim> & fe_face_values,dealii::hp::FESubfaceValues<dim,spacedim> & fe_subface_values,const typename KellyErrorEstimator<dim,spacedim>::Strategy strategy)571   irregular_face_factor(
572     const typename DoFHandler<dim, spacedim>::active_cell_iterator &cell,
573     const typename DoFHandler<dim, spacedim>::active_cell_iterator
574       &                                            neighbor_child,
575     const unsigned int                             face_no,
576     const unsigned int                             subface_no,
577     const dealii::hp::FEFaceValues<dim, spacedim> &fe_face_values,
578     dealii::hp::FESubfaceValues<dim, spacedim> &   fe_subface_values,
579     const typename KellyErrorEstimator<dim, spacedim>::Strategy strategy)
580   {
581     switch (strategy)
582       {
583         case KellyErrorEstimator<dim, spacedim>::cell_diameter_over_24:
584           {
585             return 1.0;
586           }
587         case KellyErrorEstimator<dim, spacedim>::cell_diameter:
588           {
589             return 1.0;
590           }
591         case KellyErrorEstimator<dim,
592                                  spacedim>::face_diameter_over_twice_max_degree:
593           {
594             const double cell_degree =
595               fe_face_values.get_fe_collection()[cell->active_fe_index()]
596                 .degree;
597             const double neighbor_child_degree =
598               fe_subface_values
599                 .get_fe_collection()[neighbor_child->active_fe_index()]
600                 .degree;
601             return cell->face(face_no)->child(subface_no)->diameter() /
602                    std::max(neighbor_child_degree, cell_degree) / 2.0;
603           }
604         default:
605           {
606             Assert(false, ExcNotImplemented());
607             return -std::numeric_limits<double>::max();
608           }
609       }
610   }
611 
612   /**
613    * A factor used when summing up all the contribution from different faces
614    * of each cell.
615    */
616   template <int dim, int spacedim>
617   double
cell_factor(const typename DoFHandler<dim,spacedim>::active_cell_iterator & cell,const unsigned int,const DoFHandler<dim,spacedim> &,const typename KellyErrorEstimator<dim,spacedim>::Strategy strategy)618   cell_factor(
619     const typename DoFHandler<dim, spacedim>::active_cell_iterator &cell,
620     const unsigned int /*face_no*/,
621     const DoFHandler<dim, spacedim> & /*dof_handler*/,
622     const typename KellyErrorEstimator<dim, spacedim>::Strategy strategy)
623   {
624     switch (strategy)
625       {
626         case KellyErrorEstimator<dim, spacedim>::cell_diameter_over_24:
627           {
628             return cell->diameter() / 24;
629           }
630         case KellyErrorEstimator<dim, spacedim>::cell_diameter:
631           {
632             return cell->diameter();
633           }
634         case KellyErrorEstimator<dim,
635                                  spacedim>::face_diameter_over_twice_max_degree:
636           {
637             return 1.0;
638           }
639         default:
640           {
641             Assert(false, ExcNotImplemented());
642             return -std::numeric_limits<double>::max();
643           }
644       }
645   }
646 
647 
648 
649   /**
650    * Actually do the computation on a face which has no hanging nodes (it is
651    * regular), i.e. either on the other side there is nirvana (face is at
652    * boundary), or the other side's refinement level is the same as that of
653    * this side, then handle the integration of these both cases together.
654    */
655   template <typename InputVector, int dim, int spacedim>
656   void
integrate_over_regular_face(const std::vector<const InputVector * > & solutions,ParallelData<dim,spacedim,typename InputVector::value_type> & parallel_data,std::map<typename DoFHandler<dim,spacedim>::face_iterator,std::vector<double>> & local_face_integrals,const typename DoFHandler<dim,spacedim>::active_cell_iterator & cell,const unsigned int face_no,dealii::hp::FEFaceValues<dim,spacedim> & fe_face_values_cell,dealii::hp::FEFaceValues<dim,spacedim> & fe_face_values_neighbor,const typename KellyErrorEstimator<dim,spacedim>::Strategy strategy)657   integrate_over_regular_face(
658     const std::vector<const InputVector *> &solutions,
659     ParallelData<dim, spacedim, typename InputVector::value_type>
660       &                            parallel_data,
661     std::map<typename DoFHandler<dim, spacedim>::face_iterator,
662              std::vector<double>> &local_face_integrals,
663     const typename DoFHandler<dim, spacedim>::active_cell_iterator &cell,
664     const unsigned int                                              face_no,
665     dealii::hp::FEFaceValues<dim, spacedim> &fe_face_values_cell,
666     dealii::hp::FEFaceValues<dim, spacedim> &fe_face_values_neighbor,
667     const typename KellyErrorEstimator<dim, spacedim>::Strategy strategy)
668   {
669     const typename DoFHandler<dim, spacedim>::face_iterator face =
670       cell->face(face_no);
671     const unsigned int n_solution_vectors = solutions.size();
672 
673 
674     // initialize data of the restriction
675     // of this cell to the present face
676     fe_face_values_cell.reinit(cell, face_no, cell->active_fe_index());
677 
678     // get gradients of the finite element
679     // function on this cell
680     for (unsigned int n = 0; n < n_solution_vectors; ++n)
681       fe_face_values_cell.get_present_fe_values().get_function_gradients(
682         *solutions[n], parallel_data.psi[n]);
683 
684     double factor;
685     // now compute over the other side of the face
686     if (face->at_boundary() == false)
687       // internal face; integrate jump of gradient across this face
688       {
689         Assert(cell->neighbor(face_no).state() == IteratorState::valid,
690                ExcInternalError());
691 
692         const typename DoFHandler<dim, spacedim>::active_cell_iterator
693           neighbor = cell->neighbor(face_no);
694 
695         // find which number the current face has relative to the
696         // neighboring cell
697         const unsigned int neighbor_neighbor =
698           cell->neighbor_of_neighbor(face_no);
699         Assert(neighbor_neighbor < GeometryInfo<dim>::faces_per_cell,
700                ExcInternalError());
701 
702         // get restriction of finite element function of @p{neighbor} to the
703         // common face. in the hp case, use the quadrature formula that
704         // matches the one we would use for the present cell
705         fe_face_values_neighbor.reinit(neighbor,
706                                        neighbor_neighbor,
707                                        cell->active_fe_index());
708 
709         factor = regular_face_factor<dim, spacedim>(cell,
710                                                     face_no,
711                                                     fe_face_values_cell,
712                                                     fe_face_values_neighbor,
713                                                     strategy);
714 
715         // get gradients on neighbor cell
716         for (unsigned int n = 0; n < n_solution_vectors; ++n)
717           {
718             fe_face_values_neighbor.get_present_fe_values()
719               .get_function_gradients(*solutions[n],
720                                       parallel_data.neighbor_psi[n]);
721           }
722 
723         parallel_data.neighbor_normal_vectors =
724           fe_face_values_neighbor.get_present_fe_values().get_normal_vectors();
725       }
726     else
727       {
728         factor = boundary_face_factor<dim, spacedim>(cell,
729                                                      face_no,
730                                                      fe_face_values_cell,
731                                                      strategy);
732       }
733 
734     // now go to the generic function that does all the other things
735     local_face_integrals[face] =
736       integrate_over_face(parallel_data, face, fe_face_values_cell);
737 
738     for (unsigned int i = 0; i < local_face_integrals[face].size(); i++)
739       local_face_integrals[face][i] *= factor;
740   }
741 
742 
743 
744   /**
745    * The same applies as for the function above, except that integration is
746    * over face @p face_no of @p cell, where the respective neighbor is
747    * refined, so that the integration is a bit more complex.
748    */
749   template <typename InputVector, int dim, int spacedim>
750   void
integrate_over_irregular_face(const std::vector<const InputVector * > & solutions,ParallelData<dim,spacedim,typename InputVector::value_type> & parallel_data,std::map<typename DoFHandler<dim,spacedim>::face_iterator,std::vector<double>> & local_face_integrals,const typename DoFHandler<dim,spacedim>::active_cell_iterator & cell,const unsigned int face_no,dealii::hp::FEFaceValues<dim,spacedim> & fe_face_values,dealii::hp::FESubfaceValues<dim,spacedim> & fe_subface_values,const typename KellyErrorEstimator<dim,spacedim>::Strategy strategy)751   integrate_over_irregular_face(
752     const std::vector<const InputVector *> &solutions,
753     ParallelData<dim, spacedim, typename InputVector::value_type>
754       &                            parallel_data,
755     std::map<typename DoFHandler<dim, spacedim>::face_iterator,
756              std::vector<double>> &local_face_integrals,
757     const typename DoFHandler<dim, spacedim>::active_cell_iterator &cell,
758     const unsigned int                                              face_no,
759     dealii::hp::FEFaceValues<dim, spacedim> &   fe_face_values,
760     dealii::hp::FESubfaceValues<dim, spacedim> &fe_subface_values,
761     const typename KellyErrorEstimator<dim, spacedim>::Strategy strategy)
762   {
763     const auto neighbor = cell->neighbor(face_no);
764     (void)neighbor;
765     const unsigned int n_solution_vectors = solutions.size();
766     const auto         face               = cell->face(face_no);
767 
768     Assert(neighbor.state() == IteratorState::valid, ExcInternalError());
769     Assert(face->has_children(), ExcInternalError());
770 
771     // set up a vector of the gradients of the finite element function on
772     // this cell at the quadrature points
773     //
774     // let psi be a short name for [a grad u_h], where the second index be
775     // the component of the finite element, and the first index the number
776     // of the quadrature point
777 
778     // store which number @p{cell} has in the list of neighbors of
779     // @p{neighbor}
780     const unsigned int neighbor_neighbor = cell->neighbor_of_neighbor(face_no);
781     Assert(neighbor_neighbor < GeometryInfo<dim>::faces_per_cell,
782            ExcInternalError());
783 
784     // loop over all subfaces
785     for (unsigned int subface_no = 0; subface_no < face->n_children();
786          ++subface_no)
787       {
788         // get an iterator pointing to the cell behind the present subface
789         const typename DoFHandler<dim, spacedim>::active_cell_iterator
790           neighbor_child = cell->neighbor_child_on_subface(face_no, subface_no);
791         Assert(neighbor_child->is_active(), ExcInternalError());
792 
793         // restrict the finite element on the present cell to the subface
794         fe_subface_values.reinit(cell,
795                                  face_no,
796                                  subface_no,
797                                  cell->active_fe_index());
798 
799         // restrict the finite element on the neighbor cell to the common
800         // @p{subface}.
801         fe_face_values.reinit(neighbor_child,
802                               neighbor_neighbor,
803                               cell->active_fe_index());
804 
805         const double factor =
806           irregular_face_factor<dim, spacedim>(cell,
807                                                neighbor_child,
808                                                face_no,
809                                                subface_no,
810                                                fe_face_values,
811                                                fe_subface_values,
812                                                strategy);
813 
814         // store the gradient of the solution in psi
815         for (unsigned int n = 0; n < n_solution_vectors; ++n)
816           fe_subface_values.get_present_fe_values().get_function_gradients(
817             *solutions[n], parallel_data.psi[n]);
818 
819         // store the gradient from the neighbor's side in @p{neighbor_psi}
820         for (unsigned int n = 0; n < n_solution_vectors; ++n)
821           fe_face_values.get_present_fe_values().get_function_gradients(
822             *solutions[n], parallel_data.neighbor_psi[n]);
823 
824         // call generic evaluate function
825         parallel_data.neighbor_normal_vectors =
826           fe_subface_values.get_present_fe_values().get_normal_vectors();
827 
828         local_face_integrals[neighbor_child->face(neighbor_neighbor)] =
829           integrate_over_face(parallel_data, face, fe_face_values);
830         for (unsigned int i = 0;
831              i < local_face_integrals[neighbor_child->face(neighbor_neighbor)]
832                    .size();
833              i++)
834           local_face_integrals[neighbor_child->face(neighbor_neighbor)][i] *=
835             factor;
836       }
837 
838     // finally loop over all subfaces to collect the contributions of the
839     // subfaces and store them with the mother face
840     std::vector<double> sum(n_solution_vectors, 0);
841     for (unsigned int subface_no = 0; subface_no < face->n_children();
842          ++subface_no)
843       {
844         Assert(local_face_integrals.find(face->child(subface_no)) !=
845                  local_face_integrals.end(),
846                ExcInternalError());
847         Assert(local_face_integrals[face->child(subface_no)][0] >= 0,
848                ExcInternalError());
849 
850         for (unsigned int n = 0; n < n_solution_vectors; ++n)
851           sum[n] += local_face_integrals[face->child(subface_no)][n];
852       }
853 
854     local_face_integrals[face] = sum;
855   }
856 
857 
858   /**
859    * Computate the error on the faces of a single cell.
860    *
861    * This function is only needed in two or three dimensions.  The error
862    * estimator in one dimension is implemented separately.
863    */
864   template <typename InputVector, int dim, int spacedim>
865   void
estimate_one_cell(const typename DoFHandler<dim,spacedim>::active_cell_iterator & cell,ParallelData<dim,spacedim,typename InputVector::value_type> & parallel_data,std::map<typename DoFHandler<dim,spacedim>::face_iterator,std::vector<double>> & local_face_integrals,const std::vector<const InputVector * > & solutions,const typename KellyErrorEstimator<dim,spacedim>::Strategy strategy)866   estimate_one_cell(
867     const typename DoFHandler<dim, spacedim>::active_cell_iterator &cell,
868     ParallelData<dim, spacedim, typename InputVector::value_type>
869       &                                     parallel_data,
870     std::map<typename DoFHandler<dim, spacedim>::face_iterator,
871              std::vector<double>> &         local_face_integrals,
872     const std::vector<const InputVector *> &solutions,
873     const typename KellyErrorEstimator<dim, spacedim>::Strategy strategy)
874   {
875     const unsigned int n_solution_vectors = solutions.size();
876 
877     const types::subdomain_id subdomain_id = parallel_data.subdomain_id;
878     const unsigned int        material_id  = parallel_data.material_id;
879 
880     // empty our own copy of the local face integrals
881     local_face_integrals.clear();
882 
883     // loop over all faces of this cell
884     for (const unsigned int face_no : cell->face_indices())
885       {
886         const typename DoFHandler<dim, spacedim>::face_iterator face =
887           cell->face(face_no);
888 
889         // make sure we do work only once: this face may either be regular
890         // or irregular. if it is regular and has a neighbor, then we visit
891         // the face twice, once from every side. let the one with the lower
892         // index do the work. if it is at the boundary, or if the face is
893         // irregular, then do the work below
894         if ((face->has_children() == false) && !cell->at_boundary(face_no) &&
895             (!cell->neighbor_is_coarser(face_no) &&
896              (cell->neighbor(face_no)->index() < cell->index() ||
897               (cell->neighbor(face_no)->index() == cell->index() &&
898                cell->neighbor(face_no)->level() < cell->level()))))
899           continue;
900 
901         // if the neighboring cell is less refined than the present one,
902         // then do nothing since we integrate over the subfaces when we
903         // visit the coarse cells.
904         if (face->at_boundary() == false)
905           if (cell->neighbor_is_coarser(face_no))
906             continue;
907 
908         // if this face is part of the boundary but not of the neumann
909         // boundary -> nothing to do. However, to make things easier when
910         // summing up the contributions of the faces of cells, we enter this
911         // face into the list of faces with contribution zero.
912         if (face->at_boundary() &&
913             (parallel_data.neumann_bc->find(face->boundary_id()) ==
914              parallel_data.neumann_bc->end()))
915           {
916             local_face_integrals[face] =
917               std::vector<double>(n_solution_vectors, 0.);
918             continue;
919           }
920 
921         // finally: note that we only have to do something if either the
922         // present cell is on the subdomain we care for (and the same for
923         // material_id), or if one of the neighbors behind the face is on
924         // the subdomain we care for
925         if (!(((subdomain_id == numbers::invalid_subdomain_id) ||
926                (cell->subdomain_id() == subdomain_id)) &&
927               ((material_id == numbers::invalid_material_id) ||
928                (cell->material_id() == material_id))))
929           {
930             // ok, cell is unwanted, but maybe its neighbor behind the face
931             // we presently work on? oh is there a face at all?
932             if (face->at_boundary())
933               continue;
934 
935             bool care_for_cell = false;
936             if (face->has_children() == false)
937               care_for_cell |=
938                 ((cell->neighbor(face_no)->subdomain_id() == subdomain_id) ||
939                  (subdomain_id == numbers::invalid_subdomain_id)) &&
940                 ((cell->neighbor(face_no)->material_id() == material_id) ||
941                  (material_id == numbers::invalid_material_id));
942             else
943               {
944                 for (unsigned int sf = 0; sf < face->n_children(); ++sf)
945                   if (((cell->neighbor_child_on_subface(face_no, sf)
946                           ->subdomain_id() == subdomain_id) &&
947                        (material_id == numbers::invalid_material_id)) ||
948                       ((cell->neighbor_child_on_subface(face_no, sf)
949                           ->material_id() == material_id) &&
950                        (subdomain_id == numbers::invalid_subdomain_id)))
951                     {
952                       care_for_cell = true;
953                       break;
954                     }
955               }
956 
957             // so if none of the neighbors cares for this subdomain or
958             // material either, then try next face
959             if (care_for_cell == false)
960               continue;
961           }
962 
963         // so now we know that we care for this face, let's do something
964         // about it. first re-size the arrays we may use to the correct
965         // size:
966         parallel_data.resize(cell->active_fe_index());
967 
968 
969         // then do the actual integration
970         if (face->has_children() == false)
971           // if the face is a regular one, i.e.  either on the other side
972           // there is nirvana (face is at boundary), or the other side's
973           // refinement level is the same as that of this side, then handle
974           // the integration of these both cases together
975           integrate_over_regular_face(solutions,
976                                       parallel_data,
977                                       local_face_integrals,
978                                       cell,
979                                       face_no,
980                                       parallel_data.fe_face_values_cell,
981                                       parallel_data.fe_face_values_neighbor,
982                                       strategy);
983 
984         else
985           // otherwise we need to do some special computations which do not
986           // fit into the framework of the above function
987           integrate_over_irregular_face(solutions,
988                                         parallel_data,
989                                         local_face_integrals,
990                                         cell,
991                                         face_no,
992                                         parallel_data.fe_face_values_cell,
993                                         parallel_data.fe_subface_values,
994                                         strategy);
995       }
996   }
997 } // namespace internal
998 
999 
1000 
1001 // the following function is still independent of dimension, but it
1002 // calls dimension dependent functions
1003 template <int dim, int spacedim>
1004 template <typename InputVector>
1005 void
estimate(const Mapping<dim,spacedim> & mapping,const DoFHandler<dim,spacedim> & dof_handler,const Quadrature<dim-1> & quadrature,const std::map<types::boundary_id,const Function<spacedim,typename InputVector::value_type> * > & neumann_bc,const InputVector & solution,Vector<float> & error,const ComponentMask & component_mask,const Function<spacedim> * coefficients,const unsigned int n_threads,const types::subdomain_id subdomain_id,const types::material_id material_id,const Strategy strategy)1006 KellyErrorEstimator<dim, spacedim>::estimate(
1007   const Mapping<dim, spacedim> &   mapping,
1008   const DoFHandler<dim, spacedim> &dof_handler,
1009   const Quadrature<dim - 1> &      quadrature,
1010   const std::map<types::boundary_id,
1011                  const Function<spacedim, typename InputVector::value_type> *>
1012     &                       neumann_bc,
1013   const InputVector &       solution,
1014   Vector<float> &           error,
1015   const ComponentMask &     component_mask,
1016   const Function<spacedim> *coefficients,
1017   const unsigned int        n_threads,
1018   const types::subdomain_id subdomain_id,
1019   const types::material_id  material_id,
1020   const Strategy            strategy)
1021 {
1022   // just pass on to the other function
1023   const std::vector<const InputVector *> solutions(1, &solution);
1024   std::vector<Vector<float> *>           errors(1, &error);
1025   estimate(mapping,
1026            dof_handler,
1027            quadrature,
1028            neumann_bc,
1029            solutions,
1030            errors,
1031            component_mask,
1032            coefficients,
1033            n_threads,
1034            subdomain_id,
1035            material_id,
1036            strategy);
1037 }
1038 
1039 
1040 template <int dim, int spacedim>
1041 template <typename InputVector>
1042 void
estimate(const DoFHandler<dim,spacedim> & dof_handler,const Quadrature<dim-1> & quadrature,const std::map<types::boundary_id,const Function<spacedim,typename InputVector::value_type> * > & neumann_bc,const InputVector & solution,Vector<float> & error,const ComponentMask & component_mask,const Function<spacedim> * coefficients,const unsigned int n_threads,const types::subdomain_id subdomain_id,const types::material_id material_id,const Strategy strategy)1043 KellyErrorEstimator<dim, spacedim>::estimate(
1044   const DoFHandler<dim, spacedim> &dof_handler,
1045   const Quadrature<dim - 1> &      quadrature,
1046   const std::map<types::boundary_id,
1047                  const Function<spacedim, typename InputVector::value_type> *>
1048     &                       neumann_bc,
1049   const InputVector &       solution,
1050   Vector<float> &           error,
1051   const ComponentMask &     component_mask,
1052   const Function<spacedim> *coefficients,
1053   const unsigned int        n_threads,
1054   const types::subdomain_id subdomain_id,
1055   const types::material_id  material_id,
1056   const Strategy            strategy)
1057 {
1058   estimate(StaticMappingQ1<dim, spacedim>::mapping,
1059            dof_handler,
1060            quadrature,
1061            neumann_bc,
1062            solution,
1063            error,
1064            component_mask,
1065            coefficients,
1066            n_threads,
1067            subdomain_id,
1068            material_id,
1069            strategy);
1070 }
1071 
1072 
1073 template <int dim, int spacedim>
1074 template <typename InputVector>
1075 void
estimate(const Mapping<dim,spacedim> & mapping,const DoFHandler<dim,spacedim> & dof_handler,const hp::QCollection<dim-1> & quadrature,const std::map<types::boundary_id,const Function<spacedim,typename InputVector::value_type> * > & neumann_bc,const InputVector & solution,Vector<float> & error,const ComponentMask & component_mask,const Function<spacedim> * coefficients,const unsigned int n_threads,const types::subdomain_id subdomain_id,const types::material_id material_id,const Strategy strategy)1076 KellyErrorEstimator<dim, spacedim>::estimate(
1077   const Mapping<dim, spacedim> &   mapping,
1078   const DoFHandler<dim, spacedim> &dof_handler,
1079   const hp::QCollection<dim - 1> & quadrature,
1080   const std::map<types::boundary_id,
1081                  const Function<spacedim, typename InputVector::value_type> *>
1082     &                       neumann_bc,
1083   const InputVector &       solution,
1084   Vector<float> &           error,
1085   const ComponentMask &     component_mask,
1086   const Function<spacedim> *coefficients,
1087   const unsigned int        n_threads,
1088   const types::subdomain_id subdomain_id,
1089   const types::material_id  material_id,
1090   const Strategy            strategy)
1091 {
1092   // just pass on to the other function
1093   const std::vector<const InputVector *> solutions(1, &solution);
1094   std::vector<Vector<float> *>           errors(1, &error);
1095   estimate(mapping,
1096            dof_handler,
1097            quadrature,
1098            neumann_bc,
1099            solutions,
1100            errors,
1101            component_mask,
1102            coefficients,
1103            n_threads,
1104            subdomain_id,
1105            material_id,
1106            strategy);
1107 }
1108 
1109 
1110 template <int dim, int spacedim>
1111 template <typename InputVector>
1112 void
estimate(const DoFHandler<dim,spacedim> & dof_handler,const hp::QCollection<dim-1> & quadrature,const std::map<types::boundary_id,const Function<spacedim,typename InputVector::value_type> * > & neumann_bc,const InputVector & solution,Vector<float> & error,const ComponentMask & component_mask,const Function<spacedim> * coefficients,const unsigned int n_threads,const types::subdomain_id subdomain_id,const types::material_id material_id,const Strategy strategy)1113 KellyErrorEstimator<dim, spacedim>::estimate(
1114   const DoFHandler<dim, spacedim> &dof_handler,
1115   const hp::QCollection<dim - 1> & quadrature,
1116   const std::map<types::boundary_id,
1117                  const Function<spacedim, typename InputVector::value_type> *>
1118     &                       neumann_bc,
1119   const InputVector &       solution,
1120   Vector<float> &           error,
1121   const ComponentMask &     component_mask,
1122   const Function<spacedim> *coefficients,
1123   const unsigned int        n_threads,
1124   const types::subdomain_id subdomain_id,
1125   const types::material_id  material_id,
1126   const Strategy            strategy)
1127 {
1128   estimate(StaticMappingQ1<dim, spacedim>::mapping,
1129            dof_handler,
1130            quadrature,
1131            neumann_bc,
1132            solution,
1133            error,
1134            component_mask,
1135            coefficients,
1136            n_threads,
1137            subdomain_id,
1138            material_id,
1139            strategy);
1140 }
1141 
1142 
1143 
1144 template <int dim, int spacedim>
1145 template <typename InputVector>
1146 void
estimate(const Mapping<dim,spacedim> & mapping,const DoFHandler<dim,spacedim> & dof_handler,const hp::QCollection<dim-1> & face_quadratures,const std::map<types::boundary_id,const Function<spacedim,typename InputVector::value_type> * > & neumann_bc,const std::vector<const InputVector * > & solutions,std::vector<Vector<float> * > & errors,const ComponentMask & component_mask,const Function<spacedim> * coefficients,const unsigned int,const types::subdomain_id subdomain_id_,const types::material_id material_id,const Strategy strategy)1147 KellyErrorEstimator<dim, spacedim>::estimate(
1148   const Mapping<dim, spacedim> &   mapping,
1149   const DoFHandler<dim, spacedim> &dof_handler,
1150   const hp::QCollection<dim - 1> & face_quadratures,
1151   const std::map<types::boundary_id,
1152                  const Function<spacedim, typename InputVector::value_type> *>
1153     &                                     neumann_bc,
1154   const std::vector<const InputVector *> &solutions,
1155   std::vector<Vector<float> *> &          errors,
1156   const ComponentMask &                   component_mask,
1157   const Function<spacedim> *              coefficients,
1158   const unsigned int,
1159   const types::subdomain_id subdomain_id_,
1160   const types::material_id  material_id,
1161   const Strategy            strategy)
1162 {
1163 #ifdef DEAL_II_WITH_P4EST
1164   if (dynamic_cast<const parallel::distributed::Triangulation<dim, spacedim> *>(
1165         &dof_handler.get_triangulation()) != nullptr)
1166     Assert((subdomain_id_ == numbers::invalid_subdomain_id) ||
1167              (subdomain_id_ ==
1168               dynamic_cast<
1169                 const parallel::distributed::Triangulation<dim, spacedim> &>(
1170                 dof_handler.get_triangulation())
1171                 .locally_owned_subdomain()),
1172            ExcMessage(
1173              "For parallel distributed triangulations, the only "
1174              "valid subdomain_id that can be passed here is the "
1175              "one that corresponds to the locally owned subdomain id."));
1176 
1177   const types::subdomain_id subdomain_id =
1178     ((dynamic_cast<const parallel::distributed::Triangulation<dim, spacedim> *>(
1179         &dof_handler.get_triangulation()) != nullptr) ?
1180        dynamic_cast<const parallel::distributed::Triangulation<dim, spacedim>
1181                       &>(dof_handler.get_triangulation())
1182          .locally_owned_subdomain() :
1183        subdomain_id_);
1184 #else
1185   const types::subdomain_id subdomain_id = subdomain_id_;
1186 #endif
1187 
1188   const unsigned int n_components = dof_handler.get_fe(0).n_components();
1189   (void)n_components;
1190 
1191   // sanity checks
1192   Assert(solutions.size() > 0, ExcNoSolutions());
1193   Assert(solutions.size() == errors.size(),
1194          ExcIncompatibleNumberOfElements(solutions.size(), errors.size()));
1195 
1196   for (const auto &boundary_function : neumann_bc)
1197     {
1198       (void)boundary_function;
1199       Assert(boundary_function.second->n_components == n_components,
1200              ExcInvalidBoundaryFunction(boundary_function.first,
1201                                         boundary_function.second->n_components,
1202                                         n_components));
1203     }
1204 
1205   Assert(component_mask.represents_n_components(n_components),
1206          ExcInvalidComponentMask());
1207   Assert(component_mask.n_selected_components(n_components) > 0,
1208          ExcInvalidComponentMask());
1209 
1210   Assert((coefficients == nullptr) ||
1211            (coefficients->n_components == n_components) ||
1212            (coefficients->n_components == 1),
1213          ExcInvalidCoefficient());
1214 
1215   for (unsigned int n = 0; n < solutions.size(); ++n)
1216     Assert(solutions[n]->size() == dof_handler.n_dofs(),
1217            ExcDimensionMismatch(solutions[n]->size(), dof_handler.n_dofs()));
1218 
1219   const unsigned int n_solution_vectors = solutions.size();
1220 
1221   // Map of integrals indexed by the corresponding face. In this map we store
1222   // the integrated jump of the gradient for each face.  At the end of the
1223   // function, we again loop over the cells and collect the contributions of
1224   // the different faces of the cell.
1225   std::map<typename DoFHandler<dim, spacedim>::face_iterator,
1226            std::vector<double>>
1227     face_integrals;
1228 
1229   // all the data needed in the error estimator by each of the threads is
1230   // gathered in the following structures
1231   const hp::MappingCollection<dim, spacedim> mapping_collection(mapping);
1232   const internal::ParallelData<dim, spacedim, typename InputVector::value_type>
1233     parallel_data(dof_handler.get_fe_collection(),
1234                   face_quadratures,
1235                   mapping_collection,
1236                   (!neumann_bc.empty() || (coefficients != nullptr)),
1237                   solutions.size(),
1238                   subdomain_id,
1239                   material_id,
1240                   &neumann_bc,
1241                   component_mask,
1242                   coefficients);
1243   std::map<typename DoFHandler<dim, spacedim>::face_iterator,
1244            std::vector<double>>
1245     sample_local_face_integrals;
1246 
1247   // now let's work on all those cells:
1248   WorkStream::run(
1249     dof_handler.begin_active(),
1250     static_cast<typename DoFHandler<dim, spacedim>::active_cell_iterator>(
1251       dof_handler.end()),
1252     [&solutions, strategy](
1253       const typename DoFHandler<dim, spacedim>::active_cell_iterator &cell,
1254       internal::ParallelData<dim, spacedim, typename InputVector::value_type>
1255         &                            parallel_data,
1256       std::map<typename DoFHandler<dim, spacedim>::face_iterator,
1257                std::vector<double>> &local_face_integrals) {
1258       internal::estimate_one_cell(
1259         cell, parallel_data, local_face_integrals, solutions, strategy);
1260     },
1261     [&face_integrals](
1262       const std::map<typename DoFHandler<dim, spacedim>::face_iterator,
1263                      std::vector<double>> &local_face_integrals) {
1264       internal::copy_local_to_global<dim, spacedim>(local_face_integrals,
1265                                                     face_integrals);
1266     },
1267     parallel_data,
1268     sample_local_face_integrals);
1269 
1270   // finally add up the contributions of the faces for each cell
1271 
1272   // reserve one slot for each cell and set it to zero
1273   for (unsigned int n = 0; n < n_solution_vectors; ++n)
1274     {
1275       (*errors[n]).reinit(dof_handler.get_triangulation().n_active_cells());
1276       for (unsigned int i = 0;
1277            i < dof_handler.get_triangulation().n_active_cells();
1278            ++i)
1279         (*errors[n])(i) = 0;
1280     }
1281 
1282   // now walk over all cells and collect information from the faces. only do
1283   // something if this is a cell we care for based on the subdomain id
1284   for (const auto &cell : dof_handler.active_cell_iterators())
1285     if (((subdomain_id == numbers::invalid_subdomain_id) ||
1286          (cell->subdomain_id() == subdomain_id)) &&
1287         ((material_id == numbers::invalid_material_id) ||
1288          (cell->material_id() == material_id)))
1289       {
1290         const unsigned int present_cell = cell->active_cell_index();
1291 
1292         // loop over all faces of this cell
1293         for (const unsigned int face_no : cell->face_indices())
1294           {
1295             Assert(face_integrals.find(cell->face(face_no)) !=
1296                      face_integrals.end(),
1297                    ExcInternalError());
1298             const double factor = internal::cell_factor<dim, spacedim>(
1299               cell, face_no, dof_handler, strategy);
1300 
1301             for (unsigned int n = 0; n < n_solution_vectors; ++n)
1302               {
1303                 // make sure that we have written a meaningful value into this
1304                 // slot
1305                 Assert(face_integrals[cell->face(face_no)][n] >= 0,
1306                        ExcInternalError());
1307 
1308                 (*errors[n])(present_cell) +=
1309                   (face_integrals[cell->face(face_no)][n] * factor);
1310               }
1311           }
1312 
1313         for (unsigned int n = 0; n < n_solution_vectors; ++n)
1314           (*errors[n])(present_cell) = std::sqrt((*errors[n])(present_cell));
1315       }
1316 }
1317 
1318 
1319 
1320 template <int dim, int spacedim>
1321 template <typename InputVector>
1322 void
estimate(const Mapping<dim,spacedim> & mapping,const DoFHandler<dim,spacedim> & dof_handler,const Quadrature<dim-1> & quadrature,const std::map<types::boundary_id,const Function<spacedim,typename InputVector::value_type> * > & neumann_bc,const std::vector<const InputVector * > & solutions,std::vector<Vector<float> * > & errors,const ComponentMask & component_mask,const Function<spacedim> * coefficients,const unsigned int n_threads,const types::subdomain_id subdomain_id,const types::material_id material_id,const Strategy strategy)1323 KellyErrorEstimator<dim, spacedim>::estimate(
1324   const Mapping<dim, spacedim> &   mapping,
1325   const DoFHandler<dim, spacedim> &dof_handler,
1326   const Quadrature<dim - 1> &      quadrature,
1327   const std::map<types::boundary_id,
1328                  const Function<spacedim, typename InputVector::value_type> *>
1329     &                                     neumann_bc,
1330   const std::vector<const InputVector *> &solutions,
1331   std::vector<Vector<float> *> &          errors,
1332   const ComponentMask &                   component_mask,
1333   const Function<spacedim> *              coefficients,
1334   const unsigned int                      n_threads,
1335   const types::subdomain_id               subdomain_id,
1336   const types::material_id                material_id,
1337   const Strategy                          strategy)
1338 {
1339   // forward to the function with the QCollection
1340   estimate(mapping,
1341            dof_handler,
1342            hp::QCollection<dim - 1>(quadrature),
1343            neumann_bc,
1344            solutions,
1345            errors,
1346            component_mask,
1347            coefficients,
1348            n_threads,
1349            subdomain_id,
1350            material_id,
1351            strategy);
1352 }
1353 
1354 
1355 template <int dim, int spacedim>
1356 template <typename InputVector>
1357 void
estimate(const DoFHandler<dim,spacedim> & dof_handler,const Quadrature<dim-1> & quadrature,const std::map<types::boundary_id,const Function<spacedim,typename InputVector::value_type> * > & neumann_bc,const std::vector<const InputVector * > & solutions,std::vector<Vector<float> * > & errors,const ComponentMask & component_mask,const Function<spacedim> * coefficients,const unsigned int n_threads,const types::subdomain_id subdomain_id,const types::material_id material_id,const Strategy strategy)1358 KellyErrorEstimator<dim, spacedim>::estimate(
1359   const DoFHandler<dim, spacedim> &dof_handler,
1360   const Quadrature<dim - 1> &      quadrature,
1361   const std::map<types::boundary_id,
1362                  const Function<spacedim, typename InputVector::value_type> *>
1363     &                                     neumann_bc,
1364   const std::vector<const InputVector *> &solutions,
1365   std::vector<Vector<float> *> &          errors,
1366   const ComponentMask &                   component_mask,
1367   const Function<spacedim> *              coefficients,
1368   const unsigned int                      n_threads,
1369   const types::subdomain_id               subdomain_id,
1370   const types::material_id                material_id,
1371   const Strategy                          strategy)
1372 {
1373   estimate(StaticMappingQ1<dim, spacedim>::mapping,
1374            dof_handler,
1375            quadrature,
1376            neumann_bc,
1377            solutions,
1378            errors,
1379            component_mask,
1380            coefficients,
1381            n_threads,
1382            subdomain_id,
1383            material_id,
1384            strategy);
1385 }
1386 
1387 
1388 
1389 template <int dim, int spacedim>
1390 template <typename InputVector>
1391 void
estimate(const DoFHandler<dim,spacedim> & dof_handler,const hp::QCollection<dim-1> & quadrature,const std::map<types::boundary_id,const Function<spacedim,typename InputVector::value_type> * > & neumann_bc,const std::vector<const InputVector * > & solutions,std::vector<Vector<float> * > & errors,const ComponentMask & component_mask,const Function<spacedim> * coefficients,const unsigned int n_threads,const types::subdomain_id subdomain_id,const types::material_id material_id,const Strategy strategy)1392 KellyErrorEstimator<dim, spacedim>::estimate(
1393   const DoFHandler<dim, spacedim> &dof_handler,
1394   const hp::QCollection<dim - 1> & quadrature,
1395   const std::map<types::boundary_id,
1396                  const Function<spacedim, typename InputVector::value_type> *>
1397     &                                     neumann_bc,
1398   const std::vector<const InputVector *> &solutions,
1399   std::vector<Vector<float> *> &          errors,
1400   const ComponentMask &                   component_mask,
1401   const Function<spacedim> *              coefficients,
1402   const unsigned int                      n_threads,
1403   const types::subdomain_id               subdomain_id,
1404   const types::material_id                material_id,
1405   const Strategy                          strategy)
1406 {
1407   estimate(StaticMappingQ1<dim, spacedim>::mapping,
1408            dof_handler,
1409            quadrature,
1410            neumann_bc,
1411            solutions,
1412            errors,
1413            component_mask,
1414            coefficients,
1415            n_threads,
1416            subdomain_id,
1417            material_id,
1418            strategy);
1419 }
1420 
1421 DEAL_II_NAMESPACE_CLOSE
1422 
1423 #endif
1424