Search code examples
pythonabaqus

Extract strain at nodes specified in node set [Abaqus python odb access]


Given an Abaqus odb-file including a node set (e.g. 'ALL_SECS').

NODAL-quantities like coordinates ('COORD') or displacement ('U') can be extracted at the nodes of the node set by the following pattern:

  • select step, frame and fieldoutput (e.g. 'COORD', 'U')
  • getSubset(region=) of the fieldoutput
  • get attributes of the resulting values

How can INTEGRATION_POINT-quantities be extracted / interpolated at nodes of the node set? How can fieldoutput at NODAL-position be requested using abaqus-python?

from odbAccess import *
import numpy as np


# Helper function
def values_to_array(values, dim=2, item='data'):
    length = len(values)
    array = np.zeros((length, dim), dtype='float64')
    for index in range(length):
        array[index, :] = getattr(values[index], item)
    return array


# Prepare and open
odb = openOdb(path='job.odb')   # Solution of 2D-plane-stress model
instances = odb.rootAssembly.instances
instance = instances['PART']
sett = instance.nodeSets['ALL_SECS']
step = odb.steps.keys()[-1]


# Get coordinates and number of nodes in node set
frame = odb.steps[step].frames[-1]
values_xy = frame.fieldOutputs['COORD'].getSubset(region=sett).values
xy = values_to_array(values=values_xy, dim=2, item='dataDouble')

nbr_xy = len(values_xy)
print('len(values_xy)')
print(len(values_xy))

# Get nodal-quantity and number of nodes in node set
uvw = np.zeros((nbr_xy, 2), dtype=float)

outp = odb.steps[step].frames[-1].fieldOutputs['U']
values_u = outp.getSubset(region=sett).values
uvw = values_to_array(values=values_u, dim=2, item='dataDouble')
print('len(values_u)')
print(len(values_u))

eps = np.zeros((nbr_xy, 4), dtype=float)

outp = odb.steps[step].frames[-1].fieldOutputs['E']
values_eps = outp.getSubset(position=ELEMENT_NODAL, region=sett).values
# values_eps = outp.getSubset(position=ELEMENT_NODAL).getSubset(region=sett).values
print('len(values_eps)')
print(len(values_eps))

values_eps_nodal = outp.getSubset(position=NODAL, region=sett).values
print('len(values_eps_nodal)')
print(len(values_eps_nodal))

Output:

len(values_xy)
147
len(values_u)
147
len(values_eps)
408
len(values_eps_nodal)
0

Solution

  • The following solution is a workaround to get total strain (Fieldoutput 'E') at nodes, specified in the node set 'ALL_SECS'. As the order of the extracted nodes is not known, location information, i.e. coordinates of the nodes, is extracted as well. The i-th strain in eps is the strain at the i-th coordinate in xy. This feature seems not to exist in the Abaqus API. Node-specific data, like displacements, can easily be extracted, see uv. Key steps to extract strain data at element nodes and location:

    • Identify coordinates
    • Identify mapping nodeLabel -> index
    • Combine values at nodes, extrapolated from different elements using moving average. (See link for explanations)

    Note: 2D model odb

    
    from odbAccess import *
    
    import numpy as np
    import pickle
    from operator import attrgetter
    
    
    def values_to_array(values, dim=2, item='data', dtype=np.float64):
        '''Thanks to https://stackoverflow.com/a/46925902/8935243'''
        array = np.array(
                    map(attrgetter(item), values),
                    dtype=dtype,
                    )
        return array
    
    
    def values_to_index_mapping(values, item='nodeLabel', check=True):
        node_labels = values_to_array(values, dim=1, item=item, dtype=np.int64)
    
        if check:
            assert len(set(node_labels)) == len(node_labels)
    
        mapping = {}
        for index, label in enumerate(node_labels):
            mapping[label] = index
        return mapping
    
    
    odb = openOdb(path='job.odb')
    instances = odb.rootAssembly.instances
    instance = instances['PART']
    sett = instance.nodeSets['ALL_SECS']
    step = odb.steps.keys()[-1]
    
    # Coordinates
    frame = odb.steps[step].frames[-1]
    values = frame.fieldOutputs['COORD'].getSubset(region=sett).values
    xy = values_to_array(values=values, dim=2, item='data')
    
    # Dimensions
    nbr_xy = len(values)
    
    # Mapping: nodeLabel -> index
    index_map = values_to_index_mapping(values=values, check=True)
    
    # Displacements
    uv = np.zeros((nbr_xy, 2), dtype=float)
    outp = odb.steps[step].frames[-1].fieldOutputs['U']
    values = outp.getSubset(region=sett).values
    uv[:, :] = values_to_array(values=values, dim=2, item='data')
    
    # Strains
    eps = np.zeros((nbr_xy, 4), dtype=float)
    tmp = np.zeros((nbr_xy, 1), dtype=float)
    
    values_eps = odb.steps[step].frames[-1].fieldOutputs['E'].getSubset(
                            position=ELEMENT_NODAL,
                            region=sett,
                            ).values
        # Moving average, as ELEMENT_NODAL does no averaging
        # and returns multiple values for nodes in sett
        for ee in values_eps:
            index = index_map[ee.nodeLabel]
            tmp[index] += 1
            eps[index] = (eps[index] * (tmp[index] - 1) + ee.data) / tmp[index]
    
    odb.close()