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

Add generic nodal/modal bilinear form routines #103

Open
wants to merge 19 commits into
base: main
Choose a base branch
from

Conversation

a-alveyblanc
Copy link
Contributor

@a-alveyblanc a-alveyblanc commented Dec 5, 2024

It would be helpful to have a more general version of nodal_quad_mass_matrix. My specific use case for this routine is generating operators representing bilinear forms that have derivatives on the test functions but not necessarily on the trial functions. More generally, this can be useful to generate operators representing bilinear forms whose test and trial functions are not the same.

Functionality of nodal_quad_mass_matrix and modal_quad_mass_matrix are updated to use the new, general routines.

@a-alveyblanc
Copy link
Contributor Author

Not sure why ruff was failing here. It wasn't failing locally, and I didn't change any of the files the ruff CI test was complaining about. Fixed them anyway, but happy to revert if it seems like a CI bug.

The changes in contrib/weights-from-festa-sommariva were the ones needed to make ruff happy.

@alexfikl
Copy link
Collaborator

alexfikl commented Dec 6, 2024

Not sure why ruff was failing here. It wasn't failing locally, and I didn't change any of the files the ruff CI test was complaining about. Fixed them anyway, but happy to revert if it seems like a CI bug.

The changes in contrib/weights-from-festa-sommariva were the ones needed to make ruff happy.

That's a new check in ruff 0.8.2: astral-sh/ruff#14611. Thanks for fixing it!

Copy link
Owner

@inducer inducer left a comment

Choose a reason for hiding this comment

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

Thanks, this looks great! Just a few style quibbles below.

modepy/matrices.py Outdated Show resolved Hide resolved
modepy/test/test_matrices.py Outdated Show resolved Hide resolved
@a-alveyblanc
Copy link
Contributor Author

Seems like mypy also now has issue with something I didn't touch. I'll take a closer look later today.

@alexfikl
Copy link
Collaborator

Seems like mypy also now has issue with something I didn't touch. I'll take a closer look later today.

Those seem to be due to an issue with some new numpy typing changes: numpy/numpy#27957.

modepy/matrices.py Outdated Show resolved Hide resolved
@@ -351,6 +354,77 @@ def mass_matrix(
return la.inv(inverse_mass_matrix(basis, nodes))


def modal_quad_bilinear_form(
Copy link
Owner

Choose a reason for hiding this comment

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

I'm thinking about the naming of this. I'm not sure "bilinear form" is that great a fit, because the trial functions don't appear. I thought of "projection", but that also misses the mark, because the test functions could be derivatives. In a word, I'm not sure. I can probably be convinced to go along with "bilinear form", but I figured it might be good to at least discuss the naming.

(@alexfikl, if you're reading along, please feel free to chime in too)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm also not the biggest fan of the name, but I couldn't come up with anything better. modal_quadrature_operator maybe?

Copy link
Collaborator

@alexfikl alexfikl Dec 14, 2024

Choose a reason for hiding this comment

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

Where is this modal_quad_bilinear_form supposed to be used? I'm guessing the nodal_quad_bilinear_form is used to define a proper bilinear form somewhere?

EDIT: I mostly meant "proper" in the sense of defining an inner product, but maybe that's not super relevant..?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

modal_quad_bilinear_form doesn't have any uses right now other than returning the operator that's transformed into a nodal operator.

nodal_quad_bilinear_form will be used in a grudge update that evaluates operators using quadrature (inducer/grudge#362 is the staging area for this, although a little outdated at this point). While nodal_quadrature_operator could be used for everything, nodal_quad_bilinear_form makes the corresponding grudge code cleaner when there is no overintegration.

TLDR; modal_quad_bilinear_form's current use is in nodal_quad_bilinear_form. nodal_quad_bilinear_form is used to evaluate DG operators in grudge when there is no overintegration. nodal_quadrature_operator is used when there is overintegration.

Also, the original comment is outdated now since modal_quad_bilinear_form does use trial functions (as of c063d23).

Copy link
Collaborator

Choose a reason for hiding this comment

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

Thanks for explaining! I think I got a better idea of what this is for.. but no better recommendation for a name :\

The only thing that comes to mind is that if modal_quad_bilinear_form is not actually supposed to be used outside of modepy at the moment, we can just inline it in nodal_quad_bilinear_form?

@a-alveyblanc
Copy link
Contributor Author

a-alveyblanc commented Dec 14, 2024

The first go was a confusing amalgamation of two versions of applying an operator to evaluate a bilinear form. They should now be cleanly separated with names that do a better job of describing what's happening.

What I mean by "two versions" is:

  1. We can first compute a "half" operator, i.e. the test functions evaluated at quadrature nodes times quadrature weights, then apply that to a trial solution evaluated at quadrature nodes (implemented as modal_quadrature_operator and nodal_quadrature_operator), or
  2. We can first compute a "full" operator, i.e. compute the inner product of test and trial functions using quadrature, then apply that to the coefficients of the trial solution at discretization nodes (implemented as modal_quadrature_bilinear_form and nodal_quadrature_bilinear_form)

Hopefully this is more clear. Happy to convert to a draft if we think more work needs to be done

Copy link
Collaborator

@alexfikl alexfikl left a comment

Choose a reason for hiding this comment

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

Just took a quick look and left some comments 😁

modepy/matrices.py Outdated Show resolved Hide resolved
modepy/matrices.py Outdated Show resolved Hide resolved
@@ -351,6 +355,117 @@ def mass_matrix(
return la.inv(inverse_mass_matrix(basis, nodes))


def modal_quadrature_operator(
Copy link
Owner

Choose a reason for hiding this comment

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

  • test_func_integration_matrix?
  • modal_test_matrix_quad?

Comment on lines +373 to +378
modal_operator = np.empty((len(test_functions), len(quadrature.weights)))

for i, test_f in enumerate(test_functions):
modal_operator[i] = test_f(quadrature.nodes) * quadrature.weights

return modal_operator
Copy link
Owner

Choose a reason for hiding this comment

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

return np.array([...])?

return modal_operator


def nodal_quad_operator(
Copy link
Owner

Choose a reason for hiding this comment

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

Have something like this instead?

def modal_to_nodal(basis, nodes, matrix):
    vdm = vandermonde(proj_functions, nodes)

    return la.solve(
        vdm.T, matrix
    )

and get rid of the nodal_... versions?

Comment on lines +467 to +468
if len(test_functions) != nodes.shape[1]:
raise ValueError("volume_nodes not unisolvent with proj_functions")
Copy link
Owner

Choose a reason for hiding this comment

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

Suggested change
if len(test_functions) != nodes.shape[1]:
raise ValueError("volume_nodes not unisolvent with proj_functions")
if len(proj_functions) != nodes.shape[1]:
raise ValueError("volume_nodes not unisolvent with proj_functions")

(but this is probably going away anyway)


return la.solve(vdm.T, modal_operator) @ la.inv(vdm)


def modal_quad_mass_matrix(
Copy link
Owner

Choose a reason for hiding this comment

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

I'd vote in favor of deprecating the _mass_matrix functions.

Copy link
Owner

Choose a reason for hiding this comment

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

While we're at it, deprecate the *face_mass* things, too, and (maybe) have a basis-with-node-transform-composer?

@inducer
Copy link
Owner

inducer commented Dec 17, 2024

Unsubscribing... @-mention or request review once it's ready for a look or needs attention.

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

Successfully merging this pull request may close these issues.

3 participants