Structural Analysis for Dynamo - Panel Surface Loads

Hello dynamo users,

I ran through the AU example of a water retention structure, which essentially creates a cylinder geometry then ports that into dynamo as analytical panels.

So I decided to throw some supports on and then try add some loads from within dynamo, but ran into the problem of applying surface loads.

After trying for a while, I can not come up with a good solution to apply surface loads.

Can anyone spare some advice/have some ideas?

Thanks thanks :slight_smile:

Which AU example? Might be able to tag the author if we knew which parts you were working off.

Hi Jacob,

Thanks for your reply.

The class was from Emmanuel Weyermanns “Optimizing Structural Analysis with Dynamo”.
(https://www.autodesk.com/autodesk-university/class/Optimizing-Structural-Analysis-Dynamo-2015)

The example goes through geometry creation in Dynamo, which is then pushed to Robot. Then the creation of a custom support type using a python script node and referencing the Robot API. My issue is figuring out how to apply hydrostatic loads to the panels, and water slosh loads (i.e. a varying pressure).

I have read through the Robot documentation, but am having trouble working through the python syntax (as most example are for a custom .dll using C#/VB.net). The reason we don’t want to lock the code away in a .dll is for transparency for the users.

Thanks again.

So far, I did indeed venture down the path of using a python script node which calls the Robot API to create trapezoidal loads (keeping it 2D at the moment instead of moving ahead with panels).

The problem now is that I can no longer use the structural analysis for dynamo package (as it does not have trapezoidal load capability). This is all very similar to a post from @Jonathan.Olesen back in 2018 (Dynamo - Python Output - Matching output of Structural analysis node).

My guess is I will have to venture down a custom calculate and getResults node - if anyone has any examples of syntax/required calls using python script that would be great.

Check out my thesis containing quite a lot of calls to and from Robot :slight_smile: Using genetic algorithms in Dynamo for generating and evaluating design alternatives at an early stage

2 Likes

Thanks Jonathan! Your thesis is very comprehensive - It’s great that you found a way to work with the custom type and keep using the Structural Analysis for Dynamo package nodes.

Excited to dig into your work, will update everyone with how it goes :slight_smile:

1 Like

Good morning,

Could you share with us your code using the ROBOT API for trapezoidal loads?

Thanks

Hi Arthur,

I did manage to get the trapezoidal loads working - I’m away from my computer atm and will hunt for the code when I can. From memory I used python code node and the robot API.

Just a heads up, the add in nodes (I.e. calculate/solve and get results) do not work with loads like this (not UDL / point load). So you’d need to also use a custom calculate and retrieve results node. I should have those too.

Additionally, there is not much documentation on using the Robot API however I’ll try dig up what I found about on the web.

Let me know if you’re still interested and I’ll look about.

Hi acam,

Thanks a lot for your answer. Yes I would be really interested in both your python code for the load (when you can) and in any helpful guide to use the Robot API. Let me know whenever you find something

Thanks again for sharing!

Arthur

Hi Arthur,

Here is the code for applying a trapezoidal load.
Note: in this example I provided a loop because for this particular example I ALWAYS provided a height, which was split into 10 robot elements, then the UDL force at each start/end point was calculated in a spreadsheet and passed into dynamo. That’s why you’ll see I looped through the objects list and applied the start/end values. It may take a bit to get the feeling for the API, it’s not straight forward… Should be easy enough to revert this code back to a single robot bar input and UDL. But let me know if you’re struggling and I’ll help out.

So trapazoidal load application:

#Set environment:
import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *

# add Robot Structural Analysis API reference 
from System import Environment
# get the current user folder i.e C:\Users\<you>\AppData\Roaming
user = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)
# add the reference to the interop file shipped with the package 
# you may have to hunt where yours is saved and adjust the path.
clr.AddReferenceToFileAndPath(user +r"\Dynamo\Dynamo Revit\2.0\packages\Structural Analysis for Dynamo\bin\RSA\interop.RobotOM.dll")

# add needed import to be able to use Robot Structural Analysis objects
from RobotOM import *
from System import Object
#------------------#
## get input data ##
#------------------#
# the bar id will go to the input[0] 
objects = IN[0]

# The following loads are based on the total height being split into 10:
# Relative references to height will define the names below (in the loop)
# The assumption is that the load will be applied to 10 members here.
heightloadsULS = IN[1]
LoadCaseName = IN[2]

#-------------------------------------------------------------#
# Connect to the running instance of Robot Structural Analysis
#-------------------------------------------------------------#
application = RobotApplicationClass()
# Get a reference of the current project
project = application.Project
structure = project.Structure
# Get a reference of the label server
labels = structure.Labels

# Automatically assign a case number:
caseNumber = structure.Cases.FreeNumber
# See API guide for explaination of the capital name references.
CaseLive = structure.Cases.CreateSimple(caseNumber, LoadCaseName, 
IRobotCaseNature.I_CN_EXPLOATATION, IRobotCaseAnalizeType.I_CAT_STATIC_LINEAR)
Trapezoidal = []
Trapezoidal.append(CaseLive.Records.New(IRobotLoadRecordType.I_LRT_BAR_TRAPEZOIDALE))
LoadRecord = CaseLive.Records.Get(Trapezoidal[0])

#----------------------------------#
# Apply the loads to robot elements
#----------------------------------#

# For my example I wanted to apply the load by splitting the overall
# height into 10 segments. 
numRec = 10
i = 1

while i <= numRec:
	# The SetValue numbers are explained in the API guide (page 150+)
	# I had issues using the names (like the API example page 11) so
	# reverted to using the actual integer values.
	
	# The values set below will then affect the load application step.
	LoadRecord.SetValue(13, 1) #set relative reference as true
	LoadRecord.SetValue(6, 1) #set end point of UDL (on member)
	LoadRecord.SetValue(7, 0) #set start poiint of UDL (on member)
	LoadRecord.SetValue(0, heightloadsULS[i-1]*1000) #starting load
	LoadRecord.SetValue(3, heightloadsULS[i]*1000) #end load
	LoadRecord.Objects.FromText(objects[i-1]) #grab the object to be used
	Trapezoidal.append(CaseLive.Records.New(IRobotLoadRecordType.I_LRT_BAR_TRAPEZOIDALE))
	LoadRecord = CaseLive.Records.Get(Trapezoidal[i])
	i += 1
#Assign the name to the OUT variable
OUT = caseNumber

Also as I mentioned, you will need a different node to calculate and retrieve nodes (because the Robot analysis packaged nodes do not play nice with other load types).

Calculate Model:

import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *

# add Robot Structural Analysis API reference 
from System import Environment
# get the current user folder i.e C:\Users\<you>\AppData\Roaming
user = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)
# add the reference to the interop file shipped with the package 
clr.AddReferenceToFileAndPath(user +r"\Dynamo\Dynamo Revit\2.0\packages\Structural Analysis for Dynamo\bin\RSA\interop.RobotOM.dll")

