Apart generation - part 1
In the recent years, apartment generation has been something architect have both chased and feared. In this post I’ll show some of my explorations on apartment generation in a grid space.
During a typical day at the office, I’ve been shown a new project that one of our teams has just started working on. The project consists in adding cube-like blocks together to create different types of apartments or even programs.
One of the strengths of this project is its circularity, both in terms of material circularity, and project circularity. The aim of the team was giving the project the ability to evolve over time, by reorganizing the modules that constitutes it. The project could receive extensions/transformations over time, and even potentially allowing for its inhabitants to change their facade modules if they see fit.
As often in the office, small event like this (showing me the project in this case) sparked enough curiosity for me to start working on this as a side project, at first. The question was: What if we could find a way to be presented various valid apartment configurations automatically? I certainly knew I wasn’t the first to ask this question, but I felt like this box-like apartments was constraining enough to allow for decent results without diving deep into ML models. As time went into this side project, it became a project I’d work on at the office from time to time as potentials for results started to show up.
The weapon of choice
As hinted/stated earlier, the project is based on graph datatypes, where the nodes are a block/part/function of an apartment, and the edges are the links between them. Graphs are everywhere in our daily life, and are extensively used in many of the architecture fields already.
By default, graphs don’t own or register any space data (position in 3d, shape, orientation, …), or anything fancy. They simply stores the minimum data required to represent relationships between objects. An edge between nodes means they have some sort of connection (at the most basic concept), this connection can be in one direction (as in a directed graph, like a one-way street between two crossroads) or be in both directions (as in a bi-directional graph, like friendship, hopefully).
From a basic graph structure, it’s possible to store any kind of data as attributes, both to its nodes and edges, allowing the graph to represent more complex systems that we often see in real life.
The setup
Let’s finally dive in and try to give some sense to those words. We start by defining a capable volume in which the project should be contained. We then define some blocks that represent the shared circulations. With a couple of settings that we’ll discuss, the tool displays an apartment configuration (supposedly the best, depending on the settings). One thing we can see in the image below is that the model can suggest apartments of different sizes and shapes.
Types of apartments
As seen hereunder, the model is actually capable to handle different types of apartment: 1, 2 or 3 floors (and combinations of them).
Exploration
The direct visual (and quantitative - later down) feedback allows the architects to play with the model to find a configuration that fits their requirements. While doing so, this quick process also let the architects see and (hopefully) understand how to orient the suggestions in the right direction. Moving the circulations is a simple rhino translation with the gumball, and the generations like the ones here take few milliseconds.
More settings
To provide a wider range of possibilities, more settings than the ones seen above were also implemented into the tool. It currently supports:
Any size of apartments (in block count)
As many different apartment sizes as desired
Proportions between the different apartments in the final configuration (works surprisingly well)
Pick any of the predefined ranking functions (any combination of them as well)
Assign weights to each ranking functions
Data oriented
Here bellow is one of the most important aspects of this tool: the metrics of each apartment / each configurations. This comes out of the apartment generator component, and allows the architect to plug in any solving algorithms like Galapagos, Opossum, Tuna, … to optimize the generations even further ! Architects can use any of these metrics (combined or multi-objective if necessary) as a fitness value, to tweak the generation settings/position of the circulations/etc.
Towards Architecture
It’s all fun and games, but the purpose of all these experiments was to be able to create real living spaces. This is were the work has yet to start. The three images bellow illustrate a naïve (for visualization purposes) approach to constructability and architectural representation.
In the future, the rhino model will more likely only have schematic representation of the building (less detailed than the model hereunder on the right), while tracking quantities of panel types, materials and cost estimations. The Revit team will more likely handle the proper drawing documentations, but will receive the model through RhinoInside through freshly created custom families.
Behind the scene
Once again this project has been developed on and off (when no other priorities were on the table) over 7 to 8 months. The single grasshopper file isn’t ideal (for clarity and team work), but was important to be able to illustrate the full process really quickly to the architects and clients. If the workflow spanned over few files, each iterations would require a lot more inputs… Despite the file having more than 2500 active and used components, the solution computes in half a second (#proudface). That counts for the creation of the setup, data attribution of blocks, apartment generation, data extraction and creation of about a 1000 geometries (last image). Although things can get out of hands.
The landscape of solutions
Let’s make a guess (before reading the numbers described in the gifs below )!
If there are 10 possible apartments made of 6 blocks, how many would there be made of 14 blocks? I know this answer is impossible to guess as it depends on so many other parameters, but a quick guess of the scale difference is more than enough.
A graph’s path count can become exponentially big, and go from few milliseconds to minutes of computing time disturbingly quickly. With a quick custom made component for this post, we are able to compare the landscape of potential apartments between 2 blocks, with a maximum block count.
Once the apartments (or paths between the red blocks) are computed, we are able to scroll through the entire batch of apartments (or paths) with a simple normalized slider (the one called wrongly “Graph Mapper” in the image above).
Constraining the search
As we’ve just seen, asking for paths of length 14 yields 104 498 possible solutions, but asking for paths of length 13 yields a mere 5 964 possible solutions.
From playing around with the complete apartment generation, I’ve noticed that most of the time, limiting the search count (even dramatically) doesn’t reduce the quality of the apartment configuration in the same proportions, but it still does. This is probably due to how Python’s Networkx library searches for the paths, which is good for us.
There are 2 implemented ways to limit the search count:
- limit the target count
- limit the path count
A target is described as “From a position in the graph and a given length (maximum number of blocks), what are the reachable end positions (so called targets)“.
A path is described as “A possible way to go from A to B, through a graph”.
The one to blame if things don’t work
Once again, this project has been developed quite sporadically, with different levels of attention through a decently long period of time and this is never good for a project. The core algorithm that creates the apartment is just a fraction of the whole library, but has been rewritten few times for more flexibility of use.
In the image below, we are looking at the algorithm that reads a graph, get all the settings/ranking functions/weights, then proceed into creating the “best possible configuration it can”. It’s design is surely not optimal, but is decently consistent and fairly flexible, allowing for quick new ranking functions to be added. It’s also very resilient on the cases that I’ve tested so far.
In the middle of the picture, there is a red tilted square.
On its left, the algorithm passes through every circulation nodes, look for potential targets, computes potential paths, ranks the paths, and select one (while keeping track of the proportions and other stuff).
On its right, the algorithm tries to fill the potential missed apartment due to the proportion restriction. In this second pass, the algorithm is more lenient if the possible apartments for a start-target combo would go against the desired proportions of different sized apartment.
At the bottom of that image is the system that handles the ranking of each apartments. This part basically loops over the ranking functions the users as asked for, and rank all the apartment for each start-target combos.
What’s next
I could detail way more what’s under the hood, but I feel it’s not relevant to these website posts. Plus, this model is barely scratching the surface of what’s possible with a tool like this. Nevertheless, here are few of the topics that will hopefully be implemented at some point in the future.
At the time of writing, the edges simply tell us which blocks are parts of which apartments (blocks linked together are part of the same apartment). Later, each apartment will likely have their own “sub-graph” regarding the actual connection between functions (as 2 blocks might be part of the same apartment, but might not share a connection or door between them). Suggestion of apartment function positions could be something.
The project could shift from CPython and Hops to a complete native C# plugin for Grasshopper, allowing also for potential interactions with all the great plugins available.
Better and more flexible rankings (plus additional ones not yet implemented).
Fully functioning facade suggestions (as a sub-graph system), where all the materials quantities are tracked down (not modeled, but evaluated).
Better presentation over the generated and ranked configurations for the architects to pick the overall better one (manual checks are still essentials).
An file that reads the results and transfer the selected configuration to Revit through RiR with custom families.
…
This is a fraction of what could be implemented, the list is certainly not exhaustive.
Either if the project stays on Hops or switches to C#, I will more likely make it available on GitHub for any sharp minds out there who are whiling to participate, to do so.
Antoine -