Reference documentation for deal.II version 9.2.0
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
fe_nedelec_sz.cc
Go to the documentation of this file.
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2015 - 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 
17 
19 
21 
22 // Constructor:
23 template <int dim, int spacedim>
25  : FiniteElement<dim, dim>(
26  FiniteElementData<dim>(get_dpo_vector(order),
27  dim,
28  order + 1,
29  FiniteElementData<dim>::Hcurl),
30  std::vector<bool>(compute_num_dofs(order), true),
31  std::vector<ComponentMask>(compute_num_dofs(order),
32  std::vector<bool>(dim, true)))
33 {
34  Assert(dim >= 2, ExcImpossibleInDim(dim));
35 
37  // Set up the table converting components to base components. Since we have
38  // only one base element, everything remains zero except the component in the
39  // base, which is the component itself.
40  for (unsigned int comp = 0; comp < this->n_components(); ++comp)
41  {
42  this->component_to_base_table[comp].first.second = comp;
43  }
44 
45  // Generate the 1-D polynomial basis.
46  create_polynomials(order);
47 }
48 
49 
50 
51 // Shape functions:
52 template <int dim, int spacedim>
53 double
55  const Point<dim> & /*p*/) const
56 {
58  return 0.;
59 }
60 
61 
62 
63 template <int dim, int spacedim>
64 double
66  const unsigned int /*i*/,
67  const Point<dim> & /*p*/,
68  const unsigned int /*component*/) const
69 {
70  // Not implemented yet:
71  Assert(false, ExcNotImplemented());
72  return 0.;
73 }
74 
75 
76 
77 template <int dim, int spacedim>
79 FE_NedelecSZ<dim, spacedim>::shape_grad(const unsigned int /*i*/,
80  const Point<dim> & /*p*/) const
81 {
83  return Tensor<1, dim>();
84 }
85 
86 
87 
88 template <int dim, int spacedim>
91  const unsigned int /*i*/,
92  const Point<dim> & /*p*/,
93  const unsigned int /*component*/) const
94 {
95  Assert(false, ExcNotImplemented());
96  return Tensor<1, dim>();
97 }
98 
99 
100 
101 template <int dim, int spacedim>
104  const Point<dim> & /*p*/) const
105 {
107  return Tensor<2, dim>();
108 }
109 
110 
111 
112 template <int dim, int spacedim>
115  const unsigned int /*i*/,
116  const Point<dim> & /*p*/,
117  const unsigned int /*component*/) const
118 {
119  Assert(false, ExcNotImplemented());
120  return Tensor<2, dim>();
121 }
122 
123 
124 
125 template <int dim, int spacedim>
126 std::unique_ptr<typename ::FiniteElement<dim, spacedim>::InternalDataBase>
128  const UpdateFlags update_flags,
129  const Mapping<dim, spacedim> & /*mapping*/,
130  const Quadrature<dim> &quadrature,
132  spacedim>
133  & /*output_data*/) const
134 {
135  std::unique_ptr<
136  typename ::FiniteElement<dim, spacedim>::InternalDataBase>
137  data_ptr = std_cxx14::make_unique<InternalData>();
138  auto &data = dynamic_cast<InternalData &>(*data_ptr);
139  data.update_each = requires_update_flags(update_flags);
140 
141  // Useful quantities:
142  const unsigned int degree(this->degree - 1); // Note: FE holds input degree+1
143 
144  const unsigned int vertices_per_cell = GeometryInfo<dim>::vertices_per_cell;
145  const unsigned int lines_per_cell = GeometryInfo<dim>::lines_per_cell;
146  const unsigned int faces_per_cell = GeometryInfo<dim>::faces_per_cell;
147 
148  const unsigned int n_line_dofs = this->dofs_per_line * lines_per_cell;
149  const unsigned int n_face_dofs = this->dofs_per_quad * faces_per_cell;
150 
151  const UpdateFlags flags(data.update_each);
152  const unsigned int n_q_points = quadrature.size();
153 
154  // Resize the internal data storage:
155  data.sigma_imj_values.resize(
156  n_q_points,
157  std::vector<std::vector<double>>(vertices_per_cell,
158  std::vector<double>(vertices_per_cell)));
159 
160  data.sigma_imj_grads.resize(vertices_per_cell,
161  std::vector<std::vector<double>>(
162  vertices_per_cell, std::vector<double>(dim)));
163 
164  // Resize shape function arrays according to update flags:
165  if (flags & update_values)
166  {
167  data.shape_values.resize(this->dofs_per_cell,
168  std::vector<Tensor<1, dim>>(n_q_points));
169  }
170 
171  if (flags & update_gradients)
172  {
173  data.shape_grads.resize(this->dofs_per_cell,
174  std::vector<DerivativeForm<1, dim, dim>>(
175  n_q_points));
176  }
177  // Not implementing second derivatives yet:
178  if (flags & update_hessians)
179  {
180  Assert(false, ExcNotImplemented());
181  }
182 
183  std::vector<Point<dim>> p_list(n_q_points);
184  p_list = quadrature.get_points();
185 
186 
187  switch (dim)
188  {
189  case 2:
190  {
191  // Compute values of sigma & lambda and the sigma differences and
192  // lambda additions.
193  std::vector<std::vector<double>> sigma(
194  n_q_points, std::vector<double>(lines_per_cell));
195  std::vector<std::vector<double>> lambda(
196  n_q_points, std::vector<double>(lines_per_cell));
197 
198  for (unsigned int q = 0; q < n_q_points; ++q)
199  {
200  sigma[q][0] = (1.0 - p_list[q][0]) + (1.0 - p_list[q][1]);
201  sigma[q][1] = p_list[q][0] + (1.0 - p_list[q][1]);
202  sigma[q][2] = (1.0 - p_list[q][0]) + p_list[q][1];
203  sigma[q][3] = p_list[q][0] + p_list[q][1];
204 
205  lambda[q][0] = (1.0 - p_list[q][0]) * (1.0 - p_list[q][1]);
206  lambda[q][1] = p_list[q][0] * (1.0 - p_list[q][1]);
207  lambda[q][2] = (1.0 - p_list[q][0]) * p_list[q][1];
208  lambda[q][3] = p_list[q][0] * p_list[q][1];
209  for (unsigned int i = 0; i < vertices_per_cell; ++i)
210  {
211  for (unsigned int j = 0; j < vertices_per_cell; ++j)
212  {
213  data.sigma_imj_values[q][i][j] =
214  sigma[q][i] - sigma[q][j];
215  }
216  }
217  }
218 
219  // Calculate the gradient of sigma_imj_values[q][i][j] =
220  // sigma[q][i]-sigma[q][j]
221  // - this depends on the component and the direction of the
222  // corresponding edge.
223  // - the direction of the edge is determined by
224  // sigma_imj_sign[i][j].
225  // Helper arrays:
226  const int sigma_comp_signs[GeometryInfo<2>::vertices_per_cell][2] = {
227  {-1, -1}, {1, -1}, {-1, 1}, {1, 1}};
228  int sigma_imj_sign[vertices_per_cell][vertices_per_cell];
229  unsigned int sigma_imj_component[vertices_per_cell]
230  [vertices_per_cell];
231 
232  for (unsigned int i = 0; i < vertices_per_cell; ++i)
233  {
234  for (unsigned int j = 0; j < vertices_per_cell; ++j)
235  {
236  // sigma_imj_sign is the sign (+/-) of the coefficient of
237  // x/y/z in sigma_imj_values Due to the numbering of vertices
238  // on the reference element it is easy to find edges in the
239  // positive direction are from smaller to higher local vertex
240  // numbering.
241  sigma_imj_sign[i][j] = (i < j) ? -1 : 1;
242  sigma_imj_sign[i][j] = (i == j) ? 0 : sigma_imj_sign[i][j];
243 
244  // Now store the component which the sigma_i - sigma_j
245  // corresponds to:
246  sigma_imj_component[i][j] = 0;
247  for (unsigned int d = 0; d < dim; ++d)
248  {
249  int temp_imj =
250  sigma_comp_signs[i][d] - sigma_comp_signs[j][d];
251  // Only interested in the first non-zero
252  // as if there is a second, it can not be a valid edge.
253  if (temp_imj != 0)
254  {
255  sigma_imj_component[i][j] = d;
256  break;
257  }
258  }
259  // Can now calculate the gradient, only non-zero in the
260  // component given: Note some i,j combinations will be
261  // incorrect, but only on invalid edges.
262  data.sigma_imj_grads[i][j][sigma_imj_component[i][j]] =
263  2.0 * sigma_imj_sign[i][j];
264  }
265  }
266 
267  // Now compute the edge parameterisations for a single element
268  // with global numbering matching that of the reference element:
269 
270  // Resize the edge parameterisations
271  data.edge_sigma_values.resize(lines_per_cell);
272  data.edge_sigma_grads.resize(lines_per_cell);
273  for (unsigned int m = 0; m < lines_per_cell; ++m)
274  {
275  data.edge_sigma_values[m].resize(n_q_points);
276 
277  // sigma grads are constant in a cell (no need for quad points)
278  data.edge_sigma_grads[m].resize(dim);
279  }
280 
281  // Fill the values for edge lambda and edge sigma:
282  const unsigned int
283  edge_sigma_direction[GeometryInfo<2>::lines_per_cell] = {1,
284  1,
285  0,
286  0};
287 
288  data.edge_lambda_values.resize(lines_per_cell,
289  std::vector<double>(n_q_points));
290  data.edge_lambda_grads_2d.resize(lines_per_cell,
291  std::vector<double>(dim));
292  for (unsigned int m = 0; m < lines_per_cell; ++m)
293  {
294  // e1=max(reference vertex numbering on this edge)
295  // e2=min(reference vertex numbering on this edge)
296  // Which is guaranteed to be:
297  const unsigned int e1(
299  const unsigned int e2(
301  for (unsigned int q = 0; q < n_q_points; ++q)
302  {
303  data.edge_sigma_values[m][q] =
304  data.sigma_imj_values[q][e2][e1];
305  data.edge_lambda_values[m][q] = lambda[q][e1] + lambda[q][e2];
306  }
307 
308  data.edge_sigma_grads[m][edge_sigma_direction[m]] = -2.0;
309  }
310  data.edge_lambda_grads_2d[0] = {-1.0, 0.0};
311  data.edge_lambda_grads_2d[1] = {1.0, 0.0};
312  data.edge_lambda_grads_2d[2] = {0.0, -1.0};
313  data.edge_lambda_grads_2d[3] = {0.0, 1.0};
314 
315  // If the polynomial order is 0, then no more work to do:
316  if (degree < 1)
317  {
318  break;
319  }
320 
321  // Otherwise, we can compute the non-cell dependent shape functions.
322  //
323  // Note: the local dof numberings follow the usual order of lines ->
324  // faces -> cells
325  // (we have no vertex-based DoFs in this element).
326  // For a given cell we have:
327  // n_line_dofs = dofs_per_line*lines_per_cell.
328  // n_face_dofs = dofs_per_face*faces_per_cell.
329  // n_cell_dofs = dofs_per_quad (2D)
330  // = dofs_per_hex (3D)
331  //
332  // i.e. For the local dof numbering:
333  // the first line dof is 0,
334  // the first face dof is n_line_dofs,
335  // the first cell dof is n_line_dofs + n_face_dofs.
336  //
337  // On a line, DoFs are ordered first by line_dof and then line_index:
338  // i.e. line_dof_index = line_dof + line_index*(dofs_per_line)
339  //
340  // and similarly for faces:
341  // i.e. face_dof_index = face_dof + face_index*(dofs_per_face).
342  //
343  // HOWEVER, we have different types of DoFs on a line/face/cell.
344  // On a line we have two types, lowest order and higher order
345  // gradients.
346  // - The numbering is such the lowest order is first, then higher
347  // order.
348  // This is simple enough as there is only 1 lowest order and
349  // degree higher orders DoFs per line.
350  //
351  // On a 2D cell, we have 3 types: Type 1/2/3:
352  // - The ordering done by type:
353  // - Type 1: 0 <= i1,j1 < degree. degree^2 in total.
354  // Numbered: ij1 = i1 + j1*(degree). i.e. cell_dof_index
355  // = ij1.
356  // - Type 2: 0 <= i2,j2 < degree. degree^2 in total.
357  // Numbered: ij2 = i2 + j2*(degree). i.e. cell_dof_index
358  // = degree^2 + ij2
359  // - Type 3: 0 <= i3 < 2*degree. 2*degree in total.
360  // Numbered: ij3 = i3. i.e. cell_dof_index
361  // = 2*(degree^2) + ij3.
362  //
363  // These then fit into the local dof numbering described above:
364  // - local dof numberings are:
365  // line_dofs: local_dof = line_dof_index. 0 <= local_dof <
366  // dofs_per_line*lines_per_cell face_dofs: local_dof =
367  // n_line_dofs*lines_per_cell + face_dof_index. cell dofs: local_dof
368  // = n_lines_dof + n_face_dofs + cell_dof_index.
369  //
370  // The cell-based shape functions are:
371  //
372  // Type 1 (gradients):
373  // \phi^{C_{1}}_{ij) = grad( L_{i+2}(2x-1)L_{j+2}(2y-1) ),
374  //
375  // 0 <= i,j < degree.
376  //
377  // NOTE: The derivative produced by IntegratedLegendrePolynomials does
378  // not account for the
379  // (2*x-1) or (2*y-1) so we must take this into account when
380  // taking derivatives.
381  const unsigned int cell_type1_offset = n_line_dofs;
382 
383  // Type 2:
384  // \phi^{C_{2}}_{ij) = L'_{i+2}(2x-1) L_{j+2}(2y-1) \mathbf{e}_{x}
385  // - L_{i+2}(2x-1) L'_{j+2}(2y-1) \mathbf{e}_{y},
386  //
387  // 0 <= i,j < degree.
388  const unsigned int cell_type2_offset =
389  cell_type1_offset + degree * degree;
390 
391  // Type 3 (two subtypes):
392  // \phi^{C_{3}}_{j) = L_{j+2}(2y-1) \mathbf{e}_{x}
393  //
394  // \phi^{C_{3}}_{j+degree) = L_{j+2}(2x-1) \mathbf{e}_{y}
395  //
396  // 0 <= j < degree
397  const unsigned int cell_type3_offset1 =
398  cell_type2_offset + degree * degree;
399  const unsigned int cell_type3_offset2 = cell_type3_offset1 + degree;
400 
401  if (flags & (update_values | update_gradients))
402  {
403  // compute all points we must evaluate the 1d polynomials at:
404  std::vector<Point<dim>> cell_points(n_q_points);
405  for (unsigned int q = 0; q < n_q_points; ++q)
406  {
407  for (unsigned int d = 0; d < dim; ++d)
408  {
409  cell_points[q][d] = 2.0 * p_list[q][d] - 1.0;
410  }
411  }
412 
413  // Loop through quad points:
414  for (unsigned int q = 0; q < n_q_points; ++q)
415  {
416  // pre-compute values & required derivatives at this quad
417  // point (x,y): polyx = L_{i+2}(2x-1), polyy = L_{j+2}(2y-1),
418  //
419  // for each polyc[d], c=x,y, contains the d-th derivative with
420  // respect to the co-ordinate c.
421 
422  // We only need poly values and 1st derivative for
423  // update_values, but need the 2nd derivative too for
424  // update_gradients.
425  //
426  // Note that this will need to be updated if we're supporting
427  // update_hessians.
428  const unsigned int poly_length(
429  (flags & update_gradients) ? 3 : 2);
430 
431  std::vector<std::vector<double>> polyx(
432  degree, std::vector<double>(poly_length));
433  std::vector<std::vector<double>> polyy(
434  degree, std::vector<double>(poly_length));
435  for (unsigned int i = 0; i < degree; ++i)
436  {
437  // Compute all required 1d polynomials and their
438  // derivatives, starting at degree 2. e.g. to access
439  // L'_{3}(2x-1) use polyx[1][1].
440  IntegratedLegendrePolynomials[i + 2].value(
441  cell_points[q][0], polyx[i]);
442  IntegratedLegendrePolynomials[i + 2].value(
443  cell_points[q][1], polyy[i]);
444  }
445  // Now use these to compute the shape functions:
446  if (flags & update_values)
447  {
448  for (unsigned int j = 0; j < degree; ++j)
449  {
450  const unsigned int shift_j(j * degree);
451  for (unsigned int i = 0; i < degree; ++i)
452  {
453  const unsigned int shift_ij(i + shift_j);
454 
455  // Type 1:
456  const unsigned int dof_index1(cell_type1_offset +
457  shift_ij);
458  data.shape_values[dof_index1][q][0] =
459  2.0 * polyx[i][1] * polyy[j][0];
460  data.shape_values[dof_index1][q][1] =
461  2.0 * polyx[i][0] * polyy[j][1];
462 
463  // Type 2:
464  const unsigned int dof_index2(cell_type2_offset +
465  shift_ij);
466  data.shape_values[dof_index2][q][0] =
467  data.shape_values[dof_index1][q][0];
468  data.shape_values[dof_index2][q][1] =
469  -1.0 * data.shape_values[dof_index1][q][1];
470  }
471  // Type 3:
472  const unsigned int dof_index3_1(cell_type3_offset1 +
473  j);
474  data.shape_values[dof_index3_1][q][0] = polyy[j][0];
475  data.shape_values[dof_index3_1][q][1] = 0.0;
476 
477  const unsigned int dof_index3_2(cell_type3_offset2 +
478  j);
479  data.shape_values[dof_index3_2][q][0] = 0.0;
480  data.shape_values[dof_index3_2][q][1] = polyx[j][0];
481  }
482  }
483  if (flags & update_gradients)
484  {
485  for (unsigned int j = 0; j < degree; ++j)
486  {
487  const unsigned int shift_j(j * degree);
488  for (unsigned int i = 0; i < degree; ++i)
489  {
490  const unsigned int shift_ij(i + shift_j);
491 
492  // Type 1:
493  const unsigned int dof_index1(cell_type1_offset +
494  shift_ij);
495  data.shape_grads[dof_index1][q][0][0] =
496  4.0 * polyx[i][2] * polyy[j][0];
497  data.shape_grads[dof_index1][q][0][1] =
498  4.0 * polyx[i][1] * polyy[j][1];
499  data.shape_grads[dof_index1][q][1][0] =
500  data.shape_grads[dof_index1][q][0][1];
501  data.shape_grads[dof_index1][q][1][1] =
502  4.0 * polyx[i][0] * polyy[j][2];
503 
504  // Type 2:
505  const unsigned int dof_index2(cell_type2_offset +
506  shift_ij);
507  data.shape_grads[dof_index2][q][0][0] =
508  data.shape_grads[dof_index1][q][0][0];
509  data.shape_grads[dof_index2][q][0][1] =
510  data.shape_grads[dof_index1][q][0][1];
511  data.shape_grads[dof_index2][q][1][0] =
512  -1.0 * data.shape_grads[dof_index1][q][1][0];
513  data.shape_grads[dof_index2][q][1][1] =
514  -1.0 * data.shape_grads[dof_index1][q][1][1];
515  }
516  // Type 3:
517  const unsigned int dof_index3_1(cell_type3_offset1 +
518  j);
519  data.shape_grads[dof_index3_1][q][0][0] = 0.0;
520  data.shape_grads[dof_index3_1][q][0][1] =
521  2.0 * polyy[j][1];
522  data.shape_grads[dof_index3_1][q][1][0] = 0.0;
523  data.shape_grads[dof_index3_1][q][1][1] = 0.0;
524 
525  const unsigned int dof_index3_2(cell_type3_offset2 +
526  j);
527  data.shape_grads[dof_index3_2][q][0][0] = 0.0;
528  data.shape_grads[dof_index3_2][q][0][1] = 0.0;
529  data.shape_grads[dof_index3_2][q][1][0] =
530  2.0 * polyx[j][1];
531  data.shape_grads[dof_index3_2][q][1][1] = 0.0;
532  }
533  }
534  }
535  }
536  break;
537  }
538  case 3:
539  {
540  // Compute values of sigma & lambda and the sigma differences and
541  // lambda additions.
542  std::vector<std::vector<double>> sigma(
543  n_q_points, std::vector<double>(lines_per_cell));
544  std::vector<std::vector<double>> lambda(
545  n_q_points, std::vector<double>(lines_per_cell));
546  for (unsigned int q = 0; q < n_q_points; ++q)
547  {
548  sigma[q][0] = (1.0 - p_list[q][0]) + (1.0 - p_list[q][1]) +
549  (1 - p_list[q][2]);
550  sigma[q][1] =
551  p_list[q][0] + (1.0 - p_list[q][1]) + (1 - p_list[q][2]);
552  sigma[q][2] =
553  (1.0 - p_list[q][0]) + p_list[q][1] + (1 - p_list[q][2]);
554  sigma[q][3] = p_list[q][0] + p_list[q][1] + (1 - p_list[q][2]);
555  sigma[q][4] =
556  (1.0 - p_list[q][0]) + (1.0 - p_list[q][1]) + p_list[q][2];
557  sigma[q][5] = p_list[q][0] + (1.0 - p_list[q][1]) + p_list[q][2];
558  sigma[q][6] = (1.0 - p_list[q][0]) + p_list[q][1] + p_list[q][2];
559  sigma[q][7] = p_list[q][0] + p_list[q][1] + p_list[q][2];
560 
561  lambda[q][0] = (1.0 - p_list[q][0]) * (1.0 - p_list[q][1]) *
562  (1.0 - p_list[q][2]);
563  lambda[q][1] =
564  p_list[q][0] * (1.0 - p_list[q][1]) * (1.0 - p_list[q][2]);
565  lambda[q][2] =
566  (1.0 - p_list[q][0]) * p_list[q][1] * (1.0 - p_list[q][2]);
567  lambda[q][3] = p_list[q][0] * p_list[q][1] * (1.0 - p_list[q][2]);
568  lambda[q][4] =
569  (1.0 - p_list[q][0]) * (1.0 - p_list[q][1]) * p_list[q][2];
570  lambda[q][5] = p_list[q][0] * (1.0 - p_list[q][1]) * p_list[q][2];
571  lambda[q][6] = (1.0 - p_list[q][0]) * p_list[q][1] * p_list[q][2];
572  lambda[q][7] = p_list[q][0] * p_list[q][1] * p_list[q][2];
573 
574  // Compute values of sigma_imj = \sigma_{i} - \sigma_{j}
575  // and lambda_ipj = \lambda_{i} + \lambda_{j}.
576  for (unsigned int i = 0; i < vertices_per_cell; ++i)
577  {
578  for (unsigned int j = 0; j < vertices_per_cell; ++j)
579  {
580  data.sigma_imj_values[q][i][j] =
581  sigma[q][i] - sigma[q][j];
582  }
583  }
584  }
585 
586  // We now want some additional information about
587  // sigma_imj_values[q][i][j] = sigma[q][i]-sigma[q][j] In order to
588  // calculate values & derivatives of the shape functions we need to
589  // know:
590  // - The component the sigma_imj value corresponds to - this varies
591  // with i & j.
592  // - The gradient of the sigma_imj value
593  // - this depends on the component and the direction of the
594  // corresponding edge.
595  // - the direction of the edge is determined by
596  // sigma_imj_sign[i][j].
597  //
598  // Note that not every i,j combination is a valid edge (there are only
599  // 12 valid edges in 3D), but we compute them all as it simplifies
600  // things.
601 
602  // store the sign of each component x, y, z in the sigma list.
603  // can use this to fill in the sigma_imj_component data.
604  const int sigma_comp_signs[GeometryInfo<3>::vertices_per_cell][3] = {
605  {-1, -1, -1},
606  {1, -1, -1},
607  {-1, 1, -1},
608  {1, 1, -1},
609  {-1, -1, 1},
610  {1, -1, 1},
611  {-1, 1, 1},
612  {1, 1, 1}};
613 
614  int sigma_imj_sign[vertices_per_cell][vertices_per_cell];
615  unsigned int sigma_imj_component[vertices_per_cell]
616  [vertices_per_cell];
617 
618  for (unsigned int i = 0; i < vertices_per_cell; ++i)
619  {
620  for (unsigned int j = 0; j < vertices_per_cell; ++j)
621  {
622  // sigma_imj_sign is the sign (+/-) of the coefficient of
623  // x/y/z in sigma_imj. Due to the numbering of vertices on the
624  // reference element this is easy to work out because edges in
625  // the positive direction go from smaller to higher local
626  // vertex numbering.
627  sigma_imj_sign[i][j] = (i < j) ? -1 : 1;
628  sigma_imj_sign[i][j] = (i == j) ? 0 : sigma_imj_sign[i][j];
629 
630  // Now store the component which the sigma_i - sigma_j
631  // corresponds to:
632  sigma_imj_component[i][j] = 0;
633  for (unsigned int d = 0; d < dim; ++d)
634  {
635  int temp_imj =
636  sigma_comp_signs[i][d] - sigma_comp_signs[j][d];
637  // Only interested in the first non-zero
638  // as if there is a second, it will not be a valid edge.
639  if (temp_imj != 0)
640  {
641  sigma_imj_component[i][j] = d;
642  break;
643  }
644  }
645  // Can now calculate the gradient, only non-zero in the
646  // component given: Note some i,j combinations will be
647  // incorrect, but only on invalid edges.
648  data.sigma_imj_grads[i][j][sigma_imj_component[i][j]] =
649  2.0 * sigma_imj_sign[i][j];
650  }
651  }
652  // Now compute the edge parameterisations for a single element
653  // with global numbering matching that of the reference element:
654 
655  // resize the edge parameterisations
656  data.edge_sigma_values.resize(lines_per_cell);
657  data.edge_lambda_values.resize(lines_per_cell);
658  data.edge_sigma_grads.resize(lines_per_cell);
659  data.edge_lambda_grads_3d.resize(lines_per_cell);
660  data.edge_lambda_gradgrads_3d.resize(lines_per_cell);
661  for (unsigned int m = 0; m < lines_per_cell; ++m)
662  {
663  data.edge_sigma_values[m].resize(n_q_points);
664  data.edge_lambda_values[m].resize(n_q_points);
665 
666  // sigma grads are constant in a cell (no need for quad points)
667  data.edge_sigma_grads[m].resize(dim);
668 
669  data.edge_lambda_grads_3d[m].resize(n_q_points);
670  for (unsigned int q = 0; q < n_q_points; ++q)
671  {
672  data.edge_lambda_grads_3d[m][q].resize(dim);
673  }
674  // lambda_gradgrads are constant in a cell (no need for quad
675  // points)
676  data.edge_lambda_gradgrads_3d[m].resize(dim);
677  for (unsigned int d = 0; d < dim; ++d)
678  {
679  data.edge_lambda_gradgrads_3d[m][d].resize(dim);
680  }
681  }
682 
683  // Fill the values:
684  const unsigned int
685  edge_sigma_direction[GeometryInfo<3>::lines_per_cell] = {
686  1, 1, 0, 0, 1, 1, 0, 0, 2, 2, 2, 2};
687 
688  for (unsigned int m = 0; m < lines_per_cell; ++m)
689  {
690  // e1=max(reference vertex numbering on this edge)
691  // e2=min(reference vertex numbering on this edge)
692  // Which is guaranteed to be:
693  const unsigned int e1(
695  const unsigned int e2(
697 
698  for (unsigned int q = 0; q < n_q_points; ++q)
699  {
700  data.edge_sigma_values[m][q] =
701  data.sigma_imj_values[q][e2][e1];
702  data.edge_lambda_values[m][q] = lambda[q][e1] + lambda[q][e2];
703  }
704 
705  data.edge_sigma_grads[m][edge_sigma_direction[m]] = -2.0;
706  }
707  // edge_lambda_grads
708  for (unsigned int q = 0; q < n_q_points; ++q)
709  {
710  double x(p_list[q][0]);
711  double y(p_list[q][1]);
712  double z(p_list[q][2]);
713  data.edge_lambda_grads_3d[0][q] = {z - 1.0, 0.0, x - 1.0};
714  data.edge_lambda_grads_3d[1][q] = {1.0 - z, 0.0, -x};
715  data.edge_lambda_grads_3d[2][q] = {0.0, z - 1.0, y - 1.0};
716  data.edge_lambda_grads_3d[3][q] = {0.0, 1.0 - z, -y};
717  data.edge_lambda_grads_3d[4][q] = {-z, 0.0, 1.0 - x};
718  data.edge_lambda_grads_3d[5][q] = {z, 0.0, x};
719  data.edge_lambda_grads_3d[6][q] = {0.0, -z, 1.0 - y};
720  data.edge_lambda_grads_3d[7][q] = {0.0, z, y};
721  data.edge_lambda_grads_3d[8][q] = {y - 1.0, x - 1.0, 0.0};
722  data.edge_lambda_grads_3d[9][q] = {1.0 - y, -x, 0.0};
723  data.edge_lambda_grads_3d[10][q] = {-y, 1.0 - x, 0.0};
724  data.edge_lambda_grads_3d[11][q] = {y, x, 0.0};
725  }
726  // edge_lambda gradgrads:
727  const int edge_lambda_sign[GeometryInfo<3>::lines_per_cell] = {
728  1,
729  -1,
730  1,
731  -1,
732  -1,
733  1,
734  -1,
735  1,
736  1,
737  -1,
738  -1,
739  1}; // sign of the 2nd derivative for each edge.
740  const unsigned int
741  edge_lambda_directions[GeometryInfo<3>::lines_per_cell][2] = {
742  {0, 2},
743  {0, 2},
744  {1, 2},
745  {1, 2},
746  {0, 2},
747  {0, 2},
748  {1, 2},
749  {1, 2},
750  {0, 1},
751  {0, 1},
752  {0, 1},
753  {0, 1}}; // component which edge_lambda[m] depends on.
754  for (unsigned int m = 0; m < lines_per_cell; ++m)
755  {
756  data.edge_lambda_gradgrads_3d[m][edge_lambda_directions[m][0]]
757  [edge_lambda_directions[m][1]] =
758  edge_lambda_sign[m];
759  data.edge_lambda_gradgrads_3d[m][edge_lambda_directions[m][1]]
760  [edge_lambda_directions[m][0]] =
761  edge_lambda_sign[m];
762  }
763  // Precomputation for higher order shape functions,
764  // and the face parameterisation.
765  if (degree > 0)
766  {
767  // resize required data:
768  data.face_lambda_values.resize(faces_per_cell);
769  data.face_lambda_grads.resize(faces_per_cell);
770  // for face-based shape functions:
771  for (unsigned int m = 0; m < faces_per_cell; ++m)
772  {
773  data.face_lambda_values[m].resize(n_q_points);
774  data.face_lambda_grads[m].resize(3);
775  }
776  // Fill in the values (these don't change between cells).
777  for (unsigned int q = 0; q < n_q_points; ++q)
778  {
779  double x(p_list[q][0]);
780  double y(p_list[q][1]);
781  double z(p_list[q][2]);
782  data.face_lambda_values[0][q] = 1.0 - x;
783  data.face_lambda_values[1][q] = x;
784  data.face_lambda_values[2][q] = 1.0 - y;
785  data.face_lambda_values[3][q] = y;
786  data.face_lambda_values[4][q] = 1.0 - z;
787  data.face_lambda_values[5][q] = z;
788  }
789  // gradients are constant:
790  data.face_lambda_grads[0] = {-1.0, 0.0, 0.0};
791  data.face_lambda_grads[1] = {1.0, 0.0, 0.0};
792  data.face_lambda_grads[2] = {0.0, -1.0, 0.0};
793  data.face_lambda_grads[3] = {0.0, 1.0, 0.0};
794  data.face_lambda_grads[4] = {0.0, 0.0, -1.0};
795  data.face_lambda_grads[5] = {0.0, 0.0, 1.0};
796 
797  // for cell-based shape functions:
798  // these don't depend on the cell, so can precompute all here:
799  if (flags & (update_values | update_gradients))
800  {
801  // Cell-based shape functions:
802  //
803  // Type-1 (gradients):
804  // \phi^{C_{1}}_{ijk} = grad(
805  // L_{i+2}(2x-1)L_{j+2}(2y-1)L_{k+2}(2z-1) ),
806  //
807  // 0 <= i,j,k < degree. (in a group of degree*degree*degree)
808  const unsigned int cell_type1_offset(n_line_dofs +
809  n_face_dofs);
810  // Type-2:
811  //
812  // \phi^{C_{2}}_{ijk} = diag(1, -1, 1)\phi^{C_{1}}_{ijk}
813  // \phi^{C_{2}}_{ijk + p^3} = diag(1, -1,
814  // -1)\phi^{C_{1}}_{ijk}
815  //
816  // 0 <= i,j,k < degree. (subtypes in groups of
817  // degree*degree*degree)
818  //
819  // here we order so that all of subtype 1 comes first, then
820  // subtype 2.
821  const unsigned int cell_type2_offset1(
822  cell_type1_offset + degree * degree * degree);
823  const unsigned int cell_type2_offset2(
824  cell_type2_offset1 + degree * degree * degree);
825  // Type-3
826  // \phi^{C_{3}}_{jk} = L_{j+2}(2y-1)L_{k+2}(2z-1)e_{x}
827  // \phi^{C_{3}}_{ik} = L_{i+2}(2x-1)L_{k+2}(2z-1)e_{y}
828  // \phi^{C_{3}}_{ij} = L_{i+2}(2x-1)L_{j+2}(2y-1)e_{z}
829  //
830  // 0 <= i,j,k < degree. (subtypes in groups of degree*degree)
831  //
832  // again we order so we compute all of subtype 1 first, then
833  // subtype 2, etc.
834  const unsigned int cell_type3_offset1(
835  cell_type2_offset2 + degree * degree * degree);
836  const unsigned int cell_type3_offset2(cell_type3_offset1 +
837  degree * degree);
838  const unsigned int cell_type3_offset3(cell_type3_offset2 +
839  degree * degree);
840 
841  // compute all points we must evaluate the 1d polynomials at:
842  std::vector<Point<dim>> cell_points(n_q_points);
843  for (unsigned int q = 0; q < n_q_points; ++q)
844  {
845  for (unsigned int d = 0; d < dim; ++d)
846  {
847  cell_points[q][d] = 2.0 * p_list[q][d] - 1.0;
848  }
849  }
850 
851 
852  // only need poly values and 1st derivative for update_values,
853  // but need 2nd derivative too for update_gradients.
854  const unsigned int poly_length(
855  (flags & update_gradients) ? 3 : 2);
856  // Loop through quad points:
857  for (unsigned int q = 0; q < n_q_points; ++q)
858  {
859  // pre-compute values & required derivatives at this quad
860  // point, (x,y,z): polyx = L_{i+2}(2x-1), polyy =
861  // L_{j+2}(2y-1), polyz = L_{k+2}(2z-1).
862  //
863  // for each polyc[d], c=x,y,z, contains the d-th
864  // derivative with respect to the co-ordinate c.
865  std::vector<std::vector<double>> polyx(
866  degree, std::vector<double>(poly_length));
867  std::vector<std::vector<double>> polyy(
868  degree, std::vector<double>(poly_length));
869  std::vector<std::vector<double>> polyz(
870  degree, std::vector<double>(poly_length));
871  for (unsigned int i = 0; i < degree; ++i)
872  {
873  // compute all required 1d polynomials for i
874  IntegratedLegendrePolynomials[i + 2].value(
875  cell_points[q][0], polyx[i]);
876  IntegratedLegendrePolynomials[i + 2].value(
877  cell_points[q][1], polyy[i]);
878  IntegratedLegendrePolynomials[i + 2].value(
879  cell_points[q][2], polyz[i]);
880  }
881  // Now use these to compute the shape functions:
882  if (flags & update_values)
883  {
884  for (unsigned int k = 0; k < degree; ++k)
885  {
886  const unsigned int shift_k(k * degree * degree);
887  const unsigned int shift_j(
888  k * degree); // Used below when subbing k for j
889  // (type 3)
890  for (unsigned int j = 0; j < degree; ++j)
891  {
892  const unsigned int shift_jk(j * degree +
893  shift_k);
894  for (unsigned int i = 0; i < degree; ++i)
895  {
896  const unsigned int shift_ijk(shift_jk +
897  i);
898 
899  // Type 1:
900  const unsigned int dof_index1(
901  cell_type1_offset + shift_ijk);
902 
903  data.shape_values[dof_index1][q][0] =
904  2.0 * polyx[i][1] * polyy[j][0] *
905  polyz[k][0];
906  data.shape_values[dof_index1][q][1] =
907  2.0 * polyx[i][0] * polyy[j][1] *
908  polyz[k][0];
909  data.shape_values[dof_index1][q][2] =
910  2.0 * polyx[i][0] * polyy[j][0] *
911  polyz[k][1];
912 
913  // Type 2:
914  const unsigned int dof_index2_1(
915  cell_type2_offset1 + shift_ijk);
916  const unsigned int dof_index2_2(
917  cell_type2_offset2 + shift_ijk);
918 
919  data.shape_values[dof_index2_1][q][0] =
920  data.shape_values[dof_index1][q][0];
921  data.shape_values[dof_index2_1][q][1] =
922  -1.0 *
923  data.shape_values[dof_index1][q][1];
924  data.shape_values[dof_index2_1][q][2] =
925  data.shape_values[dof_index1][q][2];
926 
927  data.shape_values[dof_index2_2][q][0] =
928  data.shape_values[dof_index1][q][0];
929  data.shape_values[dof_index2_2][q][1] =
930  -1.0 *
931  data.shape_values[dof_index1][q][1];
932  data.shape_values[dof_index2_2][q][2] =
933  -1.0 *
934  data.shape_values[dof_index1][q][2];
935  }
936  // Type 3: (note we re-use k and j for
937  // convenience):
938  const unsigned int shift_ij(
939  j + shift_j); // here we've subbed j for i,
940  // k for j.
941  const unsigned int dof_index3_1(
942  cell_type3_offset1 + shift_ij);
943  const unsigned int dof_index3_2(
944  cell_type3_offset2 + shift_ij);
945  const unsigned int dof_index3_3(
946  cell_type3_offset3 + shift_ij);
947 
948  data.shape_values[dof_index3_1][q][0] =
949  polyy[j][0] * polyz[k][0];
950  data.shape_values[dof_index3_1][q][1] = 0.0;
951  data.shape_values[dof_index3_1][q][2] = 0.0;
952 
953  data.shape_values[dof_index3_2][q][0] = 0.0;
954  data.shape_values[dof_index3_2][q][1] =
955  polyx[j][0] * polyz[k][0];
956  data.shape_values[dof_index3_2][q][2] = 0.0;
957 
958  data.shape_values[dof_index3_3][q][0] = 0.0;
959  data.shape_values[dof_index3_3][q][1] = 0.0;
960  data.shape_values[dof_index3_3][q][2] =
961  polyx[j][0] * polyy[k][0];
962  }
963  }
964  }
965  if (flags & update_gradients)
966  {
967  for (unsigned int k = 0; k < degree; ++k)
968  {
969  const unsigned int shift_k(k * degree * degree);
970  const unsigned int shift_j(
971  k * degree); // Used below when subbing k for j
972  // (type 3)
973  for (unsigned int j = 0; j < degree; ++j)
974  {
975  const unsigned int shift_jk(j * degree +
976  shift_k);
977  for (unsigned int i = 0; i < degree; ++i)
978  {
979  const unsigned int shift_ijk(shift_jk +
980  i);
981 
982  // Type 1:
983  const unsigned int dof_index1(
984  cell_type1_offset + shift_ijk);
985 
986  data.shape_grads[dof_index1][q][0][0] =
987  4.0 * polyx[i][2] * polyy[j][0] *
988  polyz[k][0];
989  data.shape_grads[dof_index1][q][0][1] =
990  4.0 * polyx[i][1] * polyy[j][1] *
991  polyz[k][0];
992  data.shape_grads[dof_index1][q][0][2] =
993  4.0 * polyx[i][1] * polyy[j][0] *
994  polyz[k][1];
995 
996  data.shape_grads[dof_index1][q][1][0] =
997  data.shape_grads[dof_index1][q][0][1];
998  data.shape_grads[dof_index1][q][1][1] =
999  4.0 * polyx[i][0] * polyy[j][2] *
1000  polyz[k][0];
1001  data.shape_grads[dof_index1][q][1][2] =
1002  4.0 * polyx[i][0] * polyy[j][1] *
1003  polyz[k][1];
1004 
1005  data.shape_grads[dof_index1][q][2][0] =
1006  data.shape_grads[dof_index1][q][0][2];
1007  data.shape_grads[dof_index1][q][2][1] =
1008  data.shape_grads[dof_index1][q][1][2];
1009  data.shape_grads[dof_index1][q][2][2] =
1010  4.0 * polyx[i][0] * polyy[j][0] *
1011  polyz[k][2];
1012 
1013  // Type 2:
1014  const unsigned int dof_index2_1(
1015  cell_type2_offset1 + shift_ijk);
1016  const unsigned int dof_index2_2(
1017  cell_type2_offset2 + shift_ijk);
1018 
1019  for (unsigned int d = 0; d < dim; ++d)
1020  {
1021  data.shape_grads[dof_index2_1][q][0]
1022  [d] =
1023  data
1024  .shape_grads[dof_index1][q][0][d];
1025  data.shape_grads[dof_index2_1][q][1]
1026  [d] =
1027  -1.0 *
1028  data
1029  .shape_grads[dof_index1][q][1][d];
1030  data.shape_grads[dof_index2_1][q][2]
1031  [d] =
1032  data
1033  .shape_grads[dof_index1][q][2][d];
1034 
1035  data.shape_grads[dof_index2_2][q][0]
1036  [d] =
1037  data
1038  .shape_grads[dof_index1][q][0][d];
1039  data.shape_grads[dof_index2_2][q][1]
1040  [d] =
1041  -1.0 *
1042  data
1043  .shape_grads[dof_index1][q][1][d];
1044  data.shape_grads[dof_index2_2][q][2]
1045  [d] =
1046  -1.0 *
1047  data
1048  .shape_grads[dof_index1][q][2][d];
1049  }
1050  }
1051  // Type 3: (note we re-use k and j for
1052  // convenience):
1053  const unsigned int shift_ij(
1054  j + shift_j); // here we've subbed j for i,
1055  // k for j.
1056  const unsigned int dof_index3_1(
1057  cell_type3_offset1 + shift_ij);
1058  const unsigned int dof_index3_2(
1059  cell_type3_offset2 + shift_ij);
1060  const unsigned int dof_index3_3(
1061  cell_type3_offset3 + shift_ij);
1062  for (unsigned int d1 = 0; d1 < dim; ++d1)
1063  {
1064  for (unsigned int d2 = 0; d2 < dim; ++d2)
1065  {
1066  data.shape_grads[dof_index3_1][q][d1]
1067  [d2] = 0.0;
1068  data.shape_grads[dof_index3_2][q][d1]
1069  [d2] = 0.0;
1070  data.shape_grads[dof_index3_3][q][d1]
1071  [d2] = 0.0;
1072  }
1073  }
1074  data.shape_grads[dof_index3_1][q][0][1] =
1075  2.0 * polyy[j][1] * polyz[k][0];
1076  data.shape_grads[dof_index3_1][q][0][2] =
1077  2.0 * polyy[j][0] * polyz[k][1];
1078 
1079  data.shape_grads[dof_index3_2][q][1][0] =
1080  2.0 * polyx[j][1] * polyz[k][0];
1081  data.shape_grads[dof_index3_2][q][1][2] =
1082  2.0 * polyx[j][0] * polyz[k][1];
1083 
1084  data.shape_grads[dof_index3_3][q][2][0] =
1085  2.0 * polyx[j][1] * polyy[k][0];
1086  data.shape_grads[dof_index3_3][q][2][1] =
1087  2.0 * polyx[j][0] * polyy[k][1];
1088  }
1089  }
1090  }
1091  }
1092  }
1093  }
1094  break;
1095  }
1096  default:
1097  {
1098  Assert(false, ExcNotImplemented());
1099  }
1100  }
1101  return data_ptr;
1102 }
1103 
1104 
1105 
1106 template <int dim, int spacedim>
1107 void
1109  const typename Triangulation<dim, dim>::cell_iterator &cell,
1110  const Quadrature<dim> & quadrature,
1111  const InternalData & fe_data) const
1112 {
1113  // This function handles the cell-dependent construction of the EDGE-based
1114  // shape functions.
1115  //
1116  // Note it will handle both 2D and 3D, in 2D, the edges are faces, but we
1117  // handle them here.
1118  //
1119  // It will fill in the missing parts of fe_data which were not possible to
1120  // fill in the get_data routine, with respect to the edge-based shape
1121  // functions.
1122  //
1123  // It should be called by the fill_fe_*_values routines in order to complete
1124  // the basis set at quadrature points on the current cell for each edge.
1125 
1126  const UpdateFlags flags(fe_data.update_each);
1127  const unsigned int n_q_points = quadrature.size();
1128 
1129  Assert(!(flags & update_values) ||
1130  fe_data.shape_values.size() == this->dofs_per_cell,
1131  ExcDimensionMismatch(fe_data.shape_values.size(),
1132  this->dofs_per_cell));
1133  Assert(!(flags & update_values) ||
1134  fe_data.shape_values[0].size() == n_q_points,
1135  ExcDimensionMismatch(fe_data.shape_values[0].size(), n_q_points));
1136 
1137  // Useful constants:
1138  const unsigned int degree(
1139  this->degree -
1140  1); // Note: constructor takes input degree + 1, so need to knock 1 off.
1141 
1142  // Useful geometry info:
1143  const unsigned int vertices_per_line(2);
1144  const unsigned int lines_per_cell(GeometryInfo<dim>::lines_per_cell);
1145 
1146  // Calculate edge orderings:
1147  std::vector<std::vector<unsigned int>> edge_order(
1148  lines_per_cell, std::vector<unsigned int>(vertices_per_line));
1149 
1150 
1151  switch (dim)
1152  {
1153  case 2:
1154  {
1155  if (flags & (update_values | update_gradients))
1156  {
1157  // Define an edge numbering so that each edge, E_{m} = [e^{m}_{1},
1158  // e^{m}_{2}] e1 = higher global numbering of the two local
1159  // vertices e2 = lower global numbering of the two local vertices
1160  std::vector<int> edge_sign(lines_per_cell);
1161  for (unsigned int m = 0; m < lines_per_cell; ++m)
1162  {
1163  unsigned int v0_loc =
1165  unsigned int v1_loc =
1167  unsigned int v0_glob = cell->vertex_index(v0_loc);
1168  unsigned int v1_glob = cell->vertex_index(v1_loc);
1169 
1170  if (v0_glob > v1_glob)
1171  {
1172  // Opposite to global numbering on our reference element
1173  edge_sign[m] = -1.0;
1174  }
1175  else
1176  {
1177  // Aligns with global numbering on our reference element.
1178  edge_sign[m] = 1.0;
1179  }
1180  }
1181 
1182  // Define \sigma_{m} = sigma_{e^{m}_{2}} - sigma_{e^{m}_{2}}
1183  // \lambda_{m} = \lambda_{e^{m}_{1}} + \lambda_{e^{m}_{2}}
1184  //
1185  // To help things, in fe_data, we have precomputed (sigma_{i} -
1186  // sigma_{j}) and (lambda_{i} + lambda_{j}) for 0<= i,j <
1187  // lines_per_cell.
1188  //
1189  // There are two types:
1190  // - lower order (1 per edge, m):
1191  // \phi_{m}^{\mathcal{N}_{0}} = 1/2 grad(\sigma_{m})\lambda_{m}
1192  //
1193  // - higher order (degree per edge, m):
1194  // \phi_{i}^{E_{m}} = grad( L_{i+2}(\sigma_{m}) (\lambda_{m}) ).
1195  //
1196  // NOTE: sigma_{m} and lambda_{m} are either a function of x OR
1197  // y
1198  // and if sigma is of x, then lambda is of y, and vice
1199  // versa. This means that grad(\sigma) requires
1200  // multiplication by d(sigma)/dx_{i} for the i^th comp of
1201  // grad(sigma) and similarly when taking derivatives of
1202  // lambda.
1203  //
1204  // First handle the lowest order edges (dofs 0 to 3)
1205  // 0 and 1 are the edges in the y dir. (sigma is function of y,
1206  // lambda is function of x). 2 and 3 are the edges in the x dir.
1207  // (sigma is function of x, lambda is function of y).
1208  //
1209  // More more info: see GeometryInfo for picture of the standard
1210  // element.
1211  //
1212  // Fill edge-based points:
1213  // std::vector<std::vector< Point<dim> > >
1214  // edge_points(lines_per_cell, std::vector<Point<dim>>
1215  // (n_q_points));
1216 
1217  std::vector<std::vector<double>> edge_sigma_values(
1218  fe_data.edge_sigma_values);
1219  std::vector<std::vector<double>> edge_sigma_grads(
1220  fe_data.edge_sigma_grads);
1221 
1222  std::vector<std::vector<double>> edge_lambda_values(
1223  fe_data.edge_lambda_values);
1224  std::vector<std::vector<double>> edge_lambda_grads(
1225  fe_data.edge_lambda_grads_2d);
1226 
1227  // Adjust the edge_sigma_* for the current cell:
1228  for (unsigned int m = 0; m < lines_per_cell; ++m)
1229  {
1230  std::transform(edge_sigma_values[m].begin(),
1231  edge_sigma_values[m].end(),
1232  edge_sigma_values[m].begin(),
1233  [&](const double edge_sigma_value) {
1234  return edge_sign[m] * edge_sigma_value;
1235  });
1236 
1237  std::transform(edge_sigma_grads[m].begin(),
1238  edge_sigma_grads[m].end(),
1239  edge_sigma_grads[m].begin(),
1240  [&](const double edge_sigma_grad) {
1241  return edge_sign[m] * edge_sigma_grad;
1242  });
1243  }
1244 
1245  // If we want to generate shape gradients then we need second
1246  // derivatives of the 1d polynomials, but only first derivatives
1247  // for the shape values.
1248  const unsigned int poly_length((flags & update_gradients) ? 3 :
1249  2);
1250 
1251  for (unsigned int m = 0; m < lines_per_cell; ++m)
1252  {
1253  const unsigned int shift_m(m * this->dofs_per_line);
1254  for (unsigned int q = 0; q < n_q_points; ++q)
1255  {
1256  // Only compute 1d polynomials if degree>0.
1257  std::vector<std::vector<double>> poly(
1258  degree, std::vector<double>(poly_length));
1259  for (unsigned int i = 1; i < degree + 1; ++i)
1260  {
1261  // Compute all required 1d polynomials and their
1262  // derivatives, starting at degree 2. e.g. to access
1263  // L'_{3}(2x-1) use polyx[1][1].
1264  IntegratedLegendrePolynomials[i + 1].value(
1265  edge_sigma_values[m][q], poly[i - 1]);
1266  }
1267  if (flags & update_values)
1268  {
1269  // Lowest order edge shape functions:
1270  for (unsigned int d = 0; d < dim; ++d)
1271  {
1272  fe_data.shape_values[shift_m][q][d] =
1273  0.5 * edge_sigma_grads[m][d] *
1274  edge_lambda_values[m][q];
1275  }
1276  // Higher order edge shape functions:
1277  for (unsigned int i = 1; i < degree + 1; ++i)
1278  {
1279  const unsigned int poly_index = i - 1;
1280  const unsigned int dof_index(i + shift_m);
1281  for (unsigned int d = 0; d < dim; ++d)
1282  {
1283  fe_data.shape_values[dof_index][q][d] =
1284  edge_sigma_grads[m][d] *
1285  poly[poly_index][1] *
1286  edge_lambda_values[m][q] +
1287  poly[poly_index][0] *
1288  edge_lambda_grads[m][d];
1289  }
1290  }
1291  }
1292  if (flags & update_gradients)
1293  {
1294  // Lowest order edge shape functions:
1295  for (unsigned int d1 = 0; d1 < dim; ++d1)
1296  {
1297  for (unsigned int d2 = 0; d2 < dim; ++d2)
1298  {
1299  // Note: gradient is constant for a given
1300  // edge.
1301  fe_data.shape_grads[shift_m][q][d1][d2] =
1302  0.5 * edge_sigma_grads[m][d1] *
1303  edge_lambda_grads[m][d2];
1304  }
1305  }
1306  // Higher order edge shape functions:
1307  for (unsigned int i = 1; i < degree + 1; ++i)
1308  {
1309  const unsigned int poly_index = i - 1;
1310  const unsigned int dof_index(i + shift_m);
1311 
1312  fe_data.shape_grads[dof_index][q][0][0] =
1313  edge_sigma_grads[m][0] *
1314  edge_sigma_grads[m][0] *
1315  edge_lambda_values[m][q] * poly[poly_index][2];
1316 
1317  fe_data.shape_grads[dof_index][q][0][1] =
1318  (edge_sigma_grads[m][0] *
1319  edge_lambda_grads[m][1] +
1320  edge_sigma_grads[m][1] *
1321  edge_lambda_grads[m][0]) *
1322  poly[poly_index][1];
1323 
1324  fe_data.shape_grads[dof_index][q][1][0] =
1325  fe_data.shape_grads[dof_index][q][0][1];
1326 
1327  fe_data.shape_grads[dof_index][q][1][1] =
1328  edge_sigma_grads[m][1] *
1329  edge_sigma_grads[m][1] *
1330  edge_lambda_values[m][q] * poly[poly_index][2];
1331  }
1332  }
1333  }
1334  }
1335  }
1336  break;
1337  }
1338  case 3:
1339  {
1340  if (flags & (update_values | update_gradients))
1341  {
1342  // Define an edge numbering so that each edge, E_{m} = [e^{m}_{1},
1343  // e^{m}_{2}] e1 = higher global numbering of the two local
1344  // vertices e2 = lower global numbering of the two local vertices
1345  std::vector<int> edge_sign(lines_per_cell);
1346  for (unsigned int m = 0; m < lines_per_cell; ++m)
1347  {
1348  unsigned int v0_loc =
1350  unsigned int v1_loc =
1352  unsigned int v0_glob = cell->vertex_index(v0_loc);
1353  unsigned int v1_glob = cell->vertex_index(v1_loc);
1354 
1355  if (v0_glob > v1_glob)
1356  {
1357  // Opposite to global numbering on our reference element
1358  edge_sign[m] = -1.0;
1359  }
1360  else
1361  {
1362  // Aligns with global numbering on our reference element.
1363  edge_sign[m] = 1.0;
1364  }
1365  }
1366 
1367  // Define \sigma_{m} = sigma_{e^{m}_{2}} - sigma_{e^{m}_{2}}
1368  // \lambda_{m} = \lambda_{e^{m}_{1}} + \lambda_{e^{m}_{2}}
1369  //
1370  // To help things, in fe_data, we have precomputed (sigma_{i} -
1371  // sigma_{j}) and (lambda_{i} + lambda_{j}) for 0<= i,j <
1372  // lines_per_cell.
1373  //
1374  // There are two types:
1375  // - lower order (1 per edge, m):
1376  // \phi_{m}^{\mathcal{N}_{0}} = 1/2 grad(\sigma_{m})\lambda_{m}
1377  //
1378  // - higher order (degree per edge, m):
1379  // \phi_{i}^{E_{m}} = grad( L_{i+2}(\sigma_{m}) (\lambda_{m}) ).
1380  //
1381  // NOTE: In the ref cell, sigma_{m} is a function of x OR y OR Z
1382  // and lambda_{m} a function of the remaining co-ords.
1383  // for example, if sigma is of x, then lambda is of y AND
1384  // z, and so on. This means that grad(\sigma) requires
1385  // multiplication by d(sigma)/dx_{i} for the i^th comp of
1386  // grad(sigma) and similarly when taking derivatives of
1387  // lambda.
1388  //
1389  // First handle the lowest order edges (dofs 0 to 11)
1390  // 0 and 1 are the edges in the y dir at z=0. (sigma is a fn of y,
1391  // lambda is a fn of x & z). 2 and 3 are the edges in the x dir at
1392  // z=0. (sigma is a fn of x, lambda is a fn of y & z). 4 and 5 are
1393  // the edges in the y dir at z=1. (sigma is a fn of y, lambda is a
1394  // fn of x & z). 6 and 7 are the edges in the x dir at z=1. (sigma
1395  // is a fn of x, lambda is a fn of y & z). 8 and 9 are the edges
1396  // in the z dir at y=0. (sigma is a fn of z, lambda is a fn of x &
1397  // y). 10 and 11 are the edges in the z dir at y=1. (sigma is a fn
1398  // of z, lambda is a fn of x & y).
1399  //
1400  // For more info: see GeometryInfo for picture of the standard
1401  // element.
1402 
1403  // Copy over required edge-based data:
1404  std::vector<std::vector<double>> edge_sigma_values(
1405  fe_data.edge_sigma_values);
1406  std::vector<std::vector<double>> edge_lambda_values(
1407  fe_data.edge_lambda_values);
1408  std::vector<std::vector<double>> edge_sigma_grads(
1409  fe_data.edge_sigma_grads);
1410  std::vector<std::vector<std::vector<double>>> edge_lambda_grads(
1411  fe_data.edge_lambda_grads_3d);
1412  std::vector<std::vector<std::vector<double>>>
1413  edge_lambda_gradgrads_3d(fe_data.edge_lambda_gradgrads_3d);
1414 
1415  // Adjust the edge_sigma_* for the current cell:
1416  for (unsigned int m = 0; m < lines_per_cell; ++m)
1417  {
1418  std::transform(edge_sigma_values[m].begin(),
1419  edge_sigma_values[m].end(),
1420  edge_sigma_values[m].begin(),
1421  [&](const double edge_sigma_value) {
1422  return edge_sign[m] * edge_sigma_value;
1423  });
1424  std::transform(edge_sigma_grads[m].begin(),
1425  edge_sigma_grads[m].end(),
1426  edge_sigma_grads[m].begin(),
1427  [&](const double edge_sigma_grad) {
1428  return edge_sign[m] * edge_sigma_grad;
1429  });
1430  }
1431 
1432  // Now calculate the edge-based shape functions:
1433  // If we want to generate shape gradients then we need second
1434  // derivatives of the 1d polynomials, but only first derivatives
1435  // for the shape values.
1436  const unsigned int poly_length((flags & update_gradients) ? 3 :
1437  2);
1438  std::vector<std::vector<double>> poly(
1439  degree, std::vector<double>(poly_length));
1440  for (unsigned int m = 0; m < lines_per_cell; ++m)
1441  {
1442  const unsigned int shift_m(m * this->dofs_per_line);
1443  for (unsigned int q = 0; q < n_q_points; ++q)
1444  {
1445  // precompute values of all 1d polynomials required:
1446  if (degree > 0)
1447  {
1448  for (unsigned int i = 0; i < degree; ++i)
1449  {
1450  IntegratedLegendrePolynomials[i + 2].value(
1451  edge_sigma_values[m][q], poly[i]);
1452  }
1453  }
1454  if (flags & update_values)
1455  {
1456  // Lowest order shape functions:
1457  for (unsigned int d = 0; d < dim; ++d)
1458  {
1459  fe_data.shape_values[shift_m][q][d] =
1460  0.5 * edge_sigma_grads[m][d] *
1461  edge_lambda_values[m][q];
1462  }
1463  if (degree > 0)
1464  {
1465  for (unsigned int i = 0; i < degree; ++i)
1466  {
1467  const unsigned int dof_index(i + 1 + shift_m);
1468  for (unsigned int d = 0; d < dim; ++d)
1469  {
1470  fe_data.shape_values[dof_index][q][d] =
1471  edge_sigma_grads[m][d] * poly[i][1] *
1472  edge_lambda_values[m][q] +
1473  poly[i][0] * edge_lambda_grads[m][q][d];
1474  }
1475  }
1476  }
1477  }
1478  if (flags & update_gradients)
1479  {
1480  // Lowest order shape functions:
1481  for (unsigned int d1 = 0; d1 < dim; ++d1)
1482  {
1483  for (unsigned int d2 = 0; d2 < dim; ++d2)
1484  {
1485  fe_data.shape_grads[shift_m][q][d1][d2] =
1486  0.5 * edge_sigma_grads[m][d1] *
1487  edge_lambda_grads[m][q][d2];
1488  }
1489  }
1490  if (degree > 0)
1491  {
1492  for (unsigned int i = 0; i < degree; ++i)
1493  {
1494  const unsigned int dof_index(i + 1 + shift_m);
1495 
1496  for (unsigned int d1 = 0; d1 < dim; ++d1)
1497  {
1498  for (unsigned int d2 = 0; d2 < dim; ++d2)
1499  {
1500  fe_data
1501  .shape_grads[dof_index][q][d1][d2] =
1502  edge_sigma_grads[m][d1] *
1503  edge_sigma_grads[m][d2] *
1504  poly[i][2] *
1505  edge_lambda_values[m][q] +
1506  (edge_sigma_grads[m][d1] *
1507  edge_lambda_grads[m][q][d2] +
1508  edge_sigma_grads[m][d2] *
1509  edge_lambda_grads[m][q][d1]) *
1510  poly[i][1] +
1511  edge_lambda_gradgrads_3d[m][d1]
1512  [d2] *
1513  poly[i][0];
1514  }
1515  }
1516  }
1517  }
1518  }
1519  }
1520  }
1521  }
1522  break;
1523  }
1524  default:
1525  {
1526  Assert(false, ExcNotImplemented());
1527  }
1528  }
1529 }
1530 
1531 
1532 
1533 template <int dim, int spacedim>
1534 void
1536  const typename Triangulation<dim, dim>::cell_iterator &cell,
1537  const Quadrature<dim> & quadrature,
1538  const InternalData & fe_data) const
1539 {
1540  // This function handles the cell-dependent construction of the FACE-based
1541  // shape functions.
1542  //
1543  // Note that it should only be called in 3D.
1544  Assert(dim == 3, ExcDimensionMismatch(dim, 3));
1545  //
1546  // It will fill in the missing parts of fe_data which were not possible to
1547  // fill in the get_data routine, with respect to face-based shape functions.
1548  //
1549  // It should be called by the fill_fe_*_values routines in order to complete
1550  // the basis set at quadrature points on the current cell for each face.
1551 
1552  // Useful constants:
1553  const unsigned int degree(
1554  this->degree -
1555  1); // Note: constructor takes input degree + 1, so need to knock 1 off.
1556 
1557  // Do nothing if FE degree is 0.
1558  if (degree > 0)
1559  {
1560  const UpdateFlags flags(fe_data.update_each);
1561 
1562  if (flags & (update_values | update_gradients))
1563  {
1564  const unsigned int n_q_points = quadrature.size();
1565 
1566  Assert(!(flags & update_values) ||
1567  fe_data.shape_values.size() == this->dofs_per_cell,
1568  ExcDimensionMismatch(fe_data.shape_values.size(),
1569  this->dofs_per_cell));
1570  Assert(!(flags & update_values) ||
1571  fe_data.shape_values[0].size() == n_q_points,
1572  ExcDimensionMismatch(fe_data.shape_values[0].size(),
1573  n_q_points));
1574 
1575  // Useful geometry info:
1576  const unsigned int vertices_per_face(
1578  const unsigned int faces_per_cell(GeometryInfo<dim>::faces_per_cell);
1579 
1580  // DoF info:
1581  const unsigned int n_line_dofs =
1582  this->dofs_per_line * GeometryInfo<dim>::lines_per_cell;
1583 
1584  // First we find the global face orientations on the current cell.
1585  std::vector<std::vector<unsigned int>> face_orientation(
1586  faces_per_cell, std::vector<unsigned int>(vertices_per_face));
1587 
1588  const unsigned int
1589  vertex_opposite_on_face[GeometryInfo<3>::vertices_per_face] = {3,
1590  2,
1591  1,
1592  0};
1593 
1594  const unsigned int
1595  vertices_adjacent_on_face[GeometryInfo<3>::vertices_per_face][2] = {
1596  {1, 2}, {0, 3}, {0, 3}, {1, 2}};
1597 
1598  for (unsigned int m = 0; m < faces_per_cell; ++m)
1599  {
1600  // Find the local vertex on this face with the highest global
1601  // numbering. This is f^m_0.
1602  unsigned int current_max = 0;
1603  unsigned int current_glob = cell->vertex_index(
1605  for (unsigned int v = 1; v < vertices_per_face; ++v)
1606  {
1607  if (current_glob <
1608  cell->vertex_index(
1610  {
1611  current_max = v;
1612  current_glob = cell->vertex_index(
1614  }
1615  }
1616  face_orientation[m][0] =
1618 
1619  // f^m_2 is the vertex opposite f^m_0.
1620  face_orientation[m][2] = GeometryInfo<dim>::face_to_cell_vertices(
1621  m, vertex_opposite_on_face[current_max]);
1622 
1623  // Finally, f^m_1 is the vertex with the greater global numbering
1624  // of the remaining two local vertices. Then, f^m_3 is the other.
1625  if (cell->vertex_index(GeometryInfo<dim>::face_to_cell_vertices(
1626  m, vertices_adjacent_on_face[current_max][0])) >
1627  cell->vertex_index(GeometryInfo<dim>::face_to_cell_vertices(
1628  m, vertices_adjacent_on_face[current_max][1])))
1629  {
1630  face_orientation[m][1] =
1632  m, vertices_adjacent_on_face[current_max][0]);
1633  face_orientation[m][3] =
1635  m, vertices_adjacent_on_face[current_max][1]);
1636  }
1637  else
1638  {
1639  face_orientation[m][1] =
1641  m, vertices_adjacent_on_face[current_max][1]);
1642  face_orientation[m][3] =
1644  m, vertices_adjacent_on_face[current_max][0]);
1645  }
1646  }
1647 
1648  // Now we know the face orientation on the current cell, we can
1649  // generate the parameterisation:
1650  std::vector<std::vector<double>> face_xi_values(
1651  faces_per_cell, std::vector<double>(n_q_points));
1652  std::vector<std::vector<double>> face_xi_grads(
1653  faces_per_cell, std::vector<double>(dim));
1654  std::vector<std::vector<double>> face_eta_values(
1655  faces_per_cell, std::vector<double>(n_q_points));
1656  std::vector<std::vector<double>> face_eta_grads(
1657  faces_per_cell, std::vector<double>(dim));
1658 
1659  std::vector<std::vector<double>> face_lambda_values(
1660  faces_per_cell, std::vector<double>(n_q_points));
1661  std::vector<std::vector<double>> face_lambda_grads(
1662  faces_per_cell, std::vector<double>(dim));
1663  for (unsigned int m = 0; m < faces_per_cell; ++m)
1664  {
1665  for (unsigned int q = 0; q < n_q_points; ++q)
1666  {
1667  face_xi_values[m][q] =
1668  fe_data.sigma_imj_values[q][face_orientation[m][0]]
1669  [face_orientation[m][1]];
1670  face_eta_values[m][q] =
1671  fe_data.sigma_imj_values[q][face_orientation[m][0]]
1672  [face_orientation[m][3]];
1673  face_lambda_values[m][q] = fe_data.face_lambda_values[m][q];
1674  }
1675  for (unsigned int d = 0; d < dim; ++d)
1676  {
1677  face_xi_grads[m][d] =
1678  fe_data.sigma_imj_grads[face_orientation[m][0]]
1679  [face_orientation[m][1]][d];
1680  face_eta_grads[m][d] =
1681  fe_data.sigma_imj_grads[face_orientation[m][0]]
1682  [face_orientation[m][3]][d];
1683 
1684  face_lambda_grads[m][d] = fe_data.face_lambda_grads[m][d];
1685  }
1686  }
1687  // Now can generate the basis
1688  const unsigned int poly_length((flags & update_gradients) ? 3 : 2);
1689  std::vector<std::vector<double>> polyxi(
1690  degree, std::vector<double>(poly_length));
1691  std::vector<std::vector<double>> polyeta(
1692  degree, std::vector<double>(poly_length));
1693 
1694  // Loop through quad points:
1695  for (unsigned int m = 0; m < faces_per_cell; ++m)
1696  {
1697  const unsigned int shift_m(m * this->dofs_per_quad);
1698  // Calculate the offsets for each face-based shape function:
1699  //
1700  // Type-1 (gradients)
1701  // \phi^{F_m,1}_{ij} = \nabla( L_{i+2}(\xi_{F_{m}})
1702  // L_{j+2}(\eta_{F_{m}}) \lambda_{F_{m}} )
1703  //
1704  // 0 <= i,j < degree (in a group of degree*degree)
1705  const unsigned int face_type1_offset(n_line_dofs + shift_m);
1706  // Type-2:
1707  //
1708  // \phi^{F_m,2}_{ij} = ( L'_{i+2}(\xi_{F_{m}})
1709  // L_{j+2}(\eta_{F_{m}}) \nabla\xi_{F_{m}}
1710  // - L_{i+2}(\xi_{F_{m}})
1711  // L'_{j+2}(\eta_{F_{m}}) \nabla\eta_{F_{m}}
1712  // ) \lambda_{F_{m}}
1713  //
1714  // 0 <= i,j < degree (in a group of degree*degree)
1715  const unsigned int face_type2_offset(face_type1_offset +
1716  degree * degree);
1717  // Type-3:
1718  //
1719  // \phi^{F_m,3}_{i} = L_{i+2}(\eta_{F_{m}}) \lambda_{F_{m}}
1720  // \nabla\xi_{F_{m}} \phi^{F_m,3}_{i+p} = L_{i+2}(\xi_{F_{m}})
1721  // \lambda_{F_{m}} \nabla\eta_{F_{m}}
1722  //
1723  // 0 <= i < degree.
1724  //
1725  // here we order so that all of subtype 1 comes first, then
1726  // subtype 2.
1727  const unsigned int face_type3_offset1(face_type2_offset +
1728  degree * degree);
1729  const unsigned int face_type3_offset2(face_type3_offset1 +
1730  degree);
1731 
1732  // Loop over all faces:
1733  for (unsigned int q = 0; q < n_q_points; ++q)
1734  {
1735  // pre-compute values & required derivatives at this quad
1736  // point: polyxi = L_{i+2}(\xi_{F_{m}}), polyeta =
1737  // L_{j+2}(\eta_{F_{m}}),
1738  //
1739  // each polypoint[k][d], contains the dth derivative of
1740  // L_{k+2} at the point \xi or \eta. Note that this doesn't
1741  // include the derivative of xi/eta via the chain rule.
1742  for (unsigned int i = 0; i < degree; ++i)
1743  {
1744  // compute all required 1d polynomials:
1745  IntegratedLegendrePolynomials[i + 2].value(
1746  face_xi_values[m][q], polyxi[i]);
1747  IntegratedLegendrePolynomials[i + 2].value(
1748  face_eta_values[m][q], polyeta[i]);
1749  }
1750  // Now use these to compute the shape functions:
1751  if (flags & update_values)
1752  {
1753  for (unsigned int j = 0; j < degree; ++j)
1754  {
1755  const unsigned int shift_j(j * degree);
1756  for (unsigned int i = 0; i < degree; ++i)
1757  {
1758  const unsigned int shift_ij(shift_j + i);
1759  // Type 1:
1760  const unsigned int dof_index1(face_type1_offset +
1761  shift_ij);
1762  for (unsigned int d = 0; d < dim; ++d)
1763  {
1764  fe_data.shape_values[dof_index1][q][d] =
1765  (face_xi_grads[m][d] * polyxi[i][1] *
1766  polyeta[j][0] +
1767  face_eta_grads[m][d] * polyxi[i][0] *
1768  polyeta[j][1]) *
1769  face_lambda_values[m][q] +
1770  face_lambda_grads[m][d] * polyxi[i][0] *
1771  polyeta[j][0];
1772  }
1773  // Type 2:
1774  const unsigned int dof_index2(face_type2_offset +
1775  shift_ij);
1776  for (unsigned int d = 0; d < dim; ++d)
1777  {
1778  fe_data.shape_values[dof_index2][q][d] =
1779  (face_xi_grads[m][d] * polyxi[i][1] *
1780  polyeta[j][0] -
1781  face_eta_grads[m][d] * polyxi[i][0] *
1782  polyeta[j][1]) *
1783  face_lambda_values[m][q];
1784  }
1785  }
1786  // Type 3:
1787  const unsigned int dof_index3_1(face_type3_offset1 +
1788  j);
1789  const unsigned int dof_index3_2(face_type3_offset2 +
1790  j);
1791  for (unsigned int d = 0; d < dim; ++d)
1792  {
1793  fe_data.shape_values[dof_index3_1][q][d] =
1794  face_xi_grads[m][d] * polyeta[j][0] *
1795  face_lambda_values[m][q];
1796 
1797  fe_data.shape_values[dof_index3_2][q][d] =
1798  face_eta_grads[m][d] * polyxi[j][0] *
1799  face_lambda_values[m][q];
1800  }
1801  }
1802  }
1803  if (flags & update_gradients)
1804  {
1805  for (unsigned int j = 0; j < degree; ++j)
1806  {
1807  const unsigned int shift_j(j * degree);
1808  for (unsigned int i = 0; i < degree; ++i)
1809  {
1810  const unsigned int shift_ij(shift_j + i);
1811  // Type 1:
1812  const unsigned int dof_index1(face_type1_offset +
1813  shift_ij);
1814  for (unsigned int d1 = 0; d1 < dim; ++d1)
1815  {
1816  for (unsigned int d2 = 0; d2 < dim; ++d2)
1817  {
1818  fe_data
1819  .shape_grads[dof_index1][q][d1][d2] =
1820  (face_xi_grads[m][d1] *
1821  face_xi_grads[m][d2] * polyxi[i][2] *
1822  polyeta[j][0] +
1823  (face_xi_grads[m][d1] *
1824  face_eta_grads[m][d2] +
1825  face_xi_grads[m][d2] *
1826  face_eta_grads[m][d1]) *
1827  polyxi[i][1] * polyeta[j][1] +
1828  face_eta_grads[m][d1] *
1829  face_eta_grads[m][d2] *
1830  polyxi[i][0] * polyeta[j][2]) *
1831  face_lambda_values[m][q] +
1832  (face_xi_grads[m][d2] * polyxi[i][1] *
1833  polyeta[j][0] +
1834  face_eta_grads[m][d2] * polyxi[i][0] *
1835  polyeta[j][1]) *
1836  face_lambda_grads[m][d1] +
1837  (face_xi_grads[m][d1] * polyxi[i][1] *
1838  polyeta[j][0] +
1839  face_eta_grads[m][d1] * polyxi[i][0] *
1840  polyeta[j][1]) *
1841  face_lambda_grads[m][d2];
1842  }
1843  }
1844  // Type 2:
1845  const unsigned int dof_index2(face_type2_offset +
1846  shift_ij);
1847  for (unsigned int d1 = 0; d1 < dim; ++d1)
1848  {
1849  for (unsigned int d2 = 0; d2 < dim; ++d2)
1850  {
1851  fe_data
1852  .shape_grads[dof_index2][q][d1][d2] =
1853  (face_xi_grads[m][d1] *
1854  face_xi_grads[m][d2] * polyxi[i][2] *
1855  polyeta[j][0] +
1856  (face_xi_grads[m][d1] *
1857  face_eta_grads[m][d2] -
1858  face_xi_grads[m][d2] *
1859  face_eta_grads[m][d1]) *
1860  polyxi[i][1] * polyeta[j][1] -
1861  face_eta_grads[m][d1] *
1862  face_eta_grads[m][d2] *
1863  polyxi[i][0] * polyeta[j][2]) *
1864  face_lambda_values[m][q] +
1865  (face_xi_grads[m][d1] * polyxi[i][1] *
1866  polyeta[j][0] -
1867  face_eta_grads[m][d1] * polyxi[i][0] *
1868  polyeta[j][1]) *
1869  face_lambda_grads[m][d2];
1870  }
1871  }
1872  }
1873  // Type 3:
1874  const unsigned int dof_index3_1(face_type3_offset1 +
1875  j);
1876  const unsigned int dof_index3_2(face_type3_offset2 +
1877  j);
1878  for (unsigned int d1 = 0; d1 < dim; ++d1)
1879  {
1880  for (unsigned int d2 = 0; d2 < dim; ++d2)
1881  {
1882  fe_data.shape_grads[dof_index3_1][q][d1][d2] =
1883  face_xi_grads[m][d1] *
1884  (face_eta_grads[m][d2] * polyeta[j][1] *
1885  face_lambda_values[m][q] +
1886  face_lambda_grads[m][d2] * polyeta[j][0]);
1887 
1888  fe_data.shape_grads[dof_index3_2][q][d1][d2] =
1889  face_eta_grads[m][d1] *
1890  (face_xi_grads[m][d2] * polyxi[j][1] *
1891  face_lambda_values[m][q] +
1892  face_lambda_grads[m][d2] * polyxi[j][0]);
1893  }
1894  }
1895  }
1896  }
1897  }
1898  }
1899  }
1900  if (flags & update_hessians)
1901  {
1902  Assert(false, ExcNotImplemented());
1903  }
1904  }
1905 }
1906 
1907 
1908 
1909 template <int dim, int spacedim>
1910 void
1912  const typename Triangulation<dim, dim>::cell_iterator &cell,
1913  const CellSimilarity::Similarity /*cell_similarity*/,
1914  const Quadrature<dim> & quadrature,
1915  const Mapping<dim, dim> & mapping,
1916  const typename Mapping<dim, dim>::InternalDataBase &mapping_internal,
1917  const ::internal::FEValuesImplementation::MappingRelatedData<dim, dim>
1918  & mapping_data,
1919  const typename FiniteElement<dim, dim>::InternalDataBase &fe_internal,
1921  &data) const
1922 {
1923  // Convert to the correct internal data class for this FE class.
1924  Assert(dynamic_cast<const InternalData *>(&fe_internal) != nullptr,
1925  ExcInternalError());
1926  const InternalData &fe_data = static_cast<const InternalData &>(fe_internal);
1927 
1928  // Now update the edge-based DoFs, which depend on the cell.
1929  // This will fill in the missing items in the InternalData
1930  // (fe_internal/fe_data) which was not filled in by get_data.
1931  fill_edge_values(cell, quadrature, fe_data);
1932  if (dim == 3 && this->degree > 1)
1933  {
1934  fill_face_values(cell, quadrature, fe_data);
1935  }
1936 
1937  const UpdateFlags flags(fe_data.update_each);
1938  const unsigned int n_q_points = quadrature.size();
1939 
1940  Assert(!(flags & update_values) ||
1941  fe_data.shape_values.size() == this->dofs_per_cell,
1942  ExcDimensionMismatch(fe_data.shape_values.size(),
1943  this->dofs_per_cell));
1944  Assert(!(flags & update_values) ||
1945  fe_data.shape_values[0].size() == n_q_points,
1946  ExcDimensionMismatch(fe_data.shape_values[0].size(), n_q_points));
1947 
1948  if (flags & update_values)
1949  {
1950  // Now have all shape_values stored on the reference cell.
1951  // Must now transform to the physical cell.
1952  std::vector<Tensor<1, dim>> transformed_shape_values(n_q_points);
1953  for (unsigned int dof = 0; dof < this->dofs_per_cell; ++dof)
1954  {
1955  const unsigned int first =
1956  data.shape_function_to_row_table[dof * this->n_components() +
1957  this->get_nonzero_components(dof)
1958  .first_selected_component()];
1959 
1960  mapping.transform(make_array_view(fe_data.shape_values[dof]),
1962  mapping_internal,
1963  make_array_view(transformed_shape_values));
1964  for (unsigned int q = 0; q < n_q_points; ++q)
1965  {
1966  for (unsigned int d = 0; d < dim; ++d)
1967  {
1968  data.shape_values(first + d, q) =
1969  transformed_shape_values[q][d];
1970  }
1971  }
1972  }
1973  }
1974  if (flags & update_gradients)
1975  {
1976  // Now have all shape_grads stored on the reference cell.
1977  // Must now transform to the physical cell.
1978  std::vector<Tensor<2, dim>> input(n_q_points);
1979  std::vector<Tensor<2, dim>> transformed_shape_grads(n_q_points);
1980  for (unsigned int dof = 0; dof < this->dofs_per_cell; ++dof)
1981  {
1982  for (unsigned int q = 0; q < n_q_points; ++q)
1983  {
1984  input[q] = fe_data.shape_grads[dof][q];
1985  }
1986  mapping.transform(make_array_view(input),
1988  mapping_internal,
1989  make_array_view(transformed_shape_grads));
1990 
1991  const unsigned int first =
1992  data.shape_function_to_row_table[dof * this->n_components() +
1993  this->get_nonzero_components(dof)
1994  .first_selected_component()];
1995 
1996  for (unsigned int q = 0; q < n_q_points; ++q)
1997  {
1998  for (unsigned int d1 = 0; d1 < dim; ++d1)
1999  {
2000  for (unsigned int d2 = 0; d2 < dim; ++d2)
2001  {
2002  transformed_shape_grads[q][d1] -=
2003  data.shape_values(first + d2, q) *
2004  mapping_data.jacobian_pushed_forward_grads[q][d2][d1];
2005  }
2006  }
2007  }
2008 
2009  for (unsigned int q = 0; q < n_q_points; ++q)
2010  {
2011  for (unsigned int d = 0; d < dim; ++d)
2012  {
2013  data.shape_gradients[first + d][q] =
2014  transformed_shape_grads[q][d];
2015  }
2016  }
2017  }
2018  }
2019 }
2020 
2021 
2022 
2023 template <int dim, int spacedim>
2024 void
2026  const typename Triangulation<dim, dim>::cell_iterator &cell,
2027  const unsigned int face_no,
2028  const Quadrature<dim - 1> & quadrature,
2029  const Mapping<dim, dim> & mapping,
2030  const typename Mapping<dim, dim>::InternalDataBase & mapping_internal,
2031  const ::internal::FEValuesImplementation::MappingRelatedData<dim, dim>
2032  & mapping_data,
2033  const typename FiniteElement<dim, dim>::InternalDataBase &fe_internal,
2035  &data) const
2036 {
2037  // Note for future improvement:
2038  // We don't have the full quadrature - should use QProjector to create the 2D
2039  // quadrature.
2040  //
2041  // For now I am effectively generating all of the shape function vals/grads,
2042  // etc. On all quad points on all faces and then only using them for one face.
2043  // This is obviously inefficient. I should cache the cell number and cache
2044  // all of the shape_values/gradients etc and then reuse them for each face.
2045 
2046  // convert data object to internal
2047  // data for this class. fails with
2048  // an exception if that is not
2049  // possible
2050  Assert(dynamic_cast<const InternalData *>(&fe_internal) != nullptr,
2051  ExcInternalError());
2052  const InternalData &fe_data = static_cast<const InternalData &>(fe_internal);
2053 
2054  // Now update the edge-based DoFs, which depend on the cell.
2055  // This will fill in the missing items in the InternalData
2056  // (fe_internal/fe_data) which was not filled in by get_data.
2057  fill_edge_values(cell,
2059  fe_data);
2060  if (dim == 3 && this->degree > 1)
2061  {
2062  fill_face_values(cell,
2064  fe_data);
2065  }
2066 
2067  const UpdateFlags flags(fe_data.update_each);
2068  const unsigned int n_q_points = quadrature.size();
2069  const typename QProjector<dim>::DataSetDescriptor offset =
2071  cell->face_orientation(face_no),
2072  cell->face_flip(face_no),
2073  cell->face_rotation(face_no),
2074  n_q_points);
2075 
2076  if (flags & update_values)
2077  {
2078  // Now have all shape_values stored on the reference cell.
2079  // Must now transform to the physical cell.
2080  std::vector<Tensor<1, dim>> transformed_shape_values(n_q_points);
2081  for (unsigned int dof = 0; dof < this->dofs_per_cell; ++dof)
2082  {
2083  mapping.transform(make_array_view(fe_data.shape_values[dof],
2084  offset,
2085  n_q_points),
2087  mapping_internal,
2088  make_array_view(transformed_shape_values));
2089 
2090  const unsigned int first =
2091  data.shape_function_to_row_table[dof * this->n_components() +
2092  this->get_nonzero_components(dof)
2093  .first_selected_component()];
2094 
2095  for (unsigned int q = 0; q < n_q_points; ++q)
2096  {
2097  for (unsigned int d = 0; d < dim; ++d)
2098  {
2099  data.shape_values(first + d, q) =
2100  transformed_shape_values[q][d];
2101  }
2102  }
2103  }
2104  }
2105  if (flags & update_gradients)
2106  {
2107  // Now have all shape_grads stored on the reference cell.
2108  // Must now transform to the physical cell.
2109  std::vector<Tensor<2, dim>> input(n_q_points);
2110  std::vector<Tensor<2, dim>> transformed_shape_grads(n_q_points);
2111  for (unsigned int dof = 0; dof < this->dofs_per_cell; ++dof)
2112  {
2113  for (unsigned int q = 0; q < n_q_points; ++q)
2114  {
2115  input[q] = fe_data.shape_grads[dof][offset + q];
2116  }
2117  mapping.transform(input,
2119  mapping_internal,
2120  make_array_view(transformed_shape_grads));
2121 
2122  const unsigned int first =
2123  data.shape_function_to_row_table[dof * this->n_components() +
2124  this->get_nonzero_components(dof)
2125  .first_selected_component()];
2126 
2127  for (unsigned int q = 0; q < n_q_points; ++q)
2128  {
2129  for (unsigned int d1 = 0; d1 < dim; ++d1)
2130  {
2131  for (unsigned int d2 = 0; d2 < dim; ++d2)
2132  {
2133  transformed_shape_grads[q][d1] -=
2134  data.shape_values(first + d2, q) *
2135  mapping_data.jacobian_pushed_forward_grads[q][d2][d1];
2136  }
2137  }
2138  }
2139 
2140  for (unsigned int q = 0; q < n_q_points; ++q)
2141  {
2142  for (unsigned int d = 0; d < dim; ++d)
2143  {
2144  data.shape_gradients[first + d][q] =
2145  transformed_shape_grads[q][d];
2146  }
2147  }
2148  }
2149  }
2150 }
2151 
2152 
2153 
2154 template <int dim, int spacedim>
2155 void
2157  const typename Triangulation<dim, dim>::cell_iterator & /*cell*/,
2158  const unsigned int /*face_no*/,
2159  const unsigned int /*sub_no*/,
2160  const Quadrature<dim - 1> & /*quadrature*/,
2161  const Mapping<dim, dim> & /*mapping*/,
2162  const typename Mapping<dim, dim>::InternalDataBase & /*mapping_internal*/,
2163  const ::internal::FEValuesImplementation::MappingRelatedData<dim, dim>
2164  & /*mapping_data*/,
2165  const typename FiniteElement<dim, dim>::InternalDataBase & /*fe_internal*/,
2167  & /*data*/) const
2168 {
2169  Assert(false, ExcNotImplemented());
2170 }
2171 
2172 
2173 
2174 template <int dim, int spacedim>
2177  const UpdateFlags flags) const
2178 {
2180 
2181  if (flags & update_values)
2183 
2184  if (flags & update_gradients)
2185  out |= update_gradients | update_values |
2188 
2189  if (flags & update_hessians)
2190  // Assert (false, ExcNotImplemented());
2195 
2196  return out;
2197 }
2198 
2199 
2200 
2201 template <int dim, int spacedim>
2202 std::string
2204 {
2205  // note that the
2206  // FETools::get_fe_from_name
2207  // function depends on the
2208  // particular format of the string
2209  // this function returns, so they
2210  // have to be kept in synch
2211 
2212  std::ostringstream namebuf;
2213  namebuf << "FE_NedelecSZ<" << dim << ">(" << this->degree - 1 << ")";
2214 
2215  return namebuf.str();
2216 }
2217 
2218 
2219 
2220 template <int dim, int spacedim>
2221 std::unique_ptr<FiniteElement<dim, dim>>
2223 {
2224  return std_cxx14::make_unique<FE_NedelecSZ<dim, spacedim>>(*this);
2225 }
2226 
2227 
2228 
2229 template <int dim, int spacedim>
2230 std::vector<unsigned int>
2232 {
2233  // internal function to return a vector of "dofs per object"
2234  // where the objects inside the vector refer to:
2235  // 0 = vertex
2236  // 1 = edge
2237  // 2 = face (which is a cell in 2D)
2238  // 3 = cell
2239  std::vector<unsigned int> dpo(dim + 1);
2240  dpo[0] = 0;
2241  dpo[1] = degree + 1;
2242  dpo[2] = 2 * degree * (degree + 1);
2243  if (dim == 3)
2244  {
2245  dpo[3] = 3 * degree * degree * (degree + 1);
2246  }
2247  return dpo;
2248 }
2249 
2250 
2251 
2252 template <int dim, int spacedim>
2253 unsigned int
2254 FE_NedelecSZ<dim, spacedim>::compute_num_dofs(const unsigned int degree) const
2255 {
2256  // Internal function to compute the number of DoFs
2257  // for a given dimension & polynomial order.
2258  switch (dim)
2259  {
2260  case 2:
2261  return 2 * (degree + 1) * (degree + 2);
2262 
2263  case 3:
2264  return 3 * (degree + 1) * (degree + 2) * (degree + 2);
2265 
2266  default:
2267  {
2268  Assert(false, ExcNotImplemented());
2269  return 0;
2270  }
2271  }
2272 }
2273 
2274 
2275 
2276 template <int dim, int spacedim>
2277 void
2279 {
2280  // fill the 1d polynomials vector:
2281  IntegratedLegendrePolynomials =
2283 }
2284 
2285 
2286 
2287 // explicit instantiations
2288 #include "fe_nedelec_sz.inst"
2289 
Mapping::transform
virtual void transform(const ArrayView< const Tensor< 1, dim >> &input, const MappingKind kind, const typename Mapping< dim, spacedim >::InternalDataBase &internal, const ArrayView< Tensor< 1, spacedim >> &output) const =0
internal::FEValuesImplementation::FiniteElementRelatedData::shape_gradients
GradientVector shape_gradients
Definition: fe_update_flags.h:590
internal::FEValuesImplementation::FiniteElementRelatedData
Definition: fe_update_flags.h:524
FE_NedelecSZ::InternalData::edge_lambda_grads_2d
std::vector< std::vector< double > > edge_lambda_grads_2d
Definition: fe_nedelec_sz.h:346
mapping_covariant_gradient
@ mapping_covariant_gradient
Definition: mapping.h:84
FE_NedelecSZ::InternalData::edge_sigma_values
std::vector< std::vector< double > > edge_sigma_values
Definition: fe_nedelec_sz.h:304
FE_NedelecSZ::create_polynomials
void create_polynomials(const unsigned int degree)
Definition: fe_nedelec_sz.cc:2278
StandardExceptions::ExcNotImplemented
static ::ExceptionBase & ExcNotImplemented()
Triangulation
Definition: tria.h:1109
FiniteElement< dim, dim >::component_to_base_table
std::vector< std::pair< std::pair< unsigned int, unsigned int >, unsigned int > > component_to_base_table
Definition: fe.h:2574
FiniteElementData
Definition: fe_base.h:147
fe_nedelec_sz.h
update_default
@ update_default
No update.
Definition: fe_update_flags.h:69
parallel::transform
void transform(const InputIterator &begin_in, const InputIterator &end_in, OutputIterator out, const Predicate &predicate, const unsigned int grainsize)
Definition: parallel.h:211
FE_NedelecSZ::fill_fe_subface_values
virtual void fill_fe_subface_values(const typename Triangulation< dim, dim >::cell_iterator &cell, const unsigned int face_no, const unsigned int sub_no, const Quadrature< dim - 1 > &quadrature, const Mapping< dim, dim > &mapping, const typename Mapping< dim, dim >::InternalDataBase &mapping_internal, const ::internal::FEValuesImplementation::MappingRelatedData< dim, dim > &mapping_data, const typename FiniteElement< dim, dim >::InternalDataBase &fedata, ::internal::FEValuesImplementation::FiniteElementRelatedData< dim, dim > &data) const override
Definition: fe_nedelec_sz.cc:2156
GeometryInfo
Definition: geometry_info.h:1224
FE_NedelecSZ::shape_grad
virtual Tensor< 1, dim > shape_grad(const unsigned int i, const Point< dim > &p) const override
Definition: fe_nedelec_sz.cc:79
DoFHandler::n_components
unsigned int n_components(const DoFHandler< dim, spacedim > &dh)
ComponentMask
Definition: component_mask.h:83
FE_NedelecSZ::get_data
virtual std::unique_ptr< typename ::FiniteElement< dim, spacedim >::InternalDataBase > get_data(const UpdateFlags update_flags, const Mapping< dim, spacedim > &mapping, const Quadrature< dim > &quadrature, ::internal::FEValuesImplementation::FiniteElementRelatedData< dim, spacedim > &output_data) const override
Definition: fe_nedelec_sz.cc:127
CellSimilarity::Similarity
Similarity
Definition: fe_update_flags.h:378
FE_NedelecSZ::shape_grad_grad
virtual Tensor< 2, dim > shape_grad_grad(const unsigned int i, const Point< dim > &p) const override
Definition: fe_nedelec_sz.cc:103
FE_NedelecSZ::clone
virtual std::unique_ptr< FiniteElement< dim, dim > > clone() const override
Definition: fe_nedelec_sz.cc:2222
FE_NedelecSZ::InternalData::face_lambda_values
std::vector< std::vector< double > > face_lambda_values
Definition: fe_nedelec_sz.h:387
update_values
@ update_values
Shape function values.
Definition: fe_update_flags.h:78
FE_NedelecSZ::compute_num_dofs
unsigned int compute_num_dofs(const unsigned int degree) const
Definition: fe_nedelec_sz.cc:2254
Physics::Elasticity::Kinematics::d
SymmetricTensor< 2, dim, Number > d(const Tensor< 2, dim, Number > &F, const Tensor< 2, dim, Number > &dF_dt)
FE_NedelecSZ::InternalData
Definition: fe_nedelec_sz.h:239
update_jacobian_pushed_forward_grads
@ update_jacobian_pushed_forward_grads
Definition: fe_update_flags.h:197
QProjector
Definition: qprojector.h:78
bool
DerivativeForm< 1, dim, dim >
FE_NedelecSZ::InternalData::edge_lambda_gradgrads_3d
std::vector< std::vector< std::vector< double > > > edge_lambda_gradgrads_3d
Definition: fe_nedelec_sz.h:369
Mapping
Abstract base class for mapping classes.
Definition: mapping.h:302
internal::FEValuesImplementation::FiniteElementRelatedData::shape_function_to_row_table
std::vector< unsigned int > shape_function_to_row_table
Definition: fe_update_flags.h:635
FE_NedelecSZ::get_dpo_vector
static std::vector< unsigned int > get_dpo_vector(const unsigned int degree)
Definition: fe_nedelec_sz.cc:2231
GeometryInfo::face_to_cell_vertices
static unsigned int face_to_cell_vertices(const unsigned int face, const unsigned int vertex, const bool face_orientation=true, const bool face_flip=false, const bool face_rotation=false)
FE_NedelecSZ::shape_grad_grad_component
virtual Tensor< 2, dim > shape_grad_grad_component(const unsigned int i, const Point< dim > &p, const unsigned int component) const override
Definition: fe_nedelec_sz.cc:114
FE_NedelecSZ::FE_NedelecSZ
FE_NedelecSZ(const unsigned int order)
Definition: fe_nedelec_sz.cc:24
FE_NedelecSZ::shape_value
virtual double shape_value(const unsigned int i, const Point< dim > &p) const override
Definition: fe_nedelec_sz.cc:54
update_covariant_transformation
@ update_covariant_transformation
Covariant transformation.
Definition: fe_update_flags.h:168
TrilinosWrappers::internal::begin
VectorType::value_type * begin(VectorType &V)
Definition: trilinos_sparse_matrix.cc:51
internal::FEValuesImplementation::FiniteElementRelatedData::shape_values
ShapeVector shape_values
Definition: fe_update_flags.h:583
Tensor< 1, dim >
QProjector::DataSetDescriptor
Definition: qprojector.h:220
DEAL_II_NAMESPACE_OPEN
#define DEAL_II_NAMESPACE_OPEN
Definition: config.h:358
FE_NedelecSZ::InternalData::shape_values
std::vector< std::vector< Tensor< 1, dim > > > shape_values
Definition: fe_nedelec_sz.h:248
update_gradients
@ update_gradients
Shape function gradients.
Definition: fe_update_flags.h:84
FE_NedelecSZ::requires_update_flags
virtual UpdateFlags requires_update_flags(const UpdateFlags update_flags) const override
Definition: fe_nedelec_sz.cc:2176
FE_NedelecSZ::InternalData::shape_grads
std::vector< std::vector< DerivativeForm< 1, dim, dim > > > shape_grads
Definition: fe_nedelec_sz.h:257
FiniteElement::InternalDataBase::update_each
UpdateFlags update_each
Definition: fe.h:715
TrilinosWrappers::internal::end
VectorType::value_type * end(VectorType &V)
Definition: trilinos_sparse_matrix.cc:65
FE_NedelecSZ::fill_fe_values
virtual void fill_fe_values(const typename Triangulation< dim, dim >::cell_iterator &cell, const CellSimilarity::Similarity cell_similarity, const Quadrature< dim > &quadrature, const Mapping< dim, dim > &mapping, const typename Mapping< dim, dim >::InternalDataBase &mapping_internal, const ::internal::FEValuesImplementation::MappingRelatedData< dim, dim > &mapping_data, const typename FiniteElement< dim, dim >::InternalDataBase &fedata, ::internal::FEValuesImplementation::FiniteElementRelatedData< dim, dim > &data) const override
Definition: fe_nedelec_sz.cc:1911
update_jacobian_pushed_forward_2nd_derivatives
@ update_jacobian_pushed_forward_2nd_derivatives
Definition: fe_update_flags.h:206
FE_NedelecSZ::shape_value_component
virtual double shape_value_component(const unsigned int i, const Point< dim > &p, const unsigned int component) const override
Definition: fe_nedelec_sz.cc:65
GeometryInfo::line_to_cell_vertices
static unsigned int line_to_cell_vertices(const unsigned int line, const unsigned int vertex)
FE_NedelecSZ::shape_grad_component
virtual Tensor< 1, dim > shape_grad_component(const unsigned int i, const Point< dim > &p, const unsigned int component) const override
Definition: fe_nedelec_sz.cc:90
FiniteElement
Definition: fe.h:648
FE_NedelecSZ::fill_edge_values
void fill_edge_values(const typename Triangulation< dim, dim >::cell_iterator &cell, const Quadrature< dim > &quadrature, const InternalData &fedata) const
Definition: fe_nedelec_sz.cc:1108
UpdateFlags
UpdateFlags
Definition: fe_update_flags.h:66
mapping_nedelec
@ mapping_nedelec
Definition: mapping.h:113
FE_NedelecSZ::fill_face_values
void fill_face_values(const typename Triangulation< dim, dim >::cell_iterator &cell, const Quadrature< dim > &quadrature, const InternalData &fedata) const
Definition: fe_nedelec_sz.cc:1535
ArrayView::make_array_view
ArrayView< typename std::remove_reference< typename std::iterator_traits< Iterator >::reference >::type, MemorySpaceType > make_array_view(const Iterator begin, const Iterator end)
Definition: array_view.h:607
QProjector::DataSetDescriptor::face
static DataSetDescriptor face(const unsigned int face_no, const bool face_orientation, const bool face_flip, const bool face_rotation, const unsigned int n_quadrature_points)
Definition: quadrature.cc:1141
StandardExceptions::ExcInternalError
static ::ExceptionBase & ExcInternalError()
Assert
#define Assert(cond, exc)
Definition: exceptions.h:1419
FE_NedelecSZ::InternalData::edge_lambda_values
std::vector< std::vector< double > > edge_lambda_values
Definition: fe_nedelec_sz.h:335
update_hessians
@ update_hessians
Second derivatives of shape functions.
Definition: fe_update_flags.h:90
FE_NedelecSZ::fill_fe_face_values
virtual void fill_fe_face_values(const typename Triangulation< dim, dim >::cell_iterator &cell, const unsigned int face_no, const Quadrature< dim - 1 > &quadrature, const Mapping< dim, dim > &mapping, const typename Mapping< dim, dim >::InternalDataBase &mapping_internal, const ::internal::FEValuesImplementation::MappingRelatedData< dim, dim > &mapping_data, const typename FiniteElement< dim, dim >::InternalDataBase &fedata, ::internal::FEValuesImplementation::FiniteElementRelatedData< dim, dim > &data) const override
Definition: fe_nedelec_sz.cc:2025
StandardExceptions::ExcImpossibleInDim
static ::ExceptionBase & ExcImpossibleInDim(int arg1)
FE_NedelecSZ::InternalData::face_lambda_grads
std::vector< std::vector< double > > face_lambda_grads
Definition: fe_nedelec_sz.h:397
StandardExceptions::ExcDimensionMismatch
static ::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
Point< dim >
FiniteElementData::n_components
unsigned int n_components() const
Quadrature::size
unsigned int size() const
memory.h
FE_NedelecSZ::InternalData::edge_lambda_grads_3d
std::vector< std::vector< std::vector< double > > > edge_lambda_grads_3d
Definition: fe_nedelec_sz.h:357
FE_NedelecSZ::get_name
virtual std::string get_name() const override
Definition: fe_nedelec_sz.cc:2203
FE_NedelecSZ::InternalData::sigma_imj_grads
std::vector< std::vector< std::vector< double > > > sigma_imj_grads
Definition: fe_nedelec_sz.h:291
Quadrature::get_points
const std::vector< Point< dim > > & get_points() const
mapping_covariant
@ mapping_covariant
Definition: mapping.h:73
DEAL_II_NAMESPACE_CLOSE
#define DEAL_II_NAMESPACE_CLOSE
Definition: config.h:359
IntegratedLegendreSZ::generate_complete_basis
static std::vector< Polynomials::Polynomial< double > > generate_complete_basis(const unsigned int degree)
Definition: polynomials_integrated_legendre_sz.cc:76
Quadrature
Definition: quadrature.h:85
first
Point< 2 > first
Definition: grid_out.cc:4352
FE_NedelecSZ::InternalData::edge_sigma_grads
std::vector< std::vector< double > > edge_sigma_grads
Definition: fe_nedelec_sz.h:318
FE_NedelecSZ::InternalData::sigma_imj_values
std::vector< std::vector< std::vector< double > > > sigma_imj_values
Definition: fe_nedelec_sz.h:274
FE_NedelecSZ::mapping_kind
MappingKind mapping_kind
Definition: fe_nedelec_sz.h:155