Set material to a new wall type

Hi All, @c.poupin

By using Revit Python Shell (a similar approach to Dynamo), I’ve written the code below to iterate over all materials within the document. I grabbed the material named Béton, coulé sur place with the ID 183853, which I’m trying to use as a layer material in my new wall type. However, I’m encountering the following error related to the MaterialId."

Exception : Microsoft.Scripting.ArgumentTypeException: expected Reference, got Int32

import math
from Autodesk.Revit.DB import *
from System.Collections.Generic import IList, List
uidoc = __revit__.ActiveUIDocument
doc = uidoc.Document
t = Transaction(doc, 'create New wall type')

# getting the first wall type within the document
first_wall_type = FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Walls).WhereElementIsElementType().FirstElement()

# looking for the material named "Béton, coulé sur place " in the document
mat_Ids = FilteredElementCollector(doc).OfClass(Material).ToElementIds()

for m in mat_Ids:
    mat = doc.GetElement(m)
    if mat.Name == "Béton, coulé sur place":
        mid = m

c = 1/0.3048

# Starting transaction

t.Start()

voile_BA_15 = first_wall_type.Duplicate('voile-BA_15')

cs = voile_BA_15.GetCompoundStructure()
Thick_wall = 0.20*c

mat = doc.GetElement(mid)

cl = CompoundStructureLayer()
cl.Width = Thick_wall
cl.MaterialId = mat.Id
cs.SetLayeres.LIST[CompoundStructureLayer](cl)
voile_BA_15.SetCompoundStructure(cs)

t.Commit()

Any help would be appreciated

Thanks.

here an example


import clr
import sys
import System

#import Revit API
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
import Autodesk.Revit.DB as DB
#import specify namespace
from Autodesk.Revit.DB.Structure import *


#import net library
from System import Array
from System.Collections.Generic import List, IList, Dictionary

clr.AddReference('RevitNodes')
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)
clr.ImportExtensions(Revit.GeometryReferences)

#import transactionManager and DocumentManager (RevitServices is specific to Dynamo)
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

doc = DocumentManager.Instance.CurrentDBDocument


clr.AddReference("System.Core")
clr.ImportExtensions(System.Linq)
 
 
t = Transaction(doc, 'create New wall type')

# getting the first wall type within the document
first_wall_type = FilteredElementCollector(doc)\
							.OfCategory(BuiltInCategory.OST_Walls)\
							.WhereElementIsElementType()\
							.First(lambda x : x.GetCompoundStructure() is not None and x.GetCompoundStructure().GetLayers().Count == 1)

# looking for the material named "Béton, coulé sur place " in the document
mat = FilteredElementCollector(doc).OfClass(Material).First(lambda x : x.Name == "Béton, coulé sur place")


c = 1/0.3048

# Starting transaction
if True:
	t.Start()
	
	voile_BA_15 = first_wall_type.Duplicate('voile-BA_15')
	
	cs = voile_BA_15.GetCompoundStructure()
	Thick_wall = 0.20*c

	for structLayer in cs.GetLayers():
		cs.SetMaterialId(structLayer.LayerId, mat.Id)
		structLayer.Width = Thick_wall
	voile_BA_15.SetCompoundStructure(cs)
	t.Commit()

OUT = voile_BA_15
1 Like

Hi @c.poupin

I tested your script, but I got the following error, related to the line below:

image

lvl

However, I tested the same code in the Revit Python Shell, where I was able to access the level properties, but I received the following error in the RPS console related to this part of the code:

Exception : System.MissingMemberException: ‘NoneType’ object has no attribute ‘GetLayers’

for structLayer in cs.GetLayers():
	cs.SetMaterialId(structLayer.LayerId, mat.Id)
	structLayer.Width = Thick_wall

Thanks.

Probably, the type you are duplicating has no CompoundStructure Layers, please look at all of my code

1 Like

@c.poupin

Effectively, after debugging the code I discovered that the first_wall_type is a curtain wall, which does not seem to have a CompoundStructureLayer . In this case, I need to apply a filter that selects only the Basic Wall kind, but I’m struggling with how to do that.

I tried this syntax for the filter, but it doesn’t work!

filter = ElementCategoryFilter(BuiltInCategory.OST_Walls)
First_wall_types = FilteredElementCollector(doc).WherePasses(filter).WhereElementIsElementType().First(lambda x : x.Kind == WallKind.Basic)

I’m getting this error:

Exception : System.MissingMemberException: ‘FilteredElementCollector’ object has no attribute ‘First’

Thanks.

for this example I use LINQ with Ironpython3, but you can replace by another type of filter (Predicate.Find, list comprenhesion, next(iterable), etc…)

https://daren-thomas.gitbooks.io/scripting-autodesk-revit-with-revitpythonshell/content/using_linq_in_ironpython/

2 Likes

Hi @c.poupin

It’s hard for me to use this filtering method at the moment. However, I solved my issue another way, and finally, I got my code working and tested it by creating walls as shown in the image below:

Here the Final code (using RPS):

import math
from Autodesk.Revit.DB import *
from System.Collections.Generic import IList, List
uidoc = __revit__.ActiveUIDocument

doc = uidoc.Document


t = Transaction(doc, 'create Manhole')


wall_types = FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Walls).WhereElementIsElementType().ToElements()

mat_Ids = FilteredElementCollector(doc).OfClass(Material).ToElementIds()

levels = FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Levels).ToElements()

types = []
for w in wall_types:
	if str(getattr(w, 'Kind')) == 'Basic':
		types.append(w)

for m in mat_Ids:
    mat = doc.GetElement(m)
    if mat.Name == "Béton, coulé sur place": 
        mid = m
        
for l in levels:
    lvl_Name = l.Name
    if lvl_Name == "Niveau 0":
        lvl_Id = l.Id
        
# Create Points and Lines:

c = 1/0.3048
Thick_wall = 0.20
Pt0 = XYZ(-(0.60 + Thick_wall/2)*c,-(0.60 + Thick_wall/2)*c,0)
Pt1 = XYZ((0.60 + Thick_wall/2)*c,-(0.60 + Thick_wall/2)*c,0)
Pt2 = XYZ((0.60 + Thick_wall/2)*c, (0.60 + Thick_wall/2)*c,0)
Pt3 = XYZ(-(0.60 + Thick_wall/2)*c,(0.60 + Thick_wall/2)*c,0)

Lines = []
Line1 = Line.CreateBound(Pt0, Pt1)
Lines.append(Line1)
Line2 = Line.CreateBound(Pt1, Pt2)
Lines.append(Line2)
Line3 = Line.CreateBound(Pt2, Pt3)
Lines.append(Line3)
Line4 = Line.CreateBound(Pt3, Pt0)
Lines.append(Line4)

t.Start()
# Create new wall type and its material:
voile_BA_15 = types[0].Duplicate('voile-BA_15')
	
cs = voile_BA_15.GetCompoundStructure()


for structLayer in cs.GetLayers():
	cs.SetLayerFunction(structLayer.LayerId, MaterialFunctionAssignment.Structure)
	cs.SetMaterialId(structLayer.LayerId, mid)
	structLayer.Width = Thick_wall*c
voile_BA_15.SetCompoundStructure(cs)

# Create walls:
for l in Lines:
    Wall = Wall.Create(doc, l, voile_BA_15.Id, lvl_Id, c*2.00,0.00, False, True)

t.Commit()

Thanks a lot Cyril.