Implementazione dei metodi di RK su MatLab

Messaggioda astrolabio95 » 03/07/2019, 17:12

Salve a tutti,

Scusate se torno a tediarvi, vorrei proporvi questo nuovo problema.
Nell'ultimo anno il professore ha introdotto questa nuova tipologia di esercizi che riguarda i metodi iterativi e, nella fattispecie, il metodo di Runge-Kutta.

Ad esempio


Immagine


Ho capito più o meno la fisica grazie al libro "Calcolo Scientifico", ma non riesco ad implementare questo metodo su MatLab.
Purtroppo essendo una tipologia nuova non ho nemmeno dei codici, non so proprio dove sbattere la testa.

Grazie a chiunque voglia darmi una mano.
astrolabio95
Junior Member
Junior Member
 
Messaggio: 119 di 296
Iscritto il: 27/11/2015, 19:39

Re: Implementazione dei metodi di RK su MatLab

Messaggioda astrolabio95 » 03/07/2019, 17:23

In particolare, non ho ben compreso se quella ''n'' si riferisce ad un istante di tempo oppure ad un punto del mesh spaziale.



Immagine
astrolabio95
Junior Member
Junior Member
 
Messaggio: 121 di 296
Iscritto il: 27/11/2015, 19:39

Re: Implementazione dei metodi di RK su MatLab

Messaggioda feddy » 03/07/2019, 22:37

Visto che lo shooting ist klar...

Prima cosa: ridurre la ODE ad un sistema di ODEs del prim'ordine.
Poi, $u_n \approx u(t_n)$. E ovviamente con $t_{n+1}$ si intende $t_n+h$, ossia l'istante temporale successivo al tempo $n$.
La "mesh" spaziale qui sarà un semplice "linspace" (visto che il metodo è supposto essere a passo costante) tra $0$ e $L$.

Ora, i metodi Runge-Kutta sono facili da implementare (è un ciclo for), l'unica cosa che **potrebbe** complicare la situazioni è se il metodo è implicito (o semiimplicito): per capirlo, guarda il tableau che hai davanti (e magari apri un testo introduttivo). Chiaramente non è implicito, sarà semiimplicito oppure esplicito. La differenza in un caso oppure nell'altro potrebbe essere che ad ogni passo è richiesta la risoluzione di un sistema non lineare per trovare i nuovi $K_i$, **ma**, visto che la ODE è lineare, anche nel caso di un metodo semiimplicito avrai a che fare con sistemi lineari. In particolare, puoi fattorizzare la matrice di iterazione del metodo una volta per tutte in LU (ad esempio) e risolvere tutti i sistemi con la matrice fattorizzata. Questa cosa può sembrarti in un certo senso "frivola", ma non lo è a mio avviso, visto che con un metodo di shooting ti è richiesto di risolvere più volte lo stesso problema.

Qual è l'ordine di tale metodo? E' A-Stabile?

Per verificare l'implementazione puoi risolverla anche con differenze finite centrate, visto che il problema è molto semplice e ti basta solamente discretizzare la derivata seconda come al solito e il problema risulta (chiamo l'incognita $\varphi =u$ per comodità)

\[ -k \frac{u_{i+1}-2u_i+u_{i-1}}{h^2}+b u_i = 1\]
con $u_1=0$ e la condizione di Neumann al bordo da imporre ad esempio con un nodo fantasma (o anche differenze finite decentrate).
Ultima modifica di feddy il 04/07/2019, 00:34, modificato 1 volta in totale.
Avatar utente
feddy
Moderatore
Moderatore
 
Messaggio: 2532 di 5934
Iscritto il: 26/06/2016, 00:25
Località: SISSA

Re: Implementazione dei metodi di RK su MatLab

Messaggioda feddy » 04/07/2019, 00:31

