Optimalizace kapacity vleku (NetLogo)

= Zadání =

Název simulace: Optimalizace kapacity vleku

Předmět: 4IT495 Simulace systémů (LS 2015/2016)

Autor: Bc. Martin Hradil

Typ modelu: Multiagentní

Modelovací nástroj: NetLogo 5.3.1

= Definice problému =

Příjmy skiareálu s jednou sjezdovkou jsou z drtivé většiny tvořeny z prodeje permanentek. Pro největší příjmy je tedy vhodné, aby se do skiareálu vešlo co nejvíce lidí.

Celý skiareál má ale určitou kapacitu lidí, kteří se do něj vejdou, a při tom se ještě vzájemně na sjezdovce neblokují. Limitovat počet lidí na sjezdovce je možné kapacitou vleku (kolik lyžařů/čas vlek vyveze na kopec, nebo po jaké době vyveze jednoho lyžaře).

= Cíl =

Cílem simulace je při zadané šířce sjezdovky nalézt maximální kapacitu vleku, při které se lyžaři ještě nebudou blokovat tolik, aby se hromadili na kopci kvůli ucpání sjezdovky.

= Metoda =

Jelikož se jedná o multiagentní simulaci, jako prostředek byl zvolen program NetLogo, v poslední verzi 5.3.1. V něm byl vytvořen model skiareálu, ve kterém se jednotliví agenti pohybují.

Jelikož každý člověk má jiné schopnosti a chová se na sjezdovce jinak, lze jednotlivé lyžaře obtížně vyjádřit čísly. V nástroji NetLogo je možné vlastnosti lažařů jako rychlost nebo velikost obloučků náhodně generovat. Podklady pro nastavení generování těchto parametrů by bylo možné získat pozorováním na nějaké sjezdovce. To však nebylo vzhledem k aktuálnímu ročnímu období možné a tak byly odhadnuty.

= Model =

Tato část obsahuje popis modelu, jeho grafické rozhraní a logiku. První je vysvětlen samotný model, následně jak ho používat.

Grafické Rozhraní
Grafické rozhraní se skládá z části nastavení a ovládání, hlavního okna s vizualizací děje, a grafů a monitorů.



Část s ovládáním obsahuje posuvníky pro nastavení parametrů v rámci vhodných mezí a tlačítka pro prvotní nastavení a běh.

Hlavní okno s vizualizací obsahuje grafický model skiareálu. Ten se skládá z několika částí:


 * Kolem procházející cesta
 * Příchozí cesta do fronty
 * Fronta
 * Vlek
 * Výstup z vleku
 * Sjezdovka

Celé pozadí je zelené a má znázorňovat les nebo louku.

V pravé části jsou zobrazeny číselné výstupy simulace v číslech a grafech.
 * lift capacity - znázornění proměnné liftCapacity (invertované kapacity vleku). Po kolika ticích vlek vyveze dalšího lyžaře.
 * persons stuck on the top - znázornění počtu lidí zablokovaných na začátku svahu.
 * persons in skiareal - počet lidí ve skiareálu. Tedy všech kromě těch na kolem procházející cestě.
 * persons blocked total - počet celkově zablokovaných lyžařů ostatními lyžaři.
 * queue length - počet lidí ve frontě.

Implementace
V modelu existují lyžaři, kolem kterých se celá simulace odehrává. Ti mohou být v několika stavech, podle kterých se různě chovají chovají. Tyto stavy jsou uloženy v proměnných. Dále model obsahuje globální proměnné a několik lokálních proměnných.

