Вы находитесь на странице: 1из 83

Dan RacoŃi

Elemente de Fortran 95
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ă

1
Dan RacoŃi
Elemente de Fortran 95
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 interpolation
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,divdf3,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 polynomial pieces
c
do 20 i=1,nm1

2
Dan RacoŃi
Elemente de Fortran 95
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)/dtau
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 interpolation
! from * a practical guide to splines * by c. de boor
integer i,istep,j,n,nm1
real aloger,algerp,c(4,20),decay,divdf1,divdf3,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 polynomial 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)/dtau
20 c(4,i) = (divdf3/dtau)/dtau
!
! estimate max.interpolation error on (-1,1).
errmax = 0.

3
Dan RacoŃi
Elemente de Fortran 95
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.

4
Dan RacoŃi
Elemente de Fortran 95
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

5
Dan RacoŃi
Elemente de Fortran 95
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 variabile 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

6
Dan RacoŃi
Elemente de Fortran 95
i=i1*i2+i3/i4
j1=i1**2 ; j2=i2**2 ; j3=i3**2 ; j4=i4**2 ; j=j1+j2+j3+j4
k1=i1+j1 ; k2=i2+j2 ; k3=i3+j3 ; k4=i4/j4 ; k=k1/k2*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.d0
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
!

7
Dan RacoŃi
Elemente de Fortran 95
! Calculator stiintific 1
!
! Conventia implicita de declarare a variabilelor
! 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,putere1,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 variabilelor
!
implicit none
real x,y,suma,diferenta,produs,raport,putere1,putere2
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

8
Dan RacoŃi
Elemente de Fortran 95
n=2
putere1=x**n
putere2=y**x
namelist/lista1/x,y,suma,diferenta,produs,raport,putere1,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:
f ( x) = a1 + a 2 x 2
f ' ( x ) = 2a 2 x
g ( x) = sin(πx)
g ' ( x) = π cos(πx)
f ( x)
h( x ) =
g ( x)
f ' ( x) g ( x) − f ( x) g ' ( x)
h' ( x ) =
g 2 ( x)

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


utilizează convenŃia explicită de declarare a variabilelor.

9
Dan RacoŃi
Elemente de Fortran 95

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 functiei 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 functiei 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:


 11
a a12   x1   b1 
a   = 
 21 a 22   x 2  b2 
cu metoda Cramer. Se calculează determinanŃii de ordinul doi:

10
Dan RacoŃi
Elemente de Fortran 95

a11 a12
d0 = = a11a 22 − a12 a 21
a 21 a 22
b1 a12
d1 =
b2 a 22
a11 b1
d2 =
a 21 b2
Se presupune că determinantul d0 este diferit de zero.

d1
x1 =
d0
d2
x2 =
d0
program p3
!
! Rezolva un sistem de doua ecuatii algebrice liniare cu metoda Cramer
!
real a11,a12,b1,x1
real a21,a22,b2,x2

det2(a,b,c,d)=a*d-b*c ! determinant de ordinul 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.

11
Dan RacoŃi
Elemente de Fortran 95

 a11 a12 a13   x1   b1 


a    
 21 a 22 a 23   x 2  = b2 
 a31 a32 a33   x3  b3 

a11 a12 a13


d 0 = a 21 a 22 a 23
a31 a32 a33
b1 a12 a13
d1 = b2 a 22 a 23
b3 a 32 a33
a11 b1 a13
d 2 = a 21 b2 a 23
a31 b3 a33
a11 a12 b1
d 3 = a 21 a 22 b2
a31 a 23 b3
Se presupune că determinantul d0 este diferit de zero.
DeterminanŃii de ordin trei se calculează prin dezvoltare după prima linie:
a11 a12 a13
a a 23 a a13 a a13
a 21 a 22 a 23 = (−1)1+1 a11 22 + (−1) 2+1 a 21 12 + (−1) (1+3) a31 12
a32 a33 a32 a33 a 22 a 23
a31 a32 a33
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:
d1
x1 =
d0
d2
x2 =
d0
d3
x3 =
d0

program p4
!
! Rezolva un sistem de trei ecuatii algebrice liniare
! cu regula lui Cramer
!

det2(a,b,c,d)=a*d-b*c ! determinant de ordinul 2


!
! Determinant de ordinul trei (dezvoltare dupa prima linie)

12
Dan RacoŃi
Elemente de Fortran 95
!
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 liniare
! 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 prima 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.d0
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)

13
Dan RacoŃi
Elemente de Fortran 95
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

14
Dan RacoŃi
Elemente de Fortran 95
.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

15
Dan RacoŃi
Elemente de Fortran 95
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 zero'
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

16
Dan RacoŃi
Elemente de Fortran 95
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

17
Dan RacoŃi
Elemente de Fortran 95
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

18
Dan RacoŃi
Elemente de Fortran 95
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 programata'
end select

write(*,*)'Introduceti doua numere reale:'


read(*,*)a,b
write(*,*)'Intoduceti operatia aritmetica:'
read(*,'(a)')operatie

19
Dan RacoŃi
Elemente de Fortran 95
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.

20
Dan RacoŃi
Elemente de Fortran 95
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

21
Dan RacoŃi
Elemente de Fortran 95

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:


y= x
f ( y) = y 2 − x = 0
f ' ( y) = 2 y
Şirul iterativ Newton este:
f (yk )  x 
y k +1 = y k − k
= 0.5 y k + k  , k=0,1,…
f '( y )  y 
După cum se observă calculul radicalului se reduce la operaŃii aritmetice
elementare.
AproximaŃia iniŃială este:

