A new version of Group Clashes

I just updated my Clash Grouper plugin for Navisworks.

The main purpose of this update was to solve some issue encountered by early adopters. The plugin should now be more stable. Many thanks to the users who contributed to this release with their feedback and test models.

I also add some new features to the application, that I will showcase with this example. Detecting clashes in this simple layout of ducts (Selection A, in blue) and pipes (Selection B, in red) yield 8 clashes, spread like this:

An example of a clash test

Creating subgroups

Grouping with two condition will now create a first group per the first rule. It will then divide this first group into subgroups, following the second rule.

If we group this example by Selection A (the ducts), we get the following groups, named after the item used to create the group. All clashes involving the same item from selection A are grouped together:

Grouping by Selection A

If we add a new group rule, say, by grid intersection, the plugin will break these groups into subgroup, according to this new rule. Here, it will rename the existing group by adding the nearest grid intersection name, and break the group {Clash 7, Clash 8} into two, each one belonging to a different grid intersection.

Grouping by Selection A and Grids

Keep existing groups

You can now keep existing groups, so the Group Clashes will run only on the remaining clashes. This open more possibilities for complex workflows to group and sort clash results.

For example, you can group by status, explode the “Active” group and keep this “Approved” group. After running again the grouping function by level, it will only take into account the clash result, and keep the “Approved” group intact, allowing you to focus on “Active” group

Another example, if we create manually the following group in our previous clash test:

An existing group

We can then run a Group by Grid intersection on the remaining clashes to create the following groups for the remaining clashes, without disturbing the existing group.

Remaining clashes are grouped

Batch grouping

You can now select multiple clash tests to apply the same grouping rules to all of them

Batch processing

Along these new features, a few corrections have been made. Some groups where not properly named, this is now corrected, and these groups names should now be more meaningful. Handling missing grids or levels is now better managed, and the application should be generally more stable.

As usual, you will find this new version of Group Clashes on the Autodesk App Store. If you want to develop your own grouping rules, you can also find the entire source code on Github.

Happy grouping!

Group Clashes

If you have already run some clash detection, you have probably ended up with thousand of clashes, and wondering how you could find something interesting in this mess.


Furthermore, finding clashes is not really useful in itself. The purpose of clash detection is to be able to find and hopefully solve issues in the design. And we quickly realize that a clash is not an issue in itself, but can be the symptom of an issue. Being able to extract a real issue from a meaningless bunch of clashes is what we are looking for. This is how we can gain some return from clash detection.

To do so, I tend to focus on specific subjects. Instead of running useless clash detections between entire model, I rather focus on specific issues and know beforehand what I am looking for.

For example, instead of running a clash detection between an architectural and a structural model, and end up with thousand of clashes, we can run a clash detection only between architectural rooms and structural concrete beams. As we know which type of element are involved in the clash detection, we can understand what a “clash” mean. Here, it means that there is a beam below the ceiling height. Furthermore, we can also group these clashes by room, and immediately highlight the problematic area where we can focus our efforts.


To help in this regards, I created a plugin for Navisworks Manage to automatically group these clashes. After a beta version published last year, I finally take the time to properly develop a full-fledged application and publish it on the Autodesk App Store. It is a fully redesigned Group Clashes Navisworks plugin, with a new interface that integrates seamlessly into the Navisworks interface.


The grouping rules have also been redesigned, and now include the following methods :

  • Group by Level: This rule will group clashes according to their nearest level, and name the group after the level.


  • Group by Grid Intersection: This rule will group clashes according to their nearest grid intersection, and name the group after these grids.


  • Group by Selection A: This rule will group all clashes belonging to an element of the selection A, and name the group after this element. As an example, if a room in Selection A has many clashes with beams in Selection B, all these clashes will be grouped.


  • Group by Selection B: This rule will group all clashes belonging to an element of the selection B, and name the group after this element.


  • Group by Assigned To, Approved By, and Status: These three rules will use various properties of the clash to group them. As an example, you can use this rule to group all clashes assigned to you.

You can also group with two rules, the first one will rename the clash group created by the second one. This enables various possibilities, like having clashes grouped by a given selection and renamed according to the one assigned to.

