deal.II version GIT relicensing-6834-g5b78e6bcdf 2026-10-01 11:20:01+00:00
\(\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\}}\)
Loading...
Searching...
No Matches
fe_nedelec_sz.cc
Go to the documentation of this file.
1// -----------------------------------------------------------------------------
2//
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception OR LGPL-2.1-or-later
4// Copyright (C) 2018 - 2026 by the deal.II authors
5//
6// This file is part of the deal.II library.
7//
8// Detailed license information governing the source code and contributions
9// can be found in LICENSE.md and CONTRIBUTING.md at the top level directory.
10//
11// -----------------------------------------------------------------------------
12
13
15
17#include <deal.II/fe/fe_tools.h>
18
19#include <memory>
20
22
23// Constructor:
24template <int dim, int spacedim>
26 : FiniteElement<dim, dim>(
27 FiniteElementData<dim>(get_dpo_vector(order),
28 dim,
29 order + 1,
30 FiniteElementData<dim>::Hcurl),
31 std::vector<bool>(compute_num_dofs(order), true),
32 std::vector<ComponentMask>(compute_num_dofs(order),
33 ComponentMask(std::vector<bool>(dim, true))))
34{
35 Assert(dim >= 2, ExcImpossibleInDim(dim));
36
38 // Set up the table converting components to base components. Since we have
39 // only one base element, everything remains zero except the component in the
40 // base, which is the component itself.
41 for (unsigned int comp = 0; comp < this->n_components(); ++comp)
42 {
43 this->component_to_base_table[comp].first.second = comp;
44 }
45
46 // Generate the 1-D polynomial basis.
47 create_polynomials(order);
48
49 // Compute the face embedding.
51
52 // The implementation assumes that all faces have the same
53 // number of DoFs.
55 const unsigned int face_no = 1;
56 for (unsigned int i = 0; i < GeometryInfo<dim>::max_children_per_face; ++i)
57 {
58 face_embeddings[i].reinit(this->n_dofs_per_face(face_no),
59 this->n_dofs_per_face(face_no));
60 }
61
62 FETools::compute_face_embedding_matrices<dim, double>(
63 *this, face_embeddings, 0, 0, 1.e-15 * std::exp(std::pow(order, 1.075)));
64
65 switch (dim)
66 {
67 case 1:
68 {
69 this->interface_constraints.reinit(0, 0);
70 break;
71 }
72
73 case 2:
74 {
75 this->interface_constraints.reinit(2 * this->n_dofs_per_face(face_no),
76 this->n_dofs_per_face(face_no));
77 for (unsigned int i = 0; i < GeometryInfo<2>::max_children_per_face;
78 ++i)
79 {
80 for (unsigned int j = 0; j < this->n_dofs_per_face(face_no); ++j)
81 {
82 for (unsigned int k = 0; k < this->n_dofs_per_face(face_no);
83 ++k)
84 {
86 i * this->n_dofs_per_face(face_no) + j, k) =
87 face_embeddings[i](j, k);
88 }
89 }
90 }
91 break;
92 }
93
94 case 3:
95 {
96 this->interface_constraints.reinit(
97 4 * (this->n_dofs_per_face(face_no) - this->degree),
98 this->n_dofs_per_face(face_no));
99 unsigned int target_row = 0;
100 for (unsigned int i = 0; i < 2; ++i)
101 for (unsigned int j = this->degree; j < 2 * this->degree;
102 ++j, ++target_row)
103 for (unsigned int k = 0; k < this->n_dofs_per_face(face_no); ++k)
104 this->interface_constraints(target_row, k) =
105 face_embeddings[2 * i](j, k);
106 for (unsigned int i = 0; i < 2; ++i)
107 for (unsigned int j = 3 * this->degree;
108 j < GeometryInfo<3>::lines_per_face * this->degree;
109 ++j, ++target_row)
110 for (unsigned int k = 0; k < this->n_dofs_per_face(face_no); ++k)
111 this->interface_constraints(target_row, k) =
112 face_embeddings[i](j, k);
113 for (unsigned int i = 0; i < 2; ++i)
114 for (unsigned int j = 0; j < 2; ++j)
115 for (unsigned int k = i * this->degree;
116 k < (i + 1) * this->degree;
117 ++k, ++target_row)
118 for (unsigned int l = 0; l < this->n_dofs_per_face(face_no);
119 ++l)
120 this->interface_constraints(target_row, l) =
121 face_embeddings[i + 2 * j](k, l);
122 for (unsigned int i = 0; i < 2; ++i)
123 for (unsigned int j = 0; j < 2; ++j)
124 for (unsigned int k = (i + 2) * this->degree;
125 k < (i + 3) * this->degree;
126 ++k, ++target_row)
127 for (unsigned int l = 0; l < this->n_dofs_per_face(face_no);
128 ++l)
129 this->interface_constraints(target_row, l) =
130 face_embeddings[2 * i + j](k, l);
131 for (unsigned int i = 0; i < GeometryInfo<3>::max_children_per_face;
132 ++i)
133 for (unsigned int j =
134 GeometryInfo<3>::lines_per_face * this->degree;
135 j < this->n_dofs_per_face(face_no);
136 ++j, ++target_row)
137 for (unsigned int k = 0; k < this->n_dofs_per_face(face_no); ++k)
138 this->interface_constraints(target_row, k) =
139 face_embeddings[i](j, k);
140 break;
141 }
142
143 default:
145 }
146}
147
148
149
150// Shape functions:
151template <int dim, int spacedim>
152double
154 const Point<dim> & /*p*/) const
155{
157 return 0.;
158}
159
160
161
162template <int dim, int spacedim>
163double
165 const unsigned int i,
166 const Point<dim> &p,
167 const unsigned int component) const
168{
169 AssertIndexRange(i, this->n_dofs_per_cell());
170 AssertIndexRange(component, dim);
171
172 std::unique_ptr<
173 typename ::FiniteElement<dim, spacedim>::InternalDataBase>
174 data_ptr = std::make_unique<InternalData>();
175
176 std::vector<Point<dim>> p_list = {p};
177
178 // compute the data
179 this->evaluate(p_list, update_values, data_ptr);
180
181 // access the data
182 auto &data = dynamic_cast<InternalData &>(*data_ptr);
183 return data.shape_values[i][0][component];
184}
185
186
187
188template <int dim, int spacedim>
191 const Point<dim> & /*p*/) const
192{
194 return Tensor<1, dim>();
195}
196
197
198
199template <int dim, int spacedim>
202 const unsigned int i,
203 const Point<dim> &p,
204 const unsigned int component) const
205{
206 AssertIndexRange(i, this->n_dofs_per_cell());
207 AssertIndexRange(component, dim);
208
209 std::unique_ptr<
210 typename ::FiniteElement<dim, spacedim>::InternalDataBase>
211 data_ptr = std::make_unique<InternalData>();
212
213 std::vector<Point<dim>> p_list = {p};
214
215 // compute the data
216 this->evaluate(p_list, update_gradients, data_ptr);
217
218 // access the data
219 auto &data = dynamic_cast<InternalData &>(*data_ptr);
220 return data.shape_grads[i][0][component];
221}
222
223
224
225template <int dim, int spacedim>
228 const Point<dim> & /*p*/) const
229{
231 return Tensor<2, dim>();
232}
233
234
235
236template <int dim, int spacedim>
239 const unsigned int i,
240 const Point<dim> &p,
241 const unsigned int component) const
242{
243 AssertIndexRange(i, this->n_dofs_per_cell());
244 AssertIndexRange(component, dim);
245
246 std::unique_ptr<
247 typename ::FiniteElement<dim, spacedim>::InternalDataBase>
248 data_ptr = std::make_unique<InternalData>();
249
250 std::vector<Point<dim>> p_list = {p};
251
252 // compute the data
253 this->evaluate(p_list, update_hessians, data_ptr);
254
255 // access the data
256 auto &data = dynamic_cast<InternalData &>(*data_ptr);
257 return data.shape_hessians[i][0][component];
258}
259
260
261
262template <int dim, int spacedim>
263void
265 const std::vector<Point<dim>> &p_list,
266 const UpdateFlags update_flags,
267 std::unique_ptr<
268 typename ::FiniteElement<dim, spacedim>::InternalDataBase> &data_ptr)
269 const
270{
271 auto &data = dynamic_cast<InternalData &>(*data_ptr);
272 data.update_each = requires_update_flags(update_flags);
273
274 // Useful quantities:
275 const unsigned int degree(this->degree - 1); // Note: FE holds input degree+1
276
277 const unsigned int vertices_per_cell = GeometryInfo<dim>::vertices_per_cell;
278 const unsigned int lines_per_cell = GeometryInfo<dim>::lines_per_cell;
279 const unsigned int faces_per_cell = GeometryInfo<dim>::faces_per_cell;
280
281 const unsigned int n_line_dofs = this->n_dofs_per_line() * lines_per_cell;
282 // we assume that all quads have the same number of dofs
283 const unsigned int n_face_dofs = this->n_dofs_per_quad(0) * faces_per_cell;
284
285 const unsigned int n_q_points = p_list.size();
286
287 const UpdateFlags flags(data.update_each);
288
289 // Resize the internal data storage:
290 data.sigma_imj_values.resize(
291 n_q_points,
292 std::vector<std::vector<double>>(vertices_per_cell,
293 std::vector<double>(vertices_per_cell)));
294
295 data.sigma_imj_grads.resize(vertices_per_cell,
296 std::vector<std::vector<double>>(
297 vertices_per_cell, std::vector<double>(dim)));
298
299 // Resize shape function arrays according to update flags:
300 if (flags & update_values)
301 data.shape_values.resize(this->n_dofs_per_cell(),
302 std::vector<Tensor<1, dim>>(n_q_points));
303
304 if (flags & update_gradients)
305 data.shape_grads.resize(this->n_dofs_per_cell(),
306 std::vector<DerivativeForm<1, dim, dim>>(
307 n_q_points));
308
309 if (flags & update_hessians)
310 data.shape_hessians.resize(this->n_dofs_per_cell(),
311 std::vector<DerivativeForm<2, dim, dim>>(
312 n_q_points));
313
314 // Compute values of sigma & lambda and the sigma differences and
315 // lambda additions.
316 std::vector<std::vector<double>> sigma(n_q_points,
317 std::vector<double>(lines_per_cell));
318 std::vector<std::vector<double>> lambda(n_q_points,
319 std::vector<double>(lines_per_cell));
320
321 switch (dim)
322 {
323 case 2:
324 {
325 for (unsigned int q = 0; q < n_q_points; ++q)
326 {
327 sigma[q][0] = (1.0 - p_list[q][0]) + (1.0 - p_list[q][1]);
328 sigma[q][1] = p_list[q][0] + (1.0 - p_list[q][1]);
329 sigma[q][2] = (1.0 - p_list[q][0]) + p_list[q][1];
330 sigma[q][3] = p_list[q][0] + p_list[q][1];
331
332 lambda[q][0] = (1.0 - p_list[q][0]) * (1.0 - p_list[q][1]);
333 lambda[q][1] = p_list[q][0] * (1.0 - p_list[q][1]);
334 lambda[q][2] = (1.0 - p_list[q][0]) * p_list[q][1];
335 lambda[q][3] = p_list[q][0] * p_list[q][1];
336 for (unsigned int i = 0; i < vertices_per_cell; ++i)
337 for (unsigned int j = 0; j < vertices_per_cell; ++j)
338 data.sigma_imj_values[q][i][j] = sigma[q][i] - sigma[q][j];
339 }
340
341 // Calculate the gradient of sigma_imj_values[q][i][j] =
342 // sigma[q][i]-sigma[q][j]
343 // - this depends on the component and the direction of the
344 // corresponding edge.
345 // - the direction of the edge is determined by
346 // sigma_imj_sign[i][j].
347 // Helper arrays:
348 const int sigma_comp_signs[GeometryInfo<2>::vertices_per_cell][2] = {
349 {-1, -1}, {1, -1}, {-1, 1}, {1, 1}};
350 int sigma_imj_sign[vertices_per_cell][vertices_per_cell];
351 unsigned int sigma_imj_component[vertices_per_cell]
352 [vertices_per_cell];
353
354 for (unsigned int i = 0; i < vertices_per_cell; ++i)
355 for (unsigned int j = 0; j < vertices_per_cell; ++j)
356 {
357 // sigma_imj_sign is the sign (+/-) of the coefficient of
358 // x/y/z in sigma_imj_values Due to the numbering of vertices
359 // on the reference element it is easy to find edges in the
360 // positive direction are from smaller to higher local vertex
361 // numbering.
362 sigma_imj_sign[i][j] = (i < j) ? -1 : 1;
363 sigma_imj_sign[i][j] = (i == j) ? 0 : sigma_imj_sign[i][j];
364
365 // Now store the component which the sigma_i - sigma_j
366 // corresponds to:
367 sigma_imj_component[i][j] = 0;
368 for (unsigned int d = 0; d < dim; ++d)
369 {
370 int temp_imj =
371 sigma_comp_signs[i][d] - sigma_comp_signs[j][d];
372 // Only interested in the first non-zero
373 // as if there is a second, it can not be a valid edge.
374 if (temp_imj != 0)
375 {
376 sigma_imj_component[i][j] = d;
377 break;
378 }
379 }
380 // Can now calculate the gradient, only non-zero in the
381 // component given: Note some i,j combinations will be
382 // incorrect, but only on invalid edges.
383 data.sigma_imj_grads[i][j][sigma_imj_component[i][j]] =
384 2.0 * sigma_imj_sign[i][j];
385 }
386
387 // Now compute the edge parameterisations for a single element
388 // with global numbering matching that of the reference element:
389
390 // Resize the edge parameterisations
391 data.edge_sigma_values.resize(lines_per_cell,
392 std::vector<double>(n_q_points));
393 data.edge_sigma_grads.resize(lines_per_cell,
394 std::vector<double>(dim));
395
396 // Fill the values for edge lambda and edge sigma:
397 const unsigned int
398 edge_sigma_direction[GeometryInfo<2>::lines_per_cell] = {1,
399 1,
400 0,
401 0};
402
403 data.edge_lambda_values.resize(lines_per_cell,
404 std::vector<double>(n_q_points));
405
406 data.edge_lambda_grads_2d.resize(lines_per_cell,
407 std::vector<double>(dim));
408
409 for (unsigned int m = 0; m < lines_per_cell; ++m)
410 {
411 // e1=max(reference vertex numbering on this edge)
412 // e2=min(reference vertex numbering on this edge)
413 // Which is guaranteed to be:
414 const unsigned int e1(
416 const unsigned int e2(
418 for (unsigned int q = 0; q < n_q_points; ++q)
419 {
420 data.edge_sigma_values[m][q] =
421 data.sigma_imj_values[q][e2][e1];
422 data.edge_lambda_values[m][q] = lambda[q][e1] + lambda[q][e2];
423 }
424
425 data.edge_sigma_grads[m][edge_sigma_direction[m]] = -2.0;
426 }
427
428 data.edge_lambda_grads_2d[0] = {-1.0, 0.0};
429 data.edge_lambda_grads_2d[1] = {1.0, 0.0};
430 data.edge_lambda_grads_2d[2] = {0.0, -1.0};
431 data.edge_lambda_grads_2d[3] = {0.0, 1.0};
432
433 // If the polynomial order is 0, then no more work to do:
434 if (degree < 1)
435 break;
436
437 // Otherwise, we can compute the non-cell dependent shape functions.
438 //
439 // Note: the local dof numberings follow the usual order of lines ->
440 // faces -> cells
441 // (we have no vertex-based DoFs in this element).
442 // For a given cell we have:
443 // n_line_dofs = dofs_per_line*lines_per_cell.
444 // n_face_dofs = dofs_per_face*faces_per_cell.
445 // n_cell_dofs = dofs_per_quad (2d)
446 // = dofs_per_hex (3d)
447 //
448 // i.e. For the local dof numbering:
449 // the first line dof is 0,
450 // the first face dof is n_line_dofs,
451 // the first cell dof is n_line_dofs + n_face_dofs.
452 //
453 // On a line, DoFs are ordered first by line_dof and then line_index:
454 // i.e. line_dof_index = line_dof + line_index*(dofs_per_line)
455 //
456 // and similarly for faces:
457 // i.e. face_dof_index = face_dof + face_index*(dofs_per_face).
458 //
459 // HOWEVER, we have different types of DoFs on a line/face/cell.
460 // On a line we have two types, lowest order and higher order
461 // gradients.
462 // - The numbering is such the lowest order is first, then higher
463 // order.
464 // This is simple enough as there is only 1 lowest order and
465 // degree higher orders DoFs per line.
466 //
467 // On a 2d cell, we have 3 types: Type 1/2/3:
468 // - The ordering done by type:
469 // - Type 1: 0 <= i1,j1 < degree. degree^2 in total.
470 // Numbered: ij1 = i1 + j1*(degree). i.e. cell_dof_index
471 // = ij1.
472 // - Type 2: 0 <= i2,j2 < degree. degree^2 in total.
473 // Numbered: ij2 = i2 + j2*(degree). i.e. cell_dof_index
474 // = degree^2 + ij2
475 // - Type 3: 0 <= i3 < 2*degree. 2*degree in total.
476 // Numbered: ij3 = i3. i.e. cell_dof_index
477 // = 2*(degree^2) + ij3.
478 //
479 // These then fit into the local dof numbering described above:
480 // - local dof numberings are:
481 // line_dofs: local_dof = line_dof_index. 0 <= local_dof <
482 // dofs_per_line*lines_per_cell face_dofs: local_dof =
483 // n_line_dofs*lines_per_cell + face_dof_index. cell dofs: local_dof
484 // = n_lines_dof + n_face_dofs + cell_dof_index.
485 //
486 // The cell-based shape functions are:
487 //
488 // Type 1 (gradients):
489 // \phi^{C_{1}}_{ij} = grad( L_{i+2}(2x-1)L_{j+2}(2y-1) ),
490 //
491 // 0 <= i,j < degree.
492 //
493 // NOTE: The derivative produced by IntegratedLegendrePolynomials does
494 // not account for the
495 // (2*x-1) or (2*y-1) so we must take this into account when
496 // taking derivatives.
497 const unsigned int cell_type1_offset = n_line_dofs;
498
499 // Type 2:
500 // \phi^{C_{2}}_{ij} = L'_{i+2}(2x-1) L_{j+2}(2y-1) \mathbf{e}_{x}
501 // - L_{i+2}(2x-1) L'_{j+2}(2y-1) \mathbf{e}_{y},
502 //
503 // 0 <= i,j < degree.
504 const unsigned int cell_type2_offset =
505 cell_type1_offset + degree * degree;
506
507 // Type 3 (two subtypes):
508 // \phi^{C_{3}}_{j} = L_{j+2}(2y-1) \mathbf{e}_{x}
509 //
510 // \phi^{C_{3}}_{j+degree} = L_{j+2}(2x-1) \mathbf{e}_{y}
511 //
512 // 0 <= j < degree
513 const unsigned int cell_type3_offset1 =
514 cell_type2_offset + degree * degree;
515 const unsigned int cell_type3_offset2 = cell_type3_offset1 + degree;
516
518 {
519 // compute all points we must evaluate the 1d polynomials at:
520 std::vector<Point<dim>> cell_points(n_q_points);
521 for (unsigned int q = 0; q < n_q_points; ++q)
522 for (unsigned int d = 0; d < dim; ++d)
523 cell_points[q][d] = 2.0 * p_list[q][d] - 1.0;
524
525 // Loop through quad points:
526 for (unsigned int q = 0; q < n_q_points; ++q)
527 {
528 // pre-compute values & required derivatives at this quad
529 // point (x,y): polyx = L_{i+2}(2x-1), polyy = L_{j+2}(2y-1),
530 //
531 // for each polyc[d], c=x,y, contains the d-th derivative with
532 // respect to the coordinate c.
533
534 // We only need poly values and 1st derivative for
535 // update_values, but need the 2nd derivative too for
536 // update_gradients. For update_hessians we also need the 3rd
537 // derivatives.
538 const unsigned int poly_length =
539 (flags & update_hessians) ?
540 4 :
541 ((flags & update_gradients) ? 3 : 2);
542
543 std::vector<std::vector<double>> polyx(
544 degree, std::vector<double>(poly_length));
545 std::vector<std::vector<double>> polyy(
546 degree, std::vector<double>(poly_length));
547 for (unsigned int i = 0; i < degree; ++i)
548 {
549 // Compute all required 1d polynomials and their
550 // derivatives, starting at degree 2. e.g. to access
551 // L'_{3}(2x-1) use polyx[1][1].
552 IntegratedLegendrePolynomials[i + 2].value(
553 cell_points[q][0], polyx[i]);
554 IntegratedLegendrePolynomials[i + 2].value(
555 cell_points[q][1], polyy[i]);
556 }
557 // Now use these to compute the shape functions:
558 if (flags & update_values)
559 {
560 for (unsigned int j = 0; j < degree; ++j)
561 {
562 const unsigned int shift_j(j * degree);
563 for (unsigned int i = 0; i < degree; ++i)
564 {
565 const unsigned int shift_ij(i + shift_j);
566
567 // Type 1:
568 const unsigned int dof_index1(cell_type1_offset +
569 shift_ij);
570 data.shape_values[dof_index1][q][0] =
571 2.0 * polyx[i][1] * polyy[j][0];
572 data.shape_values[dof_index1][q][1] =
573 2.0 * polyx[i][0] * polyy[j][1];
574
575 // Type 2:
576 const unsigned int dof_index2(cell_type2_offset +
577 shift_ij);
578 data.shape_values[dof_index2][q][0] =
579 data.shape_values[dof_index1][q][0];
580 data.shape_values[dof_index2][q][1] =
581 -1.0 * data.shape_values[dof_index1][q][1];
582 }
583 // Type 3:
584 const unsigned int dof_index3_1(cell_type3_offset1 +
585 j);
586 data.shape_values[dof_index3_1][q][0] = polyy[j][0];
587 data.shape_values[dof_index3_1][q][1] = 0.0;
588
589 const unsigned int dof_index3_2(cell_type3_offset2 +
590 j);
591 data.shape_values[dof_index3_2][q][0] = 0.0;
592 data.shape_values[dof_index3_2][q][1] = polyx[j][0];
593 }
594 }
595 if (flags & update_gradients)
596 {
597 for (unsigned int j = 0; j < degree; ++j)
598 {
599 const unsigned int shift_j(j * degree);
600 for (unsigned int i = 0; i < degree; ++i)
601 {
602 const unsigned int shift_ij(i + shift_j);
603
604 // Type 1:
605 const unsigned int dof_index1(cell_type1_offset +
606 shift_ij);
607 data.shape_grads[dof_index1][q][0][0] =
608 4.0 * polyx[i][2] * polyy[j][0];
609 data.shape_grads[dof_index1][q][0][1] =
610 4.0 * polyx[i][1] * polyy[j][1];
611 data.shape_grads[dof_index1][q][1][0] =
612 data.shape_grads[dof_index1][q][0][1];
613 data.shape_grads[dof_index1][q][1][1] =
614 4.0 * polyx[i][0] * polyy[j][2];
615
616 // Type 2:
617 const unsigned int dof_index2(cell_type2_offset +
618 shift_ij);
619 data.shape_grads[dof_index2][q][0][0] =
620 data.shape_grads[dof_index1][q][0][0];
621 data.shape_grads[dof_index2][q][0][1] =
622 data.shape_grads[dof_index1][q][0][1];
623 data.shape_grads[dof_index2][q][1][0] =
624 -1.0 * data.shape_grads[dof_index1][q][1][0];
625 data.shape_grads[dof_index2][q][1][1] =
626 -1.0 * data.shape_grads[dof_index1][q][1][1];
627 }
628 // Type 3:
629 const unsigned int dof_index3_1(cell_type3_offset1 +
630 j);
631 data.shape_grads[dof_index3_1][q][0][0] = 0.0;
632 data.shape_grads[dof_index3_1][q][0][1] =
633 2.0 * polyy[j][1];
634 data.shape_grads[dof_index3_1][q][1][0] = 0.0;
635 data.shape_grads[dof_index3_1][q][1][1] = 0.0;
636
637 const unsigned int dof_index3_2(cell_type3_offset2 +
638 j);
639 data.shape_grads[dof_index3_2][q][0][0] = 0.0;
640 data.shape_grads[dof_index3_2][q][0][1] = 0.0;
641 data.shape_grads[dof_index3_2][q][1][0] =
642 2.0 * polyx[j][1];
643 data.shape_grads[dof_index3_2][q][1][1] = 0.0;
644 }
645 }
646 if (flags & update_hessians)
647 {
648 for (unsigned int j = 0; j < degree; ++j)
649 {
650 const unsigned int shift_j(j * degree);
651 for (unsigned int i = 0; i < degree; ++i)
652 {
653 const unsigned int shift_ij(i + shift_j);
654
655 // Type 1:
656 const unsigned int dof_index1(cell_type1_offset +
657 shift_ij);
658 data.shape_hessians[dof_index1][q][0][0][0] =
659 8.0 * polyx[i][3] * polyy[j][0];
660 data.shape_hessians[dof_index1][q][1][0][0] =
661 8.0 * polyx[i][2] * polyy[j][1];
662
663 data.shape_hessians[dof_index1][q][0][1][0] =
664 data.shape_hessians[dof_index1][q][1][0][0];
665 data.shape_hessians[dof_index1][q][1][1][0] =
666 8.0 * polyx[i][1] * polyy[j][2];
667
668 data.shape_hessians[dof_index1][q][0][0][1] =
669 data.shape_hessians[dof_index1][q][1][0][0];
670 data.shape_hessians[dof_index1][q][1][0][1] =
671 data.shape_hessians[dof_index1][q][1][1][0];
672
673 data.shape_hessians[dof_index1][q][0][1][1] =
674 data.shape_hessians[dof_index1][q][1][1][0];
675 data.shape_hessians[dof_index1][q][1][1][1] =
676 8.0 * polyx[i][0] * polyy[j][3];
677
678
679
680 // Type 2:
681 const unsigned int dof_index2(cell_type2_offset +
682 shift_ij);
683 for (unsigned int d = 0; d < dim; ++d)
684 {
685 data.shape_hessians[dof_index2][q][0][0][d] =
686 data.shape_hessians[dof_index1][q][0][0][d];
687 data.shape_hessians[dof_index2][q][0][1][d] =
688 data.shape_hessians[dof_index1][q][0][1][d];
689 data.shape_hessians[dof_index2][q][1][0][d] =
690 -1.0 *
691 data.shape_hessians[dof_index1][q][1][0][d];
692 data.shape_hessians[dof_index2][q][1][1][d] =
693 -1.0 *
694 data.shape_hessians[dof_index1][q][1][1][d];
695 }
696 }
697 // Type 3:
698 const unsigned int dof_index3_1(cell_type3_offset1 +
699 j);
700 data.shape_hessians[dof_index3_1][q][0][0][0] = 0.0;
701 data.shape_hessians[dof_index3_1][q][0][0][1] = 0.0;
702 data.shape_hessians[dof_index3_1][q][0][1][0] = 0.0;
703 data.shape_hessians[dof_index3_1][q][0][1][1] =
704 4.0 * polyy[j][2];
705 data.shape_hessians[dof_index3_1][q][1][0][0] = 0.0;
706 data.shape_hessians[dof_index3_1][q][1][0][1] = 0.0;
707 data.shape_hessians[dof_index3_1][q][1][1][0] = 0.0;
708 data.shape_hessians[dof_index3_1][q][1][1][1] = 0.0;
709
710 const unsigned int dof_index3_2(cell_type3_offset2 +
711 j);
712 data.shape_hessians[dof_index3_2][q][0][0][0] = 0.0;
713 data.shape_hessians[dof_index3_2][q][0][0][1] = 0.0;
714 data.shape_hessians[dof_index3_2][q][0][1][0] = 0.0;
715 data.shape_hessians[dof_index3_2][q][0][1][1] = 0.0;
716 data.shape_hessians[dof_index3_2][q][1][0][0] =
717 4.0 * polyx[j][2];
718 data.shape_hessians[dof_index3_2][q][1][0][1] = 0.0;
719 data.shape_hessians[dof_index3_2][q][1][1][0] = 0.0;
720 data.shape_hessians[dof_index3_2][q][1][1][1] = 0.0;
721 }
722 }
723 }
724 }
725 break;
726 }
727
728 case 3:
729 {
730 for (unsigned int q = 0; q < n_q_points; ++q)
731 {
732 sigma[q][0] = (1.0 - p_list[q][0]) + (1.0 - p_list[q][1]) +
733 (1 - p_list[q][2]);
734 sigma[q][1] =
735 p_list[q][0] + (1.0 - p_list[q][1]) + (1 - p_list[q][2]);
736 sigma[q][2] =
737 (1.0 - p_list[q][0]) + p_list[q][1] + (1 - p_list[q][2]);
738 sigma[q][3] = p_list[q][0] + p_list[q][1] + (1 - p_list[q][2]);
739 sigma[q][4] =
740 (1.0 - p_list[q][0]) + (1.0 - p_list[q][1]) + p_list[q][2];
741 sigma[q][5] = p_list[q][0] + (1.0 - p_list[q][1]) + p_list[q][2];
742 sigma[q][6] = (1.0 - p_list[q][0]) + p_list[q][1] + p_list[q][2];
743 sigma[q][7] = p_list[q][0] + p_list[q][1] + p_list[q][2];
744
745 lambda[q][0] = (1.0 - p_list[q][0]) * (1.0 - p_list[q][1]) *
746 (1.0 - p_list[q][2]);
747 lambda[q][1] =
748 p_list[q][0] * (1.0 - p_list[q][1]) * (1.0 - p_list[q][2]);
749 lambda[q][2] =
750 (1.0 - p_list[q][0]) * p_list[q][1] * (1.0 - p_list[q][2]);
751 lambda[q][3] = p_list[q][0] * p_list[q][1] * (1.0 - p_list[q][2]);
752 lambda[q][4] =
753 (1.0 - p_list[q][0]) * (1.0 - p_list[q][1]) * p_list[q][2];
754 lambda[q][5] = p_list[q][0] * (1.0 - p_list[q][1]) * p_list[q][2];
755 lambda[q][6] = (1.0 - p_list[q][0]) * p_list[q][1] * p_list[q][2];
756 lambda[q][7] = p_list[q][0] * p_list[q][1] * p_list[q][2];
757
758 // Compute values of sigma_imj = \sigma_{i} - \sigma_{j}
759 // and lambda_ipj = \lambda_{i} + \lambda_{j}.
760 for (unsigned int i = 0; i < vertices_per_cell; ++i)
761 for (unsigned int j = 0; j < vertices_per_cell; ++j)
762 data.sigma_imj_values[q][i][j] = sigma[q][i] - sigma[q][j];
763 }
764
765 // We now want some additional information about
766 // sigma_imj_values[q][i][j] = sigma[q][i]-sigma[q][j] In order to
767 // calculate values & derivatives of the shape functions we need to
768 // know:
769 // - The component the sigma_imj value corresponds to - this varies
770 // with i & j.
771 // - The gradient of the sigma_imj value
772 // - this depends on the component and the direction of the
773 // corresponding edge.
774 // - the direction of the edge is determined by
775 // sigma_imj_sign[i][j].
776 //
777 // Note that not every i,j combination is a valid edge (there are only
778 // 12 valid edges in 3d), but we compute them all as it simplifies
779 // things.
780
781 // store the sign of each component x, y, z in the sigma list.
782 // can use this to fill in the sigma_imj_component data.
783 const int sigma_comp_signs[GeometryInfo<3>::vertices_per_cell][3] = {
784 {-1, -1, -1},
785 {1, -1, -1},
786 {-1, 1, -1},
787 {1, 1, -1},
788 {-1, -1, 1},
789 {1, -1, 1},
790 {-1, 1, 1},
791 {1, 1, 1}};
792
793 int sigma_imj_sign[vertices_per_cell][vertices_per_cell];
794 unsigned int sigma_imj_component[vertices_per_cell]
795 [vertices_per_cell];
796
797 for (unsigned int i = 0; i < vertices_per_cell; ++i)
798 for (unsigned int j = 0; j < vertices_per_cell; ++j)
799 {
800 // sigma_imj_sign is the sign (+/-) of the coefficient of
801 // x/y/z in sigma_imj. Due to the numbering of vertices on the
802 // reference element this is easy to work out because edges in
803 // the positive direction go from smaller to higher local
804 // vertex numbering.
805 sigma_imj_sign[i][j] = (i < j) ? -1 : 1;
806 sigma_imj_sign[i][j] = (i == j) ? 0 : sigma_imj_sign[i][j];
807
808 // Now store the component which the sigma_i - sigma_j
809 // corresponds to:
810 sigma_imj_component[i][j] = 0;
811 for (unsigned int d = 0; d < dim; ++d)
812 {
813 int temp_imj =
814 sigma_comp_signs[i][d] - sigma_comp_signs[j][d];
815 // Only interested in the first non-zero
816 // as if there is a second, it will not be a valid edge.
817 if (temp_imj != 0)
818 {
819 sigma_imj_component[i][j] = d;
820 break;
821 }
822 }
823 // Can now calculate the gradient, only non-zero in the
824 // component given: Note some i,j combinations will be
825 // incorrect, but only on invalid edges.
826 data.sigma_imj_grads[i][j][sigma_imj_component[i][j]] =
827 2.0 * sigma_imj_sign[i][j];
828 }
829
830 // Now compute the edge parameterisations for a single element
831 // with global numbering matching that of the reference element:
832
833 // resize the edge parameterisations
834 data.edge_sigma_values.resize(lines_per_cell,
835 std::vector<double>(n_q_points));
836 data.edge_lambda_values.resize(lines_per_cell,
837 std::vector<double>(n_q_points));
838 data.edge_sigma_grads.resize(lines_per_cell,
839 std::vector<double>(dim));
840 data.edge_lambda_grads_3d.resize(
841 lines_per_cell,
842 std::vector<std::vector<double>>(n_q_points,
843 std::vector<double>(dim)));
844 data.edge_lambda_gradgrads_3d.resize(
845 lines_per_cell,
846 std::vector<std::vector<double>>(dim, std::vector<double>(dim)));
847
848 // Fill the values:
849 const unsigned int
850 edge_sigma_direction[GeometryInfo<3>::lines_per_cell] = {
851 1, 1, 0, 0, 1, 1, 0, 0, 2, 2, 2, 2};
852
853 for (unsigned int m = 0; m < lines_per_cell; ++m)
854 {
855 // e1=max(reference vertex numbering on this edge)
856 // e2=min(reference vertex numbering on this edge)
857 // Which is guaranteed to be:
858 const unsigned int e1(
860 const unsigned int e2(
862
863 for (unsigned int q = 0; q < n_q_points; ++q)
864 {
865 data.edge_sigma_values[m][q] =
866 data.sigma_imj_values[q][e2][e1];
867 data.edge_lambda_values[m][q] = lambda[q][e1] + lambda[q][e2];
868 }
869
870 data.edge_sigma_grads[m][edge_sigma_direction[m]] = -2.0;
871 }
872
873 // edge_lambda_grads
874 for (unsigned int q = 0; q < n_q_points; ++q)
875 {
876 double x(p_list[q][0]);
877 double y(p_list[q][1]);
878 double z(p_list[q][2]);
879 data.edge_lambda_grads_3d[0][q] = {z - 1.0, 0.0, x - 1.0};
880 data.edge_lambda_grads_3d[1][q] = {1.0 - z, 0.0, -x};
881 data.edge_lambda_grads_3d[2][q] = {0.0, z - 1.0, y - 1.0};
882 data.edge_lambda_grads_3d[3][q] = {0.0, 1.0 - z, -y};
883 data.edge_lambda_grads_3d[4][q] = {-z, 0.0, 1.0 - x};
884 data.edge_lambda_grads_3d[5][q] = {z, 0.0, x};
885 data.edge_lambda_grads_3d[6][q] = {0.0, -z, 1.0 - y};
886 data.edge_lambda_grads_3d[7][q] = {0.0, z, y};
887 data.edge_lambda_grads_3d[8][q] = {y - 1.0, x - 1.0, 0.0};
888 data.edge_lambda_grads_3d[9][q] = {1.0 - y, -x, 0.0};
889 data.edge_lambda_grads_3d[10][q] = {-y, 1.0 - x, 0.0};
890 data.edge_lambda_grads_3d[11][q] = {y, x, 0.0};
891 }
892
893 // edge_lambda gradgrads:
894 const int edge_lambda_sign[GeometryInfo<3>::lines_per_cell] = {
895 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, -1, 1}; // sign of the 2nd
896 // derivative for each
897 // edge.
898
899 const unsigned int
900 edge_lambda_directions[GeometryInfo<3>::lines_per_cell][2] = {
901 {0, 2},
902 {0, 2},
903 {1, 2},
904 {1, 2},
905 {0, 2},
906 {0, 2},
907 {1, 2},
908 {1, 2},
909 {0, 1},
910 {0, 1},
911 {0, 1},
912 {0, 1}}; // component which edge_lambda[m] depends on.
913
914 for (unsigned int m = 0; m < lines_per_cell; ++m)
915 {
916 data.edge_lambda_gradgrads_3d[m][edge_lambda_directions[m][0]]
917 [edge_lambda_directions[m][1]] =
918 edge_lambda_sign[m];
919 data.edge_lambda_gradgrads_3d[m][edge_lambda_directions[m][1]]
920 [edge_lambda_directions[m][0]] =
921 edge_lambda_sign[m];
922 }
923
924 // If the polynomial order is 0, then no more work to do:
925 if (degree < 1)
926 break;
927
928 // resize required data:
929 data.face_lambda_values.resize(faces_per_cell,
930 std::vector<double>(n_q_points));
931 data.face_lambda_grads.resize(faces_per_cell,
932 std::vector<double>(dim));
933
934 // Fill in the values (these don't change between cells).
935 for (unsigned int q = 0; q < n_q_points; ++q)
936 {
937 double x(p_list[q][0]);
938 double y(p_list[q][1]);
939 double z(p_list[q][2]);
940 data.face_lambda_values[0][q] = 1.0 - x;
941 data.face_lambda_values[1][q] = x;
942 data.face_lambda_values[2][q] = 1.0 - y;
943 data.face_lambda_values[3][q] = y;
944 data.face_lambda_values[4][q] = 1.0 - z;
945 data.face_lambda_values[5][q] = z;
946 }
947
948 // gradients are constant:
949 data.face_lambda_grads[0] = {-1.0, 0.0, 0.0};
950 data.face_lambda_grads[1] = {1.0, 0.0, 0.0};
951 data.face_lambda_grads[2] = {0.0, -1.0, 0.0};
952 data.face_lambda_grads[3] = {0.0, 1.0, 0.0};
953 data.face_lambda_grads[4] = {0.0, 0.0, -1.0};
954 data.face_lambda_grads[5] = {0.0, 0.0, 1.0};
955
956 // for cell-based shape functions:
957 // these don't depend on the cell, so can precompute all here:
959 {
960 // Cell-based shape functions:
961 //
962 // Type-1 (gradients):
963 // \phi^{C_{1}}_{ijk} = grad(
964 // L_{i+2}(2x-1)L_{j+2}(2y-1)L_{k+2}(2z-1) ),
965 //
966 // 0 <= i,j,k < degree. (in a group of degree*degree*degree)
967 const unsigned int cell_type1_offset(n_line_dofs + n_face_dofs);
968 // Type-2:
969 //
970 // \phi^{C_{2}}_{ijk} = diag(1, -1, 1)\phi^{C_{1}}_{ijk}
971 // \phi^{C_{2}}_{ijk + p^3} = diag(1, -1,
972 // -1)\phi^{C_{1}}_{ijk}
973 //
974 // 0 <= i,j,k < degree. (subtypes in groups of
975 // degree*degree*degree)
976 //
977 // here we order so that all of subtype 1 comes first, then
978 // subtype 2.
979 const unsigned int cell_type2_offset1(cell_type1_offset +
980 degree * degree * degree);
981 const unsigned int cell_type2_offset2(cell_type2_offset1 +
982 degree * degree * degree);
983 // Type-3
984 // \phi^{C_{3}}_{jk} = L_{j+2}(2y-1)L_{k+2}(2z-1)e_{x}
985 // \phi^{C_{3}}_{ik} = L_{i+2}(2x-1)L_{k+2}(2z-1)e_{y}
986 // \phi^{C_{3}}_{ij} = L_{i+2}(2x-1)L_{j+2}(2y-1)e_{z}
987 //
988 // 0 <= i,j,k < degree. (subtypes in groups of degree*degree)
989 //
990 // again we order so we compute all of subtype 1 first, then
991 // subtype 2, etc.
992 const unsigned int cell_type3_offset1(cell_type2_offset2 +
993 degree * degree * degree);
994 const unsigned int cell_type3_offset2(cell_type3_offset1 +
995 degree * degree);
996 const unsigned int cell_type3_offset3(cell_type3_offset2 +
997 degree * degree);
998
999 // compute all points we must evaluate the 1d polynomials at:
1000 std::vector<Point<dim>> cell_points(n_q_points);
1001 for (unsigned int q = 0; q < n_q_points; ++q)
1002 {
1003 for (unsigned int d = 0; d < dim; ++d)
1004 {
1005 cell_points[q][d] = 2.0 * p_list[q][d] - 1.0;
1006 }
1007 }
1008
1009 // We only need poly values and 1st derivative for
1010 // update_values, but need the 2nd derivative too for
1011 // update_gradients. For update_hessians we also need 3rd
1012 // derivative.
1013 const unsigned int poly_length =
1014 (flags & update_hessians) ?
1015 4 :
1016 ((flags & update_gradients) ? 3 : 2);
1017
1018 // Loop through quad points:
1019 for (unsigned int q = 0; q < n_q_points; ++q)
1020 {
1021 // pre-compute values & required derivatives at this quad
1022 // point, (x,y,z): polyx = L_{i+2}(2x-1), polyy =
1023 // L_{j+2}(2y-1), polyz = L_{k+2}(2z-1).
1024 //
1025 // for each polyc[d], c=x,y,z, contains the d-th
1026 // derivative with respect to the coordinate c.
1027 std::vector<std::vector<double>> polyx(
1028 degree, std::vector<double>(poly_length));
1029 std::vector<std::vector<double>> polyy(
1030 degree, std::vector<double>(poly_length));
1031 std::vector<std::vector<double>> polyz(
1032 degree, std::vector<double>(poly_length));
1033 for (unsigned int i = 0; i < degree; ++i)
1034 {
1035 // compute all required 1d polynomials for i
1036 IntegratedLegendrePolynomials[i + 2].value(
1037 cell_points[q][0], polyx[i]);
1038 IntegratedLegendrePolynomials[i + 2].value(
1039 cell_points[q][1], polyy[i]);
1040 IntegratedLegendrePolynomials[i + 2].value(
1041 cell_points[q][2], polyz[i]);
1042 }
1043 // Now use these to compute the shape functions:
1044 if (flags & update_values)
1045 {
1046 for (unsigned int k = 0; k < degree; ++k)
1047 {
1048 const unsigned int shift_k(k * degree * degree);
1049 const unsigned int shift_j(
1050 k * degree); // Used below when subbing
1051 // k for j (type 3)
1052 for (unsigned int j = 0; j < degree; ++j)
1053 {
1054 const unsigned int shift_jk(j * degree + shift_k);
1055 for (unsigned int i = 0; i < degree; ++i)
1056 {
1057 const unsigned int shift_ijk(shift_jk + i);
1058
1059 // Type 1:
1060 const unsigned int dof_index1(
1061 cell_type1_offset + shift_ijk);
1062
1063 data.shape_values[dof_index1][q][0] =
1064 2.0 * polyx[i][1] * polyy[j][0] *
1065 polyz[k][0];
1066 data.shape_values[dof_index1][q][1] =
1067 2.0 * polyx[i][0] * polyy[j][1] *
1068 polyz[k][0];
1069 data.shape_values[dof_index1][q][2] =
1070 2.0 * polyx[i][0] * polyy[j][0] *
1071 polyz[k][1];
1072
1073 // Type 2:
1074 const unsigned int dof_index2_1(
1075 cell_type2_offset1 + shift_ijk);
1076 const unsigned int dof_index2_2(
1077 cell_type2_offset2 + shift_ijk);
1078
1079 data.shape_values[dof_index2_1][q][0] =
1080 data.shape_values[dof_index1][q][0];
1081 data.shape_values[dof_index2_1][q][1] =
1082 -1.0 * data.shape_values[dof_index1][q][1];
1083 data.shape_values[dof_index2_1][q][2] =
1084 data.shape_values[dof_index1][q][2];
1085
1086 data.shape_values[dof_index2_2][q][0] =
1087 data.shape_values[dof_index1][q][0];
1088 data.shape_values[dof_index2_2][q][1] =
1089 -1.0 * data.shape_values[dof_index1][q][1];
1090 data.shape_values[dof_index2_2][q][2] =
1091 -1.0 * data.shape_values[dof_index1][q][2];
1092 }
1093 // Type 3: (note we re-use k and j for
1094 // convenience):
1095 const unsigned int shift_ij(
1096 j + shift_j); // here we've subbed
1097 // j for i, k for j.
1098 const unsigned int dof_index3_1(
1099 cell_type3_offset1 + shift_ij);
1100 const unsigned int dof_index3_2(
1101 cell_type3_offset2 + shift_ij);
1102 const unsigned int dof_index3_3(
1103 cell_type3_offset3 + shift_ij);
1104
1105 data.shape_values[dof_index3_1][q][0] =
1106 polyy[j][0] * polyz[k][0];
1107 data.shape_values[dof_index3_1][q][1] = 0.0;
1108 data.shape_values[dof_index3_1][q][2] = 0.0;
1109
1110 data.shape_values[dof_index3_2][q][0] = 0.0;
1111 data.shape_values[dof_index3_2][q][1] =
1112 polyx[j][0] * polyz[k][0];
1113 data.shape_values[dof_index3_2][q][2] = 0.0;
1114
1115 data.shape_values[dof_index3_3][q][0] = 0.0;
1116 data.shape_values[dof_index3_3][q][1] = 0.0;
1117 data.shape_values[dof_index3_3][q][2] =
1118 polyx[j][0] * polyy[k][0];
1119 }
1120 }
1121 }
1122 if (flags & update_gradients)
1123 {
1124 for (unsigned int k = 0; k < degree; ++k)
1125 {
1126 const unsigned int shift_k(k * degree * degree);
1127 const unsigned int shift_j(
1128 k * degree); // Used below when subbing
1129 // k for j (type 3)
1130 for (unsigned int j = 0; j < degree; ++j)
1131 {
1132 const unsigned int shift_jk(j * degree + shift_k);
1133 for (unsigned int i = 0; i < degree; ++i)
1134 {
1135 const unsigned int shift_ijk(shift_jk + i);
1136
1137 // Type 1:
1138 const unsigned int dof_index1(
1139 cell_type1_offset + shift_ijk);
1140
1141 data.shape_grads[dof_index1][q][0][0] =
1142 4.0 * polyx[i][2] * polyy[j][0] *
1143 polyz[k][0];
1144 data.shape_grads[dof_index1][q][0][1] =
1145 4.0 * polyx[i][1] * polyy[j][1] *
1146 polyz[k][0];
1147 data.shape_grads[dof_index1][q][0][2] =
1148 4.0 * polyx[i][1] * polyy[j][0] *
1149 polyz[k][1];
1150
1151 data.shape_grads[dof_index1][q][1][0] =
1152 data.shape_grads[dof_index1][q][0][1];
1153 data.shape_grads[dof_index1][q][1][1] =
1154 4.0 * polyx[i][0] * polyy[j][2] *
1155 polyz[k][0];
1156 data.shape_grads[dof_index1][q][1][2] =
1157 4.0 * polyx[i][0] * polyy[j][1] *
1158 polyz[k][1];
1159
1160 data.shape_grads[dof_index1][q][2][0] =
1161 data.shape_grads[dof_index1][q][0][2];
1162 data.shape_grads[dof_index1][q][2][1] =
1163 data.shape_grads[dof_index1][q][1][2];
1164 data.shape_grads[dof_index1][q][2][2] =
1165 4.0 * polyx[i][0] * polyy[j][0] *
1166 polyz[k][2];
1167
1168 // Type 2:
1169 const unsigned int dof_index2_1(
1170 cell_type2_offset1 + shift_ijk);
1171 const unsigned int dof_index2_2(
1172 cell_type2_offset2 + shift_ijk);
1173
1174 for (unsigned int d = 0; d < dim; ++d)
1175 {
1176 data.shape_grads[dof_index2_1][q][0][d] =
1177 data.shape_grads[dof_index1][q][0][d];
1178 data.shape_grads[dof_index2_1][q][1][d] =
1179 -1.0 *
1180 data.shape_grads[dof_index1][q][1][d];
1181 data.shape_grads[dof_index2_1][q][2][d] =
1182 data.shape_grads[dof_index1][q][2][d];
1183
1184 data.shape_grads[dof_index2_2][q][0][d] =
1185 data.shape_grads[dof_index1][q][0][d];
1186 data.shape_grads[dof_index2_2][q][1][d] =
1187 -1.0 *
1188 data.shape_grads[dof_index1][q][1][d];
1189 data.shape_grads[dof_index2_2][q][2][d] =
1190 -1.0 *
1191 data.shape_grads[dof_index1][q][2][d];
1192 }
1193 }
1194 // Type 3: (note we re-use k and j for
1195 // convenience):
1196 const unsigned int shift_ij(
1197 j + shift_j); // here we've subbed
1198 // j for i, k for j.
1199 const unsigned int dof_index3_1(
1200 cell_type3_offset1 + shift_ij);
1201 const unsigned int dof_index3_2(
1202 cell_type3_offset2 + shift_ij);
1203 const unsigned int dof_index3_3(
1204 cell_type3_offset3 + shift_ij);
1205 for (unsigned int d1 = 0; d1 < dim; ++d1)
1206 {
1207 for (unsigned int d2 = 0; d2 < dim; ++d2)
1208 {
1209 data
1210 .shape_grads[dof_index3_1][q][d1][d2] =
1211 0.0;
1212 data
1213 .shape_grads[dof_index3_2][q][d1][d2] =
1214 0.0;
1215 data
1216 .shape_grads[dof_index3_3][q][d1][d2] =
1217 0.0;
1218 }
1219 }
1220 data.shape_grads[dof_index3_1][q][0][1] =
1221 2.0 * polyy[j][1] * polyz[k][0];
1222 data.shape_grads[dof_index3_1][q][0][2] =
1223 2.0 * polyy[j][0] * polyz[k][1];
1224
1225 data.shape_grads[dof_index3_2][q][1][0] =
1226 2.0 * polyx[j][1] * polyz[k][0];
1227 data.shape_grads[dof_index3_2][q][1][2] =
1228 2.0 * polyx[j][0] * polyz[k][1];
1229
1230 data.shape_grads[dof_index3_3][q][2][0] =
1231 2.0 * polyx[j][1] * polyy[k][0];
1232 data.shape_grads[dof_index3_3][q][2][1] =
1233 2.0 * polyx[j][0] * polyy[k][1];
1234 }
1235 }
1236 }
1237 if (flags & update_hessians)
1238 {
1239 for (unsigned int k = 0; k < degree; ++k)
1240 {
1241 const unsigned int shift_k(k * degree * degree);
1242 const unsigned int shift_j(
1243 k * degree); // Used below when subbing
1244 // k for j type 3
1245
1246 for (unsigned int j = 0; j < degree; ++j)
1247 {
1248 const unsigned int shift_jk(j * degree + shift_k);
1249 for (unsigned int i = 0; i < degree; ++i)
1250 {
1251 const unsigned int shift_ijk(shift_jk + i);
1252
1253 // Type 1:
1254 const unsigned int dof_index1(
1255 cell_type1_offset + shift_ijk);
1256
1257 data.shape_hessians[dof_index1][q][0][0][0] =
1258 8.0 * polyx[i][3] * polyy[j][0] *
1259 polyz[k][0];
1260 data.shape_hessians[dof_index1][q][1][0][0] =
1261 8.0 * polyx[i][2] * polyy[j][1] *
1262 polyz[k][0];
1263 data.shape_hessians[dof_index1][q][2][0][0] =
1264 8.0 * polyx[i][2] * polyy[j][0] *
1265 polyz[k][1];
1266
1267 data.shape_hessians[dof_index1][q][0][1][0] =
1268 data.shape_hessians[dof_index1][q][1][0][0];
1269 data.shape_hessians[dof_index1][q][1][1][0] =
1270 8.0 * polyx[i][1] * polyy[j][2] *
1271 polyz[k][0];
1272 data.shape_hessians[dof_index1][q][2][1][0] =
1273 8.0 * polyx[i][1] * polyy[j][1] *
1274 polyz[k][1];
1275
1276 data.shape_hessians[dof_index1][q][0][2][0] =
1277 data.shape_hessians[dof_index1][q][2][0][0];
1278 data.shape_hessians[dof_index1][q][1][2][0] =
1279 data.shape_hessians[dof_index1][q][2][1][0];
1280 data.shape_hessians[dof_index1][q][2][2][0] =
1281 8.0 * polyx[i][1] * polyy[j][0] *
1282 polyz[k][2];
1283
1284
1285 data.shape_hessians[dof_index1][q][0][0][1] =
1286 data.shape_hessians[dof_index1][q][1][0][0];
1287 data.shape_hessians[dof_index1][q][1][0][1] =
1288 data.shape_hessians[dof_index1][q][1][1][0];
1289 data.shape_hessians[dof_index1][q][2][0][1] =
1290 data.shape_hessians[dof_index1][q][2][1][0];
1291
1292 data.shape_hessians[dof_index1][q][0][1][1] =
1293 data.shape_hessians[dof_index1][q][1][1][0];
1294 data.shape_hessians[dof_index1][q][1][1][1] =
1295 8.0 * polyx[i][0] * polyy[j][3] *
1296 polyz[k][0];
1297 data.shape_hessians[dof_index1][q][2][1][1] =
1298 8.0 * polyx[i][0] * polyy[j][2] *
1299 polyz[k][1];
1300
1301 data.shape_hessians[dof_index1][q][0][2][1] =
1302 data.shape_hessians[dof_index1][q][2][1][0];
1303 data.shape_hessians[dof_index1][q][1][2][1] =
1304 data.shape_hessians[dof_index1][q][2][1][1];
1305 data.shape_hessians[dof_index1][q][2][2][1] =
1306 8.0 * polyx[i][0] * polyy[j][1] *
1307 polyz[k][2];
1308
1309
1310 data.shape_hessians[dof_index1][q][0][0][2] =
1311 data.shape_hessians[dof_index1][q][2][0][0];
1312 data.shape_hessians[dof_index1][q][1][0][2] =
1313 data.shape_hessians[dof_index1][q][2][1][0];
1314 data.shape_hessians[dof_index1][q][2][0][2] =
1315 data.shape_hessians[dof_index1][q][2][2][0];
1316
1317 data.shape_hessians[dof_index1][q][0][1][2] =
1318 data.shape_hessians[dof_index1][q][2][1][0];
1319 data.shape_hessians[dof_index1][q][1][1][2] =
1320 data.shape_hessians[dof_index1][q][2][1][1];
1321 data.shape_hessians[dof_index1][q][2][1][2] =
1322 data.shape_hessians[dof_index1][q][2][2][1];
1323
1324 data.shape_hessians[dof_index1][q][0][2][2] =
1325 data.shape_hessians[dof_index1][q][2][2][0];
1326 data.shape_hessians[dof_index1][q][1][2][2] =
1327 data.shape_hessians[dof_index1][q][2][2][1];
1328 data.shape_hessians[dof_index1][q][2][2][2] =
1329 8.0 * polyx[i][0] * polyy[j][0] *
1330 polyz[k][3];
1331
1332
1333 // Type 2:
1334 const unsigned int dof_index2_1(
1335 cell_type2_offset1 + shift_ijk);
1336 const unsigned int dof_index2_2(
1337 cell_type2_offset2 + shift_ijk);
1338
1339 for (unsigned int d1 = 0; d1 < dim; ++d1)
1340 {
1341 for (unsigned int d2 = 0; d2 < dim; ++d2)
1342 {
1343 data.shape_hessians[dof_index2_1][q]
1344 [0][d1][d2] =
1345 data.shape_hessians[dof_index1][q]
1346 [0][d1][d2];
1347 data.shape_hessians[dof_index2_1][q]
1348 [1][d1][d2] =
1349 -1.0 *
1350 data.shape_hessians[dof_index1][q]
1351 [1][d1][d2];
1352 data.shape_hessians[dof_index2_1][q]
1353 [2][d1][d2] =
1354 data.shape_hessians[dof_index1][q]
1355 [2][d1][d2];
1356
1357 data.shape_hessians[dof_index2_2][q]
1358 [0][d1][d2] =
1359 data.shape_hessians[dof_index1][q]
1360 [0][d1][d2];
1361 data.shape_hessians[dof_index2_2][q]
1362 [1][d1][d2] =
1363 -1.0 *
1364 data.shape_hessians[dof_index1][q]
1365 [1][d1][d2];
1366 data.shape_hessians[dof_index2_2][q]
1367 [2][d1][d2] =
1368 -1.0 *
1369 data.shape_hessians[dof_index1][q]
1370 [2][d1][d2];
1371 }
1372 }
1373 }
1374 // Type 3: (note we re-use k and j for
1375 // convenience):
1376 const unsigned int shift_ij(
1377 j + shift_j); // here we've subbed
1378 // j for i, k for j.
1379 const unsigned int dof_index3_1(
1380 cell_type3_offset1 + shift_ij);
1381 const unsigned int dof_index3_2(
1382 cell_type3_offset2 + shift_ij);
1383 const unsigned int dof_index3_3(
1384 cell_type3_offset3 + shift_ij);
1385 for (unsigned int d1 = 0; d1 < dim; ++d1)
1386 {
1387 for (unsigned int d2 = 0; d2 < dim; ++d2)
1388 {
1389 for (unsigned int d3 = 0; d3 < dim; ++d3)
1390 {
1391 data.shape_hessians[dof_index3_1][q]
1392 [d1][d2][d3] = 0.0;
1393 data.shape_hessians[dof_index3_2][q]
1394 [d1][d2][d3] = 0.0;
1395 data.shape_hessians[dof_index3_3][q]
1396 [d1][d2][d3] = 0.0;
1397 }
1398 }
1399 }
1400 data.shape_hessians[dof_index3_1][q][0][1][1] =
1401 4.0 * polyy[j][2] * polyz[k][0];
1402 data.shape_hessians[dof_index3_1][q][0][1][2] =
1403 4.0 * polyy[j][1] * polyz[k][1];
1404
1405 data.shape_hessians[dof_index3_1][q][0][2][1] =
1406 data.shape_hessians[dof_index3_1][q][0][1][2];
1407 data.shape_hessians[dof_index3_1][q][0][2][2] =
1408 4.0 * polyy[j][0] * polyz[k][2];
1409
1410
1411 data.shape_hessians[dof_index3_2][q][1][0][0] =
1412 4.0 * polyx[j][2] * polyz[k][0];
1413 data.shape_hessians[dof_index3_2][q][1][0][2] =
1414 4.0 * polyx[j][1] * polyz[k][1];
1415
1416 data.shape_hessians[dof_index3_2][q][1][2][0] =
1417 data.shape_hessians[dof_index3_2][q][1][0][2];
1418 data.shape_hessians[dof_index3_2][q][1][2][2] =
1419 4.0 * polyx[j][0] * polyz[k][2];
1420
1421
1422 data.shape_hessians[dof_index3_3][q][2][0][0] =
1423 4.0 * polyx[j][2] * polyy[k][0];
1424 data.shape_hessians[dof_index3_3][q][2][0][1] =
1425 4.0 * polyx[j][1] * polyy[k][1];
1426
1427 data.shape_hessians[dof_index3_3][q][2][1][0] =
1428 data.shape_hessians[dof_index3_3][q][2][0][1];
1429 data.shape_hessians[dof_index3_3][q][2][1][1] =
1430 4.0 * polyx[j][0] * polyy[k][2];
1431 }
1432 }
1433 }
1434 }
1435 }
1436 break;
1437 }
1438
1439 default:
1440 {
1442 break;
1443 }
1444 }
1445}
1446
1447
1448
1449template <int dim, int spacedim>
1450std::unique_ptr<typename ::FiniteElement<dim, spacedim>::InternalDataBase>
1452 const UpdateFlags update_flags,
1453 const Mapping<dim, spacedim> & /*mapping*/,
1454 const Quadrature<dim> &quadrature,
1456 spacedim>
1457 & /*output_data*/) const
1458{
1459 std::unique_ptr<
1460 typename ::FiniteElement<dim, spacedim>::InternalDataBase>
1461 data_ptr = std::make_unique<InternalData>();
1462
1463 const unsigned int n_q_points = quadrature.size();
1464 std::vector<Point<dim>> p_list(n_q_points);
1465 p_list = quadrature.get_points();
1466
1467 this->evaluate(p_list, update_flags, data_ptr);
1468
1469 return data_ptr;
1470}
1471
1472
1473
1474template <int dim, int spacedim>
1475void
1477 const typename Triangulation<dim, dim>::cell_iterator &cell,
1478 const Quadrature<dim> &quadrature,
1479 const InternalData &fe_data) const
1480{
1481 // This function handles the cell-dependent construction of the EDGE-based
1482 // shape functions.
1483 //
1484 // Note it will handle both 2d and 3d, in 2d, the edges are faces, but we
1485 // handle them here.
1486 //
1487 // It will fill in the missing parts of fe_data which were not possible to
1488 // fill in the get_data routine, with respect to the edge-based shape
1489 // functions.
1490 //
1491 // It should be called by the fill_fe_*_values routines in order to complete
1492 // the basis set at quadrature points on the current cell for each edge.
1493
1494 const UpdateFlags flags(fe_data.update_each);
1495 const unsigned int n_q_points = quadrature.size();
1496
1497 Assert(!(flags & update_values) ||
1498 fe_data.shape_values.size() == this->n_dofs_per_cell(),
1499 ExcDimensionMismatch(fe_data.shape_values.size(),
1500 this->n_dofs_per_cell()));
1501 Assert(!(flags & update_values) ||
1502 fe_data.shape_values[0].size() == n_q_points,
1503 ExcDimensionMismatch(fe_data.shape_values[0].size(), n_q_points));
1504
1505 // Useful constants:
1506 const unsigned int degree(
1507 this->degree -
1508 1); // Note: constructor takes input degree + 1, so need to knock 1 off.
1509
1510 // Useful geometry info:
1511 const unsigned int vertices_per_line(2);
1512 const unsigned int lines_per_cell(GeometryInfo<dim>::lines_per_cell);
1513
1514 // Calculate edge orderings:
1515 std::vector<std::vector<unsigned int>> edge_order(
1516 lines_per_cell, std::vector<unsigned int>(vertices_per_line));
1517
1518
1519 switch (dim)
1520 {
1521 case 2:
1522 {
1524 {
1525 // Define an edge numbering so that each edge, E_{m} = [e^{m}_{1},
1526 // e^{m}_{2}] e1 = higher global numbering of the two local
1527 // vertices e2 = lower global numbering of the two local vertices
1528 std::vector<int> edge_sign(lines_per_cell);
1529 for (unsigned int m = 0; m < lines_per_cell; ++m)
1530 {
1531 unsigned int v0_loc =
1533 unsigned int v1_loc =
1535 unsigned int v0_glob = cell->vertex_index(v0_loc);
1536 unsigned int v1_glob = cell->vertex_index(v1_loc);
1537
1538 // Check for hanging edges on the current face. If we
1539 // encounter a hanging edge, we use the vertex indices
1540 // from the parent.
1541 if (cell->face(m)->at_boundary() == false)
1542 if (cell->neighbor_is_coarser(m))
1543 {
1544 v0_glob = cell->parent()->vertex_index(v0_loc);
1545 v1_glob = cell->parent()->vertex_index(v1_loc);
1546 }
1547
1548 if (v0_glob > v1_glob)
1549 {
1550 // Opposite to global numbering on our reference element
1551 edge_sign[m] = -1.0;
1552 }
1553 else
1554 {
1555 // Aligns with global numbering on our reference element.
1556 edge_sign[m] = 1.0;
1557 }
1558 }
1559
1560 // Define \sigma_{m} = sigma_{e^{m}_{2}} - sigma_{e^{m}_{1}}
1561 // \lambda_{m} = \lambda_{e^{m}_{1}} + \lambda_{e^{m}_{2}}
1562 //
1563 // To help things, in fe_data, we have precomputed (sigma_{i} -
1564 // sigma_{j}) and (lambda_{i} + lambda_{j}) for 0<= i,j <
1565 // lines_per_cell.
1566 //
1567 // There are two types:
1568 // - lower order (1 per edge, m):
1569 // \phi_{m}^{\mathcal{N}_{0}} = 1/2 grad(\sigma_{m})\lambda_{m}
1570 //
1571 // - higher order (degree per edge, m):
1572 // \phi_{i}^{E_{m}} = grad( L_{i+2}(\sigma_{m}) (\lambda_{m}) ).
1573 //
1574 // NOTE: sigma_{m} and lambda_{m} are either a function of x OR
1575 // y
1576 // and if sigma is of x, then lambda is of y, and vice
1577 // versa. This means that grad(\sigma) requires
1578 // multiplication by d(sigma)/dx_{i} for the i^th comp of
1579 // grad(sigma) and similarly when taking derivatives of
1580 // lambda.
1581 //
1582 // First handle the lowest order edges (dofs 0 to 3)
1583 // 0 and 1 are the edges in the y dir. (sigma is function of y,
1584 // lambda is function of x). 2 and 3 are the edges in the x dir.
1585 // (sigma is function of x, lambda is function of y).
1586 //
1587 // More more info: see GeometryInfo for picture of the standard
1588 // element.
1589 //
1590 // Fill edge-based points:
1591 // std::vector<std::vector< Point<dim> > >
1592 // edge_points(lines_per_cell, std::vector<Point<dim>>
1593 // (n_q_points));
1594
1595 std::vector<std::vector<double>> edge_sigma_values(
1596 fe_data.edge_sigma_values);
1597 std::vector<std::vector<double>> edge_sigma_grads(
1598 fe_data.edge_sigma_grads);
1599
1600 std::vector<std::vector<double>> edge_lambda_values(
1601 fe_data.edge_lambda_values);
1602 std::vector<std::vector<double>> edge_lambda_grads(
1603 fe_data.edge_lambda_grads_2d);
1604
1605 // Adjust the edge_sigma_* for the current cell:
1606 for (unsigned int m = 0; m < lines_per_cell; ++m)
1607 {
1608 std::transform(edge_sigma_values[m].begin(),
1609 edge_sigma_values[m].end(),
1610 edge_sigma_values[m].begin(),
1611 [&](const double edge_sigma_value) {
1612 return edge_sign[m] * edge_sigma_value;
1613 });
1614
1615 std::transform(edge_sigma_grads[m].begin(),
1616 edge_sigma_grads[m].end(),
1617 edge_sigma_grads[m].begin(),
1618 [&](const double edge_sigma_grad) {
1619 return edge_sign[m] * edge_sigma_grad;
1620 });
1621 }
1622
1623 // If we want to generate shape gradients then we need second
1624 // derivatives of the 1d polynomials, but only first derivatives
1625 // for the shape values.
1626 const unsigned int poly_length =
1627 (flags & update_hessians) ?
1628 4 :
1629 ((flags & update_gradients) ? 3 : 2);
1630
1631
1632 for (unsigned int m = 0; m < lines_per_cell; ++m)
1633 {
1634 const unsigned int shift_m(m * this->n_dofs_per_line());
1635 for (unsigned int q = 0; q < n_q_points; ++q)
1636 {
1637 // Only compute 1d polynomials if degree>0.
1638 std::vector<std::vector<double>> poly(
1639 degree, std::vector<double>(poly_length));
1640 for (unsigned int i = 1; i < degree + 1; ++i)
1641 {
1642 // Compute all required 1d polynomials and their
1643 // derivatives, starting at degree 2. e.g. to access
1644 // L'_{i+2}(edge_sigma) use polyx[i][1].
1645 IntegratedLegendrePolynomials[i + 1].value(
1646 edge_sigma_values[m][q], poly[i - 1]);
1647 }
1648 if (flags & update_values)
1649 {
1650 // Lowest order edge shape functions:
1651 for (unsigned int d = 0; d < dim; ++d)
1652 {
1653 fe_data.shape_values[shift_m][q][d] =
1654 0.5 * edge_sigma_grads[m][d] *
1655 edge_lambda_values[m][q];
1656 }
1657 // Higher order edge shape functions:
1658 for (unsigned int i = 1; i < degree + 1; ++i)
1659 {
1660 const unsigned int poly_index = i - 1;
1661 const unsigned int dof_index(i + shift_m);
1662 for (unsigned int d = 0; d < dim; ++d)
1663 {
1664 fe_data.shape_values[dof_index][q][d] =
1665 edge_sigma_grads[m][d] *
1666 poly[poly_index][1] *
1667 edge_lambda_values[m][q] +
1668 poly[poly_index][0] *
1669 edge_lambda_grads[m][d];
1670 }
1671 }
1672 }
1673 if (flags & update_gradients)
1674 {
1675 // Lowest order edge shape functions:
1676 for (unsigned int d1 = 0; d1 < dim; ++d1)
1677 {
1678 for (unsigned int d2 = 0; d2 < dim; ++d2)
1679 {
1680 // Note: gradient is constant for a given
1681 // edge.
1682 fe_data.shape_grads[shift_m][q][d1][d2] =
1683 0.5 * edge_sigma_grads[m][d1] *
1684 edge_lambda_grads[m][d2];
1685 }
1686 }
1687 // Higher order edge shape functions:
1688 for (unsigned int i = 1; i < degree + 1; ++i)
1689 {
1690 const unsigned int poly_index = i - 1;
1691 const unsigned int dof_index(i + shift_m);
1692
1693 fe_data.shape_grads[dof_index][q][0][0] =
1694 edge_sigma_grads[m][0] *
1695 edge_sigma_grads[m][0] *
1696 edge_lambda_values[m][q] * poly[poly_index][2];
1697
1698 fe_data.shape_grads[dof_index][q][0][1] =
1699 (edge_sigma_grads[m][0] *
1700 edge_lambda_grads[m][1] +
1701 edge_sigma_grads[m][1] *
1702 edge_lambda_grads[m][0]) *
1703 poly[poly_index][1];
1704
1705 fe_data.shape_grads[dof_index][q][1][0] =
1706 fe_data.shape_grads[dof_index][q][0][1];
1707
1708 fe_data.shape_grads[dof_index][q][1][1] =
1709 edge_sigma_grads[m][1] *
1710 edge_sigma_grads[m][1] *
1711 edge_lambda_values[m][q] * poly[poly_index][2];
1712 }
1713 }
1714 if (flags & update_hessians)
1715 {
1716 // Lowest order edge shape function
1717 for (unsigned int d1 = 0; d1 < dim; ++d1)
1718 {
1719 for (unsigned int d2 = 0; d2 < dim; ++d2)
1720 {
1721 for (unsigned int d3 = 0; d3 < dim; ++d3)
1722 {
1723 fe_data.shape_hessians[shift_m][q][d1][d2]
1724 [d3] = 0;
1725 }
1726 }
1727 }
1728
1729 // Higher order edge shape function
1730 for (unsigned int i = 0; i < degree; ++i)
1731 {
1732 const unsigned int dof_index(i + 1 + shift_m);
1733
1734 for (unsigned int d1 = 0; d1 < dim; ++d1)
1735 {
1736 for (unsigned int d2 = 0; d2 < dim; ++d2)
1737 {
1738 for (unsigned int d3 = 0; d3 < dim; ++d3)
1739 {
1740 fe_data.shape_hessians[dof_index][q]
1741 [d1][d2][d3] =
1742 edge_sigma_grads[m][d1] *
1743 edge_sigma_grads[m][d2] *
1744 edge_sigma_grads[m][d3] *
1745 poly[i][3] *
1746 edge_lambda_values[m][q] +
1747 poly[i][2] *
1748 (edge_sigma_grads[m][d1] *
1749 edge_sigma_grads[m][d2] *
1750 edge_lambda_grads[m][d3] +
1751 edge_sigma_grads[m][d3] *
1752 edge_sigma_grads[m][d1] *
1753 edge_lambda_grads[m][d2] +
1754 edge_sigma_grads[m][d3] *
1755 edge_sigma_grads[m][d2] *
1756 edge_lambda_grads[m][d1]);
1757 }
1758 }
1759 }
1760 }
1761 }
1762 }
1763 }
1764 }
1765 break;
1766 }
1767 case 3:
1768 {
1770 {
1771 // Define an edge numbering so that each edge, E_{m} = [e^{m}_{1},
1772 // e^{m}_{2}] e1 = higher global numbering of the two local
1773 // vertices e2 = lower global numbering of the two local vertices
1774 std::vector<int> edge_sign(lines_per_cell);
1775 std::vector<bool> line_neighbor_is_coarser(
1777
1778 // Check for hanging faces. If we encounter hanging faces,
1779 // we use the vertex indices from the parent.
1780 for (unsigned int f : cell->face_indices())
1781 if (!cell->face(f)->at_boundary())
1782 if (cell->neighbor_is_coarser(f))
1783 for (unsigned int m = 0;
1784 m < GeometryInfo<dim>::lines_per_face;
1785 ++m)
1786 line_neighbor_is_coarser
1788
1789 // Next, we cover the case where we encounter a hanging edge but
1790 // not a hanging face. This is always the case if the cell
1791 // currently considered shares all faces with cells of the same
1792 // refinement level but shares one edge with a coarser cell,
1793 // e.g.:
1794 // *----*----*---------*
1795 // / / / / |
1796 // *----*----* / |
1797 // / / / / |
1798 // *----*----*---------* *
1799 // | | | | / |
1800 // *----*----* | * *
1801 // | | | | / | / |
1802 // *----*----*----*----* * *
1803 // | | | | | / | /
1804 // *----*----*----*----* *
1805 // | | | | | /
1806 // *----*----*----*----*
1807 // where the cell at the left bottom is the currently
1808 // considered cell.
1809 //
1810 // In that case, we determine the direction of the hanging edge
1811 // based on the vertex indices from the parent cell.
1812 //
1813 // Note:
1814 // This also covers cases where five or more cells are adjacent
1815 // to one edge.
1816 //
1817 if (cell->is_active())
1818 for (unsigned int line : cell->line_indices())
1819 {
1820 // If we already know this is a hanging edge, we do not need
1821 // to run further checks to confirm whether it is indeed a
1822 // hanging edge.
1823 if (line_neighbor_is_coarser[line])
1824 continue;
1825
1826 const int cell_level = cell->level();
1827 for (auto &neighbor_cell :
1828 cell->get_cells_adjacent_to_line(line))
1829 if (neighbor_cell->level() != cell_level)
1830 {
1831 line_neighbor_is_coarser[line] = true;
1832 break;
1833 }
1834 }
1835
1836 for (unsigned int line : cell->line_indices())
1837 {
1838 const unsigned int v0_loc =
1840 const unsigned int v1_loc =
1842
1843 // get the global vertex indices
1844 unsigned int v0_glob;
1845 unsigned int v1_glob;
1846 if (line_neighbor_is_coarser[line])
1847 {
1848 // hanging edge case
1849 v0_glob = cell->parent()->vertex_index(v0_loc);
1850 v1_glob = cell->parent()->vertex_index(v1_loc);
1851 }
1852 else
1853 {
1854 // normal case
1855 v0_glob = cell->vertex_index(v0_loc);
1856 v1_glob = cell->vertex_index(v1_loc);
1857 }
1858
1859 // get the direction in comparison to the reference element
1860 if (v0_glob > v1_glob)
1861 {
1862 // Opposite to global numbering on our reference element
1863 edge_sign[line] = -1.0;
1864 }
1865 else
1866 {
1867 // Aligns with global numbering on our reference element.
1868 edge_sign[line] = 1.0;
1869 }
1870 }
1871
1872 // Define \sigma_{m} = sigma_{e^{m}_{1}} - sigma_{e^{m}_{2}}
1873 // \lambda_{m} = \lambda_{e^{m}_{1}} + \lambda_{e^{m}_{2}}
1874 //
1875 // To help things, in fe_data, we have precomputed (sigma_{i} -
1876 // sigma_{j}) and (lambda_{i} + lambda_{j}) for 0<= i,j <
1877 // lines_per_cell.
1878 //
1879 // There are two types:
1880 // - lower order (1 per edge, m):
1881 // \phi_{m}^{\mathcal{N}_{0}} = 1/2 grad(\sigma_{m})\lambda_{m}
1882 //
1883 // - higher order (degree per edge, m):
1884 // \phi_{i}^{E_{m}} = grad( L_{i+2}(\sigma_{m}) (\lambda_{m}) ).
1885 //
1886 // NOTE: In the ref cell, sigma_{m} is a function of x OR y OR Z
1887 // and lambda_{m} a function of the remaining co-ords.
1888 // for example, if sigma is of x, then lambda is of y AND
1889 // z, and so on. This means that grad(\sigma) requires
1890 // multiplication by d(sigma)/dx_{i} for the i^th comp of
1891 // grad(sigma) and similarly when taking derivatives of
1892 // lambda.
1893 //
1894 // First handle the lowest order edges (dofs 0 to 11)
1895 // 0 and 1 are the edges in the y dir at z=0. (sigma is a fn of y,
1896 // lambda is a fn of x & z). 2 and 3 are the edges in the x dir at
1897 // z=0. (sigma is a fn of x, lambda is a fn of y & z). 4 and 5 are
1898 // the edges in the y dir at z=1. (sigma is a fn of y, lambda is a
1899 // fn of x & z). 6 and 7 are the edges in the x dir at z=1. (sigma
1900 // is a fn of x, lambda is a fn of y & z). 8 and 9 are the edges
1901 // in the z dir at y=0. (sigma is a fn of z, lambda is a fn of x &
1902 // y). 10 and 11 are the edges in the z dir at y=1. (sigma is a fn
1903 // of z, lambda is a fn of x & y).
1904 //
1905 // For more info: see GeometryInfo for picture of the standard
1906 // element.
1907
1908 // Copy over required edge-based data:
1909 std::vector<std::vector<double>> edge_sigma_values(
1910 fe_data.edge_sigma_values);
1911 std::vector<std::vector<double>> edge_lambda_values(
1912 fe_data.edge_lambda_values);
1913 std::vector<std::vector<double>> edge_sigma_grads(
1914 fe_data.edge_sigma_grads);
1915 std::vector<std::vector<std::vector<double>>> edge_lambda_grads(
1916 fe_data.edge_lambda_grads_3d);
1917 std::vector<std::vector<std::vector<double>>>
1918 edge_lambda_gradgrads_3d(fe_data.edge_lambda_gradgrads_3d);
1919
1920 // Adjust the edge_sigma_* for the current cell:
1921 for (unsigned int m = 0; m < lines_per_cell; ++m)
1922 {
1923 std::transform(edge_sigma_values[m].begin(),
1924 edge_sigma_values[m].end(),
1925 edge_sigma_values[m].begin(),
1926 [&](const double edge_sigma_value) {
1927 return edge_sign[m] * edge_sigma_value;
1928 });
1929 std::transform(edge_sigma_grads[m].begin(),
1930 edge_sigma_grads[m].end(),
1931 edge_sigma_grads[m].begin(),
1932 [&](const double edge_sigma_grad) {
1933 return edge_sign[m] * edge_sigma_grad;
1934 });
1935 }
1936
1937 // Now calculate the edge-based shape functions:
1938 // If we want to generate shape gradients then we need second
1939 // derivatives of the 1d polynomials, but only first derivatives
1940 // for the shape values.
1941 const unsigned int poly_length =
1942 (flags & update_hessians) ?
1943 4 :
1944 ((flags & update_gradients) ? 3 : 2);
1945
1946 std::vector<std::vector<double>> poly(
1947 degree, std::vector<double>(poly_length));
1948 for (unsigned int m = 0; m < lines_per_cell; ++m)
1949 {
1950 const unsigned int shift_m(m * this->n_dofs_per_line());
1951 for (unsigned int q = 0; q < n_q_points; ++q)
1952 {
1953 // precompute values of all 1d polynomials required:
1954 // for example poly[i][1] = L'_{i+2}(edge_sigma_values)
1955 if (degree > 0)
1956 {
1957 for (unsigned int i = 0; i < degree; ++i)
1958 {
1959 IntegratedLegendrePolynomials[i + 2].value(
1960 edge_sigma_values[m][q], poly[i]);
1961 }
1962 }
1963 if (flags & update_values)
1964 {
1965 // Lowest order edge shape functions:
1966 for (unsigned int d = 0; d < dim; ++d)
1967 {
1968 fe_data.shape_values[shift_m][q][d] =
1969 0.5 * edge_sigma_grads[m][d] *
1970 edge_lambda_values[m][q];
1971 }
1972 // Higher order edge shape functions
1973 if (degree > 0)
1974 {
1975 for (unsigned int i = 0; i < degree; ++i)
1976 {
1977 const unsigned int dof_index(i + 1 + shift_m);
1978 for (unsigned int d = 0; d < dim; ++d)
1979 {
1980 fe_data.shape_values[dof_index][q][d] =
1981 edge_sigma_grads[m][d] * poly[i][1] *
1982 edge_lambda_values[m][q] +
1983 poly[i][0] * edge_lambda_grads[m][q][d];
1984 }
1985 }
1986 }
1987 }
1988 if (flags & update_gradients)
1989 {
1990 // Lowest order edge shape functions:
1991 for (unsigned int d1 = 0; d1 < dim; ++d1)
1992 {
1993 for (unsigned int d2 = 0; d2 < dim; ++d2)
1994 {
1995 fe_data.shape_grads[shift_m][q][d1][d2] =
1996 0.5 * edge_sigma_grads[m][d1] *
1997 edge_lambda_grads[m][q][d2];
1998 }
1999 }
2000 // Higher order edge shape functions
2001 if (degree > 0)
2002 {
2003 for (unsigned int i = 0; i < degree; ++i)
2004 {
2005 const unsigned int dof_index(i + 1 + shift_m);
2006
2007 for (unsigned int d1 = 0; d1 < dim; ++d1)
2008 {
2009 for (unsigned int d2 = 0; d2 < dim; ++d2)
2010 {
2011 fe_data
2012 .shape_grads[dof_index][q][d1][d2] =
2013 edge_sigma_grads[m][d1] *
2014 edge_sigma_grads[m][d2] *
2015 poly[i][2] *
2016 edge_lambda_values[m][q] +
2017 (edge_sigma_grads[m][d1] *
2018 edge_lambda_grads[m][q][d2] +
2019 edge_sigma_grads[m][d2] *
2020 edge_lambda_grads[m][q][d1]) *
2021 poly[i][1] +
2022 edge_lambda_gradgrads_3d[m][d1]
2023 [d2] *
2024 poly[i][0];
2025 }
2026 }
2027 }
2028 }
2029 }
2030 if (flags & update_hessians)
2031 {
2032 // Lowest order edge shape functions:
2033 for (unsigned int d1 = 0; d1 < dim; ++d1)
2034 {
2035 for (unsigned int d2 = 0; d2 < dim; ++d2)
2036 {
2037 for (unsigned int d3 = 0; d3 < dim; ++d3)
2038 {
2039 fe_data.shape_hessians[shift_m][q][d1][d2]
2040 [d3] =
2041 0.5 * edge_sigma_grads[m][d1] *
2042 edge_lambda_gradgrads_3d[m][d3][d2];
2043 }
2044 }
2045 }
2046
2047 // Higher order edge shape functions
2048 if (degree > 0)
2049 {
2050 for (unsigned int i = 0; i < degree; ++i)
2051 {
2052 const unsigned int dof_index(i + 1 + shift_m);
2053
2054 for (unsigned int d1 = 0; d1 < dim; ++d1)
2055 {
2056 for (unsigned int d2 = 0; d2 < dim; ++d2)
2057 {
2058 for (unsigned int d3 = 0; d3 < dim;
2059 ++d3)
2060 {
2061 fe_data
2062 .shape_hessians[dof_index][q]
2063 [d1][d2][d3] =
2064 edge_sigma_grads[m][d1] *
2065 edge_sigma_grads[m][d2] *
2066 edge_sigma_grads[m][d3] *
2067 poly[i][3] *
2068 edge_lambda_values[m][q] +
2069 poly[i][2] *
2070 (edge_sigma_grads[m][d1] *
2071 edge_sigma_grads[m][d2] *
2072 edge_lambda_grads[m][q]
2073 [d3] +
2074 edge_sigma_grads[m][d3] *
2075 edge_sigma_grads[m][d1] *
2076 edge_lambda_grads[m][q]
2077 [d2] +
2078 edge_sigma_grads[m][d3] *
2079 edge_sigma_grads[m][d2] *
2080 edge_lambda_grads[m][q]
2081 [d1]) +
2082 poly[i][1] *
2083 (edge_sigma_grads[m][d1] *
2084 edge_lambda_gradgrads_3d
2085 [m][d3][d2] +
2086 edge_sigma_grads[m][d2] *
2087 edge_lambda_gradgrads_3d
2088 [m][d3][d1] +
2089 edge_sigma_grads[m][d3] *
2090 edge_lambda_gradgrads_3d
2091 [m][d2][d1]);
2092 }
2093 }
2094 }
2095 }
2096 }
2097 }
2098 }
2099 }
2100 }
2101 break;
2102 }
2103 default:
2104 {
2106 }
2107 }
2108}
2109
2110
2111
2112template <int dim, int spacedim>
2113void
2115 const typename Triangulation<dim, dim>::cell_iterator &cell,
2116 const Quadrature<dim> &quadrature,
2117 const InternalData &fe_data) const
2118{
2119 // This function handles the cell-dependent construction of the FACE-based
2120 // shape functions.
2121 //
2122 // Note that it should only be called in 3d.
2123 Assert(dim == 3, ExcDimensionMismatch(dim, 3));
2124 //
2125 // It will fill in the missing parts of fe_data which were not possible to
2126 // fill in the get_data routine, with respect to face-based shape functions.
2127 //
2128 // It should be called by the fill_fe_*_values routines in order to complete
2129 // the basis set at quadrature points on the current cell for each face.
2130
2131 // Useful constants:
2132 const unsigned int degree(
2133 this->degree -
2134 1); // Note: constructor takes input degree + 1, so need to knock 1 off.
2135
2136 // Do nothing if FE degree is 0.
2137 if (degree > 0)
2138 {
2139 const UpdateFlags flags(fe_data.update_each);
2140
2142 {
2143 const unsigned int n_q_points = quadrature.size();
2144
2145 Assert(!(flags & update_values) ||
2146 fe_data.shape_values.size() == this->n_dofs_per_cell(),
2147 ExcDimensionMismatch(fe_data.shape_values.size(),
2148 this->n_dofs_per_cell()));
2149 Assert(!(flags & update_values) ||
2150 fe_data.shape_values[0].size() == n_q_points,
2151 ExcDimensionMismatch(fe_data.shape_values[0].size(),
2152 n_q_points));
2153
2154 // Useful geometry info:
2155 const unsigned int vertices_per_face(
2157 const unsigned int faces_per_cell(GeometryInfo<dim>::faces_per_cell);
2158
2159 // DoF info:
2160 const unsigned int n_line_dofs =
2161 this->n_dofs_per_line() * GeometryInfo<dim>::lines_per_cell;
2162
2163 // First we find the global face orientations on the current cell.
2164 std::vector<std::vector<unsigned int>> face_orientation(
2165 faces_per_cell, std::vector<unsigned int>(vertices_per_face));
2166
2167 const unsigned int
2168 vertex_opposite_on_face[GeometryInfo<3>::vertices_per_face] = {3,
2169 2,
2170 1,
2171 0};
2172
2173 const unsigned int
2174 vertices_adjacent_on_face[GeometryInfo<3>::vertices_per_face][2] = {
2175 {1, 2}, {0, 3}, {3, 0}, {2, 1}};
2176
2177 for (unsigned int m = 0; m < faces_per_cell; ++m)
2178 {
2179 // Check, if we are on a hanging face.
2180 bool cell_has_coarser_neighbor = false;
2181 if (cell->face(m)->at_boundary() == false)
2182 if (cell->neighbor_is_coarser(m))
2183 cell_has_coarser_neighbor = true;
2184
2185 // Find the local vertex on this face with the highest global
2186 // numbering. This is f^m_0.
2187 unsigned int current_max = 0;
2188
2189 // We start with the hanging face case, where the face
2190 // orientation is determined based on the vertex indices
2191 // of the parent cell.
2192 if (cell_has_coarser_neighbor)
2193 {
2194 unsigned int current_glob = cell->parent()->vertex_index(
2196 for (unsigned int v = 1; v < vertices_per_face; ++v)
2197 {
2198 if (current_glob <
2199 cell->parent()->vertex_index(
2201 {
2202 current_max = v;
2203 current_glob = cell->parent()->vertex_index(
2205 }
2206 }
2207 }
2208 // Otherwise, the face orientation is based on its own
2209 // vertex indices.
2210 else
2211 {
2212 unsigned int current_glob = cell->vertex_index(
2214 for (unsigned int v = 1; v < vertices_per_face; ++v)
2215 {
2216 if (current_glob <
2217 cell->vertex_index(
2219 {
2220 current_max = v;
2221 current_glob = cell->vertex_index(
2223 }
2224 }
2225 }
2226
2227 face_orientation[m][0] =
2229
2230 // f^m_2 is the vertex opposite f^m_0.
2231 face_orientation[m][2] = GeometryInfo<dim>::face_to_cell_vertices(
2232 m, vertex_opposite_on_face[current_max]);
2233
2234 // Finally, f^m_1 is the vertex with the greater global numbering
2235 // of the remaining two local vertices. Then, f^m_3 is the other.
2236 // Again, we need to distinguish between the hanging face and the
2237 // non-hanging face cases. In the case of hanging faces, we
2238 // consider the vertex indices from the parent. Otherwise, we
2239 // consider the vertex indices of the face itself.
2240 if (cell_has_coarser_neighbor)
2241 {
2242 if (cell->parent()->vertex_index(
2244 m, vertices_adjacent_on_face[current_max][0])) >
2245 cell->parent()->vertex_index(
2247 m, vertices_adjacent_on_face[current_max][1])))
2248 {
2249 face_orientation[m][1] =
2251 m, vertices_adjacent_on_face[current_max][0]);
2252 face_orientation[m][3] =
2254 m, vertices_adjacent_on_face[current_max][1]);
2255 }
2256 else
2257 {
2258 face_orientation[m][1] =
2260 m, vertices_adjacent_on_face[current_max][1]);
2261 face_orientation[m][3] =
2263 m, vertices_adjacent_on_face[current_max][0]);
2264 }
2265 }
2266 else
2267 {
2268 if (cell->vertex_index(
2270 m, vertices_adjacent_on_face[current_max][0])) >
2271 cell->vertex_index(
2273 m, vertices_adjacent_on_face[current_max][1])))
2274 {
2275 face_orientation[m][1] =
2277 m, vertices_adjacent_on_face[current_max][0]);
2278 face_orientation[m][3] =
2280 m, vertices_adjacent_on_face[current_max][1]);
2281 }
2282 else
2283 {
2284 face_orientation[m][1] =
2286 m, vertices_adjacent_on_face[current_max][1]);
2287 face_orientation[m][3] =
2289 m, vertices_adjacent_on_face[current_max][0]);
2290 }
2291 }
2292 }
2293 // Now we know the face orientation on the current cell, we can
2294 // generate the parameterisation:
2295 std::vector<std::vector<double>> face_xi_values(
2296 faces_per_cell, std::vector<double>(n_q_points));
2297 std::vector<std::vector<double>> face_xi_grads(
2298 faces_per_cell, std::vector<double>(dim));
2299 std::vector<std::vector<double>> face_eta_values(
2300 faces_per_cell, std::vector<double>(n_q_points));
2301 std::vector<std::vector<double>> face_eta_grads(
2302 faces_per_cell, std::vector<double>(dim));
2303
2304 std::vector<std::vector<double>> face_lambda_values(
2305 faces_per_cell, std::vector<double>(n_q_points));
2306 std::vector<std::vector<double>> face_lambda_grads(
2307 faces_per_cell, std::vector<double>(dim));
2308 for (unsigned int m = 0; m < faces_per_cell; ++m)
2309 {
2310 for (unsigned int q = 0; q < n_q_points; ++q)
2311 {
2312 face_xi_values[m][q] =
2313 fe_data.sigma_imj_values[q][face_orientation[m][0]]
2314 [face_orientation[m][1]];
2315 face_eta_values[m][q] =
2316 fe_data.sigma_imj_values[q][face_orientation[m][0]]
2317 [face_orientation[m][3]];
2318 face_lambda_values[m][q] = fe_data.face_lambda_values[m][q];
2319 }
2320 for (unsigned int d = 0; d < dim; ++d)
2321 {
2322 face_xi_grads[m][d] =
2323 fe_data.sigma_imj_grads[face_orientation[m][0]]
2324 [face_orientation[m][1]][d];
2325 face_eta_grads[m][d] =
2326 fe_data.sigma_imj_grads[face_orientation[m][0]]
2327 [face_orientation[m][3]][d];
2328
2329 face_lambda_grads[m][d] = fe_data.face_lambda_grads[m][d];
2330 }
2331 }
2332 // Now can generate the basis
2333 const unsigned int poly_length =
2334 (flags & update_hessians) ? 4 :
2335 ((flags & update_gradients) ? 3 : 2);
2336
2337
2338 std::vector<std::vector<double>> polyxi(
2339 degree, std::vector<double>(poly_length));
2340 std::vector<std::vector<double>> polyeta(
2341 degree, std::vector<double>(poly_length));
2342
2343 // Loop through quad points:
2344 for (unsigned int m = 0; m < faces_per_cell; ++m)
2345 {
2346 // we assume that all quads have the same number of dofs
2347 const unsigned int shift_m(m * this->n_dofs_per_quad(0));
2348 // Calculate the offsets for each face-based shape function:
2349 //
2350 // Type-1 (gradients)
2351 // \phi^{F_m,1}_{ij} = \nabla( L_{i+2}(\xi_{F_{m}})
2352 // L_{j+2}(\eta_{F_{m}}) \lambda_{F_{m}} )
2353 //
2354 // 0 <= i,j < degree (in a group of degree*degree)
2355 const unsigned int face_type1_offset(n_line_dofs + shift_m);
2356 // Type-2:
2357 //
2358 // \phi^{F_m,2}_{ij} = ( L'_{i+2}(\xi_{F_{m}})
2359 // L_{j+2}(\eta_{F_{m}}) \nabla\xi_{F_{m}}
2360 // - L_{i+2}(\xi_{F_{m}})
2361 // L'_{j+2}(\eta_{F_{m}}) \nabla\eta_{F_{m}}
2362 // ) \lambda_{F_{m}}
2363 //
2364 // 0 <= i,j < degree (in a group of degree*degree)
2365 const unsigned int face_type2_offset(face_type1_offset +
2366 degree * degree);
2367 // Type-3:
2368 //
2369 // \phi^{F_m,3}_{i} = L_{i+2}(\eta_{F_{m}}) \lambda_{F_{m}}
2370 // \nabla\xi_{F_{m}}
2371 // \phi^{F_m,3}_{i+p} = L_{i+2}(\xi_{F_{m}})
2372 // \lambda_{F_{m}} \nabla\eta_{F_{m}}
2373 //
2374 // 0 <= i < degree.
2375 //
2376 // here we order so that all of subtype 1 comes first, then
2377 // subtype 2.
2378 const unsigned int face_type3_offset1(face_type2_offset +
2379 degree * degree);
2380 const unsigned int face_type3_offset2(face_type3_offset1 +
2381 degree);
2382
2383 // Loop over all faces:
2384 for (unsigned int q = 0; q < n_q_points; ++q)
2385 {
2386 // pre-compute values & required derivatives at this quad
2387 // point: polyxi = L_{i+2}(\xi_{F_{m}}), polyeta =
2388 // L_{j+2}(\eta_{F_{m}}),
2389 //
2390 // each polypoint[k][d], contains the dth derivative of
2391 // L_{k+2} at the point \xi or \eta. Note that this doesn't
2392 // include the derivative of xi/eta via the chain rule.
2393 for (unsigned int i = 0; i < degree; ++i)
2394 {
2395 // compute all required 1d polynomials:
2396 IntegratedLegendrePolynomials[i + 2].value(
2397 face_xi_values[m][q], polyxi[i]);
2398 IntegratedLegendrePolynomials[i + 2].value(
2399 face_eta_values[m][q], polyeta[i]);
2400 }
2401 // Now use these to compute the shape functions:
2402 if (flags & update_values)
2403 {
2404 for (unsigned int j = 0; j < degree; ++j)
2405 {
2406 const unsigned int shift_j(j * degree);
2407 for (unsigned int i = 0; i < degree; ++i)
2408 {
2409 const unsigned int shift_ij(shift_j + i);
2410 // Type 1:
2411 const unsigned int dof_index1(face_type1_offset +
2412 shift_ij);
2413 for (unsigned int d = 0; d < dim; ++d)
2414 {
2415 fe_data.shape_values[dof_index1][q][d] =
2416 (face_xi_grads[m][d] * polyxi[i][1] *
2417 polyeta[j][0] +
2418 face_eta_grads[m][d] * polyxi[i][0] *
2419 polyeta[j][1]) *
2420 face_lambda_values[m][q] +
2421 face_lambda_grads[m][d] * polyxi[i][0] *
2422 polyeta[j][0];
2423 }
2424 // Type 2:
2425 const unsigned int dof_index2(face_type2_offset +
2426 shift_ij);
2427 for (unsigned int d = 0; d < dim; ++d)
2428 {
2429 fe_data.shape_values[dof_index2][q][d] =
2430 (face_xi_grads[m][d] * polyxi[i][1] *
2431 polyeta[j][0] -
2432 face_eta_grads[m][d] * polyxi[i][0] *
2433 polyeta[j][1]) *
2434 face_lambda_values[m][q];
2435 }
2436 }
2437 // Type 3:
2438 const unsigned int dof_index3_1(face_type3_offset1 +
2439 j);
2440 const unsigned int dof_index3_2(face_type3_offset2 +
2441 j);
2442 for (unsigned int d = 0; d < dim; ++d)
2443 {
2444 fe_data.shape_values[dof_index3_1][q][d] =
2445 face_xi_grads[m][d] * polyeta[j][0] *
2446 face_lambda_values[m][q];
2447
2448 fe_data.shape_values[dof_index3_2][q][d] =
2449 face_eta_grads[m][d] * polyxi[j][0] *
2450 face_lambda_values[m][q];
2451 }
2452 }
2453 }
2454 if (flags & update_gradients)
2455 {
2456 for (unsigned int j = 0; j < degree; ++j)
2457 {
2458 const unsigned int shift_j(j * degree);
2459 for (unsigned int i = 0; i < degree; ++i)
2460 {
2461 const unsigned int shift_ij(shift_j + i);
2462 // Type 1:
2463 const unsigned int dof_index1(face_type1_offset +
2464 shift_ij);
2465 for (unsigned int d1 = 0; d1 < dim; ++d1)
2466 {
2467 for (unsigned int d2 = 0; d2 < dim; ++d2)
2468 {
2469 fe_data
2470 .shape_grads[dof_index1][q][d1][d2] =
2471 (face_xi_grads[m][d1] *
2472 face_xi_grads[m][d2] * polyxi[i][2] *
2473 polyeta[j][0] +
2474 (face_xi_grads[m][d1] *
2475 face_eta_grads[m][d2] +
2476 face_xi_grads[m][d2] *
2477 face_eta_grads[m][d1]) *
2478 polyxi[i][1] * polyeta[j][1] +
2479 face_eta_grads[m][d1] *
2480 face_eta_grads[m][d2] *
2481 polyxi[i][0] * polyeta[j][2]) *
2482 face_lambda_values[m][q] +
2483 (face_xi_grads[m][d2] * polyxi[i][1] *
2484 polyeta[j][0] +
2485 face_eta_grads[m][d2] * polyxi[i][0] *
2486 polyeta[j][1]) *
2487 face_lambda_grads[m][d1] +
2488 (face_xi_grads[m][d1] * polyxi[i][1] *
2489 polyeta[j][0] +
2490 face_eta_grads[m][d1] * polyxi[i][0] *
2491 polyeta[j][1]) *
2492 face_lambda_grads[m][d2];
2493 }
2494 }
2495 // Type 2:
2496 const unsigned int dof_index2(face_type2_offset +
2497 shift_ij);
2498 for (unsigned int d1 = 0; d1 < dim; ++d1)
2499 {
2500 for (unsigned int d2 = 0; d2 < dim; ++d2)
2501 {
2502 fe_data
2503 .shape_grads[dof_index2][q][d1][d2] =
2504 (face_xi_grads[m][d1] *
2505 face_xi_grads[m][d2] * polyxi[i][2] *
2506 polyeta[j][0] +
2507 (face_xi_grads[m][d1] *
2508 face_eta_grads[m][d2] -
2509 face_xi_grads[m][d2] *
2510 face_eta_grads[m][d1]) *
2511 polyxi[i][1] * polyeta[j][1] -
2512 face_eta_grads[m][d1] *
2513 face_eta_grads[m][d2] *
2514 polyxi[i][0] * polyeta[j][2]) *
2515 face_lambda_values[m][q] +
2516 (face_xi_grads[m][d1] * polyxi[i][1] *
2517 polyeta[j][0] -
2518 face_eta_grads[m][d1] * polyxi[i][0] *
2519 polyeta[j][1]) *
2520 face_lambda_grads[m][d2];
2521 }
2522 }
2523 }
2524 // Type 3:
2525 const unsigned int dof_index3_1(face_type3_offset1 +
2526 j);
2527 const unsigned int dof_index3_2(face_type3_offset2 +
2528 j);
2529 for (unsigned int d1 = 0; d1 < dim; ++d1)
2530 {
2531 for (unsigned int d2 = 0; d2 < dim; ++d2)
2532 {
2533 fe_data.shape_grads[dof_index3_1][q][d1][d2] =
2534 face_xi_grads[m][d1] *
2535 (face_eta_grads[m][d2] * polyeta[j][1] *
2536 face_lambda_values[m][q] +
2537 face_lambda_grads[m][d2] * polyeta[j][0]);
2538
2539 fe_data.shape_grads[dof_index3_2][q][d1][d2] =
2540 face_eta_grads[m][d1] *
2541 (face_xi_grads[m][d2] * polyxi[j][1] *
2542 face_lambda_values[m][q] +
2543 face_lambda_grads[m][d2] * polyxi[j][0]);
2544 }
2545 }
2546 }
2547 }
2548 if (flags & update_hessians)
2549 {
2550 for (unsigned int j = 0; j < degree; ++j)
2551 {
2552 const unsigned int shift_j(j * degree);
2553 for (unsigned int i = 0; i < degree; ++i)
2554 {
2555 const unsigned int shift_ij(shift_j + i);
2556
2557 // Type 1:
2558 const unsigned int dof_index1(face_type1_offset +
2559 shift_ij);
2560 for (unsigned int d1 = 0; d1 < dim; ++d1)
2561 {
2562 for (unsigned int d2 = 0; d2 < dim; ++d2)
2563 {
2564 for (unsigned int d3 = 0; d3 < dim; ++d3)
2565 {
2566 fe_data.shape_hessians[dof_index1][q]
2567 [d1][d2][d3] =
2568 polyxi[i][1] *
2569 face_xi_grads[m][d3] *
2570 (face_eta_grads[m][d1] *
2571 (polyeta[j][2] *
2572 face_eta_grads[m][d2] *
2573 face_lambda_values[m][q] +
2574 polyeta[j][1] *
2575 face_lambda_grads[m][d2]) +
2576 polyeta[j][1] *
2577 face_eta_grads[m][d2] *
2578 face_lambda_grads[m][d1]) +
2579 polyxi[i][0] *
2580 (polyeta[j][3] *
2581 face_eta_grads[m][d1] *
2582 face_eta_grads[m][d2] *
2583 face_eta_grads[m][d3] *
2584 face_lambda_values[m][q] +
2585 polyeta[j][2] *
2586 (face_eta_grads[m][d1] *
2587 face_eta_grads[m][d2] *
2588 face_lambda_grads[m][d3] +
2589 face_eta_grads[m][d3] *
2590 (face_eta_grads[m][d1] *
2591 face_lambda_grads[m]
2592 [d2] +
2593 face_eta_grads[m][d2] *
2594 face_lambda_grads
2595 [m][d1]))) +
2596 (polyxi[i][1] * polyeta[j][1] *
2597 face_eta_grads[m][d3] +
2598 polyxi[i][2] * polyeta[j][0] *
2599 face_xi_grads[m][d3]) *
2600 (face_xi_grads[m][d1] *
2601 face_lambda_grads[m][d2] +
2602 face_xi_grads[m][d2] *
2603 face_lambda_grads[m][d1]) +
2604 face_lambda_grads[m][d3] *
2605 (polyxi[i][2] * polyeta[j][0] *
2606 face_xi_grads[m][d1] *
2607 face_xi_grads[m][d2] +
2608 polyxi[i][1] * polyeta[j][1] *
2609 (face_xi_grads[m][d1] *
2610 face_eta_grads[m][d2] +
2611 face_xi_grads[m][d2] *
2612 face_eta_grads[m][d1])) +
2613 face_lambda_values[m][q] *
2614 (polyxi[i][3] * polyeta[j][0] *
2615 face_xi_grads[m][d1] *
2616 face_xi_grads[m][d2] *
2617 face_xi_grads[m][d3] +
2618 polyxi[i][1] * polyeta[j][2] *
2619 face_eta_grads[m][d3] *
2620 (face_xi_grads[m][d1] *
2621 face_eta_grads[m][d2] +
2622 face_xi_grads[m][d2] *
2623 face_eta_grads[m][d1]) +
2624 polyxi[i][2] * polyeta[j][1] *
2625 (face_xi_grads[m][d3] *
2626 face_xi_grads[m][d2] *
2627 face_eta_grads[m][d1] +
2628 face_xi_grads[m][d1] *
2629 (face_xi_grads[m][d2] *
2630 face_eta_grads[m][d3] +
2631 face_xi_grads[m][d3] *
2632 face_eta_grads[m][d2])));
2633 }
2634 }
2635 }
2636
2637 // Type 2:
2638 const unsigned int dof_index2(face_type2_offset +
2639 shift_ij);
2640 for (unsigned int d1 = 0; d1 < dim; ++d1)
2641 {
2642 for (unsigned int d2 = 0; d2 < dim; ++d2)
2643 {
2644 for (unsigned int d3 = 0; d3 < dim; ++d3)
2645 {
2646 fe_data.shape_hessians[dof_index2][q]
2647 [d1][d2][d3] =
2648 face_xi_grads[m][d1] *
2649 (polyxi[i][1] * polyeta[j][1] *
2650 (face_eta_grads[m][d2] *
2651 face_lambda_grads[m][d3] +
2652 face_eta_grads[m][d3] *
2653 face_lambda_grads[m][d2]) +
2654 polyxi[i][2] * polyeta[j][0] *
2655 (face_xi_grads[m][d2] *
2656 face_lambda_grads[m][d3] +
2657 face_xi_grads[m][d3] *
2658 face_lambda_grads[m][d2]) +
2659 face_lambda_values[m][q] *
2660 (face_eta_grads[m][d2] *
2661 (polyxi[i][1] *
2662 polyeta[j][2] *
2663 face_eta_grads[m][d3] +
2664 polyxi[i][2] *
2665 polyeta[j][1] *
2666 face_xi_grads[m][d3]) +
2667 face_xi_grads[m][d2] *
2668 (polyxi[i][2] *
2669 polyeta[j][1] *
2670 face_eta_grads[m][d3] +
2671 polyxi[i][3] *
2672 polyeta[j][0] *
2673 face_xi_grads[m][d3]))) -
2674 polyxi[i][0] *
2675 face_eta_grads[m][d1] *
2676 (face_eta_grads[m][d2] *
2677 (polyeta[j][3] *
2678 face_eta_grads[m][d3] *
2679 face_lambda_values[m][q] +
2680 polyeta[j][2] *
2681 face_lambda_grads[m][d3]) +
2682 polyeta[j][2] *
2683 face_eta_grads[m][d3] *
2684 face_lambda_grads[m][d2]) -
2685 face_eta_grads[m][d1] *
2686 (polyxi[i][1] *
2687 face_xi_grads[m][d3] *
2688 (polyeta[j][2] *
2689 face_eta_grads[m][d2] *
2690 face_lambda_values[m][q] +
2691 polyeta[j][1] *
2692 face_lambda_grads[m][d2]) +
2693 face_xi_grads[m][d2] *
2694 (polyxi[i][1] *
2695 (polyeta[j][2] *
2696 face_eta_grads[m][d3] *
2697 face_lambda_values[m]
2698 [q] +
2699 polyeta[j][1] *
2700 face_lambda_grads[m]
2701 [d3]) +
2702 polyxi[i][2] * polyeta[j][1] *
2703 face_xi_grads[m][d3] *
2704 face_lambda_values[m][q]));
2705 }
2706 }
2707 }
2708 }
2709 // Type 3:
2710 const unsigned int dof_index3_1(face_type3_offset1 +
2711 j);
2712 const unsigned int dof_index3_2(face_type3_offset2 +
2713 j);
2714 for (unsigned int d1 = 0; d1 < dim; ++d1)
2715 {
2716 for (unsigned int d2 = 0; d2 < dim; ++d2)
2717 {
2718 for (unsigned int d3 = 0; d3 < dim; ++d3)
2719 {
2720 fe_data.shape_hessians[dof_index3_1][q]
2721 [d1][d2][d3] =
2722 face_xi_grads[m][d1] *
2723 (face_eta_grads[m][d2] *
2724 (polyeta[j][2] *
2725 face_eta_grads[m][d3] *
2726 face_lambda_values[m][q] +
2727 polyeta[j][1] *
2728 face_lambda_grads[m][d3]) +
2729 face_lambda_grads[m][d2] *
2730 polyeta[j][1] *
2731 face_eta_grads[m][d3]);
2732
2733 fe_data.shape_hessians[dof_index3_2][q]
2734 [d1][d2][d3] =
2735 face_eta_grads[m][d1] *
2736 (face_xi_grads[m][d2] *
2737 (polyxi[j][2] *
2738 face_xi_grads[m][d3] *
2739 face_lambda_values[m][q] +
2740 polyxi[j][1] *
2741 face_lambda_grads[m][d3]) +
2742 face_lambda_grads[m][d2] *
2743 polyxi[j][1] * face_xi_grads[m][d3]);
2744 }
2745 }
2746 }
2747 }
2748 }
2749 }
2750 }
2751 }
2752 }
2753}
2754
2755
2756
2757template <int dim, int spacedim>
2758void
2760 const typename Triangulation<dim, dim>::cell_iterator &cell,
2761 const CellSimilarity::Similarity /*cell_similarity*/,
2762 const Quadrature<dim> &quadrature,
2763 const Mapping<dim, dim> &mapping,
2764 const typename Mapping<dim, dim>::InternalDataBase &mapping_internal,
2766 &mapping_data,
2767 const typename FiniteElement<dim, dim>::InternalDataBase &fe_internal,
2769 &data) const
2770{
2771 // Convert to the correct internal data class for this FE class.
2772 Assert(dynamic_cast<const InternalData *>(&fe_internal) != nullptr,
2774 const InternalData &fe_data = static_cast<const InternalData &>(fe_internal);
2775
2776 // Now update the edge-based DoFs, which depend on the cell.
2777 // This will fill in the missing items in the InternalData
2778 // (fe_internal/fe_data) which was not filled in by get_data.
2779 fill_edge_values(cell, quadrature, fe_data);
2780 if (dim == 3 && this->degree > 1)
2781 {
2782 fill_face_values(cell, quadrature, fe_data);
2783 }
2784
2785 const UpdateFlags flags(fe_data.update_each);
2786 const unsigned int n_q_points = quadrature.size();
2787
2788 Assert(!(flags & update_values) ||
2789 fe_data.shape_values.size() == this->n_dofs_per_cell(),
2790 ExcDimensionMismatch(fe_data.shape_values.size(),
2791 this->n_dofs_per_cell()));
2792 Assert(!(flags & update_values) ||
2793 fe_data.shape_values[0].size() == n_q_points,
2794 ExcDimensionMismatch(fe_data.shape_values[0].size(), n_q_points));
2795
2796 if (flags & update_values)
2797 {
2798 // Now have all shape_values stored on the reference cell.
2799 // Must now transform to the physical cell.
2800 std::vector<Tensor<1, dim>> transformed_shape_values(n_q_points);
2801 for (unsigned int dof = 0; dof < this->n_dofs_per_cell(); ++dof)
2802 {
2803 const unsigned int first =
2804 data.shape_function_to_row_table[dof * this->n_components() +
2805 this->get_nonzero_components(dof)
2806 .first_selected_component()];
2807
2808 mapping.transform(make_array_view(fe_data.shape_values[dof]),
2810 mapping_internal,
2811 make_array_view(transformed_shape_values));
2812 for (unsigned int q = 0; q < n_q_points; ++q)
2813 {
2814 for (unsigned int d = 0; d < dim; ++d)
2815 {
2816 data.shape_values(first + d, q) =
2817 transformed_shape_values[q][d];
2818 }
2819 }
2820 }
2821 }
2822
2823 if (flags & update_gradients)
2824 {
2825 // Now have all shape_grads stored on the reference cell.
2826 // Must now transform to the physical cell.
2827 std::vector<Tensor<2, dim>> input(n_q_points);
2828 std::vector<Tensor<2, dim>> transformed_shape_grads(n_q_points);
2829 for (unsigned int dof = 0; dof < this->n_dofs_per_cell(); ++dof)
2830 {
2831 for (unsigned int q = 0; q < n_q_points; ++q)
2832 {
2833 input[q] = fe_data.shape_grads[dof][q];
2834 }
2835 mapping.transform(make_array_view(input),
2837 mapping_internal,
2838 make_array_view(transformed_shape_grads));
2839
2840 const unsigned int first =
2841 data.shape_function_to_row_table[dof * this->n_components() +
2842 this->get_nonzero_components(dof)
2843 .first_selected_component()];
2844
2845 for (unsigned int q = 0; q < n_q_points; ++q)
2846 {
2847 for (unsigned int d1 = 0; d1 < dim; ++d1)
2848 {
2849 for (unsigned int d2 = 0; d2 < dim; ++d2)
2850 {
2851 transformed_shape_grads[q][d1] -=
2852 data.shape_values(first + d2, q) *
2853 mapping_data.jacobian_pushed_forward_grads[q][d2][d1];
2854 }
2855 }
2856 }
2857
2858 for (unsigned int q = 0; q < n_q_points; ++q)
2859 {
2860 for (unsigned int d = 0; d < dim; ++d)
2861 {
2862 data.shape_gradients[first + d][q] =
2863 transformed_shape_grads[q][d];
2864 }
2865 }
2866 }
2867 }
2868
2869 if (flags & update_hessians)
2870 {
2871 // Now have all shape_grads stored on the reference cell.
2872 // Must now transform to the physical cell.
2873 std::vector<Tensor<3, dim>> input(n_q_points);
2874 std::vector<Tensor<3, dim>> transformed_shape_hessians(n_q_points);
2875 for (unsigned int dof = 0; dof < this->n_dofs_per_cell(); ++dof)
2876 {
2877 for (unsigned int q = 0; q < n_q_points; ++q)
2878 {
2879 input[q] = fe_data.shape_hessians[dof][q];
2880 }
2881 mapping.transform(make_array_view(input),
2883 mapping_internal,
2884 make_array_view(transformed_shape_hessians));
2885
2886 const unsigned int first =
2887 data.shape_function_to_row_table[dof * this->n_components() +
2888 this->get_nonzero_components(dof)
2889 .first_selected_component()];
2890
2891 for (unsigned int q = 0; q < n_q_points; ++q)
2892 {
2893 for (unsigned int d1 = 0; d1 < dim; ++d1)
2894 {
2895 for (unsigned int d2 = 0; d2 < dim; ++d2)
2896 {
2897 for (unsigned int d3 = 0; d3 < dim; ++d3)
2898 {
2899 for (unsigned int d4 = 0; d4 < dim; ++d4)
2900 {
2901 transformed_shape_hessians[q][d1][d3][d4] -=
2902 (data.shape_values(first + d2, q) *
2903 mapping_data
2905 [q][d2][d1][d3][d4]) +
2906 (data.shape_gradients[first + d1][q][d2] *
2907 mapping_data
2909 [d4]) +
2910 (data.shape_gradients[first + d2][q][d3] *
2911 mapping_data
2913 [d4]) +
2914 (data.shape_gradients[first + d2][q][d4] *
2915 mapping_data
2917 [d1]);
2918 }
2919 }
2920 }
2921 }
2922 }
2923
2924 for (unsigned int q = 0; q < n_q_points; ++q)
2925 {
2926 for (unsigned int d = 0; d < dim; ++d)
2927 {
2928 data.shape_hessians[first + d][q] =
2929 transformed_shape_hessians[q][d];
2930 }
2931 }
2932 }
2933 }
2934}
2935
2936
2937
2938template <int dim, int spacedim>
2939void
2941 const typename Triangulation<dim, dim>::cell_iterator &cell,
2942 const unsigned int face_no,
2943 const hp::QCollection<dim - 1> &quadrature,
2944 const Mapping<dim, dim> &mapping,
2945 const typename Mapping<dim, dim>::InternalDataBase &mapping_internal,
2947 &mapping_data,
2948 const typename FiniteElement<dim, dim>::InternalDataBase &fe_internal,
2950 &data) const
2951{
2952 AssertDimension(quadrature.size(), 1);
2953
2954 // Note for future improvement:
2955 // We don't have the full quadrature - should use QProjector to create the 2d
2956 // quadrature.
2957 //
2958 // For now I am effectively generating all of the shape function vals/grads,
2959 // etc. On all quad points on all faces and then only using them for one face.
2960 // This is obviously inefficient. I should cache the cell number and cache
2961 // all of the shape_values/gradients etc and then reuse them for each face.
2962
2963 // convert data object to internal
2964 // data for this class. fails with
2965 // an exception if that is not
2966 // possible
2967 Assert(dynamic_cast<const InternalData *>(&fe_internal) != nullptr,
2969 const InternalData &fe_data = static_cast<const InternalData &>(fe_internal);
2970
2971 // Now update the edge-based DoFs, which depend on the cell.
2972 // This will fill in the missing items in the InternalData
2973 // (fe_internal/fe_data) which was not filled in by get_data.
2974 fill_edge_values(cell,
2975 QProjector<dim>::project_to_all_faces(this->reference_cell(),
2976 quadrature[0]),
2977 fe_data);
2978 if (dim == 3 && this->degree > 1)
2979 {
2980 fill_face_values(cell,
2982 this->reference_cell(), quadrature[0]),
2983 fe_data);
2984 }
2985
2986 const UpdateFlags flags(fe_data.update_each);
2987 const unsigned int n_q_points = quadrature[0].size();
2988 const auto offset =
2989 QProjector<dim>::DataSetDescriptor::face(this->reference_cell(),
2990 face_no,
2991 cell->combined_face_orientation(
2992 face_no),
2993 n_q_points);
2994
2995 if (flags & update_values)
2996 {
2997 // Now have all shape_values stored on the reference cell.
2998 // Must now transform to the physical cell.
2999 std::vector<Tensor<1, dim>> transformed_shape_values(n_q_points);
3000 for (unsigned int dof = 0; dof < this->n_dofs_per_cell(); ++dof)
3001 {
3002 mapping.transform(make_array_view(fe_data.shape_values[dof],
3003 offset,
3004 n_q_points),
3006 mapping_internal,
3007 make_array_view(transformed_shape_values));
3008
3009 const unsigned int first =
3010 data.shape_function_to_row_table[dof * this->n_components() +
3011 this->get_nonzero_components(dof)
3012 .first_selected_component()];
3013
3014 for (unsigned int q = 0; q < n_q_points; ++q)
3015 {
3016 for (unsigned int d = 0; d < dim; ++d)
3017 {
3018 data.shape_values(first + d, q) =
3019 transformed_shape_values[q][d];
3020 }
3021 }
3022 }
3023 }
3024 if (flags & update_gradients)
3025 {
3026 // Now have all shape_grads stored on the reference cell.
3027 // Must now transform to the physical cell.
3028 std::vector<Tensor<2, dim>> input(n_q_points);
3029 std::vector<Tensor<2, dim>> transformed_shape_grads(n_q_points);
3030 for (unsigned int dof = 0; dof < this->n_dofs_per_cell(); ++dof)
3031 {
3032 for (unsigned int q = 0; q < n_q_points; ++q)
3033 {
3034 input[q] = fe_data.shape_grads[dof][offset + q];
3035 }
3036 mapping.transform(input,
3038 mapping_internal,
3039 make_array_view(transformed_shape_grads));
3040
3041 const unsigned int first =
3042 data.shape_function_to_row_table[dof * this->n_components() +
3043 this->get_nonzero_components(dof)
3044 .first_selected_component()];
3045
3046 for (unsigned int q = 0; q < n_q_points; ++q)
3047 {
3048 for (unsigned int d1 = 0; d1 < dim; ++d1)
3049 {
3050 for (unsigned int d2 = 0; d2 < dim; ++d2)
3051 {
3052 transformed_shape_grads[q][d1] -=
3053 data.shape_values(first + d2, q) *
3054 mapping_data.jacobian_pushed_forward_grads[q][d2][d1];
3055 }
3056 }
3057 }
3058
3059 for (unsigned int q = 0; q < n_q_points; ++q)
3060 {
3061 for (unsigned int d = 0; d < dim; ++d)
3062 {
3063 data.shape_gradients[first + d][q] =
3064 transformed_shape_grads[q][d];
3065 }
3066 }
3067 }
3068 }
3069 if (flags & update_hessians)
3070 {
3071 // Now have all shape_grads stored on the reference cell.
3072 // Must now transform to the physical cell.
3073 std::vector<Tensor<3, dim>> input(n_q_points);
3074 std::vector<Tensor<3, dim>> transformed_shape_hessians(n_q_points);
3075 for (unsigned int dof = 0; dof < this->n_dofs_per_cell(); ++dof)
3076 {
3077 for (unsigned int q = 0; q < n_q_points; ++q)
3078 input[q] = fe_data.shape_hessians[dof][offset + q];
3079
3080 mapping.transform(input,
3082 mapping_internal,
3083 make_array_view(transformed_shape_hessians));
3084
3085 const unsigned int first =
3086 data.shape_function_to_row_table[dof * this->n_components() +
3087 this->get_nonzero_components(dof)
3088 .first_selected_component()];
3089
3090 for (unsigned int q = 0; q < n_q_points; ++q)
3091 {
3092 for (unsigned int d1 = 0; d1 < dim; ++d1)
3093 {
3094 for (unsigned int d2 = 0; d2 < dim; ++d2)
3095 {
3096 for (unsigned int d3 = 0; d3 < dim; ++d3)
3097 {
3098 for (unsigned int d4 = 0; d4 < dim; ++d4)
3099 {
3100 transformed_shape_hessians[q][d1][d3][d4] -=
3101 (data.shape_values(first + d2, q) *
3102 mapping_data
3104 [q][d2][d1][d3][d4]) +
3105 (data.shape_gradients[first + d1][q][d2] *
3106 mapping_data
3108 [d4]) +
3109 (data.shape_gradients[first + d2][q][d3] *
3110 mapping_data
3112 [d4]) +
3113 (data.shape_gradients[first + d2][q][d4] *
3114 mapping_data
3116 [d1]);
3117 }
3118 }
3119 }
3120 }
3121 }
3122
3123 for (unsigned int q = 0; q < n_q_points; ++q)
3124 {
3125 for (unsigned int d = 0; d < dim; ++d)
3126 {
3127 data.shape_hessians[first + d][q] =
3128 transformed_shape_hessians[q][d];
3129 }
3130 }
3131 }
3132 }
3133}
3134
3135
3136
3137template <int dim, int spacedim>
3138void
3140 const typename Triangulation<dim, dim>::cell_iterator & /*cell*/,
3141 const unsigned int /*face_no*/,
3142 const unsigned int /*sub_no*/,
3143 const Quadrature<dim - 1> & /*quadrature*/,
3144 const Mapping<dim, dim> & /*mapping*/,
3145 const typename Mapping<dim, dim>::InternalDataBase & /*mapping_internal*/,
3147 & /*mapping_data*/,
3148 const typename FiniteElement<dim, dim>::InternalDataBase & /*fe_internal*/,
3150 & /*data*/) const
3151{
3153}
3154
3155
3156
3157template <int dim, int spacedim>
3180
3181
3182
3183template <int dim, int spacedim>
3184std::string
3186{
3187 // note that the FETools::get_fe_by_name function depends on the particular
3188 // format of the string this function returns, so they have to be kept in sync
3189 std::ostringstream namebuf;
3190 namebuf << "FE_NedelecSZ<" << Utilities::dim_string(dim, spacedim) << ">("
3191 << this->degree - 1 << ")";
3192
3193 return namebuf.str();
3194}
3195
3196
3197
3198template <int dim, int spacedim>
3199std::unique_ptr<FiniteElement<dim, dim>>
3201{
3202 return std::make_unique<FE_NedelecSZ<dim, spacedim>>(*this);
3203}
3204
3205
3206
3207template <int dim, int spacedim>
3208std::vector<unsigned int>
3210{
3211 // internal function to return a vector of "dofs per object"
3212 // where the objects inside the vector refer to:
3213 // 0 = vertex
3214 // 1 = edge
3215 // 2 = face (which is a cell in 2d)
3216 // 3 = cell
3217 std::vector<unsigned int> dpo;
3218
3219 dpo.push_back(0);
3220 dpo.push_back(degree + 1);
3221 if (dim > 1)
3222 dpo.push_back(2 * degree * (degree + 1));
3223 if (dim > 2)
3224 dpo.push_back(3 * degree * degree * (degree + 1));
3225
3226 return dpo;
3227}
3228
3229
3230
3231template <int dim, int spacedim>
3232unsigned int
3234{
3235 // Internal function to compute the number of DoFs
3236 // for a given dimension & polynomial order.
3237 switch (dim)
3238 {
3239 case 2:
3240 return 2 * (degree + 1) * (degree + 2);
3241
3242 case 3:
3243 return 3 * (degree + 1) * (degree + 2) * (degree + 2);
3244
3245 default:
3246 {
3248 return 0;
3249 }
3250 }
3251}
3252
3253
3254
3255template <int dim, int spacedim>
3256void
3258{
3259 // fill the 1d polynomials vector:
3260 IntegratedLegendrePolynomials =
3262}
3263
3264
3265
3266template <int dim, int spacedim>
3267const FullMatrix<double> &
3269 const unsigned int child,
3270 const RefinementCase<dim> &refinement_case) const
3271{
3272 AssertIndexRange(refinement_case,
3274 Assert(refinement_case != RefinementCase<dim>::no_refinement,
3275 ExcMessage(
3276 "Prolongation matrices are only available for refined cells!"));
3277 AssertIndexRange(child, this->reference_cell().n_children(refinement_case));
3278
3279 // initialization upon first request
3280 if (this->prolongation[refinement_case - 1][child].n() == 0)
3281 {
3282 std::scoped_lock lock(prolongation_matrix_mutex);
3283
3284 // if matrix got updated while waiting for the lock
3285 if (this->prolongation[refinement_case - 1][child].n() ==
3286 this->n_dofs_per_cell())
3287 return this->prolongation[refinement_case - 1][child];
3288
3289 // now do the work. need to get a non-const version of data in order to
3290 // be able to modify them inside a const function
3291 FE_NedelecSZ<dim> &this_nonconst = const_cast<FE_NedelecSZ<dim> &>(*this);
3292
3293 // Reinit the vectors of
3294 // restriction and prolongation
3295 // matrices to the right sizes.
3296 // Restriction only for isotropic
3297 // refinement
3299 // Fill prolongation matrices with embedding operators
3301 this_nonconst,
3302 this_nonconst.prolongation,
3303 true,
3304 1.e-15 * std::exp(std::pow(this->degree, 1.075)));
3305 }
3306
3307 // we use refinement_case-1 here. the -1 takes care of the origin of the
3308 // vector, as for RefinementCase<dim>::no_refinement (=0) there is no data
3309 // available and so the vector indices are shifted
3310 return this->prolongation[refinement_case - 1][child];
3311}
3312
3313// explicit instantiations
3314#include "fe/fe_nedelec_sz.inst"
3315
*  iterator end()
*  *  iterator begin()
ArrayView< std::remove_reference_t< typename std::iterator_traits< Iterator >::reference >, MemorySpaceType > make_array_view(const Iterator begin, const Iterator end)
std::vector< std::vector< double > > edge_lambda_grads_2d
std::vector< std::vector< Tensor< 1, dim > > > shape_values
std::vector< std::vector< std::vector< double > > > sigma_imj_values
std::vector< std::vector< double > > edge_sigma_grads
std::vector< std::vector< double > > edge_sigma_values
std::vector< std::vector< DerivativeForm< 2, dim, dim > > > shape_hessians
std::vector< std::vector< std::vector< double > > > sigma_imj_grads
std::vector< std::vector< double > > face_lambda_values
std::vector< std::vector< DerivativeForm< 1, dim, dim > > > shape_grads
std::vector< std::vector< std::vector< double > > > edge_lambda_grads_3d
std::vector< std::vector< double > > edge_lambda_values
std::vector< std::vector< std::vector< double > > > edge_lambda_gradgrads_3d
std::vector< std::vector< double > > face_lambda_grads
void evaluate(const std::vector< Point< dim > > &p_list, const UpdateFlags update_flags, std::unique_ptr< typename ::FiniteElement< dim, spacedim >::InternalDataBase > &data_ptr) const
unsigned int compute_num_dofs(const unsigned int degree) const
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 std::unique_ptr< FiniteElement< dim, dim > > clone() const override
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
FE_NedelecSZ(const unsigned int order)
virtual UpdateFlags requires_update_flags(const UpdateFlags update_flags) const override
static std::vector< unsigned int > get_dpo_vector(const unsigned int degree)
void create_polynomials(const unsigned int degree)
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 void fill_fe_face_values(const typename Triangulation< dim, dim >::cell_iterator &cell, const unsigned int face_no, const hp::QCollection< 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
virtual const FullMatrix< double > & get_prolongation_matrix(const unsigned int child, const RefinementCase< dim > &refinement_case=RefinementCase< dim >::isotropic_refinement) const override
virtual std::string get_name() const override
virtual Tensor< 2, dim > shape_grad_grad_component(const unsigned int i, const Point< dim > &p, const unsigned int component) const override
virtual Tensor< 1, dim > shape_grad_component(const unsigned int i, const Point< dim > &p, const unsigned int component) const override
virtual Tensor< 1, dim > shape_grad(const unsigned int i, const Point< dim > &p) const override
virtual Tensor< 2, dim > shape_grad_grad(const unsigned int i, const Point< dim > &p) const override
virtual double shape_value_component(const unsigned int i, const Point< dim > &p, const unsigned int component) const override
void fill_face_values(const typename Triangulation< dim, dim >::cell_iterator &cell, const Quadrature< dim > &quadrature, const InternalData &fedata) const
void fill_edge_values(const typename Triangulation< dim, dim >::cell_iterator &cell, const Quadrature< dim > &quadrature, const InternalData &fedata) const
MappingKind mapping_kind
virtual double shape_value(const unsigned int i, const Point< dim > &p) const override
const unsigned int degree
Definition fe_data.h:450
unsigned int n_dofs_per_face(unsigned int face_no=0, unsigned int child=0) const
unsigned int n_components() const
unsigned int n_unique_faces() const
void reinit_restriction_and_prolongation_matrices(const bool isotropic_restriction_only=false, const bool isotropic_prolongation_only=false)
std::vector< std::pair< std::pair< unsigned int, unsigned int >, unsigned int > > component_to_base_table
Definition fe.h:2706
FullMatrix< double > interface_constraints
Definition fe.h:2573
std::vector< std::vector< FullMatrix< double > > > prolongation
Definition fe.h:2561
static std::vector< Polynomials::Polynomial< double > > generate_complete_basis(const unsigned int degree)
Abstract base class for mapping classes.
Definition mapping.h:318
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
Definition point.h:111
static DataSetDescriptor face(const ReferenceCell< dim > &reference_cell, const unsigned int face_no, const types::geometric_orientation combined_orientation, const unsigned int n_quadrature_points)
Class which transforms dim - 1-dimensional quadrature rules to dim-dimensional face quadratures.
Definition qprojector.h:68
const std::vector< Point< dim > > & get_points() const
unsigned int size() const
unsigned int size() const
Definition collection.h:314
std::vector< Tensor< 4, spacedim > > jacobian_pushed_forward_2nd_derivatives
std::vector< Tensor< 3, spacedim > > jacobian_pushed_forward_grads
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
#define DEAL_II_NOT_IMPLEMENTED()
Point< 2 > first
Definition grid_out.cc:4639
#define Assert(cond, exc)
static ::ExceptionBase & ExcImpossibleInDim(int arg1)
#define AssertDimension(dim1, dim2)
#define AssertIndexRange(index, range)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
static ::ExceptionBase & ExcMessage(std::string arg1)
UpdateFlags
@ update_jacobian_pushed_forward_2nd_derivatives
@ update_jacobian_pushed_forward_grads
@ update_hessians
Second derivatives of shape functions.
@ update_values
Shape function values.
@ update_covariant_transformation
Covariant transformation.
@ update_gradients
Shape function gradients.
@ update_default
No update.
@ mapping_covariant_gradient
Definition mapping.h:100
@ mapping_covariant
Definition mapping.h:89
@ mapping_nedelec
Definition mapping.h:129
@ mapping_covariant_hessian
Definition mapping.h:150
std::vector< index_type > data
Definition mpi.cc:734
void compute_embedding_matrices(const FiniteElement< dim, spacedim > &fe, std::vector< std::vector< FullMatrix< number > > > &matrices, const bool isotropic_only=false, const double threshold=1.e-12)
std::string dim_string(const int dim, const int spacedim)
Definition utilities.cc:547
STL namespace.
::VectorizedArray< Number, width > exp(const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > pow(const ::VectorizedArray< Number, width > &, const Number p)
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)
static unsigned int line_to_cell_vertices(const unsigned int line, const unsigned int vertex)