MEP Systems UI and using IfcRelNests to persist order in IFC
As a followup of this https://community.osarch.org/discussion/3316/ifcspace-good-for-spatial-containment-of-ifcdistributionelements#latest and the suggestion for MEP Systems improvements asked in https://community.osarch.org/discussion/3213/ifcdistributionsystem-modeling-a-simple-circuit#latest
I am wondering if the implied order in IfcRelNests could be leveraged to store "Branch" information within a IFCDistributionCircuit (or a "system" in general).
This is a possible improvement in the UI:

- Is the current UIList for Systems
- Would be a new UIList to handle the elements which are part of a given system selected in the previous list. Currently there are operators to assign/unassign an element to a system. However, the port connectivity needs to be done manually in the ports (4) panel. Here since the connection order is available, maybe the connectivity handling could be made easier? I see some interesting use cases:
- Display: Show in this panel the elements assigned to the system in a tree like structure of branches (if there is a circular connection, just stop if the element is already displayed).
- Display: Show for each element the number of ports which are not connected / connected to other system / total number of ports of the element
- Operator: Create a group of connected elements.In 3DViewport you select a group of elements. The active one (the last selected) is used as head, checking the ports available and closest to other elements. Example: you select all the sewage elements in a bathroom that end up in a fitting to the general pipe. That fitting has a SOURCE port to the "general" sewage distribution system. That last active fitting is used to connect the ports of the rest of the elements and set the SINK/SOURCE relationships for the rest
- Operator: Replace one element with another. In 3DViewport you select two elements (one from unassigned system and another assigned) the ports from one are removed and the corresponding ones form the other are used. Maybe easiest is to assume that the replacing element is close to the replaced one and the closest ports decide which one is replaced with which one. Example: replace an IfcPipeSegment replace by an IfcPipeFitting (with a T junction with three ports for example).
- Operator: Remove one element (which is not the final one of the branch), which would be somewhat similar to the previous one, but using the next connected element as replacing element. I do not know if this is something useful enough? Example: an IfcPipeFitting T junction is no longer needed and just a segment is enough
- Is the current UIList for Ports. Maybe the single Port panel and the Ports Panel should be combined in a single one?
- Is a panel that shows the unassigned IfcDsitribution Elements. The idea behind is to have a better view of the remaining ones to be connected. Maybe this one should show a tree grouping them for , pipe, duct, cable, cablecarrier and then for fitting, segment, appliance etc.
For the trees created in the UIList 2 above persisting the order based on the user feedback (the " Create a group of connected elements" above establishes the active as the head, and the rest in order) might be a good thing to have. With just nominating the "heads" would be enough. Maybe IfcRelNests can be used for this?
Cheers!
Vicente.


Comments
My two cents:

