Step 3a - Thermal expansion

In this sidebar we'll introduce a thermal expansion eigenstrain. To demonstrate the effect we reshape the domain from step 3 and make it narrow like a cantilever.

#
# Added subdomains and subdomain-specific properties
# https://mooseframework.inl.gov/modules/tensor_mechanics/tutorials/introduction/step03.html
#

[GlobalParams]
  displacements = 'disp_x disp_y'
[]

[Mesh]
  [generated]
    type = GeneratedMeshGenerator
    dim = 2
    nx = 10
    ny = 20
    xmin = -0.25
    xmax = 0.25
    ymax = 5
  []
  [block1]
    type = SubdomainBoundingBoxGenerator
    input = generated
    block_id = 1
    bottom_left = '-0.25 0 0'
    top_right = '0 5 0'
  []
  [block2]
    type = SubdomainBoundingBoxGenerator
    input = block1
    block_id = 2
    bottom_left = '0 0 0'
    top_right = '0.25 5 0'
  []

  # select a single node in the center of the bottom boundary
  [pin]
    type = ExtraNodesetGenerator
    input = block2
    new_boundary = pin
    coord = '0 0 0'
  []
[]

[AuxVariables]
  [T]
  []
[]

[AuxKernels]
  [temperature_ramp]
    type = FunctionAux
    execute_on = TIMESTEP_BEGIN
    variable = T
    function = 300+5*t
  []
[]

[Modules/TensorMechanics/Master]
  [all]
    add_variables = true
    automatic_eigenstrain_names = true
    generate_output = 'vonmises_stress'
  []
[]

[BCs]
  [pin_x]
    type = DirichletBC
    variable = disp_x
    boundary = pin
    value = 0
  []
  [bottom_y]
    type = DirichletBC
    variable = disp_y
    boundary = bottom
    value = 0
  []
[]

[Materials]
  [elasticity]
    type = ComputeIsotropicElasticityTensor
    youngs_modulus = 1e9
    poissons_ratio = 0.3
  []
  [expansion1]
    type = ComputeThermalExpansionEigenstrain
    temperature = T
    thermal_expansion_coeff = 0.001
    stress_free_temperature = 300
    eigenstrain_name = thermal_expansion
    block = 1
  []
  [expansion2]
    type = ComputeThermalExpansionEigenstrain
    temperature = T
    thermal_expansion_coeff = 0.002
    stress_free_temperature = 300
    eigenstrain_name = thermal_expansion
    block = 2
  []
  [stress]
    type = ComputeLinearElasticStress
  []
[]

[Executioner]
  type = Transient
  solve_type = NEWTON
  petsc_options_iname = '-pc_type'
  petsc_options_value = 'lu'
  end_time = 5
  dt = 1
[]

[Outputs]
  exodus = true
[]
(moose/modules/tensor_mechanics/tutorials/introduction/mech_step03a.i)

Input file

Mesh

Note the xmin and xmax upper and lower x-dimension extents are supplied here. The origin will lie in the center of the bottom boundary of this generated mesh.

New is the ExtraNodesetGenerator which we append to the existing chain of mesh generators. This generator allows us to create a new nodeset containing all nodes located at the coordinates the user specified in "coord". Here we create a nodeset containing the single node at the origin. You need to make sure that a node actually exists at each specified coordinate! We call this nodeset pin for obvious reasons and will use it below in the BCs.

AuxVariables

We introduce a new auxiliary variable T (for temperature). Auxiliary variables are variables we're not solving for, but are computing directly. To simplify this step we are not solving a heat conduction problem, but instead just prescribing a global temperature that is rising with time (see next section). Auxiliary variables can be coupled in everywhere regular (so called nonlinear) variables are coupled. They are a great tool for simplifying a model during development.

AuxKernels

The FunctionAux AuxKernel can set an AuxVariable to a function of space and time. Note the "execute_on" parameter that is available in many MOOSE systems. Here we skip execution during LINEAR and NON_LINEAR iterations and only update the variable value at the beginning of the timestep.

TensorMechanics Master Action

We've added the "automatic_eigenstrain_names" parameter to the master action. With this option enabled the master action will try to automatically detect all material objects that provide eigenstrain properties. This works well for most scenarios. Note that MOOSE will print a list of detected eigenstrain names very early in its console output. Look for


*** Automatic Eigenstrain Names ***
all: thermal_expansion

when you run this example. Here all is the master action block name and thermal_expansion is the "eigenstrain_name" parameter value for the two eigenstrain materials below. The action correctly detected it and verified that eigenstrains are provided on all subdomains covered by the master action block. To manually supply the eigenstrain material properties use the "eigenstrain_names" parameter. Like so


[Modules/TensorMechanics/Master]
  [all]
    add_variables = true
    eigenstrain_names = 'thermal_expansion'
    generate_output = 'vonmises_stress'
  []
[]

BCs

We have changed the way we apply the boundary condition on the x displacement variable disp_x to only constrain this variable at the pin "boundary". Above we defined this boundary as the nodeset containing the single node at (0,0,0).

Pinning at a single point is less restrictive and allows the model to expand in x-direction along the bottom boundary (which will happen due to isotropic thermal expansion). Yet we still remove all rigid body modes

  • Translation, because we fix both x and y displacement on at least one node

  • Rotation, because we fix y displacement on another node (actually on all nodes along the bottom boundary)

Pinning nodes to remove rigid body modes is an important tool to create mechanics simulations that converge. The presence of rigid body modes will lead to non-convergence**. BCs on single nodes rather than whole boundaries can help avoid overconstraining your problems. Keep in mind that to remove all 6 rigid body modes in a 3D simulation you need to apply BCs on at least 3 nodes (which cannot be co-linear). One node will have to be constrained in 3 direction, one in 2 and one in just one direction. The first node will remove three translation modes. The second node will remove two rotational modes (and will establish an axis of rotation). The third node will remove that final rotational mode.

Materials

An "Eigenstrain" in MOOSE is a stress free strain. It is an intrinsic shape change of a volume element due to effects like thermal expansion, swelling, diffusion of over/undersized solutes, etc.

We use two ComputeThermalExpansionEigenstrain objects to compute an eigenstrain tensor in each of the two subdomains. The "stress_free_temperature" is set to 300K, which is the initial temperature set for the T AuxVariable. At this temperature we assume the eigenstrain to be zero (with contraction at temperatures lower than 300K and expansion above). The "thermal_expansion_coeff" is chosen differently on the two subdomains. This effectively models a bimetallic strip.

Questions

Expected outcome

Think about what you expect to happen when you run the input.

Click here for the answer.

Overconstraining

Apply the disp_x boundary condition to the entire bottom surface again and observe what happens. Undo that change before you move on to the next question.

Click here for the answer.

Constraining even less

In the original input we're fixing the y displacement to 0 in the entire bottom boundary. Try to relax this constraint a bit try to add a second single node boundary using the ExtraNodesetGenerator (chained in after the pin generator). Use one of the two bottom corner nodes. Now think about where you have to apply the disp_y != 0 boundary condition.

Click here for the answer.

Once you've answered the questions and run this example we will move on to Step 4 and setup a cantilever problem that prepares us for contact.