Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

FluxPrint

FluxPrint is an open-source Python package implementing flux footprint models for eddy covariance data analysis. It provides footprint-model implementations behind a single, consistent interface so researchers can compare spatially resolved fluxes with field measurements, and add new models by following a small convention. It is designed for interoperability with ecosystem flux datasets (e.g. FLUXNET). See Figure 1 for the conceptual scheme.

Conceptual scheme for FluxPrint.

Figure 1. Conceptual scheme for FluxPrint.


Why FluxPrint?

Most eddy-covariance users already have Kljun's official FFP scripts or EddyPro's built-in footprint estimates. FluxPrint adds, on top of the same science:

  • Verified fidelity: the Kljun et al. (2015) implementation is pinned against the original FFP code (vendored in this repository) by regression tests asserting bitwise-identical fields — a dedicated CI job fails if any registered model ever diverges from its reference implementation.
  • A batch workflow: one call takes a half-hourly table (FLUXNET/ICOS style), validates and estimates missing micrometeorology per record, and returns a typed FootprintSeries ready for climatologies.
  • A typed object API: georeferencing, source-area contours, plots, NetCDF/GeoTIFF/Shapefile export, and provenance metadata on every result.

Features

  • Footprint models behind one interface, selected by name: Kljun et al. (2015) and Hsieh et al. (2000, with the Detto et al. 2006 crosswind expansion); Kormann & Meixner (2001) is planned. A new model is only its physics — a per-record kernel registered with @footprint_model inherits the grid, record loop, validation, smoothing and provenance.
  • A typed footprint object (Footprint): a 2-D source-area field on a fixed grid centred on the tower, plus FootprintSeries for time-ordered stacks.
  • Two coordinate frames: a local, tower-centred metric grid, and a georeferenced projected grid (georeference()); lon/lat is display-only.
  • Source-area contours: contours() for the 50/80% isopleths, plot() for a quick look, to_shapefile() for GIS.
  • Serialization: NetCDF is the native format (CF grid mapping included), with GeoTIFF conversion; outputs carry provenance (package/model version, citation, settings).
  • Aggregation: collapse a FootprintSeries into a climatology.

Installation

pip install fluxprint

Or from source for development:

pip install git+https://github.com/pedrohenriquecoimbra/fluxprint

import fluxprint is light: the geo/plotting stack (xarray/netcdf4, rasterio, pyproj, fiona/shapely, matplotlib) is imported lazily by the operations that need it. Those libraries are still installed as dependencies today; a future release will move them into the already-declared extras (fluxprint[netcdf], [tiff], [crs], [shapefile]; [viz] adds folium for interactive maps, [all] installs everything).


Quickstart

From a met table to a climatology (the batch path)

import pandas as pd
import fluxprint

data = pd.read_csv("halfhours.csv", na_values=[-9999])  # FLUXNET-style table

climatology = fluxprint.wrapper(
    data=data,
    zm=20.0,       # aerodynamic height: z - d, see note below
    pblh=1500.0,   # boundary-layer height [m] - not in FLUXNET tables, so
                   # supply it (or a PBLH/BLH column, or opt into the crude
                   # 1000 m constant with fill_all=True)
    tower=(4321000.0, 3210000.0),   # tower position, for georeferencing
    tower_crs="EPSG:3035",
    dst="climatology.nc",           # optional: write the result
)

