diff --git a/generate_all_operators.py b/generate_all_operators.py index 6ce4a12dcab8ddddd60fb2e05107591d8415a84a..05c7ee2dabc57b02e0b3baf93805bfb13d833b73 100644 --- a/generate_all_operators.py +++ b/generate_all_operators.py @@ -51,7 +51,8 @@ from hog.forms import ( supg_diffusion, advection, supg_advection, - grad_rho_by_rho_dot_u, + grad_rho_by_rho_dot_u, nonlinear_diffusion_newton_galerkin_symmetric_part, + nonlinear_diffusion_newton_galerkin_asymmetric_part, nonlinear_diffusion_newton_galerkin_asymmetric_lumped_part, ) from hog.forms_boundary import ( mass_boundary, @@ -623,6 +624,18 @@ def all_operators( TestSpace(P1), form=partial(nonlinear_diffusion_newton_galerkin, coefficient_function_space=P1, only_newton_galerkin_part_of_form=False), type_descriptor=type_descriptor, geometries=list(geometries), opts=opts, blending=blending)) + ops.append(OperatorInfo("P1", "NonlinearDiffusionNewtonGalerkinSymmetricPart", TrialSpace(P1), + TestSpace(P1), form=partial(nonlinear_diffusion_newton_galerkin_symmetric_part, + coefficient_function_space=P1), + type_descriptor=type_descriptor, geometries=list(geometries), opts=opts, blending=blending)) + ops.append(OperatorInfo("P1", "NonlinearDiffusionNewtonGalerkinAsymmetricPart", TrialSpace(P1), + TestSpace(P1), form=partial(nonlinear_diffusion_newton_galerkin_asymmetric_part, + coefficient_function_space=P1), + type_descriptor=type_descriptor, geometries=list(geometries), opts=opts, blending=blending)) + ops.append(OperatorInfo("P1", "NonlinearDiffusionNewtonGalerkinAsymmetricLumpedPart", TrialSpace(P1), + TestSpace(P1), form=partial(nonlinear_diffusion_newton_galerkin_asymmetric_lumped_part, + coefficient_function_space=P1), + type_descriptor=type_descriptor, geometries=list(geometries), opts=opts, blending=blending)) ops.append(OperatorInfo("P1Vector", "Diffusion", TrialSpace(P1Vector), TestSpace(P1Vector), form=diffusion, type_descriptor=type_descriptor, geometries=list(geometries), opts=opts, blending=blending)) diff --git a/hog/forms.py b/hog/forms.py index f67f0781d698489310f163fcd996231aecee66e0..fdee07a0c06ea7cd4545f6c6cf998b4781543149 100644 --- a/hog/forms.py +++ b/hog/forms.py @@ -317,6 +317,213 @@ Note: :math:`a(k) = 1/8 + k^2` is currently hard-coded and the form is intended ) +def nonlinear_diffusion_newton_galerkin_symmetric_part( + trial: TrialSpace, + test: TestSpace, + geometry: ElementGeometry, + symbolizer: Symbolizer, + coefficient_function_space: FunctionSpace, + blending: GeometryMap = IdentityMap(), +) -> Form: + docstring = f""" +todo: heavy code duplication, this can be implemented with small changes to nonlinear_diffusion_newton_galerkin + +Symmetric part of the bi-linear form for the solution of the non-linear diffusion equation by a Newton-Galerkin approach + +Weak formulation + + u: trial function (space: {trial}) + v: test function (space: {test}) + k: FE coefficient function (space: {coefficient_function_space}) + + ∫ a(k) ∇u · ∇v + +Note: :math:`a(k) = 1/8 + k^2` is currently hard-coded and the form is intended for :math:`k = u`. +""" + if trial != test: + raise HOGException( + "Trial space must be equal to test space to assemble diffusion matrix." + ) + + if blending != IdentityMap(): + raise HOGException( + "The nonlinear_diffusion_newton_galerkin form does currently not support blending." + ) + + def integrand( + *, + jac_a_inv, + jac_a_abs_det, + grad_u, + grad_v, + k, + tabulate, + **_, + ): + a = sp.Rational(1, 8) + k["k"] * k["k"] + + diffusion_term = a * tabulate( + dot(jac_a_inv.T * grad_u, jac_a_inv.T * grad_v) * jac_a_abs_det + ) + + return diffusion_term + + return process_integrand( + integrand, + trial, + test, + geometry, + symbolizer, + blending=blending, + is_symmetric=True, + docstring=docstring, + fe_coefficients={"k": coefficient_function_space}, + ) + + +def nonlinear_diffusion_newton_galerkin_asymmetric_part( + trial: TrialSpace, + test: TestSpace, + geometry: ElementGeometry, + symbolizer: Symbolizer, + coefficient_function_space: FunctionSpace, + blending: GeometryMap = IdentityMap(), +) -> Form: + docstring = f""" + +todo: heavy code duplication, this can be implemented with small changes to nonlinear_diffusion_newton_galerkin + +Asymmetric part of bi-linear form for the solution of the non-linear diffusion equation by a Newton-Galerkin approach + +Weak formulation + + u: trial function (space: {trial}) + v: test function (space: {test}) + k: FE coefficient function (space: {coefficient_function_space}) + + ∫ a'(k) u ∇k · ∇v + +Note: :math:`a(k) = 1/8 + k^2` is currently hard-coded and the form is intended for :math:`k = u`. +""" + if trial != test: + raise HOGException( + "Trial space must be equal to test space to assemble diffusion matrix." + ) + + if blending != IdentityMap(): + raise HOGException( + "The nonlinear_diffusion_newton_galerkin form does currently not support blending." + ) + + def integrand( + *, + jac_a_inv, + jac_a_abs_det, + u, + grad_v, + k, + grad_k, + tabulate, + **_, + ): + a_prime = 2 * k["k"] + + newton_galerkin_term = ( + a_prime + * u + * dot(jac_a_inv.T * grad_k["k"], tabulate(jac_a_inv.T * grad_v)) + * tabulate(jac_a_abs_det) + ) + + return newton_galerkin_term + + return process_integrand( + integrand, + trial, + test, + geometry, + symbolizer, + blending=blending, + is_symmetric=False, + docstring=docstring, + fe_coefficients={"k": coefficient_function_space}, + ) + + +def nonlinear_diffusion_newton_galerkin_asymmetric_lumped_part( + trial: TrialSpace, + test: TestSpace, + geometry: ElementGeometry, + symbolizer: Symbolizer, + coefficient_function_space: FunctionSpace, + blending: GeometryMap = IdentityMap(), +) -> Form: + docstring = f""" + +todo: heavy code duplication, this can be implemented with small changes to nonlinear_diffusion_newton_galerkin + +Asymmetric part of bi-linear form for the solution of the non-linear diffusion equation by a Newton-Galerkin approach. Optimized with mass lumping. + +Weak formulation + + u: trial function (space: {trial}) + v: test function (space: {test}) + k: FE coefficient function (space: {coefficient_function_space}) + + ∫ a'(k) u ∇k · ∇v + +Note: :math:`a(k) = 1/8 + k^2` is currently hard-coded and the form is intended for :math:`k = u`. +""" + if trial != test: + raise HOGException( + "Trial space must be equal to test space to assemble diffusion matrix." + ) + + if blending != IdentityMap(): + raise HOGException( + "The nonlinear_diffusion_newton_galerkin form does currently not support blending." + ) + + def integrand( + *, + jac_a_inv, + jac_a_abs_det, + u, + v, + grad_v, + k, + grad_k, + tabulate, + **_, + ): + # todo this turns into a diagonal matrix, can this further get optimized? + # todo can you get the indices of u and v and compare those instead of the whole expressions? + if not u.equals(v): + return 0 + else: + a_prime = 2 * k["k"] + + newton_galerkin_term = ( + a_prime + * dot(jac_a_inv.T * grad_k["k"], tabulate(jac_a_inv.T * grad_v)) + * tabulate(jac_a_abs_det) + ) + + return newton_galerkin_term + + return process_integrand( + integrand, + trial, + test, + geometry, + symbolizer, + blending=blending, + is_symmetric=False, + docstring=docstring, + fe_coefficients={"k": coefficient_function_space}, + ) + + def epsilon( trial: TrialSpace, test: TestSpace, @@ -372,9 +579,11 @@ where is_symmetric=trial == test, docstring=docstring, fe_coefficients={"mu": coefficient_function_space}, - rot_type=RotationType.PRE_AND_POST_MULTIPLY - if rotation_wrapper - else RotationType.NO_ROTATION, + rot_type=( + RotationType.PRE_AND_POST_MULTIPLY + if rotation_wrapper + else RotationType.NO_ROTATION + ), ) @@ -580,9 +789,9 @@ Weak formulation blending=blending, is_symmetric=False, docstring=docstring, - rot_type=RotationType.POST_MULTIPLY - if rotation_wrapper - else RotationType.NO_ROTATION, + rot_type=( + RotationType.POST_MULTIPLY if rotation_wrapper else RotationType.NO_ROTATION + ), ) @@ -621,9 +830,9 @@ def gradient( blending=blending, is_symmetric=False, docstring=docstring, - rot_type=RotationType.PRE_MULTIPLY - if rotation_wrapper - else RotationType.NO_ROTATION, + rot_type=( + RotationType.PRE_MULTIPLY if rotation_wrapper else RotationType.NO_ROTATION + ), ) @@ -906,18 +1115,20 @@ Weak formulation blending=blending, is_symmetric=False, docstring=docstring, - fe_coefficients={ - "ux": velocity_function_space, - "uy": velocity_function_space, - "uz": velocity_function_space, - } - if constant_cp - else { - "ux": velocity_function_space, - "uy": velocity_function_space, - "uz": velocity_function_space, - "cp": coefficient_function_space, - }, + fe_coefficients=( + { + "ux": velocity_function_space, + "uy": velocity_function_space, + "uz": velocity_function_space, + } + if constant_cp + else { + "ux": velocity_function_space, + "uy": velocity_function_space, + "uz": velocity_function_space, + "cp": coefficient_function_space, + } + ), ) @@ -1097,7 +1308,7 @@ Weak formulation ∫ ((∇ρ / ρ) · u) v """ - + from hog.recipes.integrands.volume.frozen_velocity import integrand return process_integrand( @@ -1114,6 +1325,7 @@ Weak formulation }, ) + def zero_form( trial: TrialSpace, test: TestSpace,