Contact Verification

Overview

Finite element contact addresses the interaction of two surfaces that apply loads to one another.

Hertz Contact of Cylinder and Rigid Surface

The problem is an infinite cylinder in contact with a rigid plane. The problem is taken from Wang and Zhu (2013). See also Johnson (1985).

The analytic expressions for this problem rely on , the radius of a so-called equivalent cylinder.

where and are the radii of two cylinders in contact that have parallel axes. In our case, = 3, and is infinity. This gives = 3.

We also require : where and are Young's modulus and Poisson's ratio with subscripts representing each of the two bodies. In our case, = 1E6, = 0.3, = infinity, and = 0. This gives = 9.1E-7.

is the line load per unit length. We take this to be a pressure applied to the bottom half of the cylinder, 2E3, times . = 1.2E4.

The peak load, which occurs at the centerline of the cylinder, is with

This gives = 0.204 and = 37405. Bison computes as ~3.80E4, giving an error of 1.52%.

Figure 1: Contact traction for Hertz cylinder contact problem.

Input Syntax

#
# Hertz Contact of Cylinder and Rigid Surface
#   See https://doi.org/10.1007/978-0-387-92897-5_491
#
# 1/E* = (1-v1^2)/E1 + (1-v2^2)/E2
# v1 = 0.3
# E1 = 1e6
# v2 = 0
# E2 = infinity
# 1/E* = (1-0.09)/1e6 = 9.1e-7
# EstarInv = 9.1e-7
# 1/Re = (R1+R2)/R1/R2
# R1 = 3
# R2 = infinity
# 1/Re = 1/3
# Re = 3.0
# P = pressure at 0.1 seconds * 2*R1
# P = 2e3 * 6
# P = 1.2e4
#
# a is half width of contacting area
# a = sqrt(4 * P * Re / pi * EstarInv)
# a = 0.204
#
# Pmax = 2 * P / pi / a
# Pmax = 37405
#

[GlobalParams<<<{"href": "../../syntax/GlobalParams/index.html"}>>>]
  displacements = 'disp_x disp_y'
[]

[Mesh<<<{"href": "../../syntax/Mesh/index.html"}>>>]
  [input_file]
    type = FileMeshGenerator<<<{"description": "Read a mesh from a file.", "href": "../../source/meshgenerators/FileMeshGenerator.html"}>>>
    file<<<{"description": "The filename to read."}>>> = hertz_cyl_coarser.e
  []
  [secondary]
    type = LowerDBlockFromSidesetGenerator<<<{"description": "Adds lower dimensional elements on the specified sidesets.", "href": "../../source/meshgenerators/LowerDBlockFromSidesetGenerator.html"}>>>
    new_block_id<<<{"description": "The lower dimensional block id to create"}>>> = 10001
    new_block_name<<<{"description": "The lower dimensional block name to create (optional)"}>>> = 'secondary_lower'
    sidesets<<<{"description": "The sidesets from which to create the new block"}>>> = '3'
    input<<<{"description": "The mesh we want to modify"}>>> = input_file
  []
  [primary]
    type = LowerDBlockFromSidesetGenerator<<<{"description": "Adds lower dimensional elements on the specified sidesets.", "href": "../../source/meshgenerators/LowerDBlockFromSidesetGenerator.html"}>>>
    new_block_id<<<{"description": "The lower dimensional block id to create"}>>> = 10000
    sidesets<<<{"description": "The sidesets from which to create the new block"}>>> = '2'
    new_block_name<<<{"description": "The lower dimensional block name to create (optional)"}>>> = 'primary_lower'
    input<<<{"description": "The mesh we want to modify"}>>> = secondary
  []
[]

[Problem<<<{"href": "../../syntax/Problem/index.html"}>>>]
  type = ReferenceResidualProblem
  extra_tag_vectors = 'ref'
  reference_vector = 'ref'
[]

