Creating a Roof from a Ceiling via Python

I’m trying to create a roof based on an existing ceiling using Dynamo and Python.

Below is the Python script. It feels like I’m on the right track, but I’m clearly missing something. When I run the script, I receive the following warning:

TypeError : No method matches given arguments for NewFootPrintRoof: (<class 'Autodesk.Revit.DB.CurveArray'>, <class 'Autodesk.Revit.DB.Level'>, <class 'Autodesk.Revit.DB.RoofType'>) ['  File "<string>", line 85, in <module>\n']

Which is weird, because the NewFootPrintRoof method requires the inputs as given.
Even AI can’t figure this one out. So I’m hoping a human might have a brighter idea.

# INPUTS
ceilings = [doc.GetElement(ElementId(5683347))] 
systeemplafond_type = get_rooftype_by_name("NLRS_45_RO_systeemplafond_GEN")
output = []
errors = []

# CODE
TransactionManager.Instance.EnsureInTransaction(doc)

for ceiling in ceilings:
    ceiling_lvl = doc.GetElement(ceiling.LevelId)
    ceiling_offset = ceiling.get_Parameter(BuiltInParameter.CEILING_HEIGHTABOVELEVEL_PARAM).AsDouble()
    ceiling_profile = doc.GetElement(ceiling.SketchId).Profile

    footprint = CurveArray()
    loop = ceiling_profile[0] # first array as boundary
    for c in loop:
        footprint.Append(c)

    roof = doc.Create.NewFootPrintRoof(footprint, ceiling_lvl, systeemplafond_type)
    output.append(roof)
    
TransactionManager.Instance.TransactionTaskDone()

OUT = output

Has anyone encountered this before, or does anyone see what I’m doing wrong?

Any help or pointers would be greatly appreciated.

What imported modules are you using because if you have attached the full code then this is probably the avenue where you are having issues.

Also if the above is your full code suprised you dont have issues with “get_rooftype_by_name”

For readability, I only included the part of the code that causes the issue. Below is the full script:

import sys
import clr

clr.AddReference("ProtoGeometry")
from Autodesk.DesignScript.Geometry import *

clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)

clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

clr.AddReference("RevitAPI")
import Autodesk
from Autodesk.Revit.DB import *

import System
from System.Collections.Generic import List

doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication
uidoc = uiapp.ActiveUIDocument
app = uiapp.Application
intVersion = int(app.VersionNumber)

# FUNCTIONS
def to_list(obj): 
    return obj if isinstance(obj, list) else [obj]

def get_rooftype_by_name(name):
    """Function to get a Roof Type by name."""
    types = FilteredElementCollector(doc).OfClass(RoofType)
    for type in types:
        if type.get_Parameter(BuiltInParameter.ALL_MODEL_TYPE_NAME).AsString() == name:
            return type
    return None

# INPUTS
ceilings = [doc.GetElement(ElementId(5683347))] 
systeemplafond_type = get_rooftype_by_name("NLRS_45_RO_systeemplafond_GEN")
output = []
errors = []

# CODE
TransactionManager.Instance.EnsureInTransaction(doc)

for ceiling in ceilings:
    ceiling_lvl = doc.GetElement(ceiling.LevelId)
    ceiling_offset = ceiling.get_Parameter(BuiltInParameter.CEILING_HEIGHTABOVELEVEL_PARAM).AsDouble()
    ceiling_profile = doc.GetElement(ceiling.SketchId).Profile

    footprint = CurveArray()
    loop = ceiling_profile[0] # first array as boundary
    for c in loop:
        footprint.Append(c)

    roof = doc.Create.NewFootPrintRoof(footprint, ceiling_lvl, systeemplafond_type)
    output.append(roof)
    
TransactionManager.Instance.TransactionTaskDone()

OUT = output

By the looks of it you’re missing the ‘out’ parameter for the resulting curves (which I recall is a requirement in some conditions). How to manage that will depend on your Python engine.

I am using the CPython3 engine. Running the python script in Dynamo 3.6 in Revit 2026

