How to retrieve nested components from family instance in Link

I’m trying to get the doors from a linked curtain wall.
Previously when they weren’t in a linked file, I could use FamilyInstances.RetrieveNestedComponents, but @john_pierson has kindly left us an error message that this doesn’t work with linked documents because it has to be able to iterate through the current document and this doesn’t work with links. I found the python on his GitHub (maybe C# would have a clue, but I haven’t found it yet) and tried to patch it for this scenario. Or maybe there’s another node I’m not aware of yet?

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

clr.AddReference("RevitNodes")
import Revit

clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager

clr.ImportExtensions(Revit.Elements)

# Get the current Revit document
doc = DocumentManager.Instance.CurrentDBDocument

def GetNestedFamilies(fi, doc):
    # list to hold all subcomponents
    internalFamilies = []
    internalFamilies.append(fi)
    # list to hold nested elements
    nestedList = []
    # counter for internalFamilies list
    flag = 0
    # loop control
    stopString = "keepGoing"
    while stopString == "keepGoing":
        # if flag != internalFamilies.Count:
        if flag != len(internalFamilies):
            # iterate through subcomponents
            for subComponent in internalFamilies[flag].GetSubComponentIds():
                # check if subcomponent is in linked doc
                if subComponent.IsLinkedElementId(doc):
                    # get link instance for linked doc
                    revitLinkInstance = doc.GetElement(subComponent).GetLinkInstance()
                    # get unique IDs of all elements in linked doc
                    elementIds = revitLinkInstance.GetLinkedElementIds()
                    # get elements with specified IDs from active doc
                    elements = doc.GetElements(elementIds)
                    # use LINQ to filter elements and get doors nested inside linked wall
                    nestedDoors = [element for element in elements if element.Category.Name == "Doors" and element.Parent.Id == fi.Id]
                    # add nested doors to output list
                    nestedList.AddRange(nestedDoors)
                else:
                    # get family instance for subcomponent
                    internalFamily = doc.GetElement(subComponent)
                    # enable further digging
                    internalFamilies.append(internalFamily)
                    # add to output list
                    nestedList.append(internalFamily.ToDSType(True))
            # increment flag
            flag += 1
            stopString = "keepGoing"
        else:
            stopString = "stahp it"
    return nestedList

def tolist(obj1):
    if hasattr(obj1,"__iter__"): return obj1
    else: return [obj1]

# Get the input family instance and linked document
familyInstances = tolist(UnwrapElement(IN[0]))
# familyInstance = UnwrapElement(IN[0])
linkedDocument = UnwrapElement(IN[1])
# Get the linked document object
linkedDoc = doc.GetElement(linkedDocument)

subLists = []

# iterate through the given instances
for fi in familyInstances:
    subLists.append(GetNestedFamilies(fi, linkedDoc))
		
OUT = subLists

I re-titled this thread to be more of a question as you are looking to do something my node does not do. I have not been able to research the linked document stuff more, but I know it will be pretty involved as you are going to be managing several documents at once, and Dynamo is really meant to work on the current one. (This is a Dynamo limitation, not Rhythm). There is some (limited) support for background documents, but it is unstable to say the least.

(none of this is to say that it is impossible, though. Just that I have not added that ability to my node, nor do I plan to)

Thanks for the feedback, maybe instead of picking the wall and trying to get the doors I could pick the doors and find a path back up to the wall. I was curious if you’ve had a chance to try ChatGPT yet and how it contrasts with Generative Design. It seems like they are both AI, but that’s about as much as I can guess at what’s under the hood. I could try to say they are both using machine learning but I’m sure how accurate that is either.
Most of the changes I was trying in your python code were based on suggestions from ChatGPT

would it make a difference if the family was loaded in both files? Which I think it might be… I was just referencing the instance in the link, but the family is in both of them.

At this time you’re not going to get much useful info from that in my experience. Live tweeted a 30 minute attempt to use the tool to do something simple the other day. You can have a look here: https://twitter.com/JacobWSmall/status/1600477115853737984

2 Likes

depending on how complex the problem is I’ve gotten relatively good results. I think the difference is you were trying to simplify what you asked it, I’ve pushed in the other direction trying to make sure I’ve gotten specific jargon. Like saying CurtainWall instead of of just Wall, or Specifying Instances in a Link File etc. Basically, I’ve learned you have to ask smart questions to get smart answers, and occasionally it’s helped me see I’m asking the wrong question to begin with.

If that’s the case. Work with the family in your current file and use the node as is.

2 Likes

Maybe I’m confused, as is it has one input which is the instance. I’m not sure how’d feed it a linked instance but still reference the local family? I was thinking of adding another input but I was still looking at how I’d find the matching family locally.