Group Clashes can have difficulties in managing clash reports with more than 10 000 clashes. Be smart when you set up your clash tests, and everything will be fine.

Group Clashes is now out of beta, and you will have to pay $10 to download it on the Autodesk App Store.

Yet, Group Clashes is also open-source. You can find the entire source code on Github, build your own plugin, and develop your own grouping rules.

Measuring ceiling heights

I recently have to measure the actual headroom of every room in an architectural model, and copy this value in a room parameter.

Instead of checking manually every room, I create a small Dynamo definition, based on the most underrated node in Dynamo, Raybounce.

The Raybounce.ByOriginDirection is basically a laser rangefinder for Dynamo. It works with an origin point and a direction, and give in return the first intersecting element, along with the point of intersection. It is pretty powerful, and its uses range from basic measurements to advanced Line Of Sight Analysis.


Using DynamoMEP, I retrieve every room in the model, and create a grid of points in each of them. These points are arbitrary spaced 50 cm apart, and serve as origin points for my Raybounce node.


Furthermore, in order to avoid that my laser beams hit the floor, I move my origin points 1 cm above the floor level.


The Raybounce.ByOriginDirection use these points, a Z vector as a direction and a 3D view. Since only elements visible in this view will be detected, I hide doors and stairs to remove interferences with these elements.


Along with the intersection point, the Raybounce.ByOriginDirection return the origin point that I filter out with a boolean mask.



I also make use of the List.Map node to perform any kind of operation (Flatten, Sort …) on the sublist containing the points while keeping them grouped by lists corresponding to the original rooms.


I finally calculate the headroom height, and retrieve the shortest one for each room. I pass this value to the Limit Offset parameter of the corresponding room.


Initially, every room’s Limit Offset is 2m.


After running the Dynamo script, every Limit Offset is updated to reflect the actual minimum headroom in each room. Since we have a sloped roof, the minimum headroom is not necessarily the ceiling, but can be the lower part of the roof.


Using the Raybounce node can be quite challenging, especially when it comes to sorting the resulting points, but it is totally worth the effort. You will find here the Dynamo definition, feel free to use it for your own project.

This was also the occasion for me to update DynamoMEP for Dynamo 1.0, and add a Grid function to create a nice array of point in a Room or a Space. As usual, you will find these updates in the Dynamo Package Manager.

Using Dynamo for MEP Design – Part 2

This is the second part of my article, originally published in the official magazine of Autodesk User Group International, AUGIWorld.

Link between terminals and the main duct.

To fully exploit Duct sizing capabilities in Revit, we generally need a fully connected network between the mechanical equipment and Air Terminals. But drawing every duct for the entire networks from source to terminal can be time consuming and not relevant in the early phase of a project, when architectural layout is subject to major changes.

A possibility is to use Dynamo to virtually link every terminal to a placeholder family that will collect and sum Airflows in a given area and send the sum to a placeholder family used to perform duct sizing calculations on the main branch.


Revit provide us the Connect the main duct to “M_Rectangular Duct Connector – Supply Air – Air Terminal”. This is a generic terminal that will simulate the rest of the terminals. We connect this generic terminal to our main branch, and use it to simulate the rest of the duct networks.

The following Dynamo definition sums airflows of the selected Air Terminal and pass the value in the Airflow parameter of the placeholder family. This placeholder family now simulate the airflow of all selected air terminals. Since this family is connected to the main duct networks, we can now perform duct sizing for the main branch, without having to model the entire duct layout.


A word of warning anyway, since this placeholder family is integrated into the system, flow sum for the duct system is multiplied by two, since Revit count both the airflow of every air terminal and the airflow coming from the placeholder family.

Dynamo File

From Specified Airflow to actual terminal Flow

Another example of the power of Dynamo come when linking Air terminal to their enclosing MEP Space. In this example, we will see how to retrieve the required airflow in a given MEP Space, and distribute this value on every air terminal enclosed in this space.

