ChangeTypeId for pipes and pipe fittings at once like "Change type"

Hi i try to write simple code to batch “Change type” for few systems but i stopped on method “ChangeTypeId”. Now my code change pipes type but leaves pipe fittings. There is a method which works like:
image
It’s anoying to change type for each system…
Thank you in advance!

import System
import os
from rpw import revit
from Autodesk.Revit.UI.Selection import *
from Autodesk.Revit.DB import *
from pyrevit import forms
from pyrevit import output

doc = revit.doc
uidoc = revit.uidoc

## Class and def
class CustomISelectionFilter(ISelectionFilter):
	def __init__(self, nom_categorie):
		self.nom_categorie = nom_categorie
	def AllowElement(self, e):
		if e.Category.Name in self.nom_categorie:
        # if self.nom_categorie.Contains(e.Category.Name):
		#if e.Category.Name == self.nom_categorie:
			return True
		else:
			return False
	def AllowReference(self, ref, point):
		return true

## Picking elements
with forms.WarningBar(title="Pick elements in model[pipes/pipe fittings"):
    collector = uidoc.Selection.PickObjects(ObjectType.Element,CustomISelectionFilter("Pipes Pipe Fittings"))

for i in collector:
	el=doc.GetElement(i.ElementId)
	print(el.GetTypeId)

transaction = Transaction(doc, 'Change type - PYLAB')
transaction.Start()

for i in collector:
	try:
		el=doc.GetElement(i.ElementId)
		el.ChangeTypeId(ElementId(142438))
	except Exception as e:
		print(e)
transaction.Commit()

99% you can’t do it. I think I’ve already tried :frowning:

1 Like

Yeah i look for a way around. Like pipe type prefer fittings etc. but i didn’t find anything… Very sad info

Actually, you can change fitting types, but only to valid fitting types (as per the pipe types routing preferences)
so let’s say you have a target pipe type, then after changing all pipe’s type to that one, you have to change all fitting types to the new types which are defined in the new pipe type’s routing preferences, if that makes sense.

rpm = pipe_type.RoutingPreferenceManager
rc = DB.RoutingConditions(DB.RoutingPreferenceErrorLevel.None) 
rc.AppendCondition(DB.RoutingCondition(size)) # size = size of the pipe

try:
    mech_fitting = fitting.MEPModel
except InvalidObjectException:
    continue

part_type = mech_fitting.PartType

if part_type == DB.PartType.Elbow:
    logger.debug('it is an Elbow')
    new_fitting_id = rpm.GetMEPPartId(
        DB.RoutingPreferenceRuleGroupType.Elbows,
        rc
    )
elif part_type == DB.PartType.Tee:
    logger.debug('it is a Tee')
    new_fitting_id = rpm.GetMEPPartId(
        DB.RoutingPreferenceRuleGroupType.Junctions,
        rc
    )
elif part_type == DB.PartType.Cross:
    logger.debug('it is a Cross')
    new_fitting_id = rpm.GetMEPPartId(
        DB.RoutingPreferenceRuleGroupType.Crosses,
        rc
    )
else:
    new_fitting_id = None
logger.debug('current fitting id: {}'.format(fitting.GetTypeId()))
if (new_fitting_id
        and fitting.Id != new_fitting_id
        and new_fitting_id.IntegerValue != -1):
    logger.debug('new fitting id: {}'.format(new_fitting_id))
    fitting.ChangeTypeId(new_fitting_id)
2 Likes

Thank you for your answer. This is the way i am looking for! I rewrite code from you to better understand the whole process. I have one problem. It is posible to get MEPPartId by size in criterion?
image

Now i can pick only one type of MEPPart by index… I want to change pipe fitting by different sizes.
My code:

import os

from Autodesk.Revit.UI.Selection import *
from Autodesk.Revit.DB import *
from pyrevit import forms
from pyrevit import output
from rpw import revit

doc = revit.doc
uidoc = revit.uidoc

## Class and def
class CustomISelectionFilter(ISelectionFilter):
	def __init__(self, nom_categorie):
		self.nom_categorie = nom_categorie
	def AllowElement(self, e):
		if e.Category.Name in self.nom_categorie:
        # if self.nom_categorie.Contains(e.Category.Name):
		#if e.Category.Name == self.nom_categorie:
			return True
		else:
			return False
	def AllowReference(self, ref, point):
		return true

def Pargetstr(element, name):
    return (element.GetParameters(name))[0].AsValueString()

def Parget(element, name):
    return (element.GetParameters(name))[0].AsString()

## Picking elements
with forms.WarningBar(title="Pick elements in model[pipes/pipe fittings"):
    collector = uidoc.Selection.PickObjects(ObjectType.Element,CustomISelectionFilter("Pipes Pipe Fittings"))


pipe_type = doc.GetElement(ElementId(261488))
rpm = pipe_type.RoutingPreferenceManager
rc = RoutingConditions(RoutingPreferenceErrorLevel.None)
print(pipe_type)
print(rpm)

transaction = Transaction(doc, 'Add insulation - PYLAB')
transaction.Start()

# for loop through picked elements
for i in collector:
    i =  doc.GetElement(i)
    fitting = i
    i = i.MEPModel
    mech_fitting = i.PartType
    print(mech_fitting)

