Category Archives: Python

[Revit] Delete parameters including hidden ones

In some case you need add or delete many parameters. Spiderinnet did many great articles about parameters, here are 2 of them :

Create shared parameter

Create project parameter

Some Revit addins and extensions are adding many parameters to you project. Some are not even visible to the user. It means that you have to use API to remove it.  In most common case you’ll never see it unless you use Revit Lookup. But when you export your model or do a duct pressure loss report it appears on it. So I made a script to get quickly rid of unwanted parameters (hidden or not).

from Autodesk.Revit.DB import *
from System import Guid

uidoc = __revit__.ActiveUIDocument
doc = __revit__.ActiveUIDocument.Document
app = __revit__.Application

#Retrieve all parameters in the document
params = FilteredElementCollector(doc).OfClass(ParameterElement)
filteredparams = []

#Store parameters which has a name starting with "magi" or "MC"
for param in params:
    if param.Name.startswith(("magi", "MC")): #startswith method accept tuple
        filteredparams.append(param)
        print param.Name #To check if a parameter in the list is not supposed to be deleted

#Delete all parameters in the list
t = Transaction(doc, "Delete parameters")
t.Start()
for param in filteredparams:
    doc.Delete(param.Id)
t.Commit()

Cheers !

[Revit] Change fittings reference level without moving it

A common pain in Revit is to manage object’s reference level :

  • If you change a duct/pipe reference level. It stays at the same location which is great.
  • If you change any fitting/accessory reference level. It move at the same offset on the defined level. It generates many errors when you change a level elevation during a project…
from Autodesk.Revit.DB import *

uidoc = __revit__.ActiveUIDocument
doc = __revit__.ActiveUIDocument.Document
getselection = uidoc.Selection.GetElementIds

#Get current selection and store it
selection = getselection()

#Ask user to pick an object which has the desired reference level
def pickobject():
    from Autodesk.Revit.UI.Selection import ObjectType
    __window__.Hide()
    picked = uidoc.Selection.PickObject(ObjectType.Element, "Sélectionnez la référence")
    __window__.Show()
    return picked

#Retrieve needed information from reference object
ref_object = doc.GetElement(pickobject().ElementId)
ref_level = ref_object.ReferenceLevel 
ref_levelid = ref_level.Id

t = Transaction(doc, "Change reference level")

t.Start()

#Change reference level and relative offset for each selected object in order to change reference plane without moving the object
for e in selection:
	object = doc.GetElement(e)
	object_param_level = object.get_Parameter(BuiltInParameter.FAMILY_LEVEL_PARAM)
	object_Level = doc.GetElement(object_param_level.AsElementId())
	object_param_offset = object.get_Parameter(BuiltInParameter.INSTANCE_FREE_HOST_OFFSET_PARAM)
	object_newoffset = object_param_offset.AsDouble() + object_Level.Elevation - ref_level.Elevation
	object_param_level.Set(ref_levelid)
	object_param_offset.Set(object_newoffset)
	
t.Commit()

I hope you’ll enjoy it as much as I do.

[Revit] Copy shared parameters from rooms of a linked file to your own spaces

It is very useful to be able to copy shared parameter from a linked file to you own file especially if you want to make a stable link to an external database or maintain data consistency between different models.

The Autodesk Space Naming Utility is very useful but limited to room/space number and name. With the following script methodology you are able to copy any shared or built in parameter.

Unfortunately, Space property «Room» return None when the room is in a linked file. Hopefully there is a workaround which has been highlighted here by Revitalizer. You can use the GetRoomAtPoint as followed (same in the other way to get space from room).

from Autodesk.Revit.DB import *
from Autodesk.Revit.DB.Mechanical import Space
from Autodesk.Revit.DB.Architecture import Room
from Autodesk.Revit.UI import UIApplication
from System import Guid

uidoc = __revit__.ActiveUIDocument
doc = __revit__.ActiveUIDocument.Document
getselection = uidoc.Selection.GetElementIds
app = __revit__.Application

#reference desired link
for e in app.Documents:
	if e.Title == "[LinkName].rvt":
		lien = e

#Reference the parameter you want to copy by GUID or BuiltInParameter
paramguid = Guid("88938699-b86d-4efa-aeb6-ce66d17d7755")

t = Transaction(doc, "Copy shared parameter from rooms to spaces")

