determine the required amount of sensor-equipped vehicles to achieve a sufficient environmental monitoring coverage in a city
  • Python 66.7%
  • R 23%
  • Shell 4.8%
  • Makefile 3.1%
  • Dockerfile 1.3%
  • Other 1.1%
Find a file
Fabian Missbrenner a3cfc0d417 Add CO2 field reconstruction artifact
Cache the minute-level SUMO emission field and road geometry, render the busy/calm CO2 animation in notebook 7, and prepare the inert reconstruction sweep with CI wiring.
2026-07-24 15:47:11 +02:00
.forgejo/workflows Add CO2 field reconstruction artifact 2026-07-24 15:47:11 +02:00
cache Add CO2 field reconstruction artifact 2026-07-24 15:47:11 +02:00
doc Add slides for November 2025 research meeting 2026-07-23 16:10:49 +02:00
graphics Add CO2 field reconstruction artifact 2026-07-24 15:47:11 +02:00
lib De-clutter file structure and enable CI (#2) 2025-08-27 11:16:55 +00:00
out Switch to 'visited in time bin' metric (#12) 2025-09-11 11:31:28 +00:00
selection Record negative vehicle-selection result 2026-07-20 15:56:07 +02:00
src Add CO2 field reconstruction artifact 2026-07-24 15:47:11 +02:00
tabpfn Harden TabPFN speed benchmark 2026-07-20 16:02:51 +02:00
.1_session-info.txt Record R (package) versions for reproducibility purposes (#14) 2025-09-12 13:58:39 +00:00
.2_session-info.txt Record R (package) versions for reproducibility purposes (#14) 2025-09-12 13:58:39 +00:00
.3_session-info.txt Record R (package) versions for reproducibility purposes (#14) 2025-09-12 13:58:39 +00:00
.4_session-info.txt Record R (package) versions for reproducibility purposes (#14) 2025-09-12 13:58:39 +00:00
.5_session-info.txt Record R (package) versions for reproducibility purposes (#14) 2025-09-12 13:58:39 +00:00
.6_session-info.txt Record R (package) versions for reproducibility purposes (#14) 2025-09-12 13:58:39 +00:00
.7_session-info.txt Add CO2 field reconstruction artifact 2026-07-24 15:47:11 +02:00
.gitattributes Add CO2 field reconstruction artifact 2026-07-24 15:47:11 +02:00
.gitignore Add CO2 field reconstruction artifact 2026-07-24 15:47:11 +02:00
.gitmodules De-clutter file structure and enable CI (#2) 2025-08-27 11:16:55 +00:00
.lfsconfig Prepare envmon handover clone path 2026-06-09 21:03:16 +00:00
1-AoI_Raster.html Make notebooks distinguishable by name 2025-09-04 16:52:37 +02:00
1-AoI_Raster.Rmd Record R (package) versions for reproducibility purposes (#14) 2025-09-12 13:58:39 +00:00
2-Per-Cell_AoI.html Make notebooks distinguishable by name 2025-09-04 16:52:37 +02:00
2-Per-Cell_AoI.Rmd Record R (package) versions for reproducibility purposes (#14) 2025-09-12 13:58:39 +00:00
3-Parameter_Study.Rmd Record R (package) versions for reproducibility purposes (#14) 2025-09-12 13:58:39 +00:00
4-Required_Penetration.html Make notebooks distinguishable by name 2025-09-04 16:52:37 +02:00
4-Required_Penetration.Rmd Record R (package) versions for reproducibility purposes (#14) 2025-09-12 13:58:39 +00:00
5-Cell_Reachability.html Switch to 'visited in time bin' metric (#12) 2025-09-11 11:31:28 +00:00
5-Cell_Reachability.Rmd Record R (package) versions for reproducibility purposes (#14) 2025-09-12 13:58:39 +00:00
6-No_AoI.html Switch to 'visited in time bin' metric (#12) 2025-09-11 11:31:28 +00:00
6-No_AoI.Rmd Record R (package) versions for reproducibility purposes (#14) 2025-09-12 13:58:39 +00:00
7-Field_Reconstruction.html Add CO2 field reconstruction artifact 2026-07-24 15:47:11 +02:00
7-Field_Reconstruction.Rmd Add CO2 field reconstruction artifact 2026-07-24 15:47:11 +02:00
AGENTS.md Document pivot from AoI to visit-based slot-coverage metric 2026-07-23 15:52:18 +02:00
Containerfile Prepare envmon handover clone path 2026-06-09 21:03:16 +00:00
envmon.emissions.add.xml Add CO2 field reconstruction artifact 2026-07-24 15:47:11 +02:00
envmon.sif Switch to 'visited in time bin' metric (#12) 2025-09-11 11:31:28 +00:00
envmon.sumocfg Add CO2 field reconstruction artifact 2026-07-24 15:47:11 +02:00
Makefile Add CO2 field reconstruction artifact 2026-07-24 15:47:11 +02:00
parallel.sbatch Switch to 'visited in time bin' metric (#12) 2025-09-11 11:31:28 +00:00
README.md Add ranked future-directions table to README 2026-07-23 16:03:20 +02:00
reconstruct.sbatch Add CO2 field reconstruction artifact 2026-07-24 15:47:11 +02:00
VERSIONS Prepare envmon handover clone path 2026-06-09 21:03:16 +00:00

envmon

R-based geospatial analysis of sensing coverage in vehicular sensor networks. Uses SUMO traffic simulation traces from the Luxembourg LuST scenario to study how well moving vehicles can keep grid cells supplied with sensor readings (e.g. CO2 pollution). The core question: what penetration rate of sensor-equipped vehicles is needed to guarantee at least N visited time slots per hour for at least X percent of the cells of a city grid?

Metric. Each observation hour is divided into twelve 5-minute slots; a cell counts as visited in a slot if at least one equipped vehicle records a position inside it (notebook 6). The project initially measured freshness as Age of Information (AoI), but AoI was dropped as the primary metric because a cell's peak AoI is censored by the observation window: its value depends on when the last vehicle leaves the cell within the hour (see the discussion in 6-No_AoI.Rmd). Notebooks 1-4 document the earlier AoI line and are retained for reference.

Prerequisites

Dependency Notes
R 4.x The Containerfile pins ghcr.io/rocker-org/geospatial:4.5.1 for local container builds; local installs need the packages listed there
Podman (or Docker) For containerised builds; skip if using LOCAL_R=1
Git LFS Default hydration is about 8 GiB after excluding envmon.sif; notebooks use the full LuST trace and precomputed result Parquet files
csv2parquet From domoritz/arrow-tools — used in the data pipeline
SUMO 1.8.0 Only needed to regenerate the raw trace; lib/sumo is a source submodule and must be built before lib/sumo/bin/sumo exists

Getting Started

Committed *.html files are the fastest review path. Rendering notebooks is the reproducibility check.

# Clone the public repository
git clone https://code.fabimi.net/luna/envmon.git
cd envmon

# Pull LFS objects
git lfs install
git lfs pull

# Optional: retrieve the Singularity image for SLURM/HPC use
git lfs pull -I envmon.sif

Optional submodules

Only needed for the Data Pipeline; not needed to render notebooks from committed LFS data.

git submodule update --init lib/LuSTScenario lib/sumo
make container.exists              # build the Podman image
make PODMAN=docker container.exists # build with Docker
make 1-AoI_Raster.html             # render a notebook inside the container

Local R

Install the R packages listed in the Containerfile, then prefix commands with LOCAL_R=1:

LOCAL_R=1 make 6-No_AoI.html

Data Pipeline

Optional: cache/envmon.parquet is committed via LFS, so reviewers do not need to run SUMO before rendering notebooks.

The trace data is produced in three sequential steps (each target depends on the previous):

SUMO simulation ──► FCD XML ──► CSV ──► Parquet
make out/envmon.fcd.xml    # 1. Run SUMO → Floating Car Data XML
make out/envmon.csv        # 2. xml2csv.py → semicolon-delimited CSV
make cache/envmon.parquet  # 3. csv2parquet → Parquet (used by notebooks)

make out/envmon.fcd.xml requires a built SUMO binary at lib/sumo/bin/sumo; make out/envmon.csv uses SUMO's tools/xml/xml2csv.py; make cache/envmon.parquet requires csv2parquet.

Analysis Notebooks

Notebooks 1-4 use the superseded AoI metric; notebook 5 (reachability) supports both metrics; notebook 6 defines the current visit-based metric.

# File Purpose Key Parameters
1 1-AoI_Raster.Rmd Single-vehicle AoI visualisation on a raster grid frame_duration
2 2-Per-Cell_AoI.Rmd Per-cell AoI for sampled vehicle subsets penetration_rate
3 3-Parameter_Study.Rmd Compute-heavy sweep under default params (seq_len(10) × c(0.1,0.3,0.7,0.9) × 10 workers) repetitions, penetration_rates, no_workers
4 4-Required_Penetration.Rmd Determine the required penetration rate (loads pre-computed results)
5 5-Cell_Reachability.Rmd Grid cell reachability analysis sample_size, time windows
6 6-No_AoI.Rmd Visit-based slot-coverage metric (current) slot_width, penetration_rate

3-Parameter_Study.html is intentionally not committed because the full default render is a parameter sweep; CI and smoke runs use reduced parameters.

Rendering

make 3-Parameter_Study.html                # full default sweep in the container
LOCAL_R=1 make 3-Parameter_Study.html      # full default sweep with local R

# Recommended smoke render for notebook 3
R --vanilla -e 'rmarkdown::render("3-Parameter_Study.Rmd", params=list(repetitions=seq(1), penetration_rates=c(0.001)))'

# Custom parameters
R --vanilla -e 'rmarkdown::render("2-Per-Cell_AoI.Rmd", params=list(penetration_rate=0.001))'

Extracting a standalone R script

make 3-Parameter_Study.R     # runs knitr::purl() to extract R code

Batch Processing (SLURM)

Batch runs for the current visit metric use the standalone script extracted from notebook 6 (make 6-No_AoI.R); it accepts the notebook parameters via optparse (including --slot_width) and writes one visits.parquet per run — the committed results under out/cell-visits/ were produced this way.

src/run-aoi.R is the equivalent CLI for the superseded AoI metric:

Rscript src/run-aoi.R \
  --penetration_rate 0.01 \
  --repetition 1 \
  --cell_size 200 \
  --crs 32632 \
  --busy_start 28800 --busy_end 32400 \
  --calm_start 57600 --calm_end 61200

Only --penetration_rate is required; the rest have sensible defaults. Output goes to out/{SLURM_ARRAY_JOB_ID}/{SLURM_ARRAY_TASK_ID}/ on a cluster, or out/local/{UUID}/ for local runs. Each run produces aoi.parquet, grid.shp, and session-info.txt.

See parallel.sbatch for the SLURM array job template; as committed it invokes src/run-aoi.R, so substitute the purled 6-No_AoI.R for visit-metric runs.

Project Structure

.
├── 1-AoI_Raster.Rmd … 6-No_AoI.Rmd   # analysis notebooks
├── Makefile                            # build automation
├── Containerfile                       # Podman/Docker image definition
├── VERSIONS                            # pinned tool versions
├── envmon.sumocfg                      # SUMO simulation config
├── parallel.sbatch                     # SLURM batch script
├── src/
│   ├── helpers.R                       # shared functions (loaders, grid, binning, AoI)
│   └── run-aoi.R                       # standalone CLI for batch AoI computation (superseded metric)
├── cache/                              # cached data (Parquet, RData, shapefiles)
├── out/                                # pipeline outputs and batch results
├── lib/
│   ├── sumo/                           # SUMO v1_8_0 (git submodule)
│   └── LuSTScenario/                   # Luxembourg traffic scenario (git submodule)
├── graphics/                           # generated figures plus tracked graphics/6/aoi-problem.png input illustration
└── doc/                                # presentations

CI

Forgejo Actions renders all six notebooks with reduced parameters on every pull request and uploads the HTML output as artifacts.

Future Directions

Candidate extensions toward publication, ranked by payoff:

Direction Core question Why it is strong Effort
Field reconstruction Does slot coverage guarantee accurate pollution maps? SUMO's emission model yields a ground-truth CO2 field generated by the very traffic being sampled; kriging/GP reconstruction error vs. penetration derives principled values for the ad-hoc constants (slot width 300 s, N = 6, X = 75 %) and is free of the window-censoring artifact that ruled out peak AoI Medium
Analytic thinning model Can required penetration be computed in closed form? Random equipping at rate p thins the full visit process, so P(cell c covered in slot s) = 1 (1 p)^m with m the number of distinct vehicles visiting (c, s) in the full trace — exact, replaces the repetition-based sweeps of notebooks 3/4/6, and the shared-vehicle dependence explains why ranking vehicles independently fails Low
Vehicle selection How few vehicles suffice if chosen well? Large oracle-vs-random headroom; the per-cell indicator 1{≥ N slots} is not submodular, but its truncation min(#slots, N) is, so lazy greedy carries a (1 1/e) guarantee on the surrogate; a learner should predict visit sets and marginal gain, not per-pair hits Medium
Multi-day generalization Does a selection made today still cover tomorrow? The selection objective is an expectation over future days, but LuST is a single synthetic day; perturbed SUMO demand seeds or real multi-day taxi traces make the claim testable Medium
Cross-city scaling Does required penetration transfer across cities? MoST, TAPASCologne, InTAS, or real taxi traces defuse the single-city objection; a scaling law against road density or urban form would be citable on its own High
Metric design How sensitive is the metric to its constants? Sweeps over slot width, N, X, and cell size (MAUP) plus a slot phase-shift check turn ad-hoc choices into defended ones Low
Fleet heterogeneity Which fleet mix buys coverage cheapest? Bus lines are repeatable, hence have predictable visit sets — ideal input for selection; budgeted equipping matches how real deployments work Medium
Micro-detour steering Can bounded detours rescue never-visited cells? Covering empty (cell, slot) pairs under a detour budget is budgeted set cover; motivated by the censored tail in notebook 5 High
Weighted coverage Coverage where it matters most Cell weights (population exposure) and slot weights (time-of-day exposure) drop directly into the coverage objective Low

Communication realism is deliberately out of scope: a 300 s slot tolerates minutes of upload delay by construction, so the abstraction is justified in prose rather than modeled (e.g. an ns-3/Veins coupling).