FamilyDocument NewSweep - Transaction error

Hi there,

I am trying to create a script that will take an input Polyline which represents a linked floor’s boundaries as an input.

Using these curves the script then opens and creates a new generic family document and creates a sweep (using a temporary profile atm) following this complete boundary edge.

This portion of the script seems to be working well, as if I output the sweep variable it shows me a sweep element with an element ID.

import clr 
import sys
import os
sys.path.append('C:\Program Files (x86)\IronPython 2.7\Lib')
from System import Array
from System.Collections.Generic import *

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")
clr.AddReference("RevitAPIUI")

import Autodesk
from Autodesk.Revit.DB import *
from Autodesk.Revit.UI import *

Document = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication
app = uiapp.Application
uidoc = uiapp.ActiveUIDocument


# Create a new family document using a specific family template
template_path = "C:\\ProgramData\\Autodesk\\RVT 2021\\Family Templates\\English\\Metric Generic Model.rft"
doc = app.NewFamilyDocument(template_path)

# Get the input curves from Dynamo
DSpolycurve = IN[0]
# Turn the Dynamo curves in Revit Lines
RevitLines = [x.ToRevitType() for x in DSpolycurve.Curves()]

# Create a curvearray represnting the path using the revit Lines 
patharr = CurveArray()
for RVT_lin in RevitLines:
	patharr.Append(RVT_lin)

TransactionManager.Instance.EnsureInTransaction(doc)

# Get three points from input floor curves
DSpts = [Curve.StartPoint for Curve in DSpolycurve.Curves()]
threepts = [x.ToRevitType() for x in DSpts[0:3]]
# Create sketchplane using 3 points
pl = Plane.CreateByThreePoints(threepts[0],threepts[1],threepts[2])
sketchPlane = Autodesk.Revit.DB.SketchPlane.Create(doc,pl)

# Create curveloops for profile creation
Profile_arrarr = CurveArrArray()
Profile_arr = CurveArray()
# Create basic points for test profile
pnt1 = XYZ(0,0,0)
pnt2 = XYZ(0.21,0,0)
pnt3 = XYZ(0.21,0.21,0)
pnt4 = XYZ(0,0.21,0)
# Append to curvearray
Profile_arr.Append(Line.CreateBound(pnt1, pnt2))
Profile_arr.Append(Line.CreateBound(pnt2, pnt3))
Profile_arr.Append(Line.CreateBound(pnt3, pnt4))
Profile_arr.Append(Line.CreateBound(pnt4, pnt1))
Profile_arrarr.Append(Profile_arr)

# Create a profile using previously defined curveloop
profile = doc.Application.Create.NewCurveLoopsProfile(Profile_arrarr)

trans = SubTransaction(doc)
trans.Start()
# Create sweep
sweep = doc.FamilyCreate.NewSweep(True, patharr,sketchPlane, profile, 0, ProfilePlaneLocation.Start);
trans.Commit()

TransactionManager.Instance.TransactionTaskDone()

OUT = sweep

image

My issue arises when I try to add these few lines of code to the script to save the family document to my desktop:

# Define Save as options
SaveAsOpt = SaveAsOptions()
SaveAsOpt.OverwriteExistingFile = True

# Define new filepath
desktop = os.path.join(os.path.join(os.environ['USERPROFILE']), 'Desktop')
file_path = os.path.join(desktop, "Fire Barrier.rfa")

# Save the family document to the user's desktop
doc.SaveAs(file_path, SaveAsOpt)

OUT = doc

Dynamo Error

I’ve tried all sorts to try and get it to close the transaction but can’t seem to get it to work.

Is it something to do with me background opening the family document to create the sweep?

A couple of other similar forum posts (albiet not very well detailed and neither solved) can be found here:

Any suggestions appreciated!

Bumping for today - Thanks

Are these lines inside of an open Transaction?

Not after this line, is it?

no idea whats wrong but have you tryed using a seperate python node to save the file my think is that it somehow doesnt close sweep settings and you can not save. would be a bug in that case, just spewing out what i can think of and i am probably completly off though

Correct, it is all inside the same transaction.

Here is the full code:

