From 5c8e0d9adf0d96a6b30e6798457a4ffae18c1e8d Mon Sep 17 00:00:00 2001 From: Marcus Mohr <marcus.mohr@lmu.de> Date: Mon, 3 Mar 2025 15:27:48 +0100 Subject: [PATCH 1/3] Draft for resolving issue 48 The commit - adds component_index as keyword to IntegrandSymbols - makes gradient and divergence form pass component_index to process_integrand - the corresponding integrands now check the shape of grad_u resp. grad_v and, if it is not square, revert to extracting the corresponding component - moves the is_implemented check from the call of HyTeGIntegrator outwards, so that the call to form_func is protected against out-of-bounds indices --- generate_all_hyteg_forms.py | 38 ++++++++++----------- hog/forms.py | 2 ++ hog/integrand.py | 9 ++++- hog/recipes/integrands/volume/divergence.py | 21 +++++++++--- hog/recipes/integrands/volume/gradient.py | 21 +++++++++--- 5 files changed, 60 insertions(+), 31 deletions(-) diff --git a/generate_all_hyteg_forms.py b/generate_all_hyteg_forms.py index b37446c..96a7b26 100644 --- a/generate_all_hyteg_forms.py +++ b/generate_all_hyteg_forms.py @@ -1135,30 +1135,28 @@ def main(): inline_values=form_info.inline_quad, ) - mat = form_func( - form_info.form_name, - row, - col, - trial, - test, - geometry, - quad, - symbolizer, - blending=form_info.blending, - ) - form_codes.append( - HyTeGIntegrator( - form_info.class_name(row, col), - mat, + if form_info.is_implemented( row, col, geometry.dimensions ): + mat = form_func( + form_info.form_name, + row, + col, + trial, + test, geometry, quad, symbolizer, - not_implemented=not form_info.is_implemented( - row, col, geometry.dimensions - ), - integrate_rows=form_info.integrate_rows, + blending=form_info.blending, + ) + form_codes.append( + HyTeGIntegrator( + form_info.class_name(row, col), + mat, + geometry, + quad, + symbolizer, + integrate_rows=form_info.integrate_rows, + ) ) - ) form_classes.append( HyTeGFormClass( form_info.class_name(row, col), diff --git a/hog/forms.py b/hog/forms.py index ec630ce..5ed4b0e 100644 --- a/hog/forms.py +++ b/hog/forms.py @@ -579,6 +579,7 @@ Weak formulation geometry, symbolizer, blending=blending, + component_index=component_index, is_symmetric=False, docstring=docstring, rot_type=RotationType.POST_MULTIPLY @@ -620,6 +621,7 @@ def gradient( geometry, symbolizer, blending=blending, + component_index=component_index, is_symmetric=False, docstring=docstring, rot_type=RotationType.PRE_MULTIPLY diff --git a/hog/integrand.py b/hog/integrand.py index 0731370..a95b193 100644 --- a/hog/integrand.py +++ b/hog/integrand.py @@ -220,6 +220,9 @@ class IntegrandSymbols: # tabulate: Callable[[Union[sp.Expr, sp.Matrix], str], sp.Matrix] | None = None + # For backward compatibility with (sub-)form generation this integer allows to select a component + component_index: int | None = None + def process_integrand( integrand: Callable[..., Any], @@ -230,6 +233,7 @@ def process_integrand( blending: GeometryMap = IdentityMap(), boundary_geometry: ElementGeometry | None = None, fe_coefficients: Dict[str, Union[FunctionSpace, None]] | None = None, + component_index: int | None = None, is_symmetric: bool = False, rot_type: RotationType = RotationType.NO_ROTATION, docstring: str = "", @@ -293,7 +297,7 @@ def process_integrand( finite-element function coefficients, they will be available to the callable as `k` supply None as the FunctionSpace for a std::function-type coeff (only works for old forms) :param is_symmetric: whether the bilinear form is symmetric - this is exploited by the generator - :param rot_type: whether the operator has to be wrapped with rotation matrix and the type of rotation that needs + :param rot_type: whether the operator has to be wrapped with rotation matrix and the type of rotation that needs to be applied, only applicable for Vectorial spaces :param docstring: documentation of the integrand/bilinear form - will end up in the docstring of the generated code """ @@ -482,6 +486,9 @@ def process_integrand( mat = create_empty_element_matrix(trial, test, volume_geometry) it = element_matrix_iterator(trial, test, volume_geometry) + if component_index is not None: + s.component_index = component_index + for data in it: s.u = data.trial_shape s.grad_u = data.trial_shape_grad diff --git a/hog/recipes/integrands/volume/divergence.py b/hog/recipes/integrands/volume/divergence.py index 75ae751..f2ea653 100644 --- a/hog/recipes/integrands/volume/divergence.py +++ b/hog/recipes/integrands/volume/divergence.py @@ -26,10 +26,21 @@ def integrand( grad_u, v, tabulate, + component_index, **_, ): - return ( - -(jac_b_inv.T * tabulate(jac_a_inv.T * grad_u)).trace() - * tabulate(v * jac_a_abs_det) - * jac_b_abs_det - ) + # working with vector-valued functions + if grad_u.is_square: + return ( + -(jac_b_inv.T * tabulate(jac_a_inv.T * grad_u)).trace() + * tabulate(v * jac_a_abs_det) + * jac_b_abs_det + ) + + # working with scalar-valued functions (backward compatibility) + else: + return ( + -(jac_b_inv.T * tabulate(jac_a_inv.T * grad_u))[component_index] + * tabulate(v * jac_a_abs_det) + * jac_b_abs_det + ) diff --git a/hog/recipes/integrands/volume/gradient.py b/hog/recipes/integrands/volume/gradient.py index 982ba23..134271d 100644 --- a/hog/recipes/integrands/volume/gradient.py +++ b/hog/recipes/integrands/volume/gradient.py @@ -26,10 +26,21 @@ def integrand( u, grad_v, tabulate, + component_index, **_, ): - return ( - -(jac_b_inv.T * tabulate(jac_a_inv.T * grad_v)).trace() - * tabulate(u * jac_a_abs_det) - * jac_b_abs_det - ) + # working with vector-valued functions + if grad_v.is_square: + return ( + -(jac_b_inv.T * tabulate(jac_a_inv.T * grad_v)).trace() + * tabulate(u * jac_a_abs_det) + * jac_b_abs_det + ) + + # working with scalar-valued functions (backward compatibility) + else: + return ( + -(jac_b_inv.T * tabulate(jac_a_inv.T * grad_v))[component_index] + * tabulate(u * jac_a_abs_det) + * jac_b_abs_det + ) -- GitLab From 41c146f26462206297d04e9ab3afefc651f183e9 Mon Sep 17 00:00:00 2001 From: Marcus Mohr <marcus.mohr@lmu.de> Date: Mon, 3 Mar 2025 17:16:47 +0100 Subject: [PATCH 2/3] Quick fix for file_path() and P2PlusBubble forms This should temporarily fix the problem in the "form-generation" job of the pipeline with the p2_plus_bubble_diffusion_affine_qe form. For the moment we place it in the p2 folder. However, file_path() needs refactoring, especially if we add more spaces. --- generate_all_hyteg_forms.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/generate_all_hyteg_forms.py b/generate_all_hyteg_forms.py index 96a7b26..ae86507 100644 --- a/generate_all_hyteg_forms.py +++ b/generate_all_hyteg_forms.py @@ -166,8 +166,8 @@ class FormInfo: sub_dir = "p1" if self.trial_family == "N1E1": sub_dir = "n1e1" - elif self.trial_family == "P2 enhanced with Bubble": - return "p2_plus_bubble" + elif self.trial_family == "P2 enhanced with Bubble" and self.test_family == "P2 enhanced with Bubble": + sub_dir = "p2" elif self.trial_degree == self.test_degree: sub_dir = f"p{self.trial_degree}" else: -- GitLab From 7138af037eac2abb4c5c3ac646d7302eb77296b2 Mon Sep 17 00:00:00 2001 From: Marcus Mohr <marcus.mohr@lmu.de> Date: Mon, 3 Mar 2025 17:31:20 +0100 Subject: [PATCH 3/3] Fix generation of pspg forms --- generate_all_hyteg_forms.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/generate_all_hyteg_forms.py b/generate_all_hyteg_forms.py index ae86507..2c49ddd 100644 --- a/generate_all_hyteg_forms.py +++ b/generate_all_hyteg_forms.py @@ -166,7 +166,10 @@ class FormInfo: sub_dir = "p1" if self.trial_family == "N1E1": sub_dir = "n1e1" - elif self.trial_family == "P2 enhanced with Bubble" and self.test_family == "P2 enhanced with Bubble": + elif ( + self.trial_family == "P2 enhanced with Bubble" + and self.test_family == "P2 enhanced with Bubble" + ): sub_dir = "p2" elif self.trial_degree == self.test_degree: sub_dir = f"p{self.trial_degree}" @@ -836,7 +839,9 @@ def form_func( quad, symbolizer ) elif name.startswith("pspg"): - return pspg(trial, test, geometry, quad, symbolizer, blending=blending) + return pspg( + trial, test, geometry, quad, symbolizer, blending=blending + ).integrate(quad, symbolizer) elif name.startswith("linear_form"): return linear_form(trial, test, geometry, quad, symbolizer, blending=blending) elif name.startswith("divt"): @@ -1135,7 +1140,7 @@ def main(): inline_values=form_info.inline_quad, ) - if form_info.is_implemented( row, col, geometry.dimensions ): + if form_info.is_implemented(row, col, geometry.dimensions): mat = form_func( form_info.form_name, row, -- GitLab