From an Electrical Design standpoint, one of the biggest issues with implementing Revit in an Electrical Engineering Firm is Panel Schedules. Though the default Revit panels have come a long way, they are still unusable to many Engineering firms. Keeping track of hundreds of circuits, and applying complicated demand factors for many different load types can be a huge undertaking for anyone. Every firm that I've worked with has created their own custom solution. Autodesk probably isn’t going to get it right for everybody any time soon, so an in-house panel schedule solution seems to be the only real solution for now.
The first step in taking on this challenge is being able to tell the difference between different element types in the electrical equipment category.
One way to tell them apart is through the Part Type parameter, the way to access the Part Type Parameter is a little hidden though. From the family instance, you need to access the original family’s parameters and then reference that number from a table.
The parameter we are accessing is the “FAMILY_CONTENT_PART_TYPE”
|
Part Type Name |
|
Index |
|
Undefined Part Type |
= |
-1 |
|
Normal |
= |
0 |
|
Duct Mounted |
= |
1 |
|
Junction Box |
= |
2 |
|
Attaches To |
= |
3 |
|
Breaks Into |
= |
4 |
|
Elbow |
= |
5 |
|
Tee |
= |
6 |
|
Transition |
= |
7 |
|
Cross |
= |
8 |
|
Cap |
= |
9 |
|
Tap Perpendicular |
= |
10 |
|
Tap Adjustable |
= |
11 |
|
Offset |
= |
12 |
|
Union |
= |
13 |
|
Panelboard |
= |
14 |
|
Transformer |
= |
15 |
|
Switchboard |
= |
16 |
|
Other Panel |
= |
17 |
|
Equipment Switch |
= |
18 |
|
Switch |
= |
19 |
|
Valve - Breaks Into |
= |
20 |
|
Spud - Perpendicular |
= |
21 |
|
Spud - Adjustable |
= |
22 |
|
Damper |
= |
23 |
|
Wye |
= |
24 |
|
Lateral Tee |
= |
25 |
|
Lateral Cross |
= |
26 |
|
Pants |
= |
27 |
|
Multi Port |
= |
28 |
|
Valve - Normal |
= |
29 |
|
Tee |
= |
30 |
|
Cross |
= |
31 |
|
Flange |
= |
32 |
|
Junction Box Elbow |
= |
34 |
|
Channel Elbow |
= |
35 |
|
Channel Vertical Elbow |
= |
36 |
|
Channel Cross |
= |
37 |
|
Channel Tee |
= |
38 |
|
Channel Transition |
= |
39 |
|
Channel Union |
= |
40 |
|
Channel Offset |
= |
41 |
|
Channel Multi Port |
= |
42 |
|
Ladder Elbow |
= |
43 |
|
Ladder Vertical Elbow |
= |
44 |
|
Ladder Cross |
= |
45 |
|
Ladder Tee |
= |
46 |
|
Ladder Transition |
= |
47 |
|
Ladder Union |
= |
48 |
Here is the Code:
namespace QCSpike
{
[Transaction(TransactionMode.Manual)]
[Regeneration(RegenerationOption.Manual)]
public class PartType : IExternalCommand
{
public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
{
UIApplication RevitUiApp = commandData.Application;
UIDocument RevitUiDoc = RevitUiApp.ActiveUIDocument;
Document RevitDoc = RevitUiDoc.Document;
BuiltInParameter partTypeParam = BuiltInParameter.FAMILY_CONTENT_PART_TYPE;
BuiltInParameter nameParam = BuiltInParameter.RBS_ELEC_PANEL_NAME;
int PanelBoardIndex = 14;
int TransformerIndex = 15;
int SwitchBoardIndex = 16;
int OtherPanelIndex = 17;
int EquipmentSwitchIndex = 18;
StringBuilder PanelBoardList = new StringBuilder();
StringBuilder TransformerList = new StringBuilder();
StringBuilder SwitchBoardList = new StringBuilder();
StringBuilder OtherPanelList = new StringBuilder();
StringBuilder EquipmentSwitchList = new StringBuilder();
ElementCategoryFilter electricalEquipmentFilter = new ElementCategoryFilter(BuiltInCategory.OST_ElectricalEquipment);
FilteredElementCollector collector = new FilteredElementCollector(RevitDoc).WhereElementIsNotElementType();
IList elemList = collector.WherePasses(electricalEquipmentFilter).ToElements();
foreach (Element eqp in elemList)
{
FamilyInstance ElecEqp = eqp as FamilyInstance;
Family elecFam = ElecEqp.Symbol.Family;
Element elecElem = elecFam as Element;
if (elecElem.get_Parameter(partTypeParam).AsInteger() == PanelBoardIndex)
{
if (PanelBoardList.Length == 0)
{
PanelBoardList.AppendFormat("PanelBoards: \n");
}
PanelBoardList.AppendFormat("\t" + eqp.get_Parameter(nameParam).AsString() + "\n");
}
if (elecElem.get_Parameter(partTypeParam).AsInteger() == TransformerIndex)
{
if (TransformerList.Length == 0)
{
TransformerList.AppendFormat("Transformers: \n");
}
TransformerList.AppendFormat("\t" + eqp.get_Parameter(nameParam).AsString() + "\n");
}
if (elecElem.get_Parameter(partTypeParam).AsInteger() == SwitchBoardIndex)
{
if (SwitchBoardList.Length == 0)
{
SwitchBoardList.AppendFormat("SwitchBoards: \n");
}
SwitchBoardList.AppendFormat("\t" + eqp.get_Parameter(nameParam).AsString() + "\n");
}
if (elecElem.get_Parameter(partTypeParam).AsInteger() == OtherPanelIndex)
{
if (OtherPanelList.Length == 0)
{
OtherPanelList.AppendFormat("Other Panels: \n");
}
OtherPanelList.AppendFormat("\t" + eqp.get_Parameter(nameParam).AsString() + "\n");
}
if (elecElem.get_Parameter(partTypeParam).AsInteger() == EquipmentSwitchIndex)
{
if (EquipmentSwitchList.Length == 0)
{
EquipmentSwitchList.AppendFormat("Disconnects: \n");
}
EquipmentSwitchList.AppendFormat("\t" + eqp.Name + "\n");
}
}
MessageBox.Show(PanelBoardList + "\n" + TransformerList + "\n" + SwitchBoardList + "\n" + OtherPanelList + "\n" + EquipmentSwitchList + "\n" + SwitchList);
return Result.Succeeded;
}
}
}
Again, this is just one of the first steps in creating a custom In-House Panel Schedule solution, it snowballs from here. Should you completely bypass the built in Demand Factors because they don’t completely calculate loads the way Engineers need them to? Should Power Factors also be separately calculated? Furthermore, this parameter could also be a good way to analyze duct and piping systems by individual pieces.
-E Judd Kidman
RAD Software Developer