I think one thing that could ease the learning curve of BB is the standardization of UI elements in different contexts.
So I'm going to take advantage of your goodwill @falken10vdl! :D
Why not follow the UI pattern of "Spatial Decomposition", with the necessary adjustments?
Like this:
In (1) the ports become visible as soon as the element is selected (3DViewport or system UI)
In (2) it is possible to show filtering by system (the default is by port order as Vicente proposed) or by IfcRelNests
Thanks!
For what it's worth, here's an AI assessment thus far...
9:38 AM
Scrutinized proposed system architecture for design soundness
The user is asking me to evaluate the architecture proposed in the PR and related discussions. Let me analyze the code and design decisions.
Let me think about what's being proposed:
data.pyandgroup.py) - A tree structure for representing MEP system hierarchies, with node types: system, connection_group, branch_group, element._group_connected_elements), then ordered by flow direction (_order_connected_elements).Let me evaluate this critically.
Show more
Done
Looking at the PR holistically, there are some solid ideas but also significant architectural concerns. Here's my assessment:
What's Good
The core concept is sound. Separating the logical tree structure (
SystemTreeNode/SystemTree) from the flat Blender UIList is the right instinct. Blender'sUIListis inherently flat, and MEP systems are inherently hierarchical, so a bridging layer is needed.Connection grouping by port connectivity (
_group_connected_elements) is a genuinely useful feature — identifying connected subgraphs within a system is exactly what users need to visualize flow paths.The tree-based expansion for viewport selection sync (
_expand_to_element_via_tree,update_system_uilist_indices) is a nice UX touch.Significant Concerns
1. The tree is defined twice.
SystemTreeNodeandSystemTreeappear in full in bothdata.pyandgroup.py— identical classes, duplicated. This is a maintenance hazard and suggests the boundaries between modules aren't clear. It should live in one place and be imported.2. Module-level mutable global state.
_current_system_treeas a module-level global is fragile. It creates implicit coupling — any code can callget_system_tree()and get whatever was last built, with no guarantee it's current. There's no invalidation mechanism; it just gets overwritten onimport_groups. In Blender's environment where operators, handlers, and UI draws can interleave unpredictably, this is a source of subtle bugs.3. The synthetic ID scheme is brittle. Connection groups use
-(system_id * 1000 + idx + 1), branch groups use-2000000 - (element_id * 100 + branch_idx). These magic-number formulas have hard collision boundaries — a system with >999 connection groups or an element with >99 branches would collide. More importantly, the encoding scheme is implicit; you have to know the formula to decode what a negative ID means. A registry or typed wrapper would be safer.4. JSON strings as property storage.
connection_groups_jsonandcustom_start_elements_jsonstored asStringPropertyis a workaround for Blender's limited property types, but it means parsing JSON on every access, no schema validation, and easy corruption. Every call site does its ownjson.loads/json.dumps— there's no single accessor managing serialization.5.
load_groupis doing too much. That single function simultaneously builds the tree, populates the UIList, computes connection groups, orders elements, handles expansion state, and manages synthetic IDs. It's deeply nested and hard to follow. The tree construction and UIList population should be separate passes: build the tree first, then flatten it to the UIList based on expansion state.6. Tight coupling between
group.pyand system-specific logic. TheGrouptool class now contains extensive MEP-specific methods (_group_connected_elements,_order_connected_elements,_find_start_element,_build_connection_tree, etc.). This is system/MEP domain logic living in a generic group tool. It makes the group tool harder to reason about for non-system group types.7. The "rebuild from element" operator stores persistent state in JSON props.
custom_start_elements_jsonmaps"system_id:connection_group_index"to element IDs. But connection group indices are positional — they change whenever elements are added/removed. This means stored rebuild keys can silently point to wrong groups after edits.Suggested Direction
If I were advising on this, I'd suggest:
load_groupenormously.data.pyor a newtree.py).group.pygeneric.The overall feature direction — showing connected element chains in the system UI, tracking unassigned elements, syncing selection — is valuable and clearly wanted by the community. The architecture just needs a refactoring pass to make it maintainable as complexity grows.
9:43 AM
Examined architecture alignment against IFC schema concepts
The user is asking about how well the proposed architecture aligns with the IFC schema. Let me think about this based on the documents provided.
Key IFC concepts at play here:
Now I need to evaluate whether the PR's approach properly maps these IFC relationships and maintains the semantic distinctions between systems, elements, ports, and how they connect to each other.
This is where the more fundamental issues lie, I think. Several things stand out:
The "Connection Group" Concept Has No IFC Counterpart
The PR introduces "connection groups" — clusters of elements connected by ports within a system — as a first-class concept in the tree with synthetic negative IDs, dedicated toggle operators, and UI rendering. But this is purely a visualization convenience. IFC has no notion of a "connection group." Elements belong to a system (
IfcRelAssignsToGroup), and they connect to each other via ports (IfcRelConnectsPorts). The connected subgraph is an emergent property, not a stored entity.This isn't necessarily wrong for a UI tool, but the problem is that these synthetic groups are treated almost like real IFC entities — they get IDs (negative ones), they're stored in the same list as actual
IfcSystementries, and the toggle/expand machinery treats them similarly. This blurs the line between IFC data and derived UI state. A user or downstream developer could reasonably ask: "What is this thing with ID -4001?" and the answer is "nothing in IFC."The Ordering Logic Replicates What Ports Already Express
_order_connected_elementsand_build_connection_treewalk the port graph to determine element order and branching. This is essentially re-deriving the topology that IFC already encodes through:IfcDistributionPort.FlowDirection(SOURCE/SINK/SOURCEANDSINK)IfcRelConnectsPorts(which port connects to which)ContainedInrelationship back to its elementThe PR's ordering algorithm tries to find a "start element" by looking for boundary elements with SINK ports, then walks connected-to/connected-from. But it conflates the two directions in a way that's a bit loose — it combines
get_connected_toandget_connected_fromand deduplicates, which effectively discards flow direction information during traversal. The IFC model already tells you which way flow goes; the code should follow that more faithfully rather than treating connectivity as an undirected graph and then trying to infer direction.The Community Discussion Raises IfcRelNests — The PR Doesn't Address It
In the OSArch thread (document 5), falken10vdl explicitly asks whether
IfcRelNestscould persist branch ordering within a system. Moult's response clarifies the semantics — nests describe hosted/attached objects with implied ordering for non-product objects. This is directly relevant because:IfcRelNests(or even just user-defined start elements), the tree wouldn't need full recomputation each timecustom_start_elements_jsonhack is essentially trying to solve this persistence problem outside IFC, when IFC may already provide a mechanismThe PR sidesteps this question entirely by keeping everything as runtime-derived UI state.
System Hierarchy vs. Element Hierarchy Is Conflated
IFC clearly separates:
IfcDistributionSystemcan contain sub-systems viaIfcRelAggregates(e.g., main electrical system → branch circuits)IfcRelAssignsToGroupThe PR's tree mixes all three into a single hierarchy: system nodes → connection group nodes → branch group nodes → element nodes. This flattening makes it harder to distinguish "this element is in this system" from "this element is connected after that element" from "this subsystem is part of that system." They're fundamentally different IFC relationships being presented as parent-child in one tree.
The Unassigned Elements List Is a Good IFC-Aligned Addition
One thing the PR gets right from an IFC perspective: showing distribution elements not assigned to any system. This directly queries
IfcRelAssignsToGroupmembership and surfaces a real data gap. The community clearly valued this — walpa's feedback was positive. It aligns with how IFC models are actually validated.What Better Alignment Would Look Like
IfcRelAggregates) → elements (viaIfcRelAssignsToGroup), with connectivity shown as a view on the elements, not as synthetic container nodes interleaved with real entitiesIfcRelNestsfor persisting user-defined ordering, as the community discussion suggests, rather than storing it in JSON string properties outside the IFC fileThe feature is solving a real problem — MEP engineers need to see how elements connect within systems — but the solution would be stronger if it leaned on what IFC already provides rather than building a parallel structure alongside it.
@walpa Syncing the UIList index based on the selected object I think that it is not currently how Bonsai does it ( @Moult , is this something related to performance? Or just would be confusing to end user?). Updating the index of one UIList based on the update of another UIList I see it is done in several places in Bonsai (for example in the Spatial panels you are mentioning above, the selection in the top BIM_UL_containers_manager UIList updates the contents in BIM_UL_elements UIList below ) so I guess that would be the recommended option.

