Model Axes
An axis is a configurable dimension for your model’s runs that can be wired into other parts of your model configuration to enable powerful features like fanning a single model out to N model runs per trigger based on a combination or partition of input data.
For example, declare a ref_year axis with the values 2023, 2024, and
2025, and every trigger queues three runs instead of one: the same model, run
once per reference year, each run reading its own year’s slice of the same input
data.
A trigger is whatever starts a run — new input data arriving, or someone pressing “Run model” — as described in Run modes and scheduling.
When to Use an Axis
Declare an axis when the same forecast logic runs over a dimension of your data and each version reads a different slice of one file: for example, one run per reference year. Your model code stays as it is, and every result stays under a single model that people switch between in the pd4castr app.
Sensitivities are distinctly different in that they change the input data for a specific run via SQL, whereas an axis is used to trigger additional model runs for the inputs you already have.
Combined, they can be used to trigger fan-out model runs of individualised input data, with sensitivities applied to each run.
How Axes Change Your Runs
A trigger queues one run per combination of axis values, then multiplies that by your sensitivities:
runs per trigger = (product of each axis's value count) × (1 base run + number of sensitivities)A model with a three-value ref_year axis, a second axis with two values, and
three sensitivities queues 3 × 2 × (1 + 3) = 24 runs every time it triggers. All
24 share the same runDatetime.
Each axis’s default value picks the model’s base run: the run people get
without choosing anything. The app opens on it, and the platform’s latest-run
API endpoints answer with it. When a model declares more than one axis, the base
run is the combination of every axis’s default.
The platform caps a model at 200 runs per trigger and 100 values per axis. The CLI checks your configuration against them on your own machine before it uploads anything, so a publish over either limit fails in your terminal. If you need to trigger more runs than these limits allow, contact support to discuss your requirements.
What Your Model Container Sees
Adding an axis changes nothing inside your model code. The container receives
the same environment variables it always did: one INPUT_<KEY>_URL per input,
plus OUTPUT_URL and MODEL_RUN_ID. No environment variable carries the run’s
axis values.
What changes is the file behind INPUT_<KEY>_URL. For a partitioned input, that
file holds only the rows for this run’s value, so the 2024 run downloads the
2024 rows and nothing else. The column the file was partitioned on stays in the
file, which means your existing queries that filter or group by it keep working
— they just match every row now.
Configuration
Declare axes in the axes array in .pd4castrrc.json. Each entry has the
following fields.
| Field | Type | Required | Description |
|---|---|---|---|
key | string | Yes | Stable identifier for this axis. Lowercase alphanumeric, with hyphens/underscores. Must be unique within the model. |
label | string | No | Name shown above the axis’s values in the pd4castr app. |
description | string | No | Help text shown in the axis’s tooltip in the pd4castr app. |
type | string | Yes | The value type: number, string, or boolean. |
valuesFrom | object | Yes | Where the axis’s values come from. Only { "kind": "static", "values": [...] } is supported today, with at least one value. |
default | matches type | Yes | The value that defines this axis’s base run. Must be one of valuesFrom.values. |
Declared values must be unique within the axis and match the declared type. A
number value must be a whole number between zero and 9,007,199,254,740,991.
Both limits keep a value’s text identical everywhere the platform writes it,
whether that’s a storage path, a label, or a query. A string value can’t be
empty. It can hold letters, digits, underscores, dots, and hyphens, and it must
start with a letter or a digit.
Here’s a ref_year axis with three fixed values and a default:
{
"axes": [
{
"key": "ref_year",
"label": "Reference Year",
"type": "number",
"valuesFrom": {
"kind": "static",
"values": [2023, 2024, 2025]
},
"default": 2024
}
]
}Partitioning Inputs and Datasets by an Axis
You can partition an input or dataset by mapping an axis to a specific column in
its file, using the input’s or dataset’s own axes field. Each run then reads
only the rows carrying its own axis value. A file that maps no axis is shared,
and every run gets all of it.
An example:
"inputs": [
{
"key": "forecast_values",
"axes": { "ref_year": { "kind": "partition", "column": "REF_YR" } }
},
{ "key": "mt" }
]forecast_values reads only its own year’s rows on every run. mt maps no
axis, so every run gets the whole file, unchanged.
Four rules govern partitioning:
- Only a static input can be partitioned, and it must declare both
uploadFileFormatandtargetFileFormatasparquet. - A partitioned dataset must declare
fileFormatasparquet. - An input or dataset can be partitioned on at most one axis.
- The key naming the partition must match an axis declared in the model’s
axesarray.
Axis Values in Model Run Views
A model run view parameter can name an axis with
defaultFrom: "run.axis.<key>". The platform accepts that reference and checks
the key against your axes array, but it doesn’t yet hand the running view its
axis value: an optional parameter resolves to null, and a required one is
rejected when the view runs. Set that parameter another way for now.
What You See in the App
You can configure how axes are represented in the pd4castr app with the label
and description fields. The app opens on the base run, with every axis at its
default.
Changing Axes on a Published Model
Publishing an existing model comes in two shapes: updating its current revision in place, or creating a new revision. Updating an existing model covers how you pick between them. Axes constrain that choice.
Updating a model’s current revision in place can’t add an axis, remove an axis,
or move an axis’s default to a different value — any of those changes the
revision’s base run, so publish fails and you publish a new revision instead.
Adding or removing a non-default value in place is allowed, but removing will
hide the related model run variants from the model run history, though their
data stays available through the API.
An axis key’s type can’t change across the revisions of one model group,
whether you’re updating in place or publishing a new revision. To change an
axis’s value type, declare a new key instead of reusing the old one.
Custom Run Datetime Queries
If your model declares axes, keep your
custom run datetime query
reading only shared inputs, meaning the ones that map no axis. Every run from a
trigger is supposed to carry the same runDatetime. A query reading a
partitioned input would read a different set of rows in each run and hand each
one a different runDatetime, which breaks that.
Next Steps
- See Model inputs for the full input configuration reference, including static and data-fetcher inputs.
- See Model datasets for publishing reference data alongside your model.
- See Sensitivities for how sensitivity runs multiply alongside axis runs.
- See Publishing for the full publish workflow.
- See the Configuration file reference for the complete schema.