Saturday, 14 September 2013

Dynamo - Max using Reduce

Wow, following Zach Kron’s very kind article over at Buildz, I guess I’d better get posting. Here’s a quick study using Reduce, one of the List Processing nodes I talked about last time. I’ve had a couple of comments suggesting that Reduce is a bit hard to understand, which implies I didn’t explain it very well. So here goes for a more detailed explanation. Or perhaps I should just stop while I’m behind.

There are lots of ways to find the maximum element in a list. This one uses Reduce.

image

Reduce takes a function, an initial value, and a list. In this case, my function is a custom node called Max, which returns the higher of two input numbers.

So I feed my list into Reduce, and set the initial value (the a input on the Reduce node) to the First value in the list. This way, I know that my final output will be a value from the list. (You might think you could just use zero as an initial value, but what would happen if all the items in the list were negative numbers?)

So Reduce takes the initial number (I tend to think of this as ‘the number it has in its hand’), and feeds it to Max alongside the first item from the list. Obviously, they’re both the same number, so Max outputs that number. Then Reduce takes that number and feeds it to Max alongside the second item in the list. And so on. At each stage, if the number from the list is higher than the number that Reduce has in its hand already, then Max gives that higher number to Reduce. And after Reduce has walked through all the items in the list, the number it has in its hand is the highest number in the list.

Does that make sense?

Here’s the definition of Max:

image

It’d be trivial to change this into a Min node that returned the smaller of the two numbers. Then you could plug that into Reduce to extract the Minimum value from a list.

So, Reduce steps through each item in a list and ‘has a value in its hand’. Your function needs to take those two values as inputs, and give an output value back to Reduce. The eventual output from Reduce is the output from the function when it’s invoked with the last item in the list and the value that Reduce has in its hand at that point.

Clear as mud.

Tuesday, 3 September 2013

Dynamo - List Processing

Many Dynamo layouts need to process lists. Lacing is one option, and recursion is another, but sometimes the built-in list-processing nodes Map, Reduce and Combine are just what you need.

Map applies a function to each element of a list and generates a list of the results. The function needs to have one unconnected input, and is called once for each element in the list: The element is fed into the unconnected input, and the function’s output is appended to Map’s output-list.

This is an example that doubles each element of a list:

image

You’d probably use Lacing for this in a real-world layout, but Map will work with custom nodes, whereas Lacing only works with Lacing-enabled built-in nodes at the moment. I’ll often create a custom node to ‘wrap’ a bunch of nodes, just to surface the single input that Map needs.

Combine is like Map, but takes two or more input lists. The number of unconnected inputs on the function needs to match the number of lists in the Combine. Just like Map, the output from Combine is a list of the outputs of the individual function calls.

And here’s an example using Combine to generate a series of Square numbers:

image

The same comment about Lacing applies…

In contrast to Map and Combine, Reduce just produces a single value, not a list. It’s inputs are a list, a function, and an initial value. The function needs to take one list element and the initial value, and output a single value. That value is then fed into the function along with the next element in the list. And the output from the Reduce node is the output from the last function-call.

As an example, here is Factorial implemented with Reduce:

image

Note that there’s nothing to stop you using a list as your ‘single input value’, so you can use Reduce to implement lots of other list-processing functions. And of course your function can inspect and edit the contents of the ‘single input value’ at each stage. Reduce is really very versatile.

Another example, generating a Fibonacci series using Reduce:

image

Which uses this Fibonacci custom node:

image

It’s a bit inelegant in places, but it does the job.

For the code-geeks, it does look as though the Reduce node in Dynamo is actually implemented as Fold in the underlying F#, so the name might change in future Dynamo releases.

Friday, 2 August 2013

Dynamo - Randomize and Export Image

So, once you have a way of generating random numbers and saving screenshots in Dynamo, you can generate this kind of thing:

Slide29

I was interested in exploring these folded, origami-like stadium roof forms. Technically, this is an adaptive component repeated on a divided path. The adaptive component has three parameters: Twist, Fold and Bump; and the number of divisions in the path is parameterised as well. Which gives me a design space with four dimensions, containing a wide variety of forms:

