The 2D domain used in the tutorial, where we only mesh one fourth by exploiting symmetry

One of the major uses of solid mechanics is to investigate the stresses experienced by an object during operation, including normal and unusual conditions. One of the major strengths of FEM, is that it can represent even complicated geometry, given a suitable mesh. The MOOSE framework is not a meshing tool, and only generates simple meshes for simple geometries, such as rectangles and blocks. Therefore, the mesh must be generated using some other tool such as Cubit.

In this problem we will model a the 2D body shown on the right. To reduce the computational expense, we exploit symmetry and only represent one fourth of the body, as shown in the figure. The mesh file can be found in the tutorial directory. We will begin modeling the 2D deformation of the trapezoid assuming small strains and linear elasticity. To run a MOOSE simulation, we must construct various required elements for the simulation, either in an input file or using peacock.

Creating the input file

Variables and the GlobalParams block

In the tensor_mechanics module we used displacements as the variables for the FEM simulation. Instead of creating a vector of displacements in MOOSE, we treat each displacement variable as a separate scalar: in 2D the two displacement variables are disp_x and disp_y.

We tell MOOSE the name of the displacement variables as the argument to the parameter displacements in the GlobalParams block. At the top of the input file, create the block:

  displacements = 'disp_x disp_y'

We use the GlobalParams block so that the displacements parameter can be used by multiple blocks within the input file. In this input file, the displacements parameter will be used automatically in the mesh, stress divergence, and strain sections of the input file.

Mesh block

To read in the mesh file, create a mesh block that looks like this:

  file = necking_quad4.e

To learn more about the Mesh block, look here.

Stress Divergence an in the Tensor Mechanics Master Action

The tensor mechanics master action automatically creates the variables, stress divergence kernel, and the strain calculator. The master action uses the number of displacement variables given in the displacements parameter, the mesh dimension and order, and the problem coordinate system to correctly select, the stress divergence kernels, the strain formulations, and the displacement variable shape functions for the input file.

The strain options include SMALL for small linearized strain and FINITE for incremental, history dependent, large strain. Using the add_variables option will set up the individual MOOSE variables for displacements with the correct shape functions.

Add the syntax for the tensor mechanics master action to the input file. Note the difference in the name of the master action block compared to the other block names in this input file; this difference denotes an action in MOOSE.

    strain = SMALL
    add_variables = true

The Tensor Mechanics Master Action automatically creates the stress divergence residual for all displacement variables. For more information about the Kernels block, look here.

Each variable is defined with a shape function family and order. The master action uses information about order of the mesh to automatically set the family and order for the variable shape functions. In this problem we are using the default: family = lagrange and order = first. To learn more about variables in MOOSE, look here.

Materials block

The stress divergence kernels require a rank 2 tensor material property be created that contains the stress. To calculate the stress we must add at least two materials blocks. The first defines the elasticity tensor that relates the elastic strain to the stress, and the second computes the stress. Recall that the strain calculator is defined as part of the master action, where we set assumptions for small deformations and linear elasticity.

    type = ComputeIsotropicElasticityTensor
    youngs_modulus = 2.1e5
    poissons_ratio = 0.3
    type = ComputeLinearElasticStress

For more information about the Materials block, look here. To learn more about tensor mechanics materials, look here.

BCs block

Now that we have set up our mesh, the variables we want to solve for, and all the information needed to define the residual equations, we need to define the boundary conditions (BCs) on our domain. In our problem we will fix the x-displacement on the left side of the trapezoid, fix the y-displacement on the right side of the trapezoid, and apply a fixed displacement equal to 0.0035 on the top side.

    type = PresetBC
    variable = disp_x
    boundary = left
    value = 0.0
    type = PresetBC
    variable = disp_y
    boundary = bottom
    value = 0.0
    type = PresetBC
    variable = disp_y
    boundary = top
    value = 0.0035

For more information about the BCs block, look here.

Preconditioning block

In MOOSE, the nonlinear partial differential equations can be solved either using Newton's method or the Jacobian Free Newton Krylov method (JFNK). For Newton's method, the full Jacobian matrix is required (look here to learn more about the Jacobian matrix). However, by default MOOSE only creates the on-diagonal blocks for multiple variable systems. Therefore, we tell MOOSE to create the entire Jacobian using the Preconditioning block.

    type = SMP
    full = true

When using JFNK, the Jacobian is used to precondition the solve, and therefore having the full Jacobian is not required for JFNK but can often improve the solve. For more information about the Preconditioning block, look here.

Executioner block

We tell MOOSE how we want to solve the system using the executioner block. In this problem we will do a steady state solve with Newton's method. There are two types of iterations used in the solve. The linear iterations are used to multiple the inverse of the Jacobian for a Newton solve and they are used to apply the preconditioner when using JFNK. The nonlinear iterations are used to converge to the solution. Both sets of iterations have a relative tolerance, which defines how far the residual value must drop for the solve to stop. Here we will use the default numerical tolerances (these are l_tol = 1e-5 and nl_rel_tol = 1e-9, for reference). The actually solve is conducted using the PetSc package, therefore we need to tell PetSc how to solve the system. In this case we will use the additive Schwartz method (ASM) (and LU decomposition of the subblocks) in parallel but LU decomposition for a singe processor solve. The petsc options shown below work well for most mechanics problems.

  type = Steady

  solve_type = 'NEWTON'

  petsc_options = -snes_ksp_ew
  petsc_options_iname = '-pc_type -sub_pc_type -pc_asm_overlap -ksp_gmres_restart'
  petsc_options_value = 'asm lu 1 101'

For more information about the Executioner block, look here.

Outputs block

We need to output our results, and we will use the Exodus file format. We will also output a performance log telling us information about how long the different parts of the problem took.

  exodus = true
  print_perf_log = true

For more information about the Outputs block, look here.

Running the Simulation

Now that we have completed the input file, we can run the simulation. If you would like to check your input file, look at the input file part_1.1.i in the tutorials directory. This can be run from the command line using the command

~/EXECUTABLE_PATH/tensor_mechanics-opt -i INPUT_FILE_NAME.i

or you can run it in PEACOCK. The domain will deform slightly upward and the x- and y-displacements should look like this:

x-displacements for linear elasticity

y-displacements for linear elasticity

Refining the Mesh

Our mesh is fairly coarse, which will hurt the accuracy of our simulation. Rather than generate a new mesh file that has a finer mesh, it is easy to refine the mesh in MOOSE. You simply add the parameter uniform_refine = N, where N is the number of refinements. To improve our solution, add to the mesh block

uniform_refine = 1

Visualizing Tensor Fields

It is often helpful to visualize tensor fields across our domain, such as the stress or the strain. To do this, we use AuxVariables, which are dependent variables that are calculated throughout a simulation. The values for these AuxVariables are calculated by corresponding AuxKernels.

Rather than adding two more blocks to the input file, we will use the tensor mechanics master action to generate both the xx component of the total stress tensor and the scalar vonMises stress quantity. Add the single line to the tensor mechanics master action:

    generate_output = 'stress_xx vonmises_stress'

Now, run the simulation again. You can compare your file against part_1.2.i. The stress fields should look like this:

XX component of the stress for linear elasticity

Von Mises stress for linear elasticity

Look at the documentation for more information about AuxVariables and AuxKernels.

Part 2: 2D Axisymmetric Simulation