# get routing preference MEPPartId
    if mech_fitting == PartType.Elbow:
        print('it is an Elbow')
        new_fitting_id = rpm.GetMEPPartId(
            RoutingPreferenceRuleGroupType.Elbows,
            rc)
        part_fitting_id = rpm.GetRule(
            RoutingPreferenceRuleGroupType.Elbows,
            0)
        part_fitting_id = part_fitting_id.MEPPartId
        print(new_fitting_id)
        print(part_fitting_id)
	

    fitting.ChangeTypeId(ElementId(631474)) # change by preselect id

transaction.Commit()

You have to append an actual RoutingCondition to rc:

rc.AppendCondition(RoutingCondition(size))

You can see it in my example above.

Ok i understand but what if my pipes have different sizes? Can i use size of pipe fitting?

You will need to have a reducer on either side, so I guess you should use the desired fitting size. My use case set a constant size for the whole branch, so I never had to handle these kind of situations.

1 Like

Ok i will think about this and write my whole code if i work around the problem :stuck_out_tongue: thanks for your fast reply!

I think i have working scripy:

Paweł Kińczyk (c)
from Autodesk.Revit.UI.Selection import *
from Autodesk.Revit.DB import *
from pyrevit import forms
from rpw import revit


# Get revit model
doc = revit.doc
uidoc = revit.uidoc


# Class and def
class CustomISelectionFilter(ISelectionFilter):
    def __init__(self, nom_categorie):
        self.nom_categorie = nom_categorie

    def AllowElement(self, e):
        if e.Category.Name in self.nom_categorie:
            # if self.nom_categorie.Contains(e.Category.Name):
            # if e.Category.Name == self.nom_categorie:
            return True
        else:
            return False

    def AllowReference(self, ref, point):
        return True


def get_dict_of_elements(build_in_category):
    elements = FilteredElementCollector(doc).OfCategory(
        build_in_category).WhereElementIsElementType().ToElements()
    return {Element.Name.GetValue(e): e for e in elements}


# Picking elements
with forms.WarningBar(title="Pick elements in model[pipes/pipe fittings]"):
    collector = uidoc.Selection.PickObjects(
        ObjectType.Element, CustomISelectionFilter("Pipes Pipe Fittings"))

# Get pipe types
pipe_types_dict = get_dict_of_elements(BuiltInCategory.OST_PipeCurves)

# Chose pipe type you want to change
pipe_type_name = forms.CommandSwitchWindow.show(pipe_types_dict.keys(), message='Select pipe type',
                                                recognize_access_key=False)

# Get routing preference
if pipe_type_name == None:
    forms.alert("You didn't pick any pipe type", exitscript=True)
    raise Exception("You didn't pick any pipe type")

pipe_type = pipe_types_dict[pipe_type_name]
rpm = pipe_type.RoutingPreferenceManager
rc = RoutingConditions(RoutingPreferenceErrorLevel.None)

# Clear unuse elements
del pipe_types_dict

# Sort elements pipe fittings/pipes
collector_fittings = []
collector_pipes = []
for element in collector:
    element_category = doc.GetElement(
        element).LookupParameter("Category").AsValueString()
    if element_category == "Pipes":
        collector_pipes.append(element)
    else:
        collector_fittings.append(element)


# Clear unuse elements
del collector

transaction = Transaction(doc, 'Batch change pipe - PYLAB')
transaction.Start()

# for loop through picked elements
for element in collector_pipes:

    try:
        print('it is a Pipe')
        element = doc.GetElement(element)
        element.ChangeTypeId(pipe_type.Id)
    except Exception as e:
        print("Pipe error")
        print(e)


for element in collector_fittings:
    refs = []
    try:
        element = doc.GetElement(element)
        fitting = element
        element = element.MEPModel

        # Get info about connected elements
        connectors = element.ConnectorManager.Connectors

        size_fit = float(0)
        for c in connectors:
            for r in c.AllRefs:
                c_size = float(r.Owner.LookupParameter("Size").AsString()[0:3])
                print(c_size)
                if size_fit <= c_size:
                    size_fit = c_size

        rc.AppendCondition(RoutingCondition(size_fit))

        pipe_fitting = element.PartType

        # Get routing preference MEPPartId
        if pipe_fitting == PartType.Elbow:
            print('it is an Elbow')
            new_fitting_id = rpm.GetMEPPartId(
                RoutingPreferenceRuleGroupType.Elbows,
                rc)
            part_fitting_id = rpm.GetRule(
                RoutingPreferenceRuleGroupType.Elbows,
                0)
            part_fitting_id = part_fitting_id.MEPPartId

        elif pipe_fitting == PartType.Tee:
            print('it is a Tee')
            new_fitting_id = rpm.GetMEPPartId(
                RoutingPreferenceRuleGroupType.Junctions, rc)
        elif pipe_fitting == PartType.Cross:
            print('it is a Cross')
            new_fitting_id = rpm.GetMEPPartId(
                RoutingPreferenceRuleGroupType.Crosses, rc)
        elif pipe_fitting == PartType.Transition:
            print('it is a Transition')
            new_fitting_id = rpm.GetMEPPartId(
                RoutingPreferenceRuleGroupType.Transitions, rc)
        else:
            new_fitting_id = None
            print('current fitting id: {}'.format(fitting.GetTypeId()))

        if (new_fitting_id
                and fitting.Id != new_fitting_id
                and new_fitting_id.IntegerValue != -1):
            fitting.ChangeTypeId(new_fitting_id)
    except Exception as e:
        print("Fitting error")
        print(e)

transaction.Commit()

works nice with similar pipes:


but has errors with very different (similar to change type in revit)

If you looking for future improvement visit my git: PYLAB/script.py at Batch_change_pipe_type · PawelKinczyk/PYLAB · GitHub

1 Like