ClimKern: a Python package for calculating radiative feedbacks

June 13, 2026 ยท View on GitHub

DOI License: MIT

Overview

The radiative kernel technique outlined in Soden & Held (2006) and Soden et al. (2008) is commonly used to calculate climate feedbacks. The "kernels" refer to datasets containing the radiative sensitivities of TOA (or surface) radiation to changes in fields such as temperature, specific humidity, and surface albedo; they are typically computed using offline radiative transfer calculations.

ClimKern

  • standardizes the assumptions used in producing radiative feedbacks using kernels
  • simplifies the calculations by giving users access to functions tailored for climate model and reanalysis output
  • provides access to a repository of 11 different radiative kernels to quantify interkernel spread

The below information is meant to be a quickstart guide, but all functions and capabilities can be found at ClimKern's documentation site.

Installation

ClimKern is built on the Xarray architecture and requires several other packages for regridding and climate model output compatibility. The easiest method is to create a new conda environment using conda or mamba:

conda create -n ck_env python=3.11 esmpy -c conda-forge

A conda environment is necessary because ESMPy, which is required for regridding kernels, is unavailable via pip.

Next, activate the new environment:

conda activate ck_env

Finally, install ClimKern with pip:

pip install climkern

Once installed, ClimKern needs radiative kernels and (optionally) tutorial data, which are stored separately from the package because of PyPI size limitations (they total ~5 GB). You no longer have to download everything up front. By default, ClimKern fetches each kernel/tutorial file on demand from Project Pythia's Jetstream2 object store the first time you use it, caches it locally, and reuses the cached copy afterwards. The full dataset is also archived on Zenodo (please cite it if you use the kernels).

If you would rather grab the full dataset in one shot (for offline use), the download script still works and now unpacks into the same cache:

python -m climkern download

Streaming vs. caching

ClimKern's data source is controlled globally with ck.set_options(...) or the CLIMKERN_DATA_SOURCE environment variable:

import climkern as ck

ck.set_options(data_source="cache")   # default: download-on-demand + reuse
ck.set_options(data_source="stream")  # read straight from Jetstream2, write nothing to disk
ck.set_options(data_source="local")   # only use already-downloaded files (offline)

# temporary override:
with ck.set_options(data_source="stream"):
    kern = ck.tutorial_data("ctrl")
  • Where the cache lives: a per-OS cache directory (e.g. ~/.cache/climkern on Linux), not your home or site-packages directory. Override it with ck.set_options(cache_dir="/path") or the CLIMKERN_DATA_DIR environment variable.
  • On HPC or small home quotas: ~/.cache sits on your home filesystem, which clusters often keep small. Set CLIMKERN_DATA_DIR to scratch or project storage (e.g. in your .bashrc or job script) so kernels don't fill your home directory โ€” for example export CLIMKERN_DATA_DIR=$SCRATCH/climkern. Because ClimKern caches per file, you typically store only the kernels you use, not the full 5 GB.
  • stream writes nothing to disk.
  • Staying current: cached files are verified against hashes shipped with the package, so if a kernel is corrected in a new ClimKern release, the fixed file is re-downloaded automatically when you upgrade. ClimKern also warns once per session if a newer kernel dataset is available (disable with ck.set_options(version_check=False)).

IMPORTANT: SSL Certificate Errors It is possible to get an SSL certificate error when trying to run the download script. You may try updating your certificate authorities with pip install --upgrade certifi.

If that does not work, you can manually download the data.zip file from Zenodo and unzip it in your ClimKern package directory.

Optional:

You can test your installation via pytest.

pip install pytest
pytest -v --pyargs climkern

All three tests should pass.

Basic tutorial

Temperature, water vapor, and surface albedo feedbacks

This brief tutorial will cover the basics of using ClimKern. Please check the documentation for a more complete list of available functions. We start by importing ClimKern and accessing our tutorial data:

import climkern as ck

ctrl, pert = ck.tutorial_data("ctrl"), ck.tutorial_data("pert")

These datasets have all the necessary variables for computing feedbacks. Let's start with temperature feedbacks.

LR, Planck = ck.calc_T_feedbacks(
    ctrl.T, ctrl.TS, ctrl.PS, pert.T, pert.TS, pert.PS, pert.TROP_P, kern="GFDL"
)

To produce succinct output, let's use ClimKern's spatial average function. Additionally, we will normalize the feedbacks by global average surface temperature change to convert from Wm-2, the output of ClimKern functions, to the more commonly used units of Wm-2K-1.

# compute global average surface temperature change
dTS_glob_avg = ck.spat_avg(pert.TS - ctrl.TS)

# normalize temperature feedbacks by temperature change and take
# the annual average
print("The global average lapse rate feedback is {val:.2f} W/m^2/K.".format(
    val=(ck.spat_avg(LR)/dTS_glob_avg).mean()))
print("The global average Planck feedback is {val:.2f} W/m^2/K.".format(
    val=(ck.spat_avg(Planck)/dTS_glob_avg).mean()))

Expected result with the GFDL kernel:

The global average lapse rate feedback is -0.41 W/m^2/K.

The global average Planck feedback is -3.12 W/m^2/K.

The water vapor and surface albedo feedbacks are calculated similarly:

q_lw,q_sw = ck.calc_q_feedbacks(ctrl.Q,ctrl.T,ctrl.PS,
                                pert.Q,pert.PS,pert.TROP_P,
                                kern="GFDL",method=1)
