Python help - Get subelements

Hi

I am trying to get the subelements from a multistorey stair. This should be possible by getting the stairs ids from the GetAllStairsIds method and then calling Element.GetSubelements to get the stair subelements. I though this Python script would work but I am getting an error message. Any ideas as to how to do this?

import clr

clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument

clr.AddReference('RevitNodes')
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)

clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *

str1 = []
str2 = []
mstr = UnwrapElement(IN[0])
stid = mstr.GetAllStairsIds()
for i in stid:
	str1.append(doc.GetElement(i))
str2 = str1[1].GetSubelements()
str3 = []
for j in str2:
	str3.append(j.UniqueId)

OUT = str3;

The error is:

Warning: IronPythonEvaluator.EvaluateIronPythonScript operation failed.
Traceback (most recent call last):
File “”, line 24, in
IndexError: index out of range: 1

Using Dynamo 1.3 and Revit 2019.

Thanks

Get subelements.dyn (4.6 KB)

Can you post the output of strid and str1?

According to your error message, I believe it is because you are calling str1[1], but since you are only feeding it 1 stair, you would need to call str1[0].

Maybe try:

for s in str1:
    str2 = s.GetSubelements()

Hi Sean

This worked (although I’m no Python expert so not sure how elegant it is):

import clr

clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument

clr.AddReference('RevitNodes')
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)

clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *

str1 = []
str2 = []
mstr = UnwrapElement(IN[0])
stid = mstr.GetAllStairsIds()
for i in stid:
	str1.append(doc.GetElement(i))
for s in str1:
	str2 = s.GetSubelements()

OUT = str2;

Any idea how to then get the element from the Revit.DB.subelement?

I think you need to use the .ToDSType() on the subelements to get them back after unwrapping them

If that doesn’t work, you could get s.Id then use doc.GetElement(d.Id).

1 Like

Thanks Sean. So would the syntax be:

str2 = s.GetSubelements.ToDSType()

I tried this and got an error: AttributeError: ‘builtin_function_or_method’ object has no attribute ‘ToDSType’

That doesn’t work because .GetSubelements is already a method that was not finished (it is missing the ‘()’ ), so you cannot call a method on top of a method. Try making a new variable str3 = str2.ToDSType()

1 Like

What is interesting to me is that I don’t even get results for the s.GetSubelements() method, but get the individual stairs in the first go. What version of Dynamo are you using?

image

@kennyb6

Thanks. I tried a few different way (not sure of the syntax) but kept getting the same error: List[Subelement]’ object has no attribute ‘ToDSType’. Any ideas

@SeanP

I’ve tried it in Dynamo 2.0 and 1.3.3 with Revit 2019 and I can get the DB elements. GetSubelements I think is new to Revit 2018. Are you using an older version?

Get subelements_5_Dynamo 1_3.dyn (4.7 KB)
Get subelements_5_Dynamo 2_0.dyn (6.9 KB)

I ran it on 1.3.3 in Revit 2018.3. perhaps you could get the I’d of the subelements s.Id and then doc.GetElement(s.Id).

What exactly are you trying to do? That may help further the discussion.

@SeanP

This post talks about a bit about how I got to this point. I am bascially automatting stair documentation. So take a stair(s), get its risers/landing and create dimension, tags, number systems, etc. It is all working except for if it is a multistorey stair. I need to be able to get the typology of each substair.

I tried with both Id and UniqueId and both returned the error: AttributeError: ‘list’ object has no attribute ‘UniqueId’

"
import clr

clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument

clr.AddReference('RevitNodes')
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)

clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *

str1 = []
str2 = []
str3 = []
mstr = UnwrapElement(IN[0])
stid = mstr.GetAllStairsIds()
for i in stid:
str1.append(doc.GetElement(i))
for s in str1:
str2.append(s.GetSubelements())
for t in str2:
str3.append(str2.UniqueId)

OUT = str3, str2, str1, stid
";

You can find all of the methods of a SubElement here.

I found the unique Id of it, not quite sure how to look up the element using it. SubElements do not have a normal Id. The problem was that getting a subelement puts it inside of a list, so it isn’t enough to just call a method on it but you have to dig one list deeper before you can:

str3 = []
for s in str2:
	for j in s:
		str3.append(j.UniqueId)

put that at the end of your code to get the unique id or to use any of the other methods/properties.
And SubElements do not have ToDSType() so need to find another way.

Will this previous post work to get the actual elements?

I think the issue is that he wants the subelements as an element in Dynamo, not the main element (multistory stairs), as he already has that.

According to your post you got the Unique ID of the subelements, and the DS in that imagr converted the GUID to Element. I assume that can be used for the GUID of the subelements as well.

Yep so I can get the unique ID as shown

import clr

clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument

clr.AddReference('RevitNodes')
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)

clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *

str1 = []
str2 = []
str3 = []
mstr = UnwrapElement(IN[0])
stid = mstr.GetAllStairsIds()
for i in stid:
	str1.append(doc.GetElement(i))
for s in str1:
	str2.append(s.GetSubelements())
for s in str2:
	for j in s:
		str3.append(j.UniqueId)

OUT = str3, str2, str1, stid

image

Not sure what to do with that and how I can get geometry from it. Topology.Faces doesn’t work on db.subelements.

image

I think I have solved it. Tried topology.faces on the elements and even through they are the same element (and Id), it return all of them?! Don’t understand why but it seemed to have worked!

Get subelements_5_Dynamo 1_3.dyn (19.1 KB)

2 Likes

This appears to be all you need to get the stair element, from which you can get the topology (as one long list)

stid = mstr.GetAllStairsIds()
for i in stid:
	str1.append(doc.GetElement(i))

But if I try to get the landings and stair runs, it still revers back to the main elements which has been copied up into the multistorey stair. I really need to be able to identify the stair run and landing elements within the multistoreystair, otherwise it will be impossible to sort all the surfaces into any logical order

Get subelements_6_Dynamo 1_3.dyn (9.8 KB)

Is it possible to sort using PointAtParameter of surfaces and sort using the Z value?

That would only solve part of the problem. I need the individual elements (landings, stair runs, etc) to be able to tag, create number systems, etc. Dimensioning is only one part of it. So we need elements, not just surfaces.

So it’s back to the problem of what to do with the db.subelements. What are they and how can they be used? It isn’t really clear from the documentation.