📄 lm.f90
字号:
30 iflag = 2
CALL fdjac2(fcn, m, n, x, fvec, fjac, iflag, epsfcn)
nfev = nfev + n
IF (iflag < 0) GO TO 300
! If requested, call fcn to enable printing of iterates.
IF (nprint <= 0) GO TO 40
iflag = 0
IF (MOD(iter-1,nprint) == 0) CALL fcn(m, n, x, fvec, iflag)
IF (iflag < 0) GO TO 300
! Compute the qr factorization of the jacobian.
40 CALL qrfac(m, n, fjac, .true., ipvt, wa1, wa2)
! On the first iteration and if mode is 1, scale according
! to the norms of the columns of the initial jacobian.
IF (iter /= 1) GO TO 80
IF (mode == 2) GO TO 60
DO j = 1, n
diag(j) = wa2(j)
IF (wa2(j) == zero) diag(j) = one
END DO
! On the first iteration, calculate the norm of the scaled x
! and initialize the step bound delta.
60 wa3(1:n) = diag(1:n)*x(1:n)
xnorm = enorm(n, wa3)
delta = factor*xnorm
IF (delta == zero) delta = factor
! Form (q transpose)*fvec and store the first n components in qtf.
80 wa4(1:m) = fvec(1:m)
DO j = 1, n
IF (fjac(j,j) == zero) GO TO 120
sum = DOT_PRODUCT( fjac(j:m,j), wa4(j:m) )
temp = -sum/fjac(j,j)
DO i = j, m
wa4(i) = wa4(i) + fjac(i,j)*temp
END DO
120 fjac(j,j) = wa1(j)
qtf(j) = wa4(j)
END DO
! compute the norm of the scaled gradient.
gnorm = zero
IF (fnorm == zero) GO TO 170
DO j = 1, n
l = ipvt(j)
IF (wa2(l) == zero) CYCLE
sum = zero
DO i = 1, j
sum = sum + fjac(i,j)*(qtf(i)/fnorm)
END DO
gnorm = MAX(gnorm, ABS(sum/wa2(l)))
END DO
! test for convergence of the gradient norm.
170 IF (gnorm <= gtol) info = 4
IF (info /= 0) GO TO 300
! rescale if necessary.
IF (mode == 2) GO TO 200
DO j = 1, n
diag(j) = MAX(diag(j), wa2(j))
END DO
! beginning of the inner loop.
! determine the Levenberg-Marquardt parameter.
200 CALL lmpar(n, fjac, ipvt, diag, qtf, delta, par, wa1, wa2)
! store the direction p and x + p. calculate the norm of p.
DO j = 1, n
wa1(j) = -wa1(j)
wa2(j) = x(j) + wa1(j)
wa3(j) = diag(j)*wa1(j)
END DO
pnorm = enorm(n, wa3)
! on the first iteration, adjust the initial step bound.
IF (iter == 1) delta = MIN(delta, pnorm)
! evaluate the function at x + p and calculate its norm.
iflag = 1
CALL fcn(m, n, wa2, wa4, iflag)
nfev = nfev + 1
IF (iflag < 0) GO TO 300
fnorm1 = enorm(m, wa4)
! compute the scaled actual reduction.
actred = -one
IF (p1*fnorm1 < fnorm) actred = one - (fnorm1/fnorm)**2
! Compute the scaled predicted reduction and
! the scaled directional derivative.
DO j = 1, n
wa3(j) = zero
l = ipvt(j)
temp = wa1(l)
DO i = 1, j
wa3(i) = wa3(i) + fjac(i,j)*temp
END DO
END DO
temp1 = enorm(n,wa3)/fnorm
temp2 = (SQRT(par)*pnorm)/fnorm
prered = temp1**2 + temp2**2/p5
dirder = -(temp1**2 + temp2**2)
! compute the ratio of the actual to the predicted reduction.
ratio = zero
IF (prered /= zero) ratio = actred/prered
! update the step bound.
IF (ratio <= p25) THEN
IF (actred >= zero) temp = p5
IF (actred < zero) temp = p5*dirder/(dirder + p5*actred)
IF (p1*fnorm1 >= fnorm .OR. temp < p1) temp = p1
delta = temp*MIN(delta,pnorm/p1)
par = par/temp
ELSE
IF (par /= zero .AND. ratio < p75) GO TO 260
delta = pnorm/p5
par = p5*par
END IF
! test for successful iteration.
260 IF (ratio < p0001) GO TO 290
! successful iteration. update x, fvec, and their norms.
DO j = 1, n
x(j) = wa2(j)
wa2(j) = diag(j)*x(j)
END DO
fvec(1:m) = wa4(1:m)
xnorm = enorm(n, wa2)
fnorm = fnorm1
iter = iter + 1
! tests for convergence.
290 IF (ABS(actred) <= ftol .AND. prered <= ftol .AND. p5*ratio <= one) info = 1
IF (delta <= xtol*xnorm) info = 2
IF (ABS(actred) <= ftol .AND. prered <= ftol &
.AND. p5*ratio <= one .AND. info == 2) info = 3
IF (info /= 0) GO TO 300
! tests for termination and stringent tolerances.
IF (nfev >= maxfev) info = 5
IF (ABS(actred) <= epsmch .AND. prered <= epsmch &
.AND. p5*ratio <= one) info = 6
IF (delta <= epsmch*xnorm) info = 7
IF (gnorm <= epsmch) info = 8
IF (info /= 0) GO TO 300
! end of the inner loop. repeat if iteration unsuccessful.
IF (ratio < p0001) GO TO 200
! end of the outer loop.
GO TO 30
! termination, either normal or user imposed.
300 IF (iflag < 0) info = iflag
iflag = 0
IF (nprint > 0) CALL fcn(m, n, x, fvec, iflag)
RETURN
! last card of subroutine lmdif.
END SUBROUTINE lmdif
SUBROUTINE lmder1(fcn, m, n, x, fvec, fjac, tol, info, ipvt)
! Code converted using TO_F90 by Alan Miller
! Date: 1999-12-09 Time: 12:45:54
! N.B. Arguments LDFJAC, WA & LWA have been removed.
INTEGER, INTENT(IN) :: m
INTEGER, INTENT(IN) :: n
REAL (dp), INTENT(IN OUT) :: x(:)
REAL (dp), INTENT(OUT) :: fvec(:)
REAL (dp), INTENT(IN OUT) :: fjac(:,:) ! fjac(ldfjac,n)
REAL (dp), INTENT(IN) :: tol
INTEGER, INTENT(OUT) :: info
INTEGER, INTENT(IN OUT) :: ipvt(:)
! EXTERNAL fcn
INTERFACE
SUBROUTINE fcn(m, n, x, fvec, fjac, iflag)
IMPLICIT NONE
INTEGER, PARAMETER :: dp = SELECTED_REAL_KIND(12, 60)
INTEGER, INTENT(IN) :: m, n
REAL (dp), INTENT(IN) :: x(:)
REAL (dp), INTENT(IN OUT) :: fvec(:)
REAL (dp), INTENT(OUT) :: fjac(:,:)
INTEGER, INTENT(IN OUT) :: iflag
END SUBROUTINE fcn
END INTERFACE
! **********
! subroutine lmder1
! The purpose of lmder1 is to minimize the sum of the squares of
! m nonlinear functions in n variables by a modification of the
! levenberg-marquardt algorithm. This is done by using the more
! general least-squares solver lmder. The user must provide a
! subroutine which calculates the functions and the jacobian.
! the subroutine statement is
! subroutine lmder1(fcn, m, n, x, fvec, fjac, tol, info, ipvt)
! where
! fcn is the name of the user-supplied subroutine which
! calculates the functions and the jacobian. fcn must
! be declared in an interface statement in the user
! calling program, and should be written as follows.
! subroutine fcn(m, n, x, fvec, fjac, iflag)
! integer :: m, n, ldfjac, iflag
! REAL (dp) :: x(:), fvec(:), fjac(:,:)
! ----------
! if iflag = 1 calculate the functions at x and
! return this vector in fvec. do not alter fjac.
! if iflag = 2 calculate the jacobian at x and
! return this matrix in fjac. do not alter fvec.
! ----------
! return
! end
! the value of iflag should not be changed by fcn unless
! the user wants to terminate execution of lmder1.
! in this case set iflag to a negative integer.
! m is a positive integer input variable set to the number of functions.
! n is a positive integer input variable set to the number
! of variables. n must not exceed m.
! x is an array of length n. on input x must contain
! an initial estimate of the solution vector. on output x
! contains the final estimate of the solution vector.
! fvec is an output array of length m which contains
! the functions evaluated at the output x.
! fjac is an output m by n array. the upper n by n submatrix
! of fjac contains an upper triangular matrix r with
! diagonal elements of nonincreasing magnitude such that
! t t t
! p *(jac *jac)*p = r *r,
! where p is a permutation matrix and jac is the final calculated
! Jacobian. Column j of p is column ipvt(j) (see below) of the
! identity matrix. The lower trapezoidal part of fjac contains
! information generated during the computation of r.
! ldfjac is a positive integer input variable not less than m
! which specifies the leading dimension of the array fjac.
! tol is a nonnegative input variable. termination occurs
! when the algorithm estimates either that the relative
! error in the sum of squares is at most tol or that
! the relative error between x and the solution is at most tol.
! info is an integer output variable. If the user has terminated
! execution, info is set to the (negative) value of iflag.
! See description of fcn. Otherwise, info is set as follows.
! info = 0 improper input parameters.
! info = 1 algorithm estimates that the relative error
! in the sum of squares is at most tol.
! info = 2 algorithm estimates that the relative error
! between x and the solution is at most tol.
! info = 3 conditions for info = 1 and info = 2 both hold.
! info = 4 fvec is orthogonal to the columns of the
! jacobian to machine precision.
! info = 5 number of calls to fcn with iflag = 1 has reached 100*(n+1).
! info = 6 tol is too small. No further reduction in
! the sum of squares is possible.
! info = 7 tol is too small. No further improvement in
! the approximate solution x is possible.
! ipvt is an integer output array of length n. ipvt
! defines a permutation matrix p such that jac*p = q*r,
! where jac is the final calculated jacobian, q is
! orthogonal (not stored), and r is upper triangular
! with diagonal elements of nonincreasing magnitude.
! column j of p is column ipvt(j) of the identity matrix.
! wa is a work array of length lwa.
! lwa is a positive integer input variable not less than 5*n+m.
! subprograms called
! user-supplied ...... fcn
! minpack-supplied ... lmder
! argonne national laboratory. minpack project. march 1980.
! burton s. garbow, kenneth e. hillstrom, jorge j. more
! **********
INTEGER :: maxfev, mode, nfev, njev, nprint
REAL (dp) :: ftol, gtol, xtol
REAL (dp), PARAMETER :: factor = 100._dp, zero = 0.0_dp
info = 0
! check the input parameters for errors.
IF ( n <= 0 .OR. m < n .OR. tol < zero ) GO TO 10
! call lmder.
maxfev = 100*(n + 1)
ftol = tol
xtol = tol
gtol = zero
mode = 1
nprint = 0
CALL lmder(fcn, m, n, x, fvec, fjac, ftol, xtol, gtol, maxfev, &
mode, factor, nprint, info, nfev, njev, ipvt)
IF (info == 8) info = 4
10 RETURN
! last card of subroutine lmder1.
END SUBROUTINE lmder1
SUBROUTINE lmder(fcn, m, n, x, fvec, fjac, ftol, xtol, gtol, maxfev, &
mode, factor, nprint, info, nfev, njev, ipvt)
! Code converted using TO_F90 by Alan Miller
! Date: 1999-12-09 Time: 12:45:50
! N.B. Arguments LDFJAC, DIAG, QTF, WA1, WA2, WA3 & WA4 have been removed.
INTEGER, INTENT(IN) :: m
INTEGER, INTENT(IN) :: n
REAL (dp), INTENT(IN OUT) :: x(:)
REAL (dp), INTENT(OUT) :: fvec(m)
REAL (dp), INTENT(OUT) :: fjac(:,:) ! fjac(ldfjac,n)
REAL (dp), INTENT(IN) :: ftol
REAL (dp), INTENT(IN) :: xtol
REAL (dp), INTENT(IN OUT) :: gtol
INTEGER, INTENT(IN OUT) :: maxfev
INTEGER, INTENT(IN) :: mode
REAL (dp), INTENT(IN) :: factor
INTEGER, INTENT(IN) :: nprint
INTEGER, INTENT(OUT) :: info
INTEGER, INTENT(OUT) :: nfev
INTEGER, INTENT(OUT) :: njev
INTEGER, INTENT(OUT) :: ipvt(:)
INTERFACE
SUBROUTINE fcn(m, n, x, fvec, fjac, iflag)
IMPLICIT NONE
INTEGER, PARAMETER :: dp = SELECTED_REAL_KIND(12, 60)
INTEGER, INTENT(IN) :: m, n
REAL (dp), INTENT(IN) :: x(:)
REAL (dp), INTENT(IN OUT) :: fvec(:)
REAL (dp), INTENT(OUT) :: fjac(:,:)
INTEGER, INTENT(IN OUT) :: iflag
END SUBROUTINE fcn
END INTERFACE
! **********
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -