Announcements
Attention for Customers without Multi-Factor Authentication or Single Sign-On - OTP Verification rolls out April 2025. Read all about it here.

Super slow run time

Anonymous

Super slow run time

Anonymous
Not applicable

Hi everybody. I'm new to this forum and relatively new to Fusion 360. However, I am an old, old dog when it comes to procedural design (2D and 3D CAD using an API), also known as module generation, with over 30 years experience doing design this way. I never use the GUI of a CAD tool except to inspect the output of my generator.

 

I've also been programming in Python since 1995, so I have been looking forward with anticipation to moving to Fusion 360 from OpenSCAD, which is a rapid-prototyping module-generation system I've used for some time now.

 

But first, huge kudos to Brian E. and his team for making such a complete, thorough, well-documented and seemingly super-useful api to Fusion. I know you've been at it for years and I'm sure it was a slog at times.

 

Compared to Fusion 360, OpenSCAD is a toy. Yet for a toy, it's utterly putting Fusion to shame in terms of ease of use, language simplicity, performance, and memory usage.

 

My design on Fusion is running ~1000x slower than my OpenSCAD implementation (20 seconds on OpenSCAD and 20 minutes and counting (job not finished yet) on Fusion) and using ~100x more memory (234MB on OpenSCAD vs 20GB and counting (job not finished yet) on Fusion).

 

I am using the DirectDesignType of design, which I have turned from Fusion's preferences. I am also experimenting with this in my python code:

# go to direct modeling -- turn off parametric design
# and turn off tracking timeline
design.designType=adsk.fusion.DesignTypes.DirectDesignType

though I can't say for sure if the above is working.

 

So I'm frustrated. More than half of my interactions with Fusion 360 and the api end up with me killing Fusion and restarting. The difference between using the DirectDesignType directive and not is between having the job run, after ~30 minutes, vs. having Fusion hang forever and me having to kill the job.

 

I'm doing nothing fancy at all in my script. Just laying down around 300 to 400 circles in a computed, grid-like layout. The computations for placing the circles are trivial and involve simple, integer arithmetic (+, -, *, / operators only). My computer is a still-current beast running Windows 10 on an Intel Core i7-3930K CPU at 3.2GHz with 32GB RAM and tons of disk.

 

I figure I must be missing something here. I know the architecture of a CAD system built for API-centric design is different than one built for GUI-centric design since I've built systems like this, myself. But, I wouldn't expect this big a differential in performance, memory or ease of use after so many years of labor and optimization behind the Fusion api.

 

Anybody have any idea what I could be doing wrong?

 

 

 

0 Likes
Reply
1,850 Views
13 Replies
Replies (13)

JesusFreke
Advocate
Advocate

I'm in pretty much the same boat - an openscad refugee who prefers programmatic design. I found fusion's API a bit verbose, coming from openscad. I ended up writing a wrapper around fusion's api to make common openscad-like operations much easier (http://fscad.org). I also ran into some performance issues, although not nearly as drastic as you describe.

 

Using direct design mode does make things faster, as it sounds like you already discovered, but I found that many of fusion's core operations are a bit slow. Just creating a new component takes... ~100-200ms if I'm remembering correctly, which can add up quickly.

 

The biggest single thing I did to improve performance was to use the TemporaryBRepManager as much as possible. It creates and manipulates temporary brep objects which aren't a part of the fusion document, and have *much* less overhead.

 

Feel free to check out my wrapper api if you're interested. It's a bit rough around the edges, and is still missing some functionality (e.g. no support for text atm), but patches always welcome 🙂

 

Or if you have any questions about TemporaryBRepManager, I'm happy to share my experience with it.

 

0 Likes

JesusFreke
Advocate
Advocate

Also, if you want to post your script, I'm happy to take a look and offer advice on potentially faster ways to do what you want to do.

0 Likes

Anonymous
Not applicable

Thanks for the feedback. I'm making a simple test case that I will post when done.

0 Likes

Anonymous
Not applicable

This is disturbing, without even considering the code complexity differences.

 

// OpenSCAD code to make an array of circles 30 x 30
// Run time < 1 second, memory usage 58.6MB
for (x=[0:1:30]) {
    for (y=[0:1:30]) {
        translate([x,y,0]) circle(d=0.2);
    }
}
# python api with Fusion 360
# Run Time 171 seconds (assuming no sketches to being with), memory usage 4.6GB
import adsk.core, adsk.fusion, adsk.cam, traceback from datetime import datetime start=datetime.now() def delete_all(sketches): for i in range(sketches.count): try: sketches.item(i).deleteMe() except: pass # setup links to Fusion app=adsk.core.Application.get() # current design design=app.activeProduct # go to direct modeling -- turn off parametric design = 0 # and turn off tracking timeline design.designType=adsk.fusion.DesignTypes.DirectDesignType # root component of active design rootComp=design.rootComponent # sketches in root component sketches=rootComp.sketches delete_all(sketches) xyPlane=rootComp.xYConstructionPlane sketch=sketches.add(xyPlane) circle=sketch.sketchCurves.sketchCircles # get to sketching circles c=circle.addByCenterRadius # hole (circle) pointer pt3D=adsk.core.Point3D # get to core 3D point routines c_array=[]
for x in range(30): for y in range(30): c_array.append(c(pt3D.create(x,y,0),0.2)) end=datetime.now() print(end-start)

