tcpyVPI
A Python package to calculate the tropical cyclone ventilated Potential Intensity (vPI) and the Genesis Potential Index using vPI (GPIv) from gridded datafiles.
See Chavas, Camargo, & Tippett (2025, J. Clim.) for details.
Author: Dan Chavas (2025)
Collaborators: Aaron Kruskie, Jose Ocegueda Sanchez (2025)
Installation
pip install tcpyVPI
Or install from source:
git clone https://github.com/drchavas/tcpyVPI.git
cd tcpyVPI
pip install -e .
Features
- Monthly Mean Data: Compute GPIv from ERA5 monthly mean reanalysis (d633001)
- Hourly Data: Compute GPIv from ERA5 hourly reanalysis (d633000) via THREDDS remote access
- Climatology: Compute and store monthly climatologies of GPIv and its components
- Anomalies: Calculate anomalies relative to climatological means
- Standardized Anomalies: Compute z-scores for statistical analysis
- Configurable: Pressure levels, thresholds and PI options can be overridden for sensitivity testing; defaults reproduce Chavas et al. (2025)
Quick Start
Monthly Mean Computation
from tcpyVPI import run_vpigpiv
# Compute GPIv for September 2022
results = run_vpigpiv(2022, 9)
Hourly Computation
from tcpyVPI import run_vpigpiv_hourly
# Compute GPIv for August 15, 2020 at 12Z
results = run_vpigpiv_hourly(2020, 8, 15, hour=12)
With Anomalies
from tcpyVPI import run_vpigpiv_hourly
# First, compute or load a climatology
results = run_vpigpiv_hourly(
2020, 8, 15, hour=12,
compute_anomalies=True,
climatology_path='gpiv_climatology.nc'
)
Data Loading
The package provides flexible data loading from NCAR RDA THREDDS servers:
from tcpyVPI import load_era5_data, load_era5_hourly
# Load monthly mean data
ds_monthly = load_era5_data(2022, 9, data_source='monthly')
# Load hourly data for a specific time
ds_hourly = load_era5_data(2020, 8, day=15, hour=12, data_source='hourly')
# Load all hours of a day
ds_day = load_era5_hourly(2020, 8, 15)
ERA5 Dataset Structure
The package accesses ERA5 data via THREDDS with the following structure:
Monthly Mean (d633001):
- All 12 months in a single file per variable per year
- Both surface and pressure level variables
Hourly (d633000):
- Surface variables: Monthly files containing all hours
- Example:
e5.oper.an.sfc.128_165_10u.ll025sc.2020080100_2020083123.nc
- Example:
- Pressure level variables: Daily files containing 24 hours
- Example:
e5.oper.an.pl.128_131_u.ll025uv.2020081500_2020081523.nc
- Example:
Climatology Computation
from tcpyVPI import compute_monthly_climatology, compute_gpiv_from_dataset
# Compute 40-year climatology (1980-2020)
climatology = compute_monthly_climatology(
compute_gpiv_from_dataset,
years=range(1980, 2020),
output_path='gpiv_climatology.nc'
)
Computing Components Individually
from tcpyVPI import (
load_era5_data,
calculate_potential_intensity,
calculate_vws,
calculate_entropy_deficit,
calculate_etac,
)
# Load data
ds = load_era5_data(2022, 9, data_source='monthly')
# Calculate individual components
PI, asdeq = calculate_potential_intensity(ds)
VWS = calculate_vws(ds)
Chi = calculate_entropy_deficit(ds, asdeq)
eta_c = calculate_etac(ds)
Configuration
By default the package reproduces the configuration of Chavas et al. (2025), and you never need to touch any of this. Since v1.2.0 the choices that were previously hardcoded can be overridden for sensitivity testing:
| Argument | Default | Meaning |
|---|---|---|
shear_p_top |
200 hPa | top of the bulk shear layer |
shear_p_bot |
850 hPa | bottom of the bulk shear layer |
chi_p_mid |
600 hPa | mid-level for the entropy deficit |
vort_level |
850 hPa | level of the relative vorticity |
vort_cap |
3.7e-5 s⁻¹ | cap on the magnitude of absolute vorticity |
VI_max |
0.145 | ventilation index above which vPI = 0 |
gpiv_exponent |
4.90 | exponent in GPIv = (102.1 · vPI · η_c)^a |
CKCD |
0.9 | ratio C_k/C_d, passed to tcpyPI |
ascent_flag |
0 | tcpyPI: 0 = reversible, 1 = pseudo-adiabatic |
diss_flag |
1 | tcpyPI: 1 = dissipative heating on, 0 = off |
ptop |
50 hPa | sounding above this level is ignored |
# defaults - reproduces the paper
results = run_vpigpiv(2022, 9)
# override any subset
results = run_vpigpiv(2022, 9, chi_p_mid=500, shear_p_top=250)
They work on run_vpigpiv, run_vpigpiv_hourly and compute_gpiv_from_dataset,
and the level/threshold arguments are also on the individual calculate_*
functions. Defaults are importable as module constants
(DEFAULT_SHEAR_P_TOP, etc.).
See python_notebooks/tcpyVPI_ERA5builtin_example.ipynb section 3 for a
runnable demo of passing these values. For a side-by-side default-vs-custom
comparison with difference maps, see
github_tests/tcpyVPI_ERA5_from_github.ipynb.
Two caveats:
- Pressure levels are selected exactly, not by nearest neighbour. Asking for
a level the dataset does not contain raises a
KeyErrorlisting what is available; interpolate onto that level first. gpiv_exponentis tied to the normalising constant 102.1, which was calibrated jointly with the default exponent 4.90 to match the observed global mean genesis count. Changing the exponent alone leaves GPIv un-normalised: spatial patterns remain meaningful, absolute values do not.
Example Notebooks
| Notebook | What it shows |
|---|---|
python_notebooks/tcpyVPI_ERA5builtin_example.ipynb |
Shortest path: monthly and hourly via the wrapper functions, plus the configuration options |
python_notebooks/tcpyVPI_ERA5_example.ipynb |
Loading and computing in separate steps, with custom plots |
python_notebooks/tcpyVPI_CESM2_example.ipynb |
Climate-model output instead of reanalysis |
python_notebooks/tcpyVPI_ERA5climoanomaly_Jose.ipynb |
Climatologies and anomalies |
github_tests/tcpyVPI_ERA5_from_github.ipynb |
Installing from GitHub rather than PyPI, and comparing output across versions or configurations |
Output Variables
The main computation returns a dataset with:
| Variable | Description | Units |
|---|---|---|
GPIv |
Ventilated Genesis Potential Index | - |
vPI |
Ventilated Potential Intensity | m/s |
PI |
Potential Intensity | m/s |
VWS |
Vertical Wind Shear (200-850 hPa) | m/s |
Chi |
Entropy Deficit | - |
eta_c |
Capped absolute vorticity (850 hPa), signed | s⁻¹ |
eta_c_cyclonic |
Same, hemisphere-mirrored and clipped at zero — the form GPIv uses | s⁻¹ |
ventilation_index |
Ventilation Index | - |
A note on eta_c
Two vorticity fields are returned, and the difference matters if you plot or analyse them:
eta_cis the signed absolute vorticity, clipped by magnitude to ±vort_cap. It is negative in the Southern Hemisphere, which is physically correct and is what you want on a map.eta_c_cyclonicmirrors the hemispheres so cyclonic rotation is positive everywhere, then clips anticyclonic values to zero. This is the field GPIv is built from, because GPIv raises it to a non-integer power (4.90) and a negative base would be NaN.
calculate_etac() returns the signed form by default; pass cyclonic=True for
the mirrored one.
eta_signed = calculate_etac(ds) # negative in the SH
eta_cyclonic = calculate_etac(ds, cyclonic=True) # non-negative everywhere
Through v1.2.0 there was only one field and it was wrong in the SH; see the v1.3.0 entry in CHANGELOG.md.
When computing anomalies, additional fields are added:
*_anom: Anomaly fields*_clim: Climatological values
Dependencies
- numpy
- xarray
- tcpyPI
- matplotlib (for plotting)
- cartopy (for plotting)
License
MIT License - see LICENSE file for details.
Citation
If you use this package, please cite:
Chavas, D. R., Camargo, S. J., & Tippett, M. K. (2025). "Tropical cyclone genesis potential using a ventilated potential intensity". Journal of Climate.
Metadata
Release files for tcpyVPI 1.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| tcpyvpi-1.3.0.tar.gz | 28.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| tcpyvpi-1.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 54.4 kB
Release files / tcpyvpi-1.3.0.tar.gz
| Download URL | tcpyvpi-1.3.0.tar.gz |
|---|---|
| Size | 28.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a78a358191d26ce0d007a2b77ac2e6fff23e934791c7b854a67d248c7bd3d5a7
|
|
BLAKE2b-256 checksum How to use checksums |
fba5131f9003eb93ed6523445b1b7fa0185979f8413f83346d4ddf84fbece3b3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 9, 2026.
Transparency logRelease files / tcpyvpi-1.3.0-py3-none-any.whl
| Download URL | tcpyvpi-1.3.0-py3-none-any.whl |
|---|---|
| Size | 25.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
46c12c0df22e40e26319c10f27a72c5615d8ef1d39d23396eb59a5e07b50a077
|
|
BLAKE2b-256 checksum How to use checksums |
29338137ccf43653ee10a7eb4b90a7e1615aac90ef4b5ce329878e7d886794ac
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 9, 2026.
Transparency log