Skip to content

About inventories

You are viewing in-progress documentation for v2 (Beta). Switch to the stable version for the current production release.

An inventory is FastFuels’ discrete picture of fuel: a census of individual fuel elements over a domain — today, the trees — each recorded with its own location, size, and species. Where a grid is a continuous field (a fixed lattice of cells, each holding a value) and a layerset describes fuel statistically (a class of plants summarized by cover and density), an inventory names the elements one by one. It is the representation you reach for when an element is large and distinct enough that its individual height, size, and position matter — a single tree bends the wind, ladders a surface fire into the crowns, and casts shade, in ways an averaged fuel class cannot express.

This page is about the idea of an inventory: what it stores, why FastFuels represents fuel object-by-object at all, how the three ways of building a tree inventory differ, and how those per-tree records become the 3D fuel a fire model consumes. It is not a walk-through of any request — the five inventory how-to guides cover the procedures — and it does not re-teach the two topics that already have their own explanation pages: the algorithm internals of detecting trees from a canopy height model, and the rule syntax of modifications. Those sit beneath this page; here we stay with the concepts they assume.

Three ways to represent fuel — and where an inventory fits

Section titled “Three ways to represent fuel — and where an inventory fits”

A landscape’s fuel can be described in three complementary ways, and FastFuels uses all three:

  • As a continuous field — a grid, a raster where every cell carries a value (a surface-fuel load, a canopy bulk density). Good for properties that vary smoothly and are defined everywhere.
  • As a statistical group — a layerset, a way to describe fuels too numerous or too small to enumerate (grass, litter, dense shrub) by their cover, clumping, and bulk density rather than as individuals.
  • As discrete objects — an inventory, a list of the individual elements themselves, each with a location and physical dimensions.

An inventory is that third representation. You enumerate something when its individuality carries information the other two throw away — when this tree is 30 m tall and that gap beside it is empty, and the fire will care about both.

In the v2 API the inventory resource models trees, because trees are the fuel elements whose individual size, height, species, and arrangement matter most, and the ones FastFuels’ 3D machinery has the most to work with. But the idea is not limited to trees. Standing dead snags, downed coarse woody debris, and individual shrubs are all discrete fuel objects the same per-element census describes — forest inventories in the field record exactly these. Trees are simply where the resource begins. The continuous and statistical representations cover the rest of the fuelbed, and a complete fuel model is assembled from all three (see An inventory is one stratum).

A tree inventory, concretely, is a table — one row per stem:

ColumnUnitWhat it is
x, ymthe tree’s position in the domain’s projected CRS
heightmtotal tree height
dbhcmdiameter at breast height
crown_ratiofraction of the height that is live crown (0–1)
fia_species_codethe tree’s FIA species code (categorical)
fia_status_codeFIA status — 1 is live, the rest dead/removed

This seven-column set is the inventory’s full vocabulary. Not every inventory carries all of it — which columns are present depends on the source, and that turns out to be the most consequential thing about a tree inventory (see The columns you have gate what you can do). Because each row is an independent point in the domain’s CRS, an inventory can be edited at the level of individual stems — a tree can be dropped, shrunk, or thinned out of the list in a way a grid cell never can, since a cell always exists at its place in the lattice.

Why enumerate trees in 3D: structure, not just fuel load

Section titled “Why enumerate trees in 3D: structure, not just fuel load”

It is tempting to think of vegetation as fuel — combustible mass that a fire consumes — and to reason about fire from how much of it there is. That view is incomplete, and the gap is the reason FastFuels exists. Vegetation also shapes the physical environment the fire burns in, and it does so through its three-dimensional structure, not its mass alone.

FastFuels produces fuel inputs for physics-based fire models — QUIC-Fire, FIRETEC, FDS. Unlike the quasi-empirical surface-spread models behind most fire software, these simulate the fire, the wind, and the atmosphere together, without assuming the fuel is homogeneous, and they require the fuel described as a 3D lattice of voxels — each carrying a bulk density, a moisture, a surface-area-to-volume ratio. The reason they need that resolution is physical:

  • The canopy reshapes the wind. A stand of trees is a porous obstacle that absorbs momentum from the wind — fast above the canopy, slowed and stirred within it. The shear at the canopy top spins up intermittent gusts that punch down into the stand and carry heat to unburned fuel, which is why fire spread through a forest is bursty rather than steady. How strong these effects are depends on where the foliage sits — its density and vertical arrangement — which is exactly what a per-tree inventory of crowns encodes.
  • Structure sets microclimate and continuity. The canopy shades the surface, shelters it from drying winds, and breaks the fuel into connected patches and gaps. The empty space between crowns matters as much as the crowns themselves; both govern where a fire can carry and where it stalls.
  • Crown fire is a structural threshold. A surface fire climbs into the crowns (torching) only when the gap to the live canopy — the canopy base height — is small enough, and a crown fire sustains itself running tree to tree only when the canopy is dense enough (its canopy bulk density high enough). Both are facts about vertical structure, not total fuel.

