fortran - curs

83
Dan RacoŃi Elemente de Fortran 95 1 Cuprins 0. Introducere 1.0 Constante şi variabile 1.1 OperaŃii algebrice simple 2.1 InstrucŃiunea IF 2.1.1 InstrucŃiunea IF aritmetic 2.1.2 InstrucŃiunea IF logic 2.1.3 InstrucŃiunea BLOCK IF 2.1.4 Compararea şirurilor de caractere 2.1.5 InstrucŃiunea select case 3. InstrucŃiunea DO 3.1 Forma 1 3.2 Forma 2 3.3 Forma 3 3.4 InstrucŃiunea DO WHILE 3.5 IteraŃii 3.5.1 Calculul radicalului 3.5.2 Rezolvarea ecuaŃiilor algebrice neliniare cu metoda Newton 3.5.3 Rezolvarea sistemelor algebrice neliniare de două ecuaŃii cu metoda Newton 3.5.4 Rezolvarea ecuaŃiilor algebrice polinomiale cu coeficienŃi complecşi cu metoda Newton 4. Dezvoltări în serie 5. Tablouri 5.1 Vectori 5.2 Matrice 5.3 Gauss Seidel 5.4 Alocarea dinamică de memorie (în execuŃie) 6. FuncŃii şi subprograme 6.1 Clauza contains. FuncŃii interne 6.2 FuncŃii externe 6.3 FuncŃii în complex 6.4 InstrucŃiunea external 6.5 Subrutine 6.5.1 Transmiterea tablourilor la subprograme 6.5.2 Rezolvarea sistemelor de ecuaŃii algebrice lineare 6.5.3 Calculul valorilor proprii 7. InstrucŃiunea COMMON 7.1 InstrucŃiunea COMMON blank 7.2 InstrucŃiunea COMMON etichetat 7.3 InstrucŃiunea BLOCK DATA 8. InstrucŃiunea INTERFACE 9. InstrucŃiunea MODULE 10. AplicaŃii 10.1 Calculul integralelor definite, QUADPACK 10.2 Integrarea ecuaŃiilor diferenŃiale ordinare, problema Cauchy 10.3 EcuaŃia Burgers omogenă

Upload: gabriela-milea

Post on 11-Aug-2015

221 views

Category:

Documents


7 download

DESCRIPTION

curs FORTRAN - limbaj de programare

TRANSCRIPT

Page 1: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

1

Cuprins 0. Introducere 1.0 Constante şi variabile 1.1 OperaŃii algebrice simple 2.1 InstrucŃiunea IF 2.1.1 InstrucŃiunea IF aritmetic 2.1.2 InstrucŃiunea IF logic 2.1.3 InstrucŃiunea BLOCK IF 2.1.4 Compararea şirurilor de caractere 2.1.5 InstrucŃiunea select case 3. InstrucŃiunea DO 3.1 Forma 1 3.2 Forma 2 3.3 Forma 3 3.4 InstrucŃiunea DO WHILE 3.5 IteraŃii 3.5.1 Calculul radicalului 3.5.2 Rezolvarea ecuaŃiilor algebrice neliniare cu metoda Newton 3.5.3 Rezolvarea sistemelor algebrice neliniare de două ecuaŃii cu metoda Newton 3.5.4 Rezolvarea ecuaŃiilor algebrice polinomiale cu coeficienŃi complecşi cu metoda Newton 4. Dezvoltări în serie 5. Tablouri 5.1 Vectori 5.2 Matrice 5.3 Gauss Seidel 5.4 Alocarea dinamică de memorie (în execuŃie) 6. FuncŃii şi subprograme 6.1 Clauza contains. FuncŃii interne 6.2 FuncŃii externe 6.3 FuncŃii în complex 6.4 InstrucŃiunea external 6.5 Subrutine 6.5.1 Transmiterea tablourilor la subprograme 6.5.2 Rezolvarea sistemelor de ecuaŃii algebrice lineare 6.5.3 Calculul valorilor proprii 7. InstrucŃiunea COMMON 7.1 InstrucŃiunea COMMON blank 7.2 InstrucŃiunea COMMON etichetat 7.3 InstrucŃiunea BLOCK DATA 8. InstrucŃiunea INTERFACE 9. InstrucŃiunea MODULE 10. AplicaŃii 10.1 Calculul integralelor definite, QUADPACK 10.2 Integrarea ecuaŃiilor diferenŃiale ordinare, problema Cauchy 10.3 EcuaŃia Burgers omogenă

Page 2: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

2

10.4 EcuaŃia Poisson 10.5 EcuaŃia de potenŃial pe cerc 10.6 Rezolvarea sistemelor de ecuaŃii neliniare 0. Introducere Fortran este un limbaj de programare potrivit în special pentru calculule numerice şi calcule ştiinŃifice. Limbajul dezvoltat plecând din 1950 a fost utilizat extensiv în meteorologie, analiza structurilor cu metoda elementelor finite, computational fluid dynamics (CFD), computational physics and computational chemistry. Este limbajul de programare utilizat pe supercalculatoare. Numele limbajului provine de la FORmula TRANslating System. Versiunile succesive au adăugat procesarea şirurilor de caractere, block if, do enddo, do while (FOTRAN 77), programarea modulară, array sections, object-based programming (Fortran 90/95) şi object-oriented and generic programming (Fortran 2003). Prin evoluŃie limbajul a devenit deosebit de complex. În expunerea succintă care urmează s-au avut în vedere în special aspectele legate de metodele numerice şi CFD. Pentru compatibilitate cu bibliotecile de programe existente, NETLIB.ORG, Fortran 90 Codes, etc., se prezintă toată gama de instrucŃiuni incluzând instrucŃiunea COMMON şi BLOCK DATA. Programarea modulară (MODULE) permite scrierea de programe compacte şi bine structurate şi de aceea este recomandată ca tehnică de programare. Sunt prezentate o serie de exemple simple (tehnici numerice de bază) dar şi aplicaŃii mai complexe (ecuaŃii diferenŃiale cu derivate parŃiale 2D). Unele programe au fost păstrate în forma originală deoarece sunt algoritmi omologaŃi. Forma fixă a limbajului *.f, *.for are 80 de coloane cu un caracter de continuare în coloana 6 (diferit de zero) . Zona 1-5 este zonă etichetă. Zona 7-72 este zonă instrucŃiune. Comentariile încep cu litera C din coloana 1 sau cu !. Următorul program face parte din biblioteca pppack din NETIB. c ivex.f chapter iv. runge example, with cubic hermite inter polation c from * a practical guide to splines * by c. de boor integer i,istep,j,n,nm1 real aloger,algerp,c(4,20),decay,divdf1,divdf 3,dtau,dx,errmax,g,h * ,pnatx,step,tau(20) data step, istep /20., 20/ g(x) = 1./(1.+(5.*x)**2) print 600 600 format(28h n max.error decay exp.//) decay = 0. do 40 n=2,20,2 c choose interpolation points tau(1), ..., tau(n) , equally c spaced in (-1,1), and set c(1,i) = g(tau( i)), c(2,i) = c gprime(tau(i)) = -50.*tau(i)*g(tau(i))**2, i=1,...,n. nm1 = n-1 h = 2./float(nm1) do 10 i=1,n tau(i) = float(i-1)*h - 1. c(1,i) = g(tau(i)) 10 c(2,i) = -50.*tau(i)*c(1,i)**2 c calculate the coefficients of the polynomi al pieces c do 20 i=1,nm1

Page 3: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

3

dtau = tau(i+1) - tau(i) divdf1 = (c(1,i+1) - c(1,i))/dtau divdf3 = c(2,i) + c(2,i+1) - 2.*divdf1 c(3,i) = (divdf1 - c(2,i) - divdf3)/dta u 20 c(4,i) = (divdf3/dtau)/dtau c c estimate max.interpolation error on (-1,1) . errmax = 0. do 30 i=2,n dx = (tau(i)-tau(i-1))/step do 30 j=1,istep h = float(j)*dx c evaluate (i-1)st cubic piece c pnatx = c(1,i-1)+h*(c(2,i-1)+h*(c(3, i-1)+h*c(4,i-1))) c 30 errmax = amax1(errmax,abs(g(tau(i-1) +h)-pnatx)) aloger = alog(errmax) if (n .gt. 2) decay = * (aloger - algerp)/alog(float(n)/float( n-2)) algerp = aloger 40 print 640,n,errmax,decay 640 format(i3,e12.4,f11.2) stop end

Forma free a limbajului are extensia *.f90. Caracterul de continuare este &, la sfârşitul liniei. Comentariile încep cu semnul de exclamare !. ! ivex.f90 ! chapter iv. runge example, with cubic hermite int erpolation ! from * a practical guide to splines * by c. de boor integer i,istep,j,n,nm1 real aloger,algerp,c(4,20),decay,divdf1,divdf 3,dtau,dx,errmax,g,h & ,pnatx,step,tau(20) data step, istep /20., 20/ g(x) = 1./(1.+(5.*x)**2) print 600 600 format(28h n max.error decay exp.//) decay = 0. do 40 n=2,20,2 ! choose interpolation points tau(1), ..., tau(n) , equally ! spaced in (-1,1), and set c(1,i) = g(tau( i)), c(2,i) = ! gprime(tau(i)) = -50.*tau(i)*g(tau(i))**2, i=1,...,n. nm1 = n-1 h = 2./float(nm1) do 10 i=1,n tau(i) = float(i-1)*h - 1. c(1,i) = g(tau(i)) 10 c(2,i) = -50.*tau(i)*c(1,i)**2 ! calculate the coefficients of the polynomi al pieces ! do 20 i=1,nm1 dtau = tau(i+1) - tau(i) divdf1 = (c(1,i+1) - c(1,i))/dtau divdf3 = c(2,i) + c(2,i+1) - 2.*divdf1 c(3,i) = (divdf1 - c(2,i) - divdf3)/dta u 20 c(4,i) = (divdf3/dtau)/dtau ! ! estimate max.interpolation error on (-1,1) . errmax = 0.

Page 4: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

4

do 30 i=2,n dx = (tau(i)-tau(i-1))/step do 30 j=1,istep h = float(j)*dx ! evaluate (i-1)st cubic piece ! pnatx = c(1,i-1)+h*(c(2,i-1)+h*(c(3, i-1)+h*c(4,i-1))) ! 30 errmax = amax1(errmax,abs(g(tau(i-1) +h)-pnatx)) aloger = alog(errmax) if (n .gt. 2) decay = & (aloger - algerp)/alog(float(n)/float(n -2)) algerp = aloger 40 print 640,n,errmax,decay 640 format(i3,e12.4,f11.2) stop end

1.0 Constante şi variabile In limbajul FORTRAN sunt definite următoarele tipuri de constante: a) Constante de tip întreg, numere cu semn fără punct zecimal: 12, +54, -321 b) Constante de tip real simplă precizie, numere cu semn şi punct zecimal şi eventual exponent: 1.1 , +5.3, 8.31451e0, 9.7654e-3 c) Constante de tip real dublă precizie, numere cu semn şi punct zecimal. Exponentul se notează cu litera d (dublă precizie): 3.14d0, 8.31451d0,7.77d+3,6.754d-9. d) Constante complexe simplă precizie: (parte_reală_simplă_precizie,parte_imaginară_simplă_precizie) (1.2,-3.4) e) Constante complexe dublă precizie: (parte_reală_dublă_precizie,parte_imaginară_dublă_precizie) (+3,1234d2,+0.987d0) f) Constante de tip logic, .true. pentru adevărat şi .false. pentru fals. g) Constante de tip şir de caractere: ‘sir1’,’sirul_doi_de_caractere’,”Van’t Hoff” program constante implicit none integer i real a real(4) x real(8) s double precision f logical adev,fals character(4) sir1,sir2 complex z1 complex(8) z2 i=-3 a=1.1 x=3.5e-4 s=8.31451d0 f=0.123456789e-5 adev=.true.

Page 5: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

5

fals=.false. sir1='abcd' sir2="ab'd" z1=(4.,-3.) z2=(1.234d-2,0.98765d2) namelist/lista/i,a,x,s,f,adev,fals,sir1,sir2,z1,z2 write(*,lista) end program constante

Variabilele în FORTRAN sunt de tipul: a) Intregi integer listă_variabile integer(4) listă_variabile integer indice1,indice2,alfa integer(4) indice3,indice4 b) Reale simplă precizie: real listă_variabile real(4) listă_variabile real j,i,s1,beta real(4) gama,lambda_1 c) Reale dublă precizie: real(8) listă_variabile double precision listă_variabile real(8) w1,w2 double precision k1,h2 d) Complexe simplă precizie: complex listă_variabile complex(4) listă_variabile complex y2,z2,a1,b2 e) Complexe dublă precizie complex(8) lista_variabile double complex lista_variabile complex(8) zz1,a_y double complex ew,er f) Logice

Page 6: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

6

logical listă_variabile logical predicat1,predicat2 Variabilele de tip logic iau valorile adevărat .true. , şi fals .false. h) Sir de caractere character(lungime_şir) lista_variabile character(3) sir1,sir2 character(16) nume,prenume program constante1 ! declaratii explicite de var iabile scalare implicit none ! se suspenda conventia implicita integer(kind=2) c1,c2,c3,c4 ; integer*2 c integer(2) d1,d2,d3,d4 ; integer*2 d integer(kind=4) e1,e2,e3,e4 ; integer*4 e integer(4) :: b1,b2,b3,b4 ; integer b integer a1,a2,a3,a4 ; integer*4 a real(kind=4) i1,i2,i3,i4 ; real*4 i real(4) j1,j2,j3,j4 ; real j real(4) k1,k2,k3,k4 ; real k real*4 l1,l2,l3,l4 ; real*4 l real(kind=8) :: di1,di2,di3,di4 ; real*8 di real(8) dj1,dj2,dj3,dj4 ; real(8) dj real*8 dk1,dk2,dk3,dk4 ; real*8 dk real(8) :: de1,de2,de3,de4,de double precision dl1,dl2,dl3,dl4,dl complex(kind=4) z1,z2,z3,z4 complex(4) w1,w2,w3,w4 ; complex*8 w complex :: v1,v2,v3,v4 complex(kind=8) dz1,dz2,dz3,dz4 complex(8) dw1,dw2,dw3,dw4 double complex :: dv1,dv2,dv3,dv4 logical(kind=2) q1,q2,q3,q4 logical(4) r1,r2,r3,r4 logical p1,p2,p3,p4 c1=1 ; c2=2 ; c3=3 ; c4=4_2 c=c1+c2+c3*c4 d1=-1 ; d2=-2 ; d3=-3 ; d4=-4_2 d=d1+d2+d3-d4 e1=1201 ; e2=1202 ; e3=1203 ; e4=1204 e=e1+e2+e3+e4 a1=-1411 ; a2=-1412 ; a3=-1413_4 ; a4=-1414_4 a=a1*a2/a3+a4 namelist/lista1/c1,c2,c3,c4,c,d1,d2,d3,d4,d write(*,lista1) ; pause 1 namelist/lista2/e1,e2,e3,e4,e,a1,a2,a3,a4,a write(*,lista2) ; pause 2 i1=1.1001 ; i2=-1.21e-01_4 ; i3=4.12 ; i4=5.6

Page 7: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

7

i=i1*i2+i3/i4 j1=i1**2 ; j2=i2**2 ; j3=i3**2 ; j4=i4**2 ; j=j1+j 2+j3+j4 k1=i1+j1 ; k2=i2+j2 ; k3=i3+j3 ; k4=i4/j4 ; k=k1/k 2*k3/k4 l1=0._4 ; l2=0.01_4 ; l3=+0.02e+03_4 ; l4=0.03e-03 l=l1+l2+l3+l4 namelist/lista3/i1,i2,i3,i4,i,j1,j2,j3,j4,j namelist/lista4/k1,k2,k3,k4,k,l1,l2,l3,l4,l write(*,lista3) ; pause 3 write(*,lista4) ; pause 4 di1=1._8 ; di2=2._8 ; di3=3._8 ; di4=4.d0 di=di1/di2+di3**di4 dj1=-0.00123_8 ; dj2=.005_8 ; dj3=+06d-3 ; dj4=0.d 0 dj=abs(dj1)+abs(dj2)+abs(dj3)+abs(dj4) dk1=dble(k1) dk2=dble(k2) dk3=dble(k3) dk4=dble(k4) dk=dk1+dk2+dk3+dk4 de1=dk1*dk2 ; de2=dk2-dk3 ; de3=(dk1-dk2)/(dk3+dk4 ) de4=de1*de2+de3 de=de1-de2-de3+de4 namelist/lista5/di1,di2,di3,di4,di,dj1,dj2,dj3,dj4 ,dj namelist/lista6/dk1,dk2,dk3,dk4,dk,de1,de2,de3,de4 ,de write(*,lista5) ; pause 5 write(*,lista6) ; pause 6 z1=(1.,2.) ; z2=(-1.e03_4,7.01_4) z3=cmplx(i1,i2) ; z4=cmplx(i3,i4) w1=conjg(z1) ;w2=conjg(z2); w3=z1+z2-(z3-z4) ; w4= abs(w3) w=w1/w2+w2*w3 namelist/lista7/z1,z2,z3,z4,w1,w2,w3,w4,w write(*,lista7) ; pause 7 j1=real(w) ; j2=imag(w) write(*,*)'partea reala w=',j1 write(*,*)'partea imaginara w=',j2 write(*,*)' w=',w v1=z1+w1 ; v2=z2-w2 ; v3=z3/w3 ; v4=z4*w4 namelist/lista8/v1,v2,v3,v4 write(*,lista8) ; pause 8 q1=.true. ; q2=.false. q3=c1<c2 ; q4=c3>c4 r1=dk1<=dk2 ; r2=q3.and.q4 ; r3=.not.r2 ; r4=q3.or .q4 p1=r1.and.r2 ; p2=.not.(r1.or.r2) ; p3=p1.and.p2 p4=p1.or.p2 namelist/lista9/q1,q2,q3,q4,r1,r2,r3,r4 write(*,lista9) ; pause 9 namelist/lista10/p1,p2,p3,p4 write(*,lista10) end program constante1

1.1 OperaŃii algebrice simple Programul p1 utilizează limbajul FORTRAN pentru a operaŃii algebrice elementare în real şi complex. Se utilizează convenŃia implicită de declarare a variabilelor. Variabilele care încep cu literele (a-h,o-z) sunt de tip real simplă precizie. Variabilele care încep cu literele i,j,k,l,m sunt de tip întreg. program p1 !

Page 8: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

8

! Calculator stiintific 1 ! ! Conventia implicita de declarare a variabilel or ! Variabilele care incep cu literele (a-h,o-z ) sunt reale ! simpla precizie. ! Variabilele care incep cu literele i,j,k,l, m,m sunt de tip ! intreg. ! complex z1,z2,sc,dc,pc,rc,puc write(*,*)'program p1' x=-1.123 y=6.764 suma=x+y diferenta=x-y produs=x*y raport=x/y n=2 putere1=x**n putere2=y**x namelist/lista1/x,y,suma,diferenta,produs,raport,p utere1,putere2 write(*,lista1) x1=-2. ; y1=1.4 x2= 9.1 ; y2=0.7 z1=cmplx(x1,y1) ! z1=x1+sqrt(-1)*y1 z2=cmplx(x2,y2) ! z2=x2+sqrt(-1)*y2 ! ! Operatii aritmetice simple in complex ! sc=z1+z2 dc=z1-z2 pc=z1*z2 rc=z1/z2 rc_r=real(rc) ! partea reala rc_i=imag(rc) ! partea imaginara puc=z1**n namelist/lista2/z1,z2,sc,dc,pc,rc,rc_r,rc_i,puc write(*,lista2) end program p1

Programul p1e utilizează limbajul FORTRAN pentru a operaŃii algebrice elementare în real şi complex. Se utilizează convenŃia explicită de declarare a variabilelor. program p1e ! ! Calculator stiintific 1 ! ! Conventia explicita de declarare a variabilel or ! implicit none real x,y,suma,diferenta,produs,raport,putere1,pute re2 integer n real x1,y1,x2,y2 complex z1,z2,sc,dc,pc,rc,puc real rc_r,rc_i write(*,*)'program p1e' x=-1.123 y=6.764 suma=x+y diferenta=x-y produs=x*y raport=x/y

Page 9: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

9

