Skip to content

Commit d52ca03

Browse files
committed
Add example_primes.f90
1 parent 56b802f commit d52ca03

File tree

2 files changed

+98
-0
lines changed

2 files changed

+98
-0
lines changed

examples/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,6 @@ target_link_libraries(example_lmder1 minpack)
55

66
add_executable(example_lmdif1 example_lmdif1.f90)
77
target_link_libraries(example_lmdif1 minpack)
8+
9+
add_executable(example_primes example_primes.f90)
10+
target_link_libraries(example_primes minpack)

examples/example_primes.f90

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
module types
2+
implicit none
3+
private
4+
public dp
5+
6+
integer, parameter :: dp=kind(0d0)
7+
8+
end module
9+
10+
module find_fit_module
11+
12+
! This module contains a general function find_fit() for a nonlinear least
13+
! squares fitting. The function can fit any nonlinear expression to any data.
14+
15+
use minpack, only: lmdif1
16+
use types, only: dp
17+
implicit none
18+
private
19+
public find_fit
20+
21+
contains
22+
23+
subroutine find_fit(data_x, data_y, expr, pars)
24+
! Fits the (data_x, data_y) arrays with the function expr(x, pars).
25+
! The user can provide any nonlinear function 'expr' depending on any number of
26+
! parameters 'pars' and it must return the evaluated expression on the
27+
! array 'x'. The arrays 'data_x' and 'data_y' must have the same
28+
! length.
29+
real(dp), intent(in) :: data_x(:), data_y(:)
30+
interface
31+
function expr(x, pars) result(y)
32+
use types, only: dp
33+
implicit none
34+
real(dp), intent(in) :: x(:), pars(:)
35+
real(dp) :: y(size(x))
36+
end function
37+
end interface
38+
real(dp), intent(inout) :: pars(:)
39+
40+
real(dp) :: tol, fvec(size(data_x))
41+
integer :: iwa(size(pars)), info, m, n
42+
real(dp), allocatable :: wa(:)
43+
44+
tol = sqrt(epsilon(1._dp))
45+
m = size(fvec)
46+
n = size(pars)
47+
allocate(wa(m*n + 5*n + m))
48+
call lmdif1(fcn, m, n, pars, fvec, tol, info, iwa, wa, size(wa))
49+
if (info /= 1) stop "failed to converge"
50+
51+
contains
52+
53+
subroutine fcn(m, n, x, fvec, iflag)
54+
integer, intent(in) :: m, n, iflag
55+
real(dp), intent(in) :: x(n)
56+
real(dp), intent(out) :: fvec(m)
57+
! Suppress compiler warning:
58+
fvec(1) = iflag
59+
fvec = data_y - expr(data_x, x)
60+
end subroutine
61+
62+
end subroutine
63+
64+
end module
65+
66+
67+
program example_primes
68+
69+
! Find a nonlinear fit of the form a*x*log(b + c*x) to a list of primes.
70+
71+
use find_fit_module, only: find_fit
72+
use types, only: dp
73+
implicit none
74+
75+
real(dp) :: pars(3)
76+
real(dp), parameter :: y(*) = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, &
77+
37, 41, 43, 47, 53, 59, 61, 67, 71]
78+
integer :: i
79+
pars = [1._dp, 1._dp, 1._dp]
80+
call find_fit([(real(i, dp), i=1,size(y))], y, expression, pars)
81+
print *, pars
82+
83+
contains
84+
85+
function expression(x, pars) result(y)
86+
real(dp), intent(in) :: x(:), pars(:)
87+
real(dp) :: y(size(x))
88+
real(dp) :: a, b, c
89+
a = pars(1)
90+
b = pars(2)
91+
c = pars(3)
92+
y = a*x*log(b + c*x)
93+
end function
94+
95+
end program

0 commit comments

Comments
 (0)