An averaged fuel-type class — a single label standing in for a whole stand — collapses all of this. Representing each tree as a discrete 3D object keeps it, because the individual crowns, their heights, and the gaps between them are the structure the wind and the fire respond to. That is the case for an inventory: it is the form of fuel data fine-grained enough to feed a model that treats fire and vegetation as a coupled physical system.

The three sources: modeled, observed, or your own

Section titled “The three sources: modeled, observed, or your own”

How you get a tree inventory is the first real decision, and there are three primary ways — distinguished less by mechanics than by what kind of truth they give you.

SourceWhat it isAttributesThe trade-off
TreeMap / PIMa statistical expansion of FIA forest plots over your domainfull (all seven columns)modeled but complete
CHMdirect detection of crowns from a canopy-height surfacex, y, height onlyobserved but thin
Uploadtree records you bring yourself (CSV, GeoJSON, or GeoPackage)whatever your file hasyour own data

TreeMap (via PIM expansion) is modeled but complete. A TreeMap inventory starts from a PIM grid — a raster that maps each 30 m cell to the best-matching real FIA forest plot. The expansion (an inhomogeneous Poisson point process) scatters that plot’s actual measured trees across the cell, preserving its species mix and size distribution. The result carries the full attribute set — species, DBH, crown ratio — because it is built from real, fully-measured plots. The catch is in the word matching: these are the trees of a stand statistically like yours, not the specific trees on your ground. Because it draws from complete plot tree lists, it includes the smaller and sub-canopy stems a remote sensor never sees, so its counts run higher than a crown-detection method’s.

A CHM is observed but thin. A CHM inventory is detected directly from a canopy height model — a raster of vegetation-top height — by finding the local maxima that mark treetops. These are your actual overstory crowns, where they really stand. But a surface seen from above only ever observed the top of the canopy, so a CHM tree carries x, y, and height and nothing else: no species, no diameter, no crown ratio, and no record of the sub-canopy hidden beneath the dominant crowns. (How the detection works, and the over- versus under-detection you tune, are the subject of How tree detection from a CHM works.)

An upload is your own data. If you already have a tree list — from field plots, a TLS scan, another model — you can upload it as a CSV, GeoJSON, or GeoPackage and map your columns onto the v2 names. You must supply at least x, y, and height; everything else is optional. This is maximum control — the inventory is exactly the trees you provide — at the cost of producing and preparing the data yourself.

The through-line is the trade-off in the last column: observed-but-thin (the real canopy surface, but only its geometry), modeled-but-complete (every attribute, but from a model of a stand like yours), and your-own (exactly your trees, and the responsibility for them). Which one is right depends on what your simulation needs, not on which is “best.”

There is a fourth way to get an inventory, but it is not a fourth way to find trees — it is a way to complete trees you already have. GDAM (a Generalized Dendro Allometric Model) takes a completed inventory and imputes the morphology a thin source left blank: dbh, crown_ratio, and fia_species_code, predicted from each tree’s position and height. It is the natural next step after a CHM detection or a coordinates-and-heights upload — it turns an x, y, height point list into a full one. Existing values are preserved; only the missing cells are filled. GDAM is why “thin” need not be a dead end: a CHM inventory that cannot be treated or voxelized on its own becomes one that can, once its missing columns are imputed.

The seven-column table is not just a description — it is a contract. The same set of columns is what the source writes and what the consumers (treatments, voxelization) require, and a column that isn’t there closes off everything downstream that needed it. This is the most practical consequence of choosing a source:

CapabilityNeedsAvailable on…
Position, height filtersx, y, heightevery inventory
Silvicultural treatmentsdbhTreeMap, upload-with-DBH; not CHM
Voxelization into a 3D griddbh, crown_ratio, species, statusTreeMap, full uploads; not raw CHM