n=2 putere1=x**n putere2=y**x namelist/lista1/x,y,suma,diferenta,produs,raport,p utere1,putere2 write(*,lista1) x1=-2. ; y1=1.4 x2= 9.1 ; y2=0.7 z1=cmplx(x1,y1) ! z1=x1+sqrt(-1)*y1 z2=cmplx(x2,y2) ! z2=x2+sqrt(-1)*y2 ! ! Operatii aritmetice simple in complex ! sc=z1+z2 dc=z1-z2 pc=z1*z2 rc=z1/z2 rc_r=real(rc) ! partea reala rc_i=imag(rc) ! partea imaginara puc=z1**n namelist/lista2/z1,z2,sc,dc,pc,rc,rc_r,rc_i,puc write(*,lista2) end program p1e

Programul p2 arată utilizarea funcŃiilor formulă (statement functions). FuncŃiile formulă corespund funcŃiilor din analiza matematică (funcŃii reale de una sau mai multe variabile reale sau complexe). nume_funcŃie(argumente_formale)=expresie_aritmetică In funcŃia formulă pe lângă variabile se pot utiliza constante definite în program înainte de apelul funcŃiei. Apelul funcŃiei se face prin nume şi cu argumentele efective. valoare=nume_funcŃie(argumente_efective) Există o corespondenŃă biunivocă între tipul şi numărul argumentelor formale şi efective. In cazul în care funcŃia este mai complexă se utilizează clauza contains sau funcŃii externe. Programul p2 calculează funcŃiile:

)(

)(')()()(')('

)(

)()(

)cos()('

)sin()(

2)('

)(

2

2

221

xg

xgxfxgxfxh

xg

xfxh

xxg

xxg

xaxf

xaaxf

−=

=

===

+=

πππ

Se utilizează convenŃia implicită de declarare a variabilelor. În programul p2e se utilizează convenŃia explicită de declarare a variabilelor.

Page 10: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

10

program p2 ! ! Statement function ! f(x)=a1+a2*x**2 fp(x)=2.*a2*x ! derivata functiei f(x) g(x)=sin(pi*x) gp(x)=pi*cos(pi*x) ! derivata functiei g(x) h(x)=f(x)/g(x) hp(x)=(fp(x)*g(x)-f(x)*gp(x))/g(x)**2 ! derivata f unctiei h(x) write(*,*)'program p2' a1=1.21 ; a2=-1.32e-1 ; pi=4.*atan(1.) x=1.1 write(*,*)'x=',x,' f(x)=',f(x),' fp(x)=',fp(x) write(*,*)'x=',x,' g(x)=',g(x),' gp(x)=',gp(x) write(*,*)'x=',x,' h(x)=',h(x),' hp(x)=',hp(x) end program p2 program p2e ! ! Statement function ! implicit none real x,f,fp,g,gp,h,hp real a1,a2,pi f(x)=a1+a2*x**2 fp(x)=2.*a2*x ! derivata functiei f(x) g(x)=sin(pi*x) gp(x)=pi*cos(pi*x) ! derivata functiei g(x) h(x)=f(x)/g(x) hp(x)=(fp(x)*g(x)-f(x)*gp(x))/g(x)**2 ! derivata f unctiei h(x) write(*,*)'program p2' a1=1.21 ; a2=-1.32e-1 ; pi=4.*atan(1.) x=1.1 write(*,*)'x=',x,' f(x)=',f(x),' fp(x)=',fp(x) write(*,*)'x=',x,' g(x)=',g(x),' gp(x)=',gp(x) write(*,*)'x=',x,' h(x)=',h(x),' hp(x)=',hp(x) end program p2e

Programul p3 calculează soluŃia unui sistem de două ecuaŃii algebrice liniare:

=

2

1

2

1

2221

1211

b

b

x

x

aa

aa

cu metoda Cramer. Se calculează determinanŃii de ordinul doi:

Page 11: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

11

221

1112

222

1211

211222112221

12110

ba

bad

ab

abd

aaaaaa

aad

=

=

−==

Se presupune că determinantul d0 este diferit de zero.

0

22

0

11

d

dx

d

dx

=

=

program p3 ! ! Rezolva un sistem de doua ecuatii algebrice lin iare cu metoda Cramer ! real a11,a12,b1,x1 real a21,a22,b2,x2 det2(a,b,c,d)=a*d-b*c ! determinant de ordinu l doi ! ! Coeficientii sistemului ! a11= 1.2e0 ; a12= 2.3e0 ; b1=5.e-2 a21=-0.7e1 ; a22= 9.3e0 ; b2=4.e0 write(*,*)'program p3' ! ! Calculul determinantilor de ordin doi ! d0=det2(a11,a21,a12,a22) if(d0 == 0.)stop 'sistem singular' d1=det2(b1 ,b2 ,a12,a22) d2=det2(a11,a21,b1 ,b2 ) ! ! Cramer ! x1=d1/d0 ; x2=d2/d0 ! ! Verificarea solutiei ! v1=a11*x1+a12*x2-b1 v2=a21*x1+a22*x2-b2 namelist/l1/a11,a12,b1,a21,a22,b2,x1,x2,v1,v2 write(*,l1) end program p3

Programul p4 calculează soluŃia unui sistem de trei ecuaŃii algebrice liniare cu metoda Cramer. Se utilizează convenŃia implicită de declarare a variabilelor. In programul p4e se utilizează convenŃia explicită de declarare a variabilelor.

Page 12: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

12

=

3

2

1

3

2

1

333231

232221

131211

b

b

b

x

x

x

aaa

aaa

aaa

32331

22221

11211

3

33331

23221

13111

2

33323

23222

13121

1

333231

232221

131211

0

baa

baa

baa

d

aba

aba

aba

d

aab

aab

aab

d

aaa

aaa

aaa

d

=

=

=

=

Se presupune că determinantul d0 este diferit de zero. DeterminanŃii de ordin trei se calculează prin dezvoltare după prima linie:

2322

131231

)31(

3332

131221

12

3332

232211

11

333231

232221

131211

)1()1()1(aa

aaa

aa

aaa

aa

aaa

aaa

aaa

aaa+++ −+−+−=

Se defineşte o funcŃie formulă pentru calculul determinantului de ordinul doi si o funcŃie formulă pentru calculul determinantului de ordinul trei care utilizează funcŃia formulă a determinantului de ordin 2. SoluŃiile se calculează cu regula lui Cramer:

0

33

0

22

0

11

d

dx

d

dx

d

dx

=

=

=

program p4 ! ! Rezolva un sistem de trei ecuatii algebrice linia re ! cu regula lui Cramer ! det2(a,b,c,d)=a*d-b*c ! determinant de ordinul 2 ! ! Determinant de ordinul trei (dezvoltare dupa prim a linie)

Page 13: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

13

! det3(a11,a21,a31,a12,a22,a32,a13,a23,a33)= $ +(-1.e0)**(1+1)*a11*det2(a22,a32,a23,a33) $ +(-1.e0)**(2+1)*a21*det2(a12,a32,a13,a33) $ +(-1.e0)**(3+1)*a31*det2(a12,a22,a13,a23) ! ! Coeficientii sistemului de ecuatii liniare ! a11=-1.e0 ; a12=+1.e0 ; a13=3.e0 ; b1=4. e0 a21=-2.e0 ; a22=-3.e0 ; a23=5.e0 ; b2=1.e0 a31= 4.e0 ; a32=-6.e0 ; a33=1.1e0 ; b3=0.9e0 ! ! Calculul determinantilor ! d0=det3(a11,a21,a31,a12,a22,a32,a13,a23,a33) if(d0.eq.0.)stop 'sistem singular' d1=det3(b1 ,b2 ,b3 ,a12,a22,a32,a13,a23,a33) d2=det3(a11,a21,a31,b1 ,b2 ,b3 ,a13,a23,a33) d3=det3(a11,a21,a31,a12,a22,a32,b1 ,b2 ,b3 ) ! ! Cramer ! x1=d1/d0 ; x2=d2/d0 ; x3=d3/d0 ! ! Verificarea solutiei ! v1=a11*x1+a12*x2+a13*x3-b1 v2=a21*x1+a22*x2+a23*x3-b2 v3=a31*x1+a32*x2+a33*x3-b3 namelist/l1/a11,a12,a13,b1,a21,a22,a32,b2,a31,a32, a33,b3, # x1,x2,x3,v1,v2,v3 write(*,l1) end program p4 program p4e ! ! Rezolva un sistem de trei ecuatii algebrice linia re ! cu regula lui Cramer ! implicit real(8) (a-h,o-z) ! dubla precizie det2(a,b,c,d)=a*d-b*c ! determinant de ordinul 2 ! ! Determinant de ordinul trei (dezvoltare dupa prim a linie) ! det3(a11,a21,a31,a12,a22,a32,a13,a23,a33)= $ +(-1.d0)**(1+1)*a11*det2(a22,a32,a23,a33) $ +(-1.d0)**(2+1)*a21*det2(a12,a32,a13,a33) $ +(-1.d0)**(3+1)*a31*det2(a12,a22,a13,a23) ! ! Coeficientii sistemului de ecuatii liniare ! a11=-1.d0 ; a12=+1.d0 ; a13=3.d0 ; b1=4.d 0 a21=-2.d0 ; a22=-3.d0 ; a23=5.d0 ; b2=1.d0 a31= 4.d0 ; a32=-6.d0 ; a33=1.1d0 ; b3=0.9d0 ! ! Calculul determinantilor ! d0=det3(a11,a21,a31,a12,a22,a32,a13,a23,a33) if(d0.eq.0.)stop 'sistem singular' d1=det3(b1 ,b2 ,b3 ,a12,a22,a32,a13,a23,a33)

Page 14: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

14

d2=det3(a11,a21,a31,b1 ,b2 ,b3 ,a13,a23,a33) d3=det3(a11,a21,a31,a12,a22,a32,b1 ,b2 ,b3 ) ! ! Cramer ! x1=d1/d0 ; x2=d2/d0 ; x3=d3/d0 ! ! Verificarea solutiei ! v1=a11*x1+a12*x2+a13*x3-b1 v2=a21*x1+a22*x2+a23*x3-b2 v3=a31*x1+a32*x2+a33*x3-b3 namelist/l1/a11,a12,a13,b1,a21,a22,a32,b2,a31,a32, a33,b3, # x1,x2,x3,v1,v2,v3 write(*,l1) end program p4e

2.1 InstrucŃiunea IF (dacă) InstrucŃiunea IF este utilizată pentru comparaŃii. 2.1.1 InstrucŃiunea IF aritmetic if(expresie)eticheta_1,eticheta_2,eticheta_3 Dacă valoarea numerică a expresiei este mai mică decât zero se face salt la eticheta_1. Dacă valoarea numerica a expresiei este egală cu zero se face salt la eticheta_2. Dacă valoarea numerică a expresiei este mai mare decât zero se face salt la eticheta 3. InstrucŃiunea If aritmetic nu este recomandată. Se preferă instrucŃiunea if logic. program if1 ! instructiunea if aritmetic real a,b,c,delta a=1.1 ; b=1.3 ; c=4.5 delta=b**2-4.*a*c if(delta)10,20,30 10 continue write(*,*)'delta negativ' goto 40 20 continue write(*,*)'delta egal cu zero' goto 40 30 continue write(*,*)"delta mai mare decat zero" 40 continue end program if1

2.1.2 InstrucŃiunea IF logic O expresie relaŃională constă în două sau mai multe expresii a caror valoare este comparată pentru a determina dacă relaŃia specificată de catre operatorii logici este satisfăcută. Operatorii relaŃionali sunt: .lt. sau < mai mic .le. sau <= mai mic sau egal .eq. sau == egal .ne. sau /= neegal

Page 15: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

15

.gt. sau > mai mare

.ge. sau >= mai mare sau egal Operatorii logici uzuali sunt: .and. şi logic .or. sau logic .not. negaŃie .eqv. echivalenŃă logică In cazul operatorului .and. expresia este adevărată dacă atât expresia_1 cât şi expresia_2 sunt adevărate. Tabela de adevăr a propoziŃiei (.not.p) este: p .not.p .true. .false. .false. .true. Tabelela de adevăr a propoziŃiei (p.and.q) este următoarea: p q p.and.q .true. .true. .true. .true. .false. .false. .false. .true. .false. .false. .false. .false. Tabela de adevăr a propoziŃiei (p.or.q) este următoarea: p q p.or.q .true. .true. .true. .true. .false. .true. .false. .true. .true. .false. .false. .false. Tabela de adevăr a propoziŃiei (p.eqv.q) este următoarea: p q p.eqv.q .true. .true. .true. .true. .false. .false. .false. .true. .false. .false. .false. .true. logical predicat,expresie_1,expresie_2 . . expresie_1=a.lt.5 . . . expresie_2= b.ge.h

Page 16: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

16

predicat=expresie_1. and. expresie_2 InstrucŃiunea if logic este următoarea: if(expresie)intrucŃiune_atribuire if(a. gt. 0.) x=1.3 Dacă expresia este adevărată se execută instrucŃiunea de atribuire. In caz contrar se trece la următoarea instrucŃiune. if(expresie)goto etichetă if(r. le. 9.)goto 15 Dacă expresia este adevărată se face salt la instrucŃiunea care are eticheta respectivă. program if2 ! if logic real a,b,c,delta ! ! Coeficientii ecuatiei de gradul doi ! a=-2.1 ; b=-4.2 ; c=5.6e0 delta=b*b-4.*a*c if(delta < 0.)write(*,*)'delta negativ' if(delta == 0.)write(*,*)'delta egal cu zero' if(delta > 0.)write(*,*)'delta mai mare decat zer o' if(delta < 0.)goto 55 write(*,*)'Radacini reale' x1=(-b+sqrt(delta))/(2.*a) if(delta > 0.)x2=(-b+sqrt(delta))/(2.*a) write(*,*)'x1=',x1,'x2=',x2 stop 55 continue write(*,*)'radacini complexe' x1r=-b/(2.*a) ; x1c=+sqrt(-delta)/(2.*a) x2r=-b/(2.*a) ; x2c=-sqrt(-delta)/(2.*a) end program if2

2.1.3 InstrucŃiunea BLOC IF Sintaxa instrucŃiunii bloc if este următoarea: if(expresie_1)then bloc _1 elseif(expresie_2)then bloc_2 elseif(expresie_3)then bloc_3 … elseif(expresie_n)then bloc_n

Page 17: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

17

else bloc_else endif Dacă expresia_1 este adevărată se execută blocul 1 de instrucŃiuni şi se sare la instrucŃiunea care urmează după endif. Dacă expresia_n este adevărată se execută blocul n de instrucŃiuni şi se sare la instrucŃiunea care urmează după endif. Dacă toate expresiile sunt false se execută blocul else (dacă există). De exemplu: if(condiŃie_logică)then Bloc de instrucŃiuni (se execută dacă condiŃia logică este adevărată) endif if(condiŃie_logică)then Bloc de instrucŃiuni_1 (se execută dacă condiŃia logică este adevărată) else Bloc de instrucŃiuni_2 (se execută dacă condiŃia logică este falsă) endif program if3 real a,b,c,delta logical predicat1 a=0.9 ; b=1.4 ; c=8.e-2 delta=b*b-4.*a*c predicat1=delta < 0. if(predicat1)then write(*,*)'delta negativ' elseif(delta == 0.)then write(*,*)'delta egal cu zero' else write(*,*)'delta mai mare decat zero' endif end program if3 program if4 real a,b,c logical predicat1,predicat2,predicat3 a=-4.e3 ; b=9.5 ; c=45. predicat1=a > 0. predicat2=(a<0.).or.(c<0.) predicat3=((b+c)<0.).and.(b>0.) namelist/lista/a,b,c,predicat1,predicat2,predicat3 write(*,lista) if(predicat1)then write(*,*)'conditia 1 este adevarata, a>0.' elseif(predicat2)then write(*,*)'conditia 2 este adevarata,(a<0.).or.( c<0.)' elseif(predicat3)then write(*,*)'conditia 3 este adevarata,((b+c)<0.). and.(b>0.)' elseif(a*b*c>9.)then

Page 18: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

18

write(*,*)'a*b*c>9.' else write(*,*)'Toate propozitiile logice sunt false' endif end program if4

2.1.4 Compararea şirurilor de caractere Şirurile de caractere se compară lexical definind operatorii: variabila_logică=lle(sir1,sir2) mai mic sau egal lexical variabila_logică=llt(sir1,sir2) mai mic lexical variabila_logică=lgt(sir1,sir2) mai mare egal lexical variabila_logică=lge(sir1,sir2) mai mare sau egal lexical logical l1,l2 l1=lle(‘abc’,’abd’) return .true.

2.1.5 InstrucŃiunea select case InstrucŃiunea select case are următoarea sintaxă: select case(expr) case(case_value_1) block_1 case(case_value_2) block_2 . . . case default block_default end select Se evaluează expresia (expr). Rezultatul, case_index se compară cu fiecare case_value pentru a găsi o concordanŃă (poate fi numai una). Când o concordanŃă există se execută blocul respectiv şi se sare la instrucŃiunea de după end select. Dacă expresia este logică atunci: case_index .eqv. case_value Dacă expresia este de tip numeric sau de tip caracter atunci: case_index = = case_value Exemplu: integer i select case(i) case(:-1) ! i<= -1 index = -1 case(0) ! i=0 index=0

Page 19: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

19

case(1:) ! i>= 1 end select Exemplu: select case (itest.eq.1) case(.true.) call subprogram1 case(.false.) call subprogram2 end select Exemplu: select case(itest) case(1) call sub1 case(2) call sub2 case default call subd end select Interval A match case low: case_index>=low :high case_index<=high low:high low<=case_index<=high program select_case implicit none integer numar real a,b character(1) operatie write(*,*)'Introduceti un numar (intreg)' read(*,*)numar select case(numar) case(1,3,5,7:9,12) write(*,*)'Numarul este 1 sau 3 sau 5 sau 7,8,9 sau 12' case default write(*,*)'Numarul nu este in secventa programa ta' end select write(*,*)'Introduceti doua numere reale:' read(*,*)a,b write(*,*)'Intoduceti operatia aritmetica:' read(*,'(a)')operatie

Page 20: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

20

select case(operatie) case('+') write(*,*)'Suma este:',a+b case('-') write(*,*)'Diferenta este:',a-b case('*') write(*,*)'Produsul este:',a*b case('/') write(*,*)'Raportul este:',a/b case default write(*,*)'Operatie nedefinita' end select end program select_case

3. InstrucŃiunea DO InstrucŃiunea DO este utilizată pentru realizarea ciclurilor. 3.1 Forma 1 Sintaxa instrucŃiunii este: do etichetă variabila_întreagă = start , final, increment bloc_instrucŃiuni etichetă continue Variabila întreagă ia valori de la start până la final fiind incrementată cu valoarea increment. Dacă variabila increment nu este specificată se consideră implicit valoarea 1. Limbajul Fortran acceptă şi variabile de tip real pentru variabilele start,final şi increment. InstrucŃiunea se execută de: max(int(final-start+increment)/increment),0) ori. 3.2 Forma 2 Sintaxa instrucŃiunii este: do etichetă variabilă_întreagă=start, final, increment bloc instrucŃiuni eticheta enddo Eticheta este opŃională. do variabilă_întreagă=start, final, increment bloc instrucŃiuni enddo Variabila întreagă ia valori de la start până la final fiind incrementată cu valoarea increment. Ieşirea forŃată dintr-un ciclu do se face cu instrucŃiunea exit. do variabilă_întreagă=start, final, increment bloc instructiuni if(conditie_logica)exit enddo Eliminarea unor instrucŃiuni din ciclu se face cu instrucŃiunea cycle.

Page 21: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

21

do var=start,final,increment bloc1 if(conditie_logică) cycle bloc2 enddo Dacă condiŃia logică este adevărată blocul 2 de instrucŃiuni nu se mai execută. 3.3 Forma 3 Sintaxa instrucŃiunii este: do bloc instrucŃiuni if(condiŃie_logică)exit enddo Ieşirea din ciclu se face cu instrucŃiunea exit. 3.4 InstrucŃiunea do while Sintaxa instrucŃiunii este: do eticheta while(condiŃie_logică) bloc instrucŃiuni eticheta enddo Ciclul se execută cât timp condiŃia logică este adevărată. Eticheta este opŃională: do while(condiŃie_logică) bloc instrucŃiuni enddo program do1 ! ! Cicluri do elementare ! implicit real(8) (a-h,o-z) ! dubla precizie do 10 i=1,5 write(*,*)'i=',i 10 continue write(*,*) do i=1,6 write(*,*)'i=',i enddo write(*,*) do i=-10,14,2 write(*,*)'i=',i enddo