22
Dan RacoŃi
Elemente de Fortran 95
x
y0 =
2
Calculul se opreşte dacă:
f (y ) < ε
k

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:


f ( x) = 0

este:
f (x k )
x k +1 = x k − k=0,1,2,…
f '(x k )
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ă:
f (x k ) < ε1
sau dacă diferenŃa între două valori x este mai mică decât o valoare impusă:
x k +1 − x k < ε 2
Numărul de iteraŃii este limitat la valoarea nmax pentru a evita o buclă infinită.
Considerăm ecuaŃia neliniară:

23
Dan RacoŃi
Elemente de Fortran 95
exp(− x) = sin( x)
f ( x) = exp(− x) − sin( x)
f ' ( x) = − exp(− x) − cos( x)
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 iteratii
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:
f ( x, y ) = 0
g ( x, y ) = 0
este:
 ∂f ( x k , y k ) ∂f ( x k , y k ) 
  ∆x   f ( x k , y k )
 ∂x ∂y    = −  k 
 ∂g ( x , y ) ∂g ( x k , y k )  ∆y 
k k k
 g(x , y )
 ∂x ∂y 
 
x k +1 = x k + ∆x
k=0,1,…
y k +1 = y k + ∆y
Indicele k este contorul de iteraŃii.
AproximaŃia iniŃială este determinată minimizând funcŃia de două variabile:
φ ( x, y ) = f 2 ( x, y ) + g 2 ( x, y )
as < x < ad
bx < y < b y
prin explorarea domeniului în care se caută soluŃia.

24
Dan RacoŃi
Elemente de Fortran 95
Derivatele parŃiale sunt calculate numeric cu formule de derivare cu diferenŃe
centrale:
∂f f ( x + h, y ) − f ( x − h, y )
=
∂x 2h
∂f f ( x, y + h ) − f ( x, y − h )
=
∂y 2h

∂g g ( x + h, y ) − g ( x − h, y )
=
∂x 2h
∂f g ( x, y + h ) − g ( x , y − h )
=
∂y 2h
IteraŃiile sunt oprite dacă este îndeplinită condiŃia:
∆x + ∆y < ε
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 intervalului pentru x
real(8) :: ad=+10.d0 ! marginea dreapta a intervalului pentru x
real(8) :: bl=-10.d0 ! marginea stanga a intervalului pentru y
real(8) :: bd=+10.d0 ! marginea dreapta a intervalului pentru y
integer,parameter :: n=10 ! numarul de intervale pe 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 ! determinantul 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

25
Dan RacoŃi
Elemente de Fortran 95
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 metoda 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:
h( z ) = a1 + a 2 z + a3 z 2 + a 4 z 3 + a 5 z 4 = 0
a1 , a 2 , a3 , a 4 , a 5 ∈ C
este echivalentă cu sistemul de ecuaŃii algebrice:
f ( x, y ) = Re(h( z )) = 0
g ( x, y ) = Im(h( z )) = 0
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).

26
Dan RacoŃi
Elemente de Fortran 95