t.Start()
#Get all spaces in the current project
for space in FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_MEPSpaces):	
	if space.Location != None: #Check if the space is placed
		#Get room at space insertion point location. Credit to Revitalizer : https://forums.autodesk.com/t5/revit-api/mep-space-class-room-property-returns-null-with-linked-models/td-p/3650268
		room = lien.GetRoomAtPoint(space.Location.Point)
		#Check if there is actually a room at this location
		if room != None:
			#Call desired parameter in both room and space
			spaceparam = space.get_Parameter(paramguid)
			roomparam = room.get_Parameter(paramguid)
			try:
				#Try to set space parameter value with room parameter value. It can fail if value is null for exemple 
				spaceparam.Set(roomparam.AsString())
			except:
				pass
t.Commit()

__window__.Close()

 

 

[Revit] Adding fluids using CoolProp

Sometimes you need to add new temperature in your project for at least 3 reasons :

  • When you use SI units Revit default fluids are bugged. I have seen them bugged for more than 5 years… Templates were made in Fahrenheit and some temperatures just don’t work when converted into °C or K.
  • Revit default fluids don’t have enough temperatures. About 5K between each and they usually just don’t fit the temperature you need in your project.
  • Water, ethylene and propylene glycol are the only default fluid available.

Here is a script example to add water to Revit. This way you can add any fluid available in CoolProp to Revit :

from Autodesk.Revit.DB import *
from Autodesk.Revit.DB.Architecture import *
from Autodesk.Revit.DB.Analysis import *
from Autodesk.Revit.DB.Plumbing import *
from Autodesk.Revit.Exceptions import *
from Autodesk.Revit.UI import TaskDialogCommonButtons
from Autodesk.Revit.UI import TaskDialogResult
import ctypes

#Load CoolProp shared library and configure PropsSI c_types units
CP = ctypes.cdll.LoadLibrary(r"E:\Cyril\Dropbox\CVC\BIM_Revit\ScriptsPython\dll\CoolProp.dll")
PropsSI = CP.PropsSI
PropsSI.argtypes = (ctypes.c_char_p, ctypes.c_char_p, ctypes.c_double, ctypes.c_char_p, ctypes.c_double, ctypes.c_char_p)
PropsSI.restype = ctypes.c_double

uidoc = __revit__.ActiveUIDocument
doc = __revit__.ActiveUIDocument.Document

#Set desired fluid, initial temperature(freezing temperature ?), desired pressure for properties call
fluid = 'Water'
t_init = 273.15
pressure = 101325

#Check if fluid_type exist and create it if not
fluid_type = FluidType.GetFluidType(doc, fluid)
if fluid_type == None:
	t = Transaction(doc, "Create fluid type")
	t.Start()
	FluidType.Create(doc, fluid)
	t.Commit()
	fluid_type = FluidType.GetFluidType(doc, fluid)

#Add new temperature with associated heat capacity and viscosity
t = Transaction(doc, "Add temperature")
t.Start()
for i in range(1,100):
	#Call CoolProp to get fluid properties and convert it to internal units if necessary 
	temperature = 273.15+i
	viscosity = UnitUtils.ConvertToInternalUnits(PropsSI('V','T',t_init+i,'P',pressure,fluid),DisplayUnitType.DUT_PASCAL_SECONDS)
	density = UnitUtils.ConvertToInternalUnits(PropsSI('D','T',t_init+i,'P',pressure,fluid),DisplayUnitType.DUT_KILOGRAMS_PER_CUBIC_METER)
	#Catching exceptions and trying to overwrite temperature if asked by user in the TaskDialog
	try:
		fluid_type.AddTemperature(FluidTemperature(temperature,viscosity,density))
	except ArgumentException:
		result = TaskDialog.Show("Error", "Temperature already exist, do you want to overwrite it ?",TaskDialogCommonButtons.Yes | TaskDialogCommonButtons.No | TaskDialogCommonButtons.Cancel, TaskDialogResult.Yes)
		if result == TaskDialogResult.Yes:
			try:
				fluid_type.RemoveTemperature(temperature)
				fluid_type.AddTemperature(FluidTemperature(temperature,viscosity,density))
			except ArgumentException:
				TaskDialog.Show("Overwrite error", "Temperature is currently in use and cannot be overwritten")
		elif result == TaskDialogResult.No:
			pass
		else:
			break