Page 22: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

22

write(*,*) n=10 do i=n,1,-1 write(*,*)'i=',i enddo write(*,*) do 12345 k=1,15,3 write(*,*)'k=',k 12345 enddo write(*,*) j=0. do while(j<5) write(*,*)'j=',j j=j+1 enddo write(*,*) x=10.d0 do while(x>0.d0) write(*,*)'x=',x x=x-1.d0 enddo write(*,*) x=-5.1d0 do x=x+1.5d0 if(x<0.d0)cycle write(*,*)'x=',x,' radical x=',sqrt(x) if(x>20.d0)exit enddo end program do1

3.5 IteraŃii Numeroşi algoritmi numerici sunt iterativi. LimitaŃi întotdeauna numărul de iteraŃii pentru a evita buclele infinite. 3.5.1 Calculul radicalului Calculul radicalului se bazează pe rezolvarea ecuaŃiei neliniare:

yyf

xyyf

xy

2)('

0)( 2

==−=

=

Şirul iterativ Newton este:

+=−=+

kk

k

kkk

y

xy

yf

yfyy 5.0

)('

)(1 , k=0,1,…

După cum se observă calculul radicalului se reduce la operaŃii aritmetice elementare. AproximaŃia iniŃială este:

Page 23: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

23

20 x

y =

Calculul se opreşte dacă:

ε<)( kyf

Numărul de iteraŃii este limitat de o valoare maximă pentru a evita intrarea într-o buclă infinită. program radical implicit real(8) (a-h,o-z) integer,parameter :: iter_max=10 real(8) :: eps=1.d-8 logical succes fy(y)=y**2-x x=9.d0 y=x/2.d0 ! aproximatia initiala Newton f=fy(y) write(*,'(/,a,/)')'Iteratiile Newton' succes=.false. iter=0 write(*,*)iter,y,f do while((iter<iter_max).and.(f>eps)) iter=iter+1 y=0.5d0*(y+x/y) f=fy(y) write(*,*)iter,y,f enddo write(*,*) if(iter<iter_max)succes=.true. if(succes)then write(*,*)'x=',x,' radical(x)=',y else write(*,*)'Metoda nu converge' endif end program radical

3.5.2 Rezolvarea ecuaŃiilor algebrice neliniare cu metoda Newton Metoda Newton pentru rezolvarea ecuaŃiei neliniare:

0)( =xf este:

)('

)(1k

kkk

xf

xfxx −=+ k=0,1,2,…

Variabila k este contorul de iteraŃii. Pentru pornirea iteraŃiilor se alege o valoare iniŃială x0. Metoda este convergentă în apropierea soluŃiei. IteraŃiile sunt oprite dacă modulul funcŃiei este mai mic decât o valoare impusă:

1)( ε<kxf

sau dacă diferenŃa între două valori x este mai mică decât o valoare impusă:

21 ε<−+ kk xx

Numărul de iteraŃii este limitat la valoarea nmax pentru a evita o buclă infinită. Considerăm ecuaŃia neliniară:

Page 24: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

24

)cos()exp()('

)sin()exp()(

)sin()exp(

xxxf

xxxf

xx

−−−=−−=

=−

Programul pentru rezolvarea ecuaŃiei neliniare este prezentat în continuare. program iteratii_1 implicit real(8) (a-h,o-z) parameter (eps1=1.d-5) parameter (eps2=1.d-6) integer,parameter :: nmax=25 ! numarul maxim de it eratii fct(x)=exp(-x)-sin(x) ! functia dfct(x)=-exp(-x)-cos(x) ! derivata write(*,*)'Iteratiile metodei Newton' x=0.1d0 ! aproximatia initiala do iter=0,nmax f=fct(x) write(*,*)iter,x,f if(abs(f)<eps1)goto 33 df=dfct(x) dx=f/df if(abs(dx)<eps2)goto 33 x=x-dx enddo write(*,*)'Metoda nu converge in nmax iteratii' stop 33 continue write(*,*) write(*,*)'Solutia ecuatiei este =',x write(*,*)'Valoarea functiei este=',fct(x) end program iteratii_1

3.5.3 Rezolvarea sistemelor algebrice neliniare de două ecuaŃii cu metoda Newton

Metoda Newton pentru rezolvarea sistemului de ecuaŃii neliniare:

0),(

0),(

==

yxg

yxf

este:

−=

∆∆

∂∂

∂∂

∂∂

∂∂

),(

),(

),(),(

),(),(

kk

kk

kkkk

kkkk

yxg

yxf

y

x

y

yxg

x

yxgy

yxf

x

yxf

yyy

xxxkk

kk

∆+=∆+=

+

+

1

1

k=0,1,…

Indicele k este contorul de iteraŃii. AproximaŃia iniŃială este determinată minimizând funcŃia de două variabile:

yx

ds

byb

axa

yxgyxfyx

<<<<

+= ),(),(),( 22φ

prin explorarea domeniului în care se caută soluŃia.

Page 25: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

25

Derivatele parŃiale sunt calculate numeric cu formule de derivare cu diferenŃe centrale:

h

hyxfhyxf

y

fh

yhxfyhxf

x

f

2

),(),(2

),(),(

−−+=∂∂

−−+=∂∂

h

hyxghyxg

y

fh

yhxgyhxg

x

g

2

),(),(2

),(),(

−−+=∂∂

−−+=∂∂

IteraŃiile sunt oprite dacă este îndeplinită condiŃia: ε<∆+∆ yx

Numărul maxim de iteraŃii este limitat pentru a nu se intra într-o buclă infinită. program iteratii_2 implicit none real(8) x,y,f,g,fct,gct,det2 real(8) :: al=-10.d0 ! marginea stanga a interval ului pentru x real(8) :: ad=+10.d0 ! marginea dreapta a interval ului pentru x real(8) :: bl=-10.d0 ! marginea stanga a interval ului pentru y real(8) :: bd=+10.d0 ! marginea dreapta a interval ului pentru y integer,parameter :: n=10 ! numarul de intervale p e x si y real(8) :: hx ! pas de discretizare pe axa x real(8) :: hy ! pas de discretizare pe axa y real(8) :: fmin ! valoarea minima a functiei fct(x )**2+gct(x)**2 real(8) :: xs ! abscisa punctului de minim real(8) :: ys ! ordonata punctului de minim real(8) d0,d1,d2 real(8) dx,dy real(8) a11,a12,a21,a22 integer iter,i,j real(8) pas,dfdx,dfdy,dgdx,dgdy integer,parameter :: iter_max=15 ! ! Sistemul de ecuatii neliniare ! fct(x,y)=x**2-3.d0*x+2.d0*y-0.01d0*exp(y) gct(x,y)=x-0.98d0*y det2(a11,a21,a12,a22)=a11*a22-a12*a21 ! determinan tul de ordin doi write(*,'(a,/)')"program iteratii_2" hx=(ad-al)/(n-1) ! pasul de discretizare pe axa x hy=(bd-bl)/(n-1) ! pasul de discretizare pe axa y fmin=1.d77 ! ! Se determina minimul functiei fct(x,y)**2+gct(x,y )**2 prin explorarea ! domeniului al<x<ad, bl<y<bd ! do i=1,n-1 do j=1,n-1 x=al+(i-1)*hx y=bl+(j-1)*hy f=fct(x,y)**2 + gct(x,y)**2

Page 26: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

26

if(f<fmin)then fmin=f xs=x ; ys=y endif enddo enddo if(fmin.eq.1.d77)stop 'nelocalizare 2D' x=xs ; y=ys ! aproximatiile initiale Newton pas=1.d0/512.d0 ! pas de derivare numerica write(*,'(/,a,/)')'Iteratiile metodei Newton' write(*,*)' x y f g' do iter=1,iter_max f=fct(x,y) ; g=gct(x,y) write(*,'(i3,2x,4(g13.6,1x))')iter,x,y,f,g if(abs(f)+abs(g) < 1.d-6)go to 33 ! ! Derivatele partiale ale functiei fct(x,y ) ! dfdx=(fct(x+pas,y)-fct(x-pas,y))/(pas+pas) dfdy=(fct(x,y+pas)-fct(x,y-pas))/(pas+pas) ! ! Derivatele partiale ale functiei gct(x,y ) ! dgdx=(gct(x+pas,y)-gct(x-pas,y))/(pas+pas) dgdy=(gct(x,y+pas)-gct(x,y-pas))/(pas+pas) ! ! Rezolvarea unui sistem liniar de gradul doi cu m etoda Cramer ! d0=det2(dfdx,dgdx,dfdy,dgdy) if(d0.eq.0.d0)stop 'Jacobian singular' d1=det2(-f,-g,dfdy,dgdy) d2=det2(dfdx,dgdx,-f,-g) dx=d1/d0 ! corectiile Newton dy=d2/d0 if(abs(dx)+abs(dy) < 1.d-6)goto 33 x=x+dx ! iteratiile Newton y=y+dy enddo write(*,*)'neconvergenta Newton 2D' stop 33 write(*,'(/,a,f13.6,f13.6)')'Solutia =',x,y write(*,'(a,f13.6,f13.6)')'Functiile=',fct(x,y), gct(x,y) 66 continue end program iteratii_2

3.5.4 Rezolvarea ecuaŃiilor algebrice polinomiale cu coeficienŃi complecşi cu metoda Newton

Rezolvarea ecuaŃiilor algebrice polinomiale cu coeficienŃi în complex de reduce la rezolvarea unui sistem de două ecuaŃii algebrice neliniare în real. Fie ecuaŃia:

Caaaaa

zazazazaazh

∈=++++=

54321

45

34

2321

,,,,

0)(

este echivalentă cu sistemul de ecuaŃii algebrice:

0))(Im(),(

0))(Re(),(

====

zhyxg

zhyxf

Conform teoremei fundamentale a algebrei sistemul de două ecuaŃii are 4 soluŃii (o ecuaŃie de gradul patru are patru soluŃii complexe).

Page 27: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

27

program iteratii_3 ! ! Calculeaza o solutie complexa a ecuatiei algebric e (polinomiale) ! a1+a2*z+a3*z**2+a4*z**3+a5*z**4=0 ! implicit real(8) (a-h,o-z) integer,parameter :: iter_max=15 complex(8) z,fz complex a1,a2,a3,a4,a5 ! ! Ecuatia algebrica polinomiala in complex ! fz(z)=a1+a2*z+a3*z**2+a4*z**3+a5*z**4 ! ! Sistemul de doua ecuatii neliniare echivalent ! fct(x,y)=real(fz(cmplx(x,y))) gct(x,y)=imag(fz(cmplx(x,y))) det2(a11,a21,a12,a22)=a11*a22-a12*a21 ! determinan tul de ordin doi ! ! Coeficientii complecsi ai ecuatiei algebrice ! a1=(1.0d0, 0.45d0) a2=(2.0d0, 0.88d0) a3=(3.0d0,-0.55d0) a4=(0.3d0, 0.79d0) a5=(1.0d0,-1.08d0) write(*,'(a,/)')"program iteratii_3" x=-1.d0 ; y=+1.d0 ! aproximatiile initiale New ton pas=1.d0/512.d0 ! pas de derivare numerica write(*,'(/,a,/)')'Iteratiile metodei Newton' write(*,*)' x y f g' do iter=1,iter_max f=fct(x,y) ; g=gct(x,y) write(*,'(i3,2x,4(g13.6,1x))')iter,x,y,f,g if(abs(f)+abs(g) < 1.d-6)go to 33 ! ! Derivatele partiale ale functiei fct(x,y ) ! dfdx=(fct(x+pas,y)-fct(x-pas,y))/(pas+pas) dfdy=(fct(x,y+pas)-fct(x,y-pas))/(pas+pas) ! ! Derivatele partiale ale functiei gct(x,y ) ! dgdx=(gct(x+pas,y)-gct(x-pas,y))/(pas+pas) dgdy=(gct(x,y+pas)-gct(x,y-pas))/(pas+pas) ! ! Rezolvarea unui sistem liniar de gradul doi cu m etoda Cramer ! d0=det2(dfdx,dgdx,dfdy,dgdy) if(d0.eq.0.d0)stop 'Jacobian singular' d1=det2(-f,-g,dfdy,dgdy) d2=det2(dfdx,dgdx,-f,-g) dx=d1/d0 ! corectiile Newton dy=d2/d0 if(abs(dx)+abs(dy) < 1.d-6)goto 33 x=x+dx ! iteratiile Newton y=y+dy enddo write(*,*)'neconvergenta Newton 2D'

Page 28: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

28

stop 33 write(*,'(/,a,f13.6,f13.6)')'Solutia =',x,y write(*,'(a,f13.6,f13.6)')'Functiile=',fct(x,y), gct(x,y) 66 continue end program iteratii_3

4. Dezvoltări în serie SoluŃia analitică a ecuaŃiei Poisson:

11

11

22

2

2

2

+<<−+<<−

−=∂∂+

∂∂

y

x

y

u

x

u

cu condiŃia la limită u=0 pe contur este:

∑ ∑∞

=

= +=

5,3,1 5,3,1224 )(

)2

cos()2

cos(128),(

n m nmmn

ynxm

yxu

ππ

π

program ds1 ! ! Solutia analitica (serii duble) Ec. Poisson ! Laplacian(u)=-2 ! -1<x<+1 ! -1<y<+1 ! Conditia la limita u=0 pe frontiera ! implicit real(8) (a-h,o-z) pi=4.d0*atan(1.d0) x=0.45d0 ; y=-0.3d0 u=0.d0 do n=1,11,2 do m=1,11,2 u=u+(-1.d0)**(0.5d0*(m+n)-1)* # cos(m*pi*x/2.d0)*cos(n*pi*y/2.d0)/(m*n* (m**2+n**2)) enddo enddo ue=u*128/pi**4 write(*,'(a,g13.6)')' x=',x,' y=',y,' u=',ue end FuncŃia exponenŃială se calculează utilizând dezvoltarea în serie:

...!

...!3!21

132

++++++=i

xxxxe

ix

Calculul se efectuează adunând termen cu termen. Dacă un termen este mai mic decât toleranŃa impusă calculul se opreşte:

ε<!k

xk

! ------------------------------------------------- -------- ! Calculeaza exp(x) pentru x dat utilizand dezvolta rea in serie ! infinita cu o toleranta data ! ------------------------------------------------- --------

Page 29: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

29

PROGRAM calculul_functiei_exponentiale ! DEZVOLTAR E IN SERIE IMPLICIT NONE INTEGER :: index ! numarul d e termeneni REAL(8) :: termen ! un termen REAL(8) :: exp_calc ! valoarea seriei REAL(8) :: X ! valoarea argumentului REAL(8),PARAMETER :: tol = 1.d-9 ! toleranta WRITE(*,*)'INTRODUCETI X' READ(*,*) X index = 1 ! primul te rmen din serie exp_calc = 1.0 termen = X ! al doilea termen in serie DO IF (ABS(termen) < tol) EXIT exp_calc = exp_calc + termen index = index + 1 termen = termen * (X / index) ENDDO WRITE(*,*) 'Dupa ', index, ' iteratii:' WRITE(*,*) ' Exp_calculat = ', exp_calc WRITE(*,*) ' Exp_exact = ', EXP(X) WRITE(*,*) ' Abs(Error) = ', ABS(exp_calc - EXP(X)) END PROGRAM calculul_functiei_exponentiale

5. Tablouri Limbajul FORTRAN acceptă tablouri cu până la 7 dimensiuni. Tablourile cu o dimensiune corespund vectorilor n-dimensionali. Tablourile cu două dimensiuni corespund matricilor. Declararea unui tablou se face în felul următor: Tip nume_tablou(n1i:n1f,n2i:n2f,n3i:n3f) unde: tip : integer(4), real(4), real(8), logical, complex(4), complex(8) nume_tablou: numele tabloului n1i : valoarea întreagă iniŃială a indicelui (dacă lipseşte se consideră implicit 1) n1f : valoarea întreagă finală a indicelui real(8) v(1:3) corespunde lui v(1),v(2),v(3) real(8) v1(2) corespunde lui v1(1),v1(2) real mat(1:2,1:2) corespunde lui mat(1,1),mat(1,2) mat(2,1),mat(2,2) 5.1 Vectori Vectorii sunt tablouri cu o dimensiune. OperaŃiile matematice cu vectori sunt identice cu cele din algebră pentru vectori de tip real şi complex. OperaŃiile elementare în complex sunt definite in limbajul FORTRAN. Considerăm vectori de dimensiune n.

Page 30: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

30

OperaŃiile cu vectoriale sunt definite în limbajul FORTRAN. Dacă a şi b sunt doi vectori cu trei elemente complexe, operaŃia:

bac += este echivalentă cu adunarea explicită a elementelor vectorilor:

333

222

111

bac

bac

bac

+=+=+=

In FORTRAN se scrie: complex a(3),b(3),c(3)

)3()3()3(

)2()2()2(

)1()1()1(

bac

bac

bac

sau

bac

+=+=

+=

+=

ÎnmulŃirea unui vector cu o constantă:

nicvv

vcv

ii ,...,2,1,12

12

===

Adunarea a doi vectori:

nivvv

vvv

iii ,...,2,1,213

213

=+=+=

Scăderea a doi vectori:

nivvv

vvv

iii ,...,2,1,213

213

=−=−=

Produsul scalar a doi vectori:

i

n

ii vvvv 2

1121. ∑

=

=

Norma unui vector: 5.02

1

= ∑

=

n

iivv

Dacă vectorul este de tip real atunci:

( ) 5.0.vvv =

In FORTRAN este definită operaŃia de înmulŃire a doi vectori, element cu element.

=

3

2

1

x

x

x

x

=

3

2

1

y

y

y

y

=

33

22

11

*

yx

yx

yx

yx

InstrucŃiunile: real x(3),z(3),s

Page 31: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

31

s=sum(x*z) conduc la:

332211 yxyxyxs ++=

program vect1 ! operatii elementare cu vectori implicit none integer,parameter :: n=5 ! dimensiunea vectorului real v1(n),v2(1:n),v3(n) real s1,s2,ps,p1,p2,v1min,v2min,v1max,v2max,norma,c onst integer i v1=(/1.,1.2,3.,4.1,5.5/) ! elementele vectorului 1 data v2/9.,3.1,2.,1.1,3.3/ ! elementele vectorului 2 declarate cu ! data lista_v/lista_con stante/ write(*,*)'Program vect1' do i=1,n write(*,*)v1(i),v2(i) enddo ! ! Suma elementelor vectorilor ! s1=0.d0 ; s2=0.d0 do i=1,n s1=s1+v1(i) s2=s2+v2(i) enddo write(*,*)'Suma_v1=',s1,' Suma_v2=',s2 ! ! Functia sum(vector) calculeaza suma elementelor v ectorului ! write(*,*)'Suma_v1=',sum(v1),' Suma_v2=',sum(v2) ! ! Produsul elementelor vectorilor ! p1=1.d0 ; p2=1.d0 do i=1,n p1=p1*v1(i) p2=p2*v2(i) enddo write(*,*)'Produs_v1=',p1,' Produs_v2=',p2 ! ! Functia product(vector) calculeaza produsul eleme ntelor vectorului ! write(*,*)'Produs_v1=',product(v1),' Produs_v2=',p roduct(v2) ! ! Maximul si minimul din fiecare vector ! v1max=v1(1) ; v2max=v2(1) v1min=v1(1) ; v2min=v2(1) do i=2,n if(v1(i)>v1max)v1max=v1(i) if(v2(i)>v2max)v2max=v2(i) if(v1(i)<v1min)v1min=v1(i) if(v2(i)<v2min)v2min=v2(i) enddo write(*,*)'v1_max=',v1max,' v2_max=',v2max write(*,*)'v1_min=',v1min,' v2_min=',v2min !

Page 32: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

32

! Inmultirea unui vector cu o constanta ! const=1.345 v3=v1*const ! vectorial write(*,*)'Inmultirea vectorului v1 cu constanta= ',const write(*,'(2g13.6)')(v1(i),v3(i),i=1,n) ! ! Adunarea a doi vectori ! v3=v1+v2 ! vectorial ! ! Adunarea explicita ! write(*,*)'Suma a doi vectori' do i=1,n v3(i)=v1(i)+v2(i) write(*,'(3g13.6)')v1(i),v2(i),v3(i) enddo ! ! Scaderea a doi vectori ! v3=v1-v2 ! vectorial ! ! Scaderea explicita ! write(*,*)'Diferenta a doi vectori' do i=1,n v3(i)=v1(i)-v2(i) write(*,'(3g13.6)')v1(i),v2(i),v3(i) enddo ! ! Produsul scalar ! write(*,*)'Produs scalar' ps=0.d0 do i=1,n ps=ps+v1(i)*v2(i) enddo write(*,*)'Produs_scalar=',ps ! ! Functia dot_product(vector1,vector2) calculeaza p rodusul scalar ! write(*,*)'Produs_scalar=',dot_product(v1,v2) ! ! Inmultirea a doi vectori component cu component ! v3=v1*v2 write(*,*)'Inmultirea pe componente' write(*,'(i3,2x,3g13.6)')(i,v1(i),v2(i),v3(i),i=1, n) ! ! Norma unui vector ! norma=sqrt(dot_product(abs(v1),abs(v1))) write(*,*)'norma vectorului v1=',norma end program vect1 program maxloc_minloc ! ! locul valorii maxime si valoarea maxima intr-un v ector

Page 33: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

33

! locul valorii minime si valoarea minima intr-un v ector ! implicit none integer locatie(1) real,dimension(5) :: x=(/1.,4.,7.,5.,-1./) real xmax,xmin write(*,*)x locatie=maxloc(x) ! indicele valorii maxime xmax=maxval(x) ! valoarea maxima write(*,*)locatie,xmax locatie=minloc(x) ! indicele valorii minime xmin=minval(x) ! valoarea minima write(*,*)locatie,xmin end program maxloc_minloc

5.2 Matrici Matricile sunt tablouri cu două dimensiuni. Matricile sunt memorate pe coloană. real a(1:2,1:3) echivalentă cu real a(2,3) a(1,1) a(1,2) a(1,3) a(2,1) a(2,2) a(2,3) Reprezentarea internă: 1 a(1,1) 2 a(2,1) 3 a(1,2) 4 a(2,2) 5 a(1,3) 6 a(2,3) OperaŃiile matriciale din algebră se transpun direct in limbajul FORTRAN pentru matrice cu elemente întregi, reale şi complexe. Considerăm matrice cu elemente complexe pătrate de dimensiune n. ÎnmulŃirea unei matrice cu o constantă:

njnicac

cAC

ijij ,...,2,1,,...,2,1, ====

Adunarea a două matrice:

njnibac

BAC

ijijij ,...,2,1,,...,2,1, ==+=+=

Scăderea a două matrice:

njnibac

BAC

ijijij ,...,2,1,,...,2,1, ==−=−=

ÎnmulŃirea a două matrice:

njnibac

ABC

kj

n

jikij ,...,2,1,,...,2,1,

1

===

=

∑=

Page 34: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

34

Norma unei matrice: 5.0

1 1

2

= ∑∑

= =

n

i

n

jijaA

OperaŃiile matriciale sunt definite în FORTRAN. complex a(2,2),b(2,2),c(2,2)

)2,2()2,2()2,2(

)1,2()1,2()1,2(

)2,1()2,1()2,1(

)1,1()1,1()1,1(

:

bac

bac

bac

bac

sau

bac

+=+=+=

+=

+=

Programul mat1.f90 efectuează calculele matriciale elementare matricial . program mat1 implicit none integer,parameter :: n=3 ! dimensiunea matricilor real,dimension(n,n) :: a,b ! se declara matricile a si b ! cu n linii si n coloan e real c(n,n),v1(n),v2(n) real :: const=3.3 ! Se defineste constanta const real norma integer i,j data (a(1,j),j=1,n)/1.,2.,3./ ! prima linie din m atricea a data (a(2,j),j=1,n)/4.,5.,6./ ! a doua linie din m atricea a data (a(3,j),j=1,n)/7.,8.,9./ ! a treia linie din m atricea a data b/-1.,-2.,-3., & ! prima coloana din matrice a b -6.,-4.,-2., & ! a doua coloana din matrice a b 8., 2., 1./ ! a treia coloana din matricea b data v1(1),v1(2),v1(3)/1.1,2.2,3.3/ ! vectorul v1 write(*,*)'Matricea a' do i=1,n write(*,'(3g13.6)')(a(i,j),j=1,n) enddo write(*,*)'Matricea b' write(*,'(3g13.6)')((b(i,j),j=1,n),i=1,n) ! ! Produsul unei matrici cu o constanta ! c=const*a ! matricial write(*,*)'Produsul unei matrici cu o constanta' write(*,*)'Matricea c' write(*,'(3g13.6)')((c(i,j),j=1,n),i=1,n) ! ! Suma a doua matrici ! c=a+b ! matricial

Page 35: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

35

write(*,*)'Suma a doua matrici' write(*,*)'Matricea c' write(*,'(3g13.6)')((c(i,j),j=1,n),i=1,n) ! ! Diferenta a doua matrici ! c=a-b ! matricial write(*,*)'Diferenta a doua matrici' write(*,*)'Matricea c' write(*,'(3g13.6)')((c(i,j),j=1,n),i=1,n) ! ! Produsul unei matrici cu un vector ! v2=matmul(a,v1) write(*,*)'Produsul unei matrici cu un vector' write(*,'(g13.6)')(v2(i),i=1,n) ! ! Produsul a doua matrici ! c=matmul(a,b) write(*,*)'Produsul a doua matrici' write(*,*)'Matricea c' write(*,'(3g13.6)')((c(i,j),j=1,n),i=1,n) ! ! Norma matriciala ! norma=0.d0 do i=1,n do j=1,n norma=norma+abs(a(i,j))**2 enddo enddo norma=sqrt(norma) write(*,*)'Norma matricei a' write(*,*)'norma=',norma end program mat1

Programul mat2.f90 efectuează operaŃiile matriciale explicit. program mat2 implicit none integer,parameter :: n=3 ! dimensiunea matricilor real,dimension(n,n) :: a,b ! se declara matricile a si b ! cu n linii si n coloan e real c(n,n),v1(n),v2(n) real :: const=3.3 ! Se defineste constanta const real norma,suma integer i,j,k data (a(1,j),j=1,n)/1.,2.,3./ ! prima linie din m atricea a data (a(2,j),j=1,n)/4.,5.,6./ ! a doua linie din m atricea a data (a(3,j),j=1,n)/7.,8.,9./ ! a treia linie din m atricea a data b/-1.,-2.,-3., & ! prima coloana din matrice a b -6.,-4.,-2., & ! a doua coloana din matrice a b

Page 36: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

36

8., 2., 1./ ! a treia coloana din matricea b data v1(1),v1(2),v1(3)/1.1,2.2,3.3/ ! vectorul v1 write(*,*)'Matricea a' do i=1,n write(*,'(3g13.6)')(a(i,j),j=1,n) enddo write(*,*)'Matricea b' write(*,'(3g13.6)')((b(i,j),j=1,n),i=1,n) ! ! Produsul unei matrici cu o constanta ! do i=1,n do j=1,n c(i,j)=const*a(i,j) enddo enddo write(*,*)'Produsul unei matrici cu o constanta' write(*,*)'Matricea c' write(*,'(3g13.6)')((c(i,j),j=1,n),i=1,n) ! ! Suma a doua matrici ! do i=1,n do j=1,n c(i,j)=a(i,j)+b(i,j) enddo enddo write(*,*)'Suma a doua matrici' write(*,*)'Matricea c' write(*,'(3g13.6)')((c(i,j),j=1,n),i=1,n) ! ! Diferenta a doua matrici ! do i=1,n do j=1,n c(i,j)=a(i,j)-b(i,j) enddo enddo write(*,*)'Diferenta a doua matrici' write(*,*)'Matricea c' write(*,'(3g13.6)')((c(i,j),j=1,n),i=1,n) ! ! Produsul unei matrici cu un vector ! do i=1,n suma=0. do j=1,n suma=suma+a(i,j)*v1(j) enddo v2(i)=suma enddo write(*,*)'Produsul unei matrici cu un vector' write(*,'(g13.6)')(v2(i),i=1,n) ! ! Produsul a doua matrici ! do i=1,n do j=1,n

Page 37: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

37

suma=0. do k=1,n suma=suma+a(i,k)*b(k,j) enddo c(i,j)=suma enddo enddo write(*,*)'Produsul a doua matrici' write(*,*)'Matricea c' write(*,'(3g13.6)')((c(i,j),j=1,n),i=1,n) ! ! Norma matricei a ! norma=0.d0 do i=1,n do j=1,n norma=norma+abs(a(i,j))**2 enddo enddo norma=sqrt(norma) write(*,*)'Norma matricei a' write(*,*)'norma=',norma end program mat2

Matricele pot fi iniŃializate cu instrucŃiunea data sau utilizând instrucŃiunea reshape: result=reshape(source,shape) InstrucŃiunea: a=reshape((/1.,2.,3.,4./),(/2.,2./) este echivalentă cu:

=

.4.2

.3.1a

program reshape_function implicit none real a(2,3),b(3,3) integer i ! ! Matricea a memorata pe coloane ! a=reshape((/1.,2.,3.,4.,5.,6./),(/2,3/)) do i=1,2 write(*,*)a(i,:) enddo ! ! Matricea unitate (3,3) ! b=reshape((/1.,0.,0.,0.,1.,0.,0.,0.,1./),(/3,3/)) write(*,*) do i=1,3 write(*,*)b(i,:) enddo

Page 38: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

38

end program reshape_function

Advanced. ARRAY SECTIONS Se definesc (extrag) tablouri din vectori şi matrice. real(4) dimension(100) :: vector integer,dimension(6) :: ivector=(/1,4,8,43,54,88/) Array section SemnificaŃie vector(:) tot vectorul vector(1:100) tot vectorul vector(1:10) tablou unidimensional conŃinând primele 10 elemente din vector vector(51:100) tablou unidimensional conŃinând elementele 51:100 din vector vector(51:) identic cu vector(51:100) vector(10:1:-1) tablou unidimensional conŃinând primele 10 elemente din

vector în ordine inversă vector(/10,88,3,5/) tablou unidimensional conŃinând elementele 10,88,3,5 din

vector, în această ordine vector(ivector) tablou unidimensional conŃinând elementele 1,4,8,43,54,88

din vector în această ordine real,dimension(100,100) :: matrice Array section SemnificaŃie matrice(:,:) toată matricea matrice(1:100,1:100) toată matricea matrice(7,:) tablou unidimensional conŃinând linia 7 din matrice matrice(7,1:100) tablou unidimensional conŃinând linia 7 din matrice matrice(:,7) tablou unidimensional conŃinând coloana 7 din matrice matrice(1:10,81:90) tablou bidimensional conŃinând sub_blocul din matrice

indicat prin rangul indicilor; tablou(10,10) program initializare_matrici integer,parameter :: lin=4 ! numarul de lini i integer,parameter :: col=3 ! numarul de colo ane real,dimension(lin,col) :: a ! se declara o ma trice (lin,col) a(1,:)=(/1.,2.,3./) ! prima linie din matrice a(2,:)=(/4.,5.,6./) ! a doua linie din matrice a(3,:)=(/(i,i=-1,1)/) ! a treia linie din matrice a(4,:)=(/(0.,i=1,3)/) ! a patra linie din matrice do i=1,lin write(*,'(3g13.5)')a(i,:) ! se scrie linia i enddo

Page 39: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

39

end program initializare_matrici

program array_constructor implicit none integer,parameter :: n=3 real, dimension(n) :: m1(n,n) real,dimension(n) :: x,v real s integer i,j real rand write(*,*)'Matricea m1' do i=1,n do j=1,n m1(i,j)=rand(0) ! generare aleatoare enddo write(*,*)(m1(i,j),j=1,n) ! scriere explicita x(i)=rand(0) enddo write(*,*) write(*,*)'Prima linie din matricea m1' write(*,*)m1(1,:) write(*,*)'A doua linie din matricea m1' write(*,*)m1(2,:) write(*,*)'A treia linie din matricea m1' write(*,*)m1(3,:) ! ! Inmultirea explicita a unei matrici cu un vector ! do i=1,n s=0. do j=1,n s=s+m1(i,j)*x(j) enddo v(i)=s enddo write(*,*) write(*,*)v ! ! Inmultirea cu array_constructor ! do i=1,n v(i)=sum(m1(i,:)*x) ! m1(i,:) corespunde unui vec tor enddo ! m1(i,:)*x inmultirea compon ent cu component ! a doi vectori, rezultatul este un vector ! sum calculeaza suma vectoru lui write(*,*)v end program array_constructor

Advanced program array ! Tablouri in F90 implicit none integer,parameter :: n=3 real, dimension(n,n) :: a,b,c real rand integer i,j,k do i=1,n do j=1,n a(i,j)=rand(0) ! se genereaza aleator elementel e matricei A b(i,j)=rand(0) ! se genereaza aleator elementel e matricei B enddo

Page 40: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

40

enddo write(*,*)'Matricea A' ; call scrie_matrice(a,n) write(*,*)'Matricea B' ; call scrie_matrice(b,n) ! ! Inmultirea explicita a doua matrici in FORTRAN 90 ! do i=1,n do j=1,n c(i,j)=sum(a(i,:)*b(:,j)) enddo enddo write(*,*)'Matricea C' ; call scrie_matrice(c,n) end program array subroutine scrie_matrice(a,n) ! tipareste un tablou implicit none integer :: n,i real,dimension(n,n) :: a do i=1,n write(*,' (6(g12.5,1x))')a(i,:) ! scrie o linie enddo write(*,*) ! scrie o linie alba end subroutine scrie_matrice

Automatic array program automatic integer,parameter :: ndim=5 integer,parameter :: n=2 real a(ndim,n) do i=1,n ; do j=1,n ; a(i,j)=rand(0) ; enddo ; endd o call sub1(ndim,n,a) end program automatic subroutine sub1(ndim,m,b) real b(ndim,m) real c(m) ! automatic array real d(m,m) ! automatic array do i=1,m ; c(i)=rand(0) ; do j=1,m ; d(i,j)=rand(0) ; enddo ; enddo do i=1,m write(*,*)b(i,:),c(i) enddo write(*,*) do i=1,m write(*,*)d(i,:) enddo end subroutine sub1

5.3 Gauss Seidel Metoda Gauss Seidel este o metodă iterativă pentru calculul soluŃiei unui sistem de ecuaŃii algebrice liniare. Metoda converge dacă matricea sistemului este simetrică şi pozitiv definită. Metoda converge dacă matricea sistemului este diagonal dominantă pe linii. Considerăm sistemul de n ecuaŃii algebrice liniare:

Page 41: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

41

∑=

=n

jijij bxa

1

i=1,2,…,n

IteraŃiile metodei Gauss Seidel se efectuează conform ecuaŃiei:

ii

i

j

n

ij

kjij

kjiji

ki a

xaxab

x∑ ∑

= +=

+

+

−−=

1

1 1

1

1 i=1,2,…,n

Cu k s-a notat contorul de iteraŃii k=0,1,… Se pleacă de la o aproximaŃie iniŃială dată. IteraŃiile se opresc când norma reziduului este mai mică decât o toleranŃă impusă:

ε<−=

r

Axbr k

program gauss_seidel ! ! Determina solutia unui sistem diagonal dominant ! cu metoda iterativa Gauss Seidel ! implicit none integer,parameter :: n=3 integer,parameter :: it_max=111 ! numarul maxim de iteratii real(8),parameter :: eps=1.d-5 ! toleranta impusa real(8) norma_reziduu real(8) a(n,n),b(n),x(n),r(n),s integer i,j,iter data a/10.d0,2.d0,2.d0, & ! prima coloana din ma tricea a 1.d0,10.d0,2.d0, & ! a doua coloana d in matricea a 1.d0,1.d0,10.d0/ ! a treia coloana d in matricea a b=(/12.d0,13.d0,14.d0/) ! vectorul b write(*,*)'matricea A' do i=1,n write(*,'(5g11.4)')(a(i,j),j=1,n) enddo write(*,*)'vectorul b' do i=1,n write(*,'(5g11.4)')b(i) enddo x=0.01d0 ! aproximatia initiala (vectorial) write(*,*)'Iteratii Seidel' r=matmul(a,x)-b ! calculul reziduului (matricial) norma_reziduu=maxval(abs(r)) iter=0 do while((iter<it_max).and.(norma_reziduu>eps)) do i=1,n s=0.d0

Page 42: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

42

do j=1,i-1 ! suma de la j=1 pana la i-1 s=s+a(i,j)*x(j) enddo do j=i+1,n ! suma de la j=i+1 pana l a n s=s+a(i,j)*x(j) enddo if(a(i,i).ne.0.d0)then x(i)=(b(i)-s)/a(i,i) else stop 'pivot zero' endif enddo iter=iter+1 r=matmul(a,x)-b ! calculul reziduului (matricia l) norma_reziduu=maxval(abs(r)) write(*,'(a,i5,f13.5)')'iter=',iter, norma_rezi duu enddo if(iter<it_max)then write(*,*)'solutia' write(*,'(g12.5,f13.5)')(x(i),r(i),i=1,n) else write(*,*)'neconvergenta Seidel' endif end program gauss_seidel program gauss_seidel_array_sections ! ! Determina solutia unui sistem diagonal dominant ! cu metoda iterativa Gauss Seidel ! implicit none integer,parameter :: n=3 integer,parameter :: it_max=111 ! numarul maxim de iteratii real(8),parameter :: eps=1.d-5 ! toleranta impusa real(8) norma_reziduu real(8) a(n,n),b(n),x(n),r(n),s,s1,s2 integer i,j,iter data a/10.d0,2.d0,2.d0, & ! prima coloana din ma tricea a 1.d0,10.d0,2.d0, & ! a doua coloana din matricea a 1.d0,1.d0,10.d0/ ! a treia coloana din matricea a b=(/12.d0,13.d0,14.d0/) ! vectorul b write(*,*)'matricea A' do i=1,n write(*,'(5g11.4)')(a(i,j),j=1,n) enddo write(*,*)'vectorul b' do i=1,n write(*,'(5g11.4)')b(i) enddo x=0.01d0 ! aproximatia initiala (vectorial) write(*,*)'Iteratii Seidel' r=matmul(a,x)-b ! calculul reziduului (matricial) norma_reziduu=maxval(abs(r)) iter=0

Page 43: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

43

do while((iter<it_max).and.(norma_reziduu>eps)) do i=1,n s1=sum(a(i,1:i-1)*x(1:i-1)) ! suma de la 1 la i-1 s2=sum(a(i,i+1:n)*x(i+1:n)) ! suma de la i+ 1 la n s=s1+s2 if(a(i,i).ne.0.d0)then x(i)=(b(i)-s)/a(i,i) else stop 'pivot zero' endif enddo iter=iter+1 r=matmul(a,x)-b ! calculul reziduului (matricia l) norma_reziduu=maxval(abs(r)) write(*,'(a,i5,f13.5)')'iter=',iter, norma_rezi duu enddo if(iter<it_max)then write(*,*)'solutia' write(*,'(g12.5,f13.5)')(x(i),r(i),i=1,n) else write(*,*)'neconvergenta Seidel' endif end program gauss_seidel_array_sections

5.4 Alocarea dinamică de memorie (în execuŃie) In multe cazuri acelaşi algoritm matricial se utilizează pentru ordine de mărime diferite ale matricelor. Dacă nu se cunoaşte aprioric dimensiunea matricelor şi a vectorilor aceştia sunt declaraŃi de tip alocatabil iar rezervarea de memorie se face în momentul execuŃiei. program alocate implicit none integer ialoc0,ialoc1,ialoc2,ialoc3,ialoc4,ialoc5 integer n,i,j real(8) s,drand ! ! Alocarea dinamica de memorie in timpul executiei ! ! ! Se declara alocatabila matricea a ! real(8),allocatable :: a(:,:) ! ! Se declara alocatabili vectorii b si c ! real(8),allocatable :: b(:),c(:) ! ! Se citeste ordinul matricei ! write(*,*)'Introduceti n' read(*,*)n if(n<2)n=2 ! ! Se aloca spatiu pentru matricea a ! Daca alocarea reuseste variabila ialoc0 ia valoa rea 0. ! In caz contrar se opreste executia programului.

Page 44: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

44

! allocate (a(n,n),stat=ialoc0) ; if(ialoc0.ne.0 )stop 'ialoc0' ! ! Se aloca spatiu pentru vectorul b. ! Daca alocarea reuseste variabila ialoc1 ia valoa rea 0. ! In caz contrar se opreste executia programului. ! allocate (b(n ),stat=ialoc1) ; if(ialoc1.ne.0)st op 'ialoc1' ! ! Se aloca spatiu pentru vectorul c. ! Daca alocarea reuseste variabila ialoc2 ia valoa rea 0. ! In caz contrar se opreste executia programului. ! allocate (c(n ),stat=ialoc2) ; if(ialoc2.ne.0)st op 'ialoc2' ! ! Se genereaza aleator elementele matricei a si al e vectorului b ! do i=1,n do j=1,n a(i,j)=drand(0) enddo b(i)=drand(0) enddo ! ! Se inmulteste matricea a cu vectorul b si se obt ine vectorul c. ! write(*,*)'Vectorul c' do i=1,n s=0.d0 do j=1,n s=s+a(i,j)*b(i) enddo c(i)=s write(*,*)i,c(i) enddo ! ! Se elibereaza spatiul ocupat de matricea a. ! Daca dealocarea reuseste ialoc3 ia valoarea zero. ! deallocate (a,stat=ialoc3);if(ialoc3.ne.0)stop 'ialoc3' ! ! Se elibereaza spatiul ocupat de vectorul b. ! Daca dealocarea reuseste ialoc4 ia valoarea zero. ! deallocate (b,stat=ialoc4);if(ialoc4.ne.0)stop 'ialoc4' ! ! Se elibereaza spatiul ocupat de vectorul c. ! Daca dealocarea reuseste ialoc4 ia valoarea zero. ! deallocate (c,stat=ialoc5);if(ialoc5.ne.0)stop 'ialoc5' end program alocate

6. FuncŃii şi subprograme 6.1 Clauza contains. FuncŃii interne

Page 45: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

45

Anterior s-au definit funcŃiile formulă care permit descrierea unei funcŃii definite printr-o singură ecuaŃie. In cazul în care expresia funcŃiei este mai complexă se utilizează funcŃii interne declarate în programul principal după cuvântul cheie contains: program nume_program declaraŃii . . .variabilă=nume_funcŃie(argumente efective) contains tip function nume_funcŃie(argumente_formale) declaratii . . nume_funcŃie=expresie end function nume_functie end program nume_program program contains_exemple ! ! Calculeaza f(x,y)=exp(x)*sin(pi*y) pentru x>=0 ! exp(x)*cos(pi*y) pentru x<0 ! implicit none real(4) x,y,c,pi x=1.1 ; y=2.1 ; pi=4.*atan(1.) c=fct(x,y) ! apelul functiei write(*,*)x,y,c c=fct(-2.1,-1.1) ! apelul functiei write(*,*)-2.1,-1.1,c contains real(4) function fct(x,y) implicit none real(4),intent(in) :: x,y ! parametrii de intrare , intent(in) ! ! Valoarea variabilei pi este preluata din programu l apelant, ! asociere HOST ! if(x<0.)then fct=exp(x)*cos(pi*y) ! expresia functiei ! numele functiei apare oblig atoriu ! intr-o instructiune de atribuire else fct=exp(x)*sin(pi*x) endif end function fct end program contains_exemple

Page 46: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

46

6.2 FuncŃii externe FuncŃiile externe au aceeaşi structură ca şi funcŃiile interne dar constituie unităŃi separate de program. Numele funcŃiei apare obligatoriu într-o instrucŃiune de atribuire. Toate variabilele trebuie să fie definite în interiorul funcŃiei. tip function nume_funcŃie(argumente_formale) declaratii . . nume_funcŃie=expresie end function nume_functie Intre tipul şi numărul de argumente din programul apelant şi funcŃie există o corespondenŃă biunivocă. FuncŃia factorial

1!0

...3.2.1!

== nn

permite calculul combinărilor:

)!(!

!

mnm

nCm

n −=

PROGRAM EXEMPLU_FACTORIAL IMPLICIT NONE INTEGER N,M,FACTORIAL,COMBINARI,F N=4 ; M=2 F=FACTORIAL(N) COMBINARI=FACTORIAL(N)/FACTORIAL(M)/FACTORIAL(N-M) WRITE(*,*)'N=',N,' M=',M,' F=',F,' C=',COMBINARI END PROGRAM EXEMPLU_FACTORIAL INTEGER FUNCTION FACTORIAL(N) IMPLICIT NONE INTEGER, INTENT(IN) :: N ! ARGUMENTU L INTEGER :: F,I IF(N==0)THEN FACTORIAL=1 ELSEIF(N>1)THEN F = 1 ! SE CALCUL EAZA IN BUCLA n! DO I = 1, N F = F * I END DO FACTORIAL = F ELSE STOP 'ARGUMENT INCORECT' ENDIF END FUNCTION FACTORIAL

6.2.1.FuncŃii în complex

Page 47: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

47

O mare atenŃie trebuie acordată calculului cu funcŃii complexe deoarece pot avea mai multe valori (sun multiforme). De exemplu calculul radicalului in Fortran: „ As a result of type complex is the principal value, with the real part greather than or equal to zero. When the real part of the result is zero, the imaginary part is greather than or equal to zero.” Se dau două numere reale x şi y. Se determină numărul complex:

iyxz += şi se calculează funcŃia complexă:

zzzf

1)( +=

Partea reală şi partea imaginară sunt ))(Re( zf şi ))(Im( zf . program functii_complexe implicit none real x,y complex z,fz,fct x=2. ; y=2.2 ; z=cmplx(x,y) fz=fct(z) write(*,*)'z=',z,' fz=',fz write(*,*)'x=',x,' y=',y,' Real(fz)=',real(fz) write(*,*)'x=',x,' y=',y,' Imag(fz)=',imag(fz) end program functii_complexe complex function fct(z) complex,intent(in) ::z fct=z+1./z end function fct

Profil Jukovski general Considerăm un cerc cu centrul în cadranul doi în punctul M. Raza cercului este a. DistanŃa de la centrul cercului la originea axelor O, segmentul OM este m. Unghiul ascuŃit făcut de OM cu axa orizontală este δ. DistanŃa de la originea axelor la cerc pe axa orizontală este q.

-1

-0.5

0

0.5

1

-1 -0.5 0 0.5 1

y

x

Profi l Jucovski general

Figura 6.2.1 Profil Jukovski generat prin transformare conformă

Page 48: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

48

Considerăm transformarea de coordonate:

θδηθδξ

sinsin

coscos

am

am

++=+−=

şi numărul complex: ηξζ i+=

Transformarea conformă Jucovski:

ζζ

2qz +=

reprezintă conform exteriorul unui cerc de rază a cu centrul în M pe exteriorul unui profil în planul z. Coordonatele carteziene ale profilului sunt:

)Im(

)Re(

zy

zx

==

program jukovski_g ! profil Jukovski general implicit real(8) (a-h,o-z) real(8) m complex(8) zeta,z pi=4.d0*atan(1.d0) open(1,file='c:\for\jg.txt') q=0.4d0 ! constanta din transformata Jukovski delta=15.d0/180.d0*pi m=0.1d0 a=sqrt(q**2+m**2+2*q*m*cos(delta)) ! (18.66) Cara foli do teta=0.d0,2*pi,pi/24.d0 csi=-m*cos(delta)+a*cos(teta) eta= m*sin(delta)+a*sin(teta) zeta=cmplx(csi,eta) z=zeta+q**2/zeta ! transformata Jukowski x=real(z) ! coordonate carteziene y=imag(z) write(*,'(6(f10.6,1x))')x,y,xx(teta),yy(teta),cs i,eta write(1,'(6(f10.6,1x))')x,y,xx(teta),yy(teta),cs i,eta enddo contains real(8) function xx(teta) real(8) teta xx=(-m*cos(delta)+a*cos(teta))* & (1+q**2/(m**2+a**2-2*m*a*cos(teta+delta))) end function xx real(8) function yy(teta) real(8) teta yy=( m*sin(delta)+a*sin(teta))* & (1-q**2/(m**2+a**2-2*m*a*cos(teta+delta))) end function yy end program jukovski_g

6.3 FuncŃii recursive

Page 49: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

49

FuncŃiile recursive sunt funcŃiile care se autoapelează. Un exemplu clasic este funcŃia factorial:

1!1

1!0

)!1(!

==

−= nnn

FuncŃiile recursive sunt implementate în limbajul FORTRAN. In cazul funcŃiilor clasice în corpul funcŃiei apărea obligatoriu expresia: nume_funcŃie=expresie_aritmetică. In cazul funcŃiilor recursive, valoarea funcŃiei este memorată într-o variabilă auxiliară declarată cu cuvântul cheie result. recursive function nume_funcŃie(argumente_formale) result(valoarea_funcŃiei) declaratii . . valoarea_funcŃiei=expresie end function nume_functie end program nume_program program recursivef ! ! Calculeaza functia factorialorial recursiv ! implicit none integer n,f,factorial n=4 f=factorial(n) ! apelul functiei recurs ive factorial write(*,*)'n=',n,' factorialorial=',f end recursive function factorial(n) result(s_fact) ! valoarea functie i este ! memorata in vari abila s_fact ! de tip intreg specificat in result implicit none integer,intent(in) :: n integer :: s_fact if(n<0)stop 'argument incorect' if(n<=1)then s_fact=1 else s_fact=n*factorial(n-1) ! recursivitate endif end function factorial

Advanced

Page 50: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

50

Copyright 1993, 1996 by Bo Einersson and Yurij Stokin Fortran 90 for Fortran 77 Programmer, Version 2.3 Calculul unei integrale definite cu metoda trapezelor se bazează pe formula:

( ))()(5.0)(1 bfafdxxfIb

a

+== ∫

Pentru mărirea preciziei se introduce un punct intermediar la mijlocul intervalului:

( ) ( )∫ ∫−

+−+−+=+=)(5.0

)(5.0

2 )())(5.0(5.0))(5.0()(5.0)()(ab

a

b

ab

bfabfabfafdxxfdxxfI

Se observă că pentru a calcula I2 se apelează tot la formula trapezelor (recursivitate). Eroarea absolută este dată de diferenŃa celor două integrale şi se compară cu o toleranŃă impusă:

tolII <− 12

Dacă condiŃia este realizată se calculează valoarea finală a integralei prin extrapolare Richardson, echivalentă cu formula lui Simpson:

312

2

IIII

−+=

Dacă condiŃia nu este îndeplinită, atunci se împarte intervalul în două ş.a.m.d. PROGRAM RECURSIVE ! TEST_ADAPTIVE_QUAD ! ! Copyright Bo Einersson and Yurij Stokin ! ! Fortran 90 for Fortran 77 Programmer, Version 2.3 ! ! Calculeaza o integrala definita cu metoda trapeze lor cu ! controlul erorii de integrare printr-o procedura adaptativa ! utilizand functii recursive ! IMPLICIT NONE INTERFACE FUNCTION F(X) RESULT (FUNCTION_VALUE) REAL(8), INTENT(IN) :: X REAL(8) :: FUNCTION_VALUE END FUNCTION F END INTERFACE INTERFACE RECURSIVE FUNCTION ADAPTIVE_QUAD & (F, A, B, TOL, ABS_ERROR) RESULT (REZULTAT) REAL(8), EXTERNAL :: F REAL(8), INTENT (IN) :: A, B, TOL REAL(8), INTENT (OUT) :: ABS_ERROR REAL(8) :: REZULTAT END FUNCTION ADAPTIVE_QUAD END INTERFACE REAL(8) :: A, B, TOL REAL(8) :: ABS_ERROR ! EROAREA ABS OLUTA REAL(8) :: REZULTAT ! VALOAREA CA LCULATA A INTEGRALEI REAL(8) :: PI

Page 51: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

51

REAL(8) :: VAL_E ! VALOAREA EXACT A INTEGER :: I REAL(8) :: PRIMITIVA,X PRIMITIVA(X)=-COS(X) ! PRIMITIVA FUNC TIEI CARE SE ! INTEGREAZA NUM ERIC PI = 4.0d0 * ATAN(1.0d0) A= 0.D0 ; B=PI ! LIMITELE DE INTEGRARE TOL =0.1d0 ! TOLERANTA I NITIALA DO I = 1, 5 TOL = TOL/10.0d0 REZULTAT = ADAPTIVE_QUAD (F, A, B, TO L, ABS_ERROR) WRITE(*,*) WRITE(*,"(A, F15.10, A, F15.10)")"Int _a ", & REZULTAT, " err_estm ",ABS_ERROR VAL_E=PRIMITIVA(B)-PRIMITIVA(A) ! LEI BNITZ-NEWTON WRITE(*,"(A, F15.10, A, F15.10)")"Inr_e ", & VAL_E, " err_real ",REZULTAT - VAL_ E ENDDO END PROGRAM RECURSIVE ! TEST_ADAPTIVE_QUAD FUNCTION F(X) RESULT (FUNCTION_VALUE) IMPLICIT NONE REAL(8), INTENT(IN) :: X REAL(8) :: FUNCTION_VALUE FUNCTION_VALUE = SIN(X) END FUNCTION F RECURSIVE FUNCTION ADAPTIVE_QUAD (F, A, B, TOL, ABS _ERROR) & RESULT (REZULTAT) IMPLICIT NONE INTERFACE FUNCTION F(X) RESULT (FUNCTION_VALUE) REAL(8), INTENT(IN) :: X REAL(8) :: FUNCTION_VALUE END FUNCTION F END INTERFACE REAL(8), INTENT(IN) :: A, B, TOL REAL(8), INTENT(OUT) :: ABS_ERROR REAL(8) :: REZULTAT REAL(8) :: STEP, MIDDLE_P OINT REAL(8) :: ONE_T_AREA, TW O_T_AREAS REAL(8) :: LEFT_AREA, RIG HT_AREA REAL(8) :: DIFF, ABS_ERRO R_L, ABS_ERROR_R STEP = B-A MIDDLE_POINT= 0.5d0 * (A+B) ONE_T_AREA = STEP * 0.50d0 * (F(A) + F(B)) TWO_T_AREAS = STEP * 0.25d0 * (F(A) + F(MIDD LE_POINT))+& STEP * 0.25d0 * (F(MIDDLE_POIN T) + F(B)) DIFF = TWO_T_AREAS - ONE_T_AREA IF ( ABS (DIFF) < TOL ) THEN REZULTAT = TWO_T_AREAS + DIFF/3.0d0 ! EXTRAPOLARE RICHARDSON ABS_ERROR = ABS(DIFF) ELSE LEFT_AREA = ADAPTIVE_QUAD (F, A, MID DLE_POINT, & 0.5d0*TOL, ABS_ERROR_L)

Page 52: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

52

RIGHT_AREA = ADAPTIVE_QUAD (F, MIDDLE _POINT, B, & 0.5d0*TOL, ABS_ERROR_R) REZULTAT = LEFT_AREA + RIGHT_AREA ABS_ERROR = ABS_ERROR_L + ABS_ERROR_R END IF END FUNCTION ADAPTIVE_QUAD

6.4 InstrucŃiunea External InstrucŃiunea external se utilizează pentru a transmite ca subprogramele ca parametrii la subprograme. Să considerăm următorul exemplu. Avem o funcŃie care calculează integrala unei funcŃii continue cu metoda Gauss cu trei puncte. Dorim să calculăm în acelaşi program doua integrale:

=

=

b

a

b

a

dxxI

dxxI

)sin(

)exp(

2

1

utilizând aceeaşi funcŃie (metoda Gauss) pentru calculul numeric al integralelor. Metoda Gauss pe trei puncte este:

( )

3,2,1,22

6.0

0

6.0

)()()(2

)(

3

2

1

332211

=−++=

+=

=−=

++−=∫

itabab

x

t

t

t

xfAxfAxfAab

dxxf

ii

b

a

Eroarea metodei este dată de formula restului:

)(2135

1 )4(5

2 ξfab

R

−=

unde ξ este un punct din intervalul (a,b). program external1 implicit none real a,b real f1c,f2c ! valorile calculate ale integ ralelor real f1e,f2e ! valorile analitice ale integ ralelor real er1,er2 ! eroarea absoluta real gauss3 real primitiva1,primitiva2,x external functia1,functia2 primitiva1(x)= exp(x)

Page 53: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

53

primitiva2(x)=-cos(x) a=0. ; b=0.5 f1c=gauss3(functia1,a,b) ; f1e=primitiva1(b)-prim itiva1(a) er1=abs(f1c-f1e) write(*,*)'f1c=',f1c,' f1e=',f1e,' er1=',er1 f2c=gauss3(functia2,a,b) ; f2e=primitiva2(b)-prim itiva2(a) er2=abs(f2c-f2e) write(*,*)'f2c=',f2c,' f2e=',f2e,' er2=',er2 end program external1 real function gauss3(fct,a,b) implicit none real,intent(in) :: a,b ! limitele de integrare real fct ! functia care se integreaza real t1,t2,t3 ! abscise Gauss real a1,a2,a3 ! ponderi Gauss real x1,x2,x3 t1=-sqrt(0.6) ; t2=0. ; t3=+sqrt(0.6) a1=5./9. ; a2=8./9. ; a3=5./9. x1=0.5*(b+a)+0.5*(b-a)*t1 x2=0.5*(b+a)+0.5*(b-a)*t2 x3=0.5*(b+a)+0.5*(b-a)*t3 gauss3=0.5*(b-a)*(a1*fct(x1)+a2*fct(x2)+a3*fct(x3)) end function gauss3 real function functia1(x) implicit none real,intent(in) :: x functia1=exp(x) end real function functia2(x) implicit none real,intent(in) :: x functia2=sin(x) end

6.5 Subrutine Subprogramele de tip SUBROUTINE permit calculul mai multor valori în corpul subprogramului şi transmiterea lor în programul apelant. [recursive ] subroutine nume_subrutină(lista_argumente_formale) declaraŃii . . . end subroutine nume_subrutina Se poate specifica (opŃional) tipul argumentelor transmise subrutinei: a) intent(in) argumente transmise din programul apelant subrutinei b) intent(out) argumente transmise din subrutină programului apelant c) intent(inout) argumente transmise din programul apelant si modificate in subrutină.

