|
| 1 | +module testmod_der1 |
| 2 | +implicit none |
| 3 | +private |
| 4 | +public fcn, dp |
| 5 | + |
| 6 | +integer, parameter :: dp=kind(0d0) |
| 7 | + |
| 8 | +contains |
| 9 | + |
| 10 | +subroutine fcn(m, n, x, fvec, fjac, ldfjac, iflag) |
| 11 | +integer, intent(in) :: m, n, ldfjac |
| 12 | +integer, intent(inout) :: iflag |
| 13 | +real(dp), intent(in) :: x(n) |
| 14 | +real(dp), intent(inout) :: fvec(m), fjac(ldfjac, n) |
| 15 | + |
| 16 | +integer :: i |
| 17 | +real(dp) :: tmp1, tmp2, tmp3, tmp4, y(15) |
| 18 | +y = [1.4D-1, 1.8D-1, 2.2D-1, 2.5D-1, 2.9D-1, 3.2D-1, 3.5D-1, 3.9D-1, & |
| 19 | + 3.7D-1, 5.8D-1, 7.3D-1, 9.6D-1, 1.34D0, 2.1D0, 4.39D0] |
| 20 | + |
| 21 | +if (iflag == 1) then |
| 22 | + do i = 1, 15 |
| 23 | + tmp1 = i |
| 24 | + tmp2 = 16 - i |
| 25 | + tmp3 = tmp1 |
| 26 | + if (i .gt. 8) tmp3 = tmp2 |
| 27 | + fvec(i) = y(i) - (x(1) + tmp1/(x(2)*tmp2 + x(3)*tmp3)) |
| 28 | + end do |
| 29 | +else |
| 30 | + do i = 1, 15 |
| 31 | + tmp1 = i |
| 32 | + tmp2 = 16 - i |
| 33 | + tmp3 = tmp1 |
| 34 | + if (i .gt. 8) tmp3 = tmp2 |
| 35 | + tmp4 = (x(2)*tmp2 + x(3)*tmp3)**2 |
| 36 | + fjac(i,1) = -1.D0 |
| 37 | + fjac(i,2) = tmp1*tmp2/tmp4 |
| 38 | + fjac(i,3) = tmp1*tmp3/tmp4 |
| 39 | + end do |
| 40 | +end if |
| 41 | +end subroutine |
| 42 | + |
| 43 | +end module |
| 44 | + |
| 45 | + |
| 46 | +program example_lmder1 |
| 47 | +use minpack_module, only: enorm, lmder1, chkder |
| 48 | +use testmod_der1, only: dp, fcn |
| 49 | +implicit none |
| 50 | + |
| 51 | +integer :: info |
| 52 | +real(dp) :: tol, x(3), fvec(15), fjac(size(fvec), size(x)) |
| 53 | +integer :: ipvt(size(x)) |
| 54 | +real(dp), allocatable :: wa(:) |
| 55 | + |
| 56 | +! The following starting values provide a rough fit. |
| 57 | +x = [1._dp, 1._dp, 1._dp] |
| 58 | + |
| 59 | +call check_deriv() |
| 60 | + |
| 61 | +! Set tol to the square root of the machine precision. Unless high precision |
| 62 | +! solutions are required, this is the recommended setting. |
| 63 | +tol = sqrt(epsilon(1._dp)) |
| 64 | + |
| 65 | +allocate(wa(5*size(x) + size(fvec))) |
| 66 | +call lmder1(fcn, size(fvec), size(x), x, fvec, fjac, size(fjac, 1), tol, & |
| 67 | + info, ipvt, wa, size(wa)) |
| 68 | +print 1000, enorm(size(fvec), fvec), info, x |
| 69 | +1000 format(5x, 'FINAL L2 NORM OF THE RESIDUALS', d15.7 // & |
| 70 | + 5x, 'EXIT PARAMETER', 16x, i10 // & |
| 71 | + 5x, 'FINAL APPROXIMATE SOLUTION' // & |
| 72 | + 5x, 3d15.7) |
| 73 | + |
| 74 | +contains |
| 75 | + |
| 76 | +subroutine check_deriv() |
| 77 | +integer :: iflag |
| 78 | +real(dp) :: xp(size(x)), fvecp(size(fvec)), err(size(fvec)) |
| 79 | +call chkder(size(fvec), size(x), x, fvec, fjac, size(fjac, 1), xp, fvecp, & |
| 80 | + 1, err) |
| 81 | +iflag = 1 |
| 82 | +call fcn(size(fvec), size(x), x, fvec, fjac, size(fjac, 1), iflag) |
| 83 | +iflag = 2 |
| 84 | +call fcn(size(fvec), size(x), x, fvec, fjac, size(fjac, 1), iflag) |
| 85 | +iflag = 1 |
| 86 | +call fcn(size(fvec), size(x), xp, fvecp, fjac, size(fjac, 1), iflag) |
| 87 | +call chkder(size(fvec), size(x), x, fvec, fjac, size(fjac, 1), xp, fvecp, & |
| 88 | + 2, err) |
| 89 | +print *, "Derivatives check (1.0 is correct, 0.0 is incorrect):" |
| 90 | +print *, err |
| 91 | +end subroutine |
| 92 | + |
| 93 | +end program |
0 commit comments