POLITECNICO DI MILANO Corso di Studi in Ingegneria Matematica PROGETTO PER IL CORSO DI PROGRAMMAZIONE AVANZATA PER IL CALCOLO SCIENTIFICO E DI ANALISI NUMERICA DELLE EQUAZIONI A DERIVATE PARZIALI 2 ANNO ACCADEMICO 2006-2007 Prof. Luca Formaggia Prof. Alfio Quarteroni ELEMENTI SPETTRALI DISCONTINUI PER EQUAZIONI DI TRASPORTO-REAZIONE Bianchessi Andrea Matr. 680531 Pischiutta Matteo Matr. 680203 Indice 1 Approssimazione con metodi spettrali 3 2 Metodo agli elementi spettrali discontinui 4 3 Discretizzazione temporale 6 4 Analisi del Metodo ad Elementi Spettrali Discontinui 4.1 Errori di interpolazione . . . . . . . . . . . . . . . . . . . . . . . . . . 4.2 Stima a priori dell’errore . . . . . . . . . . . . . . . . . . . . . . . . . 9 12 13 5 Integrazione Numerica Gaussiana 5.1 La classe FunzioniBase . . . . . . . . . . . . . . . . . . . . . . . . . . 5.2 La classe Elementi . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 19 20 6 Formulazioni algebriche 6.1 Formulazione algebrica del metodo G-NI . 6.2 Formulazione algebrica del metodo SDG-NI 6.3 La classe Problema . . . . . . . . . . . . . 6.4 Inserimento dei dati del problema . . . . . . . . . 21 21 23 24 25 7 Risoluzione del problema: la classe Tempo 7.1 Libreria di algebra lineare . . . . . . . . . . . . . . . . . . . . . . . . . 26 27 8 Installazione e uso 27 9 Risultati 9.1 Integrazione numerica . . . . . . . . . . . . . . . . . . . . . . . . . . 9.2 Caso stazionario . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9.3 Caso non stazionario . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 28 29 31 10 Una possibile applicazione: dinamica delle popolazioni 33 11 Conclusioni 39 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Introduzione Questo lavoro ha come obiettivo la realizzazione di un codice scritto in C++ per la risoluzione di problemi differenziali monodimensionali di trasporto-reazione del tipo ∂u + (βu)0 + γu = f ∂t con u(x, t) incognita del problema e β(x, t), γ(x, t) ed f (x, t) funzioni assegnate. Proponiamo uno schema di discretizzazione spaziale di tipo ad elementi spettrali discontinui, mentre per la discretizzazione temporale scegliamo schemi di avanzamento sia impliciti che espliciti. Confrontiamo le prestazioni del codice al variare dei parametri di discretizzazione spaziale (numero di elementi M e grado locale dei polinomi N) testandolo su casi dalla soluzione nota. In particolare confrontiamo gli ordini di convergenza del metodo con quelli proposti in letteratura [4]. Infine, proponiamo l’utilizzo del codice per la soluzione del modello di dinamica delle popolazioni di Lotka-McKendrick. 2 Analisi Numerica per le EDP II In questa parte analizzeremo l’approssimazione di problemi iperbolici lineari monodimensionali con metodi spettrali. Tratteremo dapprima il caso di un singolo intervallo, poi passeremo al metodo applicato ad una decomposizione del dominio in sottointervalli; in particolare analizzeremo il caso in cui lo spazio di ambientazione del problema sia formato da polinomi discontinui tra un intervallo e l’altro. Questa scelta è motivata dal fatto che le soluzioni di problemi iperbolici possono presentare discontinuità. Nella parte finale analizzeremo schemi di avanzamento in tempo per il problema in esame. 1 Approssimazione con metodi spettrali In un primo momento, introduciamo il problema di trasporto-reazione monodimensionale: ½ Lu := (βu)0 + γu = f −1 < x < 1 (1.1) u|x=−1 = ϕ dove u(x) è l’incognita del problema, β(x) > 0 e γ(x) ≥ 0 sono due funzioni assegnate e ϕ è un valore assegnato detto dato di inflow. Moltiplicando i termini del problema per una funzione v ∈ V , dove V è uno spazio funzionale appropriato, ad esempio V ≡ H 1 (−1, 1), integrando sull’intervallo [−1, 1] e applicando infine la formula di integrazione per parti dove necessario otteniamo la formulazione debole del problema: Z 1 Z 1 0 Trovare u ∈ V tale che: − βuv + γuv + βuv|x=1 = −1 −1 Z 1 = f v + βϕv|x=−1 ∀v ∈ V (1.2) −1 Scegliamo di approssimare lo spazio V con uno spazio VN = PN , dove PN è lo spazio dei polinomi a coefficienti reali di grado minore o uguale a N . Sia quindi uN ∈ VN l’approssimazione di u, il metodo di Galerkin spettrale (MS) consiste nel: Z 1 Z 1 0 Trovare uN ∈ VN tale che: − βuN vN + γuN vN + βuN vN |x=1 = −1 −1 Z 1 = f vN + βϕvN |x=−1 ∀vN ∈ VN (1.3) −1 3 Scegliamo infine di approssimare gli integrali presenti nella (1.3) con formule di integrazione numerica discusse nella Sezione 5 del tipo Z 1 f g dx = −1 N X αi f (xi )g(xi ) = (f, g)N i=0 per ottenere così il metodo di Galerkin spettrale con integrazione numerica (G-NI) Trovare u∗N ∈ VN tale che: 0 )N + (γu∗N , vN )N + βu∗N vN |x=1 = − (βu∗N , vN = (f, vN )N + βϕvN |x=−1 ∀vN ∈ VN (1.4) Le formulazioni (1.2)-(1.3) e (1.4) si basano sul principio di imporre debolmente le condizioni al contorno. Nel caso ϕ = 0 un’imposizione forte della condizione al contorno sarebbe stata quella di richiedere allo spazio di appartenenza della soluzione di soddisfare le condizioni al contorno, ovvero scegliere lo spazio V = {v ∈ H 1 (−1, 1) : v(−1) = 0} e di conseguenza lo spazio VN = {vN ∈ PN : vN (−1) = 0}. Nella nostra trattazione non faremo mai riferimento all’imposizione forte delle condizioni al contorno poichè l’imposizione debole risulta molto più appropriata in vista di una discretizzazione di tipo elementi spettrali discontinui. 2 Metodo agli elementi spettrali discontinui Consideriamo il problema di trasporto reazione monodimensionale ½ Lu := (βu)0 + γu = f a<x<b u|x=a = ϕ (2.1) analogo del problema (1.1) però con estremi del domino generici. Suddividiamo il dominio Ω = [a, b] in un insieme di M ≥ 2 intervalli disgiunti, detti elementi, Ωm = (x̄m−1 , x̄m ), m = 1, . . . , M , di lunghezza hm = x̄m − x̄m−1 , che soddisfino a = x̄0 < x̄1 < . . . < x̄M = b. Sia h = max{hm } e approssimiamo (2.1) proiettando l’equazione differenziale su uno spazio di funzioni che siano polinomiali su ogni elemento WN,M = {u ∈ L2 (a, b) : v|Ωm ∈ PNm , ∀ m = 1, . . . , M } (2.2) Si noti che non abbiamo imposto alcuna condizione di continuità negli estremi {x̄i }. Moltiplicando l’equazione differenziale per vδ ∈ WN,M ed integrando sull’intervallo 4 [a, b] otteniamo l’approssimazione del problema (2.1): Trovare uδ ∈ WN,M tale che: M n o X (m) 0 (m) − (m)− − + (m)+ + −(βuδ , vδ )Ωm + (γuδ , vδ )Ωm + β uδ vδ |x̄m − β uδ vδ |x̄m−1 m=1 = M X ∀vδ ∈ WN,M (2.3) (f, vδ )Ωm m=1 (m) dove uδ rappresenta la restrizione di uδ sull’elemento Ωm , mentre se vδ è una funzione discontinua in x̄m , vδ− (x̄m ) e vδ+ (x̄m ) sono il sono il suo valore sinistro e destro rispetti(1) vamente. D’ora in avanti è sottointeso che il termine uδ (x̄0 ) = ϕ. L’idea alla base di questo procedimento è quella di riprodurre il metodo di Galerkin spettrale su ogni elemento e di usare il trattamento debole delle condizioni al contor(m)+ no per imporre la continuità: nella (2.3) sostituiamo allora il termine uδ (x̄m−1 ) con (m−1)− uδ (x̄m−1 ) ad ogni punto di interfaccia interno x̄m , m = 1, . . . , M − 1. Fino a questo momento vale la notazione Z x̄m (u, v)Ωm = uvdx x̄m−1 parliamo quindi di metodo di Galerkin agli elementi spettrali discontinui (SDG method). Sostituiamo in ogni elemento quest’integrale con la formula di quadratura di GaussLobatto sull’intervallo (x̄m−1 , x̄m ) 1 : (u, v)Ωm ' (u, v)Nm ,Ωm = N X αj u(xj )v(xj ) (2.6) j=0 1 Integrazione numerica su un intervallo generico Rb Supponiamo di voler approssimare a f (x)dx con una formula di quadratura Gaussiana univocamente determinata da nodi x̂j e pesi α̂j sull’intervallo (−1, 1). Se F è una funzione che mappa l’intervallo (−1, 1) nell’intervallo (a, b), definendo fˆ(x̂) = f (F (x̂)) = f (x) abbiamo Z Z b 1 f (x)dx = a fˆ(x̂)F 0 (x̂)dx̂ ' −1 b f (x)dx ' a N X αj f (xj ) fˆ(x̂j )F 0 (x̂j )α̂j (2.4) j=0 Se scegliamo la trasformazione lineare F (x) = Z N X con b−a 2 x + a+b 2 , xj = j=0 5 la formula di quadratura diventa: b−a a+b x̂j + , 2 2 αj = b−a α̂j 2 (2.5) ottenendo così il metodo di Galerkin agli elementi spettrali discontinui con integrazione numerica (SDG-NI method): Trovare uδ ∈ WN,M tale che: M n X (m) (m) (m)− − vδ |x̄m −(βuδ , vδ0 )Nm ,Ωm + (γuδ , vδ )Nm ,Ωm + β − uδ (m−1)− + vδ |x̄m−1 − β + uδ o m=1 = M X (f, vδ )Nm ,Ωm ∀vδ ∈ WN,M m=1 (2.7) Dato che anche le vδ sono discontinue, possiamo ridurre il problema (2.7) ad un insieme di M relazioni ognuna valida sull’m-esimo elemento: (m) Per m = 1, . . . , M , trovare uδ ∈ PNm (Ωm ) tale che: (m) (m) (m)− − vδ |x̄m −(βuδ , vδ0 )Nm ,Ωm + (γuδ , vδ )Nm ,Ωm + β − uδ (m−1)− + vδ |x̄m−1 = β + uδ + (f, vδ )Nm ,Ωm ∀vδ ∈ PN m (Ωm ) (2.8) dove ora è evidente l’analogia con la formulazione G-NI (1.4): ora per l’elemento Ωm (m−1)− il dato uδ ha il ruolo di dato di inflow nel punto x̄m−1 , così come ϕ aveva il ruolo di dato di inflow nel punto x = −1 nel problema (1.4). 3 Discretizzazione temporale Consideriamo ora il problema ∂u + (βu)0 + γu = f ∂t u(x, 0) = u0 (x) u(a, t) = ϕ(t) t > 0, a < x < b (3.1) a≤x≤b t>0 dove β = β(x, t) > 0 e γ = γ(x, t) ≥ 0 sono due funzioni assegnate, f = f (x, t), u0 (x) e ϕ(t) sono funzioni regolari. L’approssimazione SDG-NI del problema (3.1) è la seguente: ∀t > 0, trovare uδ (t) ∈ WN,M tale che: ! à M n M (m) X X ∂uδ (m) (m) + −(βuδ , vδ0 )Ωm ,Nm , +(γuδ , vδ )Ωm ,Nm + , vδ ∂t m=1 m=1 Ωm ,Nm (m)− +β − uδ vδ− |x̄m − (m)+ β + uδ vδ+ |x̄m−1 o = M X (f, vδ )Ωm ,Nm m=1 6 ∀vδ ∈ WN,M (3.2) con le stesse notazioni introdotte per la (2.3). Per ogni t > 0, la formulazione algebrica della (3.2) è: M d uδ (t) + K(t)uδ (t) = b(t) dt uδ (0) = u0δ (3.3) dove K e b sono la matrice di rigidezza e il termine noto del tutto equivalenti a quelli introdotti nella (6.15), eccetto che ora hanno coefficienti dipendenti dal tempo ed M è la matrice di massa M = (mij ): mij = M X (m) (ψi (m) , ψj )Ωm ,Nm m=1 che, avendo scelto la formula di Gauss-Lobatto per approssimare gli integrali e le funzioni caratteristiche nei nodi di Gauss-Lobatto come base per WN,M , diventa: mij = M X Nm X (m) (m) (m) (m) (m) αk ψi (xk )ψj (xk ) = M X Nm X (m) αk δik δjk m=1 k=0 m=1 k=0 ovvero una matrice diagonale con coefficienti uguali ai pesi di integrazione della formula di Gauss-Lobatto nei nodi corrispondenti. Scegliamo ora di discretizzare l’asse temporale t > 0 tramite una successione di istanti temporali {tn : tn = n · ∆t} e di approssimare il termine di derivata temporale con un rapporto incrementale: d uδ n+1 − uδ n uδ (t) ' dt ∆t Se ad ogni passo scegliamo di valutare i termini K(t)uδ (t) e b(t) nell’istante temporale tn+1 otteniamo metodi impliciti: il più noto è il metodo di Eulero implicito che ha la seguente formulazione: uδ n+1 − uδ n + K n+1 uδ n+1 = bn+1 ∆t M n M + K n+1 )uδ n+1 = bn+1 + uδ ( (3.4) ∆t ∆t che ripaga l’onere computazionale richiesto dalla risoluzione del sistema lineare di matrice (M/∆t + K n+1 ) con un’assoluta stabilità indipendente dal ∆t scelto. Qualora scegliessimo di valutare i termini della formulazione algebrica nell’istante tk otteniamo metodi espliciti, tra cui il metodo di Eulero Esplicito: M uδ n+1 − uδ n + K n uδ n = bn M ∆t M n+1 M = bn+1 + ( uδ − K n )uδ n ∆t ∆t 7 (3.5) dove non è richiesta la risoluzione di nessun sistema lineare poichè M è diagonale; purtroppo questo metodo non è assolutamente stabile, anzi presenta instabilità per ∆t > C h N · |βmax | ovvero, volendo incrementare la definizione spaziale del problema (diminure h e/o aumentare N ) dobbiamo forzatamente diminuire il passo di discretizzazione temporale. Tra i metodi espliciti, di larga applicazione sono i metodi di Runge-Kutta, che all’interno di un passo temporale richiedono più valutazioni funzionali; in questo modo si guadagna non solo in accuratezza del metodo, ma anche in assoluta stabilità (nel senso di condizioni meno restrittive sul passo temporale ∆t). Ad esempio, il metodo di Runge-Kutta a 2 passi (RK2) si scrive, (omettendo il pedice δ per alleggerire la scrittura): M (u∗ − un ) = ∆t(bn − K n un ) M (u∗∗ − u∗ ) = ∆t(bn+1 − K n+1 u∗ ) (3.6) 1 n+1 n ∗∗ u = (u + u ) 2 che nel caso Nm = 1 ∀m è stabile purchè sia soddisfatta la relazione: ∆t ≤ 1 h 3 |βmax | mentre il metodo RK4 (largamente utilizzato nel caso in cui la memorizzazione di 4 valutazioni del vettore incognito non sia problematica) si scrive: M k 1 = bn − K n un 1 1 ∆t k1 ) M k2 = bn+ 2 − K n+ 2 (un + 2 1 1 ∆t (3.7) M k3 = bn+ 2 − K n+ 2 (un + k2 ) 2 M k4 = bn+1 − K n+1 (un + ∆tk3 ) un+1 = un + 1 ∆t(k1 + 2k2 + 2k3 + k4 ) 6 8 4 Analisi del Metodo ad Elementi Spettrali Discontinui Preoccupiamoci ora di fornire una stima a priori dell’errore compiuto calcolando la soluzione del problema stazionario (2.1) tramite l’approssimazione (2.7). I passaggi formali seguono quelli proposti da Houston, Schwab e Süli in [4] per il caso bidimensionale. Per rendere più agevole la scrittura nelle dimostrazioni seguenti ipotizziamo che β ∈ C0 [a, b] e definiamo per u, v ∈ H 1 (Ωm ), m = 1, . . . , M : B(u, v) = M X 0 (−βu, v )Ωm + (γu, v)Ωm − m=1 ¯ l(v) = βϕv + ¯x=a + M X m=2 M X ¯ ¯ u(m−1) β(v + − v − )¯x̄m−1 + βuv − ¯x=b (f, v)Ωm (4.1) m=1 Un semplice riordinamento dei termini del SDG method porta alla formulazione corrispondente: Trovare uδ ∈ WN,M t.c. : B(uδ , vδ ) = l(vδ ) ∀vδ ∈ WN,M (4.2) Ipotizziamo ora che il termine sorgente f ∈ L2 (a, b) e che 1 0 β +γ ≥α>0 2 (4.3) per qualche α > 0. Definiamo quindi la funzione strettamente positiva 1 c20 (x) = β 0 (x) + γ(x) 2 Prendiamo vδ = uδ e notiamo che, integrando per parti si ha: ¯x̄m 1 1 (m) (−βuδ , u0δ )Ωm = − β(uδ )2 ¯x̄m−1 + ( β 0 uδ , uδ )Ωm 2 2 9 (4.4) Inoltre possiamo riordinare i termini provenienti dalle discontinuità nel seguente modo: M X M X ¯ ¯ 1 (m) 2 ¯x̄m (m−1) (m) (m−1) ¯ − β(uδ ) x̄m−1 − βuδ (uδ − uδ ) x̄m−1 = 2 m=1 m=2 M M M M X X ¯ ¯ ¯ ¯ 1X 1X (m−1) 2 ¯ (m−1) (m) ¯ (m) 2 ¯ (m) 2 ¯ ) x̄m−1 − βuδ uδ x̄m−1 = β(uδ β(uδ ) x̄m−1 − β(uδ ) x̄m + 2 m=1 2 m=1 m=2 m=2 M M M X ¯ ¯ ¯ ¯ 1X 1 1X (m−1) (m) ¯ (m) 2 ¯ (m−1) 2 ¯ (M ) 2 ¯ β(uδ ) x̄m−1 − β(uδ ) x=b + β(uδ ) x̄m−1 − βuδ uδ x̄m−1 = 2 m=1 2 2 m=2 m=2 M i ¯¯ h X ¯ ¯ 1 1 1 (m) 2 (m−1) (m) (m−1) 2 ¯ (1) 2 ¯ (M ) 2 ¯ = β (uδ ) − 2uδ uδ + (uδ ) ¯ β(uδ ) x=a − β(uδ ) x=b + 2 2 2 m=2 x̄m−1 M ¯ ¯ ¦2 1 1 1X ¥ (1) (M ) β(uδ )2 ¯x=a − β(uδ )2 ¯x=b + β uδ (x̄m−1 ) 2 2 2 m=2 ¥ ¦ dove abbiamo introdotto la notazione di salto: u(x) = u+ (x) − u− (x). Riscriviamo quindi la formulazione equivalente per la forma bilineare B(uδ , uδ ): ¶ M µ X 1 0 B(uδ , uδ ) = ( β + γ)uδ , uδ + 2 Ωm m=1 M ¯ ¯ ¦2 1 1 1X ¥ (M ) (1) β uδ (x̄m−1 ) + β(uδ )2 ¯x=b + β(uδ )2 ¯x=a + 2 m=2 2 2 (4.5) mentre per il funzionale l(uδ ) sfruttiamo la disuguaglianza di Young e scriviamo: M X ¯ (1) (m) l(uδ ) = βϕuδ ¯x=a + (f, uδ )Ωm ≤ m=1 ¯ α 1 1 2 1 (1) βϕ + β(uδ )2 ¯x=a + kuδ k2L2 (a,b) + kf k2L2 (a,b) 2 2 2 2α (4.6) Utilizzando l’ipotesi (4.3) possiamo finalmente ricavare una stima di stabilità per il metodo SDG: αkuδ k2L2 (a,b) M X ¯ ¥ ¦2 1 (M ) + β uδ (x̄m−1 ) + β(uδ )2 ¯x=b ≤ βϕ2 + kf k2L2 (a,b) α m=2 (4.7) Decomponiamo ora l’errore del metodo SDG nel seguente modo: u − uδ = (u − Πu) + (Πu − uδ ) ≡ η + ξ 10 (4.8) dove Π è l’operatore di proiezione da L2 (a, b) in WN,M , ovvero, se u ∈ L2 (a, b), Πu è tale che (u − Πu, vδ )Ω = 0 ∀vδ ∈ WN,M . (4.9) In un primo momento cerchiamo un limite su ξ in funzione di η poi, grazie all’errore di proiezione η, troveremo una stima a priori sull’errore u − uδ . Scriviamo la forma bilineare B(ξ, ξ): B(ξ, ξ) = B(u − uδ − η, ξ) = B(u, ξ) − B(uδ , ξ) − B(η, ξ) = B(u, ξ) − l(ξ) − B(η, ξ) = −B(η, ξ) (4.10) poichè u e uδ risolvono rispettivamente (2.1) e (4.2), e ξ ∈ WN,M . Applicando (4.5) sostituendo uδ con ξ otteniamo: ¶ M µ X 1 0 + B(ξ, ξ) = ( β + γ)ξ, ξ 2 Ω m m=1 M ¯ ¯ ¦2 1 1X ¥ 1 + β ξ(x̄m−1 ) + βξ 2 ¯x=b + βξ 2 ¯x=a 2 m=2 2 2 (4.11) Facciamo ora l’ulteriore ipotesi che βvδ0 ∈ WN,M ∀vδ ∈ WN,M , (4.12) ovvero richiediamo che β sia al più lineare. Scriviamo ora il termine B(η, ξ): B(η, ξ) = M X 0 (−βη, ξ )Ωm + (γη, ξ)Ωm − m=1 M X m=2 ¯ ¯ η (m−1) β(ξ + − ξ − )¯x̄m−1 + βη − ξ − ¯x=b (4.13) notiamo che il primo termine m=1 (−βη, ξ )Ωm è identicamente nullo grazie alla (4.9) e alla (4.12). Utilizziamo la disuguaglianza di Cauchy-Schwarz e quella di Young per maggiorare i termini restanti della (4.13): PM 0 M i 1 Xh |B(η, ξ)| ≤ kc0 ηk2L2 (Ωm ) + kc0 ξk2L2 (Ωm ) + 2 m=1 ¸ M · X ¯ ¯ ¯ ¦2 1 1 ¥ − ¯2 + βη 2 ¯x=b + βξ 2 ¯x=b βη x̄m−1 + β ξ(x̄m−1 ) 4 4 m=2 11 (4.14) ottenendo così una limitazione su ξ in funzione di η: M X kc0 ξk2L2 (Ωm ) m=1 M ¯ ¯ ¦2 1X ¥ 1 + β ξ(x̄m−1 ) + βξ 2 ¯x=a + βξ 2 ¯x=b ≤ 2 m=2 2 M X M X kc0 ηk2L2 (Ωm ) + 2 m=1 ¯2 βη − ¯ x̄m−1 m=2 ¯ + 2βη 2 ¯ (4.15) x=b Definiamo quindi una norma derivata dalla disuguaglianza (4.15): kwk2DG = M X kc0 wk2L2 (Ωm ) m=1 M ¯ ¯ ¦2 1 1X ¥ + β w(x̄m−1 ) + βw2 ¯x=a + βw2 ¯x=b 2 m=2 2 (4.16) grazie a questa definizione, alla (4.15) ed alla disuguaglianza triangolare possiamo completare l’analisi a priori dell’errore; infatti: ku − uδ k2DG ≤kηk2DG + kξk2DG ≤ kηk2DG + M X kc0 ηk2L2 (Ωm ) +2 m=1 M X m=2 ¯2 ¯ βη − ¯x̄m−1 + 2βη 2 ¯x=b (4.17) e per ottenere la stima finale ci avvarremo delle stime degli errori di interpolazione che forniremo nella sezione seguente. 4.1 Errori di interpolazione Forniamo alcune stime sugli errori di interpolazione sui nodi di Gauss-LobattoLegendre. Siano quindi xj , j = 0, . . . , N gli N + 1 punti di integrazione definiti nella [Sezione 5] e ΠN u il polinomio di grado N che interpola u nei nodi xj . Le dimostrazioni possono essere trovate in ([1], Capitolo 5) e nelle referenze ivi citate. Lemma 1. Interpolazione sull’intervallo di riferimento Sia u ∈ H s (−1, 1) con s ≥ 1; allora ku − ΠN ukH k (−1,1) ≤ CN k−s |u|H s;N (−1,1) k = 0, 1 dove C è una costante positiva dipendente da k ed s ma non da N nè da u. La definizione della seminorma di Sobolev |u|H s;N (−1,1) è la seguente: 1/2 s X |u|H s;N (−1,1) = ku(j) k2L2 (−1,1) j=min(s,N +1) in particolare se N ≥ s − 1 si ha: |u|H s;N (−1,1) = ku(s) kL2 (−1,1) 12 Lemma 2. Interpolazione sull’intervallo generico Sia u ∈ H s (a, b) con s ≥ 1, ed h = b − a allora ku − ΠN ukH k (a,b) ≤ Ch(min(s,N +1)+k) N k−s |u|H s;N (a,b) k = 0, 1 dove C è una costante positiva dipendente da k ed s ma non da N nè da h. Nel caso k = 0 otteniamo la stima in L2 ku − ΠN ukL2 (a,b) ≤ Ch(min(s,N +1)) N −s |u|H s;N (a,b) (4.18) Poichè la norma k·kDG contiene anche i valori negli estremi dei sotto-intervalli, abbiamo bisogno anche di una stima dell’errore puntuale di interpolazione. Lemma 3. Errore puntuale di interpolazione Sia u ∈ H s (−1, 1) con s ≥ 1, allora ku − ΠN ukL∞ (−1,1) ≤ CN 1/2−s |u|H s;N (−1,1) (4.19) pertanto ΠN u converge puntualmente a u se N → ∞. 4.2 Stima a priori dell’errore Riprendendo la (4.17), scegliamo come operatore di proiezione in WN,M l’interpolante (m) Πδ u tale che Πδ u (ovvero ristretto all’intervallo Ωm ) interpola la funzione u nei Nm +1 nodi di Gauss-Lobatto-Legendre dell’intervallo Ωm . Grazie alla (4.19) notiamo che possiamo trovare un limite superiore ai termini derivati dalla valutazione puntuale di η, ad esempio: ¯ βη 2 ¯x̄m−1 ≤ kβkL∞ (Ωm ) kη (m−1) k2L∞ (Ωm ) (4.20) 1/2−s ≤ CkβkL∞ (Ωm ) Nm |u|H s;Nm (Ωm ) Allora, grazie alle considerazioni fatte, possiamo enunciare il seguente teorema Teorema 1. Stima a priori per il SDG method Sia [a, b] ∈ R partizionato in M sotto-intervalli Ωm di lunghezza hm . Sia uδ ∈ WN,M l’approssimazione della soluzione del problema (2.1) ottenuta tramite il metodo SDG, e supponiamo che u(m) ∈ H sm (Ωm ) per qualche sm ≥ 1. Allora, se le ipotesi (4.3) e (4.12) sono verificate, vale la seguente stima a priori dell’errore: ku − uδ k2DG ≤ M X 2min(sm ,Nm +1)−1 · C0 hm m=1 ¡ · C1 (Nm + 1)1−2sm + C2 hm (Nm + 1) 13 ¢ −2sm (4.21) |u|2H sm (Ωm ) dove C1 = kβkL∞ (Ωm ) e C2 = kc0 k2L∞ (Ωm ) e C0 non dipende da Nm nè da hm . Corollario 1. Nel caso gli ordini siano uniformi, ovvero se Nm = N , sm = s, chiamando h = max hm otteniamo 1 1 ku − uδ kDG ≤ Chmin(s,N +1)− 2 (N + 1) 2 −s |u|H s (a,b) (4.22) Nel caso in cui la soluzione sia molto regolare (s molto grande) la strategia per ottenere delle approssimate migliori è quella di mantenere h fissato e di incrementare N . Infatti se dividiamo l’intervallo [a, b] in M intervalli di lunghezza costante ed usiamo polinomi di grado N su ogni intervallo, otteniamo D = (N + 1)M gradi di libertà. Se N ≥ s − 1, la stima precedente porta a ku − uδ kDG ≤ C 1 M 1 s− 12 (N + 1) s− 21 =C 1 D s− 21 ovvero l’ordine di convergenza è indifferentemente ottenuto se incrementiamo D aumentando il grado dei polinomi o se aumentiamo il numero di elementi. Al contrario, se N < s − 1 ku − uδ kDG ≤ C 1 M N + 12 1 (N + 1) s− 12 = CM s−1−N 1 1 Ds− 2 ovvero l’ordine di convergenza è massimale per M = 1, ovvero se abbiamo un solo elemento. 14 Programmazione Avanzata per il Calcolo Scientifico Il codice di seguito presentato è l’implementazione di un risolutore per problemi di trasporto monodimensionali attraverso il metodo degli elementi spettrali discontinui. Il codice si compone di una serie di classi che interagiscono tra di loro in modo da decomporre il problema in una serie di sottoproblemi che possano essere più semplicemente gestiti ed analizzati. La decomposizione in una serie di oggetti diversi consente una comprensione migliore del codice da parte dell’utente finale, ma anche una gestione più efficace da parte dei programmatori sia in fase di implementazione che in quella di debug. Il codice può essere scomposto in quattro parti: costruzione delle basi standard degli elementi spettrali (funzionibase.hpp), estensione al dominio generico (elementi.hpp), costruzione delle matrici del problema (problema.hpp) e risoluzione nel tempo (tempo.hpp). Le dichiarazioni di ciascuna classe di oggetti sono contenute nei file con estensione .hpp, mentre la loro definizione nell’omonimo file con estensione .cpp. La definizione dei coefficienti del problema (coefficiente di trasporto, di reazione, del termine sorgente, del dato di bordo e del dato iniziale) avviene tramite la scrittura su un file chiamato datiproblema.cpp, mentre per la definizione dei dati a scelta dell’utente ci avvaliamo di un file di dati di tipo GetPot, che non richiede la ricompilazione del file sorgente. Nella Sezione 5 illustreremo le formule di integrazione Gaussiana e successivamente il modo in cui abbiamo scelto di implementarle nel nostro codice. Nella Sezione 6 illustreremo la formulazione algebrica del problema e l’implementazione della classe che costruisce la matrice di rigidezza e il termine noto del problema, mentre nella Sezione 7 discuteremo l’implementazione dei metodi di avanzamento in tempo. 5 Integrazione Numerica Gaussiana Siano x0 , . . . , xn n + [−1, 1]. Per l’approssimazione delR 11 punti distinti dell’intervallo 0 l’integrale I(f ) = −1 f (x)dx, essendo f ∈ C ([−1, 1]), si considerano formule di quadratura della forma n X In (f ) = αi f (xi ) (5.1) i=0 dove αi sono coefficienti da determinarsi opportunamente. Denotiamo con En (f ) = I(f ) − In (f ) 15 l’errore fra l’integrale esatto e la sua approssimazione (5.1). Qualora si abbia En (p) = 0 per ogni p ∈ Pr , per un opportuno r ≥ 0, si dirà che la formula (5.1) ha grado di esattezza r. Si può naturalmente avere grado di esattezza almeno pari a n prendendo Z 1 In (f ) = Πn f (x)dx −1 dove Πn f (x) ∈ Pn è il polinomio interpolatore di Lagrange della funzione f nei nodi {xi , i = 0, . . . , n} dato da Πn f (x) = n X f (xi )li (x) i=0 dove li ∈ Pn sono chiamati polinomi caratteristici e hanno la forma: n Y x − xj li (x) = xi − xj j=0 i = 0, . . . , n j6=i in particolare li (xj ) = δij . In tal caso la (5.1) diventa Z 1 Z 1X n n Z 1 X li (x)dx f (xi ) In (f ) = Πn f (x)dx = f (xi )li (x)dx = −1 −1 i=0 i=0 | −1 {z } αi In effetti, se f ∈ Pn , allora Πn f = f e quindi In (Πn f ) = I(Πn f ). Una formula alternativa per il polinomio interpolatore di f (x) nei nodi {xi , i = 0, . . . , n} è Πn f (x) = n X i=0 ωn+1 (x) f (xi ) 0 (x − xi )ωn+1 (xi ) dove ωn+1 è il polinomio nodale di grado n + 1 ωn+1 (x) = n Y (x − xi ) i=0 Ci chiediamo ora se sia possibile scegliere i nodi di interpolazione {xi , i = 0, . . . , n} in modo da ottenere formule di integrazione con grado di esattezza maggiore di n. La risposta è data dal seguente teorema: Pn Teorema 2. La formula di quadratura In (f ) = i=0 αi f (xi ) ha grado di esattezza n + m se e solo se la formula è interpolatoria ed inoltre il polinomio nodale ωn+1 associato ai nodi {xi } soddisfa la relazione Z 1 ωn+1 (x)p(x)dx = 0 ∀p ∈ Pm−1 (5.2) −1 16 dal quale discende il seguente corollario: Corollario 2. Il grado massimo di esattezza della formula di quadratura interpolatoria ad n + 1 nodi è 2n + 1 Prendendo quindi m = n + 1 il polinomio nodale ωn+1 deve soddisfare la relazione Z 1 ωn+1 (x)p(x)dx = 0 ∀p ∈ Pn (5.3) −1 in particolare diciamo che ωn+1 deve essere ortogonale a tutti i polinomi di grado inferiore. La scelta di questo polinomio (e quindi dei nodi per formule di integrazione a massimo grado di esattezza) cade necessariamente sui polinomi ortogonali di Legendre. I polinomi ortogonali di Legendre Lk ∈ Pk , per k = 0, 1, . . . , si possono calcolare mediante la seguente relazione ricorsiva a tre termini L0 = 1, Lk+1 L1 = x 2k + 1 k = xLk − Lk−1 k+1 k+1 (5.4) e costituiscono una successione per cui è soddisfatta la seguente relazione di ortogonalità: ½ Z 1 0 se m 6= k Lk Lm dx = 1 −1 (k + 2 ) se m = k −1 Essi sono linearmente indipendenti e formano una base per L2 (−1, 1); ogni funzione f ∈ L2 (−1, 1) può essere espressa tramite uno sviluppo in serie della forma f (x) = ∞ X fˆk Lk (x), 1 fˆk = (k + ) 2 con k=0 Z 1 f (x)Lk (x)dx −1 In particolare prendendo {Lk }, k = 0, . . . , n ottengo una base per Pn , ovvero p(x) = n X pˆk Lk (x) ∀p ∈ Pn k=0 quindi sostituendo nella (5.3): Z 1 ωn+1 (x) −1 n X k=0 pˆk Lk (x)dx = n X k=0 Z 1 pˆk ωn+1 (x)Lk (x)dx = 0 ⇔ ωn+1 (x) = Ln+1 (x) −1 (5.5) Il polinomio nodale scelto sarà quindi il polinomio di Legendre di grado n + 1 e quindi i nodi di quadratura saranno i punti {xj : Ln+1 (xj ) = 0, j = 0, . . . , n} detti nodi di 17 Gauss-Legendre. Concludiamo quindi che la formula (5.1) con nodi di Gauss-Legendre e pesi dati da R1 l dx, con li (x) polinomi caratteristici di Lagrange nei nodi di Gauss-Legendre, ha −1 i grado di esattezza 2n + 1, il massimo possibile fra tutte le formule di quadratura che utilizzano n + 1 nodi, ed è nota come formula di quadratura di Gauss-Legendre. Questa formula gode della proprietà di avere tutti i pesi positivi e tutti i nodi interni all’intervallo (−1, 1). Nel nostro caso, ovvero qualora la formula di integrazione venga usata per approssimare gli integrali di una formulazione debole quale la (1.3), è necessario includere gli estremi {−1; 1} tra i nodi di integrazione per poter imporre le condizioni al contorno. Scegliamo quindi come polinomio nodale ω̄n+1 (x) = Ln+1 (x) + aLn (x) + bLn−1 (x) con i coefficienti a e b scelti in modo da avere ω̄n+1 (−1) = ω̄n+1 (1) = 0. Le radici di ω̄n+1 saranno i nodi di integrazione x̄0 = −1, x̄1 , . . . , x̄n−1 , x̄n = 1 mentre i pesi ᾱi saranno ottenuti con la formula: Z 1 ¯li (x)dx ᾱi = i = 0, . . . , n (5.6) −1 dove ¯li ∈ Pn denotano ora i polinomi caratteristici di Lagrange nei nodi x̄i , i = 0, . . . , n. La formula di quadratura Z 1 n X GL f (x)dx ' In (f ) = ᾱi f (x̄i ) (5.7) −1 i=0 è detta formula di Gauss-Lobatto-Legendre. Ovviamente l’aver incluso Ln e Ln−1 nella definizione del polinomio nodale rende quest’ultimo ortogonale a tutti i polinomi di grado n − 2, quindi la formula di integrazione (5.7) avrà grado di esattezza pari a 2n − 1. Possiamo inoltre caratterizzare precisamente i nodi di integrazione per la formula di Gauss-Lobatto-Legendre: essi sono i punti {−1; 1} e l’insieme {x̄j , j = 1, . . . , n − 1 : L0n (x̄j ) = 0} (5.8) L’espressione analitica per i polinomi caratteristici ¯li è: ¯li = −1 (1 − x2 )L0n (x) , n(n + 1) (x − x̄i )Ln (x̄i ) i = 0, . . . , n (5.9) mentre i pesi ᾱi assumono la seguente espressione: ᾱi = 2 1 n(n + 1) L2n (x̄i ) 18 (5.10) 1 0.8 0.6 0.4 0.2 0 -0.2 -1 -0.5 0 0.5 1 Figura 1: Polinomi caratteristici nei nodi di Gauss-Lobatto-Legendre di grado 4 5.1 La classe FunzioniBase All’interno del file funzionibase.hpp sono dichiarate innanzi tutto le funzioni che consentono di effettuare le operazioni elementari su un polinomio rappresentato tramite il vettore dei suoi coefficienti a: Hornereval(a,x), che valuta il polinomio in un punto x secondo l’algoritmo di Horner; Deriv(a), che restituisce il vettore dei coefficienti della derivata del polinomio; NewtonHorner(a,xp,...), che trova una radice di a in prossimità del punto xp secondo l’algoritmo di Newton-Horner; Hornerdef(a,r), che effettua la deflazione, ovvero trova i coefficienti del polinomio quoziente della divisione tra il polinomio a e il binomio (x-r) dove r è una radice; root(a), che restituisce il vettore di tutte le n radici del polinomio a. Nella classe FunzioniBase viene implementato il calcolo dei nodi di integrazione di Gauss-Lobatto-Legendre e dei polinomi caratteristici di Lagrange su questi nodi per 19 l’intervallo di riferimento [−1, 1]. Il costruttore prende in ingresso solamente il numero n che rappresenta il grado del polinomio di Legendre, il cui vettore dei coefficienti viene costruito attraverso il seguente algoritmo che ricalca la relazione ricorsiva (5.4): if (n==0) CoeffLegendre[0]=1; else { if (n==1) { CoeffLegendre[0]=0; CoeffLegendre[1]=1; } else { c[0]=1; b[0]=0; b[1]=1; for (int i=1; i<=n-1; i++) { for (int j=0; j<=n; j++) { CoeffLegendre[j]= - c[j]*i/(i+1); if (j) CoeffLegendre[j]+= b[j-1]*(2*i+1)/(i+1); } for(int j=0;j<=n;j++){ c[j]=b[j]; b[j]=CoeffLegendre[j]; } } } } Una volta costruito il vettore con i coefficienti del polinomio di Legendre di grado n costruiamo il vettore dei coefficienti della sua derivata: CoeffDerivLegendre = Deriv(CoeffLegendre); In questo modo possiamo calcolare il vettore dei nodi NodiGLL[] e quello dei pesi PesiGLL[] per la formula di Gauss-Lobatto-Legendre tramite le formule (5.8) e (5.10). Infine costruiamo due matrici contenenti l’una i coefficienti dei polinomi caratteristici di Lagrange (5.9) nei nodi di integrazione –che costituiscono le funzioni di base del problema– e l’altra i coefficienti delle derivate di questi polinomi caratteristici (CoeffBase, CoeffDerivBase). 5.2 La classe Elementi In riferimento alla discretizzazione del problema fatta nella Sezione 2 la classe elementi costruisce i nodi per l’intero dominio del problema. Il costruttore prende in ingresso il numero di elementi M di lunghezza costante in cui verrà scomposto il dominio monodimensionale [a, b] e il grado n degli elementi spettrali locali su ogni elemento. Viene creata un’istanza della classe FunzioniBase di grado n e a partire da 20 questa si costruiscono i nodi di discretizzazione dell’intero dominio: la trasformazione dalle vecchie alle nuove coordinate è molto semplice, vista la natura monodimensionale del problema, ed avviene attraverso l’applicazione lineare descritta in (2.4-2.5). 6 Formulazioni algebriche In questa sezione esplicitiamo le formulazioni algebriche del metodo di Galerkin spettrale con integrazione numerica (1.4) e del metodo agli elementi spettrali discontinui (2.7). Presentiamo infine la classe problema, grazie alla quale le matrici e il termine noto del problema vengono effettivamente costruite. 6.1 Formulazione algebrica del metodo G-NI Riprendendo il discorso intrapreso nella Sezione 1, proponiamo la formulazione algebrica del metodo di Galerkin spettrale con integrazione numerica. D’ora in poi ci riferiremo a formule di integrazione di Gauss-Lobatto-Legendre con la notazione xi per i nodi di integrazione, αi per i pesi, e ψi per i polinomi caratteristici nei nodi. I polinomi caratteristici ψi , i = 0, . . . , N costituiscono una base per VN , poichè linearmente indipendenti. Possiamo dunque fornire per la soluzione u∗N del problema G-NI (1.4) la rappresentazione nodale u∗N (x) = N X u∗N (xi )ψi (x) (6.1) i=0 ovvero identificare le incognite del nostro problema con i valori assunti da u∗N in corrispondenza dei nodi xi . Inoltre, affinchè il problema (1.4) risulti verificato per ogni vN ∈ VN , basterà che lo sia per ogni funzione di base ψi , i = 0, . . . , N . Analizziamo i termini della (1.4) per ottenere la formulazione algebrica del problema: Ku = b dove abbiamo chiamato u il vettore dei coefficienti incogniti u∗N (xj ): 0 0 Termine di trasporto −(βu∗N , vN )N Sostituiamo quindi vN con ψi0 , i = 0, . . . , N e esplicitiamo i termini della sommatoria: −(βu∗N , ψi0 )N =− N X αj β(xj )u∗N (xj )ψi0 (xj ) i = 0, . . . , N (6.2) j=0 utilizzando una notazione algebrica si può scrivere, K (1) u dove K (1) = (kij ) con 21 kij = −αj β(xj )ψi0 (xj ) (6.3) Notiamo subito la matrice ha una struttura piena, a causa della presenza del termine ψi0 (xj ). Infatti, come possiamo vedere in Figura 4, l’i-esima funzione di base presenta un massimo nell’i-esimo nodo, mentre in tutti gli altri nodi ψi0 (xj ) 6= 0 per i 6= j Termine di reazione (γu∗N , vN )N Analogamente a quanto fatto per il termine di trasporto, sostituiamo vN con ψi , i = 0, . . . , N ed esplicitiamo i termini della sommatoria: (γu∗N , ψi )N = N X αj γ(xj )u∗N (xj )ψi (xj ) i = 0, . . . , N (6.4) j=0 ma dato che ψi (xj ) = δij , il termine di reazione è esprimibile in notazione algebrica tramite una matrice diagonale: K (0) u K (0) = (kij ) con dove kij = αi γ(xi )δij (6.5) Termine forzante (f, vN )N Il termine forzante è facilmente esprimibile tramite il vettore f, infatti l’espressione (f, ψj )N = N X αj f (xj )ψi (xj ) i = 0, . . . , N (6.6) j=0 porta a scrivere il vettore f = (fi ) con fi = αi f (xi ) Termini di bordo Il termine di sinistra βu∗N vN |x=1 porta all’aggiunta di un termine alla matrice di rigidezza K nella posizione (N + 1, N + 1); infatti β(xN )u∗N (xN )ψi (xN ) = β(xN )u∗N (xN )δN N (6.7) chiamiamo quindi K (B) = (kij ) dove kij = β(xi )δiN δjN (6.8) il contributo alla matrice di rigidezza dovuto all’imposizione debole delle condizioni al bordo. Il termine di destra βϕvN |x=−1 contribuisce invece alla formazione del termine noto b, infatti il termine β(x0 )ϕψi (x0 ) = β(x0 )ϕδ00 (6.9) consiste nell’aggiunta del vettore f (B) = (fi ) con al termine noto del problema. 22 fi = β(xi )ϕδi0 (6.10) Possiamo quindi esplicitare i termini della formulazione algebrica del problema Ku = b K = K (1) + K (0) + K (B) b = f + f (B) (6.11) 6.2 Formulazione algebrica del metodo SDG-NI (m) Riprendendo le notazioni introdotte nella Sezione 2, siano xj , j = 0, . . . , Nm gli Nm + (m) 1 nodi di Gauss-Lobatto sull’m-esimo intervallo e siano αj i corrispondenti pesi. Per la scelta di utilizzare funzioni discontinue, abbiamo (m−1) xNm (m) ≡ x0 ≡ x̄m−1 (m) Siano ora vδ i polinomi caratteristici di Lagrange ψi fuori dall’elemento Ωm ; dato che (m) ψi (x̄m−1 ) = 0 (m) ψi (x̄m ) = 0 per ogni per ogni (m) associati ai nodi xi , estesi a 0 i = 1, . . . , Nm e i = 0, . . . , Nm − 1 trascurando per un momento i termini di bordo, la (2.8) si riduce a: (m) Per m = 1, . . . , M , trovare uδ ∈ PNm (Ωm ) tale che: (m) (m) (m) (m) (m) −(βuδ , ψi0 (m) )Nm ,Ωm + (γuδ , ψi (m) i = 0, . . . , Nm (6.12) la cui formulazione algebrica ricalca esattamente quella presentata in (6.2)–(6.6) per il metodo spettrale G-NI. In particolare, il contributo alla matrice di rigidezza dei termini (m) del primo ordine K (1) derivante dalla valutazione di ψi0 (m) (xj ) sarà di tipo diagonale a blocchi con M blocchi quadrati di dimensione (Nm + 1) × (Nm + 1). Consideriamo ora il caso i = Nm , ovvero poniamo l’attenzione sul nodo di outflow in (m)− ogni elemento m; anche in questo caso, come nelle (6.7)-(6.8), il termine β − uδ vδ− |x̄m porta ad un contributo K (B) alla matrice di rigidezza K; infatti (m) (m)− β − (xNm )uδ )Nm ,Ωm = (f, ψi (m) (m) )Nm ,Ωm (m)− (xNm )ψNm (xNm ) = β − (xNm )uδ (m) (xNm ) (6.13) che, al di là di una notazione complicata, consiste proprio nell’aggiungere il termine (m) β − (xNm ) = β − (x̄m ) nella posizione (Nm + 1, Nm + 1) dell’m-esimo blocco diagonale, m = 1, . . . , M . Infine, consideriamo il caso i = 0, ovvero guardiamo il nodo di inflow di ogni elemento (m−1)− + m; abbiamo il contributo del termine −β + uδ vδ |x̄m−1 . Per il primo elemento m = 23 1 abbiamo un contributo al termine noto dovuto al dato di inflow ψ, del tutto analogo a quanto accadeva nella (6.9); per m = 2, . . . , M invece, abbiamo (m) (m−1)− −β + (x0 )uδ (m) (m) (m) (m−1)− (x0 )ψ0 (x0 ) = −β + (x0 )uδ (m−1) (xNm−1 ) (6.14) (m) anche qui abbiamo un contributo alla matrice di rigidezza K del termine -β + (x0 ) = −β + (x̄m−1 ) nella posizione (1, 0) (ovvero nella posizione a ”sinistra” del primo elemento) dell’m-esimo blocco diagonale, m = 2, . . . , M . Concludendo, per il problema di trasporto-reazione approssimato con il metodo SDG-NI la formulazione algebrica Ku = b può essere sintetizzata attraverso i termini K = K (1) + K (0) + K (B) b = f + f (B) (6.15) dove K (1) e K (0) sono le matrici dovute ai termini di trasporto e di reazione, K (B) è la matrice dovuta all’imposizione debole della continuità all’interfaccia degli elementi, mentre f e f (B) sono dovuti al termine forzante e al dato di inflow rispettivamente. 6.3 La classe Problema La classe problema è il cuore di tutto il codice ad elementi spettrali discontinui qui presentato. In questa classe vengono infatti costruite la matrice di rigidezza del problema (FullMtx<double> matrice_problema) il termine noto (Vcr<double> termine_noto), la matrice di massa, che essendo diagonale è memorizzata tramite un vettore (Vcr<double> matrice_massa) e il dato iniziale (Vcr<double> dato_iniziale). La costruzione degli elementi segue la traccia presentata nella Sezione 6.2. Tra i suoi membri privati la classe problema ha anche un’istanza della classe elementi introdotta nella precedente sezione. Il costruttore si occupa di valutare tutte le matrici e i vettori in funzione del problema inserito dall’utente nel file datiproblema.cpp. Ad esempio, la valutazione del vettore termine noto è stata implementata nel seguente modo: for (int k=0; k<m; k++) { for (int i=0; i<=n; i++) { termine_noto[(n+1)*k+i] = T.GET_peso() * T.GET_PesiGLL()[i] * *forzante(T.GET_NodiGLL(k)[i], tempo); if(i==0 && k==0 ) termine_noto[i] += beta(T.GET_NodiGLL(k)[i], tempo) * dirichlet(a,tempo); } } 24 Figura 2: Pattern della matrice K per l’approssimazione SDG-NI con M = 4 e Nm = 4 ∀m. In rosso il pattern della matrice K (B) . dove T è il nome dell’istanza della classe elementi presente come membro della classe problema, T.GET_peso()*T.GET_PesiGLL()[i] costituisce l’i-esimo peso di integrazione sull’intervallo generico mentre i termini forzante e beta sono valutati nel punto T.GET_NodiGLL(k)[i] all’istante tempo. Di particolare importanza per l’aspetto tempo-dipendente del problema è il metodo pubblico void aggiorna(double time) che aggiorna la matrice del problema (qualora i termini di trasporto β e reazione γ siano tempo dipendenti) e il termine noto (che contiene le condizioni al bordo che sono spesso dipendenti dal tempo) in funzione del parametro tempo che gli viene passato come argomento. 6.4 Inserimento dei dati del problema Per inserire i dati del problema, l’utente deve editare i file data.pot nella cartella ./ oppure il file datiproblema.cpp nella cartella ./src. Il file data.pot viene letto dall’header GetPot e consente di modificare alcuni parametri fondamentali per il 25 problema (dati del dominio, parametri temporali, metodo di risoluzione in tempo) senza dover ricompilare il programma. In datiproblema.cpp, invece, l’utente può descrivere il proprio problema definendo ciascun termine della formulazione (3.1): i coefficienti di trasporto β(x, t) e reazione γ(x, t), il termine forzante f (x, t), il dato di dirichlet ϕ(t), la soluzione iniziale u0 (x) e nel caso di problemi-test anche la soluzione esatta u(x, t). 7 Risoluzione del problema: la classe Tempo La classe tempo si occupa della risoluzione in tempo del problema. I membri privati della classe contengono l’istante iniziale (double tini) e quello finale (double tend) e un’istanza della classe problema. I metodi pubblici della classe tempo richiedono come parametro in input il numero di passi di discretizzazione temporale necessari e implementano i metodi di avanzamento in tempo introdotti nella Sezione 7: Eulero esplicito, Eulero implicito e Runge-Kutta di ordine 2 e 4. Abbiamo anche a disposizione un metodo per la risoluzione del problema stazionario. A titolo di esempio, proponiamo l’implementazione del metodo di Eulero esplicito: Vcr<double> pde::euler_esp(int n){ double dt = (tend - tini)/n; Vcr<double> uold = P.GET_dato_iniziale(); Vcr<double> u = uold; for (int k=1; k <= n; k++){ double istante = tini+dt*k; Vcr<double> du = P.GET_matrice_problema()*uold; du = -du; du += P.GET_termine_noto(); du = du/P.GET_matrice_massa(); u = uold + dt*du; P.aggiorna(istante); uold = u; } return u; } dove P è l’istanza della classe problema presente nella classe tempo e dove risulta molto utile l’overloading dell’operatore: Vcr<S> operator/(const Vcr<S>&, const Vcr<S>&); per la divisione componente a componente per i vettori da noi aggiunto alla libreria di algebra lineare. 26 7.1 Libreria di algebra lineare Per la gestione di vettori e matrici abbiamo scelto di utilizzare la libreria matvec.h scritta da Daoqi Yang. In particolare all’interno del nostro codice sono utilizzate matrici del tipo FullMtx<double> e vettori di tipo Vcr<double>. Abbiamo introdotto nuovi metodi alle classi di oggetti sopracitate per meglio interagire con il nostro codice, in particolare per la gestione di lettura e scrittura negli oggetti. Tra le funzioni presenti in questa libreria abbiamo utilizzato l’implementazione proposta del metodo GMRES qualora fosse necessaria la risoluzione di sistemi lineari. La scelta è ricaduta su questa libreria perché abbiamo preferito utilizzare un codice che contenesse lo stretto necessario e che fosse facilmente modificabile; all’interno del programma non abbiamo infatti l’esigenza di utilizzare strumenti più raffinati come le ublas della libreria boost. 8 Installazione e uso All’interno del pacchetto che contiene i sorgenti sono presenti tre cartelle (src, output e risultati) e un Makefile. Per compilare i file contenuti in src basta digitare nel terminale make build Verrà quindi creato il file eseguibile mesd che può essere eseguito, sempre da terminale, con ./mesd Terminata l’esecuzione del programma, l’utente potrà trovare nella cartella risultati i file .dat con la soluzione del problema ad ogni istante temporale. Per visualizzare l’andamento della soluzione basta compilare i sorgenti della cartella output make result e digitare a terminale ./plot che aprirà una finestra di GNUPlot in cui verranno visualizzate le soluzioni per ogni istante temporale richiesto. Per la visualizzazione dei risultati sarà quindi necessario aver installato nel proprio sistema il software GNUPlot (www.gnuplot.info). Per compilare i sorgenti di entrambe le cartelle basta digitare make mentre per eliminare i file con le soluzioni, i file oggetto e gli eseguibili make clean 27 9 Risultati Abbiamo testato le varie parti del nostro programma su problemi modello per verificare la buona formulazione algoritmica del codice e per quantificare l’incidenza di eventuali errori numerici che possano inficiare la convergenza della nostra soluzione. 9.1 Integrazione numerica Per verificare la buona implementazione della classe FunzioniBase.hpp (che genera tra le altre cose nodi e pesi di GLL sull’intervallo di riferimento) abbiamo verificato l’errore di integrazione compiuto approssimando l’integrale Z 1 cos(x)dx = sin(1) − sin(−1) −1 tramite la formula di quadratura di GLL al variare del grado N del polinomio di Legendre utilizzato (quindi usando N + 1 nodi di integrazione di GLL). Nell’immagine Figura 3: Errore di quadratura della formula di GLL al variare di N notiamo che abbiamo una successiva riduzione dell’errore fino ad N ' 8; successivamente, fino ad N ' 15 l’errore si assesta attorno ad un valore dell’ordine O(10−16 ) mentre al crescere di N oltre questa soglia l’insorgenza di errori numerici altera la convergenza. Terremo conto di questa considerazione nel seguito delle nostre analisi. 28 Successivamente abbiamo testato la classe element.hpp, il cui scopo è quello di generare nodi e pesi di integrazione su un intervallo generico e su una suddivisione in sottointervalli di un intervallo generico, verificando l’errore di integrazione compiuto nell’approssimare l’integrale Z π 2 cos(x) = 2 − π2 all’aumentare del numero M di sottointervalli di lunghezza uniforme h = π/M sui quali abbiamo usato formule di quadratura di GLL ad N + 1 nodi. Anche in questo caso Figura 4: Errore di quadratura al variare del numero di sottointervalli M per diversi numeri N apprezziamo una riduzione costante dell’errore all’aumentare di M sia per N = 2 che per N = 3; per N = 4 l’errore non scende oltre una soglia dell’ordine O(10−16 ). 9.2 Caso stazionario Per testare i metodi della classe problema.hpp che costruiscono la matrice di rigidezza e il termine noto del problema abbiamo considerato il problema stazionario: ( ∂u = 6 cos 6x −1 < x < 1 (9.1) ∂x u(−1) = sin(−6) 29 La soluzione esatta del problema è u(x) = sin 6x. Data la regolarità della soluzione, abbiamo a disposizione la stima a priori sull’errore del metodo SDG: µ ku − uδ kDG ≤ C h N +1 ¶N + 12 |u|H (N +1) (a,b) (9.2) In Figura 5 riportiamo l’andamento dell’errore; si verifica facilmente la bontà delle stime, notando che al variare di h si ha un andamento dell’errore di tipo linare ma con ordine crescente al crescere di N , mentre osservando l’andamento dell’errore al variare di N si nota un decremento di tipo esponenziale. Figura 5: Comportamento dell’errore ku − uδ kDG al variare di h (sinistra) ed N (destra) per il problema (9.1) Se analizziamo l’andamento dell’errore per una soluzione non regolare, ad esempio nel caso del problema ( ∂u + u = e−x + χ[−1,1] (sin(πx) + π cos(πx)), −2 < x < 2 (9.3) ∂x u(−2) = e2 che ha come soluzione u(x) = e−x + χ[−1,1] sin(πx), la stima a priori dell’errore tiene conto della regolarità della soluzione nel seguente modo: µ ku − uδ kDG ≤ C h N +1 ¶s− 21 |u|H s (−2,2) (9.4) dove s è la classe di regolarità della soluzione, nel senso che u(s) ∈ L2 (−2, 2). In questo caso la classe di regolarià è s = 2, e nei grafici dell’andamento dell’errore in Figura 6 notiamo un ordine di abbattimento dell’errore uguale a s − 1/2 = 3/2, in perfetto accordo con la stima a priori. Nell’immagine di destra possiamo inoltre notare 30 Figura 6: Comportamento dell’errore ku − uδ kDG al variare di h (sinistra) ed N (destra) per il problema (9.3) un incremento dell’ordine di convergenza al crescere di N fino a 5/2 per M = 4, 8; in questo caso i punti di discontinuità della derivata della funzione {−1, 1} corrispondono con due estremi degli elementi spettrali così che in ogni intervallo la soluzione è regolare. In questo caso l’uso di elementi discontinui permette di incrementare di un’unità l’ordine di convergenza. 9.3 Caso non stazionario Verifichiamo infine l’implementazione dei metodi di avanzamento in tempo. In un primo momento abbiamo considerato il problema ∂u 3 ∂u + =0 t > 0, −1 < x < 1 ∂t 2 ∂x (9.5) u(x, 0) = sin(2x) −1 ≤ x ≤ 1 u(−1, t) = sin(−2 − 3t) t>0 la cui soluzione esatta è u(x, t) = sin(2x − 3t). In questo caso la stima dell’ordine di convergenza del metodo dipende dall’ordine del metodo di avanzamento in tempo utilizzato. Scegliamo quindi di utilizzare il metodo di Runge Kutta del 4 ordine, che è il metodo più accurato da noi implementato. In Figura 7 possiamo visualizzare l’errore calcolato all’istante t = 1 avendo utilizzato un passo di discretizzazione temporale ∆t = 10−3 . Possiamo notare che nel caso dell’incremento del numero di elementi (hrefinement, figura a sinistra) l’ordine di convergenza per il caso N = 2 e 4 è analogo a quello ottenuto nel caso stazionario, ovvero uguale a N + 1/2. Per N ≥ 6 non si apprezza purtroppo una riduzione dell’errore costante. Se ci concentriamo invece sull’incremento successivo del grado dei polinomi (figura a destra), si mantiene un ordine 31 Figura 7: Comportamento dell’errore ku − uδ kDG al variare di h (sinistra) ed N (destra) calcolato all’istante t = 1 per il problema non stazionario (9.5) risolto con RK4 con ∆t = 10−3 di riduzione esponenziale esattamente come nel caso stazionario. Successivamente abbiamo testato il codice su un problema più complicato, ovvero la propagazione di una discontinutà nel dominio: ∂u ∂u + =0 t > 0, 0 < x < 2 ∂t ∂x (9.6) u(x, 0) = 0 0 ≤ x ≤ 2 u(0, t) = 1 t>0 In questo caso l’uso di metodi espliciti porta alla formazioni di oscillazioni intorno alla discontinuità viaggiante. Queste oscillazioni sono tuttavia limitate alla lunghezza di un elemento grazie all’uso di elementi discontinui. Possiamo notare questo fenomeno in Figura 8, dove abbiamo usato il metodo RK4 per l’avanzamento in tempo. Il punto di massima ampiezza dell’oscillazione (overshooting) si avvicina alla discontinuità all’aumentare del grado degli elementi N . Si osservi l’immagine in Figura 9 per notare questo fenomeno. L’uso di metodi di avanzamento in tempo impliciti come il metodo di Eulero all’indietro permette di ottenere soluzioni che non presentano oscillazioni lungo le discontinuità. Inoltre, questo metodo è fortemente stabile senza alcuna restrizione su ∆t. Tuttavia, la scelta di passi temporali troppo grandi porta ad un’eccessiva dissipazione del metodo, come è possibile notare in Figura 10. 32 Figura 8: Soluzione del problema (9.6) all’istante t = 0.815. Discretizzazione con M = 20 elementi ognuno di grado N = 10 (sinistra). Particolare dell’oscillazione a monte della discontinuità viaggiante (destra) Figura 9: Particolare sulla discontinuità del problema (9.6) per vari valori di N 10 Una possibile applicazione: dinamica delle popolazioni Una possibile applicazione del nostro codice è la risoluzione del sistema di LotkaMcKendrick, che descrive l’evoluzione in tempo di una popolazione strutturata per età. In particolare, il modello che studieremo fa riferimento alla situazione ideale in cui la popolazione sia isolata (ovvero non soggetta a immigrazione o emigrazione) e costituita 33 Figura 10: Visualizzazione della soluzione del problema (9.6)(sinistra) e di un problema rappresentante un’onda sinusoidale viaggiante (destra) discretizzati con M = 10 elementi di grado N = 12 all’istante t = 1. Metodo di avanzamento in tempo di Eulero all’indietro con differenti passi temporali ∆t . da individui perfettamente uguali che si differenziano solamente per la loro età. Siano quindi le variabili del problema l’età degli individui x ∈ [0, x† ], dove x† < +∞ è l’età massima che un individuo può raggiungere e il tempo t > 0. Sia u(x, t) la funzione evolutiva della popolazione detta densità di popolazione. Nel modello lineare classico di Lotka-McKendrick la densità di popolazione soddisfa la legge del bilanciamento: ∂u ∂u + = −µ(x)u ∂t ∂x dove µ(x) è il tasso di mortalità di individui dell’età x, e per x = 0 abbiamo la legge delle nascite che costituisce la condizione al bordo del nostro problema: Z x† β(x)u(x, t)dx u(0, t) = 0 dove β(x) è il tasso di fertilità di individui dell’età x, ovvero il numero medio di nascite nell’unità di tempo che si attribuiscono ad un singolo individuo di età x, e per t = 0 abbiamo la condizione iniziale u(x, 0) = u0 (x) Per ottenere la buona posizione del problema dobbiamo formulare le seguenti ipotesi: β(x) ≥ 0, β(x) ∈ L∞ (0, x† ) µ(x) ≥ 0, µ(x) ∈ L1loc (0, x† ) Z x† µ(x)dx = +∞ 0 u0 (x) ≥ 0, u0 (x) ∈ L1 (0, x† ) 34 (10.1) che assicurano l’esistenza e unicità della soluzione (si vedano le referenze citate in [7]). Si noti che anche nel caso di una funzione di densità iniziale u0 continua e regolare il problema può sviluppare delle discontinuità se non è verificata la seguente uguaglianza: Z x† u0 (0) = β(x)u0 (x)dx (10.2) 0 La presenza dell’ipotesi (10.1.3) serve sostanzialmente ad assicurare che la probabilità di sopravvivenza π(x): Rx π(x) = e− 0 µ(τ )dτ si annulli per x = x† . In questo modo si assicura che x† < +∞. Quest’ipotesi è la più delicata da trattare da un punto di vista numerico, poichè una formulazione del tasso di mortalità consistente con il suo significato biologico può ad esempio essere: µ(x) = λ (x† − x) che tende a +∞ per x → x† . Per ovviare alle difficoltà insorgenti dal trattamento numerico di un dato del genere in letteratura è stata proposta una formulazione alternativa del problema (detta equazione di rinnovo, che è un’equazione integrale di tipo Volterra). Nel nostro caso non tratteremo funzioni di tassi di mortalità tendenti a infinito. Un parametro molto utile alla comprensione del comportamento asintotico del modello di popolazione è il tasso di riproduzione Z x† R= β(x)π(x)dx 0 che rappresenta il numero di nascite che mediamente si attribuiscono ad un individuo nell’arco di tutta la sua vita. Se R > (<)1 la popolazione sarà in crescita (calo) mentre se R = 1 sarà in assetto stabile. Lo studio del modello di Lotka-McKendrick tramite il codice ad elementi spettrali discontinui da noi implementato per il problema di trasporto è abbastanza diretto: la principale implementazione supplementare da apportare al codice è quella di fornire alla classe problema.hpp un metodo di aggiornamento in tempo del termine noto che dipenda dalla soluzione u stessa; in questo modo potremo soddisfare la condizione al bordo del nostro problema. D’altro canto, questo può essere considerato come un punto di partenza per l’implementazione di metodi di soluzione di leggi di conservazione non lineari. Notiamo inoltre che la non linearità del problema impedisce l’uso di metodi di avanzamento in tempo impliciti; useremo quindi nelle simulazioni seguenti il metodo esplicito RK4. 35 1. Simuliamo in un primo caso il seguente problema: 1 ∂u ∂u + =− u t > 0, 0 < x < 1 ∂x 1+ε−x ∂t Z 1 1 e− 2 u(0, t) = u(x, t)dx t>0 −1 0 1−e 2 1 2 u(x, 0) = (1 − x)e− 2 (1−x) 0≤x≤1 (10.3) che equivale a risolvere il modello di Lotka-McKendrick con le espressioni analitiche dei tassi di mortalità e fertilità: µ(x) = β(x) = 1 , 1+ε−x 1 e− 2 ε>0 1 1 − e− 2 Abbiamo scelto questa espressione per il tasso di mortalità (e imposto ε = 10−3 ) in Figura 11: Tassi di mortalità, di fertilità, soluzione iniziale e andamento della soluzione per t ∈ [0, 5] per il problema (10.3) 36 modo da avere un rapido aumento nell’intorno di x† = 1. La scelta del tasso di fertilità e della soluzione iniziale assicurano che la condizione (10.2) sia soddisfatta: non si sviluppano quindi discontinuità. Si verifica inotre che il tasso di riproduzione R è inferiore a 1, ovvero che la popolazione è in estinzione. La simulazione effettuata con il nostro codice, con una discretizzazione spaziale di M = 10 elementi di grado N = 4 ed un metodo di avanzamento in tempo RK4 con ∆t = 2, 5 · 10−3 , il cui risultato è osservabile in Figura 11, conferma le affermazioni teoriche fatte. 2. Simuliamo ora un caso in cui si presenti una discontinuità, ovvero scegliamo una condizione iniziale differente da quella precedente: ∂u ∂u 1 + =− u t > 0, 0 < x < 1 ∂x 1+ε−x ∂t Z 1 1 (10.4) u(0, t) = u(x, t)dx t>0 1 + ε 0 2 u(x, 0) = (1 − x)e1−x 0≤x≤1 1 Si verifica inoltre che la scelta di β(x) = 1 +ε implica che il tasso di riproduzione sia 2 R = 1, ovvero che la popolazione sia in assetto stabile (ed esista quindi una soluzione stazionaria del problema). La simulazione è stata effettuata con M = 20 elementi di Figura 12: Soluzione iniziale e andamento della soluzione per t ∈ [0, 2] per il problema (10.4) di grado N = 4, con passo di discretizzazione temporale ∆t = 1 · 10−3 e il risultato è apprezzabile in Figura 12. 3. Simuliamo ora il caso in cui la formula del tasso di fertilità abbia una formula più attinente al suo significato fisico: prendiamo ad esempio β(x) = −θ(x − a0 )(x − a1 )χ[a0 ,a1 ] 37 che rappresenta la parte positiva dell’arco di parabola con concavità verso il basso di radici a0 e a1 . Prendiamo la costante θ = θ∗ in modo che la popolazione sia in assetto stabile. Imponiamo inoltre che per t > 1 il tasso di fertilità abbia un brusco abbassamento in modo da portare all’estinzione la popolazione. Sia quindi ad esempio 0≤t≤1 −θ∗ (x − 0.15)(x − 0.5)χ[0.15,0.5] (x) ∗ β(x, t) = − θ (x − 0.15)(x − 0.5)χ[0.15,0.5] (x) 1<t≤4 2 mentre il tasso di mortalità e la soluzione iniziale sono uguali a quelli del caso (10.4). Abbiamo condotto la simulazione usando M = 20 elementi di grado N = 6 con metodo di avanzamento RK4 con passo ∆t = 1 · 10−3 . Il risultato della simulazione è apprezzabile in Figura 13. Figura 13: Tasso di fertilità e andamento della soluzione per t ∈ [0, 4] per la terza simulazione 38 11 Conclusioni Il risultato del nostro lavoro consiste in un codice in C++ per la risoluzione di problemi monodimensionali di trasporto-reazione tramite elementi spettrali discontinui. Siamo arrivati a questo risultato attraverso vari passaggi: a partire dall’implementazione di funzioni che calcolino le radici di un polinomio, passando per il calcolo dei nodi e pesi di integrazione per la formula di Gauss-Lobatto-Legendre fino all’avanzamento in tempo del problema completamente discretizzato. Abbiamo comunque scelto di lavorare utilizzando matrici di tipo pieno poichè, a causa della bassa dimensionalità del problema, il passaggio alla memorizzazione di matrici in altro formato non avrebbe portato a vantaggi rilevanti. Abbiamo compreso le potenzialità e la flessibilità della programmazione ad oggetti grazie alla quale il nostro codice assume, a nostro parere, una forma comprensibile e di facile manutenzione. Per quanto riguarda eventuali sviluppi futuri, grazie all’implementazione di metodi che aggiornano la matrice di rigidezza ad ogni istante temporale il codice si presta ad un’estensione per la risoluzione di problemi non lineari. D’altro canto, l’implementazione del metodo di soluzione per l’equazione di Lotka-McKendrick rappresenta un primo passo concreto in questa direzione. Per quanto riguarda l’estensione a più dimensioni riteniamo che la struttura del problema cambi notevolmente, e di conseguenza alcune semplificazioni che abbiamo potuto implementare (quali il metodo di inserimento dei termini della matrice di rigidezza) richiederanno uno studio più accurato. 39 Riferimenti bibliografici [1] C. Canuto, M. Y. Hussaini, A. Quarteroni, and T. A. Zang. Spectral Methods. Fundamentals in Single Domains. Springer-Verlag, 2006. [2] C. Caudai. Modelli matematici di popolazioni strutturate per età. Master’s thesis, Università degli Studi di Pisa, Corso di Laurea in Matematica; Relatore: Prof. Paolo Acquistapace, 2003. [3] D. Gottlieb and J. Hesthaven. Spectral methods for hyperbolic problems. J. Comput. Appl. Math., 128:83–131, 2001. [4] P. Houston, C. Schwab, and E. Süli. Discontinuous hp-finite element methods for advection-diffusion-reaction problems. SIAM Journal on Numerical Analysis, 39(6):2133–2163, 2002. [5] C. Johnson and J. Pitkäranta. Analysis of the discontinuous Galerkin method for a scalar hyperbolic equation. Mathematics of Computation, 46(173):1–26, 1986. [6] M. Y. Kim. Discontinuous Galerkin methods for a model of population dynamics with unbounded mortality. SIAM J. Sci. Comput., 27(4):1371–1393, 2006. [7] G. Pelovska and M. Iannelli. Numerical methods for the Lotka-McKendrick’s equation. J. Comput. Appl. Math., 197(2):534–557, 2006. [8] A. Quarteroni. Modellistica Numerica per Problemi Differenziali. Springer, 2006. [9] A. Quarteroni, R. Sacco, and F. Saleri. Matematica Numerica. Springer-Verlag, 2002. [10] S. Salsa. Equazioni a derivate parziali. Springer-Verlag, 2004. [11] D. Yang. C++ and Object Oriented Numeric Computing for Scientiscts and Engineers. Springer, 2001. 40