file fortran postazione cattedra
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:
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)
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
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:
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