[Variables<<<{"href": "../../syntax/Variables/index.html"}>>>]
  [disp_x]
  []
  [disp_y]
    initial_condition<<<{"description": "Specifies a constant initial condition for this variable"}>>> = -0.01
  []
  [frictionless_normal_lm]
    order<<<{"description": "Specifies the order of the FE shape function to use for this variable (additional orders not listed are allowed)"}>>> = FIRST
    family<<<{"description": "Specifies the family of FE shape functions to use for this variable"}>>> = LAGRANGE
    block = 'secondary_lower'
    use_dual = true
  []
[]

[AuxVariables<<<{"href": "../../syntax/AuxVariables/index.html"}>>>]
  [saved_x]
  []
  [saved_y]
  []
[]

[Functions<<<{"href": "../../syntax/Functions/index.html"}>>>]
  [pressure_function]
    type = PiecewiseLinear<<<{"description": "Linearly interpolates between pairs of x-y data", "href": "../../source/functions/PiecewiseLinear.html"}>>>
    x<<<{"description": "The abscissa values"}>>> = '0. 1. 3.5'
    y<<<{"description": "The ordinate values"}>>> = '0. 2e4 2e4'
  []
  [analytic]
    type = ParsedFunction<<<{"description": "Function created by parsing a string", "href": "../../source/functions/MooseParsedFunction.html"}>>>
    symbol_names<<<{"description": "Symbols (excluding t,x,y,z) that are bound to the values provided by the corresponding items in the vals vector."}>>> = 'EstarInv Re width P'
    symbol_values<<<{"description": "Constant numeric values, postprocessor names, function names, and scalar variables corresponding to the symbols in symbol_names."}>>> = '9.1e-7 3.0 6 pressure_function'
    expression<<<{"description": "The user defined function."}>>> = '2 * P*width / pi / sqrt(4 * P*width * Re / pi * EstarInv)'
  []
[]

[Physics<<<{"href": "../../syntax/Physics/index.html"}>>>/SolidMechanics<<<{"href": "../../syntax/Physics/SolidMechanics/index.html"}>>>/QuasiStatic<<<{"href": "../../syntax/Physics/SolidMechanics/QuasiStatic/index.html"}>>>]
  [fred]
    block<<<{"description": "The list of ids of the blocks (subdomain) that the stress divergence kernels will be applied to"}>>> = '1 2 3 4 5 6 7'
    strain<<<{"description": "Strain formulation"}>>> = finite
    save_in<<<{"description": "The displacement residuals"}>>> = 'saved_x saved_y'
    extra_vector_tags<<<{"description": "The tag names for extra vectors that residual data should be saved into"}>>> = 'ref'
    generate_output<<<{"description": "Add scalar quantity output for stress and/or strain"}>>> = 'stress_xx stress_yy stress_xy'
  []
[]

[Postprocessors<<<{"href": "../../syntax/Postprocessors/index.html"}>>>]
  [traction_applied]
    type = NodalSum<<<{"description": "Computes the sum of all of the nodal values of the specified variable. Note: This object sets the default \"unique_node_execute\" flag to true to avoid double counting nodes between shared blocks.", "href": "../../source/postprocessors/NodalSum.html"}>>>
    variable<<<{"description": "The name of the variable that this postprocessor operates on"}>>> = saved_y
    boundary<<<{"description": "The list of boundaries (ids or names) from the mesh where this object applies"}>>> = 4
  []
  [_dt]
    type = TimestepSize<<<{"description": "Reports the timestep size", "href": "../../source/postprocessors/TimestepSize.html"}>>>
  []
  [bison_peak_traction]
    type = NodalExtremeValue<<<{"description": "Finds either the min or max elemental value of a variable over the domain.", "href": "../../source/postprocessors/NodalExtremeValue.html"}>>>
    boundary<<<{"description": "The list of boundaries (ids or names) from the mesh where this object applies"}>>> = 3
    variable<<<{"description": "The name of the variable that this postprocessor operates on"}>>> = frictionless_normal_lm
  []
  [analytical_peak_traction]
    type = FunctionValuePostprocessor<<<{"description": "Computes the value of a supplied function at a single point (scalable)", "href": "../../source/postprocessors/FunctionValuePostprocessor.html"}>>>
    function<<<{"description": "The function which supplies the postprocessor value."}>>> = analytic
  []
  [error]
    type = ParsedPostprocessor<<<{"description": "Computes a parsed expression with post-processors", "href": "../../source/postprocessors/ParsedPostprocessor.html"}>>>
    pp_names<<<{"description": "Post-processors arguments"}>>> = 'bison_peak_traction analytical_peak_traction'
    expression<<<{"description": "function expression"}>>> = '(bison_peak_traction-analytical_peak_traction)/analytical_peak_traction*100'
  []