Nel caso di semplici differenze finite, un rapidissimo codice è questo
Testo nascosto, fai click qui per vederlo
Codice:
k=2;b=1;L=1; %dati
m=500;
h=L/m
x=linspace(0,L,m);
A = toeplitz(sparse([1,2],[1,1],[-2,1]/(h^2),m,1));
A=k*A;
I=speye(m);
%Boundary conditions
A(1,1:2)=[1,0]; %Dirichlet
I(1,1)=0;
I(m,m)=0;
T=[0;-ones(m-2,1);-1+2/h]; %termine noto
A(m,m-1:m)=[2/h^2,-2/h^2-b];%Neumann
u=(A-b*I)\T
plot(x,u,'-o')


L'unica cosa a cui serve prestare un minimo di attenzione è la condizione al bordo di Neumann. In particolare, ho usato un "ghost node" (nodo fantasma auf italiano), cioè

\[ \frac{u_{m+1}-u_{m-1}}{2h} = -1\]

da cui \[ u_{m+1}=u_{m-1}-2h , \quad \star \]

Quindi l'ultima riga dell'equazione discretizzata risulta (**prima** di inserire la condizione al bordo):

\[ k \frac{u_{m+1}-2u_m+u_{m-1} }{h^2} - b u_m =-1 \]

da cui imponendo $(\star)$

\[ k ((\frac{2}{h^2}) u_{m-1} + (-\frac{2}{h^2}-1) u_m) = -1+\frac{2}{h}\]

Una volta imposto questo ho solamente risolto il sistema lineare di matrice $A+bI$ con il classico backslash di MatLab
Avatar utente
feddy
Moderatore
Moderatore
 
Messaggio: 2533 di 5934
Iscritto il: 26/06/2016, 00:25
Località: SISSA

Re: Implementazione dei metodi di RK su MatLab

Messaggioda Raptorista » 04/07/2019, 09:09

Moderatore: Raptorista

@atrolabio: mettere immagini del testo dell'esercizio è vietato quando il testo stesso è facilmente riscrivibile a mano. Evita questo comportamento in futuro, grazie.
Un matematico ha scritto:... come mia nonna che vuole da anni il sistema per vincere al lotto e crede che io, in quanto matematico, sia fallito perché non glielo trovo


Immagine
Avatar utente
Raptorista
Moderatore
Moderatore
 
Messaggio: 5267 di 9616
Iscritto il: 28/09/2008, 19:58

Re: Implementazione dei metodi di RK su MatLab

Messaggioda astrolabio95 » 04/07/2019, 12:14

Raptorista ha scritto:

Moderatore: Raptorista

@atrolabio: mettere immagini del testo dell'esercizio è vietato quando il testo stesso è facilmente riscrivibile a mano. Evita questo comportamento in futuro, grazie.


Chiedo scusa per aver commesso questo errore
astrolabio95
Junior Member
Junior Member
 
Messaggio: 122 di 296
Iscritto il: 27/11/2015, 19:39

Re: Implementazione dei metodi di RK su MatLab

Messaggioda astrolabio95 » 04/07/2019, 12:34

feddy ha scritto:Visto che lo shooting ist klar...

Prima cosa: ridurre la ODE ad un sistema di ODEs del prim'ordine.
Poi, $u_n \approx u(t_n)$. E ovviamente con $t_{n+1}$ si intende $t_n+h$, ossia l'istante temporale successivo al tempo $n$.
La "mesh" spaziale qui sarà un semplice "linspace" (visto che il metodo è supposto essere a passo costante) tra $0$ e $L$.

Ora, i metodi Runge-Kutta sono facili da implementare (è un ciclo for), l'unica cosa che **potrebbe** complicare la situazioni è se il metodo è implicito (o semiimplicito): per capirlo, guarda il tableau che hai davanti (e magari apri un testo introduttivo). Chiaramente non è implicito, sarà semiimplicito oppure esplicito. La differenza in un caso oppure nell'altro potrebbe essere che ad ogni passo è richiesta la risoluzione di un sistema non lineare per trovare i nuovi $K_i$, **ma**, visto che la ODE è lineare, anche nel caso di un metodo semiimplicito avrai a che fare con sistemi lineari. In particolare, puoi fattorizzare la matrice di iterazione del metodo una volta per tutte in LU (ad esempio) e risolvere tutti i sistemi con la matrice fattorizzata. Questa cosa può sembrarti in un certo senso "frivola", ma non lo è a mio avviso, visto che con un metodo di shooting ti è richiesto di risolvere più volte lo stesso problema.