We start by finding all MEP Space, and retrieving their “Specified Supply Airflow”. We also get all Air terminals, and use the Space.IsInSpace node to find if a given terminal is in the space. We make sure to set up the lacing of this node to “Cross Product” in order to test every Air Terminal with every MEP Space. This give us multiple lists of true or false indicating whether a given Air Terminal is in the space. With the usual combination of List.AllIndiceOf and GetItemAtIndex, we find our air terminals grouped by their enclosing space. We count the number of these terminals in each group, and use this count and a division to get the specified airflow on each terminal. The List.OfRepetedItem give us an instance of this specified airflow by terminal. We finally apply these value to these terminals with the Element.SetParameterByValue.


As we update the Specified Airflow of each MEP Spaces, this value will be divided by the number of terminal in the space, and applied to the said terminals.


Dynamo File

Terminal Max Flow

Another application of Dynamo is the real-time checking for max values in a given terminal equipment. In this example, we will check whether the airflow of a given terminal is below is max value, and highlight in red when the airflow is above the max value. In some way, this is similar to the conditional formatting function in Excel, except we are doing it directly into Revit.

We start by finding all air terminal unit in Revit with the “All Elements Of Category” node. Using the GetParameterValueByName, we get the Airflow on each of these air terminal. Since the Maximum Airflow is a type parameter, we use the FamilyInstance.Type node to retrieve the family type, then use again the GetParameterValueByName to find the “Max Flow”.

We can now compare this two values, and use the List.FilterByBooleanMask to find all terminals where Airflow is above the Max Airflow.


The last step is to override the color of these terminals to override by color to highlight the results.


This fairly simple example showcase the possibilities of Dynamo combined with the proper Revit objects library.

Dynamo File


Through these five examples, we see how to use Dynamo to enhance your calculation powers in Revit. It is clear by now that Revit is far more than a modeling tool, and once combined with Dynamo, it opens a lot possibilities for mechanical engineers.
Finally, I want to give my deepest thanks to Andrew Duncan, from Arup, for its great Autodesk university courses, where I get most of my inspiration for these examples.

Using Dynamo for MEP Design – Part 1

This two parts post was originally published in the official magazine of Autodesk User Group International, AUGIWorld.

Most examples of Dynamo focus on computational design and complex geometries. Many see Dynamo as a tool for creating complex geometry, and consider it from an architectural perspective. But Dynamo can be the powerful ally of every trade, all along the project life. By harnessing the data manipulation capabilities of Dynamo, you can largely improve on the current calculation features of Revit, and create new workflow for designing directly in Revit.

Through five use cases, I will present you some ideas for using Dynamo for mechanical engineering.

I will assume that you are already familiar with the interface and have a general understanding of how Dynamo works. Most examples below can be realized with “out of the box” Dynamo nodes, but to shorten my graph, I will make use of the following packages:

I will also use my own package, DynamoMEP, to manipulate Rooms and Spaces. All these packages are of course freely available on the Dynamo Package Manager. If Dynamo doesn’t include a lot of functionalities around Room, Space and Mechanical Equipment, I use extensively the Package Manager to enhance these functionalities and create new workflows for mechanical engineers.

A final word, try these examples on small models before running them in production, and work in “Manual” mode, a few graph I will use are quite hungry for memory.

Link between Room and Spaces

Rooms and Spaces are essential for everything from room names and numbers to energy modeling. And before anything else, you have to retrieve any architectural room and convert it into an MEP Space to be able to work with it. You can of course use the “Place Spaces automatically” function of Revit, but this does not match exactly every architectural room with a MEP Space, and lack some basic functionalities. To improve on this, you can use a few Dynamo nodes to create a MEP Space for every room in a given linked file.

The procedure focus on retrieving every room from the architectural linked file (with the Element.GetFromLinkedFile) and using these rooms to create a matching space using the Space.ByPoint node from DynamoMEP.


You can also retrieve parameters values from these architectural rooms and paste them into your newly created Spaces using the Element.SetParameterByName node.


As rooms evolve in the architectural model, you will be able to recreate on the fly the corresponding Spaces. However, be careful not to duplicate an existing space.

Dynamo File

