idaholab / moose

Multiphysics Object Oriented Simulation Environment
https://www.mooseframework.org
GNU Lesser General Public License v2.1
1.76k stars 1.05k forks source link

Moving 2D-Elements in a 3D mesh to an inactive subdomain (error in MooseVariableBase.C, line 145) #28204

Open jmeier opened 3 months ago

jmeier commented 3 months ago

Discussed in https://github.com/idaholab/moose/discussions/28201

Originally posted by **grunerjmeier** July 23, 2024 Dear Moose-Community, I have a 3D mesh with some volume-elements in one subdomain and some 2D elements (shell-elements) in another subdomain. The moment I try to move the 2D elements into an inactive domain (added by `add_subdomain_names` via XYZSubdomainModifier), I get the following error: ``` Assertion `_is_lower_d == _mesh.isLowerD(*it)' failed A user should not specify a mix of lower-dimensional and higher-dimensional blocks for a variable at /home/user/projects/moose/framework/src/variables/MooseVariableBase.C, line 145 ``` The inactive domain I tried to move the 2D elements to was previously empty and never used before. I only try to move the 2D elements of one subdomain (I do not try to mix element types in one inactive subdomain). Is it possible to move 2D elements to an inactive domain, if the mesh consists also of 3D elements? Thank you for your help. Jörg
lindsayad commented 3 months ago

I doubt that anyone has attempted this before, so I'm not very surprised that you've run into an issue. Based on your investigation, I believe the answer to

Is it possible to move 2D elements to an inactive domain, if the mesh consists also of 3D elements?

is no

jmeier commented 3 months ago

Thanks for your answer! In the corresponding discussion #28201, Guillaume motivated to create this issue and wrote:

We'll have to change the code a little bit because we should allow this.

I really hope that this can be solved with little effort.

jmeier commented 3 months ago

It seems that the error I am experiencing is not primarily related to assigning shell elements to an inactive subdomain. I am therefore closing this issue as resolved. Below I have attached a test model which shows the moving of volume and shell elements with a TimedSubdomainModifier without generating an error.

If you want me to submit this test as a regression test for the TimedSubdomainModifier, please let me know.

test modell code