Qual è l'ordine di tale metodo? E' A-Stabile?

Per verificare l'implementazione puoi risolverla anche con differenze finite centrate, visto che il problema è molto semplice e ti basta solamente discretizzare la derivata seconda come al solito e il problema risulta (chiamo l'incognita $\varphi =u$ per comodità)

\[ -k \frac{u_{i+1}-2u_i+u_{i-1}}{h^2}+b u_i = 1\]
con $u_1=0$ e la condizione di Neumann al bordo da imporre ad esempio con un nodo fantasma (o anche differenze finite decentrate).


Ok, sono riuscito ad implementare il metodo di Runge-Kutta utilizzando l'array dato dalla traccia.
Il problema adesso è lo shooting; o meglio, pensavo non fosse un problema ma lo è diventato adesso perché prima ero solito risolvere i problemi con lo shooting attraverso il tool ode45 di MatLab... E chiaramente suppongo che adesso ci voglia un altro approccio.

Cioè mi spiego. Questa è la risoluzione che avrei adottato col tool ode45.

Anzitutto creo una function che generi il mio sistema

Testo nascosto, fai click qui per vederlo
Codice:
function dy = sistema(t,y)

global b k

dy = y(:);

dy(1) = y(2);
dy(2) = (b/k)*y(1)-1/k;

end


Poi creo una function che risolve questo sistema di ODE con il parametro di shooting "s" che viene fuori dal metodo di bisezione.

Testo nascosto, fai click qui per vederlo
Codice:
function f = FunConv (s)

L = 1;
N = 100;
xspan = linspace(0,L,N);

options = odeset ('RelTol', 1e-10, 'AbsTol', 1e-10);

[t,y] = ode45(@sistema, xspan, [0 s], options);

f = y(end,2) + 1;
end


con questo che è, diciamo, il Main

Testo nascosto, fai click qui per vederlo
Codice:
clc; clear;

global b k

b = 1;
k = 0.5;

N = 100;
L = 1;
xspan = linspace(0,L,N);

s_vect = linspace ( -5, 5, 100);

for is=1:length(s_vect)
    s = s_vect(is);
   
    f(is) = FunConv(s);
end

figure(1);
plot (s_vect,f, 'r.-', 'markersize', 8); grid on;
title ('Gli zeri della funzione y(end,2)+1');
xlabel('Parametro s');
ylabel('f = y(end,2)+1');


s1 = 0;
s2 = 2;

ys1 = FunConv(s1);
ys2 = FunConv(s2);

if ys1*ys2 > 0
    error('Ridefinisci i parametri!');
end

ym = 1;
Tol = 1e-12;

while abs(ym) > Tol
    xm = (s1+s2)/2;
    ym = FunConv(xm);
   
    if ym*ys1 < 0
        s2 = xm;
    else
        s1 = xm;
    end
end

disp(['Il valore di s cercato è ', num2str(xm), '.'])

options = odeset('RelTol', 1e-10, 'AbsTol', 1e-10);

[t,y] = ode45(@sistema, xspan, [0 xm], options);

figure(2);
plot (xspan, y(:,1), 'b'); grid on;
title('Soluzione');
xlabel('x');
ylabel('\phi(x)');


Cioè cosa faccio; prima creo un array di parametri "s" in modo tale da passarli alla function FunConv e plottare una funzione che è la funzione differenza tra la derivata prima nota (data dal problema) e quella calcolata col parametro di shooting "s".
Faccio tutto questo per inizializzare il ciclo di shooting, cioè faccio tutto questo per assegnare i due valori iniziali, per poter entrare nel metodo di bisezione in maniera corretta.
Dopodiché eseguo lo shooting, chiamando sempre la funzione FunConv e passandole di volta in volta il parametro s = xm finché non ho che la differenza tra derivata in x = L calcolata con shooting e derivata in x = L nota sia circa pari a zero.

Quindi plotto tutto.

Adesso quello che mi chiedo è posso utilizzare questo ragionamento di base anche per il metodo RK?
astrolabio95
Junior Member
Junior Member
 
