Finding Hot Spots

For a solved Static Structural that includes an Equivalent Stress result, this script finds the locations where high stresses occur and places a label on them. Here is an illustrated example.

The script specifies the insertion of seven labels. The script places the first label at the result’s maximum value, and each subsequent label is placed at a distance of 0.01 (script line 25) in between each node. This distance between labels makes sure that all labels will not be clustered around the maximum value. The unit for this distance is based on what you have selected in your analysis. For the example above, the selected unit is meters. In addition, and again based on the currently selected unit of measure, the result threshold is 20 (script line 27). This means that no result value (or label) below this threshold is included.

import mech_dpf
import Ans.DataProcessing as dpf

def nodeDist(cur_node,nodes_dict,test_dist):
    # Compute distance between a reference node (cur_node) and 
    # a set of nodes nodes_dict and check vs a test distance (test_dist)
    # if any of the nodes in nodes_dict is close to cur_node within
    # less than test_dist, then return False. Otherwise cur_node is 
    # away from each node in nodes_dict by at least test_dist
    test=True
    for nodeId in nodes_dict.keys():
        test_node=nodes_dict[nodeId]
        dist=0.
        for i in range(0,3):
            dist+=(test_node[i]-cur_node[i])**2
        if (dist<=test_dist**2):
            test=False
            break
        
    return test

# Number of labels to display
numLabels=7
# Minimal distance between two labels (in current Mechanical unit)
minDistBetweenNodes=0.1
# Minimal stress value for which label should be displayed (in current Mechanical Unit)
thresholdStress=20.

# Dictionaries to store results
maxPairs={}
maxNodes={}

# Retrieve 'Static Structural' analysis - replace analysis name
# based on your current model
analysis=ExtAPI.DataModel.AnalysisByName('Static Structural')
# Retrieve first 'Equivalent Stress' object. replace object name
# based on your current model
resultObject=ExtAPI.DataModel.GetObjectsByName('Equivalent Stress')[0]

# Define datasources (rst from analysis)
dataSource = dpf.DataSources(analysis.ResultFileName)
# Create Mises operator
vmises = dpf.operators.result.stress_von_mises()
vmises.inputs.data_sources.Connect(dataSource)

# retrieve mesh from rst
model=dpf.Model(dataSource)
mesh=model.Mesh

# Min_max operator will be used to identify hotspots
min_max = dpf.operators.min_max.min_max() # operator instanciation

# Temporary operator
currentMises = vmises.outputs.getfields_container()

# Filter used to progressively filter data when maxima are found
tempFilter = dpf.operators.filter.field_low_pass() # operator instanciation

# Filter out stresses below thresholdStress
initFilter = dpf.operators.filter.field_high_pass() # operator instanciation
initFilter.inputs.field.Connect(currentMises)
initFilter.inputs.threshold.Connect(thresholdStress)

# update currentMises with results from filter
currentMises = initFilter.outputs.getfield()

if not(currentMises.Data):
    ExtAPI.Application.LogWarning('Threshold value exceeds maximum stress. Please set a lower value for "thresholdStress" variable ')

# Start looking for hotspots
numFound=0
while numFound<numLabels and currentMises.Data:
    # in current stress field, search for max value
    min_max.inputs.field.Connect(currentMises)
    maxData = min_max.outputs.field_max.GetData()
    
    # Check whether scoping node is far from other nodes
    if numFound>0:
        # at least one label was found, we need to check for distance
        maxNodeId=maxData.ScopingIds[0]
        maxValue=maxData.Data[0]
        # Retrieve information from node at max value out of result mesh 
        node=mesh.NodeById(maxNodeId)
        nodeCoord=[node.X, node.Y,node.Z]        
        if nodeDist(nodeCoord,maxNodes,minDistBetweenNodes): 
            # node if node is far enough from all other nodes, add to labels
            # otherwise, we simply ignore this maximum
            maxNodes[maxNodeId]=nodeCoord
            maxPairs[maxValue]=maxNodeId
            numFound+=1
    else:
        # first label at maximum value
        # Retrieve max value and corresponding node from maxData operator
        maxValue=maxData.Data[0]
        maxNodeId=maxData.ScopingIds[0]
        # Start population data in maxPairs (maxvalue:node id)
        # and maxNodes (node id: x,y,z)
        maxPairs[maxValue]=maxNodeId
        node=mesh.NodeById(maxNodeId)
        maxNodes[maxNodeId]=[node.X, node.Y,node.Z]
        numFound+=1
    
    # Filter out anything above last max value from currentMises
    tempFilter.inputs.field.Connect(currentMises)
    tempFilter.inputs.threshold.Connect(maxValue)    
    currentMises = tempFilter.outputs.getfield()
    
if numFound<numLabels and numFound>0:
    ExtAPI.Application.LogWarning('Could not find more than '+str(numFound)+' hotspots. You should set "thresholdStress" variable or "minDistBetweenNodes" to lower values')
    
if numFound==0:
    ExtAPI.Application.LogWarning('Could not find any hotspots. You should set "thresholdStress" variable or "minDistBetweenNodes" to lower values')
else:
    # Create labels on result object    
    with Transaction():
        labelsForRes = Graphics.LabelManager.GetObjectLabels(resultObject)
        Graphics.LabelManager.DeleteLabels(labelsForRes)
        for node in maxPairs.values():
            probeLabel = Graphics.LabelManager.CreateProbeLabel(resultObject)
            probeLabel.Scoping.Node = node