├── README.md ├── aba-ss.py └── odb2vtk.py /README.md: -------------------------------------------------------------------------------- 1 | # abaqus-py 2 | My python scripts for ABAQUS 3 | -------------------------------------------------------------------------------- /aba-ss.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Python functions to get stress--strain data 3 | from ABAQUS output database (odb). 4 | 5 | Author (unless otherwise stated) 6 | Marat I. Latypov 7 | Georgia Tech Lorraine 8 | marat.latypov@georgiatech-metz.fr 9 | ''' 10 | 11 | from abaqus import * 12 | from abaqusConstants import * 13 | from odbAccess import * 14 | import __main__ 15 | 16 | import numpy as np 17 | import math 18 | import sys 19 | import timeit 20 | 21 | def mequit(f): 22 | f.close() 23 | sys.exit('Script exited with an error') 24 | 25 | def getScalarData(varName, myFrame, varField, myInstance, numElements): 26 | ''' Read scalar data for requested time frame, instance and average over IPs.''' 27 | 28 | aveScalar = np.zeros((numElements)) 29 | 30 | numIntPts = len(varField.getSubset(region=myInstance.elements[0]).values) 31 | scalarData = np.zeros((numIntPts)) 32 | for el in range(0,numElements): 33 | # Isolate current and previous element's stress field 34 | abaVar = varField.getSubset(region=myInstance.elements[el]).values 35 | 36 | for ip,ipValue in enumerate(abaVar): 37 | scalarData[ip] = ipValue.data 38 | 39 | # Average the variable values for the element 40 | aveScalar[el] = np.average(scalarData,axis=0) 41 | 42 | return aveScalar 43 | 44 | def getSymTensorData(varName, myFrame, myInstance, mySet, numElements): 45 | ''' Read symmetric tensor data for requested time frame, instance, set and average over IPs.''' 46 | 47 | varField = myFrame.fieldOutputs[varName] 48 | field = varField.getSubset(region=mySet, position=CENTROID) 49 | 50 | numIntPts = len(varField.getSubset(region=myInstance.elements[0]).values) 51 | numComps = len(varField.getSubset(region=myInstance.elements[0]).values[0].data) 52 | tensorData = np.zeros((numIntPts,numComps)) 53 | aveTensor = np.zeros((numElements,numComps)) 54 | 55 | for el in range(0,numElements): 56 | # Isolate current and previous element's stress field 57 | abaVar = varField.getSubset(region=myInstance.elements[el]).values 58 | 59 | for ip,ipValue in enumerate(abaVar): 60 | for icomp,component in enumerate(ipValue.data): 61 | tensorData[ip,icomp] = ipValue.data[icomp] 62 | 63 | # Average the variable values for the element 64 | aveTensor[el,:] = np.average(tensorData,axis=0) 65 | return aveTensor 66 | 67 | def getFullTensorData(tensorData): 68 | ''' Recover full tensor (9 components) for a symmetric tensor (6 components).''' 69 | 70 | tensorFull = np.zeros((tensorData.shape[0],9)) 71 | tensorFull[:,0] = tensorData[:,0] 72 | tensorFull[:,1] = tensorData[:,3] 73 | tensorFull[:,2] = tensorData[:,4] 74 | 75 | tensorFull[:,3] = tensorData[:,3] 76 | tensorFull[:,4] = tensorData[:,1] 77 | tensorFull[:,5] = tensorData[:,5] 78 | 79 | tensorFull[:,6] = tensorData[:,4] 80 | tensorFull[:,7] = tensorData[:,5] 81 | tensorFull[:,8] = tensorData[:,2] 82 | 83 | return tensorFull 84 | 85 | def Mises(what,tensor): 86 | ''' Calulate von Mises value for stress or strain tensor. 87 | Source: DAMASK (http://damask.mpie.de).''' 88 | 89 | # Get deviatoric tensor 90 | dev = tensor - np.trace(tensor)/3.0*np.eye(3) 91 | 92 | # Symmetrize 93 | symdev = 0.5*(dev+dev.T) 94 | 95 | # Get Mises value 96 | return math.sqrt(np.sum(symdev*symdev.T)* 97 | { 98 | 'stress': 3.0/2.0, 99 | 'strain': 2.0/3.0, 100 | }[what.lower()]) 101 | 102 | def getMises(what,tensArray): 103 | ''' Average strain or stress components over elements and pass them for calculation ofMises values.''' 104 | 105 | tCompAve = np.zeros(9) 106 | # Loop over components and find their spatial averages 107 | for iComp in range(9): 108 | tCompAve[iComp] = np.average(tensArray[:,iComp]) 109 | 110 | # Call function for calculation of Mises values 111 | eq = Mises(what,np.reshape(tCompAve,(3,3))) 112 | return eq 113 | 114 | def odb2ss(fileName,instanceName=None,mySetName=None): 115 | ''' Read stress, strain tensors from the odb for 116 | all available time frames, average the components over 117 | all elements and get equivalent stress and strain.''' 118 | 119 | tic = timeit.default_timer() 120 | 121 | # Open file for status messages 122 | f = open('out_aba-ss.txt','w') 123 | 124 | # Open the odb 125 | try: 126 | odbPath = fileName + '.odb' 127 | myOdb = session.openOdb(name=odbPath) 128 | except OdbError: 129 | msg = 'ERROR! Failed to open odb at %s\n' % odbPath 130 | f.write(msg) 131 | mequit(f) 132 | 133 | msg = 'odb was successfully opened at %s\n' % odbPath 134 | f.write(msg) 135 | 136 | # The first instance is default if not provided 137 | if instanceName == None: 138 | instanceName = myOdb.rootAssembly.instances.keys()[0] 139 | 140 | # 'AllElements' set is default if not provided 141 | if mySetName == None: 142 | mySetName = 'ALLELEMENTS' 143 | 144 | # Name the Step object for convenience 145 | myStepName = myOdb.steps.keys()[0] 146 | myStep = myOdb.steps[myStepName] 147 | msg = 'Working with step %s and instance %s\n' % (myStepName, instanceName) 148 | f.write(msg) 149 | 150 | # Check if the instance exists 151 | instanceNames = myOdb.rootAssembly.instances.keys() 152 | if instanceName not in instanceNames: 153 | instanceList = '\n'.join(iInstance for iInstance in instanceNames) 154 | msg = '\nERROR!\nInstance %s was not found! Available instances in the odb:\n%s' % (instanceName, instanceList) 155 | f.write(msg) 156 | mequit(f) 157 | else: 158 | # Get Instance object 159 | myInstance = myOdb.rootAssembly.instances[instanceName] 160 | 161 | # Check if the set exists 162 | setNames = myOdb.rootAssembly.instances[instanceName].elementSets.keys() 163 | if mySetName not in setNames: 164 | setList = str(setNames) 165 | msg = '\nERROR!\nElement set %s was not found! Available sets in the odb:\n%s' % (mySetName, setList) 166 | f.write(msg) 167 | mequit(f) 168 | else: 169 | # Get Set object 170 | mySet = myInstance.elementSets[mySetName] 171 | 172 | # Get total number of elements, nodes, time frames 173 | numElements = len(myInstance.elements) 174 | numNodes = len(myInstance.nodes) 175 | numFrames = len(myStep.frames) 176 | 177 | f.write('Number of frames: %s\n' % str(numFrames)) 178 | 179 | # Allocate arrays for equivalent values 180 | eqStress = np.zeros(numFrames) 181 | eqStrain = np.zeros(numFrames) 182 | # eqRate = np.zeros(numFrames) 183 | 184 | 185 | # Start loop over time frames 186 | for iframe in range(0,numFrames): 187 | 188 | # Get object for current time frame 189 | myFrame = myStep.frames[iframe] 190 | f.write('Current time frame: %7.4f\n' % myFrame.frameValue) 191 | 192 | # Get stress tensor for current frame 193 | varName = 'S' 194 | tensor = getSymTensorData(varName, myFrame, myInstance, mySet, numElements) 195 | s = getFullTensorData(tensor) 196 | 197 | # Get equivalent stress 198 | eqStress[iframe] = getMises('stress',s) 199 | 200 | # # Get strain rate tensor for current frame 201 | # varName = 'ER' 202 | # tensor = getSymTensorData(varName, myFrame, myInstance, mySet, numElements) 203 | # rate = getFullTensorData(tensor) 204 | 205 | # # Get equivalent strain rate 206 | # eqRate[iframe] = getMises('strain',rate) 207 | 208 | # Get strain 209 | varName = 'LE' 210 | tensor = getSymTensorData(varName, myFrame, myInstance, mySet, numElements) 211 | strain = getFullTensorData(tensor) 212 | 213 | # Get equivalent strain 214 | eqStrain[iframe] = getMises('strain',strain) 215 | 216 | toc = timeit.default_timer() 217 | 218 | msg = 'Done with %s, spent %.2f min' % (fileName, (toc-tic)/60.0) 219 | f.write(msg) 220 | 221 | f.close() 222 | return eqStress, eqStrain 223 | -------------------------------------------------------------------------------- /odb2vtk.py: -------------------------------------------------------------------------------- 1 | from abaqus import * 2 | from abaqusConstants import * 3 | from odbAccess import * 4 | import __main__ 5 | 6 | import numpy as np 7 | import sys 8 | 9 | def mequit(f): 10 | f.close() 11 | sys.exit('Script exited with an error') 12 | 13 | def writeVtkMesh(vtkFileName,myInstance,numNodes,numElements,myFrame): 14 | 15 | vtkFile = open(vtkFileName, 'w') 16 | vtkFile.write('# vtk DataFile Version 2.0\n') 17 | vtkFile.write('Reconstructed Lagrangian Field Data\n') 18 | vtkFile.write('ASCII\n\n') 19 | vtkFile.write('DATASET UNSTRUCTURED_GRID\n') 20 | 21 | # Get the initial nodal coordinates 22 | initialCoords = np.ndarray(shape=(3,numNodes)) 23 | for nd in range(0, numNodes): 24 | coords = myInstance.nodes[nd].coordinates 25 | for iCoor, coord in enumerate(coords): 26 | initialCoords[iCoor,nd] = coord 27 | 28 | elementConnectivity = [] 29 | for el in range(0, numElements): 30 | con = myInstance.elements[el].connectivity 31 | elementConnectivity.append(con) 32 | 33 | totalNumNodes = numNodes 34 | totalNumElements = numElements 35 | 36 | # Print out all the coordinates to the vtk file 37 | vtkFile.write('POINTS %i float\n' % (totalNumNodes)) 38 | 39 | r = np.ndarray(shape=(3,numNodes)) 40 | 41 | # Isolate the displacement field 42 | displacements = myFrame.fieldOutputs['U'].getSubset(region=myInstance).values 43 | 44 | # Add displacements to the initial coordinates 45 | for nd in range(0, numNodes): 46 | for iCoor in range(0,3): 47 | r[iCoor,nd] = initialCoords[iCoor,nd] + displacements[nd].data[iCoor] 48 | vtkFile.write('%f\t' % (r[iCoor,nd])) 49 | vtkFile.write('\n') 50 | 51 | # Print out all the elements to the vtk file 52 | vtkFile.write('\nCELLS %i %i\n' % (totalNumElements, 9*totalNumElements)) 53 | for el in range(0,numElements): 54 | numNodesEl = len(elementConnectivity[el]) 55 | n = [0]*numNodesEl 56 | vtkFile.write('%i\t' % numNodesEl) 57 | for iNode, node in enumerate(elementConnectivity[el]): 58 | n[iNode] = node - 1 59 | vtkFile.write('%i\t' % n[iNode]) 60 | vtkFile.write('\n') 61 | 62 | # Print out all the cell types to the vtk file 63 | vtkFile.write('\nCELL_TYPES %i\n' % (totalNumElements)) 64 | for el in range(0,totalNumElements): 65 | vtkFile.write('12\n') 66 | 67 | vtkFile.write('\nCELL_DATA %i' % (totalNumElements)) 68 | 69 | vtkFile.close() 70 | 71 | def getScalarData(varName, myFrame, varField, myInstance, numElements): 72 | 73 | # vtkFile.write('\nTENSORS %s float\n' % varName) 74 | aveScalar = np.zeros((numElements)) 75 | 76 | numIntPts = len(varField.getSubset(region=myInstance.elements[0]).values) 77 | scalarData = np.zeros((numIntPts)) 78 | for el in range(0,numElements): 79 | # Isolate current and previous element's stress field 80 | abaVar = varField.getSubset(region=myInstance.elements[el]).values 81 | 82 | for ip,ipValue in enumerate(abaVar): 83 | scalarData[ip] = ipValue.data 84 | 85 | # Average the variable values for the element 86 | aveScalar[el] = np.average(scalarData,axis=0) 87 | 88 | return aveScalar 89 | 90 | def getSymTensorData(varName, myFrame, varField, myInstance, numElements): 91 | 92 | # vtkFile.write('\nTENSORS %s float\n' % varName) 93 | 94 | 95 | numIntPts = len(varField.getSubset(region=myInstance.elements[0]).values) 96 | numComps = len(varField.getSubset(region=myInstance.elements[0]).values[0].data) 97 | tensorData = np.zeros((numIntPts,numComps)) 98 | aveTensor = np.zeros((numElements,numComps)) 99 | 100 | for el in range(0,numElements): 101 | # Isolate current and previous element's stress field 102 | abaVar = varField.getSubset(region=myInstance.elements[el]).values 103 | 104 | for ip,ipValue in enumerate(abaVar): 105 | for icomp,component in enumerate(varAtPt.data) 106 | tensorData[ip,icomp] = ipValue.data[icomp] 107 | 108 | # Average the variable values for the element 109 | aveTensor[el,:] = np.average(tensorData,axis=0) 110 | return aveTensor 111 | 112 | 113 | def writeTensorData(vtkFileName, tensorData, tensorName): 114 | 115 | with open(vtkFileName,'a') as vtkFile: 116 | vtkFile.write('\nTENSORS %s float\n' % tensorName) 117 | np.savetxt(vtkFile, tensorData, fmt='%.4f', delimiter=' ') 118 | 119 | fileName = 'sdv-test' 120 | # varNames = ['SDV14', 'SDV15', 'SDV16', 'SDV17', 'SDV18', 'SDV19', 'SDV20', 'SDV21', 'SDV22'] 121 | varNames = ['S','PEEQ'] 122 | instanceName = None 123 | 124 | f = open('odb2vtk.out','w') 125 | 126 | # Open the odb and request re-input if the odb is not found 127 | try: 128 | odbPath = fileName + '.odb' 129 | myOdb = session.openOdb(name=odbPath) 130 | except OdbError: 131 | f.write('ERROR! Correct path to odb was not provided\n') 132 | mequit(f) 133 | 134 | msg = 'odb is successfully opened at %s\n' % odbPath 135 | f.write(msg) 136 | 137 | # The first instance is default if not provided 138 | if instanceName == None: 139 | instanceName = myOdb.rootAssembly.instances.keys()[0] 140 | 141 | # Name the Step object for convenience 142 | myStepName = myOdb.steps.keys()[0] 143 | myStep = myOdb.steps[myStepName] 144 | msg = 'Working with step %s and instance %s\n' % (myStepName, instanceName) 145 | f.write(msg) 146 | 147 | # Check if the given instance exists and request re-input if it doesn't 148 | instanceNames = myOdb.rootAssembly.instances.keys() 149 | if instanceName not in instanceNames: 150 | instanceList = '\n'.join(iInstance for iInstance in instanceNames) 151 | msg = '%s was not found! \nRe-input the instance name. \nInstances in the odb:\n%s' % (instanceName, instanceList) 152 | f.write(msg) 153 | mequit(f) 154 | 155 | myInstance = myOdb.rootAssembly.instances[instanceName] 156 | numElements = len(myInstance.elements) 157 | numNodes = len(myInstance.nodes) 158 | numFrames = len(myStep.frames) 159 | time = [0] 160 | 161 | f.write('Number of frames: %s\n' % str(numFrames)) 162 | 163 | mySet = myOdb.rootAssembly.instances[instanceName].elementSets['ALLELEMENTS'] 164 | 165 | velGrdData = np.zeros((numElements,9)) 166 | 167 | for iframe in range(1,numFrames): 168 | vtkFileName = '%s-%03d.vtk' % (fileName, iframe) 169 | 170 | myFrame = myStep.frames[iframe] 171 | time[0] = myFrame.frameValue 172 | 173 | f.write('%7.4f\n' % time[0]) 174 | f.write(vtkFileName + '\n') 175 | 176 | writeVtkMesh(vtkFileName,myInstance,numNodes,numElements,myFrame) 177 | 178 | for i,ivar in enumerate(varNames): 179 | varField = myFrame.fieldOutputs[ivar] 180 | field = varField.getSubset(region=mySet, position=CENTROID) 181 | 182 | print str(field.type) 183 | 184 | if str(field.type) == 'SCALAR': 185 | scalar = getScalarData(ivar, myFrame, varField, myInstance, numElements) 186 | writeScalarData(vtkFileName, velGrdData, ivar) 187 | if str(field.type) == '3D_TENSOR': 188 | scalar = getScalarData(ivar, myFrame, varField, myInstance, numElements) 189 | writeTensorData(vtkFileName, velGrdData, ivar) 190 | 191 | f.close() --------------------------------------------------------------------------------