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
Does this “multi-threading” feature mean that a call inside of ghPython component could execute data quicker than a corresponding Grasshopper component itself?
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
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.
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.
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
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.
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 ) 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.
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?
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