Strumenti Utente

Strumenti Sito


wikipaom2015:lez08

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
     
     

Note di redazione

Enrico BERTOCCHI, 2015/03/16 16:46, 2015/03/16 16:50

nell'inserimento di codice fortran 77 è possibile utilizzare o prependere 2 spazi in più, utilizzati da dokuwiki per riconoscere il codice

c234567================================================================|
      program pippo

oppure utilizzare il costrutto <code> ... </nocode> , senza modifica della spaziatura

c234567================================================================|
      program pippo

Il risultato è il medesimo, forse il secondo metodo è più comodo da scrivere.

Potresti lasciare un commento se ti fossi autenticato.
wikipaom2015/lez08.txt · Ultima modifica: 2015/06/25 07:51 da 163359