Issues with Passing Outputs Between Clusters in Python Script

Hi all,

I’m encountering some difficulties with a GhPython script that I’ve written to run three clusters consecutively. The aim is for each cluster to pass its output to the next one in sequence. However, it appears that the script doesn’t work as expected after running it for the second time or if I change the order of the clusters.
question.gh (12.0 KB)

Is there a basic type mismatch?

Expand the clusters and see where the errors are (if any).

I believe the problem comes from your use of Grasshopper.Kernel.GH_Document.AddObject() which takes an insertion index as one of its arguments. Your original script has this hard-coded as 0; I’ve replaced it with the index of the cluster in the input list and it works as expected. Note that the default value of index is 2147483647. Someone with more experience than me can probably explain the significance of the index argument!


question.gh (13.5 KB)

2 Likes

It’s the maximum value of an Int32. 2,147,483,647 - Wikipedia 2**31 -1, so one bit used for the sign.

2 Likes

@colinlsmatthews @James_Parrott if I changed the input value for ghpython node it is not update the successive values, it update only fist one , can try it ?

It’s very fiddly trying to run any component in code, dealing with dot net internals from Iron Python, running in its own .Net context. Even if I build a solution on my machine, I couldn’t guarantee you could replicate it…

I noticed the inputs inputandlist` are Python built-in functions. Don’t name variables or inputs the same as built-in functions (it’s called shadowing).

Interesting approach though - great for testing.

I haven’t tried this with Clusters, with a heavy workload or with anything complicated yet, but thanks to your code, I’ve been able to ‘remotely’ run an external component in Grasshopper, from an Iron Python 2 one. So thanks very much!

It feels safer to store external components in separate files. But all of those must be opened first, and the one with the controller only opened afterwards.

import os

import Grasshopper

import rhinoscriptsyntax as rs




def GH_doc_components(doc):
    return {component.NickName : component
            for component in doc.Objects
            }

def set_data_on(param, val):
    param.ClearData()
    param.AddVolatileData(Grasshopper.Kernel.Data.GH_Path(0), 0, val)

def get_data_from(param):
    return Grasshopper.DataTree[object](param.VolatileData).Branch(0)[0]

class MyComponent(Grasshopper.Kernel.GH_ScriptInstance):
    def __init__(self):
        # This component must be re-initialised 
        # after the component to be run remotely has been placed.
        # or e.g. set this to run last by selecting it and pressing
        # Ctrl+B
        self.GH_Doc = ghdoc.Component.Attributes.DocObject.OnPingDocument()
        self.GH_Doc_components = GH_doc_components(self.GH_Doc)

        self.all_docs_comps = {
                          os.path.splitext(os.path.basename(doc.FilePath))[0] : (doc, GH_doc_components(doc)) 
                          for doc in Grasshopper.Instances.DocumentServer.GetEnumerator()
                         }

    def RunScript(self, x, y, comp_name, gh_doc_name): 




        x = x or 10
        y = y or 37
        comp_name = comp_name or '1000*x + y'

        if gh_doc_name is None:
            doc, comps = self.GH_Doc, self.GH_Doc_components
        else:
            gh_doc_name = os.path.splitext(gh_doc_name)[0]
            doc, comps = self.all_docs_comps[gh_doc_name]

        comp = comps[comp_name] 


        set_data_on(comp.Params.Input[0], x)
        set_data_on(comp.Params.Input[1], y)

        comp.ExpireSolution(False)
        comp.CollectData()
        comp.ComputeData()

        a = get_data_from(comp.Params.Output[0])

        print(a)
        return a

image

remotely_call_another_component.gh (12.7 KB)
another_gh_doc.gh (3.6 KB)