How to set up a simple rtrace workflow.
Here we go through the process of setting up a simple Radiance model and the workflow of computing irradiance values.
Prepare a model
If you already have a Radiance model setup, you can skip this step and follow along using your own.
If you don't have a model already we can use gen room
to get ourself
a simple Radiance model.
Let's generate a open-office sized side-lit room
with four same-sized windows. The room will be 12 meters wide, 14 meters
deep, a floor to floor height of 4 meters, and a ceiling height of 3 meters. Each window is 2.5 meters in width
and 1.8 meters in height and has a sill height of 1 meter. Windows are 0.4 meters
apart from each other. Finally, we want our facade to have a thickness
of 0.1 meters. We'll call this model 'aroom'. The gen room
command is:
! gen room 12 14 4 3 \
-w 0.4 1 2.5 1.8 \
-w 3.3 1 2.5 1.8 \
-w 6.2 1 2.5 1.8 \
-w 9.1 1 2.5 1.8 \
-t 0.1 -n aroom # (1)
gen room
is a command line function. To run shell commands from inside a IPython syntax (e.g. Jupyter Notebook), start the code with an exclamation mark (!).
Afterwards, we will have a Objects
folder in our current working
directory with all of our Radiance model inside.
|____Objects
| |____window_03_aroom.rad
| |____wall_aroom.rad
| |____window_02_aroom.rad
| |____ceiling_aroom.rad
| |____window_01_aroom.rad
| |____materials_aroom.mat
| |____window_00_aroom.rad
| |____floor_aroom.rad
objview
and
make sure it's what we'd expect in terms of layout and geometry.
And we can see that it is what we'd expect.
Generate an octree file
Now that we have model, we can start to run some actual simulation. Each code block below can be copy and paste into a something like a Jupyter Lab for an interactive workflow.
First lets import all the necessary modules.
Next lets gather our model files. Notice that we have our material files first in the list.
fpaths = ["Objects/materials_aroom.mat",
"Objects/ceiling_aroom.rad",
"Objects/wall_aroom.rad",
"Objects/floor_aroom.rad",
"Objects/window_00_aroom.rad",
"Objects/window_01_aroom.rad",
"Objects/window_02_aroom.rad",
"Objects/window_03_aroom.rad",
]
Now that we know where all the paths are, we can call oconv
to get ourself a octree
for ray tracing. We'd like to save
our octree as a aroom.oct
file.
Notices that we have a aroom.oct
, which only contains the geometry.
We need to define our light source, usually some kind of sky model,
for rays to trace to. In this example, we will use Perez all-weather
sky model. There are also standard CIE skies as alternatives.
To do so, we can use gen_perez_sky
function to get our sky
description and generate a new octree with it.
First to get our sky description, we make up a clear sky on 12-21 12:00 with direct normal irradiance of 800 W/m2 and diffuse horizontal irradiance of 100 W/m2. We also need to define our location in terms of latitude, longitude, time-zone, and elevation.
date_time = datetime.datetime(2024, 12, 21, 12, 0)
sky_descr = fr.gen_perez_sky(date_time, latitude=37, longitude=122, timezone=120, dirnorm=800, diffhor=100)
aroom.oct
octree
to make a new octree file. Let's call the octree with our sky specific information,
'aroom_37_122_1221_1200.oct'.
room_sky_octree = f'aroom_37_122_1221_1200.oct'
with open(room_sky_octree, "wb") as f:
f.write(pr.oconv(stdin=sky_descr, octree=room_octree))
Get rays
We need send rays to the octree file we just created. In Radiance, rays are made of two vectors, one for the starting position and one for the direction the ray is heading. Essentially, we need six values to define our two vectors in cartesian corrdiantes. A ray positioned at x=0, y=0, z=0, pointing upwards is thus:
For this example, we're gonna simulate workplane illuminance. These are essentially virtual sensor positioned at table height pointing upwards, measuring how much light arrives at your table. To get a grid of such sensors, we can usegen_grid
utility
function, which need a polygon
, spacing
, and height
as
arguments. Spacing and height define the grid spacing and the distance
from the polygon from which the grid is based-one.
Since we are generating a grid of workplane sensors,
we can use our floor as the polygon. To get our floor polygon,
we can simply load in our floor_aroom.rad
file and parse
the polygon using the parse_polygon
function from the parsers
module.
The code block demonstrates how we generate a grid of sensors with
1 meter spacing and 0.75 meters away from the floor:
floor_primitives = fr.unpack_primitives("Objects/floor_aroom.rad")
# Since we only have one primitive in this file,
# we'll take the first one to parse.
floor_polygon = fr.parse_polygon(floor_primitives[0])
grid = fr.gen_grid(floor_polygon, 1, 0.75)
Let's trace
Finally, after all these preparation, we are ready to trace some rays. Let's first trace a single ray, and use the one of the grid sensors we had just created.
aray = " ".join(map(str, grid[0]))
option = ["-I+", "-ab", "1", "-ad", "64", "-aa", "0", "-lw", "0.01"]
result = pr.rtrace(aray.encode(), room_sky_octree, params=option)
result
, we will see the following:
Next, let's trace all of our grid sensors. Since our grid of sensors are a list of lists of floats, we need to process them a little bit before rtrace can take them.
rays = "\n".join([" ".join(map(str, row)) for row in grid])
results = pr.rtrace(rays.encode(), room_sky_octree, params=option, header=False)