Complete a tree inventory with GDAM allometry
You are viewing in-progress documentation for v2 (Beta). Switch to the stable version for the current production release.
Some inventories arrive thin: a
CHM inventory
carries only x, y, and height, and an
uploaded tree list
carries only what your file had. That’s enough to filter and mask, but not
enough to voxelize into 3D canopy fuel
or to run silvicultural treatments
— both need per-tree morphology (dbh, crown_ratio, fia_species_code).
GDAM (a Generalized Dendro Allometric Model) fills that gap. It takes a completed inventory and imputes the missing morphology columns from each tree’s position and height, writing a new inventory. Existing values are preserved; only missing columns are filled. This is the intended path from a CHM detection (or a coordinates-and-heights upload) to something a fire model can consume: CHM → allometry → voxelize.
Prerequisites
Section titled “Prerequisites”-
An API key: my-api-key.
-
A domain: your-domain-id. See Create a domain.
-
A completed source inventory that is missing morphology — most often a CHM inventory (
x,y,height). Record its id: inventory-to-complete.
The whole flow in one script:
import time
import requests
API_KEY = "my-api-key"DOMAIN_ID = "your-domain-id"# A completed inventory that carries x, y, height but is missing morphology —# e.g. one detected from a CHM, or a positions-and-heights upload.SOURCE_INVENTORY_ID = "inventory-to-complete"BASE = "https://api-v2-prod-nyvjyh5ywa-uw.a.run.app"HEADERS = {"api-key": API_KEY}
def poll(resource_id: str) -> dict: while True: r = requests.get( f"{BASE}/domains/{DOMAIN_ID}/inventories/{resource_id}", headers=HEADERS ).json() if r["status"] in ("completed", "failed"): return r time.sleep(5)
# Impute the missing dbh, crown_ratio, and fia_species_code from each tree's# position and height. Existing columns are preserved; only missing ones are# filled. Omit "impute_columns" to fill all three (the default).inv = requests.post( f"{BASE}/domains/{DOMAIN_ID}/inventories/tree/allometry/gdam", headers=HEADERS, json={ "name": "Tree inventory from GDAM allometry", "source_tree_inventory_id": SOURCE_INVENTORY_ID, },).json()inv = poll(inv["id"])print(inv["id"], inv["status"]) # -> <inventory id> completedprint([c["key"] for c in inv["columns"]]) # now includes dbh, crown_ratio, speciesCreate the GDAM inventory
Section titled “Create the GDAM inventory”POST to inventories/tree/allometry/gdam with source_tree_inventory_id
pointing at the inventory you want to complete. That’s the only required field —
by default GDAM imputes all three missing columns (dbh, crown_ratio,
fia_species_code).
curl -X 'POST' \ 'https://api-v2-prod-nyvjyh5ywa-uw.a.run.app/domains/your-domain-id/inventories/tree/allometry/gdam' \ -H 'accept: application/json' \ -H 'api-key: my-api-key' \ -H 'Content-Type: application/json' \ -d '{ "name": "Tree inventory from GDAM allometry", "source_tree_inventory_id": "inventory-to-complete"}'{ "id": "your-inventory-id", "domain_id": "your-domain-id", "type": "tree", "name": "Tree inventory from GDAM allometry", "description": "", "status": "pending", "progress": null, "created_on": "2026-07-09T16:03:32.854538Z", "modified_on": "2026-07-09T16:03:32.854538Z", "source": { "name": "gdam", "source_tree_inventory_id": "inventory-to-complete", "impute_columns": ["dbh", "crown_ratio", "fia_species_code"] }, "modifications": [], "columns": [ { "key": "x", "type": "continuous", "unit": "m" }, { "key": "y", "type": "continuous", "unit": "m" }, { "key": "height", "type": "continuous", "unit": "m" }, { "key": "dbh", "type": "continuous", "unit": "cm" }, { "key": "crown_ratio", "type": "continuous", "unit": null }, { "key": "fia_species_code", "type": "categorical", "unit": null } ], "georeference": null, "error": null, "tags": []}The 201 mints a new inventory id — record it: your-inventory-id. Poll
until completed:
curl -X 'GET' \ 'https://api-v2-prod-nyvjyh5ywa-uw.a.run.app/domains/your-domain-id/inventories/your-inventory-id' \ -H 'accept: application/json' \ -H 'api-key: my-api-key'{ "id": "your-inventory-id", "domain_id": "your-domain-id", "type": "tree", "name": "Tree inventory from GDAM allometry", "description": "", "status": "completed", "progress": { "percent": 100, "message": "Complete" }, "created_on": "2026-07-09T16:03:32.854538Z", "modified_on": "2026-07-09T16:03:46.012840Z", "source": { "name": "gdam", "source_tree_inventory_id": "inventory-to-complete", "impute_columns": ["dbh", "crown_ratio", "fia_species_code"] }, "modifications": [], "columns": [ { "key": "x", "type": "continuous", "unit": "m" }, { "key": "y", "type": "continuous", "unit": "m" }, { "key": "height", "type": "continuous", "unit": "m" }, { "key": "dbh", "type": "continuous", "unit": "cm" }, { "key": "crown_ratio", "type": "continuous", "unit": null }, { "key": "fia_species_code", "type": "categorical", "unit": null } ], "georeference": { "crs": "EPSG:32611", "bounds": [720226.0, 5189762.0, 721534.0, 5190646.0] }, "error": null, "tags": []}GDAM keeps every tree from the source — a CHM inventory of ≈9,200 treetops comes
back as ≈9,200 trees — and each row now carries x, y, height, plus the
imputed dbh (cm), crown_ratio, and fia_species_code.
Next steps
Section titled “Next steps”- Voxelize it — the completed inventory now has the columns 3D canopy fuel needs. Voxelize the inventory into a canopy bulk-density grid.
- Trim it — with
dbhin hand you can now run silvicultural treatments, or remove trees near roads or water. - Read the trees — fetch and stream the inventory data to inspect the imputed columns.
Common pitfalls
Section titled “Common pitfalls”- Source inventory not
completed. GDAM reads the source inventory’s data — poll it tocompletedbefore creating the allometry inventory. - Expecting
fia_status_code. GDAM imputesdbh,crown_ratio, andfia_species_code, but not tree status. That’s fine for voxelization — it treats a tree with nofia_status_codeas live. If your workflow needs an explicit live/dead status, it has to be present in the source inventory (an upload that includesfia_status_code, or a TreeMap inventory); neither GDAM nor voxelization adds it. - Imputed, not measured. GDAM predicts morphology from position and height; it does not observe it. The DBH, crown ratio, and species are statistical estimates for trees of that height in that place — good enough to build a plausible 3D canopy, not a substitute for measured stems. When you have real DBH or crown data, upload it rather than imputing it.
- Completing a TreeMap inventory. A TreeMap inventory already carries all seven columns, so it needs no allometry step — voxelize it directly. GDAM is for the sources that arrive thin (CHM, sparse uploads).