W ramach zajęć laboratoryjnych pobawimy się dwoma lub trzema projektami, w ramach których zetkniemy się tak z mechaniką i biologią (w pewnym niestandardowym wydaniu). Wszystko oczywiście w cieniu MES, z wykorzystaniem ulubionego programu tj. Ansysa. W tym semestrze zależy mi na tym, aby: - wykorzystać Państwa wiedzę i biegłość w pisaniu procedur w APDLu, - nauczyć Was zabawy w środowisku Ansys Workbench. Wszyscy mieli już do czynienia z APDLem, więc nie przewiduję trudności — tzn. jakby ktoś zapomniał, to zawsze jest do pomocy plik pomocy z komendami. Nie wymagam znajomości wszystkich komend, a jedynie wiedzy gdzie można je znaleźć *w-razie-wu*. Czego nam potrzeba: - [Ansys](https://di.pwr.edu.pl/oprogramowanie/oprogramowanie-ansys), - [Context](https://www.contexteditor.org/ConTEXTv0_986.exe) — edytor APDLa + wtyczka [Ansys Macros](https://www.contexteditor.org/highlighter-files/Ansys.chl) - przeczytaj [[Jak ustawić środowisko Context]], - Word, Writer, GoogleDocs lub jeszcze coś innego do napisania sprawozdania. W pierwszym rzucie zależy mi na projekcie związanym z opracowaniem algorytmu genetycznego — tu będziemy działać w APDLu, napiszemy procedurę, opracujemy wyniki i raport. Detale i garść informacji do tej części zamieszczę poniżej. # Algorytm genetyczny Algorytm genetyczny to sposób postępowania, który prowadzi nas do znalezienia możliwie najlepszego rozwiązania w danej dziedzinie możliwych rozwiązań. Zakładamy zatem, że w obszarze możliwości, jakie mamy — parametrów, jakimi może dysponować nasz obiekt, jest zestaw takich, które czynią go w określonym zadaniu najlepszym z możliwych (maksimum globalne). Obok niego istnieje cała rodzina rozwiązań dobrych i słabych. Oczywiście gdzieś tam jest jeden obiekt, który jest tym najgorszym z możliwych. Mogą istnieć obiekty, których cechy różnią się, czasem znacznie, ale całościowo prezentują podobne dostosowanie do pełnionych funkcji. Naszym celem jest opracowanie algorytmu, który będzie w dziedzinie możliwych rozwiązań poszukiwał tego, które określimy jako optymalne.  ## Zasady działania algorytmu genetycznego Celem programu jest znalezienie optymalnego wariantu struktury, który poddajecie analizie. Wygląda to tak, że do pudełka wrzucamy pewne cechy obiektu, a wyciągamy optymalny (albo bliski optymalnemu) obiekt. Liczba możliwych wariantów jest zwykle wysoka, na tyle duża, że ręczne poszukiwania tracą sens. Z tego powodu algorytm genetyczny jest dobrym rozwiązaniem, ponieważ przeszuka przestrzeń możliwych rozwiązań, wybierając możliwie najlepszy. Na początku na podstawie cech obiektu algorytm stworzy tzw. **populację pierwotną**. Nie wyczerpie ona oczywiście wszystkich wariantów, ale stanowi pierwotne źródło poszukiwań. Podobnie jak kupując samochód — jeśli pojedziemy do salonu z używanymi samochodami, to nie oznacza, że są tam wszystkie warianty i każdy dobry. Być może jednak znajdziemy coś idealnego, a na pewno będziemy w stanie wybrać coś, co spośród tych pojazdów najbardziej nam odpowiada. Nie oznacza to oczywiście zakupu. Populacja pierwotna musi być poddana ocenie — w ten sposób będziemy w stanie wskazać najlepsze jej osobniki. Następnie spośród tych osobników wybierzemy pary osobników, które w procesie tzw. **krzyżowania** stworzą tzw. **populację wtórną**. Prawdopodobieństwo wyboru osobnika jest wprost proporcjonalne do jego oceny. Im lepszy osobnik, tym łatwiej go wylosować. Kiedy uzyskamy populację wtórną, to ona zajmie miejsce populacji pierwotnej. Wówczas cykl powtórzy się w ramach kolejnych iteracji. W efekcie powinniśmy otrzymywać krzyżówki najlepszych osobników i z odpowiednio mniejszym prawdopodobieństwem krzyżówki coraz słabszych osobników. Oczywiście nie możemy być pewni, że w ramach działania naszego algorytmu uzyskamy najlepszy możliwy wariant. Z całą pewnością jednak nasz algorytm będzie dążył do znalezienia najlepszego wariantu w ramach wycinka, jakim jest nasza populacja pierwotna i jej jednostki potomne. Należy jeszcze wspomnieć o mutacjach. Z pewnym niewielkim prawdopodobieństwem, możliwe jest, że powstający osobnik potomny ulegnie **mutacji** — część jego cech ulegnie losowej zmianie lub zamianie na zasadzie inwersji. Mutacje są przydatne, kiedy algorytm ugrzęźnie w lokalnej studni słabych rozwiązań. Istnieje wówczas prawdopodobieństwo, że nowopowstały osobnik wniesie nową jakość do populacji. Jeśli będzie to dobra i pożądana cecha wówczas ma dużą szansę się powielać. Jeśli osobnik jest wciąż słaby, to będzie miał nikłe szanse na przekazanie swoich cech. ![Algorytm genetyczny](badania/dydaktyka/mechanobiologia/images/ag_schemat.png) ## Nasze zadania Jak się to ma do Waszego zadania? 1. Zrobiliście już procedurę, która potrafi narysować Wasz obiekt. 2. Teraz pora na wygenerowanie populacji pierwotnej. Do tabeli zapiszcie dane, których potrzebuje Wasza procedura, aby narysować obiekt. Tabelę najlepiej zapełnić danymi losowo w określonych zakresach. `genotyp(1,i,j) = nint(rand(par1a, par1b))` `genotyp(1,i,j)` - nazwa tabeli na dane, jest to tabela trójwymiarowa (cecha, osobnik, pokolenie). `nint(rand(par1a, par1b))` - parametry, nie wpisujemy wartości na sztywno, ale odwołujemy się przez nazwę parametru W celu odwołania się przez licznik (i,j) powinniście stworzyć **pętlę \*do**. Zajrzyjcie do kodu [gwiazda](https://slowinski.kmim.wm.pwr.edu.pl/uploads/gwiazda.pdf) z mojej strony. Losowe wypełnienie tabeli przeprowadzacie tylko dla pokolenia nr 1. Dalsze pokolenia wypełni już algorytm. Powinniście sprawdzić, czy Wasza procedura za każdym razem poprawnie rysuje obiekt. Innymi słowy, czy działa w obrębie granic zdefiniowanych parametrami. Jak sprawdzić działanie procedury? Jeśli macie już tabelę z danymi, to możecie rysować modele w pętli — narysuj model, skasuj, rysuj następny. Jeśli coś nie zadziała to Ansys z największą radością się posypie. Załóżmy, że procedura działa. Wówczas należy napisać pętlę po osobnikach, która: - zbuduje osobnika na podstawie danych zawartych w tabeli genotyp (wymiary, materiał etc.), - założy warunki brzegowe (takie same dla każdego osobnika) - obliczy i zapisze wskazane parametry, - zrobi obrazek (może się przydać, żeby obejrzeć ewolucję obiektu), - skasuje obiekt. Pętla po osobnikach znajduje się w pętli po pokoleniach... Kiedy kończy się pętla po osobnikach, to musi się jeszcze wykonać kilka operacji, które doprowadzą do powstania populacji wtórnej. Wykona się: - ocena osobników na podstawie ich parametrów (tych zapisanych w genotypie i/lub tych wyliczonych w efekcie analizy) - sortowanie i wyliczenie udziału osobnika w ogólnej puli punktów ⇒ do zbudowania koła fortuny (wektora, z którego będą losowanie osobniki rodzicielskie) Tabela punktacji poszczególnych osobników: | osobnik | punkty | | :-----: | :--------------: | | 1 | 2 | | 2 | 4 | | 3 | 22 | | 4 | 34 | | ... | | | 50 | 2 | | | ∑ - suma punktów | Tabela udziału osobnika w puli punktów — przełoży się na udział w kole fortuny: | osobnik | udział w puli | | :-----: | :-----------: | | 1 | 2/∑ | | 2 | 4/∑ | | 3 | 22/∑ | | 4 | 34/∑ | | ... | | | 50 | 2/∑ | Wygenerowany zostanie wektor koło fortuny: | 1 | 1 | 2 | 2 | 2 | 2 | ... | 50 | 50 | |:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:| w którym liczba pól opisanych numerem danego osobnika jest adekwatna do udziału w globalnej puli punktów. Teraz może odbyć się losowanie osobników rodzicielskich. Procedura zapobiega powtarzaniu się rodziców w obrębie pary (inaczej powstałby klon). Po wyborze rodziców czas na krzyżowanie. Warto zauważyć, że procedura: - pobiera numer wylosowanego rodzica i przepisuje jego cechy do tabeli genotyp, ale do kolejnego pokolenia; w ten sposób osobnik potomny dostaje część cech od jednego osobnika a część od drugiego (nie musi to być po równo, może też być losowo np. 30:70; 40:60; 10:90), - gdy cechy przepiszą się do kolejnego pokolenia, kończy się iteracja po pokoleniach. Zauważcie, że moduły wyboru rodziców, sortowanie i krzyżowanie są w istocie dosyć proste. Efekt WOW polega na tym, że w procedurach tych pojawiają się odwołania do tabel, przez co tylko wygląda to na skomplikowane — sortowanie. ![Sortowanie](sortowanie.jpg) W pętlach po każdym \*do mamy liczniki **lk** i **kk**, a potem można ten fragment przedstawić w taki sposób: ``` jeśli a < a + 1, wtedy cc = a + 1 a + 1 = a a = cc dd = b + 1 b + 1 = b b = dd lub koniec jeśli ``` Tak naprawdę porównujemy tu dwa parametry dwóch osobników w jednym przebiegu iteracji, a i a + 1 oraz b i b + 1, zmienne cc i dd są tylko kontenerami tymczasowymi na jeden z parametrów na czas zamiany. Podobnie rzecz ma się w przypadku **losowania rodziców**. Jest tam tabela **rodzice**. Jest to także trójwymiarowa tablica, ponieważ rodzice każdego osobnika są zapisywanie w ramach każdego pokolenia. Oczywiście możnaby zrobić to ramach tabeli dwuwymiarowej lub nawet bez tabeli w ramach prostych zmiennych, ale w ten sposób jesteśmy w stanie prześledzić rodowód każdego osobnika, gdyby to było potrzebne. Procedura krzyżowania polega na przepisywaniu danych osobników rodzicielskich do osobnika potomnego. Przepisywanie to polega na pobieraniu cech osobników uprzednio wylosowanych i przenoszeniu ich w pola cech osobników następnego pokolenia. W schemacie poniżej osobniki 3 i 4 są tymi, które najczęściej przekazują swoje cechy. Wypełnione w ten sposób pola opisujące cechy osobnika są w kolejnej iteracji odczytywane podczas tworzenia nowych osobników. Cykl ulega powtórzeniu. Jak widać, cały algorytm po rozbiciu na drobne elementy, powinien być łatwiejszy do zrozumienia. Powodzenia!