wikipaom2015:lez09
Differenze
Queste sono le differenze tra la revisione selezionata e la versione attuale della pagina.
Entrambe le parti precedenti la revisioneRevisione precedenteProssima revisione | Revisione precedente | ||
wikipaom2015:lez09 [2015/03/29 20:38] – 204593 | wikipaom2015:lez09 [2015/04/30 16:08] (versione attuale) – [esempio codice fortran tria3] ebertocchi | ||
---|---|---|---|
Linea 1: | Linea 1: | ||
+ | ====== FORTRAN ====== | ||
+ | ====== Controllo sui limiti di allocazione di matrici o vettori ====== | ||
+ | |||
+ | Prendiamo il seguente programma per allocare un vettore di " | ||
+ | |||
+ | < | ||
+ | c234567==============================================================72! | ||
+ | program pocciavec | ||
+ | implicit none | ||
+ | c | ||
+ | real vec | ||
+ | integer i, | ||
+ | | ||
+ | parameter(ilim=10) | ||
+ | dimension vec(ilim) | ||
+ | c noto ora che invertendo l' | ||
+ | | ||
+ | c----- fine dichiarazioni, | ||
+ | |||
+ | c | ||
+ | i=0 | ||
+ | c | ||
+ | 10 i=i+1 | ||
+ | c | ||
+ | write (*,*) i,vec(i) | ||
+ | goto 10 | ||
+ | | ||
+ | stop | ||
+ | end | ||
+ | </ | ||
+ | |||
+ | Nel programma si dichiara un vettore //vec// di ilim=10 elementi tuttavia, attraverso l’istruzione //go to//, si incrementa la variabile di conteggio //i// un numero illimitato di volte leggendo di volta in volta valori casuali del vettore. Attivando il programma da terminale, superato il numero di elementi dichiarato, il FORTRAN comincerà a stampare numeri presi dalla memoria ad esso dedicata, pari a 4 GB, fino al suo esaurimento e terminerà con la stampa dell' | ||
+ | |||
+ | Nel caso in cui: | ||
+ | |||
+ | < | ||
+ | 10 i=i+1 | ||
+ | c | ||
+ | vec(i)=0.01 | ||
+ | write (*,*) i,vec(i) | ||
+ | goto 10 | ||
+ | </ | ||
+ | |||
+ | (è stata inserita la riga vec(i)=0.01). | ||
+ | |||
+ | Da terminale sarebbero letti solamente 11 elementi del vettore, tutti pari a 9.999999E-3 (=0.01). | ||
+ | |||
+ | Se invece di vec(i)=0.01 avessimo scritto vec(i)=0.00, | ||
+ | all' | ||
+ | |||
+ | Quindi è molto rischioso lavorare fuori dai limiti di un vettore perché potrei generare dei loop pericolosi fino a provocare un blocco del programma oppure un ciclo infinito di operazioni. | ||
+ | |||
+ | Per evitare questi problemi devo aggiungere un opzione di controllo sui limiti di allocazione di un vettore ovvero: | ||
+ | |||
+ | < | ||
+ | -fbounds-check | ||
+ | </ | ||
+ | |||
+ | Questa opzione( che compila controllando i limiti delle matrici o dei vettori e avverte qualora ci siano questi tipi di problemi) deve essere aggiunta quando il programma viene richiamato da terminale, nel modo seguente: | ||
+ | |||
+ | < | ||
+ | gfortran -fbounds-check- pocciavec.for && ./a.out | ||
+ | </ | ||
+ | |||
+ | Il codice si interrompe dopo il decimo elemento del vettore (così come dovrebbe essere) senza provocare alcun tipo di problema. | ||
+ | |||
+ | Usando la SUBROUTINE per costruire lo stesso programma: | ||
+ | |||
+ | < | ||
+ | c234567==============================================================72! | ||
+ | program pocciavec | ||
+ | implicit none | ||
+ | c | ||
+ | real vec | ||
+ | integer i,ilim,imax | ||
+ | c | ||
+ | parameter(ilim=10) | ||
+ | dimension vec(ilim) | ||
+ | |||
+ | c----- fine dichiarazioni, | ||
+ | c | ||
+ | do imax=1,ilim | ||
+ | c | ||
+ | call riempi(imax, | ||
+ | enddo | ||
+ | | ||
+ | stop | ||
+ | end | ||
+ | |||
+ | subroutine riempi(n, | ||
+ | implicit none | ||
+ | integer i,n | ||
+ | real vec | ||
+ | dimension vec(n) | ||
+ | |||
+ | do i=1,n | ||
+ | | ||
+ | enddo | ||
+ | write(*,*) (vec(i), i=1,n) | ||
+ | return | ||
+ | end | ||
+ | |||
+ | </ | ||
+ | |||
+ | Il programma riempie il vettore //vec// di elementi //2.0*i// tramite subroutine. | ||
+ | Nella chiamata del programma da terminale, senza BOUNDS CHECK, non ho nessun problema perchè il vettore è stato specificato di 10 elementi in fase di dichiarazione e così risulta essere anche durante la chiamata della subroutine (n=ilim, il ciclo //do// legge 10 elementi). | ||
+ | |||
+ | Modificando il ciclo //do// del programma prima della chiamata della subroutine con | ||
+ | |||
+ | < | ||
+ | do imax=1, | ||
+ | </ | ||
+ | |||
+ | Ottenendo: | ||
+ | |||
+ | < | ||
+ | do imax=1, | ||
+ | c | ||
+ | call riempi(imax, | ||
+ | enddo | ||
+ | </ | ||
+ | |||
+ | e avviando il programma da terminale, sempre senza BOUNDS CHECK, mi da errore perché finisco in memorie in cui non posso scrivere perché non sono state assegnate al vettore durante la dichiarazione. Infatti chiedo di leggere ilim+100 (10+100) elementi quando il vettore è stato dichiarato di soli ilim=10 elementi. | ||
+ | |||
+ | Se provo a dare il BOUNDS CHECK durante la chiamata del programma da terminale, il vettore dovrebbe terminare dopo | ||
+ | il 10° elemento ma così non è perché __la funzione bounds check risolve il problema solamente se le matrici o i vettori sono dichiarati all' | ||
+ | |||
+ | ====== Allocazione Matrici con 3 dimensioni ====== | ||
+ | |||
+ | In fortran è possibile costruire matrici con più di 2 dimensioni, fino ad un limite di 7. Prendiamo come esempio il seguente caso | ||
+ | |||
+ | < | ||
+ | c234567==============================================================72! | ||
+ | program leaddim | ||
+ | implicit none | ||
+ | integer l, | ||
+ | real mat | ||
+ | parameter(lmax=2, | ||
+ | c | ||
+ | dimension mat(lmax, | ||
+ | </ | ||
+ | |||
+ | Il codice sopra indicato rappresenta la parte di dichiarazioni di un programma per la costruzione di una matrice in 3 dimensioni dove con lmax si indica il numero di LAYER, con imax il numero di RIGHE e con jmax il numero di COLONNE. | ||
+ | Possiamo notare che la matrice può anche essere dichiarata specificandone la dimensione in un secondo momento tramite il comando DIMENSION come sopra indicato. | ||
+ | |||
+ | Per riempire la matrice posso usare il seguente ciclo " | ||
+ | |||
+ | < | ||
+ | subroutine riempimat(lmax, | ||
+ | implicit none | ||
+ | real mat | ||
+ | integer l, | ||
+ | dimension mat(lmax, | ||
+ | | ||
+ | do l=1,lmax | ||
+ | do i=1,imax | ||
+ | do j=1,jmax | ||
+ | | ||
+ | enddo | ||
+ | enddo | ||
+ | enddo | ||
+ | | ||
+ | return | ||
+ | end | ||
+ | </ | ||
+ | |||
+ | che richiamerò all' | ||
+ | |||
+ | < | ||
+ | call riempimat(lmax, | ||
+ | </ | ||
+ | |||
+ | Infine per visualizzare i risultati su terminale una volta che il programma verrà chiamato dovtò usare un secondo ciclo " | ||
+ | |||
+ | < | ||
+ | do l=1,lmax | ||
+ | do i=1,imax | ||
+ | write(*,*) ' | ||
+ | enddo | ||
+ | enddo | ||
+ | </ | ||
+ | |||
+ | Inoltre è possibile, durante la chiamata della subroutine nel programma, non rispettare le dimensioni esatte della matrice come specificato nella subroutine stessa purché sia rispettato il numero totale di elementi da inserire nella matrice. | ||
+ | Per esempio avrei potuto chiamare la subroutine nel modo seguente: | ||
+ | |||
+ | < | ||
+ | call riempimat(1, | ||
+ | </ | ||
+ | |||
+ | In questo modo non avrò più una matrice 2x3x4 come dichiarato da programma ma otterrò una matrice 1x24x1 che, come è possibile notare, avrà lo stesso numero di elementi di quella precedente. | ||
+ | |||
+ | ==== Trasformazione di una matrice in un vettore ==== | ||
+ | |||
+ | Un' | ||
+ | |||
+ | < | ||
+ | subroutine riempivec(n, | ||
+ | implicit none | ||
+ | real vec | ||
+ | integer i,n | ||
+ | dimension vec(n) | ||
+ | | ||
+ | do i=1,n | ||
+ | | ||
+ | enddo | ||
+ | | ||
+ | return | ||
+ | end | ||
+ | </ | ||
+ | |||
+ | Questa subroutine prende in ingresso due variabili, una reale(vec) ed una intera(n) e riempie il vettore vec di elementi 1.*i tramite il ciclo " | ||
+ | Per richiamare questa subroutine all' | ||
+ | |||
+ | < | ||
+ | call riempivec(lmax*imax*jmax, | ||
+ | </ | ||
+ | |||
+ | Il quale prende in ingresso la mia matrice 2x3x4 di 24 elementi e la trasforma in un vettore di 24 elementi. Questo è possibile sempre se il numero totale di elementi prima e dopo combacia. | ||
+ | |||
+ | ======Generazione di una FUNCTION====== | ||
+ | |||
+ | 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' | ||
+ | |||
+ | In questo paragrafo viene trattata solo la FUNCTION dato che la spiegazione della subroutine è già contenuta in lezioni precedenti. | ||
+ | |||
+ | la FUNCTION può essere considerata una subroutine " | ||
+ | |||
+ | ====Struttura della Function==== | ||
+ | |||
+ | La struttura di una generica FUNCTION è del tipo seguente: | ||
+ | |||
+ | < | ||
+ | < | ||
+ | |||
+ | < | ||
+ | |||
+ | return | ||
+ | end | ||
+ | </ | ||
+ | |||
+ | Per richiamarla all' | ||
+ | |||
+ | < | ||
+ | c Prima è necessario definirla in fase di dichiarazione | ||
+ | |||
+ | real <nome funzione> | ||
+ | |||
+ | c Dopodiché è possibile usarla come una qualsiasi funzione implicita a fortran, per calcolare un valore scalare | ||
+ | |||
+ | < | ||
+ | </ | ||
+ | |||
+ | ==== Esempio di programma ==== | ||
+ | |||
+ | Prendiamo il seguente caso come esempio: | ||
+ | Definiamo una Function Sinxx | ||
+ | |||
+ | < | ||
+ | real function sinxx(var) | ||
+ | implicit none | ||
+ | real var | ||
+ | | ||
+ | if (var .ne. 0.0) then | ||
+ | | ||
+ | else | ||
+ | | ||
+ | endif | ||
+ | | ||
+ | return | ||
+ | end | ||
+ | </ | ||
+ | |||
+ | La function va inserita sempre all' | ||
+ | |||
+ | $$ \frac{sin(var)}{var}\ $$ | ||
+ | |||
+ | Restituisce il valore esatto nel caso in cui " | ||
+ | |||
+ | **__IMPORTANTE!!__**: | ||
+ | |||
+ | Per richiamare la FUNCTION all' | ||
+ | |||
+ | < | ||
+ | program prova | ||
+ | real sinxx | ||
+ | write(*,*) sinxx(2.5) | ||
+ | stop | ||
+ | end | ||
+ | </ | ||
+ | |||
+ | Vedo che è necessario ridichiarare all' | ||
+ | |||
+ | Il programma completo quindi risulta essere: | ||
+ | |||
+ | < | ||
+ | c234567==============================================================72! | ||
+ | |||
+ | |||
+ | c dichiarazione di una function | ||
+ | |||
+ | real function sinxx(var) | ||
+ | implicit none | ||
+ | real var | ||
+ | | ||
+ | if (var .ne. 0.0) then | ||
+ | | ||
+ | else | ||
+ | | ||
+ | endif | ||
+ | | ||
+ | return | ||
+ | end | ||
+ | | ||
+ | program prova | ||
+ | | ||
+ | real sinxx | ||
+ | write(*,*) sinxx(2.5) | ||
+ | | ||
+ | stop | ||
+ | end | ||
+ | |||
+ | </ | ||
+ | |||
+ | ====== Codice FEM Tria3 in Fortran ====== | ||
+ | |||
+ | Iniziamo ad implementare un codice ad elementi finiti in fortran con elementi triangolari a 3 nodi. In questo modo potremo avere a disposizione un programma opensource per eseguire verifiche resistenziali su oggetti. | ||
+ | |||
+ | ==== Fase di dichiarazione ==== | ||
+ | |||
+ | < | ||
+ | PROGRAM ELEMENTI FINITI TRIANGOLARI | ||
+ | PARAMETER (NODES=9) | ||
+ | PARAMETER (NELEMS=8) | ||
+ | PARAMETER (IFMAX=3, | ||
+ | DIMENSION XY(2, | ||
+ | | ||
+ | | ||
+ | </ | ||
+ | |||
+ | * NODES=9 : 9 nodi di struttura totali | ||
+ | * NELEMS=8 : 8 elementi triangolari 3 nodi in cui la struttura è divisa | ||
+ | * IFMAX=3 : 3 forze esterne nodali | ||
+ | * ICNMAX=3 : 3 nodi a cui è applicato un vincolo | ||
+ | * XY(2,NODES) : Matrice che contiene le coordinate x,y dei nodi | ||
+ | |||
+ | | |nodo 1|nodo 2|nodo 3|nodo ...| | ||
+ | | x | x1 | x2 | x3 | | | ||
+ | | y | y1 | y2 | y3 | | | ||
+ | |||
+ | * NVERT(3, | ||
+ | |||
+ | esempio: | ||
+ | |||
+ | | | ||
+ | | i | | ||
+ | | j | | ||
+ | | k | | ||
+ | |||
+ | * Matrici e vettori che vengono sempre usati a coppie: IFXY (vettore che indica a quale nodo è applicata una forza esterna), | ||
+ | |||
+ | Esempio di IFXY: Forza nodale applicata al nodo 8 | ||
+ | |||
+ | |nodo| ... | 8 | ... | | ||
+ | |||
+ | Esempio di FXY: | ||
+ | |||
+ | | x | ... | 1.5 | ... | | ||
+ | | y | ... |-2.5 | ... | | ||
+ | |||
+ | * Matrici che vengono usate a coppie: ICNXY(matrice 2xICNMAX che indica a quale nodo è applicato il vincolo e che tipo di vincolo), CNXY(matrice 2xICNMAX che indica l' | ||
+ | |||
+ | Esempio di ICNXY: Vincolo con carrello ad asse verticale applicato al nodo 13 | ||
+ | |||
+ | | nodo | ... | 13 | ... | | ||
+ | | tipo di vincolo | ||
+ | |||
+ | nella riga del tipo di vincolo: 1 è vincolo ad asse verticale, 2 è vincolo ad asse orizzontale, | ||
+ | |||
+ | Esempio di CNXY: | ||
+ | |||
+ | | U | ... | ? | ... | | ||
+ | | V | ... | 1.0 | ... | | ||
+ | |||
+ | spostamento imposto di 1 mm al nodo 13 lungo y; lungo x è stato inserito "?" | ||
+ | |||
+ | * STRUTK(2*NODES, | ||
+ | * FORCE(2*NODES) : vettore dei termini noti del sistema | ||
+ | * UV(2*NODES) : vettore degli spostamenti nodali cioè vettore delle incognite | ||
+ | |||
+ | K*$\delta$=F coincide con STRUTK*UV=FORCE | ||
+ | |||
+ | ==== Dimensionamenti fissi ==== | ||
+ | |||
+ | * D(3,3) : matrice di legame elastico | ||
+ | |||
+ | $$ | ||
+ | | ||
+ | | ||
+ | \nu & 1 & 0 \\ | ||
+ | 0 & 0 & \cfrac{1-\nu}{2} \end{bmatrix} | ||
+ | $$ | ||
+ | |||
+ | * B(3,6) : Matrice di legame spostamenti-deformazioni che è diversa da elemento a elemento perciò sarà allocata di volta in volta per ogni elemento | ||
+ | |||
+ | $$ | ||
+ | \frac{1}{2A} | ||
+ | | ||
+ | y_j - y_k & | ||
+ | \\ | ||
+ | | ||
+ | \\ | ||
+ | x_k - x_j & y_j - y_k & x_i - x_k & y_k - y_i & x_j - x_i & y_i - y_j | ||
+ | \end{bmatrix} | ||
+ | $$ | ||
+ | |||
+ | * BT(6,3) : Trasposta della matrice B | ||
+ | * DB(3,6) : Matrice prodotto tra matrice D e matrice B | ||
+ | * ELK(6,6) : Matrice rigidezza di elemento | ||
+ | |||
+ | $$ | ||
+ | \begin{bmatrix} | ||
+ | k11 & k12 & k13 & k14 & k15 & k16 | ||
+ | \\ | ||
+ | k21 & k22 & k23 & k24 & k25 & k26 | ||
+ | \\ | ||
+ | k31 & k32 & k33 & k34 & k35 & k36 | ||
+ | \\ | ||
+ | k41 & k42 & k43 & k44 & k45 & k46 | ||
+ | \\ | ||
+ | k51 & k52 & k53 & k54 & k55 & k56 | ||
+ | \\ | ||
+ | k61 & k62 & k63 & k64 & k65 & k66 | ||
+ | | ||
+ | $$ | ||
+ | * IPOINT(6) : Vettore mappatura tra GDL locali (dell' | ||
+ | * DELTAEL(6) : Vettore che contiene gli spostamenti nodali di elemento | ||
+ | * SIGMAEL(3) : Vettore che contiene le tensioni del singolo elemento $\sigma_{x}$, | ||
+ | ===== Note fortran: costrutti obsoleti ====== | ||
+ | |||
+ | ===== ARITHMETIC IF ===== | ||
+ | |||
+ | While we are on the subject of IF's, you should be aware of one archaic form called the arithmetic IF. I introduce this only because some of you will be asked to improve an existing program. You should not use this in any new programming. There is a good chance that it will be dropped from some future Fortran standard. The arithmetic IF can be recognized by the fact that the expression within the parentheses results in a numerical result, not a logical (true, false) result. The other give-away is the string of three integers (statement label references) after the right parenthesis. | ||
+ | < | ||
+ | if ( b**2-4*a*c) 100,200,300 | ||
+ | 100 print *, 'Roots are Complex' | ||
+ | go to 400 | ||
+ | 200 print *, ' | ||
+ | go to 400 | ||
+ | 300 print *, 'Two Real Roots' | ||
+ | 400 continue | ||
+ | </ | ||
+ | |||
+ | If the arithmetic expression produces a value less than zero, execution branches to the first label in the list. If it is zero, control branches to the second label, and if the value is greater than zero the program branches to the third label. Repetition of label numbers is permitted in the IF's label list. Note that I must include extra "GO TO" statements to prevent execution of some of the PRINT statements after the initial branch to another PRINT.((da http:// | ||
+ | |||
+ | ===== codice odierno ===== | ||
+ | < | ||
+ | c234567==============================================================72! | ||
+ | program leaddim | ||
+ | implicit none | ||
+ | integer l, | ||
+ | real mat | ||
+ | parameter(lmax=2, | ||
+ | c | ||
+ | dimension mat(lmax, | ||
+ | |||
+ | | ||
+ | c----- fine dichiarazioni, | ||
+ | |||
+ | c call riempimat(lmax, | ||
+ | c call riempimat(1, | ||
+ | call riempivec(lmax*imax*jmax, | ||
+ | |||
+ | cc | ||
+ | c mat(2,1,3) = 1.234567 | ||
+ | | ||
+ | do l=1,lmax | ||
+ | do i=1,imax | ||
+ | write(*,*) ' | ||
+ | enddo | ||
+ | enddo | ||
+ | | ||
+ | stop | ||
+ | end | ||
+ | |||
+ | c l' | ||
+ | |||
+ | c se non inizializzo entro il codice, con -finit-real=nan forzo un' | ||
+ | |||
+ | |||
+ | subroutine riempimat(lmax, | ||
+ | implicit none | ||
+ | real mat | ||
+ | integer l, | ||
+ | dimension mat(lmax, | ||
+ | | ||
+ | do l=1,lmax | ||
+ | do i=1,imax | ||
+ | do j=1,jmax | ||
+ | | ||
+ | enddo | ||
+ | enddo | ||
+ | enddo | ||
+ | | ||
+ | return | ||
+ | end | ||
+ | |||
+ | subroutine riempivec(n, | ||
+ | implicit none | ||
+ | real vec | ||
+ | integer i,n | ||
+ | dimension vec(n) | ||
+ | | ||
+ | do i=1,n | ||
+ | | ||
+ | enddo | ||
+ | | ||
+ | return | ||
+ | end | ||
+ | |||
+ | </ | ||
+ | |||
+ | < | ||
+ | c234567==============================================================72! | ||
+ | |||
+ | |||
+ | c dichiarazione di una function | ||
+ | |||
+ | real function sinxx(var) | ||
+ | implicit none | ||
+ | real var | ||
+ | | ||
+ | if (var .ne. 0.0) then | ||
+ | | ||
+ | else | ||
+ | | ||
+ | endif | ||
+ | | ||
+ | return | ||
+ | end | ||
+ | | ||
+ | program prova | ||
+ | real sinxx | ||
+ | | ||
+ | external sinxx | ||
+ | | ||
+ | write(*,*) sinxx(2.5) | ||
+ | | ||
+ | stop | ||
+ | end | ||
+ | |||
+ | </ | ||
+ | |||
+ | < | ||
+ | c234567==============================================================72! | ||
+ | program pocciavec | ||
+ | implicit none | ||
+ | c | ||
+ | real vec | ||
+ | integer i,ilim,imax | ||
+ | c | ||
+ | parameter(ilim=10) | ||
+ | dimension vec(ilim) | ||
+ | c noto ora che invertendo l' | ||
+ | | ||
+ | c----- fine dichiarazioni, | ||
+ | c | ||
+ | do imax=1, | ||
+ | c | ||
+ | call riempi(imax, | ||
+ | enddo | ||
+ | | ||
+ | stop | ||
+ | end | ||
+ | |||
+ | subroutine riempi(n, | ||
+ | implicit none | ||
+ | integer i,n | ||
+ | real vec | ||
+ | dimension vec(n) | ||
+ | |||
+ | do i=1,n | ||
+ | | ||
+ | enddo | ||
+ | write(*,*) (vec(i), i=1,n) | ||
+ | return | ||
+ | end | ||
+ | |||
+ | </ | ||
+ | |||
+ | ===== esempio codice fortran tria3 ===== | ||
+ | |||
+ | {{: | ||
+ | {{: |