8000 FE_DGQLegendre/FE_DGP: accept other polynomials by peterrum · Pull Request #18177 · dealii/dealii · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

FE_DGQLegendre/FE_DGP: accept other polynomials #18177

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

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

peterrum
Copy link
8000
Member

(not just Legendre basis)

Copy link
Member
@bangerth bangerth left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The FE_Q class (I believe) does this by accepting a set of interpolation points. Do you want to use the new constructor to create modal elements, or why do you take a vector of polynomials?

Separately, don't you need to address the various functions that return nodal points? I think this should be tested too :-)

Comment on lines 318 to 322
/**
* Constructor for tensor product polynomials of given polynomials @p poly.
*/
FE_DGP(const std::vector<Polynomials::Polynomial<double>> &poly);

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment was only copied from the other constructor, but I don't think it is clear at this point how the space is actually constructed. The given argument describes a one dimensional polynomial space. From this, we fill the multi-dimensional space by a truncated tensor product that picks the polynomials from the given space starting index zero in this list. So if one wants a complete polynomial degree as is suggested by the general class description, one needs to make sure that the polynomial space is sorted appropriately (to whatever space one wants to get after taking the tensor product).

In other words, I think this is a dangerous constructor because we do not enforce anything on a polynomial space, and if one hands in strange polynomials one will get a strange element. In particular, I can hand in a vector of degree much higher than the size of the polynomials, if I intend to implement some funny bubble space, but then FiniteElement::degree and similar are wrong and might produce confusing results. We could say it is up to the user to make this decision by making sure that the polynomial space is later matched with the right downstream code such as suitable quadrature formulas, but it should be clearly stated what the effects of the choices are at this point.

Comment on lines 463 to 467
/**
* Constructor for tensor product polynomials based on the
* given polynomials @p poly.
*/
FE_DGQLegendre(const std::vector<Polynomials::Polynomial<double>> &poly);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like this constructor because it will yield a polynomial space that is not a Legendre space if the given general polynomial space is not a 1D Legendre space. I think we should rename this class into FE_DGQModal or similar (or FE_DGQArbitraryPolynomialSpace, because we are not tied to use a modal space, either, if we directly hand in the polynomials), implement all functionality there including the constructor you use here, and set up FE_DGQLegendre as a light-weight class on top of FE_DGQModal.

Also note the comments I gave in the other class: It is the user's responsibility to provide useful a useful polynomial space.

Comment on lines +37 to 40
FiniteElementData<dim>(get_dpo_vector(poly.size() - 1),
1,
degree,
poly.size() - 1,
FiniteElementData<dim>::L2),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is one of the points I tried to make in the comment above: We derive the degree from the size of the polynomials. Which clearly makes sense for a sane polynomial space. But by giving the space into the hand of the user, our internal variable names get very blurry.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that could probably be addressed by adding an assertion to the body of constructor, right? Right now, you already assert that for each given polynomial, p.degree() <= degree. You will also need to assert that the max of the p.degree() is == degree.

@peterrum
Copy link
Member Author
peterrum commented Mar 1, 2025

@bangerth @kronbichler Thank you for the feedback!

In the last commits, I made the following changes:

  • add one test
  • extended the documentation of the new constructor of FE_DGP
  • and introduced FE_DGQArbitraryPolynomialSpace as the base class of FE_DGQLegendre. I went with this name since it is similar to FE_DGQArbitraryPoints. However, I can also change it FE_DGQModal.

The class hierarchy of FE_DGP and FE_DGQ are unfortunately not parallel. E.g., FE_DGP should be FE_DGPLegendre (so that I could introduce an intermediate class FE_DGPArbitraryPolynomialSpace ). However, I don't see a way to change this.

@peterrum
Copy link
Member Author
peterrum commented Mar 1, 2025

The FE_Q class (I believe) does this by accepting a set of interpolation points.

Indeed, there is such a constructor. But that is protected. Maybe someone knows the historical reason?

Do you want to use the new constructor to create modal elements, or why do you take a vector of polynomials?
Separately, don't you need to address the various functions that return nodal points? I think this should be tested too :-)

Yes, I would like to be able model elements but not necessarily based on Legendre polynomials.

