Configuration Schema
Configuration Schema Reference¶
This document provides a comprehensive reference for the ABSESpy configuration schema. All configurations are managed through Hydra and use YAML format. The schema is designed to be simple, clear, and support both single-run experiments and parameter sweeps.
Overview¶
ABSESpy uses a hierarchical configuration system based on OmegaConf (via Hydra). The configuration file is organized into four core sections:
time- Time driver configurationexp- Experiment management settingsmodel- All model parameterstracker- Data collection and tracking configuration
Basic Configuration Structure¶
defaults:
- default
- _self_
# 1. Time driver configuration
time:
start: "2020-01-01"
end: 100
# 2. Experiment management
exp:
name: my_experiment
repeats: 1
seed: 42
# 3. Model parameters
model:
density: 0.7
n_agents: 50
# 4. Data tracking
tracker:
model: {}
agents: {}
final: {}
Table of Contents¶
- 1. Time Configuration
- 2. Experiment Configuration
- 3. Model Parameters
- 4. Tracker Configuration
- 5. Logging Configuration
- Parameter Sweeps
- Complete Examples
- Best Practices
1. Time Configuration¶
The time section configures the simulation time driver. It controls when the simulation starts, ends, and how time progresses.
Time Schema¶
time:
# Start time (optional)
start: str | datetime | null # ISO format string or datetime, null = current time
# End condition (required for auto-stop)
end: int | str | datetime | null # int = max ticks, str/datetime = end date, null = no auto-stop
# Time step configuration (optional)
days: int # Duration in days
hours: int # Duration in hours
minutes: int # Duration in minutes
seconds: int # Duration in seconds
# Advanced options
irregular: bool # Enable irregular time mode (default: false)
Examples¶
Simple: Maximum Steps¶
Calendar Time¶
Duration Mode¶
Combined¶
time:
start: "2020-01-01"
end: 200 # Or stop at 200 ticks, whichever comes first
days: 1 # Each step = 1 day
Time Configuration Reference¶
| Parameter | Type | Default | Description |
|---|---|---|---|
start |
str/datetime/null | Current time | Simulation start time (ISO format) |
end |
int/str/datetime/null | null | End condition: int=tick limit, str/datetime=end date |
days |
int | 0 | Time step duration in days |
hours |
int | 0 | Time step duration in hours |
minutes |
int | 0 | Time step duration in minutes |
seconds |
int | 0 | Time step duration in seconds |
irregular |
bool | false | Enable irregular time mode |
2. Experiment Configuration¶
The exp section configures batch experiment settings, including repetitions, output management, and random seeds.
Experiment Schema¶
exp:
name: str # Experiment name
outdir: str # Output directory
repeats: int # Number of repetitions
seed: int | null # Base random seed (null = no seed)
logging: str | bool # Logging mode: "once" | "always" | false
Examples¶
Single Run¶
Batch Run with Repetitions¶
exp:
name: "batch_experiment"
outdir: "outputs"
repeats: 11 # Run 11 times with different seeds
seed: 42 # Base seed for reproducibility
logging: "once" # Log only first repeat
Experiment Configuration Reference¶
| Parameter | Type | Default | Description |
|---|---|---|---|
name |
str | "ABSESpy" | Experiment name (used in output paths) |
outdir |
str | "out" | Output directory for results |
repeats |
int | 1 | Number of repetitions (each with different seed) |
seed |
int/null | null | Base random seed (null = no seeding) |
logging |
str/bool | "once" | Logging mode: "once", "always", or false |
3. Model Parameters¶
The model section contains all model-specific parameters. These can be accessed in your model code via model.params or model.p.
Basic Model Parameters¶
Nested Parameters¶
Organize parameters hierarchically for better structure:
model:
grid:
width: 100
height: 100
torus: true
agents:
sheep:
initial_count: 100
reproduction_rate: 0.1
wolves:
initial_count: 20
reproduction_rate: 0.05
environment:
temperature: 20.0
humidity: 0.6
Access in code:
Parameter Types¶
| Type | Example | Description |
|---|---|---|
int |
42 |
Integer values |
float |
3.14 |
Floating-point numbers |
str |
"hello" |
String values |
bool |
true |
Boolean values |
list |
[1, 2, 3] |
Lists/arrays |
dict |
{key: value} |
Nested dictionaries |
Parameter Ranges (for Sweeps)¶
Define parameter ranges for automated parameter sweeps:
model:
density:
value: 0.7 # Default/single value
min: 0.5 # Minimum for sweep
max: 0.9 # Maximum for sweep
step: 0.1 # Step size
n_agents:
value: 50
min: 10
max: 100
step: 10
Note: When using parameter sweeps with Hydra, you'll use the sweeper syntax (see Parameter Sweeps section).
4. Tracker Configuration¶
The tracker section (formerly reports) defines what data to collect during simulation. It supports three types of tracking:
- Model trackers: Collect model-level metrics at each step
- Agent trackers: Collect agent-level attributes at each step
- Final trackers: Collect metrics only at the end of simulation
Tracker Schema¶
tracker:
# Model-level trackers (collected every step)
model:
metric_name: "attribute_name" # Simple format
# OR (future extension)
metric_name:
source: "attribute_name"
alias: "custom_name"
# Agent-level trackers (collected every step)
agents:
AgentBreedName: # Agent class name (exact match)
attribute_name: "attribute_name"
# OR (future extension)
attribute_name:
source: "attribute_name"
alias: "custom_name"
aggregate: "mean" # Optional: mean, sum, count, min, max, std
# Final trackers (collected only at end)
final:
final_metric: "method_name"
Simple Format (Recommended)¶
The simplest and most common format uses a string that references an attribute or method name:
tracker:
model:
n_sheep: "n_sheep" # Collects model.n_sheep at each step
n_wolves: "n_wolves" # Collects model.n_wolves at each step
population_ratio: "population_ratio" # Collects model.population_ratio
agents:
Sheep: # Agent breed name (class name)
energy: "energy" # Collects agent.energy for all Sheep
age: "age" # Collects agent.age for all Sheep
Wolf:
energy: "energy"
hunger: "hunger"
final:
burned_rate: "burned_rate" # Calls model.burned_rate() at end
total_agents: "total_agents"
Model Trackers¶
Model trackers collect data from the model instance at each simulation step.
Requirements:
- The referenced attribute/method must exist on your model class
- Methods should take no arguments (or only self)
- Should return a scalar value (int, float, bool, str)
Example Model Class:
class MyModel(MainModel):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.n_sheep = 0
self.n_wolves = 0
@property
def population_ratio(self) -> float:
"""Calculate sheep to wolf ratio."""
if self.n_wolves == 0:
return 0.0
return self.n_sheep / self.n_wolves
def total_population(self) -> int:
"""Get total population."""
return self.n_sheep + self.n_wolves
Corresponding Config:
tracker:
model:
n_sheep: "n_sheep" # Property access
n_wolves: "n_wolves" # Property access
population_ratio: "population_ratio" # Property access
total_population: "total_population" # Method call
Agent Trackers¶
Agent trackers collect data from agent instances at each step.
Requirements: - The breed name must match the agent class name exactly (case-sensitive) - The referenced attribute must exist on the agent class - Attributes should be scalar values
Data Type Handling:
When using the Aim tracker backend (backend: aim), agent variables are automatically handled based on their data types:
-
Numeric types (int, float): Recorded as Distribution objects in Aim, allowing you to visualize the full distribution of values across agents (histograms, density plots, etc.). This preserves the heterogeneity of agent attributes.
-
Boolean types: Converted to 0/1 and recorded as Distribution, with additional statistics (true_count, true_ratio).
-
String types (categorical): Recorded as frequency statistics:
{breed}.{attribute}.unique_count- Number of unique categories{breed}.{attribute}.most_common_count- Count of most common category{breed}.{attribute}.most_common_ratio- Ratio of most common category{breed}.{attribute}.{category}_count- Count for each category (if ≤10 categories)
Aim Tracker Configuration:
tracker:
backend: aim
aim:
experiment: "my_experiment"
repo: "./aim_repo" # Optional, defaults to ~/.aim
distribution_bin_count: 64 # Optional, default 64, range 1-512
log_categorical_stats: true # Optional, default true
Example Agent Classes:
class Sheep(Actor):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.energy = 50
self.age = 0
@property
def is_alive(self) -> bool:
return self.energy > 0
class Wolf(Actor):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.energy = 100
self.hunger = 0.0
Corresponding Config:
tracker:
agents:
Sheep: # Must match class name exactly
energy: "energy"
age: "age"
is_alive: "is_alive" # Property access
Wolf:
energy: "energy"
hunger: "hunger"
Final Trackers¶
Final trackers are called once at the end of the simulation.
Requirements:
- Should be a method on the model class
- Method should take no arguments (or only self)
- Can return any type (will be stored as-is)
Example:
class MyModel(MainModel):
def burned_rate(self) -> float:
"""Calculate final burn rate."""
burned = self.nature.select({"state": "burned"})
total = len(self.nature.cells)
return len(burned) / total if total > 0 else 0.0
Corresponding Config:
Agent Variable Distribution Tracking (Aim Backend)¶
When using the Aim tracker backend, agent variables are tracked as distributions rather than simple aggregates. This allows you to:
- Visualize heterogeneity: See the full distribution of agent attributes, not just mean/min/max
- Track changes over time: Observe how distributions evolve during simulation
- Compare runs: Compare distributions across different parameter settings
Example:
tracker:
backend: aim
aim:
experiment: "flood_adaptation_abm"
agents:
City:
budget: budget
population: population
Individual:
wealth: wealth
moved: moved # Boolean
status: status # String/categorical
In Aim UI, you'll see:
- City.budget as a distribution (histogram) showing the full range of budgets
- City.population as a distribution
- Individual.wealth as a distribution
- Individual.moved as a distribution (0/1) plus Individual.moved.true_count and Individual.moved.true_ratio
- Individual.status as frequency statistics (unique_count, most_common_count, etc.)
Configuration Options:
distribution_bin_count(default: 64, range: 1-512): Number of bins for Distribution histogramslog_categorical_stats(default: true): Whether to log statistics for string/categorical variables
Common Tracker Errors¶
| Error | Cause | Solution |
|---|---|---|
AttributeError: 'MyModel' has no attribute 'n_sheep' |
Attribute doesn't exist | Check attribute name spelling |
KeyError: 'Sheep' |
Agent breed name mismatch | Use exact class name (case-sensitive) |
| Empty DataFrame | No trackers defined | Add at least one tracker |
TypeError: 'str' object is not callable |
Tried to call a string | Use method name without quotes in code |
ValueError: distribution_bin_count must be... |
Invalid bin_count value | Use integer between 1 and 512 |
5. Logging Configuration¶
ABSESpy provides a unified logging configuration on top of Python's standard logging
and Hydra's job_logging. This section summarizes the YAML fields that control
logging behaviour in ABSESpy projects.
There are three main configuration entry points:
- Unified
logsection (recommended, new style) - Experiment-level
exp.loggingflag (simple mode, kept for compatibility) - Legacy
logshorthand in old examples (deprecated but still supported)
5.1 Unified log section (recommended)¶
The unified log section is defined in the core config and can be
overridden in your experiment config (for example in examples/fire_spread/config.yaml).
It controls both experiment-level logging and per-run logging:
log:
# Logging mode for repeated runs: once | separate | merge
mode: str # "once" | "separate" | "merge"
# Experiment-level logging (progress, high-level summary)
exp:
stdout:
enabled: bool # Enable experiment logs to console
level: str # e.g. "INFO", "DEBUG"
format: str # Log format string
datefmt: str # Time format
file:
enabled: bool # Enable experiment log file
level: str # File log level
format: str # File log format
datefmt: str # File time format
# Run-level logging (each model execution)
run:
stdout:
enabled: bool # Enable per-run logs to console
level: str
format: str
datefmt: str
file:
enabled: bool # Enable per-run log files
level: str
format: str
datefmt: str
name: str # Base log file name (without extension)
rotation: str | null # e.g. "1 day", "100 MB", null = no rotation
retention: str | null# e.g. "10 days", null = default policy
mesa:
level: str | null # If null, uses run.file.level
format: str | null # If null, uses run.file.format
5.1.1 log.mode¶
Controls how repeated runs share log files:
| Value | Behaviour |
|---|---|
"once" |
Only the first repeat writes to the log file |
"separate" |
Each repeat writes to its own file with an index suffix |
"merge" |
All repeats write to the same log file |
5.1.2 Experiment-level logging (log.exp.*)¶
Experiment-level logging is intended for high-level progress and summaries, not per-step model details.
| Field | Type | Description |
|---|---|---|
log.exp.stdout.enabled |
bool | Enable experiment messages on console |
log.exp.stdout.level |
str | Console log level (e.g. "INFO") |
log.exp.stdout.format |
str | Console log format string |
log.exp.stdout.datefmt |
str | Console time format |
log.exp.file.enabled |
bool | Enable experiment log file |
log.exp.file.level |
str | Experiment file log level |
log.exp.file.format |
str | Experiment file log format |
log.exp.file.datefmt |
str | Experiment file time format |
5.1.3 Run-level logging (log.run.*)¶
Run-level logging controls logging for each single model run:
| Field | Type | Description |
|---|---|---|
log.run.stdout.enabled |
bool | Enable per-run console logging |
log.run.stdout.level |
str | Per-run console log level |
log.run.stdout.format |
str | Per-run console log format |
log.run.stdout.datefmt |
str | Per-run console time format |
log.run.file.enabled |
bool | Enable per-run log files |
log.run.file.level |
str | Per-run file log level (e.g. "DEBUG") |
log.run.file.format |
str | Per-run file log format |
log.run.file.datefmt |
str | Per-run file time format |
log.run.file.name |
str | Base file name for logs (without extension) |
log.run.file.rotation |
str/null | Rotation policy, e.g. "1 day", "100 MB" |
log.run.file.retention |
str/null | Retention policy, e.g. "10 days" |
log.run.mesa.level |
str/null | Log level for Mesa loggers; null uses log.run.file.level |
log.run.mesa.format |
str/null | Log format for Mesa; null uses log.run.file.format |
Recommended: For most projects, start by modifying only: -
log.mode-log.exp.file.enabled-log.run.file.enabled-log.run.file.leveland keep the default formats unless you have special formatting needs.
5.2 Experiment-level exp.logging flag (compatibility)¶
The exp.logging field (described in 2. Experiment Configuration)
is a simpler, older switch that controls logging behaviour at the experiment level:
| Value | Behaviour |
|---|---|
"once" |
Log only the first repeat |
"always" |
Log all repeats |
false |
Disable logging for repeats (where supported) |
This flag is kept for backward compatibility. New projects should prefer the unified
logsection, which gives you explicit control over console/file logging at both experiment and run levels.
5.3 Legacy log shorthand in examples¶
Some older example configs (such as examples/wolf_sheep/config.yaml
and examples/schelling/config.yaml) use a simplified log section:
log:
name: str # Base log file name
level: str # Global log level, e.g. "INFO"
console: bool # Enable/disable console logging
file: bool # (optional) Enable/disable file logging
These fields are normalized internally to the new unified logging schema and
are maintained for compatibility with older projects. For new models, prefer
defining log.mode, log.exp.* and log.run.* instead of this shorthand.
Parameter Sweeps¶
ABSESpy supports parameter sweeps for automated batch experiments using Hydra's sweeper. You can define parameter ranges that Hydra will automatically expand into all combinations.
Using Hydra Sweeper¶
Define parameter ranges in your config and use Hydra's sweeper syntax:
# config.yaml
defaults:
- default
- _self_
# Base parameter values
model:
density: 0.7
n_agents: 50
# Hydra sweeper configuration
hydra:
sweeper:
params:
model.density: "range(0.5, 0.9, 0.1)" # 5 values: 0.5, 0.6, ..., 0.9
model.n_agents: "range(10, 100, 10)" # 10 values: 10, 20, ..., 100
# Total: 5 × 10 = 50 combinations
Run with:
Range Syntax¶
hydra:
sweeper:
params:
# Integer range: range(start, stop, step)
model.n_agents: "range(10, 100, 10)"
# Float range: range(start, stop, step)
model.density: "range(0.5, 0.9, 0.1)"
# Discrete values: [value1, value2, ...]
model.reproduction_rate: "[0.05, 0.1, 0.15, 0.2]"
Multiple Parameter Combinations¶
Hydra generates all combinations automatically:
hydra:
sweeper:
params:
model.density: "range(0.5, 0.9, 0.1)" # 5 values
model.n_agents: "range(10, 100, 10)" # 10 values
model.reproduction_rate: "[0.05, 0.1, 0.2]" # 3 values
# Total: 5 × 10 × 3 = 150 combinations
Nested Parameter Sweeps¶
model:
agents:
sheep:
reproduction_rate: 0.1
initial_energy: 50
hydra:
sweeper:
params:
model.agents.sheep.reproduction_rate: "range(0.05, 0.2, 0.05)"
model.agents.sheep.initial_energy: "range(30, 70, 10)"
Accessing Swept Parameters in Code¶
When using parameter sweeps, access the actual value in your model:
class MyModel(MainModel):
def initialize(self):
# Hydra will set the actual value for each run
density = self.params.density # Could be 0.5, 0.6, ..., 0.9
n_agents = self.params.n_agents # Could be 10, 20, ..., 100
# Use in your model logic
self.create_agents(n_agents, density)
Complete Examples¶
Example 1: Simple Model¶
defaults:
- default
- _self_
# Time: Run for 100 steps
time:
end: 100
# Experiment: Single run
exp:
name: simple_model
outdir: outputs
repeats: 1
# Model: Basic parameters
model:
name: "SimpleModel"
shape: [50, 50]
n_agents: 100
# Tracker: Basic data collection
tracker:
model:
n_agents: "n_agents"
step_count: "time.tick"
agents:
Actor:
unique_id: "unique_id"
final:
total_steps: "time.tick"
Example 2: Parameter Sweep Experiment¶
defaults:
- default
- _self_
# Time: Calendar time simulation
time:
start: "2020-01-01"
end: 365
days: 1 # Each step = 1 day
# Experiment: Batch run with repetitions
exp:
name: parameter_sweep
outdir: outputs
repeats: 5
seed: 42
# Model: Parameters with ranges
model:
density:
value: 0.7
min: 0.5
max: 0.9
step: 0.1
n_agents:
value: 50
min: 20
max: 100
step: 20
# Tracker: Comprehensive tracking
tracker:
model:
density: "params.density"
n_agents: "params.n_agents"
population: "agents.count"
final:
final_population: "agents.count"
# Hydra sweeper configuration
hydra:
sweeper:
params:
model.density: "range(0.5, 0.9, 0.1)"
model.n_agents: "range(20, 100, 20)"
Example 3: Complex Ecosystem Model¶
defaults:
- default
- _self_
# Time: One year simulation
time:
start: "2020-01-01"
end: 365
days: 1
# Experiment: Multiple repetitions
exp:
name: ecosystem_simulation
outdir: outputs
repeats: 11
seed: 42
logging: "once"
# Model: Hierarchical parameters
model:
grid:
width: 100
height: 100
torus: true
agents:
sheep:
initial_count: 100
reproduction_rate: 0.1
initial_energy: 50
wolves:
initial_count: 20
reproduction_rate: 0.05
initial_energy: 100
environment:
grass_growth_rate: 0.2
initial_grass_coverage: 0.8
# Tracker: Multi-level tracking
tracker:
model:
n_sheep: "n_sheep"
n_wolves: "n_wolves"
grass_coverage: "grass_coverage"
population_ratio: "population_ratio"
agents:
Sheep:
energy: "energy"
age: "age"
is_alive: "is_alive"
Wolf:
energy: "energy"
hunger: "hunger"
is_alive: "is_alive"
final:
final_sheep_count: "n_sheep"
final_wolf_count: "n_wolves"
survival_rate: "calculate_survival_rate"
Best Practices¶
1. Organize Parameters Hierarchically¶
# ✅ Good: Organized by component
model:
grid:
width: 100
height: 100
agents:
sheep: {...}
wolves: {...}
# ❌ Bad: Flat structure
model:
grid_width: 100
grid_height: 100
sheep_count: 100
wolf_count: 20
2. Use Descriptive Names¶
# ✅ Good: Clear names
tracker:
model:
sheep_population: "n_sheep"
wolf_population: "n_wolves"
# ❌ Bad: Unclear names
tracker:
model:
s: "n_sheep"
w: "n_wolves"
3. Match Agent Breed Names Exactly¶
# ✅ Good: Exact class name match
tracker:
agents:
Sheep: # Must match class name exactly
energy: "energy"
# ❌ Bad: Name mismatch
tracker:
agents:
sheep: # Wrong: lowercase
energy: "energy"
4. Document Custom Parameters¶
model:
# Reproduction probability per step
reproduction_rate: 0.1
# Initial energy for new agents
initial_energy: 50
5. Define Parameter Ranges for Future Sweeps¶
Even if not using sweeper immediately, define ranges:
6. Keep Configurations Simple¶
Start with simple tracker format, upgrade to advanced format only when needed:
# ✅ Good: Simple and clear
tracker:
model:
n_sheep: "n_sheep"
# ⚠️ Advanced: Only when needed
tracker:
model:
n_sheep:
source: "n_sheep"
alias: "sheep_count"
Configuration Quick Reference¶
Minimal Configuration¶
Full Configuration Template¶
defaults:
- default
- _self_
# Time driver
time:
start: "2020-01-01"
end: 365
days: 1
# Experiment management
exp:
name: my_experiment
outdir: outputs
repeats: 1
seed: 42
logging: "once"
# Model parameters
model:
# Your parameters here
param1: value1
param2: value2
# Data tracking
tracker:
model:
metric1: "attribute1"
agents:
AgentBreed:
attr1: "attr1"
final:
final_metric: "method_name"
# Parameter sweeps (optional)
hydra:
sweeper:
params:
model.param1: "range(min, max, step)"
Troubleshooting¶
Configuration Not Loading¶
Problem: Config file not found or not loading.
Solutions:
- Check file path in config_path
- Ensure YAML syntax is correct (use a YAML validator)
- Check Hydra defaults list includes default and _self_
Tracker Not Collecting Data¶
Problem: Empty DataFrames or missing columns.
Solutions:
- Verify attribute/method names match exactly (case-sensitive)
- Check that attributes exist on model/agent classes
- Ensure trackers are defined in tracker section
- Check logs for validation warnings
Parameter Sweep Not Working¶
Problem: Sweeper not generating combinations.
Solutions:
- Verify Hydra sweeper configuration
- Check parameter range syntax: range(min, max, step)
- Ensure --multirun flag is used
- Check Hydra output directory for generated configs
Agent Breed Name Not Found¶
Problem: KeyError when accessing agent trackers.
Solutions: - Ensure breed name matches class name exactly (case-sensitive) - Check that agents of that breed exist in the model - Verify agent class is properly registered
Migration from Old Schema¶
From reports to tracker¶
The reports section has been renamed to tracker for clarity. The old name is still supported for backward compatibility but will be normalized automatically.
Old (still works):
New (recommended):
From agent to agents¶
The deprecated agent key is automatically normalized to agents.
Old (still works):
New (recommended):
See Also¶
- Getting Started Guide - Basic usage
- Parameter Management Tutorial - Hands-on examples
- Experiment API - Batch experiment details
- Time Control API - Time driver details
- Hydra Documentation - Hydra framework reference