here - Department of Mathematics

Transcript

here - Department of Mathematics
POLITECNICO DI MILANO
Facoltà di Ingegneria dei Sistemi
Corso di Studi in Ingegneria Matematica
Progetto di Programmazione Avanzata per il Calcolo Scientifico
Implementazione di un Problema di
Controllo Ottimo
- Estensione della libreria GasFramework -
Professore:
Prof. Formaggia Luca
Studente:
Signorini Marianna
matr. 766131
Anno Accademico 2011-2012
Indice
1 Aspetti Teorici
1.1 Controllo Ottimo per Equazioni a Derivate Parziali . . . . . . . . . . . . .
1.1.1 Introduzione e notazioni . . . . . . . . . . . . . . . . . . . . . . . .
1.1.2 Minimizzazione di Funzionali: Risultati di Esistenza e Unicità . . .
1.1.3 Controllo di Sistemi Governati da Equazioni a Derivate Parziali di
Tipo Ellittico . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.2 Risoluzione del Sistema di Ottimalità . . . . . . . . . . . . . . . . . . . . .
2 Implementazione
2.1 C triangulation.hpp
2.2 Input.hpp . . . . . .
2.3 C aux matrices.hpp
2.4 C problem.hpp . . .
2.5 C functional.hpp . .
2.6 C solver.hpp . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
3
3
3
4
.
.
5
7
.
.
.
.
.
.
11
12
14
14
16
18
18
3 Risultati Numerici
21
3.1 Convergenza Elementi Finiti . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
3.2 Risultati sul Controllo Ottimo . . . . . . . . . . . . . . . . . . . . . . . . . . 21
i
ii
Indice
Elenco dei codici
2.1
2.2
2.3
2.4
2.5
2.6
2.7
2.8
2.9
2.10
3.1
C Triangulation.hpp - Costruttore . . . . . . . . .
Input.hpp - Condizione di Neumann . . . . . . . .
C Triangulation.hpp - Ordinamento dei vertici . .
Input.hpp - Definizione di un Problema . . . . . .
C aux matrices.hpp - C matrixB . . . . . . . . . .
C problem.hpp - C problem . . . . . . . . . . . . .
C problem.hpp - Solver del problema Ay = f + Bu
C functional.hpp - C Functional dd . . . . . . . .
C solver.hpp - C Solver . . . . . . . . . . . . . . .
C solver.hpp - CG . . . . . . . . . . . . . . . . . .
data.txt . . . . . . . . . . . . . . . . . . . . . . . .
iii
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
12
13
13
15
16
17
17
18
19
20
22
iv
Elenco dei codici
Introduzione
L’obiettivo principale di questo progetto è stato quello di implementare la risoluzione di un
problema di controllo ottimo. Obiettivo secondario è stato quello di estendere il solutore
già presente in GasFramework (per un problema di Poisson con condizioni al bordo di
Dirichlet omogenee), creando un solutore per problemi ellittici generici.
Nei diversi capitoli di questo elaborato viene descritta la problematica del controllo ottimo,
i metodi risolutivi, l’implementazione e i risultati numerici ottenuti.
In particolare, questa relazione viene suddivisa nel modo seguente.
• Nel Primo Capitolo viene affrontato l’argomento del controllo ottimo a livello teorico,
vengono descritti i problemi implementati nel codice e i metodi iterativi risolutivi
per il problema. Viene tralasciata la teoria di Galerkin Elementi Finiti, la quale
verrà citata nell’elaborato ove necessario.
• Nel Secondo Capitolo si descrive in maniera approfondita la parte del codice implementata in questo progetto, tralasciando le parti già presenti in GasFramework 1 .
L’organizzazione di questo capitolo dovrebbe permettere la comprensione della struttura del codice.
• Nel Terzo Capitolo vengono presentati i principali risultati numerici ottenuti testando il codice EF e il controllo ottimo. Questa analisi è fondamentale per verificare
il corretto funzionamento del codice.
1
Tali parti sono descritte in [5] e al link http://code.google.com/p/gas-framework/
1
2
Elenco dei codici
Capitolo
1
Aspetti Teorici
1.1
Controllo Ottimo per Equazioni a Derivate Parziali
In questa sezione si vuole introdurre la teoria del controllo ottimo e darne i principali
risultati teorici. Questa teoria si trova in [2] e in [4].
1.1.1
Introduzione e notazioni
Per poter sviluppare una teoria sul controllo ottimo, è necessario introdurre le seguenti
notazioni e definizioni:
• Il controllo u, appartenente ad uno spazio funzionale Uad (lo spazio dei controlli
ammissibili), tipicamente un sottospazio chiuso e limitato di uno spazio di Hilbert
U;
• La funzione di stato y = y(u) ∈ V , con V spazio di Hilbert, che è lo stato del
sistema che deve essere controllato da u. La funzione y(u) è la soluzione del sistema
di stato:
Ay(u) = f (u)
dove A : V → V 0 è un operatore noto, e f ∈ V 0 una funzione nota di u;
• L’osservazione z = z(u) ∈ Z, con Z spazio di Hilbert, che dipende dal controllo u
attraverso la funzione di stato e un operatore di osservazione C : V → Z continuo
e lineare:
z(u) = Cy(u) .
Questa funzione deve essere confrontata con l’osservazione desiderata zd , che è
l’obiettivo da raggiungere.
• Il funzionale costo J(u) : Uad → R
u ∈ Uad 7→ J(u) ∈ R
• Il problema di controllo: trovare il controllo ottimo u ∈ Uad tale che
J(u) = inf J(v)
v∈ Uad
o, equivalentemente, tale che
J(u) ≤ J(v) ∀ v ∈ Uad
3
4
Capitolo 1. Aspetti Teorici
1.1.2
Minimizzazione di Funzionali: Risultati di Esistenza e Unicità
Sia U uno spazio di Hilbert, dotato del prodotto interno (·, ·), e con norma k · k:=
Consideriamo la seguente forma bilineare su U
u, v 7→ π(u, v) ∀u, v ∈ U
p
(·, ·).
(1.1)
supposta simmetrica, e il seguente funzionale lineare e continuo su U
v 7→ L(v) ∀v ∈ U
(1.2)
Inoltre, sia Uad un sottospazio di U chiuso e convesso. Consideriamo ora il funzionale
costo, della forma:
J(v) = π(v, v) − 2L(v) ∀v ∈ Uad
(1.3)
L’esistenza e unicità del minimo di (1.1.2) è data dai seguenti teoremi. Le dimostrazioni
possono essere trovate in [2].
Teorema 1. Sia π(·, ·) coerciva su U :
∃α : π(v, v) > α k v k2
∀v ∈ U .
Allora esiste un unico elemento u ∈ Uad tale che
J(u) = inf J(v) .
(1.4)
v∈Uad
Teorema 2. Sotto le ipotesi del precedente Teorema,
1. L’elemento minimizzante u ∈ Uad è caratterizzato dalla seguente disuguaglianza:
π(u, v − u) > L(v − u)
v ∈ Uad
(1.5)
2. Se assumiamo anche che il funzionale v 7→ L(v) è strettamente convesso e differenziabile, e che il funzionale costo soddisfa la condizione seguente:
J(v) −→ +∞
as k v k−→ +∞
(1.6)
allora l’unica u ∈ Uad che soddisfi (1.4) è caratterizzata dalla seguente disuguaglianza:
DJ(u)[v − u] > 0 ∀v ∈ Uad
(1.7)
dove con DJ(u) si è indicata la derivata di Gateaux di J in u, definita come
l’operatore lineare DJ(u) : Uad → R tale che
J(u + δφ) − J(u)
δ→0
δ
J 0 (u)[φ] = lim
∀φ ∈ Uad
Corollario 1. Sotto le ipotesi del Teorema 2, nel caso in cui Uad = U , la (1.5) diventa:
π(u, φ) = L(φ)
∀φ ∈ U
ed è detta Equazione di Eulero associata al problema di minimo (1.4).
Corollario 2. Sotto le ipotesi del Teorema 2, la caratterizzazione (1.7) è equivalente a:
J 0 (v)[v − u] > 0
∀u ∈ Uad
1.1. Controllo Ottimo per Equazioni a Derivate Parziali
1.1.3
5
Controllo di Sistemi Governati da Equazioni a Derivate Parziali
di Tipo Ellittico
In questa sezione sarà innanzitutto introdotto il formalismo matematico necessario per
trattare il problema, e in secondo luogo si applicherà la teoria generale già discussa a
questa tipologia di problemi.
Formulazione e buona positura del problema
Siano V e H due spazi di Hilbert su R, e sia V ,→ H, con iniezione densa e continua. Ciò
significa che V ⊂ H, che ∃c > 0 tale che
k v kH 6 c k v kV
∀v ∈ V
e che V è denso in H.
In questo caso, indicando gli spazi duali di V e H rispettivamente con V 0 e H 0 , risulta
V ,→ H w H 0 ,→ V 0
(1.8)
e la tripletta (V, H, V 0 ) è detta terna hilbertiana.
Infine sia
a:V ×V →R
una forma bilineare continua e coerciva su V , e sia
L:V →R
un funzionale lineare e continuo su V .
Grazie al Teorema di Rappresentazione di Riesz e a (1.8), esiste un unico elemento f ∈ V 0
tale che
L(f ) = V 0 hf, viV
che è equavalente a L(f ) = (f, v)H nel caso in cui f ∈ H.
Inoltre vale il seguente
Lemma 1. (Lax-Milgram) Sotto le ipotesi precedenti su a(·, ·), per una data f ∈ V 0 ,
esiste un unico u ∈ V tale che:
a(u, v) = V 0 hf, viV
∀v ∈ V.
(1.9)
Si può riscrivere (1.9) notando che la forma bilineare v 7→ a(u, v) è lineare e continua
su V rispetto al secondo argomento e quindi, grazie al Teorema di Rappresentazione di
Riesz, esiste un operatore lineare A ∈ L (V, V 0 ) tale che
a(u, v) = V 0 hAu, viV
(1.10)
in V 0 .
(1.11)
Quindi (1.9) è equivalente a
Au = f
Ora è possibile formulare il problema di controllo, in accordo con il quadro generale descritto nella Sezione 1.1.1.
Sia lo spazio di Hilbert U lo spazio dei controlli, e sia B ∈ L (U, V 0 ). La variabile di
stato y(u) ∈ V è governata dalla seguente equazione detta equazione di stato:
Ay(u) = f + Bu
in V 0 .
(1.12)
6
Capitolo 1. Aspetti Teorici
Si può notare che questa equazione definisce univocamente y(u), grazie al Lemma 1. L’operatore B può essere, ad esempio, l’operatore identità o un operatore di restrizione, come
ad esempio quello di traccia. L’equazione di osservazione è invece della forma:
z(u) = Cy(u)
(1.13)
dove C ∈ L(V, H).
Infine, sia N ∈ L(U, U ), con N simmetrico e definito positivo e tale che ∃ν > 0 :
(N u, u)U ≥ ν k u k2U
(1.14)
Il termine (N u, u)U è chiamato termine di penalizzazione.
Per ogni controllo u ∈ U , si può associare il funzionale costo
1
J(u) = (k Cy(u) − zd k2H +β(N u, u)U )
2
(1.15)
dove zd ∈ H è l’osservazione desiderata.
Può essere dimostrato che vale il seguente
Teorema 3. Sotto tutte le ipotesi e le assunzioni fatte nella Sezione 1.1.3, esiste un unico
elemento u ∈ Uad tale che
J(u) = inf J(v) .
(1.16)
v∈Uad
L’elemento u è detto controllo ottimo.
L’insieme di disuguaglianze che definiscono il controllo ottimo
Dal paragrafo precedente è noto che, sotto certe ipotesi, può essere dimostrata l’esistenza
ed unicità del controllo ottimo. Per poter risolvere numericamente il problema, si può
dimostrare che vale il seguente
Teorema 4. Si assuma che valgano tutte le ipotesi e definizioni fatte nella Sezione 1.1.3,
tranne l’ipotesi (1.14). Una condizione necessaria e sufficiente affinché u sia un controllo
ottimo è che valgano le seguenti equazioni (dette sistema di ottimalità):