Page 54: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

54

In cazul în care argumentul este o funcŃie sau o subrutină aceasta se declară în instrucŃiunea external în programul apelant. Subrutina este apelată cu instrucŃiunea call: call nume_subrutină(lista_argumente_efective) Există o corespondenŃă biunivocă ca tip şi număr între lista de argumente formale şi lista de argumente efective. program subr1 ! ! Tabeleaza doua functii pentru a <= x <= b ! implicit none real a,b ! limitele intervalului in care se tabeleaza functia integer n ! numarul de puncte din tabel real fct1,fct2 ! functiile care se tabeleaza external fct1,fct2 ! functiile sunt transmise ca ar gument a=0. ; b=1. ; n=11 call tabelare(fct1,a,b,n) ! tabelarea functiei fct1 write(*,*) call tabelare(fct2,a,b,n) ! tabelarea functiei fct2 end program subr1 subroutine tabelare(functie,stanga,dreapta,m) implicit none real :: functie real,intent(in) :: stanga real,intent(in) :: dreapta integer,intent(in) :: m real dx,x integer i dx=(dreapta-stanga)/(m-1) do i=1,m x=stanga+(i-1)*dx write(*,*)x,functie(x) enddo end subroutine tabelare real function fct1(x) real,intent(in) :: x real pi pi=4.*atan(1.) fct1=exp(x)*sin(pi*x) end function fct1 real function fct2(x) real,intent(in) :: x real pi pi=4.*atan(1.) fct2=exp(x)*cos(pi*x) end function fct2

