deal.II version 9.8.0
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
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>(
28 dim,
29 order + 1,
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
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{
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{
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{
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
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(
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]
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].
553 cell_points[q][0], polyx[i]);
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]
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(
842 std::vector<std::vector<double>>(n_q_points,
843 std::vector<double>(dim)));
844 data.edge_lambda_gradgrads_3d.resize(
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);
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
1827 const int cell_level = cell->level();
1828 for (auto &neighbor_cell :
1829 cell->get_cells_adjacent_to_line(line))
1830 if (neighbor_cell->level() != cell_level)
1831 {
1832 line_neighbor_is_coarser[line] = true;
1833 break;
1834 }
1835 }
1836
1837 for (unsigned int line : cell->line_indices())
1838 {
1839 const unsigned int v0_loc =
1841 const unsigned int v1_loc =
1843
1844 // get the global vertex indices
1845 unsigned int v0_glob;
1846 unsigned int v1_glob;
1847 if (line_neighbor_is_coarser[line])
1848 {
1849 // hanging edge case
1850 v0_glob = cell->parent()->vertex_index(v0_loc);
1851 v1_glob = cell->parent()->vertex_index(v1_loc);
1852 }
1853 else
1854 {
1855 // normal case
1856 v0_glob = cell->vertex_index(v0_loc);
1857 v1_glob = cell->vertex_index(v1_loc);
1858 }
1859
1860 // get the direction in comparison to the reference element
1861 if (v0_glob > v1_glob)
1862 {
1863 // Opposite to global numbering on our reference element
1864 edge_sign[line] = -1.0;
1865 }
1866 else
1867 {
1868 // Aligns with global numbering on our reference element.
1869 edge_sign[line] = 1.0;
1870 }
1871 }
1872
1873 // Define \sigma_{m} = sigma_{e^{m}_{1}} - sigma_{e^{m}_{2}}
1874 // \lambda_{m} = \lambda_{e^{m}_{1}} + \lambda_{e^{m}_{2}}
1875 //
1876 // To help things, in fe_data, we have precomputed (sigma_{i} -
1877 // sigma_{j}) and (lambda_{i} + lambda_{j}) for 0<= i,j <
1878 // lines_per_cell.
1879 //
1880 // There are two types:
1881 // - lower order (1 per edge, m):
1882 // \phi_{m}^{\mathcal{N}_{0}} = 1/2 grad(\sigma_{m})\lambda_{m}
1883 //
1884 // - higher order (degree per edge, m):
1885 // \phi_{i}^{E_{m}} = grad( L_{i+2}(\sigma_{m}) (\lambda_{m}) ).
1886 //
1887 // NOTE: In the ref cell, sigma_{m} is a function of x OR y OR Z
1888 // and lambda_{m} a function of the remaining co-ords.
1889 // for example, if sigma is of x, then lambda is of y AND
1890 // z, and so on. This means that grad(\sigma) requires
1891 // multiplication by d(sigma)/dx_{i} for the i^th comp of
1892 // grad(sigma) and similarly when taking derivatives of
1893 // lambda.
1894 //
1895 // First handle the lowest order edges (dofs 0 to 11)
1896 // 0 and 1 are the edges in the y dir at z=0. (sigma is a fn of y,
1897 // lambda is a fn of x & z). 2 and 3 are the edges in the x dir at
1898 // z=0. (sigma is a fn of x, lambda is a fn of y & z). 4 and 5 are
1899 // the edges in the y dir at z=1. (sigma is a fn of y, lambda is a
1900 // fn of x & z). 6 and 7 are the edges in the x dir at z=1. (sigma
1901 // is a fn of x, lambda is a fn of y & z). 8 and 9 are the edges
1902 // in the z dir at y=0. (sigma is a fn of z, lambda is a fn of x &
1903 // y). 10 and 11 are the edges in the z dir at y=1. (sigma is a fn
1904 // of z, lambda is a fn of x & y).
1905 //
1906 // For more info: see GeometryInfo for picture of the standard
1907 // element.
1908
1909 // Copy over required edge-based data:
1910 std::vector<std::vector<double>> edge_sigma_values(
1911 fe_data.edge_sigma_values);
1912 std::vector<std::vector<double>> edge_lambda_values(
1913 fe_data.edge_lambda_values);
1914 std::vector<std::vector<double>> edge_sigma_grads(
1915 fe_data.edge_sigma_grads);
1916 std::vector<std::vector<std::vector<double>>> edge_lambda_grads(
1917 fe_data.edge_lambda_grads_3d);
1918 std::vector<std::vector<std::vector<double>>>
1919 edge_lambda_gradgrads_3d(fe_data.edge_lambda_gradgrads_3d);
1920
1921 // Adjust the edge_sigma_* for the current cell:
1922 for (unsigned int m = 0; m < lines_per_cell; ++m)
1923 {
1924 std::transform(edge_sigma_values[m].begin(),
1925 edge_sigma_values[m].end(),
1926 edge_sigma_values[m].begin(),
1927 [&](const double edge_sigma_value) {
1928 return edge_sign[m] * edge_sigma_value;
1929 });
1930 std::transform(edge_sigma_grads[m].begin(),
1931 edge_sigma_grads[m].end(),
1932 edge_sigma_grads[m].begin(),
1933 [&](const double edge_sigma_grad) {
1934 return edge_sign[m] * edge_sigma_grad;
1935 });
1936 }
1937
1938 // Now calculate the edge-based shape functions:
1939 // If we want to generate shape gradients then we need second
1940 // derivatives of the 1d polynomials, but only first derivatives
1941 // for the shape values.
1942 const unsigned int poly_length =
1943 (flags & update_hessians) ?
1944 4 :
1945 ((flags & update_gradients) ? 3 : 2);
1946
1947 std::vector<std::vector<double>> poly(
1948 degree, std::vector<double>(poly_length));
1949 for (unsigned int m = 0; m < lines_per_cell; ++m)
1950 {
1951 const unsigned int shift_m(m * this->n_dofs_per_line());
1952 for (unsigned int q = 0; q < n_q_points; ++q)
1953 {
1954 // precompute values of all 1d polynomials required:
1955 // for example poly[i][1] = L'_{i+2}(edge_sigma_values)
1956 if (degree > 0)
1957 {
1958 for (unsigned int i = 0; i < degree; ++i)
1959 {
1960 IntegratedLegendrePolynomials[i + 2].value(
1961 edge_sigma_values[m][q], poly[i]);
1962 }
1963 }
1964 if (flags & update_values)
1965 {
1966 // Lowest order edge shape functions:
1967 for (unsigned int d = 0; d < dim; ++d)
1968 {
1969 fe_data.shape_values[shift_m][q][d] =
1970 0.5 * edge_sigma_grads[m][d] *
1971 edge_lambda_values[m][q];
1972 }
1973 // Higher order edge shape functions
1974 if (degree > 0)
1975 {
1976 for (unsigned int i = 0; i < degree; ++i)
1977 {
1978 const unsigned int dof_index(i + 1 + shift_m);
1979 for (unsigned int d = 0; d < dim; ++d)
1980 {
1981 fe_data.shape_values[dof_index][q][d] =
1982 edge_sigma_grads[m][d] * poly[i][1] *
1983 edge_lambda_values[m][q] +
1984 poly[i][0] * edge_lambda_grads[m][q][d];
1985 }
1986 }
1987 }
1988 }
1989 if (flags & update_gradients)
1990 {
1991 // Lowest order edge shape functions:
1992 for (unsigned int d1 = 0; d1 < dim; ++d1)
1993 {
1994 for (unsigned int d2 = 0; d2 < dim; ++d2)
1995 {
1996 fe_data.shape_grads[shift_m][q][d1][d2] =
1997 0.5 * edge_sigma_grads[m][d1] *
1998 edge_lambda_grads[m][q][d2];
1999 }
2000 }
2001 // Higher order edge shape functions
2002 if (degree > 0)
2003 {
2004 for (unsigned int i = 0; i < degree; ++i)
2005 {
2006 const unsigned int dof_index(i + 1 + shift_m);
2007
2008 for (unsigned int d1 = 0; d1 < dim; ++d1)
2009 {
2010 for (unsigned int d2 = 0; d2 < dim; ++d2)
2011 {
2012 fe_data
2013 .shape_grads[dof_index][q][d1][d2] =
2014 edge_sigma_grads[m][d1] *
2015 edge_sigma_grads[m][d2] *
2016 poly[i][2] *
2017 edge_lambda_values[m][q] +
2018 (edge_sigma_grads[m][d1] *
2019 edge_lambda_grads[m][q][d2] +
2020 edge_sigma_grads[m][d2] *
2021 edge_lambda_grads[m][q][d1]) *
2022 poly[i][1] +
2023 edge_lambda_gradgrads_3d[m][d1]
2024 [d2] *
2025 poly[i][0];
2026 }
2027 }
2028 }
2029 }
2030 }
2031 if (flags & update_hessians)
2032 {
2033 // Lowest order edge shape functions:
2034 for (unsigned int d1 = 0; d1 < dim; ++d1)
2035 {
2036 for (unsigned int d2 = 0; d2 < dim; ++d2)
2037 {
2038 for (unsigned int d3 = 0; d3 < dim; ++d3)
2039 {
2040 fe_data.shape_hessians[shift_m][q][d1][d2]
2041 [d3] =
2042 0.5 * edge_sigma_grads[m][d1] *
2043 edge_lambda_gradgrads_3d[m][d3][d2];
2044 }
2045 }
2046 }
2047
2048 // Higher order edge shape functions
2049 if (degree > 0)
2050 {
2051 for (unsigned int i = 0; i < degree; ++i)
2052 {
2053 const unsigned int dof_index(i + 1 + shift_m);
2054
2055 for (unsigned int d1 = 0; d1 < dim; ++d1)
2056 {
2057 for (unsigned int d2 = 0; d2 < dim; ++d2)
2058 {
2059 for (unsigned int d3 = 0; d3 < dim;
2060 ++d3)
2061 {
2062 fe_data
2063 .shape_hessians[dof_index][q]
2064 [d1][d2][d3] =
2065 edge_sigma_grads[m][d1] *
2066 edge_sigma_grads[m][d2] *
2067 edge_sigma_grads[m][d3] *
2068 poly[i][3] *
2069 edge_lambda_values[m][q] +
2070 poly[i][2] *
2071 (edge_sigma_grads[m][d1] *
2072 edge_sigma_grads[m][d2] *
2073 edge_lambda_grads[m][q]
2074 [d3] +
2075 edge_sigma_grads[m][d3] *
2076 edge_sigma_grads[m][d1] *
2077 edge_lambda_grads[m][q]
2078 [d2] +
2079 edge_sigma_grads[m][d3] *
2080 edge_sigma_grads[m][d2] *
2081 edge_lambda_grads[m][q]
2082 [d1]) +
2083 poly[i][1] *
2084 (edge_sigma_grads[m][d1] *
2085 edge_lambda_gradgrads_3d
2086 [m][d3][d2] +
2087 edge_sigma_grads[m][d2] *
2088 edge_lambda_gradgrads_3d
2089 [m][d3][d1] +
2090 edge_sigma_grads[m][d3] *
2091 edge_lambda_gradgrads_3d
2092 [m][d2][d1]);
2093 }
2094 }
2095 }
2096 }
2097 }
2098 }
2099 }
2100 }
2101 }
2102 break;
2103 }
2104 default:
2105 {
2107 }
2108 }
2109}
2110
2111
2112
2113template <int dim, int spacedim>
2114void
2116 const typename Triangulation<dim, dim>::cell_iterator &cell,
2117 const Quadrature<dim> &quadrature,
2118 const InternalData &fe_data) const
2119{
2120 // This function handles the cell-dependent construction of the FACE-based
2121 // shape functions.
2122 //
2123 // Note that it should only be called in 3d.
2124 Assert(dim == 3, ExcDimensionMismatch(dim, 3));
2125 //
2126 // It will fill in the missing parts of fe_data which were not possible to
2127 // fill in the get_data routine, with respect to face-based shape functions.
2128 //
2129 // It should be called by the fill_fe_*_values routines in order to complete
2130 // the basis set at quadrature points on the current cell for each face.
2131
2132 // Useful constants:
2133 const unsigned int degree(
2134 this->degree -
2135 1); // Note: constructor takes input degree + 1, so need to knock 1 off.
2136
2137 // Do nothing if FE degree is 0.
2138 if (degree > 0)
2139 {
2140 const UpdateFlags flags(fe_data.update_each);
2141
2143 {
2144 const unsigned int n_q_points = quadrature.size();
2145
2146 Assert(!(flags & update_values) ||
2147 fe_data.shape_values.size() == this->n_dofs_per_cell(),
2148 ExcDimensionMismatch(fe_data.shape_values.size(),
2149 this->n_dofs_per_cell()));
2150 Assert(!(flags & update_values) ||
2151 fe_data.shape_values[0].size() == n_q_points,
2152 ExcDimensionMismatch(fe_data.shape_values[0].size(),
2153 n_q_points));
2154
2155 // Useful geometry info:
2156 const unsigned int vertices_per_face(
2159
2160 // DoF info:
2161 const unsigned int n_line_dofs =
2163
2164 // First we find the global face orientations on the current cell.
2165 std::vector<std::vector<unsigned int>> face_orientation(
2166 faces_per_cell, std::vector<unsigned int>(vertices_per_face));
2167
2168 const unsigned int
2169 vertex_opposite_on_face[GeometryInfo<3>::vertices_per_face] = {3,
2170 2,
2171 1,
2172 0};
2173
2174 const unsigned int
2175 vertices_adjacent_on_face[GeometryInfo<3>::vertices_per_face][2] = {
2176 {1, 2}, {0, 3}, {3, 0}, {2, 1}};
2177
2178 for (unsigned int m = 0; m < faces_per_cell; ++m)
2179 {
2180 // Check, if we are on a hanging face.
2181 bool cell_has_coarser_neighbor = false;
2182 if (cell->face(m)->at_boundary() == false)
2183 if (cell->neighbor_is_coarser(m))
2184 cell_has_coarser_neighbor = true;
2185
2186 // Find the local vertex on this face with the highest global
2187 // numbering. This is f^m_0.
2188 unsigned int current_max = 0;
2189
2190 // We start with the hanging face case, where the face
2191 // orientation is determined based on the vertex indices
2192 // of the parent cell.
2193 if (cell_has_coarser_neighbor)
2194 {
2195 unsigned int current_glob = cell->parent()->vertex_index(
2197 for (unsigned int v = 1; v < vertices_per_face; ++v)
2198 {
2199 if (current_glob <
2200 cell->parent()->vertex_index(
2202 {
2203 current_max = v;
2204 current_glob = cell->parent()->vertex_index(
2206 }
2207 }
2208 }
2209 // Otherwise, the face orientation is based on its own
2210 // vertex indices.
2211 else
2212 {
2213 unsigned int current_glob = cell->vertex_index(
2215 for (unsigned int v = 1; v < vertices_per_face; ++v)
2216 {
2217 if (current_glob <
2218 cell->vertex_index(
2220 {
2221 current_max = v;
2222 current_glob = cell->vertex_index(
2224 }
2225 }
2226 }
2227
2228 face_orientation[m][0] =
2230
2231 // f^m_2 is the vertex opposite f^m_0.
2232 face_orientation[m][2] = GeometryInfo<dim>::face_to_cell_vertices(
2233 m, vertex_opposite_on_face[current_max]);
2234
2235 // Finally, f^m_1 is the vertex with the greater global numbering
2236 // of the remaining two local vertices. Then, f^m_3 is the other.
2237 // Again, we need to distinguish between the hanging face and the
2238 // non-hanging face cases. In the case of hanging faces, we
2239 // consider the vertex indices from the parent. Otherwise, we
2240 // consider the vertex indices of the face itself.
2241 if (cell_has_coarser_neighbor)
2242 {
2243 if (cell->parent()->vertex_index(
2245 m, vertices_adjacent_on_face[current_max][0])) >
2246 cell->parent()->vertex_index(
2248 m, vertices_adjacent_on_face[current_max][1])))
2249 {
2250 face_orientation[m][1] =
2252 m, vertices_adjacent_on_face[current_max][0]);
2253 face_orientation[m][3] =
2255 m, vertices_adjacent_on_face[current_max][1]);
2256 }
2257 else
2258 {
2259 face_orientation[m][1] =
2261 m, vertices_adjacent_on_face[current_max][1]);
2262 face_orientation[m][3] =
2264 m, vertices_adjacent_on_face[current_max][0]);
2265 }
2266 }
2267 else
2268 {
2269 if (cell->vertex_index(
2271 m, vertices_adjacent_on_face[current_max][0])) >
2272 cell->vertex_index(
2274 m, vertices_adjacent_on_face[current_max][1])))
2275 {
2276 face_orientation[m][1] =
2278 m, vertices_adjacent_on_face[current_max][0]);
2279 face_orientation[m][3] =
2281 m, vertices_adjacent_on_face[current_max][1]);
2282 }
2283 else
2284 {
2285 face_orientation[m][1] =
2287 m, vertices_adjacent_on_face[current_max][1]);
2288 face_orientation[m][3] =
2290 m, vertices_adjacent_on_face[current_max][0]);
2291 }
2292 }
2293 }
2294 // Now we know the face orientation on the current cell, we can
2295 // generate the parameterisation:
2296 std::vector<std::vector<double>> face_xi_values(
2297 faces_per_cell, std::vector<double>(n_q_points));
2298 std::vector<std::vector<double>> face_xi_grads(
2299 faces_per_cell, std::vector<double>(dim));
2300 std::vector<std::vector<double>> face_eta_values(
2301 faces_per_cell, std::vector<double>(n_q_points));
2302 std::vector<std::vector<double>> face_eta_grads(
2303 faces_per_cell, std::vector<double>(dim));
2304
2305 std::vector<std::vector<double>> face_lambda_values(
2306 faces_per_cell, std::vector<double>(n_q_points));
2307 std::vector<std::vector<double>> face_lambda_grads(
2308 faces_per_cell, std::vector<double>(dim));
2309 for (unsigned int m = 0; m < faces_per_cell; ++m)
2310 {
2311 for (unsigned int q = 0; q < n_q_points; ++q)
2312 {
2313 face_xi_values[m][q] =
2314 fe_data.sigma_imj_values[q][face_orientation[m][0]]
2315 [face_orientation[m][1]];
2316 face_eta_values[m][q] =
2317 fe_data.sigma_imj_values[q][face_orientation[m][0]]
2318 [face_orientation[m][3]];
2319 face_lambda_values[m][q] = fe_data.face_lambda_values[m][q];
2320 }
2321 for (unsigned int d = 0; d < dim; ++d)
2322 {
2323 face_xi_grads[m][d] =
2324 fe_data.sigma_imj_grads[face_orientation[m][0]]
2325 [face_orientation[m][1]][d];
2326 face_eta_grads[m][d] =
2327 fe_data.sigma_imj_grads[face_orientation[m][0]]
2328 [face_orientation[m][3]][d];
2329
2330 face_lambda_grads[m][d] = fe_data.face_lambda_grads[m][d];
2331 }
2332 }
2333 // Now can generate the basis
2334 const unsigned int poly_length =
2335 (flags & update_hessians) ? 4 :
2336 ((flags & update_gradients) ? 3 : 2);
2337
2338
2339 std::vector<std::vector<double>> polyxi(
2340 degree, std::vector<double>(poly_length));
2341 std::vector<std::vector<double>> polyeta(
2342 degree, std::vector<double>(poly_length));
2343
2344 // Loop through quad points:
2345 for (unsigned int m = 0; m < faces_per_cell; ++m)
2346 {
2347 // we assume that all quads have the same number of dofs
2348 const unsigned int shift_m(m * this->n_dofs_per_quad(0));
2349 // Calculate the offsets for each face-based shape function:
2350 //
2351 // Type-1 (gradients)
2352 // \phi^{F_m,1}_{ij} = \nabla( L_{i+2}(\xi_{F_{m}})
2353 // L_{j+2}(\eta_{F_{m}}) \lambda_{F_{m}} )
2354 //
2355 // 0 <= i,j < degree (in a group of degree*degree)
2356 const unsigned int face_type1_offset(n_line_dofs + shift_m);
2357 // Type-2:
2358 //
2359 // \phi^{F_m,2}_{ij} = ( L'_{i+2}(\xi_{F_{m}})
2360 // L_{j+2}(\eta_{F_{m}}) \nabla\xi_{F_{m}}
2361 // - L_{i+2}(\xi_{F_{m}})
2362 // L'_{j+2}(\eta_{F_{m}}) \nabla\eta_{F_{m}}
2363 // ) \lambda_{F_{m}}
2364 //
2365 // 0 <= i,j < degree (in a group of degree*degree)
2366 const unsigned int face_type2_offset(face_type1_offset +
2367 degree * degree);
2368 // Type-3:
2369 //
2370 // \phi^{F_m,3}_{i} = L_{i+2}(\eta_{F_{m}}) \lambda_{F_{m}}
2371 // \nabla\xi_{F_{m}}
2372 // \phi^{F_m,3}_{i+p} = L_{i+2}(\xi_{F_{m}})
2373 // \lambda_{F_{m}} \nabla\eta_{F_{m}}
2374 //
2375 // 0 <= i < degree.
2376 //
2377 // here we order so that all of subtype 1 comes first, then
2378 // subtype 2.
2379 const unsigned int face_type3_offset1(face_type2_offset +
2380 degree * degree);
2381 const unsigned int face_type3_offset2(face_type3_offset1 +
2382 degree);
2383
2384 // Loop over all faces:
2385 for (unsigned int q = 0; q < n_q_points; ++q)
2386 {
2387 // pre-compute values & required derivatives at this quad
2388 // point: polyxi = L_{i+2}(\xi_{F_{m}}), polyeta =
2389 // L_{j+2}(\eta_{F_{m}}),
2390 //
2391 // each polypoint[k][d], contains the dth derivative of
2392 // L_{k+2} at the point \xi or \eta. Note that this doesn't
2393 // include the derivative of xi/eta via the chain rule.
2394 for (unsigned int i = 0; i < degree; ++i)
2395 {
2396 // compute all required 1d polynomials:
2397 IntegratedLegendrePolynomials[i + 2].value(
2398 face_xi_values[m][q], polyxi[i]);
2399 IntegratedLegendrePolynomials[i + 2].value(
2400 face_eta_values[m][q], polyeta[i]);
2401 }
2402 // Now use these to compute the shape functions:
2403 if (flags & update_values)
2404 {
2405 for (unsigned int j = 0; j < degree; ++j)
2406 {
2407 const unsigned int shift_j(j * degree);
2408 for (unsigned int i = 0; i < degree; ++i)
2409 {
2410 const unsigned int shift_ij(shift_j + i);
2411 // Type 1:
2412 const unsigned int dof_index1(face_type1_offset +
2413 shift_ij);
2414 for (unsigned int d = 0; d < dim; ++d)
2415 {
2416 fe_data.shape_values[dof_index1][q][d] =
2417 (face_xi_grads[m][d] * polyxi[i][1] *
2418 polyeta[j][0] +
2419 face_eta_grads[m][d] * polyxi[i][0] *
2420 polyeta[j][1]) *
2421 face_lambda_values[m][q] +
2422 face_lambda_grads[m][d] * polyxi[i][0] *
2423 polyeta[j][0];
2424 }
2425 // Type 2:
2426 const unsigned int dof_index2(face_type2_offset +
2427 shift_ij);
2428 for (unsigned int d = 0; d < dim; ++d)
2429 {
2430 fe_data.shape_values[dof_index2][q][d] =
2431 (face_xi_grads[m][d] * polyxi[i][1] *
2432 polyeta[j][0] -
2433 face_eta_grads[m][d] * polyxi[i][0] *
2434 polyeta[j][1]) *
2435 face_lambda_values[m][q];
2436 }
2437 }
2438 // Type 3:
2439 const unsigned int dof_index3_1(face_type3_offset1 +
2440 j);
2441 const unsigned int dof_index3_2(face_type3_offset2 +
2442 j);
2443 for (unsigned int d = 0; d < dim; ++d)
2444 {
2445 fe_data.shape_values[dof_index3_1][q][d] =
2446 face_xi_grads[m][d] * polyeta[j][0] *
2447 face_lambda_values[m][q];
2448
2449 fe_data.shape_values[dof_index3_2][q][d] =
2450 face_eta_grads[m][d] * polyxi[j][0] *
2451 face_lambda_values[m][q];
2452 }
2453 }
2454 }
2455 if (flags & update_gradients)
2456 {
2457 for (unsigned int j = 0; j < degree; ++j)
2458 {
2459 const unsigned int shift_j(j * degree);
2460 for (unsigned int i = 0; i < degree; ++i)
2461 {
2462 const unsigned int shift_ij(shift_j + i);
2463 // Type 1:
2464 const unsigned int dof_index1(face_type1_offset +
2465 shift_ij);
2466 for (unsigned int d1 = 0; d1 < dim; ++d1)
2467 {
2468 for (unsigned int d2 = 0; d2 < dim; ++d2)
2469 {
2470 fe_data
2471 .shape_grads[dof_index1][q][d1][d2] =
2472 (face_xi_grads[m][d1] *
2473 face_xi_grads[m][d2] * polyxi[i][2] *
2474 polyeta[j][0] +
2475 (face_xi_grads[m][d1] *
2476 face_eta_grads[m][d2] +
2477 face_xi_grads[m][d2] *
2478 face_eta_grads[m][d1]) *
2479 polyxi[i][1] * polyeta[j][1] +
2480 face_eta_grads[m][d1] *
2481 face_eta_grads[m][d2] *
2482 polyxi[i][0] * polyeta[j][2]) *
2483 face_lambda_values[m][q] +
2484 (face_xi_grads[m][d2] * polyxi[i][1] *
2485 polyeta[j][0] +
2486 face_eta_grads[m][d2] * polyxi[i][0] *
2487 polyeta[j][1]) *
2488 face_lambda_grads[m][d1] +
2489 (face_xi_grads[m][d1] * polyxi[i][1] *
2490 polyeta[j][0] +
2491 face_eta_grads[m][d1] * polyxi[i][0] *
2492 polyeta[j][1]) *
2493 face_lambda_grads[m][d2];
2494 }
2495 }
2496 // Type 2:
2497 const unsigned int dof_index2(face_type2_offset +
2498 shift_ij);
2499 for (unsigned int d1 = 0; d1 < dim; ++d1)
2500 {
2501 for (unsigned int d2 = 0; d2 < dim; ++d2)
2502 {
2503 fe_data
2504 .shape_grads[dof_index2][q][d1][d2] =
2505 (face_xi_grads[m][d1] *
2506 face_xi_grads[m][d2] * polyxi[i][2] *
2507 polyeta[j][0] +
2508 (face_xi_grads[m][d1] *
2509 face_eta_grads[m][d2] -
2510 face_xi_grads[m][d2] *
2511 face_eta_grads[m][d1]) *
2512 polyxi[i][1] * polyeta[j][1] -
2513 face_eta_grads[m][d1] *
2514 face_eta_grads[m][d2] *
2515 polyxi[i][0] * polyeta[j][2]) *
2516 face_lambda_values[m][q] +
2517 (face_xi_grads[m][d1] * polyxi[i][1] *
2518 polyeta[j][0] -
2519 face_eta_grads[m][d1] * polyxi[i][0] *
2520 polyeta[j][1]) *
2521 face_lambda_grads[m][d2];
2522 }
2523 }
2524 }
2525 // Type 3:
2526 const unsigned int dof_index3_1(face_type3_offset1 +
2527 j);
2528 const unsigned int dof_index3_2(face_type3_offset2 +
2529 j);
2530 for (unsigned int d1 = 0; d1 < dim; ++d1)
2531 {
2532 for (unsigned int d2 = 0; d2 < dim; ++d2)
2533 {
2534 fe_data.shape_grads[dof_index3_1][q][d1][d2] =
2535 face_xi_grads[m][d1] *
2536 (face_eta_grads[m][d2] * polyeta[j][1] *
2537 face_lambda_values[m][q] +
2538 face_lambda_grads[m][d2] * polyeta[j][0]);
2539
2540 fe_data.shape_grads[dof_index3_2][q][d1][d2] =
2541 face_eta_grads[m][d1] *
2542 (face_xi_grads[m][d2] * polyxi[j][1] *
2543 face_lambda_values[m][q] +
2544 face_lambda_grads[m][d2] * polyxi[j][0]);
2545 }
2546 }
2547 }
2548 }
2549 if (flags & update_hessians)
2550 {
2551 for (unsigned int j = 0; j < degree; ++j)
2552 {
2553 const unsigned int shift_j(j * degree);
2554 for (unsigned int i = 0; i < degree; ++i)
2555 {
2556 const unsigned int shift_ij(shift_j + i);
2557
2558 // Type 1:
2559 const unsigned int dof_index1(face_type1_offset +
2560 shift_ij);
2561 for (unsigned int d1 = 0; d1 < dim; ++d1)
2562 {
2563 for (unsigned int d2 = 0; d2 < dim; ++d2)
2564 {
2565 for (unsigned int d3 = 0; d3 < dim; ++d3)
2566 {
2567 fe_data.shape_hessians[dof_index1][q]
2568 [d1][d2][d3] =
2569 polyxi[i][1] *
2570 face_xi_grads[m][d3] *
2571 (face_eta_grads[m][d1] *
2572 (polyeta[j][2] *
2573 face_eta_grads[m][d2] *
2574 face_lambda_values[m][q] +
2575 polyeta[j][1] *
2576 face_lambda_grads[m][d2]) +
2577 polyeta[j][1] *
2578 face_eta_grads[m][d2] *
2579 face_lambda_grads[m][d1]) +
2580 polyxi[i][0] *
2581 (polyeta[j][3] *
2582 face_eta_grads[m][d1] *
2583 face_eta_grads[m][d2] *
2584 face_eta_grads[m][d3] *
2585 face_lambda_values[m][q] +
2586 polyeta[j][2] *
2587 (face_eta_grads[m][d1] *
2588 face_eta_grads[m][d2] *
2589 face_lambda_grads[m][d3] +
2590 face_eta_grads[m][d3] *
2591 (face_eta_grads[m][d1] *
2592 face_lambda_grads[m]
2593 [d2] +
2594 face_eta_grads[m][d2] *
2595 face_lambda_grads
2596 [m][d1]))) +
2597 (polyxi[i][1] * polyeta[j][1] *
2598 face_eta_grads[m][d3] +
2599 polyxi[i][2] * polyeta[j][0] *
2600 face_xi_grads[m][d3]) *
2601 (face_xi_grads[m][d1] *
2602 face_lambda_grads[m][d2] +
2603 face_xi_grads[m][d2] *
2604 face_lambda_grads[m][d1]) +
2605 face_lambda_grads[m][d3] *
2606 (polyxi[i][2] * polyeta[j][0] *
2607 face_xi_grads[m][d1] *
2608 face_xi_grads[m][d2] +
2609 polyxi[i][1] * polyeta[j][1] *
2610 (face_xi_grads[m][d1] *
2611 face_eta_grads[m][d2] +
2612 face_xi_grads[m][d2] *
2613 face_eta_grads[m][d1])) +
2614 face_lambda_values[m][q] *
2615 (polyxi[i][3] * polyeta[j][0] *
2616 face_xi_grads[m][d1] *
2617 face_xi_grads[m][d2] *
2618 face_xi_grads[m][d3] +
2619 polyxi[i][1] * polyeta[j][2] *
2620 face_eta_grads[m][d3] *
2621 (face_xi_grads[m][d1] *
2622 face_eta_grads[m][d2] +
2623 face_xi_grads[m][d2] *
2624 face_eta_grads[m][d1]) +
2625 polyxi[i][2] * polyeta[j][1] *
2626 (face_xi_grads[m][d3] *
2627 face_xi_grads[m][d2] *
2628 face_eta_grads[m][d1] +
2629 face_xi_grads[m][d1] *
2630 (face_xi_grads[m][d2] *
2631 face_eta_grads[m][d3] +
2632 face_xi_grads[m][d3] *
2633 face_eta_grads[m][d2])));
2634 }
2635 }
2636 }
2637
2638 // Type 2:
2639 const unsigned int dof_index2(face_type2_offset +
2640 shift_ij);
2641 for (unsigned int d1 = 0; d1 < dim; ++d1)
2642 {
2643 for (unsigned int d2 = 0; d2 < dim; ++d2)
2644 {
2645 for (unsigned int d3 = 0; d3 < dim; ++d3)
2646 {
2647 fe_data.shape_hessians[dof_index2][q]
2648 [d1][d2][d3] =
2649 face_xi_grads[m][d1] *
2650 (polyxi[i][1] * polyeta[j][1] *
2651 (face_eta_grads[m][d2] *
2652 face_lambda_grads[m][d3] +
2653 face_eta_grads[m][d3] *
2654 face_lambda_grads[m][d2]) +
2655 polyxi[i][2] * polyeta[j][0] *
2656 (face_xi_grads[m][d2] *
2657 face_lambda_grads[m][d3] +
2658 face_xi_grads[m][d3] *
2659 face_lambda_grads[m][d2]) +
2660 face_lambda_values[m][q] *
2661 (face_eta_grads[m][d2] *
2662 (polyxi[i][1] *
2663 polyeta[j][2] *
2664 face_eta_grads[m][d3] +
2665 polyxi[i][2] *
2666 polyeta[j][1] *
2667 face_xi_grads[m][d3]) +
2668 face_xi_grads[m][d2] *
2669 (polyxi[i][2] *
2670 polyeta[j][1] *
2671 face_eta_grads[m][d3] +
2672 polyxi[i][3] *
2673 polyeta[j][0] *
2674 face_xi_grads[m][d3]))) -
2675 polyxi[i][0] *
2676 face_eta_grads[m][d1] *
2677 (face_eta_grads[m][d2] *
2678 (polyeta[j][3] *
2679 face_eta_grads[m][d3] *
2680 face_lambda_values[m][q] +
2681 polyeta[j][2] *
2682 face_lambda_grads[m][d3]) +
2683 polyeta[j][2] *
2684 face_eta_grads[m][d3] *
2685 face_lambda_grads[m][d2]) -
2686 face_eta_grads[m][d1] *
2687 (polyxi[i][1] *
2688 face_xi_grads[m][d3] *
2689 (polyeta[j][2] *
2690 face_eta_grads[m][d2] *
2691 face_lambda_values[m][q] +
2692 polyeta[j][1] *
2693 face_lambda_grads[m][d2]) +
2694 face_xi_grads[m][d2] *
2695 (polyxi[i][1] *
2696 (polyeta[j][2] *
2697 face_eta_grads[m][d3] *
2698 face_lambda_values[m]
2699 [q] +
2700 polyeta[j][1] *
2701 face_lambda_grads[m]
2702 [d3]) +
2703 polyxi[i][2] * polyeta[j][1] *
2704 face_xi_grads[m][d3] *
2705 face_lambda_values[m][q]));
2706 }
2707 }
2708 }
2709 }
2710 // Type 3:
2711 const unsigned int dof_index3_1(face_type3_offset1 +
2712 j);
2713 const unsigned int dof_index3_2(face_type3_offset2 +
2714 j);
2715 for (unsigned int d1 = 0; d1 < dim; ++d1)
2716 {
2717 for (unsigned int d2 = 0; d2 < dim; ++d2)
2718 {
2719 for (unsigned int d3 = 0; d3 < dim; ++d3)
2720 {
2721 fe_data.shape_hessians[dof_index3_1][q]
2722 [d1][d2][d3] =
2723 face_xi_grads[m][d1] *
2724 (face_eta_grads[m][d2] *
2725 (polyeta[j][2] *
2726 face_eta_grads[m][d3] *
2727 face_lambda_values[m][q] +
2728 polyeta[j][1] *
2729 face_lambda_grads[m][d3]) +
2730 face_lambda_grads[m][d2] *
2731 polyeta[j][1] *
2732 face_eta_grads[m][d3]);
2733
2734 fe_data.shape_hessians[dof_index3_2][q]
2735 [d1][d2][d3] =
2736 face_eta_grads[m][d1] *
2737 (face_xi_grads[m][d2] *
2738 (polyxi[j][2] *
2739 face_xi_grads[m][d3] *
2740 face_lambda_values[m][q] +
2741 polyxi[j][1] *
2742 face_lambda_grads[m][d3]) +
2743 face_lambda_grads[m][d2] *
2744 polyxi[j][1] * face_xi_grads[m][d3]);
2745 }
2746 }
2747 }
2748 }
2749 }
2750 }
2751 }
2752 }
2753 }
2754}
2755
2756
2757
2758template <int dim, int spacedim>
2759void
2761 const typename Triangulation<dim, dim>::cell_iterator &cell,
2762 const CellSimilarity::Similarity /*cell_similarity*/,
2763 const Quadrature<dim> &quadrature,
2765 const typename Mapping<dim, dim>::InternalDataBase &mapping_internal,
2767 &mapping_data,
2768 const typename FiniteElement<dim, dim>::InternalDataBase &fe_internal,
2770 &data) const
2771{
2772 // Convert to the correct internal data class for this FE class.
2773 Assert(dynamic_cast<const InternalData *>(&fe_internal) != nullptr,
2775 const InternalData &fe_data = static_cast<const InternalData &>(fe_internal);
2776
2777 // Now update the edge-based DoFs, which depend on the cell.
2778 // This will fill in the missing items in the InternalData
2779 // (fe_internal/fe_data) which was not filled in by get_data.
2780 fill_edge_values(cell, quadrature, fe_data);
2781 if (dim == 3 && this->degree > 1)
2782 {
2783 fill_face_values(cell, quadrature, fe_data);
2784 }
2785
2786 const UpdateFlags flags(fe_data.update_each);
2787 const unsigned int n_q_points = quadrature.size();
2788
2789 Assert(!(flags & update_values) ||
2790 fe_data.shape_values.size() == this->n_dofs_per_cell(),
2791 ExcDimensionMismatch(fe_data.shape_values.size(),
2792 this->n_dofs_per_cell()));
2793 Assert(!(flags & update_values) ||
2794 fe_data.shape_values[0].size() == n_q_points,
2795 ExcDimensionMismatch(fe_data.shape_values[0].size(), n_q_points));
2796
2797 if (flags & update_values)
2798 {
2799 // Now have all shape_values stored on the reference cell.
2800 // Must now transform to the physical cell.
2801 std::vector<Tensor<1, dim>> transformed_shape_values(n_q_points);
2802 for (unsigned int dof = 0; dof < this->n_dofs_per_cell(); ++dof)
2803 {
2804 const unsigned int first =
2805 data.shape_function_to_row_table[dof * this->n_components() +
2806 this->get_nonzero_components(dof)
2807 .first_selected_component()];
2808
2809 mapping.transform(make_array_view(fe_data.shape_values[dof]),
2811 mapping_internal,
2812 make_array_view(transformed_shape_values));
2813 for (unsigned int q = 0; q < n_q_points; ++q)
2814 {
2815 for (unsigned int d = 0; d < dim; ++d)
2816 {
2817 data.shape_values(first + d, q) =
2818 transformed_shape_values[q][d];
2819 }
2820 }
2821 }
2822 }
2823
2824 if (flags & update_gradients)
2825 {
2826 // Now have all shape_grads stored on the reference cell.
2827 // Must now transform to the physical cell.
2828 std::vector<Tensor<2, dim>> input(n_q_points);
2829 std::vector<Tensor<2, dim>> transformed_shape_grads(n_q_points);
2830 for (unsigned int dof = 0; dof < this->n_dofs_per_cell(); ++dof)
2831 {
2832 for (unsigned int q = 0; q < n_q_points; ++q)
2833 {
2834 input[q] = fe_data.shape_grads[dof][q];
2835 }
2836 mapping.transform(make_array_view(input),
2838 mapping_internal,
2839 make_array_view(transformed_shape_grads));
2840
2841 const unsigned int first =
2842 data.shape_function_to_row_table[dof * this->n_components() +
2843 this->get_nonzero_components(dof)
2844 .first_selected_component()];
2845
2846 for (unsigned int q = 0; q < n_q_points; ++q)
2847 {
2848 for (unsigned int d1 = 0; d1 < dim; ++d1)
2849 {
2850 for (unsigned int d2 = 0; d2 < dim; ++d2)
2851 {
2852 transformed_shape_grads[q][d1] -=
2853 data.shape_values(first + d2, q) *
2854 mapping_data.jacobian_pushed_forward_grads[q][d2][d1];
2855 }
2856 }
2857 }
2858
2859 for (unsigned int q = 0; q < n_q_points; ++q)
2860 {
2861 for (unsigned int d = 0; d < dim; ++d)
2862 {
2863 data.shape_gradients[first + d][q] =
2864 transformed_shape_grads[q][d];
2865 }
2866 }
2867 }
2868 }
2869
2870 if (flags & update_hessians)
2871 {
2872 // Now have all shape_grads stored on the reference cell.
2873 // Must now transform to the physical cell.
2874 std::vector<Tensor<3, dim>> input(n_q_points);
2875 std::vector<Tensor<3, dim>> transformed_shape_hessians(n_q_points);
2876 for (unsigned int dof = 0; dof < this->n_dofs_per_cell(); ++dof)
2877 {
2878 for (unsigned int q = 0; q < n_q_points; ++q)
2879 {
2880 input[q] = fe_data.shape_hessians[dof][q];
2881 }
2882 mapping.transform(make_array_view(input),
2884 mapping_internal,
2885 make_array_view(transformed_shape_hessians));
2886
2887 const unsigned int first =
2888 data.shape_function_to_row_table[dof * this->n_components() +
2889 this->get_nonzero_components(dof)
2890 .first_selected_component()];
2891
2892 for (unsigned int q = 0; q < n_q_points; ++q)
2893 {
2894 for (unsigned int d1 = 0; d1 < dim; ++d1)
2895 {
2896 for (unsigned int d2 = 0; d2 < dim; ++d2)
2897 {
2898 for (unsigned int d3 = 0; d3 < dim; ++d3)
2899 {
2900 for (unsigned int d4 = 0; d4 < dim; ++d4)
2901 {
2902 transformed_shape_hessians[q][d1][d3][d4] -=
2903 (data.shape_values(first + d2, q) *
2904 mapping_data
2905 .jacobian_pushed_forward_2nd_derivatives
2906 [q][d2][d1][d3][d4]) +
2907 (data.shape_gradients[first + d1][q][d2] *
2908 mapping_data
2910 [d4]) +
2911 (data.shape_gradients[first + d2][q][d3] *
2912 mapping_data
2914 [d4]) +
2915 (data.shape_gradients[first + d2][q][d4] *
2916 mapping_data
2918 [d1]);
2919 }
2920 }
2921 }
2922 }
2923 }
2924
2925 for (unsigned int q = 0; q < n_q_points; ++q)
2926 {
2927 for (unsigned int d = 0; d < dim; ++d)
2928 {
2929 data.shape_hessians[first + d][q] =
2930 transformed_shape_hessians[q][d];
2931 }
2932 }
2933 }
2934 }
2935}
2936
2937
2938
2939template <int dim, int spacedim>
2940void
2942 const typename Triangulation<dim, dim>::cell_iterator &cell,
2943 const unsigned int face_no,
2944 const hp::QCollection<dim - 1> &quadrature,
2946 const typename Mapping<dim, dim>::InternalDataBase &mapping_internal,
2948 &mapping_data,
2949 const typename FiniteElement<dim, dim>::InternalDataBase &fe_internal,
2951 &data) const
2952{
2953 AssertDimension(quadrature.size(), 1);
2954
2955 // Note for future improvement:
2956 // We don't have the full quadrature - should use QProjector to create the 2d
2957 // quadrature.
2958 //
2959 // For now I am effectively generating all of the shape function vals/grads,
2960 // etc. On all quad points on all faces and then only using them for one face.
2961 // This is obviously inefficient. I should cache the cell number and cache
2962 // all of the shape_values/gradients etc and then reuse them for each face.
2963
2964 // convert data object to internal
2965 // data for this class. fails with
2966 // an exception if that is not
2967 // possible
2968 Assert(dynamic_cast<const InternalData *>(&fe_internal) != nullptr,
2970 const InternalData &fe_data = static_cast<const InternalData &>(fe_internal);
2971
2972 // Now update the edge-based DoFs, which depend on the cell.
2973 // This will fill in the missing items in the InternalData
2974 // (fe_internal/fe_data) which was not filled in by get_data.
2975 fill_edge_values(cell,
2977 quadrature[0]),
2978 fe_data);
2979 if (dim == 3 && this->degree > 1)
2980 {
2981 fill_face_values(cell,
2983 this->reference_cell(), quadrature[0]),
2984 fe_data);
2985 }
2986
2987 const UpdateFlags flags(fe_data.update_each);
2988 const unsigned int n_q_points = quadrature[0].size();
2989 const auto offset =
2991 face_no,
2993 face_no),
2994 n_q_points);
2995
2996 if (flags & update_values)
2997 {
2998 // Now have all shape_values stored on the reference cell.
2999 // Must now transform to the physical cell.
3000 std::vector<Tensor<1, dim>> transformed_shape_values(n_q_points);
3001 for (unsigned int dof = 0; dof < this->n_dofs_per_cell(); ++dof)
3002 {
3003 mapping.transform(make_array_view(fe_data.shape_values[dof],
3004 offset,
3005 n_q_points),
3007 mapping_internal,
3008 make_array_view(transformed_shape_values));
3009
3010 const unsigned int first =
3011 data.shape_function_to_row_table[dof * this->n_components() +
3012 this->get_nonzero_components(dof)
3013 .first_selected_component()];
3014
3015 for (unsigned int q = 0; q < n_q_points; ++q)
3016 {
3017 for (unsigned int d = 0; d < dim; ++d)
3018 {
3019 data.shape_values(first + d, q) =
3020 transformed_shape_values[q][d];
3021 }
3022 }
3023 }
3024 }
3025 if (flags & update_gradients)
3026 {
3027 // Now have all shape_grads stored on the reference cell.
3028 // Must now transform to the physical cell.
3029 std::vector<Tensor<2, dim>> input(n_q_points);
3030 std::vector<Tensor<2, dim>> transformed_shape_grads(n_q_points);
3031 for (unsigned int dof = 0; dof < this->n_dofs_per_cell(); ++dof)
3032 {
3033 for (unsigned int q = 0; q < n_q_points; ++q)
3034 {
3035 input[q] = fe_data.shape_grads[dof][offset + q];
3036 }
3037 mapping.transform(input,
3039 mapping_internal,
3040 make_array_view(transformed_shape_grads));
3041
3042 const unsigned int first =
3043 data.shape_function_to_row_table[dof * this->n_components() +
3044 this->get_nonzero_components(dof)
3045 .first_selected_component()];
3046
3047 for (unsigned int q = 0; q < n_q_points; ++q)
3048 {
3049 for (unsigned int d1 = 0; d1 < dim; ++d1)
3050 {
3051 for (unsigned int d2 = 0; d2 < dim; ++d2)
3052 {
3053 transformed_shape_grads[q][d1] -=
3054 data.shape_values(first + d2, q) *
3055 mapping_data.jacobian_pushed_forward_grads[q][d2][d1];
3056 }
3057 }
3058 }
3059
3060 for (unsigned int q = 0; q < n_q_points; ++q)
3061 {
3062 for (unsigned int d = 0; d < dim; ++d)
3063 {
3064 data.shape_gradients[first + d][q] =
3065 transformed_shape_grads[q][d];
3066 }
3067 }
3068 }
3069 }
3070 if (flags & update_hessians)
3071 {
3072 // Now have all shape_grads stored on the reference cell.
3073 // Must now transform to the physical cell.
3074 std::vector<Tensor<3, dim>> input(n_q_points);
3075 std::vector<Tensor<3, dim>> transformed_shape_hessians(n_q_points);
3076 for (unsigned int dof = 0; dof < this->n_dofs_per_cell(); ++dof)
3077 {
3078 for (unsigned int q = 0; q < n_q_points; ++q)
3079 input[q] = fe_data.shape_hessians[dof][offset + q];
3080
3081 mapping.transform(input,
3083 mapping_internal,
3084 make_array_view(transformed_shape_hessians));
3085
3086 const unsigned int first =
3087 data.shape_function_to_row_table[dof * this->n_components() +
3088 this->get_nonzero_components(dof)
3089 .first_selected_component()];
3090
3091 for (unsigned int q = 0; q < n_q_points; ++q)
3092 {
3093 for (unsigned int d1 = 0; d1 < dim; ++d1)
3094 {
3095 for (unsigned int d2 = 0; d2 < dim; ++d2)
3096 {
3097 for (unsigned int d3 = 0; d3 < dim; ++d3)
3098 {
3099 for (unsigned int d4 = 0; d4 < dim; ++d4)
3100 {
3101 transformed_shape_hessians[q][d1][d3][d4] -=
3102 (data.shape_values(first + d2, q) *
3103 mapping_data
3104 .jacobian_pushed_forward_2nd_derivatives
3105 [q][d2][d1][d3][d4]) +
3106 (data.shape_gradients[first + d1][q][d2] *
3107 mapping_data
3109 [d4]) +
3110 (data.shape_gradients[first + d2][q][d3] *
3111 mapping_data
3113 [d4]) +
3114 (data.shape_gradients[first + d2][q][d4] *
3115 mapping_data
3117 [d1]);
3118 }
3119 }
3120 }
3121 }
3122 }
3123
3124 for (unsigned int q = 0; q < n_q_points; ++q)
3125 {
3126 for (unsigned int d = 0; d < dim; ++d)
3127 {
3128 data.shape_hessians[first + d][q] =
3129 transformed_shape_hessians[q][d];
3130 }
3131 }
3132 }
3133 }
3134}
3135
3136
3137
3138template <int dim, int spacedim>
3139void
3141 const typename Triangulation<dim, dim>::cell_iterator & /*cell*/,
3142 const unsigned int /*face_no*/,
3143 const unsigned int /*sub_no*/,
3144 const Quadrature<dim - 1> & /*quadrature*/,
3145 const Mapping<dim, dim> & /*mapping*/,
3146 const typename Mapping<dim, dim>::InternalDataBase & /*mapping_internal*/,
3148 & /*mapping_data*/,
3149 const typename FiniteElement<dim, dim>::InternalDataBase & /*fe_internal*/,
3151 & /*data*/) const
3152{
3154}
3155
3156
3157
3158template <int dim, int spacedim>
3181
3182
3183
3184template <int dim, int spacedim>
3185std::string
3187{
3188 // note that the FETools::get_fe_by_name function depends on the particular
3189 // format of the string this function returns, so they have to be kept in sync
3190 std::ostringstream namebuf;
3191 namebuf << "FE_NedelecSZ<" << Utilities::dim_string(dim, spacedim) << ">("
3192 << this->degree - 1 << ")";
3193
3194 return namebuf.str();
3195}
3196
3197
3198
3199template <int dim, int spacedim>
3200std::unique_ptr<FiniteElement<dim, dim>>
3202{
3203 return std::make_unique<FE_NedelecSZ<dim, spacedim>>(*this);
3204}
3205
3206
3207
3208template <int dim, int spacedim>
3209std::vector<unsigned int>
3211{
3212 // internal function to return a vector of "dofs per object"
3213 // where the objects inside the vector refer to:
3214 // 0 = vertex
3215 // 1 = edge
3216 // 2 = face (which is a cell in 2d)
3217 // 3 = cell
3218 std::vector<unsigned int> dpo;
3219
3220 dpo.push_back(0);
3221 dpo.push_back(degree + 1);
3222 if (dim > 1)
3223 dpo.push_back(2 * degree * (degree + 1));
3224 if (dim > 2)
3225 dpo.push_back(3 * degree * degree * (degree + 1));
3226
3227 return dpo;
3228}
3229
3230
3231
3232template <int dim, int spacedim>
3233unsigned int
3235{
3236 // Internal function to compute the number of DoFs
3237 // for a given dimension & polynomial order.
3238 switch (dim)
3239 {
3240 case 2:
3241 return 2 * (degree + 1) * (degree + 2);
3242
3243 case 3:
3244 return 3 * (degree + 1) * (degree + 2) * (degree + 2);
3245
3246 default:
3247 {
3249 return 0;
3250 }
3251 }
3252}
3253
3254
3255
3256template <int dim, int spacedim>
3257void
3259{
3260 // fill the 1d polynomials vector:
3263}
3264
3265
3266
3267template <int dim, int spacedim>
3268const FullMatrix<double> &
3270 const unsigned int child,
3271 const RefinementCase<dim> &refinement_case) const
3272{
3273 AssertIndexRange(refinement_case,
3275 Assert(refinement_case != RefinementCase<dim>::no_refinement,
3276 ExcMessage(
3277 "Prolongation matrices are only available for refined cells!"));
3278 AssertIndexRange(child, this->reference_cell().n_children(refinement_case));
3279
3280 // initialization upon first request
3281 if (this->prolongation[refinement_case - 1][child].n() == 0)
3282 {
3283 std::scoped_lock lock(prolongation_matrix_mutex);
3284
3285 // if matrix got updated while waiting for the lock
3286 if (this->prolongation[refinement_case - 1][child].n() ==
3287 this->n_dofs_per_cell())
3288 return this->prolongation[refinement_case - 1][child];
3289
3290 // now do the work. need to get a non-const version of data in order to
3291 // be able to modify them inside a const function
3292 FE_NedelecSZ<dim> &this_nonconst = const_cast<FE_NedelecSZ<dim> &>(*this);
3293
3294 // Reinit the vectors of
3295 // restriction and prolongation
3296 // matrices to the right sizes.
3297 // Restriction only for isotropic
3298 // refinement
3300 // Fill prolongation matrices with embedding operators
3302 this_nonconst,
3303 this_nonconst.prolongation,
3304 true,
3305 1.e-15 * std::exp(std::pow(this->degree, 1.075)));
3306 }
3307
3308 // we use refinement_case-1 here. the -1 takes care of the origin of the
3309 // vector, as for RefinementCase<dim>::no_refinement (=0) there is no data
3310 // available and so the vector indices are shifted
3311 return this->prolongation[refinement_case - 1][child];
3312}
3313
3314// explicit instantiations
3315#include "fe/fe_nedelec_sz.inst"
3316
*  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)
TriaIterator< CellAccessor< dim, spacedim > > parent() const
bool is_active() const
bool neighbor_is_coarser(const unsigned int face_no) const
TriaIterator< TriaAccessor< dim - 1, dim, spacedim > > face(const unsigned int i) const
std::set< TriaActiveIterator< CellAccessor< dim, spacedim > > > get_cells_adjacent_to_line(const unsigned int i) const
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
Threads::Mutex prolongation_matrix_mutex
std::vector< Polynomials::Polynomial< double > > IntegratedLegendrePolynomials
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_cell() const
unsigned int n_dofs_per_line() const
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
unsigned int n_dofs_per_quad(unsigned int face_no=0) const
FiniteElementData(const std::vector< unsigned int > &dofs_per_object, const unsigned int n_components, const unsigned int degree, const Conformity conformity=unknown, const BlockIndices &block_indices=BlockIndices())
Definition fe_data.cc:112
ReferenceCell< dim > reference_cell() const
const ComponentMask & get_nonzero_components(const unsigned int i) const
void reinit_restriction_and_prolongation_matrices(const bool isotropic_restriction_only=false, const bool isotropic_prolongation_only=false)
FiniteElement(const FiniteElementData< dim > &fe_data, const std::vector< bool > &restriction_is_additive_flags, const std::vector< ComponentMask > &nonzero_components)
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
Definition point.h:111
static DataSetDescriptor face(const ReferenceCell< dim > &reference_cell, const unsigned int face_no, const bool face_orientation, const bool face_flip, const bool face_rotation, const unsigned int n_quadrature_points)
static Quadrature< dim > project_to_all_faces(const ReferenceCell< dim > &reference_cell, const hp::QCollection< dim - 1 > &quadrature)
const std::vector< Point< dim > > & get_points() const
unsigned int size() const
std_cxx20::ranges::iota_view< unsigned int, unsigned int > line_indices() const
std_cxx20::ranges::iota_view< unsigned int, unsigned int > face_indices() const
unsigned int vertex_index(const unsigned int i) const
unsigned int size() const
Definition collection.h:314
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()
constexpr unsigned int GeometryInfo< dim >::faces_per_cell
constexpr unsigned int GeometryInfo< dim >::lines_per_cell
constexpr unsigned int GeometryInfo< dim >::vertices_per_face
constexpr unsigned int GeometryInfo< dim >::vertices_per_cell
#define Assert(cond, exc)
static ::ExceptionBase & ExcImpossibleInDim(int arg1)
#define AssertDimension(dim1, dim2)
#define AssertIndexRange(index, range)
static ::ExceptionBase & ExcFENotPrimitive()
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
static ::ExceptionBase & ExcMessage(std::string arg1)
TriaIterator< CellAccessor< dim, spacedim > > cell_iterator
Definition tria.h:1624
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
types::geometric_orientation combined_face_orientation(const unsigned int face) const
MappingQ< dim, spacedim > StaticMappingQ1< dim, spacedim >::mapping
Definition mapping_q1.h:101
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)
void compute_face_embedding_matrices(const FiniteElement< dim, spacedim > &fe, const ArrayView< FullMatrix< number > > &matrices, const unsigned int face_coarse, const unsigned int face_fine, const double threshold=1.e-12)
std::string dim_string(const int dim, const int spacedim)
Definition utilities.cc:549
STL namespace.
::VectorizedArray< Number, width > exp(const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > pow(const ::VectorizedArray< Number, width > &, const Number p)
*  const unsigned int n_q_points
static constexpr unsigned int max_children_per_face
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 constexpr unsigned int vertices_per_cell
static constexpr unsigned int lines_per_cell
static constexpr unsigned int faces_per_cell
static constexpr unsigned int vertices_per_face
static unsigned int line_to_cell_vertices(const unsigned int line, const unsigned int vertex)
static unsigned int face_to_cell_lines(const unsigned int face, const unsigned int line, const bool face_orientation=true, const bool face_flip=false, const bool face_rotation=false)
static constexpr unsigned int lines_per_face