Regarding the filtering you talk above, let me see if I understand you right. From the picture I guess you mean the "element mode", that is by what rule are elements meaningfully ordered/presented in the UIList (they are not filtered, all of them are shown but under different types of convenient tree structures, right? For filtering out in the UILists you always have at the bottom the search/filter field).
I think that is a very good idea to have similar layout as in the Spatial Decomposition. So If I have understood you properly it would be something like this?
What display options should be available then?
flow / connectivity. The one I was proposing: ex:
Panel / Source (3 / 6 / 10)
├─ Protective device (0 / 0 / 2)
Class > Type > Occurence (like in BIM_UL_elements)
IfcElectricDistributionBoard (1) .. then type and element count
IfcProtectiveDevice (1)
IfcSwitchingDevice (2)
IfcLightFixture (6)
IfcOutlet (4)
Element Classification (like in BIM_UL_elements)
Cheers!
@theoryshaw the PR 7633 needs to be rewritten from scratch I think. I have moved it to draft. I was adding things without the overall picture and it was getting very ugly :) then I tested against a big file and it was lagging too much... I think we need to come up with a clean UI that is responsive and useful to address building MEP systems in a friendly way (and have some visual feedback if some things are missing or wrong).
What do you think of the proposal above?
Regarding the "connection group" and "branch" concepts I was using in the PR I agree that those are not IFC concepts... they are useful to understand how a number of IfcDsitributionElements assigned to a system are connected. I was defining the "connection group" because I do not see anything in IFC that forces to have a single structure of connected items (although I believe that that is probably best practice instead of having "islands" of connected elements for the same system). I was then using the "branch" concept as a single linear series of element connected since that is quite visual to understand (and in the end how it is built physically). It is true that this can be inferred by parsing the IfcDistributionPort, except for the case of what to decide to be the head of it (which automatically could be inferred by taking assumptions like being a root or a leaf, being connected to external system or not connected at all, etc.). For that maybe an IfcRelNests is the solution... or maybe this "branch" concept with user selected head is not so relevant in the end (the community feedback I think is key to understand if this should be in or not)
Cheers!
Sorry, my knowledge of the BB code is limited, I can't comment on that.
You understood correctly, sorry for using the wrong word, it's not "filter," it's "ordered/presented."
Yes, yes, I would only put the port information after the unassigned objects, just so that the ports of the unassigned objects could also appear. Purely aesthetic... :)
Having these will already be great; the others will certainly be a bonus...
Thanks
Good morning, I'm happy to see that this MEP Systems UI is under further development! Currently I'm engaged in a professional AEC project involving several MEP systems, and we're trying hard to implement Bonsai into the company workflow. Obviously, there are some limitations with the software, so I'd like to propose two ideas based on my experience:
1 - Having an UI with hierarchical group visualization is just great. But I can't see the point of adding the single elements to the UI. In my experience, what everyone wants (and asks for) is circuit-related data, not single element-data. So the idea is to (somehow...) show the aggregated info of any circuit: Type, Container, Qto (Length), number of segments, number of bendings, number of tees, etc.
What we are trying here is to create an aggregate (replicating the IfcDistributionCircuit, this is, the same elements), and to generate a Pset in this aggregate in which to store this info. Currently it's not possible to manage Psets for IfcDistributionCircuits in Bonsai.
2 - If you can achieve to show the aggregate info of a circuit, the next step an again what everyone wants (and asks for) is to show a circuit diagram (like single line diagrams for electric circuits), not to scale, but showing relationship between elements.
@Breogan10
Each user can make different uses of the information. Each type of system has a different use. The more options, the better...
These are good suggestions for more viewing options.
Yes, I also think it's missing.

I see two options:
1 - IfcDistributionSystem appears in the outliner and its information (including pset) appears in the "Object Information" tab.
2 - Include pset info in the UI that @falken10vdl is proposing.
Cheers!