6.5.1 Transmiterea tablourilor la subprograme Considerăm cazul uzual al matricelor pătrate: real matrice(ndim,ndim)

Page 55: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

55

Valoarea ndim (leading dimension) este transmisă obligatoriu subprogramului. Să presupunem că ndim=5. Dimensiunea efectivă (cu care se lucrează) este n mai mic sau egal cu ndim. Subprogramul poate fi apelat cu n=5 sau cu n=3. In cazul în care n=5 în subrutină se lucrează cu o matrice cu 5 linii şi cinci coloane. In cazul in care n=3 în subrutină se lucrează cu o matrice cu trei linii şi trei coloane. call subrutina(ndim,5,matrice) call subrutina(ndim,3,matrice) program subr2 ! ! transmiterea tablourilor in subprograme ! integer,parameter :: ndim=5 real,dimension(ndim,ndim) :: matrice integer n,i,j n=3 do i=1,n do j=1,n matrice(i,j)=rand(0) ! functia rand genereaza n umere pseudo aleatoare enddo enddo call scrie_matrice(ndim,n,matrice) ! scrie matricea de dimensiune n write(*,*) n=5 do i=1,n do j=1,n matrice(i,j)=rand(0) enddo enddo call scrie_matrice(ndim,n,matrice) end program subr2 subroutine scrie_matrice(ndim,n,a) implicit none integer,intent(in) :: ndim integer,intent(in) :: n real,dimension(ndim,*),intent(in) :: a integer i,j do i=1,n write(*,'(5(g13.6,1x))')(a(i,j),j=1,n) enddo end subroutine scrie_matrice