[]

[BCs<<<{"href": "../../syntax/NuclearMaterials/BCs/index.html"}>>>]
  [base_x]
    type = DirichletBC<<<{"description": "Imposes the essential boundary condition $u=g$, where $g$ is a constant, controllable value.", "href": "../../source/bcs/DirichletBC.html"}>>>
    variable<<<{"description": "The name of the variable that this residual object operates on"}>>> = disp_x
    boundary<<<{"description": "The list of boundary IDs from the mesh where this object applies"}>>> = '1 2'
    value<<<{"description": "Value of the BC"}>>> = 0.0
  []
  [base_y]
    type = DirichletBC<<<{"description": "Imposes the essential boundary condition $u=g$, where $g$ is a constant, controllable value.", "href": "../../source/bcs/DirichletBC.html"}>>>
    variable<<<{"description": "The name of the variable that this residual object operates on"}>>> = disp_y
    boundary<<<{"description": "The list of boundary IDs from the mesh where this object applies"}>>> = '1 2'
    value<<<{"description": "Value of the BC"}>>> = 0.0
  []
  [Pressure<<<{"href": "../../syntax/BCs/Pressure/index.html"}>>>]
    [pressure]
      boundary<<<{"description": "The list of boundaries (ids or names) from the mesh where this object applies"}>>> = 4
      function<<<{"description": "The function that describes the pressure"}>>> = pressure_function
      use_displaced_mesh<<<{"description": "Whether or not this object should use the displaced mesh for computation. Note that in the case this is true but no displacements are provided in the Mesh block the undisplaced mesh will still be used. For small strain formulations pressure should be applied to the undisplaced mesh to obtain agreement with analytical benchmark solutions."}>>> = false
    []
  []
[]

[Materials<<<{"href": "../../syntax/Materials/index.html"}>>>]
  [elas_tens]
    type = ComputeIsotropicElasticityTensor<<<{"description": "Compute a constant isotropic elasticity tensor.", "href": "../../source/materials/ComputeIsotropicElasticityTensor.html"}>>>
    block<<<{"description": "The list of blocks (ids or names) that this object will be applied"}>>> = '1 2 3 4 5 6 7'
    youngs_modulus<<<{"description": "Young's modulus of the material."}>>> = 1e6
    poissons_ratio<<<{"description": "Poisson's ratio for the material."}>>> = 0.3
  []
  [stress]
    type = ComputeFiniteStrainElasticStress<<<{"description": "Compute stress using elasticity for finite strains", "href": "../../source/materials/ComputeFiniteStrainElasticStress.html"}>>>
    block<<<{"description": "The list of blocks (ids or names) that this object will be applied"}>>> = '1 2 3 4 5 6 7'
  []
[]

[Executioner<<<{"href": "../../syntax/Executioner/index.html"}>>>]
  type = Transient
  solve_type = 'PJFNK'

  petsc_options = '-snes_ksp_ew'
  petsc_options_iname = '-pc_type -pc_factor_mat_solver_type -pc_factor_shift_type -pc_factor_shift_amount -mat_mffd_err'
  petsc_options_value = 'lu       superlu_dist               NONZERO               1e-15                   1e-5'

  line_search = 'none'

  nl_abs_tol = 1e-7

  start_time = 0.0
  end_time = 0.1
  l_tol = 1e-4
  dt = 0.1
  dtmin = 0.1

  [Predictor<<<{"href": "../../syntax/Executioner/Predictor/index.html"}>>>]
    type = SimplePredictor
    scale = 1.0
  []
[]

