Hello,
My goal is to be able to set the Mass Floors instance parameter by pulling the Masses Level.
I found a thread from around 2015 and it stated that due to Mass Floors having the “Edit” button on the instance parameters the grouping of how you set the parameter was different than the typical SetParameterValue.
assign level to “Mass Floors” parameter of mass FamilyInstance - Autodesk Community - Revit Products
I’m having a little trouble tracking what you’re after, are you wanting to create mass floors in Dynamo with a node? or are you looking to update the mass floor’s level parameter after it’s been created?
I’m looking to pull the scheduled level from the mass and update the mass floors check box
I see, so you have a mass with one floor on level 1, and you wish to create a new floor on Level 2 with Dynamo? Does that example explain the idea?
Sorry not exactly. More basic than that, if all masses are on level 1, I’d like to apply that to the mass floors selection. I’ve just not been able to figure out how to apply that setting yet.
There’s an API method and I think it’s what needs to be used to set it. Where I’m having trouble currently is that method is in the MassInstanceUtilsClass and a placed mass in Revit is a family instance, not a Mass Instance Util object, if that makes sense.
I’m going to try one last thing and see what it gives me when I use a filtered element collector to collect the mass instance class.
Edit: I didn’t work for me.
The other thing I failed to ask was, what version of Revit you’re in.
Here’s the api method if you’re interested. AddMassLevelDataToMassInstance Method
Here’s the Python I’m cooking with so far.
from os import system
import sys
sys.path.append(r'C:\Program Files (86x)\IronPython 2.7\DLLs')
sys.path.append(r'C:\Program Files (86x)\IronPython 2.7\Lib')
import os
import clr
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)
clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
clr.AddReference('RevitAPIUI')
from Autodesk.Revit.UI import *
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
import System
from System.Collections.Generic import *
import collections
doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication
app = uiapp.Application
uidoc = DocumentManager.Instance.CurrentUIApplication.ActiveUIDocument
def uw_list(obj):
if isinstance(obj, list):
return UnwrapElement(obj)
else:
return [UnwrapElement(obj)]
def list_check(obj):
if isinstance(obj, list):
return obj
else:
return [obj]
mass = UnwrapElement(IN[0])
level = UnwrapElement(IN[1])
TransactionManager.Instance.EnsureInTransaction(doc)
OUT = mass.AddMassLevelDataToMassInstance(doc, mass.Id, level.Id)
TransactionManager.Instance.TransactionTaskDone()
And here’s a screenshot.
I’m in revit 2024 latest version, I’m away from my PC right now but I can help more tomorrow morning.
Got it, it was easier than I had thought. Rather calling for the Item and asking for the method, I needed to just call the class and then the Item.
MassInstanceUtils.AddMassLevelDataToMassInstance(doc,mass.Id,level.Id)
I need to modify the code to handle a list of masses and a list of levels. To make it easier it would be best to throw it into a custom node for when you have to work with nested lists. I don’t have a published package unfortunately, maybe one of the other content creators sees this post and can put it in theirs.
Hope this helps!
Okay, here is what I have. Below is a screenshot of the workflow where I am collecting mass families as opposed to an in place mass. I did this just so I could get the level easily.
Below is the Python for this effort. Now, it’s important to note that for each mass, you need to supply a level. If this is not what you’re looking for, I can make a simple change to take a list of masses, one level and apply that level to all the masses to add a floor. I also documented the code to help make sense of things.
import clr
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument
# Check if the input is a list, if yes return it, if it's not a list, make it one.
def uwlist(input):
result = input if isinstance(input, list) else [input]
return UnwrapElement(result)
# Collect the inputs and unwrap them exposing more of their methods and properties
mass = uwlist(IN[0])
level = uwlist(IN[1])
# Start a transaction in Revit since we are creating a mass floor object.
TransactionManager.Instance.EnsureInTransaction(doc)
# Create a blank list to store our Revit floors
massFloors = []
# We use a zip function which allows us to take the mass at index 0 and level at index 0 to create the floor. Then it goes to the mass and level at index 1, creates the floor, and so on...
for m,l in zip(mass,level):
# The api used to add a mass floor to a mass. There is also a method to remove a floor via the level. This will return the element ID of the mass floor.
massFloorid = MassInstanceUtils.AddMassLevelDataToMassInstance(doc, m.Id, l.Id)
# Since it's an element ID, we want to return the actual element so we use the doc.GetElement() method.
massFloors.append(doc.GetElement(massFloorid))
#End the transaction
TransactionManager.Instance.TransactionTaskDone()
#Return what's done.
OUT = massFloors
I hope this helps!
2 Likes
That absolutely worked! Bravo!
I’ve really got to get on learning python, it’s far too useful in dynamo
1 Like
I’m glad it worked!
Some good places to start for your Python journey are:
I went the the route of starting in a Udemy class strictly about Python just to familiarize myself with the general workings of Python. Here’s the class, it tends to go on sale often for around $9-$12 https://www.udemy.com/share/101W8Q3@V7qBCr8BdWCQdOhuodF05mUiU6apPh5FaMWRhDmTNiETidYe8DxXEUH5Sjz6w4eU/
The last one I’ve been taking is the classes from Erik Frits Learn Revit API - https://learnrevitapi.com/
Lastly, how I got the most out of learning Python, was after going through a few of the video tutorials and then spend some time applying these concepts either in a blank Dynamo graph. Or, if you know if an existing workflow that has logic similar to what you learned, try to apply it!
Happy Coding!
1 Like
I worked my way through a C# Master class on Udemy last year but once I hit Revit’s API I really struggled. But in typical Dynamo I’ve been able to do everything I’ve tried to so far.
The python journey will be starting today 
Not to add to the previous but as a “just in case” any user copies a Mass (with Mass Floors Level 1 selected) to level 2, and run the script it retains the level 1 from before. I see your comment in there but I’m pretty trash at the moment when it comes to python/method overrides.
Is it difficult to have a precursor that uses the method RemoveMassLevelDataFromMassInstance to clear out any possibly applied levels?
To make that node, would be a simple change. The logic to determine if the mass floor gets removed or not could be comparing the level that the mass is on vs the mass floors level. If the mass floor level does not equal the level the mass is on, clear it and if they equal each other, leave the mass alone.
1 Like
I had to use chat GPT a little bit but I was able to get it to clear out any applied Mass Floors and only apply the ones associated to the Level the Mass is associated to. Thank you so much for your help!
Code below incase anyone needs it, CPython3
import clr
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument
masses = UnwrapElement(IN[0])
# Start a transaction in Revit
TransactionManager.Instance.EnsureInTransaction(doc)
# Iterate over each mass instance
for mass in masses:
# Get the ElementId of the mass instance
mass_id = mass.Id
# Get the existing Mass Floor level IDs associated with the mass instance
existing_level_ids = MassInstanceUtils.GetMassLevelIds(doc, mass_id)
# Iterate over each level ID and remove the associated Mass Floor
for level_id in existing_level_ids:
MassInstanceUtils.RemoveMassLevelDataFromMassInstance(doc, mass_id, level_id)
# End the transaction
TransactionManager.Instance.TransactionTaskDone()
# Check if the input is a list, if yes return it, if it's not a list, make it one.
def uwlist(input):
result = input if isinstance(input, list) else [input]
return UnwrapElement(result)
# Collect the inputs and unwrap them exposing more of their methods and properties
mass = uwlist(IN[0])
level = uwlist(IN[1])
# Start a transaction in Revit since we are creating a mass floor object.
TransactionManager.Instance.EnsureInTransaction(doc)
# Create a blank list to store our Revit floors
massFloors = []
# We use a zip function which allows us to take the mass at index 0 and level at index 0 to create the floor. Then it goes to the mass and level at index 1, creates the floor, and so on...
for m,l in zip(mass,level):
# The api used to add a mass floor to a mass. There is also a method to remove a floor via the level. This will return the element ID of the mass floor.
massFloorid = MassInstanceUtils.AddMassLevelDataToMassInstance(doc, m.Id, l.Id)
# Since it's an element ID, we want to return the actual element so we use the doc.GetElement() method.
massFloors.append(doc.GetElement(massFloorid))
#End the transaction
TransactionManager.Instance.TransactionTaskDone()
#Return what's done.
OUT = massFloors
1 Like
Love this! I got a bit carried away with it and developed this logic. it handles removing the floor if the floor level doesn’t match the masses placed level and there’s logic to add it back. I did this pretty quick so there’s probably a flaw in it somewhere. Either way, glad I could help you out!
MassFlooringAddorRemove.dyn (51.3 KB)
Packages Used:
DesignTech 1.0.8
GeniusLoci 2023.7.13
Clockwork
2 Likes