c=========================================================== c newt2: Uses multi-dimensional Newton's method c to compute a root of simple non-linear system c discussed in class c c sin(xy) - 1/2 = 0 c y^2 - 6x - 2 = 0 c c Command line input is initial guess (two numbers) c for root, and optional convergence criteria. c Estimated root written to standard output. c Tracing output similar to that from 'newtsqrt'. c=========================================================== program newt2 implicit none integer iargc real*8 r8arg, drelabs, dvl2norm real*8 r8_never parameter ( r8_never = -1.0d-60 ) c----------------------------------------------------------- c Size of system. c----------------------------------------------------------- integer neq parameter ( neq = 2 ) c----------------------------------------------------------- c Command-line arguments: Initial guess will be c input directly into 'x' array. c----------------------------------------------------------- real*8 x0(neq), tol c----------------------------------------------------------- c Variables used in Newton iteration and solution of c linear systems via LAPACK routine 'dgesv'. c----------------------------------------------------------- real*8 J(neq,neq), res(neq), & x(neq) integer ipiv(neq) integer ieq, info integer mxiter, nrhs parameter ( mxiter = 50, nrhs = 1 ) integer iter real*8 nrm2res, nrm2dx, nrm2x c----------------------------------------------------------- c Argument parsing. c----------------------------------------------------------- if( iargc() .lt. neq ) go to 900 do ieq = 1 , neq x(ieq) = r8arg(ieq,r8_never) if( x(ieq) .eq. r8_never ) go to 900 end do tol = r8arg(neq+1,1.0d-8) if( tol .le. 0.0d0 ) tol = 1.0d-8 c----------------------------------------------------------- c Newton loop. c----------------------------------------------------------- write(0,*) 'Iter x y '// & ' log10(dx) log10(res)' write(0,*) do iter = 1 , mxiter c----------------------------------------------------------- c Evaluate residual vector. c----------------------------------------------------------- res(1) = sin(x(1)*x(2)) - 0.5d0 res(2) = x(2)**2 - 6.0d0 * x(1) - 2.0d0 nrm2res = dvl2norm(res,2) c----------------------------------------------------------- c Set up Jacobian. c----------------------------------------------------------- J(1,1) = x(2) * cos(x(1) * x(2)) J(1,2) = x(1) * cos(x(1) * x(2)) J(2,1) = -6.0d0 J(2,2) = 2.0d0 * x(2) c----------------------------------------------------------- c Solve linear system (J dx = res) for update c dx. Update returned in 'res' vector. c----------------------------------------------------------- call dgesv( neq, nrhs, J, neq, ipiv, res, neq, info ) if( info .eq. 0 ) then c----------------------------------------------------------- c Update solution. c----------------------------------------------------------- nrm2x = dvl2norm(x,neq) nrm2dx = dvl2norm(res,neq) do ieq = 1 , neq x(ieq) = x(ieq) - res(ieq) end do c----------------------------------------------------------- c Tracing output: note use of max to prevent c taking log10 of 0. c----------------------------------------------------------- write(0,1000) iter, x(1), x(2), & log10(max(nrm2dx,1.0d-60)), & log10(max(nrm2res,1.0d-60)) 1000 format(i2,1p,2e24.16,0p,2f8.2) c----------------------------------------------------------- c Check for convergence. c----------------------------------------------------------- if( drelabs(nrm2dx,nrm2x,1.0d-6) .le. tol ) go to 100 else write(0,*) 'newt2: dgesv failed.' stop end if end do c----------------------------------------------------------- c No-convergence exit. c----------------------------------------------------------- write(0,*) 'No convergence after ', mxiter, & ' iterations' stop c----------------------------------------------------------- c Normal exit, write input and estimated square root c to standard output. c----------------------------------------------------------- 100 continue write(0,*) write(*,*) x stop 900 continue write(0,*) 'usage: newt2 []' stop end c----------------------------------------------------------- c dvl2norm: Returns l2-norm of double precision vector. c----------------------------------------------------------- real*8 function dvl2norm(v,n) implicit none integer n real*8 v(n) integer i dvl2norm = 0.0d0 do i = 1 , n dvl2norm = dvl2norm + v(i) * v(i) end do if( n .gt. 0 ) then dvl2norm = sqrt(dvl2norm / n) end if return end c----------------------------------------------------------- c drelabs: Function useful for 'relativizing' quantity c being monitored for detection of convergence. c----------------------------------------------------------- real*8 function drelabs(dx,x,xfloor) implicit none real*8 dx, x, xfloor if( abs(x) .lt. abs(xfloor) ) then drelabs = abs(dx) else drelabs = abs(dx/x) end if return end