Co jeszcze warto wiedzieć o SNESie?

Nie ma czegoś takiego jak idealny solver równań nieliniowych. Często bywa, że dla uzyskania satysfakcjonującej zbieżności metody typu Newtona należy dobrać odpowiednie parametry "relaksacyjne'', kryteria stopu, czy opcje pracy solvera liniowego. Przyjrzyjmy się zatem rozmaitym opcjom SNESu.

Warianty metody Newtona

Jak wspominaliśmy na samym początku części dotyczącej równań nieliniowych, w PETSc zaimplementowano pewne warianty metody Newtona, globalizujące zbieżność procesu iteracyjnego. Zasadniczo, mamy do wyboru dwa warianty:  line search methods oraz trust region methods, różniące się sposobem "uściślania'' przybliżenia generowanego przez iterację Newtona. W przypadku metod poszukiwania kierunkowego (line search) z grubsza chodzi o to, że przyjmuje się, iż wyliczona poprawka na xn jest co prawda wektorem o dobrym kierunku, ale nie zawsze dobrej długości. W najprostszym wariancie poszukiwania kierunkowego stopniowo zmniejsza się długość wektora poprawki, tak, aby ostatecznie uzyskać zmniejszenie residuum na danym kroku metody Newtona. To nam przynajmniej będzie gwarantowało, że kolejne iteracje metody będą dawały coraz lepsze przybliżenia (w sensie residuum). Więcej na ten temat można dowiedzieć się z Rozdz. 8 interesującej monografii Kelley'a [11]. Metoda trust region jest trochę bardziej skomplikowana i nie będziemy jej tu omawiać, odsyłając zainteresowanych do [13]. Standardowo, w SNESie używany jest wariant qubic line search.

Metody poszukiwania kierunkowego

Ustawiając opcję -snes_type ls decydujemy się na wariant line search, czyli poszukiwania kierunkowego. Wybór czynnika skalującego może być oparty na pewnej interpolacji zachowania się metody w poprzednich iteracjach.

Możemy teraz wybierać stopień wielomianu interpolacyjnego używanego do wyznaczenia lepszego czynnika skalującego: -snes_eq_ls [quadratic,cubic], to znaczy, odpowiednio, funkcją kwadratową lub sześcienną. Więcej szczegółów Czytelnik znajdzie u Kelley'a [11] oraz w [14]. Dodatkowo, możliwy jest także wariant
-snes_eq_ls basic. Taki wybór oznacza rezygnację z techniki line search i pozostanie przy klasycznej metodzie Newtona.

Metody wyszukiwania kierunkowego wymagają ustawienia pewnych parametrów relaksacyjnych,
-snes_eq_ls_alpha <alpha>, -snes_eq_ls_maxstep <max>, -snes_eq_ls_steptol <tol>, gdzie oznaczenia są zgodne z [4]. Na szczęście, predefiniowane wartości tych parametrów są zazwyczaj rozsądne dla wielu zagadnień. 

Parametry stopu

Przy rozwiązywaniu zagadnienia nieliniowego za pomocą SNESu mamy możliwość ustawienia wartości krytycznych dla kilku warunków stopu, a także zdefiniowania własnego kryterium. Standardowo, możemy określić wartości atol, rtol i stol, odpowiedzialnych za stwierdzenie, odpowiednio, spełnienia warunku tolerancji błędu bezwzględnego lub względnego, lub stagnacji:
Te wszystkie parametry, oraz dodatkowo, maksymalną dopuszczalną liczbę iteracji maxits i wywołań F(X), maxfcts, można ustawić poleceniem:

ierr = SNESSetTolerances(SNES snes,double rtol,double atol,double stol, int maxits,int maxfcts);

lub z linii komend: -snes_atol <atol>, -snes_rtol <rtol>, -snes_stol <stol>,
-snes_max_it <maxits> oraz -snes_max_funcs <maxfcts>. 

Inne opcje

Oczywiście, możliwe jest użycie każdej opcji dotyczącej SLESu (solverów liniowych). Będą one uwzględnione w procesie rozwiązywania układów z macierzą jakobianu.

