{{:wikipaom2015:prove_fortran.zip|file fortran postazione cattedra}} ==== Costruzione di una Matrice/Vettore ==== In questa prova, si fa uso di una struttura chiamata **Array** (dall'inglese: ordine, disposizione, schieramento). Gli "array" servono a dichiarare matrici e vettori. Possono essere, ad esempio, del tipo: === real a(20) === dove si dichiara un vettore ad elementi reali di 20 elementi allocati nella memoria a 32 bit uno dietro l'altro. Essi sono fissi in dimensione, devono essere omogenei, quindi gli elementi al loro interno devono essere tutti interi o reali e tutti in singola o doppia precisione. Di seguito, è riportato il programma che costruisce una matrice o un vettore, basato sull'utilizzo del **Ciclo DO**. Va ricordato, che il nome del programma può coincidere o meno con il nome del file senza che questo influisca sull'esecuzione dell'elaborato. Inoltre, nella fase iniziale, va prima dichiarata la natura delle variabili e, successivamente, le rispettive dimensioni. Inizializzo le colonne utilizzabili su Fortran77 (72 colonne) in questa maniera: c234567================================================================| Definisco il nome del programma program tmat Inserisco un **implicit none** in modo da dover esplicitare completamente tutte le variabili evitando di cadere in errori di programmazione implicit none Definisco due costanti nrow, ncol e dichiaro (alloco) matrice A integer nrow,ncol parameter( nrow = 3 , ncol = 5 ) real A(nrow,ncol) Definisco due indici integer irow,icol Fine Dichiarazioni ed Inizio Istruzioni INPUT matrice A da standard input (stdin) do irow = 1,nrow write(*,*) 'inserire riga',irow,'di',nrow Adesso dobbiamo scegliere tra due alternative di utilizzo del ciclo do do interno al read read(*,*) ( A(irow,icol), icol=1,ncol ) do esterno al read do icol = 1 , ncol write(*,*) 'col',icol read(*,*) A(irow,icol) enddo enddo OUTPUT matrice A su stdout do irow = 1,nrow write(*,*) 'riga',irow,'di',nrow Adesso in base alla scelta fatta in input bisogna in maniera coerente scegliere il tipo di ciclo do in output do interno al write write(*,*) ( A(irow,icol), icol=1,ncol ) do esterno al write do icol = 1 , ncol write(*,*) 'col',icol,A(irow,icol) enddo enddo stop end NOTA BENE: questo programma consente la costruzione della matrice immettendo gli elementi da tastiera uno alla volta (Metodo scomodo) ==== Prodotto Matrice/Vettore ==== Di seguito, è riportato un metodo di costruzione della matrice, che assegna gli elementi leggendo in automatico un file .txt in cui sono già stati elencati i valori degli elementi desiderati. Tale programma inoltre serve a eseguire il prodotto tra matrici/vettori (A*B=C) utilizzando il ciclo do. $$\begin{vmatrix}a_{1,1} & a_{1,2} & a_{1,3} & a_{1,4} & a_{1,5}\\a_{2,1} & a_{2,2} & a_{2,3} & a_{2,4} & a_{2,5}\\a_{3,1} & a_{3,2} & a_{3,3} & a_{3,4} & a_{3,5}\end{vmatrix} * \begin{vmatrix}b_{1,1} & b_{1,2}\\b_{2,1} & b_{2,2}\\b_{3,1} & b_{3,2}\\b_{4,1} & b_{4,2}\\b_{5,1} & b_{5,2}\end{vmatrix} = \begin{vmatrix}c_{1,1} & c_{1,2}\\c_{2,1} & c_{2,2}\\c_{3,1} & c_{3,2}\end{vmatrix}$$ L'algoritmo che descrive l'operazione che esegue il programma è il seguente: $$ C_{irow,icol}= \sum_{isum=1}^n A_{irow,isum}*B_{isum,icol} $$ Definisco il nome del programma program tmat_v1 implicit none Definisco due costanti nrow, ncol e dichiaro (alloco) le matrici A B C integer nArow,nAcol integer nBrow,nBcol integer nCrow,nCcol parameter( nArow = 3 , nAcol = 5 ) parameter( nBrow = 5 , nBcol = 2 ) parameter( nCrow = 3 , nCcol = 2 ) real A(nArow,nAcol) real B(nBrow,nBcol) real C(nCrow,nCcol) Definisco due indici per scorrere le matrici, più uno di sommatoria integer irow,icol,isum,nsum Fine Dichiarazioni ed Inizio Istruzioni INPUT matrice A da standard input (stdin) do irow = 1,nArow read(*,*) ( A(irow,icol), icol=1,nAcol ) enddo INPUT matrice B da standard input (stdin) do irow = 1,nBrow read(*,*) ( B(irow,icol), icol=1,nBcol ) enddo Inizio CALCOLO DEL PRODOTTO call prodmat(nArow,nAcol,nBcol,A,B,C) Fine CALCOLO DEL PRODOTTO OUTPUT matrice C su stdout do irow = 1,nCrow write(*,*) ( C(irow,icol), icol=1,nCcol ) enddo stop end Adesso creo un sottoprogramma 'subroutine', che viene poi richiamato tramite il comando 'call' subroutine prodmat(nAArow,nAAcol,nBBcol,AA,BB,CC) implicit none INPUT Dimensionamento matrici per prodotto integer nAArow, nAAcol, nBBcol Datrici per prodotto real AA( nAArow, nAAcol ) real BB( nAAcol, nBBcol ) OUTPUT Matrice su cui scrivere il risultato del prodotto real CC( nAArow, nBBcol ) IN/OUT , UPDATE, MODIFICA area dedicata a variabili a cui si accede in INPUT/OUTPUT VARIABILI LOCALI Dichiaro gli indici di scorrimento riga/colonna su CC e di somma integer irow, icol, isum Fine Dichiarazioni ed Inizio Istruzioni do irow = 1,nAArow do icol = 1, nBBcol CC(irow,icol)= 0.0 do isum = 1, nAAcol CC(irow,icol)=CC(irow,icol) + AA(irow,isum)*BB(isum,icol) enddo enddo enddo return end Riga di comando per compilazione ed esecuzione: ** gfortran tmat_v1.for && ./a.out < input.txt > output.txt** con la stringa **> output.txt** i risultati vengono sovrascritti sul file output.txt, mentre se avessi inserito **> > output.txt** i dati sarebbero stati accodati all'interno del file. Il file **input.txt** è così definito: 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0 ==== Cos'è un Sottoprogramma (Subroutine)? ==== Il linguaggio di programmazione FORTRAN consente di suddividere le operazioni tramite sottoprogrammi che ritornano un risultato al programma chiamante, sviluppando un approccio top-down. L'utilizzo dei sottoprogrammi è molto utile quando si deve ripetere una stessa operazione più volte, evitando così tutte le volte di copiare e incollare nel programma principale la stessa operazione. Questi sottoprogrammi possono essere del tipo FUNZIONI oppure SUBROUTINE. Funzioni e subroutine devono avere nome univoco e per il resto sono indipendenti dal programma che le ha richiamate. Il costrutto FUNZIONE restituisce un singolo valore scalare, motivo per cui spesso si ricorre al costrutto SUBROUTINE. A differenza dei programmi che terminano con “ stop end”, i sottoprogrammi terminano con “return end”. Nel sottoprogramma le etichette sono autonome perciò per dichiarare le variabili locali, si possono utilizzare etichette aventi stesso nome e tipologia di quelle già dichiarate nel programma principale (MAIN). Programma e sottoprogramma comunicano inviandosi indirizzi di memoria perciò è fondamentale che comunichino con la stessa tipologia di elementi: in particolare il programma invia i parametri passati al sottoprogramma che restituisce un valore. Creiamo adesso un sottoprogramma che determina il: ==== Vincolamento di una matrice di Rigidezza ==== Si vuole vincolare la matrice di rigidezza della struttura STRUTK ai termini noti o forze applicate sulla struttura (FORCE) e agli spostamenti che in realtà sono incogniti. Così si opera direttamente con una subroutine: subroutine vincola(N,STRUTK,FORCE,I,V) implicit none INPUT integer N integer I real V INOUT real STRUTK(N,N) real FORCE(N) LOCALI integer J Fine Dichiarazioni ed Inizio Istruzioni Affinché la matrice possa essere simmetrica e definita positiva,azzero la riga I-esima della matrice STRUTK do J = 1,N STRUTK( I , J ) = 0.0 enddo ma si sa anche che l'elemento della i-esima riga e i-esima colonna non vale zero. Scrivo 1.0 sul termine diagonale di tale riga STRUTK(I,I) = 1.0 Definisco il valore imposto V a termine noto, elemento I-esimo FORCE(I) = V Ora bisogna recuperare la simmetria della matrice annullando i termini della i-esima colonna, perciò creo due blocchi di matrice che vanno da 1 a I-1 e da I+1 ad N do J = 1 , I-1 FORCE(J) = FORCE(J) - STRUTK(J,I) * V STRUTK(J,I) = 0.0 enddo Salto caso J=I, legato alla diagonale che già era stato impostato in precedenza e si ottiene: do J = I+1 , N FORCE(J) = FORCE(J) - STRUTK(J,I) * V STRUTK(J,I) = 0.0 enddo Basta chiudere la subroutine e il main e si ottiene il codice di vincolamento. return end ~~DISCUSSION|Note di redazione~~