Description
Key Learnings
- Learn how to author and run a BIM automation script in Dynamo for Revit
- Learn how to author and run a generative workflow with Project Refinery
- Learn how to push and pull custom data to and from a Revit project into a generative workflow
- Learn how to frame a design problem in terms of goals and constraints
Speakers
- JRJacqueline RohrmannJacqueline Rohrmann (also known as That BIM Girl) is a civil engineering student from TU München. She is passionate about BIM and everything innovative - from robots to Ai. A year ago she started her YouTube-Channel on which she shares tipps and tricks for Revit as well as reports on latest trends of the construction industry. Her latest project is a series called "Coding for AEC", which is directed towards architects and engineers interested in programming. She recently finished her Master's Thesis on "Design Optimization in Early Project Stages - A Generative Design Approach to Project Development".
- Lilli SmithLilli Smith, AIA is an architect with a passion for re-envisioning the way that buildings are designed. After working for several years as an architect, she joined Revit Technology as a fledgling start up and helped grow it to where it is today in almost every architect’s tool box. She has gone on to work on many Autodesk tools including Vasari, FormIt, Dynamo, Project Fractal and Project Refinery which recently graduated to a suite of tools for generative design studies in Revit.
- Sylvester KnudsenSylvester holds a Bachelor of Architectural Technology and Construction Management and a Masters of Building Informatics from Aalborg University. As a former VDC-specialist at one of Denmark's biggest general contractors, he has gained knowledge and experience in the delivery of BIM/VDC related tasks throughout multiple project phases. Passionate about BIM, using data for better decision making and computational workflows, Sylvester is now working as a Computational Specialist at metaspace.
ALVARO ORTEGA PICKMANS: Hey. How are you guys doing? I know it's hard, like four hours and a half of deep Dynamo thing. So I think you're doing great. I've seen people dropping out, bailing after lunch. So you are legends, all of you, because you're powering through quite good. So this last part, this last workshop session we are trying to use Refinery for more things than architecture. I know most of you are architects, but there are more things other. So this is like our try of expanding the scope.
So what we are going to do these last hour and a half before the beers is try to create a parametric Dynamo script that can place lighting fixtures in our rigged model and optimize the number of lighting fixtures by minimizing the number of them and maximizing the surface area that is being eliminated by those lights. So the problem is actually the lighting, one of the key things after the whole design. So it even helps that design itself to shape the spaces, right? So that's why it is quite important to have good lighting levels, et cetera. And that's something that most of the building users notice when they are in a space. So it's quite important to have a good lighting design.
So there are several ways out there. There are proprietary software that does these like [INAUDIBLE] I think it is. But we are trying to do a novel version of that ourselves using Dynamo and Refinery. So Dynamo to create the parametric graph and parametric layout of the lighting features and Refinery to explore a lot of examples. So just heads up, I'm not a lighting specialist. I really don't know anything about lighting. So if there is any lighting specialist or designer in the room, please don't kill me if I made a mistake, because no idea. There are a lot of variables and factors in lighting analysis. We are not going to use all of them. You can do that if you want to, but for this session we are just going to look into the illumination things, not like lost factors, et cetera. And as always, I'm using metric, so I'm sorry. Cool.
So I just want to give a thanks to Jared Linden which is the actual author of this workflow, or the previous version actually. And he allows us to improve it somehow and make it ready for this session. And so if you see him, just say hi and buy him a pint. Cool. So it's going to be full hands on. I know you're tired, but it's going to be easy hopefully. And the session is divided in like nine steps until we get into Refinery. And it's basically going to show you how to create these parametric layout using Dynamo. And I challenge myself not to use any package, although we've been talking about packages like Refinery tool kit, et cetera. But I challenge myself to do that. So you don't need to follow me that much if there's an easier solution with a package, but I just wanted to try that.
So we are going to start with getting links obstructing geometry. So I'm going to switch back to Revit here. And what we need to do is go into the data sets and go to the four folder, Dynamo Refinery Revit MEP. In there, we have RVT folder where we have two files. So we need to open the MEP one. The way this model structure is it has an architectural link, which is usually how MEP generally work. They have a model they received, and then they use it as a layout. So it's very simple. It doesn't have that much. It just have a very simple building. I think it's two floors, something like that, and one big room.
What we are going to do here is trying to get all the geometry that can obstruct the lighting path from a lighting source and find out how many points are illuminated at the end. So if we go to Manage in Dynamo. It takes a while. And then we need to open-- going back to the content-- the D-Y-N folder. And as you can see here, it's actually divided by steps which resemble the same steps in here. So if you at some point get lost, I'm going to show this is screen, this slide every time that we change a step. So you can just open that file and start from there.
So I'm going to start opening the first one, lighting layout. And I try to also make it easier, if possible, by getting here all the steps in groups. We've seen groups the whole day, so I won't explain them. But essentially, you can grab this one and start from there, OK? So the way I like to work with groups is we have a code block, which is examples for the group. And then afterwards when it's done, we have an output for that. So it's like a big note made of notes, to have the Dynamo graph more structured in a way. Everyone following at this point, yes? Cool.
So the first thing we want to do here is getting all the geometry from the link file that can, for some reason, obstruct the path of a lighting. So as you can see here we have some manual inputs, which are things that we'll need to manually select before running the graph or running in Refinery. So in this case, you should be able to select the Revit model itself. So if you see here, if you hover at the bottom left of the Revit window, it says Revit links. So I'm just going to select this one and have that as an input for this group. Cool?
Now for this on, I'm using Python node, which you don't really need to know how to do. You should have it. Let me know if you don't because that will be a problem. So just going through this one right quick, it basically has two inputs. One is the actual link that you want to get items from or elements from, and a list of all the categories that you want to retrieve those items from. What I'm going to do here is specifying the name of those categories as a list. So I want to go to the library panel and then type category by name, if I'm not mistaken. Yeah, so you should have these one here. And if you connect this up to the name input-- and let's put it to automatic because it should be really fast. You'd have three items-- walls, columns, and curtain panels. Cool.
So once you do that, you can connect from these link output to the first input on the Python node and the categories into that one there. So it should be fast, and it shouldn't fail. I'm going to group these here and add that to that group to make things neat. And as you can see here, we have a bunch of Revit elements from that linked model. I don't know if there's an out of the box node or a package that has a get element from link, so you could also use that. I think it's a good way to also see that there are different ways to do Dynamo, not just by using packages. Yeah, sure.
So I'm going to put this one, Dynamo, on the left and Revit on the right. So to select things from Revit, you have essentially two nodes to select them manually, right? You have this one which is called select model element. I just happened to rename it here. So whenever you drop it on the canvas, it flags as a warning because nothing is selected. So you can just select and press this button. And it will activate the Windows panel, right? As you can see here, if I hover something that is not an element, it just has a not allowed icon on the mouse. As soon as you hover something that you can select, it kind of lets you select the element. So if you just click there, it will be selected for Dynamo. This, as you can see, is a Revit link instance element with that ID. And that's it. Any questions about that?
Nice, I'm going to delete this because we don't need it. So what we are actually after is the geometry side of those elements, right? We don't really want the element itself. We want the space that it occupies. So if you go to the library and search for an element dot solid-- so this node takes input Revit elements and outputs all the solids for those elements. And then we should be able to produce something on the background now. It takes a while. Yep, so you should have something like this.
So essentially, we just retrieved all the walls, columns, and curtain panels. Again, you could select any item you want just by supplying that category name to that list. Here, we are just going to have it simple in this case. OK, it's doing something. I don't know what it is, something weird. It happened to you before, right? So don't copy this node three times, please.
OK as you can see here, we have a list of solids. So what we want to do is to have simpler data structure. We want to flatten that. So just right click, flatten, and you have that as an input there. Now this is a part that, if you remember, we need to use that remember node for. This is a Revit input. So we never run from Refinery. It won't have that geometry to be retrieved from Revit, so we need to use that data remember. There we go. Cool. And I'd like to switch off the preview, because it consumes RAM memory. So if you select the nodes that you want to hide, you select them. And then on the canvas, you right click. And then you can press hide all geometric previews. And I still have this one.
That's better? Good, thank you. So I'm just going to add those nodes to the group. It has to make things nice and clean. And if you press Control L, Dynamo kind of tries to rearrange and make it better for you, the layout, if you select the group. And that's the first part. All good? Any questions? So was easy, right? Cool. Sorry, again?
AUDIENCE: What was it that you hid? What did you hide?
ALVARO ORTEGA PICKMANS: The geometry preview-- so by default, every node that outputs geometry has a preview in the background. So that's fine most of the time, but it can consume a lot of memory and graphics. So what I like to do is if I'm not really using it for now, I just select the node and then you can uncheck the preview if you want to. Yeah, it doesn't expire. If you want to select multiple nodes at the same time, you can just select all of them and right click out on the canvas, outside of any node. And then in this case, show all geometry because they are hidden. Now you can hide them again. Cool.
And I'm actually going to save this on a different file so we can see the progress, instead of over-writing this. And let's call this life scary. So that's the first part of the session. Just going to go back to here. So now what we want to do is calculate the lighting levels or lighting layout on a particular room, right? So we need to get that room's geometry. And particularly, we need to get the floor surface and the ceiling surfaces essentially, right?
So this was set up to be a challenge. I don't know what's your mood to do a challenge now. I hope you want to. Maybe, I don't know. So up to you guys. Are you up for it, show of hands? Yay, excited! I mean, I was going to give the solution afterwards, the concept of how to do this in one way. There are several ways. And feel free to use packages, all right? There is no requirement to not use a package. The solution for this particular graph is package-less, but you can do however you want it.
So the idea is to get the room's geometry, to get the bottom and top surfaces. I'm just going to go through these so you can see how I solved it. And you can have the same idea or principles or use any other. So whenever you get a solid from a room in Revit, it actually gives you something like that. It's actually an extrusion of a volume, right? So just using a bit of geometry, what we need to do is actually split that by faces, so get each face, because we just want the bottom and the top.
The next step would be to get the normal vectors from each surface. I don't know how you guys are in geometry. You're architects, so you should be fairly good. And I'm terrible with microphones. But idea is that you can filter out surfaces by comparing the normal vector that they have to the one that you actually want. So for horizontal surfaces, we actually want those faces that have normal vector parallel to the z-axis, right? So that's what it is actually doing. So you can filter them by is parallel to z-axis vector. And in this case, we'll get two surfaces, right? There are two horizontal ones. So you need to define which one is the top and the bottom.
So that's how I solve that. You guys want to try that? I could give like five, 10 minutes if you want. Not necessary. Tick-tock. I can play some music on the background maybe. By the way, if you got lost on the previous step, you can go to Dynamo. Close this one and then open the second one, which is where we left off before.
[AUDIO CUTS OUT]
OK, for what it's worth you could also use Building decompose faces or something like that node that we used before. Yeah, I don't remember the name. Deconstruct, that's the one. So that will give you actually the top and bottom surfaces and the vertical one. So you could use that as well. It's up to you. So anyone got it? All good? Halfway there-- nothing? Let's give a couple more minutes, and then can go on.
AUDIENCE: We're just trying to get the face of the top and the bottom. A lot of people are having trouble here.
ALVARO ORTEGA PICKMANS: You guys want me to show you that maybe? Yeah, let's do it quickly. So let me just go back to Dynamo then. So I'm going to take this group here. And to get the room, we are doing the same. We are using the same select model element. This frame thing is terrible. And we select the room from Revit. So just maximize that. So now we need to get the faces from an element. As you can see here, the element nodes have a bunch of components. There's one which is called actually faces, I think. So we could use this one right away. And then as we should be running in automatic, this should give us the faces of that room on the preview.
So as you can see here, we have all the faces for that room. And it should be a list of surfaces in here. OK, so just following the PowerPoint thing-- which I don't know how do it-- what we need to do is get in the normal parameters for those surfaces. And it's a node called normal at parameter. This one here. So the input for this node is the surfaces themself. And then UMV values, which is parameters. If you have the minimum point from the surface is the maximum-- so the minimum is zero. The maximum is one. And in between, it does your parameter. So to get the midpoint or any normal from the surface, as these surfaces are all planar, it doesn't really matter where you get the point from. It should be the same everywhere. And I'm just getting it from the midpoint, essentially.
Now we should have a list of vectors. And these vectors, as this is a very rectangular element, all of them are not weird vectors. So x, y, and z, and then a few with angles. So what we need to do is filter those surfaces that their normal vector is parallel to the z-axis. So if I right click and then bring the z-axis node-- there are two, actually. So you need to be careful to select the one that doesn't have an input. That's like the default z-axis for this coordinate system. And then there is another node which is parallel. And basically, this will give you a list of Booleans with true or false.
So as you can see, the first surface is actually horizontal because it's parallel to the z-axis. It's normal and the last one. So is it coincidence that the first and the last are the ones that we are after? And now we need to use the filter by Boolean mask. So I'm just going to uncheck the preview here and this one as well, just to show you that. So if you can see here, we already have-- and it doesn't rotate. OK, it's doing some weird things, Dynamo.
OK, I cannot orbit. But in theory, we have the two top and bottom surfaces. The only problem now is that we don't really know which one it is in a parametric way. We know that we have two. They should be top and bottom, but we cannot affirm 100% that the first one is the bottom one and the last one is the top. That's impossible, right? So we need to create a logic that actually tells us that. Why do I have a hand now?
OK now, so what we need to do is take the elevation of each surface to see at which elevation they are. And then select OK. The one that is lower will be the bottom, and the one that is higher will be the top, right? So to do that, we are going to use something that I haven't seen much used in Dynamo, although it is there, which is called function compose. And it is hard stuff, so please bear with me. So the idea is that we want to take a point from the surface and then take the z-coordinates to see the elevation. So there is a component called point at parameter from a surface. So we want to use that, right? So I adjust reuse the same code blocking here. You will see that it actually outputs the middle points for both, kind of total extension of the surface. It's not the actual centroid of the surface. Say again, sorry. Yep.
Yeah, so they do have x and y and z values, but those vectors coordinates are relative to the origin always. So if you can see here, let me just switch back to this. Yeah. True, yeah. But it's not 100% stable, I think, because it pretty much depends on the geometry. If it comes from Revit, yeah. That should be it. If it comes from another source, we don't really-- yeah. And this is a more stable approach, because you actually check in the center point at elevation.
So as you can see here, this outputs two points. One has 4,000 millimeters, and the other one 6,600. OK, delete this one. So after that, we actually want to get the z value, the z-coordinate for that point. So it's actually point dot z, I think. So here we get those values, right? Now we could say OK, select the minimum and the maximum. But there is a cool feature in Dynamo which is not really known, which is least maximum item by key. Yeah. What it does is accepts a list of items and a function to be used to define which one is maximum and minimum. So by using this, we can avoid actually getting the points and displaying them on the preview. And on this case, it would be not a big difference in terms of performance. But if you have thousands of rooms and you want to do those at the same time, that will help a lot.
So to use this function compose, you need to not give one of the inputs. So in theory, we are not going to give the surface input. We are going to connect this one there, and then we are actually composing a function. So it means that it will run this function on whatever input we have in least. And then it will use this output for the next function. So you can concatenate as many functions as you want, as long as it has one output that it can kind of change if that makes sense. Again, haven't seen it done much, but it's quite cool to know.
So I'm getting the maximum item by key. So the input that I need to give to this node is the actual list of surfaces. In this case, I just have two. So we got that. As you can see, as I'm getting the maximum item here it actually gives me the higher surface in that list. Likewise, there is a minimum item by key which does exactly the same. And we can reuse the same kind of function, because it's exactly the same logic that we need to follow. So now if I select that-- I think it's not quite clear from this perspective. Yeah, maybe that's better. Kind of cool.
So what we are trying to do here is kind of reduce the amount of duplicates nodes that we need to use for some cleanliness OCD thing that I have. So we actually now have the bottom surface and the top surface. So we could grab all of these and put it on this group. And yeah, what I like to do is giving some actual output. I'm just going to put floor there and a ceiling link. Nope, too much. And probably hide all your entries, because we don't really need them for now. Yeah, true. And add to group. So all good so far? Again, for the first part you could have just used that building decompose or deconstruct node, because that's what it's doing there. And I bet it's doing the same logic as in here. But it's good to have that notion of how it's doing things and not just rely on black boxes. Cool. I think that's it for this one.
Let me just go quickly here. So yeah, now what we want to do is-- we have selected from the link model every wall, every curtain panel, and every column that is there. But again, not all of them will be within that room, right? And we don't really want to check obstructions with the whole model because that would be a waste of computing power. So what we want to do in here is not a challenge, so I will do it. Don't worry. I'm going to grab this one here and probably save as. And this one. So I'm going to grab this group here. And I'm going to change a little bit this input, although in the solution it's like it is now. Just to kind of reorganize things a little bit. So we need the first surface in here, and we also need the ceiling.
And this is just me being a little bit OCD with naming, so you don't need to follow me that good. One thing that I forgot and is quite important is that we are getting geometry from Revit in this node as well. So what do we need? Yay, cool! So I realized this morning that we can place data remember node in here after we actually get all the faces. But in this particular case, we are just interested in two, right? So it wouldn't make sense to store all that information on the graph when we are going to sort that later on. So what I did here is just add two data remembers. (SINGING) Remember me. Here and another one for that. And then we kind of reconnect this minimum item here, maximum item there. So whenever Refinery launches and then tries to run this graph, it will essentially not run anything until the data remember. So I guess that's computing power that we save as well, because it's just reading that from the cache. Good thing to know.
Now, there are several ways to-- again? No, minimum key maximum key. Yeah, because before I had the maximum key above. But when I did Control L, which kind of reorganized everything, Dynamo does a fairly good job on that. So in order to exclude all these geometry that we don't really want, what we are going to do is get in the bounding box of those two surfaces. Anyone knows what bounding box is? Not you. Anyone else? So basically, it's like a rectangular geometry or rectangular volume that encapsulates all the geometries that you input into it. So essentially, the bounding box for this thing will be like a rectangular extrusion, right? I'm going to show that anyway.
So we want to create the bounding box for the floors and ceilings. To do that, we are going to create a list. And I'm going to connect the floor and the ceiling. Actually connect them here, because otherwise it won't work. And there is a node called bounding box by geometry, these here. Its input is a list of a bunch of geometry essentially. So bounding boxes don't have a graphic representation of them. It's just like an abstract thing that happens to be in geometry. If you want to ever see how it looks, there is a to cuboid method that accepts a bounding box and returns basically that shape. So it's basically a rectangular line to the x and y-axis and z-axis.
So from the data remember node, we will connect them because those are every possible obstacle that is on the model. And what we want to do is check if those are within that bounding box. So bounding boxes are quite nice to know and to use because they are super lightweight. They don't consume that much memory, super condensed, mathematical things. So if you ever see any constraints on your graph or it's slowing down, probably try to change it from bounding boxes whenever you can. So I'm going to actually copy these and have, as an input, the actual obstacles from here. Just to give a preview of how they look, they look like that. It's a single bounding box for all those geometry. What we need to do is set it to longest. Yeah. So now we are getting all the bounding boxes for every wall, ceiling, curtain walls, and columns.
So again, not a big thing because walls are rectangular as well. Columns tend to be as well. But I think one thing to notice here is that, for example, this one here is quite rectangular and quite big. That's because the bounding boxes are always aligned to the x and y-axis. So if you have a wall at 45 degrees, for example, it won't be that rectangle. It will be from the minimum point to the maximum point, so it will be a big extrusion.
So once we have those bounding boxes, the bounding box element also has intersects or contains. I fail to remember. Intersects, I guess it is, yeah. So what this will give you, again, is list of Booleans, truth or false, whether bounding box is within another bounding box. So if we just do this, we'll get a bunch of trues but also falses. So this is one way of filtering geometry that you don't really need for this case, right? It's outside your space context. And then what do we need to use to filter these things, anyone? You won't get a [INAUDIBLE] for this. It's super easy.
OK, you are tired. I am as well. We need to use the filter by Boolean mask.
AUDIENCE: You filter by Boolean mask.
ALVARO ORTEGA PICKMANS: Yay! After I did it, yeah. So we are going to do these, and then we should have that in list of solids and an out list of solids. So we really care now about the in one. So let's uncheck that preview. And again, code block for real obstacles. So I think it seems like they are exactly the same, but they're not. So we have filter out a few elements. Actually, we had 199, and now we have 146. So quite a lot. Any questions so far? Any complaints so far?
AUDIENCE: Can you zoom in on the thing with the code block, the floor to ceiling aspect of it?
ALVARO ORTEGA PICKMANS: This one here?
AUDIENCE: Yeah.
ALVARO ORTEGA PICKMANS: Yeah, this is just a personal preference to have your graph tidy and clean and readable for other people, right? So what I usually tend to do is for a group, we again have inputs-- as many inputs that group needs-- and then it has outputs. I see that as a custom node kind of thing. You have inputs and outputs. Or as a big note that you kind of customize. One thing to notice that we see here is the way Dynamo works is kind of copies that geometry overlay flow. So if you have geometry as an output and then as an input again, it would be like two different instances of that geometry. So that will increase your brand consumption. So just use this carefully. I wouldn't recommend to have surfaces as an input because in here, essentially you have two surfaces. But in here, you have other two. So you have four, essentially. But for this case, I wanted to make it clear and decouple each group. So essentially, you could just connect this one in there, and it would work just fine. And frame is awesome.
OK, so again, add to group and Control L to have things tidy. OK, so any other questions so far? Nope? Cool, what we want to do now is on the floor, generate a grid of points that we can analyze coming from our lighting source, right? We want to have as much points as we can handle and then check how much light they get, how much intensity they get from all the lights that we are going to place. I think I have an image as well, somehow.
This is not a challenge, so don't be scared. This is just a way to show how I tackled this issue. Most of these things are geometry related, and on geometry you need to be quite clever. Otherwise, you will blow your computer. So the way I went for this exercise was, again, bounding boxes. They are awesome, cannot stress that enough. And as you can see here, what I'm doing is getting the floor's bounding box. We have the bounding box of the floor, right? We can get that from Dynamo, because we saw there is a bounding box by geometry node. It's fairly easy. And one cool property of the bounding box is that you can also get the minimum point and the maximum point there. And those points are quite important, because it defines kind of the whole context of the bounding box.
So what you can do with those is if you see on the sketch, if you create a vector by using the minimum point and the maximum point it will have a length or magnitude. That vector will have an x and y-coordinate as you were saying before. That x and y, in this case, would be exactly the length of the floor, the maximum length. And the width will be the y, so the maximum width of that floor, if that makes any sense. Does it? Yeah, just geometry. Once we have those values, we need to define a maximum distance for that grid of points, right? So in this case, I just called it s. And we to find the number of divisions that floor will have in x and y or length and width. So basically, you just need to divide the maximum length and width by that distance. And then usually round up, because then you will get closer points if it's not an integer. And then what we are going to do is create a range of values from 0 to 1. And we need to have those number of divisions for each x and y values or parameters.
So I think I'm just going to show this one, because I think we are short on time. Let's go to open these here. And again, it might be completely different as to what I have here. I just rehearsed this once. I'm doing this live with you. It will be the result of this one, so it will be the fifth script. Everyone here so far? I just opened the lighting layout, five zillion light locations file.
So this is the result for what I just explained. Basically what I'm getting is the floor as an input, so the surface floor, and maximum grid size which is defined as a manual input on Refinery. In this case, it's 715 millimeters. Don't know how much that is in imperial, sorry. I don't know. A note in here is that the lower the [INAUDIBLE] is, the more points you will get and the longer it will take to run the whole script. This script is quite intense and heavy. So I'm just keeping it to a high value.
So just going back here, as you can see I'm getting the bounding box for that floor, which would be what I showed before, and then getting the minimum point and the maximum point. Those are the points that I'm using to create that vector or diagonal of that kind of square. And something I haven't explained, and I don't know how many of you know-- Dynamo, you can create your own functions as a designer script language on code blocks, and reuse it as many places as you want. I'm not going to show how to do that here, but I'm going to show you.
So you see here, I have parameters by length and separation function. That's a function that is only available in this context on this graph. And the way you define it is on a code block. So there's quite good resources on how to create functions in design script language, et cetera. So I wouldn't go through that. But the key thing to note here is that we can reuse these whenever we want. It doesn't appear, but it does work. It should work. I don't know if it's because it's on the same code block or not. Yeah, so the idea is we can reuse that, and I'm reusing this function on here. And I tend to use a lot of code blocks just because they look like you're a real programmer. So it's quite cool. And also because I think it's more performant. This is just an assumption that I have. I'm not 100% sure, but it looks like it.
So what this function is doing is whatever I just explained here. So getting the floor width out of the x-coordinate of that vector, of that diagonal. The y would be the length. And then just doing that range with the grid size. So as you can see here, you should-- maybe because I wasn't running it? Yeah, cool. So here you have a list of parameters which will be for the results of the last function. So what we are doing here is getting those points on that surface, which seems to be quite a lot.
Right, so we are getting all of them now. Thing is, we don't really need all of them because we have voids. It's not actually a nice rectangle. It has voids. It has different rooms on it. So we want to filter those that, again, we don't really care about. So again using a [? cosine ?] function. Doesn't work again.
So all of you know the does intersect node? Geometry does intersect, so that's what I'm using on that function. Let me go there real quick. So as you can see here, I'm accepting a surface as the first input and a list of points as the second input. And I think for some reason I'm flattening them just in case to be sure. And I'm doing that geometry does intersect, all right? Once we do that, this intersect variable would be a list of true and falses. And then we can use it on the filter by Boolean mask and then just return those on the in key of the dictionary, if that makes sense. I don't know how you guys are familiar with code blocks or these kind of things.
Anyway, there's no need to do it that way. It's just because we are going to reuse these functions. And I don't like to copy and paste three nodes that are exactly the same when I can do these kind of things. And so we are filtering those that does intersect with the surface. And what we get out of this is that and then preview. So you can see here it's only whatever is within that room or within that surface geometry. So what is next? Sweet, so now we need to do something similar for the ceiling point. Again, I'm not an expert in lighting design, so I just assume that it's good for an office layout, for example, to have a grid, a layout for lights. It is not taking into account the external light that comes from the windows or anything else. It's just those lights, that's it. I didn't want to over-complicate this thing.
And so these should go somewhere here. And as you can see again, we have a ceiling input which would be that ceiling over here. Again, this is slightly different from what I just did before, because I did it a different way when I was prepping for this. If you open the same file, you should be ready to go. Now it also needs two inputs like width distance and length distance. Those are the first Refinery inputs that we are going to speak about today.
So let me just actually show, because I think it would be better than me talking a lot. We are going to input that there. So essentially, that will drive the degree distance for that ceiling, like the same that we did before with the floor. We have 750 distance. Now we need to have more, because we don't really want 5,000 lighting devices. So I think I'm going to reuse this completely. Can I do this? In theory, yes. Because again, it's the same principle essentially. It's just getting that grid of points on the ceiling. There is one thing, though, that we need to take care of once this stop breaking. Let me just hide that one. And is it zoomed enough for you, or do I need to zoom more? Thank you. OK, what's going on? Let's put this closer here.
So we are going to do something similar. Maybe I just will run in manual for now. We need to get the bounding box of that ceiling, which again will give you the minimum and maximum point, give you the diagonal. And in this case, we actually want to have a different grid size for x and y parameters. So I'm going to just put here x distance, and in here y distance. And this is why I like those functions, because then you can reuse that and just change the input. And then the logic is exactly the same. You don't need to copy so many nodes, which is nice not to do. And then we have here width distance and length distance, which are the inputs that we have for Refinery. So these will drive the location of the lighting fixtures once I run this. Everyone with me now? Yes, OK! Cool.
So one thing I realized while doing this is that, again, I'm not an expert in lighting design. But I think I wouldn't like to have a light exactly on the wall, right? I think that doesn't make sense. Although in here, we have. But yeah, it's all right. So what we actually want to do is remove those points from the list. Now this doesn't select anything. So we could do it two ways. Once we have the list of points, we remove the first and the last. But we can do something more performant, which is here we are getting a range of parameters to use that. So instead of generating those points and then removing those points, we can avoid creating those points of the first place. And that would be faster on your Dynamo graph.
So I don't remember how I did this. But I think I will do something like list remove item at index. And then we'll do that least. And we need to actually get the last index of that list. So again, I'd like to use code blocks. Yeah, I cannot help it. So to get the last index of the list-- although we know there is five-- we need to do it in a way that is parametrically viable. So if we have more points, we cannot really hard code the number of items. Yep? Let's give it a try. I think I did try, but it had some issues while you want to remove more indices. Yeah, so it takes out the first one and then the second one. So I think in this case, you need to actually specify. If you input a minus one, it might just do the trick. Maybe they changed something. I remember that was the case.
So in here, we want to actually get the last index of that, which is five. And then we want to create a list. Let's do it in a code block as well. We want to create a list with the first item that always will be 0 and with that index that we just calculated. So we should have 0 and 5 whenever I run it. And then we can just have this as an input for list remove item. So on the solution, I think I did it differently, dropping the first item and dropping the second item. So there's not just one way to do things, just different or more performant ways. And yes, so now I should have node point two, node point four, node point eight, and then the same here. So that means no matter what distance I put on the maximum the minimum distance, x and y distances for the lighting layout, it will always work which is what we are after, essentially.
So if I select this one, you can see in the preview if I run it. Yeah, we only get points that are not on the walls. So that's that for it. Yeah, OK. Think I'm going to rush a little bit. So now the next part would be to-- this one, right? Not this one. This is what we just did, number five-- ray tracing. I'm just going to explain this one, and then we are going to probably just skip to the final solution because we need to see Refinery. But it's a nice concept to grasp, I think. OK, I will keep on. There we go.
So what we want to do now is we have some locations for some lighting fixtures. And we want to analyze for each point on the floor that we calculated how much intensity they get from all the lights, super intense geometry work. So essentially, we'll do that for every point. So you have 1,000 points, and you have 10 lighting fixtures, it will be 1,000 times 10 which is 10,000, right? So it will be an exponential run time, which is quite heavy. So the more points you get, the longer it will take. So to do these a little bit better-- let me just skip to that one-- we are, again, using bounding boxes. They are great.
Instead of first checking if it intersects with the actual geometry, what we can do is check if it intersects with the bounding box. If it doesn't, it means that there is no way it can intersect with the geometry because it's outside completely from that context. So I'm just going to play these, because I think it's quite cool. Yeah, I had a free Sunday to do this. As you can see here, there's a comparison between not using the bounding box and using bounding box. This one is for every check, you need to check with the geometric. I don't know how many faces it need to checks, and that will be quite expensive. On the other hand this one, as soon as it doesn't intersect with the bounding box, it's goes to the next iteration because it doesn't really need to check that. It knows there's no way to check with that geometry. In this case this one has a real finish, as you can see here, and this one is steel. There you go. So again, I think when I did the test it cut the time in half, so it's quite a good thing to do. It's quite a good improvement.
But again, there are better algorithms to do this than just a for loop. So I will just probably show you, because this is something that is difficult to do in Dynamo out of the box, quite hard to do it. So I did use a Python script to do that. And I think I'm just probably skip to the final one and then show everything over there. The rest is super easy, just coloring things or calculating numbers. We've been over that a lot. But this one is like the crumb here, like the best thing that you could ever do.
So I actually based this algorithm on online source. I don't know if this will open on frame. Yeah, it will. So if you are curious enough and you have the time, you can read through it and then see why it's doing what it's doing now. But essentially, it's doing that bounding box intersection pre filtering before checking the actual does intersect. So if you're familiar with Python, what it did is create some classes for a custom ray object and a custom bounding geometry. And it does this intersects method, which is quite long and harder to explain mainly because I don't really remember how I did it. So it's super hard.
But essentially, the key line to check is this one here. So basically before checking if that geometry does intersect, which is a Dynamo built in function, it does this, OK? This geometry that I have actually intersects with the ray. If it doesn't, read fails and then continues. So that's the improvement that we did for this graph. Again, you can have this, have a read if you're curious, and then use it. And I think I'm just going to run it once and then go through the rest of the graph. Again, even with that improvement it takes maybe 10 seconds or 15 seconds. Bear in mind that you need to check for every lighting fixture. You need to check every point on the floor, so that's hard stuff.
And done, so let's go through these. This Python outputs a bunch of things, not just the intensities of the lightings. Just out of curiosity, those are the lines that it generate which is quite a lot. So that's why it's so intensive. Thus, the Python run time-- so it took like 10 seconds to do all that process. With a kind of naive approach, it would have taken like twice, more or less. And probably let's not see these, because we don't need it for Refinery. And what we did from the previous scripts to this one is just add some color. Adding color to the lighting fixtures-- big sphere, yellow sphere. And then coloring the floor points. So as you can see here, they input still these floor points. And we have those point intensities, which is calculated within the Python script and is an output of that Python script. So again, we can just reuse it.
So as you can see, some of them are 0 meaning that they don't receive any light. Some of them are like 534, et cetera. So it kind of varies across the graph. We got the maximum item of all of them. And we are doing our rule of thumbs here. So if it's red, it means it's the maximum one. So we are just dividing by the maximum value and multiplying by 255, because colors go from 0 to 255 for those who don't know. And for the blue, basically we just subtracted that value from the grid and did a trick. That's sort of a heat map for this kind of analysis.
And then the Refinery outputs-- so the goals that we want to set here is that I want to have as many points eliminated as possible, right? But we want to constrain them to not be too much eliminated, so we don't really want a really bright light in our face. And then we want to minimize the number of lighting fixtures that we have on this layout, just to save a little bit of money for beers later. Any questions so far? OK, let's save as again, as this one here. And I think I'm just going to skip through these.
Yeah, Refinery time! Hey, we are doing great, right? Super fast, yay. By the way, there was a challenge. But yeah, we'll skip it. So thank you. You're welcome! Again, just very basic stuff. Refinery-- you've done this before, so I'm just going to skip through these. We are going to launch Refinery now from Revit, not from Dynamo. So this is going to be a new thing that we are going to try now, see if it works. So let's do that. That will be cool. Again, you saved as. You need to export for Refinery again. So now, everyone, do you have Revit open still, or are you guys thinking about beers like I am?
So now if you're in Revit, you see that under the add ins tab, you should have a Refinery add in or tool there. If you click that, it will do the same as on Dynamo. It will launch Refinery, and then you have all the studies that we had before this session. And close and open again. Yep, cool. So now we exported that Dynamo graph for Refinery on Dynamo. That's new. Let me get the one quick thing. Again, bear in mind that Refinery's in beta. I cannot stress that enough again. So maybe we need to kill these guys here. So as you can see here, as we mentioned before, Refinery launches at six Dynamo [INAUDIBLE]. So sometimes they don't stop whenever you want to. So a work around for now is just killing them yourself.
Yeah, maybe that's too many, right? Yeah, OK, let's try this one. And just for the sake of simplicity-- where are they stored, in documents?
AUDIENCE: Yeah.
ALVARO ORTEGA PICKMANS: So Refinery-- as you can see, we have loads of them. So yeah, sorry, guys. I'm sorry. You did a great job, though. Now let's try again. So if you open Refinery again from Revit, it should launch. There's no studies? And we are going to create a new one. Sorry, I also deleted mine, so we need to export it again. Refinery, export, and there you go. Cool. So now again, we are in Refinery from Revit. So now we should be able to select this one. Tell me if you don't. We select it, and then one thing that it's here enabling is that you are able to select those inputs, the same one that we did before on Dynamo from Refinery. So it sometimes needs a little bit of time. It's a little bit shy still. But yeah, I think I haven't explained that in order for them to appear, you actually need to set them to be all of the inputs for Refinery. So you can see here this is an input. Otherwise, it won't show.
OK, so how much time do we have? 20 minutes. Let's do one thing. Let's not check that as an input, because otherwise it won't work. And then save and export again. So hopefully in the next version, that will be available and ready to use. Now it has some quirks. So don't ship it for production just yet. Hold your horses. So again, we have those selections, the link model and the room selections, hard coded for now. But again, we have the inputs that we want to use. And in this case, we want to maximize the number of floors that are lit on that room. We want to minimize those are over-lit, because we don't want super bright room. And then we also want to minimize the number of lighting fixtures just to drinks and stuff. And let's make these the default ones. And then just for a fun thing, let's put this one to six. And again, optimize. So we want to get the best results possible. So this should start soon-- or not.
One thing you can do is check if this hasn't started for some reason. So before, we were explain about how can you see all the results from Refinery, right? We saw that we had that extra file, but we also have-- no, it hasn't started yet. So shall I kill it again? It's difficult to have too many bars. So Refinery's there, CPU performance-- let's try again. Maybe it didn't like the 6. You never know. OK, so no. Luckily enough, I have the results here so we can just see them here.
So this is what we did, right? Select the script. That's the thing. It was working on my laptop when I did the content, so you will get something like being able to select the items from Revit. And you will be able to run as well. So what we get from Refinery at the end of the process and all the generations, et cetera, it's like this graph or these results. So as you can see here, I modify the y-axis to represent the number of points that are illuminated on the floor. Yeah, that's the y-axis. So the higher, the better. The x-axis is the number of lighting fixture required for that level of illumination. And the size is the lighting power, which is something I haven't explained-- basically just the maximum distance that the ray of light can travel from the source to a point. So if the point is too far, it doesn't take that into account.
And as you can see here-- I think it's quite good to see that for the same amount of illuminated points, you can either use 30 lighting sources, 17 maybe, or 8. So you should go that way, more to the left. And then like Sylvester and Jacqueline explained before, you can also filter them by whatever values you want to, are interested into. So using this graph, you could easily filter them. And before finishing this, let's see if-- yeah, I think Refinery is tired as well. Like six hours, it's too much. So any questions? Any complaints? Just say now. Well, not say now, because we do actually have a way for you to tell us.
Let's me just close everything. Data sets-- you should have in here a Refinery feedback survey. So I think it takes like one minute to do it. It has three questions. And then any comments, and--
AUDIENCE: There's actually a couple more than three. It has a next page.
ALVARO ORTEGA PICKMANS: It has a next page, so maybe it's five minutes.
JACQUELINE: Sorry, should talk on the microphone. So this is the first time that we've all done this workshop. So we'd really appreciate your feedback on the workshop itself and then also on Refinery the tool.
ALVARO ORTEGA PICKMANS: And all the content will be uploaded, at some point.
JACQUELINE: Yes, so all of the content-- after AU, they publish it all. They're going to record and probably edit these sessions a little bit so that they can be consumed by other people. We'll take out some of the challenge times and things like that. But yeah, so you can do it all again.
ALVARO ORTEGA PICKMANS: Any questions?
Downloads
Tags
Product | |
Industries | |
Topics |