!
La teoria module cashkarp implicit none integer,private,parameter::q=selected_real_kind(14,300) real(kind=q),private,parameter::n11776=11776,n16632=16632,n6237=6237,& n24948=24948,n1540=1540,n3262=3262,n37800=37800,n4600=4600, & n44275=44275,n6831=6831,n8855=8855,n9361=9361,n38500=38500,& n20125=20125,n27648=27648,n10240=10240,n39550=39550,& n148600=148600,n94675=94675,n7479=7479,n96768=96768,& n2530=2530,n10=10 real(kind=q),private,parameter::a21=n11776*n16632 real(kind=q),private,parameter::a31=n11776*n6237,a32=3*n11776*n6237 real(kind=q),private,parameter::a41=n11776*n24948,a42=-3*n11776*n24948,& a43=4*n11776*n24948 real(kind=q),private,parameter::a51=-11*n11776*n1540,a52=135*n11776*n1540,& a53=-140*n11776*n1540,a54=70*n11776*n1540 real(kind=q),private,parameter::a61=n8855*n3262,a62=n8855*n37800,& a63=n8855*n4600,a64=n8855*n44275,a65=n8855*n6831 real(kind=q),private,parameter::b51=n10240*n9361,b53=n10240*n38500,& b54=n10240*n20125,b56=n10240*n27648 real(kind=q),private,parameter::b41=n2530*n39550,b43=n2530*n148600,& b44=n2530*n94675,b45=n2530*n7479,b46=n2530*n96768 real(kind=q),private,parameter::b31=344565760,b33=-362700800,b34=997427200 real(kind=q),private,parameter::b21=-1468938240,b22=n10*244823040 real(kind=q),private,parameter::b11=979292160 real(kind=q),private,parameter::c2=195858432,c3=293787648,c4=587575296 real(kind=q),private,parameter::c5=979292160,c6=856880640 ! real(kind=q),dimension(:),private,allocatable::yp,ytn ! corrisponde a k1. real(kind=q),dimension(:),private,allocatable::k2,k3,k4,k5,k6 integer,private::nv=0 private:: esempio_cashkarp public:: program_test,xcontrollo,cash_karp,hermite,xscashkarp ! contains subroutine xcontrollo(tot) ! Se il valore di tot e' zero non ci sono errori evidenti. real(kind=q),intent(out)::tot tot=abs(a21-c2) tot=tot+abs(a31+a32-c3) tot=tot+abs(a41+a42+a43-c4) tot=tot+abs(a51+a52+a53+a54-c5) tot=tot+abs(a61+a62+a63+a64+a65-c6) tot=tot+abs(b51+b53+b54+b56-b11) tot=tot+abs(b41+b43+b44+b45+b46-b11) tot=tot+abs(b31+b33+b34-b11) tot=tot+abs(b21+b22-b11) return end subroutine xcontrollo ! subroutine xscashkarp(y,nm,not_ok) real(kind=q),intent(in),dimension(1:)::y integer,optional,intent(in)::nm logical,intent(out)::not_ok not_ok=.false. if(nv==0) then nv=size(y,1) if(present(nm)) then nv=max(nv,nm) end if allocate(ytn(nv),k2(nv),k3(nv),k4(nv)) allocate(k5(nv),k6(nv),yp(nv)) ytn(:)=0.0_q k2(:)=0.0_q k3(:)=0.0_q k4(:)=0.0_q k5(:)=0.0_q k6(:)=0.0_q yp(:)=0.0_q else if(size(y,1)>size(ytn,1)) then not_ok=.true. end if return end subroutine xscashkarp ! subroutine cash_karp(yn,nv,y,hv,f,yt) ! ! nv rappresenta il numero di variabili da integrare e deve ! valere almeno 2 perche' la prima variabile e' quella ! indipendente. ! hv rappresenta l'ampiezza del passo di integrazione ! y(:) rappresenta il vettore delle variabili a inizio passo. ! yn(:) rappresenta il vettore delle variabili a fine passo. ! yt(:) rappresenta il vettore delle derivate prime a inizio passo ! ma e' opzionale perche', se non viene dato, viene ! calcolato internamente. ! ytn(:) rappresenta il vettore delle derivate prime a fine passo, che ! viene calcolato solo se yt(:) e' passato alla subroutine. ! f(z,w) e' la subroutine che calcola il vettore delle derivate prime ! quando è noto il vettore delle variabili. ! yp(:) rappresenta il vettore delle variabili a fine passo ma ! calcolato con una precisione minore. Se yp(:) differisce ! eccessivamente da yn(:) bisogna rifare il passo riducendo ! il valore di hv. Si noti che yp non è in argomento poiche' ! viene data come memoria del modulo. ! integer,intent(in)::nv real(kind=q),intent(in),dimension(1:)::y real(kind=q),intent(in),dimension(1:),optional::yt real(kind=q),intent(in)::hv real(kind=q),intent(out),dimension(1:)::yn interface subroutine f(z,w) integer,parameter::q=selected_real_kind(15,300) real(kind=q),intent(in),dimension(1:)::w real(kind=q),intent(out),dimension(1:)::z end subroutine f end interface real(kind=q)::h h=hv/b11 if(present(yt)) then ytn(1:nv)=yt(1:nv) else call f(ytn,y) end if yp(1:nv)=y(1:nv)+(h*a21)*ytn(1:nv) call f(k2,yp) yp(1:nv)=y(1:nv)+(h*a31)*ytn(1:nv)+(h*a32)*k2(1:nv) call f(k3,yp) yp(1:nv)=y(1:nv)+(h*a41)*ytn(1:nv)+(h*a42)*k2(1:nv)+& (h*a43)*k3(1:nv) call f(k4,yp) yp(1:nv)=y(1:nv)+(h*a51)*ytn(1:nv)+(h*a52)*k2(1:nv)+& (h*a53)*k3(1:nv)+(h*a54)*k4(1:nv) call f(k5,yp) yp(1:nv)=y(1:nv)+(h*a61)*ytn(1:nv)+(h*a62)*k2(1:nv)+& (h*a63)*k3(1:nv)+(h*a64)*k4(1:nv)+(h*a65)*k5(1:nv) call f(k6,yp) yn=y ! per trascrivere eventuali dati oltre i primi nv. yn(1:nv)=yn(1:nv)+(h*b51)*ytn(1:nv)+(h*b53)*k3(1:nv)+& (h*b54)*k4(1:nv)+(h*b56)*k6(1:nv) ! Valore meno preciso usabile solo per controllo: yp(1:nv)=y(1:nv)+(h*b41)*ytn(1:nv)+(h*b43)*k3(1:nv)+& (h*b44)*k4(1:nv)+(h*b45)*k5(1:nv)+(h*b46)*k6(1:nv) if(present(yt)) then call f(ytn,yn) end if return end subroutine cash_karp ! subroutine hermite(yora,y,yt,yn,ytn,theta,n) ! ! interpolazione cubica (di Hermite) ! integer,intent(in)::n real(kind=q),intent(in)::theta real(kind=q),intent(in),dimension(1:)::y,yt,yn,ytn real(kind=q),intent(out),dimension(1:)::yora real(kind=q):: h,d1,d2,d3,d4,ds,dsq,tq ! ! La variabile indipendente deve essere la prima. ! h=yn(1)-y(1) tq=theta*theta ds=theta-1.0_q dsq=ds*ds d1=dsq*(2.0_q*theta+1.0_q) d2=dsq*theta*h d3=tq*(3.0_q-2.0_q*theta) d4=tq*ds*h yora(1:n)=d1*y(1:n)+d2*yt(1:n)+d3*yn(1:n)+d4*ytn(1:n) return end subroutine hermite ! subroutine esempio_cashkarp(z,w) ! ! Il tempo e' ottenuto risolvendo l'equazione differenziale: ! `t = 1 e il valore del tempo e' memorizzato nella prima ! componente di w. Il vettore z rappresenta il valore ! delle derivate prime corrispondenti ai valori delle ! variabili memorizzate nel vettore w. ! real(kind=q),intent(in),dimension(1:)::w real(kind=q),intent(out),dimension(1:)::z real(kind=q)::r32 ! if(w(1)>=0.0_q) then z(1)=1 ! `t z(2)=w(4) ! `x z(3)=w(5) ! `y r32=w(2)*w(2)+w(3)*w(3) r32=1.0_q/(r32*sqrt(r32)) z(4)=-w(2)*r32 ! `vx z(5)=-w(3)*r32 ! `vy else ! ! Per poter inizializzare il calcolo , w(1) deve essere ! negativo e il vettore z(:) rappresenta allora il vettore ! delle variabili e non il vettore delle loro derivate prime. ! Al tempo w(1).lt.0 il valore assoluto di w(1) indica ! l'eccentricita' che deve essere maggiore di 0 e inferiore ! ad 1. ! Non e' ammessa una eccentricita' esattamente nulla perche' ! allora w(1) non sarebbe negativo ma qualsiasi valore pur ! piccolissimo va bene... ! r32=min(0.999999_q,abs(w(1))) z(1)=0.0_q ! t=0 z(2)=1-r32 ! 1-e z(3)=0.0_q z(4)=0.0_q z(5)=sqrt((1.0_q+r32)/(1.0_q-r32)) ! sqrt((1+e)/(1-e)) write(unit=*,fmt="(1a,4f18.10)") " ",z(2:) end if return ! ! Questo esempio e' il problema del moto di un pianeta attorno al sole ! che occupa l'origine delle coordinate. Il semiasse maggiore e' sempre ! uno, se il moto e' ellittico ossia se l'eccentricita', mai negativa, ! risulta essere inferiore ad 1. Se valesse esattamente 1 il moto ! sarebbe parabolico. Se e indica l'eccentricita', allora a t=w(1)=0 ! bisogna imporre queste condizioni iniziali: z(1)=0, z(2)=1-e, z(3)=0, ! z(4)=0, z(5)=sqrt((1+e)/(1-e)) ossia il moto inizia al perielio. ! end subroutine esempio_cashkarp ! subroutine program_test(ece,passie,girie,posizioni) real(kind=q),intent(in),optional::ece integer,intent(in),optional::passie,girie real(kind=q),dimension(0:,1:),intent(out),optional::posizioni integer::passi,giri,j,kp real(kind=q)::ec,hv,t0,s,x real(kind=q),dimension(5)::y,yn,yt,yora logical::boh !---- write(unit=*,fmt=*)"Esegue alcune prove di funzionamento",& " di questo modulo (module cashkarp)" write(unit=*,fmt=*)" " call xcontrollo(x) write(unit=*,fmt=*)"1) Se vale 0.0 ",& "i coefficienti sono forse giusti : ",x if(present(ece)) then ec=ece else write(unit=*,fmt="(a)",advance="no") & " Assegna l'eccentricita' dell'orbita " read(unit=*,fmt=*) ec ec=max(1.0e-30_q,min(0.999999_q,ec)) end if if(present(passie)) then passi=passie else write(unit=*,fmt="(a)",advance="no") & " Assegna il numero di passi" read(unit=*,fmt=*) passi end if if(present(girie)) then giri=girie else write(unit=*,fmt="(a)",advance="no") & " Assegna il numero di giri" read(unit=*,fmt=*) giri end if ! if(present(posizioni)) then posizioni=0.0_q end if ! call xscashkarp(y,5,boh) if(boh) then write(unit=*,fmt=*)"Fallisce l'inizializzazione di cashkarp: invia e stop!" read(unit=*,fmt=*) stop end if ! hv*passi deve corrispondere ad un dodicesimo di giro ossia π/6 hv=2.0_q*atan(1.0_q)/(3.0_q*max(1,passi)) yn(:)=0 yn(1)=-ec call esempio_cashkarp(y,yn) ! Ogni j=passi dovrebbe aver fatto un dodicesimo di giro. do kp=1,giri*12-12 do j=1,passi call cash_karp(yn,5,y,hv,esempio_cashkarp) y=yn end do end do do kp=1,12 do j=1,passi call cash_karp(yn,5,y,hv,esempio_cashkarp) y=yn end do write(unit=*,fmt="(i5,4f18.10)") kp,y(2:5) end do write(unit=*,fmt=*)"Ora il tempo vale: ",y(1) t0=giri*atan(1.0_q)*8.0_q write(unit=*,fmt=*)"Il tempo voluto sarebbe:",t0 read(unit=*,fmt=*) ! if(.not.present(posizioni)) then return end if ! ! Esegue questi calcoli solo se deve fare una tabella con ! le posizioni distanziate un centesimo di tempo ovvero ! un centesimo di radiante, dato che fa un giro in 6.28318.... ! call esempio_cashkarp(yt,y) call cash_karp(yn,5,y,hv,esempio_cashkarp,yt) do kp=0,630 procedo:do if(yn(1)>t0) then exit procedo end if y=yn yt(1:5)=ytn(1:5) call cash_karp(yn,5,y,hv,esempio_cashkarp,yt) end do procedo s=(t0-y(1))/(yn(1)-y(1)) call hermite(yora,y,yt,yn,ytn,s,5) posizioni(kp,1)=yora(2) posizioni(kp,2)=yora(3) ! read(unit=*,fmt=*) t0=t0+0.01_q end do return end subroutine program_test ! end module cashkarp ! !Per verificare scommenta il program seguente:
! !program xcashkarp ! use cashkarp ! implicit none ! call program_test() ! write(unit=*,fmt="(1x,1a)",advance="no") "Un invio per finire: " ! read(unit=*,fmt=*) ! stop !end program xcashkarp !