About Custom Calculations

Introduction

A custom calculation uses a formula you write with weather forecast data. You choose variables such as temperature, rain, or wind, then describe how to combine or change their values. WindBorne runs the calculation at each location in the forecast grid and returns the result.

  1. Choose your grids The WM-6 max_temperature_2m_3h and min_temperature_2m_3h over the same three-hour window.
  2. Apply your calculation Subtract the minimum from the maximum at every grid cell.
  3. Get a new weather field One output grid showing the three-hour temperature range.

For example, subtracting the three-hour minimum temperature from the three-hour maximum gives the temperature range at each location. More detailed calculations can compare variables, average conditions over time, or combine pressure levels.

Available endpoints

Validate a calculation, calculate a grid, or generate threshold polygons.

The calculation and polygon endpoints currently support WeatherMesh 6 global and 3 km CONUS. They check that the required forecast data is available when you run the calculation.

1. Setup

For a gridded calculation, send the following request parameters:

For requests with multiple forecast hours, each hour is calculated separately. Hours that don’t have all the required input data are omitted from the result and reported in anchor_errors . Results for the remaining hours are still returned. If every requested hour fails, the request returns an error.

In the example below, the calculation finds the maximum temperature over the next 72 hours at each grid cell. The input covers hours 0–360, so output grids can be calculated for hours 0–288. Later hours are skipped because their 72-hour window extends beyond the available input.

Full forecast input and custom calculation output from hour 0 to hour 360 All 121 input steps are available. Blue output covers hours 0–288, giving 97 output grids. The output at hour 12 uses 25 input samples from hours 12–84. Forecast inputs 121 forecast steps Custom calculation output 97 output grids 0h72h144h216h288h360h

Hour 12 · Inputs 12–84h (25 samples) → 1 grid

The output uses the same grid as the input data. When you set lat_range and lon_range on a supported grid, only data for that area is loaded and calculated. The output may include extra cells around the edges.

2. Variables

Forecast variables are lowercase snake_case references enclosed in square brackets. A reference without selectors, such as [temperature_2m] , uses the ensemble mean. Selectors inside the brackets choose a distribution, level, or member; for example, [temperature_2m(members=42)] selects ensemble member 42. Forecast inputs retain their native units.

See Variables for the variables and pressure levels available for a model. Its distribution_details field shows whether each variable supports deterministic, percentile, threshold-probability, or ensemble-member selections. Custom Calculations use the forecast variable values in their documented native units and do not convert them automatically.

2.1 Accumulated variable timing

Variables like [snowfall_3h] and [total_precipitation_3h] represent totals over the three hours ending at their valid time rather than values at a single instant. A value valid at 06:00 therefore covers 03:00–06:00. The calculation language uses the API's valid time directly and does not shift these variables.

3. Arithmetic operators and precedence

Calculations support these basic math operations:

  • Add values with +
  • Subtract values with -
  • Multiply values with *
  • Divide values with /
  • Keep a value’s sign with +value , or reverse it with -value
  • Group calculations with parentheses: (expression)

Calculations follow Python’s usual order: parentheses and function calls first, then positive or negative signs, multiplication and division, and finally addition and subtraction. Operations with the same priority run from left to right.

Here, multiplication happens before addition:

Use parentheses to change the order. Here, addition happens first:

You can combine arithmetic with functions:

To calculate a reciprocal, divide 1 by the value:

