Simple MEP System Traversal

Here is a simple MEP system traversal implementation that especially addresses the issue of determining what equipment is connected to the systems.

The following read-only external command traverses all MEP systems in the document, using the MEPSystem.Elements property to retrieve most of the desired elements with very little effort.

More than half the code is actually fussing about with formatting the result:


[Transaction( TransactionMode.ReadOnly )]
public class Command : IExternalCommand
{
  static string PluralSuffix( int n )
  {
    return 1 == n ? "" : "s";
  }
 
  void TraverseSystems( Document doc )
  {
    FilteredElementCollector systems
      = new FilteredElementCollector( doc )
        .OfClass( typeof( MEPSystem ) );
 
    int i, n;
    string s;
    string[] a;
 
    StringBuilder message = new StringBuilder();
 
    foreach( MEPSystem system in systems )
    {
      message.AppendLine( "System Name: "
        + system.Name );
 
      message.AppendLine( "Base Equipment: "
        + system.BaseEquipment );
 
      ConnectorSet cs = system.ConnectorManager
        .Connectors;
 
      i = 0;
      n = cs.Size;
      a = new string[n];
 
      s = string.Format(
        "{0} element{1} in ConnectorManager: ",
        n, PluralSuffix( n ) );
 
      foreach( Connector c in cs )
      {
        Element e = c.Owner;
 
        if( null != e )
        {
          a[i++] = e.GetType().Name
            + " " + e.Id.ToString();
        }
      }
 
      message.AppendLine( s
        + string.Join( ", ", a ) );
 
      i = 0;
      n = system.Elements.Size;
      a = new string[n];
 
      s = string.Format(
        "{0} element{1} in System: ",
        n, PluralSuffix( n ) );
 
      foreach( Element e in system.Elements )
      {
        a[i++] = e.GetType().Name
          + " " + e.Id.ToString();
      }
 
      message.AppendLine( s
        + string.Join( ", ", a ) );
    }
 
    n = systems.Count<Element>();
 
    string caption =
      string.Format( "Traverse {0} MEP System{1}",
      n, (1 == n ? "" : "s") );
 
    TaskDialog dlg = new TaskDialog( caption );
    dlg.MainContent = message.ToString();
    dlg.Show();
  }
 
  public Result Execute(
    ExternalCommandData commandData,
    ref string message,
    ElementSet elements )
  {
    UIApplication uiapp = commandData.Application;
    UIDocument uidoc = uiapp.ActiveUIDocument;
    Document doc = uidoc.Document;
 
    TraverseSystems( doc );
 
    return Result.Succeeded;
  }
}

I executed this on an absolutely trivial system:

Simple system

That generates the following message box as a result:

Resulting message

Obviously, you will want to clean up the reporting significantly to suit your needs.
Currently, the owner elements in the ConnectorSet are listed, and the same elements also appear in the system elements list.
Here is another result of running this on two systems, an electrical and a duct system, with the elements highlighted in yellow:

Duplicated elements

Also, the API reports four elements in the system including one duct segment, whereas the UI reports three, which is what one would expect, so some identification of duplicate elements needs to be added to make this useful.

Furthermore, reporting on these ‘logical’ systems may have the limitation that in-line equipment such as duct dampers and valves are not reported as part of the system.
The other system traversal samples based on physical connectivity provide this info, however.

For now, the main point is to demonstrate that this simple access exists at all.

For your convenience, here is
MepSystemTraversal.zip containing
the source code, Visual Studio solution and add-in manifest for this command.

For more advanced traversal algorithms and determining the correct order of the individual system elements in the direction of the flow, you can look at the

TraverseSystem SDK sample

(2010,
2011)
for mechanical systems and the

AdnRme
sample
for electrical ones.


Comments

3 responses to “Simple MEP System Traversal”

  1. Great stuff! Thanks for posting!

  2. Hi Jeremy,
    Thanks for your great Blog and posts. I have a lot of “Unassigned Systems” in a MEP model and was wondering how to filter them? Following code gives me only the well assigned systems but not the rest:
    FilteredElementCollector collector = new FilteredElementCollector(doc).OfClass(typeof(MechanicalSystem));
    or … ()typeof(MEPSystem));
    The interesting point here is that Revit identifies these systems anyways and shows me them in the system browser. So my understanding is that there should be another way of filtering to catch these kind of systems.
    Regards

  3. Dear Puyan,
    I cannot say off-hand.
    I would suggest exploring the model in depth using RevitLookup or, better still, interactive API exploration using the Revit Python or Ruby shell as described here:
    http://thebuildingcoder.typepad.com/blog/2013/11/intimate-revit-database-exploration-with-the-python-shell.html
    If you simply create a small new model and ensure that such a system exists, it should be pretty easy to find in RevitLookup by snooping the database, and that will show you how to retrieve it using a fiitered element collector as well.
    Cheers, Jeremy.

Leave a Reply

Discover more from Autodesk Developer Blog

Subscribe now to keep reading and get access to the full archive.

Continue reading