diff --git a/hog/forms.py b/hog/forms.py index 5ed4b0eeea7aeecc044ad81ba042bb9ff4ad7e0f..db70846c44ea1bce2c55c183635131d3db62f992 100644 --- a/hog/forms.py +++ b/hog/forms.py @@ -329,6 +329,7 @@ def epsilon( variable_viscosity: bool = True, coefficient_function_space: Optional[FunctionSpace] = None, rotation_wrapper: bool = False, + rigid_body_mode: bool = False, ) -> Form: docstring = f""" "Epsilon" operator. @@ -353,6 +354,7 @@ where from hog.recipes.integrands.volume.rotation import RotationType from hog.recipes.integrands.volume.epsilon import integrand + from hog.recipes.integrands.volume.epsilon_rigid import integrand as integrand_rigid from hog.recipes.integrands.volume.epsilon_affine import ( integrand as integrand_affine, ) @@ -363,6 +365,9 @@ where if blending == IdentityMap(): integr = integrand_affine + if rigid_body_mode: + integr = integrand_rigid + return process_integrand( integr, trial, @@ -640,6 +645,8 @@ def full_stokes( component_test: int = 0, variable_viscosity: bool = True, coefficient_function_space: Optional[FunctionSpace] = None, + rotation_wrapper: bool = False, + rigid_body_mode: bool = False, ) -> Form: docstring = f""" Implements the fully coupled viscous operator of the Stokes problem. @@ -670,11 +677,17 @@ where ε(w) := (1/2) (∇w + (∇w)ᵀ) """ - + from hog.recipes.integrands.volume.rotation import RotationType from hog.recipes.integrands.volume.full_stokes import integrand + from hog.recipes.integrands.volume.full_stokes_rigid import integrand as integrand_rigid + + if rigid_body_mode: + intgr = integrand_rigid + else: + intgr = integrand return process_integrand( - integrand, + intgr, trial, test, geometry, @@ -683,6 +696,7 @@ 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, ) diff --git a/hog/recipes/integrands/volume/epsilon_rigid.py b/hog/recipes/integrands/volume/epsilon_rigid.py new file mode 100644 index 0000000000000000000000000000000000000000..15cc9564d5ff4c911f5563253c1e23ce6147b984 --- /dev/null +++ b/hog/recipes/integrands/volume/epsilon_rigid.py @@ -0,0 +1,71 @@ +# HyTeG Operator Generator +# Copyright (C) 2024 HyTeG Team +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +from hog.recipes.common import * + + +def integrand( + *, + jac_a_inv, + jac_a_abs_det, + jac_b_inv, + jac_b_abs_det, + u, + v, + grad_u, + grad_v, + k, + x, + scalars, + tabulate, + volume_geometry, + **_, +): + + grad_u_chain = jac_b_inv.T * tabulate(jac_a_inv.T * grad_u) + grad_v_chain = jac_b_inv.T * tabulate(jac_a_inv.T * grad_v) + + def symm_grad(w): + return 0.5 * (w + w.T) + + symm_grad_u = symm_grad(grad_u_chain) + symm_grad_v = symm_grad(grad_v_chain) + + c_rot_penalty = scalars("c_rot_penalty") + + if volume_geometry.dimensions == 2: + rigid_z = sp.Matrix([[-x[1, 0]], [x[0, 0]]]) + rigid_body_model_val = dot(rigid_z, u) * dot(rigid_z, v) + elif volume_geometry.dimensions == 3: + rigid_z = sp.Matrix([[-x[1, 0]], [x[0, 0]], [0]]) + rigid_z = rigid_z / rigid_z.norm() + + rigid_y = sp.Matrix([[0], [-x[2, 0]], [x[1, 0]]]) + rigid_y = rigid_y / rigid_y.norm() + + rigid_x = sp.Matrix([[x[2, 0]], [0], [-x[0, 0]]]) + rigid_x = rigid_x / rigid_x.norm() + + rigid_body_model_val = dot(rigid_z, u) * dot(rigid_z, v) + dot(rigid_y, u) * dot(rigid_y, v) + dot(rigid_x, u) * dot(rigid_x, v) + + return ( + ( + double_contraction(2 * k["mu"] * symm_grad_u, symm_grad_v) + + c_rot_penalty * rigid_body_model_val + ) + * tabulate(jac_a_abs_det) + * jac_b_abs_det + ) diff --git a/hog/recipes/integrands/volume/full_stokes_rigid.py b/hog/recipes/integrands/volume/full_stokes_rigid.py new file mode 100644 index 0000000000000000000000000000000000000000..2ba8cf05716467d93b410d05e2c848783a10130c --- /dev/null +++ b/hog/recipes/integrands/volume/full_stokes_rigid.py @@ -0,0 +1,74 @@ +# HyTeG Operator Generator +# Copyright (C) 2024 HyTeG Team +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +from hog.recipes.common import * + + +def integrand( + *, + jac_a_inv, + jac_a_abs_det, + jac_b_inv, + jac_b_abs_det, + u, + v, + grad_u, + grad_v, + k, + x, + scalars, + tabulate, + volume_geometry, + **_, +): + + grad_u_chain = jac_b_inv.T * tabulate(jac_a_inv.T * grad_u) + grad_v_chain = jac_b_inv.T * tabulate(jac_a_inv.T * grad_v) + + def symm_grad(w): + return 0.5 * (w + w.T) + + symm_grad_u = symm_grad(grad_u_chain) + symm_grad_v = symm_grad(grad_v_chain) + + div_u = (jac_b_inv.T * tabulate(jac_a_inv.T * grad_u)).trace() + div_v = (jac_b_inv.T * tabulate(jac_a_inv.T * grad_v)).trace() + + c_rot_penalty = scalars("c_rot_penalty") + + if volume_geometry.dimensions == 2: + rigid_z = sp.Matrix([[-x[1, 0]], [x[0, 0]]]) + rigid_body_model_val = dot(rigid_z, u) * dot(rigid_z, v) + elif volume_geometry.dimensions == 3: + rigid_z = sp.Matrix([[-x[1, 0]], [x[0, 0]], [0]]) + rigid_z = rigid_z / rigid_z.norm() + + rigid_y = sp.Matrix([[0], [-x[2, 0]], [x[1, 0]]]) + rigid_y = rigid_y / rigid_y.norm() + + rigid_x = sp.Matrix([[x[2, 0]], [0], [-x[0, 0]]]) + rigid_x = rigid_x / rigid_x.norm() + + rigid_body_model_val = dot(rigid_z, u) * dot(rigid_z, v) + dot(rigid_y, u) * dot(rigid_y, v) + dot(rigid_x, u) * dot(rigid_x, v) + + return k["mu"] * ( + ( + double_contraction(2 * symm_grad_u, symm_grad_v) + * tabulate(jac_a_abs_det) + * jac_b_abs_det + ) + - (2.0 / 3.0) * div_u * div_v * tabulate(jac_a_abs_det) * jac_b_abs_det + ) + (c_rot_penalty * rigid_body_model_val) * tabulate(jac_a_abs_det) * jac_b_abs_det