Proměnné, parametry, obory hodnot
Proměnné z nastavení v UI:


 * slopeWidth - šířka sjezdovky, udáváná v "patches". Může nabývat hodnot od 10 do 55.
 * slopeMaxCurve - maximální úhel obloučku lyžaře vzhledem k jeho pohledu. Může nabývat hodnot od 0 do 90. Tzn. při 0° jede rovně přímo dolů, při 90° dělá obloučky až do pravého úhlu ke směru sjezdovky.
 * slopeSpeedDeviation - směrodatná odchylka pro generování náhodně rychlosti lyžařů. Může nabývat hodnot od 0 do 0,01.
 * liftCapacity - tato proměnná limituje, po jakém čase (po kolika ticích) vlek vyveze dalšího lyžaře. Když se má v daném ticku vyvézt další lyžař, tato proměnná se porovná a je-li větší než "lastPersonLifted", první lyžař z fronty nastoupí na vlek a proměnná se vynuluje. Může nabývat hodnot od 0 do 400.
 * newPeopleFrequency - Šance # z 1000, že se v daném ticku vytvoří nový člověk. Může nabývat hodnot od 0 do 100.
 * maxQueueLenght - Pokud je fronta na vlek delší než #, kolem procházející lidé nevstoupí do skiareálu. Může nabývat hodnot od 0 do 50.
 * stopChance - Šance # z 1 000 000, že se lyžař na sjezdovce v daném ticku zastaví. Může nabývat hodnot od 1 do 500.
 * StopDuration - Na jak dlouho se lyžař zastaví, udávaná v ticks. Může nabývat hodnot od 0 do 3000.

Globální proměnné:


 * lastNewPerson - tato proměnná limituje, po jakém čase mohou kolem procházet noví potencionální lyžaři. Jestliže je na ně fronta moc dlouhá, procházejí kolem skiareálu a mizí. S každým tickem se přičítá 1. Když se má v daném ticku vytvořit další člověk, tato proměnná se porovná a je-li větší než 10, vytvoří se nový člověk a proměnná se vynuluje.
 * liftSpeed - tato proměnná vyjadřuje rychlost pohybu lyžařů na vleku. Je nastavena na 0,05.
 * walkSpeed - tato proměnná vyjadřuje rychlost chůze lyžařů. Je použita, pokud je lyžař kdekoli kromě sjezdovky nebo vleku. Je nastavena na 0,13.
 * lastPersonLifted - tato proměnná vyjadřuje, před kolika ticky byl vyvezen poslední lyžař. S každým tickem se přičítá 1. Může nabývat hodnot od 0 do hodnoty nastavené v "liftCapacity".
 * personsInSkiareal - Proměnná vyjadřující počet lidí ve skiareálu. Tzn. těch, kteří jsou kdekoli kromě cesty procházející okolo. Může nabývat hodnot od 0 do nekonečna. (při hodně dlouhé době běhu simulace)
 * QueueLength - Proměnná vyjadřující počet lidí ve frontě nebo na cestě na konec fronty. Může nabývat hodnot od 0 do nekonečna. (při hodně dlouhé době běhu simulace a změně určitých nastavení)
 * onTheTopCount - Proměnná vyjadřující počet lidí na výstupu z vleku, kteří jsou zablokování a nemohou jet po sjezdovce dolů. Může nabývat hodnot od 0 do nekonečna. (při hodně dlouhé době běhu simulace)
 * blockedTotal - Proměnná vyjadřující počet lidí zablokovaných ostatními lyžaři, na sjezdovce a výstupu z vleku. Může nabývat hodnot od 0 do nekonečna. (při hodně dlouhé době běhu simulace)

Proměnné lyžařů:


 * place - Proměnná vyjadřující, kde se daný člověk nachází. Může nabývat hodnot road, roadUp, queue, lift, liftExit, slope, toQueue.
 * slopeSpeed - Proměnná vyjadřující rychlost lyžaře na sjezdovce. Může nabývat hodnot z normálního rozdělení 0,03;slopeSpeedDeviation, minimálně však 0,005.
 * slopeStart - Proměnná vyjadřující, na jaké souřadnici X začne lyžař sjíždět sjezdovku. Může nabývat hodnot od 15 do slopeWidth + 15
 * slopeDirection - Proměnná vyjadřující, na jakou stranu v daném ticku lyžař na sjezdovce zatáčí. Může nabývat hodnot "left" nebo "right"
 * slopeAngle - totéž jako interní proměnná heading, ale používána pouze, pokud je proměnná place="slope". Vyjadřuje aktuální směr pohybu na sjezdovce. U jednotlivých lyžařů může nabývat hodnot od 180 - slopeCurve do 180 + slopeCurve. Při určitém nastavení tedy u všech od 90 do 270.
 * slopeCurve - Proměnná vyjadřující maximální úhel obloučku daného lyžaře. Generována po opuštění vleku, náhodně v rozmezí od 0 do slopeMaxCurve. Při určitém nastavení tedy u všech od 0 do 90.
 * personsBeforeMe - Proměnná vyjadřující počet lidí, kteří jsou před daným lyžařem na sjezdovce a blokují ho (Počet lidí na sousedech patche o 2 před lyžařem). Může nabývat hodnot od 0 do nekonečna.
 * stoppedAgo - Proměnná vyjadřující, před jak dlouho dobou (počet ticků) lyžař náhodně zastavil. S každým tickem se přičítá 1. Může nabývat hodnot od 0 do nekonečna.

