The analysis is performed with JuliaFEM v0.3.3

The model

The example model is a bracket that is attached to two adapter plates via tie contacts. The adapter plates are constrained from one of their side as fixed.

The Bracket is modeled as cast iron while the Adapter plates are modeled as steel.

The material parameters are listed in the following table.

Part Material E [MPa] μ ρ [kg/m3]
Adapter plates Steel 208000 0.300 7800
LDU Bracket Cast Iron 165000 0.275 7100

The code

First all the packages needed in the calculation are included by typing using package_name .

using JuliaFEM
using JuliaFEM.Preprocess
using JuliaFEM.Postprocess
using JuliaFEM.Abaqus: create_surface_elements

The mesh needs to be read from ABAQUS input file to JuliaFEM. The function abaqus_read_mesh(ABAQUS_input_file_name::String) will do the trick.

# read mesh
mesh = abaqus_read_mesh("LDU_ld_r2.inp")

Problem(problem_type, problem_name::String, problem_dimension) function will construct a new field problem where problem_type is the type of the problem (Elasticity, Dirichlet, Mortar etc.), problem_name::String is the name of the problem and problem_dimension is the number of DOF:s in one node (1 in a heat problem, 2 in a 2D problem, 3 in an elastic 3D problem, 6 in a 3D beam problem, etc.).

create_elements(mesh, Element_set_name::String) function will collect the element sets from the ABAQUS input file. In this example the element sets are named as bracket_elements and adapterplate_elements.

update!(element_set_name, parameter::String, value) will update the material parameters for the model. In this example there are two different materials for the two different element sets.

The element sets are then added into the element list of the Problem: add_elements!(bracket, bracket_elements), add_elements!(bracket, adapterplate_elements)

# create a field problem with two different materials
bracket = Problem(Elasticity, "LDU_Bracket", 3)
bracket_elements = create_elements(mesh, "LDUBracket")
adapterplate_elements = create_elements(mesh, "Adapterplate1", "Adapterplate2")
update!(bracket_elements, "youngs modulus", 208.0E3)
update!(bracket_elements, "poissons ratio", 0.30)
update!(bracket_elements, "density", 7.80E-9)
update!(adapterplate_elements, "youngs modulus", 165.0E3)
update!(adapterplate_elements, "poissons ratio", 0.275)
update!(adapterplate_elements, "density", 7.10E-9)
add_elements!(bracket, bracket_elements)
add_elements!(bracket, adapterplate_elements)

Boundary conditions can be created from node sets. Problem(problem_type, problem_name::String, problem_dimension, parent_field_name::String) function is used again to perform this. In this method the problem type is Dirichlet and parent_field_name is the type of the Dirichlet variable (“temperature”, “displacement”, etc.).

Then the fixed nodal elements are collected from the input file with the function create_nodal_elements(mesh::Mesh, node_set_name::String).

The displacements are then updated with update!(node_set_name::String, parent_field_name direction::String, value) where direction is the direction of the displacement and value is the value of the nodal displacement which of course is 0.0 since our elements are fixed.

# create a boundary condition from a node set
fixed = Problem(Dirichlet, "fixed", 3, "displacement")
fixed_elements = create_nodal_elements(mesh, "Face_constraint_1")
update!(fixed_elements, "displacement 1", 0.0)
update!(fixed_elements, "displacement 2", 0.0)
update!(fixed_elements, "displacement 3", 0.0)

JuliaFEM allows new functions to be built with the help of other JuliaFEM functions. For example we need now a helper function to create tie contacts to our model.

Our function is called create_interface and it has three variables: mesh, slave and master. mesh refers to our input file name that is defined at the begining of this document, slave is the name of our slave surface in the input file and master is the name of the master surface. The function uses Problem() function with the Mortar method, create_surface_elements function and update! function from the JuliaFEM library.

""" A helper function to create tie contacts. """
function create_interface(mesh::Mesh, slave::String, master::String)
    interface = Problem(Mortar, "tie contact", 3, "displacement")
    interface.properties.dual_basis = false
    slave_elements = create_surface_elements(mesh, slave)
    master_elements = create_surface_elements(mesh, master)
    nslaves = length(slave_elements)
    nmasters = length(master_elements)
    update!(slave_elements, "master elements", master_elements)
    interface.elements = [slave_elements; master_elements]
    return interface
end

Interfaces can now be applied with our own function create_interface(mesh, slave::String, master::String) that collects necessary information from our input file and creates a tie contact.

# call the helper function to create tie contacts
tie1 = create_interface(mesh,
    "LDUBracketToAdapterplate1",
    "Adapterplate1ToLDUBracket") 
tie2 = create_interface(mesh,
    "LDUBracketToAdapterplate2",
    "Adapterplate2ToLDUBracket")

All problems need to be added into Solver(solver_type, problem_names) function where solver_type is the type of the solver (Modal, Linear, Nonlinear). In this example we are using a modal solver that solves generalized eigenvalue problems Ku = Muλ since we are calculating natural frequencies.

The results can be imported to xdmf file format for further review. This is performed by typing solver_name.xdmf = Xdmf(result_file_name::String) where solver_name is the name of our solver which we defined and result_file_name is the name we want to give our xdmf result file.

Yet we need to specify some properties for our analysis. We only want to calculate the first six frequencies for our model. This can be done by first typing solver_name.properties.nev = value where nev refers to the number of eigenmodes and value is the number of eigenmodes which are to be calculated, and then typing bracket_freqs.properties.which = :SM where which refers to the type of the eigenmodes (:SM, :LM , etc.) and :SM specifies that the eigen modes to be calculated shall be the smallest ones.

Finally by simply typing solver_name() we are commanding JuliaFEM to start the analysis.

# add the field and the boundary problems to the solver
bracket_freqs = Solver(Modal, bracket, fixed, tie1, tie2)
# save results to Xdmf data format ready for ParaView visualization
bracket_freqs.xdmf = Xdmf("results")
# solve 6 smallest eigenvalues
bracket_freqs.properties.nev = 6
bracket_freqs.properties.which = :SM
bracket_freqs()

Results

JuliaFEM gives the following calculation results for the analysis.

Mode f [Hz]
1 111.38
2 155.03
3 215.40
4 358.76
5 409.65
6 603.51