ÅREWEATHERmethod & sources

Every number, and where it comes from

This page exists because a mountain forecast that you cannot check is just a confident-looking guess. Below is every data source with its licence, the terms this site operates under, and each formula it applies — including the ones that are approximations, labelled as such.

No tracking No cookies No trackers or third-party embeds Non-commercial

1 · Sources and licences

Every forecast value on this site originates from a national weather service and is fetched through Open-Meteo, which aggregates their open data. Nothing is scraped. A scheduled job fetches it a few times a day and publishes the processed result here, so your browser never talks to Open-Meteo itself.

Aggregator, ensemble and reanalysis

Required attribution

All of the above is served under CC BY 4.0 (except NOAA's, which is public domain). That licence requires three things: credit the source, link the licence, and state that changes were made. This site does all three, here and in the footer of every page:

Changes were made — substantially. Nothing you see here is a raw model value. Forecasts are combined across six models with learned weights, interpolated to elevations the models never output, bias-corrected against reanalysis, and converted into derived quantities (wet bulb, snow line, wind chill, drift index, activity scores). Errors in the result are mine, not the weather services'.

Typefaces

2 · Terms this site operates under

Open-Meteo free tier

  • Non-commercial use only. No subscriptions, no advertising, nothing sold. If this site ever carried ads or a paywall it would need a paid Open-Meteo plan.
  • SMHI asks the same of its open data: use the documented APIs, do not mass-download per location, and do not fetch the same data twice. The station readings are therefore requested once for the whole country per parameter and reused for every mountain and both pages, rather than once per peak.
  • Under 10 000 API calls per day. This used to be every visitor’s own problem, because the requests came from each browser. Now a single scheduled job makes them: about 25 a day for the forecast, two more for the daily retraining, and a handful a month for the climatology and the projections. The number no longer grows with the number of visitors.
  • No API key, and therefore no key of mine embedded in the page for anyone to lift.
  • Attribution required, as above.

The schedule is deliberately frugal. The forecast is rebuilt every three hours — about as often as the high-resolution models update, so more often would just fetch the same numbers twice. The bias model is retrained once a day, the 30-year climatology once a month and the climate projections once a quarter. Your browser asks this site for the result and checks on each visit whether it has changed; an unchanged file costs nothing.

Exactly which requests are made

So you can audit it rather than take my word:

Privacy

  • No analytics, no cookies, no fingerprinting, no accounts, no logs — I have no server to log anything with.
  • Exactly one external host is contacted from your browser: opendata-download-metobs.smhi.se, for the live station observations. The forecast itself is served from this site. No analytics, no embeds, no third-party fonts or scripts of any kind — typefaces are self-hosted precisely so that loading this page does not hand your IP address to a font CDN.
  • Everything remembered is in your own browser: your unit and language choice, the latest SMHI readings and the verification log in localStorage, and a copy of the site and the last forecast in the service worker’s cache so the page still opens offline. Clearing site data erases all of it. Nothing is ever sent anywhere.
  • Open-Meteo receives the summit’s coordinates from the scheduled job — a fixed position from a public list. It never sees you, your IP address or your location. SMHI receives no coordinates at all: the station request is for the whole country and the nearest ones are picked in your browser. This app never asks for or uses geolocation.

3 · The pipeline

Six raw model forecasts go in; one elevation-resolved forecast comes out. This runs every three hours in a scheduled GitHub Actions job (pipeline/ in the repository), not in your browser. In order:

  1. Fetch — surface fields from six models at summit height, pressure-level fields from two, and an ensemble for spread.
  2. Weight — combine the six into one estimate using weights learned from measured error at this exact point.
  3. Correct — apply the learned temperature and wind bias correction at the anchor height, if it passed hold-out validation.
  4. Build the sounding — assemble a vertical profile from pressure-level data.
  5. Downscale — interpolate to every m band between valley and summit, anchored to the corrected surface estimate.
  6. Derive — wet bulb, phase, snow line, cloud base, wind chill, drift index.
  7. Score — turn all of it into two verdicts with named limiting factors.

4 · Combining models

Weighted mean

Scalars are combined with a straight weighted mean over whichever models returned a value for that hour:

x̄ = Σ(wᵢ · xᵢ) / Σwᵢ
xᵢ
model i's value for this hour
wᵢ
that model's skill weight (below); models with no value drop out of both sums

Wind is a vector, not a number

Averaging wind directions is a classic way to produce nonsense — the mean of 350° and 10° is 180°, exactly backwards. Wind is decomposed into components first:

u = −v·sin(θ) v = −V·cos(θ) speed = √(ū² + v̄²) direction = atan2(−ū, −v̄)
V, θ
wind speed and the direction it blows from, in degrees
u, v
eastward and northward components, which average correctly

Skill weights

Each model's weight is a softmax over its measured mean absolute error, gently tilted by a prior that reflects native grid resolution:

wᵢ ∝ pᵢ · exp( −(MAEᵢ − MAEbest) / τ ), τ = 0.7 °C
MAEᵢ
mean absolute temperature error of model i against ERA5-Land over the training window
pᵢ
prior, 0.90–1.35, higher for finer native grids
τ
temperature of the softmax: a model 0.7 °C worse than the best gets ~1/e of its weight
Weights are renormalised each hour over the models that actually returned data.

5 · The sounding, and why not a lapse rate

The usual shortcut for mountain temperature is to subtract a fixed 0.65 °C per 100 m. That is right on average and badly wrong exactly when it matters. On a clear, calm winter night in Jämtland, cold air drains into the valley and the profile inverts: Åre village sits at −18 °C while the summit of Åreskutan is at −6 °C. A fixed lapse rate does not just miss this — it gets the sign backwards, by twelve degrees.

So instead the app requests temperature, humidity, wind and geopotential height at pressure levels hPa from ICON and GFS, giving a genuine vertical profile above the mountain. Heights are averaged across whichever models answered; the profile is sorted by height and interpolated linearly:

f(z) = fₖ₋₁ + (fₖ − fₖ₋₁) · (z − zₖ₋₁) / (zₖ − zₖ₋₁)
z
target elevation in metres
k
the first sounding level above z
Outside the profile the gradient of the nearest layer is extended rather than clamped.

Anchoring

The sounding knows the shape of the atmosphere; the six-model surface ensemble knows the best value at summit height. Both are kept: the offset between them is applied in full at the anchor and decays with distance, so near the mountain you get the ensemble and far above it you get the free atmosphere.

T(z) = Tsnd(z) + [ Tanchor − Tsnd(za) ] · exp( −|z − za| / L )
Tsnd
temperature interpolated from the sounding
Tanchor
skill-weighted, bias-corrected surface ensemble at anchor height
za
anchor elevation — the summit height passed to the API
L
m decay scale
Relative humidity is anchored the same way and clamped to 1–100 %. If no sounding is available for an hour, the app falls back to a constant °C/100 m and says so on the profile card.

Wind with height

Near the ground the surface forecast wins — it knows about roughness and the boundary layer. Higher up, the free-atmosphere sounding takes over. Then terrain accelerates the flow towards an exposed summit, which is why a ridge feels twice as windy as the plateau below it.

w = exp( −|z − za| / Lw ) u(z) = (1−w)·usnd(z) + w·usfc (same for v) E(z) = 1 + (Emax − 1) · [ (z − zbase) / (zsummit − zbase) ]1.4 V(z) = E(z) · √(u² + v²) gust = V(z) · G
Lw
m blend scale
Emax
terrain exposure factor at the summit, 1.34 for Åreskutan (see the mountain table)
G
the surface model's own gust ratio, clamped to 1.15–2.30
Approximation. The exposure factor is hand-set per summit from terrain shape, not measured or fitted. It is the least rigorous number on this site.

Precipitation with height

P(z) = Psfc · clamp( 1 + k · (z − za)/1000 , 0.55 , 1.9 )
k
per kilometre of ascent — forced ascent wrings more water out of the same air
Approximation. A blunt linear stand-in for orographic enhancement, which really depends on wind direction relative to the slope and on airmass humidity.

6 · Thermodynamics

Dew point — Magnus-Tetens

γ = ln(RH/100) + 17.625·T / (243.04 + T) Td = 243.04·γ / (17.625 − γ)
T
air temperature, °C
RH
relative humidity, %

Wet-bulb temperature — Stull (2011)

This is the variable that actually decides whether precipitation reaches you as snow. Air at +2 °C and 40 % humidity has a wet bulb near −1 °C, and it snows — which is why a forecast that places the snow line by air temperature puts it hundreds of metres too low.

Tw = T·atan[0.151977·√(RH + 8.313659)] + atan(T + RH) − atan(RH − 1.676331) + 0.00391838·RH3/2·atan(0.023101·RH) − 4.686035
Stull, R. (2011). Wet-Bulb Temperature from Relative Humidity and Air Temperature. J. Appl. Meteor. Climatol. 50, 2267–2269. Valid roughly −20 to +50 °C and 5–99 % RH.

Precipitation phase and the snow line

snow if Tw ≤ °C rain if Tw ≥ °C mix otherwise (liquid and solid split 50/50) snow line = elevation where Tw crosses °C, linearly interpolated between bands

Snow ratio — millimetres of water to centimetres of snow

Ten to one is the folk rule and it is wrong at both ends: warm snow packs dense, and the driest cold smoke sits near −12 °C. A step function of air temperature:

depth (cm) = Psolid (mm) × ratio(T) / 10
Approximation. Real snow density also depends on wind, riming and crystal habit, none of which are modelled here.

Wind chill — Environment Canada / JAG-TI

Twc = 13.12 + 0.6215·T − 11.37·V0.16 + 0.3965·T·V0.16
V
wind speed in km/h at 10 m
Defined only for T ≤ 10 °C and V ≥ 4.8 km/h; outside that the air temperature is returned unchanged.

Humidex, and one "feels like" number

e = 6.11 · exp[ 5417.753 · (1/273.16 − 1/(273.15 + Td)) ] humidex = T + 0.5555·(e − 10) feels = Twc if T ≤ 10 °C feels = max(T, humidex) − clamp((Vm/s − 3)·0.25, 0, 4) if T > 10 °C
The warm-side wind term is my own addition: 12 m/s on a ridge is worth a couple of degrees even in July. It is not part of the standard humidex.

Cloud base — Espy's rule

cloud base ≈ zvalley + 125 · (T − Td)
Approximation. Strictly the lifting condensation level for a parcel from the valley floor. The summit is additionally reported as "in cloud" when its interpolated humidity exceeds 92 %.

Wind loading index

Not an avalanche forecast — only the meteorological half of the question: is there loose snow available, and is the wind strong enough to move it?

available = clamp( newSnowcm / 8 , 0 , 1 ) cold = 1 if T < −1 °C, else clamp((0.5 − T)/1.5, 0.15, 1) transport = clamp( (V − ) / 9 , 0 , 1 )0.8 index = 100 · available · cold · transport
newSnow
last 6 hours in full, plus a quarter of the last 24
V
summit wind, m/s — m/s is roughly where dry loose snow starts moving
Approximation, and a deliberately crude one. It ignores aspect, slope angle, terrain traps and the entire snowpack history — that is to say, most of what an avalanche forecast is about.

7 · The machine learning

All of it trains once a day in the scheduled pipeline, from public data, and is published with the forecast — weights, scores and all — so the learning log on the forecast page shows exactly what was learned and how well it held up.

Training data

Every archived forecast from every model since January 2023 — what each one predicted at the time — against ERA5-Land reanalysis for the same hours and the same point. The pipeline keeps this record and adds to it each day, so the training set grows rather than slides: tens of thousands of hours, where the browser could only ever afford about a thousand. It ends six days ago, because the reanalysis takes that long to catch up.

Standardisation

zⱼ = (xⱼ − μⱼ) / σⱼ, with σⱼ = 1 where the feature is constant

Ridge regression on the residual

The target is not temperature — it is what the weighted ensemble got wrong. Solved in closed form by Gaussian elimination with partial pivoting; the intercept is not penalised.

y = Ttruth − Tensemble β = (ZᵀZ + λnI)−1 Zᵀy, λ = 0.08 (temperature), 0.15 (wind) correction = clamp( βᵀz + ȳ , −6 , +6 ) °C
Z
standardised feature matrix, tens of thousands of rows × 9 columns
λ
ridge penalty — keeps the coefficients modest, so one odd month cannot swing them

Features

Nine, each with a physical reason to be there. This is the baseline candidate — the two below see a good deal more:

The contest: trees and a neural network

A straight line through nine features cannot say “the models are too warm on calm, clear nights” or “they miss the lee warming when the westerly is strong” — those are interactions, and the valley cold pool and the summit’s lee side are exactly what a mountain forecast gets wrong. So two heavier models compete with the ridge for each correction: gradient-boosted trees (LightGBM, trained on absolute error, stopped early on a validation block) and a neural network (a multilayer perceptron, two hidden layers of 64 and 32 units, also stopped early).

They see more than the ridge: each model’s own temperature as its departure from the ensemble, the wind direction, and what the forecast was doing in the 24 hours around the hour in question — warming, cooling, a front arriving. The features are built by one function for training and for the live forecast, so a model is never shown numbers in production that it did not see in training.

eligible ⟺ MAEcandidate < 0.995 · MAEuncorrected (on the hold-out block) winner = the simplest eligible candidate within 1 % of the lowest MAE order of simplicity: ridge → boosted trees → neural network

Every candidate trains on the same older 75 % of the history and is scored on the same newest 25 %. To be used at all it must beat the uncorrected forecast by 0.5 %. The lowest error wins — unless a simpler candidate is within 1 % of it, in which case the simpler one does: a more complicated model has to be clearly better, not marginally lucky. The winner is refitted on all the history before it is used, and the published scores are the ones from before that refit.

Precipitation probability — logistic regression

p = 1 / (1 + e−(βᵀz + b)), target: ERA5-Land precipitation ≥ 0.1 mm
features
√(ensemble precipitation), fraction of models that are wet, humidity, cloud cover
Fitted by batch gradient descent, 500 iterations, L2 penalty 0.01.

Validation, and the right to switch itself off

The last 25 % of the window is held out as a contiguous block — not a random split, which would leak information across neighbouring hours. Each learned component must beat the baseline it replaces on that block by at least 0.5 %, or it is disabled and the app tells you so on the learning-log card.

MAE = mean |forecast − truth| (temperature, wind) Brier = mean (p − outcome)² (precipitation) use the correction ⟺ MAEcorrected < 0.995 · MAEbaseline
The honest caveat about the target. ERA5-Land is a ~9 km reanalysis grid, not a summit weather station. It is a good reference for systematic model bias and a poor one for the last few hundred metres of local terrain effect. A correction trained this way makes the grid-scale forecast better; it cannot know that a particular gully funnels wind.
A second caveat: the archive is mostly short-range. Open-Meteo’s historical-forecast archive is stitched together from the first hours of each model run, so what the models learn from is largely their own 0–6 hour forecasts. The forecast you read runs to seven days, and a model’s bias on day five is not guaranteed to be its bias on day one. The correction is the best estimate available, not a proof.

Checking against thermometers

Everything above is model output corrected against another model's best estimate of the past. The ground-truth panel on the forecast page closes that loop with actual instruments: SMHI's automatic stations, read live.

Stations are ranked by distance with a penalty for being at a very different height, since a valley station 5 km away says less about a summit than a ridge station 12 km away:

cost = distancekm + |zstation − zsummit| /
Distance is the great-circle distance. Stations beyond km are ignored entirely.

The forecast is then interpolated down the sounding to that station's exact elevation and the hour it reported, and the two are put side by side. Every comparison is appended to a rolling log in your browser — deduplicated by station and hour, capped at entries — so that after a few days of use the app can show you its own measured bias at that peak, against a thermometer rather than a reanalysis grid.

What this comparison is not. A station is a different place, not merely a different altitude of the same one. The difference you see mixes genuine downscaling error with the unavoidable fact that the weather 15 km away is different weather. It is a sanity check, not a verification — and a reading is never fed into a forecast, because a valley thermometer cannot correct a summit prediction without inventing information.

The scorecard, and when a thermometer may train

The pipeline keeps a longer memory than your browser can. Once a day it writes down what the published forecast says at the best-ranked SMHI station’s height for each of the next 168 hours, both with the learned correction and without it, and as the hours pass it scores both against what the station measured. The learning log shows the result by lead day over the last days. It is the only number on the site that answers “how good is this forecast” with an instrument rather than another model.

A station replaces ERA5-Land as the training target only if it stands within km of the summit and within m of its height. Then the summit correction learns from a thermometer instead of a reanalysis grid — temperature and wind; precipitation stays with ERA5-Land. Any other station only keeps score. A thermometer in a valley knows a great deal about that valley’s cold pools and nothing about the summit ridge, and training the summit on it would be teaching the forecast the wrong mountain.

Worth looking up: northern lights and a sea of clouds

Northern lights. For every hour of every night: how likely activity at NOAA’s forecast Kp reaches Åre (a logistic curve, half-way at Kp ), times the share of ensemble members with less than % cloud, times darkness (sun below °, half credit down to °), with up to taken off weak nights under a full moon. The night’s figure is its best hour. NOAA forecasts Kp three days ahead and no further, so the later nights say so instead of guessing. NOAA SWPC data is in the public domain.

Sea of clouds. A daylight hour counts when the summit is dry (humidity under %), at least two bands between and m are saturated (over %), and mid and high cloud together stay under %. A day is marked when or more hours count. It is a heuristic on a 100 m grid, and a cloud sea can sit a hundred metres higher or lower than any model puts it.

Ensemble spread

p10, p50, p90 = linearly interpolated quantiles over 20–40 ensemble members band at elevation z = quantile + [ T(z) − T(summit) ]
The spread is computed at summit height and shifted to the displayed band, which assumes uncertainty is roughly constant through the depth of one mountain.

8 · The zones

The front page tells the week in five parts of Åreskutan rather than one number for the mountain. Each zone is read straight off one of the 100 m bands above — never interpolated a second time — and labelled with a landmark so a reader knows which bit of hill a number belongs to.

One day, one zone

A zone's day is the highest and lowest temperature of that calendar day at that band, the coldest feels-like, the strongest sustained wind and gust (with the direction of the windiest hour), and the total precipitation split into rain and snow by the wet-bulb phase. Cloud is the daylight mean; a zone counts as in cloud when, for more than half of the daylight hours, its humidity is above 92 % or the cloud base sits below it under more than 60 % cover.

The icon

Decided from the zone's own numbers, in this order: thunder risk (CAPE above 700 J/kg in any hour), then precipitation of 0.3 mm or more — snow when at least 70 % of it fell as snow, sleet from 30 %, otherwise rain — then in cloud, then cloud cover: clear under 25 %, partly cloudy under 70 %, cloudy above. The summit and the village can and do get different icons on the same day.

The headline

The sentence at the top picks, at the summit, the coldest day, the windiest day and the day with most new snow, and in the village the wettest day. The day to aim for is the one with the lowest of 2 × wind + 4 × precipitation + cloud ÷ 10, plus 15 if the summit is in cloud. That is a way of pointing at a day, not a score anyone should quote, and it is never shown as a number.

The panorama is a drawing, not a map. The silhouette is a simplified side view, and the fresh snow painted on it only ever shows snow forecast to fall that day — the models carry no reliable snow-cover map, so the drawing does not pretend to know what is already lying there.

9 · Constants and the mountain

Read live from the running configuration.

Physical tunables

The mountain

10 · Probabilities and the outlook

Everything behind the odds page.

What counts as what

Each row is a test applied to one member's own day at the chosen elevation.

Calibration

Exactly one figure on that page is calibrated.

Phase, without humidity

Ensemble members do not carry humidity.

10 · Climate projections

Everything behind the winter ahead page: which models, which scenario, and every threshold a number on that page is counted against.

The models

Seven CMIP6 HighResMIP models, daily, 1950–2050, statistically downscaled to 10 km and bias-corrected against ERA5 by Open-Meteo. Historical runs cover 1950–2014; from 2015 the projections follow SSP5-8.5, the only scenario these high-resolution experiments were run under.

Thresholds

Every one of these is a judgement call. They are listed here so the judgement can be argued with rather than inferred.

The snowpack model

The climate data carries snowfall but not snow depth, so season length and every figure involving a 30 cm cover come from a degree-day model written for this site. Precipitation phase is decided at each elevation from the wet-bulb temperature, exactly as in the forecast; what falls as snow is added to a water-equivalent store, and each day melt = 3.5 × max(0, Tmean) millimetres are taken back out. Depth is water equivalent at a settled density of 300 kg/m³.

This is the weakest link on that page. There is no wind redistribution, no rain percolating and refreezing, no aspect or shading, and no snowmaking. The output is an index that moves in the right direction by roughly the right amount, not a measurement of snow depth.

Why one point

These grid cells are 20–50 km before downscaling — wider than the distance from Åre to Storlien. The massif is read at one point, and elevation is applied afterwards with the same lapse rate the forecast uses. Height is the variable that actually matters here, and it is the one the models can support.

10 · What this is not

This is not an avalanche forecast. The wind-loading index and new-snow figures are meteorological indices. They know nothing about aspect, slope angle, terrain traps, or the buried weak layer that decides whether a slope releases. For avalanche danger in the Swedish fjäll use lavinprognoser.se; for official warnings, SMHI.
  • Not a weather station. Every number is a model output, downscaled. No observation from the mountain itself enters the calculation.
  • Not validated against summit observations. The reported skill is against reanalysis, which is the best free reference available but not ground truth.
  • Coordinates and elevations are approximate summit positions, hand-entered.
  • Terrain exposure factors are hand-set, not fitted to anything.
  • The forecast degrades with range. Beyond about three days the ensemble spread on the hourly chart is more informative than the line through it.

The source is public: every formula on this page is in js/physics.js, js/ml.js and js/forecast.js, and tools/selftest.mjs checks them against known cases offline.

11 · Contact

Wrong forecast, broken chart, a zone that sits at the wrong height, or an exposure factor you think is nonsense — all of it is welcome. There are two ways to reach me.

Bugs and suggestions — the better channel

The source is public, so an issue is easier to act on than an email: it keeps the discussion attached to the code and anyone else hitting the same thing can find it.

Open an issue on GitHub →

Email

The address is not written anywhere in this page's source — only a ciphertext is. The key is derived from the answer below, so answering is what produces the address. It costs you five seconds and costs an address-harvesting crawler more than it is willing to spend.

If you are reporting a forecast that was wrong

This is the useful kind of bug report, and the hardest to act on without detail. Include:

  • Which mountain, and the exact hour — the forecast changes every hour and I cannot reconstruct what you saw without it.
  • What the app said and what actually happened — "it said −4 °C and 8 m/s at the summit at 09:00, it was more like −12 °C and blowing hard".
  • Roughly when you loaded it, since a forecast made three days out is a different claim from one made that morning.
  • Whether the learning log said the correction was active or disabled.

Systematic errors are the interesting ones. If the summit is always too warm, or the wind is always understated at the tree line, that is a fixable bug in the exposure factor or the downscaling — not just weather being weather.