The bldfm package¶
This package contains the BLDFM model. It includes core modules for the PBL model, spectral solver, and utility functions, as well as higher-level modules for configuration, interface, I/O, caching, plotting, and synthetic data generation.
Core modules¶
bldfm.pbl_model module¶
- bldfm.pbl_model.phi(x)[source]¶
Stability correction function for eddy diffusivity in Monin-Obukhov Similarity Theory (MOST).
- Parameters:
x (float or numpy.ndarray) – Dimensionless stability parameter (z / mol).
- Returns:
Stability correction factor for eddy diffusivity.
- Return type:
Notes
For stable conditions (x > 0), a linear relationship is used.
For unstable conditions (x < 0), the Businger-Dyer formulation is applied.
- bldfm.pbl_model.psi(x)[source]¶
Stability correction function for Monin-Obukhov Similarity Theory (MOST).
- Parameters:
x (float or numpy.ndarray) – Dimensionless stability parameter (z / mol).
- Returns:
Stability correction factor for momentum.
- Return type:
Notes
For stable conditions (x > 0), a linear relationship is used.
For unstable conditions (x < 0), the Businger-Dyer formulation is applied.
- bldfm.pbl_model.vertical_profiles(n, meas_height, wind, ustar=None, z0=None, mol=1000000000.0, prsc=1.0, closure='MOST', domain_height=None, stretch=None, z0_min=0.001, z0_max=2.0, tke=None)[source]¶
Computes vertical profiles of horizontal wind components and eddy diffusivity in the planetary boundary layer (PBL) based on Monin-Obukhov Similarity Theory (MOST) or other closure models.
- Parameters:
n (int) – Number of vertical grid points between z0 and meas_height.
meas_height (float) – Measurement height above the ground.
wind (tuple of floats) – Zonal (u) and meridional (v) wind components at the measurement height.
ustar (float or numpy.ndarray) – Friction velocity [m/s].
mol (float or numpy.ndarray, optional) – Monin-Obukhov length. Default is 1e9 (neutral conditions).
prsc (float, optional) – Prandtl or Schmidt number. Default is 1.0.
closure (str, optional) – Closure model to use. Options are “MOST”, “CONSTANT”, or “OAAHOC”. Default is “MOST”.
z0 (float or numpy.ndarray, optional) – Roughness length. Default is -1e9 (auto-calculated).
z0_min (float, optional) – Minimum allowable roughness length. Default is 0.001.
z0_max (float, optional) – Maximum allowable roughness length. Default is 2.0.
tke (float or numpy.ndarray, optional) – Turbulent kinetic energy [m²/s²] for the “OAAHOC” closure. If not provided, it will default to 1.0.
- Returns:
z (numpy.ndarray): 1D array of vertical grid points.
profiles (tuple of numpy.ndarray): 1D arrays of horizontal wind components (u, v) and eddy diffusivities (Kx, Ky, Kz) at each vertical grid point.
- Return type:
- Raises:
ValueError – If invalid closure type is provided.
Notes
The “OAAHOC” closure uses a one-and-a-half order closure model based on Schumann-Lilly.
The “MOST” closure uses Monin-Obukhov Similarity Theory.
References
Kormann, R., & Meixner, F. X. (2001). An analytical footprint model for non-neutral stratification. Boundary-Layer Meteorology, 99(2), 207–224. https://doi.org/10.1023/A:1018991015119
Schumann, U. (1991). Subgrid length-scales for large-eddy simulation of stratified turbulence. Theoretical and Computational Fluid Dynamics, 2(5), 279–290. https://doi.org/10.1007/BF00271468
bldfm.solver module¶
- bldfm.solver.steady_state_transport_solver(srf_flx, z, profiles, domain, levels, modes=(512, 512), meas_pt=(0.0, 0.0), srf_bg_conc=0.0, footprint=False, analytic=False, halo=None, precision='single', cache=None)[source]¶
Solves the steady-state advection-diffusion equation for a concentration with flux boundary condition given vertical profiles of wind and eddy diffusivity using the Fourier, linear shooting, and semi-implicit Euler methods.
- Parameters:
srf_flx (ndarray of float) – 2D field of surface kinematic flux at z=z0 [m/s].
z (ndarray of float) – 1D array of vertical grid points from z0 to zm [m].
profiles (tuple of ndarray) – Tuple containing 1D arrays of vertical profiles of zonal wind, meridional wind [m/s], and eddy diffusivities [m²/s].
domain (tuple of float) – Tuple containing domain sizes (xmax, ymax) [m].
levels (float or ndarray of float) – Vertical level for output or optionally 1D array of output levels.
modes (tuple of int, optional) – Tuple containing the number of zonal and meridional Fourier modes (nlx, nly). Default is (512, 512).
meas_pt (tuple of float, optional) – Coordinates of the measurement point (xm, ym) [m] relative to srf_flx, where the origin is at srf_flx[0, 0]. Default is (0.0, 0.0).
srf_bg_conc (float, optional) – Surface background concentration at z=z0 [scalar_unit]. Default is 0.0.
footprint (bool, optional) – If True, activates footprints (Green’s function) for output. Default is False.
analytic (bool, optional) – If True, uses the analytic solution for constant wind and eddy diffusivity. Default is False.
halo (float, optional) – Width of the zero-flux halo around the domain [m]. Default is -1e9, which sets the halo to max(xmax, ymax).
- Returns:
z (ndarray of float) – Heights [m] at levels.
conc (ndarray of float) – 2D or 3D field of concentration at levels or Green’s function.
flx (ndarray of float) – 2D or 3D field of kinematic flux at levels or footprint.
bldfm.utils module¶
- bldfm.utils.compute_wind_fields(u_rot, wind_dir)[source]¶
Computes the zonal (u) and meridional (v) wind components from a rotated wind speed and direction using the meteorological convention.
- Parameters:
- Returns:
- A tuple (u, v) where:
u (float): Zonal wind component (east-west, positive = eastward).
v (float): Meridional wind component (north-south, positive = northward).
- Return type:
- bldfm.utils.get_source_area(f, g)[source]¶
Rescale g so contour levels represent cumulative contribution of f.
For the transformed field, the contour at level R encloses the region where sum(f) = R.
- Parameters:
f (ndarray) – Function values (e.g., flux footprint).
g (ndarray) – Function defining level sets (often same as f).
- Returns:
g_rescaled – Transformed field where contour values equal cumulative contribution.
- Return type:
ndarray
- bldfm.utils.ideal_source(nxy, domain, src_loc=None, shape='diamond')[source]¶
Creates a synthetic source field in the shape of a circle or diamond. Useful for testing purposes.
- Parameters:
- Returns:
A 2D array representing the source field.
- Return type:
- bldfm.utils.point_measurement(f, g)[source]¶
Computes the convolution of two 2D arrays evaluated at a specific point.
- Parameters:
f (numpy.ndarray) – First 2D array.
g (numpy.ndarray) – Second 2D array.
- Returns:
The result of the convolution at the specified point.
- Return type:
- bldfm.utils.setup_logging(level=None, format_string=None, log_file=None, log_dir='logs', auto_file=True, run_name=None)[source]¶
Set up logging configuration with customizable options.
- Parameters:
level (str or int) – Logging level (DEBUG, INFO, WARNING, ERROR, CRITICAL)
format_string (str) – Custom format string for log messages
log_file (str) – Optional specific log file name (overrides auto_file)
log_dir (str) – Directory to store log files
auto_file (bool) – If True, automatically generate timestamped filename
run_name (str) – Optional run name to include in log filename
- bldfm.utils.source_area_circular(X, Y, meas_pt)[source]¶
Base function for circular contours centered at measurement point.
g = -(r^2), so contours are concentric circles.
- Parameters:
X (ndarray (ny, nx)) – Coordinate grids.
Y (ndarray (ny, nx)) – Coordinate grids.
meas_pt (tuple (xm, ym)) – Measurement (tower) location.
- Returns:
g
- Return type:
ndarray (ny, nx)
- bldfm.utils.source_area_contribution(flx)[source]¶
Base function for contribution (isopleth) contours: g = flx.
- Parameters:
flx (ndarray (ny, nx)) – Footprint field.
- Returns:
g
- Return type:
ndarray (ny, nx)
- bldfm.utils.source_area_crosswind(X, Y, meas_pt, wind)[source]¶
Base function for crosswind ridge contours.
g = -(perpendicular distance from wind axis)^2. Contours are symmetric ridges parallel to the wind direction.
- bldfm.utils.source_area_sector(X, Y, meas_pt, wind)[source]¶
Base function for angular sector contours from upwind axis.
g = -abs(theta), where theta is angular deviation from upwind direction. Contours form pie-slice sectors centered on the upwind direction.
bldfm.fft_manager module¶
- class bldfm.fft_manager.FFTManager(wisdom_file='fftw_wisdom.pkl', num_threads=1, cache_keepalive=30)[source]¶
Bases:
objectManages pyFFTW with wisdom and caching for optimal performance in Dask environments.
This class addresses memory issues in Dask parallelized environments by: - Using pyfftw numpy interface for compatibility - Loading/saving FFTW wisdom for optimal planning - Enabling pyfftw caching to prevent repeated object allocation - Providing proper memory management and cleanup
- bldfm.fft_manager.fft2(input_data, norm='backward')[source]¶
Global function for 2D FFT using the FFT manager.
- bldfm.fft_manager.get_fft_manager(num_threads=1, cache_keepalive=30)[source]¶
Get or create the global FFT manager instance.
If the manager already exists with different num_threads, it is re-initialised with the new thread count.
Configuration and interface¶
bldfm.config_parser module¶
YAML configuration parser and dataclass schema for BLDFM.
- Defines the configuration hierarchy:
BLDFMConfig ├── DomainConfig ├── List[TowerConfig] ├── MetConfig ├── SolverConfig ├── OutputConfig └── ParallelConfig
- class bldfm.config_parser.BLDFMConfig(domain: ~bldfm.config_parser.DomainConfig, towers: ~typing.List[~bldfm.config_parser.TowerConfig], met: ~bldfm.config_parser.MetConfig, solver: ~bldfm.config_parser.SolverConfig = <factory>, output: ~bldfm.config_parser.OutputConfig = <factory>, parallel: ~bldfm.config_parser.ParallelConfig = <factory>)[source]¶
Bases:
objectTop-level BLDFM configuration.
- domain: DomainConfig¶
- output: OutputConfig¶
- parallel: ParallelConfig¶
- solver: SolverConfig¶
- towers: List[TowerConfig]¶
- class bldfm.config_parser.DomainConfig(nx: int, ny: int, xmax: float, ymax: float, nz: int, modes: Tuple[int, int] = (512, 512), halo: float | None = None, ref_lat: float | None = None, ref_lon: float | None = None, output_levels: List[int] | None = None, full_output: bool = False)[source]¶
Bases:
objectConfiguration for the computational domain.
- class bldfm.config_parser.MetConfig(ustar: float | List[float] | None = None, mol: float | List[float] = 1000000000.0, wind_speed: float | List[float] = 5.0, wind_dir: float | List[float] = 270.0, z0: float | None = None, timestamps: List[str] | None = None)[source]¶
Bases:
objectMeteorological forcing data (scalar for single-time, list for timeseries).
- class bldfm.config_parser.OutputConfig(format: str = 'netcdf', directory: str = './output')[source]¶
Bases:
objectOutput configuration.
- class bldfm.config_parser.ParallelConfig(num_threads: int = 1, max_workers: int = 1, use_cache: bool = False)[source]¶
Bases:
objectParallelism configuration.
- class bldfm.config_parser.SolverConfig(closure: str = 'MOST', precision: str = 'single', footprint: bool = False, surface_flux_shape: str = 'diamond', analytic: bool = False, src_loc: Tuple[float, float] | None = None)[source]¶
Bases:
objectSolver configuration.
- class bldfm.config_parser.TowerConfig(name: str, lat: float, lon: float, z_m: float, x: float = 0.0, y: float = 0.0)[source]¶
Bases:
objectConfiguration for a single measurement tower.
- bldfm.config_parser.latlon_to_xy(lat, lon, ref_lat, ref_lon)[source]¶
Convert lat/lon to local x/y (meters) relative to a reference point.
Uses an equirectangular (flat-Earth) approximation, which is accurate to <0.1% for domains up to ~100 km at mid-latitudes.
- Parameters:
- Returns:
x, y – Easting and northing in meters relative to (ref_lat, ref_lon).
- Return type:
- bldfm.config_parser.load_config(path: str | Path) BLDFMConfig[source]¶
Load a BLDFM configuration from a YAML file.
- Parameters:
path (str or Path) – Path to the YAML configuration file.
- Returns:
Parsed and validated configuration.
- Return type:
- bldfm.config_parser.parse_config_dict(raw: dict) BLDFMConfig[source]¶
Parse a BLDFM configuration from a dictionary.
- Parameters:
raw (dict) – Raw configuration dictionary (e.g. from YAML).
- Returns:
Parsed and validated configuration.
- Return type:
bldfm.interface module¶
High-level interface for running BLDFM simulations.
Provides convenience functions that wrap the manual workflow of compute_wind_fields -> vertical_profiles -> steady_state_transport_solver into single function calls driven by configuration objects.
- bldfm.interface.run_bldfm_multitower(config: BLDFMConfig, surface_flux: ndarray | None = None) dict[source]¶
Run BLDFM for all towers and all timesteps.
- Parameters:
config (BLDFMConfig) – Full BLDFM configuration with towers and met data.
surface_flux (ndarray, optional) – 2D surface flux field (reused for all towers/timesteps).
- Returns:
Mapping of tower_name -> list of result dicts (one per timestep).
- Return type:
- bldfm.interface.run_bldfm_parallel(config: BLDFMConfig, max_workers: int | None = None, parallel_over: str = 'towers', surface_flux: ndarray | None = None) dict[source]¶
Run BLDFM in parallel using ProcessPoolExecutor.
- Parameters:
config (BLDFMConfig) – Full BLDFM configuration with towers and met data.
max_workers (int, optional) – Number of worker processes. Defaults to config.parallel.max_workers.
parallel_over (str) – Parallelization strategy: - “towers”: distribute towers across workers, each runs full timeseries - “time”: for each tower, distribute timesteps across workers - “both”: flatten all (tower, timestep) pairs across workers
surface_flux (ndarray, optional) – 2D surface flux field (not passed to subprocesses to avoid large serialization; each worker generates its own ideal source).
- Returns:
Mapping of tower_name -> list of result dicts (one per timestep). Same format as run_bldfm_multitower.
- Return type:
- bldfm.interface.run_bldfm_single(config: BLDFMConfig, tower: TowerConfig, met_index: int = 0, surface_flux: ndarray | None = None, cache=None) dict[source]¶
Run a single BLDFM solve for one tower at one timestep.
- Encapsulates the 3-step workflow:
compute_wind_fields(wind_speed, wind_dir) -> (u, v)
vertical_profiles(nz, z_m, (u, v), …) -> (z, profiles)
steady_state_transport_solver(srf_flx, z, profiles, …) -> (grid, conc, flx)
- Parameters:
config (BLDFMConfig) – Full BLDFM configuration.
tower (TowerConfig) – Tower to compute footprint/concentration for.
met_index (int) – Index into the met timeseries (0 for single-timestep configs).
surface_flux (ndarray, optional) – 2D surface flux field. If None, generates an ideal source.
cache (GreensFunctionCache, optional) – Cache instance for footprint reuse.
- Returns:
Result dictionary with keys: - grid: (X, Y, Z) coordinate arrays - conc: concentration field - flx: flux field - tower_name: name of the tower - timestamp: timestamp or index - params: dict of met parameters used
- Return type:
- bldfm.interface.run_bldfm_timeseries(config: BLDFMConfig, tower: TowerConfig, surface_flux: ndarray | None = None) list[source]¶
Run BLDFM for all timesteps in the met config for a single tower.
- Parameters:
config (BLDFMConfig) – Full BLDFM configuration with timeseries met data.
tower (TowerConfig) – Tower to compute footprint/concentration for.
surface_flux (ndarray, optional) – 2D surface flux field (reused for all timesteps).
- Returns:
One result dict per timestep (same format as run_bldfm_single).
- Return type:
bldfm.cli module¶
Command-line interface for BLDFM.
- Usage:
bldfm run config.yaml bldfm run config.yaml –dry-run bldfm run config.yaml –plot
Data and I/O¶
bldfm.synthetic module¶
Synthetic data generators for testing and demonstration.
Provides functions to generate realistic-looking meteorological timeseries and tower grid configurations without requiring real observational data.
- bldfm.synthetic.generate_synthetic_timeseries(n_timesteps: int = 48, dt_minutes: int = 30, start_time: str = '2024-01-01T00:00', ustar_range: Tuple[float, float] = (0.1, 0.8), mol_range: Tuple[float, float] = (-500.0, 500.0), wind_speed_range: Tuple[float, float] = (1.0, 8.0), wind_dir_mean: float = 270.0, wind_dir_std: float = 30.0, seed: int | None = None) dict[source]¶
Generate a synthetic meteorological timeseries with diurnal cycle.
Produces ustar, Monin-Obukhov length, wind speed, and wind direction arrays that follow a realistic diurnal pattern (unstable daytime, stable nighttime) with added noise.
- Parameters:
n_timesteps (int) – Number of time steps to generate.
dt_minutes (int) – Time step interval in minutes.
start_time (str) – ISO-format start time string.
ustar_range (tuple of float) – (min, max) friction velocity [m/s].
mol_range (tuple of float) – (min_negative, max_positive) Monin-Obukhov length [m]. Negative = unstable, positive = stable.
wind_speed_range (tuple of float) – (min, max) wind speed [m/s].
wind_dir_mean (float) – Mean wind direction [degrees].
wind_dir_std (float) – Standard deviation of wind direction [degrees].
seed (int, optional) – Random seed for reproducibility.
- Returns:
Dictionary with keys matching MetConfig schema: ustar, mol, wind_speed, wind_dir, timestamps (all lists).
- Return type:
- bldfm.synthetic.generate_towers_grid(n_towers: int = 4, center_lat: float = 50.95, center_lon: float = 11.586, spacing_m: float = 500.0, z_m: float = 10.0, layout: str = 'grid', seed: int | None = None) List[dict][source]¶
Generate tower configurations in various spatial layouts.
- Parameters:
n_towers (int) – Number of towers to generate.
center_lat (float) – Center point of the tower array [decimal degrees].
center_lon (float) – Center point of the tower array [decimal degrees].
spacing_m (float) – Approximate spacing between towers [meters].
z_m (float) – Measurement height [meters] (same for all towers).
layout (str) – Spatial layout: “grid”, “random”, or “transect”.
seed (int, optional) – Random seed for reproducibility (used by “random” layout).
- Returns:
Tower configurations matching TowerConfig schema.
- Return type:
bldfm.io module¶
NetCDF I/O for BLDFM footprint results.
Saves and loads multi-tower, multi-timestep footprint fields as CF-1.8 compliant xarray Datasets with zlib compression.
- bldfm.io.load_footprints_from_netcdf(filepath)[source]¶
Load footprint results from a NetCDF file.
- Parameters:
filepath (str or Path) – Path to the NetCDF file.
- Returns:
Dataset with footprint, concentration, and metadata.
- Return type:
xr.Dataset
- bldfm.io.save_footprints_to_netcdf(results, config, filepath)[source]¶
Save multitower results to a CF-compliant NetCDF file.
- Parameters:
results (dict) – Output of run_bldfm_multitower: {tower_name: [result_dict, …]}.
config (BLDFMConfig) – Configuration used for the run.
filepath (str or Path) – Output file path.
bldfm.cache module¶
Disk cache for Green’s function results.
When footprint=True, the solver output depends only on the vertical profiles, domain geometry, and measurement point — not on the surface flux field. Caching these results avoids redundant solves when re-running with the same PBL/domain configuration.
- class bldfm.cache.GreensFunctionCache(cache_dir='.bldfm_cache')[source]¶
Bases:
objectDisk-based cache for Green’s function solver outputs.
Cache key is a SHA-256 hash of the solver inputs that determine the Green’s function: vertical grid, profiles, domain, modes, measurement point, halo, and precision.
- Parameters:
cache_dir (str or Path) – Directory for cache files. Created if it does not exist.
Plotting¶
bldfm.plotting package¶
Plotting package for BLDFM footprint visualisation.
All matplotlib-based functions accept an optional ax parameter for
composability. Optional dependencies (contextily, windrose, plotly) are
imported lazily and raise helpful messages when missing.
- bldfm.plotting.extract_percentile_contour(flx, grid, pct=0.8, level=0)[source]¶
Find the contour level that encloses pct of the cumulative footprint.
- Parameters:
- Returns:
level (float) – Contour level value.
area (float) – Approximate area [m^2] enclosed by that contour.
- bldfm.plotting.plot_convergence(grid_sizes, errors, fits=None, marker='o', ax=None, xlabel='$h$ [m]', ylabel='Relative RMSE', title=None)[source]¶
Log-log convergence plot.
- Parameters:
grid_sizes (array-like) – Effective grid spacings (h).
errors (array-like) – Error values (e.g., RMSE).
fits (list of (func, params, label), optional) – Curve fits to overlay. Each element is a tuple: (function, parameter_dict, label_string). Example: (lambda h, a, b: a * h**b, {“a”: 0.1, “b”: 2.0}, “$O(h^2)$”)
marker (str) – Marker style for data points (default “o”).
ax (matplotlib Axes, optional)
xlabel (str) – X-axis label (default “$h$ [m]”).
ylabel (str) – Y-axis label (default “Relative RMSE”).
title (str, optional)
- Returns:
ax
- Return type:
matplotlib Axes
- bldfm.plotting.plot_field_comparison(fields, domain, src_pt=None, cmap='turbo', figsize=None, level=0)[source]¶
2x2 panel comparison: conc, flux, and relative differences.
Top-left: concentration, top-right: flux. Bottom-left: relative difference concentration, bottom-right: relative difference flux.
- Parameters:
fields (dict) – Must contain keys: “conc”, “flx”, “conc_ref”, “flx_ref”. Values may be 2-D or 3-D arrays. If 3D, sliced at level.
domain (tuple (xmax, ymax)) – Domain extents for imshow.
src_pt (tuple (x, y), optional) – Source point coordinates to mark with a red star on top panels.
cmap (str) – Colormap name (default “turbo”).
figsize (tuple, optional) – Figure size (width, height). Default (10, 6).
level (int) – Z-index to use when fields are 3D. Default 0 (surface).
- Returns:
fig (matplotlib Figure)
axes (ndarray of Axes (2x2))
- bldfm.plotting.plot_footprint_comparison(fields, grids, labels, meas_pt=None, n_levels=6, vmin=None, vmax=None, cmap='turbo', figsize=None, title=None, level=0)[source]¶
Multi-panel contour plot comparing footprint models side-by-side.
- Parameters:
fields (list of ndarray) – List of 2-D (or 3-D) footprint fields to compare. If 3D, sliced at level.
grids (list of tuple) – List of (X, Y) or (X, Y, Z) coordinate arrays (one per field).
meas_pt (tuple (x, y), optional) – Measurement point coordinates to mark with a red star on each panel.
n_levels (int) – Number of contour levels (default 6).
vmin (float, optional) – Minimum contour level. If None, uses 5% of vmax.
vmax (float, optional) – Maximum contour level. If None, uses max across all fields.
cmap (str) – Colormap name (default “turbo”).
figsize (tuple, optional) – Figure size (width, height).
title (str, optional) – Overall figure title.
level (int) – Z-index to use when fields are 3D. Default 0 (surface).
- Returns:
fig (matplotlib Figure)
axes (ndarray of Axes)
- bldfm.plotting.plot_footprint_field(flx, grid, ax=None, contour_pcts=None, cmap='RdYlBu_r', title=None, level=0, **pcolormesh_kw)[source]¶
Plot a 2-D footprint field with optional percentile contours.
- Parameters:
flx (ndarray (ny, nx) or (nz, ny, nx)) – Footprint (or concentration) field. If 3D, sliced at level.
grid (tuple (X, Y, Z)) – Coordinate arrays from the solver.
ax (matplotlib Axes, optional)
contour_pcts (list of float, optional) – Percentile fractions to overlay as contours (e.g. [0.5, 0.8]).
cmap (str) – Colourmap name.
title (str, optional)
level (int) – Z-index to use when flx is 3D. Default 0 (surface).
**pcolormesh_kw – Forwarded to
ax.pcolormesh.
- Returns:
ax
- Return type:
matplotlib Axes
- bldfm.plotting.plot_footprint_interactive(flx, grid, title=None, xlim=None, ylim=None, level=0)[source]¶
Create an interactive Plotly heatmap of the footprint.
Requires the optional
plotlypackage.- Parameters:
flx (ndarray (ny, nx) or (nz, ny, nx)) – Footprint field. If 3D, sliced at level.
grid (tuple (X, Y, Z)) – Coordinate arrays.
title (str, optional)
xlim (tuple of float, optional) – (xmin, xmax) axis range. Useful for excluding halo padding.
level (int) – Z-index to use when flx is 3D. Default 0 (surface).
- Returns:
fig
- Return type:
plotly.graph_objects.Figure
- bldfm.plotting.plot_footprint_on_map(flx, grid, config, tower=None, ax=None, contour_pcts=None, tile_source=None, land_cover=False, land_cover_size=(512, 512), alpha=0.5, cmap='RdYlBu_r', title=None, level=0)[source]¶
Overlay footprint contours and tower marker(s) on map tiles.
Requires
contextily(default) orowslib(when land_cover=True).- Parameters:
flx (ndarray (ny, nx) or (nz, ny, nx)) – Footprint field. If 3D, sliced at level.
grid (tuple (X, Y, Z)) – Coordinate arrays (local metres).
config (BLDFMConfig) – Configuration (for ref_lat/ref_lon and tower metadata).
tower (TowerConfig, optional) – Specific tower to highlight. If None, all towers are plotted.
ax (matplotlib Axes, optional)
contour_pcts (list of float, optional) – Percentile contours to draw (default [0.5, 0.8]).
tile_source (contextily tile source, optional) – Defaults to OpenStreetMap. Ignored when land_cover=True unless explicitly provided (in which case both layers are rendered).
land_cover (bool) – If True, use ESA WorldCover 2021 as the basemap instead of OSM tiles. Requires the optional
owslibpackage.land_cover_size (tuple of int) – Pixel dimensions (width, height) for the WMS request (default (512, 512)). Increase for higher resolution.
alpha (float) – Transparency for footprint fill.
cmap (str) – Colourmap for the footprint fill.
title (str, optional)
level (int) – Z-index to use when flx is 3D. Default 0 (surface).
- Returns:
ax
- Return type:
matplotlib Axes
- bldfm.plotting.plot_footprint_timeseries(results, grid, pcts=None, ax=None, title=None, level=0)[source]¶
Plot temporal evolution of footprint extent.
- Parameters:
results (list of dict) – Output of run_bldfm_timeseries (list of result dicts for one tower).
grid (tuple (X, Y, Z)) – Coordinate arrays (from first result, assumed constant).
pcts (list of float, optional) – Percentile fractions to track (default [0.5, 0.8]).
ax (matplotlib Axes, optional)
title (str, optional)
level (int) – Z-index to use when footprint fields are 3D. Default 0 (surface).
- Returns:
ax
- Return type:
matplotlib Axes
- bldfm.plotting.plot_source_area_contours(flx, grid, source_area_field, levels=None, ax=None, contour_colors=None, cmap='RdYlBu_r', title=None, level=0, colorbar=True, **pcolormesh_kw)[source]¶
Plot footprint field with source area contour overlay.
The
source_area_fieldshould be the output ofget_source_area(flx, g)for some base functiong.- Parameters:
flx (ndarray (ny, nx) or (nz, ny, nx)) – Original footprint field (plotted as pcolormesh background). If 3D, sliced at level.
grid (tuple (X, Y, Z) or (X, Y)) – Coordinate arrays from the solver.
source_area_field (ndarray (ny, nx) or (nz, ny, nx)) – Rescaled field from
get_source_area(), where contour levels represent cumulative contribution fractions. If 3D, sliced at level.levels (list of float, optional) – Contribution fraction levels (default [0.25, 0.5, 0.75]).
ax (matplotlib Axes, optional)
contour_colors (list of str, optional) – Colors for contour lines (default [‘white’, ‘magenta’, ‘cyan’]).
cmap (str) – Colourmap for background pcolormesh.
title (str, optional)
level (int) – Z-index to use when fields are 3D. Default 0 (surface).
colorbar (bool) – Whether to add a colorbar. Default True.
**pcolormesh_kw – Forwarded to
ax.pcolormesh.
- Returns:
ax
- Return type:
matplotlib Axes
- bldfm.plotting.plot_source_area_gallery(flx, grid, meas_pt, wind, levels=None, cmap='RdYlBu_r', figsize=None, level=0)[source]¶
Multi-panel plot showing all 5 source area contour types.
- Parameters:
flx (ndarray (ny, nx) or (nz, ny, nx)) – Footprint field. If 3D, sliced at level.
grid (tuple (X, Y, Z) or (X, Y)) – Coordinate arrays from the solver.
meas_pt (tuple (xm, ym)) – Measurement point.
wind (tuple (u, v)) – Wind components (m/s).
levels (list of float, optional) – Contribution fraction levels (default [0.25, 0.5, 0.75]).
cmap (str) – Colourmap for background.
figsize (tuple, optional) – Figure size (default (18, 10)).
level (int) – Z-index to use when flx is 3D. Default 0 (surface).
- Returns:
fig (matplotlib Figure)
axes (ndarray of Axes (2, 3))
- bldfm.plotting.plot_vertical_profiles(z_list, profiles_list, labels, meas_height=None, figsize=None, title=None)[source]¶
Multi-panel (1x2) profile plot: wind speed and diffusivity vs height.
Left panel: wind speed |U| = sqrt(u² + v²) vs z. Right panel: Kz vs z.
- Parameters:
z_list (list of array-like) – List of z arrays (one per stability condition).
profiles_list (list of tuple) – List of profile tuples (u, v, Kx, Ky, Kz), one per stability condition.
labels (list of str) – Legend labels for each profile (e.g., “L = -10 m”).
meas_height (float, optional) – Measurement height to mark with a horizontal dashed line.
figsize (tuple, optional) – Figure size (width, height). Default (10, 5).
title (str, optional) – Overall figure title.
- Returns:
fig (matplotlib Figure)
axes (ndarray of Axes (1x2))
- bldfm.plotting.plot_vertical_slice(field, grid, slice_axis, slice_index, ax=None, cmap='viridis', title=None, xlabel=None, ylabel=None)[source]¶
2D slice from a 3D field.
- Parameters:
field (ndarray (nz, ny, nx)) – 3-D field to slice.
grid (tuple (X, Y, Z)) – 3-D coordinate arrays from the solver.
slice_axis (str) – Axis to slice along: “x”, “y”, or “z”.
slice_index (int) – Index along the slice axis.
ax (matplotlib Axes, optional)
cmap (str) – Colormap name (default “viridis”).
title (str, optional)
xlabel (str, optional) – X-axis label (auto-generated if None).
ylabel (str, optional) – Y-axis label (auto-generated if None).
- Returns:
ax
- Return type:
matplotlib Axes
- bldfm.plotting.plot_wind_rose(wind_speed, wind_dir, ax=None, bins=None, title=None)[source]¶
Plot a wind rose from meteorological data.
Requires the optional
windrosepackage.- Parameters:
wind_speed (array-like) – Wind speed values.
wind_dir (array-like) – Wind direction values (degrees, meteorological convention).
ax (WindroseAxes, optional)
bins (array-like, optional) – Speed bins.
title (str, optional)
- Returns:
ax
- Return type:
WindroseAxes
bldfm.plotting.footprint module¶
Core footprint plots and percentile contour computation.
- bldfm.plotting.footprint.extract_percentile_contour(flx, grid, pct=0.8, level=0)[source]¶
Find the contour level that encloses pct of the cumulative footprint.
- Parameters:
- Returns:
level (float) – Contour level value.
area (float) – Approximate area [m^2] enclosed by that contour.
- bldfm.plotting.footprint.plot_footprint_field(flx, grid, ax=None, contour_pcts=None, cmap='RdYlBu_r', title=None, level=0, **pcolormesh_kw)[source]¶
Plot a 2-D footprint field with optional percentile contours.
- Parameters:
flx (ndarray (ny, nx) or (nz, ny, nx)) – Footprint (or concentration) field. If 3D, sliced at level.
grid (tuple (X, Y, Z)) – Coordinate arrays from the solver.
ax (matplotlib Axes, optional)
contour_pcts (list of float, optional) – Percentile fractions to overlay as contours (e.g. [0.5, 0.8]).
cmap (str) – Colourmap name.
title (str, optional)
level (int) – Z-index to use when flx is 3D. Default 0 (surface).
**pcolormesh_kw – Forwarded to
ax.pcolormesh.
- Returns:
ax
- Return type:
matplotlib Axes
- bldfm.plotting.footprint.plot_footprint_on_map(flx, grid, config, tower=None, ax=None, contour_pcts=None, tile_source=None, land_cover=False, land_cover_size=(512, 512), alpha=0.5, cmap='RdYlBu_r', title=None, level=0)[source]¶
Overlay footprint contours and tower marker(s) on map tiles.
Requires
contextily(default) orowslib(when land_cover=True).- Parameters:
flx (ndarray (ny, nx) or (nz, ny, nx)) – Footprint field. If 3D, sliced at level.
grid (tuple (X, Y, Z)) – Coordinate arrays (local metres).
config (BLDFMConfig) – Configuration (for ref_lat/ref_lon and tower metadata).
tower (TowerConfig, optional) – Specific tower to highlight. If None, all towers are plotted.
ax (matplotlib Axes, optional)
contour_pcts (list of float, optional) – Percentile contours to draw (default [0.5, 0.8]).
tile_source (contextily tile source, optional) – Defaults to OpenStreetMap. Ignored when land_cover=True unless explicitly provided (in which case both layers are rendered).
land_cover (bool) – If True, use ESA WorldCover 2021 as the basemap instead of OSM tiles. Requires the optional
owslibpackage.land_cover_size (tuple of int) – Pixel dimensions (width, height) for the WMS request (default (512, 512)). Increase for higher resolution.
alpha (float) – Transparency for footprint fill.
cmap (str) – Colourmap for the footprint fill.
title (str, optional)
level (int) – Z-index to use when flx is 3D. Default 0 (surface).
- Returns:
ax
- Return type:
matplotlib Axes
bldfm.plotting.comparison module¶
Multi-panel comparison plots.
- bldfm.plotting.comparison.plot_field_comparison(fields, domain, src_pt=None, cmap='turbo', figsize=None, level=0)[source]¶
2x2 panel comparison: conc, flux, and relative differences.
Top-left: concentration, top-right: flux. Bottom-left: relative difference concentration, bottom-right: relative difference flux.
- Parameters:
fields (dict) – Must contain keys: “conc”, “flx”, “conc_ref”, “flx_ref”. Values may be 2-D or 3-D arrays. If 3D, sliced at level.
domain (tuple (xmax, ymax)) – Domain extents for imshow.
src_pt (tuple (x, y), optional) – Source point coordinates to mark with a red star on top panels.
cmap (str) – Colormap name (default “turbo”).
figsize (tuple, optional) – Figure size (width, height). Default (10, 6).
level (int) – Z-index to use when fields are 3D. Default 0 (surface).
- Returns:
fig (matplotlib Figure)
axes (ndarray of Axes (2x2))
- bldfm.plotting.comparison.plot_footprint_comparison(fields, grids, labels, meas_pt=None, n_levels=6, vmin=None, vmax=None, cmap='turbo', figsize=None, title=None, level=0)[source]¶
Multi-panel contour plot comparing footprint models side-by-side.
- Parameters:
fields (list of ndarray) – List of 2-D (or 3-D) footprint fields to compare. If 3D, sliced at level.
grids (list of tuple) – List of (X, Y) or (X, Y, Z) coordinate arrays (one per field).
meas_pt (tuple (x, y), optional) – Measurement point coordinates to mark with a red star on each panel.
n_levels (int) – Number of contour levels (default 6).
vmin (float, optional) – Minimum contour level. If None, uses 5% of vmax.
vmax (float, optional) – Maximum contour level. If None, uses max across all fields.
cmap (str) – Colormap name (default “turbo”).
figsize (tuple, optional) – Figure size (width, height).
title (str, optional) – Overall figure title.
level (int) – Z-index to use when fields are 3D. Default 0 (surface).
- Returns:
fig (matplotlib Figure)
axes (ndarray of Axes)
bldfm.plotting.diagnostics module¶
Diagnostic and analysis plots: convergence, vertical profiles, vertical slices.
- bldfm.plotting.diagnostics.plot_convergence(grid_sizes, errors, fits=None, marker='o', ax=None, xlabel='$h$ [m]', ylabel='Relative RMSE', title=None)[source]¶
Log-log convergence plot.
- Parameters:
grid_sizes (array-like) – Effective grid spacings (h).
errors (array-like) – Error values (e.g., RMSE).
fits (list of (func, params, label), optional) – Curve fits to overlay. Each element is a tuple: (function, parameter_dict, label_string). Example: (lambda h, a, b: a * h**b, {“a”: 0.1, “b”: 2.0}, “$O(h^2)$”)
marker (str) – Marker style for data points (default “o”).
ax (matplotlib Axes, optional)
xlabel (str) – X-axis label (default “$h$ [m]”).
ylabel (str) – Y-axis label (default “Relative RMSE”).
title (str, optional)
- Returns:
ax
- Return type:
matplotlib Axes
- bldfm.plotting.diagnostics.plot_vertical_profiles(z_list, profiles_list, labels, meas_height=None, figsize=None, title=None)[source]¶
Multi-panel (1x2) profile plot: wind speed and diffusivity vs height.
Left panel: wind speed |U| = sqrt(u² + v²) vs z. Right panel: Kz vs z.
- Parameters:
z_list (list of array-like) – List of z arrays (one per stability condition).
profiles_list (list of tuple) – List of profile tuples (u, v, Kx, Ky, Kz), one per stability condition.
labels (list of str) – Legend labels for each profile (e.g., “L = -10 m”).
meas_height (float, optional) – Measurement height to mark with a horizontal dashed line.
figsize (tuple, optional) – Figure size (width, height). Default (10, 5).
title (str, optional) – Overall figure title.
- Returns:
fig (matplotlib Figure)
axes (ndarray of Axes (1x2))
- bldfm.plotting.diagnostics.plot_vertical_slice(field, grid, slice_axis, slice_index, ax=None, cmap='viridis', title=None, xlabel=None, ylabel=None)[source]¶
2D slice from a 3D field.
- Parameters:
field (ndarray (nz, ny, nx)) – 3-D field to slice.
grid (tuple (X, Y, Z)) – 3-D coordinate arrays from the solver.
slice_axis (str) – Axis to slice along: “x”, “y”, or “z”.
slice_index (int) – Index along the slice axis.
ax (matplotlib Axes, optional)
cmap (str) – Colormap name (default “viridis”).
title (str, optional)
xlabel (str, optional) – X-axis label (auto-generated if None).
ylabel (str, optional) – Y-axis label (auto-generated if None).
- Returns:
ax
- Return type:
matplotlib Axes
bldfm.plotting.timeseries module¶
Temporal footprint evolution plots.
- bldfm.plotting.timeseries.plot_footprint_timeseries(results, grid, pcts=None, ax=None, title=None, level=0)[source]¶
Plot temporal evolution of footprint extent.
- Parameters:
results (list of dict) – Output of run_bldfm_timeseries (list of result dicts for one tower).
grid (tuple (X, Y, Z)) – Coordinate arrays (from first result, assumed constant).
pcts (list of float, optional) – Percentile fractions to track (default [0.5, 0.8]).
ax (matplotlib Axes, optional)
title (str, optional)
level (int) – Z-index to use when footprint fields are 3D. Default 0 (surface).
- Returns:
ax
- Return type:
matplotlib Axes
bldfm.plotting.interactive module¶
Interactive (non-matplotlib) plotting backends.
- bldfm.plotting.interactive.plot_footprint_interactive(flx, grid, title=None, xlim=None, ylim=None, level=0)[source]¶
Create an interactive Plotly heatmap of the footprint.
Requires the optional
plotlypackage.- Parameters:
flx (ndarray (ny, nx) or (nz, ny, nx)) – Footprint field. If 3D, sliced at level.
grid (tuple (X, Y, Z)) – Coordinate arrays.
title (str, optional)
xlim (tuple of float, optional) – (xmin, xmax) axis range. Useful for excluding halo padding.
level (int) – Z-index to use when flx is 3D. Default 0 (surface).
- Returns:
fig
- Return type:
plotly.graph_objects.Figure
bldfm.plotting.meteorology module¶
Meteorological data visualizations.
- bldfm.plotting.meteorology.plot_wind_rose(wind_speed, wind_dir, ax=None, bins=None, title=None)[source]¶
Plot a wind rose from meteorological data.
Requires the optional
windrosepackage.- Parameters:
wind_speed (array-like) – Wind speed values.
wind_dir (array-like) – Wind direction values (degrees, meteorological convention).
ax (WindroseAxes, optional)
bins (array-like, optional) – Speed bins.
title (str, optional)
- Returns:
ax
- Return type:
WindroseAxes
bldfm.plotting.contours module¶
Source area contour visualization functions.
These functions combine the output of bldfm.utils.get_source_area()
with matplotlib contour overlays. The get_source_area computation
itself lives in bldfm.utils – this module handles only visualization.
Source area contours represent the spatial region that contributes a given fraction of the measured flux. Different “base functions” produce different contour geometries:
Contribution contours (g = f): standard isopleth contours
Circular contours (g = -(r^2)): concentric circles from tower
Upwind contours (g = dot(wind_hat, r)): upwind distance bands
Crosswind contours (g = -(perp distance)^2): crosswind ridges
Sector contours (g = -abs(theta)): angular sectors from upwind axis
See also
bldfm.utils.get_source_areaRescale a field so contour levels represent cumulative contribution fractions.
- bldfm.plotting.contours.plot_source_area_contours(flx, grid, source_area_field, levels=None, ax=None, contour_colors=None, cmap='RdYlBu_r', title=None, level=0, colorbar=True, **pcolormesh_kw)[source]¶
Plot footprint field with source area contour overlay.
The
source_area_fieldshould be the output ofget_source_area(flx, g)for some base functiong.- Parameters:
flx (ndarray (ny, nx) or (nz, ny, nx)) – Original footprint field (plotted as pcolormesh background). If 3D, sliced at level.
grid (tuple (X, Y, Z) or (X, Y)) – Coordinate arrays from the solver.
source_area_field (ndarray (ny, nx) or (nz, ny, nx)) – Rescaled field from
get_source_area(), where contour levels represent cumulative contribution fractions. If 3D, sliced at level.levels (list of float, optional) – Contribution fraction levels (default [0.25, 0.5, 0.75]).
ax (matplotlib Axes, optional)
contour_colors (list of str, optional) – Colors for contour lines (default [‘white’, ‘magenta’, ‘cyan’]).
cmap (str) – Colourmap for background pcolormesh.
title (str, optional)
level (int) – Z-index to use when fields are 3D. Default 0 (surface).
colorbar (bool) – Whether to add a colorbar. Default True.
**pcolormesh_kw – Forwarded to
ax.pcolormesh.
- Returns:
ax
- Return type:
matplotlib Axes
- bldfm.plotting.contours.plot_source_area_gallery(flx, grid, meas_pt, wind, levels=None, cmap='RdYlBu_r', figsize=None, level=0)[source]¶
Multi-panel plot showing all 5 source area contour types.
- Parameters:
flx (ndarray (ny, nx) or (nz, ny, nx)) – Footprint field. If 3D, sliced at level.
grid (tuple (X, Y, Z) or (X, Y)) – Coordinate arrays from the solver.
meas_pt (tuple (xm, ym)) – Measurement point.
wind (tuple (u, v)) – Wind components (m/s).
levels (list of float, optional) – Contribution fraction levels (default [0.25, 0.5, 0.75]).
cmap (str) – Colourmap for background.
figsize (tuple, optional) – Figure size (default (18, 10)).
level (int) – Z-index to use when flx is 3D. Default 0 (surface).
- Returns:
fig (matplotlib Figure)
axes (ndarray of Axes (2, 3))