Poniżej przestawiamy wybrane kody źródłowe programów omawianych w pierwszej części podręcznika Obliczenia inżynierskie i naukowe (PWN, 2011). Większość z nich jest dostępna na licencji Creative Commons BY-SA.
Listing 5.1 - invlaplace.m. [Pobierz]
%% %% Listing 5.1 w książce "Obliczenia inżynierskie i naukowe", PWN 2011 %% (C) Piotr Krzyżanowski, 2011 %% %% Możesz używać tego kodu zgodnie z licencją Creative Commons BY-SA, %% zob. http://creativecommons.org/licenses/by-sa/3.0/pl/ %% % skrypt invlaplace.m for i=1:N for j=1:i L(i,j) = j; end for j=i:N L(i,j) = i; end end
Listing 5.2 - invlaplace2.m. [Pobierz]
%% %% Listing 5.2 w książce "Obliczenia inżynierskie i naukowe", PWN 2011 %% (C) Piotr Krzyżanowski, 2011 %% %% Możesz używać tego kodu zgodnie z licencją Creative Commons BY-SA, %% zob. http://creativecommons.org/licenses/by-sa/3.0/pl/ %% % skrypt invlaplace.m - wersja zmodyfikowana L = zeros(N,N); for i=1:N for j=1:i L(i,j) = j; end for j=i:N L(i,j) = i; end end
Listing 5.3 - invlaplace3.m. [Pobierz]
%% %% Listing 5.2 w książce "Obliczenia inżynierskie i naukowe", PWN 2011 %% (C) Piotr Krzyżanowski, 2011 %% %% Możesz używać tego kodu zgodnie z licencją Creative Commons BY-SA, %% zob. http://creativecommons.org/licenses/by-sa/3.0/pl/ %% % skrypt invlaplace.m - wersja działająca na blokach macierzy L = zeros(N,N); for i=1:N L(i,i:N) = L(i:N,i) = i; end
Listing 5.4 - invlap1d.m. [Pobierz]
%% %% Listing 5.4 w książce "Obliczenia inżynierskie i naukowe", PWN 2011 %% (C) Piotr Krzyżanowski, 2011 %% %% Możesz używać tego kodu zgodnie z licencją Creative Commons BY-SA, %% zob. http://creativecommons.org/licenses/by-sa/3.0/pl/ %% function L = invlap1d(N) % funkcja invlap1d - generuje macierz odwrotną do 1-wym laplasjanu % z warunkami Dirichleta z lewego i Neumanna z prawego krańca odcinka % % wywołanie: L = invlap1d(N) % % N - wymiar macierzy % L - macierz odwrotna laplasjanu L = zeros(N,N); for i=1:N L(i,i:N) = L(i:N,i) = i; end end
Listing 5.5 - invlap1dsuper.m. [Pobierz]
%% %% Listing 5.5 w książce "Obliczenia inżynierskie i naukowe", PWN 2011 %% (C) Piotr Krzyżanowski, 2011 %% %% Możesz używać tego kodu zgodnie z licencją Creative Commons BY-SA, %% zob. http://creativecommons.org/licenses/by-sa/3.0/pl/ %% function [L, norma] = invlap1d(N,p) % Funkcja invlap1d - generuje macierz odwrotną do 1-wym laplasjanu % z warunkami Dirichleta z lewego i Neumanna z prawego krańca odcinka % % Wywołanie: % [L, norma] = invlap1d(N, p) % Parametry: % N - rozmiar macierzy % p - jaka norma macierzy (opcjonalnie, domyślnie: 2) % Wyniki: % L - macierz odwrotna laplasjanu % norma - (p)-ta norma macierzy L (opcjonalnie) % obsługa parametrów wejściowych - wartości domyślne if (nargin < 2) p = 2; if (nargin < 1) error('Za mała liczba argumentów'); end end % właściwa treść funkcji L = zeros(N,N); for i=1:N L(i,i:N) = L(i:N,i) = i; end % normę liczymy tylko wtedy, gdy użytkownik jej zażąda if (nargout > 1) norma = norm(L,p); end end
Listing 5.7 - divdif.m. [Pobierz]
%% %% Listing 5.7 w książce "Obliczenia inżynierskie i naukowe", PWN 2011 %% (C) Piotr Krzyżanowski, 2011 %% %% Możesz używać tego kodu zgodnie z licencją Creative Commons BY-SA, %% zob. http://creativecommons.org/licenses/by-sa/3.0/pl/ %% function df = divdif(f, x, h) % % DF = divdif(F, X, H) % % Wyznacza przybliżenie F'(X) ze wzoru (F(X+H)-F(X-H)) / (2H) % Jeśli nie podano H, przyjmuje się H = max(|X|,1)*sqrt(eps). if nargin < 3 h = max(abs(x),1)*sqrt(eps); end f1 = feval(f,x+h); f2 = feval(f,x-h); df = (f1-f2)./(2*h); end
Listing 6.1 - funkcja2d.m. [Pobierz]
%% %% Listing 6.1 w książce "Obliczenia inżynierskie i naukowe", PWN 2011 %% (C) Piotr Krzyżanowski, 2011 %% %% Możesz używać tego kodu zgodnie z licencją Creative Commons BY-SA, %% zob. http://creativecommons.org/licenses/by-sa/3.0/pl/ %% disp('Wizualizacja funkcji 2D'); % definicja funkcji do zwizualizowania: skorzystamy z funkcji anonimowej; % dzięki użyciu operatorów tablicowych, argumenty x,y mogą być macierzami ff = @(x,y) abs(sin(x-1)).^((y+1).^2).*abs(cos((y+1))).^((x-1).^2); % utworzenie siatki na dziedzinie funkcji x = linspace(-3,3,30); % węzły na osi OX y = linspace(-4,4,40); % węzły na osi OY [X,Y] = meshgrid(x,y); % siatka na płaszczyźnie % wyznaczenie wartości ff na siatce Z = ff(X,Y); % wizualizacja: contour(X,Y,Z); % poziomice pause(5); mesh(X,Y,Z); % powierzchnia pause(5); surf(X,Y,Z); % powierzchnia inaczej pause(5); imagesc(X,Y,Z); % mapa axis('xy','square'); pause(5);
Listing 6.2 - stationary.m. [Pobierz]
%% %% Listing 6.2 w książce "Obliczenia inżynierskie i naukowe", PWN 2011 %% (C) Piotr Krzyżanowski, 2011 %% %% Możesz używać tego kodu zgodnie z licencją Creative Commons BY-SA, %% zob. http://creativecommons.org/licenses/by-sa/3.0/pl/ %% clear; delta = 9/7; TOL = 1e-3; % jaką wartość $||F||^2$ uznajemy za "małą"? % Definicja funkcji prawej strony przydatna do zabawy z polem wprost w skrypcie % jest dopuszczalna tylko w Octave: MATLAB wymaga zdefiniowania tej funkcji % w osobnym pliku function [f1, f2, f3] = pole(u1, u2, u3, delta) f1 = 1 - u1 - delta*(u2.^2+u3.^2); f2 = -u2 + delta*u1.*u2; f3 = -u3 + delta*u1.*u3; end % szukamy punktów stacjonarnych w prostokącie $(u_2,u_3)\in [-A,A]\times [-A,A]$... N = 30; A = 0.6; u2 = linspace(-A,A,N); u3 = linspace(-A,A,N); [U2, U3] = meshgrid(u2,u3); % ...i dla u1 = [0.7..0.8] for u1 = linspace(0.7,1.2,50) [F1 F2 F3] = pole(u1, U2, U3, delta); G = double(F1.^2 + F2.^2 + F3.^2 < TOL); % czy znaleźliśmy choć jeden punkt, w którym F jest małe? if max(G(:)) > 0 fprintf(stderr,'Mala norma dla u1 = %g',u1); % MATLAB nie zna stderr... [i, j] = find(G); fprintf(stderr,' i np. (u2,u3) = (%5.3g,%5.3g)\n', ... U2(i(1),j(1)), U3(i(1),j(1))); mesh(U2,U3,G); title(['u1=', num2str(u1)]); pause(1); end end
Listing 6.3 - spyc.m. [Pobierz]
%% %% Listing 6.3 w książce "Obliczenia inżynierskie i naukowe", PWN 2011 %% (C) Piotr Krzyżanowski, 2011 %% %% Możesz używać tego kodu zgodnie z licencją Creative Commons BY-SA, %% zob. http://creativecommons.org/licenses/by-sa/3.0/pl/ %% function spyc(D) if (nnz(D) < 10000) % wybór markera m ='*'; else m ='.'; end if nnz(D>0) spy(D>0, ['r',m]); % wizualizacja dodatnich elementów macierzy D hold on; end if nnz(D<0) spy(D<0, ['b',m]); % wizualizacja ujemnych elementów macierzy D end hold off; end
Listing 7.2 - solvegr.m. [Pobierz]
%% %% Listing 7.2 w książce "Obliczenia inżynierskie i naukowe", PWN 2011 %% (C) Piotr Krzyżanowski, 2011 %% %% Możesz używać tego kodu zgodnie z licencją Creative Commons BY-SA, %% zob. http://creativecommons.org/licenses/by-sa/3.0/pl/ %% function x = solvegr(e, W, D, b, tol, maxit) % % Rozwiazuje (I - e*W*D^{-1})x = (1-e)b % 0 <= e <= 1, % W - symetryczna % D - diagonalna, dod. okresl. if nargin < 5 tol = 1e-8; end if nargin < 6 maxit = 100; end switch e case 0 x = b; case 1 opts.maxit = maxit; opts.tol = tol; k = 16; [V, EV, info] = eigs(W, D, k, 'lm', opts); EV = diag(EV); nof1 = sum(abs(EV-1) < 1e-6); % liczba wartości własnych bliskich "1" if nof1 > 1 warning(['Wykryto ', num2str(nof1), ' wartosci wlasnych bliskich 1']); disp(sort(EV, 'descend')); end [m, i] = max(EV); y = V(:,i); x = D*y; x = x/sum(x); otherwise % 0 < e < 1 DW = @(x) (D*x - e*W*x); b = (1-e)*b; if exist('OCTAVE_VERSION') % Octave [y, flag, relres, iter, resid] = pcr(DW, b, tol, maxit, D); fprintf(stderr, 'PCR: \n'); else % MATLAB [y, flag, relres, iter, resid] = minres(DW, b, tol, maxit, D); stderr = 2; % deskryptor stderr w MATLABie fprintf(stderr, 'MINRES: \n'); end semilogy(abs(resid)); fprintf(stderr, '\tKod zakonczenia: %d\n\tRelRes: %e\n\tIteracji: %d\n', flag, relres, prod(iter)); x = D*y; end end
Listing 7.4 - Hequation.m. [Pobierz]
%% %% Listing 7.4 w książce "Obliczenia inżynierskie i naukowe", PWN 2011 %% (C) Piotr Krzyżanowski, 2011 %% %% Możesz używać tego kodu zgodnie z licencją Creative Commons BY-SA, %% zob. http://creativecommons.org/licenses/by-sa/3.0/pl/ %% function y = Hequation(x) % x może być wektorem lub macierzą global c; global S; y = x - 1.0./(1.0 - c*S*x); end
Listing 7.5 - newton.m. [Pobierz]
%% %% Listing 7.5 w książce "Obliczenia inżynierskie i naukowe", PWN 2011 %% (C) Piotr Krzyżanowski, 2011 %% %% Możesz używać tego kodu zgodnie z licencją Creative Commons BY-SA, %% zob. http://creativecommons.org/licenses/by-sa/3.0/pl/ %% function [x, resid, info, output] = newton(nazwa_f, x0, atol, rtol, step, maxit) % % [x, resid, info, output] = newton(nazwa_f, x0, atol, rtol, step, maxit) % % Rozwiązuje układ równań nieliniowych F(x) = 0, gdzie F jest zadana M-funkcją o % nazwie "nazwa_f". % Parametry wejścia: % nazwa_f - nazwa M-funkcji zadającej funkcję F(). % Ta funkcja *musi* przyjmować także argumenty macierzowe! % x0 - przybliżenie początkowe rozwiązania % atol, rtol - tolerancja błędu residualnego % step - co ile iteracji uaktualniać macierz pochodnej; % step = 1 daje standardową metodę Newtona, % step > maxit daje metodę cięciw % maxit - maksymalna dopuszczalna liczba iteracji % Wyjście: % x - końcowe przybliżenie rozwiązania % resid - wektor zawierający historię zbieżnosci, % resid(i) - wartość normy residuum w i-tej iteracji % info - kod zakończenia: = 1 - sukces, = 0 - przekroczona maxit % output - struktura zawierająca statystyki % kilka pomocniczych definicji epsq = sqrt(eps); % pierwiastek z podwojonej precyzji maszyny unit = ones(size(x0)); % wektor złożony z samych jedynek % początkowe rozwiązanie przybliżone x = x0; % wyznaczenie residuum początkowego fx = feval(nazwa_f, x); iter = 1; resid(iter) = norm(fx); while( (resid(iter) >= (atol + rtol*resid(1))) & (iter < maxit) ) if (mod(iter-1, step) == 0) % aproksymacja pochodnej - wszystkie kolumny jednocześnie h = epsq*max(abs(x),unit); xh = x*unit' + diag(h); Df = (feval(nazwa_f, xh) - fx*unit')./(unit*h'); % rozkład macierzy pochodnej do wykorzystania [L, U, p] = lu(Df, 'vector'); end % poprawka przybliżonego rozwiązania, x = x - Df\fx; x = x - U\(L\fx(p)); % wyznaczenie residuum fx = feval(nazwa_f, x); iter = iter + 1; resid(iter) = norm(fx); end info = ~(iter == maxit); output.iterations = iter - 1; end
Listing 7.7 - solvevdw.m. [Pobierz]
%% %% Listing 7.7 w książce "Obliczenia inżynierskie i naukowe", PWN 2011 %% (C) Piotr Krzyżanowski, 2011 %% %% Możesz używać tego kodu zgodnie z licencją Creative Commons BY-SA, %% zob. http://creativecommons.org/licenses/by-sa/3.0/pl/ %% R = physical_constant('MOLAR_GAS_CONSTANT'); % tylko Octave-forge; % w MATLAB-ie wpiszemy R = 8.314472; a = 0.3640e-12; % stałe dla ditlenku węgla b = 42.67e-6; T = 303; % temperatura P = 1.0133e5; % ciśnienie N = 0.22722; % liczba moli gazu V0 = N*R*T/P % objetosc gazu idealnego z rownania Clapeyrona vdw = @(V) (P+(N^2*a)./(V.^2)).*(V-N*b)-N*R*T; [V, FV, info, output, fjac] = fsolve(vdw, V0) %{ % wariant z fzero [V, FV, info, output] = fzero(vdw, V0); % wariant z wyznaczeniem miejsc zerowych wielomianu polyvdw = [P, -N*(b*P+R*T), N^2*a, -N^3*a*b]; V = roots(polyvdw) %}
Listing 7.9 - vanderpoleps.m. [Pobierz]
%% %% Listing 7.9 w książce "Obliczenia inżynierskie i naukowe", PWN 2011 %% (C) Piotr Krzyżanowski, 2011 %% %% Możesz używać tego kodu zgodnie z licencją Creative Commons BY-SA, %% zob. http://creativecommons.org/licenses/by-sa/3.0/pl/ %% function dY = vanderpoleps(t, Y, epsilon) dY = [Y(2); ... epsilon*(1-Y(1)^2)*Y(2) - Y(1)]; end
Listing 7.10 - vanderpoltest.m. [Pobierz]
%% %% Listing 7.10 w książce "Obliczenia inżynierskie i naukowe", PWN 2011 %% (C) Piotr Krzyżanowski, 2011 %% %% Możesz używać tego kodu zgodnie z licencją Creative Commons BY-SA, %% zob. http://creativecommons.org/licenses/by-sa/3.0/pl/ %% % oscylator Van der Pola % parametry zadania epsilon = 0.8; Tmin = 0; Tmax = 60; Y0 = [0.01; 0]; % warunek początkowy % t - zestaw $N$ punktów, w których chcemy wyznaczyć rozwiązanie y na przedziale [Tmin, Tmax] N = 1000; t = linspace (Tmin, Tmax, N); % rozwiąż! Y - tablica wartości rozwiązania w punktach t if exist('OCTAVE_VERSION') % wersja dla Octave vanderpol = @(Y,t) vanderpoleps(t,Y,epsilon); [Y, info, msg] = lsode(vanderpol, Y0, t); if (info ~= 2) disp(['Problemy w dzialaniu lsode: ', msg]); end else % wersja dla MATLAB-a vanderpol = @(t,Y) vanderpoleps(t,Y,epsilon); [t, Y] = ode45(vanderpol, t, Y0); end % wizualizacja i zapis wykresów do pliku filename = ['vanderpol', 'T-', num2str(Tmax,'%g'), ... 'epsilon-', num2str(epsilon,'%g')]; % główny człon nazwy pliku plot(t, Y(:,1)); % wykres rozwiązania $y(t)$ title('Oscylator Van der Pola'); xlabel('czas (t)'); legend('y(t)'); print('-depsc', [filename, '-sol.eps']); input('Nacisnij dowolny klawisz...'); % czekaj na naciśnięcie klawisza! plot(Y(:,1), Y(:,2)); % wykres fazowy rozwiązania $(y(t),y'(t))$ title('Krzywa fazowa oscylatora Van der Pola'); xlabel('y_1(t)'); ylabel('y_2(t)'); print('-depsc', [filename, '-phase.eps']);
Listing 7.11 - lorenztest.m. [Pobierz]
%% %% Listing 7.11 w książce "Obliczenia inżynierskie i naukowe", PWN 2011 %% (C) Piotr Krzyżanowski, 2011 %% %% Możesz używać tego kodu zgodnie z licencją Creative Commons BY-SA, %% zob. http://creativecommons.org/licenses/by-sa/3.0/pl/ %% % rozwiązanie równania Lorenza sigma = 10; r = 28; b = 8/3; % t - zestaw punktów, w których chcemy wyznaczyć rozwiązanie y % na przedziale [0,T] T = 200; N = 10000; % wybieramy bardzo dużo punktów, by mieć lepszą wizualizację skomplikowanego rozwiązania t = linspace (0, T, N); % y0 - warunek początkowy y0 = [0.01; 0; 0]; % rozwiąż! y - tablica wartości rozwiązania w punktach t if exist('OCTAVE_VERSION') % wersja dla Octave [y, info, msg] = lsode( @(y,t)(lorenz(t,y,sigma,r,b)), y0, t); msg else % wersja dla MATLABa [t, y] = ode15s( @(t,y)(lorenz(t,y,sigma,r,b)), y0, t); end % wizualizacja i zapis do pliku plot(y(:,1), y(:,2), 'r-'); title('Rozwiazanie modelu Lorenza: rzut 2D'); xlabel('x(t)'); ylabel('y(t)'); print('-depsc', 'lorenz2d.eps'); plot3(y(:,1), y(:,2), y(:,3), 'b-'); title('Rozwiazanie modelu Lorenza: rzut 3D'); xlabel('x(t)'); ylabel('y(t)'); zlabel('z(t)'); print('-depsc', 'lorenz3d.eps');
Listing 7.12 - lorenz.m. [Pobierz]
%% %% Listing 7.12 w książce "Obliczenia inżynierskie i naukowe", PWN 2011 %% (C) Piotr Krzyżanowski, 2011 %% %% Możesz używać tego kodu zgodnie z licencją Creative Commons BY-SA, %% zob. http://creativecommons.org/licenses/by-sa/3.0/pl/ %% function ydot = lorenz(t,y,sigma,r,b) ydot = [sigma*(y(2)-y(1)); ... -y(1)*y(3) + r*y(1)-y(2); ... y(1)*y(2) - b*y(3)]; end
Listing 7.13 - cvrdrhs.m. [Pobierz]
%% %% Listing 7.13 w książce "Obliczenia inżynierskie i naukowe", PWN 2011 %% (C) Piotr Krzyżanowski, 2011 %% %% Możesz używać tego kodu zgodnie z licencją Creative Commons BY-SA, %% zob. http://creativecommons.org/licenses/by-sa/3.0/pl/ %% function [du, flag, data] = cvrdrhs(t, u, data) global Lap2D; global beta; du = -beta*(Lap2D*u) + u - u.^3; flag = 0; end
Listing 7.14 - lap1ddset.m. [Pobierz]
%% %% Listing 7.14 w książce "Obliczenia inżynierskie i naukowe", PWN 2011 %% (C) Piotr Krzyżanowski, 2011 %% %% Możesz używać tego kodu zgodnie z licencją Creative Commons BY-SA, %% zob. http://creativecommons.org/licenses/by-sa/3.0/pl/ %% function L = lap1ddset(N, h) % tworzy macierz rzadką, odpowiadajacą macierzy % (minus!) jednowymiarowego laplasjanu, z zerowym warunkiem Dirichleta % N - liczba węzłów wewnętrznych, h - krok siatki ii = [1:N, 2:N, 1:N-1]; jj = [1:N, 1:N-1, 2:N]; vv = [2*ones(1,N), -ones(1,2*(N-1))]/(h^2); L = sparse(ii,jj,vv,N,N); end
Listing 7.15 - cvrunrd.m. [Pobierz]
%% %% Listing 7.15 w książce "Obliczenia inżynierskie i naukowe", PWN 2011 %% (C) Piotr Krzyżanowski, 2011 %% %% Możesz używać tego kodu zgodnie z licencją Creative Commons BY-SA, %% zob. http://creativecommons.org/licenses/by-sa/3.0/pl/ %% % Należy odkomentować linię z oznaczeniem wybranej metody SOLVER = 'CVODES'; % MATLAB/OCTAVE, o ile zainstalowano sundialsTB % SOLVER = 'ODE15S'; % tylko MATLAB % SOLVER = 'ODE5R'; % tylko Octave if ~exist('OCTAVE_VERSION') % MATLAB stderr = 2; stb = '/home/przykry/Matlab/sundialsTB'; else % Octave stb = '/home/przykry/Octave/sundialsTB'; end addpath(stb); startup_STB(stb); % inicjalizacja sundialsTB global Lap2D; global beta; %------------------------ % PARAMETRY i PODSTAWOWE OBIEKTY %------------------------ % parametry zadania a = 1; b = 1; % rozmiary obszaru $\Omega$ Tmin = 0.0; Tmax = 15.0; % długość przedziału czasowego beta = 5e-4; % współczynnik dyfuzji % parametry dyskretyzacji przestrzennej Nx = 266; Ny = 267; % wewnętrzne węzły siatki NEQ = Nx*Ny; % rozmiar zadania hx = a/(Nx+1); hy = b/(Ny+1); % rozmiar oczka siatki xx = hx*[1:Nx]'; yy = hy*[1:Ny]'; % współrzędne węzłów dyskretyzacji % dyskretny operator dyfuzji Lap1Dx = lap1ddset(Nx, hx); Ix = speye(Nx, Nx); Lap1Dy = lap1ddset(Ny, hy); Iy = speye(Ny, Ny); Lap2D = kron(Iy, Lap1Dx) + kron(Lap1Dy, Ix); clear Lap1Dx; clear Lap1Dy; %------------------------ % DANE POCZĄTKOWE %------------------------ u0 = zeros(Nx,Ny); % dane początkowe wczytujemy z pliku w formacie row-major-order (jak w OpenDX) u0datNx = 256; u0datNy = u0datNx; u0dat = load(['cvrd-N', num2str(u0datNx), '-step0.txt']); u0dat = permute(u0dat,[2 1]); % indeks wiersza ma odpowiadać współrzędnej OX mNx = min(Nx,u0datNx); mNy = min(Ny,u0datNy); u0(1:mNx,1:mNy) = u0dat(1:mNx,1:mNy); % musimy "rozprostować" wektor tak, by mogły na nim działać solvery ODE u0 = u0(:); %------------------------ % PARAMETRY PRACY SOLVERA %------------------------ % toleracja błędu rtol = 1.0e-5; atol = 1.0e-6; switch SOLVER case 'CVODES' data.P = []; % przestrzeń robocza options = CVodeSetOptions('UserData', data, 'RelTol', rtol, 'AbsTol', atol, 'LinearSolver', 'GMRES'); CVodeInit(@cvrdrhs, 'BDF', 'Newton', Tmin, u0, options); case {'ODE15S', 'ODE5R'} options = odeset('AbsTol', atol, 'RelTol', rtol, 'JPattern', (Lap2D ~= 0), 'Stats', 'on'); otherwise error('Wybrano nieznana metode'); end %------------------------ % ROZWIĄZANIE RÓWNANIA RÓŻNICZKOWEGO %------------------------ nout = 100; T = linspace(Tmin, Tmax, nout+1); % chwile, w których chcemy poznać rozwiązanie U = zeros(nout+1, NEQ); % tablica na zapisanie wartości rozwiązania w chwilach T U(1,:) = u0'; % profil początkowy fprintf(stderr,'Start symulacji\n'); tic; switch SOLVER case 'CVODES' for i = 2:nout+1 tout = T(i); [status,t,u] = CVode(tout,'Normal'); U(i,:) = u'; T(i) = t; si = CVodeGetStats; fprintf(stderr, 'status = %d t = %.2e nst = %d q = %d h = %.2e\n', ... status, t, si.nst, si.qlast, si.hlast); end CVodeFree; case 'ODE15S' [T, U] = ode15s(@cvrdrhs, T, u0, options); case 'ODE5R' [T, U] = ode5r(@cvrdrhs, [Tmin, Tmax], u0, options); nout = length(T)-1; end wct = toc; % pomiar czasu działania solvera %------------------------ % ZAPIS lub WIZUALIZACJA WYNIKÓW %------------------------ fprintf(stderr,'Czas obliczen: %g (s)\n', wct); filename = [lower(SOLVER),'-',num2str(Nx),'x',num2str(Ny),'-step']; for i = 1:nout+1 % animacja rozwiązania w czasie t = T(i); u = reshape(U(i,:),Nx,Ny); imagesc(xx,yy,u); axis('xy', 'square'); title(['t = ',num2str(t)]); if (i == 1) || (i == nout+1) colorbar('EastOutside'); print('-depsc',[filename,num2str(i-1),'.eps']); end pause(0.1); end
Listing 8.1 - brus.m. [Pobierz]
%% %% Listing 8.1 w książce "Obliczenia inżynierskie i naukowe", PWN 2011 %% (C) Piotr Krzyżanowski, 2011 %% %% Możesz używać tego kodu zgodnie z licencją Creative Commons BY-SA, %% zob. http://creativecommons.org/licenses/by-sa/3.0/pl/ %% function dx = brus(x, t) dx = [1+x(1)^2*x(2)-4*x(1); ... 3*x(1)-x(1)^2*x(2)]; end
Listing 8.2 - brusselator.cc. [Pobierz]
/* ** ** Listing 8.2 w książce "Obliczenia inżynierskie i naukowe", PWN 2011 ** (C) Piotr Krzyżanowski, 2011 ** ** Możesz używać tego kodu zgodnie z licencją Creative Commons BY-SA, ** zob. http://creativecommons.org/licenses/by-sa/3.0/pl/ ** */ /* Moduł Octave */ /* kompilacja: mkoctfile brusselator.cc */ #include <octave/oct.h> DEFUN_DLD (brusselator, args, , "Funkcja prawej strony brusselatora") { ColumnVector dx(2); ColumnVector x = (ColumnVector) args(0).vector_value(); dx(0) = 1.0 + x(0)*x(0)*x(1) - 4.0*x(0); dx(1) = 3.0*x(0) - x(0)*x(0)*x(1); return octave_value (dx); }
Listing 8.4 - brusselator.c. [Pobierz]
/* ** ** Listing 8.4 w książce "Obliczenia inżynierskie i naukowe", PWN 2011 ** (C) Piotr Krzyżanowski, 2011 ** ** Możesz używać tego kodu zgodnie z licencją Creative Commons BY-SA, ** zob. http://creativecommons.org/licenses/by-sa/3.0/pl/ ** */ /* brusselator - wersja MEX */ #include "mex.h" void mexFunction( int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[] ) { double *T; /* wskaźnik do skalara wejściowego */ double *X; /* wektor wejściowy */ double *dX; /* wektor wyjściowy, F(x) */ /* Check for proper number of arguments. */ if(nrhs!=2) { mexErrMsgTxt("Wymagane parametry: T (skalar) i X (wektor kolumnowy o 2 wspolrzednych"); } else if(nlhs>1) { mexErrMsgTxt("Funkcja zwraca tylko jeden wynik"); } /* Create matrix for the return argument. */ plhs[0] = mxCreateDoubleMatrix(2,1, mxREAL); /* Assign values/pointers to each input and output. */ T = mxGetPr(prhs[0]); X = mxGetPr(prhs[1]); dX = mxGetPr(plhs[0]); dX[0] = 1.0 + X[0]*X[0]*X[1] - 4.0*X[0]; dX[1] = 3.0*X[0] - X[0]*X[0]*X[1]; }