tirsdag 5. april 2016

Dynamo and Optimo: Optimizing your Carl Bass Keynote Experience

For a long time now, I've have felt an urge to explore the capabilities of the Optimo package in Dynamo. However it has seemed like such a montainous task that I've constantly postponed my interest. Easter break however, provided a window for dwelving into these things.

I've experienced that the best way to learn anything in the world of Dynamo is to have a problem that you can experiment on. As I'll have to be somewhat careful with examples from my daily job, I figured why not make it an abstract one.

So to get you in the mood, picture yourself at AU 2016. Tech nerds are swarming and Carl Bass (CB) is about to hold his opening keynote. This year however, there are no seats provided in the room and the room acoustics are horrendous. To accomodate this awful planning mistake, Autodesk has put up a number of bars serving the finest beers available.
(An appreciation party and opening keynote all at once make for one heck of a opening, right?)
Lazy as you are you want to be as close to the bar as possible while also be as close as possible to CB. Additionally you want to hear CB as good as you can as he speaks about coming trends and whatnot.

Or somewhat redefined: Given CB's position, the position of the bars and an acoustic map of the venue, which X,Y gives me the shortest distance to both beer and Mr. Bass, while also having the best acoustics?
Where to stand? (PS. stick figure not drawn with dynamo.)

My acoustic map. More black=Better Acoustics

Although the example is "dumb" it provides an interesting enough example case for taking Optimo for a run. Consider the post a Layperson's guide to the galaxy of optimization.

If you want to learn the indepths of Optimo I suggest going over to their website
here: http://bim-sim.org/Optimo/

Some optimization terms explained first: 
Simply put, the genetic optimization in the Optimo package tries to mimick Darwin's theory of evolution.
You make a 1. generation population, decides what is desirable "genes" and Optimo iterates through the "generations" to help you find the optimal solutions to your problem. The spesific algorithm used in Optimo is called NSGA-II
(If you want the whole shebang go to Wikipedia:https://en.wikipedia.org/wiki/Multi-objective_optimization)

Populationlist:
This is just how many initial values we would like to evaluate.
In our example that would be how many different values of X and Y would we like to evaluate in our script. A larger population can have some effect on our outcome in terms of accuracy, but more importantly it drives the the main datastructure of the script, so:
Larger population=More datapoints=More readable graph.

Objective:The objectives in our example is to minimize:
  1. The distance from the given X,Y-values to the closest bar
  2. The distance from the given X,Y-values to CB
  3. The amount of white at the given X,Y according to the acoustic map. (Black is better.)

Fitness function:
First of all the term "Fitness" can be anything. It's just a measurement. All Optimo tries to do is to minimize the fitnessvalue for all objectives. This means that we have to design the fitness function so they report fitness in the way Optimo likes it.
If you want to maximize something, you would have to multiply that something with -1 so that the fitness reports lower values for better solutions. If you want the resulting fitness values to be in a comperable range consider introducing some factors to even the fitness functions out between each other (Like multiplying with 10, dividing by 1000 etc..)
In our example two of our fitness functions returns a distance in meters and the lower the distance the fitter the X,Y-value are. The third one obtains a brightness value from an acoustic map based on the given X,Y and the blacker the spot is the lower the fitnessvalue (aka "more fit")

Pareto-front:
This is our results. A Pareto front is the resulting graph of fitness values that indicates the solutions for the problem at hand where none of the fitness function results can be better without others becoming worse. Read about it here: https://en.wikipedia.org/wiki/Pareto_efficiency 
In our example we will obtain a 3d scatter plot because we have 3 objectives with varying fitness values. the value that is closest to 0 will be the most optimum value if you weigh all the fitness results the same.

The Main script:
The script below shows the basic layout for any script using Optimo. I'll try my best to explain each node to demystify the Optimo package. (It isn't as hard as it looks..) Please notify the organization of variables and fitness functions in lists as this is how the Optimo nodes works.

  • NSGA_II.InitialSolutionList:
    Sounds complicated, but isn't. Creates a number(PopulationSize) of random values between lower and upper limits for our position's X and Y respectively and adds x placeholder lists for our fitness functions. In our example it creates 5 sublists,
    [0] and [1] for random values of X and Y respectively.
    [2],[3],[4] containing just 0's for later to be overwritten with our fitness results.

  • Fitness functions:
    In this script we have 3 objectives, and each of the objectives has its own fitness function. All they do is some simple stuff to calculate the different fitness values,
Bar Fitness
Carl Bass Distance Fitness
Carl Bass Audio Fitness
  • NSGA_II.AssignFitnessFuncResults
    This is just a custom node from the Optimo package to assign our initial fitness results to the initial population list so that the resulting list contain both our X,Y-values as well as the fitness values.
  • NSGA Function
    This is where the magic happens and I'm not gonna go into this in detail. Shortly put it mimicks our main graph, except it has node which sorts the fitness result for each generation and add some randomness as to "mutate" into better fitness results.
  • Loop Completion Check
    This node acts as a counter and returns a boolean value which tells the loop node when to stop. The number you give as a input here equals the number of generations you will iterate through.
    Higher number=More generations=More precise results.
Pressing run begins the iteration and once we have some results we can start to interpret them.




You can observe two things from the above:
1. The resulting Pareto front. As you can see the distance from bars and CB are rather linear on the Pareto front, and the fitness values based on the acoustic map (Z-value) fluctuates a bit more, as one could expect. The closest point to zero is marked by a line.
2. The most optimal point to stand if you value all the objectives equally. (Marked red in gif)
As you can see, the point made by the three fitness values at index 12 is the point closest to 0,0 and we can then extract the X,Y values at index 12 from our population list.

Sooo, where to stand?.. Here:

Now, the Pareto front can look very different depending on the problem, and if I understood it correctly it's practically an entire science just interpreting them, but for many problems in the AEC-industry it should be quite readable. Searching for optimalization online will get you many hits based in Academia, but hopefully we'll see this on more practical cases in the future as it has awesome potential!

Ps. Datasets will not be provided as of yet since you'll learn much more by doing it your self. (That's at least my opinion.) Reach out if you're in dire need! :)