PythonNet3 is likely going to work out better here if you’re ok migrating. C# would be easiest and most maintainable.

Try the following though may be best to use PythonNet3 as Jacob indicated above

import sys
import clr

clr.AddReference("ProtoGeometry")
from Autodesk.DesignScript.Geometry import *

clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)

clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

clr.AddReference("RevitAPI")
import Autodesk
from Autodesk.Revit.DB import *

import System
from System.Collections.Generic import List

doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication
uidoc = uiapp.ActiveUIDocument
app = uiapp.Application
intVersion = int(app.VersionNumber)

# FUNCTIONS
def to_list(obj): 
    return obj if isinstance(obj, list) else [obj]

def get_rooftype_by_name(name):
    """Function to get a Roof Type by name."""
    types = FilteredElementCollector(doc).OfClass(RoofType)
    for type in types:
        if type.get_Parameter(BuiltInParameter.ALL_MODEL_TYPE_NAME).AsString() == name:
            return type
    return None

# INPUTS
ceilings = [doc.GetElement(ElementId(5683347))] 
systeemplafond_type = get_rooftype_by_name("NLRS_45_RO_systeemplafond_GEN")
output = []
errors = []

# CODE
TransactionManager.Instance.EnsureInTransaction(doc)

for ceiling in ceilings:
    ceiling_lvl = doc.GetElement(ceiling.LevelId)
    ceiling_offset = ceiling.get_Parameter(BuiltInParameter.CEILING_HEIGHTABOVELEVEL_PARAM).AsDouble()
    ceiling_profile = doc.GetElement(ceiling.SketchId).Profile

    footprint = CurveArray()
   loop = ceiling_profile[0]# first array as boundary
    for c in loop:
        footprint.Append(c)

    footPrintToModelCurveMapping = clr.StrongBox[ModelCurveArray](ModelCurveArray())

    roof = doc.Create.NewFootPrintRoof(footprint, ceiling_lvl, systeemplafond_type,footPrintToModelCurveMapping)
    output.append(roof)
  
TransactionManager.Instance.TransactionTaskDone()

OUT = output

here is the syntax for CPython3 or PythonNet3 (preferred)

import sys
import clr

clr.AddReference("ProtoGeometry")
from Autodesk.DesignScript.Geometry import *

clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)

clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

clr.AddReference("RevitAPI")
import Autodesk
from Autodesk.Revit.DB import *

import System
from System.Collections.Generic import List

doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication
uidoc = uiapp.ActiveUIDocument
app = uiapp.Application
intVersion = int(app.VersionNumber)

# FUNCTIONS
def to_list(obj): 
    return obj if isinstance(obj, list) else [obj]

def get_rooftype_by_name(name):
    """Function to get a Roof Type by name."""
    types = FilteredElementCollector(doc).OfClass(RoofType)
    for type in types:
        if type.get_Parameter(BuiltInParameter.ALL_MODEL_TYPE_NAME).AsString() == name:
            return type
    return None

# INPUTS
ceilings = [UnwrapElement(IN[0])] 
systeemplafond_type = get_rooftype_by_name("Toit - 200 mm")
output = []
errors = []

# CODE
TransactionManager.Instance.EnsureInTransaction(doc)

for ceiling in ceilings:
    ceiling_lvl = doc.GetElement(ceiling.LevelId)
    ceiling_offset = ceiling.get_Parameter(BuiltInParameter.CEILING_HEIGHTABOVELEVEL_PARAM).AsDouble()
    ceiling_profile = doc.GetElement(ceiling.SketchId).Profile

    footprint = ceiling_profile[0]
    # NOT NECESSARY
    # loop = ceiling_profile[0] # first array as boundary
    # for c in loop:
    #     footprint.Append(c)
    out_curveArr = ModelCurveArray()
    roof, out_curveArr = doc.Create.NewFootPrintRoof(footprint, ceiling_lvl, systeemplafond_type, out_curveArr)
    output.append(roof)
    
TransactionManager.Instance.TransactionTaskDone()

OUT = output

Thanks Cyril, that worked! Thanks as well to Jacob and Brendan for thinking along with me.