Link between Excel and Spaces

One of the most featured use of Dynamo is the link with Excel spreadsheets. Theses nodes link two of our most used design tools, Excel and Revit.

For the mechanical engineer, this provide the ability to add programmatic values directly in Revit Spaces. In the following example, I will show you how to load the specified airflow value from an Excel spreadsheet. I will make extensive use of Dynamo lists, and present some ways to manipulate them.

We start with a path to an Excel file, and use it to feed the Excel.ReadFromFile node. This node read line by line the content of our Excel file. We remove the first line, the header, with the List.RestOfItems node, and use the Transpose node to convert our list of Excel rows into a list of Excel columns. By now, each list in our Dynamo node represent an Excel column.


With the List.GetItemAtIndex, we retrieve a list containing all MEP Space number and a list with their associate airflow.

To feed the “Specified Supply Airflow” parameter of our modeled Spaces, we need match them with the Space number in our Excel spreadsheet. To do so, we start by retrieving them (All Element of Category node), and get their number (Element.GetParameterValueByName).

The node List.FirstItemOf give us the row number of each of these Space Number in our Excel file. For each of our existing MEP Space in our model, we can now get the corresponding row in Excel.


Using the List.GetItemAtIndex, we get the required Airflow value in the Excel Spreadsheet. Before pasting them into Revit with the Element.SetParameterByName, we convert them to cubic foot, since Dynamo always work in Feet.


The entire business of retrieving values from Excel spreadsheet is generally only a matter of list, and nodes like Transpose, GetItemAtInded and FirstIndexOf are quite useful here. If this example only cover the specified airflow, it can of course be extended to every kind of data sorted in an Excel spreadsheet.

Just make sure that your MEP Space numbers match between your Excel file and your Revit model, since any discrepancy will make the FirstIndexOf fail.

Dynamo File

Next week, stay tuned for the second part of this post, where all secrets of airflow and terminals will be revealed.

MEP design and Dynamo

Most of the work we see with Dynamo involves designing complex parametric geometry. But Dynamo can also help you automate your design and make more informed decisions, even on the most ordinary cubic building.

A lot of tasks of the MEP engineer involves retrieving information from the architectural model and can be automated using Dynamo.

The first task of the MEP engineer is to retrieve rooms from the architectural model and create MEP Spaces from it. The “Place Spaces Automatically” Revit function can be useful here, but it is far from enough in many cases. There isn’t any control on the created spaces, and properties from the room cannot be added to the newly created space.

To improve on this function, I start exploring space creation in Dynamo. There isn’t much support for Room and Space built in Dynamo. Some package can fill this gap (Lunchbox from Nathan Miller and Clockworks from Andreas Dieckmann) but does not offer a complete solution. Furthermore, we need support for linked files, since architectural rooms are most of time in linked files.

So I create my own Dynamo package, called DynamoMEP. This package contains a set of nodes for creating and working with Room and MEP Space.


I use these custom nodes to create an MEP Space from every Room in a linked architectural project.

I start by retrieving linked rooms using SteamNodes, a great package from Juline Benoit. Using Element.GetFromLinkedFile gives me a list of rooms in the linked file (The Get Document came from the Grimshaw package).


Using the Room.FromElement node, I convert these linked elements into Rooms. I can now get their location points, and create my MEP spaces based on these points.


Still using the DynamoMEP package, I can retrieve basic properties from these spaces, like their origin point, their associated level and their bounding elements.


My model has now a matching MEP Space for every room created in the linked model. Since we are using Dynamo, we can have a much more sophisticated workflow, and retrieve specific properties in the rooms to have them added to the newly created space.

DynamoMEP is still in this infancy, and need a lot of improvement, so don’t hesitate to report any bug or missing feature. You can add an issue on Github, or post a comment below. I hope to add new features as I develop MEP workflows in Dynamo.


Details Items, subcategories and filled regions

I am currently working with multiple detail items to create a set of views for architectural detailing. These Detail Items must comply with a precise standard for color and line weights, and of course, be consistent all over the model.

To implement these requirements, I define a set of subcategories for these detail items. Let see how it works with these two wood windows details.