Messaggio: 123 di 296
Iscritto il: 27/11/2015, 19:39

Re: Implementazione dei metodi di RK su MatLab

Messaggioda feddy » 04/07/2019, 12:48

Non cambia nulla. L'importante è che tu risolva la tua ODE, e poi applichi la tecnica di shooting. Non cambia l'idea se cambi il metodo per risolvere la tua equazione
Avatar utente
feddy
Moderatore
Moderatore
 
Messaggio: 2534 di 5934
Iscritto il: 26/06/2016, 00:25
Località: SISSA

Re: Implementazione dei metodi di RK su MatLab

Messaggioda astrolabio95 » 04/07/2019, 18:00

feddy ha scritto:Non cambia nulla. L'importante è che tu risolva la tua ODE, e poi applichi la tecnica di shooting. Non cambia l'idea se cambi il metodo per risolvere la tua equazione


Risolto!

Grazie mille, non pensavo di riuscirci!

Posto il codice per chi volesse usufruirne

Testo nascosto, fai click qui per vederlo
Codice:
function K = Kappa(phi)

global k b

K(1) = phi(2);
K(2) = (b/k)*phi(1) - 1/k;

end

function PHI = RK3(x,phi0)

N = length(x);
h = x(2) - x(1);

PHI = nan(N,2);
PHI(1,:) = phi0;

phi = phi0;

for i=2:N
    phi1 = phi;
    K1 = Kappa(phi1);
    phi2 = phi + h/2*K1;
    K2 = Kappa(phi2);
    phi3 = phi + h*(-K1+2*K2);
    K3 = Kappa(phi3);
   
    phi = phi + h*(1/6*K1 + 4/6*K2 + 1/6*K3);
   
    PHI(i,:) = phi;
end


function f = shooting(s)

global b k

b = 1; k = 0.5;

N = 100;
L = 1;
x = linspace (0, L, N);
h = x(2) - x(1);

phi0 = [0,s];

PHI = RK3(x,phi0);

f = PHI(end,2) + 1;
end


clc; clear all; close all;

global b k

b = 1; k = 0.5;

N = 100;
L = 1;
x = linspace (0, L, N);
h = x(2) - x(1);

s_vect = linspace (-10,10,50);

for is = 1:length(s_vect)
    s = s_vect(is);
   
    f(is) = shooting(s);
end

figure(1);
plot (s_vect, f, 'r.--'); grid on;
title('Zeri della funzione differenza');
xlabel('Parametro di shooting');
ylabel('Funzione differenza');

s1 = -2;
s2 = 2;

ys1 = shooting(s1);
ys2 = shooting(s2);

if ys1*ys2 > 0
    disp('Parametri iniziali da rivedere!')
else
    disp('Ok!')
end

ym = 1;
Tol = 1e-10;

while abs(ym) > Tol
   
   xm = (s1+s2)/2;
   ym = shooting(xm);
   
   if ys1*ym < 0
       s2 = xm;
   else
       s1 = xm;
   end
end

disp(['Il parametro di shooting cercato è ', num2str(xm) ,'.'])

phi0 = [0,xm];

PHI = RK3(x,phi0);

figure(2);
plot (x, PHI(1:N,1), 'b'); grid on;
title('Soluzione con RK3 e shooting.');
xlabel('x');
ylabel('\phi(x)');




Ecco la soluzione graficata

Immagine

Grazie a tutti, siete davvero disponibili e molto chiari
astrolabio95
Junior Member
Junior Member
 
Messaggio: 124 di 296
Iscritto il: 27/11/2015, 19:39

Re: Implementazione dei metodi di RK su MatLab

Messaggioda feddy » 04/07/2019, 18:02

Di nulla, hai fatto tutto te! ;)
Avatar utente
feddy
Moderatore
Moderatore
 
Messaggio: 2535 di 5934
Iscritto il: 26/06/2016, 00:25
Località: SISSA


Torna a Analisi Numerica e Ricerca Operativa

Chi c’è in linea

Visitano il forum: Nessuno e 1 ospite