# Model

The Model class provides access to weather forecast data from Jua's weather prediction models. It allows you to retrieve future weather predictions with flexible spatial and temporal selection options.

Historical weather data (known as hindcasts) are also available directly directly through the `Model` class. Hindcasts are past model runs that allow you to analyze historical weather patterns, evaluate model performance, or test your pipelines. All model runs that are older that **90 days** (i.e. an having an `init_time` that is more than 90 days in the past) are classified as **hindcasts**.

Information about model/query pricing is available in the [developer portal](https://developer.jua.ai).

### Overview

The Model class serves as your interface to Jua's weather forecasting capabilities. It provides methods to:

* Retrieve forecast data for global coverage or specific locations
* Access forecasts for specific initialization times or the latest available forecast
* Query metadata about available forecasts
* Check forecast availability and readiness

### List Available Models

{% tabs %}
{% tab title="Code" %}

```python
from jua.weather import Models

print("Available models:")
for model in Models:
    print(f"  - {model}")
```

{% endtab %}

{% tab title="Output" %}

```
Available models:
  - Models.EPT1_5
  - Models.EPT1_5_EARLY
  - Models.EPT2
  - Models.EPT2_E
  - Models.EPT2_EARLY
  - Models.EPT2_HRRR
  - Models.EPT2_RR
  - Models.EPT2_REASONING
  - Models.AIFS
  - Models.AURORA
  - Models.ECMWF_IFS_SINGLE
  - Models.ICON_EU
  - Models.ICON_GLOBAL
  - Models.NOAA_GFS_SINGLE
  - Models.ECMWF_AIFS_ENSEMBLE
  - Models.ECMWF_AIFS_SINGLE
  - Models.ECMWF_IFS_ENSEMBLE
  - Models.GFS_GLOBAL_ENSEMBLE
  - Models.GFS_GLOBAL_SINGLE
  - Models.GFS_GRAPHCAST
  - Models.ICON_D2
  - Models.KNMI_HARMONIE_AROME_EUROPE
  - Models.KNMI_HARMONIE_AROME_NETHERLANDS
  - Models.METEOFRANCE_AROME_FRANCE_HD
  - Models.UKMO_GLOBAL_DETERMINISTIC_10KM
  - Models.UKMO_UK_DETERMINISTIC_2KM

```

{% endtab %}
{% endtabs %}

### Request model metadata

{% tabs %}
{% tab title="Code" %}

```python
import json

from jua import JuaClient
from jua.weather import Models

client = JuaClient()
model = client.weather.get_model(Models.EPT1_5)
metadata = model.get_metadata()
print(json.dumps(metadata.model_dump(), indent=4, default=str))
```

{% endtab %}

{% tab title="Output" %}

```
{
    "model": "ept1_5",
    "variables": [
        "air_temperature_at_height_level_2m",
        "wind_speed_at_height_level_10m",
        "wind_direction_at_height_level_10m",
        "wind_speed_at_height_level_100m",
        "wind_direction_at_height_level_100m",
        "air_pressure_at_mean_sea_level",
        "geopotential_at_pressure_level_50000Pa",
        "surface_downwelling_shortwave_flux_sum_1h"
    ],
    "grid": {
        "num_latitudes": 2221,
        "num_longitudes": 4440
    }
}
```

{% endtab %}
{% endtabs %}

### Getting the Forecasts Available for a Model

{% tabs %}
{% tab title="Code" %}

```python
from jua import JuaClient
from jua.weather import Models

client = JuaClient()
model = client.weather.get_model(Models.EPT2)

# The available forecasts will be returned in descending order,
#  from most recent to oldest; this returns the 10 most recent forecasts
available_forecasts = model.get_available_forecasts(limit=10)
for forecast in available_forecasts:
    print(f" - {forecast.init_time}")

```

{% endtab %}

{% tab title="Output" %}

```
Available init times for ept2
 - 2025-10-30 06:00:00
 - 2025-10-30 00:00:00
 - 2025-10-29 18:00:00
 - 2025-10-29 12:00:00
 - 2025-10-29 06:00:00
 - 2025-10-29 00:00:00
 - 2025-10-28 18:00:00
 - 2025-10-28 12:00:00
 - 2025-10-28 06:00:00
 - 2025-10-28 00:00:00
```

{% endtab %}
{% endtabs %}

The `get_available_forecasts` forecast response is paginated. So to obtain all available forecasts for a model, you need to iterate through the responses.

{% tabs %}
{% tab title="Code" %}

```python
from jua import JuaClient
from jua.weather import Models

client = JuaClient()
model = client.weather.get_model(Models.EPT2)

# Paginate through the response to get all available init_times
result = model.get_available_forecasts(limit=1000)
available_forecasts = list(result.forecasts)
while result.has_more:
    result = result.next()
    available_forecasts.extend(result.forecasts)

print(f"Available init times for {model}: {len(available_forecasts)}")

```

{% endtab %}

{% tab title="Output" %}

```
Available init times for ept2: 4134
```

{% endtab %}
{% endtabs %}

You can also specify a range of dates for which you want to get available `init_times`.

{% tabs %}
{% tab title="Code" %}

```python
from datetime import datetime

from jua import JuaClient
from jua.weather import Models

client = JuaClient()
model = client.weather.get_model(Models.EPT2)

# get the available hindcasts from EPT-2 for January 2025
available_forecasts = model.get_available_forecasts(
    since=datetime(2025, 1, 1),
    before=datetime(2025, 2, 1),
    limit=200,
)
for forecast in available_forecasts:
    print(f" - {forecast.init_time}")
```

{% endtab %}

{% tab title="Output" %}

<pre><code><strong> - 2025-02-01 00:00:00
</strong> - 2025-01-31 18:00:00
 - 2025-01-31 12:00:00
 - 2025-01-31 06:00:00
 - 2025-01-31 00:00:00
 - 2025-01-30 18:00:00
 - 2025-01-30 12:00:00
 - 2025-01-30 06:00:00
 - 2025-01-30 00:00:00
 - 2025-01-29 18:00:00
 - 2025-01-29 12:00:00
 - 2025-01-29 06:00:00
 - 2025-01-29 00:00:00
 - 2025-01-28 18:00:00
 - 2025-01-28 12:00:00
 - 2025-01-28 06:00:00
 - 2025-01-28 00:00:00
 - 2025-01-27 18:00:00
 - 2025-01-27 12:00:00
 - 2025-01-27 06:00:00
 - 2025-01-27 00:00:00
 - 2025-01-26 18:00:00
 - 2025-01-26 12:00:00
 - 2025-01-26 06:00:00
 - 2025-01-26 00:00:00
 - 2025-01-25 18:00:00
 - 2025-01-25 12:00:00
 - 2025-01-25 06:00:00
 - 2025-01-25 00:00:00
 - 2025-01-24 18:00:00
 - 2025-01-24 12:00:00
 - 2025-01-24 06:00:00
 - 2025-01-24 00:00:00
 - 2025-01-23 18:00:00
 - 2025-01-23 12:00:00
 - 2025-01-23 06:00:00
 - 2025-01-23 00:00:00
 - 2025-01-22 18:00:00
 - 2025-01-22 12:00:00
 - 2025-01-22 06:00:00
 - 2025-01-22 00:00:00
 - 2025-01-21 18:00:00
 - 2025-01-21 12:00:00
 - 2025-01-21 06:00:00
 - 2025-01-21 00:00:00
 - 2025-01-20 18:00:00
 - 2025-01-20 12:00:00
 - 2025-01-20 06:00:00
 - 2025-01-20 00:00:00
 - 2025-01-19 18:00:00
 - 2025-01-19 12:00:00
 - 2025-01-19 06:00:00
 - 2025-01-19 00:00:00
 - 2025-01-18 18:00:00
 - 2025-01-18 12:00:00
 - 2025-01-18 06:00:00
 - 2025-01-18 00:00:00
 - 2025-01-17 18:00:00
 - 2025-01-17 12:00:00
 - 2025-01-17 06:00:00
 - 2025-01-17 00:00:00
 - 2025-01-16 18:00:00
 - 2025-01-16 12:00:00
 - 2025-01-16 06:00:00
 - 2025-01-16 00:00:00
 - 2025-01-15 18:00:00
 - 2025-01-15 12:00:00
 - 2025-01-15 06:00:00
 - 2025-01-15 00:00:00
 - 2025-01-14 18:00:00
 - 2025-01-14 12:00:00
 - 2025-01-14 06:00:00
 - 2025-01-14 00:00:00
 - 2025-01-13 18:00:00
 - 2025-01-13 12:00:00
 - 2025-01-13 06:00:00
 - 2025-01-13 00:00:00
 - 2025-01-12 18:00:00
 - 2025-01-12 12:00:00
 - 2025-01-12 06:00:00
 - 2025-01-12 00:00:00
 - 2025-01-11 18:00:00
 - 2025-01-11 12:00:00
 - 2025-01-11 06:00:00
 - 2025-01-11 00:00:00
 - 2025-01-10 18:00:00
 - 2025-01-10 12:00:00
 - 2025-01-10 06:00:00
 - 2025-01-10 00:00:00
 - 2025-01-09 18:00:00
 - 2025-01-09 12:00:00
 - 2025-01-09 06:00:00
 - 2025-01-09 00:00:00
 - 2025-01-08 18:00:00
 - 2025-01-08 12:00:00
 - 2025-01-08 06:00:00
 - 2025-01-08 00:00:00
 - 2025-01-07 18:00:00
 - 2025-01-07 12:00:00
 - 2025-01-07 06:00:00
 - 2025-01-07 00:00:00
 - 2025-01-06 18:00:00
 - 2025-01-06 12:00:00
 - 2025-01-06 06:00:00
 - 2025-01-06 00:00:00
 - 2025-01-05 18:00:00
 - 2025-01-05 12:00:00
 - 2025-01-05 06:00:00
 - 2025-01-05 00:00:00
 - 2025-01-04 18:00:00
 - 2025-01-04 12:00:00
 - 2025-01-04 06:00:00
 - 2025-01-04 00:00:00
 - 2025-01-03 18:00:00
 - 2025-01-03 12:00:00
 - 2025-01-03 06:00:00
 - 2025-01-03 00:00:00
 - 2025-01-02 18:00:00
 - 2025-01-02 12:00:00
 - 2025-01-02 06:00:00
 - 2025-01-02 00:00:00
 - 2025-01-01 18:00:00
 - 2025-01-01 12:00:00
 - 2025-01-01 06:00:00
 - 2025-01-01 00:00:00
</code></pre>

{% endtab %}
{% endtabs %}

### Check if the forecasted data is available

{% tabs %}
{% tab title="Code" %}

```python
from jua import JuaClient
from jua.weather import Models

client = JuaClient()
model = client.weather.get_model(Models.EPT1_5)

# init_time might be any valid datetime object or datetime string
if model.is_ready(forecasted_hours=480, init_time="latest"):
    print(f"{model.name} has at least 480 hours of forecast data available")
else:
    print(f"{model.name} does not yet have 480 hours of forecast data available")

```

{% endtab %}

{% tab title="Output" %}

```
ept1_5 has at least 480 hours of forecast data available
```

{% endtab %}
{% endtabs %}

### Requesting the forecast data

{% tabs %}
{% tab title="Point-Based" %}

```python
from jua import JuaClient
from jua.types.geo import LatLon
from jua.weather import Models, Variables

# Setup JuaClient
client = JuaClient()

# Choose the model
model = client.weather.get_model(Models.EPT1_5)

# Defining the sites that we are interested in
sites = [
    # label is optional
    LatLon(55.06, 13.00, label="Kriegers Flak"),
    LatLon(54.04, 5.96, label="Gemini Wind Farm"),
    LatLon(51.71, 2.91, label="Borssele III & IV"),
    LatLon(53.89, 1.79, label="Hornsea Two"),
]

# Define the variables we are interested in
# If set to `None` all available variables will be loaded
variables = [
    Variables.WIND_SPEED_AT_HEIGHT_LEVEL_100M,
]

site_forecasts = model.get_forecasts(
    init_time="latest", # or any valid datetime / datetime string
    points=sites,
    # The below parameters are optional
    variables=variables,
    min_lead_time=0, # hours
    max_lead_time=72, # hours
    method="bilinear",
)

# Convert the response to an xarray dataset
print(site_forecasts.to_xarray()) 
```

```
<xarray.Dataset> Size: 2kB
Dimensions:                          (points: 4, init_time: 1,
                                      prediction_timedelta: 73)
Coordinates:
  * points                           (points) object 32B 'borssele_iii_&_iv' ...
  * init_time                        (init_time) datetime64[ns] 8B 2025-10-30...
  * prediction_timedelta             (prediction_timedelta) timedelta64[ns] 584B ...
    latitude                         (points) float32 16B 51.71 54.04 ... 55.06
    longitude                        (points) float32 16B 2.91 5.96 1.79 13.0
    requested_lat                    (points) float64 32B 51.71 54.04 ... 55.06
    requested_lon                    (points) float64 32B 2.91 5.96 1.79 13.0
Data variables:
    wind_speed_at_height_level_100m  (points, init_time, prediction_timedelta) float32 1kB ...
```

> ⚠️ When querying data with `method="nearest"` the returned coordinates will be slightly different to the requested ones, as it will return the coordinates of the nearest grid points for the model.
> {% endtab %}

{% tab title="Region-Based" %}

> ⚠️ Region-based requests can be expensive. For more information, see our [pricing](https://developer.jua.ai) docs.
>
> ⚠️ Requests might be large and take a long time to load.

```python
from datetime import datetime

from jua import JuaClient
from jua.weather import Models, Variables

client = JuaClient()
model = client.weather.get_model(Models.EPT2)
 
# Define the data we want to load
# In all cases scalars, lists and slices are supported
# If set to `None` the whole dimension will be loaded
europe_lat_slice = slice(36, 71) 
europe_lon_slice = slice(-15, 50)
forecast_window = [0, 12, 24]  # Hours
variables = [
    Variables.AIR_TEMPERATURE_AT_HEIGHT_LEVEL_2M,
    Variables.WIND_SPEED_AT_HEIGHT_LEVEL_100M,
]

forecast = model.get_forecasts(
    init_time=datetime(2025, month=7, day=1, hour=0),
    variables=variables,
    latitude=europe_lat_slice,
    longitude=europe_lon_slice,
    prediction_timedelta=forecast_window,
)

print(forecast.to_xarray())

```

```
Reading data... | 35.8 MB | 30.2 MB/s
<xarray.Dataset> Size: 8MB
Dimensions:                             (init_time: 1, prediction_timedelta: 3,
                                         latitude: 421, longitude: 781)
Coordinates:
  * init_time                           (init_time) datetime64[ns] 8B 2025-07-01
  * prediction_timedelta                (prediction_timedelta) timedelta64[ns] 24B ...
  * latitude                            (latitude) float32 2kB 36.0 ... 71.0
  * longitude                           (longitude) float32 3kB -15.0 ... 50.0
Data variables:
    air_temperature_at_height_level_2m  (init_time, prediction_timedelta, latitude, longitude) float32 4MB ...
    wind_speed_at_height_level_100m     (init_time, prediction_timedelta, latitude, longitude) float32 4MB ...
```

{% endtab %}
{% endtabs %}

### Requesting Hindcasts for Models

Hindcasts can be obtained directly through the same `get_forecasts` method.

{% tabs %}
{% tab title="Point-Based" %}

```python
from datetime import datetime
from jua import JuaClient
from jua.types.geo import LatLon
from jua.weather import Models, Variables

# Setup JuaClient
client = JuaClient()

# Choose the model
model = client.weather.get_model(Models.EPT2)

# Defining the sites that we are interested in
sites = [
    # label is optional
    LatLon(55.06, 13.00, label="Kriegers Flak"),
    LatLon(54.04, 5.96, label="Gemini Wind Farm"),
    LatLon(51.71, 2.91, label="Borssele III & IV"),
    LatLon(53.89, 1.79, label="Hornsea Two"),
]

# Define the variables we are interested in
# If set to `None` all available variables will be loaded
variables = [
    Variables.WIND_SPEED_AT_HEIGHT_LEVEL_10M,
]

site_forecasts = model.get_forecasts(
    init_time=slice(
        datetime(2025, month=1, day=1),
        datetime(2025, month=3, day=31, hour=23, minute=59),
    ),
    points=sites,
    # The below parameters are optional
    variables=variables,
    min_lead_time=0, # hours
    max_lead_time=72, # hours
    method="bilinear",
)

# Convert the response to an xarray dataset
print(site_forecasts.to_xarray()) 
```

```
<xarray.Dataset> Size: 424kB
Dimensions:                         (points: 4, init_time: 360,
                                     prediction_timedelta: 73)
Coordinates:
  * points                          (points) object 32B 'borssele_iii_&_iv' ....
  * init_time                       (init_time) datetime64[ns] 3kB 2025-01-01...
  * prediction_timedelta            (prediction_timedelta) timedelta64[ns] 584B ...
    latitude                        (points) float32 16B 51.71 54.04 53.89 55.06
    longitude                       (points) float32 16B 2.91 5.96 1.79 13.0
    requested_lat                   (points) float64 32B 51.71 54.04 53.89 55.06
    requested_lon                   (points) float64 32B 2.91 5.96 1.79 13.0
Data variables:
    wind_speed_at_height_level_10m  (points, init_time, prediction_timedelta) float32 420kB ...
```

> ⚠️ When querying data with `method="nearest"` the returned coordinates will be slightly different to the requested ones, as it will return the coordinates of the nearest grid points for the model.
> {% endtab %}

{% tab title="Region-Based" %}

> ⚠️ Region-based requests can be expensive. For more information, see our [pricing](https://developer.jua.ai) docs. In this example, the `request_credit_limit` needs to be increased for the `JuaClient` or the request will fail.
>
> ⚠️ Requests might be large and take a long time to load.
>
> ⚠️ When pulling large grids, it's better to make smaller requests and combine the data locally (also so that your local memory does not run out)

```python
europe_lat_slice = slice(36, 71) 
europe_lon_slice = slice(-15, 50)
variables = [
    Variables.AIR_TEMPERATURE_AT_HEIGHT_LEVEL_2M,
    Variables.WIND_SPEED_AT_HEIGHT_LEVEL_100M,
]

forecast = model.get_forecasts(
    init_time=slice(
        datetime(2025, month=1, day=1, hour=0),
        datetime(2025, month=1, day=1, hour=18),
    ),
    variables=variables,
    latitude=europe_lat_slice,
    longitude=europe_lon_slice,
    max_lead_time=2 * 24,
)

```

```
<xarray.Dataset> Size: 516MB
Dimensions:                             (init_time: 4,
                                         prediction_timedelta: 49,
                                         latitude: 421, longitude: 781)
Coordinates:
  * init_time                           (init_time) datetime64[ns] 32B 2025-0...
  * prediction_timedelta                (prediction_timedelta) timedelta64[ns] 392B ...
  * latitude                            (latitude) float32 2kB 36.0 ... 71.0
  * longitude                           (longitude) float32 3kB -15.0 ... 50.0
Data variables:
    air_temperature_at_height_level_2m  (init_time, prediction_timedelta, latitude, longitude) float32 258MB ...
    wind_speed_at_height_level_100m     (init_time, prediction_timedelta, latitude, longitude) float32 258MB ...
```

{% endtab %}
{% endtabs %}