6.5.2 Rezolvarea sistemelor de ecuaŃii algebrice lineare Prin discretizarea ecuaŃiilor fizicii matematice se obŃin sisteme algebrice liniare de mari dimensiuni. O cale pentru a rezolva aceste sisteme de ecuaŃii liniare este algoritmul Gauss cu pivotare parŃială. Algoritmul Gauss are extrem de multe variante şi implementări, vezi NETLIB.ORG . Vom prezenta implementarea standard datorată lui C. B. Moler, ALGORITHM 423, LINEAR EQUATION SOLVER, C.A.C.M. 15 (1972), P. 274. .

Page 56: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

56

AUTHORS: E. HAIRER AND G. WANNER UNIVERSITE DE GENEVE, DEPT. DE MATHEM ATIQUES CH-1211 GENEVE 24, SWITZERLAND E-MAIL: [email protected] [email protected] THIS CODE IS DESCRIBED IN: E. HAIRER, S.P. NORSETT AND G. WANNER, SOL VING ORDINARY DIFFERENTIAL EQUATIONS I. NONSTIFF PROBLEM S. 2ND EDITION. SPRINGER SERIES IN COMPUTATIONAL MATHEMATI CS, SPRINGER-VERLAG (1996)

Considerăm sistemul algebric linear: bAx =

Matricea A este descompusă într-un produs de două matrice triunghiulare L (lower) şi U (upper). Rezolvarea sistemului de ecuaŃii este redusă la rezolvarea a două sisteme de ecuaŃii cu matrice triunghiulară prin retrosubstituŃie.

yUx

bLy

bLUx

LUA

==

==

Pentru a calcula inversa unei matrice de dimensiune 3 se rezolvă prin retrosubstituŃie trei sisteme algebrice liniare. Elementele matricei inverse sunt notate cu xij:

==−

100

010

0011 IAA

==

100

010

001

333231

232221

131211

I

xxx

xxx

xxx

A

==

100

010

001

333231

232221

131211

I

xxx

xxx

xxx

LU

=

0

0

1

31

21

11

x

x

x

LU

=

0

1

0

32

22

12

x

x

x

LU

=

1

0

0

33

23

13

x

x

x

LU

program inversa_moler

! ! Calculeaza inversa unei matrici patrate de dimen siune n. ! Se efectueaza descompunerea LU a matricei sistem ului. ! Se rezolva apoi prin retrosubstitutie n sisteme algebrice ! avand drept membru drept cate o coloana din matr icea unitate. ! ! matricea A(n,n) real(8) n*n ! matricea X=A**(-1)(n,n) real(8) n*n ! vectorul B(n) real(8) n ! Total real(8) 2*n*n+n

Page 57: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

57

! vectorul ip(n) integer(4) ! implicit real(8) (a-h,o-z) integer,parameter :: n=5 real(8) a(n,n),x(n,n),b(n) real(8) c(n,n) ! matricea unitate real(8) as(n,n) ! matricea A salvata pentru verifi care integer ip(n) ! vector permutari linii do i=1,n do j=1,n a(i,j)=drand(0) enddo enddo write(*,*)'Matricea [A]' write(*,'(5f12.5)')((a(i,j),j=1,n),i=1,n) as=a ! salveaza matricea A pentru verificare call DEC (N, N, A, IP, IER) ! MOLER (matricea A e ste inlocuita ! cu descompun erea LU) if(ier.ne.0)stop 'matrice singulara' ! ! Calcul inversa X(*,*) cite o coloana o data' ! do j=1,n ! coloana j din matricea inversa b=0.d0 ! vectorial b(j)=1.d0 write(*,*)'Coloana=',j write(*,'(i2,2x,f7.2)')(k,b(k),k=1,n) call SOL (N, N, A, B, IP) ! retrosubstitutie ! membrul drept B este coloana j din ! matricea unitate la intrare ! dupa executie B contine coloana j ! din matricea inversa do i=1,n x(i,j)=b(i) enddo enddo write(*,*)'Matricea [A]**(-1)' write(*,'(5f12.5)')((x(i,j),j=1,n),i=1,n) c=matmul(x,as) write(*,*)'Matricea [A]**(-1)*[A]' write(*,'(5f7.3)')((c(i,j),j=1,n),i=1,n) end SUBROUTINE DEC (N, NDIM, A, IP, IER) ! ! AUTHORS: E. HAIRER AND G. WANNER ! UNIVERSITE DE GENEVE, DEPT. DE MATHE MATIQUES ! CH-1211 GENEVE 24, SWITZERLAND ! E-MAIL: [email protected] ! [email protected] h ! ! THIS CODE IS DESCRIBED IN:

Page 58: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

58

! E. HAIRER, S.P. NORSETT AND G. WANNER, SO LVING ORDINARY ! DIFFERENTIAL EQUATIONS I. NONSTIFF PROBLE MS. 2ND EDITION. ! SPRINGER SERIES IN COMPUTATIONAL MATHEMAT ICS, ! SPRINGER-VERLAG (1993) ! ! VERSION REAL DOUBLE PRECISION INTEGER N,NDIM,IP,IER,NM1,K,KP1,M,I,J DOUBLE PRECISION A,T DIMENSION A(NDIM,N), IP(N) !-------------------------------------------------- --------------------- ! MATRIX TRIANGULARIZATION BY GAUSSIAN ELIMINATION . ! INPUT.. ! N = ORDER OF MATRIX. ! NDIM = DECLARED DIMENSION OF ARRAY A . ! A = MATRIX TO BE TRIANGULARIZED. ! OUTPUT.. ! A(I,J), I.LE.J = UPPER TRIANGULAR FACTOR, U . ! A(I,J), I.GT.J = MULTIPLIERS = LOWER TRIANGUL AR FACTOR, I - L. ! IP(K), K.LT.N = INDEX OF K-TH PIVOT ROW. ! IP(N) = (-1)**(NUMBER OF INTERCHANGES) OR O . ! IER = 0 IF MATRIX A IS NONSINGULAR, OR K IF F OUND TO BE ! SINGULAR AT STAGE K. ! USE SL TO OBTAIN SLUTION OF LINEAR SYSTEM. ! DETERM(A) = IP(N)*A(1,1)*A(2,2)*...*A(N,N). ! IF IP(N)=O, A IS SINGULAR, SL WILL DIVIDE BY ZER O. ! ! REFERENCE.. ! C. B. MOLER, ALGORITHM 423, LINEAR EQUATION S OLVER, ! C.A.C.M. 15 (1972), P. 274. !-------------------------------------------------- --------------------- IER = 0 IP(N) = 1 IF (N .EQ. 1) GO TO 70 NM1 = N - 1 DO 60 K = 1,NM1 KP1 = K + 1 M = K DO 10 I = KP1,N IF (DABS(A(I,K)) .GT. DABS(A(M,K))) M = I 10 CONTINUE IP(K) = M T = A(M,K) IF (M .EQ. K) GO TO 20 IP(N) = -IP(N) A(M,K) = A(K,K) A(K,K) = T 20 CONTINUE IF (T .EQ. 0.D0) GO TO 80 T = 1.D0/T DO 30 I = KP1,N 30 A(I,K) = -A(I,K)*T DO 50 J = KP1,N T = A(M,J) A(M,J) = A(K,J) A(K,J) = T IF (T .EQ. 0.D0) GO TO 45 DO 40 I = KP1,N 40 A(I,J) = A(I,J) + A(I,K)*T 45 CONTINUE 50 CONTINUE 60 CONTINUE 70 K = N

Page 59: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

59

IF (A(N,N) .EQ. 0.D0) GO TO 80 RETURN 80 IER = K IP(N) = 0 RETURN END SUBROUTINE DEC SUBROUTINE SOL (N, NDIM, A, B, IP) ! VERSION REAL DOUBLE PRECISION INTEGER N,NDIM,IP,NM1,K,KP1,M,I,KB,KM1 DOUBLE PRECISION A,B,T DIMENSION A(NDIM,N), B(N), IP(N) !-------------------------------------------------- --------------------- ! SOLUTION OF LINEAR SYSTEM, A*X = B . ! INPUT.. ! N = ORDER OF MATRIX. ! NDIM = DCLARED DIMENSION OF ARRAY A . ! A = TRIANGULARIZED MATRIX OBTAINED FROM DC. ! B = RIGHT HAND SIDE VECTOR. ! IP = PIVOT VECTOR OBTAINED FROM DC. ! DO NOT USE IF DC HAS SET IER .NE. 0. ! OUTPUT.. ! B = SOLUTION VECTOR, X . !-------------------------------------------------- --------------------- IF (N .EQ. 1) GO TO 50 NM1 = N - 1 DO 20 K = 1,NM1 KP1 = K + 1 M = IP(K) T = B(M) B(M) = B(K) B(K) = T DO 10 I = KP1,N 10 B(I) = B(I) + A(I,K)*T 20 CONTINUE DO 40 KB = 1,NM1 KM1 = N - KB K = KM1 + 1 B(K) = B(K)/A(K,K) T = -B(K) DO 30 I = 1,KM1 30 B(I) = B(I) + A(I,K)*T 40 CONTINUE 50 B(1) = B(1)/A(1,1) RETURN END SUBROUTINE SOL

6.5.3 Calculul valorilor proprii Numeroase probleme de inginerie (vibraŃiile structurilor aerospaŃiale) conduc la probleme de valori proprii de tipul:

xAx λ= Cu λ s-au notat valorile proprii iar cu x vectorii proprii. Matricea A poate fi reală sau complexă. Rezultatele unor importante cercetări desfăşurate în anii 1970-1980 au condus la realizarea unui pachet de programe numit EISPACK (NETLIB.ORG). În această colecŃie de subrutine sunt programaŃi algoritmii numerici pentru probleme de valori proprii.

Page 60: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

60

Vom considera o problemă un pic mai complicată, problema generalizată de valori proprii:

BxAx λ= Fie ecuaŃia diferenŃială, problema Sturm-Liouville:

bxa

ydx

yd

<=<=

= λ2

2

