New ghPython with Node-in-Code and Multi-threading

Thanks to Steve and Giulio, a new version (0.6.0.3) of the ghPython scripting component for Grasshopper is available on food4Rhino


Major new features:.

  • Node-in-Code™: almost every Grasshopper component is now callable in ghPython

  • Multi-threading: now easy for ghPython scripts to execute on multiple threads

Download here…


Posted Dec 10, 2013 by Bob McNeel on Rhino News, etc.

2 Likes

This is a pretty exciting release to me. I’m in the process of putting together a longer explanation of what is new, but in short the latest ghPython lets you call all of the components in Grasshopper as if they were functions (yes autocomplete works for this) AND do this on multiple threads in very few lines of script. For example, a script calling Voronoi and Area components would look like

import ghpythonlib.components as ghcomp

#points is an input to this script
curves = ghcomp.Voronoi(points)
centroids = ghcomp.Area(curves).centroid
3 Likes

Does this “multi-threading” feature mean that a call inside of ghPython component could execute data quicker than a corresponding Grasshopper component itself?

More details: http://stevebaer.wordpress.com/2013/12/11/ghpython-node-in-code/

yep :smiley:

My blog post has a sample where I get a 3X speed improvement on my 4 CPU computer using the multi-threading feature.

This is very cool, thanks Steve and Giulio!!!

So, when can we call Grasshopper component functions (like Voronoi) in a normal Python script (not running inside Grasshopper) ? :smiling_imp:

–Mitch

Hi @stevebaer and @piac,
I’ve tried the component and it works like a charm. I’ve tried it with both grasshopper components and 3rd parties. I stumble upon 2 questions that I didn’t manage to figure out.