Lokální proměnné jednotlivých procedur:


 * inQueue - Proměnná používaná pro sečtení lidí ve frontě a na cestě na konec fronty v daném ticku. Může nabývat hodnot od 0 do nekonečna.
 * onTheTop - Proměnná používaná pro sečtení lidí na vršku sjezdovky v daném ticku. Může nabývat hodnot od 0 do nekonečna.
 * personCount - Proměnná používaná pro sečtení lidí před daným lyžařem v daném ticku, pokud by bylo potřeba sčítat více než jeden patch. Může nabývat hodnot od 0 do nekonečna.
 * blocked - Proměnná používaná pro sečtení všech zablokovaných lidí v daném ticku. Může nabývat hodnot od 0 do nekonečna.

Postup simulace
Simulace sestává z několika fází.

Vygenerování plochy

Po stistknutí tlačítka setup se vše vymaže a nastaví se plocha (zabarví se zeleně a přes ní následně obdélníky označující vlek, sjezdovku, frontu, výstup z vleku, cestu kolem a cestu ke frontě). Nastaví se také liftSpeed na 0.05 a walkSpeed na 0.13, lastNewPerson na 0 a lastPersonLifted na 0

Běh simulace

Simulace se spustí nebo zastaví stisknutím tlačítka Go, které funguje jako přepínač a stále dokola tedy volá jednu "Go". V rámci procedury Go se:

Může vytvořit nový člověk:
 * Pokud byl předchozí člověk vytvořen před více než 10 ticky a platí, že (random 1000 < newPeopleFrequency), je vytvořen.
 * Jeho pozice je nastavena na 90,4, tzn úplně vpravo na kolem procházející cestě. Jeho velikost na 3, a směr na 0,4, tzn vodorovně doleva.
 * je umístěn na kolem procházející cestu (proměnná place="road").
 * stoppedAgo je mu nastaveno na 100 000 (záměrně veliké číslo, větší než StopDuration).

Může být smazán člověk, který prošel kolem
 * Pokud je člověk na kolem procházející cestě a opustil obrazovku (ycor < 1), je smazán (die).

Nastaví se proměnné pro daný tick a sečtou se lidé:
 * set lastPersonLifted lastPersonLifted + 1
 * let inQueue 0
 * let onTheTop 0
 * let blocked 0
 * Pokud jsou lidé ve frontě nebo na cestě do fronty, přičte se k inQueue 1.
 * Pokud jsou lidé na začátku sjezdovky, přičte se k onTheTop 1.
 * následně se queueLength se nastaví na inQueue, onTheTopCount na onTheTop.

Zajistí pohyb všech lidí:

Pokud je osoba na kolem procházející cestě, na úrovni cesty do fronty, a lidí ve frontě je méně než maxQueueLength:
 * nastaví se její poloha na cestu ke frontě (place="roadUp") a směr nahoru (facexy 69 11).
 * k počtu lidí ve skiareálu se přičte 1.
 * popojde o walkSpeed.

Pokud je osoba na cestě ke frontě:
 * Pokud je na úrovni fronty (ycor > 11), zařadí se do ní, otočí se doleva, nastaví se jí místo na frontu (place="queue").
 * Pokud není na úrovni fronty (ycor > 11), popojde o walkSpeed.

