Reference documentation for deal.II version 9.1.0-pre
fe_enriched.cc
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2016 - 2018 by the deal.II authors
4 //
5 // This file is part of the deal.II library.
6 //
7 // The deal.II library is free software; you can use it, redistribute
8 // it, and/or modify it under the terms of the GNU Lesser General
9 // Public License as published by the Free Software Foundation; either
10 // version 2.1 of the License, or (at your option) any later version.
11 // The full text of the license can be found in the file LICENSE.md at
12 // the top level directory of deal.II.
13 //
14 // ---------------------------------------------------------------------
15 
16 
17 #include <deal.II/base/std_cxx14/memory.h>
18 
19 #include <deal.II/fe/fe_enriched.h>
20 #include <deal.II/fe/fe_tools.h>
21 
22 
23 DEAL_II_NAMESPACE_OPEN
24 
25 namespace internal
26 {
27  namespace FE_Enriched
28  {
29  namespace
30  {
35  template <typename T>
36  std::vector<unsigned int>
37  build_multiplicities(const std::vector<std::vector<T>> &functions)
38  {
39  std::vector<unsigned int> multiplicities;
40  multiplicities.push_back(1); // the first one is non-enriched FE
41  for (unsigned int i = 0; i < functions.size(); i++)
42  multiplicities.push_back(functions[i].size());
43 
44  return multiplicities;
45  }
46 
47 
51  template <int dim, int spacedim>
52  std::vector<const FiniteElement<dim, spacedim> *>
53  build_fes(
54  const FiniteElement<dim, spacedim> * fe_base,
55  const std::vector<const FiniteElement<dim, spacedim> *> &fe_enriched)
56  {
57  std::vector<const FiniteElement<dim, spacedim> *> fes;
58  fes.push_back(fe_base);
59  for (unsigned int i = 0; i < fe_enriched.size(); i++)
60  fes.push_back(fe_enriched[i]);
61 
62  return fes;
63  }
64 
65 
70  template <int dim, int spacedim>
71  bool
72  consistency_check(
73  const std::vector<const FiniteElement<dim, spacedim> *> &fes,
74  const std::vector<unsigned int> & multiplicities,
75  const std::vector<std::vector<std::function<const Function<spacedim> *(
76  const typename ::Triangulation<dim, spacedim>::cell_iterator
77  &)>>> & functions)
78  {
79  AssertThrow(fes.size() > 0, ExcMessage("FEs size should be >=1"));
80  AssertThrow(fes.size() == multiplicities.size(),
81  ExcMessage(
82  "FEs and multiplicities should have the same size"));
83 
84  AssertThrow(functions.size() == fes.size() - 1,
85  ExcDimensionMismatch(functions.size(), fes.size() - 1));
86 
87  AssertThrow(multiplicities[0] == 1,
88  ExcMessage("First multiplicity should be 1"));
89 
90  const unsigned int n_comp_base = fes[0]->n_components();
91 
92  // start from fe=1 as 0th is always non-enriched FE.
93  for (unsigned int fe = 1; fe < fes.size(); fe++)
94  {
95  const FE_Nothing<dim> *fe_nothing =
96  dynamic_cast<const FE_Nothing<dim> *>(fes[fe]);
97  if (fe_nothing)
99  fe_nothing->is_dominating(),
100  ExcMessage(
101  "Only dominating FE_Nothing can be used in FE_Enriched"));
102 
103  AssertThrow(
104  fes[fe]->n_components() == n_comp_base,
105  ExcMessage(
106  "All elements must have the same number of components"));
107  }
108  return true;
109  }
110 
111 
116  template <int dim, int spacedim>
117  bool
118  check_if_enriched(
119  const std::vector<const FiniteElement<dim, spacedim> *> &fes)
120  {
121  // start from fe=1 as 0th is always non-enriched FE.
122  for (unsigned int fe = 1; fe < fes.size(); fe++)
123  if (dynamic_cast<const FE_Nothing<dim> *>(fes[fe]) == nullptr)
124  // this is not FE_Nothing => there will be enrichment
125  return true;
126 
127  return false;
128  }
129  } // namespace
130  } // namespace FE_Enriched
131 } // namespace internal
132 
133 
134 template <int dim, int spacedim>
136  const FiniteElement<dim, spacedim> &fe_base)
137  : FE_Enriched<dim, spacedim>(fe_base,
138  FE_Nothing<dim, spacedim>(fe_base.n_components(),
139  true),
140  nullptr)
141 {}
142 
143 
144 template <int dim, int spacedim>
146  const FiniteElement<dim, spacedim> &fe_base,
147  const FiniteElement<dim, spacedim> &fe_enriched,
148  const Function<spacedim> * enrichment_function)
149  : FE_Enriched<dim, spacedim>(
150  &fe_base,
151  std::vector<const FiniteElement<dim, spacedim> *>(1, &fe_enriched),
152  std::vector<std::vector<std::function<const Function<spacedim> *(
153  const typename Triangulation<dim, spacedim>::cell_iterator &)>>>(
154  1,
155  std::vector<std::function<const Function<spacedim> *(
156  const typename Triangulation<dim, spacedim>::cell_iterator &)>>(
157  1,
158  [=](const typename Triangulation<dim, spacedim>::cell_iterator &)
159  -> const Function<spacedim> * { return enrichment_function; })))
160 {}
161 
162 
163 template <int dim, int spacedim>
165  const FiniteElement<dim, spacedim> * fe_base,
166  const std::vector<const FiniteElement<dim, spacedim> *> &fe_enriched,
167  const std::vector<std::vector<std::function<const Function<spacedim> *(
168  const typename Triangulation<dim, spacedim>::cell_iterator &)>>> &functions)
169  : FE_Enriched<dim, spacedim>(
170  internal::FE_Enriched::build_fes(fe_base, fe_enriched),
171  internal::FE_Enriched::build_multiplicities(functions),
172  functions)
173 {}
174 
175 
176 template <int dim, int spacedim>
178  const std::vector<const FiniteElement<dim, spacedim> *> &fes,
179  const std::vector<unsigned int> & multiplicities,
180  const std::vector<std::vector<std::function<const Function<spacedim> *(
181  const typename Triangulation<dim, spacedim>::cell_iterator &)>>> &functions)
182  : FiniteElement<dim, spacedim>(
183  FETools::Compositing::multiply_dof_numbers(fes, multiplicities, false),
184  FETools::Compositing::compute_restriction_is_additive_flags(
185  fes,
186  multiplicities),
187  FETools::Compositing::compute_nonzero_components(fes,
188  multiplicities,
189  false))
190  , enrichments(functions)
191  , is_enriched(internal::FE_Enriched::check_if_enriched(fes))
192  , fe_system(
193  std_cxx14::make_unique<FESystem<dim, spacedim>>(fes, multiplicities))
194 {
195  // descriptive error are thrown within the function.
196  Assert(internal::FE_Enriched::consistency_check(fes,
197  multiplicities,
198  functions),
199  ExcInternalError());
200 
201  initialize(fes, multiplicities);
202 
203  // resize to be consistent with all FEs used to construct the FE_Enriched,
204  // even though we will never use the 0th element.
205  base_no_mult_local_enriched_dofs.resize(fes.size());
206  for (unsigned int fe = 1; fe < fes.size(); fe++)
207  base_no_mult_local_enriched_dofs[fe].resize(multiplicities[fe]);
208 
211  this->n_base_elements()));
212 
213  // build the map: (base_no, base_m) -> vector of local element DoFs
214  for (unsigned int system_index = 0; system_index < this->dofs_per_cell;
215  ++system_index)
216  {
217  const unsigned int base_no =
218  this->system_to_base_table[system_index].first.first;
219  if (base_no == 0) // 0th is always non-enriched FE
220  continue;
221 
222  const unsigned int base_m =
223  this->system_to_base_table[system_index].first.second;
224 
225  Assert(base_m < base_no_mult_local_enriched_dofs[base_no].size(),
226  ExcMessage(
227  "Size mismatch for base_no_mult_local_enriched_dofs: "
228  "base_index = " +
229  std::to_string(this->system_to_base_table[system_index].second) +
230  "; base_no = " + std::to_string(base_no) +
231  "; base_m = " + std::to_string(base_m) +
232  "; system_index = " + std::to_string(system_index)));
233 
234  Assert(base_m < base_no_mult_local_enriched_dofs[base_no].size(),
236  base_m, base_no_mult_local_enriched_dofs[base_no].size()));
237 
238  base_no_mult_local_enriched_dofs[base_no][base_m].push_back(system_index);
239  }
240 
241  // make sure that local_enriched_dofs.size() is correct, that is equals to
242  // DoFs per cell of the corresponding FE.
243  for (unsigned int base_no = 1;
244  base_no < base_no_mult_local_enriched_dofs.size();
245  base_no++)
246  {
247  for (unsigned int m = 0;
248  m < base_no_mult_local_enriched_dofs[base_no].size();
249  m++)
250  Assert(base_no_mult_local_enriched_dofs[base_no][m].size() ==
251  fes[base_no]->dofs_per_cell,
253  base_no_mult_local_enriched_dofs[base_no][m].size(),
254  fes[base_no]->dofs_per_cell));
255  }
256 }
257 
258 
259 template <int dim, int spacedim>
260 const std::vector<std::vector<std::function<const Function<spacedim> *(
263 {
264  return enrichments;
265 }
266 
267 
268 template <int dim, int spacedim>
269 double
271  const Point<dim> & p) const
272 {
273  Assert(
274  !is_enriched,
275  ExcMessage(
276  "For enriched finite elements shape_value() can not be defined on the reference element."));
277  return fe_system->shape_value(i, p);
278 }
279 
280 
281 template <int dim, int spacedim>
282 std::unique_ptr<FiniteElement<dim, spacedim>>
284 {
285  std::vector<const FiniteElement<dim, spacedim> *> fes;
286  std::vector<unsigned int> multiplicities;
287 
288  for (unsigned int i = 0; i < this->n_base_elements(); i++)
289  {
290  fes.push_back(&base_element(i));
291  multiplicities.push_back(this->element_multiplicity(i));
292  }
293 
294  return std::unique_ptr<FE_Enriched<dim, spacedim>>(
295  new FE_Enriched<dim, spacedim>(fes, multiplicities, get_enrichments()));
296 }
297 
298 
299 template <int dim, int spacedim>
302 {
303  UpdateFlags out = fe_system->requires_update_flags(flags);
304 
305  if (is_enriched)
306  {
307  // if we ask for values or gradients, then we would need quadrature points
308  if (flags & (update_values | update_gradients))
310 
311  // if need gradients, add update_values due to product rule
312  if (out & update_gradients)
313  out |= update_values;
314  }
315 
317 
318  return out;
319 }
320 
321 
322 template <int dim, int spacedim>
323 template <int dim_1>
324 std::unique_ptr<typename FiniteElement<dim, spacedim>::InternalDataBase>
326  std::unique_ptr<typename FESystem<dim, spacedim>::InternalData> fes_data,
327  const UpdateFlags flags,
328  const Quadrature<dim_1> &quadrature) const
329 {
330  // Pass ownership of the FiniteElement::InternalDataBase object
331  // that fes_data points to, to the new InternalData object.
332  auto update_each_flags = fes_data->update_each;
333  auto data = std_cxx14::make_unique<InternalData>(std::move(fes_data));
334 
335  // copy update_each from FESystem data:
336  data->update_each = update_each_flags;
337 
338  // resize cache array according to requested flags
339  data->enrichment.resize(this->n_base_elements());
340 
341  const unsigned int n_q_points = quadrature.size();
342 
343  for (unsigned int base = 0; base < this->n_base_elements(); ++base)
344  {
345  data->enrichment[base].resize(this->element_multiplicity(base));
346  for (unsigned int m = 0; m < this->element_multiplicity(base); ++m)
347  {
348  if (flags & update_values)
349  data->enrichment[base][m].values.resize(n_q_points);
350 
351  if (flags & update_gradients)
352  data->enrichment[base][m].gradients.resize(n_q_points);
353 
354  if (flags & update_hessians)
355  data->enrichment[base][m].hessians.resize(n_q_points);
356  }
357  }
358 
359  return std::move(data);
360 }
361 
362 
363 template <int dim, int spacedim>
364 std::unique_ptr<typename FiniteElement<dim, spacedim>::InternalDataBase>
366  const UpdateFlags update_flags,
367  const Mapping<dim, spacedim> &mapping,
368  const Quadrature<dim - 1> & quadrature,
370  &output_data) const
371 {
372  auto data =
373  fe_system->get_face_data(update_flags, mapping, quadrature, output_data);
376  std::move(data)),
377  update_flags,
378  quadrature);
379 }
380 
381 
382 template <int dim, int spacedim>
383 std::unique_ptr<typename FiniteElement<dim, spacedim>::InternalDataBase>
385  const UpdateFlags update_flags,
386  const Mapping<dim, spacedim> &mapping,
387  const Quadrature<dim - 1> & quadrature,
389  spacedim>
390  &output_data) const
391 {
392  auto data =
393  fe_system->get_subface_data(update_flags, mapping, quadrature, output_data);
396  std::move(data)),
397  update_flags,
398  quadrature);
399 }
400 
401 
402 template <int dim, int spacedim>
403 std::unique_ptr<typename FiniteElement<dim, spacedim>::InternalDataBase>
405  const UpdateFlags flags,
406  const Mapping<dim, spacedim> &mapping,
407  const Quadrature<dim> & quadrature,
409  &output_data) const
410 {
411  auto data = fe_system->get_data(flags, mapping, quadrature, output_data);
414  std::move(data)),
415  flags,
416  quadrature);
417 }
418 
419 
420 template <int dim, int spacedim>
421 void
423  const std::vector<const FiniteElement<dim, spacedim> *> &fes,
424  const std::vector<unsigned int> & multiplicities)
425 {
426  Assert(fes.size() == multiplicities.size(),
427  ExcDimensionMismatch(fes.size(), multiplicities.size()));
428 
429  // Note that we need to skip every fe with multiplicity 0 in the following
430  // block of code
431  this->base_to_block_indices.reinit(0, 0);
432 
433  for (unsigned int i = 0; i < fes.size(); i++)
434  if (multiplicities[i] > 0)
435  this->base_to_block_indices.push_back(multiplicities[i]);
436 
437  {
438  // If the system is not primitive, these have not been initialized by
439  // FiniteElement
440  this->system_to_component_table.resize(this->dofs_per_cell);
441  this->face_system_to_component_table.resize(this->dofs_per_face);
442 
446  *this,
447  false);
448 
452  *this,
453  false);
454  }
455 
456  // restriction and prolongation matrices are built on demand
457 
458  // now set up the interface constraints for h-refinement.
459  // take them from fe_system:
460  this->interface_constraints = fe_system->interface_constraints;
461 
462  // if we just wrap another FE (i.e. use FE_Nothing as a second FE)
463  // then it makes sense to have support points.
464  // However, functions like interpolate_boundary_values() need all FEs inside
465  // FECollection to be able to provide support points irrespectively whether
466  // this FE sits on the boundary or not. Thus for moment just copy support
467  // points from fe system:
468  {
469  this->unit_support_points = fe_system->unit_support_points;
470  this->unit_face_support_points = fe_system->unit_face_support_points;
471  }
472 
473  // take adjust_quad_dof_index_for_face_orientation_table from FESystem:
474  {
476  fe_system->adjust_line_dof_index_for_line_orientation_table;
477  }
478 }
479 
480 
481 template <int dim, int spacedim>
482 std::string
484 {
485  std::ostringstream namebuf;
486 
487  namebuf << "FE_Enriched<" << Utilities::dim_string(dim, spacedim) << ">[";
488  for (unsigned int i = 0; i < this->n_base_elements(); ++i)
489  {
490  namebuf << base_element(i).get_name();
491  if (this->element_multiplicity(i) != 1)
492  namebuf << '^' << this->element_multiplicity(i);
493  if (i != this->n_base_elements() - 1)
494  namebuf << '-';
495  }
496  namebuf << ']';
497 
498  return namebuf.str();
499 }
500 
501 
502 template <int dim, int spacedim>
504 FE_Enriched<dim, spacedim>::base_element(const unsigned int index) const
505 {
506  return fe_system->base_element(index);
507 }
508 
509 
510 template <int dim, int spacedim>
511 void
513  const typename Triangulation<dim, spacedim>::cell_iterator &cell,
514  const CellSimilarity::Similarity cell_similarity,
515  const Quadrature<dim> & quadrature,
516  const Mapping<dim, spacedim> & mapping,
517  const typename Mapping<dim, spacedim>::InternalDataBase & mapping_internal,
518  const ::internal::FEValuesImplementation::MappingRelatedData<dim,
519  spacedim>
520  & mapping_data,
521  const typename FiniteElement<dim, spacedim>::InternalDataBase &fe_internal,
523  &output_data) const
524 {
525  Assert(dynamic_cast<const InternalData *>(&fe_internal) != nullptr,
526  ExcInternalError());
527  const InternalData &fe_data = static_cast<const InternalData &>(fe_internal);
528 
529  // call FESystem's method to fill everything without enrichment function
530  fe_system->fill_fe_values(cell,
531  cell_similarity,
532  quadrature,
533  mapping,
534  mapping_internal,
535  mapping_data,
536  *fe_data.fesystem_data,
537  output_data);
538 
539  if (is_enriched)
541  quadrature, fe_data, mapping_data, cell, output_data);
542 }
543 
544 
545 template <int dim, int spacedim>
546 void
548  const typename Triangulation<dim, spacedim>::cell_iterator &cell,
549  const unsigned int face_no,
550  const Quadrature<dim - 1> & quadrature,
551  const Mapping<dim, spacedim> & mapping,
552  const typename Mapping<dim, spacedim>::InternalDataBase & mapping_internal,
553  const ::internal::FEValuesImplementation::MappingRelatedData<dim,
554  spacedim>
555  & mapping_data,
556  const typename FiniteElement<dim, spacedim>::InternalDataBase &fe_internal,
558  &output_data) const
559 {
560  Assert(dynamic_cast<const InternalData *>(&fe_internal) != nullptr,
561  ExcInternalError());
562  const InternalData &fe_data = static_cast<const InternalData &>(fe_internal);
563 
564  // call FESystem's method to fill everything without enrichment function
565  fe_system->fill_fe_face_values(cell,
566  face_no,
567  quadrature,
568  mapping,
569  mapping_internal,
570  mapping_data,
571  *fe_data.fesystem_data,
572  output_data);
573 
574  if (is_enriched)
576  quadrature, fe_data, mapping_data, cell, output_data);
577 }
578 
579 
580 template <int dim, int spacedim>
581 void
583  const typename Triangulation<dim, spacedim>::cell_iterator &cell,
584  const unsigned int face_no,
585  const unsigned int sub_no,
586  const Quadrature<dim - 1> & quadrature,
587  const Mapping<dim, spacedim> & mapping,
588  const typename Mapping<dim, spacedim>::InternalDataBase & mapping_internal,
589  const ::internal::FEValuesImplementation::MappingRelatedData<dim,
590  spacedim>
591  & mapping_data,
592  const typename FiniteElement<dim, spacedim>::InternalDataBase &fe_internal,
594  &output_data) const
595 {
596  Assert(dynamic_cast<const InternalData *>(&fe_internal) != nullptr,
597  ExcInternalError());
598  const InternalData &fe_data = static_cast<const InternalData &>(fe_internal);
599 
600  // call FESystem's method to fill everything without enrichment function
601  fe_system->fill_fe_subface_values(cell,
602  face_no,
603  sub_no,
604  quadrature,
605  mapping,
606  mapping_internal,
607  mapping_data,
608  *fe_data.fesystem_data,
609  output_data);
610 
611  if (is_enriched)
613  quadrature, fe_data, mapping_data, cell, output_data);
614 }
615 
616 
617 template <int dim, int spacedim>
618 template <int dim_1>
619 void
621  const Quadrature<dim_1> &quadrature,
622  const InternalData & fe_data,
624  & mapping_data,
625  const typename Triangulation<dim, spacedim>::cell_iterator &cell,
627  &output_data) const
628 {
629  // mapping_data will contain quadrature points on the real element.
630  // fe_internal is needed to get update flags
631  // finally, output_data should store all the results we need.
632 
633  // Either dim_1==dim
634  // (fill_fe_values) or dim_1==dim-1
635  // (fill_fe_(sub)face_values)
636  Assert(dim_1 == dim || dim_1 == dim - 1, ExcInternalError());
637  const UpdateFlags flags = fe_data.update_each;
638 
639  const unsigned int n_q_points = quadrature.size();
640 
641  // First, populate output_data object (that shall hold everything requested
642  // such as shape value, gradients, hessians, etc) from each base element. That
643  // is almost identical to FESystem::compute_fill_one_base(), the difference
644  // being that we do it irrespectively of cell_similarity and use
645  // base_fe_data.update_flags
646 
647  // TODO: do we need it only for dim_1 == dim (i.e. fill_fe_values)?
648  if (dim_1 == dim)
649  for (unsigned int base_no = 1; base_no < this->n_base_elements(); base_no++)
650  {
651  const FiniteElement<dim, spacedim> &base_fe = base_element(base_no);
652  typename FiniteElement<dim, spacedim>::InternalDataBase &base_fe_data =
653  fe_data.get_fe_data(base_no);
655  spacedim>
656  &base_data = fe_data.get_fe_output_object(base_no);
657 
658  const UpdateFlags base_flags = base_fe_data.update_each;
659 
660  for (unsigned int system_index = 0; system_index < this->dofs_per_cell;
661  ++system_index)
662  if (this->system_to_base_table[system_index].first.first == base_no)
663  {
664  const unsigned int base_index =
665  this->system_to_base_table[system_index].second;
666  Assert(base_index < base_fe.dofs_per_cell, ExcInternalError());
667 
668  // now copy. if the shape function is primitive, then there
669  // is only one value to be copied, but for non-primitive
670  // elements, there might be more values to be copied
671  //
672  // so, find out from which index to take this one value, and
673  // to which index to put
674  unsigned int out_index = 0;
675  for (unsigned int i = 0; i < system_index; ++i)
676  out_index += this->n_nonzero_components(i);
677  unsigned int in_index = 0;
678  for (unsigned int i = 0; i < base_index; ++i)
679  in_index += base_fe.n_nonzero_components(i);
680 
681  // then loop over the number of components to be copied
682  Assert(this->n_nonzero_components(system_index) ==
683  base_fe.n_nonzero_components(base_index),
684  ExcInternalError());
685  for (unsigned int s = 0;
686  s < this->n_nonzero_components(system_index);
687  ++s)
688  {
689  if (base_flags & update_values)
690  for (unsigned int q = 0; q < n_q_points; ++q)
691  output_data.shape_values[out_index + s][q] =
692  base_data.shape_values(in_index + s, q);
693 
694  if (base_flags & update_gradients)
695  for (unsigned int q = 0; q < n_q_points; ++q)
696  output_data.shape_gradients[out_index + s][q] =
697  base_data.shape_gradients[in_index + s][q];
698 
699  if (base_flags & update_hessians)
700  for (unsigned int q = 0; q < n_q_points; ++q)
701  output_data.shape_hessians[out_index + s][q] =
702  base_data.shape_hessians[in_index + s][q];
703  }
704  }
705  }
706 
707  Assert(base_no_mult_local_enriched_dofs.size() == fe_data.enrichment.size(),
709  fe_data.enrichment.size()));
710  // calculate hessians, gradients and values for each function
711  for (unsigned int base_no = 1; base_no < this->n_base_elements(); base_no++)
712  {
713  Assert(
714  base_no_mult_local_enriched_dofs[base_no].size() ==
715  fe_data.enrichment[base_no].size(),
717  fe_data.enrichment[base_no].size()));
718  for (unsigned int m = 0;
719  m < base_no_mult_local_enriched_dofs[base_no].size();
720  m++)
721  {
722  // Avoid evaluating quadrature points if no dofs are assigned. This
723  // happens when FE_Nothing is used together with other FE (i.e. FE_Q)
724  // as enrichments.
725  if (base_no_mult_local_enriched_dofs[base_no][m].size() == 0)
726  continue;
727 
728  Assert(enrichments[base_no - 1][m](cell) != nullptr,
729  ExcMessage("The pointer to the enrichment function is NULL"));
730 
731  Assert(enrichments[base_no - 1][m](cell)->n_components == 1,
732  ExcMessage(
733  "Only scalar-valued enrichment functions are allowed"));
734 
735  if (flags & update_hessians)
736  {
737  Assert(fe_data.enrichment[base_no][m].hessians.size() ==
738  n_q_points,
740  fe_data.enrichment[base_no][m].hessians.size(),
741  n_q_points));
742  for (unsigned int q = 0; q < n_q_points; q++)
743  fe_data.enrichment[base_no][m].hessians[q] =
744  enrichments[base_no - 1][m](cell)->hessian(
745  mapping_data.quadrature_points[q]);
746  }
747 
748  if (flags & update_gradients)
749  {
750  Assert(fe_data.enrichment[base_no][m].gradients.size() ==
751  n_q_points,
753  fe_data.enrichment[base_no][m].gradients.size(),
754  n_q_points));
755  for (unsigned int q = 0; q < n_q_points; q++)
756  fe_data.enrichment[base_no][m].gradients[q] =
757  enrichments[base_no - 1][m](cell)->gradient(
758  mapping_data.quadrature_points[q]);
759  }
760 
761  if (flags & update_values)
762  {
763  Assert(fe_data.enrichment[base_no][m].values.size() == n_q_points,
765  fe_data.enrichment[base_no][m].values.size(),
766  n_q_points));
767  for (unsigned int q = 0; q < n_q_points; q++)
768  fe_data.enrichment[base_no][m].values[q] =
769  enrichments[base_no - 1][m](cell)->value(
770  mapping_data.quadrature_points[q]);
771  }
772  }
773  }
774 
775  // Finally, update the standard data stored in output_data
776  // by expanding the product rule for enrichment function.
777  // note that the order if important, namely
778  // output_data.shape_XYZ contains values of standard FEM and we overwrite
779  // it with the updated one in the following order: hessians -> gradients ->
780  // values
781  if (flags & update_hessians)
782  {
783  for (unsigned int base_no = 1; base_no < this->n_base_elements();
784  base_no++)
785  {
786  for (unsigned int m = 0;
787  m < base_no_mult_local_enriched_dofs[base_no].size();
788  m++)
789  for (unsigned int i = 0;
790  i < base_no_mult_local_enriched_dofs[base_no][m].size();
791  i++)
792  {
793  const unsigned int enriched_dof =
794  base_no_mult_local_enriched_dofs[base_no][m][i];
795  for (unsigned int q = 0; q < n_q_points; ++q)
796  {
797  const Tensor<2, spacedim> grad_grad = outer_product(
798  output_data.shape_gradients[enriched_dof][q],
799  fe_data.enrichment[base_no][m].gradients[q]);
800  const Tensor<2, spacedim, double> sym_grad_grad =
801  symmetrize(grad_grad) * 2.0; // symmetrize does [s+s^T]/2
802 
803  output_data.shape_hessians[enriched_dof][q] *=
804  fe_data.enrichment[base_no][m].values[q];
805  output_data.shape_hessians[enriched_dof][q] +=
806  sym_grad_grad +
807  output_data.shape_values[enriched_dof][q] *
808  fe_data.enrichment[base_no][m].hessians[q];
809  }
810  }
811  }
812  }
813 
814  if (flags & update_gradients)
815  for (unsigned int base_no = 1; base_no < this->n_base_elements(); base_no++)
816  {
817  for (unsigned int m = 0;
818  m < base_no_mult_local_enriched_dofs[base_no].size();
819  m++)
820  for (unsigned int i = 0;
821  i < base_no_mult_local_enriched_dofs[base_no][m].size();
822  i++)
823  {
824  const unsigned int enriched_dof =
825  base_no_mult_local_enriched_dofs[base_no][m][i];
826  for (unsigned int q = 0; q < n_q_points; ++q)
827  {
828  output_data.shape_gradients[enriched_dof][q] *=
829  fe_data.enrichment[base_no][m].values[q];
830  output_data.shape_gradients[enriched_dof][q] +=
831  output_data.shape_values[enriched_dof][q] *
832  fe_data.enrichment[base_no][m].gradients[q];
833  }
834  }
835  }
836 
837  if (flags & update_values)
838  for (unsigned int base_no = 1; base_no < this->n_base_elements(); base_no++)
839  {
840  for (unsigned int m = 0;
841  m < base_no_mult_local_enriched_dofs[base_no].size();
842  m++)
843  for (unsigned int i = 0;
844  i < base_no_mult_local_enriched_dofs[base_no][m].size();
845  i++)
846  {
847  const unsigned int enriched_dof =
848  base_no_mult_local_enriched_dofs[base_no][m][i];
849  for (unsigned int q = 0; q < n_q_points; ++q)
850  {
851  output_data.shape_values[enriched_dof][q] *=
852  fe_data.enrichment[base_no][m].values[q];
853  }
854  }
855  }
856 }
857 
858 
859 template <int dim, int spacedim>
862 {
863  return *fe_system;
864 }
865 
866 
867 template <int dim, int spacedim>
868 bool
870 {
871  return true;
872 }
873 
874 
875 template <int dim, int spacedim>
876 void
878  const FiniteElement<dim, spacedim> &source,
879  FullMatrix<double> & matrix) const
880 {
881  if (const FE_Enriched<dim, spacedim> *fe_enr_other =
882  dynamic_cast<const FE_Enriched<dim, spacedim> *>(&source))
883  {
884  fe_system->get_face_interpolation_matrix(fe_enr_other->get_fe_system(),
885  matrix);
886  }
887  else
888  {
889  AssertThrow(
890  false,
891  (typename FiniteElement<dim,
892  spacedim>::ExcInterpolationNotImplemented()));
893  }
894 }
895 
896 
897 template <int dim, int spacedim>
898 void
900  const FiniteElement<dim, spacedim> &source,
901  const unsigned int subface,
902  FullMatrix<double> & matrix) const
903 {
904  if (const FE_Enriched<dim, spacedim> *fe_enr_other =
905  dynamic_cast<const FE_Enriched<dim, spacedim> *>(&source))
906  {
907  fe_system->get_subface_interpolation_matrix(fe_enr_other->get_fe_system(),
908  subface,
909  matrix);
910  }
911  else
912  {
913  AssertThrow(
914  false,
915  (typename FiniteElement<dim,
916  spacedim>::ExcInterpolationNotImplemented()));
917  }
918 }
919 
920 
921 template <int dim, int spacedim>
922 std::vector<std::pair<unsigned int, unsigned int>>
924  const FiniteElement<dim, spacedim> &fe_other) const
925 {
926  if (const FE_Enriched<dim, spacedim> *fe_enr_other =
927  dynamic_cast<const FE_Enriched<dim, spacedim> *>(&fe_other))
928  {
929  return fe_system->hp_vertex_dof_identities(fe_enr_other->get_fe_system());
930  }
931  else
932  {
933  Assert(false, ExcNotImplemented());
934  return std::vector<std::pair<unsigned int, unsigned int>>();
935  }
936 }
937 
938 
939 template <int dim, int spacedim>
940 std::vector<std::pair<unsigned int, unsigned int>>
942  const FiniteElement<dim, spacedim> &fe_other) const
943 {
944  if (const FE_Enriched<dim, spacedim> *fe_enr_other =
945  dynamic_cast<const FE_Enriched<dim, spacedim> *>(&fe_other))
946  {
947  return fe_system->hp_line_dof_identities(fe_enr_other->get_fe_system());
948  }
949  else
950  {
951  Assert(false, ExcNotImplemented());
952  return std::vector<std::pair<unsigned int, unsigned int>>();
953  }
954 }
955 
956 
957 template <int dim, int spacedim>
958 std::vector<std::pair<unsigned int, unsigned int>>
960  const FiniteElement<dim, spacedim> &fe_other) const
961 {
962  if (const FE_Enriched<dim, spacedim> *fe_enr_other =
963  dynamic_cast<const FE_Enriched<dim, spacedim> *>(&fe_other))
964  {
965  return fe_system->hp_quad_dof_identities(fe_enr_other->get_fe_system());
966  }
967  else
968  {
969  Assert(false, ExcNotImplemented());
970  return std::vector<std::pair<unsigned int, unsigned int>>();
971  }
972 }
973 
974 
975 template <int dim, int spacedim>
978  const FiniteElement<dim, spacedim> &fe_other) const
979 {
980  // need to decide which element constrain another.
981  // for example Q(2) dominate Q(4) and thus some DoFs of Q(4) will be
982  // constrained. If we have Q(2) and Q(4)+POU, then it's clear that Q(2)
983  // dominates, namely our DoFs will be constrained to make field continuous.
984  // However, we need to check for situations like Q(4) vs Q(2)+POU.
985  // In that case the domination for the underlying FEs should be the other way,
986  // but this implies that we can't constrain POU dofs to make the field
987  // continuous. In that case, through an error
988 
989  // if it's also enriched, do domination based on each one's FESystem
990  if (const FE_Enriched<dim, spacedim> *fe_enr_other =
991  dynamic_cast<const FE_Enriched<dim, spacedim> *>(&fe_other))
992  {
993  return fe_system->compare_for_face_domination(
994  fe_enr_other->get_fe_system());
995  }
996  else
997  {
998  Assert(false, ExcNotImplemented());
1000  }
1001 }
1002 
1003 template <int dim, int spacedim>
1004 const FullMatrix<double> &
1006  const unsigned int child,
1007  const RefinementCase<dim> &refinement_case) const
1008 {
1009  return fe_system->get_prolongation_matrix(child, refinement_case);
1010 }
1011 
1012 
1013 template <int dim, int spacedim>
1014 const FullMatrix<double> &
1016  const unsigned int child,
1017  const RefinementCase<dim> &refinement_case) const
1018 {
1019  return fe_system->get_restriction_matrix(child, refinement_case);
1020 }
1021 
1022 
1023 /* ----------------------- FESystem::InternalData ------------------- */
1024 
1025 
1026 template <int dim, int spacedim>
1028  std::unique_ptr<typename FESystem<dim, spacedim>::InternalData> fesystem_data)
1029  : fesystem_data(std::move(fesystem_data))
1030 {}
1031 
1032 
1033 template <int dim, int spacedim>
1036  const unsigned int base_no) const
1037 {
1038  return fesystem_data->get_fe_data(base_no);
1039 }
1040 
1041 
1042 template <int dim, int spacedim>
1045  const unsigned int base_no) const
1046 {
1047  return fesystem_data->get_fe_output_object(base_no);
1048 }
1049 
1050 
1051 // explicit instantiations
1052 #include "fe_enriched.inst"
1053 
1054 DEAL_II_NAMESPACE_CLOSE
Shape function values.
Definition: tria.h:71
virtual const FiniteElement< dim, spacedim > & base_element(const unsigned int index) const override
Definition: fe_enriched.cc:504
virtual std::vector< std::pair< unsigned int, unsigned int > > hp_line_dof_identities(const FiniteElement< dim, spacedim > &fe_other) const override
Definition: fe_enriched.cc:941
virtual void get_face_interpolation_matrix(const FiniteElement< dim, spacedim > &source, FullMatrix< double > &matrix) const override
Definition: fe_enriched.cc:877
FullMatrix< double > interface_constraints
Definition: fe.h:2445
virtual const FullMatrix< double > & get_restriction_matrix(const unsigned int child, const RefinementCase< dim > &refinement_case=RefinementCase< dim >::isotropic_refinement) const override
InternalData(std::unique_ptr< typename FESystem< dim, spacedim >::InternalData > fesystem_data)
FE_Enriched(const FiniteElement< dim, spacedim > &fe_base, const FiniteElement< dim, spacedim > &fe_enriched, const Function< spacedim > *enrichment_function)
Definition: fe_enriched.cc:145
const std::vector< std::vector< std::function< const Function< spacedim > *(const typename Triangulation< dim, spacedim >::cell_iterator &)> > > get_enrichments() const
Definition: fe_enriched.cc:262
bool is_dominating() const
Definition: fe_nothing.cc:178
SymmetricTensor< 4, dim, Number > outer_product(const SymmetricTensor< 2, dim, Number > &t1, const SymmetricTensor< 2, dim, Number > &t2)
virtual FiniteElementDomination::Domination compare_for_face_domination(const FiniteElement< dim, spacedim > &fe_other) const override
Definition: fe_enriched.cc:977
std::vector< std::pair< std::pair< unsigned int, unsigned int >, unsigned int > > component_to_base_table
Definition: fe.h:2579
std::vector< std::vector< EnrichmentValues > > enrichment
Definition: fe_enriched.h:549
std::unique_ptr< typename FiniteElement< dim, spacedim >::InternalDataBase > setup_data(std::unique_ptr< typename FESystem< dim, spacedim >::InternalData > fes_data, const UpdateFlags flags, const Quadrature< dim_1 > &quadrature) const
Definition: fe_enriched.cc:325
std::vector< Point< dim-1 > > unit_face_support_points
Definition: fe.h:2464
STL namespace.
Transformed quadrature points.
#define AssertThrow(cond, exc)
Definition: exceptions.h:1329
static::ExceptionBase & ExcInterpolationNotImplemented()
const bool is_enriched
Definition: fe_enriched.h:581
std::unique_ptr< To > dynamic_unique_cast(std::unique_ptr< From > &&p)
Definition: utilities.h:630
void multiply_by_enrichment(const Quadrature< dim_1 > &quadrature, const InternalData &fe_data, const internal::FEValuesImplementation::MappingRelatedData< dim, spacedim > &mapping_data, const typename Triangulation< dim, spacedim >::cell_iterator &cell, internal::FEValuesImplementation::FiniteElementRelatedData< dim, spacedim > &output_data) const
Definition: fe_enriched.cc:620
std::vector< Point< dim > > unit_support_points
Definition: fe.h:2457
virtual std::vector< std::pair< unsigned int, unsigned int > > hp_vertex_dof_identities(const FiniteElement< dim, spacedim > &fe_other) const override
Definition: fe_enriched.cc:923
virtual std::string get_name() const override
Definition: fe_enriched.cc:483
const std::vector< std::vector< std::function< const Function< spacedim > *(const typename Triangulation< dim, spacedim >::cell_iterator &)> > > enrichments
Definition: fe_enriched.h:570
unsigned int element_multiplicity(const unsigned int index) const
Definition: fe.h:3111
unsigned int size() const
static::ExceptionBase & ExcMessage(std::string arg1)
void initialize(const std::vector< const FiniteElement< dim, spacedim > * > &fes, const std::vector< unsigned int > &multiplicities)
Definition: fe_enriched.cc:422
void build_cell_tables(std::vector< std::pair< std::pair< unsigned int, unsigned int >, unsigned int >> &system_to_base_table, std::vector< std::pair< unsigned int, unsigned int >> &system_to_component_table, std::vector< std::pair< std::pair< unsigned int, unsigned int >, unsigned int >> &component_to_base_table, const FiniteElement< dim, spacedim > &finite_element, const bool do_tensor_product=true)
std::unique_ptr< typename FESystem< dim, spacedim >::InternalData > fesystem_data
Definition: fe_enriched.h:532
Third derivatives of shape functions.
const std::unique_ptr< const FESystem< dim, spacedim > > fe_system
Definition: fe_enriched.h:694
#define Assert(cond, exc)
Definition: exceptions.h:1227
UpdateFlags
unsigned int n_nonzero_components(const unsigned int i) const
Definition: fe.h:3275
static::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
Abstract base class for mapping classes.
Definition: dof_tools.h:57
void reinit(const unsigned int n_blocks, const size_type n_elements_per_block)
Definition: fe.h:42
virtual std::unique_ptr< typename FiniteElement< dim, spacedim >::InternalDataBase > get_data(const UpdateFlags flags, const Mapping< dim, spacedim > &mapping, const Quadrature< dim > &quadrature,::internal::FEValuesImplementation::FiniteElementRelatedData< dim, spacedim > &output_data) const override
Definition: fe_enriched.cc:404
unsigned int n_base_elements() const
Definition: fe.h:3102
SymmetricTensor< 2, dim, Number > symmetrize(const Tensor< 2, dim, Number > &t)
unsigned int n_components() const
Second derivatives of shape functions.
internal::FEValuesImplementation::FiniteElementRelatedData< dim, spacedim > & get_fe_output_object(const unsigned int base_no) const
virtual double shape_value(const unsigned int i, const Point< dim > &p) const override
Definition: fe_enriched.cc:270
std::string dim_string(const int dim, const int spacedim)
Definition: utilities.cc:170
virtual UpdateFlags requires_update_flags(const UpdateFlags update_flags) const override
Definition: fe_enriched.cc:301
const unsigned int dofs_per_cell
Definition: fe_base.h:297
std::vector< Point< spacedim > > quadrature_points
virtual const FullMatrix< double > & get_prolongation_matrix(const unsigned int child, const RefinementCase< dim > &refinement_case=RefinementCase< dim >::isotropic_refinement) const override
virtual void get_subface_interpolation_matrix(const FiniteElement< dim, spacedim > &source, const unsigned int subface, FullMatrix< double > &matrix) const override
Definition: fe_enriched.cc:899
Shape function gradients.
std::vector< std::vector< std::vector< unsigned int > > > base_no_mult_local_enriched_dofs
Definition: fe_enriched.h:559
std::vector< std::pair< unsigned int, unsigned int > > system_to_component_table
Definition: fe.h:2513
void push_back(const size_type size)
void build_face_tables(std::vector< std::pair< std::pair< unsigned int, unsigned int >, unsigned int >> &face_system_to_base_table, std::vector< std::pair< unsigned int, unsigned int >> &face_system_to_component_table, const FiniteElement< dim, spacedim > &finite_element, const bool do_tensor_product=true)
const unsigned int dofs_per_face
Definition: fe_base.h:290
std::vector< std::pair< std::pair< unsigned int, unsigned int >, unsigned int > > system_to_base_table
Definition: fe.h:2544
static::ExceptionBase & ExcNotImplemented()
std::vector< std::pair< unsigned int, unsigned int > > face_system_to_component_table
Definition: fe.h:2525
virtual std::unique_ptr< FiniteElement< dim, spacedim > > clone() const override
Definition: fe_enriched.cc:283
const FESystem< dim, spacedim > & get_fe_system() const
Definition: fe_enriched.cc:861
BlockIndices base_to_block_indices
Definition: fe.h:2556
std::vector< std::pair< std::pair< unsigned int, unsigned int >, unsigned int > > face_system_to_base_table
Definition: fe.h:2550
virtual std::vector< std::pair< unsigned int, unsigned int > > hp_quad_dof_identities(const FiniteElement< dim, spacedim > &fe_other) const override
Definition: fe_enriched.cc:959
virtual std::unique_ptr< typename FiniteElement< dim, spacedim >::InternalDataBase > get_subface_data(const UpdateFlags update_flags, const Mapping< dim, spacedim > &mapping, const Quadrature< dim-1 > &quadrature,::internal::FEValuesImplementation::FiniteElementRelatedData< dim, spacedim > &output_data) const override
Definition: fe_enriched.cc:384
unsigned int n_components(const DoFHandler< dim, spacedim > &dh)
std::vector< int > adjust_line_dof_index_for_line_orientation_table
Definition: fe.h:2508
FiniteElement< dim, spacedim >::InternalDataBase & get_fe_data(const unsigned int base_no) const
UpdateFlags update_each
Definition: fe.h:713
virtual bool hp_constraints_are_implemented() const override
Definition: fe_enriched.cc:869
virtual std::unique_ptr< typename FiniteElement< dim, spacedim >::InternalDataBase > get_face_data(const UpdateFlags update_flags, const Mapping< dim, spacedim > &mapping, const Quadrature< dim-1 > &quadrature,::internal::FEValuesImplementation::FiniteElementRelatedData< dim, spacedim > &output_data) const override
Definition: fe_enriched.cc:365
static::ExceptionBase & ExcInternalError()