Solar analysis in Grasshopper

Danil Nagy
Generative Design
Published in
14 min readFeb 27, 2017

A large portion of a building’s performance has to do with how it behaves in relation to its environment, and one of the most important aspects of this environment is the sun. Thus, the way in which a building interacts with the sun, and what this interaction means for how the building performs and the way in which the building is experienced is often of primary concern for the architect, particularly in the early stages of massing and conceptual design.

Two very common types of solar analyses for architectural design are

  • shadow study, which evaluates the extent to which a new building casts shadow on its surrounding area
  • insolation analysis, which evaluates the degree to which a building’s surfaces (for example its facade) absorb the incoming thermal energy of the sun

Both of these analyses are very useful in the schematic design process because they can have a big influence on the way the building’s form develops. Likewise, we can use these same metrics within the generative design process to automatically ‘evolve’ building forms that perform better in relation to the sun. Luckily, both of these analyses can also be quite easily done in Grasshopper. Let’s see how we can compute these measures by using a simple example of a building with a variable form and an adjacent park. You can follow along by downloading this grasshopper file, which contains three groups of nodes which we will use to get started:

  • a Sun Angles component (developed by Arend in C#) for calculating the direction of the sun based on a time and a location on the earth
  • a Python node which creates a form for a turning building split up into individual surfaces for each panel of its facade. The inputs of the node are the building’s floor area, length/width ratio, height, turning angle, and panel width. The output of the node is a list of surfaces representing the panels of the building’s facade.
  • a set of nodes to create a rectangle that defines the edges of the park

In the following two demos we will use this geometry to calculate the amount of shadow that is cast by the building onto the park, as well the amount of solar energy that is absorbed by each of the building’s facade panels. You can use the geometry provided or you can try it with your own project. If you get stuck along the way you can also download the final working version of the definition here.

Calculating sun angle

In order to perform both of these analyses we first need to know the direction of the sun’s rays. This direction can be directly computed given a time during the year and a location on the earth. To do the calculation we will use the Sun Angles node included in the provided Grasshopper file. Using this node you can calculate the position of the sun at a given day and time of the year. You can also use the inputs for GMT, latitude, and longitude to change the position on the earth and the local timezone according to your study area. The included settings are for New York City.

This node relies on a simple algorithm to compute the solar angle, which is all we will need to perform our analyses. For more complicated types of environmental analysis such as daylighting, Grasshopper has special libraries such as Ladybug and DIVA which include specialized nodes for computing the solar angle. However, in this case we will be doing fairly simple analyses which can be computed directly in Grasshopper based only on the sun’s direction, and thus it is easier to use the provided code rather than relying on a separate library.

Shadow study

For the first analysis we will calculate the portion of the park’s area which will be covered by the building’s shadow throughout the year. In order to calculate this amount we will first convert the park boundary to mesh geometry, and then use the vertices of the mesh to calculate which areas of the park are hidden from the sun by the building’s form. The use of a mesh as a grid of samples to evaluate some measure is very common in simulation and is similar to the FEA analysis covered in the previous article. In 2-d structural analysis, the elements of the mesh compute the distribution of force over an object’s surface. In this case, the elements calculate the amount of sunlight that hit each point in the park without being occluded by the building. To calculate the occlusions we will use the Occlusion component provided in Grasshopper which calculates whether or not a point can be seen given a direction and a set of obstruction geometry.

Setting up the simulation grid

To generate the simulation grid we will use Grasshopper’s Mesh UV component which takes in a surface or rectangle curve and converts it to a mesh with a given number of vertices in the U and V directions. We will then use the Deconstruct Mesh component to extract the vertices from the mesh. These vertices will be used as the ‘samples’ to calculate the occlusions along the surface. We will then use this mesh again to visualize the occlusions as shadows on the park’s surface.

Calculating occlusions

Next we will use Grasshopper’s Occlusion node to calculate whether the building’s form blocks the sunlight from hitting each of the sample points in the mesh. The Occlusion node takes in three inputs:

  • Samples (S) — one or more points where the occlusion is tested

To specify the sample points we directly plug in the vertices of the mesh coming from the Deconstruct Mesh component.

  • Obstructions (O) — one or more meshes representing obstacles that block or ‘occlude’ the specified vector from hitting the sample points

For the obstructions we will use the tower’s facade. We first us the Join component to join the individual surfaces of the facade, then the Cap component to create a closed solid form, and finally use the Mesh component to covert the joined polysurface into mesh geometry. Since this mesh will only be used as occluding geometry we do not care how the meshing is done and thus can use the basic Mesh component with default settings.

  • Rays (R) — one or more vectors describing the view rays we want to test

For the rays we will plug in the direction of the sun generated by the Sun Angles component. Because this vector points from the origin toward the sun, we must first reverse the direction of the vector so that it points down onto our geometry.

The results of the calculation are a list of values specifying how many of the provided vectors are able to avoid the obstruction geometry and hit each sample point. Since for now we are using only a single view vector, each sample has a value of either ‘1’ if the view was blocked, or ‘0’ if it wasn’t.

Visualizing occlusions

To visualize the occlusions on the mesh, we can assign colors to each vertex of the mesh according to the data from the occlusion calculation. To create a range of colors based on data we can use the Gradient node in Grasshopper. The Gradient node creates a color spectrum and outputs color values along the spectrum based on input values (t) within a specified range.

To make sure that all data point fall within the spectrum, the limits of the range (L0) and (L1) should be set as the minimum and maximum values in the data set. To get these minimum and maximum values we can use Grasshopper’s Bounds component to compute the range of the data, and the Deconstruct Domain component to extracts the values.

Once the bounds are set, we can connect the actual occlusion data coming from the Occlusion node into the Gradient component’s ‘t’ input to remap the occlusion data to a range of colors. To get a realistic visualization of shadows we use a simple gradient going from white for ‘0’ or no shadow, to black for ‘1’ or in shadow.

Finally, we will use the Construct Mesh component to construct our visualization mesh. This component will use the same vertex and face definitions from the Deconstruct Mesh component we used previously. This time, however, we will input our calculated color information which will specify the color of the mesh by it’s vertices.

The resulting mesh visualizes the shadow cast by the tower onto the park below. You can try changing the hour and month parameters of the Sun Angles node to see how the shadow changes over the day and throughout the year. You can also increase the resolution of the analysis grid by increasing the value of the ‘U’ and ‘V’ inputs of the Mesh UV component. This will create more sample points and smooth out the shadow visualization. Be careful, however, because each calculation will also increase the time required by Grasshopper to perform the calculation. If your mesh is too fine it can cause Grasshopper to freeze or even crash.

Aggregating over time

Although it can be useful to see the exact shadow cast by the building at a certain time of day and day of year, typically we want to understand how shadows behave in aggregate over the entire year. To do this we need to consider not just one moment in time but a sampling of times throughout the day and days throughout the year. Let’s see how we can extend our example to compute the total shadow cast on the park over time.

First we will replace the single values of the ‘Hour’ and ‘Month’ inputs of the Sun Angles component with ranges of values representing different time periods. To construct a range of values we use the Range component, which creates a range of values evenly spaced across a domain. To specify the domain we can use the Construct Domain component or type the domain directly into a Panel component. We will use a domain of ‘6 to 18’ to create a range of hours between 6:00 AM and 6:00 PM, and a domain of ‘1 to 12’ to create a range of months from January to December. We will input ‘9’ into the ’N’ input of each Range component to create an even sampling of 10 values along each domain.

When you plug in a list of values into the ‘Hour’ and ‘Month’ inputs, the Sun Angles node will produce a separate sun direction vector for each combination of month and hour. When you plug in this list of direction vectors into the Occlusion component it will calculate the occlusion for each view vector and return the number of vectors which were occluded for each sample point. Thus without changing anything about the rest of the definition, our park mesh now visualizes the total number of times that each vertex is in shadow through 100 times of the year, with the darkest points always in shadow and the lightest points never in shadow. Again you can experiment with the resolution of the mesh to smooth out the visualization at the expense of computation time.

Extracting metrics

Our work so far provides a useful visualization tool for analyzing the amount of shadow cast by a building throughout the year. However, to make the analysis useful in an automated generative design workflow, we need to derive a single numerical metric which can be either minimized or maximized as an objective during optimization.

In our tower and park example, we may want to minimize the total shadow cast on the park throughout the year. To calculate this total we can use the Mass addition component to sum up the total number of occlusions of all point in the mesh. We can then minimize this value during optimization to derive the tower form that blocks the least amount of sunlight from the park.

Insolation on facade

Insolation is another common type of analysis measuring the relationship between a building and the sun. Insolation measures how much of the sun’s energy is absorbed by the surfaces of a building. This can be useful for measuring how the sun warms up the interior of the building, which can be very useful for residential projects in cold climates, but harmful in office buildings and hotter climates. To see how we can calculate the insolation of a building facade let’s go back to our simple Grasshopper example. For this example we will use the facade surface panels coming from the Python node and the vector representing the direction of the sun. We will not need the park geometry, and the previous definition will be hidden in the screenshots for clarity.

To calculate the insolation of each facade panel we will first calculate the angle between each panel and the sun’s direction. We will then calculate each panel’s insolation as the portion of the sun’s vector that is directly perpendicular to the panel. We will then visualize this value directly on the facade’s geometry. As before, we will extend the definition to calculate the average insolation over a range of times throughout the year. Finally we will extract a single metric which we can use as an objective during the optimization process.

Extracting panel orientation vectors

The first thing we need to do is extract the orientation of each panel in the building as a vector. Since we will again be using mesh geometry to visualize the results of our analysis, we will first convert the surface geometry of each panel to a mesh using the Mesh UV component. To make sure we get a simple mesh with one face for each panel we will input a value of ‘1’ for both ‘U’ and ‘V’ inputs.

Once we have each panel represented by a mesh with a single face, we can use the Face Normals component to calculate the direction of the normal of each face. This component will output the center points and normal vectors for each face of a collection of meshes. Both outputs will be in data tree format, with a branch for each input mesh containing a list of data for the faces in each mesh. Since all of our meshes have only a single face, our data should have the same number of branches as we have panels (960 in this case) with a single value in each branch.

We can visualize the vectors by using the Vector display component and inputting the centers and normal vectors of each face. To see the vectors you may need to scale them using the Amplitude component.

Calculating insolation on panels

The insolation (also called solar irradiance) on a surface is defined as the percentage of the sun’s total energy that is absorbed by the surface. This can be computed based on the angle between the sun’s direction vector and the surface’s normal vector. If the sun vector and surface normal are exactly aligned (sun is pointing directly at the surface) the surface absorbs all of the sun’s energy. If the sun hits the surface at an angle, however, the surface will only absorb a portion of the sun’s energy.

Using trigonometry, we can compute the portion of the sun’s energy that is absorbed by the surfaces as the cosine of the angle between the sun’s vector and the surface normal. This can be interpreted as the ‘projection’ of the full solar vector onto the direction vector of the surface. When the angle is zero, the cosine of the angle is 1, which means that the the solar vector is directly aligned with the panel and 100% of the solar energy is absorbed by the panel. As the angle increases, its cosine decreases, representing the percentage of the solar energy that is orientated with the surface. At an angle of 90⁰, the cosine becomes 0, which means that 0% of the sun’s energy is absorbed by the panel. At angles over 90⁰ the cosine becomes negative. However, since we cannot absorb negative amounts of energy we interpret any negative values as 0.

Calculating the insolation as the cosine of the angle between solar and surface normal vector

To compute this value in Grasshopper we first use the Angle component to calculate the angle between each vector coming from the Face Normals component and the direction of the sun. In this case we will not reverse the sun’s direction because we want the direction pointing from each face towards the sun. Since we will also later extend this definition to calculate over a series of solar direction we will maintain the data tree structure of the normal data, with one branch for each panel. Next we will calculate the cosine of each angle using Grasshopper’s Cosine component. Finally, we will pass these values through a simple Python node that uses the max() function to return the maximum of an input value and 0. This will ensure that any negative values are interpreted as absorbing 0% of the solar energy.

Visualizing results

Now that we have the insolation values for each panel, we can again use the Gradient node to assign different colors to each facade mesh based on its insolation value. Since we know that insolation values always range between 0 (no solar energy absorbed) and 1 (all solar energy absorbed), we can connect them directly to the Gradient component which assumes that the input values range from 0 to 1 by default. To display the colors on the mesh we again use the Deconstruct mesh component to split the mesh into its vertices and faces, and the Construct mesh component to rebuild the meshes with the same vertex and face definition but with our newly generated colors.

Aggregating over a time range

As before, we can also aggregate the insolation information over a series of times throughout the day and months throughout the year. In this case we will analyze insolation over the course of one day. Also, since we need a single value to visualize on the panel, we need to summarize the insolation data computed for each sun vector. You can summarize the data in a variety of ways depending on what you want to study. For example, you might be interested in knowing the average insolation of each panel over a period of time, or the maximum insolation of each panel at any one time. In this case we will use the Bounds and Deconstruct Domain components to extract the maximum insolation value for each panel before passing it into the (t) parameter of the Gradient component which generates a color for each panel based on its maximum insolation value.

Extracting metrics

As before, we also want to summarize the insolation analysis into one or more numeric measures for the whole building which we can either minimize or maximize during optimization. For this we will again use the Mass Addition component to sum the maximum insolation values of each panel in the building. To get the sum over all panels make sure to flatten the input of the Mass Addition component.

We can now minimize this total insolation value during optimization to derive the tower form that has the least direct exposure to the sun’s energy (suitable for warmer climates) or maximize it to create the most potential for passive heating (suitable for residential uses in colder climates). We can even develop a more complex function which tries to minimize the solar radiation during warmer months and maximize it during colder months.

Full simulation workflow for shadow study and facade insolation

This workflow can be used to simulate useful metrics for how a building interacts with the sun in the environment, including the extent to which it obstructs sun from other objects in the environment and how much solar radiation is absorbed by different parts of the building. Since these metrics can be calculated statically they are very useful for generative design, and can be customized to fit the needs of your project.

--

--