# add needed import to be able to use Robot Structural Analysis objects
from RobotOM import *
from System import Object

# have an input just to control the graph flow.
objects = IN[0]

# Connect to the running instance of Robot Structural Analysis
application = RobotApplicationClass()
# Get a reference of the current project
project = application.Project
structure = project.Structure
# Get a reference of the label server
labels = structure.Labels

# Check out the API, there is an extensive array of options here
# This will just do your stock standard calculations.
project.CalcEngine.AnalysisParams.IgnoreWarnings = True
calcEngine = project.CalcEngine
calcEngine.AutoGenerateModel = True
#calcEngine.AutoFreezeResults = True
calcEngine.UseStatusWindow = True
OUT = calcEngine.Calculate()

Grab results:

import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *

# add Robot Structural Analysis API reference 
from System import Environment
# get the current user folder i.e C:\Users\<you>\AppData\Roaming
user = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)
# add the reference to the interop file shipped with the package 
clr.AddReferenceToFileAndPath(user +r"\Dynamo\Dynamo Revit\2.0\packages\Structural Analysis for Dynamo\bin\RSA\interop.RobotOM.dll")

# add needed import to be able to use Robot Structural Analysis objects
from RobotOM import *
from System import Object

# get input data 
# input 0 is just a result that indicates if the calculation ran ok.
# also makes sure we get loads AFTER running analysis.
calculateOutcome = IN[0]
# list of robot bar IDs that you want loads from:
inputBarIDs = IN[1]

