from material import *
from part import *
from section import *
from interaction import *
from step import *
from job import *
from mesh import *
import odbAccess
import Pabq.common_tools.abq_tools as at
import pickle
import numpy as np
[docs]def modeler(
name=None,
grip_lengths=None,
double_nut=None,
add=None,
write_input=None,
save_cae=None,
submit=None
):
"""
Create an Abaqus model of a uniaxial bolt test.
Parameters
----------
name : str, optional
Name of the model. This string is also used as a base name upon which alternative suffixes are appended for
several sub objects of the model e.g. the jog is named as `name`_job.
By default, a generic name "BoltAndNut" is used
grip_lengths : array-like of two floats, optional
Tow floats are expected in an array (list or tuple) giving the grip length, l_g (first float), and the threaded
grip length, l_t (second float). Default implies l_g = 28, l_t = 10
double_nut : bool, optional
Single or double nut assembly. Default implies single nut.
add : bool, optional
Whether or not to add the model in the existing session or create a new session (deletes all other models). The
default value is True (the model will be added to the current session, existing models remain untouched)
write_input : bool, optional
Whether or not to write the input file for the created model. Default is `False`
save_cae : bool, optional
Whether or not to save the model in a .cae file in the working directory. Default is `False`
submit : bool, optional
Whether or not to submit for analysis. Default is `False`
Return
------
`model` object
Notes
-----
The modelling script is a continuation of the work of Erik Grimsmo [1]. The initial script was used to model 5
uniaxial bolt tests. The current script is a complete revision allowing for a parametric definition of the bolt
assembly grip length, the threaded part of the grip length and the number of nuts (single or double nut assembly).
This way, an arbitrary bolt assembly can be modeled on demand for specific applications.
Currently, the bolt diameter and the grade are fixed (M16 8.8).
[1] E. L. Grimsmo, A. Aalberg, M. Langseth, and A. H. Clausen, "Failure modes of bolt and nut assemblies under
tensile loading" Journal of Constructional Steel Research, vol. 126, pp. 15-25, Nov. 2016.
"""
if name is None:
name = 'boltAndNut'
if add is None:
add = True
if add:
mdb.Model(name)
else:
# Start new model database.
Mdb()
# Change the pre-existing model name.
mdb.models.changeKey(
fromName='Model-1',
toName=name
)
if grip_lengths is None:
grip_lengths = (28., 10.)
if double_nut is None:
double_nut = False
n_nuts = 1
if double_nut:
n_nuts = 2
if write_input is None:
write_input = False
if save_cae is None:
save_cae = False
if submit is None:
submit = False
# Assign model object to a variable.
mdl = mdb.models[name]
# Names given to various objects throughout the model
names = {
"model": name,
"job": name + "_job",
}
# Basic input variables
l_g = grip_lengths[0]
l_t = grip_lengths[1]
# Bolt related
head_height = 10.0 #Head height
thread_pitch = 2.0 #Thread pitch (measured: 1.99)
d_unthr = 15.87 #Major diameter (external threads)
l_unthr = l_g - l_t
d_bolt_max = 15.88 #Major diameter (external threads)
d_bolt_min = 13.36 #Minor diameter (external threads)
d_ch = 15.15 #Smallest diameter of chamfer at start of threads of bolt
l_ch = 2.3 #Length of chamfer at start of threads of bolt
# Nut related
nut_size = 25.43 #Wrench size
d_nut_min = 14.05 #Minor diameter (internal threads)
d_nut_max = 16.36 #Major diameter (internal threads)
d_ch_nut_max = 17.55 #Largest diameter of chamfer at nut end
d_ch_nut_min = 15.25 #Smallest diameter of chamfer at nut end
d_first_thread = 14.54 #Diameter of first thread in nut
h_nut = 14.20 #Height of nut | measured: 14.20
n_threads_in_nut = 5 #Numer of threads on nut
# Washer
h_washer = 1
b_washer = (nut_size - d_nut_max) / 2
washer_elasticity = 1e9
# Mesh sizes
mesh_nut_max = 0.4 #Global mesh of the nut
mesh_nut_min = 0.1 #Local mesh of the nut (around the threads)
mesh_bolt_max = 1.0 #Global mesh of the bolt
mesh_bolt_min = 0.4 #Local mesh of the bolt
mesh_bolt_threads = 0.1 #Mesh around threads of bolt
mesh_washer = 1.0 #Mesh of washer
#A medium mesh density is global mesh = 0.3 and local mesh = 0.2
# General
velocity = 0.013
eps = 0.001
time = 500
l_f = 3
n_threads = int(divmod(l_t + (n_nuts * h_nut) + l_f, thread_pitch)[0])
# n_threads = 12
# Useful tangents
t30 = tan(radians(30))
t60 = tan(radians(60))
fric_coeff = 0.2 #Friction coefficient for tangential friction in contact property
# mass_scale = 1E7 #Mass scaling factor
target_inc = 1E-3 #Target increment
mdl.setValues(noPartsInputFile=ON)
######################
##### Part Module ####
######################
##### Sketch and create the bolt #####
bolt_sktch = mdl.ConstrainedSketch(
name='boltSketch',
sheetSize=200.0
)
bolt_sktch.sketchOptions.setValues(
viewStyle=AXISYM
)
bolt_sktch.ConstructionLine(
point1=(0.0, -100.0),
point2=(0.0, 100.0))
# Head and unthreaded shank
bolt_sktch.Line(
point1=(0.0, 0.0),
point2=(nut_size/2, 0.0)
)
bolt_sktch.Line(
point1=(nut_size/2, 0.0),
point2=(nut_size/2, head_height)
)
bolt_sktch.Line(
point1=(nut_size/2, head_height),
point2=(d_unthr/2, head_height)
)
bolt_sktch.Line(
point1=(d_unthr/2, head_height),
point2=(d_unthr/2, head_height+l_unthr)
)
# Chamfer part and first (special) thread
d_sp = 15.3 #Diameter of special thread
nut_pos, l_sp = divmod(l_t - l_ch - t30*(d_sp/2-d_bolt_min/2) - 1.23, thread_pitch)
nut_pos = nut_pos + 1
ch_alpha_bolt = (d_bolt_max-d_bolt_min)/(2*t60)
ch_beta_bolt = (thread_pitch-2*ch_alpha_bolt)/3
ch_gamma_bolt = 2*ch_beta_bolt
bolt_sktch.Line(
point1=(d_unthr/2, head_height+l_unthr),
point2=(d_ch/2, head_height+l_unthr+l_ch)
)
bolt_sktch.Line(
point1=(d_ch/2, head_height+l_unthr+l_ch),
point2=(d_sp/2, head_height+l_unthr+l_ch+l_sp)
)
line = [
bolt_sktch.Line(
point1=(d_sp/2, head_height+l_unthr+l_ch+l_sp),
point2=(d_bolt_min/2, head_height+l_unthr+l_ch+l_sp+t30*(d_sp/2-d_bolt_min/2))
)
]
# Height up to and including the chamfer part and first (special) thread
bolt_uthr_height = head_height+l_unthr+l_ch+l_sp+t30*(d_sp/2-d_bolt_min/2) # (Height to first thread)
# Normal threads
for i in range(n_threads):
line.append(
bolt_sktch.Line(
point1=(
d_bolt_min/2,
bolt_uthr_height+i*thread_pitch
),
point2=(
d_bolt_min/2,
bolt_uthr_height+ch_gamma_bolt+i*thread_pitch
)
)
)
line.append(
bolt_sktch.Line(
point1=(
d_bolt_min/2,
bolt_uthr_height+ch_gamma_bolt+i*thread_pitch
),
point2=(
d_bolt_max/2,
bolt_uthr_height+ch_gamma_bolt+ch_alpha_bolt+i*thread_pitch
)
)
)
line.append(
bolt_sktch.Line(
point1=(
d_bolt_max/2,
bolt_uthr_height+ch_gamma_bolt+ch_alpha_bolt+i*thread_pitch
),
point2=(
d_bolt_max/2,
bolt_uthr_height+ch_gamma_bolt+ch_alpha_bolt+ch_beta_bolt+i*thread_pitch
)
)
)
line.append(
bolt_sktch.Line(
point1=(
d_bolt_max/2,
bolt_uthr_height+ch_gamma_bolt+ch_alpha_bolt+ch_beta_bolt+i*thread_pitch
),
point2=(
d_bolt_min/2,
bolt_uthr_height+ch_gamma_bolt+ch_alpha_bolt+ch_beta_bolt+ch_alpha_bolt+i*thread_pitch
)
)
)
# Finish up sketch
bolt_sktch.Line(
point1=(
d_bolt_min/2,
bolt_uthr_height+n_threads*thread_pitch
),
point2=(
0.0,
bolt_uthr_height+n_threads*thread_pitch
)
)
bolt_sktch.Line(
point1=(
0.0,
bolt_uthr_height+n_threads*thread_pitch
),
point2=(
0.0,
0.0
)
)
bolt_part = mdl.Part(
dimensionality=AXISYMMETRIC,
name='bolt',
type=DEFORMABLE_BODY
)
bolt_part.BaseShell(
sketch=bolt_sktch
)
##### Sketch and create the nuts #####
ch_alpha_nut = (d_nut_max - d_nut_min) / 2 * t30
ch_beta_nut = 2 * (thread_pitch - 2 * ch_alpha_nut) / 3
ch_gamma_nut = ch_beta_nut / 2
h_ch = (h_nut -
((d_nut_max - d_ch_nut_min) / 2 * t30 +
ch_gamma_nut +
(d_nut_max - d_first_thread) / 2 * t30 +
ch_beta_nut +
(d_first_thread - d_nut_min) * t30 +
(d_nut_max - d_first_thread) / 2 * t30 +
ch_gamma_nut +
ch_alpha_nut +
ch_beta_nut +
ch_alpha_nut +
(n_threads_in_nut - 3) * thread_pitch +
ch_gamma_nut +
(d_nut_max - d_first_thread) / 2 * t30 +
ch_beta_nut +
(d_first_thread - d_nut_min) * t30 +
(d_nut_max - d_first_thread) / 2 * t30 +
ch_gamma_nut +
(d_nut_max - d_ch_nut_min) / 2 * t30)
) / 2
nut_part = []
for nut in range(n_nuts):
if nut == 0:
th_offset = 0
else:
th_offset = 189.536E-03 + 10.464E-03 + eps
h_ch1 = h_ch - th_offset
nut_sktch = mdl.ConstrainedSketch(
name='nutSketch',
sheetSize=200.0
)
nut_sktch.sketchOptions.setValues(viewStyle=AXISYM)
nut_sktch.ConstructionLine(
point1=(
0.0,
-100.0
),
point2=(
0.0,
100.0
)
)
# Chamfer and first (special) thread
nut_sktch.Line(
point1=(
nut_size/2,
0.0
),
point2=(
d_ch_nut_max/2,
0.0
)
)
nut_sktch.Line(
point1=(
d_ch_nut_max/2,
0.0
),
point2=(
d_ch_nut_min/2,
h_ch1
)
)
nut_sktch.Line(
point1=(
d_ch_nut_min/2,
h_ch1
),
point2=(
d_nut_max/2,
h_ch1+(d_nut_max-d_ch_nut_min)/2*t30
)
)
nut_sktch.Line(
point1=(
d_nut_max/2,
h_ch1+(d_nut_max-d_ch_nut_min)/2*t30
),
point2=(
d_nut_max/2,
h_ch1+(d_nut_max-d_ch_nut_min)/2*t30+ch_gamma_nut
)
)
nut_sktch.Line(
point1=(
d_nut_max/2,
h_ch1+(d_nut_max-d_ch_nut_min)/2*t30+ch_gamma_nut
),
point2=(
d_first_thread/2,
h_ch1+(d_nut_max-d_ch_nut_min)/2*t30+ch_gamma_nut+(d_nut_max-d_first_thread)/2*t30
)
)
nut_sktch.Line(
point1=(
d_first_thread/2,
h_ch1+(d_nut_max-d_ch_nut_min)/2*t30+ch_gamma_nut+(d_nut_max-d_first_thread)/2*t30
),
point2=(
d_first_thread/2,
(
h_ch1 +
(d_nut_max-d_ch_nut_min)/2*t30 +
ch_gamma_nut +
(d_nut_max-d_first_thread)/2*t30 +
ch_beta_nut +
(d_first_thread-d_nut_min)*t30
)
)
)
nut_sktch.Line(
point1=(
d_first_thread/2,
(
h_ch1+
(d_nut_max-d_ch_nut_min)/2*t30+
ch_gamma_nut+
(d_nut_max-d_first_thread)/2*t30+
ch_beta_nut+
(d_first_thread-d_nut_min)*t30
)
),
point2=(
d_nut_max/2,
(
h_ch1 +
(d_nut_max-d_ch_nut_min)/2*t30 +
ch_gamma_nut +
(d_nut_max-d_first_thread)/2*t30 +
ch_beta_nut +
(d_first_thread-d_nut_min)*t30 +
(d_nut_max-d_first_thread)/2*t30
)
)
)
# Height up to and including the chamfer part and first (special) thread
nut_uthr_height = (
h_ch1 +
(d_nut_max-d_ch_nut_min)/2*t30 +
ch_gamma_nut +
(d_nut_max-d_first_thread)/2*t30 +
ch_beta_nut +
(d_first_thread-d_nut_min)*t30 +
(d_nut_max-d_first_thread)/2*t30
)
# Normal threads
for i in range(n_threads_in_nut-2):
nut_sktch.Line(
point1=(
d_nut_max/2,
nut_uthr_height+i*thread_pitch
),
point2=(
d_nut_max/2,
nut_uthr_height+ch_gamma_nut+i*thread_pitch
)
)
nut_sktch.Line(
point1=(
d_nut_max/2,
nut_uthr_height+ch_gamma_nut+i*thread_pitch
),
point2=(
d_nut_min/2,
nut_uthr_height+ch_gamma_nut+ch_alpha_nut+i*thread_pitch
)
)
nut_sktch.Line(
point1=(
d_nut_min/2,
nut_uthr_height+ch_gamma_nut+ch_alpha_nut+i*thread_pitch
),
point2=(
d_nut_min/2,
nut_uthr_height+ch_gamma_nut+ch_alpha_nut+ch_beta_nut+i*thread_pitch
)
)
nut_sktch.Line(
point1=(
d_nut_min/2,
nut_uthr_height+ch_gamma_nut+ch_alpha_nut+ch_beta_nut+i*thread_pitch
),
point2=(
d_nut_max/2,
nut_uthr_height+ch_gamma_nut+ch_alpha_nut+ch_beta_nut+ch_alpha_nut+i*thread_pitch
)
)
# Height up to and including last normal thread
height_with_threads = (nut_uthr_height+
ch_gamma_nut+
ch_alpha_nut+
ch_beta_nut+
ch_alpha_nut+
(n_threads_in_nut-3)*thread_pitch) # (Height up to last thread)
# The opposite special thread and chamfer
nut_sktch.Line(
point1=(
d_nut_max/2,
height_with_threads
),
point2=(
d_nut_max/2,
height_with_threads+ch_gamma_nut
)
)
nut_sktch.Line(
point1=(
d_nut_max/2,
height_with_threads+ch_gamma_nut
),
point2=(
d_first_thread/2,
(height_with_threads+
ch_gamma_nut+
(d_nut_max-d_first_thread)/2*t30)
)
)
nut_sktch.Line(
point1=(
d_first_thread/2,
(height_with_threads+
ch_gamma_nut+
(d_nut_max-d_first_thread)/2*t30)
),
point2=(
d_first_thread/2,
(height_with_threads+
ch_gamma_nut+
(d_nut_max-d_first_thread)/2*t30+
ch_beta_nut+
(d_first_thread-d_nut_min)*t30)
)
)
nut_sktch.Line(
point1=(
d_first_thread/2,
(height_with_threads+
ch_gamma_nut+
(d_nut_max-d_first_thread)/2*t30+
ch_beta_nut+
(d_first_thread-d_nut_min)*t30)
),
point2=(
d_nut_max/2,
(height_with_threads+
ch_gamma_nut+
(d_nut_max-d_first_thread)/2*t30+
ch_beta_nut+
(d_first_thread-d_nut_min)*t30+
(d_nut_max-d_first_thread)/2*t30)
)
)
nut_sktch.Line(
point1=(
d_nut_max/2,
(height_with_threads+
ch_gamma_nut+
(d_nut_max-d_first_thread)/2*t30+
ch_beta_nut+
(d_first_thread-d_nut_min)*t30+
(d_nut_max-d_first_thread)/2*t30)
),
point2=(
d_nut_max/2,
(height_with_threads+
ch_gamma_nut+
(d_nut_max-d_first_thread)/2*t30+
ch_beta_nut+
(d_first_thread-d_nut_min)*t30+
(d_nut_max-d_first_thread)/2*t30+
ch_gamma_nut)
)
)
nut_sktch.Line(
point1=(
d_nut_max/2,
(height_with_threads+
ch_gamma_nut+
(d_nut_max-d_first_thread)/2*t30+
ch_beta_nut+
(d_first_thread-d_nut_min)*t30+
(d_nut_max-d_first_thread)/2*t30+
ch_gamma_nut)
),
point2=(
d_ch_nut_min/2,
(height_with_threads+
ch_gamma_nut+
(d_nut_max-d_first_thread)/2*t30+
ch_beta_nut+
(d_first_thread-d_nut_min)*t30+
(d_nut_max-d_first_thread)/2*t30+
ch_gamma_nut+
(d_nut_max-d_ch_nut_min)/2*t30)
)
)
nut_sktch.Line(
point1=(
d_ch_nut_min/2,
(height_with_threads+
ch_gamma_nut+
(d_nut_max-d_first_thread)/2*t30+
ch_beta_nut+
(d_first_thread-d_nut_min)*t30+
(d_nut_max-d_first_thread)/2*t30+
ch_gamma_nut+
(d_nut_max-d_ch_nut_min)/2*t30)
),
point2=(
d_ch_nut_max/2,
h_nut
)
)
# Finish up sketch
nut_sktch.Line(
point1=(d_ch_nut_max/2, h_nut),
point2=(nut_size/2, h_nut)
)
nut_sktch.Line(
point1=(nut_size/2, h_nut),
point2=(nut_size/2, 0.0)
)
# Create nut part
nut_part.append(mdl.Part(
dimensionality=AXISYMMETRIC,
name='nut%d' % (nut+1),
type=DEFORMABLE_BODY))
nut_part[-1].BaseShell(sketch=nut_sktch)
del nut_sktch
##### Sketch and create the washer #####
washer_sktch = mdl.ConstrainedSketch(
name='washerSketch',
sheetSize=200.0
)
washer_sktch.sketchOptions.setValues(viewStyle=AXISYM)
washer_sktch.ConstructionLine(
point1=(0.0, -100.0),
point2=(0.0, 100.0)
)
washer_sktch.rectangle(
point1=(9, 0.0),
point2=(9 + b_washer, h_washer)
)
# Create the washer part
washer_part = mdl.Part(
dimensionality=AXISYMMETRIC,
name='washer',
type=DEFORMABLE_BODY
)
washer_part.BaseShell(sketch=washer_sktch)
#### Partitioning ####
# Partitioning of bolt
partition_sktch = mdl.ConstrainedSketch(
gridSpacing=1.27,
name='__profile__',
sheetSize=51.15,
transform=bolt_part.MakeSketchTransform(
sketchPlane=bolt_part.faces.findAt(
(6.6, 3.333333, 0.0),
(0.0, 0.0, 1.0)
),
sketchPlaneSide=SIDE1,
sketchOrientation=RIGHT,
origin=(0.0, 0.0, 0.0)
)
)
bolt_part.projectReferencesOntoSketch(
filter=COPLANAR_EDGES,
sketch=partition_sktch
)
partition_sktch.Line(
point1=(
d_unthr/2,
0.0
),
point2=(
d_unthr/2.0,
head_height
)
)
partition_sktch.Line(
point1=(
d_unthr/2,
head_height
),
point2=(
0.0,
head_height
)
)
partition_sktch.Line(
point1=(
d_unthr/2,
head_height+l_unthr-mesh_bolt_max
),
point2=(
0.0,
head_height+l_unthr-mesh_bolt_max
)
)
partition_sktch.Line(
point1=(
d_unthr/2,
head_height+l_unthr
),
point2=(
0.0,
head_height+l_unthr
)
)
partition_sktch.Line(
point1=(
d_ch/2,
head_height+l_unthr+l_ch
),
point2=(
0.0,
head_height+l_unthr+l_ch
)
)
partition_sktch.Line(
point1=(
d_bolt_max/2-(2+mesh_bolt_min),
head_height+l_unthr+l_ch
),
point2=(
d_bolt_max/2-(2+mesh_bolt_min),
bolt_uthr_height+n_threads*thread_pitch
)
)
partition_sktch.Line(
point1=(
d_bolt_max/2-2,
head_height+l_unthr+l_ch
),
point2=(
d_bolt_max/2-2,
bolt_uthr_height+n_threads*thread_pitch
)
)
partition_sktch.Line(
point1=(
d_bolt_max/2-(2+mesh_bolt_min),
bolt_uthr_height+nut_pos*thread_pitch-thread_pitch
),
point2=(
d_bolt_max/2,
bolt_uthr_height+nut_pos*thread_pitch-thread_pitch
)
)
partition_sktch.Line(
point1=(
d_bolt_max/2-2,
bolt_uthr_height+nut_pos*thread_pitch-thread_pitch+ch_gamma_bolt
),
point2=(
d_bolt_max/2,
bolt_uthr_height+nut_pos*thread_pitch-thread_pitch+ch_gamma_bolt
)
)
partition_sktch.Line(
point1=(
d_bolt_max/2-2,
bolt_uthr_height+nut_pos*thread_pitch+((n_threads_in_nut+1)*thread_pitch)*n_nuts+2*thread_pitch
),
point2=(
d_bolt_max/2,
bolt_uthr_height+nut_pos*thread_pitch+((n_threads_in_nut+1)*thread_pitch)*n_nuts+2*thread_pitch
)
)
partition_sktch.Line(
point1=(
d_bolt_max/2-(2+mesh_bolt_min),
(
bolt_uthr_height +
nut_pos*thread_pitch +
((n_threads_in_nut+1)*thread_pitch)*n_nuts +
2*thread_pitch +
ch_gamma_bolt
)
),
point2=(
d_bolt_max/2,
(
bolt_uthr_height +
nut_pos*thread_pitch +
((n_threads_in_nut+1)*thread_pitch)*n_nuts +
2*thread_pitch +
ch_gamma_bolt
)
)
)
bolt_part.PartitionFaceBySketch(
faces=bolt_part.faces.findAt(((6.6, 3.333333, 0.0), )),
sketch=partition_sktch
)
del partition_sktch
# Partitioning of nut
for nut in nut_part:
partition_nut_sktch = mdl.ConstrainedSketch(
gridSpacing=0.95,
name='partitionNutSketch',
sheetSize=38.12,
transform=nut.MakeSketchTransform(
sketchPlane=nut.faces.findAt((nut_size/2-eps, eps, 0.0), (0.0, 0.0, 1.0)),
sketchPlaneSide=SIDE1,
sketchOrientation=RIGHT,
origin=(0.0, 0.0, 0.0))
)
nut.projectReferencesOntoSketch(
filter=COPLANAR_EDGES,
sketch=partition_nut_sktch
)
partition_nut_sktch.Line(
point1=(d_ch_nut_max/2, 0),
point2=(d_ch_nut_max/2, h_nut)
)
partition_nut_sktch.Line(
point1=(d_ch_nut_max/2+0.5, 0),
point2=(d_ch_nut_max/2+0.5, h_nut)
)
nut.PartitionFaceBySketch(
faces=nut.faces.findAt(((nut_size/2-eps, eps, 0.0), )),
sketch=partition_nut_sktch
)
#### Define surfaces ####
#Bolt
bolt_part.Surface(
name='threadSurf',
side1Edges=bolt_part.edges.getByBoundingBox(
d_bolt_max/2-2.0+eps,
bolt_uthr_height+nut_pos*thread_pitch-thread_pitch-eps,
-eps,
d_bolt_max+eps,
(
bolt_uthr_height+
nut_pos*thread_pitch+
((n_threads_in_nut+1)*thread_pitch)*n_nuts+
2*thread_pitch+
ch_gamma_bolt+
eps
),
eps
)
)
bolt_part.Surface(
name='head',
side1Edges=bolt_part.edges.findAt(((nut_size/2-eps, head_height, 0), ), ))
#Nut
for i, nut in enumerate(nut_part):
nut.Surface(
name='threadSurf',
side1Edges=nut.edges.getByBoundingBox(
d_nut_min/2-eps,
eps,
-eps,
d_ch_nut_max/2+eps,
h_nut+eps,
eps
)
)
nut.Surface(
name='nut_down',
side1Edges=nut.edges.findAt(((nut_size/2-eps, 0, 0), ), ((d_ch_nut_max/2+eps, 0, 0), ), )
)
nut.Surface(
name='nut_up',
side1Edges=nut.edges.findAt(((nut_size / 2 - eps, h_nut, 0),), ((d_ch_nut_max / 2 + eps, h_nut, 0),), )
)
#Washer
washer_part.Surface(
name='washerToNut',
side1Edges=washer_part.edges.findAt(((9 + b_washer/2, h_washer, 0),),)
)
washer_part.Surface(
name='washerToHead',
side1Edges=washer_part.edges.findAt(((9 + b_washer/2, 0, 0),),)
)
######################
##### Mesh Module ####
######################
##### Mesh bolt #####
# Element type
bolt_part.setElementType(
elemTypes=(
ElemType(
elemCode=CAX4R,
elemLibrary=EXPLICIT,
secondOrderAccuracy=OFF,
hourglassControl=DEFAULT,
distortionControl=DEFAULT
),
ElemType(
elemCode=CAX3,
elemLibrary=EXPLICIT,
secondOrderAccuracy=OFF,
distortionControl=DEFAULT
)
),
regions=(bolt_part.faces, )
)
# The threaded portion of the bolt is given enhanced hourglass stiffness
bolt_part.setElementType(
elemTypes=(
ElemType(
elemCode=CAX4R,
elemLibrary=EXPLICIT,
secondOrderAccuracy=OFF,
hourglassControl=ENHANCED,
distortionControl=DEFAULT),
ElemType(
elemCode=CAX3,
elemLibrary=EXPLICIT,
secondOrderAccuracy=OFF,
distortionControl=DEFAULT)
),
regions=(
bolt_part.faces.findAt(((eps, bolt_uthr_height+n_threads*thread_pitch-eps, 0.0), )), )
)
## Mesh control
bolt_part.setMeshControls(
elemShape=QUAD,
regions=bolt_part.faces,
technique=FREE,
allowMapped=False
)
bolt_part.setMeshControls(
elemShape=QUAD,
regions=bolt_part.faces.findAt(
((nut_size/2-eps, eps, 0.0), ),
((eps, eps, 0.0), ),
((eps, head_height+eps, 0.0), ),
((eps, head_height+l_unthr+l_ch+eps, 0.0), ),
),
technique=STRUCTURED
)
## Seeding
bolt_part.seedPart(
deviationFactor=0.1,
minSizeFactor=0.1,
size=mesh_bolt_max
)
bolt_part.seedEdgeBySize(
constraint=FINER,
deviationFactor=0.1,
edges=bolt_part.edges.getByBoundingBox(
-eps,
head_height+l_unthr-eps,
-eps,
d_bolt_max/2+eps,
1E3,
eps
),
minSizeFactor=0.1,
size=mesh_bolt_min
)
bolt_part.seedEdgeBySize(
constraint=FINER,
deviationFactor=0.1,
edges=bolt_part.edges.getByBoundingBox(
d_bolt_max/2-(2+mesh_bolt_min)+eps,
bolt_uthr_height+nut_pos*thread_pitch-thread_pitch+eps,
-eps,
d_bolt_max/2+eps,
bolt_uthr_height+nut_pos*thread_pitch+n_threads_in_nut*thread_pitch+2*thread_pitch+ch_gamma_bolt-eps,
eps
),
minSizeFactor=0.1,
size=mesh_bolt_threads
)
bolt_part.generateMesh()
##### Mesh nut #####
# Element type
for nut in nut_part:
nut.setElementType(
elemTypes=(
ElemType(
elemCode=CAX4R,
elemLibrary=EXPLICIT,
secondOrderAccuracy=OFF,
hourglassControl=DEFAULT,
distortionControl=DEFAULT
),
ElemType(
elemCode=CAX3,
elemLibrary=EXPLICIT,
secondOrderAccuracy=OFF,
distortionControl=DEFAULT)),
regions=(
bolt_part.faces.findAt(((nut_size/2-eps, eps, 0.0), )),
)
)
# Mesh control
nut.setMeshControls(
elemShape=QUAD,
regions=nut.faces.findAt(((nut_size/2-eps, eps, 0.0), )),
technique=STRUCTURED
)
nut.setMeshControls(
elemShape=QUAD,
regions=nut.faces.findAt(((d_ch_nut_max/2-eps, 1.0, 0.0), ),),
technique=FREE
)
nut.setMeshControls(
elemShape=QUAD,
regions=nut.faces.findAt(((d_ch_nut_max/2+eps, 1.0, 0.0), ),),
technique=FREE,
allowMapped=FALSE
)
# Seeding
nut.seedPart(
deviationFactor=0.1,
minSizeFactor=0.1,
size=mesh_nut_max
)
nut.seedEdgeBySize(
constraint=FINER,
deviationFactor=0.1,
edges=nut.edges.getByBoundingBox(d_nut_min/2-eps,-eps,-eps,d_ch_nut_max/2+eps,h_nut+eps,eps),
minSizeFactor=0.1,
size=mesh_nut_min
)
nut.seedEdgeBySize(
constraint=FINER,
deviationFactor=0.1,
edges=nut.edges.findAt(((d_ch_nut_max/2+0.5, 1.0, 0.0),)),
minSizeFactor=0.1,
size=mesh_nut_max
)
nut.generateMesh()
##### Mesh washer #####
#Mesh
washer_part.setMeshControls(
elemShape=QUAD,
regions=washer_part.faces.findAt(
((9 + b_washer/2, h_washer/2, 0.0), ),
),
technique=STRUCTURED
)
washer_part.seedPart(
deviationFactor=0.1,
minSizeFactor=0.1,
size=mesh_washer
)
washer_part.setElementType(
elemTypes=(
ElemType(
elemCode=CAX4R,
elemLibrary=EXPLICIT,
secondOrderAccuracy=OFF,
hourglassControl=DEFAULT,
distortionControl=DEFAULT),
ElemType(
elemCode=CAX3,
elemLibrary=EXPLICIT
)
),
regions=(
washer_part.faces.findAt(
((9 + b_washer/2, h_washer/2, 0.0), ),
),
)
)
washer_part.generateMesh()
##### Material definitions #####
bolt_material = mdl.Material(name='SMMA_bolt')
threads_material = mdl.Material(name='SMMA_threads')
nut_material = mdl.Material(name='SMMA_nut')
washer_material = mdl.Material(name='washer')
washer_material.Elastic(table=((washer_elasticity, 0.3), ))
washer_material.Density(table=((7.8e-09, ), ))
##### Create sections and assign #####
mdl.HomogeneousSolidSection(
material='SMMA_bolt',
name='boltSection',
thickness=None
)
mdl.HomogeneousSolidSection(
material='SMMA_threads',
name='threadSection',
thickness=None
)
mdl.HomogeneousSolidSection(
material='SMMA_nut',
name='nutSection',
thickness=None
)
mdl.HomogeneousSolidSection(
material='washer',
name='washerSection',
thickness=None
)
for nut in nut_part:
nut.SectionAssignment(
offset=0.0,
offsetField='',
offsetType=MIDDLE_SURFACE,
region=Region(faces=nut.faces),
sectionName='nutSection',
thicknessAssignment=FROM_SECTION
)
bolt_part.SectionAssignment(
offset=0.0,
offsetField='',
offsetType=MIDDLE_SURFACE,
region=Region(
faces=bolt_part.faces.getByBoundingBox(
-eps,
-eps,
-eps,
nut_size/2+eps,
bolt_uthr_height+nut_pos*thread_pitch-thread_pitch+eps,
eps
)
),
sectionName='boltSection',
thicknessAssignment=FROM_SECTION
)
bolt_part.SectionAssignment(
offset=0.0,
offsetField='',
offsetType=MIDDLE_SURFACE,
region=Region(
faces=bolt_part.faces.getByBoundingBox(
-eps,
(
bolt_uthr_height +
nut_pos*thread_pitch +
((n_threads_in_nut + 1) * thread_pitch) * n_nuts +
2*thread_pitch +
ch_gamma_bolt -
eps
),
-eps,
d_bolt_max/2+eps,
bolt_uthr_height+n_threads*thread_pitch,
eps
)
),
sectionName='boltSection',
thicknessAssignment=FROM_SECTION
)
bolt_part.SectionAssignment(
offset=0.0,
offsetField='',
offsetType=MIDDLE_SURFACE,
region=Region(
faces=bolt_part.faces.findAt(
(
(
eps,
bolt_uthr_height+n_threads*thread_pitch-eps,
0.0
),
),
)
),
sectionName='boltSection',
thicknessAssignment=FROM_SECTION
)
bolt_part.SectionAssignment(
offset=0.0,
offsetField='',
offsetType=MIDDLE_SURFACE,
region=Region(
faces=bolt_part.faces.getByBoundingBox(
d_bolt_max/2-(2+mesh_bolt_min)-eps,
bolt_uthr_height+nut_pos*thread_pitch-thread_pitch-eps,
-eps,
d_bolt_max/2+eps,
(
bolt_uthr_height +
nut_pos*thread_pitch +
((n_threads_in_nut+1)*thread_pitch)*n_nuts +
2*thread_pitch +
ch_gamma_bolt+eps
),
eps
)
),
sectionName='threadSection',
thicknessAssignment=FROM_SECTION
)
washer_part.SectionAssignment(
offset=0.0,
offsetField='',
offsetType=MIDDLE_SURFACE,
region=Region(
faces=washer_part.faces
),
sectionName='washerSection',
thicknessAssignment=FROM_SECTION
)
#########################
#### Assembly module ####
#########################
##### Create assembly #####
assembly = mdl.rootAssembly
assembly.DatumCsysByThreePoints(
coordSysType=CYLINDRICAL,
origin=(0.0, 0.0, 0.0),
point1=(1.0, 0.0, 0.0),
point2=(0.0, 0.0, -1.0)
)
bolt_inst = assembly.Instance(
dependent=ON,
name='bolt-1',
part=bolt_part
)
nut_inst = []
nut_inst.append(assembly.Instance(
dependent=ON,
name='nut-1',
part=nut_part[0]
))
for nut in range(n_nuts-1):
nut_inst.append(assembly.Instance(
dependent=ON,
name='nut-%d' % (nut+2),
part=nut_part[1]
))
washer1_inst = assembly.Instance(
dependent=ON,
name='washer-1',
part=washer_part
)
washer2_inst = assembly.Instance(
dependent=ON,
name='washer-2',
part=washer_part
)
#Create sets that are used for boundary conditions
assembly.Set(
edges=bolt_inst.edges.findAt(((nut_size/2-eps, head_height, 0.0), )),
name='boltHead'
)
for i, nut in enumerate(nut_inst):
assembly.Set(
edges=nut.edges.findAt(((nut_size/2-eps, 0.0, 0.0), )),
name='nut%d' % i
)
assembly.Set(
edges=washer1_inst.edges.findAt(((12.75, 0.0, 0.0), )),
name='washerToHead'
)
assembly.Set(
edges=washer1_inst.edges.findAt(((9 + b_washer/2, h_washer, 0.0), )),
name='washerVel'
)
assembly.Set(
edges=washer2_inst.edges.findAt(((9 + b_washer/2, h_washer, 0.0), )),
name='washerToNut'
)
assembly.Set(
edges=washer2_inst.edges.findAt(((9 + b_washer/2, 0, 0.0), )),
name='washerFixed'
)
# Translate nut and washers to wanted position
for nut in range(n_nuts):
assembly.translate(
instanceList=('nut-%d' % (nut+1), ),
vector=(
0.0,
(bolt_uthr_height + nut_pos*thread_pitch - (thread_pitch/2) * 0.77) + nut*(h_nut + eps),
0.0)
)
assembly.translate(
instanceList=('washer-1', ),
vector=(0.0, head_height + eps, 0.0)
)
assembly.translate(
instanceList=('washer-2', ),
vector=(
0.0,
bolt_uthr_height + nut_pos*thread_pitch - (thread_pitch/2) * 0.77 - h_washer - eps,
0.0
)
)
#####################
#### Step module ####
#####################
##### Create step #####
mdl.ExplicitDynamicsStep(
massScaling=(
(
SEMI_AUTOMATIC,
MODEL,
AT_BEGINNING,
0.0,
target_inc,
BELOW_MIN,
0,
0,
0.0,
0.0,
0,
None
),
),
name='Explicit',
previous='Initial',
timePeriod=time
)
##### Create output variables #####
mdl.fieldOutputRequests['F-Output-1'].setValues(
numIntervals=40,
variables=(
'S',
'PEEQ',
'LE',
'ER',
'U',
'V',
'A',
'RF',
'CSTRESS',
'ENER',
'SDV',
'STATUS'
)
)
mdl.HistoryOutputRequest(
createStepName='Explicit',
name='RF',
rebar=EXCLUDE,
numIntervals=500,
region=assembly.sets['washerFixed'],
sectionPoints=DEFAULT,
variables=('RT', )
)
mdl.HistoryOutputRequest(
createStepName='Explicit',
name='Disp1',
rebar=EXCLUDE,
numIntervals=500,
region=assembly.sets['boltHead'],
sectionPoints=DEFAULT,
variables=('UT', )
)
mdl.HistoryOutputRequest(
createStepName='Explicit',
name='Disp2',
rebar=EXCLUDE,
numIntervals=500,
region=assembly.sets['nut%d' % 0],
sectionPoints=DEFAULT,
variables=('UT', )
)
mdl.HistoryOutputRequest(
createStepName='Explicit',
name='Disp3',
rebar=EXCLUDE,
numIntervals=500,
region=assembly.sets['washerVel'],
sectionPoints=DEFAULT,
variables=('UT', )
)
############################
#### Interaction module ####
############################
##### Contact #####
#Contact property
contact_prprty = mdl.ContactProperty('Contact')
contact_prprty.TangentialBehavior(
dependencies=0,
directionality=ISOTROPIC,
elasticSlipStiffness=None,
formulation=PENALTY,
fraction=0.005,
maximumElasticSlip=FRACTION,
pressureDependency=OFF,
shearStressLimit=None,
slipRateDependency=OFF,
table=((fric_coeff, ), ),
temperatureDependency=OFF
)
contact_prprty.NormalBehavior(
allowSeparation=ON,
constraintEnforcementMethod=DEFAULT,
pressureOverclosure=HARD
)
for i in range(n_nuts):
mdl.SurfaceToSurfaceContactExp(
clearanceRegion=None,
createStepName='Initial',
datumAxis=None,
initialClearance=OMIT,
interactionProperty='Contact',
master=bolt_inst.surfaces['threadSurf'],
mechanicalConstraint=PENALTY,
name='threads%d' % i,
slave=nut_inst[i].surfaces['threadSurf'],
sliding=FINITE
)
if not(i == 0):
mdl.SurfaceToSurfaceContactExp(
clearanceRegion=None,
createStepName='Initial',
datumAxis=None,
initialClearance=OMIT,
interactionProperty='Contact',
master=nut_inst[i-1].surfaces['nut_up'],
mechanicalConstraint=PENALTY,
name='between_nuts%d' % i,
slave=nut_inst[i].surfaces['nut_down'],
sliding=FINITE
)
mdl.SurfaceToSurfaceContactExp(
clearanceRegion=None,
createStepName='Initial',
datumAxis=None,
initialClearance=OMIT,
interactionProperty='Contact',
master=washer2_inst.surfaces['washerToNut'],
mechanicalConstraint=PENALTY,
name='washerToNut',
slave=nut_inst[0].surfaces['nut_down'],
sliding=FINITE
)
mdl.SurfaceToSurfaceContactExp(
clearanceRegion=None,
createStepName='Initial',
datumAxis=None,
initialClearance=OMIT,
interactionProperty='Contact',
master=washer1_inst.surfaces['washerToHead'],
mechanicalConstraint=PENALTY,
name='washerToHead',
slave=bolt_inst.surfaces['head'],
sliding=FINITE
)
mdl.SelfContactExp(
createStepName='Initial',
interactionProperty='Contact',
mechanicalConstraint=PENALTY,
name='selfContact_bolt',
surface=bolt_inst.surfaces['threadSurf']
)
for i, nut in enumerate(nut_inst):
mdl.SelfContactExp(
createStepName='Initial',
interactionProperty='Contact',
mechanicalConstraint=PENALTY,
name='selfContact_nut%d' % i,
surface=nut.surfaces['threadSurf']
)
#####################
#### Load module ####
#####################
##### Boundary conditions #####
#Define smooth step
mdl.SmoothStepAmplitude(
data=((0.0, 0.0), (5.0, 1.0)),
name='smoothStep',
timeSpan=STEP
)
#Fix bolt head
mdl.DisplacementBC(
amplitude=UNSET,
createStepName='Initial',
distributionType=UNIFORM,
fieldName='',
localCsys=None,
name='fixU2',
region=assembly.sets['washerFixed'],
u1=UNSET,
u2=SET,
ur3=UNSET
)
#Apply velocity to nut top surface
mdl.VelocityBC(
amplitude='smoothStep',
createStepName='Explicit',
distributionType=UNIFORM,
fieldName='',
localCsys=None,
name='vel',
region=assembly.sets['washerVel'],
v1=UNSET,
v2=-velocity,
vr3=UNSET
)
####################
#### Job module ####
####################
##### Create job #####
bolt_job = mdb.Job(
activateLoadBalancing=False,
atTime=None,
contactPrint=OFF,
description='',
echoPrint=OFF,
explicitPrecision=SINGLE,
historyPrint=OFF,
memory=90,
memoryUnits=PERCENTAGE,
model=names["model"],
modelPrint=OFF,
multiprocessingMode=DEFAULT,
name=names["job"],
nodalOutputPrecision=SINGLE,
numCpus=1,
numDomains=1,
parallelizationMethodExplicit=DOMAIN,
queue=None,
resultsFormat=ODB,
scratch='',
type=ANALYSIS,
userSubroutine='',
waitHours=0,
waitMinutes=0
)
if write_input:
mdb.jobs[names["job"]].writeInput()
##### Edit the input file #####
#The input file must be edited when an external mat.inp is to be included.
import fileinput
for line in fileinput.input(names["job"]+'.inp', inplace=True):
print(line.replace("*Material, name=SMMA_bolt",
"*INCLUDE,input=mat_bolt.inp")),
for line in fileinput.input(names["job"]+'.inp', inplace=True):
print(line.replace("*Material, name=SMMA_threads",
"*INCLUDE,input=mat_threads.inp")),
for line in fileinput.input(names["job"]+'.inp', inplace=True):
print(line.replace("*Material, name=SMMA_nut",
"*INCLUDE,input=mat_nut.inp")),
if save_cae:
mdb.saveAs(pathName=name + '.cae')
if submit:
bolt_job.submit(consistencyChecking=OFF)
bolt_job.waitForCompletion()
return mdb
[docs]def export_results(name=None):
"""
Get results from bolt odb.
Parameters
----------
modelname : str
Model base name (before the "_"). The results will be exported to a pickle file with the name
"modelname"_results.pkl
Returns
-------
tuple
"""
if name is None:
name = "B_28_10"
odb = odbAccess.openOdb(name + "_job.odb")
print odb, type(odb)
timedisp = np.r_[[at.fetch_hist(odb, 'Explicit', 'Node PART-1-1.1', 'U2')]][0].transpose()
time, disp = (timedisp[0], -timedisp[1])
load = np.zeros(len(disp))
for i in range(6):
load = load + np.r_[[at.fetch_hist(odb, 'Explicit', 'Node PART-1-1.%d' % (8966+i), 'RF2')]][0, :, 1]
results = {
"Time": time.tolist(),
"Extension": disp.tolist(),
"Load": load.tolist()
}
with open(name + "_results.pkl", "wb") as fh:
pickle.dump(results, fh)
return results
[docs]def main(**kargs):
name = "BD_28_10"
modeler(
name=name,
grip_lengths=(28, 10),
double_nut=True,
add=False,
write_input=True,
save_cae=True,
submit=False
)
export_results(name=name)
if __name__ == "__main__":
main()