Clicky

Přejít k obsahu
Piráti a Nezávislí Brandýs nad Labem-Stará Boleslav
AktualityLávka a varianty mostu

12/2022 · aktualizace k 5. 9. 2026

Most Generála Lišky

Reprodukovatelný skript

Původní podklad zpřístupněný přímo na webu.

Stáhnout původní soubor

/** Orientační citlivost; nemění zdrojová data ani kalibraci aplikace.
 * node doprava/tools/porovnani_mostu.mjs
 * Výstup docs/most-generala-lisky-citlivost/. Kapacita je hypotéza, ne odvození ze šířky.
 */
import {readFileSync,writeFileSync,mkdirSync} from 'node:fs';
import {fileURLToPath} from 'node:url';
import {dirname,resolve} from 'node:path';
import {createHash} from 'node:crypto';
const root=resolve(dirname(fileURLToPath(import.meta.url)),'..');
const out=resolve(root,'../docs/most-generala-lisky-citlivost');
const read=p=>JSON.parse(readFileSync(resolve(root,p),'utf8'));
globalThis.fetch=async p=>({ok:true,json:async()=>read(p)});
const {sestavGraf}=await import('../model/js/graf.js');
const {nactiPoptavku,sestavOd,OBDOBI}=await import('../model/js/poptavka.js');
const {pridelDopravu,bprCasy}=await import('../model/js/assignment.js');
const {spocitejCesty}=await import('../model/js/typicke-cesty.js');
const fc=read('data/sit.geojson'),uzly=read('data/uzly.json');
const keys=new Set(read('data/scenare.json').find(s=>s.id==='most-svabinskeho').useky);
const scope=fc.features.filter(f=>keys.has(f.properties.osm));
if(scope.length!==keys.size)throw Error('Neúplná množina úseků');
const baseGraf=sestavGraf(structuredClone(fc),{uzlovyModel:true,dataUzlu:uzly});
const pop=await nactiPoptavku('data/zony.json',baseGraf);
const od={};
for(const period of [OBDOBI.ODPOLEDNE,OBDOBI.RANO])od[period]=sestavOd(pop,baseGraf,1,null,{obdobi:period});
const mista=read('data/mista.json');
const paths=[['sb-namesti','br-namesti'],['br-namesti','sb-namesti'],['zamek','sb-namesti'],['sb-namesti','zamek'],['sb-namesti','d10-exit14']];
const profiles=read('data/kalibrace.json').profily;
if(!profiles)throw Error('Chybí kalibrační profily');
const round=x=>Math.round(x*1000)/1000;
function city(f){return f.geometry.coordinates.some(([x,y])=>x>=14.64&&x<=14.71&&y>=50.17&&y<=50.215)}
async function run(period,demand,speed,cap,iterations=36){
 const copy=structuredClone(fc);
 for(const f of copy.features)if(keys.has(f.properties.osm)){f.properties.kmh=Math.min(f.properties.kmh,speed);f.properties.cap*=cap;}
 // Sestavit celý graf znovu: kapacity pohybů v uzlech se nesmějí nechat ze základního stavu.
 const g=sestavGraf(copy,{uzlovyModel:true,dataUzlu:uzly});
 const matrix=od[period].map(p=>({...p,q:p.q*demand}));
 const r=await pridelDopravu(g,matrix,{iterace:iterations});
 const times=bprCasy(g,r.objemyHran);
 // Nezaokrouhlené vozohodiny pro rozdíly menší než jednotka.
 let vh=0,vkm=0,localKm=0;
 for(let e=0;e<g.pocetHran;e++){
  vh+=r.objemyHran[e]*times[e]/3600;vkm+=r.objemyHran[e]*g.delka[e]/1000;
  const f=g.feats[g.featId[e]];
  if(city(f)&&['residential','living_street'].includes(f.properties.cls))localKm+=r.objemyHran[e]*g.delka[e]/1000;
 }
 for(let t=0;t<g.krizovatky.pocetOdb;t++)vh+=r.objemyOdb[t]*r.zdrzeniOdb[t]/3600;
 const measured={};
 for(const p of profiles){const kk=Array.isArray(p.osm)?p.osm:[p.osm];measured[p.usek]=round(kk.reduce((s,k)=>s+(r.objemyFeat[g.osmNaFeatId.get(k)]||0),0));}
 const bridge=g.osmNaFeatId.get('38738623#1391583733');
 const dirs=[];for(let e=0;e<g.pocetHran;e++)if(g.featId[e]===bridge)dirs.push({vpred:g.vpred[e],vozH:round(r.objemyHran[e]),vc:round(r.objemyHran[e]/g.kapacita[e])});
 const roads=g.feats.filter(f=>city(f)&&!keys.has(f.properties.osm)).map(f=>({osm:f.properties.osm,nazev:f.properties.nm,trida:f.properties.cls,vozH:round(r.objemyFeat[f.properties.id])}));
 return {period,demand,speed,cap,iterations,vozH:round(vh),vozKm:round(vkm),obytnychVozKm:round(localKm),neobslouzeno:r.metriky.neobslouzeno,most:measured['1-0521'],smery:dirs,profily:measured,cesty:spocitejCesty(g,mista.mista,times,paths,null,r.zdrzeniOdb),ulice:roads};
}
const cached=process.argv.includes("--checks-only")?JSON.parse(readFileSync(resolve(out,"vysledky.json"),"utf8")):null;
const runs=cached?.runs ?? [];
if(!cached)for(const period of [OBDOBI.ODPOLEDNE,OBDOBI.RANO])for(const demand of [.9,1,1.15])for(const speed of [50,40,30])for(const cap of [1,.9,.8,.7]){
 runs.push(await run(period,demand,speed,cap));
 if(runs.length%12===0)console.log(`Hotovo ${runs.length}/72`);
}
for(const r of runs){if(!r.ulice)continue;const b=runs.find(b=>b.period===r.period&&b.demand===r.demand&&b.speed===50&&b.cap===1);
 r.deltaVozH=round(r.vozH-b.vozH);r.deltaVozHPct=round(100*(r.vozH/b.vozH-1));r.deltaVozKm=round(r.vozKm-b.vozKm);r.deltaObytnychVozKm=round(r.obytnychVozKm-b.obytnychVozKm);
 r.deltaCestyS=r.cesty.map((c,i)=>({o:c.o,d:c.d,sekund:round(60*(c.minuty-b.cesty[i].minuty))}));
 const refs=new Map(b.ulice.map(u=>[u.osm,u]));
 r.narusty=r.ulice.map(u=>({...u,zaklad:refs.get(u.osm).vozH,delta:round(u.vozH-refs.get(u.osm).vozH)})).sort((a,b)=>b.delta-a.delta).slice(0,12);
}
for(const r of runs)delete r.ulice;
// Numerical sensitivity, not a convergence certificate.
const check=[];
for(const period of [OBDOBI.ODPOLEDNE,OBDOBI.RANO])for(const iterations of [12,72])for(const [speed,cap] of [[50,1],[40,1],[30,1],[40,.9],[30,.9],[30,.8],[30,.7]]){
 const r=cached?.check.find(r=>r.period===period&&r.speed===speed&&r.cap===cap&&r.iterations===iterations) ?? await run(period,1,speed,cap,iterations);delete r.ulice;check.push(r);
}
const files=['data/sit.geojson','data/uzly.json','data/zony.json','data/kalibrace.json','data/scenare.json','model/js/graf.js','model/js/assignment.js','model/js/poptavka.js','model/js/krizovatky.js','tools/porovnani_mostu.mjs'];
const result={provedeno:new Date().toISOString(),metoda:'Pevná OD pro každé období; 36 iterací; síť 2026, nikoli rekonstrukce 2022; 72 scénářů + 28 numerických kontrol.',sha256:Object.fromEntries(files.map(p=>[p,createHash('sha256').update(readFileSync(resolve(root,p))).digest('hex')])),useky:scope.map(f=>f.properties),delkaKoridoruM:scope.reduce((s,f)=>s+f.properties.len,0),runs,check};
mkdirSync(out,{recursive:true});writeFileSync(resolve(out,'vysledky.json'),JSON.stringify(result,null,2)+'\n');
const cols=['period','demand','speed','cap','iterations','most','vozH','deltaVozH','deltaVozHPct','vozKm','deltaVozKm','obytnychVozKm','deltaObytnychVozKm','neobslouzeno'];
writeFileSync(resolve(out,'vysledky.csv'),cols.join(';')+'\n'+runs.map(r=>cols.map(k=>r[k]).join(';')).join('\n')+'\n');
console.log(`Uloženo. Délka modelového koridoru: ${result.delkaKoridoruM} m.`);