Creating a central control to execute various grasshopper scripts

Hi everyone!

I’ve been working on creating a grasshopper script that can create a large number of scenes, to be used for rendering video frames. For every frame of the video, a scene has to be created. The script consists of multiple blocks that all have to run in a certain order, to create a single frame.

Here is a picture of what the script looks like. In this scenerio, it should run all blocks 50 times. After this number is reached, it should stop automatically. Every block should output a signal when finished, so that it can be communicated to the central control that the next block can start. After block 4, in case the frame number is not yet at the maximum (in this case 50), another run should be initialized.

Would such a central control be possible with Python in Grasshopper? I would like to keep the number of dependencies on other plugins low. I’ve looked into automatic trigger components (e.g. Honeybee Fly) but that doesn’t seem to allow enough control, since some blocks run external commands (e.g. through CMD).

Hope someone has any ideas, any feedback or references are much appreciated. Thanks!

I may be oversimplifying this but it seems to me all you need are boolean gates at each logic block.

If the condition for the previous block was met, for example block 5 finished and output a non null value, then the condition to activate block 6 would be true, and block 6 would execute.

You could repeat this logic for as many blocks as needed.

All these logic blocks would exist nested within a larger definition, let’s call it “scene handler” for now.

Then for your scene inputs say a list of 50 views or frames or whatever you would loop through these until the frames list length has been met.

for each item in the loop you would be calling your “scene handler” definition that has all the stepped logic blocks in it.

This would mean if you had 50 frames, you would be calling the “scene handler” definition 50 times in total. each logic block step inside the scene handler definition would be called at step 1, then 2, and onward to step 6 or whatever the final step is. outputting the result for that specific frame and appending the result to a list outside of this definition.

EDIT:

It would be helpful to see the input and expected output of each “code block” but within the below code you would be including the logic for each block in the placeholder definitions (B_01 for example would be “Code block 1: Generate Geometry”) This function either would handle this in python or would need to execute an external definition or other script. This would apply to each unique step.

You can also look into the Grasshopper Utilities panel where you will find “Data Input” “Data Output” components. These allow you to pass data between grasshopper definitions external to your current open definition.

Stream Successful Geometry From One Script:

Receive Successful Geometry Into Another Script:


Example of basic logic:

ghenv.Component.Name = "Component Template"
ghenv.Component.NickName = "CT"
ghenv.Component.Description = "Component Template Description"

ghenv.Component.Params.Input[0].Name ="Scenes"
ghenv.Component.Params.Input[0].NickName ="S"
ghenv.Component.Params.Input[0].Description ="Scenes To Process"

ghenv.Component.Params.Input[1].Name ="Process"
ghenv.Component.Params.Input[1].NickName ="P"
ghenv.Component.Params.Input[1].Description ="Set True To Process Scenes"

ghenv.Component.Params.Output[0].Name ="Output"
ghenv.Component.Params.Output[0].NickName ="O"
ghenv.Component.Params.Output[0].Description ="Output Description"

ghenv.Component.Params.Output[1].Name ="Status Message"
ghenv.Component.Params.Output[1].NickName ="M"
ghenv.Component.Params.Output[1].Description ="Scene Handler Status Message"

#Component info showing how many scenes will be processed
ghenv.Component.Message = str(len(S)) + " Scenes"


processed_scenes = []

#Scene Processing Step 01 Function
def B_01(scene):
    # >>> Implement B_01 Function Here <<<
    B_01_success = True  # For demonstration purposes, assuming B_01 always succeeds
    return B_01_success

#Scene Processing Step 02 Function
def B_02(scene):
    # >>> Implement B_02 Function Here <<<
    B_02_success = True  # For demonstration purposes, assuming B_02 always succeeds
    return B_02_success

#Scene Processing Step 03 Function
def B_03(scene):
    # >>> Implement B_03 Function Here <<<
    B_03_success = True  # For demonstration purposes, assuming B_03 always succeeds
    return B_03_success

#Scene Processing Master Function Sequentially Stepping Through Logic Blocks
def scene_handler(S):
    for scene in S:
        if B_01(scene):
            if B_02(scene):
                if B_03(scene):
                    processed_scenes.append(scene)
    M = "All Scenes Processed Successfully!"
    return M


if P:
    M = scene_handler(S)  # Assign the return value of scene_handler to M
    O = processed_scenes
    print(O)
    print(M)

20230815_Scene_Processing_Example_01a.gh (7.7 KB)

20230815_Stream_GH_Input.gh (6.1 KB)
20230815_Stream_GH_Output.gh (6.5 KB)

2 Likes

Hi Michael,

Thanks a lot for your reply and suggestions! The base logic looks very helpfull, I’ll look into it to see if I can get it to work with my code ‘blocks’.

Below is an example of a code block. The input is previously generated Honeybee model properties (different for every scene). This example block generates Radiance Rad files and outputs the location of these files. The file generation is toggled through _run by a boolean. So optimally, when the previous block is finished, this boolean is toggled on. Then, when finished, an output is communicated (I think I should add an ‘succes’ output to Gen_rad_files) that activates the next boolean and switches _run back to false.

code_block_example.gh (21.8 KB)

Thanks for sharing more info.

I’d have to see what your “model” output looks like data structure wise on HB_Assign_Grids_And_Views component but I think you can just simplify by adding a null check gate:

If you have a valid model output on that 2nd component in the purple group, it will trigger Null as False and then the inverted boolean will trigger True and therefore run the Gen_rad_files script you created.

But depending on if your components upstream of this are triggering more than once per input, this could create a data hitch.

Could you do me a favor and internalise the data of the “model” output node on the first component and reupload the GH so I can test the boolean logic easier?

Thanks!

Hi Michael,

Thanks for your reply!
Attatched is the grasshopper code with internalised model data. I’ve also added the next code block.

Indeed, upstream are some components that are triggering more than once per input.
interface_COPY.gh (42.4 KB)

To run the scripts, Honeybee Radiance should be installed.