program iteratii_3
!
! Calculeaza o solutie complexa a ecuatiei algebrice (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 ! determinantul 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 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 metoda 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'

27
Dan RacoŃi
Elemente de Fortran 95
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:


∂ u ∂ 2u
2
+ = −2
∂x 2 ∂y 2
− 1 < x < +1
− 1 < y < +1
cu condiŃia la limită u=0 pe contur este:
mπx nπy
∞ ∞ cos( ) cos( )
128
u ( x, y ) = 4 ∑ ∑ 2 2
π n =1,3,5 m=1,3,5 mn(m 2 + n 2 )

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:


x x2 x3 xi
ex = 1+ + + + ... + + ...
1 2! 3! i!
Calculul se efectuează adunând termen cu termen. Dacă un termen este mai mic decât
toleranŃa impusă calculul se opreşte:
xk

k!

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

28
Dan RacoŃi
Elemente de Fortran 95
PROGRAM calculul_functiei_exponentiale ! DEZVOLTARE IN SERIE
IMPLICIT NONE

INTEGER :: index ! numarul de 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 termen 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.

29
Dan RacoŃi
Elemente de Fortran 95

OperaŃiile cu vectoriale sunt definite în limbajul FORTRAN. Dacă a şi b sunt doi


vectori cu trei elemente complexe, operaŃia:
c = a +b
este echivalentă cu adunarea explicită a elementelor vectorilor:
c1 = a1 + b1
c 2 = a 2 + b2
c3 = a3 + b3
In FORTRAN se scrie:
complex a(3),b(3),c(3)
c = a+b
sau
c(1) = a (1) + b(1)
c ( 2) = a ( 2) + b ( 2)
c(3) = a (3) + b(3)
ÎnmulŃirea unui vector cu o constantă:
v 2 = cv1
v 2i = cv1i , i = 1,2,..., n
Adunarea a doi vectori:
v3 = v1 + v 2
v3i = v1i + v 2i , i = 1,2,..., n
Scăderea a doi vectori:
v3 = v1 − v2
v3i = v1i − v 2i , i = 1,2,..., n
Produsul scalar a doi vectori:
n
v1 .v 2 = ∑ v1i v 2i
i =1
Norma unui vector:
0.5
 n 2

v =  ∑ vi 
 i =1 
 
Dacă vectorul este de tip real atunci:
v = (v .v )
0.5

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


element.
 x1   y1   x1 y1 
     
x = x2  y =  y2  x * y = x2 y 2 
x  y  x y 
 3  3  3 3
InstrucŃiunile:

real x(3),z(3),s

30
Dan RacoŃi
Elemente de Fortran 95
s=sum(x*z)

conduc la:
s = x1 y1 + x 2 y 2 + x3 y 3

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,const
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_constante/
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 vectorului
!
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 elementelor vectorului
!
write(*,*)'Produs_v1=',product(v1),' Produs_v2=',product(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
!

31
Dan RacoŃi
Elemente de Fortran 95
! 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 produsul 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 vector

32
Dan RacoŃi
Elemente de Fortran 95
! locul valorii minime si valoarea minima intr-un vector
!
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ă:
C = cA
cij = caij , i = 1,2,..., n, j = 1,2,..., n
Adunarea a două matrice:
C = A+ B
cij = aij + bij , i = 1,2,..., n, j = 1,2,..., n
Scăderea a două matrice:
C = A− B
cij = aij − bij , i = 1,2,..., n, j = 1,2,..., n
ÎnmulŃirea a două matrice:
C = AB
n
cij = ∑ aik bkj , i = 1,2,..., n, j = 1,2,..., n
j =1

33
Dan RacoŃi
Elemente de Fortran 95
Norma unei matrice:
0.5
 n n 2
A =  ∑∑ aij 
 i =1 j =1 
OperaŃiile matriciale sunt definite în FORTRAN.

complex a(2,2),b(2,2),c(2,2)

c = a+b
sau :
c(1,1) = a (1,1) + b(1,1)
c(1,2) = a (1,2) + b(1,2)
c(2,1) = a (2,1) + b(2,1)
c(2,2) = a (2,2) + b(2,2)

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 coloane
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 matricea a


data (a(2,j),j=1,n)/4.,5.,6./ ! a doua linie din matricea a
data (a(3,j),j=1,n)/7.,8.,9./ ! a treia linie din matricea a

data b/-1.,-2.,-3., & ! prima coloana din matricea b


-6.,-4.,-2., & ! a doua coloana din matricea 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

34
Dan RacoŃi
Elemente de Fortran 95

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 coloane
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 matricea a


data (a(2,j),j=1,n)/4.,5.,6./ ! a doua linie din matricea a
data (a(3,j),j=1,n)/7.,8.,9./ ! a treia linie din matricea a

data b/-1.,-2.,-3., & ! prima coloana din matricea b


-6.,-4.,-2., & ! a doua coloana din matricea b

35
Dan RacoŃi
Elemente de Fortran 95
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

36
Dan RacoŃi
Elemente de Fortran 95
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:


1. 3.
a= 
2. 4.

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

37
Dan RacoŃi
Elemente de Fortran 95
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 linii
integer,parameter :: col=3 ! numarul de coloane
real,dimension(lin,col) :: a ! se declara o matrice (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

38
Dan RacoŃi
Elemente de Fortran 95
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 vector
enddo ! m1(i,:)*x inmultirea component cu component
! a doi vectori, rezultatul este un vector
! sum calculeaza suma vectorului
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 elementele matricei A
b(i,j)=rand(0) ! se genereaza aleator elementele matricei B
enddo

39
Dan RacoŃi
Elemente de Fortran 95
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 ; enddo
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:

40
Dan RacoŃi
Elemente de Fortran 95
n

∑a
j =1
ij x j = bi i=1,2,…,n

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


i −1 n
bi − ∑ aij x kj +1 − ∑a ij x kj
j =1 j = i +1
xik +1 = i=1,2,…,n
aii
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 = b − Ax k
r <ε

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 matricea 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

do while((iter<it_max).and.(norma_reziduu>eps))
do i=1,n
s=0.d0

41
Dan RacoŃi
Elemente de Fortran 95
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 la 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 (matricial)
norma_reziduu=maxval(abs(r))
write(*,'(a,i5,f13.5)')'iter=',iter, norma_reziduu
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 matricea 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

42
Dan RacoŃi
Elemente de Fortran 95

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 (matricial)
norma_reziduu=maxval(abs(r))
write(*,'(a,i5,f13.5)')'iter=',iter, norma_reziduu
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 valoarea 0.
! In caz contrar se opreste executia programului.

43
Dan RacoŃi
Elemente de Fortran 95
!
allocate (a(n,n),stat=ialoc0) ; if(ialoc0.ne.0)stop 'ialoc0'
!
! Se aloca spatiu pentru vectorul b.
! Daca alocarea reuseste variabila ialoc1 ia valoarea 0.
! In caz contrar se opreste executia programului.
!
allocate (b(n ),stat=ialoc1) ; if(ialoc1.ne.0)stop 'ialoc1'
!
! Se aloca spatiu pentru vectorul c.
! Daca alocarea reuseste variabila ialoc2 ia valoarea 0.
! In caz contrar se opreste executia programului.
!
allocate (c(n ),stat=ialoc2) ; if(ialoc2.ne.0)stop 'ialoc2'
!
! Se genereaza aleator elementele matricei a si ale 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 obtine 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

44
Dan RacoŃi
Elemente de Fortran 95
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 programul apelant,
! asociere HOST
!
if(x<0.)then
fct=exp(x)*cos(pi*y) ! expresia functiei
! numele functiei apare obligatoriu
! intr-o instructiune de atribuire
else
fct=exp(x)*sin(pi*x)
endif

end function fct

end program contains_exemple

45
Dan RacoŃi
Elemente de Fortran 95
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
n!= 1.2.3...n
0!= 1
permite calculul combinărilor:
n!
C nm =
m!(n − m)!

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 ! ARGUMENTUL


INTEGER :: F,I

IF(N==0)THEN
FACTORIAL=1
ELSEIF(N>1)THEN
F = 1 ! SE CALCULEAZA 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

46
Dan RacoŃi
Elemente de Fortran 95
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:


z = x + iy
şi se calculează funcŃia complexă:
1
f (z) = z +
z
Partea reală şi partea imaginară sunt Re( f ( z )) şi Im( f ( z )) .

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.
Profil Jucovski general
1

0.5

0
y

-0.5

-1
-1 -0.5 0 0.5 1
x
Figura 6.2.1 Profil Jukovski generat prin transformare conformă

47
Dan RacoŃi
Elemente de Fortran 95

Considerăm transformarea de coordonate:


ξ = −m cos δ + a cos θ
η = + m sin δ + a sin θ
şi numărul complex:
ζ = ξ + iη
Transformarea conformă Jucovski:

q2
z =ζ +
ζ
reprezintă conform exteriorul unui cerc de rază a cu centrul în M pe exteriorul unui profil
în planul z.
Coordonatele carteziene ale profilului sunt:
x = Re( z )
y = Im( z )
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) Carafoli

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),csi,eta
write(1,'(6(f10.6,1x))')x,y,xx(teta),yy(teta),csi,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

48
Dan RacoŃi
Elemente de Fortran 95

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


funcŃia factorial:
n!= n(n − 1)!
0!= 1
1!= 1
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 recursive factorial

write(*,*)'n=',n,' factorialorial=',f
end
recursive function factorial(n) result(s_fact)
! valoarea functiei este
! memorata in variabila 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

49
Dan RacoŃi
Elemente de Fortran 95

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:


b
I 1 = ∫ f ( x)dx =0.5( f (a) + f (b) )
a
Pentru mărirea preciziei se introduce un punct intermediar la mijlocul intervalului:
0.5 ( b − a ) b
I2 = ∫
a
f ( x)dx + ∫ f ( x)dx = 0.5( f (a) + f (0.5(b − a)) ) + 0.5( f (0.5(b − a)) + f (b))
0.5 ( b − a )

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ă:
I 2 − I 1 < tol
Dacă condiŃia este realizată se calculează valoarea finală a integralei prin
extrapolare Richardson, echivalentă cu formula lui Simpson:
I 2 − I1
I = I2 +
3
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 trapezelor 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 ABSOLUTA
REAL(8) :: REZULTAT ! VALOAREA CALCULATA A INTEGRALEI
REAL(8) :: PI

50
Dan RacoŃi
Elemente de Fortran 95
REAL(8) :: VAL_E ! VALOAREA EXACTA
INTEGER :: I
REAL(8) :: PRIMITIVA,X
PRIMITIVA(X)=-COS(X) ! PRIMITIVA FUNCTIEI CARE SE
! INTEGREAZA NUMERIC
PI = 4.0d0 * ATAN(1.0d0)
A= 0.D0 ; B=PI ! LIMITELE DE INTEGRARE
TOL =0.1d0 ! TOLERANTA INITIALA

DO I = 1, 5
TOL = TOL/10.0d0
REZULTAT = ADAPTIVE_QUAD (F, A, B, TOL, ABS_ERROR)
WRITE(*,*)
WRITE(*,"(A, F15.10, A, F15.10)")"Int_a ", &
REZULTAT, " err_estm ",ABS_ERROR
VAL_E=PRIMITIVA(B)-PRIMITIVA(A) ! LEIBNITZ-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_POINT


REAL(8) :: ONE_T_AREA, TWO_T_AREAS
REAL(8) :: LEFT_AREA, RIGHT_AREA
REAL(8) :: DIFF, ABS_ERROR_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(MIDDLE_POINT))+&
STEP * 0.25d0 * (F(MIDDLE_POINT) + 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, MIDDLE_POINT, &
0.5d0*TOL, ABS_ERROR_L)

