A bolted joint is a classical engineering problem.
Joints are often very challenging in mechanical design, and a bolted joint is not an exception. The challenge requires particular care in lightweight design where composites and other lightweight materials are used. These materials do not permitt the bolts to be tightened such that the load is primarilly transferred through shear between the members. Rather, the bolted solution must rely on bearing between the bolt and the part(s).
The current example assumes the latter in an experimental configuration as illustrated below:
Symmetry about half the length of the plate is assumed, and the bolt is simplified to a discret rigid cylinder being infinitely stiff.
The problem is included as a case study in the course TMM4175 Lightweight Design and discussed further there.
from abaqus import *
from abaqusConstants import *
from part import EdgeArray
def isapprox(val1,val2,tol=1E-3): return True if abs(val1-val2) < tol else False
def getByPO(seq, x=None, y=None, z=None):
result = seq[0:0]
for item in seq:
xp, yp, zp = item.pointOn[0]
xt = True if x==None else isapprox(x,xp)
yt = True if y==None else isapprox(y,yp)
zt = True if z==None else isapprox(z,zp)
if xt and yt and zt:
result = result + seq[item.index:item.index+1]
return result
def getByR(seq, r=None):
result = seq[0:0]
for item in seq:
try:
radius = item.getRadius()
if r==None:
result = result + seq[item.index:item.index+1]
else:
if isapprox(radius,r):
result = result + seq[item.index:item.index+1]
except:
pass
return result
def boltedJoint(modelname, L, b, d, r, dr, t, esize, ner, nec, net, Fx):
'''
L: total length of the plate
b: width of the plate
d: distance from center of hole to the end of the plate
r: radius of the hole
dr: additional radius for the cylindrical region surrounding the hole
t: thickness of the plate
esize: global element size of the plate
ner: number of elements radially for the cylindrical region
nec: number of elements along circular edges
net: number of elements through the thickness
Fx: applied force on the bolt
'''
mod = mdb.Model(name=modelname)
# --------------------
# The plate with hole
# --------------------
ske = mod.ConstrainedSketch(name='__profile__', sheetSize=200.0)
ske.rectangle(point1=(-d, -0.5*b), point2=(L-d, 0.5*b))
ske.CircleByCenterPerimeter(center=(0, 0), point1=(r, 0))
prt1 = mod.Part(name='Plate', dimensionality=THREE_D, type=DEFORMABLE_BODY)
prt1.BaseSolidExtrude(sketch=ske, depth=t)
del mod.sketches['__profile__']
prt1.DatumCsysByDefault(coordSysType=CARTESIAN)
# Partitions
prt1.WirePolyLine(points=(((r+dr,0.0,0.0), (r+dr,0.0,t)),), mergeType=IMPRINT, meshable=ON)
e1=getByPO(prt1.edges, x=r+dr)[0]
e2=getByR(prt1.edges)[0]
prt1.PartitionCellBySweepEdge(sweepPath=e2, cells=prt1.cells, edges=(e1,))
id1 = prt1.DatumPlaneByPrincipalPlane(principalPlane=YZPLANE, offset=0).id
id2 = prt1.DatumPlaneByPrincipalPlane(principalPlane=YZPLANE, offset=d).id
id3 = prt1.DatumPlaneByPrincipalPlane(principalPlane=XZPLANE, offset=0).id
prt1.PartitionCellByDatumPlane(cells=prt1.cells, datumPlane=prt1.datums[id1])
prt1.PartitionCellByDatumPlane(cells=prt1.cells, datumPlane=prt1.datums[id2])
prt1.PartitionCellByDatumPlane(cells=prt1.cells, datumPlane=prt1.datums[id3])
# Mesh
prt1.seedPart(size=esize, deviationFactor=0.1, minSizeFactor=0.1)
prt1.seedEdgeByNumber(edges=prt1.edges.findAt(coordinates=((r+0.5*dr,0,0),)),
number=ner, constraint=FINER)
prt1.seedEdgeByNumber(edges=getByR(prt1.edges), number=nec, constraint=FINER)
prt1.seedEdgeByNumber(edges=prt1.edges.findAt(coordinates=((r,0,0.5*t),)),
number=net, constraint=FINER)
prt1.generateMesh()
# Material and section
mat = mod.Material(name='Some polymer')
mat.Elastic(table=((2000.0, 0.35), ))
mod.HomogeneousSolidSection(name='Plate section', material='Some polymer', thickness=None)
prt1.SectionAssignment(region=prt1.Set(name='cells', cells=prt1.cells), sectionName='Plate section')
# ---------
# The bolt
# ---------
ske = mod.ConstrainedSketch(name='__profile__', sheetSize=200.0)
ske.CircleByCenterPerimeter(center=(0.0, 0.0), point1=(r, 0.0))
prt2 = mod.Part(name='Bolt', dimensionality=THREE_D, type=DISCRETE_RIGID_SURFACE)
prt2.BaseShellExtrude(sketch=ske, depth=t*1.1)
del mod.sketches['__profile__']
# Partitions
id1 = prt2.DatumPlaneByPrincipalPlane(principalPlane=YZPLANE, offset=0.0).id
id2 = prt2.DatumPlaneByPrincipalPlane(principalPlane=XZPLANE, offset=0.0).id
prt2.PartitionFaceByDatumPlane(datumPlane=prt2.datums[id1], faces=prt2.faces)
prt2.PartitionFaceByDatumPlane(datumPlane=prt2.datums[id2], faces=prt2.faces)
# Mesh
prt2.setMeshControls(regions=prt2.faces, elemShape=QUAD, technique=STRUCTURED)
prt2.seedEdgeByNumber(edges=getByR(prt2.edges), number=nec, constraint=FINER)
e1 = EdgeArray([e for e in prt2.edges if e.pointOn[0][2] > 0 and e.pointOn[0][2]<t])
prt2.seedEdgeByNumber(edges=e1, number=net, constraint=FINER)
prt2.generateMesh()
# ---------
# Assembly
# ---------
ass = mod.rootAssembly
ass.DatumCsysByDefault(CARTESIAN)
ins1 = ass.Instance(name='Plate', part=prt1, dependent=ON)
ins2 = ass.Instance(name='Bolt', part=prt2, dependent=ON)
ass.translate(instanceList=('Bolt', ), vector=(0.0, 0.0, -t*0.05))
# Interactions
# NOTE: from 2022 the argument 'master' has become 'main'
# and 'slave' is 'secondary', according to the woke dictionary.
# For some unknown reasons, PENALTY is kept....
region1 = ass.Surface(name='hole', side1Faces=getByR(ins1.faces, r=r))
region2 = ass.Surface(name='bolt', side1Faces=getByR(ins2.faces))
cp = mod.ContactProperty('cp-1')
cp.TangentialBehavior(formulation=PENALTY, table=((0.2,),), fraction=0.005)
mod.SurfaceToSurfaceContactStd(name='contact', createStepName='Initial',
master=region2, slave=region1, sliding=FINITE, interactionProperty='cp-1')
rfid = ass.ReferencePoint(point=(0.0, 0.0, t/2.0)).id
reg_rf = ass.Set(name='rf rb', referencePoints = (ass.referencePoints[rfid],))
reg_rb = ass.Set(name='faces bolt', faces=ins2.faces)
mod.RigidBody(name='Constraint-1', refPointRegion=reg_rf, bodyRegion=reg_rb)
# Steps and loading:
mod.StaticStep(name='Step-1', previous='Initial', nlgeom=ON)
mod.DisplacementBC(name='bc bolt', createStepName='Step-1', region=reg_rf,
u2=0.0, u3=0.0, ur1=0.0, ur2=0.0, ur3=0.0)
reg_fix_ux = ass.Set(name='faces fix ux', faces=getByPO(ins1.faces, x=L-d))
mod.DisplacementBC(name='fix ux', createStepName='Step-1', region=reg_fix_ux, u1=0.0)
mod.ConcentratedForce(name='Fx', createStepName='Step-1', region=reg_rf, cf1=-Fx)
# Job and results
job = mdb.Job(name=modelname, model=modelname)
job.submit(consistencyChecking=OFF)
boltedJoint(modelname='M1', L=100.0, b=50.0, d=25.0, r=8.0, dr=4.0, t=6.0,
esize=1.5, ner=8, nec=20, net=6, Fx=1E4)