t.Commit()

Enjoy !

Working with fluid properties 2/2 : Using CoolProp in IronPython

Unfortunately, python wrapper cannot be used in ironpython environment (or at least I didn’t success to do so). So I had to find another way to use it directly in Revit. I used shared library (.dll) which can be downloaded on sourceforge : http://sourceforge.net/projects/coolprop/files/CoolProp/5.1.1/shared_library/Windows/64bit/.

It was a little tricky for a non professional programmer like me to understand how to call this CoolProp.dll properly. ctypes tutorial describe how to do it with standard python library. CoolProp documentation says that CoolProp support stdcall and cdecl call which means that you are supposed to be able to use cdll and windll. I tried and failed with windll then I found a post on stackoverflow that describe the same process i used but with cdll. I still don’t understand why windll didn’t work but at least I can use CoolProp in an IronPython environment.

import ctypes

#Load CoolProp shared library
CP = ctypes.cdll.LoadLibrary("/PathTo/CoolProp.dll")
#making PropsSI function call shorter
PropsSI = CP.PropsSI
#Convert python data type entered in PropsSI function call to expected argtypes for PropsSI function in the .dll
PropsSI.argtypes = (ctypes.c_char_p, ctypes.c_char_p, ctypes.c_double, ctypes.c_char_p, ctypes.c_double, ctypes.c_char_p)
#Convert returned value from .dll to desired data type which is a float in python
PropsSI.restype = ctypes.c_double

#You can then call PropsSI function as in previous article
print PropsSI('C','T',275.15,'P',101325,'INCOMP::Water')

For more info about data types check here

Next article will talk about how to add fluids in Revit using CoolProp power !

Working with fluid properties 1/2 : Using CoolProp in a standard python environment

When you work in HVAC, you always need fluid properties in your calculations. The most common property you need for pipe work is heat capacity Cp,  mass density ρ and dynamic viscosity µ. We will use CoolProp which is an awesome open source cross-platform library developed in C++ with wrappers available for most common languages and environment (including python, Libre Office, Excel, shared library dll). You can thank developers and their supporters for this great library.

You may install CoolProp for python by typing “pip install CoolProp” in your command line (cmd.exe on windows) or with Anaconda.

You can then use it in a python script. Here is an example for Pure Fluid :

#Add CoolProp to your pythonpath
import sys
sys.path.append(r"PathToTheCoolPropFolder")
#Example, for me it is : sys.path.append(r"C:\Anaconda\Lib\site-packages\CoolProp-5.1.1-py2.7-win-amd64.egg")

#Import PropsSI function which will be used from CoolProp
from CoolProp.CoolProp import PropsSI

#Ask CoolProp water's heat capacity at 275.15 K (2°C) and common Earth pressure 101325 Pa
PropsSI('C','T',275.15,'P',101325,'INCOMP::Water') #return 4182.587592215201

#Ask CoolProp water's mass density and viscosity with same conditions
PropsSI('D','T',275.15,'P',101325,'INCOMP::Water') #return 1003.076063639064
PropsSI('C','T',275.15,'P',101325,'INCOMP::Water') #return 0.0016507819947969692

INCOMP stands for incompressible fluids, you can also work with Humid Air Properties for example with another function from CoolProp. Click to see list of available fluids.

We often need mixture properties (ethylen or propylen glycol, ethanol etc…). Here is an example :

#Ask CoolProp the heat capacity of mixture Water/ASHRAE, Ethylene Glycol 25% (volume based)  at 275.15 K (2°C) and common Earth pressure 101325 Pa
PropsSI('C','T',275.15,'P',101325,'INCOMP::AEG[0.25]') #return 3684.7400408010444
#Ask CoolProp ASHRAE, Ethylene Glycol's mass density, heat capacity and freezing temperature with same conditions
PropsSI('D','T',275.15,'P',101325,'INCOMP::AEG[0.25]') #return 1043.3307802810543
PropsSI('V','T',275.15,'P',101325,'INCOMP::AEG[0.25]') #return 0.0032736727033664615
PropsSI('T_FREEZE','T',275.15,'P',101325,'INCOMP::AEG[0.25]') #return 261.0307763027968 (~ -12°C)

Click here to see inputs available for PropsSI function and units used (SI as said in the function name).

Enjoy !