Loads are duplicated in second run and keeps adding in N-times run (API/ Dynamo)

Hi all,

I’m currently working on some scripts to automate the design proces in our company with the use of Dynamo.

And because the structural packages doesn’t include some load options and loadcombinations i ended up writing the whole proces in python scripts inside dynamo. the picture below show the representation of the proces.


The whole script works fine for the first run. but when i run it a second time(change for example the bar section due wrong UC) the loads[red box picture above] will duplicate in the robot structural model.(see pictures below)
Run 1 run 2

This is the representation of adding load to a bar.


Add load to bar(5)

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

from System import Environment
user = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)
clr.AddReferenceToFileAndPath(user +r"\Dynamo\Dynamo Core\1.3\packages\Structural Analysis for Dynamo\bin\RSA\Interop.RobotOM.dll")
from RobotOM import *
from System import Object

objects = IN[0]
LoadCaseID = IN[1]
ILRT = IN[2]
LoadPX = IN[3]
LoadPY = IN[4]
LoadPZ = IN[5]


application = RobotApplicationClass()
project = application.Project
structure = project.Structure
labels = structure.Labels
loads = structure.Cases

CreatedLoads = []
simplecase = loads.Get(LoadCaseID)

Uniform = []
Uniform.append(simplecase.Records.New(ILRT))
LoadRecord = simplecase.Records.Get(Uniform[0])
LoadRecord.SetValue(0,LoadPX)
LoadRecord.SetValue(1,LoadPY)
LoadRecord.SetValue(2,LoadPZ)
LoadRecord.Objects.FromText(objects)
CreatedLoads.append(LoadRecord.UniqueID)
#Assign your output to the OUT variable.
OUT = CreatedLoads

This is the code i use now. but what i want to do is make an if statement if there is a load applied inside a loadcase, delete the load and add again(load input will sometimes change); If not add load to desired bar.

The problem i have at the moment is that i can’t find which API code has the applied load ID.

I thought i could be inside IRobotLoadRecordMngr(see attached picture). but don’t know if this is true?
I hope someone can help me a little bit?