51
Dan RacoŃi
Elemente de Fortran 95
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
I 1 = ∫ exp( x)dx
a
b
I 2 = ∫ sin( x)dx
a
utilizând aceeaşi funcŃie (metoda Gauss) pentru calculul numeric al integralelor.
Metoda Gauss pe trei puncte este:
b−a
b

∫a f ( x)dx = 2 ( A1 f ( x1 ) + A2 f ( x2 ) + A3 f ( x3 ) )
t1 = − 0.6
t2 = 0
t 3 = + 0.6
b+a b−a
xi = + t i , i = 1,2,3
2 2
Eroarea metodei este dată de formula restului:
1  b − a  (4)
5

R2 =   f (ξ )
135  2 
unde ξ este un punct din intervalul (a,b).

program external1
implicit none
real a,b
real f1c,f2c ! valorile calculate ale integralelor
real f1e,f2e ! valorile analitice ale integralelor
real er1,er2 ! eroarea absoluta
real gauss3
real primitiva1,primitiva2,x

external functia1,functia2
primitiva1(x)= exp(x)

52
Dan RacoŃi
Elemente de Fortran 95
primitiva2(x)=-cos(x)
a=0. ; b=0.5
f1c=gauss3(functia1,a,b) ; f1e=primitiva1(b)-primitiva1(a)
er1=abs(f1c-f1e)
write(*,*)'f1c=',f1c,' f1e=',f1e,' er1=',er1
f2c=gauss3(functia2,a,b) ; f2e=primitiva2(b)-primitiva2(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ă.

53
Dan RacoŃi
Elemente de Fortran 95
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 argument
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)

