568 lines
14 KiB
FortranFixed
568 lines
14 KiB
FortranFixed
C This file contains all the subroutines needed by the nonlinear solver broydn
|
|
C code modified based on on-line version in Numerical Recipes Website, Dec 28, 2004
|
|
|
|
SUBROUTINE cpbroydn(x0min,x,x0max,STPMX,n,
|
|
& fveccopy,funcv,TOLF,ierr)
|
|
implicit none
|
|
INTEGER n,NP,MAXITS,ierr
|
|
double precision x(n),EPS,TOLF,TOLMIN,TOLX,STPMX
|
|
double precision x0min(n),x0max(n),fveccopy(n)
|
|
LOGICAL check
|
|
! PARAMETER (NP=1000,MAXITS=250,EPS=1.0d-7,TOLF=1.0d-4,
|
|
! & TOLMIN=1.d-6,TOLX=EPS)
|
|
PARAMETER(NP=1000,MAXITS=250,EPS=1.0d-7,TOLX=EPS)
|
|
CU USES fdjac,funcv,lnsrch,qrdcmp,qrupdt,rsolv
|
|
INTEGER i,its,j,k
|
|
double precision den,f,fold,stpmax,sum,temp,test,c(NP),
|
|
& d(NP),fvcold(NP),g(NP),p(NP),qt(NP,NP),r(NP,NP),
|
|
& s(NP),t(NP),w(NP),xold(NP),fvec(NP)
|
|
LOGICAL restrt,sing,skip
|
|
EXTERNAL funcv
|
|
TOLMIN=TOLF*0.01d0
|
|
call funcv(n,x,fvec,f)
|
|
test=0.0d0
|
|
do 11 i=1,n
|
|
if(dabs(fvec(i)).gt.test)test=dabs(fvec(i))
|
|
11 continue
|
|
if(test.lt..01d0*TOLF)then
|
|
ierr=0
|
|
! check=.false.
|
|
return
|
|
endif
|
|
sum=0.0d0
|
|
do 12 i=1,n
|
|
sum=sum+x(i)*x(i)
|
|
12 continue
|
|
stpmax=STPMX*dmax1(dsqrt(sum),dble(n))
|
|
restrt=.true.
|
|
do 42 its=1,MAXITS
|
|
if(restrt)then
|
|
do i=1,n
|
|
if(x(i).lt.x0min(i).or.x(i).gt.x0max(i))then
|
|
ierr=1
|
|
return
|
|
endif
|
|
enddo
|
|
call cpfdjac(n,x,fvec,NP,r,funcv)
|
|
call cpqrdcmp(r,n,NP,c,d,sing)
|
|
! if(sing) pause 'singular Jacobian in broydn'
|
|
if(sing)then
|
|
ierr=2
|
|
return
|
|
end if
|
|
do 14 i=1,n
|
|
do 13 j=1,n
|
|
qt(i,j)=0.0d0
|
|
13 continue
|
|
qt(i,i)=1.0d0
|
|
14 continue
|
|
do 18 k=1,n-1
|
|
if(c(k).ne.0.0d0)then
|
|
do 17 j=1,n
|
|
sum=0.0d0
|
|
do 15 i=k,n
|
|
sum=sum+r(i,k)*qt(i,j)
|
|
15 continue
|
|
sum=sum/c(k)
|
|
do 16 i=k,n
|
|
qt(i,j)=qt(i,j)-sum*r(i,k)
|
|
16 continue
|
|
17 continue
|
|
endif
|
|
18 continue
|
|
do 21 i=1,n
|
|
r(i,i)=d(i)
|
|
do 19 j=1,i-1
|
|
r(i,j)=0.0d0
|
|
19 continue
|
|
21 continue
|
|
else
|
|
do 22 i=1,n
|
|
s(i)=x(i)-xold(i)
|
|
22 continue
|
|
do 24 i=1,n
|
|
sum=0.0d0
|
|
do 23 j=i,n
|
|
sum=sum+r(i,j)*s(j)
|
|
23 continue
|
|
t(i)=sum
|
|
24 continue
|
|
skip=.true.
|
|
do 26 i=1,n
|
|
sum=0.0d0
|
|
do 25 j=1,n
|
|
sum=sum+qt(j,i)*t(j)
|
|
25 continue
|
|
w(i)=fvec(i)-fvcold(i)-sum
|
|
if(dabs(w(i)).ge.EPS*(dabs(fvec(i))+
|
|
& dabs(fvcold(i))))then
|
|
skip=.false.
|
|
else
|
|
w(i)=0.0d0
|
|
endif
|
|
26 continue
|
|
if(.not.skip)then
|
|
do 28 i=1,n
|
|
sum=0.0d0
|
|
do 27 j=1,n
|
|
sum=sum+qt(i,j)*w(j)
|
|
27 continue
|
|
t(i)=sum
|
|
28 continue
|
|
den=0.0d0
|
|
do 29 i=1,n
|
|
den=den+s(i)*s(i)
|
|
29 continue
|
|
do 31 i=1,n
|
|
s(i)=s(i)/den
|
|
31 continue
|
|
call cpqrupdt(r,qt,n,NP,t,s)
|
|
do 32 i=1,n
|
|
if(r(i,i).eq.0.0d0) then
|
|
write(*,*) 'r singular in broydn'
|
|
end if
|
|
d(i)=r(i,i)
|
|
32 continue
|
|
endif
|
|
endif
|
|
do 34 i=1,n
|
|
sum=0.0d0
|
|
do 33 j=1,n
|
|
sum=sum+qt(i,j)*fvec(j)
|
|
33 continue
|
|
p(i)=-sum
|
|
34 continue
|
|
do 36 i=n,1,-1
|
|
sum=0.0d0
|
|
do 35 j=1,i
|
|
sum=sum-r(j,i)*p(j)
|
|
35 continue
|
|
g(i)=sum
|
|
36 continue
|
|
do 37 i=1,n
|
|
xold(i)=x(i)
|
|
fvcold(i)=fvec(i)
|
|
37 continue
|
|
fold=f
|
|
call cprsolv(r,n,NP,d,p)
|
|
|
|
! Gu modification starts
|
|
do 100 i=1,n
|
|
if(xold(i).lt.x0min(i).or.xold(i).gt.x0max(i))then
|
|
ierr=1
|
|
return
|
|
endif
|
|
100 continue
|
|
! Gu modification ends
|
|
call cplnsrch(n,xold,fold,g,p,x,f,
|
|
& stpmax,check,funcv,fvec)
|
|
test=0.0d0
|
|
do 38 i=1,n
|
|
if(dabs(fvec(i)).gt.test)test=dabs(fvec(i))
|
|
fveccopy(i)=fvec(i)
|
|
38 continue
|
|
if(test.lt.TOLF)then
|
|
ierr=0
|
|
! check=.false.
|
|
return
|
|
endif
|
|
if(check)then
|
|
if(restrt)then
|
|
ierr=3
|
|
return
|
|
else
|
|
test=0.0d0
|
|
den=dmax1(f,.5d0*dble(n))
|
|
do 39 i=1,n
|
|
temp=dabs(g(i))*dmax1(dabs(x(i)),1.0d0)/den
|
|
if(temp.gt.test)test=temp
|
|
39 continue
|
|
if(test.lt.TOLMIN)then
|
|
ierr=4
|
|
return
|
|
else
|
|
restrt=.true.
|
|
endif
|
|
endif
|
|
else
|
|
restrt=.false.
|
|
test=0.0d0
|
|
do 41 i=1,n
|
|
temp=(dabs(x(i)-xold(i)))/dmax1(dabs(x(i)),1.0d0)
|
|
if(temp.gt.test)test=temp
|
|
41 continue
|
|
if(test.lt.TOLX)then
|
|
ierr=4
|
|
! check=.true.
|
|
return
|
|
endif
|
|
endif
|
|
42 continue
|
|
ierr=5
|
|
return
|
|
END
|
|
|
|
SUBROUTINE cpfdjac(n,x,fvec,np,df,funcv)
|
|
implicit none
|
|
INTEGER n,np
|
|
double precision df(np,np),fvec(n),x(n),EPS
|
|
PARAMETER (EPS=1.0d-4)
|
|
CU USES funcv
|
|
INTEGER i,j,k
|
|
double precision h,temp,f(n),fsqsum
|
|
external funcv
|
|
do 12 j=1,n
|
|
temp=x(j)
|
|
h=EPS*dabs(temp)
|
|
if(h.eq.0.0d0)h=EPS
|
|
x(j)=temp+h
|
|
h=x(j)-temp
|
|
call funcv(n,x,f,fsqsum)
|
|
x(j)=temp
|
|
do 11 i=1,n
|
|
df(i,j)=(f(i)-fvec(i))/h
|
|
11 continue
|
|
12 continue
|
|
return
|
|
END
|
|
c
|
|
SUBROUTINE cplnsrch(n,xold,fold,g,p,x,f,
|
|
& stpmax,check,funcv,fvec)
|
|
implicit none
|
|
INTEGER n
|
|
LOGICAL check
|
|
DOUBLE PRECISION f,fold,stpmax,g(n),p(n),x(n),
|
|
*xold(n),ALF,TOLX,fvec(n)
|
|
PARAMETER (ALF=1.d-4,TOLX=1.d-7)
|
|
EXTERNAL funcv
|
|
CU USES funcv
|
|
INTEGER i
|
|
DOUBLE PRECISION a,alam,alam2,alamin,b,disc,
|
|
*f2,rhs1,rhs2,slope,sum,temp,test,tmplam
|
|
check=.false.
|
|
sum=0.0d0
|
|
do 11 i=1,n
|
|
sum=sum+p(i)*p(i)
|
|
11 continue
|
|
sum=dsqrt(sum)
|
|
if(sum.gt.stpmax)then
|
|
do 12 i=1,n
|
|
p(i)=p(i)*stpmax/sum
|
|
12 continue
|
|
endif
|
|
slope=0.0d0
|
|
do 13 i=1,n
|
|
slope=slope+g(i)*p(i)
|
|
13 continue
|
|
! if(slope.ge.0.0d0)pause 'roundoff problem in lnsrch'
|
|
test=0.0d0
|
|
do 14 i=1,n
|
|
temp=dabs(p(i))/dmax1(dabs(xold(i)),1.0d0)
|
|
if(temp.gt.test)test=temp
|
|
14 continue
|
|
alamin=TOLX/test
|
|
alam=1.0d0
|
|
1 continue
|
|
do 15 i=1,n
|
|
x(i)=xold(i)+alam*p(i)
|
|
15 continue
|
|
call funcv(n,x,fvec,f)
|
|
if(alam.lt.alamin)then
|
|
do 16 i=1,n
|
|
x(i)=xold(i)
|
|
16 continue
|
|
check=.true.
|
|
return
|
|
else if(f.le.fold+ALF*alam*slope)then
|
|
return
|
|
else
|
|
if(alam.eq.1.0d0)then
|
|
tmplam=-slope/(2.0d0*(f-fold-slope))
|
|
else
|
|
rhs1=f-fold-alam*slope
|
|
rhs2=f2-fold-alam2*slope
|
|
a=(rhs1/alam**2-rhs2/alam2**2)/(alam-alam2)
|
|
b=(-alam2*rhs1/alam**2+alam*rhs2/alam2**2)/
|
|
& (alam-alam2)
|
|
if(a.eq.0.0d0)then
|
|
tmplam=-slope/(2.0d0*b)
|
|
else
|
|
disc=b*b-3.0d0*a*slope
|
|
if(disc.lt.0.0d0) then
|
|
tmplam=0.5d0*alam
|
|
else if(b.le.0.0d0)then
|
|
tmplam=(-b+dsqrt(disc))/(3.0d0*a)
|
|
else
|
|
tmplam=-slope/(b+dsqrt(disc))
|
|
endif
|
|
endif
|
|
if(tmplam.gt..5d0*alam)tmplam=.5d0*alam
|
|
endif
|
|
endif
|
|
alam2=alam
|
|
f2=f
|
|
alam=dmax1(tmplam,.1d0*alam)
|
|
goto 1
|
|
END
|
|
c
|
|
SUBROUTINE cpqrdcmp(a,n,np,c,d,sing)
|
|
implicit none
|
|
INTEGER n,np
|
|
DOUBLE PRECISION a(np,np),c(n),d(n)
|
|
LOGICAL sing
|
|
INTEGER i,j,k
|
|
DOUBLE PRECISION scale,sigma,sum,tau
|
|
sing=.false.
|
|
do 17 k=1,n-1
|
|
scale=0.0d0
|
|
do 11 i=k,n
|
|
scale=dmax1(scale,dabs(a(i,k)))
|
|
11 continue
|
|
if(scale.eq.0.0d0)then
|
|
sing=.true.
|
|
c(k)=0.0d0
|
|
d(k)=0.0d0
|
|
else
|
|
do 12 i=k,n
|
|
a(i,k)=a(i,k)/scale
|
|
12 continue
|
|
sum=0.0d0
|
|
do 13 i=k,n
|
|
sum=sum+a(i,k)**2
|
|
13 continue
|
|
sigma=dsign(dsqrt(sum),a(k,k))
|
|
a(k,k)=a(k,k)+sigma
|
|
c(k)=sigma*a(k,k)
|
|
d(k)=-scale*sigma
|
|
do 16 j=k+1,n
|
|
sum=0.0d0
|
|
do 14 i=k,n
|
|
sum=sum+a(i,k)*a(i,j)
|
|
14 continue
|
|
tau=sum/c(k)
|
|
do 15 i=k,n
|
|
a(i,j)=a(i,j)-tau*a(i,k)
|
|
15 continue
|
|
16 continue
|
|
endif
|
|
17 continue
|
|
d(n)=a(n,n)
|
|
if(d(n).eq.0.0d0)sing=.true.
|
|
return
|
|
END
|
|
c
|
|
SUBROUTINE cpqrupdt(r,qt,n,np,u,v)
|
|
implicit none
|
|
INTEGER n,np
|
|
DOUBLE PRECISION r(np,np),qt(np,np),u(np),v(np)
|
|
CU USES rotate
|
|
INTEGER i,j,k
|
|
do 11 k=n,1,-1
|
|
if(u(k).ne.0.0d0)goto 1
|
|
11 continue
|
|
k=1
|
|
1 do 12 i=k-1,1,-1
|
|
call cprotate(r,qt,n,np,i,u(i),-u(i+1))
|
|
if(u(i).eq.0.0d0)then
|
|
u(i)=dabs(u(i+1))
|
|
else if(dabs(u(i)).gt.dabs(u(i+1)))then
|
|
u(i)=dabs(u(i))*dsqrt(1.0d0+(u(i+1)/u(i))**2)
|
|
else
|
|
u(i)=dabs(u(i+1))*dsqrt(1.0d0+(u(i)/u(i+1))**2)
|
|
endif
|
|
12 continue
|
|
do 13 j=1,n
|
|
r(1,j)=r(1,j)+u(1)*v(j)
|
|
13 continue
|
|
do 14 i=1,k-1
|
|
call cprotate(r,qt,n,np,i,r(i,i),-r(i+1,i))
|
|
14 continue
|
|
return
|
|
END
|
|
c
|
|
SUBROUTINE cprsolv(a,n,np,d,b)
|
|
implicit none
|
|
INTEGER n,np
|
|
DOUBLE PRECISION a(np,np),b(n),d(n)
|
|
INTEGER i,j
|
|
DOUBLE PRECISION sum
|
|
b(n)=b(n)/d(n)
|
|
do 12 i=n-1,1,-1
|
|
sum=0.0d0
|
|
do 11 j=i+1,n
|
|
sum=sum+a(i,j)*b(j)
|
|
11 continue
|
|
b(i)=(b(i)-sum)/d(i)
|
|
12 continue
|
|
return
|
|
END
|
|
c
|
|
SUBROUTINE cprotate(r,qt,n,np,i,a,b)
|
|
implicit none
|
|
INTEGER n,np,i
|
|
DOUBLE PRECISION a,b,r(np,np),qt(np,np)
|
|
INTEGER j
|
|
DOUBLE PRECISION c,fact,s,w,y
|
|
if(a.eq.0.0d0)then
|
|
c=0.0d0
|
|
s=dsign(1.0d0,b)
|
|
else if(dabs(a).gt.dabs(b))then
|
|
fact=b/a
|
|
c=dsign(1.0d0/dsqrt(1.0d0+fact**2),a)
|
|
s=fact*c
|
|
else
|
|
fact=a/b
|
|
s=dsign(1.0d0/dsqrt(1.0d0+fact**2),b)
|
|
c=fact*s
|
|
endif
|
|
do 11 j=i,n
|
|
y=r(i,j)
|
|
w=r(i+1,j)
|
|
r(i,j)=c*y-s*w
|
|
r(i+1,j)=s*y+c*w
|
|
11 continue
|
|
do 12 j=1,n
|
|
y=qt(i,j)
|
|
w=qt(i+1,j)
|
|
qt(i,j)=c*y-s*w
|
|
qt(i+1,j)=s*y+c*w
|
|
12 continue
|
|
return
|
|
END
|
|
|
|
subroutine cpxmprove(N,NP,a,b,x,mark)
|
|
implicit none
|
|
INTEGER i,j,idum,N,NP,indx(N),mark
|
|
double precision d,a(NP,NP),b(N),x(N),aa(NP,NP)
|
|
|
|
do 12 i=1,N
|
|
x(i)=b(i)
|
|
do 11 j=1,N
|
|
aa(i,j)=a(i,j)
|
|
11 continue
|
|
12 continue
|
|
call cpludcmp(aa,N,NP,indx,d,mark)
|
|
if (mark .eq. 0) goto 20
|
|
call cplubksb(aa,N,NP,indx,x)
|
|
call cpmprove(a,aa,N,NP,indx,b,x)
|
|
20 continue
|
|
return
|
|
END
|
|
|
|
|
|
SUBROUTINE cpmprove(a,alud,n,np,indx,b,x)
|
|
implicit none
|
|
INTEGER n,np,indx(n),NMAX
|
|
double precision a(np,np),alud(np,np),b(n),x(n)
|
|
PARAMETER (NMAX=500)
|
|
CU USES lubksb
|
|
INTEGER i,j
|
|
double precision r(NMAX)
|
|
DOUBLE PRECISION sdp
|
|
do 12 i=1,n
|
|
sdp=-b(i)
|
|
do 11 j=1,n
|
|
sdp=sdp+(a(i,j))*(x(j))
|
|
11 continue
|
|
r(i)=sdp
|
|
12 continue
|
|
call cplubksb(alud,n,np,indx,r)
|
|
do 13 i=1,n
|
|
x(i)=x(i)-r(i)
|
|
13 continue
|
|
return
|
|
END
|
|
|
|
SUBROUTINE cpludcmp(a,n,np,indx,d,mark)
|
|
implicit none
|
|
INTEGER n,np,indx(n),NMAX
|
|
double precision d,a(np,np),TINY
|
|
PARAMETER (NMAX=500,TINY=1.0d-20)
|
|
INTEGER i,imax,j,k,mark
|
|
double precision aamax,dum,sum,vv(NMAX)
|
|
mark=1
|
|
d=1.0d0
|
|
do 12 i=1,n
|
|
aamax=0.0d0
|
|
do 11 j=1,n
|
|
if (dabs(a(i,j)).gt.aamax) aamax=dabs(a(i,j))
|
|
11 continue
|
|
if (aamax.eq.0.0d0) then
|
|
! singular matrix
|
|
mark=0
|
|
return
|
|
end if
|
|
vv(i)=1.0d0/aamax
|
|
12 continue
|
|
do 19 j=1,n
|
|
do 14 i=1,j-1
|
|
sum=a(i,j)
|
|
do 13 k=1,i-1
|
|
sum=sum-a(i,k)*a(k,j)
|
|
13 continue
|
|
a(i,j)=sum
|
|
14 continue
|
|
aamax=0.0d0
|
|
do 16 i=j,n
|
|
sum=a(i,j)
|
|
do 15 k=1,j-1
|
|
sum=sum-a(i,k)*a(k,j)
|
|
15 continue
|
|
a(i,j)=sum
|
|
dum=vv(i)*dabs(sum)
|
|
if (dum.ge.aamax) then
|
|
imax=i
|
|
aamax=dum
|
|
endif
|
|
16 continue
|
|
if (j.ne.imax)then
|
|
do 17 k=1,n
|
|
dum=a(imax,k)
|
|
a(imax,k)=a(j,k)
|
|
a(j,k)=dum
|
|
17 continue
|
|
d=-d
|
|
vv(imax)=vv(j)
|
|
endif
|
|
indx(j)=imax
|
|
if(a(j,j).eq.0.0d0)a(j,j)=TINY
|
|
if(j.ne.n)then
|
|
dum=1.0d0/a(j,j)
|
|
do 18 i=j+1,n
|
|
a(i,j)=a(i,j)*dum
|
|
18 continue
|
|
endif
|
|
19 continue
|
|
return
|
|
END
|
|
|
|
SUBROUTINE cplubksb(a,n,np,indx,b)
|
|
implicit none
|
|
INTEGER n,np,indx(n)
|
|
double precision a(np,np),b(n)
|
|
INTEGER i,ii,j,ll
|
|
double precision sum
|
|
ii=0
|
|
do 12 i=1,n
|
|
ll=indx(i)
|
|
sum=b(ll)
|
|
b(ll)=b(i)
|
|
if (ii.ne.0)then
|
|
do 11 j=ii,i-1
|
|
sum=sum-a(i,j)*b(j)
|
|
11 continue
|
|
else if (sum.ne.0.0d0) then
|
|
ii=i
|
|
endif
|
|
b(i)=sum
|
|
12 continue
|
|
do 14 i=n,1,-1
|
|
sum=b(i)
|
|
do 13 j=i+1,n
|
|
sum=sum-a(i,j)*b(j)
|
|
13 continue
|
|
b(i)=sum/a(i,i)
|
|
14 continue
|
|
return
|
|
END
|