Copy link
Member
@kronbichler kronbichler left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think with the changes made this looks much better. Thank you.

@@ -1005,11 +1005,45 @@ FE_DGQArbitraryNodes<dim, spacedim>::clone() const



// ---------------------------------- FE_DGQLegendre -------------------------
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// ---------------------------------- FE_DGQLegendre -------------------------
// ---------------------------------- FE_DGQArbitraryPolynomialSpace -------------------------

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed!

@kronbichler
Copy link
Member

The FE_Q class (I believe) does this by accepting a set of interpolation points.

Indeed, there is such a constructor. But that is protected. Maybe someone knows the historical reason?

I think you refer to the class FE_DGQ? Because for FE_Q we have the constructor of a quadrature formula as part of the public interface. In any case, the in #3770 we introduced the protected constructor taking the points. I think it could make sense to make FE_DGQArbitraryPolynomialSpace a base class of the main FE_DGQ class (or more precisely, have the inheritance order from base to derived as FE_DGQArbitraryPolynomialSpace -> FE_DGQArbitraryNodes -> FE_DGQ). The FE_DGQLegendre would then inherit from the new class. But I am not sure if this can be made entirely backwards compatible, and it likely needs a more fundamental redesigned compared to what you try to do in this PR?

Regarding the history: We historically had FE_Q and FE_DGQ taking different paths. At the time I started working with deal.II around 2008, I think we already had FE_DGQArbitraryNodes (extending the protected constructor taking a Quadrature formula), but we did not yet have arbitrary points for FE_Q, just the equidistant ones. As time went on, we went to the Gauss-Lobatto points as the default in #2438. But we never tried to make this entirely uniform. I wonder if we should take a bit more time to discuss this here (or in the near future), but I am definitely in favor of the current patch in the current form already.

@peterrum
Copy link
Member Author
peterrum commented Mar 3, 2025

@kronbichler Thank you for the history lesson :)

@peterrum
Copy link
Member Author
peterrum commented Mar 3, 2025

Regarding the doxygen warning. It complains about FE_DGQ which seems to be odd!? Any ideas?

@kronbichler
Copy link
Member
kronbichler commented Mar 3, 2025

Hm, the error is strange, I see

/home/runner/work/dealii/dealii/source/fe/fe_dgq.cc:65: warning: no uniquely matching class member found for 
  template < dim, spacedim >
  FE_DGQ< dim, spacedim >::FE_DGQ(const unsigned int degree)
Possible candidates:
  'template < dim1, spacedim1 >
  friend class FE_DGQ< dim, spacedim >::FE_DGQ' at line 378 of file /home/runner/work/dealii/dealii/include/deal.II/fe/fe_dgq.h
  'FE_DGQ< dim, spacedim >::FE_DGQ(const unsigned int p)' at line 120 of file /home/runner/work/dealii/dealii/include/deal.II/fe/fe_dgq.h
  'FE_DGQ< dim, spacedim >::FE_DGQ(const std::vector< Polynomials::Polynomial< double > > &polynomials)' at line 337 of file /home/runner/work/dealii/dealii/include/deal.II/fe/fe_dgq.h

Could it be that the std::vector can be constructed from a lenght parameter p, and that the problem might be solved by marking the second constructor explicit? (I'm just guessing here.)

Copy link
Member
@bangerth bangerth left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's see that we can move this forward.

Comment on lines +37 to 40
FiniteElementData<dim>(get_dpo_vector(poly.size() - 1),
1,
degree,
poly.size() - 1,
FiniteElementData<dim>::L2),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that could probably be addressed by adding an assertion to the body of constructor, right? Right now, you already assert that for each given polynomial, p.degree() <= degree. You will also need to assert that the max of the p.degree() is == degree.

class FE_DGQLegendre : public FE_DGQ<dim, spacedim>
class FE_DGQArbitraryPolynomialSpace : public FE_DGQ<dim, spacedim>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've got to admit that this looks a bit backward. FE_DGQ should be the derived class, and FE_DGQArbitraryPolynomialSpace the base class. Do you know why it is this way around?

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

Successfully merging this pull request may close these issues.

3 participants
0