I have a question about Dynamo in Revit, and I’ve honestly reached a point where I don’t really know what else to try. I would really appreciate your help
At the moment, I’m working on automating the process of moving my drawing elements to a different phase. Most of it is going well, but I’m still struggling with Rooms and Room Tags.
What I’m trying to achieve is basically this:
Select all room instances from one phase
Copy them (like Ctrl+C)
Paste them in exactly the same location
But place them in a new phase
So essentially, I want to duplicate all rooms (and their tags) into another phase, without having to recreate everything manually.
Does anyone have experience with this, or maybe some ideas on how to approach it? A solution using Dynamo nodes or a Python script inside Dynamo would both be great.
Don’t have time to write all your automation for you, but since room duplication has a few sneaky bits and others have asked similar elsewhere I’m providing the Python below. You’ll need to manage any additional parameters you care to match those values, though I grabbed name and number (see the note around line 72), and you’ll need to manage tagging on your own (I don’t recommend such).
Copy Rooms to Phase Python Script
########################################
############## Properties ##############
########################################
__author__ = 'Jacob Small'
__version__ = '0.1.0'
__description__ = "Duplicate a room into a new phase"
__RevitBuilds__ = "2027.0"
__DynamoBuilds__ = "4.0"
__ReleaseNotes__ = "POC only"
__Dependancies__ = "None"
__Copyright__ = "2026, Autodesk Inc."
__License__ = "Apache 2"
########################################
### Configure the Python environment ###
########################################
### standard imports ###
import sys #add the sys class to the Python environment so we can work with the sys objects
import clr #add the CLR (common language runtime) class to the Python environment so we can work with .net libraries
### Dynamo Revit imports ###
clr.AddReference("RevitNodes") #add Dynamo's Revit nodes library to the clr
import Revit #import Dynamo's Revit node class
clr.ImportExtensions(Revit.Elements) #add the element conversion methods to the CLR
clr.ImportExtensions(Revit.GeometryConversion) #add the geometry conversion methods to the CLR
clr.AddReference("RevitServices") #add the Revit services library to the CLR
import RevitServices #import the Revit services class to the Python environment
from RevitServices.Persistence import DocumentManager #import the document manager class to the Python environment
from RevitServices.Transactions import TransactionManager #import the transaction manager class to the Python environment
### Revit API imports ###
clr.AddReference("RevitAPI") #add the Revit API to the CLR
import Autodesk #add the Autodesk class to the Python environment
from Autodesk.Revit.DB import * #import every class of the Revit API to the Python environment
from Autodesk.Revit.DB.Architecture import Room #import the room class from the Architecture library of the Revit API
#########################################
###### Global variables and inputs ######
#########################################
### documents and standard variables ###
doc = DocumentManager.Instance.CurrentDBDocument #the current Revit document
### imports and unwrapping ###
initialRooms = UnwrapElement(IN[0]) #import the elements from IN[0] of the Dynamo environment and convert to native Revit elements
if not initialRooms.__class__ == [].__class__ : initialRooms = [initialRooms] #ensure that elems is a list, not an individual object, so that we can always prepare for a loop
initialRooms = [i for i in initialRooms if i.__class__ == Room]
if len(initialRooms)==0: sys.exit("\r\rProvide a list of rooms in the roomsToDupliacte input (IN[0]).\r\r")#throw a warning if nothing is in the OUT list
phase = UnwrapElement(IN[1]) #the phase in which the new rooms will be created
if not phase.__class__ == Phase: sys.exit("\r\rProvide a phase into the targetPhase input (IN[1]).\r\r") #if the phase input isn't a phase throw a warning
### output lists ###
OUT = [] #defining out here because I'm lazy like that
#########################################
############ Code goes here #############
#########################################
### section 1 ###
TransactionManager.Instance.EnsureInTransaction(doc) #start transaction
for initialRoom in initialRooms: #for each of the initial rooms
lvl = initialRoom.Level #get the level
location = initialRoom.Location.Point #get the location0
exist = doc.GetRoomAtPoint(location,phase) #check for a room at the phase and location
if not exist: #if not found
uv = UV(location.X,location.Y) #get the UV location
newRoom = doc.Create.NewRoom(lvl,uv) #create a new room
newRoom.Name = initialRoom.Name #set the name
newRoom.Number = initialRoom.Number #set the number
### you might want to set some parameter values here too, or in a subsequent node based on the input values ###
OUT.append(["Created room", newRoom]) #add the room to the output list
else: #otherwise
OUT.append(["Found room", exist]) #add the found room to the output list
TransactionManager.Instance.TransactionTaskDone() #end transaction
If you’d rather utilize something that more closely mimics the copy paste function you mention, you can make use of the CopyElements method of the ElementTransformUtils class that takes a view as the input and output. However I don’t recommend it as this can lead to multiple rooms in the same boundary (unless you’re in a project where bounding elements never change such as only painting and changing a window out).
Jacob points out some really important considerations for dealing with Rooms and Phases. You’ll need to address these issues regardless of your path forward, but you can literally copy/paste Rooms to a new Phase through the UI. Select all your rooms via “Select All Instances > In View”, a selection filter, or a schedule, then paste to a view in the targeted phase. The new rooms will be created in the active phase and in their respective locations.
Hey Jacob,
I have used your code, and it works great except for one major issue: it doesn’t place the rooms in the other phase. Instead, it places the duplicate rooms in the phase that is used in the active view.
I have a sample project that I can share with you, but I can’t upload a file because I am apparently a new user. However, I think that if you open a random model and create two phases (the current one you are using and another one, as I called it, “2. Koperstekening”), then if you run this command in a view where Phase 2 is the active phase, it works. But if you run it in Phase 1, it places the rooms in that phase instead, so it places them on the active phase.
Correct. That’s the process you’d need to follow. This is how Revit handles pretty much every element filtering property (Phase, Design Option, Workset, etc.). What’s your reason for not wanting to change views?
You could use this Room creation method and specify the phase in order to create an unplaced room on the correct phase, and then use this method to place that room in your model at the appropriate location if you don’t want to work with the active view. However, it’s way easier to just set your active view to a view with the appropriate phase and then use the one of the previous methods suggested.
As I mentioned above, you can do this via the UI with just a couple clicks as long as you paste to the correct phase.