SeaWolf-AI commited on
Commit
a2bc37c
·
verified ·
1 Parent(s): c39e046

Precipitation tab with its fusion settings

Browse files
Files changed (1) hide show
  1. index.html +10 -9
index.html CHANGED
@@ -72,7 +72,7 @@ svg{width:100%;height:auto;display:block}.lg{display:flex;flex-wrap:wrap;gap:6px
72
  <div class="mbody"><div id="lmap"></div><iframe id="wfr" title="Live weather map" hidden></iframe></div>
73
  <div class="mft" id="mft"></div></div></div>
74
  <div class="etabs" id="etabs" role="tablist" aria-label="Weather element">
75
- <button type="button" class="et on" data-e="tmax">Max temperature</button><button type="button" class="et" data-e="tmin">Min temperature</button><button type="button" class="et" data-e="wind">Wind</button></div>
76
  <main>
77
  <noscript><h1>Global Weather Model Leaderboard</h1><p>Daily accuracy ranking of global weather forecast models, AI and physics: Darwin-Prediction-Weather, ECMWF AIFS, ECMWF IFS, GFS, AIGFS, ICON, JMA, GEM and MET Norway, scored against ERA5 for 24 world cities since 2026-01-01, with a 10-day outlook. 2026 year to date, RMSE of daily maximum temperature in °C at 1, 3, 5 and 7 days ahead: Darwin-Prediction-Weather (VIDRAFT, AI) 0.84, 1.17, 1.59, 2.09. ECMWF AIFS (AI) 1.35, 1.59, 1.90, 2.42. ECMWF IFS (Physics) 1.44, 1.77, 2.21, 2.85. Data: <a href="https://huggingface.co/datasets/FINAL-Bench/Weather-Model-Forecast-Archive">Weather-Model-Forecast-Archive</a>. Contact: vidraft@mail.vidraft.net</p></noscript>
78
  <div class="ctl">
@@ -99,7 +99,7 @@ svg{width:100%;height:auto;display:block}.lg{display:flex;flex-wrap:wrap;gap:6px
99
  <h3 class="h3">By period and forecast day, 24 cities</h3><div class="tw"><table class="wt" id="wper"></table></div>
100
  <h3 class="h3" style="margin-top:16px">By city and forecast day, 2026 year to date</h3><div class="tw"><table class="wt" id="wcity"></table></div><div class="lg" id="lg3"></div></div>
101
  <div class="pn" style="margin-top:14px"><h2>How it is scored</h2>
102
- <p class="note">Every day each model's forecast is recorded for up to 10 days ahead. When the observed value for a day is published, every forecast made for that day is scored and the cumulative record is updated, once a day. A forecast issued N days earlier is compared with the ERA5 value for the same UTC day at each city. Each element has its own tab and its own ranking: daily maximum temperature, daily minimum temperature, and daily maximum wind speed. Lower RMSE ranks higher. Models are compared on the same cases: days and cities where every listed model issued a forecast. Type shows how a model works: <b>AI</b> models learn the forecast from data, <b>Physics (Supercomputer)</b> models solve the equations of the atmosphere on supercomputers. ERA5 is published about five days after the fact, so the latest verification date trails today. Forecasts 1 to 7 days ahead are scored from 2026-01-01; forecasts 8 to 10 days ahead are archived from 2026-11-13 and enter the ranking as their target days are verified. <b>Darwin-Prediction-Weather</b> is VIDRAFT's fusion engine: local bias correction plus skill-weighted fusion of the public models, fitted only on days before the one being scored. It is ranked on exactly the same cases as the public models. In the 10-day outlook the fusion for days beyond the longest scored lead uses that lead's calibration.</p></div>
103
  <footer>Full daily record since 2026-01-01 (every model forecast and the ERA5 value): <a href="https://huggingface.co/datasets/FINAL-Bench/Weather-Model-Forecast-Archive">Weather-Model-Forecast-Archive</a>. Weather data by <a href="https://open-meteo.com/">Open-Meteo.com</a> (CC BY 4.0). Verification: ERA5, Copernicus Climate Change Service. Model sources: ECMWF, NOAA NCEP, DWD, JMA, ECCC, MET Norway. Engine: <a href="https://huggingface.co/FINAL-Bench/Darwin-Prediction-Weather">Darwin-Prediction-Weather</a>. Leaderboard application: Apache License 2.0. Compiled record and model: CC BY-NC 4.0. Contact: <a href="mailto:vidraft@mail.vidraft.net">vidraft@mail.vidraft.net</a></footer>
104
  </main><script>
105
  const CITIES={"Seoul":[37.57,126.98],"Busan":[35.18,129.08],"Tokyo":[35.68,139.69],"Beijing":[39.90,116.40],"Singapore":[1.35,103.82],"Delhi":[28.61,77.21],"Dubai":[25.20,55.27],"Moscow":[55.76,37.62],"Berlin":[52.52,13.40],"London":[51.51,-0.13],"Paris":[48.86,2.35],"Madrid":[40.42,-3.70],"Cairo":[30.04,31.24],"Nairobi":[-1.29,36.82],"Johannesburg":[-26.20,28.05],"New York":[40.71,-74.01],"Chicago":[41.88,-87.63],"Los Angeles":[34.05,-118.24],"Mexico City":[19.43,-99.13],"Sao Paulo":[-23.55,-46.63],"Buenos Aires":[-34.60,-58.38],"Sydney":[-33.87,151.21],"Anchorage":[61.22,-149.90],"Reykjavik":[64.15,-21.94]};
@@ -138,7 +138,7 @@ const num=v=>(v===null||v===undefined)?NaN:v,fin=Number.isFinite;
138
  // 10-day outlook: each model's latest forecast, and the fusion built with the calibration of the matching lead (leads beyond the scored range use the longest scored lead)
139
  function ocalc(c){const city=NAMES[c],days=OLX.dates.slice(1,11),ms=MK.filter(m=>OLX.models[m]&&OLX.models[m][city]);
140
  const scored=LEADS.map((L,i)=>MK.some(m=>F[m]&&F[m][i]&&F[m][i][c].some(v=>v!==null&&v!==undefined))?i:-1).filter(i=>i>=0);
141
- const fz=(li,L,t,val)=>{const use=ms.filter(m=>F[m]&&F[m][li]&&fin(val(m)));if(use.length<3)return NaN;const {bias,mse}=fit(li,L,t,use);const good=use.filter(m=>fin(mse[m])&&mse[m]>0&&fin(bias[m][c]));if(good.length<3)return NaN;let ws=0,f=0;good.forEach(m=>ws+=1/mse[m]);good.forEach(m=>f+=(1/mse[m])/ws*(val(m)-bias[m][c]));return f};
142
  const fus=days.map((d,k)=>{const L=k+1;let li=LEADS.indexOf(L);if(!scored.includes(li))li=scored.length?scored[scored.length-1]:-1;return li<0?NaN:fz(li,LEADS[li],dates.length,m=>num(OLX.models[m][city][L]))});
143
  const Rc=OLX.recent,Dl=+$("lead").value,Lp=Math.min(Dl,7),liH=LEADS.indexOf(Lp),pd=Rc?Rc.dates:[],ob=Rc?Rc.obs[city]||[]:[],idx=d=>Math.round((Date.parse(d)-Date.parse(dates[0]))/864e5);
144
  const pf=(m,j)=>Rc&&Rc.F[m]&&Rc.F[m][city]?num(Rc.F[m][city][Lp-1][j]):NaN,PF=pd.map((d,j)=>liH<0?NaN:fz(liH,Lp,idx(d),m=>pf(m,j)));
@@ -166,12 +166,13 @@ function outlook(){if(!OLX){$("otiles").innerHTML="";$("otab").innerHTML="";$("o
166
  $("otab").innerHTML=h;
167
  $("onote").textContent=`Forecasts issued ${iss}, in ${U}. The large numbers are the Darwin-Prediction-Weather forecast; "± models" is half the spread between the models, a guide to how settled the forecast is.${Rc?` "Actual value" is what really happened. Past days show each forecast issued ${Lp} day${Lp>1?"s":""} earlier and, in colour, how far it was from the actual value. Recent actual values are preliminary until ERA5 is published. * Today so far (${Rc.today_hours}:00 UTC). WIN marks the closest forecast of each day; days ahead receive their WIN when the actual value is in.${Object.keys(wcount).length?" Wins in the last "+wins.filter(Boolean).length+" days: "+Object.entries(wcount).sort((a,b)=>b[1]-a[1]).map(([m,n])=>inf(m)[0]+" "+n).join(", ")+".":""}`:""}`}
168
  // bias and weights use only days whose truth was known before scoring day t (t-30 .. t-lead)
169
- function fit(li,D,t,ms){const w0=Math.max(0,t-30),t1=t-D;const bias={},mse={};
170
  for(const m of ms){bias[m]=[];let s2=0,n2=0;
171
- for(let c=0;c<NAMES.length;c++){let s=0,n=0;for(let d=w0;d<=t1;d++){const e=num(F[m][li][c][d])-num(O[c][d]);if(fin(e)){s+=e;n++}}bias[m][c]=n>=7?s/n:NaN}
172
  for(let c=0;c<NAMES.length;c++)for(let d=w0;d<=t1;d++){const e=num(F[m][li][c][d])-bias[m][c]-num(O[c][d]);if(fin(e)){s2+=e*e;n2++}}
173
- mse[m]=n2?s2/n2:NaN}
174
  return{bias,mse}}
 
175
  const memo={};
176
  // one pass: overall, per-city and per-month squared errors on the cases every listed model covers
177
  function run(li,t0,t1,ci){const key=[li,t0,t1,ci].join("|");if(memo[key])return memo[key];const D=LEADS[li];
@@ -179,11 +180,11 @@ function run(li,t0,t1,ci){const key=[li,t0,t1,ci].join("|");if(memo[key])return
179
  const EL=MK.filter(m=>(cov[m]||0)>=Math.max(1,0.6*tot)&&tot>0),OUT=MK.filter(m=>!EL.includes(m));
180
  const mk=()=>{const A={};return{A,add:(k,gs,e)=>{if(!fin(e))return;const a=A[k]||(A[k]={s:0,n:0,g:{}});a.s+=e*e;a.n++;for(const g of gs){const b=a.g[g]||(a.g[g]=[0,0]);b[0]+=e*e;b[1]++}}}},P=mk(),Q=mk();
181
  // P: every common case (public models only). Q: the cases where the fusion also exists, so it is ranked on identical cases.
182
- for(let t=t0;t<=t1;t++){const {bias,mse}=fit(li,D,t,EL);const good=EL.filter(m=>fin(mse[m])&&mse[m]>0);let ws=0;good.forEach(m=>ws+=1/mse[m]);const mon=dates[t].slice(0,7);
183
  for(let c=0;c<NAMES.length;c++){if(ci>=0&&c!==ci)continue;const o=num(O[c][t]);if(!fin(o))continue;if(!EL.every(m=>fin(num(F[m][li][c][t]))))continue;
184
  for(const m of EL)P.add(m,["c"+c,mon],num(F[m][li][c][t])-o);
185
- let fu=0,ok=good.length>=3&&good.length===EL.length;for(const m of good){const x=num(F[m][li][c][t])-bias[m][c];if(!fin(x)){ok=false;break}fu+=(1/mse[m])/ws*x}
186
- if(ok){for(const m of EL)Q.add(m,["c"+c,mon],num(F[m][li][c][t])-o);Q.add("darwin",["c"+c,mon],fu-o)}}}
187
  const A=Q.A.darwin?Q.A:P.A,ks=EL.filter(m=>A[m]).concat(A.darwin?["darwin"]:[]);
188
  const rows=ks.map(m=>({m,r:Math.sqrt(A[m].s/A[m].n),n:A[m].n})).sort((a,b)=>a.r-b.r);let rk=0,prev=null;rows.forEach((x,i)=>{if(prev===null||x.r.toFixed(2)!==prev){rk=i+1;prev=x.r.toFixed(2)}x.rk=rk});
189
  const pub=rows.filter(x=>x.m!=="darwin");
 
72
  <div class="mbody"><div id="lmap"></div><iframe id="wfr" title="Live weather map" hidden></iframe></div>
73
  <div class="mft" id="mft"></div></div></div>
74
  <div class="etabs" id="etabs" role="tablist" aria-label="Weather element">
75
+ <button type="button" class="et on" data-e="tmax">Max temperature</button><button type="button" class="et" data-e="tmin">Min temperature</button><button type="button" class="et" data-e="wind">Wind</button><button type="button" class="et" data-e="precip">Precipitation</button></div>
76
  <main>
77
  <noscript><h1>Global Weather Model Leaderboard</h1><p>Daily accuracy ranking of global weather forecast models, AI and physics: Darwin-Prediction-Weather, ECMWF AIFS, ECMWF IFS, GFS, AIGFS, ICON, JMA, GEM and MET Norway, scored against ERA5 for 24 world cities since 2026-01-01, with a 10-day outlook. 2026 year to date, RMSE of daily maximum temperature in °C at 1, 3, 5 and 7 days ahead: Darwin-Prediction-Weather (VIDRAFT, AI) 0.84, 1.17, 1.59, 2.09. ECMWF AIFS (AI) 1.35, 1.59, 1.90, 2.42. ECMWF IFS (Physics) 1.44, 1.77, 2.21, 2.85. Data: <a href="https://huggingface.co/datasets/FINAL-Bench/Weather-Model-Forecast-Archive">Weather-Model-Forecast-Archive</a>. Contact: vidraft@mail.vidraft.net</p></noscript>
78
  <div class="ctl">
 
99
  <h3 class="h3">By period and forecast day, 24 cities</h3><div class="tw"><table class="wt" id="wper"></table></div>
100
  <h3 class="h3" style="margin-top:16px">By city and forecast day, 2026 year to date</h3><div class="tw"><table class="wt" id="wcity"></table></div><div class="lg" id="lg3"></div></div>
101
  <div class="pn" style="margin-top:14px"><h2>How it is scored</h2>
102
+ <p class="note">Every day each model's forecast is recorded for up to 10 days ahead. When the observed value for a day is published, every forecast made for that day is scored and the cumulative record is updated, once a day. A forecast issued N days earlier is compared with the ERA5 value for the same UTC day at each city. Each element has its own tab and its own ranking: daily maximum temperature, daily minimum temperature,, daily maximum wind speed and daily precipitation total. Lower RMSE ranks higher. Models are compared on the same cases: days and cities where every listed model issued a forecast. Type shows how a model works: <b>AI</b> models learn the forecast from data, <b>Physics (Supercomputer)</b> models solve the equations of the atmosphere on supercomputers. ERA5 is published about five days after the fact, so the latest verification date trails today. Forecasts 1 to 7 days ahead are scored from 2026-01-01; forecasts 8 to 10 days ahead are archived from 2026-11-13 and enter the ranking as their target days are verified. <b>Darwin-Prediction-Weather</b> is VIDRAFT's fusion engine: skill-weighted fusion of the public models, with local bias correction for temperature and wind, fitted only on days before the one being scored. It is ranked on exactly the same cases as the public models. In the 10-day outlook the fusion for days beyond the longest scored lead uses that lead's calibration.</p></div>
103
  <footer>Full daily record since 2026-01-01 (every model forecast and the ERA5 value): <a href="https://huggingface.co/datasets/FINAL-Bench/Weather-Model-Forecast-Archive">Weather-Model-Forecast-Archive</a>. Weather data by <a href="https://open-meteo.com/">Open-Meteo.com</a> (CC BY 4.0). Verification: ERA5, Copernicus Climate Change Service. Model sources: ECMWF, NOAA NCEP, DWD, JMA, ECCC, MET Norway. Engine: <a href="https://huggingface.co/FINAL-Bench/Darwin-Prediction-Weather">Darwin-Prediction-Weather</a>. Leaderboard application: Apache License 2.0. Compiled record and model: CC BY-NC 4.0. Contact: <a href="mailto:vidraft@mail.vidraft.net">vidraft@mail.vidraft.net</a></footer>
104
  </main><script>
105
  const CITIES={"Seoul":[37.57,126.98],"Busan":[35.18,129.08],"Tokyo":[35.68,139.69],"Beijing":[39.90,116.40],"Singapore":[1.35,103.82],"Delhi":[28.61,77.21],"Dubai":[25.20,55.27],"Moscow":[55.76,37.62],"Berlin":[52.52,13.40],"London":[51.51,-0.13],"Paris":[48.86,2.35],"Madrid":[40.42,-3.70],"Cairo":[30.04,31.24],"Nairobi":[-1.29,36.82],"Johannesburg":[-26.20,28.05],"New York":[40.71,-74.01],"Chicago":[41.88,-87.63],"Los Angeles":[34.05,-118.24],"Mexico City":[19.43,-99.13],"Sao Paulo":[-23.55,-46.63],"Buenos Aires":[-34.60,-58.38],"Sydney":[-33.87,151.21],"Anchorage":[61.22,-149.90],"Reykjavik":[64.15,-21.94]};
 
138
  // 10-day outlook: each model's latest forecast, and the fusion built with the calibration of the matching lead (leads beyond the scored range use the longest scored lead)
139
  function ocalc(c){const city=NAMES[c],days=OLX.dates.slice(1,11),ms=MK.filter(m=>OLX.models[m]&&OLX.models[m][city]);
140
  const scored=LEADS.map((L,i)=>MK.some(m=>F[m]&&F[m][i]&&F[m][i][c].some(v=>v!==null&&v!==undefined))?i:-1).filter(i=>i>=0);
141
+ const fz=(li,L,t,val)=>{const use=ms.filter(m=>F[m]&&F[m][li]&&fin(val(m)));if(use.length<3)return NaN;const {bias,mse}=fit(li,L,t,use);const good=use.filter(m=>fin(mse[m])&&mse[m]>0&&fin(bias[m][c]));if(good.length<3)return NaN;let ws=0,f=0;good.forEach(m=>ws+=wt(mse[m]));good.forEach(m=>f+=wt(mse[m])/ws*(val(m)-bias[m][c]));return clip(f)};
142
  const fus=days.map((d,k)=>{const L=k+1;let li=LEADS.indexOf(L);if(!scored.includes(li))li=scored.length?scored[scored.length-1]:-1;return li<0?NaN:fz(li,LEADS[li],dates.length,m=>num(OLX.models[m][city][L]))});
143
  const Rc=OLX.recent,Dl=+$("lead").value,Lp=Math.min(Dl,7),liH=LEADS.indexOf(Lp),pd=Rc?Rc.dates:[],ob=Rc?Rc.obs[city]||[]:[],idx=d=>Math.round((Date.parse(d)-Date.parse(dates[0]))/864e5);
144
  const pf=(m,j)=>Rc&&Rc.F[m]&&Rc.F[m][city]?num(Rc.F[m][city][Lp-1][j]):NaN,PF=pd.map((d,j)=>liH<0?NaN:fz(liH,Lp,idx(d),m=>pf(m,j)));
 
166
  $("otab").innerHTML=h;
167
  $("onote").textContent=`Forecasts issued ${iss}, in ${U}. The large numbers are the Darwin-Prediction-Weather forecast; "± models" is half the spread between the models, a guide to how settled the forecast is.${Rc?` "Actual value" is what really happened. Past days show each forecast issued ${Lp} day${Lp>1?"s":""} earlier and, in colour, how far it was from the actual value. Recent actual values are preliminary until ERA5 is published. * Today so far (${Rc.today_hours}:00 UTC). WIN marks the closest forecast of each day; days ahead receive their WIN when the actual value is in.${Object.keys(wcount).length?" Wins in the last "+wins.filter(Boolean).length+" days: "+Object.entries(wcount).sort((a,b)=>b[1]-a[1]).map(([m,n])=>inf(m)[0]+" "+n).join(", ")+".":""}`:""}`}
168
  // bias and weights use only days whose truth was known before scoring day t (t-30 .. t-lead)
169
+ function fit(li,D,t,ms){const c0=CF(),w0=Math.max(0,t-c0.win),t1=t-D;const bias={},mse={};
170
  for(const m of ms){bias[m]=[];let s2=0,n2=0;
171
+ for(let c=0;c<NAMES.length;c++){if(!c0.bias){bias[m][c]=0;continue}let s=0,n=0;for(let d=w0;d<=t1;d++){const e=num(F[m][li][c][d])-num(O[c][d]);if(fin(e)){s+=e;n++}}bias[m][c]=n>=7?s/n:NaN}
172
  for(let c=0;c<NAMES.length;c++)for(let d=w0;d<=t1;d++){const e=num(F[m][li][c][d])-bias[m][c]-num(O[c][d]);if(fin(e)){s2+=e*e;n2++}}
173
+ mse[m]=n2>=(c0.bias?1:100)?s2/n2:NaN}
174
  return{bias,mse}}
175
+ const FCFG={tmax:{win:30,bias:1,p:1},tmin:{win:30,bias:1,p:1},wind:{win:30,bias:1,p:1},precip:{win:150,bias:0,p:8}},CF=()=>FCFG[EK],wt=v=>Math.pow(v,-CF().p),clip=v=>EK==="precip"?Math.max(0,v):v;
176
  const memo={};
177
  // one pass: overall, per-city and per-month squared errors on the cases every listed model covers
178
  function run(li,t0,t1,ci){const key=[li,t0,t1,ci].join("|");if(memo[key])return memo[key];const D=LEADS[li];
 
180
  const EL=MK.filter(m=>(cov[m]||0)>=Math.max(1,0.6*tot)&&tot>0),OUT=MK.filter(m=>!EL.includes(m));
181
  const mk=()=>{const A={};return{A,add:(k,gs,e)=>{if(!fin(e))return;const a=A[k]||(A[k]={s:0,n:0,g:{}});a.s+=e*e;a.n++;for(const g of gs){const b=a.g[g]||(a.g[g]=[0,0]);b[0]+=e*e;b[1]++}}}},P=mk(),Q=mk();
182
  // P: every common case (public models only). Q: the cases where the fusion also exists, so it is ranked on identical cases.
183
+ for(let t=t0;t<=t1;t++){const {bias,mse}=fit(li,D,t,EL);const good=EL.filter(m=>fin(mse[m])&&mse[m]>0);let ws=0;good.forEach(m=>ws+=wt(mse[m]));const mon=dates[t].slice(0,7);
184
  for(let c=0;c<NAMES.length;c++){if(ci>=0&&c!==ci)continue;const o=num(O[c][t]);if(!fin(o))continue;if(!EL.every(m=>fin(num(F[m][li][c][t]))))continue;
185
  for(const m of EL)P.add(m,["c"+c,mon],num(F[m][li][c][t])-o);
186
+ let fu=0,ok=good.length>=3&&good.length===EL.length;for(const m of good){const x=num(F[m][li][c][t])-bias[m][c];if(!fin(x)){ok=false;break}fu+=wt(mse[m])/ws*x}
187
+ if(ok){for(const m of EL)Q.add(m,["c"+c,mon],num(F[m][li][c][t])-o);Q.add("darwin",["c"+c,mon],clip(fu)-o)}}}
188
  const A=Q.A.darwin?Q.A:P.A,ks=EL.filter(m=>A[m]).concat(A.darwin?["darwin"]:[]);
189
  const rows=ks.map(m=>({m,r:Math.sqrt(A[m].s/A[m].n),n:A[m].n})).sort((a,b)=>a.r-b.r);let rk=0,prev=null;rows.forEach((x,i)=>{if(prev===null||x.r.toFixed(2)!==prev){rk=i+1;prev=x.r.toFixed(2)}x.rk=rk});
190
  const pub=rows.filter(x=>x.m!=="darwin");