Change Size for fabrication parts issue

Hi Everyone, Hope you’re doing well.

I was working on fabrication part mainly on fabrication network service change.

So I was working with change size method which will help me to change the size which is available in service. But my output shows the success but the size doesn’t get changed. Even I have tried with other service and size but no difference. The change size method in Revit API is not working for me. Is anyone facing the same ? or may be if you could give me the exact issue where I am missing that would be very helpful. Thanks alot for your help and time.

@jacob.small @solamour @c.poupin it would be helpful if I have anything from your side.

my WIP code is:

# Import necessary .NET and Revit API references
import clr
clr.AddReference('RevitServices')
clr.AddReference('RevitAPI')
clr.AddReference('RevitNodes')
clr.AddReference('System')

import System
from System.Collections.Generic import HashSet
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

from Autodesk.Revit.DB import *
from Autodesk.Revit.DB.Fabrication import *

# Get the current document
doc = DocumentManager.Instance.CurrentDBDocument
uidoc = DocumentManager.Instance.CurrentUIApplication.ActiveUIDocument

# Get user selection
selection_ids = uidoc.Selection.GetElementIds()

# Output placeholder
OUT = None

# ✅ Fix Count check using Python len()
if len(selection_ids) > 0:
    # ✅ Convert to proper .NET HashSet[ElementId]
    selIds = HashSet[ElementId]()
    for eid in selection_ids:
        selIds.Add(eid)

    try:
        TransactionManager.Instance.EnsureInTransaction(doc)

        # Get Fabrication config
        config = FabricationConfiguration.GetFabricationConfiguration(doc)

        # Get all loaded services
        allLoadedServices = config.GetAllLoadedServices()

        # ✅ Create size mappings using .NET HashSet
        sizeMappings = HashSet[FabricationPartSizeMap]()
        
        mapping = FabricationPartSizeMap(
            "2",      # Display size
            2.0,          # WidthDiameter
            2.0,          # Depth
            False,        # isProductList
            ConnectorProfileType.Rectangular,
            allLoadedServices[0].ServiceId,
            0             # Palette ID
        )
        mapping.MappedWidthDiameter = 2
        mapping.MappedDepth = 2
        sizeMappings.Add(mapping)

        # Create the network changer
        changesize = FabricationNetworkChangeService(doc)

        # Apply size change
        result = changesize.ChangeSize(selIds, sizeMappings)

        # Handle failures
        if result != FabricationNetworkChangeServiceResult.Success:
            errorIds = changesize.GetElementsThatFailed()
            if errorIds.Count > 0:
                OUT = "There was a problem with the change size."
            else:
                OUT = "Failed but no error elements found."
        else:
            doc.Regenerate()
            OUT = "Succeeded"

        TransactionManager.Instance.TransactionTaskDone()

    except Exception as ex:
        TransactionManager.Instance.ForceCloseTransaction()
        OUT = "Exception: " + str(ex)

else:
    OUT = "Please select at least one element."

I’m not an expert in fabrication but I know there are a lot of ‘you can’t do that’ boundaries. Best to post your DYN and a sample rvt file with all required references. I can try and have a look once that is done, but no promises as my day job has me doing pretty big lifts the next few weeks.

I’m not a Fabrication Part expert too, but it seems to me that to add size to an element you need to use CADmep or ESTmep software.

@shank_nv it’s possible to add a size via the Revit UI interface?

Hi @c.poupin thanks for that. Here is the API method that I have used it

public FabricationNetworkChangeServiceResult ChangeSize(
	ISet<ElementId> selection,
	ISet<FabricationPartSizeMap> fabricationPartSizeMaps
)

and I want to use the same method to apply diameter to all parts (inlcuding pipes and fittings)

Hi @jacob.small thanks for your prompt response. Here are the sample files attached
ParallelPipeDrawing_Change size.dyn (7.0 KB)

You can try on dummy file as well. I was using a dummy file only and a simple network as shown in snip.
for your refence.

Problem is I would not know how to build that dummy file, so your ask is for me to first learn the UI to do what you’re the expert in so that I can try and apply my expertise to solve your problem… And that learning so I can build the dummy file is certainly more than I have time for now, but if you post that Revit file and all links we might need then we’re getting closer.

@shank_nv

if you just want to change an (existing) size, you can use the parameter FABRICATION_PRODUCT_ENTRY directly

# Import necessary .NET and Revit API references
import clr
import sys
import System
clr.AddReference('RevitServices')
clr.AddReference('RevitAPI')
clr.AddReference('RevitNodes')

from System.Collections.Generic import HashSet
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

from Autodesk.Revit.DB import *
from Autodesk.Revit.DB.Fabrication import *

# Get the current document
doc = DocumentManager.Instance.CurrentDBDocument
uidoc = DocumentManager.Instance.CurrentUIApplication.ActiveUIDocument