Ay(u) = f + Bu
A∗ p(u) = C ∗ Λ(C(y(u) − zd ))

 −1 ∗
ΛU B p(u) + βN (u) = 0
in V 0
in V 0
in Uad .
(1.17)
Dove con Λ = ΛH e ΛU si indicano gli isomorfismi canonici da H in H 0 e da U in U 0 , e
con A∗ ∈ L(V, V 0 ), C ∗ ∈ L(H 0 , V 0 ) e B ∗ ∈ L(V, U 0 ) gli operatori aggiunti di A, C e B.
Inoltre, se N soddisfa (1.14), il controllo ottimo è unico.
Se invece N = 0 e Uad è limitato, esiste almeno una soluzione.
Infine, se N = 0 e
∃α0 > 0 : k Cy(u) − zd k2H > α0 k u k2U
allora il controllo ottimo è unico.
∀u ∈ Uad ,
1.2. Risoluzione del Sistema di Ottimalità
7
Esempi: problemi di controllo implementati
Nel seguito vengono descritti i problemi di controllo che sono stati implementati nel
progetto.
• Osservazione e controllo distribuiti
In questo primo caso, secondo le notazioni introdotte, risulta V = H 1 (Ω), Uad =
L2 (Ω), Z = L2 (Ω), C è l’immersione di H 1 (Ω) in L2 (Ω), N u = u e Bv = v in L2 (Ω).
In particolare la derivata di Gateaux del funzionale assume la forma:
DJ(u) = p + βu ∈ L2 (Ω) .
• Osservazione distribuita e controllo al bordo
In questo secondo caso, secondo le notazioni introdotte, risulta V = H 1 (Ω), Uad =
L2 (∂Ω) e il controllo rientra come condizione di Neumann, Z = L2 (Ω), C è l’immersione di H 1 (Ω) in L2 (Ω), N u = u in L2 (∂Ω) e B è l’operatore da H 1 (Ω) in L2 (∂Ω).
In particolare la derivata di Gateaux del funzionale assume la forma:
DJ(u) = Bp + βu ∈ L2 (∂Ω) .
1.2
Risoluzione del Sistema di Ottimalità
In questa sezione si vogliono descrivere i principali strumenti utilizzati per la risoluzione
del problema di controllo ottimo. In particolare, si discuteranno gli algoritmi utilizzati per
la risoluzione del sistema di ottimalità (1.17), dopo essere opportunamente discretizzato
tramite il metodo di Galerkin Elementi Finiti. La teoria di Galerkin Elementi Finiti verrà
utilizzata anche nell’analisi dei risultati numerici (Capitolo 3), ma non verrà trattata in
modo approfondito a livello teorico1 .
Il sistema di ottimalità discretizzato può essere risolto in maniera diretta tramite un
approccio one shot, fornendo il controllo ottimo, lo stato del sistema e la variabile duale.
Tuttavia questo approccio non è stato adottato in questo progetto.
Infatti il sistema in questione può essere risolto anche iterativamente ricordando che l’obiettivo del problema di controllo ottimo è minimizzare il funzionale costo definito in (1.15)
e quindi, essendo il funzionale quadratico, azzerare la sua derivata di Gateaux. In particolare la terza equazione del sistema (1.17) pone la derivata di Gateaux del funzionale
pari a zero. L’obiettivo del metodo iterativo sarà quindi quello di trovare il minimo del
funzionale, ovvero risolvere la terza equazione del sistema, risolvendo le altre in maniera
diretta, ad ogni passo del metodo iterativo.
Con un abuso di notazioni, vengono nel seguito indicati con le stesse notazioni presenti
nel sistema di ottimalità le matrici ottenute discretizzando la formulazione debole di tale
sistema. Le variabili in grassetto indicheranno i vettori dei valori nodali delle variabili.
Lo schema generale di un metodo iterativo di discesa applicato alla discretizzazione del
sistema (1.17) viene riportato nel seguente riquadro:
1
Per una teoria esaustiva vedere [4]
8
Capitolo 1. Aspetti Teorici
Dato u0 , una tolleranza toll e un numero massimo di iterazioni,
per k = 0, 1, 2, ..
do {
Ayk = f + Buk
A∗ pk = C ∗ Λ(C(yk − zd ))
∗ k
DJk = Λ−1
U B p + βN uk
calcolo una direzione di discesa dk
calcolo il passo nella direzione di discesa αk
uk+1 = uk + αk dk
} while (non ho raggiunto la tolleranza desiderata
o il massimo numero di iterazioni)
I diversi metodi iterativi si differenziano per la scelta della direzione di discesa. In questo
progetto sono stati implementati il metodo del gradiente (SD) e il metodo del gradiente
coniugato (CG). In questi due casi si ha:
SD:
dk = −DJk ,
CG:
d0 = −DJ0 ,
βk+1 =
k DJk+1 k2
,
k DJk k2
dk+1 = −DJk+1 + βk+1 dk .
In particolare, nel caso del gradiente coniugato, a causa di errori numerici, è possibile che
la direzione dk non sia una direzione di discesa. Per evitare questo problema, tipicamente
viene implementata una versione alternativa di questo metodo: il metodo del gradiente
coniugato con restart. In questa variante del CG ogni K passi viene fatto il restart,
prendendo come direzione di discesa quella del gradiente. Questa versione è quella che è
stata implementata nel progetto, con la possibilità di scegliere dopo quanti passi si desidera
effettuare il restart. Inoltre nel progetto sono stati implementati dei casi in cui viene fatto
il restart automaticamente, fino ad un massimo di due volte: il primo caso è il quello in cui
la direzione prescelta non sia una direzione di discesa, e il secondo è quello in cui il passo
sia troppo picccolo, ma la norma del gradiente non sia ancora inferiore alla tolleranza
prefissata. Questa scelta porta sia a vantaggi che a svantaggi. Infatti vi sono casi in cui
effettivamente viene di molto migliorata la prestazione del metodo. Ve ne sono però altri
in cui il numero di iterazioni viene inutilmente aumentato di due. La scelta di applicare
anche questo tipo di restart è stata dettata dal fatto che l’obiettivo primario è quello di
garantire, ove possbile, la convergenza del metodo.
La scelta del passo αk è molto delicata in quanto potrebbe causare la non convergenza o
un aumento del numero di iterazioni dei metodi iterativi. Il parametro αk andrebbe scelto
ad ogni iterazione in modo tale da minimizzare il funzionale nella direzione di discesa dk ,
ovvero la funzione
g(α) = J(uk + αdk ) .
Solitamente non si procede con una ricerca esatta di αk , ma si ricerca un passo che
diminuisca almeno sufficientemente il valore del funzionale2 . In particolare viene ricercato
un passo αk che soddisfi la condizione di Armijo:
J(uk + αk dk ) 6 J(uk ) + c1 αk (DJk , dk ) ,
2
Esistono condizioni che garantiscano un passo sufficiente e necessario(condizioni di Wolfe o
Goldenstain), ma in questo lavoro sono state considerati solo passi sufficienti.
1.2. Risoluzione del Sistema di Ottimalità
9
dove c1 ∈ (0, 1). Tale proprietà garantisce che J(uk+1 ) < J(uk ) strettamente.
Per trovare il passo αk si considera, per ogni iterazione del metodo iterativo, un valore
iniziale di α , α = α0 e si diminuisce tale passo iterativamente, ad esempio dimezzandolo,
finché non si soddisfa il criterio di Armijo o non è stato raggiunto un numero massimo di
iterazioni. Il valore finale di questo procedimento sarà αk .
Per quanto riguarda la scelta di α0 , ci sono diverse possibilità. Di seguito verrà descritta
quella adottata nel progetto. Poiché l’obiettivo è quello di minimizzare g(α), l’idea è quella
di prendere come α0 un valore sufficientemente elevato tale che, detto α∗ = argminα g(α),
risulti α∗ ∈ [0, α0 ]. Innanzitutto si può notare dal sistema di ottimalità discretizzato che
DJ è lineare affine nel suo argomento, ovvero che
b : DJ(u) = Au
b +b
∃A
f,
dove b
f = DJ(0). Si può quindi prendere come α0 = 2b
α. Per il calcolo di α
b si calcola il
punto in cui si annulla la derivata prima di g(α). Risulta infatti:
g 0 (b
α) = (DJ(uk + α
bdk ), dk ) = 0
b k+α
(A(u
bdk ) + b
f , dk ) = 0
b k) + b
b αdk ) + α
(A(u
f + A(b
bb
f −α
bb
f , dk ) = 0
(DJ(uk ) + α
b(DJ(dk ) − b
f ), dk ) = 0
da cui, grazie alla linearità del prodotto scalare,
α
b=−
(DJ(uk ), dk )
.
(DJ(dk ) − b
f , dk )
Nel caso in cui questo passo iniziale sia troppo piccolo, viene considerato α0 = 1.
10
Capitolo 1. Aspetti Teorici
Capitolo
2
Implementazione
In questo capitolo, prima di procedere alla descrizione delle varie classi implementate, si
vogliono delineare le librerie esterne utilizzate, le scelte effettuate e l’impostazione globale
del lavoro.
Innanzitutto vengono di seguito elencati librerie e tools esterni utilizzati:
• Per la gestione di matrici e vettori sono state ulitizzate la libreria Eigen3 1 per la
gestione di matrici sparse e per la risoluzione dei sistemi lineari con matrici sparse e la
Standard Template Library nei casi in cui fossero necessari degli algoritmi contenuti
nell’header <algorithm>.
• Per la creazione della mesh è stata utilizzata la libreria CGAL2 , su cui è basata la
classe triangulation, descritta nella Sezione 2.1.
• Per la creazione del Makefile è stato utilizzato il tool CMake 3 . Questo tool, tramite
alcune direttive, crea in automatico il Makefile per la compilazione e il linking,
semplificando la creazione del Makefile.
In secondo luogo si vogliono descrivere le principali scelte di programmazione effettuate:
• È stato deciso di mantenere la stessa filosofia di programmazione adottata in GasFramework, creando una libreria costruita solo da header files. Tale scelta può
portare sia benefici che svantaggi. Da una parte, infatti, non è necessario compilare
ed installare la libreria, ma è sufficiente indicare al compilatore la sua posizione.
D’altra parte, nel caso di una modifica alla libreria, è necessario ricompilare tutti i
codici che dipendono da essa. Tale approccio causa inoltre un aumento del tempo
di compilazione, che comunque rimane modesto.
• Tutte le classi inerenti la costruzione e risoluzione del problema di controllo appartengono al namespace gas :: control. È stata fatta questa scelta in modo tale da
caratterizzare tutti gli elementi di questa nuova parte con lo stesso namespace.
Infine, per quanto riguarda l’impostazione globale del lavoro, si può dire quanto segue:
• Innanzitutto è stata costruita una classe, la classe C problem, che risolvesse con elementi finiti P1 un generico problema ellittico, con condizioni al bordo non omogenee
sia di Dirichlet che di Neumann (Per dettagli sull’implementazione vedere la Sezione
1
per la documentazione vedere il link http://eigen.tuxfamily.org/index.php?title=Main Page
per la documentazione vedere il link http://www.cgal.org/
3
per la documentazione vedere il link http://www.cmake.org/
2
11
12
Capitolo 2. Implementazione
2.4). Infatti in GasFramework era stato costruito un esempio per la risoluzione del
problema di Poisson con condizioni al bordo di Dirichlet omogenee. Uno degli obiettivi di questo progetto è stato quello di rendere più generico il problema da risolvere.
Per fare ciò è stata estesa anche la classe triangulation.
• In secondo luogo è stato implementato il problema del controllo ottimo, obiettivo
principale di questo progetto. Per fare ciò è stato necessario ampliare la classe
C problem in modo tale che risolvesse problemi del tipo Ay = f + Bu, adatta
per la risoluzione dei problemi primali e duali, costruire le classi C Functional dd e
C Functional db, che calcolassero il valore del funzionale da minimizzare e della sua
derivata in un punto, e costruire la classe C Solver con le sue classi derivate per la
risoluzione iterativa del problema.
Di seguito sono descritte le classi implementate e il loro scopo. Per le classi che sono state
estese da GasFramework vengono sottolineate solo le nuove implementazioni4 . L’ordine
scelto nel seguito del capitolo permette la comprensione dell’organizzazione del programma.
2.1
C triangulation.hpp
Classe triangulation
Questa classe è necessaria per la definizione della triangolazione del dominio. Per la
creazione della mesh viene utilizzata la libreria CGAL. La struttura generale della classe è
stata presa da quella già esistente presente in GasFramework, ma la classe è stata ampliata
per fornire nuove funzionalità. In particolare, ora è possibile avere una partizione dei nodi
di bordo in nodi di Dirichlet e di Neumann e, nel caso di dominio rettangolare, avere una
lista dei lati di Neumann. Queste nuove implementazioni permettono l’imposizione delle
condizioni al bordo di Dirichlet nel caso di domini che siano poligoni convessi generici, e
delle condizioni di Neumann non omogenee nel caso di domini cartesiani.
Si precisa che la mesh è pensata per poligoni convessi generici, ma che la lista dei lati di
Neumann è costruita presupponendo il dominio rettangolare poiché questa proprietà viene
sfruttata per l’ordinamento dei nodi di bordo.
Al costruttore della triangolazione vanno passati la lista dei nodi di bordo tramite gli
iteratori di inizio e fine della lista begin e end, la condizione di Neumann neu cond e la
massima ampiezza degli elementi h (Codice 2.1).
1
2
3
4
5
6
class triangulation{
public:
template <typename iterator , typename neumann cond>
triangulation (iterator begin, iterator end, neumann cond const & neu cond,
double h = 0.);
};
Codice 2.1: C Triangulation.hpp - Costruttore
In particolare, neumann cond è un funtore della forma scritta nel Codice 2.2, derivato
pubblicamente dalla classe
template <typename derived > class function<1, derived >,
già implementata in GasFramework. Dato un punto P (x, y), il funtore restituisce 1 se il
4
Per la documentazione di quanto già implementato in GasFramework si rimanda a [5] e al link
http://code.google.com/p/gas-framework/
2.1. C triangulation.hpp
13
punto appartiene al bordo di Neumann, 0 altrimenti. Questo funtore deve essere definito
dall’utente.
1
2
3
4
class neumann cond : public gas::functional::function<2, neumann cond>{
public:
inline double operator()(double const x, double const y) const;
};
Codice 2.2: Input.hpp - Condizione di Neumann
Tra i metodi aggiunti alla preesistente classe, sono fondamentali gli iteratori che puntano
al primo e all’ultimo elemento delle liste dei nodi di Dirichlet e di Neumann e dei lati
di Neumann. I lati sono oggetti della classe edge, aggiunta come membro privato all’interno della classe triangulation. Tale classe fornisce la mappa che porta dall’intervallo
(−1, 1) alle coordinate del lato, che è un segmento in R2 . Tale mappa è necessaria per
permettere l’integrazione 1D su un lato di Neumann utilizzando gli strumenti già forniti
da GasF ramework. Per l’identificazione dei lati di Neumann, inoltre, è stata definita una
classe apposita che fornisce, dati due lati, l’ordinamento (Codice 2.3). Il costruttore della
classe compare prende in ingresso le cordinate degli estremi del dominio (xa, xb) × (ya, yb)
e l’operatore () restituisce 1 se A < B, 0 altrimenti.
Per l’identificazione dei lati di Neumann, vengono dapprima riordinati i nodi di Neumann
in un vector della STL ausiliario secondo l’ordinamento fornito (utilizzando std :: sort
presente nella Standard Template Library - header <algorithm>) e infine vengono assemblati i lati solo se due punti consecutivi appartengono allo stesso lato. Vengono confrontati
anche il primo e l’ultimo elemento del vettore ausiliario.
1
2
3
4
5
6
7
8
9
10
class triangulation{
private:
class compare{
public:
compare(double const & xa=0, double const & xb=1, double const & ya=0,
double const & yb=1);
bool operator()(cdt t::Vertex handle const & A, cdt t::Vertex handle const & B);
...
};
};
Codice 2.3: C Triangulation.hpp - Ordinamento dei vertici
Classi L2 prod d e L2 prod b
L2 prod d e L2 prod b sono due classi ausiliarie che, data la triangolazione in ingresso
al costruttore, calcolano il prodotto scalare in L2 tra due funzioni P1 rappresentate dal
vettore dei valori nei nodi. In particolare, il primo calcola il prodotto suddetto su tutto il
dominio, mentre il secondo solo sul bordo di Neumann.
Nel costruttore viene costruita la matrice di massa Mij = (φj , φi )L2 , i, j = 1..n, dove con
φi si è indicata la funzione base dello spazio P1 relativa al nodo i − esimo (in 2D nel
primo caso e in 1D nel secondo). Per il calcolo dell’integrale sono state utilizzate le classi
di integrazione già implementate in GasFramework. Va sottolineato che, nel caso 1D,
va integrato il prodotto delle funzioni di base esplicitamente moltiplicate per lo jacobiano
della trasformazione del lato a partire dall’intervallo (−1, 1), definendo un apposito funtore
14
Capitolo 2. Implementazione
che lo restituisca.
Per il calcolo del prodotto in L2 viene utilizzata la matrice di massa. È noto infatti che,
se Mij = (φj , φi )L2 , i, j = 1..n è la matrice di massa, dato un vettore u = {ui }i ∈ Rn in
cui siano contenuti i valori nodali della funzione u ∈ P1 , risulta
u=
n
X
ui φi
i=1
e
(u, u)L2 = u0 M u
grazie alla linearità dell’integrale.
Queste due classi sono necessarie per la risoluzione iterativa del problema di controllo
ottimo. La prima deve essere utilizzata nel caso di controllo distribuito, mentre la seconda
nel caso di controllo sul bordo.
2.2
Input.hpp
L’header file Input.hpp è un header file ausiliario al main.cpp e deve essere definito dall’utente per poter formulare il problema. Va incluso direttamente nel main. Nel programma
un esempio di questo file è il file input01.hpp. Qualsiasi funzione che è necessaria per
l’utilizzo del programma va definita come nel Codice 2.2. Per ogni problema che si vuole
definire, inoltre, va scritta una classe apposita che contenga i funtori per la definizione dei
coefficienti, della forzante e delle condizioni al bordo di un problema ellittico del tipo:


−∇ · (ν∇y) + ∇ · (by) + γy = f in Ω
y=g
su ΓD


ν∇y · n − b · ny = h
su ΓN
La classe PROBLEMA va definita come nel Codice 2.4, dove con forzante si definisce f ,
con neumann h, con dirichlet g e dove b = [b1, b2]0 .
2.3
C aux matrices.hpp
Nell’header file C aux matrices.hpp sono implementate le classi per la definizione delle
matrici B e C per la soluzione di un problema di controllo in cui l’equazione di stato può
essere scritto nella forma
AP y = fP + Bu ,
e il problema duale nella forma
AD p = fD + Cy .
In particolare, sono state implementate due varianti per B e una sola per C.
Per quanto riguarda la matrice B, è stata implementata sia la versione in cui il problema
di controllo abbia controllo distribuito C matrixB d, sia quella in cui il controllo sia sul
bordo di Neumann C matrixB b. Entrambe le classi sono ereditate pubblicamente dalla
classe virtuale C matrixB. Nel primo caso B è la matrice di massa relativa alla mesh, a cui
sono state azzerate le righe relative ai nodi di Dirichlet, mentre nel secondo è la matrice di
massa associata ai nodi di Neumann e che estende il controllo a zero sul resto del dominio.
Per quanto riguarda invece la matrice C, è stata implementata solo la versione relativa
all’osservazione distribuita C matrixC d, analoga alla stessa versione di B.
Nel Codice 2.5 vengono riportati gli elementi essenziali della classe.
2.3. C aux matrices.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class PROBLEMA{
public:
// coefficienti del problema
class nu : public gas::functional::function<2,nu>{
public:
inline double operator()(double const x, double const y)const; };
class b1 : public gas::functional::function<2,b1>{
public:
inline double operator()(double const x, double const y)const; };
class b2 : public gas::functional::function<2,b2>{
public:
inline double operator()(double const x, double const y)const; };
class gamma : public gas::functional::function<2,gamma>{
public:
inline double operator()(double const x, double const y)const; };
// forzante del problema
class forzante : public gas::functional::function<2,forzante>{
public:
inline double operator()(double const x, double const y) const; };
//condizioni al bordo
class dirichlet : public gas::functional::function<2,dirichlet>{
public:
inline double operator()(double const x, double const y)const; };
// condizione al bordo di neumann espressa come funzione di una sola variabile
class neumann: public gas::functional::function<1,neumann> {
public:
neumann(double mx,double my,double qx,double qy,double jac,unsigned int n);
inline double operator()(double const x) const; };
};
Codice 2.4: Input.hpp - Definizione di un Problema
15
16
1
2
3
4
5
6
7
8
9
10
11
12
13
Capitolo 2. Implementazione
class C matrixB{
...
public:
// Costruttore
C matrixB(triangulation const & cdt){};
// metodo che restituisce la matrice B
//la classe C matrixC ha un metodo analogo: matrix t const & C();
matrix t const & B();
// numero di righe della matrice
unsigned int const & n1();
// Distruttore
virtual ˜C matrixB(){};
... };
14
15
16
17
18
class C matrixB d:public C matrixB{
public:
C matrixB d(triangulation const & cdt);
˜C matrixB d(){}; };
19
20
21
22
23
24
class C matrixB b:public C matrixB{
...
public:
C matrixB b(triangulation const & cdt);
˜C matrixB b(){}; };
Codice 2.5: C aux matrices.hpp - C matrixB
2.4
C problem.hpp
Ora che sono stati definiti gli input necessari alla dichiarazione del problema, può essere descritta una delle classi fondamentali implementate: la classe template C problem.
Questa classe è necessaria per la risoluzione di problemi differenziali della forma Ay = f
e Ay = f + Bu. In particolare la risoluzione del primo problema permette di testare il
codice EF, mentre quella del secondo è necessaria per la risoluzione del problema di controllo ottimo.
Le firme dei principali metodi della classe sono riportate nel Codice 2.6. Ora verranno
analizzati il costruttore e i metodi.
Il costruttore crea una copia privata della matrice B e una referenza privata alla triangolazione, costruisce la matrice A e il vettore f del problema scritto nella forma Ay = f + Bu
(approssimazione di Galerkin EF del problema continuo). Le condizioni al bordo di Dirichlet vengono imposte per penalizzazione: sia, ad esempio, il nodo i − esimo un nodo di
Dirichlet. Allora la riga i − esima della matrice viene azzerata, il coefficiente Aii viene
posto pari ad alpha ed fi uguale ad α moltiplicato per il valore che deve essere imposto
nel nodo di Dirichlet. Per semplicità si è posto α = 1.
I due solutori risolvono i problemi Ay = f e Ay = f + Bu, rispettivamente, tramite la
fattorizzazione e il solutore SparseLU per sistemi lineari delle Eigen5 . L’implementazione
del solutore relativo al problema Ay = f + Bu viene riportata nel Codice 2.7.
I metodi per il calcolo degli errori ricevono in ingresso uno o più funtori della forma già
vista nella Sezione 2.1.
5
la
documentazione
si
2.0/group Sparse Module.html
può
trovare
all’indirizzo
http://eigen.tuxfamily.org/dox-
2.4. C problem.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
17
// tipi per l’algebra lineare, utilizzati in tutto il codice
typedef Eigen::SparseMatrix<double> matrix t;
typedef Eigen::VectorXd vector t;
// problem def nome della classe in cui sono stati definiti tutti
// i coefficienti del problema, ad esempio PROBLEMA (come definito sopra)
template<typename problem def >
class C problem {...
public:
// Costruttore
// cdt triangolazione sulla quale va costruito il problema
// B matrice per la risoluzione del problema Ay=f+Bu.
C problem (triangulation const & cdt,matrix t const & B);
// Solutori
// solutore del problema Ay=f+Bu : Restituisce y, dato u
vector t solve (const vector t & u);
// solutore del problema Ay=f
void solve ();
//Post−process della soluzione
// norma L2 della soluzione y del problema
double normL2 () const;
// norma H1 della soluzione y del problema
double normH1 () const;
// errore L2 della soluzione y del problema, rispetto alla soluzione reale y0
// y0 soluzione reale del problema
template <typename function >
double errL2 (function const & y0) const;
// errore H1 della soluzione y del problema, rispetto alla soluzione reale y0
// y0 soluzione reale del problema
// y0x,y0y derivate della soluzione reale del problema rispetto ad x e ad y
template <typename function ,typename function x ,typename function y >
double errH1 (function const & y0, function x const & y0x,
function y const & y0y) const;
private:
// matrici e vettore del sistema
matrix t M A;
matrix t M B;
vector t M f;
};
Codice 2.6: C problem.hpp - C problem
1
2
3
4
5
6
7
8
9
template<typename problem def >
vector t C problem<problem def >::
solve (const vector t & u){ ...
Eigen::SparseLU<matrix t, Eigen::UmfPack> lu(M A);
gas assert(lu.succeeded());
vector t ff=M f+M B∗u;
x =lu.solve(ff);
return x ;
}
Codice 2.7: C problem.hpp - Solver del problema Ay = f + Bu
18
2.5
Capitolo 2. Implementazione
C functional.hpp
In questo header file sono state implementate le classi C Functional dd e C Functional db,
nelle quali sono implementati i funzionali
1
β
Jdd = (y − zd , y − zd )L2(Ω) + (u, u)L2(Ω)
2
2
e
1
β
Jdb = (y − zd , y − zd )L2(Ω) + (u, u)L2(ΓN )
2
2
rispettivamente.
I metodi fondamentali per il problema di controllo presenti in queste classi sono un metodo per la valutazione del funzionale e uno per il calcolo della derivata del funzionale. Nel
costruttore delle classi vengono presi in ingresso una referenza alla triangolazione, un funtore, dichiarato come già descritto nella Sezione 2.1, che restituisca il valore desiderato
dello stato zd , e il parametro β. Il costruttore assembla le matrici necessarie per il calcolo
del funzionale e della sua derivata. Vengono riportati nel Codice 2.8 gli elementi essenziali
della classe C Functional dd. La classe C Functional db è analoga.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
template <typename zeta d >
class C Functional dd{
public:
C Functional dd (triangulation const & cdt, zeta d const & zd,double beta=0.1);
// valore del funzionale valutato in y e u
// y stato del sistema
// u controllo del sistema
double eval (const vector t & y,const vector t & u);
//Derivata del funzionale valutata in p e u
// p variabile duale del sistema
// u controllo del sistema
vector t compute der(const vector t & p,const vector t & u);
//! Distruttore
˜C Functional dd(){};
... };
Codice 2.8: C functional.hpp - C Functional dd
Per la valutazione del funzionale, il primo dei due integrali viene calcolato esplicitamente,
non essendo necessariamente zd una funzione P1 . Nel secondo viene invece sfruttata la
matrice di massa relativa ai nodi su cui è definito il vettore u, calcolata nel costruttore
(valgono le stesse considerazioni fatte nella Sezione 2.1). Per quanto riguarda il calcolo
della derivata del funzionale, data la forma dei funzionali, è possibile calcolarla direttamente come somma di due prodotti matrice-vettore, senza dover risolvere il sistema
lineare associato. Nel primo caso, infatti, si ha DJdd = p + βu, mentre nel secondo risulta
DJdb = p|Γ + βu.
N
2.6
C solver.hpp
In questo header file è definita e implementata la classe fondamentale per la risoluzione
di un problema di controllo: la classe C solver. Questa classe è una classe base da per
la risoluzione del problema con un generico metodo iterativo, da cui vengono ereditate
pubblicamente altre due classi, in cui vengono implementati i metodi iterativi steepest
2.6. C solver.hpp
19
descent (SD) (metodo del gradiente) e il metodo del gradiente coniugato (CG). Nella
classe base viene definito ma non implementato il metodo solve. Tale metodo è infatti
implementato in ogni classe derivata. Inoltre vengono definiti ed implementati i metodi
comuni a tutte le classi derivate, come ad esempio il metodo protetto per la definizione
del passo α e i metodi per la restituzione dei risultati calcolati dal metodo (Codice 2.9).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
class C solver{
public:
// Costruttore
// tolD tolleranza del metodo iterativo per la norma della derivata del funzionale
// tol tolleranza del metodo iterativo per la norma della differenza tra due
// iterate successive
// maxit numero massimo di iterazioni del metodo iterativo
C solver(double tolD=1.e−2,double tol=1.e−3,unsigned int maxit=1000,
double c1=1.e−3);
// Solutore template
// cdt triangolazione
// P,D problemi primale e duale
// J funzionale
// u0 vettore iniziale per il metodo iterativo
// err normaL2 della differenza tra le ultime due iterate di u
// errD normaL2 della derivata del funzionale alla fine del metodo
// Il solutore viene implementato in ogni classe derivata
template<typename Ny ,typename Nu ,typename P ,typename D ,typename J >
void solve(triangulation const & cdt,C problem<P > & P,C problem<D > & D,
J & J,vector t u0,double & err=1.,double & errD=1.);
// valore del funzionale J
inline double J(){return M J;}
// numero di iterazioni dell’ultima chiamata del solutore
inline int it(){return M it;}
// stato y
inline vector t y(){return M y;}
// controllo u
inline vector t u(){return M u;}
// Distruttore
virtual ˜C solver(){};
protected:
// Calcolo del passo alpha
// ...
// d direzione di discesa
// DJ derivata corrente del funzionale
// y,u valori correnti dello stato e del controllo
// f derivata del funzionale nel caso di controllo nullo
template<typename Ny ,typename Nu ,typename P ,typename D ,typename J >
double alpha(triangulation const & cdt,C problem<P > & P,C problem<D > & D,
J & J,vector t const & d,vector t const & DJ,vector t const &y,
vector t const &u,vector t const & f);
};
Codice 2.9: C solver.hpp - C Solver
Di particolare interesse è la scelta del parametro α in quanto la convergenza o meno del
metodo iterativo è fortemente influenzata da tale scelta. Nel codice è stata implementata
la condizione di Armijo (Sezione 1.2), la quale garantisce un passo sufficiente. Ciò tuttavia
non assicura la convergenza del metodo ad un punto di minimo locale, in quanto il passo
20
Capitolo 2. Implementazione
potrebbe essere in alcuni casi troppo corto. In questi casi il metodo iterativo converge
poiché la norma della differenza tra due iterate è inferiore alla tolleranza e non perché la
norma della derivata del funzionale nel punto è inferiore alla tolleranza prevista. Bisogna
essere consapevoli di questa limitazione nel valutare i risultati ottenuti.
Per quanto riguarda invece l’implementazione dei metodi iterativi, sono state definite due
classi derivate pubblicamente dalla classe base sopra descritta: SD e CG. In queste due
classi viene implementato il metodo solve descritto nella Sezione 1.2. Nel primo caso viene
utilizzato il metodo del gradiente per la risoluzione del problema, mentre nel secondo il
metodo del gradiente coniugato con restart che può essere fissata dall’utente tramite il
metodo set restart . Nel Codice 2.10 vengono riportate le dichiarazioni dei metodi della
classe CG. Quelli della classe SD sono analoghi, eccezion fatta per il metodo set restart
che non è presente in questa classe.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class CG:public C solver{
public:
// Costruttore
CG(double tolD=1.e−2,double tol=1.e−3,int maxit=1000,double c1=1.e−3);
// metodo della classe per fissare il valore del restart.
// R: numero delle iterazioni dopo le quali va fatto il restart,
// fissato per default a 10.
void set restart(unsigned int R){M restart=R; return;};
// Solutore template metodo gradiente coniugato
template<typename Ny ,typename Nu ,typename P ,typename D , typename J >
void solve(triangulation const & cdt,C problem<P > & P,C problem<D > & D,
J & J,vector t u0);
// Distruttore
virtual ˜CG(){};
};
Codice 2.10: C solver.hpp - CG
Capitolo
3
Risultati Numerici
In questo capitolo vengono descritte le principali prove effettuate per testare il codice.
Innanzitutto è stato testato il solutore Elementi Finiti (EF) ed è stato verificato che
l’ordine di convergenza al variare della dimensione della mesh fosse quello previsto dalla
teoria. In secondo luogo sono stati confrontati i vari metodi di risoluzione del problema
di controllo ottimo.
3.1
Convergenza Elementi Finiti
Dalla teoria degli Elementi Finiti è noto che utilizzando EF P1 l’errore commesso rispetto
alla soluzione reale del problema dipende dalla dimensione della mesh h secondo il seguente
Teorema 5. Sia u ∈ H 2 (Ω) la soluzione esatta di un generico problema ellittico su un
dominio Ω, e sia uh ∈ P1 la sua approssimazione EF. Allora valgono le seguenti stime a
priori dell’errore:
k u − uh kL2 (Ω) 6 Ch2 |u|H 2 (Ω) ,
k u − uh kH 1 (Ω) 6 Ch|u|H 2 (Ω) .
Consideriamo quindi il dominio Ω = (0, 1) × (0, 1) e il seguente problema:

−∆u + ∂u = f in Ω
∂x
u = g
su ∂Ω
con f , g scelti in modo tale che la soluzione esatta del problema sia u = cos(2πx)cos(2πy).
Come si può notare in Figura 3.1, gli ordini di convergenza sono quelli attesi. Il grafico è
stato ottenuto con Gnuplot.
3.2
Risultati sul Controllo Ottimo
Nel programma sono stati implementati i problemi di controllo ottimo con osservazione
distribuita e controllo sia ditribuito che al bordo, come descritto nella Sezione 1.1.3.
Per testare il codice sono state scritte quattro varianti del problema, i cui input sono
contenuti nel direttorio /examples/control negli header files input01.hpp, input02.hpp,
input03.hpp e input04.hpp.
Il problema primale senza controllo è il seguente:
(
−4y = f in Ω
+b.c
su ∂Ω
21
22
Capitolo 3. Risultati Numerici
1
Errori
0.1
ErrL2
ErrH1
h
h^2
0.01
0.001
0.0001
0.01
0.1
h
Figura 3.1: Errore EF P1 al variare della dimensione della mesh h
con Ω = (0, 1) × (0, 1) ed f e le condizioni al bordo scelte in modo tale da ottenere come
soluzione esatta y = cos(2πx)cos(2πy). In particolare, anche l’osservazine desiderata nei
vari casi sarà zd = cos(2πx)cos(2πy).
Nei primi due file di input è contento l’input del problema di controllo con condizioni al
bordo di Dirichlet, mentre nei secondi due con condizioni al bordo miste. In particolare,
è stata imposta la condizione di Neumann sul bordo x = 0. Inoltre in input01.hpp e in
input03.hpp le condizioni al bordo e la forzante dei problemi sono quelli esatti, cosı̀ che
il controllo dovrebbe essere nullo. Dall’altra parte, in input02.hpp e in input04.hpp sono
state imposte rispettivamente forzante nulla e condizione di Neumann pari a 1. Queste
prove sono state effettuate per verificare che in questi casi una penalizzazione minore del
controllo porta ad avere un errore dello stato rispetto al valore desiderato minore. Questo
errore dovrebbe tendere a zero al diminuire di β.
Nel main.cpp, il cui eseguibile è chiamato control, c’è la possibilità di scegliere uno dei
quattro input di volta in volta, includendone uno. Nel main c’è anche la possibilità di
scegliere quale tipo di controllo si vuole testare. Il controllo al bordo è possibile solo
con gli ultimi due file di input, in quanto negli altri ci sono solo condizioni al bordo di
Dirichlet. Viene inoltre letto in input un file tramite GetPot 1 . Il nome del file può essere
passato al main quando viene lanciato da linea di comando come argomento. Ciò consente
di modificare alcun parametri del problema senza bisogno di ricompilare il main. La
struttura del file da leggere viene riportata nel Codice 3.1.
1
2
3
# tolleranze per l’incremento e la derivata del funzionale
tol=1.e−8;
tolD=1.e−6;
4
5
6
# massimo numero di iterazioni
maxit=1000;
7
8
9
# iterazioni per il restart
rest=10;
Codice 3.1: data.txt
Nel main.cpp vengono testati i diversi metodi implementati con u0 = 0, u0 = 1 e u0 = 5 al
variare di β. Vengono salvati in diversi files il numero di iterazioni e gli errori commessi in
1
Per documentazione e downloads vedere il link http://getpot.sourceforge.net/
3.2. Risultati sul Controllo Ottimo
23
ogni caso. Per le prove effettuate è stata scelta una griglia avente come diametro massimo
degli elementi h = 0.05.
Come già sottolineato nei precedenti capitoli, la convergenza dei metodi ad un punto di
minimo non è garantita in quanto ad ogni iterazione viene scelto un passo αk sufficiente
ma non necessario.
Vengono riportati nelle tabelle alcuni dei risultati ottenuti. Sono stati utilizzati come
parametri quelli presenti nel Codice 3.1. Si può osservare che tendenzialmente il numero
di iterazioni aumenta e l’errore in norma L2 diminuisce all’aumentare di β. Inoltre il
numero di iterazioni effettuate dal metodo del gradiente è in genere dello stesso ordine o
superiore a quello del metodo del gradiente coniugato, in accordo con la teoria.
I casi in cui il numero di iterazioni del CG è superiore a quello del metodo SD sono
dovuti al fatto che i metodi vengono arrestati in punti diversi o al restart automatico. I
casi invece in cui l’errore L2 della variabile di stato rispetto all’osservazione desiderata
aumenti al diminuire di β o non abbia un andamento regolare sono da attribuire al fatto
che il metodo può arrestarsi anche nel caso di passi troppo piccoli.
Da notare, inoltre, è il fatto che nel caso in cui il controllo ottimo sia teoricamente u = 0,
al diminuire di β, l’errore diminuisce e ci si sposta dalla soluzione u = 0. Ciò è dovuto al
fatto che viene trovato l’ottimo numerico e non quello analitico. Infatti la struttura della
mesh influenza il calcolo dell’errore ed è possibile trovare una soluzione diversa da quella
analitica che porti a valori del funzionale più bassi. Si ricorda che il minimo numero di
iterazioni nel caso del metodo del CG è influenzato dalla scelta fatta sul restart automatico
(vedere Sezione 1.2 per dettagli).
Tabella 3.1: input01.hpp - controllo distribuito - metodo CG - u0 = 5
β
0.1
0.01
0.001
0.0001
0.00001
0.000001
iterazioni
7
7
8
17
19
127
k uk−1 − uk k
1.746194e-19
9.732412e-17
3.286921e-17
3.803061e-15
1.719397e-16
1.443248e-02
k DJ(uk ) k
4.905003e-06
4.309319e-06
4.849156e-06
6.081916e-06
1.010696e-03
2.384511e-07
J(uk )
2.817328e-03
2.979786e-03
3.049550e-03
3.043438e-03
1.597462e-02
2.181577e-03
k y − zd k
3.828668e-03
3.779787e-03
3.637176e-03
3.283235e-03
2.016787e-02
2.276910e-03
Tabella 3.2: input01.hpp - controllo distribuito - metodo SD - u0 = 5
β
0.1
0.01
0.001
0.0001
0.00001
0.000001
iterazioni
4
6
8
44
86
242
k uk−1 − uk k
6.931539e-04
9.719703e-17
6.119148e-14
6.258350e-17
1.286274e-03
3.163452e-03
k DJ(uk ) k
8.353852e-07
5.245213e-06
2.975052e-05
2.088559e-06
9.143450e-07
9.895524e-07
J(uk )
2.825751e-03
2.965141e-03
3.005940e-03
3.095564e-03
2.673561e-03
2.280276e-03
k y − zd k
3.828111e-03
3.782453e-03
3.687715e-03
3.198107e-03
2.586034e-03
2.313746e-03
24
Capitolo 3. Risultati Numerici
Tabella 3.3: input02.hpp - controllo distribuito - metodo CG - u0 = 0
β
0.1
0.01
0.001
0.0001
0.00001
0.000001
iterazioni
2
2
4
6
15
30
k uk−1 − uk k
3.973247e-17
8.128808e-17
1.384445e-15
2.090896e-02
2.001884e-14
1.483609e-17
k DJ(uk ) k
1.834639e-02
1.834639e-02
3.272423e-04
2.551814e-07
1.132725e-04
6.437225e-06
J(uk )
3.026171e-01
3.026171e-01
2.890667e-01
1.918925e-01
9.031582e-02
3.141025e-02
k y − zd k
4.279653e-01
4.279653e-01
2.398475e-01
1.436361e-01
3.942348e-02
1.002148e-02
Tabella 3.4: input02.hpp - controllo distribuito - metodo SD - u0 = 0
β
0.1
0.01
0.001
0.0001
0.00001
0.000001
iterazioni
1
1
3
6
82
222
k uk−1 − uk k
7.946495e-17
1.625762e-16
1.061525e-14
3.801534e-13
9.885370e-10
3.425149e-16
k DJ(uk ) k
1.834639e-02
1.834639e-02
3.272423e-04
2.449575e-04
1.904661e-05
2.807607e-06
J(uk )
3.026171e-01
3.026171e-01
2.890667e-01
1.916218e-01
9.232980e-02
3.165789e-02
k y − zd k
4.279653e-01
4.279653e-01
2.398475e-01
1.513602e-01
4.725746e-02
1.054011e-02
Tabella 3.5: input04.hpp - controllo al bordo - metodo CG - u0 = 1
β
0.1
0.01
0.001
0.0001
0.00001
0.000001
iterazioni
4
7
7
16
40
133
k uk−1 − uk k
6.855121e-16
1.594874e-13
1.621604e-15
0.000000e+00
1.335208e-13
2.614776e-15
k DJ(uk ) k
7.333707e-01
8.359146e-03
3.149897e-02
3.750333e-03
4.735434e-04
4.142406e-04
J(uk )
5.206274e+00
4.464447e+00
1.534915e+00
5.251646e-01
1.771998e-01
7.270107e-02
k y − zd k
6.957129e+00
2.836763e+00
3.818816e-01
1.317583e-01
4.666804e-02
3.710797e-02
Tabella 3.6: input04.hpp - controllo al bordo - metodo SD - u0 = 1
β
0.1
0.01
0.001
0.0001
0.00001
0.000001
iterazioni
2
4
4
11
65
695
k uk−1 − uk k
2.258347e-14
7.443065e-14
5.626461e-14
1.010081e-14
4.163958e-14
8.862783e-14
k DJ(uk ) k
7.333707e-01
5.067475e-04
3.188088e-02
3.097668e-03
3.051896e-04
1.960878e-05
J(uk )
5.206274e+00
4.464518e+00
1.579287e+00
5.360576e-01
1.830720e-01
7.280136e-02
k y − zd k
6.957129e+00
2.843803e+00
4.637165e-01
1.497051e-01
5.716353e-02
3.735970e-02
Bibliografia
[1] Formaggia L., Fuhrman M. (2012), Notes of the course in optimal control of PDE,
Mathematics Department F.Brioschi, Politecnico di Milano
[2] Lions J.L. (1971), Optimal Control of Systems Governed by Patrial Differential
Equations, Springer-Verlag, New York
[3] Quarteroni A. (2008), Matematica Numerica (3a ed.), Springer-Verlag, Milano
[4] Quarteroni A. (2008), Modellistica Numerica per Problemi Differenziali (4a ed.),
Springer-Verlag, Milano
[5] Ferrarese D., Penati M. , Progetto di Programmazione Avanzata per il Calcolo Scientifico - GasFramework, Professore Formaggia L., Politecnico di Milano (A.A.
2009-2010)
25