Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Teach FEEvaluation RT and Nedelec evaluation #9545

Open
2 of 6 tasks
kronbichler opened this issue Feb 18, 2020 · 5 comments
Open
2 of 6 tasks

Teach FEEvaluation RT and Nedelec evaluation #9545

kronbichler opened this issue Feb 18, 2020 · 5 comments

Comments

@kronbichler
Copy link
Member

kronbichler commented Feb 18, 2020

This issue is to keep track of the work to support Raviart-Thomas and Nedelec elements in the context of MatrixFree and FEEvaluation. We need the following steps:

  • We need suitable polynomial spaces compatible with tensor products and ideally with matrix-free evaluators. I am thinking of nodal variants in terms of Gauss/Gauss-Lobatto bases or, for the case we want to do face integrals (incompressible flow with velocity represented by RT), we would probably even prefer Polynomials::HermiteLikeInterpolation. I have yet to review what polynomials we have exactly in the various RT and Nedelec classes; at least at first sight they do not seem to be easily decomposable into tensor products.
  • Teach internal::MatrixFreeFunctions::ShapeInfo to read out the information for RT and Nedelec elements. Once we have Teach FiniteElement how to fill MF::ShapeInfo #9544 in place, it should be straight-forward to do so; one extension we still need is support for anisotropic polynomials, i.e., the tensor product of multiple 1D formulas because we have degree k in some directions and k+1 in some other.
  • Teach the matrix-free evaluators the case with anisotropic polynomials.
  • Implement the Piola and Nedelec mappings in FEEvaluation. Given that this is a switch to a different formula in all get_value(), submit_value(), get_curl functions etc., we could either add it by an additional template parameter MappingKind that selects the right formula, or by a simple if statement. The latter would be less intrusive but require additional if clauses in inner loops. The compiler is typically pretty good at figuring them out, but if we put too many it might at some point refuse to optimize what we want to be optimized. We can start with that option. Note that for gradients with RT we will need the gradient of the Jacobian of the mapping, so the places where we construct the mapping in
    this->update_flags_cells =
    MappingInfoStorage<dim, dim, VectorizedArrayType>::compute_update_flags(
    update_flags_cells, quad);
    need to get aware of this fact.
  • Regarding the case of faces/edges not in the standard orientation: We need to adjust the basis functions so that Piola transform is still correct. Probably we need
    const unsigned int n = this->degree;
    const unsigned int face_no = 0;
    Assert(n * n == this->n_dofs_per_quad(face_no), ExcInternalError());
    for (unsigned int local = 0; local < this->n_dofs_per_quad(face_no); ++local)
    // face support points are in lexicographic ordering with x running
    // fastest. invert that (y running fastest)
    {
    unsigned int i = local % n, j = local / n;
    // face_orientation=false, face_flip=false, face_rotation=false
    this->adjust_quad_dof_index_for_face_orientation_table[face_no](local,
    0) =
    j + i * n - local;
    // face_orientation=false, face_flip=false, face_rotation=true
    this->adjust_quad_dof_index_for_face_orientation_table[face_no](local,
    1) =
    i + (n - 1 - j) * n - local;
    // face_orientation=false, face_flip=true, face_rotation=false
    this->adjust_quad_dof_index_for_face_orientation_table[face_no](local,
    2) =
    (n - 1 - j) + (n - 1 - i) * n - local;
    // face_orientation=false, face_flip=true, face_rotation=true
    this->adjust_quad_dof_index_for_face_orientation_table[face_no](local,
    3) =
    (n - 1 - i) + j * n - local;
    // face_orientation=true, face_flip=false, face_rotation=false
    this->adjust_quad_dof_index_for_face_orientation_table[face_no](local,
    4) = 0;
    // face_orientation=true, face_flip=false, face_rotation=true
    this->adjust_quad_dof_index_for_face_orientation_table[face_no](local,
    5) =
    j + (n - 1 - i) * n - local;
    // face_orientation=true, face_flip=true, face_rotation=false
    this->adjust_quad_dof_index_for_face_orientation_table[face_no](local,
    6) =
    (n - 1 - i) + (n - 1 - j) * n - local;
    // face_orientation=true, face_flip=true, face_rotation=true
    this->adjust_quad_dof_index_for_face_orientation_table[face_no](local,
    7) =
    (n - 1 - j) + i * n - local;
    // for face_orientation == false, we need to switch the sign
    for (unsigned int i = 0; i < 4; ++i)
    this->adjust_quad_dof_sign_for_face_orientation_table[face_no](local,
    i) = 1;
    (in particular quad_dof_sign_for_face_orienation_table) and then apply the operations from
    if (adjust_quad_dof_sign_for_face_orientation(
    local_quad_dof_index,
    face_index_from_dof_index,
    cell->face_orientation(face_index_from_dof_index),
    cell->face_flip(face_index_from_dof_index),
    cell->face_rotation(face_index_from_dof_index)))
    dof_sign = -1.0;
    and
    for (unsigned int k = 0; k < n_q_points; ++k)
    for (unsigned int d = 0; d < dim; ++d)
    output_data.shape_values(first + d, k) =
    dof_sign * fe_data.transformed_shape_values[k][d];
    .
  • Check what else needs to be done with adaptive grids. I'm undecided if we need to introduce a factor of 0.5 or 2. somewhere, so that the Piola transformation looks the same on both sides.
@jwitte08
Copy link
Contributor

With a student, I am working on RT elements build up as a tensor product of 1D elements.

Today, we had a look into FE_RaviartThomas and FE_RaviartThomasNodal's implementations. The first is close to the mathematical theory and assumes less regularity from the ansatz space. However, the latter (based on a nodal, primitive ansatz) has clear advantages seen from a technical perspective.

For example, in 2D one constructs an anisotropic quadrature formula Q_{k+2,k+1} for the x-component and Q_{k+1,k+2} for the y-component using QProjector. The node functionals with a one-to-one correspondence to these quadrature points uniquely determine the continuity in normal direction. Therefore, each component is readily decomposed into 1D node functionals.

Thus, we decided to start with the FE_RaviartThomasNodal filling the ShapeInfo having #9544 in mind. Let me know if you need some help with the new interface provided by FiniteElement.

@bangerth
Copy link
Member

bangerth commented Feb 21, 2020 via email

@kronbichler
Copy link
Member Author

kronbichler commented Feb 22, 2022

After discussion with @nfehn, we came up with a more detailed plan for approaching the problem.

Regarding the first point:

  • Extend the PolynomialsRaviartThomas class
    template <int dim>
    class PolynomialsRaviartThomasNodal : public TensorPolynomialsBase<dim>
    so that also the d * (k+1)^d space can be represented besides the RT - this is not strictly needed for RT, but makes it easier to create other H(div) conforming spaces and just test out non-anisotropic spaces can be done. I have an idea how to make that work.

Regarding the third bullet point (make the evaluators capable of doing anisotropic polynomials):

Regarding the fourth and fifth point I made some more specific comments in the original post.

@kronbichler
Copy link
Member Author

Apart from the cleanup in #12728, I think we need to postpone the additional topics in this issue to after the 9.4 release. I think we have a nice "experimental" state in terms of affine transformations and basic stuff, and can fix hanging nodes (#13671) as well as non-affine meshes to the next release. We would not have the time to properly test and implement all missing features to have full support for RT (let alone Nedelec, that was also part of the topic).

@kronbichler
Copy link
Member Author

We made progress with #13990 and some preceding commits, but the rest needs to be postponed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Development

No branches or pull requests

4 participants