Data and code from: Hyperlocal sensing and inverse modeling reveal community impacts of urban air pollutant emissions
Data files
Sep 24, 2026 version files 16.76 GB
-
BC_Inverse_Repo_V1.1.zip
16.76 GB
-
README.md
18.89 KB
Abstract
Addressing urban air pollution requires identifying, quantifying, and mitigating emission sources, yet bottom-up inventories often lack fine spatiotemporal precision and rarely capture unpermitted or informally operated sources. We combine dense mobile and fixed-site measurements in a Bayesian inverse modeling framework to produce hourly, hyperlocal black carbon (BC) emission maps (150 m × 150 m) that reveal how and where key sources are underrepresented. In West Oakland, CA — an overburdened community near major freight infrastructure — our approach identifies underestimated and unaccounted emission sources, increasing estimated BC emissions by ~33%. These corrections quadruple the contribution of neighborhood and port-related sources to population-weighted exposures (from 5 to 20%), disproportionately affecting low-income neighborhoods adjacent to freight corridors. Our results demonstrate that combining dense observational data with inverse modeling enables detection and quantification of overlooked emissions, supporting targeted intervention. Sensitivity analyses indicate similar performance with a substantially reduced fixed-site network (~10 monitors; ~1 site / km2, compared with 6.7 sites/km2 in the full campaign), paired with time-averaged mobile maps, supporting applicability in data-limited urban settings.
Dataset DOI: 10.5061/dryad.0gb5mkmfx
Description of the data and file structure
This dataset supports the manuscript “Hyperlocal Sensing and Inverse Modeling Reveal Community Impacts of Urban Air Pollutant Emissions.” It contains the code and input data used for the inverse-modeling analysis of black carbon (BC) emissions in West Oakland, California.
The inversion combines spatially and temporally resolved BC observations, atmospheric source–receptor sensitivities generated using the Stochastic Time-Inverted Lagrangian Transport (STILT) model, and a gridded prior BC emissions inventory. The resulting posterior emissions represent observationally constrained updates to the prior inventory.
All materials are provided as a single compressed archive (BC_Inverse_Repo_V1.1.zip) to preserve the directory structure used by the analysis scripts. After downloading, unzip the archive before running the model.
Terminology
- Black carbon (BC): A light-absorbing component of particulate matter produced primarily by incomplete combustion.
- Prior emissions: BC emissions supplied to the inverse model before observational constraints are incorporated.
- Posterior emissions: BC emissions estimated after updating the prior using the observations and atmospheric transport model.
- STILT: Stochastic Time-Inverted Lagrangian Transport model, used here to calculate the sensitivity of receptor concentrations to upwind emissions.
- Footprint: A STILT source–receptor sensitivity field describing how emissions from individual grid cells influence a particular receptor observation.
- Receptor: A geographic location at which an observational BC constraint is defined.
- WRF domain: A spatial modeling grid from the Weather Research and Forecasting model. The d02 and d03 suffixes identify nested WRF domains.
Files included in this Dryad record
The dataset is distributed as:
BC_Inverse_Repo_V1.1.zip
Contains model code, configuration files, and input data required to run the inversion.
After extracting BC_Inverse_Repo_V1.1.zip, the directory structure is:
BC_Inverse_Repo_V1.1/
├── model_run.py
├── config/
│ ├── run.yaml
│ └── requirements.txt
├── util_scripts/
│ ├── io_utils.py
│ ├── covar_utils.py
│ └── inv_utils.py
├── input_data/
│ ├── footprints_d03/
│ ├── obs_data/
│ │ ├── assim_obs.csv
│ │ ├── asim_obs_spatial_error.csv
│ │ └── asim_obs_temporal_error.nc
│ └── prior_ems/
│ ├── emBC_2017-05-15_2017-08-31.d02
│ ├── emBC_2017-05-15_2017-08-31.d03
│ └── mask/
│ ├── sect_mask.nc
│ └── water_mask.nc
└── output_data/
├── ems_post/
└── ems_dif/
Input data
1. STILT footprints
Directory: input_data/footprints_d03/
This directory contains the STILT source–receptor sensitivity fields used to construct the atmospheric transport matrix for the inverse model.
Files follow the naming convention:
YYYYmmddHHMM_lon_lat_5_foot.nc
where the filename identifies the receptor time and location. Times are stored in GMT/UTC.
The principal footprint field is foot, which describes the sensitivity of concentration at a receptor to surface emissions from individual upwind grid cells. The footprint files also contain the spatial and temporal coordinates associated with the sensitivity field.
| Variable/information | Description |
|---|---|
foot |
STILT source–receptor sensitivity field |
| spatial coordinates | Location of the footprint grid cells |
time |
Backward transport time represented by the footprint |
The raw STILT sensitivities are converted in the workflow to units relating observed BC concentration to BC emission flux before construction of the inversion matrix.
Footprint files are NetCDF files and can be opened using xarray, netCDF4, Panoply, or other NetCDF-compatible software.
import xarray as xr
ds = xr.open_dataset(
"input_data/footprints_d03/<footprint_filename>.nc"
)
2. BC observations
File: input_data/obs_data/assim_obs.csv
This file contains the BC observations supplied to the inverse model. It is stored in wide format: each row represents one receptor location and the timestamp columns contain hourly BC concentrations.
The file contains 549 receptor locations and 2,400 hourly concentration fields covering the observational analysis period.
| Column | Description | Units / interpretation |
|---|---|---|
| Unnamed: 0 | Row identifier retained when the dataframe was written to CSV | Unitless |
| hourly timestamp columns | BC concentration at each receptor and hour | µg m⁻³ |
geometry |
Receptor location stored as a Well-Known Text point (POINT (longitude latitude)) |
Geographic coordinate |
lon |
Receptor longitude | Decimal degrees |
lat |
Receptor latitude | Decimal degrees |
The hourly columns span 2017-05-19 00:00 through 2017-08-26 23:00 GMT/UTC.
Example:
import pandas as pd
obs = pd.read_csv("input_data/obs_data/assim_obs.csv")
3. Spatial observation-error component
File: input_data/obs_data/asim_obs_spatial_error.csv
This file contains the receptor-specific spatial component used in characterizing observation/model-data error.
| Column | Description | Units / interpretation |
|---|---|---|
lat_lon |
Receptor coordinate stored as (latitude, longitude) |
Decimal degrees |
spatial_error |
Location-specific spatial component of the BC observation/model-data mismatch | µg m⁻³ |
The file contains one value for each of the 549 receptor locations.
Example:
import pandas as pd
spatial_error = pd.read_csv(
"input_data/obs_data/asim_obs_spatial_error.csv"
)
4. Temporal observation-error component
File: input_data/obs_data/asim_obs_temporal_error.nc
This NetCDF file contains the hourly temporal component used in characterizing observation/model-data error. It contains 2,400 hourly values corresponding to the same observational period represented in assim_obs.csv.
The file was written as an xarray DataArray; consequently, some NetCDF readers display its data variable using the automatically generated name __xarray_dataarray_variable__.
| Variable | Description | Units / interpretation |
|---|---|---|
time |
Timestamp associated with each temporal-error value | GMT/UTC |
__xarray_dataarray_variable__ |
Hour-specific temporal component of the BC observation/model-data mismatch | µg m⁻³ |
The automatically generated variable name does not represent a separate physical quantity.
Example:
import xarray as xr
temporal_error = xr.open_dataarray(
"input_data/obs_data/asim_obs_temporal_error.nc"
)
The spatial and temporal error components are used in constructing the observational error covariance information used by the inversion.
Prior BC emissions
5. emBC_2017-05-15_2017-08-31.d02
6. emBC_2017-05-15_2017-08-31.d03
These files contain hourly gridded prior BC emissions for the nested WRF d02 and d03 domains.
Although the filenames do not end in .nc, both are NetCDF files in WRF emissions-input format. The .d02 and .d03 suffixes identify the corresponding WRF domain.
The two files contain the same principal variables but differ in spatial resolution:
| File | Grid size | Horizontal resolution | Time steps |
|---|---|---|---|
.d02 |
99 × 99 | 1,350 m | 2,616 hourly fields |
.d03 |
72 × 72 | 150 m | 2,616 hourly fields |
Variables
| Variable | Description | Units |
|---|---|---|
Times |
Timestamp associated with each hourly emissions field, stored in WRF format (YYYY-MM-DD_HH:MM:SS) |
Date/time |
E_BC |
Gridded black carbon emissions | g BC hr⁻¹ |
The d03 emissions provide the high-resolution prior used with the d03 STILT footprints in the inverse analysis. The d02 file provides emissions for the coarser parent domain.
These files can be opened directly using standard NetCDF software despite the absence of a .nc extension:
import xarray as xr
d02 = xr.open_dataset(
"input_data/prior_ems/emBC_2017-05-15_2017-08-31.d02"
)
d03 = xr.open_dataset(
"input_data/prior_ems/emBC_2017-05-15_2017-08-31.d03"
)
They can also be inspected using netCDF4, ncdump, Panoply, or similar software. The supplied filenames should be retained because the analysis workflow references the domain-specific names.
Sector and spatial information
7. Sector-resolved emissions reference
File: input_data/prior_ems/mask/sect_mask.nc
Despite the historical filename sect_mask.nc, this file is not an integer-coded categorical mask. It contains separate hourly BC emissions fields for eight source sectors. These fields provide the sector information used in constructing the sector-segmented prior-emissions covariance structure.
The file contains 24 hourly slices on a 126 × 126 grid with 150 m resolution.
Dimensions
| Dimension | Size | Description |
|---|---|---|
Time |
24 | Hourly emissions profile |
north_south |
126 | North–south grid dimension |
west_east |
126 | East–west grid dimension |
Variables
| Variable | Description | Units |
|---|---|---|
LAT |
Grid-cell latitude | degrees |
LON |
Grid-cell longitude | degrees |
Cars |
BC emissions from cars | g BC hr⁻¹ |
Trucks |
BC emissions from heavy-duty trucks | g BC hr⁻¹ |
CHE |
BC emissions from cargo-handling equipment | g BC hr⁻¹ |
OGV_Port |
BC emissions from ocean-going vessels associated with the Port | g BC hr⁻¹ |
OGV_OffPort |
BC emissions from ocean-going vessels outside the Port category | g BC hr⁻¹ |
HC_Port |
BC emissions from harbor craft associated with the Port | g BC hr⁻¹ |
Locomotives |
BC emissions from locomotives | g BC hr⁻¹ |
HC_OffPort |
BC emissions from harbor craft outside the Port category | g BC hr⁻¹ |
Here, CHE denotes cargo-handling equipment, OGV denotes ocean-going vessels, and HC denotes harbor craft.
Sector identity is represented by the named variables rather than by numerical categorical codes.
Example:
import xarray as xr
sector_data = xr.open_dataset(
"input_data/prior_ems/mask/sect_mask.nc"
)
8. Water mask
File: input_data/prior_ems/mask/water_mask.nc
This file contains a binary water mask aligned with the 62 × 62 cropped d03 grid used by the inversion.
Like the temporal-error file, it was written as an xarray DataArray, so some NetCDF readers display the data variable as __xarray_dataarray_variable__.
Dimensions
| Dimension | Size |
|---|---|
north_south |
62 |
west_east |
62 |
Variable interpretation
| Value | Interpretation |
|---|---|
0 |
Land/non-water grid cell |
1 |
Water grid cell |
The mask is unitless. Its cells are aligned positionally with the corresponding cropped d03 grid.
Example:
import xarray as xr
water_mask = xr.open_dataarray(
"input_data/prior_ems/mask/water_mask.nc"
)
Output data
Model outputs are generated automatically during execution.
9. Posterior emissions
Directory: output_data/ems_post/
Files follow the naming convention:
ems_d03_post_YYYY-MM-DD.nc
These NetCDF files contain the posterior BC emissions estimated by the inverse model for the indicated day on the d03 grid.
The posterior represents the prior emissions after incorporation of the observational constraints.
10. Posterior-minus-prior emissions corrections
Directory: output_data/ems_dif/
Files follow the naming convention:
ems_d03_dif_YYYY-MM-DD.nc
These NetCDF files contain:
posterior emissions - prior emissions
Positive values indicate that the inversion increased estimated BC emissions relative to the prior, while negative values indicate that it decreased them.
The emissions-difference fields use the same spatial grid and emissions units as the corresponding prior and posterior fields.
Analytical workflow
The principal data flow is:
Prior BC emissions
+
STILT source-receptor footprints
+
BC observations
+
Observation-error information
+
Prior-emissions covariance information
│
▼
Bayesian inverse model
│
├── Posterior BC emissions
└── Posterior-minus-prior corrections
The prior inventory provides the initial estimate of BC emissions. STILT footprints describe how emissions from each grid cell influence BC concentrations at individual receptors. These are combined to calculate modeled receptor concentrations.
Observed BC concentrations are then used to constrain differences between modeled and measured concentrations. Observation-error information controls the relative weighting of the observational constraints, while the prior-emissions covariance structure controls the spatial, temporal, and sectoral structure of allowable emissions adjustments.
The inverse solution produces posterior emissions and the corresponding change relative to the prior inventory.
Code/software
The inversion workflow is implemented in Python and executed through a single entry-point script:
model_run.py— main script that runs the inverse model over the configured analysis period.
Execution is controlled through:
config/run.yaml— analysis dates, input/output paths, covariance options, prior configuration, and model parameters.config/requirements.txt— Python dependencies required to run the workflow.
Supporting modules are:
util_scripts/io_utils.py— input/output utilities for observations, emissions, footprints, and outputs.util_scripts/covar_utils.py— construction of observational and prior-emissions covariance matrices.util_scripts/inv_utils.py— forward-model and inverse-solution routines.
Running the model
- Download and extract
BC_Inverse_Repo_V1.1.zip. - Install the Python packages listed in:
config/requirements.txt
- Review the settings in:
config/run.yaml
- From the repository root, run:
python model_run.py
Outputs are written to output_data/ems_post/ and output_data/ems_dif/.
File formats
CSV
CSV files are comma-separated tabular files and can be opened with spreadsheet software or read using Python, R, MATLAB, or similar software.
Example:
import pandas as pd
df = pd.read_csv("input_data/obs_data/assim_obs.csv")
NetCDF
NetCDF is a self-describing scientific data format commonly used for multidimensional atmospheric and geospatial data.
Dataset-style NetCDF files can be opened with:
import xarray as xr
ds = xr.open_dataset("filename.nc")
Files stored as a single xarray DataArray, including asim_obs_temporal_error.nc and water_mask.nc, can be opened with:
da = xr.open_dataarray("filename.nc")
The prior-emissions files ending in .d02 and .d03 are also NetCDF files even though they do not use a .nc extension.
Spatial and temporal conventions
- Observation and STILT times are stored in GMT/UTC.
- Geographic locations are expressed in decimal degrees.
- The high-resolution WRF d03 emissions grid has a horizontal resolution of 150 m.
- The d02 emissions grid has a horizontal resolution of 1.35 km.
- The observation matrix contains 2,400 hourly time steps from May 19 through August 26, 2017.
- The WRF prior-emissions files contain 2,616 hourly fields, with individual timestamps stored in the
Timesvariable.
Missing and categorical data
For NetCDF files, missing values, where applicable, follow the _FillValue or related metadata stored in the file.
water_mask.nc uses the following categorical values:
0 = land/non-water
1 = water
sect_mask.nc does not use numerical sector codes; sectors are represented by separate named variables.
Access information
How to access
Download BC_Inverse_Repo_V1.1.zip from this Dryad record. Extract the archive locally while preserving its directory structure.
Contact
For questions related to the dataset, code, or associated analysis, please contact the corresponding author of the associated manuscript.