Floor division ( // ), modulo ( % ), bitwise operators, and shortcuts such as += are not supported. Use = for assignments, explained in section 4. Calculations do not support loops, imports, or other Python statements.

4. Calculation structure and evaluation

The last expression in a calculation describes the expected result at each grid cell, forecast hour, and selected pressure level.

A calculation must include at least one forecast variable, which defines the grid to calculate on. Expressions containing only numbers, such as 2 or tan(radians(45)) , pass syntax validation but cannot be calculated.

Numbers in a calculation apply to every input value. For example, the following expression subtracts 2 from the temperature at every grid cell and forecast hour:

When an expression contains multiple forecast variables, they are matched by location and valid time before the calculation is performed:

A calculation may contain zero or more assignments followed by a final expression. Each assignment binds a lowercase snake_case name to an expression so it can be reused later in the calculation. Assigned names are bare identifiers; square brackets identify forecast references.

Every assignment ends with a semicolon. Line breaks are formatting whitespace and do not separate statements.

Assignments are evaluated from left to right. You can assign a name more than once. A reassignment uses the name’s previous value to calculate its new value. Later references use the new value, while earlier assignments keep the expression they originally captured. You cannot use a name before it has been assigned, including in its own first assignment.

This constant-only example illustrates assignment syntax; execution still requires a forecast reference:

4.1 Multi-level expressions

An upper-air variable without a level= selector returns one grid for each available pressure level. Select one level, such as level=850 , to get a single grid. Use a list like level=[850, 700, 500] to get a separate grid for each of those levels.

The examples below show how different level selections affect the result:

5. Core functions

Core functions take numbers, forecast variables, or calculations as inputs. They calculate a result separately at each grid cell.

To combine values across pressure levels, time, or ensemble members, use aggregate_level(...) , aggregate_time(...) , or aggregate_members(...) , explained in section 9. Each uses min , max , sum , or mean to choose how the values are combined.

Core functions do not combine values from different locations.

5.1 Comparing and combining values

5.2 Scores and limits

5.3 Math functions

5.4 Angles and trigonometry

5.5 Rounding

You can use functions inside other functions and combine them with math operators. This example combines warm temperatures and calm winds into a mosquito-suitability score:

Use the function names and inputs listed above. Version 1 does not support custom functions.

6. Conditional expressions

Use if / else to choose between two results. If the condition is true, the calculation uses the first result. Otherwise, it uses the result after else . Every if needs an else .

This example converts temperature to Celsius, then replaces temperatures below zero with 0 :

You can compare values using < , <= , > , >= , == , and != . You cannot combine conditions with and or or .

6.1 Checking for finite values

Use is_finite(value) to check whether a value is a regular number. It returns false for missing or undefined values ( NaN ) and positive or negative infinity. It checks each grid cell without changing its value.

This example keeps regular temperature values and replaces all others with 0 :

7. Selecting another forecast

The request parameter forecast_hours chooses which output hours to calculate. The selectors in this section choose which forecast data a variable reads while each output hour is calculated.

By default, a variable uses data for the forecast hour being calculated. Time selectors let you choose another hour or a list of hours from the same forecast run. Selecting one hour gives one grid that you can use directly in a calculation. Selecting several hours keeps their grids separate; you can combine them, pick one, or calculate with another input that uses the same hours in the same order.

Use offset_hours to select hours relative to the hour being calculated. For example, offset_hours=24 selects 24 hours later, and offset_hours=-6 selects 6 hours earlier. A list such as offset_hours=[-6, 0, 6] selects all three times.

Use forecast_hour to select hours counted from forecast_zero . The valid time is forecast_zero + forecast_hour ; forecast_zero can differ from initialization_time . See Run Information for a run's forecast_zero and available hours. For example, forecast_hour=24 always selects hour 24. It also accepts a list of hours. You cannot use offset_hours and forecast_hour together in the same variable reference.

Selecting one hour gives one grid, so you can use it directly in a calculation. This example calculates the temperature change over the next 24 hours:

You can also combine time and distribution selectors in a function. This example picks the higher of the 90th-percentile temperature 24 hours later and the mean temperature at the current hour:

Selecting a list keeps each hour’s grid separate:

For a calculation at hour 12, this selects temperature at hours 6, 12, and 18, returning three grids in that order. The next section explains how to work with these layers.

8. Working with multi-grid results

A calculation can return multiple grids. For example, it may return one grid for each selected pressure level or forecast hour. The following functions let you arrange grids in a specific order, select a grid by its pressure level or time, or aggregate multiple grids into one result. Each function processes every grid cell separately.

8.1 Stack results

Use stack(first, ...) to combine results into an ordered stack of separate grids.

This creates two grids: temperature at 850 hPa, followed by dewpoint at 700 hPa. Each grid keeps its own values.

8.2 Select a pressure layer

Use pressure_layer(value, index) to select one pressure layer from a result. Indices start at 0 and follow the order of the selected levels.

This calculates temperature minus dewpoint at two pressure levels and three times. Index 1 selects the result at 500 hPa, keeping all three times.

8.3 Select a time layer

Use time_layer(value, index) to select one time layer from a result. Indices start at 0 and follow the order of the selected times.

This calculates the temperature change from the current hour at two pressure levels for offsets 0, 6, and 12 hours. Index 1 selects the change after 6 hours, keeping both pressure levels.

8.4 Reduce layers

Use reduce(value, operation) to combine values across all times and vertical levels into one grid. The calculation happens separately at each grid cell.

This example finds the highest temperature at each grid cell across two vertical levels and two times: 850 and 500 hPa, at the hour being calculated and 6 hours later.

Choose min , max , sum , or mean as the operation. For example, reduce(value, mean) averages values across all times and vertical levels at each grid cell. Write the operation name without parentheses; mean(a, b) is a separate function that averages its inputs.

To combine only vertical levels while keeping times separate, use aggregate_level(...) in section 9.1. To combine values across time, use aggregate_time(...) in section 9.2. To combine ensemble members while keeping times separate, use aggregate_members(...) in section 9.3.

9. Aggregate across levels, times, or members

Aggregation takes multiple values at each grid cell and produces one result. It can work across any one of three dimensions: pressure levels, times, or ensemble members.

Each aggregation uses a value and an operation . Choose min , max , sum , or mean to control how the values are combined.

9.1 Pressure levels

Use aggregate_level(value, operation) to combine values across pressure levels at each grid cell. It returns one grid for each selected time.

You can combine all levels in the input or specify a pressure range using aggregate_level(value, operation, level_start, level_end) .

Both ends of the range are included. Write the pressure bounds as numbers, rather than variables or calculations.

The range must stay within the available pressure levels and include at least one level. Invalid ranges reject the request. If a level inside the range is missing, it is left out. The range is not shortened automatically.

9.2 Time

Use aggregate_time(value, operation, hours_before, hours_after) to combine values across a time window at each grid cell. Both ends of the window are included.

If the input already selects a list of times, use aggregate_time(value, operation) to combine those times.

Use 0 to start or end the window at the hour being calculated. Write both bounds as whole numbers of zero or more. Fractions, variables, calculations, and decimal forms such as 6.0 are not supported.

The calculation includes every available input sample within the window. A variable’s own time coverage stays the same: each value of [total_precipitation_3h] still represents a three-hour total.

9.3 Members

Use aggregate_members(value, operation) to combine values across all ensemble members at each grid cell. It returns one grid for each selected time.

The input must use the members selector so the calculation contains all available ensemble members.

Member aggregation uses every ensemble member available for the selected model and initialization time. To use one member without aggregating, select it directly, such as [temperature_2m(members=42)] .

10. Errors

Invalid calculations or level selections reject the request. For requests with multiple forecast hours, hours without all the required input data are skipped. Results are returned for the remaining hours.

Errors identify the affected expression and show the available pressure levels or forecast hours when relevant.