Pokud je člověk ve frontě:
 * Pokud není první ve frontě a není nikdo před ním, popojde o walkSpeed.
 * Pokud je první ve frontě a vlek vyvezl posledního minimálně před určeným časem (lastPersonLifted > liftCapacity), nastaví se jeho poloha na vlek (place="lift").

Pokud je člověk na vleku:
 * pokud není na kopci (ycor < 84), popojede o liftSpeed.
 * pokud je na kopci (ycor > 84), nastaví se mu směr doprava (heading 90), náhodně začáteční souřadnice X na sjezdovce a poloha na výstup z vleku (place="liftExit").

Pokud je člověk na výstupu z vleku:
 * Pokud je na X souřadnici, kde má začít lyžovat:
 * Nastaví se mu směry dolů (heading a slopeAngle na 180), poloha na sjezdovku (place="slope"),
 * Nastaví se mu směr obloučku (slopeDirection) podle toho, zda je v pravé nebo levé části sjezdovky. Zleva doprava, zprava doleva.
 * Nastaví se mu rychlost lyžování (slopeSpeed) z normálního rozdělení 0.03;slopeSpeedDeviation
 * Náhodně se mu nastaví maximální velikost obloučku (slopeCurve) mezi 0 a slopeMaxCurve.
 * pokud není, popojde o walkSpeed