[Preconditioning<<<{"href": "../../syntax/Preconditioning/index.html"}>>>]
  [SMP]
    type = SMP<<<{"description": "Single matrix preconditioner (SMP) builds a preconditioner using user defined off-diagonal parts of the Jacobian.", "href": "../../source/preconditioners/SingleMatrixPreconditioner.html"}>>>
    full<<<{"description": "Set to true if you want the full set of couplings between variables simply for convenience so you don't have to set every off_diag_row and off_diag_column combination."}>>> = true
  []
[]

[VectorPostprocessors<<<{"href": "../../syntax/VectorPostprocessors/index.html"}>>>]
  [cont_press]
    type = NodalValueSampler<<<{"description": "Samples values of nodal variable(s).", "href": "../../source/vectorpostprocessors/NodalValueSampler.html"}>>>
    variable<<<{"description": "The names of the variables that this VectorPostprocessor operates on"}>>> = frictionless_normal_lm
    boundary<<<{"description": "The list of boundaries (ids or names) from the mesh where this object applies"}>>> = '3'
    sort_by<<<{"description": "What to sort the samples by"}>>> = id
  []
[]

[Outputs<<<{"href": "../../syntax/Outputs/index.html"}>>>]
  print_linear_residuals<<<{"description": "Enable printing of linear residuals to the screen (Console)"}>>> = true
  exodus<<<{"description": "Output the results using the default settings for Exodus output."}>>> = true
  csv<<<{"description": "Output the scalar variable and postprocessors to a *.csv file using the default CSV output."}>>> = true
  [console]
    type = Console<<<{"description": "Object for screen output.", "href": "../../source/outputs/Console.html"}>>>
    max_rows<<<{"description": "The maximum number of postprocessor/scalar values displayed on screen during a timestep (set to 0 for unlimited)"}>>> = 5
  []
  [csv1]
    type = CSV<<<{"description": "Output for postprocessors, vector postprocessors, and scalar variables using comma seperated values (CSV).", "href": "../../source/outputs/CSV.html"}>>>
    show<<<{"description": "A list of the variables and postprocessors that should be output to the Exodus file (may include Variables, ScalarVariables, and Postprocessor names)."}>>> = 'cont_press'
    file_base<<<{"description": "The desired solution output name without an extension. If not provided, MOOSE sets it with Outputs/file_base when available. Otherwise, MOOSE uses input file name and this object name for a master input or uses master file_base, the subapp name and this object name for a subapp input to set it."}>>> = cylinder_frictionless
  []
[]

[UserObjects<<<{"href": "../../syntax/UserObjects/index.html"}>>>]
  [weighted_vel_uo]
    type = LMWeightedGapUserObject<<<{"description": "Provides the mortar normal Lagrange multiplier for constraint enforcement.", "href": "../../source/userobjects/LMWeightedGapUserObject.html"}>>>
    primary_boundary<<<{"description": "The name of the primary boundary sideset."}>>> = 2
    secondary_boundary<<<{"description": "The name of the secondary boundary sideset."}>>> = 3
    primary_subdomain<<<{"description": "The name of the primary subdomain."}>>> = 10000
    secondary_subdomain<<<{"description": "The name of the secondary subdomain."}>>> = 10001
    disp_x<<<{"description": "The x displacement variable"}>>> = disp_x
    disp_y<<<{"description": "The y displacement variable"}>>> = disp_y
    lm_variable<<<{"description": "The Lagrange multiplier variable representing the contact pressure."}>>> = frictionless_normal_lm
  []
[]

