Arenas and Substrates

This page covers environment configuration: arena geometry, food sources, odorscapes, and obstacles.


Arena Types

Circular Arena (Petri Dish)

Default: dish (100 mm diameter)

from larvaworld.lib import reg

# Preconfigured circular arena (dims are in meters)
env_params = reg.conf.Env.getID("dish").get_copy()
print(env_params.arena.geometry, env_params.arena.dims)  # circular (0.1, 0.1)

Rectangular Arena

from larvaworld.lib import reg

# Preconfigured rectangular arena (200 mm x 200 mm)
env_params = reg.conf.Env.getID("arena_200mm").get_copy()
print(env_params.arena.geometry, env_params.arena.dims)  # rectangular (0.2, 0.2)

Preconfigured Arenas

from larvaworld.lib import reg

# List available arenas
env_ids = reg.conf.Env.confIDs
print(env_ids)

# Load arena
env_conf = reg.conf.Env.getID("arena_200mm").get_copy()

Food Sources

Larvaworld supports three types of food distributions:

1. Discrete Patches

Purpose: Localized food sources

from larvaworld.lib import reg

env_params = reg.conf.Env.getID("arena_200mm").get_copy()

# Create 3 food patches (group generator creates N individual sources)
env_params.food_params.source_groups = {
    "patches": {
        "N": 3,  # number of patches
        "mode": "uniform",
        "shape": "rect",
        "loc": (0.0, 0.0),
        "scale": (0.07, 0.07),
        "radius": 0.005,  # 5 mm
        "amount": 3.0,
        "substrate": {"type": "standard", "quality": 1.0},
        "color": "green",
    }
}

2. Food Grid

Purpose: Regular grid of patches

from larvaworld.lib import reg

env_params = reg.conf.Env.getID("arena_200mm").get_copy()

# Place food patches on a regular grid
env_params.food_params.source_groups = {
    "grid": {
        "N": 16,  # total patches (e.g., 4x4)
        "mode": "grid",
        "shape": "rect",
        "loc": (0.0, 0.0),
        "scale": (0.2, 0.2),
        "radius": 0.003,
        "amount": 3.0,
        "substrate": {"type": "standard", "quality": 1.0},
        "color": "green",
    }
}

3. Uniform Substrate

Purpose: Continuous nutritious substrate

from larvaworld.lib import reg

env_params = reg.conf.Env.getID("arena_200mm").get_copy()
env_params.food_params.source_groups = {}
env_params.food_params.source_units = {}
env_params.food_params.food_grid = {
    "grid_dims": (51, 51),
    "initial_value": 1e-6,
    "substrate": {"type": "standard", "quality": 1.0},
}

Nutritious Substrates

Larvaworld implements real experimental substrates.

The following table reproduces the compound densities reported in the Larvaworld paper (see Citing larvaworld).

Substrate

Glucose (μg/ml)

Yeast (μg/ml)

Agar (μg/ml)

Source

standard-medium

100

50

16

Kaun et al. (2007)

PED-tracker

10*

187.5

5000

Schumann et al. (2020)

cornmeal

70.3**

14.1

6.6

Wosniack et al. (2021)

sucrose

17.1

0

4

Wosniack et al. (2021)

*Saccharose instead of glucose **Dextrose instead of glucose

In Larvaworld configuration, these correspond to Substrate.type values:

  • standard-mediumstandard

  • PED-trackerPED_tracker

  • cornmealcornmeal

  • sucrosesucrose

Usage:

from larvaworld.lib import reg

env_params = reg.conf.Env.getID("arena_200mm").get_copy()
env_params.food_params.food_grid = {
    "grid_dims": (51, 51),
    "initial_value": 1e-6,
    "substrate": {"type": "standard", "quality": 1.0},
}

Odorscapes

Odor layers are created from sources (food patches) that have an odor.id. To enable odor diffusion, set env_params.odorscape to "Gaussian" or "Diffusion".

from larvaworld.lib import reg

env_params = reg.conf.Env.getID("arena_200mm").get_copy()
env_params.odorscape = {"odorscape": "Gaussian", "grid_dims": (51, 51)}

# One odorized food patch produces an odor layer with id="apple"
env_params.food_params.source_units = {
    "apple_patch": {
        "pos": (0.02, 0.0),
        "radius": 0.005,
        "amount": 3.0,
        "odor": {"id": "apple", "intensity": 1.0, "spread": 0.02},
        "substrate": {"type": "standard", "quality": 1.0},
        "color": "green",
        "regeneration": False,
    }
}

Obstacles and Borders

Arena Borders

from larvaworld.lib import reg

env_params = reg.conf.Env.getID("arena_200mm").get_copy()

# Borders are configured via env_params.border_list.
# Vertices are interpreted as pairs of points (p0,p1), (p1,p2), ... (p3,p0):
p0, p1, p2, p3 = (-0.1, -0.1), (0.1, -0.1), (0.1, 0.1), (-0.1, 0.1)
env_params.border_list = {
    "wall0": {
        "vertices": [p0, p1, p1, p2, p2, p3, p3, p0],
        "width": 0.001,
    }
}

Larva Initial Placement

Control where larvae start:

larva_groups = {
    "explorers": {
        "model": "explorer",
        "distribution": {
            "N": 20,
            "mode": "uniform",       # Distribution mode
            "loc": (0.0, 0.0),       # center (meters)
            "scale": (0.01, 0.01),   # spread (meters)
            "shape": "circle",
        },
    }
}

Distribution Modes

Mode

Description

"uniform"

Uniform random within shape

"periphery"

Ring around center

"line"

Linear arrangement

"grid"

Regular grid

See Table 4 for details.


Complete Example

from larvaworld.lib import reg
from larvaworld.lib.sim import ExpRun
from larvaworld.lib.util import AttrDict

# Start from a built-in experiment template and override env/larvae
exp_params = reg.conf.Exp.getID("dish").get_copy()

env_params = reg.conf.Env.getID("arena_200mm").get_copy()
env_params.odorscape = {"odorscape": "Gaussian", "grid_dims": (51, 51)}
env_params.food_params.source_units = {
    "food_patch": {
        "pos": (0.02, 0.0),
        "radius": 0.008,
        "amount": 3.0,
        "odor": {"id": "food_odor", "intensity": 1.0, "spread": 0.03},
        "substrate": {"type": "standard", "quality": 1.0},
        "color": "green",
    }
}

exp_params.env_params = env_params
exp_params.larva_groups = AttrDict(
    {
        "foragers": AttrDict(
            {
                "model": "forager",
                "distribution": {
                    "N": 5,
                    "mode": "periphery",
                    "shape": "circle",
                    "loc": (0.0, 0.0),
                    "scale": (0.08, 0.08),
                },
            }
        )
    }
)

run = ExpRun(experiment="dish", parameters=exp_params, duration=0.2, screen_kws={})
run.simulate()