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