@Maciek_Kubica don’t know if you have some examples(vba,c#,python) or know someone who can help me with this.

Thanks in advance

Edward

PS: dynamo file attached.
Loads keeps adding 0_01.dyn (49.3 KB)

The versions of the programs i use are:
Robot structural analysis 2020
Dynamo studio 1.3.0.946/Dynamo core 1.3.4.6666

the load changes because the values and element arent bind like revit elements would if you use ToDSType(bool).

and i believe, from the documentation you posted, instead of “LoadRecord.SetValue(1,LoadPY)”, you can use “LoadRecord.Get(index)” to get the value at that particular index. sadly i do not have Robot structural analysis installed and hence unable to test out the api for you

1 Like

Hello
Here is source in C# :
RobotApplication robotApp = new RobotApplication();

        IRobotBarServer barsServer = robotApp.Project.Structure.Bars;
        IRobotCaseServer casesServer = robotApp.Project.Structure.Cases;

        RobotCaseCollection caseCollection = casesServer.GetAll();


        IRobotCase loadCase = null;
        IRobotSimpleCase simpleLoadCase = null;
        IRobotLoadRecord loadRecord = null;
        IRobotLoadRecordMngr loadRecordManager = null;

        for (int i =1; i <= caseCollection.Count; i++)
        {
            loadCase = (caseCollection.Get(i) as IRobotCase);
            if (loadCase != null)
            {
                switch (loadCase.Type)
                {
                    case IRobotCaseType.I_CT_SIMPLE:

                        {
                            simpleLoadCase = (loadCase as IRobotSimpleCase);
        
                            if (simpleLoadCase != null)
                            {
                                loadRecordManager = simpleLoadCase.Records;

                                for (int j=1; j <= loadRecordManager.Count; j++)
                                {
                                    loadRecord = (loadRecordManager.Get(j) as IRobotLoadRecord);

                                    if (loadRecord != null)
                                    {
                                        IRobotLoadRecordCommon loadRecordCommom = (loadRecord as IRobotLoadRecordCommon);

                                        if ( loadRecordCommom != null )
                                        {
                                            if (loadRecordCommom.IsAutoGenerated == true)
                                            {
                                                continue;
                                            }
                                        }

                                        IRobotCollection bars = barsServer.GetMany(loadRecord.Objects);

                                        for (int k=1; k <= bars.Count; k++)
                                        {
                                            IRobotBar bar = (bars.Get(k) as IRobotBar);

                                            if (bar != null)
                                            {
                                                switch (loadRecord.Type)
                                                {
                                                    case IRobotLoadRecordType.I_LRT_BAR_UNIFORM:

                                                        {

                                                        }
                                                        break;
                                                    case IRobotLoadRecordType.I_LRT_BAR_MOMENT_DISTRIBUTED:
                                                        break;
                                                    case IRobotLoadRecordType.I_LRT_BAR_TRAPEZOIDALE:
                                                        break;
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        break;
                    case IRobotCaseType.I_CT_COMBINATION:
                        break;
                    case IRobotCaseType.I_CT_CODE_COMBINATION:
                        break;
                    case IRobotCaseType.I_CT_MOBILE:
                        break;
                }
            }
        }
    }
1 Like

@stillgotme @sleczkt

Thanks for your reply and examples.

I got it solved for myself, but there is still something happening that should not happen in my opinion.

for example: if i have a robot file where multiple loads are applied inside a load case, then when running the script it doesn’t delete all aplied loads. I gues it has something to do with the range on the counted list. See picture(red area) and script below.

I hope someone of you can figure it out why this happens?

Add load to bar(5)
import clr
clr.AddReference(‘ProtoGeometry’)
from Autodesk.DesignScript.Geometry import *

from System import Environment
user = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)
clr.AddReferenceToFileAndPath(user +r"\Dynamo\Dynamo Core\1.3\packages\Structural Analysis for Dynamo\bin\RSA\Interop.RobotOM.dll")
from RobotOM import *
from System import Object

objects = IN[0]
LoadCaseID = IN[1]
ILRT = IN[2]
LoadPX = IN[3]
LoadPY = IN[4]
LoadPZ = IN[5]


application = RobotApplicationClass()
project = application.Project
structure = project.Structure
labels = structure.Labels
loads = structure.Cases

CreatedLoads = []
cas = structure.Cases.Get(LoadCaseID)
simplecase = IRobotSimpleCase
simplecase = cas
rec = IRobotLoadRecord
IRobotLoadRecordMngr = simplecase.Records
count = IRobotLoadRecordMngr.Count

for i in range(1,count+1,1):
	#rec = simplecase.Records.Get(i)
	#rec.SetValue(0,objects)
	#rec.Description = "Modified record2"
	rec = simplecase.Records.Delete(i)

Uniform = []
Uniform.append(simplecase.Records.New(ILRT))
LoadRecord = simplecase.Records.Get(Uniform[0])
LoadRecord.SetValue(0,LoadPX)
LoadRecord.SetValue(1,LoadPY)
LoadRecord.SetValue(2,LoadPZ)
LoadRecord.Objects.FromText(objects)
CreatedLoads.append(LoadRecord.UniqueID)
#Assign your output to the OUT variable.
OUT = CreatedLoads, count

Here is the updated dynamo file.
Loads keeps adding partly solved.dyn (49.6 KB)

why not just

for i in IRobotLoadRecordMngr:
    ind = IRobotLoadRecordMngr.index(i)
    rec = simplecase.Records.Delete(ind)

Your loop should start from 0, not 1. That may be why it seems like it’s missing some because it’s not getting the first item of the list.

for i in range(0,recs.Count-1,1):

@stillgotme and @SeanP

Thanks for your replies.
I tried both options you are describing.

This is how i implemented the code from @stillgotme


This gave the following error:
“Warning: IronPythonEvaluator.EvaluateIronPythonScript operation failed.”
I Don’t know why it’s this error, normally the evaluator gives a line where the code is wrong.
.
This is how i implemented the code from @SeanP

This is the start in Robot, see red box, i gave id numbers in the memo field of the description.

This is the result after run 1

So the loads with number 1,3 and 5 are removed. and 1 load without a number is created(conform last part of the code).

Here are the dynamo files:
Loads keeps adding partly solved _stillgotme.dyn (49.7 KB)
Loads keeps adding partly solved _SeanP.dyn (49.6 KB)

Please let me know if i missed something or wrote it wrong.

Many thanks in advance.

Edward

image

If my guess is correct, by deleting one record after another, you´re skipping 1 because the records reorder.

records = [record1, record2, record3, record4]
records.Delete(0)
records = [records2, record3, record4]
records.Delete(1)
records = [records2, records4]

That might be why your MEMO1,MEMO3 and MEMO5 were deleted.
A possible workaround could be to iterate backwards through the index list.

range(10) --> [0,1,2,3,4,5,6,7,8,9]
range(10)[::-1] -->[9,8,7,6,5,4,3,2,1,0]
# Or
range(9,-1,-1) -->[9,8,6,5,4,3,2,1,0]

Or delete the record at index 0 as often as there are records

 for _ in range(records.Count):
    records.Delete(0)

It might not be your goal, but your python script deletes all records of the load case and adds only 1 new record.

I tried to go through it and simplify/comment whats happening. Though, you should know that I don´t have Robot installed and could not test it. AND I have no idea how to work in Robot. The changes are only based on making the python script more readable.

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

from System import Environment
user = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)
clr.AddReferenceToFileAndPath(user +r"\Dynamo\Dynamo Core\1.3\packages\Structural Analysis for Dynamo\bin\RSA\Interop.RobotOM.dll")
from RobotOM import *
from System import Object

objects = IN[0]
LoadCaseID = IN[1]
ILRT = IN[2]
LoadPX = IN[3]
LoadPY = IN[4]
LoadPZ = IN[5]


application = RobotApplicationClass()
project = application.Project
structure = project.Structure
labels = structure.Labels
loads = structure.Cases

CreatedLoads = []

# Get the LoadCase
# -> IRobotSimpleCase
case = structure.Cases.Get(LoadCaseID)

# Get the records of the LoadCase
# -> IRobotLoadRecordMngr
records = case.Records

# Delete ALL records of this load case
# Starting from the last
for index in range(records.Count)[::-1]:
    records.Delete(index)

Uniform = []
# Create a new record
new_record_index = records.New(ILRT)
new_record = records.Get(new_record_index)
# Set values of new record
new_record.SetValue(0,LoadPX)
new_record.SetValue(1,LoadPY)
new_record.SetValue(2,LoadPZ)

# bar node id (?)
new_record.Objects.FromText(objects)

CreatedLoads.append(new_record.UniqueID)
Uniform.append(new_record)
OUT = CreatedLoads, records.Count

@Kibar

Many thanks for your reply. I think you’re right. if have to check it out later but it sounds like you found the problem.

It might not be your goal, but your python script deletes all records of the load case and adds only 1 new record.

actually it is my goal to get rid off all loads inside a load case, it just to make it usable for everyone.
It’s just for this script that there is only one load added. In the bigger script, as described in the start of this topic it adds multiple loads.

Thanks

Edward

1 Like

Hi all,
I have similar problem but with duplicated load combinations. When I run script a multiple time in RSA it is happening this:

Would you have any idea how I could change this script to remove combinations?

Thanks in advance

@DagmaraG
I have had the same problem. I solved it by adding an if statement.
in my case ‘if the loadcombination exist’ --> delete combination and write again
‘if not the loadcombination exist’ --> write combination.
See the code below.

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

from System import Environment
user = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)
clr.AddReferenceToFileAndPath(user +r"\Dynamo\Dynamo Core\1.3\packages\Structural Analysis for Dynamo\bin\RSA\Interop.RobotOM.dll")
from RobotOM import *
from System import Object

#The inputs to this node will be stored as a list in the IN variables.
CombCaseNumber = IN[0]
CombCaseName = IN[1]
CCombNumber = IN[2]
CFactors = IN[3]
IRCBT = IN[4]
IRCN = IN[5]
IRCAT = IN[6]

application = RobotApplicationClass()
project = application.Project
structure = project.Structure
labels = structure.Labels
loads = structure.Cases

for k in range(len(CombCaseNumber)):
	if(loads.Exist(CombCaseNumber[k])):
		Selectionscases = structure.Selections.Get(IRobotObjectType.I_OT_CASE)
		Selectionscases.FromText(CombCaseNumber[k])
		project.Structure.Cases.DeleteMany(Selectionscases)
		CaseComb = structure.Cases.CreateCombination(CombCaseNumber[k],CombCaseName[k],IRCBT[k],IRCN[k],IRCAT[k])
		IRobotCaseFactorMngr
		for j in range(len(CCombNumber[k])):
			caseManage1 = CaseComb.CaseFactors
			caseManage1.New(CCombNumber[k][j],CFactors[k][j])
	if not(loads.Exist(CombCaseNumber[k])):
		CaseComb = structure.Cases.CreateCombination(CombCaseNumber[k],CombCaseName[k],IRCBT[k],IRCN[k],IRCAT[k])
		IRobotCaseFactorMngr
		for j in range(len(CCombNumber[k])):
			caseManage1 = CaseComb.CaseFactors
			caseManage1.New(CCombNumber[k][j],CFactors[k][j])
Out = CombCaseNumber

I hope this will help for you.

@Kibar
thanks for your solution. this is how i implemented it and it works.
adding solved

everybody thanks for your help.

gr Edward

1 Like

@1234eddie

Thanks Edward, it works properly now.

Hi there,
I’m a little late to the party, and forgive me if I’ll sound harsh, but I’m on a mission of teaching a better python style coding to as many people I can :smile:

This will hopefully be useful to prevent propagating code ugliness via copy-pasting…

import clr
# We don't need Protogeometry library for this, script, removed
# With RSA 2023 we can point directly to the app folder
clr.AddReferenceToFileAndPath(r"C:\Program Files\Autodesk\Robot Structural Analysis Professional 2023\Exe\Interop.RobotOM.dll")
# import * is a bad practice in python world, better to explicitly import what whe need
from RobotOM import RobotApplicationClass
# no need to import System.Object, removed

# python code style uses snake_case for variables names, and C# variables should begin with a lowercase letter...
# I know it's a matter of styling and personal preference, but sticking to best practices helps you and other to quickly identify what are you talking about...
# That said I'm keeping them as they are 
CombCaseNumber = IN[0]
CombCaseName = IN[1]
CCombNumber = IN[2]
CFactors = IN[3]
IRCBT = IN[4]
IRCN = IN[5]
IRCAT = IN[6]

application = RobotApplicationClass()
# you use only loads, so you can keep just it
loads = application.Project.Structure.Cases

# here you use a loop on range(len(list)) to get the index and then retrieve the element;
# you can save this by using enumerate(list) that returs both the index and the element
# for k, number in enumerate(CombCaseNumber):
# and then replace CombCaseNumber[k] with number,
# or even use zip() to get all the corresponding items from all the lists
# (maybe this is more unreadable than before, as there are many lists involved):
for num, name, caseNumbers, caseFactors, combType, combNature, comAnalyzeType in zip(CombCaseNumber, CombCaseName, CCombNumber, CFactors, IRCBT, IRCN, IRCAT):
    # no need to use parenthesis in with if
    if loads.Exist(num):
        # in my test, selectioncases is useless because we already have the number to delete;
        # and since project.Structure.Cases is the same as loads, you can just call
        loads.Delete(num)
    # the rest of the code is duplicated, since we already know that the load doesn't exist anymore and we need to create the new one in any case..
    # again we directly use loads and take advantage of the zip()ed objects
    caseComb = loads.CreateCombination(num, name, combType, combNature, comAnalyzeType)
    # no Idea why there is a IRobotCaseFactorMngr hanging around here, removed
    # we can save some CPU by storing the caseFactors outside the loop
    caseManage = caseComb.Casefactors
    # another loop that can be simplified with zip
    for cNum, cFactor in zip(caseNumbers, caseFactors):
        caseManage.New(cNum, cFactor)

Out = CombCaseNumber