1.- I could not find LadyBug (I’m guessing it has something to do with the fact that its a python component)
2.- I tried using CustomPreview (ghcomp.CustomPreview(geometry=Geometry,shader=colors) but I didn’t get it to work.

-Miguel

PS. I still need to try the multi-threading but it looks promising.

Hello, this is some NICE improvement!!
So far I scripted my own MT within C# components, which was working but sometimes cumbersome …
I gave it a try, especially benchmarking the parallel feature. Calling the functions works well, but the performance is somehow not as expected … I took Steve Baer’s example and tried a Mesh|Plane, a CurveCP, and a Mesh|Ray version of it. But no matter which input variable I supply as the list variable to parallelize [and scale up, therefore], the perfomance does not increase compared to the original one. Though, the outputs are correct.
Am I missing some detail, or is it an unavoidable overhead [David R mentioned having to create a new GH document for each component call …(?)] ?

Would be great if you could give me a hint!

But in general - Thanks for the great work!! Makes life a lot easier
Best,
Robert

Here’s my sample definition

ghpython_MT.gh (37.2 KB)

This should already be possible, with the same code, after the GhPython has been installed and run at least once. The first time the component is initialized, it copies its ghpythonlib library into the the standard script libraries folder, where also rhinoscriptsyntax resides.

In the future we might change the time when this happens. This was convenient for the first release.

Giulio

Giulio Piacentino
for Robert McNeel & Associates
giulio@mcneel.com

Super COOOOOLLL… Thanks Giulio!

–Mitch

Hi Miguel

1.- Yes, you are right. It’s just that there’s no GH_Component-derived entity in the menu for LadyBug. In the future, McNeel might add support for UserObjects. This might, in fact, be a good idea more in general.

2.- For now, I would stay away from this type of component, that heavily relies on document for preview (similarly, Vector Preview, Text Preview, PointList). This has to do with the way these components are instantiated and kept in memory. We might work on making this work in the future. I’ve added a wish to the bugtracker.

Giulio

Giulio Piacentino
for Robert McNeel & Associates
giulio@mcneel.com

Geez, you guys beat me to the topic of my next blog post :smiley:

Here’s a sample that will run in the stand alone python editor

import rhinoscriptsyntax as rs
import ghpythonlib.components as ghcomp
import scriptcontext

points = rs.GetPoints(True)
curves = ghcomp.Voronoi(points)

for curve in curves:
    scriptcontext.doc.Objects.AddCurve(curve)
rs.AddPoints(points)

Ok, here’s the new blog post on the topic of calling component and parallel functions from the standard “EditPythonScript” editor.

1 Like

I’m trying to figure out which part of your definition you would like me to look at. There are several python components in there; could you either remove all of the unnecessary pieces or at least circle the component you are working on?
Thanks

Oh, sorry - and thanks for the fast reply!

Here is an updated version. I have tried to parallelize three different components - and, when possible, change the list-variable of the python parallel run funciton. They are grouped andghpython_MT.gh (38.4 KB) labeled this time.

Thanks for the great user oriented development!

Best,
Robert

This is great for helping us find the functions that “should” be faster using multiple threads.

Here’s what I’ve figured out so far:
1 - MeshPlane intersection
There is a function in RhinoCommon called
Rhino.Geometry.Intersect.Intersection.MeshPlane
which takes a list of planes as input. This is what the grasshopper component is directly calling. I can see why the code would be slower calling the function 1000 times on different threads passing in a single plane versus 1 time passing in 1000 planes. There is significant “setup” code for a data structure to generate the intersections inside of this function. The data structure is recreated in each threaded call which is what is slowing things down. We need to look at this function again and figure out a way to reuse the data structure in the multi-threaded case.

2 - Curve ClosestPoint Test
This one is a little strange and I still don’t know exactly why the code runs approximately the same speed as the single threaded solution. There must be something happening in the component code which is causing the overhead. I modified your script so I could test just using pure RhinoCommon calls in the parallel code instead of the component call (oh yeah, you can do that by the way :smiling_imp:) and got a 2X speed boost.

import ghpythonlib.components as ghcomp
import ghpythonlib.parallel

# True == use component function in parallel code
# False == just use RhinoCommon in the parallel code
useghcomp = False

#custom function that is executed by parallel.run
def curveCP(curve):
    if useghcomp:
        result = ghcomp.CurveClosestPoint(pt, curve).point
    else:
        result = []
        for point in pt:
            rc, t = curve.ClosestPoint(point)
            result.append(curve.PointAt(t))
    return result

if parallel:
    pt = ghpythonlib.parallel.run(curveCP, crv, True)
else:
    results = []
    for curve in crv:
        results.extend(ghcomp.CurveClosestPoint(pt, curve).point)
    pt = results

I’m going to need to spend a little more time trying to figure out what the issue is here.

3 - MeshRay Test
This test does seem to run 3X faster on my computer than the serial version. One thing to point out is that you need to ignore the timing the very first time your python script is executed (or the first time after you edited the script.) There is significant overhead in “compiling” the script that doesn’t really help with figuring out timing issue. After you’ve editing a script click the “parallel” toggle a couple times to get a better feel for timing.

Thanks for sending in this sample, these are very useful for me to figure out the problem spots.

The new release of ghpython is awesome!

Hey @stevebaer, in your “Outside the Canvas” blog post you add the curves to doc.Objects. Is there a way to show them like in GH preview mode instead? I’m imagining that accessing the gh components from a REPL window would be a cool way to experiment. And then when you’re ready you could just “bake”.

I’ve been playing with the new component for a bit and it’s just mind blowing, it’s really straight foward. With this upgrade I don’t see myself using rhinoscriptsyntax,

Do you guys think this update might mean the end of rhinoscriptsyntax?

PS. thanks for this early xmas gift

No. There’s a lot of stuff in rhinoscriptsyntax that you simply can’t do in Grasshopper.

–Mitch

Like? @Helvetosaur
The only things I can think of are: rs.getObject, rs.command but thats about it (for what i use it).
I’m not saying it should be killed. I’m just curious about what coming.
-Miguel