Documente Academic
Documente Profesional
Documente Cultură
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
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
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
real(8) listă_variabile
double precision listă_variabile
real(8) w1,w2
double precision k1,h2
complex listă_variabile
complex(4) listă_variabile
complex y2,z2,a1,b2
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
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
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
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
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
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
nume_funcŃie(argumente_formale)=expresie_aritmetică
valoare=nume_funcŃie(argumente_efective)
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'
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)
write(*,*)'program p2'
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
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
11
Dan RacoŃi
Elemente de Fortran 95
program p4
!
! Rezolva un sistem de trei ecuatii algebrice liniare
! cu regula lui Cramer
!
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
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
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
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.
p q p.and.q
.true. .true. .true.
.true. .false. .false.
.false. .true. .false.
.false. .false. .false.
p q p.or.q
.true. .true. .true.
.true. .false. .true.
.false. .true. .true.
.false. .false. .false.
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
if(expresie)intrucŃiune_atribuire
if(expresie)goto etichetă
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
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
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
select case(expr)
case(case_value_1)
block_1
case(case_value_2)
block_2
.
.
.
case default
block_default
end select
18
Dan RacoŃi
Elemente de Fortran 95
case(1:) ! i>= 1
end select
Exemplu:
Exemplu:
select case(itest)
case(1)
call sub1
case(2)
call sub2
case default
call subd
end select
program select_case
implicit none
integer numar
real a,b
character(1) operatie
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
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
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.
20
Dan RacoŃi
Elemente de Fortran 95
do var=start,final,increment
bloc1
if(conditie_logică) cycle
bloc2
enddo
3.3 Forma 3
do
bloc instrucŃiuni
if(condiŃie_logică)exit
enddo
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
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.
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
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
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
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
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)))
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
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
! ---------------------------------------------------------
! 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
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
5. Tablouri
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
29
Dan RacoŃi
Elemente de Fortran 95
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
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)))
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ă.
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)
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)
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
34
Dan RacoŃi
Elemente de Fortran 95
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
35
Dan RacoŃi
Elemente de Fortran 95
8., 2., 1./ ! a treia coloana din matricea b
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
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
!
! 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
result=reshape(source,shape)
InstrucŃiunea:
a=reshape((/1.,2.,3.,4./),(/2.,2./)
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
real,dimension(100,100) :: matrice
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)
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
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)
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)
40
Dan RacoŃi
Elemente de Fortran 95
n
∑a
j =1
ij x j = bi i=1,2,…,n
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
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
write(*,*)'Iteratii Seidel'
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
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
write(*,*)'Iteratii Seidel'
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
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.
!
6. FuncŃii şi subprograme
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.)
write(*,*)x,y,c
write(*,*)-2.1,-1.1,c
contains
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.
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
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
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.”
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
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
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
48
Dan RacoŃi
Elemente de Fortran 95
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.
program recursivef
!
! Calculeaza functia factorialorial recursiv
!
implicit none
integer n,f,factorial
n=4
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
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
INTERFACE
FUNCTION F(X) RESULT (FUNCTION_VALUE)
REAL(8), INTENT(IN) :: X
REAL(8) :: FUNCTION_VALUE
END FUNCTION F
END INTERFACE
STEP = B-A
MIDDLE_POINT= 0.5d0 * (A+B)
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
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
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))
6.5 Subrutine
Subprogramele de tip SUBROUTINE permit calculul mai multor valori în corpul
subprogramului şi transmiterea lor în programul apelant.
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)
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 matrice(ndim,ndim)
54
Dan RacoŃi
Elemente de Fortran 95
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
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
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)
!
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
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
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
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))
''
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.
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.
!
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
common listă_parametrii
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
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
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
64
Dan RacoŃi
Elemente de Fortran 95
! rezultatul prin common in programul principal
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
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.
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)
write(*,*)'program quadpack'
alfa=1.d0
p=pi
call dr_dqag(f,a,b,eps,eps,key,rezult,abserr,ier)
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'
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'
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.
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')
!
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
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
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.
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
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'
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
77
Dan RacoŃi
Elemente de Fortran 95
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
end
include 'c:\for\decsol.f90' ! Gauss descompunere LU ; Retrosubstitutie
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.
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
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
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
INCLUDE 'C:\FOR\DECSOL.F90'
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'
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)
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