Source code for Pabq.modelers.bolt

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()