cu două condiŃii la limite, pentru x=a şi pentru x=b. Considerăm un sistem de funcŃii liniar independente, fi(x) care satisfac condiŃiile la limite. Căutăm soluŃia în forma (metoda Galerkin):

)()()( 2211 xfaxfaxy += Substituind această soluŃie în ecuaŃia diferenŃială obŃinem:

))()(()()( 2211''

22''

11 xfaxfaxfaxfa +=+ λ ÎnmulŃim ultima ecuaŃie succesiv cu f1(x) şi f2(x) şi integrăm de la a la b. Se obŃine problema generalizată de valori proprii:

=

∫∫

∫∫

∫∫

∫∫

2

1

2221

1211

2

1

2''

22''

1

1''

21''

1

)()()()(

)()()()(

)()()()(

)()()()(

a

a

dxxfxfdxxfxf

dxxfxfdxxfxf

a

a

dxxfxfdxxfxf

dxxfxfdxxfxf

b

a

b

a

b

a

b

ab

a

b

a

b

a

b

a λ

Se calculează analitic sau numeric integralele din ultima expresie şi se obŃin matricele A şi B, respectiv problema de valori proprii generalizată:

=

2

1

2

1

a

aB

a

aA λ

Generalizarea la n mai mare decât doi este imediată. Matricele A şi B au elemente reale şi în acest caz sunt simetrice. B.S. Garbow, J.M. Boyle, J.J. Dongarra, C.B. Moler, Matrix Eigensytem Routine EISPACK Guide Extension, Lecture Notes in Computer Science, Springer-Verlag, New York, 1977, p. 44 PROGRAM VALORI_PROPRII ! ! burton s. garbow,mathematics and computer sci ence div, ! argonne national laboratory !__________________________________________________ ___________ ! ! Se rezolva problema de valori proprii generalizat a ! ! A*x=lambda*B*x ! ! A si B sunt matrici reale ! IMPLICIT NONE INTEGER,PARAMETER :: N=5

Page 61: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

61

REAL(8),DIMENSION(N,N) :: A,B,Z,ZR,ZI REAL(8),DIMENSION(N) :: ALFR(N),ALFI(N),BETA(N) INTEGER I,J,K,IERR,MATZ REAL(8) DRAND DO I=1,N ! genereaza aleator matricea A DO J=1,N A(I,J)=DRAND(0) ENDDO ENDDO DO I=1,N ! genereaza aleator matricea B DO J=1,N B(I,J)=DRAND(0) ENDDO ENDDO MATZ=1 ! se calculeaza valorile proprii s i vectorii proprii CALL RGG(N,N,A,B,ALFR,ALFI,BETA,MATZ,Z,IERR) WRITE(*,*)'IERR=',IERR ! codul de eroare ! ! Valorile proprii ! DO I=1,N IF(BETA(I).NE.0.D0)THEN WRITE(*,1)'VP=',I,ALFR(I)/BETA(I),ALFI(I)/BETA(I) ELSE WRITE(*,1)' ',I,ALFR(I),ALFI(I),BETA(I) ENDIF ENDDO 1 FORMAT(A,I2,2X,3G13.6) ! ! VECTORII PROPRII ! ! B.S. Garbow, J.M. Boyle, J.J. Dongarra, C.B. Mole r, ! Matrix Eigensytem Routine EISPACK Guide Extension , ! Lecture Notes in Computer Science, ! Springer-Verlag, New York, 1977, p. 44 ! DO K=1,N IF(ALFI(K).EQ.0.D0)THEN DO J=1,N ZR(J,K)=Z(J,K) ZI(J,K)=0.D0 ENDDO ELSEIF(ALFI(K)>0.D0)THEN DO J=1,N ZR(J,K)=Z(J,K) ZI(J,K)=Z(J,K+1) ENDDO ELSEIF(ALFI(K)<0.D0)THEN DO J=1,N ZR(J,K)= ZR(J,K-1) ZI(J,K)=-ZI(J,K-1) ENDDO ENDIF ENDDO DO I=1,N WRITE(*,*)'VECTORUL PROPRIU ',I WRITE(*,'(G13.6,2X,G13.6)')(ZR(J,I),ZI(J,I),J=1, N) ENDDO END PROGRAM VALORI_PROPRII subroutine rgg(nm,n,a,b,alfr,alfi,beta,matz,z ,ierr) ! integer n,nm,ierr,matz

Page 62: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

62

double precision a(nm,n),b(nm,n),alfr(n),alfi (n),beta(n),z(nm,n) logical tf ! ! this subroutine calls the recommended sequenc e of ! subroutines from the eigensystem subroutine p ackage (eispack) ! to find the eigenvalues and eigenvectors (if desired) ! for the real general generalized eigenproblem ax = (lambda)bx. ! ! on input ! ! nm must be set to the row dimension of th e two-dimensional ! array parameters as declared in the callin g program ! dimension statement. ! ! n is the order of the matrices a and b . ! ! a contains a real general matrix. ! ! b contains a real general matrix. ! ! matz is an integer variable set equal to zero if ! only eigenvalues are desired. otherwise i t is set to ! any non-zero integer for both eigenvalues and eigenvectors. ! ! on output ! ! alfr and alfi contain the real and imag inary parts, ! respectively, of the numerators of the eig envalues. ! ! beta contains the denominators of the eig envalues, ! which are thus given by the ratios (alfr+ i*alfi)/beta. ! complex conjugate pairs of eigenvalues app ear consecutively ! with the eigenvalue having the positive im aginary part first. ! ! z contains the real and imaginary parts o f the eigenvectors ! if matz is not zero. if the j-th eigenval ue is real, the ! j-th column of z contains its eigenvecto r. if the j-th ! eigenvalue is complex with positive imagin ary part, the ! j-th and (j+1)-th columns of z contain t he real and ! imaginary parts of its eigenvector. the c onjugate of this ! vector is the eigenvector for the conjugat e eigenvalue. ! ! ierr is an integer output variable set eq ual to an error ! completion code described in the docume ntation for qzit. ! the normal completion code is zero. ! ! questions and comments should be directed to burton s. garbow, ! mathematics and computer science div, argonne national laboratory ! ! this version dated august 1983. ! ! --------------------------------------------- --------------------- ! if (n .le. nm) go to 10 ierr = 10 * n go to 50 ! 10 if (matz .ne. 0) go to 20 ! .......... find eigenvalues only .......... tf = .false. call qzhes(nm,n,a,b,tf,z) call qzit(nm,n,a,b,0.0d0,tf,z,ierr)

Page 63: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

63

call qzval(nm,n,a,b,alfr,alfi,beta,tf,z) go to 50 ! .......... find both eigenvalues and eigenvec tors .......... 20 tf = .true. call qzhes(nm,n,a,b,tf,z) call qzit(nm,n,a,b,0.0d0,tf,z,ierr) call qzval(nm,n,a,b,alfr,alfi,beta,tf,z) if (ierr .ne. 0) go to 50 call qzvec(nm,n,a,b,alfr,alfi,beta,z) 50 return end subroutine rgg INCLUDE 'C:\FOR\S_VALORI_PROPRII.F90'

7. InstrucŃiunea COMMON InstrucŃiunea COMMON este utilizată pentru a transmite valorile variabilelor în subprograme independent de lista de parametrii. Parametrii din instrucŃiunea COMMON trebuie să fie diferiŃi de parametrii din lista de variabile. InstrucŃiunea COMMON este deosebit de puternică dar trebuie utilizată cu mare atenŃie. 7.1 InstrucŃiunea COMMON blank Sintaxa instrucŃiunii este: common listă_parametrii InstrucŃiunea COMMON se plasează în programul principal şi în subprogramele în care se transmit valorile parametrilor. program common1 implicit none real a,b,c real x common a,b,c x=1.1 a=3. ; b=4. ; c=5. ! se initializeaza valorile vari abilelor a,b,c write(*,*)'a =',a,' b =',b,' c =',c, ' Programul pr incipal' call sub1(x) call sub2 end program common1 subroutine sub1(x) implicit none real,intent(in) :: x real a,b,c common a,b,c write(*,*)'x =',x write(*,*)'a =',a,' b =',b,' c =',c, ' Subrutina su b1' end subroutine sub1 subroutine sub2 implicit none real a1,b1,c1 common a1,b1,c1 ! corespondenta intre variabilele d in programul principal ! si subrutina

Page 64: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

64

! a1 <==> a ! b1 <==> b ! c1 <==> c ! write(*,*)'a1=',a1,' b1=',b1,' c1=',c1,' Subrutina sub2' end subroutine sub2

7.2 InstrucŃiunea COMMON etichetat Sintaxa instrucŃiunii este: common /eticheta/listă_variabile integer k(3),jj real x(3),z(3),a complex z1(5),z2(5),zz common /variabile_întregi/k,jj common /variabile_reale/x,z,a common /variabile_complexe/z1,z2,zz Se recomandă gruparea variabilelor de acelaşi tip într-o instrucŃiune common etichetată pentru a conserva alinierea în memorie. program common2 implicit none integer,parameter :: n=3 real,dimension(n,n) :: mata,matb,matc real,dimension(n) :: v1,v2,v3 real rand integer i,j common /tablouri/mata,matb,matc,v1,v2,v3 do i=1,n do j=1,n mata(i,j)=rand(0) ; matb(i,j)=rand(0) enddo v1(i)=rand(0) v2(i)=rand(0) enddo call sub1 ! calculeaza matc, v2,v3 write(*,*)'Matricea C' do i=1,n write(*,'(3(g13.6,1x))')(matc(i,j),j=1,n) enddo write(*,*)'Vectorii v2 si v3' write(*,'(2(g13.6,1x))')(v2(i),v3(i),i=1,n) end program common2 subroutine sub1 implicit none integer,parameter :: n=3 real,dimension(n,n) :: mata,matb,matc real,dimension(n) :: v1,v2,v3 common /tablouri/mata,matb,matc,v1,v2,v3 matc=mata+matb ! se calculeaza suma matricilor si se transmite

Page 65: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

65

! rezultatul prin common in pro gramul principal v2=matmul(mata,v1) ! se calculeaza produsul dintre matrice si ! vector si se transmite rezult atul in programul ! principal prin common v3=matmul(matb,v1) ! se calculeaza produsul dintre matrice si ! vector si se transmite rezult atul in programul ! principal prin common end subroutine sub1

7.3 InstrucŃiunea BLOCK DATA InstrucŃiunea block data se utilizează pentru a iniŃializa valorile variabilelor din common etichetat (labeled common) cu instrucŃiunea data. Sintaxa instrucŃiunii este block data nume declaratii common etichetat data end block data nume program block_data implicit none real constanta_gazelor real temperatura_standard real presiunea_standard common /termo/constanta_gazelor,temperatura_standar d,presiunea_standard ! ! Valorile constantelor sunt precizate in procedu ra block data ! si transmise prin common. ! write(*,*)'constanta gazelor =',constanta_gazelor ,' J/mol/K' write(*,*)'temperatura standard=',temperatura_stand ard,' K' write(*,*)'presiunea standard =',presiunea_standar d,' N/m**2' end program block_data block data constante_termodinamice implicit none real constanta_gazelor real temperatura_standard real presiunea_standard common /termo/constanta_gazelor,temperatura_standar d,presiunea_standard ! ! Initializarea variabilelor din common cu intructi unea data ! data constanta_gazelor /8.31451/ ! J/mol/K data temperatura_standard/298.15/ ! K data presiunea_standard /1.e5/ ! N/m**2 end block data constante_termodinamice

10. AplicaŃii Se prezintă în continuare o serie de aplicaŃii în FORTRAN utilizând algoritmi consacraŃi din bibliotecile de programe disponibile pe INTERNET (NETLIB.ORG).

Page 66: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

66

10.1 Calculul integralelor definite. QUADPACK. Quadpack este un pachet de programe f77 care calculează integrale definite.

R. Piessens, E. deDoncker-Kapenga, C. Uberhuber, D. Kahaner Quadpack: a Subroutine Package for Automatic Integration Springer Verlag, 1983. Series in Computational Mathematics v.1 515.43/Q1S 100394Z

program quadpack ! !***keywords automatic integrator, general-purpose , ! integrand examinator, globally adapti ve, ! gauss-kronrod !***author piessens,robert ,appl. math. & progr. d iv - k.u.leuven ! de doncker,elise,appl. math. & progr. d iv. - k.u.leuven ! implicit real(8) (a-h,o-z) common /parametrii/pi,alfa ! parametrii definiti i n programul ! principal external f ! functia care se integreaza ! ! M.L. Smoleanski, Tabele de integrale nedefinite, Ed. Tehnica, ! Bucuresti 1972, traducere din limba rusa, formula 45.1, p. 129 ! primitiva(x)=exp(alfa*x)* $ (alfa*sin(p*x)-p*cos(p*x))/(alfa**2+p**2) pi=4.d0*atan(1.d0) write(*,*)'program quadpack' alfa=1.d0 p=pi a=0.d0 ! limita inferioara a integralei d efinite b=0.5d0 ! limita superioara a integralei d efinite eps=1.d-8 ! toleranta impusa key=2 ! 10-21 puncte gauss in formula de quadratura call dr_dqag(f,a,b,eps,eps,key,rezult,abserr,ier) write(*,*)'ier=',ier ! cod de eroare write(*,*)'In=',rezult ! valoarea integralei ca lculata numeric write(*,*)'Ia=',(primitiva(b)-primitiva(a)) ! anal itic end program quadpack real(8) function f(x) implicit real(8) (a-h,o-z) g(x)=exp(alfa*x)*sin(p*x) common /parametrii/pi,alfa p=pi f=g(x) end subroutine dr_dqag(f,a,b,epsabs,epsrel,key,re sult,abserr,ier) implicit real(8) (a-h,o-z) parameter (limit=128)

Page 67: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

67

parameter (lenw=4*limit) integer iwork(limit) real(8) work(lenw) external f call dqag(f,a,b,epsabs,epsrel,key,result,abserr,ne val,ier, $ limit,lenw,last,iwork,work) end ! subroutine dqag(f,a,b,epsabs,epsrel,key,resu lt,abserr,neval,ier, ! * limit,lenw,last,iwork,work) !***begin prologue dqag !***date written 800101 (yymmdd) !***revision date 830518 (yymmdd) !***category no. h2a1a1 !***keywords automatic integrator, general-purpose , ! integrand examinator, globally adapti ve, ! gauss-kronrod !***author piessens,robert,appl. math. & progr. di v - k.u.leuven ! de doncker,elise,appl. math. & progr. d iv. - k.u.leuven !***purpose the routine calculates an approximatio n result to a given ! definite integral i = integral of f ov er (a,b), ! hopefully satisfying following claim f or accuracy ! abs(i-result)le.max(epsabs,epsrel*abs( i)). !***description ! ! computation of a definite integral ! standard fortran subroutine ! double precision version ! ! f - double precision ! function subprogam defining t he integrand ! function f(x). the actual nam e for f needs to be ! declared e x t e r n a l in t he driver program. ! ! a - double precision ! lower limit of integration ! ! b - double precision ! upper limit of integration ! ! epsabs - double precision ! absolute accoracy requested ! epsrel - double precision ! relative accuracy requested ! if epsabs.le.0 ! and epsrel.lt.max(50*rel.mach .acc.,0.5d-28), ! the routine will end with ier = 6. ! ! key - integer ! key for choice of local integ ration rule ! a gauss-kronrod pair is used with ! 7 - 15 points if key.lt.2, ! 10 - 21 points if key = 2, ! 15 - 31 points if key = 3, ! 20 - 41 points if key = 4, ! 25 - 51 points if key = 5, ! 30 - 61 points if key.gt.5. ! ! on return ! result - double precision ! approximation to the integral ! ! abserr - double precision

Page 68: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

68

! estimate of the modulus of th e absolute error, ! which should equal or exceed abs(i-result) ! ! neval - integer ! number of integrand evaluatio ns ! ! ier - integer ! ier = 0 normal and reliable t ermination of the ! routine. it is assume d that the requested ! accuracy has been ach ieved. ! ier.gt.0 abnormal termination of the routine ! the estimates for res ult and error are ! less reliable. it is assumed that the ! requested accuracy ha s not been achieved. ! error messages ! ier = 1 maximum number of sub divisions allowed ! has been achieved. on e can allow more ! subdivisions by incre asing the value of ! limit (and taking the according dimension ! adjustments into acco unt). however, if ! this yield no improve ment it is advised ! to analyze the integr and in order to ! determine the integra tion difficulaties. ! if the position of a local difficulty can ! be determined (i.e.si ngularity, ! discontinuity within the interval) one ! will probably gain fr om splitting up the ! interval at this poin t and calling the ! integrator on the sub ranges. if possible, ! an appropriate specia l-purpose integrator ! should be used which is designed for ! handling the type of difficulty involved. ! = 2 the occurrence of rou ndoff error is ! detected, which preve nts the requested ! tolerance from being achieved. ! = 3 extremely bad integra nd behaviour occurs ! at some points of the integration ! interval. ! = 6 the input is invalid, because ! (epsabs.le.0 and ! epsrel.lt.max(50*rel .mach.acc.,0.5d-28)) ! or limit.lt.1 or lenw .lt.limit*4. ! result, abserr, neval , last are set ! to zero. ! except when lenw is i nvalid, iwork(1), ! work(limit*2+1) and w ork(limit*3+1) are ! set to zero, work(1) is set to a and ! work(limit+1) to b. ! ! dimensioning parameters ! limit - integer ! dimensioning parameter for iwo rk ! limit determines the maximum n umber of subintervals ! in the partition of the given integration interval ! (a,b), limit.ge.1. ! if limit.lt.1, the routine wil l end with ier = 6. ! ! lenw - integer ! dimensioning parameter for wor k ! lenw must be at least limit*4. ! if lenw.lt.limit*4, the routin e will end with ! ier = 6. !

Page 69: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

69

! last - integer ! on return, last equals the num ber of subintervals ! produced in the subdiviosion p rocess, which ! determines the number of signi ficant elements ! actually in the work arrays. ! ! work arrays ! iwork - integer ! vector of dimension at least l imit, the first k ! elements of which contain poin ters to the error ! estimates over the subinterval s, such that ! work(limit*3+iwork(1)),... , w ork(limit*3+iwork(k)) ! form a decreasing sequence wit h k = last if ! last.le.(limit/2+2), and k = l imit+1-last otherwise ! ! work - double precision ! vector of dimension at least l enw ! on return ! work(1), ..., work(last) conta in the left end ! points of the subintervals in the partition of ! (a,b), ! work(limit+1), ..., work(limit +last) contain the ! right end points, ! work(limit*2+1), ..., work(lim it*2+last) contain ! the integral approximations o ver the subintervals, ! work(limit*3+1), ..., work(lim it*3+last) contain ! the error estimates. ! !***references (none) !***routines called dqage,xerror !***end prologue dqag include 'c:\for\s_quadpack.for'

10.2 EcuaŃii diferenŃiale ordinare. Problema Cauchy Se consideră sistemul de n ecuaŃii diferenŃiale ordinare nonstiff:

),...,()( 1'

ni yyxfxy = i=1,2,…,n

cu condiŃia iniŃială:

00

0

)( yxy

xx

i ==

Dacă soluŃiile sistemului de ecuaŃii diferenŃiale au scale diferite de timp, respectiv unele soluŃii au o variaŃie mult mai rapidă decât altele, atunci sistemul de ecuaŃii diferenŃiale este stiff. Sistemele de ecuaŃii diferenŃiale nonstiff se integrează cu metode Runge Kutta explicite. Sistemele de ecuaŃii diferenŃiale stiff se integrează cu metode Runge Kutta implicite. E. Hairer, S. P. Norsett, S. Wanner, Solving Ordinary Differential Equations I, Nonstiff Problems, Springer, New York. 1977, p. 127-128. Vom ilustra metodele Runge Kutta explicite cu o problema celor trei corpuri cu restricŃii. Se consideră două corpuri de masă 1-µ şi µ în mişcare circulară de rotaŃie în plan şi un al treilea corp de masă neglijabilă care se mişcă în acelaşi plan. EcuaŃiile sunt:

Page 70: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

70

µµµ

µµ

µµ

µµµµ

−==

+−=

++=

−−−=

−−

+−+=

1

012277471.0

))((

))((

2

2

'

5.122

2'12

5.122

211

2

2

1

2''12

''2

2

'1

1

1''21

''1

yyD

yyD

D

y

D

yyyy

D

y

D

yyyy

Sistemul de două ecuaŃii diferenŃiale de ordinul doi se transformă într-un sistem de patru ecuaŃii diferenŃiale de ordinul întâi care se integrează cu metoda DOPRI5:

2

2

1

2'32

''2

2

'1

1

1'41

''1

4'2

3'1

2

2

D

y

D

yyyy

D

y

D

yyyy

yy

yy

µµ

µµµµ

−−−=

−−

+−+=

=

=

CondiŃia iniŃială la x=0 este: y1=0.994 y2=0.0D0 y3=0.0D0 y4=-2.00158510637908252240537862224 Sistemul de integrează până la: xend=17.0652165601579625588917206249 Sistemul neliniar de patru ecuaŃii diferenŃiale ordinare are soluŃii periodice. Sistemul de patru ecuaŃii diferenŃiale este descris în subrutina FAREN. SoluŃia sistemului de ecuaŃii diferenŃiale este scrisă în subrutina SOLOUT. Reprezentarea grafică a soluŃiei este prezentată în Figura 10.2.1.

-1.5

-1

-0.5

0

0.5

1

1.5

-1.5 -1 -0.5 0 0.5 1

y2

y1

Orbita Arensdorf

'dopri5.txt' u 2:3

Figura 10.2.1. Reprezentarea soluŃiei sistemului de ecuaŃii diferenŃiale în planul fazelor C ------------------------------------------------- --------- C NUMERICAL SOLUTION OF A SYSTEM OF FIRST 0RDER

Page 71: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

71

C ORDINARY DIFFERENTIAL EQUATIONS Y'=F(X,Y). C THIS IS AN EXPLICIT RUNGE-KUTTA METHOD OF ORD ER (4)5 C DUE TO DORMAND & PRINCE (WITH STEPSIZE CONTRO L AND C DENSE OUTPUT). C C AUTHORS: E. HAIRER AND G. WANNER C UNIVERSITE DE GENEVE, DEPT. DE MATHE MATIQUES C CH-1211 GENEVE 24, SWITZERLAND C E-MAIL: [email protected] C [email protected] h C C THIS CODE IS DESCRIBED IN: C E. HAIRER, S.P. NORSETT AND G. WANNER, SO LVING ORDINARY C DIFFERENTIAL EQUATIONS I. NONSTIFF PROBLE MS. 2ND EDITION. C SPRINGER SERIES IN COMPUTATIONAL MATHEMAT ICS, C SPRINGER-VERLAG (1993) C C VERSION OF APRIL 25, 1996 C * * * * * * * * * * * * * * * * * * * * * * * * * C --- DRIVER FOR DOPRI5 ON ARENSTORF ORBIT C * * * * * * * * * * * * * * * * * * * * * * * * * IMPLICIT REAL*8 (A-H,O-Z) PARAMETER (NDGL=4,NRDENS=4) PARAMETER (LWORK=8*NDGL+5*NRDENS+21,LIWORK= NRDENS+21) DIMENSION Y(NDGL),WORK(LWORK),IWORK(LIWORK) ,RPAR(2) EXTERNAL FAREN,SOLOUT C --- DIMENSION OF THE SYSTEM OPEN(1,FILE='C:\FOR\DOPRI5.TXT') N=NDGL C --- OUTPUT ROUTINE (AND DENSE OUTPUT) IS USED DUR ING INTEGRATION IOUT=2 C --- INITIAL VALUES AND ENDPOINT OF INTEGRATION RPAR(1)=0.012277471D0 RPAR(2)=1.D0-RPAR(1) X=0.0D0 Y(1)=0.994D0 Y(2)=0.0D0 Y(3)=0.0D0 Y(4)=-2.00158510637908252240537862224D0 XEND=17.0652165601579625588917206249D0 C --- REQUIRED (RELATIVE AND ABSOLUTE) TOLERANCE ITOL=0 RTOL=1.0D-7 ATOL=RTOL C --- DEFAULT VALUES FOR PARAMETERS DO 10 I=1,20 IWORK(I)=0 10 WORK(I)=0.D0 C --- DENSE OUTPUT IS USED FOR THE TWO POSITION COO RDINATES 1 AND 2 IWORK(5)=NRDENS C --- CALL OF THE SUBROUTINE DOPRI5 CALL DOPRI5(N,FAREN,X,Y,XEND, & RTOL,ATOL,ITOL, & SOLOUT,IOUT, & WORK,LWORK,IWORK,LIWORK,RPAR,IP AR,IDID) C --- PRINT FINAL SOLUTION WRITE (6,99) Y(1),Y(2) 99 FORMAT(1X,'X = XEND Y =',2E18.10) C --- PRINT STATISTICS WRITE (6,91) RTOL,(IWORK(J),J=17,20) 91 FORMAT(' tol=',D8.2,' fcn=',I5,' step =',I4, & ' accpt=',I4,' rejct=',I3)

Page 72: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

72

STOP END C C SUBROUTINE SOLOUT (NR,XOLD,X,Y,N,CON,ICOMP, ND,RPAR,IPAR,IRTRN) C --- PRINTS SOLUTION AT EQUIDISTANT OUTPUT-POINTS BY USING "CONTD5" IMPLICIT REAL*8 (A-H,O-Z) DIMENSION Y(N),CON(5*ND),ICOMP(ND),RPAR(2) COMMON /INTERN/XOUT,DXOUT DXOUT=0.1D0 IF (NR.EQ.1) THEN WRITE (6,99) X,Y(1),Y(2),NR-1 WRITE (1,98) X,Y(1),Y(2),Y(3),Y(4) XOUT=X+DXOUT ELSE 10 CONTINUE IF (X.GE.XOUT) THEN WRITE (6,99) XOUT,CONTD5(1,XOUT,CON,I COMP,ND), & CONTD5(2,XOUT,CON,ICOMP, ND),NR-1 WRITE (1,98) XOUT,CONTD5(1,XOUT,CON,I COMP,ND), & CONTD5(2,XOUT,CON,I COMP,ND), # CONTD5(3,XOUT,CON,I COMP,ND), # CONTD5(4,XOUT,CON,I COMP,ND) XOUT=XOUT+DXOUT GOTO 10 END IF END IF 99 FORMAT(1X,'X =',F6.2,' Y =',2E18.10,' NSTEP =',I4) 98 FORMAT(5(G13.6,1X)) RETURN END C SUBROUTINE FAREN(N,X,Y,F,RPAR,IPAR) C --- ARENSTORF ORBIT IMPLICIT REAL*8 (A-H,O-Z) DIMENSION Y(N),F(N),RPAR(2) AMU=RPAR(1) AMUP=RPAR(2) F(1)=Y(3) F(2)=Y(4) R1=(Y(1)+AMU)**2+Y(2)**2 R1=R1*SQRT(R1) R2=(Y(1)-AMUP)**2+Y(2)**2 R2=R2*SQRT(R2) F(3)=Y(1)+2*Y(4)-AMUP*(Y(1)+AMU)/R1-AMU*(Y( 1)-AMUP)/R2 F(4)=Y(2)-2*Y(3)-AMUP*Y(2)/R1-AMU*Y(2)/R2 RETURN END include 'c:\for\dopri5.for'

10.3 EcuaŃia Burgers omogenă Se consideră ecuaŃia:

0)( =

∂∂+

∂∂

x

uf

t

u

cu condiŃia iniŃială, problema Cauchy: la t=0 )sin()()( 0 xxuxu π== , [ ]2,0∈x .

Pentru ecuaŃia lui Burgers:

Page 73: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

73

2),(

))(,()()(2

)(2

vuvua

vuvuavfuf

uuf

+=

−=−

=

Se consideră funcŃia flux numeric (Yee): [ ])(),()()(5.0),( uvvuavfufvuh −−+=

H.C. Yee, A Class of High-Resolution Explicit and Implicit Shock Capturing Method, NASA Technical Memorandum 101088, February 1989 Se consideră grila echidistantă cu pasul x∆ pe axa x cu nodurile i=0,1,…,n+1. La momentul de timp t se determină viteza maximă în interval:

)max(maxtiuu = i=1,2,…,n

şi se calculează pasul de timp (CFL):

max

9.0u

xt

∆=∆

Trecerea la nivelul următor de timp se face cu ecuaŃia:

[ ]),(),( 11ti

ti

ti

ti

ti

tti uuhuuh

x

tuu −+

∆+ −∆∆+= , i=1,2,…,n

In nodurile i=0 şi i=n+1 se face o extrapolare a soluŃiei (condiŃie la limită numerică). SoluŃia ecuaŃiei la momentul de timp t=1 este prezentată în Figura 10.3.1.

-1

-0.5

0

0.5

1

0 0.5 1 1.5 2

u(x

,1)

x

Ecuatia Burgers omogena

'uo3' u 1:2'ut3' u 1:2

Figura 10.3.1 SoluŃia ecuaŃiei Burgers omogene la t=1. uo3 condiŃia iniŃială ut3 solutia la t=1 program roe ! ! H.C. Yee, A Class of High-Resolution Explicit an d Implicit ! Shock Capturing Method, NASA Technical Memorandum 101088, ! February 1989 ! ! ! Ecuatia Burgers omogena !

Page 74: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

74

! 0<x<2 ! uo(x)=sin(pi*x) ! 0<t<1 implicit none integer,parameter :: m=101 real(8) x(m),u(0:m+1),v(0:m+1) integer i real uzero,umax,dx real h,t,t0,tf,dt,xs,xd open(1,file='c:\for\uo3') open(2,file='c:\for\ut3') t0=0.d0 ; tf=1.d0 ! intervalul de timp xs=0.d0 ; xd=2.d0 ! domeniul de integrare dx=(xd-xs)/(m-1) ! pasul de discretizare pe axa x do i=1,m x(i)=xs+(i-1)*dx ! grila discreta u(i)=uzero(x(i)) ! viteza initiala write(1,'(1x,2f11.4)')x(i),u(i) enddo t=t0 ! ! Iteratii in timp si spatiu ! do while(t<=tf) u(0) =u(1) ! extrapolare conditii la limi ta u(m+1)=u(m) umax=0.d0 ! se determina viteza maxima pe t ot intervalul do i=1,m umax=max(abs(u(i)),umax) enddo ! ! Pasul de timp ! dt=0.9d0*dx/umax ! Courant Friederics Levy CFL ! ! viteza la t1=t+dt ==> v ! do i=1,m v(i)=u(i)-dt/dx*(h(u(i),u(i+1))-h(u(i-1), u(i))) enddo t=t+dt do i=1,m ! actualizarea vitezelor u(i)=v(i) enddo enddo ! ! Solutia la t=tf ! do i=1,m write(2,'(1x,4f11.4)')x(i),u(i) enddo end program roe real(8) function h(u,v) ! functia flux nume ric implicit none real(8),intent(in) :: u,v real(8) f,q,a

Page 75: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

75

f(q)=0.5d0*q*q h=0.5d0*(f(u)+f(v)-abs(a(u,v))*(v-u)) end function h real(8) function a(u,v) ! viteza de propaga re la interfata implicit none real(8),intent(in) :: u,v a=0.5d0*(u+v) end real(8) function uzero(x) ! conditia initiala implicit none real(8),intent(in) :: x real(8) pi pi=4.d0*atan(1.d0) uzero=sin(pi*x) end function uzero

10.4 EcuaŃia Poisson Se consideră ecuaŃia cu derivate parŃiale:

22

2

2

2

−=∂∂+

∂∂

y

u

x

u

în domeniul dreptunghiular:

bxb

axa

+<<−+<<−

cu condiŃia la limite u=0 pe frontieră. Fie nx numărul de puncte ale grilei de discretizare pe axa x, ny numărul de puncte pe axa y. Se definesc paşi de discretizare:

1

2

1

2

−=∆

−=∆

y

x

n

by

n

ax

şi grila de discretizare: xiaxi ∆−+−= )1( i=1,2,…,nx

yjbyi ∆−+−= )1( j=1,2,…,ny

şi valorile funcŃiei în nodurile reŃelei: ),(, jiji yxuu = i=1,2,…,nx j=1,2,…,ny.

Derivatele parŃiale sunt discretizate cu formule de derivare numerică cu diferenŃe centrale:

222

2

1,,1,

2

.1,,1 −=∆

+−+

∆+− +−+−

y

uuu

x

uuu jijijijijiji

Se defineşte sistemul de ecuaŃii algebrice lineare:

02)2(2 22

2

1,,1,,1,.1, =∆+∆∆+−++−= +−+− x

y

xuuuuuuf jijijijijijiji

i=2,…,nx-1, j=2,…,ny-1

Page 76: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

76

Sistemul de ecuaŃii se completează cu ecuaŃii pe frontieră (condiŃiile la limite). Sistemul algebric linear de nx*ny ecuaŃii se rezolvă cu metoda Newton, o iteraŃie. Jacobianul se calculează numeric cu formule de derivare cu diferenŃe centrale.

0

0.05

0.1

0.15

0.2

0.25

-1 -0.5 0 0.5 1

u

y

Torsiunea unei bare dreptunghilare

Figura 10.4. SoluŃia numerică şi soluŃia analitică pentru x=-0.05 module tablouri !------------------------------------------- ----------+ ! Se rezolva ecuatia Poisson, | ! torsiunea unei bare prismatice: nabla(u)=-2 | !------------------------------------------------- ----+ implicit none integer,parameter :: nx=21 ! numarul de puncte de discretizare pe axa x integer,parameter :: ny=41 ! numarul de puncte de discretizare pe axa y integer,parameter :: n=nx*ny ! numarul de necunosc ute real(8) :: a=+0.5d0 ! -a < x < +a real(8) :: b=+1.0d0 ! -b < y < +b real(8) :: hx ! pasul de discretizare pe ax a x real(8) :: hy ! pasul de discretizare pe ax a y real(8),dimension(nx) :: x ! abscise real(8),dimension(ny) :: y ! ordonate real(8),dimension(n) :: z ! vectorul necunoscutel or real(8),dimension(n) :: f ! vectorul functiilor real(8),dimension(n,n):: df ! Jacobianul sistemulu i de ecuatii real(8),dimension(n) :: dx,bb ! work space integer,dimension(n) :: ip ! vectorul permutarilo r de linii (Gauss) real(8),dimension(n) :: fp,fm,xs ! work space real(8) :: pi=3.14159265358979d0 end module tablouri program ps3 use tablouri ! ! Ecuatia lui Poisson in dreptunghi ! Torsiunea unei bare prismatice. ! ! nabla(u)=-2 ! ! -a<x<a ; -b<y<b ; u=0 pe contur ! ! Kantorovici si Krilov, Metode aproximative ale analizei superioare ! Editura Academiei Romane, Bucuresti 1954, tradu cere din limba rusa,

Page 77: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

77

! vol 2., p. 392 ! ! u(x,y) serii duble, functia ue(x,y) ! implicit none integer i,j integer ier ! cod de eroare Gauss /=0 Jacobian sin gular real(8) pas ! pas de derivare numerica real(8) ue ! calculeaza solutia analitica real(8) uex ! solutia analitica real(8) zc ! solutia numerica open(1,file='c:\for\ps3.txt') write(1,*)'program ps3' write(1,*)'nabla(u)=-2' write(1,*)'Solutia analitica (serii duble) Kantoro vici si Krilov,' write(1,*)'"Metode aproximative ale analizei super ioare",' write(1,*)'Ed. Academiei, Bucuresti 1954, traducer e din limba rusa,' write(1,*)' p. 394' hx=2.d0*a/(nx-1) ! pasul de discretizare pe axa x hy=2.d0*b/(ny-1) ! pasul de discretizare pe axa y do i=1,nx ; x(i)=-a+(i-1)*hx ; enddo ! abscise do j=1,ny ; y(j)=-b+(j-1)*hy ; enddo ! ordonate z=0.d0 ! Aproximatia initiala call sist(z,f) ! ! Jacobian F numeric ! xs=z pas=1.D0/512.D0 ! pas derivare numerica diferen te centrale do j=1,n xs(j)=z(j)-pas ! x(j)-h call sist(xs,fm) ! f( ...,x(j)-h,... ) xs (j)=z(j)+pas ! x(j)+h call sist(xs,fp) ! f( ...,x(j)+h,...) df(:,j)=(fp-fm)/(pas+pas) ! coloana j din Jac obian xs(j)=z(j) ! restaurare x(j) enddo ! ! [J]{dx}=-{f} Newton pentru {f}={0} ! call dec(n,n,df,ip,ier) ! Gauss LU if(ier.ne.0)stop 'matrice singulara' bb=-f call sol(n,n,df,bb,ip) ! Retrosubstitutie z=z+bb ! un pas Newton write(1,*)'Solutia problemei Poisson' write(1,*)' x y numeric analitic eroare' i=nx/2 do j=1,ny uex=ue(x(i),y(j)) ; zc=z(i+(j-1)*nx) write(1,'(2f11.4,2x,3f12.5)')x(i),y(j),zc,uex, zc-uex enddo write(1,*) end program ps3

Page 78: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

78

real(8) function ue(xx,yy) use tablouri implicit none real(8),intent(in) :: xx,yy real(8) ss,c1 integer mm,nn ! ! Solutia analitica (serii duble) Kantorovici si K rilov p. 394 ! ss=0.d0 do mm=1,41,2 do nn=1,41,2 c1=(-1.d0)**(0.5d0*(mm+nn)-1)/(mm*nn*(mm**2 *b**2+nn**2*a**2)) ss=ss+c1*cos(mm*pi*xx/2.d0/a)*cos(nn*pi*yy/2.d0/b ) enddo enddo ue=ss*a**2*b**2*128/pi**4 end subroutine sist(zz,gg) use tablouri implicit none real(8),dimension(n),intent(in ) :: zz(n) ! vector ul necunoscutelor real(8),dimension(n),intent(out) :: gg(n) ! vector ul functiilor integer i,j real(8) s1,s2 do j=1,ny gg(nx+(j-1)*nx)=zz(nx+(j-1)*nx) ! sus (bound ary) gg(1 +(j-1)*nx)=zz(1 +(j-1)*nx) ! jos (bound ary) enddo do i=2,nx-1 gg(i +(1-1)*nx)=zz(i+( 1-1)*nx) ! stanga (bound ary) gg(i+(ny-1)*nx)=zz(i+(ny-1)*nx) ! dreapta (bound ary) enddo do i=2,nx-1 ! discretizare cu diferenta centr ale do j=2,ny-1 s1=(zz(i +(j-2)*nx)-2.d0*zz(i +(j-1)*nx)+ zz(i +(j )*nx)) s2=(zz(i-1+(j-1)*nx)-2.d0*zz(i +(j-1)*nx)+ zz(i+1+(j-1)*nx)) gg(i+(j-1)*nx)=s1+s2*(hx/hy)**2+2.d0*hx**2 enddo enddo end include 'c:\for\decsol.f90' ! Gauss descompunere L U ; Retrosubstitutie

10.5 EcuaŃia de potenŃial pe cerc Se consideră ecuaŃia cu derivate parŃiale:

012

112

22

222

2

2

2

2

2

2

2

=∂∂

++

∂∂∂−

∂∂

−+

∂∂

θϕ

θϕ

θϕϕ θθθ

ra

v

rra

vv

ra

v

ra

v rr

( ))(2

)1( 222max

χvvVa r +−−=

Se determină soluŃiile periodice ale ecuaŃiei de potenŃial cu condiŃiile la limite:

Page 79: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

79

r=r1 : 0=∂∂=

rvr

ϕ

r=r2 : θϕ cos∞= V Derivatele parŃiale se discretizează cu formule cu diferenŃe centrale. Se obŃine un sistem algebric neliniar care se rezolvă cu metoda Newton. Jacobianul sistemului este calculat numeric. AproximaŃia iniŃială este soluŃia ecuaŃiei Laplace pe cerc în curent paralel. SoluŃia numerică se compară cu soluŃia obŃinută prin dezvoltare în serie. Rezultatele sunt prezentate în figura 10.5.1.

-2.5

-2

-1.5

-1

-0.5

0

0.5

1

1.5

2

2.5

0 1 2 3 4 5 6 7

V_

teta

Teta

Ecuatia de potential pe cerc, Mach=0.4

Figura 10.5.1. SoluŃia numerică (puncte) şi soluŃia obŃinută prin dezvoltare în serie Mach=0.4. MODULE REZERVARE_MEMORIE PARAMETER (NR=101,NT=37,MM=NR*NT,NEC=MM) REAL(8) DR,DT,TETA(NT),VINF,VMAX REAL(8) PT(NR,-1:NT+2) REAL(8) ZZ(NEC),FCT(NEC),DFDZ(NEC,NEC) REAL(8) FP(NEC),FM(NEC),XS(NEC) INTEGER IP(NEC) REAL(8) :: TINF=300.D0 REAL(8) :: HI=1.4D0 REAL(8) :: RG=287.D0 REAL(8) :: MACH=0.4D0 REAL(8) :: R1=1.D0 REAL(8) :: R2=11.D0 REAL(8) :: PI=3.14159265358979D0 END MODULE REZERVARE_MEMORIE PROGRAM POTENTIAL_CERC_NELINIAR USE REZERVARE_MEMORIE ! ! Ecuatia de potential 2D cerc ! ! v*grad(v*v/2)=a**2*div(v) ! ! cp*T+0.5*v*v=cp*t_inf+0.5*v_inf*v_inf ! ! a**2=hi*r*t ! IMPLICIT REAL*8 (A-H,O-Z)

Page 80: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

80

OPEN(1,FILE='C:\FOR\p2.txt') CP=HI*RG/(HI-1.D0) AINF=SQRT(HI*RG*TINF) VINF=AINF*MACH VMAX=SQRT(2.D0*CP*TINF+VINF**2) DR=(R2-R1)/(NR-1.D0) ; DT=2.D0*PI/(NT-1.D0) DO J=1,NT ; TETA(J)=(J-1)*DT ; ENDDO K=0 DO I=1,NR RR=R1+(I-1)*DR DO J=1,NT K=K+1 ZZ(K)=VINF/VMAX*(RR+1.D0/RR)*COS(TETA(J)) ENDDO ENDDO CALL SIST(ZZ,FCT) H=1.D0/512.D0 ! Pasa derivare numerica DO NEWTON=1,10 ! iteratii Newton XS=ZZ DO J=1,NEC ! calculul numeric al Jaco bianului XS(J)=ZZ(J)+H CALL SIST(XS,FP) XS(J)=ZZ(J)-H CALL SIST(XS,FM) DFDZ(:,J)=(FP-FM)/(H+H) ! diferente central e coloana j XS(J)=ZZ(J) ENDDO CALL DEC(NEC,NEC,DFDZ,IP,IER) ! descompunere LU (Gauss) IF(IER.NE.0)STOP 'JACOBIAN SINGULAR' FCT=-FCT CALL SOL(NEC,NEC,DFDZ,FCT,IP) ! retrosubstitu tie ZZ=ZZ+FCT ! corectii NEWT ON CALL SIST(ZZ,FCT) ERM=MAXVAL(ABS(FCT)) ! norma erorii WRITE(*,'(1X,A,I3,A,F13.6)')'It=',NEWTON,' Er =',ERM IF(ERM.LT.0.00001D0)EXIT ! convergenta ENDDO K=0 DO I=1,NR DO J=1,NT K=K+1 ; PT(I,J)=ZZ(K)*(VMAX/VINF) ENDDO ENDDO DO I=1,NR ! periodicitate PT(I,0 )=PT(I,NT-1) PT(I,-1 )=PT(I,nt-2) PT(I,NT+1)=PT(I,2) PT(I,NT+2)=PT(I,3) ENDDO DO I=1,1 ! Solutia pe cer c RR=R1+(I-1)*DR ! Raza DO J=1,NT TE=TETA(J) VT=(PT(I,J+1)-PT(I,J-1))/(DT+DT)/RR ! Derivat a potentialului ! Solutia obtinuta prin dezvoltare in serie VTE=2.D0*SIN(TE)+MACH**2*(2.D0/3.D0*SIN(TE)-0.5D 0*SIN(3.D0*TE)) &

Page 81: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

81

+MACH**4*( 37.D0/40.D0*SIN(TE) & -25.D0/24.D0*SIN(3.D0*TE) & + 3.D0/8.D0 *SIN(5.D0*TE)+ & (HI-1.D0)*(23.D0/120.D0*SIN(TE)-11.D0/40.D0*SI N(3.D0*TE)+ & 1.D0/8.D0*SIN(5.D0*TE))) VTE=-VTE WRITE(*,'(1X,6F12.4)')TE,VT,VTE,VT-VTE IF(I.EQ.1)THEN WRITE(1,'(1X,6F12.4)')TE,VT,VTE,VT-VTE ENDIF ENDDO WRITE(1,*) ENDDO END PROGRAM POTENTIAL_CERC_NELINIAR SUBROUTINE SIST(ZZL,F) USE REZERVARE_MEMORIE IMPLICIT REAL*8 (A-H,O-Z) REAL(8),DIMENSION(NEC),INTENT(IN ) :: ZZL REAL(8),DIMENSION(NEC),INTENT(OUT) :: F K=0 DO I=1,NR DO J=1,NT K=K+1 PT(I,J)=ZZL(K) ENDDO ENDDO DO I=1,NR ! Periodicitate PT(I,0 )=PT(I,NT-1) PT(I,-1 )=PT(I,NT-2) PT(I,NT+1)=PT(I,2) PT(I,NT+2)=PT(I,3) ENDDO K=0 DO J=1,NT ! Conditia la limita pe cerc ; vr=0 K=K+1 F(K)=-3.D0*PT(1,J)+4.D0*PT(2,J)-PT(3,J) ! R =R1 ENDDO DO J=1,NT ! Conditia la limita R=R2 "Infinit" K=K+1 F(K)=PT(NR,J)-(VINF/VMAX)*R2*COS(TETA(J)) ENDDO DT1=1.D0/DT**2 DC=1.D0/DR**2 DO I=2,NR-1 DO J=1,NT RR=R1+(I-1)*DR VR=(PT(I+1,J)-PT(I-1,J))/(DR+DR) VT=(PT(I,J+1)-PT(I,J-1))/(DT+DT)/RR AP=(HI-1.D0)/2.D0*(1.D0-VR**2-VT**2) D2PDT2=(- 1.D0*PT(I,J-2)+ & +16.D0*PT(I,J-1) & -30.D0*PT(I,J ) & +16.D0*PT(I,J+1) & - 1.D0*PT(I,J+2))*DT1/12.D0 D2PDR2=(PT(I+1,J)-2.D0*PT(I,J)+PT(I-1,J))*DC D2PDRDT=(PT(I+1,J+1)+PT(I-1,J-1)- & PT(I+1,J-1)-PT(I-1,J+1))/4.D0/DR/ DT

Page 82: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

82

DPDR=(PT(I+1,J)-PT(I-1,J))/(DR+DR) K=K+1 C1=1.D0-VR**2/AP C2=1.D0-VT**2/AP C3=-2.D0*VR*VT/AP C4=1.D0+VT**2/AP F(K)=C1*D2PDR2+C2/RR**2*D2PDT2+C3*D2PDRDT/RR+ C4/RR*DPDR ENDDO ENDDO END SUBROUTINE SIST INCLUDE 'C:\FOR\DECSOL.F90'

10.6 Rezolvarea sistemelor de ecuaŃii algebrice neliniare program powell_hybrid ! ! Rezolva sisteme algebrice neliniare cu algoritmul Powell hibrid ! Sistemul algebric este descris in subrutina sist ! ! Reference: ! ! Jorge More, Burton Garbow and Kenneth Hillstro m, ! User Guide for MINPACK-1 ! Argonne National Laboratory, ! Argonne, Illinois. ! ! Modified by: ! ! John Burkardt ! implicit none integer, parameter :: n=2 ! numarul de necunoscute real(8) x(n) ! vectorul necunoscutelor real(8) f(n) ! vectorul functiilor real(8) tol ! precizia impusa integer i,info external sist ! sistemul de ecuatii nel iniare write(*,'(a,/)')'Program powell_hybrid' tol=1.d-6 ! precizia impusa x(1)=0.d0 ! aproximatia initiala x(1) x(2)=0.d0 ! aproximatia initiala x(2) call hybrd1(sist,n,x,f,tol,info) write(*,*)'info=',info select case(info) case(0) write(*,*)'improper input parameters' case(1) write(*,*)'algorithm estimates that the relative error between X and' write(*,'(a,g13.5)')' the solution is at most TO L=',tol case(2) write(*,*)'number of calls to FCN has reached or exceeded 200*(N+1)' case(3) write(*,*)' TOL is too small. No further improv ement in the' write(*,*)' approximate solution X is possible' case(4)

Page 83: Fortran - Curs

Dan RacoŃi Elemente de Fortran 95

83

write(*,*)'the iteration is not making good prog ress' end select write(*,'(/,a,/)')'Solutia' write(*,'(a,i1,a,g14.7,a,i1,a,f13.6)') & ('x(',i,')=',x(i),'f(',i,')=',f(i),i=1,n) end program powell_hybrid subroutine sist(n,x,f,iflag) implicit none integer,intent(in ) :: n real(8),intent(in ),dimension(n) :: x real(8),intent(out),dimension(n) :: f integer,intent(inout) :: iflag f(1)=x(1)**2+x(2)**2-1.d0 f(2)=x(1)-x(2) end subroutine sist !************************************************** ***************************80 ! !! HYBRD1 seeks a zero of N nonlinear equations in N variables. ! ! Discussion: ! ! HYBRD1 finds a zero of a system of N nonlinear fu nctions in N variables ! by a modification of the Powell hybrid method. T his is done by using the ! more general nonlinear equation solver HYBRD. Th e user must provide a ! subroutine which calculates the functions. The j acobian is then ! calculated by a forward-difference approximation. ! ! Reference: ! ! Jorge More, Burton Garbow and Kenneth Hillstro m, ! User Guide for MINPACK-1 ! Argonne National Laboratory, ! Argonne, Illinois. ! ! Modified by: ! ! John Burkardt ! include 'c:\for\minpack.f90'