import clr 
import sys
import os
sys.path.append('C:\Program Files (x86)\IronPython 2.7\Lib')
from System import Array
from System.Collections.Generic import *

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")
clr.AddReference("RevitAPIUI")

import Autodesk
from Autodesk.Revit.DB import *
from Autodesk.Revit.UI import *

Document = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication
app = uiapp.Application
uidoc = uiapp.ActiveUIDocument


# Create a new family document using a specific family template
template_path = "C:\\ProgramData\\Autodesk\\RVT 2021\\Family Templates\\English\\Metric Generic Model.rft"
doc = app.NewFamilyDocument(template_path)

# Get the input curves from Dynamo
DSpolycurve = IN[0]
# Turn the Dynamo curves in Revit Lines
RevitLines = [x.ToRevitType() for x in DSpolycurve.Curves()]

# Create a curvearray represnting the path using the revit Lines 
patharr = CurveArray()
for RVT_lin in RevitLines:
	patharr.Append(RVT_lin)

TransactionManager.Instance.EnsureInTransaction(doc)

# Get three points from input floor curves
DSpts = [Curve.StartPoint for Curve in DSpolycurve.Curves()]
threepts = [x.ToRevitType() for x in DSpts[0:3]]
# Create sketchplane using 3 points
pl = Plane.CreateByThreePoints(threepts[0],threepts[1],threepts[2])
sketchPlane = Autodesk.Revit.DB.SketchPlane.Create(doc,pl)

# Create curveloops for profile creation
Profile_arrarr = CurveArrArray()
Profile_arr = CurveArray()
# Create basic points for test profile
pnt1 = XYZ(0,0,0)
pnt2 = XYZ(0.21,0,0)
pnt3 = XYZ(0.21,0.21,0)
pnt4 = XYZ(0,0.21,0)
# Append to curvearray
Profile_arr.Append(Line.CreateBound(pnt1, pnt2))
Profile_arr.Append(Line.CreateBound(pnt2, pnt3))
Profile_arr.Append(Line.CreateBound(pnt3, pnt4))
Profile_arr.Append(Line.CreateBound(pnt4, pnt1))
Profile_arrarr.Append(Profile_arr)

# Create a profile using previously defined curveloop
profile = doc.Application.Create.NewCurveLoopsProfile(Profile_arrarr)

trans = SubTransaction(doc)
trans.Start()
# Create sweep
sweep = doc.FamilyCreate.NewSweep(True, patharr,sketchPlane, profile, 0, ProfilePlaneLocation.Start);
trans.Commit()

# Define Save as options
SaveAsOpt = SaveAsOptions()
SaveAsOpt.OverwriteExistingFile = True

# Define new filepath
desktop = os.path.join(os.path.join(os.environ['USERPROFILE']), 'Desktop')
file_path = os.path.join(desktop, "Fire Barrier.rfa")

# Save the family document to the user's desktop
doc.SaveAs(file_path, SaveAsOpt)

TransactionManager.Instance.TransactionTaskDone()

doc.Close()

OUT = doc

You need another SubTransaction for saving the file. By the way, You are using API Transaction and Dynamo Transaction in the same code. You can try to add subtranaction to that saving process or remove the subtransaction completely.
or you can start a API Transaction Group

I would remove those lines from my code…

Ah I did not realise the difference between subtransaction and the regular Dynamo transaction commands.

Unfortunately, even after removing the Revit transactions, I still hit errors.

Interestingly, if I freeze the saving portion of the script and try to close the FamilyDocument after creating the sweep I am given this subtransaction error:
image

This now resembles the same error that both other unresolved forum links I sent are displaying. I have checked my code thoroughly for any transactions which are not closed and I can not see any:

Is this possibly an error linked to the way in which Dynamo handles the transaction for deploying the NewSweep method within a family document?

Can you successfully create a sweep?

Current code below.

Thanks again for any help

Document = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication
app = uiapp.Application
uidoc = uiapp.ActiveUIDocument


# Create a new family document using a specific family template
template_path = "C:\\ProgramData\\Autodesk\\RVT 2021\\Family Templates\\English\\Metric Generic Model.rft"
doc = app.NewFamilyDocument(template_path)