Slide28

Of course, with a bit of Dynamo, you can generate as many variations as you need:

Slide32

The neat thing you’ll notice about the images is that they each include a readout of the values of the four parameters that generated that particular form, together with an index value. These readouts are made with model text, embedded in the mass family and parameterised. When the code sets the parameter values on the form, it also sets the parameter values on the text readouts.

Because I was interested in trying a selective, evolutionary mechanism for exploring this design space, I made Dynamo write out a text file:

Slide35

Then, when I had selected the forms that had the right ‘feel’ and were in the right part of the design space:

Slide34

I could select the relevant lines from the text file:

Slide35

And then mix and combine these parameter values to create a second generation that explored this part of the design space in more detail:

Slide36

The forms in the Second Generation are more alike than those in the First Generation, because they come from a smaller region of the design space. With subsequent generations, by selecting just the forms that appeal, I could focus in on smaller and smaller regions. And quickly zero in on the ‘ideal’ form from a large design space.

Monday, 8 July 2013

Dynamo – Random Numbers

There are two simple random number nodes in Dynamo: Random and Random With Seed. Random just generates a random number, while Random With Seed allows you to ‘seed’ (set the start conditions for) the random number generator.

I tend to use Random, but because of the way Dynamo evaluates the code (illuminated by Stephen Elliot in this post), you can get some unexpected results:

image

Here is a simple layout of one Random node and a pair of Watch nodes. Hit Run, and Surprise: The two Watch nodes report different values!

Why? Well I think it’s because, as Stephen’s description indicates, the Random node is evaluated twice, once for each Watch-node-branch, and it generates a different value each time it’s evaluated.

Bug, or feature? It’s just the way Dynamo works at the moment (this is in Version 0.5.0), so if you want to use random numbers in your layouts right now, you’ll need to take this behaviour into account.

The other option is to use Random With Seed:

image

This is a similar layout, but the Random With Seed node produces the same value each time it is called with the same seed.

Which is fine, but you will probably want to feed it with random seeds so you don’t get the same result each time you Run.

Friday, 5 July 2013

Dynamo – Export Image

This is the first in a sequence of posts explaining the work that followed on from the Parametric Punkinator. Some of which I presented at BIMShowLive in London back in May.

It started with the realisation that there wasn’t an effective way to explore the Punkinator design space. Every time you changed the input parameters, you had to wait for the form to regenerate. And then take a screenshot. And also keep track of which input parameters produced each screenshot, so that you could re-create the ‘best’ form. All of which took time.

First up then, a way to automatically take a screenshot. Now I’m sure it won’t be very long before the Team whip up a built-in node to do this. But until then, there’s Python:

ExportImage3 python code

This is a Python Script node that takes an input file name string, constructs an ImageExportOptions object, and passes that to the API call doc.ExportImage which saves an image of the screen. The Python code is from Daren Thomas at Daren@Work (and via the RevitPythonShell Wiki)

Then the only tricky thing was getting the file name and path to feed into the Python Script node correctly. The \ character that’s used in paths is interpreted as an escape character in Python strings. And in previous versions of Dynamo, those escape characters were evaluated on input to Python Script nodes. Now in 0.5.0, though, it seems as though they string is just passed through ‘raw’.

Put the Python Script node in a Custom node wrapper with a filename input, and you have a nice pluggable Export Image node:

ExportImage3 node

You can test it with a simple layout like this:

ExportImage3 test layout

But to do the job properly, you need to auto-generate the forms and the filenames, which we’ll come to shortly.

Thursday, 4 July 2013

Dynamo - Row of Points with Lacing

If you’ve followed my previous posts on the revitator blog, you’ll have noticed that I made extensive use of Map and Combine nodes to handle lists in Dynamo.

The new Lacing functionality makes most of those constructions obsolete. This post uses Lacing to re-work my Row of Points example (which in turn was based on Nathan Miller’s RevitPythonShell example):

[PG-1.2-Reference-Points.dyn4.png]