A TreeMap inventory carries the full set, so it can be treated and voxelized directly. A raw CHM inventory carries only geometry, so it can be filtered and masked but cannot be thinned (there is no diameter to thin against) and cannot be voxelized (there is no crown to build) until something supplies the missing attributes — which is exactly what GDAM is for. The field-by-field specification of each column lives in the API reference; the point here is conceptual: pick the source that carries the columns your downstream steps will demand.

Editing the stand: modifications and treatments

Section titled “Editing the stand: modifications and treatments”

Once you have trees, you often want to change them — drop the ones inside a road corridor, or thin a stand to a management target. The v2 API expresses these as two kinds of rule, and both share an important property: they are stored on the inventory and replayed whenever it is built, so the inventory is the deterministic product of its source plus its rules. Rules can be supplied when the inventory is created, or applied to one you already hold (which appends them to the inventory’s running list and re-derives the data).

ModificationsTreatments
Select byan attribute, an expression, or a spatial shapea target metric (diameter limit or basal area)
Thentransform a column, or remove the treesthin stems toward the target
Modelsarbitrary per-tree editssilvicultural management
Needs dbh?noyes — so not available on a CHM inventory

Modifications are general-purpose: a rule selects trees by condition — an attribute test (height > 30), a multi-field expression, or a spatial predicate against a feature or inline geometry — and then transforms an attribute or removes the matching trees. Pruning small stems, or removing the trees standing in a lake, are modifications. The full rule vocabulary is the subject of About modifications; this page does not re-teach it.

Treatments model real forestry. A treatment thins a stand toward a target — a diameter limit or a residual basal area — using a method that decides which stems go first: from_below (smallest first), from_above (largest first), or proportional (across all diameter classes). This is the language of fuel-reduction silviculture, and the reason it lives in FastFuels is the chain silviculture → fuel structure → fire behavior: thinning is how managers change the 3D structure of a stand, and an inventory treatment lets you make that change and then simulate its effect on fire. The classic principles show why the method matters, not just the amount removed:

  • Thinning from below removes the small understory stems that ladder a surface fire up into the crowns. That raises the canopy base height, so a longer surface flame is needed before the stand can torch — it attacks crown fire initiation.
  • Reducing the overstory’s canopy bulk density makes a running crown fire less able to sustain itself tree to tree — it attacks crown fire spread. But taking the largest trees (from_above) also removes the most fire-resistant stems, which is the opposite of what fire-resilient management wants.

Because every target is defined on tree diameter, a treatment needs a dbh column, so it cannot run on a raw CHM inventory — the API rejects the attempt rather than guessing a diameter. And a caveat worth holding onto: thinning the trees is only part of the story. Opening a canopy also changes the sub-canopy wind and the surface fuels (thinning can leave slash behind and let the surface dry and gust) — consequences that live in other parts of the fuelbed and in the fire model, not in the tree inventory. The inventory treatment models the stand change; seeing its full fire-behavior effect means voxelizing it and pairing it with the surface layer.

A fire model does not run on a list of points; it runs on a 3D grid of fuel. Voxelization crosses that gap — it turns the inventory’s stems into a regular lattice of cells, each holding a canopy fuel property such as bulk density (bulk_density.foliage.live, in kg/m**3; only the fine canopy material, the foliage, actually carries fire). Understanding it explains the attribute requirements from the other side. For each tree, voxelization:

  1. Shapes the crown. From a tree’s dbh, crown_ratio, species, and height, a crown profile model (Purves or Beta) computes the solid the foliage occupies — its maximum radius, where the live crown starts, and how the radius tapers to the top.
  2. Discretizes it. That crown solid is cut into the voxel grid: each cell gets the fraction of its volume the crown fills, then a stochastic step thins the solid into a more realistic, porous canopy.
  3. Fills it with mass. The tree’s foliage biomass — estimated from dbh, height, and species by an allometric model — is spread across the occupied cells, giving each a bulk density.
  4. Accumulates. Where crowns overlap, their bulk densities add, producing a continuous 3D canopy over the whole domain.

