program flow * * driver for kirchhoff program kirch. * computes free-streamline flow over a polygonal obstacle. * l. n. trefethen, summer 1984 * implicit double precision (a-b,d-h,o-w,y) implicit complex*16 (c,x,z) common /dual/ sgx dimension z(20),x(20),betam(20),qwork(400) dimension x2(20),z2(20),betam2(20),qwork2(400) data zi,zoffst /(0.d0,1.d0),(2.d0,0.d0)/ sgx = 1. * * input control parameters: 1 print '(''n, nq?'')' read *,n,nq do 2 k = 1,n print '(''z('',i1,'') ?'')', k read *, aa,bb 2 z(k) = dcmplx(aa,bb) tol = 10.**(-min(12,nq+2)) * * solve mapping problem: call count0 call qinitx(n,z,betam,nq,qwork) call ksolv(0,tol,n,c,x,z,betam,nq,qwork) aw = abs(c) call count * * print results: write (10,'(''w'',4f10.5)') -3.,-3.,3.,3. print '(''stagnation point:'',2f10.7)', z(n+1) write (10,'(''m -2.5 -2.3''/''t 17 stagnation point:'')') write (10,'(''m -1. -2.3''/''t 20 '',2f10.6)') z(n+1) print '(''w:'',f10.7)', aw write (10,'(''m -2.5 -2.6''/''t 17 w:'')') write (10,'(''m -1. -2.6''/''t 10 '',f10.6)') aw * * force computation 1 -- along obstacle: sgx = -1. call qinitx(n,z,betam2,nq,qwork2) x2(1) = x(1) z2(1) = z(1) write (10,101) z2(1) + zoffst kmq = 1 do 12 k = 2,n km = k-1 if (betam2(k).ge.-.9999) then * --- non-sharp edge --- x2(k) = x(k) z2(k) = zx(x2(k),k,x2(km),z2(km),kmq,n,c,x,betam2,nq,qwork2) write (10,102) z2(k) + zoffst kmq = k else * --- sharp edge --- scale = min( abs(x(k)-x(km)) , abs(x(k+1)-x(k)) ) xx = x(k) - 1.d-2*scale zz = zx(xx,0,x2(km),z2(km),kmq,n,c,x,betam2,nq,qwork2) write (10,102) zz + zoffst xx2 = x(k) - .1*zi*scale zz = zx(xx2,0,xx,zz,0,n,c,x,betam2,nq,qwork2) x2(k) = x(k) + 1.d-2*scale z2(k) = zx(x2(k),0,xx2,zz,0,n,c,x,betam2,nq,qwork2) write (10,101) z2(k) + zoffst kmq = 0 endif 12 continue zf1 = zi * (z2(n)-z(n)) * * force computation 2 -- via point x = -i : ztmp = zx(-zi,0,x(1),z(1),1,n,c,x,betam2,nq,qwork2) ztmp = zx(x(n),n,-zi,ztmp,0,n,c,x,betam2,nq,qwork2) zf2 = zi * (ztmp-z(n)) * * force computation 3 -- via point x = 1.1-i : zz = (1.1d0,-1.d0) ztmp = zx(zz,0,x(1),z(1),1,n,c,x,betam2,nq,qwork2) ztmp = zx(x(n),n,zz,ztmp,0,n,c,x,betam2,nq,qwork2) zf3 = zi * (ztmp-z(n)) * * print forces; all three sets of numbers should agree: print '('' drag ='',3f12.6)', dreal(zf1),dreal(zf2),dreal(zf3) print '('' lift ='',3f12.6)', dimag(zf1),dimag(zf2),dimag(zf3) print '('' total ='',3f12.6)', abs(zf1),abs(zf2),abs(zf3) write (10,'(''m -2.5 -2.''/''t 24 drag, lift, total force:'')') write (10,'(''m 0. -2.''/''t 30 '',3f10.6)') dreal(zf2), & dimag(zf2), abs(zf2) sgx = 1. * * plot free streamlines: 23 write (10,101) z(1) write (10,102) (z(k),k=2,n) print '('' no. of streamlines ?'')' read *, nstr if (nstr.eq.0) stop space = .1d0*(2.d0/aw) npts = 30 do 4 nl = 0,1 write (10,101) z(n-nl*(n-1)) do 3 k = 0,npts xx = (-1.)**nl * (1. + k**3*sqrt(32.*space)/npts**3) call nearx(xx,x0,z0,k0,n,x,z,betam) zz = zx(xx,0,x0,z0,k0,n,c,x,betam,nq,qwork) 3 write (10,102) zz 4 continue print '(''finished free streamlines'')' * * plot internal streamlines: do 6 nl = -nstr,nstr do 5 k = -npts,npts if (nl.eq.0.and.k.gt.0) goto 6 xx = sqrt(dcmplx(space*k**3*54./npts**3,nl*space)) if (dimag(xx).lt.0.d0) xx = -xx xx = xx + x(n+1) call nearx(xx,x0,z0,k0,n,x,z,betam) zz = zx(xx,0,x0,z0,k0,n,c,x,betam,nq,qwork) if (k.eq.-npts) write (10,101) zz write (10,102) zz 5 continue 6 continue print '(''finished internal streamlines'')' * * plot upstream equipotential lines: do 8 nl = -16,-1 klim = 2*nstr if (nl.lt.-7) klim = nstr do 7 k = -klim,klim xx = sqrt(dcmplx(2.*nl*space,k*nstr*space/klim)) if (dimag(xx).lt.0.d0) xx = -xx xx = xx + x(n+1) call nearx(xx,x0,z0,k0,n,x,z,betam) zz = zx(xx,0,x0,z0,k0,n,c,x,betam,nq,qwork) if (k.eq.-klim) write (10,101) zz write (10,102) zz 7 continue 8 continue print '(''finished upstream equipotential lines'')' * * plot downstream equipotential lines: do 11 nn = 1,2 do 10 nl = 0,27 klim = 2*nstr if (nl.eq.0) klim = 10*klim if (nl.gt.5) klim = nstr do 9 k = 0,klim xx = sqrt(dcmplx(2.*nl*space,k*(-1)**nn*nstr*space/klim)) if (dimag(xx).lt.0.d0) xx = -xx if (nn.eq.1.and.k.eq.0) xx = -xx xx = xx + x(n+1) call nearx(xx,x0,z0,k0,n,x,z,betam) zz = zx(xx,0,x0,z0,k0,n,c,x,betam,nq,qwork) if (k.eq.0) write (10,101) zz write (10,102) zz 9 continue 10 continue 11 continue print '(''finished downstream equipotential lines'')' call count 101 format ('m ',2f9.4) 102 format ('c ',2f9.4) end * kirch1 * * computes the conformal map of the upper half plane (x) onto an * asymmetrical free-streamline flow domain (z) of kirchhoff type. * x is the square root of the velocity potential. * the obstacle is composed of n-1 straight line segments with * vertices z(k) indexed from 1 to n. z(n+1) is the stagnation point. * see monakhov, "boundary-value problems with free boundaries...", iv.1. * * adapted from scpack. l. n. trefethen, june 1984. subroutine qinitx(n,z,betam,nq,qwork) * * computes nodes and weights for gauss-jacobi quadrature * implicit double precision (a-b,d-h,o-w,y) implicit complex*16(c,x,z) dimension qwork(1),z(1),betam(1) call anglex(n,z,betam) iscr = nq*(2*n+2) + 1 do 1 k = 1,n+1 inodes = nq*(k-1) + 1 iwts = nq*(n+k) + 1 1 if (betam(k).ge.-.9999) call gaussj(nq,0.d0, & betam(k),qwork(iscr),qwork(inodes),qwork(iwts)) return end subroutine ksolv(iprint,tol,n,c,x,z,betam,nq,qwork) * * directs the solution of the modified schwarz-christoffel parameter * problem for kirchhoff flow over a polygonal obstacle * implicit double precision (a-b,d-h,o-w,y) implicit complex*16(c,x,z) common /param1/ nq2,c2,x2(20),z2(20),qwork2(460),betam2(20) dimension x(1),z(1),betam(1),qwork(1) dimension ajinv(20,20),scr(900),fval(19),y(19) external kfun np = n+1 nm = n-1 nm2 = n-2 x(1) = -1. x(n) = 1. * * initial guess and ns01a control parameters: do 1 k = 2,nm 1 y(k-1) = 0. dstep = 1.d-6 dmax = 300. maxfun = 30*nm * * copy input data to /param1/ and solve nonlinear system: nq2 = nq do 2 k = 1,np x2(k) = x(k) z2(k) = z(k) 2 betam2(k) = betam(k) nwdim = nq*(2*n+3) do 3 i = 1,nwdim 3 qwork2(i) = qwork(i) call ns01a(nm2,y,fval,ajinv,dstep,dmax,tol,maxfun, & iprint,scr,kfun) * * copy output data from /param1/ and print results: c = c2 do 4 k = 2,np 4 x(k) = x2(k) call nearx(x(np),x0,z0,k0,n,x,z,betam) z(np) = zx(x(np),0,x0,z0,k0,n,c,x,betam,nq,qwork) if (iprint.ge.0) call koutp(n,c,x,z,betam,nq) return end function zx(xx,kxx,x0,z0,k0,n,c,x,betam,nq,qwork) * * computes map z(xx) * implicit double precision (a-b,d-h,o-w,y) implicit complex*16(c,x,z) dimension x(1),betam(1),qwork(1) zx = z0 + c * xquad(x0,k0,xx,kxx,n,x,betam,nq,qwork) return end subroutine yxtran(n,y,x,z,betam) * * transforms y(k) to x(k) * implicit double precision (a-b,d-h,o-w,y) implicit complex*16(c,x,z) dimension y(1),x(1),z(1),betam(1) nm = n-1 dx = 1. sumx = dx do 1 k = 2,nm dx = dx / exp(y(k-1)) 1 sumx = sumx + dx dx = 2./sumx x(2) = -1. + dx do 2 k = 3,nm dx = dx / exp(y(k-2)) 2 x(k) = x(k-1) + dx asum = 0. do 3 k = 2,nm 3 asum = asum + betam(k)*acos(dreal(-x(k))) x(n+1) = -cos( dimag(log(z(n)-z(nm))) + asum ) return end subroutine kfun(nm2,y,fval) * * this is the function whose zero must be found in ksolv * implicit double precision (a-b,d-h,o-w,y) implicit complex*16(c,x,z) dimension fval(nm2),y(nm2) common /param1/ nq,c,x(20),z(20),qwork(460),betam(20) nm = nm2+1 n = nm2+2 call yxtran(n,y,x,z,betam) zdenom = xquad(x(1),1,x(2),2,n,x,betam,nq,qwork) c = (z(2)-z(1))/zdenom do 1 k = 2,nm kp = k+1 xint = xquad(x(k),k,x(kp),kp,n,x,betam,nq,qwork) fval(k-1) = abs(z(kp)-z(k)) - abs(c*xint) 1 continue return end subroutine koutp(n,c,x,z,betam,nq) * * prints a table of k, z(k), betam(k), and x(k) * implicit double precision (a-b,d-h,o-w,y) implicit complex*16(c,x,z) dimension x(1),z(1),betam(1) print 101, n, nq do 1 k = 1,n 1 print 102, k,z(k),betam(k),x(k) print 103, z(n+1), x(n+1) print '(/'' c = ('',e15.8,'','',e15.8,'')''/)', c return 101 format (/' parameters defining map:',15x,'(n =', & i3,')',6x,'(nq =',i3,')'// & ' k', 9x,'z(k)',11x,'betam(k)',12x,'x(k)'/ & ' ---',8x,'----',11x,'--------',12x,'----'/) 102 format (i3,' (',f6.3,',',f6.3,')',f12.5, & 3x,'(',f11.8,',',f11.8,')') 103 format ('stagn. (',f6.3,',',f6.3,')',15x,'(',f11.8,',',f11.8,')') end function xquad(xa,ka,xb,kb,n,x,betam,nq,qwork) * * computes the complex line integral of xprod from xa to xb along a * straight line segment. function xquad1 is called twice. * implicit double precision (a-b,d-h,o-w,y) implicit complex*16(c,x,z) dimension x(1),betam(1),qwork(1) xmid = (xa + xb) / 2. xquad = xquad1(xa,xmid,ka,n,x,betam,nq,qwork) & -xquad1(xb,xmid,kb,n,x,betam,nq,qwork) return end function xquad1(xa,xb,ka,n,x,betam,nq,qwork) * * computes the complex line integral of xprod from xa to xb along a * straight line segment by compound one-sided gauss-jacobi quadrature. * implicit double precision (a-b,d-h,o-w,y) implicit complex*16(c,x,z) dimension x(1),betam(1),qwork(1) data resprm /1.d0/ * * step 1: one-sided gauss-jacobi quadrature for left endpoint: if (abs(xa-xb).gt.0.d0) goto 1 xquad1 = (0.,0.) return 1 r = min(1.d0,distx(xa,ka,n,x)*resprm/abs(xa-xb)) xaa = xa + r*(xb-xa) xquad1 = xqsum(xa,xaa,ka,n,x,betam,nq,qwork) * * step 2: adjoin intervals of pure gaussian quadrature if necessary: 2 if (r.eq.1.d0) return r = min(1.d0,distx(xaa,0,n,x)*resprm/abs(xaa-xb)) xbb = xaa + r*(xb-xaa) xquad1 = xquad1 + xqsum(xaa,xbb,0,n,x,betam,nq,qwork) xaa = xbb goto 2 end function distx(xx,ks,n,x) * * determines the distance from xx to the nearest singularity x(k) * other than x(ks) * implicit double precision (a-b,d-h,o-w,y) implicit complex*16(c,x,z) dimension x(1) distx = 9999. do 1 k = 1,n if (k.eq.ks) goto 1 distx = min(distx,abs(xx-x(k))) 1 continue return end function xqsum(xa,xb,ka,n,x,betam,nq,qwork) * * computes the integral of xprod from xa to xb by applying a * one-sided gauss-jacobi formula with possible singularity at xa. * ka=0: gauss-legendre * ka=1 or n: gauss-legendre after change of variables (separation pt.) * 11. c c x vector of length n containing the variables of the c equations. on entry this should contain the initial c estimate of the solution. on return it will contain the c best estimate of the solution. c c f vector of length n used as working space. on return it c contains the values of the functions at the solution x. c c ajinv two dimensional array (20 by 20) used as working space. c on return it contains an approximation to the inverse of c the jacobian matrix of the system at the solution x. c c dstep step length for use in approximating first derivatives of c the functions by differences between function values. c c dmax generous estimate of the euclidean distance of the c solution from the initial estimate. used to limit maximu c size of a single correction step. must have dmax > dstep c c acc accuracy requirement. the iterative process is assumed t c have converged and a normal return takes place when an x c is found for which the euclidean norm of f(x) is less tha c acc. c c maxfun maximum number of function evaluations (calls to calfun) c to be allowed. (generally 10*n is a sufficient number of c evaluations, although for some problems more may be c needed.) c c iprint flag which controls printing. if iprint=0 there is little c printout except error messages. if iprint=1 then each c time calfun is called the values of x and f are printed. c c w vector of length n*(2*n+5) which is used as working space c c calfun the subroutine defining the system of nonlinear equations c it must have the form c c subroutine calfun(n,x,f) c c where n, x, and f have the same meaning as given above. c calfun should set the components of f to be the function c values at x. must be declared external in the calling c program. c c notes: c c there are four possible error exits, each of which is accompanied c by an appropriate diagnostic message. these occur when c c 1. the gradient of f at x becomes so small that it is c predicted that steps much larger than dmax are needed. c c 2. the number of calls to calfun exceeds maxfun. c c 3. f(x) fails to decrease for n+4 consecutive iterations whe c a decrease is predicted, and x is within dstep of the mos c successful vector of variables. c c 4. f(x) fails to decrease even though a new (therefore, c presumably reliable) jacobian matrix has just been c obtained by finite differences, and x is within distance c dstep from the point where the jacobian was calculated. c c these error conditions can be caused by a number of factors, such c as too small values for maxfun or dmax, or very poor values for c dstep or the initial guess for x. in addition, the problem itself c may be so badly conditioned that rounding errors in the c computations make finding a solution impossible, or the equations c may be inconsistent so that no solution exists. c c another important fact to note is that only one step size, dstep, c is used for all the variables. this implies that all the variable c are expected to be of roughly the same order of magnitude. scalin c may be required to accomplish this, but this enhances the numerica c stability of the problem anyway and is definitely advisable. c c note that if the order of the system is greater than 20, then ajin c (as well as several other arrays not appearing in the calling c sequence) must have their dimensions increased. c c matrix inversion is performed by the linpack routines c dgefa followed by dgedi. these require in addition the c linpack basic linear algebra subroutines daxpy, dscal, c idamax, and dswap. c implicit real*8 (a-h,o-z) double precision x(1),f(1),lawork(20),ajinv(20,20),w(1) double precision det(2) integer ipvt(20) external calfun c set various parameters maxc=0 c 'maxc' counts the number of calls of calfun nt=n+4 ntest=nt c 'nt' and 'ntest' cause an error return if f(x) does not decrease dtest=dfloat(n+n)-0.5d0 c 'dtest' is used to maintain linear independence nx=n*n nf=nx+n nw=nf+n mw=nw+n ndc=mw+n nd=ndc+n c these parameters separate the working space array w fmin=0.0d0 c usually 'fmin' is the least calculated value of f(x), c and the best x is in w(nx+1) to w(nx+n) dd=0.0d0 c usually dd is the square of the current step length dss=dstep*dstep dm=dmax*dmax dmm=4.0d0*dm is=5 c 'is' controls a 'go to' statement following a call of calfun tinc=1.0d0 c 'tinc' is used in the criterion to increase the step length c start a new page for printing if (iprint) 1,1,85 85 print 86 86 format (1h1) c call the subroutine calfun 1 maxc=maxc+1 call calfun (n,x,f) c test for convergence fsq=0.0d0 do 2 i=1,n fsq=fsq+f(i)*f(i) 2 continue if (fsq .gt. acc**2) go to 4 c provide printing of final solution if requested 3 if (iprint) 5,999,6 6 print 7,maxc 7 format (/5x,'the final ns01a solution required', 1i5,' calls of calfun, and is') print 8,(i,x(i),f(i),i=1,n) 8 format (4x,'i',8x,'x(i)',13x,'f(i)'/(i5,2e17.8)) 999 print 9,maxc,fsq 9 format (' the sum-of-squares error at step',i4,' is',e11.4) 5 return c test for error return because f(x) does not decrease 4 go to (10,11,11,10,11),is 10 if (fsq-fmin) 15,20,20 20 if (dd-dss) 12,12,11 12 ntest=ntest-1 if (ntest) 13,14,11 14 print 16,nt 16 format (///5x,'error return from ns01a because',i5, 1' calls of calfun failed to improve the residuals') 17 do 18 i=1,n x(i)=w(nx+i) f(i)=w(nf+i) 18 continue fsq=fmin go to 3 c error return because a new jacobian is unsuccessful 13 print 19 19 format (///5x,'error return from ns01a because f(x) ', 1'failed to decrease using a new jacobian') go to 17 15 ntest=nt c test whether there have been maxfun calls of calfun 11 if (maxfun-maxc) 21,21,22 21 print 23,maxc 23 format (///5x,'error return from ns01a because there have been', 1i5,' calls of calfun') if (fsq-fmin) 3,17,17 c provide printing if requested 22 if (iprint) 24,998,25 25 print 26,maxc 26 format (/5x,'at the',i5,' th call of calfun we have') print 8,(i,x(i),f(i),i=1,n) 998 print 9,maxc,fsq 24 go to (27,28,29,87,30),is c store the result of the initial call of calfun 30 fmin=fsq do 31 i=1,n w(nx+i)=x(i) w(nf+i)=f(i) 31 continue c calculate a new jacobian approximation 32 ic=0 is=3 33 ic=ic+1 x(ic)=x(ic)+dstep go to 1 29 k=ic do 34 i=1,n w(k)=(f(i)-w(nf+i))/dstep k=k+n 34 continue x(ic)=w(nx+ic) if (ic-n) 33,35,35 c calculate the inverse of the jacobian and set the direction matri 35 k=0 do 36 i=1,n do 37 j=1,n k=k+1 ajinv(i,j)=w(k) w(nd+k)=0.0d0 37 continue w(ndc+k+i)=1.0d0 w(ndc+i)=1.0d0+dfloat(n-i) 36 continue c c invert matrix with linpack routines: lda = 20 info = 0 call dgefa(ajinv,lda,n,ipvt,info) if (info.ne.0) goto 44 ijob = 1 call dgedi(ajinv,lda,n,ipvt,det,lawork,ijob) c c start iteration by predicting the descent and newton minima 38 ds=0.0d0 dn=0.0d0 sp=0.0d0 do 39 i=1,n x(i)=0.0d0 f(i)=0.0d0 k=i do 40 j=1,n x(i)=x(i)-w(k)*w(nf+j) f(i)=f(i)-ajinv(i,j)*w(nf+j) k=k+n 40 continue ds=ds+x(i)*x(i) dn=dn+f(i)*f(i) sp=sp+x(i)*f(i) 39 continue c test whether a nearby stationary point is predicted if (fmin*fmin-dmm*ds) 41,41,42 c if so then return or revise jacobian 42 go to (43,43,44),is 44 print 45 45 format (///5x,'error return from ns01a because a nearby ', 1'stationary point of f(x) is predicted') go to 17 43 ntest=0 do 46 i=1,n x(i)=w(nx+i) 46 continue go to 32 c test whether to apply the full newton correction 41 is=2 if (dn-dd) 47,47,48 47 dd=dmax1(dn,dss) ds=0.25d0*dn tinc=1.0d0 if (dn-dss) 49,58,58 49 is=4 go to 80 c calculate the length of the steepest descent step 48 k=0 dmult=0.0d0 do 51 i=1,n dw=0.0d0 do 52 j=1,n k=k+1 dw=dw+w(k)*x(j) 52 continue dmult=dmult+dw*dw 51 continue dmult=ds/dmult ds=ds*dmult*dmult c test whether to use the steepest descent direction if (ds-dd) 53,54,54 c test whether the initial value of dd has been set 54 if (dd) 55,55,56 55 dd=dmax1(dss,dmin1(dm,ds)) ds=ds/(dmult*dmult) go to 41 c set the multiplier of the steepest descent direction 56 anmult=0.0d0 dmult=dmult*dsqrt(dd/ds) go to 98 c interpolate between the steepest descent and the newton direction 53 sp=sp*dmult anmult=(dd-ds)/((sp-ds)+dsqrt((sp-dd)**2+(dn-dd)*(dd-ds))) dmult=dmult*(1.0d0-anmult) c calculate the change in x and its angle with the first direction 98 dn=0.0d0 sp=0.0d0 do 57 i=1,n f(i)=dmult*x(i)+anmult*f(i) dn=dn+f(i)*f(i) sp=sp+f(i)*w(nd+i) 57 continue ds=0.25d0*dn c test whether an extra step is needed for independence if (w(ndc+1)-dtest) 58,58,59 59 if (sp*sp-ds) 60,58,58 c take the extra step and update the direction matrix 50 is=2 60 do 61 i=1,n x(i)=w(nx+i)+dstep*w(nd+i) w(ndc+i)=w(ndc+i+1)+1.0d0 61 continue w(nd)=1.0d0 do 62 i=1,n k=nd+i sp=w(k) do 63 j=2,n w(k)=w(k+n) k=k+n 63 continue w(k)=sp 62 continue go to 1 c express the new direction in terms of those of the direction c matrix, and update the counts in w(ndc+1) etc. 58 sp=0.0d0 k=nd do 64 i=1,n x(i)=dw dw=0.0d0 do 65 j=1,n k=k+1 dw=dw+f(j)*w(k) 65 continue go to (68,66),is 66 w(ndc+i)=w(ndc+i)+1.0d0 sp=sp+dw*dw if (sp-ds) 64,64,67 67 is=1 kk=i x(1)=dw go to 69 68 x(i)=dw 69 w(ndc+i)=w(ndc+i+1)+1.0d0 64 continue w(nd)=1.0d0 c reorder the directions so that kk is first if (kk-1) 70,70,71 71 ks=ndc+kk*n do 72 i=1,n k=ks+i sp=w(k) do 73 j=2,kk w(k)=w(k-n) k=k-n 73 continue w(k)=sp 72 continue c generate the new orthogonal direction matrix 70 do 74 i=1,n w(nw+i)=0.0d0 74 continue sp=x(1)*x(1) k=nd do 75 i=2,n ds=dsqrt(sp*(sp+x(i)*x(i))) dw=sp/ds ds=x(i)/ds sp=sp+x(i)*x(i) do 76 j=1,n k=k+1 w(nw+j)=w(nw+j)+x(i-1)*w(k) w(k)=dw*w(k+n)-ds*w(nw+j) 76 continue 75 continue sp=1.0d0/dsqrt(dn) do 77 i=1,n k=k+1 w(k)=sp*f(i) 77 continue c calculate the next vector x, and predict the right hand sides 80 fnp=0.0d0 k=0 do 78 i=1,n x(i)=w(nx+i)+f(i) w(nw+i)=w(nf+i) do 79 j=1,n k=k+1 w(nw+i)=w(nw+i)+w(k)*f(j) 79 continue fnp=fnp+w(nw+i)**2 78 continue c call calfun using the new vector of variables go to 1 c update the step size 27 dmult=0.9d0*fmin+0.1d0*fnp-fsq if (dmult) 82,81,81 82 dd=dmax1(dss,0.25d0*dd) tinc=1.0d0 if (fsq-fmin) 83,28,28 c try the test to decide whether to increase the step length 81 sp=0.0d0 ss=0.0d0 do 84 i=1,n sp=sp+dabs(f(i)*(f(i)-w(nw+i))) ss=ss+(f(i)-w(nw+i))**2 84 continue pj=1.0d0+dmult/(sp+dsqrt(sp*sp+dmult*ss)) sp=dmin1(4.0d0,tinc,pj) tinc=pj/sp dd=dmin1(dm,sp*dd) go to 83 c if f(x) improves store the new value of x 87 if (fsq-fmin) 83,50,50 83 fmin=fsq do 88 i=1,n sp=x(i) x(i)=w(nx+i) w(nx+i)=sp sp=f(i) f(i)=w(nf+i) w(nf+i)=sp w(nw+i)=-w(nw+i) 88 continue if (is-1) 28,28,50 c calculate the changes in f and in x 28 do 89 i=1,n x(i)=x(i)-w(nx+i) f(i)=f(i)-w(nf+i) 89 continue c update the approximations to j and to ajinv k=0 do 90 i=1,n w(mw+i)=x(i) w(nw+i)=f(i) do 91 j=1,n w(mw+i)=w(mw+i)-ajinv(i,j)*f(j) k=k+1 w(nw+i)=w(nw+i)-w(k)*x(j) 91 continue 90 continue sp=0.0d0 ss=0.0d0 do 92 i=1,n ds=0.0d0 do 93 j=1,n ds=ds+ajinv(j,i)*x(j) 93 continue sp=sp+ds*f(i) ss=ss+x(i)*x(i) f(i)=ds 92 continue dmult=1.0d0 if (dabs(sp)-0.1d0*ss) 94,95,95 94 dmult=0.8d0 95 pj=dmult/ss pa=dmult/(dmult*sp+(1.0d0-dmult)*ss) k=0 do 96 i=1,n sp=pj*w(nw+i) ss=pa*w(mw+i) do 97 j=1,n k=k+1 w(k)=w(k)+sp*x(j) ajinv(i,j)=ajinv(i,j)+ss*f(j) 97 continue 96 continue go to 38 end subroutine dgefa(a,lda,n,ipvt,info) integer lda,n,ipvt(1),info double precision a(lda,1) c c linpack routine. c dgefa factors a double precision matrix by gaussian elimination. c requires blas daxpy,dscal,idamax c double precision t integer idamax,j,k,kp1,l,nm1 c c gaussian elimination with partial pivoting c info = 0 nm1 = n - 1 if (nm1 .lt. 1) go to 70 do 60 k = 1, nm1 kp1 = k + 1 c c find l = pivot index c l = idamax(n-k+1,a(k,k),1) + k - 1 ipvt(k) = l c c zero pivot implies this column already triangularized c if (a(l,k) .eq. 0.0d0) go to 40 c c interchange if necessary c if (l .eq. k) go to 10 t = a(l,k) a(l,k) = a(k,k) a(k,k) = t 10 continue c c compute multipliers c t = -1.0d0/a(k,k) call dscal(n-k,t,a(k+1,k),1) c c row elimination with column indexing c do 30 j = kp1, n t = a(l,j) if (l .eq. k) go to 20 a(l,j) = a(k,j) a(k,j) = t 20 continue call daxpy(n-k,t,a(k+1,k),1,a(k+1,j),1) 30 continue go to 50 40 continue info = k 50 continue 60 continue 70 continue ipvt(n) = n if (a(n,n) .eq. 0.0d0) info = n return end subroutine dgedi(a,lda,n,ipvt,det,work,job) integer lda,n,ipvt(1),job double precision a(lda,1),det(2),work(1) c c linpack routine. c dgedi computes the determinant and inverse of a matrix c using the factors computed by dgeco or dgefa. c c requires blas daxpy,dscal,dswap c fortran dabs,mod c double precision t double precision ten integer i,j,k,kb,kp1,l,nm1 c c compute determinant c if (job/10 .eq. 0) go to 70 det(1) = 1.0d0 det(2) = 0.0d0 ten = 10.0d0 do 50 i = 1, n if (ipvt(i) .ne. i) det(1) = -det(1) det(1) = a(i,i)*det(1) c ...exit if (det(1) .eq. 0.0d0) go to 60 10 if (dabs(det(1)) .ge. 1.0d0) go to 20 det(1) = ten*det(1) det(2) = det(2) - 1.0d0 go to 10 20 continue 30 if (dabs(det(1)) .lt. ten) go to 40 det(1) = det(1)/ten det(2) = det(2) + 1.0d0 go to 30 40 continue 50 continue 60 continue 70 continue c c compute inverse(u) c if (mod(job,10) .eq. 0) go to 150 do 100 k = 1, n a(k,k) = 1.0d0/a(k,k) t = -a(k,k) call dscal(k-1,t,a(1,k),1) kp1 = k + 1 if (n .lt. kp1) go to 90 do 80 j = kp1, n t = a(k,j) a(k,j) = 0.0d0 call daxpy(k,t,a(1,k),1,a(1,j),1) 80 continue 90 continue 100 continue c c form inverse(u)*inverse(l) c nm1 = n - 1 if (nm1 .lt. 1) go to 140 do 130 kb = 1, nm1 k = n - kb kp1 = k + 1 do 110 i = kp1, n work(i) = a(i,k) a(i,k) = 0.0d0 110 continue do 120 j = kp1, n t = work(j) call daxpy(n,t,a(1,j),1,a(1,k),1) 120 continue l = ipvt(k) if (l .ne. k) call dswap(n,a(1,k),1,a(1,l),1) 130 continue 140 continue 150 continue return end subroutine daxpy(n,da,dx,incx,dy,incy) c c constant times a vector plus a vector. c jack dongarra, linpack, 3/11/78. c double precision dx(1),dy(1),da integer i,incx,incy,ixiy,m,mp1,n if(n.le.0)return if (da .eq. 0.0d0) return if(incx.eq.1.and.incy.eq.1)go to 20 ix = 1 iy = 1 if(incx.lt.0)ix = (-n+1)*incx + 1 if(incy.lt.0)iy = (-n+1)*incy + 1 do 10 i = 1,n dy(iy) = dy(iy) + da*dx(ix) ix = ix + incx iy = iy + incy 10 continue return 20 m = mod(n,4) if( m .eq. 0 ) go to 40 do 30 i = 1,m dy(i) = dy(i) + da*dx(i) 30 continue if( n .lt. 4 ) return 40 mp1 = m + 1 do 50 i = mp1,n,4 dy(i) = dy(i) + da*dx(i) dy(i + 1) = dy(i + 1) + da*dx(i + 1) dy(i + 2) = dy(i + 2) + da*dx(i + 2) dy(i + 3) = dy(i + 3) + da*dx(i + 3) 50 continue return end subroutine dscal(n,da,dx,incx) c c scales a vector by a constant. c jack dongarra, linpack, 3/11/78. c double precision da,dx(1) integer i,incx,m,mp1,n,nincx if(n.le.0)return if(incx.eq.1)go to 20 nincx = n*incx do 10 i = 1,nincx,incx dx(i) = da*dx(i) 10 continue return 20 m = mod(n,5) if( m .eq. 0 ) go to 40 do 30 i = 1,m dx(i) = da*dx(i) 30 continue if( n .lt. 5 ) return 40 mp1 = m + 1 do 50 i = mp1,n,5 dx(i) = da*dx(i) dx(i + 1) = da*dx(i + 1) dx(i + 2) = da*dx(i + 2) dx(i + 3) = da*dx(i + 3) dx(i + 4) = da*dx(i + 4) 50 continue return end integer function idamax(n,dx,incx) c c finds the index of element having max. absolute value. c jack dongarra, linpack, 3/11/78. c double precision dx(1),dmax integer i,incx,ix,n idamax = 0 if( n .lt. 1 ) return idamax = 1 if(n.eq.1)return if(incx.eq.1)go to 20 ix = 1 dmax = dabs(dx(1)) ix = ix + incx do 10 i = 2,n if(dabs(dx(ix)).le.dmax) go to 5 idamax = i dmax = dabs(dx(ix)) 5 ix = ix + incx 10 continue return 20 dmax = dabs(dx(1)) do 30 i = 2,n if(dabs(dx(i)).le.dmax) go to 30 idamax = i dmax = dabs(dx(i)) 30 continue return end subroutine dswap (n,dx,incx,dy,incy) c c interchanges two vectors. c jack dongarra, linpack, 3/11/78. c double precision dx(1),dy(1),dtemp integer i,incx,incy,ix,iy,m,mp1,n if(n.le.0)return if(incx.eq.1.and.incy.eq.1)go to 20 ix = 1 iy = 1 if(incx.lt.0)ix = (-n+1)*incx + 1 if(incy.lt.0)iy = (-n+1)*incy + 1 do 10 i = 1,n dtemp = dx(ix) dx(ix) = dy(iy) dy(iy) = dtemp ix = ix + incx iy = iy + incy 10 continue return 20 m = mod(n,3) if( m .eq. 0 ) go to 40 do 30 i = 1,m dtemp = dx(i) dx(i) = dy(i) dy(i) = dtemp 30 continue if( n .lt. 3 ) return 40 mp1 = m + 1 do 50 i = mp1,n,3 dtemp = dx(i) dx(i) = dy(i) dy(i) = dtemp dtemp = dx(i + 1) dx(i + 1) = dy(i + 1) dy(i + 1) = dtemp dtemp = dx(i + 2) dx(i + 2) = dy(i + 2) dy(i + 2) = dtemp 50 continue return end