Unless this can run faster, the situation looks pretty hopeless.

0 Likes

JesusFreke
Advocate
Advocate

Yeah, I ended up abandoning sketches entirely. For 2d designs, I'll use a brep object that consists of 1 or more faces in the same plane.


Do you actually need the 2d objects, e.g. to export as an svg (err, I guess dxf rather)? If you're just going to extrude them to create a body or holes in another body, you're probably better off creating the cylinders directly. But in either case, I would recommend using TemporaryBRepManager to create the cylinders. And then, if you only need the 2d circles, you can use the bottom faces of the temporary cylinders.


For comparison, here's the equivalent code with fscad:

 

circles = []
for x in range(30):
for y in range(30):
circles.append(Circle(.2).translate(x, y, 0))
Union(*circles).create_occurrence()

which runs in around 1 second.

 

circles_fscad.jpg

 

And here's an example using TemporaryBRepManager directly, which takes about 2 seconds. I think it could be reduced to the same ~1 second by unioning all of the temporary bodies into a single body, and only adding that single body to the root component.

 

app = adsk.core.Application.get()
app.activeProduct.designType = adsk.fusion.DesignTypes.DirectDesignType
root = app.activeProduct.rootComponent
brep = adsk.fusion.TemporaryBRepManager.get()

for x in range(30):
for y in range(30):
cylinder = brep.createCylinderOrCone(
adsk.core.Point3D.create(x, y, 0),
.2,
adsk.core.Point3D.create(x, y, -1),
.2)
# index 2 is always the top face
root.bRepBodies.add(brep.copy(cylinder.faces[2]))

 

If you want to export the result as dxf, you could create a single sketch and include the 2d bodies in the sketch, with Sketch.include(). If needed, this may be faster with a single Union'd body as well.

0 Likes

JesusFreke
Advocate
Advocate

And here it is with Unioning and adding the sketch at the end:

 

app = adsk.core.Application.get()
app.activeProduct.designType = adsk.fusion.DesignTypes.DirectDesignType
root = app.activeProduct.rootComponent
brep = adsk.fusion.TemporaryBRepManager.get()

composite_body = None

for x in range(30):
for y in range(30):
cylinder = brep.createCylinderOrCone(
adsk.core.Point3D.create(x, y, 0),
.2,
adsk.core.Point3D.create(x, y, -1),
.2)
if composite_body is None:
composite_body = brep.copy(cylinder.faces[2])
else:
brep.booleanOperation(composite_body, brep.copy(cylinder.faces[2]),
adsk.fusion.BooleanTypes.UnionBooleanType)

composite_body = root.bRepBodies.add(composite_body)

sketch = root.sketches.add(root.xYConstructionPlane)
sketch.include(composite_body)

 

This one ran in about 1.4 seconds

0 Likes

Anonymous
Not applicable

Yes, everything is 2D and is intended to be output to DXF. However, I also have some 3D versions of the same thing with complex calculations and transformations. Am I going to run into the same performance issue, then?

0 Likes

JesusFreke
Advocate
Advocate

Is it possible to implement it in such a way that you will run into performance issues? Of course. Is it possible to implement in such a way to avoid them? Likely.

0 Likes

BrianEkins
Mentor
Mentor

There's quite a bit of overhead with Fusion sketches that aren't obvious. The solver is one of those. Each time you add geometry the solver is evaluating the sketch. You can avoid this in the API by using the Sketch.isComputeDeferred property to turn off the compute, add all your geometry and then turn it back on.

 

Another overhead is that Fusion is calculating the profiles that can be created with the current sketch geometry. The Sketch.areProfilesShown property will disable the display and I believe also the computation of profiles. This setting is also available in the UI through the sketch context menu.

---------------------------------------------------------------
Brian Ekins
Inventor and Fusion 360 API Expert
Website/Blog: https://EkinsSolutions.com
2 Likes

Anonymous
Not applicable

Sounds reasonable. I figured there was stuff going on in the background that was eating up time. In a procedural approach, none of that is important since the user already has full control. Solvers for filleting, CAM, simulation, integration, etc. are where Fusion will differentiate.

0 Likes

Anonymous
Not applicable

Brian, What do you think of JesusFreke's approach?

0 Likes

JesusFreke
Advocate
Advocate

The temporary 2d brep bodies have 2 main advantages, in my mind. Performance is one, although I wasn't aware of and didn't try the tweaks that Brian mentioned. The second is that they're easier to manipulate. E.g. perform boolean operations on, etc. Especially since I had already chosen to use temporary brep objects in the 3d case, so using the same for the 2d case helped to unify the object model and reduce the special case logic to handle the two. Iirc, I think I also ran into difficulties trying to perform boolean operations on sketches.

0 Likes

BrianEkins
Mentor
Mentor

It's a viable solution depending on the geometry you need to create. The operations currently available with temporary B-Rep is limited but it does support Boolean operations.

 

Another thing that takes time when creating a sketch (or any ooeration) is that additional information is tracked to support undo. There's no way to avoid that.

 

Using temporary B-Rep is entirely outside of all the issues I've listed and is essentially a thin wrapper directly to the modeling kernel (Autodesk Shape Manager). In your case it's probably a very good solution since you're not trying to build an intelligent editable design.

---------------------------------------------------------------
Brian Ekins
Inventor and Fusion 360 API Expert
Website/Blog: https://EkinsSolutions.com
0 Likes