问题
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()
回答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:
Generate a
FieldOutput
object; syntax isFO = odbModel.steps.values()[-1].frames[-1].FieldOutput(name=data_name, description=data_description, type=SCALAR)
, whereodbModel
is an openedOdb
object,steps.values()[-1]
or a named stepsteps[...]
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
anddata_description
are strings (for stress contour plots,data_name
would be equivalent to the labelS
in the odb output)SCALAR
is a parameter from theabaqusConstants
module
Get the
rootAssembly.instance
objects, and their associated elementelementSet
s andsectionAssignment
s which have clear links to asection
with amaterial
which has adensity
attribute.- Update the
FieldOutput
object with theaddData
command; syntax isaddData(position=CENTROID, instance=instance, labels=labels, data=data)
CENTROID
is a parameter from theabaqusConstants
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 theregion
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 atdata
is an iterable of iterables offloat
s, specifying the data. In your case, a single density value means thatdata
is an iterable of length-1 iterables, each containing one value of density. The length ofdata
must be equal to the length oflabels
, as each member ofdata
exactly corresponds to theelementLabel
in the same position inlabels
.
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.
回答2:
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)
来源:https://stackoverflow.com/questions/49509158/abaqus-visualize-density