[Constraints<<<{"href": "../../syntax/Constraints/index.html"}>>>]
  [weighted_gap_lm]
    type = ComputeWeightedGapLMMechanicalContact<<<{"description": "Computes the weighted gap that will later be used to enforce the zero-penetration mechanical contact conditions", "href": "../../source/constraints/ComputeWeightedGapLMMechanicalContact.html"}>>>
    primary_boundary<<<{"description": "The name of the primary boundary sideset."}>>> = 2
    secondary_boundary<<<{"description": "The name of the secondary boundary sideset."}>>> = 3
    primary_subdomain<<<{"description": "The name of the primary subdomain."}>>> = 10000
    secondary_subdomain<<<{"description": "The name of the secondary subdomain."}>>> = 10001
    variable<<<{"description": "The name of the lagrange multiplier variable that this constraint is applied to. This parameter may not be supplied in the case of using penalty methods for example"}>>> = frictionless_normal_lm
    disp_x<<<{"description": "The x displacement variable"}>>> = disp_x
    disp_y<<<{"description": "The y displacement variable"}>>> = disp_y
    use_displaced_mesh<<<{"description": "Whether or not this object should use the displaced mesh for computation.  Note that in the case this is true but no displacements are provided in the Mesh block the undisplaced mesh will still be used."}>>> = true
    c<<<{"description": "Parameter for balancing the size of the gap and contact pressure"}>>> = 1.0e6
    weighted_gap_uo<<<{"description": "The weighted gap user object"}>>> = weighted_vel_uo
  []
  [x]
    type = NormalMortarMechanicalContact<<<{"description": "This class is used to apply normal contact forces using lagrange multipliers", "href": "../../source/constraints/NormalMortarMechanicalContact.html"}>>>
    primary_boundary<<<{"description": "The name of the primary boundary sideset."}>>> = '2'
    secondary_boundary<<<{"description": "The name of the secondary boundary sideset."}>>> = '3'
    primary_subdomain<<<{"description": "The name of the primary subdomain."}>>> = '10000'
    secondary_subdomain<<<{"description": "The name of the secondary subdomain."}>>> = '10001'
    variable<<<{"description": "The name of the lagrange multiplier variable that this constraint is applied to. This parameter may not be supplied in the case of using penalty methods for example"}>>> = frictionless_normal_lm
    secondary_variable<<<{"description": "Primal variable on secondary surface."}>>> = disp_x
    component<<<{"description": "The force component constraint that this object is supplying"}>>> = x
    use_displaced_mesh<<<{"description": "Whether or not this object should use the displaced mesh for computation.  Note that in the case this is true but no displacements are provided in the Mesh block the undisplaced mesh will still be used."}>>> = true
    compute_lm_residuals<<<{"description": "Whether to compute Lagrange Multiplier residuals"}>>> = false
    weighted_gap_uo<<<{"description": "The weighted gap user object."}>>> = weighted_vel_uo
  []
  [y]
    type = NormalMortarMechanicalContact<<<{"description": "This class is used to apply normal contact forces using lagrange multipliers", "href": "../../source/constraints/NormalMortarMechanicalContact.html"}>>>
    primary_boundary<<<{"description": "The name of the primary boundary sideset."}>>> = '2'
    secondary_boundary<<<{"description": "The name of the secondary boundary sideset."}>>> = '3'
    primary_subdomain<<<{"description": "The name of the primary subdomain."}>>> = '10000'
    secondary_subdomain<<<{"description": "The name of the secondary subdomain."}>>> = '10001'
    variable<<<{"description": "The name of the lagrange multiplier variable that this constraint is applied to. This parameter may not be supplied in the case of using penalty methods for example"}>>> = frictionless_normal_lm
    secondary_variable<<<{"description": "Primal variable on secondary surface."}>>> = disp_y
    component<<<{"description": "The force component constraint that this object is supplying"}>>> = y
    use_displaced_mesh<<<{"description": "Whether or not this object should use the displaced mesh for computation.  Note that in the case this is true but no displacements are provided in the Mesh block the undisplaced mesh will still be used."}>>> = true
    compute_lm_residuals<<<{"description": "Whether to compute Lagrange Multiplier residuals"}>>> = false
    weighted_gap_uo<<<{"description": "The weighted gap user object."}>>> = weighted_vel_uo
  []
[]
(assessment/verification/Contact/hertz/cylinder_frictionless_pressure.i)

References

  1. K. L. Johnson. Contact Mechanics. Cambridge University Press, 1985. doi:10.1017/CBO9781139171731.[BibTeX]
  2. Q. Jane Wang and Dong Zhu. Hertz Theory: Contact of Cylindrical Surfaces, pages 1639–1647. Springer US, Boston, MA, 2013. doi:10.1007/978-0-387-92897-5_491.[BibTeX]