These detail items already contain various subcategories, and I can control the color, weight and patterns of their lines in Visibility Overrides. Here Medium Lines are blue and Light Lines are red. Interesting, but not quite enough.


I open these two detail items, go to Object Styles, and create four new subcategories: Wood, Glass, Sealant and Steel. I also remove the previous subcategories. I can now select all lines in the detail item, and assign corresponding subcategories to these lines. Once these detail items are loaded back in the model, the four Detail Item subcategories are visible in the Graphic Overrides window.

I can now control line color, weight and pattern directly in my model, in the Graphic Overrides window for the current view, or in the Object Styles window to apply these colors to every details in the model.


Sadly, there is no corresponding feature for managing filled region. As you can see in the picture above, the wood pattern is still in black.

In order to change pattern or color in a filled region, you have to edit the detail item and change the filled region style in the family. If you want to edit your wood pattern, you have to open every detail items containing wood, and change the pattern in the family.

To fix this, and be able to edit directly filled region style for every detail item, I create a small piece of code. This function matches model filled region types with those inside the detail item. So if I have a filled region in my Detail Item family with the same name than one in my Revit project, this filled region will take the properties of the one in the project.


After running this function, I end up with nicely matching wood pattern, all set up directly in my Revit project.


As usual, you will find the source code for this solution below, I hope it will help you solve your filled region issues.

