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.
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
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:
[GlobalParams] 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.
To read in the mesh file, create a mesh block that looks like this:
[Mesh] file = necking_quad4.e 
To learn more about the
Mesh block, look here.
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.
[Modules/TensorMechanics/Master] [./block1] 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.
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.
[Materials] [./elasticity_tensor] type = ComputeIsotropicElasticityTensor youngs_modulus = 2.1e5 poissons_ratio = 0.3 [../] [./stress] type = ComputeLinearElasticStress [../] 
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.
[BCs] [./left] type = PresetBC variable = disp_x boundary = left value = 0.0 [../] [./bottom] type = PresetBC variable = disp_y boundary = bottom value = 0.0 [../] [./top] type = PresetBC variable = disp_y boundary = top value = 0.0035 [../] 
For more information about the
BCs block, look here.
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] [./SMP] 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.
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.
[Executioner] 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.
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.
[Outputs] exodus = true print_perf_log = true 
For more information about the
Outputs block, look here.
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:
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
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
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: