# How to Work with Ensemble Forecast Models Like GEFS Using Herbie

> Learn how to work with ensemble forecast models like GEFS using Herbie. Effortlessly resolve ensemble member names, build paths, and download variables with Herbie's model templates.

- Repository: [Brian Blaylock/herbie](https://github.com/blaylockbk/herbie)
- Tags: how-to-guide
- Published: 2026-02-26

---

**Use Herbie's model templates to automatically resolve GEFS ensemble member names, build remote file paths, and download specific variables via byte-range subsetting.**

Herbie is an open-source Python library that simplifies access to numerical weather prediction data. When you work with ensemble forecast models like GEFS, Herbie abstracts the complexity of member naming conventions, file path construction, and data subsetting through its template-based architecture.

## Understanding GEFS Ensemble Structure in Herbie

### The GEFS Template Architecture

Herbie treats every forecast model as a template that knows how to build remote file paths for different products, members, and lead times. The GEFS template is defined in [`src/herbie/models/gefs.py`](https://github.com/blaylockbk/herbie/blob/main/src/herbie/models/gefs.py)【/cache/repos/github.com/blaylockbk/herbie/main/src/herbie/models/gefs.py】.

When you instantiate a `Herbie` object in [`src/herbie/core.py`](https://github.com/blaylockbk/herbie/blob/main/src/herbie/core.py), the constructor performs three critical operations:

1. **Normalizes the request** – converts the supplied date, lead time (`fxx`), and member into the exact filename pattern the GEFS archive uses.
2. **Selects the data source** – AWS, Google Cloud, Azure, or NOAA NOMADS are tried in the order you specify (or the default priority). The mapping of sources is defined in `self.SOURCES` inside the template.
3. **Validates inputs** – ensures the chosen product, member, and lead-time are supported for the selected date range (e.g., the file-directory layout changed on 2020-09-23, see the conditional blocks in the template).

### Member Naming Conventions

GEFS stores members as `c00` (control) or `pNN` (perturbations). The template automatically translates `member=0` → `c00` and any other integer → `pNN`【/cache/repos/github.com/blaylockbk/herbie/main/src/herbie/models/gefs.py#L51-L54】.

From 2020 onward, the template also supports wave (`wave`) and chemistry (`chem.5`, `chem.25`) products, adjusting the filename pattern accordingly【/cache/repos/github.com/blaylockbk/herbie/main/src/herbie/models/gefs.py#L70-L78】.

## Instantiating Herbie for Ensemble Members

To access a specific ensemble member, pass the `member` parameter when creating the `Herbie` object. Herbie handles the translation from integer indices to GEFS naming conventions.

```python
from herbie import Herbie

# Access the control member (c00)

H_control = Herbie(
    "2023-04-01 12:00",
    model="gefs",
    product="atmos.5",
    fxx=6,
    member=0
)

# Access perturbation member 5 (p05)

H_p05 = Herbie(
    "2023-04-01 12:00",
    model="gefs",
    product="atmos.5",
    fxx=6,
    member=5
)

```

The `Herbie` constructor in [`src/herbie/core.py`](https://github.com/blaylockbk/herbie/blob/main/src/herbie/core.py)【/cache/repos/github.com/blaylockbk/herbie/main/src/herbie/core.py#L61-L84】 automatically invokes the GEFS template to build the correct remote URL based on the member value.

## Working with Multiple Ensemble Members

Because each ensemble member is stored as a separate GRIB2 file, you typically loop over the desired members, download (or subset) each, and concatenate the resulting `xarray` objects along a new "member" dimension.

```python
from herbie import Herbie
import xarray as xr

date = "2023-04-01 12:00"
model = "gefs"
product = "atmos.5"
variable = "TMP:2 m"

# Build a list of datasets, one per member

datasets = []
for mem in range(1, 31):
    H = Herbie(
        date,
        model=model,
        product=product,
        fxx=0,
        member=mem,
    )
    ds = H.xarray(search=variable)
    ds = ds.expand_dims(member=[mem])   # add member dimension

    datasets.append(ds)

# Concatenate along the new "member" axis

gefs_ensemble = xr.concat(datasets, dim="member")
print(gefs_ensemble)

```

This pattern leverages the `xarray` method in [`src/herbie/core.py`](https://github.com/blaylockbk/herbie/blob/main/src/herbie/core.py)【/cache/repos/github.com/blaylockbk/herbie/main/src/herbie/core.py#L1266-L1310】, which uses `cfgrib` to convert GRIB2 messages into `xarray.Dataset` objects.

## Subsetting Data for Efficiency

Downloading full GRIB2 files for 30+ ensemble members consumes significant bandwidth and storage. Herbie supports **byte-range subsetting** via HTTP `Range` headers, allowing you to download only specific variables.

```python
H = Herbie(
    "2023-04-01 12:00",
    model="gefs",
    product="atmos.5",
    fxx=6,
    member=0,
)

# Grab temperature and 10-m wind components in one download

search_regex = ":TMP:2 m|UGRD:10 m|VGRD:10 m:"
ds = H.xarray(search=search_regex)

print(ds)

```

The `search` parameter uses regular expressions to match GRIB2 message shortNames and level specifications. The `download` method in [`src/herbie/core.py`](https://github.com/blaylockbk/herbie/blob/main/src/herbie/core.py)【/cache/repos/github.com/blaylockbk/herbie/main/src/herbie/core.py#L334-L425】 handles the byte-range logic, while the `subset` helper identifies which byte ranges correspond to the requested variables.

## Accessing GEFS Re-forecasts

For historical GEFS re-forecasts (2000-2019), Herbie provides a separate template that constructs the unique path under `GEFSv12/reforecast/...`【/cache/repos/github.com/blaylockbk/herbie/main/src/herbie/models/gefs.py#L112-L165】.

```python
H = Herbie(
    "2005-01-01 00:00",
    model="gefs",
    product="GEFSv12/reforecast",
    fxx=24,
    member=2,              # perturbation member p02

)

# Subset variable directly

ds = H.xarray(search="TMP:2 m")
print(ds)

```

The re-forecast template supports members 0-4 and uses the same API as the operational GEFS template, ensuring consistent access across historical and current data.

## Summary

- **Template-based architecture**: Herbie uses [`src/herbie/models/gefs.py`](https://github.com/blaylockbk/herbie/blob/main/src/herbie/models/gefs.py) to handle GEFS-specific file path construction and member naming conventions (`c00` for control, `pNN` for perturbations).
- **Member translation**: Pass integer `member` values (0-30+) to the `Herbie` constructor; the template automatically converts them to GEFS filename conventions.
- **Efficient subsetting**: Use the `search` parameter with regular expressions to download only specific variables via byte-range requests, reducing bandwidth when working with multiple ensemble members.
- **Parallel processing**: Loop over ensemble members to create individual `Herbie` objects, then concatenate `xarray` datasets along a member dimension for analysis.
- **Historical data**: Access GEFS re-forecasts (2000-2019) using the same API with `product="GEFSv12/reforecast"` and members 0-4.

## Frequently Asked Questions

### How does Herbie handle GEFS ensemble member naming?

Herbie automatically translates integer member indices to GEFS filename conventions. When you specify `member=0`, the template in [`src/herbie/models/gefs.py`](https://github.com/blaylockbk/herbie/blob/main/src/herbie/models/gefs.py) converts this to `c00` (the control member). For any other integer (1-30+), it formats the member as `p01`, `p02`, etc. (perturbation members)【/cache/repos/github.com/blaylockbk/herbie/main/src/herbie/models/gefs.py#L51-L54】.

### Can I download specific variables instead of full GRIB2 files?

Yes. Herbie supports byte-range subsetting via the `search` parameter, which accepts regular expressions matching GRIB2 shortNames and level specifications. For example, `search=":TMP:2 m|UGRD:10 m:"` downloads only temperature at 2 meters and u-component wind at 10 meters. This occurs through HTTP Range headers implemented in [`src/herbie/core.py`](https://github.com/blaylockbk/herbie/blob/main/src/herbie/core.py)【/cache/repos/github.com/blaylockbk/herbie/main/src/herbie/core.py#L334-L425】, significantly reducing download times when processing multiple ensemble members.

### What is the difference between GEFS operational and re-forecast data in Herbie?

Operational GEFS data (recent forecasts) and re-forecast data (historical runs from 2000-2019) use the same `Herbie` API but different templates. For operational data, use `product="atmos.5"` or `product="atmos.25"` with members 0-30+. For re-forecasts, specify `product="GEFSv12/reforecast"` with members 0-4. The re-forecast template in [`src/herbie/models/gefs.py`](https://github.com/blaylockbk/herbie/blob/main/src/herbie/models/gefs.py) constructs the unique path under `GEFSv12/reforecast/...`【/cache/repos/github.com/blaylockbk/herbie/main/src/herbie/models/gefs.py#L112-L165】.

### How can I speed up downloads for multiple ensemble members?

Since each GEFS ensemble member resides in a separate GRIB2 file, you can parallelize downloads using Python's `concurrent.futures.ThreadPoolExecutor` to create multiple `Herbie` objects simultaneously. Additionally, always use the `search` parameter to subset variables by byte-range, downloading only the data you need rather than full files. Finally, allow Herbie to cache `.idx` inventory files locally to avoid repeated network HEAD requests when accessing the same forecast run multiple times.