# Get the input curves from Dynamo
DSpolycurve = IN[0]
# Turn the Dynamo curves in Revit Lines
RevitLines = [x.ToRevitType() for x in DSpolycurve.Curves()]

# Create a curvearray represnting the path using the revit Lines 
patharr = CurveArray()
for RVT_lin in RevitLines:
	patharr.Append(RVT_lin)


##_________________Transaction start___________________##
TransactionManager.Instance.EnsureInTransaction(doc)

# Get three points from input floor curves
DSpts = [Curve.StartPoint for Curve in DSpolycurve.Curves()]
threepts = [x.ToRevitType() for x in DSpts[0:3]]
# Create sketchplane using 3 points
pl = Plane.CreateByThreePoints(threepts[0],threepts[1],threepts[2])

sketchPlane = Autodesk.Revit.DB.SketchPlane.Create(doc,pl)

# Create curveloops for profile creation
Profile_arrarr = CurveArrArray()
Profile_arr = CurveArray()
# Create basic points for test profile
pnt1 = XYZ(0,0,0)
pnt2 = XYZ(0.21,0,0)
pnt3 = XYZ(0.21,0.21,0)
pnt4 = XYZ(0,0.21,0)
# Append to curvearray
Profile_arr.Append(Line.CreateBound(pnt1, pnt2))
Profile_arr.Append(Line.CreateBound(pnt2, pnt3))
Profile_arr.Append(Line.CreateBound(pnt3, pnt4))
Profile_arr.Append(Line.CreateBound(pnt4, pnt1))
Profile_arrarr.Append(Profile_arr)

# Create a profile using previously defined curveloop
profile = doc.Application.Create.NewCurveLoopsProfile(Profile_arrarr)

# Create sweep
sweep = doc.FamilyCreate.NewSweep(True, patharr,sketchPlane, profile, 0, ProfilePlaneLocation.Start);

TransactionManager.Instance.TransactionTaskDone()
##_________________Transaction End___________________##

doc.Close()

That should be inside of the transaction :slight_smile:

1 Like

Hello

try to close the Dynamo Transaction first

here an example

import clr
import sys
import System
from System import Array
from System.Collections.Generic import *

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

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 *
doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication 
app = uiapp.Application 
uidoc = uiapp.ActiveUIDocument

SaveAsOpt = SaveAsOptions()
SaveAsOpt.OverwriteExistingFile = True

family_template = IN[0]
save_path = IN[1]
error = None
famdoc = doc.Application.NewFamilyDocument(family_template)

arrarr = CurveArrArray()
arr = CurveArray()
#Create an ovoid profile
pnt1 = XYZ(0,0,0)
pnt2 = XYZ(0.21,0,0)
pnt3 = XYZ(0.21,0.21,0)
pnt4 = XYZ(0,0.21,0)
lstPtA = [pnt1, pnt2, pnt3, pnt4, pnt1]
for idx, pt in enumerate(lstPtA):
	if idx > 0:
		arr.Append(Line.CreateBound(lstPtA[idx - 1], pt))
arrarr.Append(arr)

#Create a path for the sweep
curves = CurveArray()
pnt5 = XYZ(0,0,0)
pnt6 = XYZ(0,4,0)
pnt7 = XYZ(4,4,0)
pnt8 = XYZ(4,0,0)
lstPtB = [pnt5, pnt6, pnt7, pnt8]
for idx, pt in enumerate(lstPtB):
	if idx > 0:
		path1 = Line.CreateBound(lstPtB[idx - 1], pt)
		curves.Append(path1)
#
# create PLane
pl = Plane.CreateByNormalAndOrigin(XYZ.BasisZ, XYZ.Zero)

TransactionManager.Instance.ForceCloseTransaction()
t = Transaction(famdoc, "FamilyCreation")
t.Start()
try:
	profile = famdoc.Application.Create.NewCurveLoopsProfile(arrarr)
	sketchPlane = Autodesk.Revit.DB.SketchPlane.Create(famdoc,pl)
	sweep = famdoc.FamilyCreate.NewSweep(True, curves, sketchPlane, profile, 0, ProfilePlaneLocation.Start)
	t.Commit()