54
Dan RacoŃi
Elemente de Fortran 95

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 numere 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.
.

55
Dan RacoŃi
Elemente de Fortran 95
AUTHORS: E. HAIRER AND G. WANNER
UNIVERSITE DE GENEVE, DEPT. DE MATHEMATIQUES
CH-1211 GENEVE 24, SWITZERLAND
E-MAIL: Ernst.Hairer@math.unige.ch
Gerhard.Wanner@math.unige.ch

THIS CODE IS DESCRIBED IN:


E. HAIRER, S.P. NORSETT AND G. WANNER, SOLVING ORDINARY
DIFFERENTIAL EQUATIONS I. NONSTIFF PROBLEMS. 2ND EDITION.
SPRINGER SERIES IN COMPUTATIONAL MATHEMATICS,
SPRINGER-VERLAG (1996)

Considerăm sistemul algebric linear:


Ax = b
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.
A = LU
LUx = b
Ly = b
Ux = y
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:
1 0 0  x11 x12 x13  1 0 0 
−1  
AA = I = 0 1 0 A x 21 x 22 x 23  = I = 0 1 0
 
0 0 1  x31 x32 x33  0 0 1

 x11 x12 x13  1 0 0


LU  x 21 x 22 x 23  = I = 0 1 0

 x31 x32 x33  0 0 1

 x11  1  x12  0  x13  0


           
LU  x 21  = 0 LU  x22  = 1 LU  x 23  = 0
 x  0  x  0  x  1
 31     32     33   

program inversa_moler
!
! Calculeaza inversa unei matrici patrate de dimensiune n.
! Se efectueaza descompunerea LU a matricei sistemului.
! Se rezolva apoi prin retrosubstitutie n sisteme algebrice
! avand drept membru drept cate o coloana din matricea 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

56
Dan RacoŃi
Elemente de Fortran 95
! 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 verificare

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 este inlocuita


! cu descompunerea 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 MATHEMATIQUES
! CH-1211 GENEVE 24, SWITZERLAND
! E-MAIL: Ernst.Hairer@math.unige.ch
! Gerhard.Wanner@math.unige.ch
!
! THIS CODE IS DESCRIBED IN:

57
Dan RacoŃi
Elemente de Fortran 95
! E. HAIRER, S.P. NORSETT AND G. WANNER, SOLVING ORDINARY
! DIFFERENTIAL EQUATIONS I. NONSTIFF PROBLEMS. 2ND EDITION.
! SPRINGER SERIES IN COMPUTATIONAL MATHEMATICS,
! 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 TRIANGULAR 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 FOUND 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 ZERO.
!
! REFERENCE..
! C. B. MOLER, ALGORITHM 423, LINEAR EQUATION SOLVER,
! 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

58
Dan RacoŃi
Elemente de Fortran 95
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:
Ax = λx
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.

59
Dan RacoŃi
Elemente de Fortran 95
Vom considera o problemă un pic mai complicată, problema generalizată de
valori proprii:
Ax = λBx
Fie ecuaŃia diferenŃială, problema Sturm-Liouville:
2
d y
= λy
dx 2
a <= x <= b
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):
y ( x) = a1 f1 ( x) + a 2 f 2 ( x)
Substituind această soluŃie în ecuaŃia diferenŃială obŃinem:
a1 f1 ( x) + a 2 f 2'' ( x) = λ (a1 f 1 ( x) + a 2 f 2 ( x))
''

Î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:
 b '' b
 b b

 ∫ f 1 ( x) f 1 ( x)dx ∫ f 2 ( x) f1 ( x)dx  a  ∫ f1 ( x) f 1 ( x)dx ∫ f 2 ( x) f 1 ( x)dx  a
''

a a   1  = λ  a a   1 
 ''
b b
 a 2   b b
 a 2 
 ∫ f 1 ( x) f 2 ( x)dx ∫ f 2 ( x) f 2 ( x)dx  ∫ f 1 ( x) f 2 ( x)dx ∫ f 2 ( x) f 2 ( x)dx 
''

a a  a a 
Se calculează analitic sau numeric integralele din ultima expresie şi se obŃin
matricele A şi B, respectiv problema de valori proprii generalizată:
a  a 
A 1  = λ B  1 
a 2  a 2 
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 science div,
! argonne national laboratory
!_____________________________________________________________
!
! Se rezolva problema de valori proprii generalizata
!
! A*x=lambda*B*x
!
! A si B sunt matrici reale
!
IMPLICIT NONE
INTEGER,PARAMETER :: N=5

60
Dan RacoŃi
Elemente de Fortran 95
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 si 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. Moler,
! 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

