Step 2 - Mortar Contact

Mortar based mechanical contact is a fairly recent addition to MOOSE. While it offers benefits such as tighter convergence and better enforcement of contact constraints as well as a better solution quality for contact interface quantities like the contact pressure, it is not quite as mature as the node on face contact used in the previous step.

Mortar based contact for 3D problems is currently in an experimental stage. Edge to edge contact and edge dropping are not fully implemented and can lead to artifacts at sharp transitions form in-contact to out of contact.

#
# Switching to mortar based mechanical contact
# https://mooseframework.inl.gov/modules/contact/tutorials/introduction/step02.html
#

[GlobalParams]
  displacements = 'disp_x disp_y'
  block = 0
[]

[Mesh]
  [generated1]
    type = GeneratedMeshGenerator
    dim = 2
    nx = 5
    ny = 15
    xmin = -0.6
    xmax = -0.1
    ymax = 5
    bias_y = 0.9
    boundary_name_prefix = pillar1
  []
  [generated2]
    type = GeneratedMeshGenerator
    dim = 2
    nx = 5
    ny = 15
    xmin = 0.1
    xmax = 0.6
    ymax = 5
    bias_y = 0.9
    boundary_name_prefix = pillar2
    boundary_id_offset = 4
  []
  [collect_meshes]
    type = MeshCollectionGenerator
    inputs = 'generated1 generated2'
  []

  patch_update_strategy = iteration
[]

[Physics/SolidMechanics/QuasiStatic]
  [all]
    add_variables = true
    strain = FINITE
    generate_output = 'vonmises_stress'
  []
[]

[Contact]
  [pillars]
    primary = pillar1_right
    secondary = pillar2_left
    model = frictionless
    formulation = mortar
    correct_edge_dropping = true
  []
[]

[BCs]
  [bottom_x]
    type = DirichletBC
    variable = disp_x
    boundary = 'pillar1_bottom pillar2_bottom'
    value = 0
  []
  [bottom_y]
    type = DirichletBC
    variable = disp_y
    boundary = 'pillar1_bottom pillar2_bottom'
    value = 0
  []
  [Pressure]
    [sides]
      boundary = 'pillar1_left pillar2_right'
      # we square time here to get a more progressive loading curve
      # (more pressure later on once contact is established)
      function = 1e4*t^2
    []
  []
[]

[Materials]
  [elasticity]
    type = ComputeIsotropicElasticityTensor
    youngs_modulus = 1e9
    poissons_ratio = 0.3
  []
  [stress]
    type = ComputeFiniteStrainElasticStress
  []
[]

[Executioner]
  type = Transient
  solve_type = NEWTON
  line_search = none
  petsc_options_iname = '-pc_type -pc_factor_shift_type'
  petsc_options_value = 'lu       NONZERO'
  end_time = 5
  dt = 0.5
  [Predictor]
    type = SimplePredictor
    scale = 1
  []
[]

[Outputs]
  exodus = true
  print_linear_residuals = false
  perf_graph = true
[]
(modules/contact/tutorials/introduction/step02.i)

Here we show the steps for migrating a node on face contact problem (the penalty based contact problem from the previous step) to a mortar formulation. Most of the extra work is performed by the Contact action.

MOOSE's mortar based contact uses Lagrange multipliers for the enforcement of the contact constraints. These Lagrange multipliers are additional solution variables (added by the Contact action) that live on lower dimensional subdomains along the contact interfaces.

The Contact action automatically adds these lower dimensional subdomains, but now that they exist in the simulation we have to be careful not to add any physics on them beyond the Lagrange multipliers. This means we have to add block restrictions for all our kernels, materials, and variables to only add them to the volume subdomains.

Input file

GlobalParams

We add block = 0 here to make sure all block restrictable objects explicitly listed in the input (and not generated by actions) are by default restricted to subdomain 0 (the two cantilever volumes) and not unrestricted (meaning they would also live on the lower dimensional meshes).

Try removing those lines to see what happens. Running mechanics on the lower dimensional subdomains will introduce an unphysical artificial stiffness and will change the results significantly.

Besides the added block restriction we only change the Contact block.

Contact

We change the "formulation" to mortar and remove the "penalty" and "normalize_penalty" parameters. They have no function in mortar contact.

Tasks and questions

Penetration

Let's look at the penetration variable again:

Visualize the penetration variable. You may have to rescale the visualization to start the color scale at 0. Negative penetrations are not of interest here (they effectively are the gap width)

You should see a maximum interpenetration of about 5.1e-9. That's quite an improvement compared to penalty contact!

Contact pressure

Note that the contact_pressure variable is added but not used with the mortar formulation. The physical meaning of the Lagrange multiplier is the normal contact pressure.

Visualize the contact pressure by plotting the pillars_normal_lm variable.

Extracting contact pressure data

To get a better picture of the contact pressure distribution along a contact surface it can be helpful to create a line plot of the pressure.

Look at the NodalValueSamplervectorpostprocessor and see if you can use its "block" parameter to output the pillars_normal_lm variable on the pillars_secondary_subdomain subdomain.

Click here for the answer.

Once you've answered the questions and run this example we will move on to add thermal transport and later on thermal contact. You will need to build the combined-opt executable to follow along.