Zmianę opcji SLESu wykorzystywanego przez SNES możemy uzyskać z programu, wyłuskując kontekst SLESu funkcją int SNESGetSLES( SNES MojSnes, SLES * MojSnesSles ) a następnie używając procedur typu SLESGetKSP() lub SLESGetPC(). Naturalnie, to samo uzyskamy podając odpowiednie opcje w linii komend.

Zazwyczaj programy (w początkowym stadium) nie są wolne od błędów. Można się w szczególności obawiać, że zaprogramowana przez nas macierz jakobianu nie jest idealna. Na szczęście, możemy porównać działanie programu z naszą macierzą jakobianu i programu, w którym zostanie użyta jej aproksymacja metodą różnic skończonych. W wypadku, gdy używamy macierzy typu powłokowego, możemy naszą funkcję Jakobian(), realizującą działanie jakobianu, zastąpić jej aproksymacją generowaną wewnętrznie przez PETSc metodą różnic skończonych: wystarczy uruchomić program z opcją -snes_mf. Podobny skutek można uzyskać (ale już tylko dla niepowłokowej macierzy jakobianu) stosując opcję -snes_fd. Nie znamy bliżej różnic między tymi opcjami. Po co stosować te opcje? Na pewno przydadzą się one tym, którzy nie potrafią (lub nie mają czasu) implementować funkcji Jakobian(). Czasem macierz jakobianu może być skomplikowana! Autorzy oficjalnego manuala twierdzą ponadto, że możemy w ten sposób łatwo sprawdzić, czy poprawnie zaimplementowaliśmy jakobian: bo jeśli nie, to, rozwiązując zagadnienie raz z własnym jakobianem, a drugi raz z opcją -snes_mf, powinniśmy dostać istotnie różniące się wyniki. To prawda, ale od razu chcielibyśmy ostrzec wszystkich pesymistów: jeśli postępując w wyżej opisany sposób, rzeczywiście dostaniecie różne wyniki (rozwiązania, liczbę iteracji, itp.) nie wpadajcie w desperację. Jest bardzo prawdopodobne, że po prostu rozwiązujecie swoje zadanie z niedobrymi parametrami! Pamiętajcie, że wyznaczenie aproksymacji jakobianu jest numerycznie bardzo kosztowne (wymaga za każdym razem obliczania wielu wartości Funkcji()) a jednym z ograniczeń ustawianym w SNESie jest właśnie liczba wywołań funkcji!

Śledzenie pracy SNESu

Przebieg procesu iteracyjnego możemy śledzić używając opcji linii komend -snes_xmonitor lub

-snes_monitor.
Rysunek 11: Przebieg zbieżności SNESu, opcja -snes_xmonitor.
Ponadto, każdy SNES posiada (oczywiście!...) swoją przeglądarkę, wyświetlającą parametry wywołania SNESu: int SNESView(SNES snes,Viewer viewer), gdzie, jak zwykle, jako viewer możemy podać VIEWER_STDOUT_WORLD. Z linii komend uzyskamy ten sam efekt podając opcję -snes_view. Oto przykładowy wynik obejrzenia SNESu:
SNES Object:
  method: ls

    line search variant: SNESCubicLineSearch
    alpha=0.0001, maxstep=1e+08, steptol=1e-12
  maximum iterations=50, maximum function evaluations=1000
  tolerances: relative=1e-08, absolute=1e-50, truncation=1e-12, solution=1e-08
  total number of linear solver iterations=13
  total number of function evaluations=6
KSP Object:
  method: gmres
    GMRES: restart=30, using Modified GramSchmidt Orthogonalization
  maximum iterations=10000, initial guess is zero
  tolerances:  relative=1e-05, absolute=1e-50, divergence=10000
  left preconditioning
PC Object:
  method: none
  linear system matrix = precond matrix:
Matrix Object:

  type=MATSHELL, rows=343, cols=343
Nieliniowe zagadnienie różniczkowe w PETSc Spis treści Podsumowanie SNESu
 

Copyright (C) Marcin Bojko i Piotr Krzyzanowski, 1998.
Ostatnia modyfikacja: 12.X.98.