2

I'm trying to optimize the porosity distribution of a certain material. I would like to visualize the results. I can visualize the different materials using 'visualize->material' however he gives every material a random color. I would like the least dense materials to be blue and the densest to be red. So the same as for the stress plots.

Is there a way to do this in Abaqus?

If there's no simple way to do this in the GUI, I was wondering would it be possible by using scripting? I tried to change a single color which resulted in the following code:

session.viewports['Viewport: 1'].enableMultipleColors()
session.viewports['Viewport: 1'].setColor(initialColor='#BDBDBD')
cmap=session.viewports['Viewport: 1'].colorMappings['Material']
session.viewports['Viewport: 1'].setColor(colorMapping=cmap)
session.viewports['Viewport: 1'].disableMultipleColors()
session.viewports['Viewport: 1'].enableMultipleColors()
session.viewports['Viewport: 1'].setColor(initialColor='#BDBDBD')
cmap = session.viewports['Viewport: 1'].colorMappings['Material']
cmap.updateOverrides(overrides={'IMPLANT_MATERIAL0':(True, '#FF0000', 
    'Default', '#FF0000')})
session.viewports['Viewport: 1'].setColor(colorMapping=cmap)
session.viewports['Viewport: 1'].disableMultipleColors()
session.viewports['Viewport: 1'].enableMultipleColors()
session.viewports['Viewport: 1'].setColor(initialColor='#BDBDBD')
cmap = session.viewports['Viewport: 1'].colorMappings['Material']
session.viewports['Viewport: 1'].setColor(colorMapping=cmap)
session.viewports['Viewport: 1'].disableMultipleColors()
dROOOze
  • 1,727
  • 1
  • 9
  • 17
ThaNoob
  • 520
  • 7
  • 23

2 Answers2

1

It's probably not the perfect method but this works. Limitations:

-You need to manually put in the amount of materials.

-Your materials should be ranked according to density(mat1,mat2->density1

-You should put your material name in the script (in my case it was 'Implant')

Suggestions for improvement are always welcome, this was just quick and dirty.

from math import floor

diminishing_factor = 10 #This factor diminishes the amount of colors to: 
amount of materials/diminishing factor. This is necessary
#because apparently abaqus can only handle a limited amount of colors (+-50)

def create_color_lst(amount_of_mat):

    color_lst=[]

    total_length = 256*4-1 #0 telt ook dus -1
    interval = floor(total_length/(amount_of_mat-1)) #*10 because we'll give 
    10 consequent materials the same color, because abaqus can't handle it
    for i in range(0,amount_of_mat):
        pos = int(floor(i/diminishing_factor))*diminishing_factor*interval
        if pos<256: #Green is rising
            col_pos=pos
            code = (0,col_pos,255)
        elif pos<512: #Blue is diminishing
            col_pos=pos-255
            code = (0,255,255-col_pos)
        elif pos<768:
            col_pos = pos - 511
            code = (col_pos,255,0)
        elif pos<1024:
            col_pos = pos - 767
            code = (255,255-col_pos,0)
        else:
            raise ValueError('Color position is too high: '+str(pos))
        hex_code='#%02x%02x%02x' % code
        color_lst.append(hex_code.upper())
    return color_lst

def update_colors(color_lst):
    session.viewports['Viewport: 1'].enableMultipleColors()
    session.viewports['Viewport: 1'].setColor(initialColor='#BDBDBD')
    cmap = session.viewports['Viewport: 1'].colorMappings['Material']
    for i in range(0,amount_of_mat):
        material = 'IMPLANT_MATERIAL'+str(i)
        cmap.updateOverrides(overrides={material:(True, color_lst[i],
            'Default', color_lst[i])})
        if i%10==0:
            print(i)
    session.viewports['Viewport: 1'].setColor(colorMapping=cmap)
    session.viewports['Viewport: 1'].disableMultipleColors()


amount_of_mat=494 #We can't get this you should always check this! (you 
probably could but I'm to lazy to search it)


color_lst = create_color_lst(amount_of_mat) #Creates a list with strings 
that contain the color names

update_colors(color_lst) #Updates the display (it's possible that you still 
need to go to the display color dialog and press apply)
ThaNoob
  • 520
  • 7
  • 23
1

If you're looking for something like stress plot visualisation, you'll have to write your own FieldOutput data. It's generally easier to output the data directly to an external visualiser, but it's possible (if not a bit convoluted) to do this in Abaqus.

The general process is this:

  1. Generate a FieldOutput object; syntax is FO = odbModel.steps.values()[-1].frames[-1].FieldOutput(name=data_name, description=data_description, type=SCALAR), where

    • odbModel is an opened Odb object,
    • steps.values()[-1] or a named step steps[...] is the step you want to output to,
    • frames[-1] is the last frame (or a frame of your choice) that you want to output to in this step,
    • data_name and data_description are strings (for stress contour plots, data_name would be equivalent to the label S in the odb output)
    • SCALAR is a parameter from the abaqusConstants module
  2. Get the rootAssembly.instance objects, and their associated element elementSets and sectionAssignments which have clear links to a section with a material which has a density attribute.

  3. Update the FieldOutput object with the addData command; syntax is addData(position=CENTROID, instance=instance, labels=labels, data=data)
    • CENTROID is a parameter from the abaqusConstants module (assuming you just want to have element densities at the element centroid; you can stick them at integration points too, if you really wanted)
    • instance is the instance associated with the element set (or more generally the region assigned with this material)
    • labels is an iterable (list, tuple) of integers specifying the element labels of the associated instance for which the data is to be written at
    • data is an iterable of iterables of floats, specifying the data. In your case, a single density value means that data is an iterable of length-1 iterables, each containing one value of density. The length of data must be equal to the length of labels, as each member of data exactly corresponds to the elementLabel in the same position in labels.

