Scenario Specifications
This page documents the public spec classes under abacus.scenario_planner.
Most users create one of the three concrete scenario specs:
CurrentScenarioSpecManualAllocationScenarioSpecFixedBudgetOptimizedScenarioSpec
Abacus also exposes shared base models such as
HistoricalReferenceScenarioSpec and SimulatedScenarioSpec, but you do not
normally instantiate those directly.
Shared fields
All public scenario specs inherit these core fields:
| Field | Meaning |
|---|---|
name |
Display name for the scenario |
start_date |
Requested scenario start date |
end_date |
Requested scenario end date |
scenario_id |
Stable scenario key used in outputs |
If you do not set scenario_id, Abacus derives one by slugifying name.
Scenario IDs must be unique within one ScenarioPlanner.compare(...) call.
CurrentScenarioSpec
Use CurrentScenarioSpec for a historical reference plan.
Requirements:
- the requested window must overlap observed data
- no allocation or budget inputs are needed
Shared simulated-scenario fields
ManualAllocationScenarioSpec and FixedBudgetOptimizedScenarioSpec both
inherit these fields:
| Field | Default | Meaning |
|---|---|---|
budget_distribution_over_period |
None |
Optional time distribution of the total budget |
include_last_observations |
False |
Passed through to response sampling for lag context |
include_carryover |
True |
Extend the evaluated window to capture lagged effects |
noise_level |
0.001 |
Response-sampling noise level |
Set noise_level=0.0 when you want deterministic realised spend paths.
ManualAllocationScenarioSpec
Use ManualAllocationScenarioSpec when you already know the total allocation
you want to simulate.
Supported allocation shapes
allocation can be:
- a dict of
{channel: total_budget}for("channel",)budgets only - an
xarray.DataArray - a
DataArraySpec
For panel budgets such as ("geo", "channel") or
("geo", "brand", "channel"), use xarray.DataArray or DataArraySpec.
Dict allocations must match the model’s channel coordinates exactly. Missing or
extra keys raise ValueError.
FixedBudgetOptimizedScenarioSpec
Use FixedBudgetOptimizedScenarioSpec when you want Abacus to optimise the
allocation.
Optimisation fields
| Field | Meaning |
|---|---|
total_budget |
Total spend over the full scenario horizon |
response_variable |
Variable used by the optimiser |
budget_bounds |
Explicit lower and upper bounds |
spend_constraint_lower |
Relative lower bound when deriving defaults |
spend_constraint_upper |
Relative upper bound when deriving defaults |
default_constraints |
Passed through to the underlying optimiser |
The default response_variable is
"total_media_contribution_original_scale".
Default bound derivation
If you do not pass budget_bounds, Abacus derives them from historical
reference spend.
For each omitted relative constraint side, Abacus uses 0.3. That gives the
default Meridian-style bounds:
- lower bound: scaled reference spend ×
(1 - 0.3) - upper bound: scaled reference spend ×
(1 + 0.3)
If historical reference spend sums to zero, Abacus cannot derive those default
bounds and raises ValueError.
Supported budget_bounds shapes
budget_bounds can be:
- a dict of
{channel: (lower, upper)}for("channel",)budgets only - an
xarray.DataArray - a
DataArraySpec
For xarray or DataArraySpec, the dims must be (*budget_dims, "bound")
with "lower" and "upper" values on the bound dimension.
budget_distribution_over_period
Both simulated scenario types support budget_distribution_over_period.
The object must:
- have dims
("date", *budget_dims) - contain one weight per scenario period
- sum to
1acrossdatefor every budget cell
The date coordinates can be:
- integer positions
0 .. num_periods - 1, or - exact dates that match the requested scenario window
If the dates do not match the scenario window exactly, Abacus raises
ValueError.
DataArraySpec
Use DataArraySpec when you want JSON-friendly or YAML-friendly planner
inputs.
Abacus materialises DataArraySpec as an xarray.DataArray before it
validates dims and coordinates.
Common pitfalls
- Reusing the same
scenario_idtwice in one comparison - Using dict allocations or dict bounds for panel budgets
- Passing an allocation or bounds object with missing coordinates
- Providing a
budget_distribution_over_periodthat does not sum to1