-
Notifications
You must be signed in to change notification settings - Fork 7
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
base: main
Are you sure you want to change the base?
Changes from 7 commits
88ac3b5
ee62ab0
26e1258
c99dc72
19b1cda
6cbcfd5
8ea7aed
e40277e
3881f15
1de0b7f
72175ad
c026e74
fb7fb1f
d3d5ac6
c063d23
d3f9e36
6adb3e7
f914a0a
6f86301
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -66,6 +66,8 @@ | |
.. autofunction:: modal_quad_mass_matrix_for_face | ||
.. autofunction:: nodal_quad_mass_matrix_for_face | ||
.. autofunction:: spectral_diag_nodal_mass_matrix | ||
.. autofunction:: modal_quad_bilinear_form | ||
.. autofunction:: nodal_quad_bilinear_form | ||
|
||
Differentiation is also convenient to express by using :math:`V^{-1}` to | ||
obtain modal values and then using a Vandermonde matrix for the derivatives | ||
|
@@ -351,6 +353,68 @@ def mass_matrix( | |
return la.inv(inverse_mass_matrix(basis, nodes)) | ||
|
||
|
||
def modal_quad_bilinear_form( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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) There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Where is this EDIT: I mostly meant "proper" in the sense of defining an inner product, but maybe that's not super relevant..? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
TLDR; Also, the original comment is outdated now since There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
||
quadrature: Quadrature, | ||
test_functions: Sequence[Callable[[np.ndarray], np.ndarray]] | ||
) -> np.ndarray: | ||
r"""Using the *quadrature*, provide a matrix :math:`A` that | ||
satisfies: | ||
|
||
.. math:: | ||
|
||
\displaystyle (A \boldsymbol u)_i = \sum_j w_j \phi_i(r_j) u_j, | ||
|
||
where :math:`\phi_i` are the *test_functions* at the nodes | ||
:math:`r_j` of *quadrature*, with corresponding weights :math:`w_j`. | ||
""" | ||
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 | ||
Comment on lines
+373
to
+378
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
|
||
def nodal_quad_bilinear_form( | ||
test_functions: Sequence[Callable[[np.ndarray], np.ndarray]], | ||
trial_functions: Sequence[Callable[[np.ndarray], np.ndarray]], | ||
quadrature: Quadrature, | ||
nodes: np.ndarray, | ||
uses_quadrature_domain: bool = False | ||
) -> np.ndarray: | ||
a-alveyblanc marked this conversation as resolved.
Show resolved
Hide resolved
|
||
r"""Using *quadrature*, provide a matrix :math:`A` that satisfies: | ||
|
||
.. math:: | ||
|
||
\displaystyle (A \boldsymbol u)_i = \sum_j w_j \phi_i(r_j) u_j, | ||
|
||
where :math:`\phi_i` are the Lagrange basis functions obtained from | ||
*test_functions* at *nodes*, :math:`w_j` and :math:`r_j` are the weights | ||
and nodes from *quadrature*, and :math:`u_j` are point values of the trial | ||
function at either *nodes* or the *quadrature* nodes depending on whether | ||
a quadrature domain is used (as signified by *uses_quadrature_domain*). | ||
|
||
If *uses_quadrature_domain* is set to False, then an interpolation operator | ||
is used to make the operator :math:`N \times N` where :math:`N` is the | ||
number of nodes in *nodes*. Otherwise, the operator has shape :math:`N | ||
\times N_q` where :math:`N_q` is the number of nodes associated with | ||
*quadrature*. Default behavior is to assume a quadrature domain is not used. | ||
""" | ||
if len(test_functions) != nodes.shape[1]: | ||
raise ValueError("volume_nodes not unisolvent with trial_functions") | ||
|
||
vdm_out = vandermonde(trial_functions, nodes) | ||
a-alveyblanc marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
nodal_operator = la.solve( | ||
vdm_out.T, modal_quad_bilinear_form(quadrature, test_functions)) | ||
|
||
if uses_quadrature_domain: | ||
return nodal_operator | ||
else: | ||
return nodal_operator @ resampling_matrix( | ||
trial_functions, quadrature.nodes, nodes) | ||
|
||
|
||
def modal_quad_mass_matrix( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd vote in favor of deprecating the |
||
quadrature: Quadrature, | ||
test_functions: Sequence[Callable[[np.ndarray], np.ndarray]], | ||
|
@@ -367,12 +431,7 @@ def modal_quad_mass_matrix( | |
|
||
.. versionadded :: 2024.2 | ||
""" | ||
modal_mass_matrix = np.empty((len(test_functions), len(quadrature.weights))) | ||
|
||
for i, test_f in enumerate(test_functions): | ||
modal_mass_matrix[i] = test_f(quadrature.nodes) * quadrature.weights | ||
|
||
return modal_mass_matrix | ||
return modal_quad_bilinear_form(quadrature, test_functions) | ||
|
||
|
||
def nodal_quad_mass_matrix( | ||
|
@@ -399,13 +458,12 @@ def nodal_quad_mass_matrix( | |
if nodes is None: | ||
nodes = quadrature.nodes | ||
|
||
if len(test_functions) != nodes.shape[1]: | ||
raise ValueError("volume_nodes not unisolvent with test_functions") | ||
|
||
vdm = vandermonde(test_functions, nodes) | ||
|
||
return la.solve(vdm.T, | ||
modal_quad_mass_matrix(quadrature, test_functions)) | ||
return nodal_quad_bilinear_form( | ||
test_functions, | ||
test_functions, | ||
quadrature, | ||
nodes, | ||
uses_quadrature_domain=True) | ||
|
||
|
||
def spectral_diag_nodal_mass_matrix( | ||
|
@@ -549,5 +607,4 @@ def nodal_quad_mass_matrix_for_face( | |
return la.solve(vol_vdm.T, | ||
modal_quad_mass_matrix_for_face(face, face_quad, test_functions)) | ||
|
||
|
||
# vim: foldmethod=marker |
There was a problem hiding this comment.
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?