Example script below (WARNING: Heavily recommend backing up the .odb in case something didn't turn out right)

import odbAccess
from abaqusConstants import SCALAR, CENTROID # Import constants

odbModel = odbAccess.openOdb(odb_file_path) # Put the file path of the `odb` in odb_file_path

FO = odbModel.steps.values()[-1].frames[-1].FieldOutput(name='Density', description='', type=SCALAR)

# Loop through `rootAssembly.instances`
for instance in odbModel.rootAssembly.instances.values():

    valid_materials = [] # Valid material names which have `density`

    # Loop through `instance.sectionAssignments` to check if the associated `section` has a `material` with the attribute `density`
    for i in range(len(instance.sectionAssignments)):
        sectionName = instance.sectionAssignments[i].sectionName
        matName = odbModel.sections[sectionName].material
        if hasattr(odbModel.materials[matName], 'density'):
            valid_materials.append(matName)

    sectionNames = [] # Build list of valid section names which are associated with a material which has the attribute `density`

    for s in odbModel.sections.values():
        if s.material in valid_materials:
            sectionNames.append(s.name)

    if sectionNames:

        # Loop through `sectionAssignments` and get all the `elementLabels` in the `region` of the `sectionAssignment`
        for sa in instance.sectionAssignments:
            sa_labels = []
            if sa.sectionName in sectionNames:

                # Get labels
                if sa.region.elements is not None:
                    for e in sa.region.elements:
                        sa_labels.append(e.label)

                # Get material
                matName = odbModel.sections[sa.sectionName].material
                sa_data = [(odbModel.materials[matName].density.table[0][0],)]*len(sa_labels)

                # Update `fieldOutput` object
                FO.addData(position=CENTROID, instance=instance, labels=sa_labels, data=sa_data)

# Save odb model. The FieldOutput object only exists as reference from `FO` unless the odb model is saved.
odbModel.save()
odbModel.close()
odbModel = odbAccess.openOdb(odb_file_path) # Reopen the model for visualisation. If you can't find the data_name in the list, expand the model to the step and frame for which the data is saved.

I don't work with density, but here's an example output for Young's modulus for a model with two materials assigned to various elements.

enter image description here

dROOOze
  • 1,727
  • 1
  • 9
  • 17
  • Wow again, thanks for the elaborate answer! In the beginning you mention that an external visualizer could be better. What would you recommend, something like Matlab, or rather some sort of 3D pyplot? – ThaNoob Mar 29 '18 at 12:55
  • @ThaNoob I mean that an external visualiser could be conceptually easier to use so that you don't have to dig too deeply into the ABAQUS documentation. It hinges on whether you know of a program which just reads in coordinate data and associated values and plots something out of that. The `fieldOutput` object isn't too bad once you become familiar with it, but do note that if you rely on this you'll be limited to using the CAE GUI, which for larger models could be much slower than an external visualiser designed specifically to read floating point data and plot coloured shapes – dROOOze Mar 29 '18 at 13:12
  • 1
    I tested your code and it works like a charm! Thank you very much! – ThaNoob Apr 02 '18 at 13:53
  • @Drooze, I'm trying to do exactly the same but for some shear stresses I calculated at several nodes. I have a list of node labels in the form of ints and a list of data in the form of floats. I know that I have to use this command: `FO.addData(position=NODAL, instance=instance, labels=label_lst, data=new_data_lst)` but the problem is in the types. data should be an Odb_sequencesequence float. How do I get such an object? I just have normal floats – ThaNoob Apr 19 '18 at 00:36
  • @ThaNoob Can you provide a sample of your shear stress data? – dROOOze Apr 19 '18 at 01:16
  • @Drooze this is a sample of the 10 first nodes: shear stress `[1.70248502545635, 0.913820016051841, 0.939478923170327, 0.0211083436266735, 0.484296009733275, 0.46943971002954, 0.271536055524783, 2.51726160787855e-08, 2.27564335208046, 0.411697209887649]` these are all floats. And then I have another list of node labels in the form of ints. Is this what you needed? – ThaNoob Apr 19 '18 at 07:27
  • 1
    @ThaNoob shear stress is not usually one number (unless you're doing 2D computations, or computing an equivalent stress formulation), but for the sake of your visualisation problem, if `numpy.size(new_data_lst) == numpy.size(label_lst)`, then you have to construct an inner dimension in `new_data_lst` for each of the floats, e.g. `[(1.70248502545635,), (0.913820016051841,), (0.939478923170327,), (0.0211083436266735,), ...]` This is what `_sequencesequence` means - a sequence of sequences of floats, so each of the values needs to be a sequence of length 1. – dROOOze Apr 19 '18 at 07:34
  • 1
    sorry I was unclear there: the calculated values are the magnitudes of the shear stresses normal to a surface in the nodes of that surface. I tried what you told me and once again it worked perfectly! Just adding `new_data_lst = [(data,) for data in data_lst]` did the trick! :D – ThaNoob Apr 19 '18 at 09:12