61
Dan RacoŃi
Elemente de Fortran 95
double precision a(nm,n),b(nm,n),alfr(n),alfi(n),beta(n),z(nm,n)
logical tf
!
! this subroutine calls the recommended sequence of
! subroutines from the eigensystem subroutine package (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 the two-dimensional
! array parameters as declared in the calling 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 it is set to
! any non-zero integer for both eigenvalues and eigenvectors.
!
! on output
!
! alfr and alfi contain the real and imaginary parts,
! respectively, of the numerators of the eigenvalues.
!
! beta contains the denominators of the eigenvalues,
! which are thus given by the ratios (alfr+i*alfi)/beta.
! complex conjugate pairs of eigenvalues appear consecutively
! with the eigenvalue having the positive imaginary part first.
!
! z contains the real and imaginary parts of the eigenvectors
! if matz is not zero. if the j-th eigenvalue is real, the
! j-th column of z contains its eigenvector. if the j-th
! eigenvalue is complex with positive imaginary part, the
! j-th and (j+1)-th columns of z contain the real and
! imaginary parts of its eigenvector. the conjugate of this
! vector is the eigenvector for the conjugate eigenvalue.
!
! ierr is an integer output variable set equal to an error
! completion code described in the documentation 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)

62
Dan RacoŃi
Elemente de Fortran 95
call qzval(nm,n,a,b,alfr,alfi,beta,tf,z)
go to 50
! .......... find both eigenvalues and eigenvectors ..........
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 variabilelor a,b,c
write(*,*)'a =',a,' b =',b,' c =',c, ' Programul principal'
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 sub1'
end subroutine sub1

subroutine sub2
implicit none
real a1,b1,c1
common a1,b1,c1 ! corespondenta intre variabilele din programul principal
! si subrutina

63
Dan RacoŃi
Elemente de Fortran 95
! 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

64
Dan RacoŃi
Elemente de Fortran 95
! rezultatul prin common in programul principal

v2=matmul(mata,v1) ! se calculeaza produsul dintre matrice si


! vector si se transmite rezultatul in programul
! principal prin common

v3=matmul(matb,v1) ! se calculeaza produsul dintre matrice si


! vector si se transmite rezultatul 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_standard,presiunea_standard
!
! Valorile constantelor sunt precizate in procedura block data
! si transmise prin common.
!
write(*,*)'constanta gazelor =',constanta_gazelor,' J/mol/K'
write(*,*)'temperatura standard=',temperatura_standard,' K'
write(*,*)'presiunea standard =',presiunea_standard,' 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_standard,presiunea_standard
!
! Initializarea variabilelor din common cu intructiunea 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).

65
Dan RacoŃi
Elemente de Fortran 95
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 adaptive,
! gauss-kronrod
!***author piessens,robert ,appl. math. & progr. div - k.u.leuven
! de doncker,elise,appl. math. & progr. div. - k.u.leuven
!
implicit real(8) (a-h,o-z)

common /parametrii/pi,alfa ! parametrii definiti in 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 definite


b=0.5d0 ! limita superioara a integralei definite
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 calculata numeric
write(*,*)'Ia=',(primitiva(b)-primitiva(a)) ! analitic

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,result,abserr,ier)
implicit real(8) (a-h,o-z)
parameter (limit=128)

66
Dan RacoŃi
Elemente de Fortran 95
parameter (lenw=4*limit)
integer iwork(limit)
real(8) work(lenw)
external f
call dqag(f,a,b,epsabs,epsrel,key,result,abserr,neval,ier,
$ limit,lenw,last,iwork,work)