except:
	import traceback
	error = traceback.format_exc()
	t.RollBack()
finally:
	t.Dispose()
#
famdoc.SaveAs(save_path, SaveAsOpt)

OUT = error
2 Likes

Hi @c.poupin ,
I also thank you for this code.
Would you say, this would be a proper code for any kind of Dynamo python transaction:

?

1 Like

This is one way to do it which doesn’t rely on the Dynamo Transaction manager.

But he is using Dynamo Transaction manager to force possible transaction(s) to close:

1 Like

the goal here is to close all active transactions before saving/closing the family document

3 Likes

Hi @c.poupin,

Thanks so much for your help with this - My first time dealing with background files and transactions of this complexity so has been a steep learning curve!

I did manage to get it to work yesterday with @Deniz_Maral suggestion of the TransactionGroup method but it was not as concise as your solution.

Out of curiosity, you say here that the TransactionManager.Instance.ForceCloseTransaction() is for closing transactions before saving. But it is being called before the profile, sketch plane and sweep are being created.

Does it not close the transaction of everything that was above the ForceClose? Or is it closing everything that comes after it within the API Transaction method?

TransactionManager.Instance.ForceCloseTransaction() stops the current Dynamo strategy Transaction (a kind of Group Transaction)

3 Likes

Hello
I tried with your code, but encountered the problem as shown in the image I uploaded. Can you help me fix this error? Thank you

Hi,
the error indicates that you do not have write access to the specified path, try moving the file to another location (my documents for example).

2 Likes

Thank you very much, I tried changing the path to Desktop, but still get the same error, can you help me show it more clearly with pictures? Thank you

Hi @MINHXU98765 ,

you need a file path at input (not a directory path)

import clr
import sys
import System
from System import Array
from System.Collections.Generic import *

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

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 *
doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication 
app = uiapp.Application 
uidoc = uiapp.ActiveUIDocument

SaveAsOpt = SaveAsOptions()
SaveAsOpt.OverwriteExistingFile = True

family_template_path = IN[0]
out_file_save_path = IN[1]
out = None
famdoc = doc.Application.NewFamilyDocument(family_template_path)

arrarr = CurveArrArray()
arr = CurveArray()
#Create an ovoid profile
pnt1 = XYZ(0,0,0)
pnt2 = XYZ(0.21,0,0)
pnt3 = XYZ(0.21,0.21,0)
pnt4 = XYZ(0,0.21,0)
lstPtA = [pnt1, pnt2, pnt3, pnt4, pnt1]
for idx, pt in enumerate(lstPtA):
	if idx > 0:
		arr.Append(Line.CreateBound(lstPtA[idx - 1], pt))
arrarr.Append(arr)

#Create a path for the sweep
curves = CurveArray()
pnt5 = XYZ(0,0,0)
pnt6 = XYZ(0,4,0)
pnt7 = XYZ(4,4,0)
pnt8 = XYZ(4,0,0)
lstPtB = [pnt5, pnt6, pnt7, pnt8]
for idx, pt in enumerate(lstPtB):
	if idx > 0:
		path1 = Line.CreateBound(lstPtB[idx - 1], pt)
		curves.Append(path1)
#
# create PLane
pl = Plane.CreateByNormalAndOrigin(XYZ.BasisZ, XYZ.Zero)

TransactionManager.Instance.ForceCloseTransaction()
t = Transaction(famdoc, "FamilyCreation")
t.Start()
try:
	profile = famdoc.Application.Create.NewCurveLoopsProfile(arrarr)
	sketchPlane = Autodesk.Revit.DB.SketchPlane.Create(famdoc,pl)
	sweep = famdoc.FamilyCreate.NewSweep(True, curves, sketchPlane, profile, 0, ProfilePlaneLocation.Start)
	t.Commit()
	out = "Success"
except:
	import traceback
	out = traceback.format_exc()
	t.RollBack()
finally:
	t.Dispose()
#
famdoc.SaveAs(out_file_save_path, SaveAsOpt)

OUT = out
2 Likes

Thank you very much :heart_eyes: :heart_eyes:

1 Like