``` [GlobalParams] displacements = 'disp_x disp_y disp_z' use_displaced_mesh = false [] Box1_inactive_name = 'Box1_inactive' Box1Hull_LowerDElements_inactive_name = 'Box1Hull_LowerDElements_inactive' inactive_domain_block_names = '${Box1_inactive_name} ${Box1Hull_LowerDElements_inactive_name}' [Problem] solve = true kernel_coverage_check = SKIP_LIST kernel_coverage_block_list = '${inactive_domain_block_names}' material_coverage_check = SKIP_LIST material_coverage_block_list = '${inactive_domain_block_names}' [] [Mesh] [BaseMesh] type = GeneratedMeshGenerator subdomain_name = 'BaseMesh' elem_type = 'HEX8' dim = 3 nx = 6 ny = 6 nz = 2 xmin = -3 xmax = +3 ymin = -3 ymax = +3 zmin = -2 zmax = +2 [] [Box1] type = SubdomainBoundingBoxGenerator block_name = 'Box1' input = "BaseMesh" block_id = 1 location = "INSIDE" bottom_left = "-1.0 -1.0 -0" top_right = "+1.0 +1.0 +2" [] [Box1Hull_Sideset] type = SideSetsAroundSubdomainGenerator input = 'Box1' block = 'Box1' include_only_external_sides = true new_boundary = 'Box1Hull_Sideset' [] [Box1Hull_LowerDElements] type = LowerDBlockFromSidesetGenerator input = 'Box1Hull_Sideset' sidesets = 'Box1Hull_Sideset' new_block_name = 'Box1Hull_LowerDElements' [] add_subdomain_names = ${inactive_domain_block_names} [] [Physics] [SolidMechanics] [QuasiStatic] [all] strain = SMALL incremental = true add_variables = true generate_output = 'stress_xx stress_yy stress_zz' block = 'BaseMesh Box1' [] [] [] [] # ===== Kernels for Shell-Elements [Kernels] [shell_disp_x] type = ADStressDivergenceShell block = 'Box1Hull_LowerDElements' component = 0 variable = disp_x through_thickness_order = SECOND [] [shell_disp_y] type = ADStressDivergenceShell block = 'Box1Hull_LowerDElements' component = 1 variable = disp_y through_thickness_order = SECOND [] [shell_disp_z] type = ADStressDivergenceShell block = 'Box1Hull_LowerDElements' component = 2 variable = disp_z through_thickness_order = SECOND [] [shell_rot_x] type = ADStressDivergenceShell block = 'Box1Hull_LowerDElements' component = 3 variable = rot_x through_thickness_order = SECOND [] [shell_rot_y] type = ADStressDivergenceShell block = 'Box1Hull_LowerDElements' component = 4 variable = rot_y through_thickness_order = SECOND [] [] # ===== Dummy-Kernels for Inactive Domain ===== [Kernels] [./donothing1] type = MatDiffusion block = '${inactive_domain_block_names}' variable = disp_z diffusivity = 1e-7 [] [./donothing2] type = MatDiffusion block = '${inactive_domain_block_names}' variable = disp_x diffusivity = 1e-7 [] [./donothing3] type = MatDiffusion block = '${inactive_domain_block_names}' variable = disp_y diffusivity = 1e-7 [] [] [Variables] [./rot_x] order = FIRST family = LAGRANGE block = 'Box1Hull_LowerDElements' [] [./rot_y] order = FIRST family = LAGRANGE block = 'Box1Hull_LowerDElements' [] [] [AuxVariables] [dummy] type = MooseVariableFVReal [] [] # fix the lower model boundary in y and z direction [BCs] [./back_fix_y] type = DirichletBC variable = disp_y boundary = 'back' value = 0.0 [] [./back_fix_z] type = DirichletBC variable = disp_z boundary = 'back' value = 0.0 [] [] # fix the left mdoel boundary in x direction [BCs] [./left_fix_x] type = DirichletBC variable = disp_x boundary = 'left' value = 0.0 [] [] # put some pressure on the right model boundary [BCs] [./right_Dirichlet] type = FunctionDirichletBC variable = disp_x boundary = 'right' function = right_pressure_function [] [] [Functions] [right_pressure_function] type = ParsedFunction expression = '-0.001 * t' [] [] # Material: Volume Elements [Materials] [elasticity_tensor] type = ComputeIsotropicElasticityTensor block = 'BaseMesh Box1' youngs_modulus = 1e6 poissons_ratio = 0.25 [] [stress] type = ComputeFiniteStrainElasticStress block = 'BaseMesh Box1' [] [] # Material: Shell Elements [Materials] [shell_elasticity] type = ADComputeIsotropicElasticityTensorShell block = 'Box1Hull_LowerDElements' youngs_modulus = 1e9 poissons_ratio = 0.3 through_thickness_order = SECOND [] [shell_strain] type = ADComputeIncrementalShellStrain block = 'Box1Hull_LowerDElements' displacements = 'disp_x disp_y disp_z' rotations = 'rot_x rot_y' thickness = 1.0 through_thickness_order = SECOND [] [shell_stress] type = ADComputeShellStress block = 'Box1Hull_LowerDElements' through_thickness_order = SECOND [] [] # move elements between subdomains back and forth [UserObjects] [GlobalSubdomainModifier] type = TimedSubdomainModifier times = '0.2 0.4' blocks_from = 'Box1 Box1Hull_LowerDElements' blocks_to = 'Box1_inactive Box1Hull_LowerDElements_inactive' execute_on = 'INITIAL TIMESTEP_BEGIN' [] [] [Preconditioning] [.\SMP] type = SMP full = true [] [] [Executioner] type = Transient end_time = 1.0 dtmin = 0.001 [TimeSteppers] [BlockEventTimeStepper] type = TimeSequenceStepper time_sequence = '0.05 0.1 0.2 0.4 1.0' [] [] solve_type = 'PJFNK' petsc_options = '-snes_converged_reason' petsc_options_iname = '-pc_type -pc_factor_mat_solver_package' petsc_options_value = ' lu mumps' l_tol = 1E-10 l_max_its = 20 nl_abs_tol = 1E-10 nl_rel_tol = 1e-8 nl_max_its = 20 [] [Outputs] exodus = true [] ```