end
! subroutine dqag(f,a,b,epsabs,epsrel,key,result,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 adaptive,
! gauss-kronrod
!***author piessens,robert,appl. math. & progr. div - k.u.leuven
! de doncker,elise,appl. math. & progr. div. - k.u.leuven
!***purpose the routine calculates an approximation result to a given
! definite integral i = integral of f over (a,b),
! hopefully satisfying following claim for 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 the integrand
! function f(x). the actual name for f needs to be
! declared e x t e r n a l in the 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 integration 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

67
Dan RacoŃi
Elemente de Fortran 95
! estimate of the modulus of the absolute error,
! which should equal or exceed abs(i-result)
!
! neval - integer
! number of integrand evaluations
!
! ier - integer
! ier = 0 normal and reliable termination of the
! routine. it is assumed that the requested
! accuracy has been achieved.
! ier.gt.0 abnormal termination of the routine
! the estimates for result and error are
! less reliable. it is assumed that the
! requested accuracy has not been achieved.
! error messages
! ier = 1 maximum number of subdivisions allowed
! has been achieved. one can allow more
! subdivisions by increasing the value of
! limit (and taking the according dimension
! adjustments into account). however, if
! this yield no improvement it is advised
! to analyze the integrand in order to
! determine the integration difficulaties.
! if the position of a local difficulty can
! be determined (i.e.singularity,
! discontinuity within the interval) one
! will probably gain from splitting up the
! interval at this point and calling the
! integrator on the subranges. if possible,
! an appropriate special-purpose integrator
! should be used which is designed for
! handling the type of difficulty involved.
! = 2 the occurrence of roundoff error is
! detected, which prevents the requested
! tolerance from being achieved.
! = 3 extremely bad integrand 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 invalid, iwork(1),
! work(limit*2+1) and work(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 iwork
! limit determines the maximum number of subintervals
! in the partition of the given integration interval
! (a,b), limit.ge.1.
! if limit.lt.1, the routine will end with ier = 6.
!
! lenw - integer
! dimensioning parameter for work
! lenw must be at least limit*4.
! if lenw.lt.limit*4, the routine will end with
! ier = 6.
!

68
Dan RacoŃi
Elemente de Fortran 95
! last - integer
! on return, last equals the number of subintervals
! produced in the subdiviosion process, which
! determines the number of significant elements
! actually in the work arrays.
!
! work arrays
! iwork - integer
! vector of dimension at least limit, the first k
! elements of which contain pointers to the error
! estimates over the subintervals, such that
! work(limit*3+iwork(1)),... , work(limit*3+iwork(k))
! form a decreasing sequence with k = last if
! last.le.(limit/2+2), and k = limit+1-last otherwise
!
! work - double precision
! vector of dimension at least lenw
! on return
! work(1), ..., work(last) contain 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(limit*2+last) contain
! the integral approximations over the subintervals,
! work(limit*3+1), ..., work(limit*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:


y ( x) = f ( x, y1 ,... y n ) i=1,2,…,n
'
i
cu condiŃia iniŃială:
x = x0
y i ( x0 ) = y 0
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:

69
Dan RacoŃi
Elemente de Fortran 95

y1 + µ y − µ'
y1'' = y1 + 2 y 2' − µ ' −µ 1
D1 D2
y2 y
y 2'' = y 2 − 2 y1' − µ ' −µ 2
D1 D2
D1 = (( y1 + µ ) 2 + y 22 )1.5
D2 = (( y1 − µ ' ) 2 + y 22 )1.5
µ = 0.012277471
µ' =1− µ
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:
y1' = y 3
y 2' = y 4
y1 + µ y − µ'
y1'' = y1 + 2 y 4 − µ ' −µ 1
D1 D2
y2 y
y 2'' = y 2 − 2 y 3 − µ '−µ 2
D1 D2
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.
Orbita Arensdorf
1.5
'dopri5.txt' u 2:3

0.5
y2

-0.5

-1

-1.5
-1.5 -1 -0.5 0 0.5 1
y1
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

70
Dan RacoŃi
Elemente de Fortran 95
C ORDINARY DIFFERENTIAL EQUATIONS Y'=F(X,Y).
C THIS IS AN EXPLICIT RUNGE-KUTTA METHOD OF ORDER (4)5
C DUE TO DORMAND & PRINCE (WITH STEPSIZE CONTROL AND
C DENSE OUTPUT).
C
C AUTHORS: E. HAIRER AND G. WANNER
C UNIVERSITE DE GENEVE, DEPT. DE MATHEMATIQUES
C CH-1211 GENEVE 24, SWITZERLAND
C E-MAIL: Ernst.Hairer@math.unige.ch
C Gerhard.Wanner@math.unige.ch
C
C THIS CODE IS DESCRIBED IN:
C E. HAIRER, S.P. NORSETT AND G. WANNER, SOLVING ORDINARY
C DIFFERENTIAL EQUATIONS I. NONSTIFF PROBLEMS. 2ND EDITION.
C SPRINGER SERIES IN COMPUTATIONAL MATHEMATICS,
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 DURING 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 COORDINATES 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,IPAR,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)

71
Dan RacoŃi
Elemente de Fortran 95
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,ICOMP,ND),
& CONTD5(2,XOUT,CON,ICOMP,ND),NR-1
WRITE (1,98) XOUT,CONTD5(1,XOUT,CON,ICOMP,ND),
& CONTD5(2,XOUT,CON,ICOMP,ND),
# CONTD5(3,XOUT,CON,ICOMP,ND),
# CONTD5(4,XOUT,CON,ICOMP,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:
∂u ∂f (u )
+ =0
∂t ∂x
cu condiŃia iniŃială, problema Cauchy:
la t=0 u ( x) = u 0 ( x) = sin(πx) , x ∈ [0,2] .
Pentru ecuaŃia lui Burgers:

72
Dan RacoŃi
Elemente de Fortran 95

u2
f (u ) =
2
f (u ) − f (v) = a (u , v)(u − v)
u+v
a(u , v) =
2
Se consideră funcŃia flux numeric (Yee):
h(u , v) = 0.5[ f (u ) + f (v) − a (u, v) (v − u )]
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:
u max = max(u it ) i=1,2,…,n
şi se calculează pasul de timp (CFL):
∆x
∆t = 0.9
u max
Trecerea la nivelul următor de timp se face cu ecuaŃia:
u it + ∆t = u it +
∆x
[
∆t
]
h(u it , u it+1 ) − h(u it−1 , u it ) , 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.

Ecuatia Burgers omogena


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

0.5
u(x,1)

-0.5

-1
0 0.5 1 1.5 2
x
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 and Implicit
! Shock Capturing Method, NASA Technical Memorandum 101088,
! February 1989
!
!
! Ecuatia Burgers omogena
!

73
Dan RacoŃi
Elemente de Fortran 95
! 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 limita


u(m+1)=u(m)

umax=0.d0 ! se determina viteza maxima pe tot 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 numeric


implicit none
real(8),intent(in) :: u,v
real(8) f,q,a

74
Dan RacoŃi
Elemente de Fortran 95

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 propagare 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:
∂ u ∂ 2u
2
+ = −2
∂x 2 ∂y 2
în domeniul dreptunghiular:
− a < x < +a
− b < x < +b
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:
2a
∆x =
nx − 1
2b
∆y =
ny −1
şi grila de discretizare:
xi = −a + (i − 1)∆x i=1,2,…,nx
yi = −b + ( j − 1)∆y j=1,2,…,ny
şi valorile funcŃiei în nodurile reŃelei:
u i , j = u ( xi , y j ) i=1,2,…,nx j=1,2,…,ny.
Derivatele parŃiale sunt discretizate cu formule de derivare numerică cu diferenŃe
centrale:
u i −1, j − 2u i , j + u i +1. j u i , j −1 − 2u i , j + u i , j +1
+ = −2
∆x 2 ∆y 2
Se defineşte sistemul de ecuaŃii algebrice lineare:
∆x 2
f i , j = u i −1. j − 2u i , j + u i +1, j + (u i , j −1 − 2u i , j + u i , j +1 ) 2 + 2∆x 2 = 0
∆y
i=2,…,nx-1, j=2,…,ny-1

75
Dan RacoŃi
Elemente de Fortran 95
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.

Torsiunea unei bare dreptunghilare


0.25

0.2

0.15
u

0.1

0.05

0
-1 -0.5 0 0.5 1
y
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 necunoscute
real(8) :: a=+0.5d0 ! -a < x < +a

real(8) :: b=+1.0d0 ! -b < y < +b


real(8) :: hx ! pasul de discretizare pe axa x
real(8) :: hy ! pasul de discretizare pe axa y
real(8),dimension(nx) :: x ! abscise
real(8),dimension(ny) :: y ! ordonate

real(8),dimension(n) :: z ! vectorul necunoscutelor


real(8),dimension(n) :: f ! vectorul functiilor
real(8),dimension(n,n):: df ! Jacobianul sistemului de ecuatii
real(8),dimension(n) :: dx,bb ! work space
integer,dimension(n) :: ip ! vectorul permutarilor 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, traducere din limba rusa,

76
Dan RacoŃi
Elemente de Fortran 95
! 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 singular
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) Kantorovici si Krilov,'
write(1,*)'"Metode aproximative ale analizei superioare",'
write(1,*)'Ed. Academiei, Bucuresti 1954, traducere 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 diferente 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 Jacobian
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

77
Dan RacoŃi
Elemente de Fortran 95

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 Krilov 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) ! vectorul necunoscutelor
real(8),dimension(n),intent(out) :: gg(n) ! vectorul functiilor
integer i,j
real(8) s1,s2

do j=1,ny
gg(nx+(j-1)*nx)=zz(nx+(j-1)*nx) ! sus (boundary)
gg(1 +(j-1)*nx)=zz(1 +(j-1)*nx) ! jos (boundary)
enddo

do i=2,nx-1
gg(i +(1-1)*nx)=zz(i+( 1-1)*nx) ! stanga (boundary)
gg(i+(ny-1)*nx)=zz(i+(ny-1)*nx) ! dreapta (boundary)
enddo

do i=2,nx-1 ! discretizare cu diferenta centrale


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 LU ; Retrosubstitutie

10.5 EcuaŃia de potenŃial pe cerc

Se consideră ecuaŃia cu derivate parŃiale:


 v  ∂ 2ϕ  vθ2  ∂ 2ϕ
2
2v v ∂ 2ϕ  vθ2  ∂ϕ
1 −  2 + 1 − 2  2 2 − r 2 θ
r
+ 1 +  =0
 a  ∂r
2
 a  r ∂θ ra ∂r∂θ  a 2  r∂θ
( χ − 1) 2
a2 =
2
(Vmax − (v r2 + vθ2 ) )
Se determină soluŃiile periodice ale ecuaŃiei de potenŃial cu condiŃiile la limite:

78
Dan RacoŃi
Elemente de Fortran 95
∂ϕ
r=r1 : v r = =0
∂r
r=r2 : ϕ = V∞ cos θ
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.

Ecuatia de potential pe cerc, Mach=0.4


2.5
2
1.5
1
0.5
V_teta

0
-0.5
-1
-1.5
-2
-2.5
0 1 2 3 4 5 6 7
Teta
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)