public partial class ThisApplication
	public void MatchFilledRegion()
		Document doc = this.ActiveUIDocument.Document;
		//Find all Filled Region Type, and create a dictonary with it
		Dictionary<string,FilledRegionType> modelFilledRegionTypes =
			new FilteredElementCollector(doc).OfClass(typeof(FilledRegionType)).ToElements().Cast<FilledRegionType>().ToDictionary(e => e.Name);
		//Find all loaded families
		IList<Element> elements = new FilteredElementCollector(doc).OfClass(typeof(Family)).ToElements();
		//Get Detail Item category id.
		ElementId detailItemCategoryId = doc.Settings.Categories.get_Item(BuiltInCategory.OST_DetailComponents).Id;

		//Loop on all loaded families
		foreach (Element familyElement in elements) {
			Family family = familyElement as Family;
			//Exit the families loop if it isn't a Detail Item Familly
			if (family.FamilyCategory.Id != detailItemCategoryId) continue;

			//Open the family
			Document familyDoc = doc.EditFamily(family);
			string familyPath = Path.Combine(Path.GetTempPath(),family.Name+".rfa");
			bool familyEdited = false;
			//Find all Filled Region Type in the family
			IList<Element> filledRegionTypes = new FilteredElementCollector(familyDoc).OfClass(typeof(FilledRegionType)).ToElements();
			using (Transaction famTx = new Transaction(familyDoc))
				famTx.Start("Edit Filled Region Type");
				//Loop on all Filled Region types in the family
				foreach (Element filledRegionTypeElement in filledRegionTypes)
					FilledRegionType filledRegionType = filledRegionTypeElement as FilledRegionType;
					if (modelFilledRegionTypes.ContainsKey(filledRegionType.Name))
						FilledRegionType refFilledRegion = modelFilledRegionTypes[filledRegionType.Name];
						//Change the color
						if (filledRegionType.Color.Red != refFilledRegion.Color.Red
						    || filledRegionType.Color.Blue != refFilledRegion.Color.Blue
						    || filledRegionType.Color.Green != refFilledRegion.Color.Green)
							filledRegionType.Color = refFilledRegion.Color;
							familyEdited = true;
						//Change the Background
						if (filledRegionType.Background != refFilledRegion.Background)
							filledRegionType.Background = refFilledRegion.Background;
							familyEdited = true;
						//Change line weight
						if (filledRegionType.LineWeight != refFilledRegion.LineWeight)
							filledRegionType.LineWeight = refFilledRegion.LineWeight;
							familyEdited = true;
			if (familyEdited)
				familyDoc.LoadFamily(doc, new FamilyOption());
				familyDoc.Close( false );
				familyDoc.Close( false );

public class FamilyOption : IFamilyLoadOptions
	public bool OnFamilyFound(bool familyInUse,out bool overwriteParameterValues)
		overwriteParameterValues = true;
		return true;
	public bool OnSharedFamilyFound(Family sharedFamily,bool familyInUse, out FamilySource source,out bool overwriteParameterValues )
		source = FamilySource.Family;
		overwriteParameterValues = true;
		return true;


After showcasing Metro, a web-based interface for interpreting and visualizing building codes, Flux has released its new product, simply called Flux. I just had the chance to get an invitation to their beta, and I give you here the results of my first experimentation.


Flux is the first startup to spin out of the semi-secret Google X lab. Its goal is to build a platform to design buildings more easily, but also more ecologically. So I was pretty excited when I heard about their new product, a suite of tools to link together my favorite playthings, Dynamo, Grasshopper, and Excel

Flux works as a central repository for exchanging data between Grasshopper, Excel or Dynamo. Along with the website, Flux provides plugins for these solutions. As we work in our favorite design tool, we use the Flux plugin to upload or download data to or from the Flux central server.



Flux is organized around projects, each project containing a set of Data Key. These Data Key store values retrieved from Excel, Dynamo or Grasshopper. We can’t edit these values directly in the Flux interface, but we can display them in the Data View.


Once in Flux, Data Keys can be linked together in the Flow. This interface displays a visual programming language to transform data as they pass through Flux.


The initial tutorial shows us how to exchange data between Excel and Grasshopper. After going through this starter project, I give a try to the Dynamo plug-in.

I develop upon a common workflow, where an HVAC engineer retrieves MEP spaces location and area from a Revit model and define in Excel a set of values to be uploaded in Revit. For the sake of this experience, I am using the Specified Supply Airflow, but this should work with any value, such as the occupancy of a room or the section of a duct.

I am using here one of my project, which contains a thousand MEP Spaces, and retrieve some of its parameters in Dynamo. Using the GetParameterValueByName node, I retrieve four lists for spaces names, numbers, areas, and levels.


The Flux plug-in for Dynamo presents itself as a set of six nodes and allows us to select a project, find data key in this project, and get or push values from or to Flux. I connect my GetParameterValueByName nodes to the ToFlux nodes, and these values are uploaded to Flux.


I open a new Excel spreadsheet and use the Flux plugin to create three columns, for Name, Number and Area of the MEP Spaces. Flux automatically fills the spreadsheet with the values retrieved in Revit. I create a fourth column for Specified Supply Airflow and fill in some airflow values. As I hit enter, these values are uploaded to Flux and displayed in the Data view.


Back in Dynamo, I create a third group of nodes and link the FromFlux node to a SetParameterByName node. This completes the loop and every Specified Supply Airflow values defined in Excel are added to the MEP Spaces.


The entire workflow takes some time to set up, but the result is pretty impressive, and I see many possibilities around this kind of web-based exchange. Flux also integrates the possibility to upload geometry created in Grasshopper or Dynamo, and I still have a lot to test with this new tool.

Some Thoughts About Rooms and Spaces

A lot of MEP calculations available in Revit needs analytical spaces at some point, and it is crucial to have them properly modeled.

Properly placing these spaces can be a tedious business, especially for large buildings with hundreds of rooms. You can use the Place Space Automatically function, but it can create spaces in undesired places, and does not necessarily match the architectural rooms.

Furthermore, superposing of a space upon an existing architectural room only retrieves the name and the number of the corresponding room, and falls short for any other property we could want to add to our MEP space.

One of the solutions for creating MEP spaces is to match rooms created in the linked architectural model. To do so, I wrote a small application for creating a space for each room defined in a linked model.

This application loops on every linked instance, searching for rooms, and uses these rooms to create the corresponding space, retrieving in the process a handful of parameters, like name, number, and most critically, Limit Offset.

You can find here a little ScreenCast showing how it works. The entire source code is available below.

While working on it, I also found some interesting property : Computation Height. This is a level property, and it allows to define the height used to define boundaries on this level.

Let’s create three rooms on a given level:


But if we add some variation on the floor level, the room disappears with the following warning:Warning


By default, these rooms are calculated at the level elevation. Every wall at “0 m” above the level will be used as a room boundary.

The Computation Height properties allows us to change the elevation where we calculate the room. In our example, we change the Computation Height of the Level 1 to 1 meter, and the room fit nicely between its boundaries.


Of course, this is also true for Spaces.

public void RoomToSpace()
	Document activeDocument = this.ActiveUIDocument.Document;
	//Get All linked instance
	FilteredElementCollector collector = new FilteredElementCollector(activeDocument);
	List<RevitLinkInstance> linkInstances = collector.OfCategory(BuiltInCategory.OST_RvtLinks).WhereElementIsNotElementType().ToElements().Cast<RevitLinkInstance>().ToList();
	//Get all levels
	collector = new FilteredElementCollector(activeDocument);
	List<Level> levels = collector.OfCategory(BuiltInCategory.OST_Levels).WhereElementIsNotElementType().ToElements().Cast<Level>().ToList();
	using (Transaction tx = new Transaction(activeDocument)) {
tx.Start("Create Spaces");

//Loop on all linked instance
foreach (RevitLinkInstance linkInstance in linkInstances) {
	//Get linked document
	Document linkedDocument = linkInstance.GetLinkDocument();
	//Get linked instance position
	Transform t = linkInstance.GetTotalTransform();
	//Get rooms in the linkedDocument
	collector = new FilteredElementCollector(linkedDocument);
	List<Room> linkedRooms = collector.OfCategory(BuiltInCategory.OST_Rooms).ToElements().Cast<Room>().ToList();
	//Create a space for each room
	foreach (Room room in linkedRooms) {
LocationPoint locationPoint = room.Location as LocationPoint;
XYZ roomLocationPoint = locationPoint.Point;
roomLocationPoint = t.OfPoint(roomLocationPoint);

if (roomLocationPoint != null)
	Level level = GetNearestLevel(roomLocationPoint,levels);
	UV uv = new UV(roomLocationPoint.X, roomLocationPoint.Y);
	Space space = activeDocument.Create.NewSpace(level,uv);
	space.Number = room.Number;
	space.Name = room.Name;

	Parameter limitOffset = space.get_Parameter(BuiltInParameter.ROOM_UPPER_OFFSET);


private Level GetNearestLevel(XYZ point,List<Level> levels)
	Level nearestLevel = levels.FirstOrDefault();
	double delta = Math.Abs(nearestLevel.ProjectElevation - point.Z);
	foreach (Level currentLevel in levels) {
if (Math.Abs(currentLevel.ProjectElevation - point.Z) < delta) {
	nearestLevel = currentLevel;
	delta = Math.Abs(currentLevel.ProjectElevation - point.Z);
	return nearestLevel;

Wall openings

I came back from the first meeting of the Paris Revit User Group. Julien Benoit give us great insights on how to use Dynamo for data management and Revit automation.

His point of view give me some ideas to feed my current obsession, wall openings.

Modeling opening where ducts, pipes, cable trays or conduits intersect walls or floors can be a tedious business. Anyway, it always relies on the same underlining principle: we place a face-base opening family on the wall at the intersection with the duct, the pipe or the cable tray. We also respect a few rules of thumb when placing these openings to keep a structurally sound wall.


There is a handful of plug-in for placing them automatically but they all need a fair amount of work to replace them properly afterward, so I decide to stick to a more “manual” solution.

First of all, I use Navisworks to find where I have to place these openings. It gives me a list of walls. Then, I use Dynamo to create an elevation in front of each of these walls. These elevations ease the process for placing the opening family in the concrete model.

The entire process can be sum up like this:


The Dynamo definition use the wall bounding box and normal to create the section view coordinate system. I fumble around with Min and Max points to set the proper crop box for the final view. I also use a few nodes from archi-lab.net package to retrieve walls from their ids. You can find the entire Dynamo definition here.

“A problem well defined is a problem half solved”, and displaying a view of each problem is my first step toward the solution, even if I haven’t find yet any way to automate the entire wall opening thing.