Columns are matched case-insensitively with common aliases (USTAR/u*, WD/wind_direction, WS/wind_speed, OL/L, SIGMA_V/v_sd, ...; H, the sensible heat flux, is matched exactly so FFP's lowercase h — the boundary-layer height — is never mistaken for it). Missing variables are estimated when physically possible — e.g. the Obukhov length from USTAR/H/TA/PA — and every estimated variable is recorded in the result's attrs["estimated_inputs"]. Crude constant fallbacks (including the pblh=1000 constant) require an explicit fill_all=True and warn loudly.

Use fluxprint.calculate_footprint(data, by="timestamp_column", ...) for one footprint per group (a FootprintSeries) instead of a single climatology.

zm is the aerodynamic height. All models define zm = z - d (measurement height above the zero-plane displacement), not the instrument height. Over vegetation the difference is substantial. If you pass measurement_height together with displacement (or canopy_height, using d ≈ 0.67·h), FluxPrint derives zm for you.

Compute a single footprint directly

from fluxprint.model import get_model

kljun = get_model("kljun2015")
fp = kljun(
    zm=2.0,          # measurement height above displacement [m]
    z0=0.01,         # roughness length [m]  (or pass umean instead)
    ustar=0.5,       # friction velocity [m s-1]
    pblh=1000.0,     # boundary-layer height [m]
    mo_length=-50.0, # Obukhov length [m]
    v_sigma=0.5,     # std. dev. of lateral velocity [m s-1]
    wind_dir=180.0,  # wind direction [deg] (orients the grid north-up)
    dx=2.0,          # grid spacing [m]
    tower=(4321000.0, 3210000.0),
    tower_crs="EPSG:3035",
)

fp.total()      # fraction of the flux captured by the grid (also in attrs)
fp.peak_xy()    # (x, y) of the footprint peak, metres from the tower
fp.contours([0.5, 0.8])   # 50%/80% source-area isopleths
fp.plot(rs=[0.5, 0.8])    # quick-look plot (matplotlib)

Inputs may be scalars (one record) or equal-length sequences (composited into a single footprint, fp.n records). Records failing the model's validity checks (including NaN gaps) are rejected per record.

Georeference and export

geo = fp.georeference("EPSG:3035")   # local metres -> projected coords (needs pyproj)
geo.to_netcdf("footprint.nc")        # needs xarray/netcdf4; CF grid mapping included
geo.to_tiff("footprint.tif")         # needs rasterio
geo.to_shapefile("contours.shp", rs=[0.5, 0.8])  # needs fiona

Adding a model

A model is a callable mapping micrometeorological inputs to one 2-D Footprint in the local frame. Register it by name and it becomes selectable everywhere:

from fluxprint.model import register_model
from fluxprint.footprint import Footprint

@register_model("my_model", description="My footprint parameterisation")
def calc(*, zm, ustar, pblh, mo_length, v_sigma, wind_dir, z0=None, umean=None,
         domain=None, dx=None, dy=None, tower=None, tower_crs=None, time=None,
         **kwargs) -> Footprint:
    f = ...  # 2-D field on a regular grid centred on the tower
    return Footprint.from_grid(f, dx=dx, tower=tower, tower_crs=tower_crs, time=time)
from fluxprint.model import available_models, get_model
available_models()        # ['kljun2015', 'my_model']
get_model("my_model")(...)

The registry is backed by regorator. New models are expected to come with a reference oracle in tests/test_reference_regression.py pinning them against their original implementation — CI enforces this.


API reference

Top level (import fluxprint)

  • calculate_footprint(data, by=None, model="kljun2015", on_error="skip", ...) — footprint each group of a table; returns a FootprintSeries. on_error decides what a failed group costs: drop it ("skip"), abort ("raise"), or keep an all-NaN member with the reason in attrs["error"] ("nan"). The series is eager — right for grouped climatologies (tens to hundreds of members); for one footprint per record over long records, use map_footprints below instead.
  • map_footprints(data, model="kljun2015", ...) — the xarray/dask-native compute path: maps the model's per-record kernel over arrays of any dimensionality and returns a DataArray with dims (*input_dims, y, x). Lazy over dask-backed inputs; a bad record costs a NaN plane, never the job; rejections are summarised once per block.
  • wrapper(...) — calculate_footprint + aggregation + optional file output.
  • empty_footprint(model, domain=..., dx=...) — a NaN template on the model's grid. This is the template API: use it to learn the exact output grid/shape (~2 ms) instead of running the model on placeholder meteorology.
  • ALIASES — the table of column aliases process_footprint_inputs recognizes (model inputs and estimator drivers).
  • read_handler / read_from_url / read_from_file — table/NetCDF/TIFF readers.
  • Legacy write_to_* helpers are deprecated: use the Footprint.to_* methods.
  • fluxprint.commons.start_logging(path) — opt-in file logging for applications: attaches a handler to the fluxprint logger (the package itself stays silent by default via a NullHandler).

fluxprint.model

  • get_model(name) — return the registered model callable.
  • available_models() — list registered model names.
  • register_model(name, description="", **attrs) — decorator to register a model.
  • FootprintModel — the callable protocol models conform to.

fluxprint.footprint.Footprint

  • Footprint.from_grid(f, dx, dy=None, **meta) — build a local, tower-centred footprint.
  • georeference(target_crs) / to_lonlat() — local → projected; display lon/lat.
  • total(), peak_xy(), normalized(), contours(rs) — analysis helpers.
  • captured_fraction — fraction of the flux the domain captures (= total()).
  • level_for(r) — the source-area field level for fraction r (fractions are of the full unit-integral footprint, not of the captured total).
  • smoothed() — the standard FFP 3×3 double-convolution smoothing, applicable to any footprint (fluxprint.footprint.smooth_field is the array primitive).
  • weighted_mean(field, min_coverage=None) — footprint-weighted mean of a gridded quantity; owns the NaN mask and the coverage threshold, and returns a uniform field unchanged whatever the normalization or truncation.
  • replace(**changes) — variant constructor (fp.replace(time=None)); copies attrs, shares the arrays unless replaced.
  • plot(rs=None) — matplotlib quick look (never calls plt.show()).
  • to_netcdf / from_netcdf, to_tiff / from_tiff, to_xarray / from_xarray, to_shapefile.

fluxprint.footprint.FootprintSeries

  • aggregate(smooth=True) — collapse the stack to a 2-D climatology.
  • georeference(target_crs), to_netcdf / from_netcdf, to_xarray / from_xarray.

See CHANGELOG.md for release notes and deprecations.


Examples

See the sample/ directory for usage examples.


Citing FluxPrint

If FluxPrint contributes to your research, please cite the software (see CITATION.cff) alongside the footprint-model paper you used (e.g. Kljun et al., 2015 — the models' own citations and DOIs are stamped into every output's metadata).


Contributing

Contributions are welcome — see CONTRIBUTING.md for the development setup, and open a pull request from a feature branch.


License

Licensed under the European Union Public Licence v. 1.2 (EUPL-1.2). See the LICENSE file for details. The vendored Kljun et al. (2015) FFP reference code (fluxprint/model/Kljun_et_al_2015_original/) is distributed under its own permissive licence (see the license.txt alongside it), copyright (C) 2015–2023 Natascha Kljun.


Acknowledgments

  • Kljun, N., Calanca, P., Rotach, M. W., Schmid, H. P. (2015): The simple two-dimensional parameterisation for Flux Footprint Predictions (FFP), Geosci. Model Dev. 8, 3695–3713, doi:10.5194/gmd-8-3695-2015.
  • Hsieh, C.-I., Katul, G., Chi, T. (2000): An approximate analytical model for footprint estimation of scalar fluxes in thermally stratified atmospheric flows, Adv. Water Resour. 23, 765–772, doi:10.1016/S0309-1708(99)00042-1.
  • Kormann, R., Meixner, F. X. (2001): An analytical footprint model for non-neutral stratification, Boundary-Layer Meteorol. 99, 207–224, doi:10.1023/A:1018991015119.

Contact

Metadata

Release files for fluxprint 0.4.0a1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for fluxprint 0.4.0a1
File Size Uploaded
fluxprint-0.4.0a1.tar.gz 122.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for fluxprint 0.4.0a1
File Interpreter ABI Platform
fluxprint-0.4.0a1-py3-none-any.whl Python 3 none any Details

Total release size: 223.9 kB

Release files / fluxprint-0.4.0a1.tar.gz

Download URL fluxprint-0.4.0a1.tar.gz
Size 122.8 kB
Tags Source
SHA-256 checksum
How to use checksums
b0965a206e295ecb456386d5c0672c6b7d1bcea2c77566a8c6274d71e491cf7b
BLAKE2b-256 checksum
How to use checksums
3730ef3a8831f700700c82ea986361f003453b7e283007045764597169e347ce
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/5.1.1 CPython/3.8.12

Release files / fluxprint-0.4.0a1-py3-none-any.whl

Download URL fluxprint-0.4.0a1-py3-none-any.whl
Size 101.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
145c765841e116aa973764750953f52a4de5d7f03d274bac68a2c1136aee43cb
BLAKE2b-256 checksum
How to use checksums
ff24414b0df118aec3715a7a56e36d5c0e6982021d1b4e2d587ae093f4153ec3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/5.1.1 CPython/3.8.12

Release history Release notifications | RSS feed

0.4.0

2 release files

This release

0.4.0a1 This release

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.0

2 release files

0.0.4

2 release files

0.0.3

2 release files

0.0.2

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page