79
Dan RacoŃi
Elemente de Fortran 95
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 Jacobianului
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 centrale 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) ! retrosubstitutie
ZZ=ZZ+FCT ! corectii NEWTON
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 cerc


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 ! Derivata potentialului

! Solutia obtinuta prin dezvoltare in serie

VTE=2.D0*SIN(TE)+MACH**2*(2.D0/3.D0*SIN(TE)-0.5D0*SIN(3.D0*TE)) &

80
Dan RacoŃi
Elemente de Fortran 95
+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*SIN(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

81
Dan RacoŃi
Elemente de Fortran 95
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 Hillstrom,
! 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 neliniare

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 TOL=',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 improvement in the'
write(*,*)' approximate solution X is possible'
case(4)

82
Dan RacoŃi
Elemente de Fortran 95
write(*,*)'the iteration is not making good progress'
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

!*****************************************************************************8
0
!
!! HYBRD1 seeks a zero of N nonlinear equations in N variables.
!
! Discussion:
!
! HYBRD1 finds a zero of a system of N nonlinear functions in N variables
! by a modification of the Powell hybrid method. This is done by using the
! more general nonlinear equation solver HYBRD. The user must provide a
! subroutine which calculates the functions. The jacobian is then
! calculated by a forward-difference approximation.
!
! Reference:
!
! Jorge More, Burton Garbow and Kenneth Hillstrom,
! User Guide for MINPACK-1
! Argonne National Laboratory,
! Argonne, Illinois.
!
! Modified by:
!
! John Burkardt
!

include 'c:\for\minpack.f90'

83

Вам также может понравиться