# Connect to the running instance of Robot Structural Analysis
application = RobotApplicationClass()
# Get a reference of the current project
project = application.Project
structure = project.Structure

numberOfBars = len(inputBarIDs)
i = 0
barStresses = []

while i < numberOfBars:
	# have a look at robot API pg 316 for some info about this part.
	# and the example file page 16. The data structure is a bit hard to
	# figure out.
	
	# for this example the .Value(inputBarIDS[i],1,0).Fz/1000
	# end up meaning: value( robot bar ID, Bar End, Offset ).(axis)
	# The results are given using N so we divide by 1000 to get kN.
	barStresses.append(structure.Results.Bars.Forces.Value(inputBarIDs[i],1,0).Fz/1000)
	i += 1

# pass the list of values - this was displayed in dynamo and passed
# to an excel sheet for record.
OUT = barStresses

Hopefully this helps you out a bit. I would take a good look at the ros-example code to get an idea of what to expect. Once you get the feeling for how the API plays in python, it’s a bit easier to figure out.

As a bonus here is a quick alteration of the bar forces to get node forces:

import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *

# add Robot Structural Analysis API reference 
from System import Environment
# get the current user folder i.e C:\Users\<you>\AppData\Roaming
user = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)
# add the reference to the interop file shipped with the package 
clr.AddReferenceToFileAndPath(user +r"\Dynamo\Dynamo Revit\2.0\packages\Structural Analysis for Dynamo\bin\RSA\interop.RobotOM.dll")

# add needed import to be able to use Robot Structural Analysis objects
from RobotOM import *
from System import Object

# get input data 
# input 0 is just a result that indicates if the calculation ran ok.
# also makes sure we get loads AFTER running analysis.
calculateOutcome = IN[0]
# list of robot node IDs that you want reactions from:
inputNodeIDs = IN[1]

# Connect to the running instance of Robot Structural Analysis
application = RobotApplicationClass()
# Get a reference of the current project
project = application.Project
structure = project.Structure

numberOfNodes = len(inputNodeIDs)
i = 0
nodeReactions = [[]]
nodeReactions.append([])
nodeReactions.append([])

while i < numberOfNodes:
	nodeReactions[0].append(structure.Results.Nodes.Reactions.Value(inputNodeIDs[i],1).Fx/1000)
	
	nodeReactions[1].append(structure.Results.Nodes.Reactions.Value(inputNodeIDs[i],2).Fx/1000)
	
	nodeReactions[2].append(structure.Results.Nodes.Reactions.Value(inputNodeIDs[i],3).Fx/1000)
	
	i += 1

OUT = nodeReactions[ros_api.pdf|attachment](upload://q5Cgcka7ImQWdJvavPSThBfkyux.pdf) (1.1 MB) [ros-example.pdf|attachment](upload://tVKu9FsdB44MrSTMYuoS34yJVXB.pdf) (455.4 KB)[ros_api.pdf|attachment](upload://q5Cgcka7ImQWdJvavPSThBfkyux.pdf) (1.1 MB) [ros-example.pdf|attachment](upload://tVKu9FsdB44MrSTMYuoS34yJVXB.pdf) (455.4 KB)
1 Like

Also check out the following links for some API documentation:

https://forums.autodesk.com/t5/robot-structural-analysis-forum/where-to-find-robot-open-standard-api-documentation/td-p/5843100

https://forums.autodesk.com/t5/robot-structural-analysis-forum/api-tutorial/m-p/5545971#M31227

1 Like

Hi @acam694

Do you think it is possible to amend the codes you have provided to apply moving load in RSA?

Thanks.

Hi - without going too far down a rabbit hole myself (I don’t deal with moving loads usually), this looks like a promising route:

It also looks like the prominent figures that are Rafal and Artur are well versed in the moving loads api.

Let us know how you get on.

A.

1 Like

Thank you for getting back to me. I’ll have a look and if I am successful I should let you know.

Kind regards
Abdul