This is why a raw CHM inventory cannot be voxelized directly. Height alone fixes only where a crown’s top is; building the crown solid needs dbh and crown_ratio, and filling it with mass needs dbh and species. With those columns absent, there is no crown to discretize and no biomass to distribute, so the trees fall out. A CHM inventory has to be enriched first (with GDAM, or by supplying measured crown sizes) — the same DBH dependency that blocks treatments, seen from the voxelization side.

An inventory is one stratum, not the whole fuelbed

Section titled “An inventory is one stratum, not the whole fuelbed”

This is the conceptual point worth holding onto above the others: an inventory is the tree layer of the fuelbed, not the entire fuelbed. A complete fuel model has structure from the ground up — a surface stratum (grass, litter, downed wood), a mid-level of shrubs and ladder fuels, and the tree canopy overhead. An inventory models the trees: the canopy, and the woody part of the ladder. It says nothing about the grass and litter that carry a surface fire along the ground, which come from the other representations — a layerset, or a surface-fuel grid.

Two layers of incompleteness stack here. Across strata, the trees are one part of the fuelbed and must be combined with a surface and sub-canopy layer to make a fire model’s full input. And within the trees, a CHM inventory captures only the dominant overstory — a detected crown is best read as the canopy-dominant tree plus whatever it hides, so subordinate, sub-canopy stems are systematically missed. A TreeMap or uploaded inventory can include the smaller stems, but it is still only the trees.

Lifecycle, reproducibility, and reading the data

Section titled “Lifecycle, reproducibility, and reading the data”

Generating an inventory is asynchronous. A create call returns immediately with status: "pending", and the inventory walks pending → running → completed (or failed). Its georeference — the CRS and bounding box — is empty until the job lands on completed; only then is the tree data readable. (An upload is two steps: the create call hands back a signed URL you PUT the file to, and the server processes it once it arrives.)

Reproducibility is built into the resource. An inventory stores a checksum — a version marker that changes every time the data is rebuilt and is untouched by metadata-only edits — so a resource derived from an inventory can record the checksum it was built from and later detect whether its source has changed. For the one source with a random element, the TreeMap point-process expansion, a seed pins the randomness: the same grid, point process, and seed always produce the same trees. Source plus rules plus seed is a complete, replayable recipe.

Reading the data is paged, because an inventory can hold a great many trees. data/metadata returns the shape of the dataset — the total row count, the column names, and how the rows are split into partitions — without downloading any trees, and data/{partition_index} returns one partition’s rows (as JSON or CSV). You stream the whole inventory by reading metadata for the partition count and then looping over the partitions. The coordinates are in the domain’s CRS, recorded in the inventory’s georeference.

Two whole-resource operations round this out. Duplicate makes an independent, byte-for-byte copy of a completed inventory under a new id — a true clone, not a re-derivation — carrying over its source, rules, columns, and checksum verbatim. Export packages the trees into a downloadable file (Parquet, CSV, GeoJSON, or GeoPackage) for use outside the API.

An inventory belongs to exactly one domain and inherits its CRS and extent; every tree’s coordinates are in that frame, and an inventory can only reference resources in its own domain. Its connections to the rest of v2:

  • Grids are both the source and the destination. A TreeMap inventory is expanded from a PIM grid and a CHM inventory is detected from a CHM grid, so for those sources a grid is where the trees come from (and the inventory records the source grid’s checksum to detect staleness). Voxelization then sends the inventory the other way, into a 3D canopy fuel grid.
  • Features remove trees. A feature — a road, a water body — can be referenced by a modification’s spatial condition to drop the trees that fall inside it. Removing trees from a point set is the inventory-side counterpart to masking a grid’s cells.
  • Layersets and surface-fuel grids complete the fuelbed. The strata an inventory does not model — surface grass and litter, statistical shrub — come from layersets and surface-fuel grids, and are stacked with the voxelized canopy into a single 3D fuelbed.
  • GDAM derives one inventory from another, imputing the morphology a thin source left out.
  • Exports package the result — most often the voxelized canopy stacked with the surface and topography grids that make a fire model’s input.

The thread, as everywhere in v2: the domain is the unit of geographic scope, and an inventory is the discrete, per-tree layer of fuel measured within it.

The procedures that put all of this to work are the five inventory how-to guides:

The two explanation pages that sit beneath this one go deeper on the topics it only summarizes:

And About domains is the spatial frame an inventory attaches to. Companion explanation pages for Grids and Point Clouds — the rasters an inventory comes from and a future detection source — build on the same resource model.