jmeier commented 2 months ago

Sorry, I have to re-open the issue. My last comment is now outdated as the code I give there is using [Physics/SolidMechanics/QuasiStatic].add_variables = true and in its current state this does not apply the block-restriction correctly (already addressed in #28307). Therefore, the disp-variables have been not block restricted and did not trigger the error.

As a first step: I would like to understand what the motivation behind this check is. Why is it checked whether variables are defined on both lower dimensional blocks and higher dimensional blocks if they are block-restricted?

https://github.com/idaholab/moose/blob/6271a40236eb166e603f72aadfe474b6c06786de/framework/src/variables/MooseVariableBase.C#L151-L156

A good counterexample are the disp variables, which should (often must?) be defined for all possible blocks. For which variables must this not be the case?

@GiudGiud, please allow me to tag you here as we had the initial discussion in #28201 and you also suggested to change this behaviour.

Edit: This seems to be commit this check had been introduced: https://github.com/idaholab/moose/commit/8d8d065125b4cafd53cc13f7b3261b36dd937003

GiudGiud commented 2 months ago

@lindsayad

I dont know why we ban variables to be both lower-D and higher-D

jmeier commented 2 months ago

Thanks to the marvelous explanaition of @roystgnr over there in libmesh it looks the error message might a bit misleading. Citing from https://github.com/libMesh/libmesh/discussions/3937:

But let me try to help anyway: looking into MooseMesh::cacheInfo(), where the data structure is being set, it looks like isLowerD() isn't returning what the name says ("is this lower-dimensional than the rest of the mesh"), it's trying to return what the Doxygen comment says ("do elements in this subdomain have interior_parent() values assigned"). By that definition, it can absolutely be correct for some blocks of beams to return true (because they're boundary elements of 2D or 3D elements) while others return false (because they're free-standing beams).

If I understand correctly, the check restricts having one and the same variable in blocks with interior_parent() values and without interior_parent() values assigned.

Depending on where this discussion goes, we should at least adapt the error message.

jmeier commented 1 month ago

Please allow me to come back to this issue: Would it be an option to propose an PR changing the mooseError to mooseWarning till the underlying issue is solved?

GiudGiud commented 1 month ago

Works for me. We should check in an example where it works, and try to identify the situations where it does not (block restriction to a block and to a lowerD block touching this block?) @lindsayad added this error in 12d2312462c I think

lindsayad commented 1 month ago

Yea I mean how would you evaluate the value of a monomial variable on a higher D face coincident with a lower-d element? There are two different sets of degrees of freedom to choose from

GiudGiud commented 1 month ago

we could have a new integrity check that makes sure this particular case does not happen? @jmeier are you avoiding this case in your case?

jmeier commented 1 month ago

Yea I mean how would you evaluate the value of a monomial variable on a higher D face coincident with a lower-d element? There are two different sets of degrees of freedom to choose from

I agree that we cannot mix lower-d-elements and higher-d-elements. So the error message is correct. But if I understand the explanation here correctly, Moose does not check if lower-d-elements are mixed with higher-d-elements. If I understand the explanation correctly, the function name _mesh.isLowerD() is a bit misleading - the function does not return if a subdomain is "lower-d" but "if elements in this subdomain have interior_parent() values assigned".

Please consider the susanne mesh shown below. Some of the "lineSignPole" beams are not connected to higher-d subdomains, others are. I'll get the error for them.

image

we could have a new integrity check that makes sure this particular case does not happen?

Yes we should. But I do not know how to detect compatible subdomains.

@jmeier are you avoiding this case in your case?

Yes, by only moving one type of elements into another empty subdomain.

lindsayad commented 1 month ago

I think we should change the implementation of isLowerD so that it matches the name better