select_fabParts = UnwrapElement(IN[0])
new_exist_diam = IN[1]

if len(select_fabParts) > 0:

    try:
        size_exist= all(
                    next((True for i in range(p.GetProductListEntryCount()) if str(new_exist_diam) == p.GetProductListEntryName(i)), False)\
                    for p in select_fabParts)
        if size_exist : 
            TransactionManager.Instance.EnsureInTransaction(doc)
            for part in select_fabParts:
                part.get_Parameter(BuiltInParameter.FABRICATION_PRODUCT_ENTRY).Set(str(new_exist_diam))
            TransactionManager.Instance.TransactionTaskDone()

            OUT = f"succes change to : {new_exist_diam}"
        else:
            OUT = f"invalid input size : {new_exist_diam}"

    except Exception as ex:
        OUT = "Exception: " + str(ex)
else:
    OUT = "Please select at least one element."

Hi @c.poupin I am trying it out in 2022 revit version with Cpython3 inside dynamo. Its not working for me

Kindly let me know what might be the issue ?

Is size “4” one of the available sizes?

can you share your rvt file (a sample file) ?

Yes @c.poupin its available in product entry. Please take a look

Sample file.rvt (7.8 MB)

It’s work correctly with the sample

I’ve updated the code to identify elements that don’t have the required size.

# Import necessary .NET and Revit API references
import clr
import sys
import System
clr.AddReference('RevitServices')
clr.AddReference('RevitAPI')
clr.AddReference('RevitNodes')

from System.Collections.Generic import HashSet
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

from Autodesk.Revit.DB import *
from Autodesk.Revit.DB.Fabrication import *

# Get the current document
doc = DocumentManager.Instance.CurrentDBDocument
uidoc = DocumentManager.Instance.CurrentUIApplication.ActiveUIDocument

select_fabParts = UnwrapElement(IN[0])
new_exist_diam = IN[1]

if len(select_fabParts) > 0:

    try:
        size_exist= all(
                    next((True for i in range(p.GetProductListEntryCount()) if str(new_exist_diam) == p.GetProductListEntryName(i)), False)\
                    for p in select_fabParts)
        if size_exist : 
            TransactionManager.Instance.EnsureInTransaction(doc)
            for part in select_fabParts:
                part.get_Parameter(BuiltInParameter.FABRICATION_PRODUCT_ENTRY).Set(str(new_exist_diam))
            TransactionManager.Instance.TransactionTaskDone()

            OUT = {"Result" : f"success input size : {new_exist_diam}"}
        else:
            failElements = [
                        p for p in select_fabParts
                            if all(str(new_exist_diam) != p.GetProductListEntryName(i) for i in range(p.GetProductListEntryCount()))
                            ]
                                
            OUT = {"Result" : f"invalid input size : {new_exist_diam}" , "Bad Elements without the input Size" : failElements}

    except Exception as ex:
        OUT = {"Result" :"Exception: " + str(ex)}
else:
    OUT = {"Result" :"Please select at least one element."}

I have checked it for other sizes as well. Yeah you’re right its working for size 4. But I have also checked it for otehr sizes of 6,8 or something. Its again failing. May I know what might be the issue ?

Size (example 8) not available for some items

use this code

Hi @c.poupin I found the solution by setting the property itself. I wont use the parameter but rather I use the property called “ProductListEntry” for parts. here is my updated code that works for any diameter available.

# Import necessary .NET and Revit API references
import clr
import sys
import System
clr.AddReference('RevitServices')
clr.AddReference('RevitAPI')
clr.AddReference('RevitNodes')

from System.Collections.Generic import HashSet
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

from Autodesk.Revit.DB import *
from Autodesk.Revit.DB.Fabrication import *

# Get the current document
doc = DocumentManager.Instance.CurrentDBDocument
uidoc = DocumentManager.Instance.CurrentUIApplication.ActiveUIDocument

# Inputs
select_fabParts = UnwrapElement(IN[0])  # List of FabricationParts
new_diameter_name = str(IN[1])               # Target diameter as string (e.g., "2\"")

updated_ids = []

TransactionManager.Instance.EnsureInTransaction(doc)

for part in select_fabParts:
    if isinstance(part, FabricationPart) and part.GetProductListEntryCount() > 0:
        matched_index = -1
        for i in range(part.GetProductListEntryCount()):
            name = part.GetProductListEntryName(i)
            if name.strip().lower() == new_diameter_name.strip().lower():
                matched_index = i
                break
        if matched_index >= 0:
            try:
                part.ProductListEntry = matched_index
                updated_ids.append(part.Id)
            except:
                pass  # Ignore failures

TransactionManager.Instance.TransactionTaskDone()

OUT = updated_ids

Thanks alot for your support and time.

2 Likes