• Non ci sono risultati.

3.2 Descrizione delle classi

3.2.1 La classe CompositeDifferentialProblem

Nella directory src/DifferentialProblem contenuta all’interno del re- pository Git si trovano i file relativi alla definizione delle classi utilizzate per la soluzione di problemi differenziali. La classe che sintetizza tutte le funzionalità implementate è chiamata CompositeDifferentialProblem. In figura 3.1 è rappresentato il diagramma UML che rappresenta le relazioni tra le classi utilizzate per la descrizione di problemi differenziali. Per faci- litare la lettura sono stati riportati solo i metodi principali e si è deciso di tralasciare tutti i parametri in ingresso delle funzioni.

Per utilizzare queste classi in un file sorgente C++ è stato creato il file header DifferentialProblem.hpp che, una volta incluso, si occupa di in- cludere a sua volta i file header necessari all’utilizzo di tutte le funzionalità di tali classi.

Trattiamo come prima cosa la classe AbstractDifferentialProblem. Come si intuisce dal nome, essa è una classe astratta che descrive l’inter- faccia di base di ogni classe concreta che implementa un tipo particolare di problema differenziale. Tale classe contiene dunque come membri protetti uno shared pointer che punta alla mesh del problema e uno che punta allo spazio a elementi finiti, una dolfin::Function che contiene la soluzione del problema e una mappa che contiene le condizioni di Dirichlet relative

Figura 3.1: Diagramma UML delle relazioni tra le classi che descrivono il generico problema differenziale

al problema, ciascuna associata al proprio nome identificativo. Tale nome è necessario nel caso in cui si voglia in seguito rimuovere o modificare uno degli oggetti di tipo dolfin::dirichletBC contenuti nella std::map. La classe contiene inoltre, come succede per la maggior parte delle classi della libreria DOLFIN, un membro pubblico di tipo dolfin::Parameters chia- mato parameters che contiene i parametri della classe che possono essere definiti da parte dell’utente (come ad esempio il numero massimo di itera- zioni di un metodo iterativo, la tolleranza del test di convergenza. . . ). Tutte le impostazioni pubbliche della classe AbstractDifferentialProblem so- no contenute in questa variabile, che è liberamente modificabile dall’utente. Le funzioni setCoefficient e setIntegrationSubdomain servono rispet- tivamente a settare i valori dei coefficienti e le dolfin::meshFunction che descrivono i sotto-domini di integrazione (si veda [HKL+11]). Tali funzioni sono in realtà metodi pure virtual e devono essere ridefiniti in ogni clas- se derivata, poiché la classe AbstractDifferentialProblem non conosce il tipo di dolfin::Form che rappresenterà l’equazione nella classe concreta: la classe AbstractDifferentialProblem infatti non contiene alcun mem- bro protetto di tipo dolfin::Form. Lo stesso vale per i metodi solve() e clone().

Dalla classe AbstractDifferentialProblem derivano le classi templa- te LinearDifferentialProblem e NonlinearDifferentialProblem. La prima implementa un’interfaccia per problemi differenziali lineari, mentre la seconda è pensata per problemi non lineari. Entrambe sono template-izzate sulle dolfin::Form che definiscono il problema: per problemi lineari è ne- cessario specificare la forma bilineare e la forma lineare, mentre per problemi non lineari occorre indicare le forme che permettono il calcolo del residuo e dello jacobiano del problema. La classe LinearDifferentialProblem ha un terzo argomento template: la factory di solutori lineari. Il valore di default di tale argomento template è la classe LinearSolverFactory presente nella libreria (si veda sezione 3.2.2), ma è possibile istanziare un oggetto di tipo LinearDifferentialProblem su una factory creata dall’utente in modo da permettere l’utilizzo di solutori lineari differenti. Si rimanda alla documen- tazione Doxygen per i dettagli sui parametri di ingresso dei costruttori delle due classi. Entrambe le classi inoltre ereditano dalla classe base la variabile parameters e la arricchiscono con i parametri specifici del problema imple- mentato. Anche in questo caso, si veda la documentazione Doxygen per i dettagli.

La classe CompositeDifferentialProblem implementa un problema dif- ferenziale “composto”, cioè un sistema di problemi differenziali accoppiati. In altre parole, essa rappresenta un insieme di problemi differenziali in cui i coefficienti di un’equazione possono essere le soluzioni di un’altra equazione. La classe contiene tre membri protetti:

ziali che compongono il sistema, ciascuno identificato da una strin- ga. Il secondo membro di questa mappa è uno std::unique_ptr a AbstractDifferentialProblem. Grazie al polimorfismo, la mappa può contenere qualunque oggetto il cui tipo sia derivato tramite eredi- tarietà da AbstractDifferentialProblem, e quindi in particolare sia LinearDifferentialProblem che NonlinearDifferentialProblem. La mappa avrà full-ownership su tali oggetti. L’aggiunta di un pro- blema alla mappa avviene infatti attraverso la chiamata alla funzione addProblem(), che ha due diverse firme:

1 // addProblem: prima versione

2 void addProblem (const std::string& problemName,

3 AbstractDifferentialProblem& problem); 4

5 // addProblem: seconda versione 6 void addProblem

7 (const std::string& problemName,

8 std::unique_ptr<AbstractDifferentialProblem>&

9 problem);

La prima versione chiama il metodo clone() sulla variabile problem e inserisce il risultato nella mappa. La seconda invece inserisce diretta- mente il puntatore nella mappa usando la move semantic. In entrambi i casi quindi il problema inserito nella mappa ha lifespan coincidente con quello della mappa stessa.

• solveOrder_ è un std::vector<std::string> i cui elementi indica- no l’ordine in cui i problemi presenti nella variabile storedProblems_ devono essere risolti. Ogni elemento di tale vettore contiene infat- ti una stringa che identifica in modo univoco un problema conte- nuto in storedProblems_. L’iniettività di tale associazione è data dal fatto che la stringa identificativa dei problemi è la chiave di una std::map. L’ordine in cui questi nomi compaiono in solveOrder_ determina l’ordine in cui i problemi contenuti in storedProblems_ saranno risolti.

• problemsLinks_ è una std::map che contiene tutti i link fra problemi. Un link è una dipendenza del coefficiente di un problema contenuto in storedProblems_ dalla soluzione di un altro problema anch’esso contenuto in storedProblems_. In particolare, la mappa associa una terna di std::string a una coppia (std::string, int): la prima identifica il coefficiente dipendente attraverso il nome del problema, il tipo di forma in cui il coefficiente compare e il nome del coefficiente stesso; la seconda identifica la funzione da cui il coefficiente in que- stione dipende attraverso il nome del problema e la componente della soluzione di tale problema che deve essere usata come valore per il

coefficiente dipendente (nel caso in cui il problema target del link sia vettoriale). Il valore -1 è usato come segnaposto per identificare l’in- tera soluzione. La chiamata a addLink() si occupa sia di aggiungere il link passato come argomento alla variabile problemsLinks_ che di effettuare il linking vero e proprio tra problemi, attraverso l’uso del metodo setCoefficient.

A questo punto è possibile risolvere uno solo o tutti i problemi contenuti in storedProblems_ (nell’ordine stabilito da solveOrder_) chiamando il metodo solve() in una delle sue due forme.

Documenti correlati