Compose grids
You are viewing in-progress documentation for v2 (Beta). Switch to the stable version for the current production release.
POST /domains/{domain_id}/grids/compose creates a grid whose bands are copied
or computed from the bands of existing grids.
For how grids share a lattice, see
Resolution, alignment, and snapping.
Prerequisites
Section titled “Prerequisites”-
An API key: my-api-key.
-
A domain: your-domain-id. See Create a domain.
-
Completed 2D input grids on one lattice — same CRS, origin, cell size, and shape. The recipes use three grids from Build surface fuel grids from LANDFIRE:
- an FBFM40 grid with the
fbfmband: your-fbfm40-grid-id; - its FBFM40 lookup grid with
fuel_load.1hr,fuel_load.10hr,fuel_load.100hr,fuel_load.live_herb,fuel_load.live_woody, andfuel_depth: your-lookup-grid-id; - an FCCS lookup grid with
fuel_load.litter,fuel_load.1hr,fuel_load.10hr, andfuel_load.live_herb: your-fccs-lookup-grid-id. List all four in the lookup request’sbands.
To put a grid on another grid’s lattice, resample it.
- an FBFM40 grid with the
-
Optional — a completed road feature in the same domain, for Restrict an operation to a feature: your-road-feature-id. See Create road and water features from OpenStreetMap.
Copy bands into a new grid
Section titled “Copy bands into a new grid”To copy bands, list each input grid in inputs with an alias, then add one
select operation per output band. from names the source band as
alias.band_key; output names the new band. An alias starts with a letter
and contains only letters, digits, and underscores. Each input is a different
grid with its own alias.
curl -X 'POST' \ 'https://api-v2-prod-nyvjyh5ywa-uw.a.run.app/domains/your-domain-id/grids/compose' \ -H 'accept: application/json' \ -H 'api-key: my-api-key' \ -H 'Content-Type: application/json' \ -d '{ "name": "Selected surface bands", "inputs": [ { "grid_id": "your-fbfm40-grid-id", "alias": "codes" }, { "grid_id": "your-lookup-grid-id", "alias": "fbfm40" }, { "grid_id": "your-fccs-lookup-grid-id", "alias": "fccs" } ], "operations": [ { "type": "select", "output": "fbfm", "from": "codes.fbfm" }, { "type": "select", "output": "fuel_depth", "from": "fbfm40.fuel_depth" }, { "type": "select", "output": "fuel_load.1hr", "from": "fbfm40.fuel_load.1hr" }, { "type": "select", "output": "fuel_load.litter", "from": "fccs.fuel_load.litter" } ]}'import fastfuels_sdk.v2 as ff
ff.set_api_key("my-api-key")
codes = ff.get_grid("your-domain-id", "your-fbfm40-grid-id")fbfm40 = ff.get_grid("your-domain-id", "your-lookup-grid-id")fccs = ff.get_grid("your-domain-id", "your-fccs-lookup-grid-id")
grid = ff.grids.create_grid_from_compose( {"codes": codes, "fbfm40": fbfm40, "fccs": fccs}, operations=[ ff.compose.select("fbfm", "codes.fbfm"), ff.compose.select("fuel_depth", "fbfm40.fuel_depth"), ff.compose.select("fuel_load.1hr", "fbfm40.fuel_load.1hr"), ff.compose.select("fuel_load.litter", "fccs.fuel_load.litter"), ], name="Selected surface bands",){ "id": "your-grid-id", "domain_id": "your-domain-id", "name": "Selected surface bands", "description": "", "status": "pending", "progress": null, "created_on": "2026-10-16T20:58:34.799807", "modified_on": "2026-10-16T20:58:34.799807", "checksum": "a99d96c59b864dc681a7d9bc6ac7575b", "source": { "name": "compose", "inputs": [ { "grid_id": "your-fbfm40-grid-id", "alias": "codes", "source_grid_checksum": "9108d05ae9574c32acf72acd09eed001" }, { "grid_id": "your-lookup-grid-id", "alias": "fbfm40", "source_grid_checksum": "fc406cea560c4a50bd5a2d7509fa1b59" }, { "grid_id": "your-fccs-lookup-grid-id", "alias": "fccs", "source_grid_checksum": "11aabe8aec4a42789cbac050c2c76a41" } ], "bands": [ { "key": "fbfm", "name": null, "description": null, "type": "categorical", "unit": null, "index": 0, "nodata": null, "summary": null }, { "key": "fuel_depth", "name": null, "description": null, "type": "continuous", "unit": "m", "index": 1, "nodata": null, "summary": null }, { "key": "fuel_load.1hr", "name": null, "description": null, "type": "continuous", "unit": "kg/m**2", "index": 2, "nodata": null, "summary": null }, { "key": "fuel_load.litter", "name": null, "description": null, "type": "continuous", "unit": "kg/m**2", "index": 3, "nodata": null, "summary": null } ], "operations": [ { "type": "select", "output": "fbfm", "from": "codes.fbfm" }, { "type": "select", "output": "fuel_depth", "from": "fbfm40.fuel_depth" }, { "type": "select", "output": "fuel_load.1hr", "from": "fbfm40.fuel_load.1hr" }, { "type": "select", "output": "fuel_load.litter", "from": "fccs.fuel_load.litter" } ] }, "modifications": [], "bands": [ { "key": "fbfm", "name": null, "description": null, "type": "categorical", "unit": null, "index": 0, "nodata": null, "summary": null }, { "key": "fuel_depth", "name": null, "description": null, "type": "continuous", "unit": "m", "index": 1, "nodata": null, "summary": null }, { "key": "fuel_load.1hr", "name": null, "description": null, "type": "continuous", "unit": "kg/m**2", "index": 2, "nodata": null, "summary": null }, { "key": "fuel_load.litter", "name": null, "description": null, "type": "continuous", "unit": "kg/m**2", "index": 3, "nodata": null, "summary": null } ], "georeference": null, "error": null, "chunks": { "shape": [512, 512], "count": null, "count_by_axis": null }, "tags": []}Record the new grid id: your-grid-id.
- Output bands follow the order of
operations. - A selected band keeps the type and unit of its source band.
outputis a band key: a quantity such asfuel_load,fuel_depth,bulk_density, orfbfm, optionally followed by one or more.labelparts, as infuel_load.1hrorfuel_moisture.live.shrub. The quantity sets the band’s type and unit, so it must match the band you select.- Each
outputappears once per request.
Poll to completion
Section titled “Poll to completion”curl -X 'GET' \ 'https://api-v2-prod-nyvjyh5ywa-uw.a.run.app/domains/your-domain-id/grids/your-grid-id' \ -H 'accept: application/json' \ -H 'api-key: my-api-key'grid.wait(){ "id": "your-grid-id", "domain_id": "your-domain-id", "name": "Selected surface bands", "description": "", "status": "completed", "progress": { "percent": 100, "message": "Complete" }, "created_on": "2026-10-16T20:58:34.799807Z", "modified_on": "2026-10-16T20:58:38.246437Z", "checksum": "a99d96c59b864dc681a7d9bc6ac7575b", "source": { "operations": [ { "type": "select", "from": "codes.fbfm", "output": "fbfm" }, { "type": "select", "from": "fbfm40.fuel_depth", "output": "fuel_depth" }, { "type": "select", "from": "fbfm40.fuel_load.1hr", "output": "fuel_load.1hr" }, { "type": "select", "from": "fccs.fuel_load.litter", "output": "fuel_load.litter" } ], "bands": [ { "unit": null, "nodata": null, "type": "categorical", "description": null, "name": null, "summary": null, "index": 0, "key": "fbfm" }, { "unit": "m", "nodata": null, "type": "continuous", "description": null, "name": null, "summary": null, "index": 1, "key": "fuel_depth" }, { "unit": "kg/m**2", "nodata": null, "type": "continuous", "description": null, "name": null, "summary": null, "index": 2, "key": "fuel_load.1hr" }, { "unit": "kg/m**2", "nodata": null, "type": "continuous", "description": null, "name": null, "summary": null, "index": 3, "key": "fuel_load.litter" } ], "name": "compose", "inputs": [ { "grid_id": "your-fbfm40-grid-id", "source_grid_checksum": "9108d05ae9574c32acf72acd09eed001", "alias": "codes" }, { "grid_id": "your-lookup-grid-id", "source_grid_checksum": "fc406cea560c4a50bd5a2d7509fa1b59", "alias": "fbfm40" }, { "grid_id": "your-fccs-lookup-grid-id", "source_grid_checksum": "11aabe8aec4a42789cbac050c2c76a41", "alias": "fccs" } ] }, "modifications": [], "bands": [ { "key": "fbfm", "name": null, "description": null, "type": "categorical", "unit": null, "index": 0, "nodata": 32767, "summary": { "type": "categorical", "count": 1350, "nodata_count": 0, "unique_count": 9 } }, { "key": "fuel_depth", "name": null, "description": null, "type": "continuous", "unit": "m", "index": 1, "nodata": null, "summary": { "type": "continuous", "count": 1350, "nodata_count": 0, "min": 0.0, "max": 0.6096000075340271, "mean": 0.3284840874760239, "std": 0.1410640435394784 } }, { "key": "fuel_load.1hr", "name": null, "description": null, "type": "continuous", "unit": "kg/m**2", "index": 2, "nodata": null, "summary": { "type": "continuous", "count": 1350, "nodata_count": 0, "min": 0.0, "max": 1.3001821041107178, "mean": 0.3080750756200265, "std": 0.4163060013339203 } }, { "key": "fuel_load.litter", "name": null, "description": null, "type": "continuous", "unit": "kg/m**2", "index": 3, "nodata": null, "summary": { "type": "continuous", "count": 1350, "nodata_count": 0, "min": 0.0, "max": 0.5088643431663513, "mean": 0.2847216115778105, "std": 0.14141084268679605 } } ], "georeference": { "crs": "EPSG:32611", "transform": [ 29.438767164252283, 0.0, 720227.9398802927, 0.0, -29.438767164262632, 5190646.487014395 ], "shape": [30, 45] }, "error": null, "chunks": { "shape": [512, 512], "count": 1, "count_by_axis": { "x": 1, "y": 1 } }, "tags": []}Compute a band from other bands
Section titled “Compute a band from other bands”To compute a band, add a compute operation with an operator and a list of
operands. Here each cell takes the larger of the FBFM40 and FCCS 1-hour loads.
curl -X 'POST' \ 'https://api-v2-prod-nyvjyh5ywa-uw.a.run.app/domains/your-domain-id/grids/compose' \ -H 'accept: application/json' \ -H 'api-key: my-api-key' \ -H 'Content-Type: application/json' \ -d '{ "name": "Larger 1-hr load of FBFM40 and FCCS", "inputs": [ { "grid_id": "your-lookup-grid-id", "alias": "fbfm40" }, { "grid_id": "your-fccs-lookup-grid-id", "alias": "fccs" } ], "operations": [ { "type": "compute", "output": "fuel_load.1hr", "operator": "max", "operands": [ "fbfm40.fuel_load.1hr", "fccs.fuel_load.1hr" ] } ]}'import fastfuels_sdk.v2 as ff
ff.set_api_key("my-api-key")
fbfm40 = ff.get_grid("your-domain-id", "your-lookup-grid-id")fccs = ff.get_grid("your-domain-id", "your-fccs-lookup-grid-id")
grid = ff.grids.create_grid_from_compose( {"fbfm40": fbfm40, "fccs": fccs}, operations=[ ff.compose.compute( "fuel_load.1hr", "max", ["fbfm40.fuel_load.1hr", "fccs.fuel_load.1hr"] ), ], name="Larger 1-hr load of FBFM40 and FCCS",){ "id": "your-grid-id", "domain_id": "your-domain-id", "name": "Larger 1-hr load of FBFM40 and FCCS", "description": "", "status": "pending", "progress": null, "created_on": "2026-10-16T20:58:35.164403", "modified_on": "2026-10-16T20:58:35.164403", "checksum": "f13f4b5324a74e5b944302e962592021", "source": { "name": "compose", "inputs": [ { "grid_id": "your-lookup-grid-id", "alias": "fbfm40", "source_grid_checksum": "fc406cea560c4a50bd5a2d7509fa1b59" }, { "grid_id": "your-fccs-lookup-grid-id", "alias": "fccs", "source_grid_checksum": "11aabe8aec4a42789cbac050c2c76a41" } ], "bands": [ { "key": "fuel_load.1hr", "name": null, "description": null, "type": "continuous", "unit": "kg/m**2", "index": 0, "nodata": null, "summary": null } ], "operations": [ { "operator": "max", "operands": ["fbfm40.fuel_load.1hr", "fccs.fuel_load.1hr"], "type": "compute", "output": "fuel_load.1hr" } ] }, "modifications": [], "bands": [ { "key": "fuel_load.1hr", "name": null, "description": null, "type": "continuous", "unit": "kg/m**2", "index": 0, "nodata": null, "summary": null } ], "georeference": null, "error": null, "chunks": { "shape": [512, 512], "count": null, "count_by_axis": null }, "tags": []}operator | Operands | Output unit |
|---|---|---|
add, average, min, max | two or more | the first band operand’s unit |
subtract | exactly two | the first band operand’s unit |
multiply | two or more | the product of the operand units |
divide | exactly two | the quotient of the operand units |
- Operands are band references, numbers, or typed literals; at least one is a band reference.
- Band operands must be continuous. For
add,subtract,average,min, andmax, their units must be compatible; values are converted to the output unit. - A compute output is continuous, and its unit must be the unit of the
outputkey’s quantity. - Where the operation’s conditions hold, a cell that is nodata in any band operand is nodata in the output.
Scale a band by a number
Section titled “Scale a band by a number”To multiply or divide by a constant, pass a bare number as an operand. In
multiply and divide, a bare number is unitless. In add, subtract,
average, min, and max, a bare number is taken in the output unit; a
typed literal there needs a unit, or the request returns 422.
curl -X 'POST' \ 'https://api-v2-prod-nyvjyh5ywa-uw.a.run.app/domains/your-domain-id/grids/compose' \ -H 'accept: application/json' \ -H 'api-key: my-api-key' \ -H 'Content-Type: application/json' \ -d '{ "name": "Half 1-hr load", "inputs": [ { "grid_id": "your-lookup-grid-id", "alias": "fbfm40" } ], "operations": [ { "type": "compute", "output": "fuel_load.1hr", "operator": "multiply", "operands": [ "fbfm40.fuel_load.1hr", 0.5 ] } ]}'import fastfuels_sdk.v2 as ff
ff.set_api_key("my-api-key")
fbfm40 = ff.get_grid("your-domain-id", "your-lookup-grid-id")
grid = ff.grids.create_grid_from_compose( {"fbfm40": fbfm40}, operations=[ ff.compose.compute("fuel_load.1hr", "multiply", ["fbfm40.fuel_load.1hr", 0.5]), ], name="Half 1-hr load",){ "id": "your-grid-id", "domain_id": "your-domain-id", "name": "Half 1-hr load", "description": "", "status": "pending", "progress": null, "created_on": "2026-10-16T20:58:35.477035", "modified_on": "2026-10-16T20:58:35.477035", "checksum": "c7698cb736d3445ca2760df5c7902d44", "source": { "name": "compose", "inputs": [ { "grid_id": "your-lookup-grid-id", "alias": "fbfm40", "source_grid_checksum": "fc406cea560c4a50bd5a2d7509fa1b59" } ], "bands": [ { "key": "fuel_load.1hr", "name": null, "description": null, "type": "continuous", "unit": "kg/m**2", "index": 0, "nodata": null, "summary": null } ], "operations": [ { "operator": "multiply", "operands": ["fbfm40.fuel_load.1hr", 0.5], "type": "compute", "output": "fuel_load.1hr" } ] }, "modifications": [], "bands": [ { "key": "fuel_load.1hr", "name": null, "description": null, "type": "continuous", "unit": "kg/m**2", "index": 0, "nodata": null, "summary": null } ], "georeference": null, "error": null, "chunks": { "shape": [512, 512], "count": null, "count_by_axis": null }, "tags": []}Use a constant with a unit
Section titled “Use a constant with a unit”To give a constant a unit, pass a typed literal:
{"type": "literal", "value": 50, "unit": "g/m**2"}. The value is converted
to the output unit, so this adds 0.05 kg/m**2 to every cell. Units are
UDUNITS-2 strings with ** exponents, such as kg/m**2, kg/m**3, m,
and %.
curl -X 'POST' \ 'https://api-v2-prod-nyvjyh5ywa-uw.a.run.app/domains/your-domain-id/grids/compose' \ -H 'accept: application/json' \ -H 'api-key: my-api-key' \ -H 'Content-Type: application/json' \ -d '{ "name": "1-hr load plus 50 g/m**2", "inputs": [ { "grid_id": "your-lookup-grid-id", "alias": "fbfm40" } ], "operations": [ { "type": "compute", "output": "fuel_load.1hr", "operator": "add", "operands": [ "fbfm40.fuel_load.1hr", { "type": "literal", "value": 50, "unit": "g/m**2" } ] } ]}'import fastfuels_sdk.v2 as ff
ff.set_api_key("my-api-key")
fbfm40 = ff.get_grid("your-domain-id", "your-lookup-grid-id")
grid = ff.grids.create_grid_from_compose( {"fbfm40": fbfm40}, operations=[ ff.compose.compute( "fuel_load.1hr", "add", ["fbfm40.fuel_load.1hr", ff.compose.literal(50, unit="g/m**2")], ), ], name="1-hr load plus 50 g/m**2",){ "id": "your-grid-id", "domain_id": "your-domain-id", "name": "1-hr load plus 50 g/m**2", "description": "", "status": "pending", "progress": null, "created_on": "2026-10-16T20:58:35.799170", "modified_on": "2026-10-16T20:58:35.799170", "checksum": "e0791ba17bdb4fe9918d353315bb913a", "source": { "name": "compose", "inputs": [ { "grid_id": "your-lookup-grid-id", "alias": "fbfm40", "source_grid_checksum": "fc406cea560c4a50bd5a2d7509fa1b59" } ], "bands": [ { "key": "fuel_load.1hr", "name": null, "description": null, "type": "continuous", "unit": "kg/m**2", "index": 0, "nodata": null, "summary": null } ], "operations": [ { "operator": "add", "operands": [ "fbfm40.fuel_load.1hr", { "type": "literal", "value": 50, "unit": "g/m**2" } ], "type": "compute", "output": "fuel_load.1hr" } ] }, "modifications": [], "bands": [ { "key": "fuel_load.1hr", "name": null, "description": null, "type": "continuous", "unit": "kg/m**2", "index": 0, "nodata": null, "summary": null } ], "georeference": null, "error": null, "chunks": { "shape": [512, 512], "count": null, "count_by_axis": null }, "tags": []}Convert a computed band to another unit
Section titled “Convert a computed band to another unit”To write a compute result in a different but compatible unit, set unit on
the compute operation. Here the live herbaceous load times 67 % has the unit
kg*%/m**2; "unit": "kg/m**2" converts it so it fits a fuel_load band.
curl -X 'POST' \ 'https://api-v2-prod-nyvjyh5ywa-uw.a.run.app/domains/your-domain-id/grids/compose' \ -H 'accept: application/json' \ -H 'api-key: my-api-key' \ -H 'Content-Type: application/json' \ -d '{ "name": "Cured herbaceous load", "inputs": [ { "grid_id": "your-lookup-grid-id", "alias": "fbfm40" } ], "operations": [ { "type": "compute", "output": "fuel_load.cured_herb", "operator": "multiply", "operands": [ "fbfm40.fuel_load.live_herb", { "type": "literal", "value": 67, "unit": "%" } ], "unit": "kg/m**2" } ]}'import fastfuels_sdk.v2 as ff
ff.set_api_key("my-api-key")
fbfm40 = ff.get_grid("your-domain-id", "your-lookup-grid-id")
grid = ff.grids.create_grid_from_compose( {"fbfm40": fbfm40}, operations=[ ff.compose.compute( "fuel_load.cured_herb", "multiply", ["fbfm40.fuel_load.live_herb", ff.compose.literal(67, unit="%")], unit="kg/m**2", ), ], name="Cured herbaceous load",){ "id": "your-grid-id", "domain_id": "your-domain-id", "name": "Cured herbaceous load", "description": "", "status": "pending", "progress": null, "created_on": "2026-10-16T20:58:36.099646", "modified_on": "2026-10-16T20:58:36.099646", "checksum": "1feb3483287d44d1b060ef2711d603fe", "source": { "name": "compose", "inputs": [ { "grid_id": "your-lookup-grid-id", "alias": "fbfm40", "source_grid_checksum": "fc406cea560c4a50bd5a2d7509fa1b59" } ], "bands": [ { "key": "fuel_load.cured_herb", "name": null, "description": null, "type": "continuous", "unit": "kg/m**2", "index": 0, "nodata": null, "summary": null } ], "operations": [ { "operator": "multiply", "operands": [ "fbfm40.fuel_load.live_herb", { "type": "literal", "value": 67, "unit": "%" } ], "type": "compute", "output": "fuel_load.cured_herb", "unit": "kg/m**2" } ] }, "modifications": [], "bands": [ { "key": "fuel_load.cured_herb", "name": null, "description": null, "type": "continuous", "unit": "kg/m**2", "index": 0, "nodata": null, "summary": null } ], "georeference": null, "error": null, "chunks": { "shape": [512, 512], "count": null, "count_by_axis": null }, "tags": []}Apply an operation only where conditions hold
Section titled “Apply an operation only where conditions hold”To restrict an operation to some cells, add conditions and an else
fallback. A cell takes the operation’s result where every condition holds and
the else value everywhere else. Here the two 1-hour loads are averaged only
where both are positive; other cells keep the FBFM40 load.
curl -X 'POST' \ 'https://api-v2-prod-nyvjyh5ywa-uw.a.run.app/domains/your-domain-id/grids/compose' \ -H 'accept: application/json' \ -H 'api-key: my-api-key' \ -H 'Content-Type: application/json' \ -d '{ "name": "Average 1-hr load where both sources have fuel", "inputs": [ { "grid_id": "your-lookup-grid-id", "alias": "fbfm40" }, { "grid_id": "your-fccs-lookup-grid-id", "alias": "fccs" } ], "operations": [ { "type": "compute", "output": "fuel_load.1hr", "operator": "average", "operands": [ "fbfm40.fuel_load.1hr", "fccs.fuel_load.1hr" ], "conditions": [ { "band": "fbfm40.fuel_load.1hr", "operator": "gt", "value": 0 }, { "band": "fccs.fuel_load.1hr", "operator": "gt", "value": 0 } ], "else": "fbfm40.fuel_load.1hr" } ]}'import fastfuels_sdk.v2 as ff
ff.set_api_key("my-api-key")
fbfm40 = ff.get_grid("your-domain-id", "your-lookup-grid-id")fccs = ff.get_grid("your-domain-id", "your-fccs-lookup-grid-id")
grid = ff.grids.create_grid_from_compose( {"fbfm40": fbfm40, "fccs": fccs}, operations=[ ff.compose.compute( "fuel_load.1hr", "average", ["fbfm40.fuel_load.1hr", "fccs.fuel_load.1hr"], conditions=[ ff.compose.condition("fbfm40.fuel_load.1hr", "gt", 0), ff.compose.condition("fccs.fuel_load.1hr", "gt", 0), ], else_="fbfm40.fuel_load.1hr", ), ], name="Average 1-hr load where both sources have fuel",){ "id": "your-grid-id", "domain_id": "your-domain-id", "name": "Average 1-hr load where both sources have fuel", "description": "", "status": "pending", "progress": null, "created_on": "2026-10-16T20:58:36.430258", "modified_on": "2026-10-16T20:58:36.430258", "checksum": "3436adc81ec746b0ab0b9f8536239ff8", "source": { "name": "compose", "inputs": [ { "grid_id": "your-lookup-grid-id", "alias": "fbfm40", "source_grid_checksum": "fc406cea560c4a50bd5a2d7509fa1b59" }, { "grid_id": "your-fccs-lookup-grid-id", "alias": "fccs", "source_grid_checksum": "11aabe8aec4a42789cbac050c2c76a41" } ], "bands": [ { "key": "fuel_load.1hr", "name": null, "description": null, "type": "continuous", "unit": "kg/m**2", "index": 0, "nodata": null, "summary": null } ], "operations": [ { "operator": "average", "operands": ["fbfm40.fuel_load.1hr", "fccs.fuel_load.1hr"], "type": "compute", "output": "fuel_load.1hr", "conditions": [ { "band": "fbfm40.fuel_load.1hr", "operator": "gt", "value": 0 }, { "band": "fccs.fuel_load.1hr", "operator": "gt", "value": 0 } ], "else": "fbfm40.fuel_load.1hr" } ] }, "modifications": [], "bands": [ { "key": "fuel_load.1hr", "name": null, "description": null, "type": "continuous", "unit": "kg/m**2", "index": 0, "nodata": null, "summary": null } ], "georeference": null, "error": null, "chunks": { "shape": [512, 512], "count": null, "count_by_axis": null }, "tags": []}- An attribute condition has a
band(alias.band_key), anoperator—eq,ne,gt,lt,ge,le, orin— and avalue.intakes a list;gt,lt,ge, andletake a single number. - An attribute condition is false on nodata cells.
elseis required wheneverconditionsis set. It can be:- a band reference with the same type and unit as the output;
- a number;
- a typed literal whose unit is the output’s unit;
- an FBFM40 label such as
"NB1", for a categorical output; - an inline compute.
Choose a source grid by fuel model
Section titled “Choose a source grid by fuel model”To pick between grids by category, test a categorical band with eq, ne, or
in. Here grass and grass-shrub cells take the FCCS 1-hour load and all other
cells take the FBFM40 load. FBFM40 labels such as "GR1" and codes such as
101 are interchangeable; the stored operation holds the codes.
curl -X 'POST' \ 'https://api-v2-prod-nyvjyh5ywa-uw.a.run.app/domains/your-domain-id/grids/compose' \ -H 'accept: application/json' \ -H 'api-key: my-api-key' \ -H 'Content-Type: application/json' \ -d '{ "name": "FCCS 1-hr load in grass fuel models", "inputs": [ { "grid_id": "your-fbfm40-grid-id", "alias": "codes" }, { "grid_id": "your-lookup-grid-id", "alias": "fbfm40" }, { "grid_id": "your-fccs-lookup-grid-id", "alias": "fccs" } ], "operations": [ { "type": "select", "output": "fuel_load.1hr", "from": "fccs.fuel_load.1hr", "conditions": [ { "band": "codes.fbfm", "operator": "in", "value": [ "GR1", "GR2", "GS1", "GS2" ] } ], "else": "fbfm40.fuel_load.1hr" } ]}'import fastfuels_sdk.v2 as ff
ff.set_api_key("my-api-key")
codes = ff.get_grid("your-domain-id", "your-fbfm40-grid-id")fbfm40 = ff.get_grid("your-domain-id", "your-lookup-grid-id")fccs = ff.get_grid("your-domain-id", "your-fccs-lookup-grid-id")
grid = ff.grids.create_grid_from_compose( {"codes": codes, "fbfm40": fbfm40, "fccs": fccs}, operations=[ ff.compose.select( "fuel_load.1hr", "fccs.fuel_load.1hr", conditions=[ ff.compose.condition("codes.fbfm", "in", ["GR1", "GR2", "GS1", "GS2"]), ], else_="fbfm40.fuel_load.1hr", ), ], name="FCCS 1-hr load in grass fuel models",){ "id": "your-grid-id", "domain_id": "your-domain-id", "name": "FCCS 1-hr load in grass fuel models", "description": "", "status": "pending", "progress": null, "created_on": "2026-10-16T20:58:36.750633", "modified_on": "2026-10-16T20:58:36.750633", "checksum": "7cf2eb66dd634016b8f576486c63f084", "source": { "name": "compose", "inputs": [ { "grid_id": "your-fbfm40-grid-id", "alias": "codes", "source_grid_checksum": "9108d05ae9574c32acf72acd09eed001" }, { "grid_id": "your-lookup-grid-id", "alias": "fbfm40", "source_grid_checksum": "fc406cea560c4a50bd5a2d7509fa1b59" }, { "grid_id": "your-fccs-lookup-grid-id", "alias": "fccs", "source_grid_checksum": "11aabe8aec4a42789cbac050c2c76a41" } ], "bands": [ { "key": "fuel_load.1hr", "name": null, "description": null, "type": "continuous", "unit": "kg/m**2", "index": 0, "nodata": null, "summary": null } ], "operations": [ { "type": "select", "output": "fuel_load.1hr", "from": "fccs.fuel_load.1hr", "conditions": [ { "band": "codes.fbfm", "operator": "in", "value": [101, 102, 121, 122] } ], "else": "fbfm40.fuel_load.1hr" } ] }, "modifications": [], "bands": [ { "key": "fuel_load.1hr", "name": null, "description": null, "type": "continuous", "unit": "kg/m**2", "index": 0, "nodata": null, "summary": null } ], "georeference": null, "error": null, "chunks": { "shape": [512, 512], "count": null, "count_by_axis": null }, "tags": []}Restrict an operation to a polygon
Section titled “Restrict an operation to a polygon”To limit an operation to an area you draw, add a geometry condition with
"source": "geometry", an operator (within, outside, or intersects),
and a GeoJSON geometry. Here the 1-hour load is halved inside a polygon.
Replace the coordinates with a polygon inside your domain.
curl -X 'POST' \ 'https://api-v2-prod-nyvjyh5ywa-uw.a.run.app/domains/your-domain-id/grids/compose' \ -H 'accept: application/json' \ -H 'api-key: my-api-key' \ -H 'Content-Type: application/json' \ -d '{ "name": "Half 1-hr load inside a treatment polygon", "inputs": [ { "grid_id": "your-lookup-grid-id", "alias": "fbfm40" } ], "operations": [ { "type": "compute", "output": "fuel_load.1hr", "operator": "multiply", "operands": [ "fbfm40.fuel_load.1hr", 0.5 ], "conditions": [ { "source": "geometry", "operator": "within", "geometry": { "type": "Polygon", "coordinates": [ [ [ -114.1122, 46.825 ], [ -114.1038, 46.825 ], [ -114.1038, 46.8325 ], [ -114.1122, 46.8325 ], [ -114.1122, 46.825 ] ] ] }, "crs": { "type": "name", "properties": { "name": "EPSG:4326" } } } ], "else": "fbfm40.fuel_load.1hr" } ]}'import fastfuels_sdk.v2 as fffrom fastfuels_sdk.v2.client_library.models import ( GridGeometrySpatialCondition, GridGeometrySpatialConditionCrsType0, GridGeometrySpatialConditionGeometry, SpatialOperator,)
ff.set_api_key("my-api-key")
fbfm40 = ff.get_grid("your-domain-id", "your-lookup-grid-id")
treatment_area = GridGeometrySpatialCondition( source="geometry", operator=SpatialOperator.WITHIN, geometry=GridGeometrySpatialConditionGeometry.from_dict( { "type": "Polygon", "coordinates": [ [ [-114.1122, 46.8250], [-114.1038, 46.8250], [-114.1038, 46.8325], [-114.1122, 46.8325], [-114.1122, 46.8250], ] ], } ), crs=GridGeometrySpatialConditionCrsType0.from_dict( {"type": "name", "properties": {"name": "EPSG:4326"}} ),)
grid = ff.grids.create_grid_from_compose( {"fbfm40": fbfm40}, operations=[ ff.compose.compute( "fuel_load.1hr", "multiply", ["fbfm40.fuel_load.1hr", 0.5], conditions=[treatment_area], else_="fbfm40.fuel_load.1hr", ), ], name="Half 1-hr load inside a treatment polygon",){ "id": "your-grid-id", "domain_id": "your-domain-id", "name": "Half 1-hr load inside a treatment polygon", "description": "", "status": "pending", "progress": null, "created_on": "2026-10-16T21:39:06.533097", "modified_on": "2026-10-16T21:39:06.533097", "checksum": "ff12be9513134efca32abb32d86d4716", "source": { "name": "compose", "inputs": [ { "grid_id": "your-lookup-grid-id", "alias": "fbfm40", "source_grid_checksum": "8a75a64ef6584089a139dd3e379c56ed" } ], "bands": [ { "key": "fuel_load.1hr", "name": null, "description": null, "type": "continuous", "unit": "kg/m**2", "index": 0, "nodata": null, "summary": null } ], "operations": [ { "operator": "multiply", "operands": ["fbfm40.fuel_load.1hr", 0.5], "type": "compute", "output": "fuel_load.1hr", "conditions": [ { "source": "geometry", "operator": "within", "geometry": { "type": "Polygon", "coordinates": [ [ [-114.1122, 46.825], [-114.1038, 46.825], [-114.1038, 46.8325], [-114.1122, 46.8325], [-114.1122, 46.825] ] ] }, "crs": { "type": "name", "properties": { "name": "EPSG:4326" } }, "target": "centroid" } ], "else": "fbfm40.fuel_load.1hr" } ] }, "modifications": [], "bands": [ { "key": "fuel_load.1hr", "name": null, "description": null, "type": "continuous", "unit": "kg/m**2", "index": 0, "nodata": null, "summary": null } ], "georeference": null, "error": null, "chunks": { "shape": [512, 512], "count": null, "count_by_axis": null }, "tags": []}crssets the geometry’s CRS as a GeoJSON CRS object. Without it, the coordinates are read in the domain’s CRS.targetpicks what is tested. Withcentroid(the default), each cell’s center is tested. Withcell,withinmatches cells entirely inside the geometry,intersectsmatches every cell the geometry touches, andoutsidematches cells it doesn’t touch.buffer_mwidens the geometry by that many meters before testing.
Restrict an operation to a feature
Section titled “Restrict an operation to a feature”To limit an operation to a stored feature, add a feature condition with
"source": "feature" and the feature’s feature_id. The feature must be
completed and in the same domain. Here cells whose center lies within 10 m of
a road take 0 kg/m**2.
curl -X 'POST' \ 'https://api-v2-prod-nyvjyh5ywa-uw.a.run.app/domains/your-domain-id/grids/compose' \ -H 'accept: application/json' \ -H 'api-key: my-api-key' \ -H 'Content-Type: application/json' \ -d '{ "name": "1-hr load with roads cleared", "inputs": [ { "grid_id": "your-lookup-grid-id", "alias": "fbfm40" } ], "operations": [ { "type": "select", "output": "fuel_load.1hr", "from": "fbfm40.fuel_load.1hr", "conditions": [ { "source": "feature", "operator": "outside", "feature_id": "your-road-feature-id", "buffer_m": 10 } ], "else": { "type": "literal", "value": 0, "unit": "kg/m**2" } } ]}'import fastfuels_sdk.v2 as fffrom fastfuels_sdk.v2.client_library.models import ( GridFeatureSpatialCondition, SpatialOperator,)
ff.set_api_key("my-api-key")
fbfm40 = ff.get_grid("your-domain-id", "your-lookup-grid-id")
off_road = GridFeatureSpatialCondition( source="feature", operator=SpatialOperator.OUTSIDE, feature_id="your-road-feature-id", buffer_m=10,)
grid = ff.grids.create_grid_from_compose( {"fbfm40": fbfm40}, operations=[ ff.compose.select( "fuel_load.1hr", "fbfm40.fuel_load.1hr", conditions=[off_road], else_=ff.compose.literal(0, unit="kg/m**2"), ), ], name="1-hr load with roads cleared",){ "id": "your-grid-id", "domain_id": "your-domain-id", "name": "1-hr load with roads cleared", "description": "", "status": "pending", "progress": null, "created_on": "2026-10-16T20:58:37.321900", "modified_on": "2026-10-16T20:58:37.321900", "checksum": "9f45e398846a49758fddd6735ec373b1", "source": { "name": "compose", "inputs": [ { "grid_id": "your-lookup-grid-id", "alias": "fbfm40", "source_grid_checksum": "fc406cea560c4a50bd5a2d7509fa1b59" } ], "bands": [ { "key": "fuel_load.1hr", "name": null, "description": null, "type": "continuous", "unit": "kg/m**2", "index": 0, "nodata": null, "summary": null } ], "operations": [ { "type": "select", "output": "fuel_load.1hr", "from": "fbfm40.fuel_load.1hr", "conditions": [ { "source": "feature", "operator": "outside", "feature_id": "your-road-feature-id", "buffer_m": 10.0, "target": "centroid" } ], "else": { "type": "literal", "value": 0, "unit": "kg/m**2" } } ] }, "modifications": [], "bands": [ { "key": "fuel_load.1hr", "name": null, "description": null, "type": "continuous", "unit": "kg/m**2", "index": 0, "nodata": null, "summary": null } ], "georeference": null, "error": null, "chunks": { "shape": [512, 512], "count": null, "count_by_axis": null }, "tags": []}operator, target, and buffer_m work as for a geometry condition.
Fall back to a computed value
Section titled “Fall back to a computed value”To compute the fallback, set else to an inline compute: an object with
operator and operands. Here cells where the FCCS 1-hour load is 0 keep
the FBFM40 load, and all other cells take the average of the two.
curl -X 'POST' \ 'https://api-v2-prod-nyvjyh5ywa-uw.a.run.app/domains/your-domain-id/grids/compose' \ -H 'accept: application/json' \ -H 'api-key: my-api-key' \ -H 'Content-Type: application/json' \ -d '{ "name": "Averaged 1-hr load with FBFM40 infill", "inputs": [ { "grid_id": "your-lookup-grid-id", "alias": "fbfm40" }, { "grid_id": "your-fccs-lookup-grid-id", "alias": "fccs" } ], "operations": [ { "type": "select", "output": "fuel_load.1hr", "from": "fbfm40.fuel_load.1hr", "conditions": [ { "band": "fccs.fuel_load.1hr", "operator": "eq", "value": 0 } ], "else": { "operator": "average", "operands": [ "fbfm40.fuel_load.1hr", "fccs.fuel_load.1hr" ] } } ]}'import fastfuels_sdk.v2 as ff
ff.set_api_key("my-api-key")
fbfm40 = ff.get_grid("your-domain-id", "your-lookup-grid-id")fccs = ff.get_grid("your-domain-id", "your-fccs-lookup-grid-id")
grid = ff.grids.create_grid_from_compose( {"fbfm40": fbfm40, "fccs": fccs}, operations=[ ff.compose.select( "fuel_load.1hr", "fbfm40.fuel_load.1hr", conditions=[ff.compose.condition("fccs.fuel_load.1hr", "eq", 0)], else_=ff.compose.inline_compute( "average", ["fbfm40.fuel_load.1hr", "fccs.fuel_load.1hr"] ), ), ], name="Averaged 1-hr load with FBFM40 infill",){ "id": "your-grid-id", "domain_id": "your-domain-id", "name": "Averaged 1-hr load with FBFM40 infill", "description": "", "status": "pending", "progress": null, "created_on": "2026-10-16T20:58:37.615726", "modified_on": "2026-10-16T20:58:37.615726", "checksum": "b7c648b9034c492e9878a0d3aa63c629", "source": { "name": "compose", "inputs": [ { "grid_id": "your-lookup-grid-id", "alias": "fbfm40", "source_grid_checksum": "fc406cea560c4a50bd5a2d7509fa1b59" }, { "grid_id": "your-fccs-lookup-grid-id", "alias": "fccs", "source_grid_checksum": "11aabe8aec4a42789cbac050c2c76a41" } ], "bands": [ { "key": "fuel_load.1hr", "name": null, "description": null, "type": "continuous", "unit": "kg/m**2", "index": 0, "nodata": null, "summary": null } ], "operations": [ { "type": "select", "output": "fuel_load.1hr", "from": "fbfm40.fuel_load.1hr", "conditions": [ { "band": "fccs.fuel_load.1hr", "operator": "eq", "value": 0 } ], "else": { "operator": "average", "operands": ["fbfm40.fuel_load.1hr", "fccs.fuel_load.1hr"] } } ] }, "modifications": [], "bands": [ { "key": "fuel_load.1hr", "name": null, "description": null, "type": "continuous", "unit": "kg/m**2", "index": 0, "nodata": null, "summary": null } ], "georeference": null, "error": null, "chunks": { "shape": [512, 512], "count": null, "count_by_axis": null }, "tags": []}The inline compute follows the operand rules of a compute operation, has no
conditions of its own, and its unit must be compatible with the output’s.
Multi-step math
Section titled “Multi-step math”An operation cannot read another operation’s output: every band reference names an input alias. To get a result that needs more than one step, use one compute with many operands or chain two composes.
Combine many bands in one compute
Section titled “Combine many bands in one compute”To sum, multiply, average, or take the minimum or maximum of several bands,
list them all as operands of one compute. Here the FCCS 1-hour, litter, and
10-hour loads are summed.
curl -X 'POST' \ 'https://api-v2-prod-nyvjyh5ywa-uw.a.run.app/domains/your-domain-id/grids/compose' \ -H 'accept: application/json' \ -H 'api-key: my-api-key' \ -H 'Content-Type: application/json' \ -d '{ "name": "FCCS dead surface load", "inputs": [ { "grid_id": "your-fccs-lookup-grid-id", "alias": "fccs" } ], "operations": [ { "type": "compute", "output": "fuel_load.dead", "operator": "add", "operands": [ "fccs.fuel_load.1hr", "fccs.fuel_load.litter", "fccs.fuel_load.10hr" ] } ]}'import fastfuels_sdk.v2 as ff
ff.set_api_key("my-api-key")
fccs = ff.get_grid("your-domain-id", "your-fccs-lookup-grid-id")
grid = ff.grids.create_grid_from_compose( {"fccs": fccs}, operations=[ ff.compose.compute( "fuel_load.dead", "add", ["fccs.fuel_load.1hr", "fccs.fuel_load.litter", "fccs.fuel_load.10hr"], ), ], name="FCCS dead surface load",){ "id": "your-grid-id", "domain_id": "your-domain-id", "name": "FCCS dead surface load", "description": "", "status": "pending", "progress": null, "created_on": "2026-10-16T20:58:37.889660", "modified_on": "2026-10-16T20:58:37.889660", "checksum": "86f787acaa0d4558bc2973626f4acf71", "source": { "name": "compose", "inputs": [ { "grid_id": "your-fccs-lookup-grid-id", "alias": "fccs", "source_grid_checksum": "11aabe8aec4a42789cbac050c2c76a41" } ], "bands": [ { "key": "fuel_load.dead", "name": null, "description": null, "type": "continuous", "unit": "kg/m**2", "index": 0, "nodata": null, "summary": null } ], "operations": [ { "operator": "add", "operands": [ "fccs.fuel_load.1hr", "fccs.fuel_load.litter", "fccs.fuel_load.10hr" ], "type": "compute", "output": "fuel_load.dead" } ] }, "modifications": [], "bands": [ { "key": "fuel_load.dead", "name": null, "description": null, "type": "continuous", "unit": "kg/m**2", "index": 0, "nodata": null, "summary": null } ], "georeference": null, "error": null, "chunks": { "shape": [512, 512], "count": null, "count_by_axis": null }, "tags": []}Chain two composes
Section titled “Chain two composes”To mix operators, such as (a + b) ÷ c, compose the first step, then pass the resulting grid as an input to a second compose. A composed grid is on the same lattice as its inputs, so it combines with them.
-
Compose a + b — here the 1-hour plus live herbaceous load.
Step 1 — a + b curl -X 'POST' \'https://api-v2-prod-nyvjyh5ywa-uw.a.run.app/domains/your-domain-id/grids/compose' \-H 'accept: application/json' \-H 'api-key: my-api-key' \-H 'Content-Type: application/json' \-d '{"name": "Fine fuel load","inputs": [{"grid_id": "your-lookup-grid-id","alias": "fbfm40"}],"operations": [{"type": "compute","output": "fuel_load.fine","operator": "add","operands": ["fbfm40.fuel_load.1hr","fbfm40.fuel_load.live_herb"]}]}'Step 1 — a + b import fastfuels_sdk.v2 as ffff.set_api_key("my-api-key")fbfm40 = ff.get_grid("your-domain-id", "your-lookup-grid-id")grid = ff.grids.create_grid_from_compose({"fbfm40": fbfm40},operations=[ff.compose.compute("fuel_load.fine","add",["fbfm40.fuel_load.1hr", "fbfm40.fuel_load.live_herb"],),],name="Fine fuel load",){"id": "your-composed-grid-id","domain_id": "your-domain-id","name": "Fine fuel load","description": "","status": "pending","progress": null,"created_on": "2026-10-16T20:58:38.211266","modified_on": "2026-10-16T20:58:38.211266","checksum": "12450d8466a9403aa8bf2496f2ed8339","source": {"name": "compose","inputs": [{"grid_id": "your-lookup-grid-id","alias": "fbfm40","source_grid_checksum": "fc406cea560c4a50bd5a2d7509fa1b59"}],"bands": [{"key": "fuel_load.fine","name": null,"description": null,"type": "continuous","unit": "kg/m**2","index": 0,"nodata": null,"summary": null}],"operations": [{"operator": "add","operands": ["fbfm40.fuel_load.1hr", "fbfm40.fuel_load.live_herb"],"type": "compute","output": "fuel_load.fine"}]},"modifications": [],"bands": [{"key": "fuel_load.fine","name": null,"description": null,"type": "continuous","unit": "kg/m**2","index": 0,"nodata": null,"summary": null}],"georeference": null,"error": null,"chunks": {"shape": [512, 512],"count": null,"count_by_axis": null},"tags": []}Record its id, your-composed-grid-id, and poll it to
completed. -
Compose (a + b) ÷ c, with the step 1 grid as one input — here the fine fuel load divided by the fuel depth. The condition sends cells with zero depth to
else.Step 2 — (a + b) ÷ c curl -X 'POST' \'https://api-v2-prod-nyvjyh5ywa-uw.a.run.app/domains/your-domain-id/grids/compose' \-H 'accept: application/json' \-H 'api-key: my-api-key' \-H 'Content-Type: application/json' \-d '{"name": "Fine fuel bulk density","inputs": [{"grid_id": "your-composed-grid-id","alias": "fine"},{"grid_id": "your-lookup-grid-id","alias": "fbfm40"}],"operations": [{"type": "compute","output": "bulk_density.fine","operator": "divide","operands": ["fine.fuel_load.fine","fbfm40.fuel_depth"],"conditions": [{"band": "fbfm40.fuel_depth","operator": "gt","value": 0}],"else": {"type": "literal","value": 0,"unit": "kg/m**3"}}]}'Step 2 — (a + b) ÷ c import fastfuels_sdk.v2 as ffff.set_api_key("my-api-key")fine_load = ff.get_grid("your-domain-id", "your-composed-grid-id")fbfm40 = ff.get_grid("your-domain-id", "your-lookup-grid-id")grid = ff.grids.create_grid_from_compose({"fine": fine_load, "fbfm40": fbfm40},operations=[ff.compose.compute("bulk_density.fine","divide",["fine.fuel_load.fine", "fbfm40.fuel_depth"],conditions=[ff.compose.condition("fbfm40.fuel_depth", "gt", 0)],else_=ff.compose.literal(0, unit="kg/m**3"),),],name="Fine fuel bulk density",){"id": "your-grid-id","domain_id": "your-domain-id","name": "Fine fuel bulk density","description": "","status": "pending","progress": null,"created_on": "2026-10-16T20:58:55.240100","modified_on": "2026-10-16T20:58:55.240100","checksum": "add7c7abf1a94cfba26f4d64ac971804","source": {"name": "compose","inputs": [{"grid_id": "your-composed-grid-id","alias": "fine","source_grid_checksum": "12450d8466a9403aa8bf2496f2ed8339"},{"grid_id": "your-lookup-grid-id","alias": "fbfm40","source_grid_checksum": "fc406cea560c4a50bd5a2d7509fa1b59"}],"bands": [{"key": "bulk_density.fine","name": null,"description": null,"type": "continuous","unit": "kg/m**3","index": 0,"nodata": null,"summary": null}],"operations": [{"operator": "divide","operands": ["fine.fuel_load.fine", "fbfm40.fuel_depth"],"type": "compute","output": "bulk_density.fine","conditions": [{"band": "fbfm40.fuel_depth","operator": "gt","value": 0}],"else": {"type": "literal","value": 0,"unit": "kg/m**3"}}]},"modifications": [],"bands": [{"key": "bulk_density.fine","name": null,"description": null,"type": "continuous","unit": "kg/m**3","index": 0,"nodata": null,"summary": null}],"georeference": null,"error": null,"chunks": {"shape": [512, 512],"count": null,"count_by_axis": null},"tags": []}
If the job fails
Section titled “If the job fails”A request that passes validation can still fail while the grid is built. The
grid then lands in status: failed with an error. One cause is a
divide whose denominator is zero in some cells. Here, step 2 above without
its condition:
{ "id": "your-grid-id", "domain_id": "your-domain-id", "name": "Fine fuel bulk density", "description": "", "status": "failed", "progress": { "percent": 100, "message": "Failed" }, "created_on": "2026-10-16T20:58:55.558944Z", "modified_on": "2026-10-16T20:58:56.821182Z", "checksum": "9a39f175cb7e44718db3a0f0a129f805", "source": { "operations": [ { "type": "compute", "operator": "divide", "output": "bulk_density.fine", "operands": ["fine.fuel_load.fine", "fbfm40.fuel_depth"] } ], "bands": [ { "unit": "kg/m**3", "nodata": null, "type": "continuous", "description": null, "name": null, "summary": null, "index": 0, "key": "bulk_density.fine" } ], "name": "compose", "inputs": [ { "grid_id": "your-composed-grid-id", "source_grid_checksum": "12450d8466a9403aa8bf2496f2ed8339", "alias": "fine" }, { "grid_id": "your-lookup-grid-id", "source_grid_checksum": "fc406cea560c4a50bd5a2d7509fa1b59", "alias": "fbfm40" } ] }, "modifications": [], "bands": [ { "key": "bulk_density.fine", "name": null, "description": null, "type": "continuous", "unit": "kg/m**3", "index": 0, "nodata": null, "summary": null } ], "georeference": null, "error": { "code": "COMPOSE_NON_FINITE_RESULT", "message": "Compose computation produced non-finite values, such as inf or NaN, in valid cells.", "suggestion": "Check divide operations for zero denominators, or add a condition (with an else fallback) that routes those cells to the fallback instead of the computed result." }, "chunks": { "shape": [512, 512], "count": null, "count_by_axis": null }, "tags": []}To fix it, add a condition that sends those cells to else, as in
Chain two composes, and submit the request again.
Common errors
Section titled “Common errors”Each of these returns 422 and creates no grid. The Python SDK raises
ValueError before sending the request for some of them: an output
reference, a missing band, a duplicate output, and conditions without
else.
-
Referencing another operation’s output. An operand such as
"fuel_load.fine"names a band that another operation in the same request produces, not an input band. Chain two composes instead.{"detail": "Band reference 'fuel_load.fine' must use an input alias, e.g. 'a.fuel_load.1hr'."} -
Referencing a band the input doesn’t have. Use a band listed in the error, or add an input that carries the band.
{"detail": "Source grid your-fccs-lookup-grid-id is missing required bands: ['fuel_depth']. Available bands: ['fuel_load.10hr', 'fuel_load.1hr', 'fuel_load.litter', 'fuel_load.live_herb']"} -
An
outputkey that doesn’t match the result. Here a load divided by a depth (kg/m**3) is namedfuel_load.1hr(kg/m**2). Name the output after what it holds —bulk_density.1hr— or, for a compatible unit, setuniton the compute.{"detail": "Output band 'fuel_load.1hr' doesn't match what this operation produces: 'fuel_load' bands are continuous with kg/m**2, not continuous with kg/m**3. Name the output after what it holds, or set `unit` on a compute to convert."} -
An
outputkey that isn’t a band key. Start the key with one of the quantities the error lists.{"detail": [{"type": "value_error","loc": ["body", "operations", 0, "select", "output"],"msg": "Value error, 'fine_fuel' is not a band key. Use <quantity> or <quantity>.<label>, with a quantity from ['annual_disturbance', 'aspect', 'bulk_density', 'cbd', 'cbh', 'cc', 'cfl', 'chm', 'curing', 'duff_depth', 'elevation', 'fbfm', 'fbfm13', 'fccs', 'fuel_depth', 'fuel_load', 'fuel_moisture', 'heat_content', 'irradiance', 'leaf_area_density', 'plt_cn', 'savr', 'slope', 'spcd', 'tm_id', 'tree_id', 'volume_fraction'] and a label of lowercase letters, digits and underscores.","input": "fine_fuel","ctx": {"error": {}}}]} -
A categorical band as a compute operand. Use the categorical band in a condition instead, as in Choose a source grid by fuel model.
{"detail": "Compute operands must reference continuous bands."} -
gt,lt,ge, orleon a categorical band. Useeq,ne, orinwith a list of codes or labels.{"detail": "Categorical compose conditions support only eq, ne, and in."} -
conditionswithoutelse. Add anelsevalue.{"detail": [{"type": "value_error","loc": ["body", "operations", 0, "select"],"msg": "Value error, `else` is required when `conditions` are present.","input": {"type": "select","output": "fuel_load.1hr","from": "fbfm40.fuel_load.1hr","conditions": [{"band": "fbfm40.fuel_depth","operator": "gt","value": 0}]},"ctx": {"error": {}}}]} -
The same
outputtwice. Give each operation its ownoutputkey.{"detail": [{"type": "value_error","loc": ["body", "operations"],"msg": "Value error, Duplicate values are not allowed: fuel_load.1hr","input": [{"type": "select","output": "fuel_load.1hr","from": "fbfm40.fuel_load.1hr"},{"type": "select","output": "fuel_load.1hr","from": "fccs.fuel_load.1hr"}],"ctx": {"error": {}}}]} -
Inputs on different lattices. Resample the grid named in the error onto the other grid, as the error says. See Resample or reproject a grid.
{"detail": "Grid grid-to-resample has horizontal shape (15, 22), but grid your-lookup-grid-id has (30, 45). Resample grid grid-to-resample with alignment.target='grid' and alignment.grid_id='your-lookup-grid-id' before using these grids together."}
Inputs must also be 2D and completed; a 3D grid or a grid that is still
processing is rejected.
Next steps
Section titled “Next steps”- Read the result — fetch and stream the grid data.
- Edit the result in place — modify a grid.