Pokud je člověk na sjezdovce:
 * Nastaví se mu počet blokujících lidí (personCount) na 0
 * Postupně se sečte počet blokujících lidí na patchích před ním přes proměnou personCount, a přiřadí do proměnné personsBeforeMe.
 * Pokud je směr otáčení lyžaře (slopeDirection) doprava a není náhodně zastavený (stoppedAgo > stopDuration):
 * úhel(slopeAngle) pohybu se změní o +0,2
 * Pokud narazil na limit úhlu obloučku (slopeAngle > 180 + slopeCurve), změní se směr otáčení na doleva
 * Pokud je směr otáčení lyžaře (slopeDirection) doleva a není náhodně zastavený (stoppedAgo > stopDuration):
 * úhel(slopeAngle) pohybu se změní o -0,2
 * Pokud narazil na limit úhlu obloučku (slopeAngle < 180 + slopeCurve), změní se směr otáčení na doleva
 * Nastaví se mu směr na vypočítaný směr pohybu (heading=slopeAngle)
 * Pokud vyjel ze sjezdovky do lesa kvůli blokaci, vrátí se zpět na sjezdovku (xcor se nastaví na nejbližší na sjezdovce).
 * Pokud dojel na konec sjezdovky (ycor<12), nastaví se mu poloha na chůzi na konec fronty (place="toQueue) a směr doprava (heading 90).
 * Pokud se má náhodně zastavit (random 1000000 < stopChance), vynuluje se čas posledního zastavení (stoppedAgo=0).
 * K času, kdy se naposled zastavil, se přičte 1.
 * Pokud ho nikdo neblokuje (personsBeforeMe) a nemá stát (stoppedAgo > stopDuration), posune se o slopeSpeed.
 * Pokud je blokován, k globální proměnné blocked se přičte 1.
 * pokud je skoro u konce svahu (ycor<16), ignoruje blokování, zuje lyže a zbytek svahu dojde rychlostí walkSpeed.

Pokud je člověk na cestě na konec fronty:
 * popojde o walkSpeed
 * pokud na jeho úrovni ve frontě nikdo není, zařadí se (ycor=11, poloha na frontu (place="queue"), směr doleva (heading 270).

Omezení modelu
Jak již bylo řečeno, jednotliví lidé se těžko parametrizují, protože každý lyžuje jinak, má jiné preference ohledně ucpanosti sjezdovky a jaký potřebuje prostor kolem sebe. Tyto parametry byly odhadnuty a nastaveny tak, jak by je nejspíše měla většina lyžařů.

Vzhledem k rozměrům sjezdovek (šířka v jednotkách až desítkách metrů, délka ve stovkách metrů) není možné vytvořit model se správně velkými poměry sjezdovky a vleku, protože by byl hrozně vysoký a nevešel se na monitor. Jako náhrada byla rychlost na vleku a sjezdovce (horizontálně po modelu) násobně zmenšena. Proto se může zdát, že lidé pěšky chodí mnohem rychleji než se pohybují na vleku nebo lyžují.

Samotná kolem procházející cesta a cesta do fronty nejsou pro model vůbec důležité. Důležité je, že do fronty přibývají další lidé, když je fronta krátká. Tyto dvě cesty byly do modelu implementovány kvůli přehlednosti a srozumitelnosti vizualizace.

Jak model používat

 * Nastavit slopeWidth na šířku sjezdovky, pro kterou chceme zjistit optimální rychlost vleku.
 * Nastavit liftCapacity na 0 (lyžaři jsou nabírání okamžitě, nečekají).
 * Stisknout setup a Go
 * V tuto chvíli je vidět, že do skiareálu stále přicházejí další lidé (graf 3), protože fronta je stále krátká.
 * Kvůli kapacitě vleku se lidé začínají hromadit na kopci (graf 2) kvůli vzájemné blokaci (graf 4), což je nežádoucí. Je třeba snížit kapacitu vleku (zvýšit čas po kterém vlek bere další lyžaře)
 * Pomalu zmenšujeme liftCapacity dokud nevidíme, že ubývá lyžařů zaseklých na kopci (graf 2).
 * Vidíme, že nahoře zablokovaných lyžařů ubývá (graf 2), stejně tak jako na sjezdovce (graf 4). Také ale výrazně přibývá lidí ve frontě (graf 5). Až tak že musí stát v lese a nevejdou se na obrazovku.
 * Stiskneme znovu setup
 * Scénář by se měl opakovat, ale vidíme, že na kopci se lidé dlouhodobě nehromadí, protože je správně nastavena kapacita vleku.

Další nastavitelné parametry je možné libovolně měnit podle individuálně vypozorovaných zkušeností a situace. Ovlivňují chování lyžařů na svahu a tím i jejich rychlost překonání sjezdovky a tím hromadění lidí po výstupu z vleku.

= Výsledky =

Postup simulace byl shodný s návodem napsaným výše. Po zjištění optimální kapacity byla simulace spuštěna znovu. Celkem 5x, po dobu 50 000 ticks. Pokud za tuto dobu maximální počet osob zablokovaných na začátku sjezdovky nepřekročil hodnotu 10, bylo zjištěné nastavení kapacity považováno za finální a zaznamenáno.

Toto bylo provedeno pro každý pátý násobek možné šířky sjezdovky. Při tom byly ostatní parametry nastaveny takto:
 * slopeMaxCurve - 45
 * slopeSpeedDeviation - 0,01
 * NewPeopleFrequency - 100
 * maxQueueLength - 34
 * stopChance - 45
 * stopDuration - 2025

Výsledné hodnoty jsou v následující tabulce a grafu napravo.

Je vidět, že maximální kapacita vleku má souvislost se šířkou sjezdovky. Dá se vyjádřit mocninou regresní funkcí Y=376,86x^(-0,788), s hodnotou spolehlivosti R^2=0,9916.

= Závěr =

Zadaný problém se mi podařilo vyřešit. Otázkou je, jestli jsou parametry simulace nastaveny správně, podle skutečnosti. To by šlo zjistit pouze dlouhodobým pozorováním reality, které bohužel není v mých možnostech.

I když ze simulace vyplývají jednoznačná čísla, při pozorování vizualizace je vidět, že sjezdovka bývá při hraniční hodnotě kapacity lanovky značně zalidněná. Model nijak nebere v potaz subjektivní preference lyžařů, kteří by mohli při příliš velké zalidněnosti odcházet. To by mohl být další krok v rozšíření modelu. Spolu s ověřením, zda jsou nastavené parametry shodné s realitou.

= Ke stažení = - Soubor se simulací pro NetLogo

- Soubor pro MS Excel se zaznamenanými výsledky