You can see how this old layout uses Map nodes to apply multiplication to the number sequences, and then a Combine node to feed the lists into the XYZ.

Re-worked in Dynamo 0.5.0, it looks like this:

PG 1.2 Row of Points layout

The multiply nodes have Longest lacing, so they use the single slider values to multiply each value in the number sequence. The XYZ also has Longest lacing, so it uses the single zero Z-value alongside each pair of X and Y values:

PG 1.2 Row of Points screenshot

Using the number sliders as inputs allows you to dynamically change the scaling of the row of points in X and Y:

Unable to display content. Adobe Flash is required.

Wednesday, 3 July 2013

Dynamo - Lacing 3D

The last post looked at Dynamo Lacing with 2 lists, using a UV node. This time, I’m looking at Lacing with 3 lists using an XYZ node.

Diving straight in with this layout:

Lacing3DLayout

The Number Sequence nodes create the three lists {10, 20, 30, 40}, {10, 20, 30} and {10, 20}, which are then fed into the X, Y and Z inputs of the XYZ node.

Changing the Lacing of the XYZ node generates these sequences:

First: {(10, 10, 10)}

Shortest: {(10, 10, 10) (20, 20, 20)}

Longest: {(10, 10, 10) (20, 20, 20) (30, 30, 20) (40, 30, 20)}

Cross Product: {(10, 10, 10) (10, 10, 20) (10, 20, 10) (10, 20, 20) … (40, 30, 20)}

And here are the screenshots:

Lacing3DFirst
First
Lacing3DShortest
Shortest
Lacing3DLongest
Longest
Lacing3DCrossProduct
Cross Product

You can see how First creates one RefPoint; Shortest creates two (the length of the shortest list); Longest creates four (the length of the longest list); and Cross Product creates 24 (= 2 x 3 x 4, the product of the lengths of all the lists).

That seems to explain how Lacing works technically, but there’s more experimentation to come, to find out how best to make it work in practice.

Tuesday, 2 July 2013

Lacing

I wasn’t sure that I understood the new Lacing functionality in Dynamo (This post is based on Dynamo 0.5.0), so I did some experiments.

Each node in Dynamo has a Lacing setting (right-click the node, and select Lacing from the context menu), which can be First, Shortest, Longest, or Cross Product. Lacing controls how the node deals with list inputs. Each setting has a tooltip that gives you some guidance. For example, Shortest’s tooltip is: ‘For two lists {a,b,c}{1,2} returns {a1,b2}’

So the idea here is that you have a two-input node (a UV node for example), which can take a list on each input. The Lacing setting tells the node how to combine the elements from each list: Do you want all the combinations, or just a selection?

Based on the tooltips, I drew up this table:

image

The two input lists {a, b, c} and {1, 2} are along the top and at the left. In the middle of the table are the possible combinations. (a1), (a2), etc. And I’ve highlighted the combinations that are returned by each Lacing setting.

For example, First just returns (a1), so the UV node would just give you one UV element. Shortest returns (a1) and (b2), a List of two UV elements. And so on.

Put another way, First just combines the first element from each input list. Shortest combines the corresponding elements (a and 1, b and 2, etc.) from each list, until the shortest list runs out of elements. Longest does the same, except that it carries on combining until the longest list runs out of elements, re-using the last element from shorter lists as necessary. Cross Product combines all the elements from all the lists.

That’s the theory. How does it work in practice? Here is a layout I built to test the two-input case:

image

This layout creates a pair of number sequences, {10, 20, 30} and {10, 20}, and feeds them to a UV node. The output of the UV node is used to create RefPoints on a Face.

Changing the Lacing of the UV node does generate each of these sequences:

First: {(10, 10)}

Shortest: {(10, 10) (20, 20)}

Longest: {(10, 10) (20, 20) (30, 20)}

Cross Product: {(10, 10) (10, 20) (20, 10) (20, 20) (30, 10) (30, 20)}

And here are the matching screenshots:

Lacing2DFirst
First
Lacing2DShortest
Shortest
Lacing2DLongest
Longest
Lacing2DCrossProduct
Cross Product

Next, Lacing with 3 lists!