# The bill of quantities definition, on the Grasshopper canvas

AT6012 Design Research: Technology Transformations
Cork Centre for Architectural Education, University College Cork
30 August 2026

The definition that reads a timber model as a demand on a forest. It takes the
members you have already drawn, computes their volumes, maps each to a building
group, and reports which ecological groups the specification pulls on.

## Read this first

**No `.gh` file ships, for the reason given in the Ladybug submodule: a
Grasshopper definition is a binary file written by Rhino and nothing here can
author one.** What ships instead is the component sequence below plus
`scripts/boq_to_forest.py`, which is real Python that runs in two places. Paste
it into a Python 3 Script component in Rhino 8 and it works on the canvas.
Run it in a terminal and it works on a CSV. Same code, same answer.

Run the terminal version first so you have a number before you have a canvas.

```
cd scripts
python boq_to_forest.py ../data/example_boq.csv
```

The example is 48.8 m3 across nine members, and it reaches 5 of 7 building
groups while pulling on 6 of 7 ecological groups. Those are your targets.

## What to install

| | |
|---|---|
| Rhino 8 | The Python 3 Script component is built in. Rhino 7 works too, through GhPython, with the note below |
| Nothing else | The script uses only the Python standard library. No Ladybug, no plugins, no internet |

**Rhino 7 note.** GhPython runs IronPython 2.7. The script avoids f-strings in
the parts the canvas needs, but if you hit a syntax error on Rhino 7, run the
terminal version and type the volumes in. The analysis is the point.

## Definition 1. Volumes off the model

This is the half Grasshopper does well. The quantities come off the geometry,
so they update when the design changes.

| Step | Component | Wiring |
|---|---|---|
| 1 | `Brep` parameter, set to multiple | Right-click, Set Multiple Breps, pick your timber members in Rhino |
| 2 | `Volume` | `G` from the Brep parameter. The `V` output is the volume of each |
| 3 | `Text` parameter, set to multiple | One species per member, in the same order. `Picea glauca`, `Acer saccharum` and so on |
| 4 | `Panel` | On the `V` output, to check the units before anything else |

**Check the units before you go further.** `Volume` returns model units cubed.
If Rhino is set to millimetres, a glulam column reads as 4,200,000,000 rather
than 4.2, and every number after it is wrong by a factor of a billion. Set the
document to metres, or divide by 1e9 with a `Division` component and say in your
dossier that you did.

**Keeping species and members in the same order** is the fiddly part. The
reliable method is one Brep parameter per species: five species means five
Brep parameters and five text values, then `Merge` both streams in the same
order. Trying to hold thirty mixed members in one list and remember which is
which is where this goes wrong.

## Definition 2. The demand

| Step | Component | Wiring |
|---|---|---|
| 1 | `Python 3 Script` | Rhino 8: right-click the canvas, Maths > Script, then choose Python 3 |
| 2 | Paste `scripts/boq_to_forest.py` | The whole file, unedited |
| 3 | Add input `species` | Zoom in, click the + on the input side. Name it `species`, set Type hint to `str`, set Access to List |
| 4 | Add input `volume` | Name it `volume`, Type hint `float`, Access List |
| 5 | Add outputs | `report`, `bg_demand`, `eg_demand`, `bg_labels`, `eg_labels` |
| 6 | Wire | Species text into `species`, the `V` output into `volume` |
| 7 | `Panel` | On `report`. This is the reading |

The script detects the canvas by looking for those two input names in its own
globals, so the same file behaves as a library in a terminal and as a component
here.

## Definition 3. Seeing it

The report is text. Two components turn it into something you can put in a
dossier.

| Step | Component | Wiring |
|---|---|---|
| 1 | `Quick Graph` | `bg_demand` into `Y`. Seven bars, one per building group |
| 2 | `Text Tag 3D` | `bg_labels` as `T`, a point series as `L`, so the bars are named |

The bar chart is the argument. A specification whose bars are two tall columns
at BG1 and BG2 with nothing else is the industrial pull the paper describes,
drawn.

## Reading the answer

The example bill comes back at **90.4% of its volume in BG1 and BG2**, which are
the two conifer groups. That is what a typical mass-timber specification looks
like, and it is the finding the example exists to show: spruce, fir and pine
carry almost all structural timber, so almost all the demand lands on `CON-Bor`
and `CON-Pin`.

Two things follow, and both belong in your dossier.

**A narrow pull works against diversification.** A forest managed to supply
BG1 and BG2 is a forest managed for a handful of conifers, which is the
composition the FDN scenarios are trying to move away from. So the
specification is not a neutral downstream consequence of the forest. It is one
of the forces shaping it, and that is the paper's argument.

**A wide pull is not automatically the better answer.** Spreading demand across
seven building groups only helps if the forest can meet it, at the volumes you
need, within a distance that makes sense. The spread tells you which question to
put to the forest. It is not a score, and the script says so on every run for
that reason.

## Where to take it

Put your own model through it, then open `qgis/` and look at where the supply
actually is. The derived layer counts how many building groups each hectare of
the study landscape could supply, and **337 cells out of 1,649,532 can supply
all seven**. A specification that reaches seven groups is asking for something
that exists on 337 hectares of a 136 by 121 km landscape.

That gap between what a drawing asks for and what a territory holds is the whole
exercise.

## Sources

Osborne, P., Aquilué, N., Mina, M., Moe, K., Jemtrud, M., and Messier, C.
(2023). A trait-based approach to both forestry and timber building can
synchronize forest harvest and resilience. *PNAS Nexus*, 2(8), pgad254.
https://doi.org/10.1093/pnasnexus/pgad254

Verified at Crossref on 30 August 2026: *PNAS Nexus* 2(8), six authors, issue
August 2023. Open access, and Tables 1 and 2 were read from the full text.

Supporting data: https://doi.org/10.5281/zenodo.8184010 The deposit asks that
anyone using it for a research study or project contacts Peter Osborne.