alb = ck.calc_alb_feedback(ctrl.FSUS,ctrl.FSDS,
                           pert.FSUS,pert.FSDS,
                           kern="GFDL")

print("The global average water vapor feedback is {val:.2f} W/m^2/K.".format(
    val=(ck.spat_avg(q_lw+q_sw)/dTS_glob_avg).mean()))
print("The global average surface albedo feedback is {val:.2f} W/m^2/K."
      .format(
    val=(ck.spat_avg(alb)/dTS_glob_avg).mean()))

Expected result:

The global average water vapor feedback is 1.44 W/m^2/K.

The global average surface albedo feedback is 0.38 W/m^2/K.

Cloud feedbacks

The cloud feedbacks, calculated using Soden et al. (2008) adjustment method, require all-sky and clear-sky versions of other feedbacks and the instantaneous radiative forcing.

First, we need the longwave and shortwave cloud radiative effects, which ClimKern can calculate.

dCRE_LW = ck.calc_dCRE_LW(ctrl.FLNT,pert.FLNT,ctrl.FLNTC,pert.FLNTC)
dCRE_SW = ck.calc_dCRE_SW(ctrl.FSNT,pert.FSNT,ctrl.FSNTC,pert.FSNTC)

Let's also read in the tutorial erf.

erf = ck.tutorial_data('ERF')

Next, we need the clear-sky versions of the temperature, water vapor, and surface albedo feedbacks.

#_cs means clear-sky
LR_cs,Planck_cs = ck.calc_T_feedbacks(ctrl.T,ctrl.TS,ctrl.PS,
                                pert.T,pert.TS,pert.PS,pert.TROP_P,
                                kern="GFDL",sky="clear-sky")
q_lw_cs,q_sw_cs = ck.calc_q_feedbacks(ctrl.Q,ctrl.T,ctrl.PS,
                                pert.Q,pert.PS,pert.TROP_P,
                                kern="GFDL",method=1,sky="clear-sky")
alb_cs = ck.calc_alb_feedback(ctrl.FSUS,ctrl.FSDS,
                           pert.FSUS,pert.FSDS,
                           kern="GFDL",sky="clear-sky")

At last, we can calculate the longwave and shortwave cloud feedbacks.

cld_lw = ck.calc_cloud_LW(LR + Planck,LR_cs+Planck_cs,q_lw,q_lw_cs,dCRE_LW,
                          erf.erf_lwas,erf.erf_lwcs)
cld_sw = ck.calc_cloud_SW(alb,alb_cs,q_sw,q_sw_cs,dCRE_SW,erf.erf_swas,
                          erf.erf_swcs)

print("The global average SW cloud feedback is {val:.2f} W/m^2/K.".format(
    val=(ck.spat_avg(cld_sw)/dTS_glob_avg).mean()))
print("The global average LW cloud feedback is {val:.2f} W/m^2/K.".format(
    val=(ck.spat_avg(cld_lw)/dTS_glob_avg).mean()))

Expected result:

The global average SW cloud feedback is 0.38 W/m^2/K.

The global average LW cloud feedback is 0.03 W/m^2/K.

Troubleshooting

If you are having issues downloading dependencies with pip, you can also try adding them to your conda environment with conda, i.e.:

conda install xesmf -c conda-forge

If you are having trouble downloading the kernels and tutorial data using the package's download function, you can also download the data directly from the Zenodo repository and put it in the climkern/data directory located wherever your conda/mamba environments are stored.

Other features & coming soon

ClimKern has several other useful features:

  • Four different methods for calculating water vapor feedbacks.
  • The ability to calculate the "relative humidity" version of all feedbacks following Held & Shell (2012) and Zelinka et al. (2020).
  • Functions to calculate stratospheric temperature and water vapor feedbacks.

We are continuously updating the package. Please check out the GitHub issues page for this repository for plans for new features.

Want to help? Get involved!

We deeply appreciate contributions from other scientists and programmers and are happy to attribute credit accordingly. If you wish to contribute, please read our CONTRIBUTING.md for guidelines on how to get started.

tl;dr:

  • Work from the dev branch, not main
  • Submit a pull request when ready.

๐Ÿ“– How to Cite ClimKern

If you use ClimKern in your work, please cite our paper:

Janoski, T. P., Mitevski, I., Kramer, R. J., Previdi, M., & Polvani, L. M. (2025). ClimKern v1.2: a new Python package and kernel repository for calculating radiative feedbacks. Geoscientific Model Development, 18(10), 3065โ€“3079. https://doi.org/10.5194/gmd-18-3065-2025

BibTeX
@article{janoski2025climkern,
  AUTHOR = {Janoski, T. P. and Mitevski, I. and Kramer, R. J. and Previdi, M. and Polvani, L. M.},
  TITLE = {ClimKern v1.2: a new Python package and kernel repository for calculating radiative feedbacks},
  JOURNAL = {Geoscientific Model Development},
  VOLUME = {18},
  YEAR = {2025},
  NUMBER = {10},
  PAGES = {3065--3079},
  URL = {https://gmd.copernicus.org/articles/18/3065/2025/},
  DOI = {10.5194/gmd-18-3065-2025}
}

If you are citing the software itself (e.g., for reproducibility), use the citation metadata included in our CITATION.cff file. GitHub also provides downloadable citation formats via the "Cite this repository" button on the right-hand sidebar.