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