Hi everyone, I am trying to modify the layer thickness of walls in Revit using Dynamo. Specifically, I want to set the thickness of all non-structural layers to 0 and retain only the structural layer as it is. However, I’ve encountered some challenges ,This is what I did already , but It is not working , I need help, thank you so much !
dont think all can be 0, guess with that it has to be membrane exc…but you could delete the layer…but not really what the goal is…maybe play with parting…not sure
from Autodesk.Revit.DB import Transaction, MaterialFunctionAssignment, WallType
from RevitServices.Persistence import DocumentManager
Get the active Revit document
doc = DocumentManager.Instance.CurrentDBDocument
Inputs from Dynamo
wall_types = IN[0] # List of wall types from Dynamo
Start a transaction to modify Revit elements
transaction = Transaction(doc, “Update Wall Type Layers”)
transaction.Start()
try:
for wall_type in wall_types:
# Ensure the element is a WallType
if isinstance(wall_type, WallType):
# Duplicate the wall type to create a new one
new_wall_type = wall_type.Duplicate(wall_type.Name + “_Modified”)
# Get the compound structure of the duplicated wall type
compound_structure = new_wall_type.GetCompoundStructure()
# Check if the compound structure exists
if compound_structure is not None:
# Iterate through each layer in the compound structure
for i in range(compound_structure.LayerCount):
layer = compound_structure.GetLayer(i)
# If the layer is not structural
if layer.Function != MaterialFunctionAssignment.Structure:
# Change function to Membrane
compound_structure.SetLayerFunction(i, MaterialFunctionAssignment.Membrane)
# Set thickness to 0
compound_structure.SetLayerWidth(i, 0.0)
# Apply the modified compound structure back to the new wall type
new_wall_type.SetCompoundStructure(compound_structure)
# Commit the transaction
transaction.Commit()
OUT = "Wall type layers updated successfully. Check the duplicated types."
except Exception as e:
# Roll back the transaction if there is an error
transaction.RollBack()
OUT = "Error: " + str(e)
@101532664 so I tweaked your script just a bit, it worked on my machine. Essentially, you want to unwrap the element types first (line 14). Then a bit different way of enumerating the layers (line 33, 34).
# Import necessary libraries
import clr
clr.AddReference('RevitAPI')
clr.AddReference('RevitAPIUI')
clr.AddReference('RevitServices')
from Autodesk.Revit.DB import Transaction, MaterialFunctionAssignment, WallType
from RevitServices.Persistence import DocumentManager
# Get the active Revit document
doc = DocumentManager.Instance.CurrentDBDocument
# Inputs from Dynamo
wall_types = UnwrapElement(IN[0]) # List of wall types from Dynamo
# Start a transaction to modify Revit elements
transaction = Transaction(doc, "Update Wall Type Layers")
transaction.Start()
try:
for wall_type in wall_types:
# Ensure the element is a WallType
if isinstance(wall_type, WallType):
# Duplicate the wall type to create a new one
new_wall_type = wall_type.Duplicate(wall_type.get_Name() + "_Modified")
# Get the compound structure of the duplicated wall type
compound_structure = new_wall_type.GetCompoundStructure()
# Check if the compound structure exists
if compound_structure is not None:
# Iterate through each layer in the compound structure
layers = compound_structure.GetLayers()
for i, layer in enumerate(layers):
# If the layer is not structural
if layer.Function != MaterialFunctionAssignment.Structure:
# Change function to Membrane
compound_structure.SetLayerFunction(i, MaterialFunctionAssignment.Membrane)
# Set thickness to 0
compound_structure.SetLayerWidth(i, 0.0)
# Apply the modified compound structure back to the new wall type
new_wall_type.SetCompoundStructure(compound_structure)
# Commit the transaction
transaction.Commit()
OUT = debug #"Wall type layers updated successfully. Check the duplicated types."
except Exception as e:
# Roll back the transaction if there is an error
transaction.RollBack()
OUT = "Error: " + str(e)
You’ll need to check the location line of the wall. From your sketch, it appears that the location line is set it to interior face. You would need to switch it to exterior face before switching the type. Note that this can be a little tricky, as users may have set the location line to all sorts of different options. And may have flipped some of them around facing the wrong way. But as long as the wall is in the right spot and facing the correct way, you should just be able to set it to exterior finish face.
Before changing the type, you can obtain/save the core lines of the core layer (structure) for each wall.
After changing the type, you can try to move each wall to the core lines.
import clr
import sys
import System
clr.AddReference("System.Numerics")
#
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
import Autodesk.DesignScript.Geometry as DS
#import Revit API
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
import Autodesk.Revit.DB as DB
clr.AddReference('RevitNodes')
import Revit
clr.ImportExtensions(Revit.GeometryConversion)
#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
def get_core_line(wall):
"""
return the center line of the core Layer (structure)
"""
center_line = wall.Location.Curve
structure = wall.WallType.GetCompoundStructure()
layers = structure.GetLayers()
width = wall.WallType.Width
vector_ref = XYZ.BasisZ.Negate()
if wall.Flipped:
vector_ref = vector_ref.Negate()
compute_line = center_line.CreateOffset(width * 0.5, vector_ref)
for idx, layer in enumerate(layers):
layer_width = structure.GetLayerWidth(idx)
print(layer.Function , layer_width)
if structure.IsCoreLayer(idx):
compute_line = compute_line.CreateOffset(layer_width * 0.5, vector_ref.Negate())
break
else:
compute_line = compute_line.CreateOffset(layer_width, vector_ref.Negate())
return compute_line.ToProtoType()
toList = lambda x : x if hasattr(x, "__iter__") and not isinstance(x, (str, System.String)) else [x]
#Preparing input from dynamo to revit
lst_wall = toList(UnwrapElement(IN[0]))
OUT = [[get_core_line(wall), wall] for wall in lst_wall]
The Dynamo file is now working perfectly. It successfully converts an architectural wall from the linked model into a structural wall in the host model. Now, I would like to further develop the script to also handle walls with edited profiles (edited shapes). If anyone has suggestions on what to add to the script to support this, I would greatly appreciate your help. Thank you!
import clr
clr.AddReference('RevitAPI')
clr.AddReference('RevitAPIUI')
clr.AddReference('RevitServices')
clr.AddReference("System.Numerics")
clr.AddReference('ProtoGeometry')
clr.AddReference('RevitNodes')
# Import necessary Revit and Dynamo namespaces
import Autodesk
from Autodesk.Revit.DB import (
Transaction,
MaterialFunctionAssignment,
WallType,
Wall,
XYZ,
BuiltInParameter,
ElementTransformUtils,
ElementId,
BuiltInCategory,
Structure,
FilteredElementCollector
)
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
# Import Dynamo geometry conversion
import Revit
clr.ImportExtensions(Revit.GeometryConversion)
from Autodesk.DesignScript.Geometry import *
# For copying elements
from System.Collections.Generic import List
# ============ Setup Document ============
doc = DocumentManager.Instance.CurrentDBDocument
# ============ Input Setup ============
# IN[0]: Selected walls from the "MW SelectLinkedElements" node
walls_link = UnwrapElement(IN[0])
# Ensure selected elements are walls
if not isinstance(walls_link, list):
walls_link = [walls_link] # Convert to list if single item selected
# Filter only valid Wall elements
walls_link = [wall for wall in walls_link if isinstance(wall, Wall)]
if not walls_link:
OUT = "Error: No valid walls selected from the linked model."
raise Exception(OUT)
# Dictionary to track duplicated wall types (architectural -> structural)
duplicated_wall_types = {}
# List to record new wall IDs created in host model
new_wall_ids = []
# =============================
# Helper Functions Definition
# =============================
def align_wall_to_core_line(wall):
"""Adjusts the wall's location to align with the centerline of its core structure."""
current_curve = wall.Location.Curve
current_mid = current_curve.Evaluate(0.5, True)
structure = wall.WallType.GetCompoundStructure()
if not structure:
return
layers = structure.GetLayers()
width = wall.WallType.Width
offset_dir = XYZ.BasisZ.Negate()
if wall.Flipped:
offset_dir = offset_dir.Negate()
core_line = current_curve.CreateOffset(width * 0.5, offset_dir)
for idx in range(len(layers)):
layer_width = structure.GetLayerWidth(idx)
if structure.IsCoreLayer(idx):
core_line = core_line.CreateOffset(layer_width * 0.5, offset_dir.Negate())
break
else:
core_line = core_line.CreateOffset(layer_width, offset_dir.Negate())
core_mid = core_line.Evaluate(0.5, True)
translation = XYZ(core_mid.X - current_mid.X, core_mid.Y - current_mid.Y, core_mid.Z - current_mid.Z)
wall.Location.Move(translation)
def modify_compound_structure(new_wall_type):
"""Converts non-structural layers to membrane with zero width."""
compound_structure = new_wall_type.GetCompoundStructure()
if compound_structure is not None:
layers = compound_structure.GetLayers()
for i, layer in enumerate(layers):
if layer.Function != MaterialFunctionAssignment.Structure:
compound_structure.SetLayerFunction(i, MaterialFunctionAssignment.Membrane)
compound_structure.SetLayerWidth(i, 0.0)
new_wall_type.SetCompoundStructure(compound_structure)
# ============================
# Main Transaction
# ============================
transaction = Transaction(doc, "Convert Selected Walls to Structural")
transaction.Start()
try:
# ---- Step 1: Redraw walls from linked model into host document ----
for wall_link in walls_link:
if wall_link.Location is None or wall_link.Location.Curve is None:
continue
location_curve = wall_link.Location.Curve
# Retrieve wall type and check if it exists in host
wall_type_id = wall_link.WallType.Id
wall_type = doc.GetElement(wall_type_id)
# Prevent duplicate warnings by checking if the type already exists
if wall_type is None:
wall_type_name = wall_link.WallType.get_Parameter(BuiltInParameter.ALL_MODEL_TYPE_NAME).AsString()
existing_types = [wt for wt in FilteredElementCollector(doc).OfClass(WallType)
if wt.get_Parameter(BuiltInParameter.ALL_MODEL_TYPE_NAME).AsString() == wall_type_name]
if existing_types:
wall_type = existing_types[0] # Use existing type instead of copying
else:
# 🔹 FIX: Ensure only valid types are copied
if wall_type_id is not None:
copied_elements = ElementTransformUtils.CopyElements(
wall_link.Document, List[ElementId]([wall_type_id]), doc, None, None
)
if copied_elements:
new_wall_type_id = copied_elements[0]
wall_type = doc.GetElement(new_wall_type_id)
if wall_type is None:
continue
# Retrieve parameters from the linked wall
base_level_id = wall_link.LevelId
base_offset = wall_link.get_Parameter(BuiltInParameter.WALL_BASE_OFFSET).AsDouble()
height_param = wall_link.get_Parameter(BuiltInParameter.WALL_USER_HEIGHT_PARAM)
wall_height = height_param.AsDouble() if height_param else 10.0 # Default height
is_structural = (wall_link.StructuralUsage != Structure.StructuralWallUsage.NonBearing)
# 🔹 FIX: Check if wall type exists before creating wall
if wall_type:
new_wall = Wall.Create(doc, location_curve, wall_type.Id, base_level_id, wall_height, base_offset, False, is_structural)
if new_wall:
new_wall_ids.append(new_wall.Id.IntegerValue)
# ---- Step 2: Convert architectural wall types to structural ----
host_walls = FilteredElementCollector(doc).OfClass(Wall).WhereElementIsNotElementType()
for wall in host_walls:
if wall.Id.IntegerValue in new_wall_ids:
original_wall_type = wall.WallType
if original_wall_type.Id in duplicated_wall_types:
new_wall_type = duplicated_wall_types[original_wall_type.Id]
else:
wall_type_name = original_wall_type.get_Name()
new_name = wall_type_name + "_STR"
count = 1
while any(wt for wt in FilteredElementCollector(doc).OfClass(WallType) if wt.get_Name() == new_name):
new_name = wall_type_name + f"_STR_{count}"
count += 1
new_wall_type = original_wall_type.Duplicate(new_name)
duplicated_wall_types[original_wall_type.Id] = new_wall_type
modify_compound_structure(new_wall_type)
align_wall_to_core_line(wall)
wall.WallType = new_wall_type
transaction.Commit()
OUT = "Selected walls duplicated and converted to structural successfully."
except Exception as e:
transaction.RollBack()
OUT = "Error: " + str(e)
import clr
import sys
import System
#
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
import Autodesk.DesignScript.Geometry as DS
#import Revit API
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
import Autodesk.Revit.DB as DB
clr.AddReference('RevitNodes')
import Revit
clr.ImportExtensions(Revit.GeometryConversion)
#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
wall = UnwrapElement(IN[0])
if wall.CanHaveProfileSketch():
profilCurveArray = doc.GetElement(wall.SketchId).Profile
OUT = [[c.ToProtoType() for c in carray] for carray in profilCurveArray]
then use the Wall.Create() method by profile curves