Conversion of Architectural Walls to Structural Walls

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 !


Task 1.rvt (5.4 MB)
task 1-Scenario 2.dyn (18.8 KB)

Hi @101532664 not sure if it could help but you can get/set your compound layers, here with clockwork

1 Like

Thank you Sovitek! , I will try to use it now , I hope it will help

yeah try it…genius loci have some great nodes for compound structures as well…probably it fit you better

1 Like



After I run the dynamo file, nothing changed in the wall assembly ? it supposes to make the thikness = 0, right ?

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

1 Like

The only way to set a wall layer to 0 is to make it a membrane layer. Then it will automatically be 0 thickness. So just change the function.

1 Like

this is exactly what I did, but nothing is changing Revit !! this is screenshot , and this is the python script :

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 = 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)

task 1-Scenario 4.dyn (13.1 KB)

@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)

2 Likes

Thank you so much!!, it works perfectly now

:wink:

Hello again, I’m facing two issues:

  1. The structural layer edge of the duplicated wall misaligns with the original, causing an offset.
  2. The existing walls don’t automatically switch to the duplicated wall type. I have to select the walls and switch them manually.

I will appreciate if someone help me with this, thank you!
task 1- Final.dyn (15.4 KB)
task 1- Final.rvt (5.6 MB)


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.

1 Like

That would be a separate step in your program. Get the walls. Switch the type.
Your code flow should be:

  • Get the walls you are interested in changing.
  • Set the locations line appropriately.
  • Duplicate the type.
  • Edit the type.
  • Change the walls to the correct type.

You can find good examples of all of this with a search here.

2 Likes

Hi,

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.

code to get core layer line

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]
4 Likes

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!

Task 1.rvt (6.1 MB)
Task 1-Link Model.rvt (5.5 MB)
Task 1.dyn (16.1 KB)

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)

Hi,

You can obtain the profile curves of existing walls in this way

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

another solution would be for each wall

  • copy the wall instances
  • change the type to a concrete wall type
  • fix location (align_wall_to_core_line)
2 Likes

Thank you so much c.poupin, I appreciate your help

2 Likes