Scripting components in Grasshopper can be a great way to get extra power and functionality for those comfortable with C# or VB. It can also be a much tidier way of doing certain tasks than using components, such as using mathematical formulae on a list of values.
Calculating the minimum value in a list of numbers is a great example of this – difficult to do using Grasshopper but dead easy with a few lines of script. The algorithm is simple – look through every item in the list, keeping track of the smallest item found. When we are at the end of the list, simply return this smallest value.
To implement this in Grasshopper, we can use the C# component. We’d start by specifying the input data types by right-clicking on the input, selecting ‘list’ and selecting ‘double’.
Then we’d go into the component and add our code.
private void RunScript(List<double> x, ref object A)
{
double minsofar = x[0];
foreach(double val in x)
{
minsofar = Math.Min(val, minsofar);
}
A = minsofar;
}
This works fine and gives the expected result.
But try and run this code for quite a large list, say 100000 items. This takes around a second to compute. Not an especially long time, but for such a simple calculation it still adds a noticeable lag to the canvas. I just accepted it for what it was, thinking maybe that’s simply how long it actually takes to run a bit of code.
One day, I was writing another simple component and was feeling especially lazy. I couldn’t be bothered to do the right-clicking malarkey, and decided to just cast the data types in the Grasshopper component itself. Again, there was a large list going into the component, but to my surprise it calculated in mere milliseconds. Investigating further, I found that this speed difference occurs time and time again, and can be easily demonstrated:
Here, we have a list of 100000 numbers (a series of doubles) and we’re trying to find the smallest value among them. (Of course, with an ascending series it’s going to be the first value, but the algorithm doesn’t know that.) The code for the first C# component is:
double minsofar = x[0];
foreach(double val in x)
{
minsofar = Math.Min(val, minsofar);
}
A = minsofar;
This is the same as before – we have set the input data type (called x) as double, and assumed that x is a double in the code. This consistently takes 1.2s to calculate on my laptop.
The code for the second C# component is:
double minsofar = (double) x[0];
foreach(object val in x)
{
minsofar = Math.Min((double) val, minsofar);
}
A = minsofar;
The only difference here is that we don’t tell the component input to expect a particular data type – we leave it set as ‘object’. (We still have to tell it it’s going to be a list.) Then, in the code, whenever we want to do something with this list that can only be applied as numbers, we cast the item in the list we are looking at as a double, e.g. x[0] becomes (double)x[0].
The difference this makes is astonishing – we go from a calculation time of 1.2s to a tiny 7 milliseconds.
Why this is I don’t know. Whether it works for other data types I am still investigating, and it would be great to hear if this technique is repeated elsewhere in different scenarios.
In the meantime, the lesson is clear: if you are looking to optimise your canvas as much as possible, it is worth trying to cast your variables inside your component instead.
Download the example file: