Mullion.ByElement not working with Python script

I have a Python script that generates a curtain wall as an output - however, the Mullion.ByElement node fails to get the mullions from this wall. I can get it to work if I do the following:

  1. Disconnect the Python script from the Mullion.ByElement node
  2. Run the script
  3. Reconnect the Python script
  4. Run the script again

It seems pretty dumb having to do that every time I want to use the script. Does anyone know how I can fix this issue?

For reference, I connected another Mullion.ByElement node to a Select Model Element node with a curtain wall selected, and it works fine.

The Python script is below:

import clr
import sys

# Import DocumentManager
clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.GeometryConversion)

# Import RevitAPI
clr.AddReference("RevitAPI")
from Autodesk.Revit.DB import *

#Add list object
from System.Collections.Generic import List

#The inputs to this node will be stored as a list in the IN variables.
profileCurves = IN[0]
filledRegionCurves = IN[1]
newWallType = UnwrapElement(IN[2])
inputWall = UnwrapElement(IN[3])
view = UnwrapElement(IN[4])
filledRegionType = UnwrapElement(IN[5])

doc = DocumentManager.Instance.CurrentDBDocument 
output = []

#Functions
def createCurveLoops(curveGroups):
    curveLoops = List[CurveLoop]()
    for group in curveGroups:
        revitCurves = [c.ToRevitType() for c in group]
        curveLoop = CurveLoop()
        for curve in revitCurves:
            curveLoop.Append(curve)
        curveLoops.Add(curveLoop)
    return curveLoops  

#Get parameters from input wall
inputTopConstraintId = inputWall.get_Parameter(BuiltInParameter.WALL_HEIGHT_TYPE).AsElementId()
inputUnconnectedHeightId = inputWall.get_Parameter(BuiltInParameter.WALL_USER_HEIGHT_PARAM).AsDouble()

#Get curves from input detail component
curves = List[Curve]()
for profileCurve in profileCurves:
    curves.Add(profileCurve.ToRevitType())

#Create curveloops with filled region curves
curveLoops = createCurveLoops(filledRegionCurves)

#Start transaction
TransactionManager.Instance.EnsureInTransaction(doc)

#Created non-intersecting filled region
newRegion = None;
try:
    newRegion = FilledRegion.Create(doc, filledRegionType.Id, view.Id, curveLoops)
except:
    newRegion = "nahhh bro";

#Create new wall from input curves
newWall = None;

try:
    newWall = Wall.Create(doc, curves, False)
    newWall.WallType = newWallType
    
    #Set new wall parameters
    newWall.get_Parameter(BuiltInParameter.WALL_HEIGHT_TYPE).Set(inputTopConstraintId)
    newWall.get_Parameter(BuiltInParameter.WALL_USER_HEIGHT_PARAM).Set(inputUnconnectedHeightId)
    
    #Disallow wall joins
    WallUtils.DisallowWallJoinAtEnd(newWall, 0)
    WallUtils.DisallowWallJoinAtEnd(newWall, 1)

except:
    newWall = "Dis aint be workin"
    
TransactionManager.Instance.TransactionTaskDone()
    
#Assign your output to the OUT variable.
OUT = newWall

Dynamo won’t reach-execute nodes unless their input had changed. If you provide an extra input into the Python node you can just toggle a switch boolean node) or adjust a slider and the node will reexecute.

Alternatively you can leverage Dynamomplayer instead of Dynamo.

Hi Jacob, I don’t understand what you mean by “reach-execute”. Could you expand on that? Wouldn’t the Python script execute and return the wall output before the Mullion.ByElement node attempts to execute?

Sorry that was an autocorrect issue. Re-execute. Dynamo won’t re-execute a node unless an input changes.

Therefore the Python runs once, and won’t run again unless something new is provided into it. A boolean node which you toggle before hitting run will do just that.

Thanks for the advice, but connecting and toggling a bool does not change the result. Using Dynamo Player doesn’t solve the issue either. Any other ideas?

I also don’t understand why the node needs to re-execute at all. The Python script outputs a wall element, and the Select Model Element node also outputs a wall element. The Mullion.ByElement node connected to the Python script doesn’t work, but the Mullion.ByElement node connected to Select Model Element does work. Why is that?

Need a project and the .dyn to test with.

No problem, here’s a download link with the test model, test link and .dyn: WeTransfer - Send Large Files & Share Photos Online - Up to 2GB Free

After running the script, I select the link then select all the windows from the 3D - Windows view.

Please note, the issue I described in this topic (Dynamo symbolic line geometry generating in wrong location) also applies to this script. I would be very happy if you have a solution to this problem, but it not, you will need to run the script, wire the FamilyInstance.ByPointInView node to the Python script and then re-run it to get the script to execute to the point we have been discussing.

Thanks for your time!

Just giving a boost to see if anyone has other ideas about how to resolve this. Still searching for a solution.

Tried wrapping my head around what you’re after twice now, and can’t figure it out. Mostly this is due to the initial state of the garph having some rather particular aspects around the selection effort. What type of objects I am supposed to select in the link isn’t clear, nor is the relationship to the live element which is in the “select model element” node.

The intent of the graph isn’t really clear either. The name “Window Openings and Mullions” is a bit ambiguous as far as names go. My best guess is that you’re trying to:

  • Generate a curtain wall from the profile of another wall
  • Find the windows in the curtain wall and add some mullions at these locations in the new curtain wall
  • Set the mullion type based on some property of the resulting mullions

However none of that really makes sense as you’ve already got a curtain wall selected… Likely there is a better way to go about what you’re after if this is the case, but I’d need to know more of the goal and initial state.

All of that said I think I can identify the route cause by digging into the logic flows which I can identify.

You’re generating a wall with your Python script, and then asking it for it’s mullions. As mullions are second level content they don’t exist until the transaction is complete; So we can try wiring the result of the Python node into a Transaction.End node, and that into a Transaction.Start node. This will ‘wrap up’ generating the curtain wall, then start a transaction so we can commit any changes to the new curtain wall.

Give that a try and see what you get.

The Tranastion.Start and .End nodes solve the problem! Thank you so much, I’ve been wracking my brain over that one for a while.

My apologies, I could have been more clear on the intent of the graph and understand why it’s confusing. The intent is to modify the profile of the selected curtain wall around the windows in a linked model, using the lines of a detail component that is placed at each window location. After the wall has been modified, I am changing the automatically generated mullions to the correct mullion types, representing head, sill and track studs.

It’s extra confusing because I was having trouble figuring out how to modify a wall profile using Revit API, so instead I am generating a new wall from a curve list with the modified profile, then deleting the original wall.

Before:

After:

Gotcha on the intent. It might be better to generate the wall from the face of the existing wall. This will simplify the isolation of the windows and such - they’d already be a part of the wall. For modifying existing wall sketches this may help though: Sketch Lines - Edit, Copy, Paste - #20 by jacob.small

I am curious as to why you’re putting curtain walls in place over solid walls, but perhaps that’s a question for another day.

Thanks Jacob, I’ll check out that topic.

We use curtain walls to generate stud schedules from curtain wall mullions for fabrication purposes.

Ah. I am not really a fan of that method, but what you are after with the graph makes sense now. :slight_smile:

Interesting, what alternate approach do you prefer and why? I would be interested in your recommendations.

In general it’s overmodeling. But I get that there is a need for it in some cases.

In such cases adaptive components can make sort work of it. Repeaters make the process easy to scale. The corner conditions and framing can readily be incorporated into the process. And it works for ceilings too.

Right on - I need to get more experience with adaptive components. Thanks for the tip.

1 Like