Commit ea0bc1fe357570ea079fa56adbe6566c7028b797

Authored by daniau
1 parent 7890954c6b

git-svn-id: https://lxsd.femto-st.fr/svn/fvn@2 b657c933-2333-4658-acf2-d3c7c2708721

Showing 1 changed file with 2 additions and 1 deletions Inline Diff

1 1
module fvn 2 2 module fvn
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 3 3 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! 4 4 !
! fvn : a f95 module replacement for some imsl routines 5 5 ! fvn : a f95 module replacement for some imsl routines
! it uses lapack for linear algebra 6 6 ! it uses lapack for linear algebra
! it uses modified quadpack for integration 7 7 ! it uses modified quadpack for integration
! 8 8 !
! William Daniau 2007 9 9 ! William Daniau 2007
! william.daniau@femto-st.fr 10 10 ! william.daniau@femto-st.fr
! 11 11 !
! Routines naming scheme : 12 12 ! Routines naming scheme :
! 13 13 !
! fvn_x_name 14 14 ! fvn_x_name
! where x can be s : real 15 15 ! where x can be s : real
! d : real double precision 16 16 ! d : real double precision
! c : complex 17 17 ! c : complex
! z : double complex 18 18 ! z : double complex
! 19 19 !
! 20 20 !
! This piece of code is totally free! Do whatever you want with it. However 21 21 ! This piece of code is totally free! Do whatever you want with it. However
! if you find it usefull it would be kind to give credits ;-) 22 22 ! if you find it usefull it would be kind to give credits ;-) Nevertheless, you
23 ! may give credits to quadpack authors.
! 23 24 !
! Version 1.1 24 25 ! Version 1.1
! 25 26 !
! TO DO LIST : 26 27 ! TO DO LIST :
! + Order eigenvalues and vectors in decreasing eigenvalue's modulus order -> atm 27 28 ! + Order eigenvalues and vectors in decreasing eigenvalue's modulus order -> atm
! eigenvalues are given with no particular order. 28 29 ! eigenvalues are given with no particular order.
! + Generic interface for fvn_x_name family -> fvn_name 29 30 ! + Generic interface for fvn_x_name family -> fvn_name
! + Make some parameters optional, status for example 30 31 ! + Make some parameters optional, status for example
! + use f95 kinds "double complex" -> complex(kind=8) 31 32 ! + use f95 kinds "double complex" -> complex(kind=8)
! + unify quadpack routines 32 33 ! + unify quadpack routines
! + ... 33 34 ! + ...
! 34 35 !
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 35 36 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
36 37
implicit none 37 38 implicit none
! All quadpack routines are private to the module 38 39 ! All quadpack routines are private to the module
private :: d1mach,dqag,dqag_2d_inner,dqag_2d_outer,dqage,dqage_2d_inner, & 39 40 private :: d1mach,dqag,dqag_2d_inner,dqag_2d_outer,dqage,dqage_2d_inner, &
dqage_2d_outer,dqk15,dqk15_2d_inner,dqk15_2d_outer,dqk21,dqk21_2d_inner,dqk21_2d_outer, & 40 41 dqage_2d_outer,dqk15,dqk15_2d_inner,dqk15_2d_outer,dqk21,dqk21_2d_inner,dqk21_2d_outer, &
dqk31,dqk31_2d_inner,dqk31_2d_outer,dqk41,dqk41_2d_inner,dqk41_2d_outer, & 41 42 dqk31,dqk31_2d_inner,dqk31_2d_outer,dqk41,dqk41_2d_inner,dqk41_2d_outer, &
dqk51,dqk51_2d_inner,dqk51_2d_outer,dqk61,dqk61_2d_inner,dqk61_2d_outer,dqpsrt 42 43 dqk51,dqk51_2d_inner,dqk51_2d_outer,dqk61,dqk61_2d_inner,dqk61_2d_outer,dqpsrt
43 44
44 45
contains 45 46 contains
46 47
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 47 48 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! 48 49 !
! Matrix inversion subroutines 49 50 ! Matrix inversion subroutines
! 50 51 !
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 51 52 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
subroutine fvn_s_matinv(d,a,inva,status) 52 53 subroutine fvn_s_matinv(d,a,inva,status)
! 53 54 !
! Matrix inversion of a real matrix using BLAS and LAPACK 54 55 ! Matrix inversion of a real matrix using BLAS and LAPACK
! 55 56 !
! d (in) : matrix rank 56 57 ! d (in) : matrix rank
! a (in) : input matrix 57 58 ! a (in) : input matrix
! inva (out) : inversed matrix 58 59 ! inva (out) : inversed matrix
! status (ou) : =0 if something failed 59 60 ! status (ou) : =0 if something failed
! 60 61 !
integer, intent(in) :: d 61 62 integer, intent(in) :: d
real, intent(in) :: a(d,d) 62 63 real, intent(in) :: a(d,d)
real, intent(out) :: inva(d,d) 63 64 real, intent(out) :: inva(d,d)
integer, intent(out) :: status 64 65 integer, intent(out) :: status
65 66
integer, allocatable :: ipiv(:) 66 67 integer, allocatable :: ipiv(:)
real, allocatable :: work(:) 67 68 real, allocatable :: work(:)
real twork(1) 68 69 real twork(1)
integer :: info 69 70 integer :: info
integer :: lwork 70 71 integer :: lwork
71 72
status=1 72 73 status=1
73 74
allocate(ipiv(d)) 74 75 allocate(ipiv(d))
! copy a into inva using BLAS 75 76 ! copy a into inva using BLAS
!call scopy(d*d,a,1,inva,1) 76 77 !call scopy(d*d,a,1,inva,1)
inva(:,:)=a(:,:) 77 78 inva(:,:)=a(:,:)
! LU factorization using LAPACK 78 79 ! LU factorization using LAPACK
call sgetrf(d,d,inva,d,ipiv,info) 79 80 call sgetrf(d,d,inva,d,ipiv,info)
! if info is not equal to 0, something went wrong we exit setting status to 0 80 81 ! if info is not equal to 0, something went wrong we exit setting status to 0
if (info /= 0) then 81 82 if (info /= 0) then
status=0 82 83 status=0
deallocate(ipiv) 83 84 deallocate(ipiv)
return 84 85 return
end if 85 86 end if
! we use the query fonction of xxxtri to obtain the optimal workspace size 86 87 ! we use the query fonction of xxxtri to obtain the optimal workspace size
call sgetri(d,inva,d,ipiv,twork,-1,info) 87 88 call sgetri(d,inva,d,ipiv,twork,-1,info)
lwork=int(twork(1)) 88 89 lwork=int(twork(1))
allocate(work(lwork)) 89 90 allocate(work(lwork))
! Matrix inversion using LAPACK 90 91 ! Matrix inversion using LAPACK
call sgetri(d,inva,d,ipiv,work,lwork,info) 91 92 call sgetri(d,inva,d,ipiv,work,lwork,info)
! again if info is not equal to 0, we exit setting status to 0 92 93 ! again if info is not equal to 0, we exit setting status to 0
if (info /= 0) then 93 94 if (info /= 0) then
status=0 94 95 status=0
end if 95 96 end if
deallocate(work) 96 97 deallocate(work)
deallocate(ipiv) 97 98 deallocate(ipiv)
end subroutine 98 99 end subroutine
99 100
subroutine fvn_d_matinv(d,a,inva,status) 100 101 subroutine fvn_d_matinv(d,a,inva,status)
! 101 102 !
! Matrix inversion of a double precision matrix using BLAS and LAPACK 102 103 ! Matrix inversion of a double precision matrix using BLAS and LAPACK
! 103 104 !
! d (in) : matrix rank 104 105 ! d (in) : matrix rank
! a (in) : input matrix 105 106 ! a (in) : input matrix
! inva (out) : inversed matrix 106 107 ! inva (out) : inversed matrix
! status (ou) : =0 if something failed 107 108 ! status (ou) : =0 if something failed
! 108 109 !
integer, intent(in) :: d 109 110 integer, intent(in) :: d
double precision, intent(in) :: a(d,d) 110 111 double precision, intent(in) :: a(d,d)
double precision, intent(out) :: inva(d,d) 111 112 double precision, intent(out) :: inva(d,d)
integer, intent(out) :: status 112 113 integer, intent(out) :: status
113 114
integer, allocatable :: ipiv(:) 114 115 integer, allocatable :: ipiv(:)
double precision, allocatable :: work(:) 115 116 double precision, allocatable :: work(:)
double precision :: twork(1) 116 117 double precision :: twork(1)
integer :: info 117 118 integer :: info
integer :: lwork 118 119 integer :: lwork
119 120
status=1 120 121 status=1
121 122
allocate(ipiv(d)) 122 123 allocate(ipiv(d))
! copy a into inva using BLAS 123 124 ! copy a into inva using BLAS
!call dcopy(d*d,a,1,inva,1) 124 125 !call dcopy(d*d,a,1,inva,1)
inva(:,:)=a(:,:) 125 126 inva(:,:)=a(:,:)
! LU factorization using LAPACK 126 127 ! LU factorization using LAPACK
call dgetrf(d,d,inva,d,ipiv,info) 127 128 call dgetrf(d,d,inva,d,ipiv,info)
! if info is not equal to 0, something went wrong we exit setting status to 0 128 129 ! if info is not equal to 0, something went wrong we exit setting status to 0
if (info /= 0) then 129 130 if (info /= 0) then
status=0 130 131 status=0
deallocate(ipiv) 131 132 deallocate(ipiv)
return 132 133 return
end if 133 134 end if
! we use the query fonction of xxxtri to obtain the optimal workspace size 134 135 ! we use the query fonction of xxxtri to obtain the optimal workspace size
call dgetri(d,inva,d,ipiv,twork,-1,info) 135 136 call dgetri(d,inva,d,ipiv,twork,-1,info)
lwork=int(twork(1)) 136 137 lwork=int(twork(1))
allocate(work(lwork)) 137 138 allocate(work(lwork))
! Matrix inversion using LAPACK 138 139 ! Matrix inversion using LAPACK
call dgetri(d,inva,d,ipiv,work,lwork,info) 139 140 call dgetri(d,inva,d,ipiv,work,lwork,info)
! again if info is not equal to 0, we exit setting status to 0 140 141 ! again if info is not equal to 0, we exit setting status to 0
if (info /= 0) then 141 142 if (info /= 0) then
status=0 142 143 status=0
end if 143 144 end if
deallocate(work) 144 145 deallocate(work)
deallocate(ipiv) 145 146 deallocate(ipiv)
end subroutine 146 147 end subroutine
147 148
subroutine fvn_c_matinv(d,a,inva,status) 148 149 subroutine fvn_c_matinv(d,a,inva,status)
! 149 150 !
! Matrix inversion of a complex matrix using BLAS and LAPACK 150 151 ! Matrix inversion of a complex matrix using BLAS and LAPACK
! 151 152 !
! d (in) : matrix rank 152 153 ! d (in) : matrix rank
! a (in) : input matrix 153 154 ! a (in) : input matrix
! inva (out) : inversed matrix 154 155 ! inva (out) : inversed matrix
! status (ou) : =0 if something failed 155 156 ! status (ou) : =0 if something failed
! 156 157 !
integer, intent(in) :: d 157 158 integer, intent(in) :: d
complex, intent(in) :: a(d,d) 158 159 complex, intent(in) :: a(d,d)
complex, intent(out) :: inva(d,d) 159 160 complex, intent(out) :: inva(d,d)
integer, intent(out) :: status 160 161 integer, intent(out) :: status
161 162
integer, allocatable :: ipiv(:) 162 163 integer, allocatable :: ipiv(:)
complex, allocatable :: work(:) 163 164 complex, allocatable :: work(:)
complex :: twork(1) 164 165 complex :: twork(1)
integer :: info 165 166 integer :: info
integer :: lwork 166 167 integer :: lwork
167 168
status=1 168 169 status=1
169 170
allocate(ipiv(d)) 170 171 allocate(ipiv(d))
! copy a into inva using BLAS 171 172 ! copy a into inva using BLAS
!call ccopy(d*d,a,1,inva,1) 172 173 !call ccopy(d*d,a,1,inva,1)
inva(:,:)=a(:,:) 173 174 inva(:,:)=a(:,:)
174 175
! LU factorization using LAPACK 175 176 ! LU factorization using LAPACK
call cgetrf(d,d,inva,d,ipiv,info) 176 177 call cgetrf(d,d,inva,d,ipiv,info)
! if info is not equal to 0, something went wrong we exit setting status to 0 177 178 ! if info is not equal to 0, something went wrong we exit setting status to 0
if (info /= 0) then 178 179 if (info /= 0) then
status=0 179 180 status=0
deallocate(ipiv) 180 181 deallocate(ipiv)
return 181 182 return
end if 182 183 end if
! we use the query fonction of xxxtri to obtain the optimal workspace size 183 184 ! we use the query fonction of xxxtri to obtain the optimal workspace size
call cgetri(d,inva,d,ipiv,twork,-1,info) 184 185 call cgetri(d,inva,d,ipiv,twork,-1,info)
lwork=int(twork(1)) 185 186 lwork=int(twork(1))
allocate(work(lwork)) 186 187 allocate(work(lwork))
! Matrix inversion using LAPACK 187 188 ! Matrix inversion using LAPACK
call cgetri(d,inva,d,ipiv,work,lwork,info) 188 189 call cgetri(d,inva,d,ipiv,work,lwork,info)
! again if info is not equal to 0, we exit setting status to 0 189 190 ! again if info is not equal to 0, we exit setting status to 0
if (info /= 0) then 190 191 if (info /= 0) then
status=0 191 192 status=0
end if 192 193 end if
deallocate(work) 193 194 deallocate(work)
deallocate(ipiv) 194 195 deallocate(ipiv)
end subroutine 195 196 end subroutine
196 197
subroutine fvn_z_matinv(d,a,inva,status) 197 198 subroutine fvn_z_matinv(d,a,inva,status)
! 198 199 !
! Matrix inversion of a double complex matrix using BLAS and LAPACK 199 200 ! Matrix inversion of a double complex matrix using BLAS and LAPACK
! 200 201 !
! d (in) : matrix rank 201 202 ! d (in) : matrix rank
! a (in) : input matrix 202 203 ! a (in) : input matrix
! inva (out) : inversed matrix 203 204 ! inva (out) : inversed matrix
! status (ou) : =0 if something failed 204 205 ! status (ou) : =0 if something failed
! 205 206 !
integer, intent(in) :: d 206 207 integer, intent(in) :: d
double complex, intent(in) :: a(d,d) 207 208 double complex, intent(in) :: a(d,d)
double complex, intent(out) :: inva(d,d) 208 209 double complex, intent(out) :: inva(d,d)
integer, intent(out) :: status 209 210 integer, intent(out) :: status
210 211
integer, allocatable :: ipiv(:) 211 212 integer, allocatable :: ipiv(:)
double complex, allocatable :: work(:) 212 213 double complex, allocatable :: work(:)
double complex :: twork(1) 213 214 double complex :: twork(1)
integer :: info 214 215 integer :: info
integer :: lwork 215 216 integer :: lwork
216 217
status=1 217 218 status=1
218 219
allocate(ipiv(d)) 219 220 allocate(ipiv(d))
! copy a into inva using BLAS 220 221 ! copy a into inva using BLAS
!call zcopy(d*d,a,1,inva,1) 221 222 !call zcopy(d*d,a,1,inva,1)
inva(:,:)=a(:,:) 222 223 inva(:,:)=a(:,:)
223 224
! LU factorization using LAPACK 224 225 ! LU factorization using LAPACK
call zgetrf(d,d,inva,d,ipiv,info) 225 226 call zgetrf(d,d,inva,d,ipiv,info)
! if info is not equal to 0, something went wrong we exit setting status to 0 226 227 ! if info is not equal to 0, something went wrong we exit setting status to 0
if (info /= 0) then 227 228 if (info /= 0) then
status=0 228 229 status=0
deallocate(ipiv) 229 230 deallocate(ipiv)
return 230 231 return
end if 231 232 end if
! we use the query fonction of xxxtri to obtain the optimal workspace size 232 233 ! we use the query fonction of xxxtri to obtain the optimal workspace size
call zgetri(d,inva,d,ipiv,twork,-1,info) 233 234 call zgetri(d,inva,d,ipiv,twork,-1,info)
lwork=int(twork(1)) 234 235 lwork=int(twork(1))
allocate(work(lwork)) 235 236 allocate(work(lwork))
! Matrix inversion using LAPACK 236 237 ! Matrix inversion using LAPACK
call zgetri(d,inva,d,ipiv,work,lwork,info) 237 238 call zgetri(d,inva,d,ipiv,work,lwork,info)
! again if info is not equal to 0, we exit setting status to 0 238 239 ! again if info is not equal to 0, we exit setting status to 0
if (info /= 0) then 239 240 if (info /= 0) then
status=0 240 241 status=0
end if 241 242 end if
deallocate(work) 242 243 deallocate(work)
deallocate(ipiv) 243 244 deallocate(ipiv)
end subroutine 244 245 end subroutine
245 246
246 247
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 247 248 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! 248 249 !
! Determinants 249 250 ! Determinants
! 250 251 !
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 251 252 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
function fvn_s_det(d,a,status) 252 253 function fvn_s_det(d,a,status)
! 253 254 !
! Evaluate the determinant of a square matrix using lapack LU factorization 254 255 ! Evaluate the determinant of a square matrix using lapack LU factorization
! 255 256 !
! d (in) : matrix rank 256 257 ! d (in) : matrix rank
! a (in) : The Matrix 257 258 ! a (in) : The Matrix
! status (out) : =0 if LU factorization failed 258 259 ! status (out) : =0 if LU factorization failed
! 259 260 !
integer, intent(in) :: d 260 261 integer, intent(in) :: d
real, intent(in) :: a(d,d) 261 262 real, intent(in) :: a(d,d)
integer, intent(out) :: status 262 263 integer, intent(out) :: status
real :: fvn_s_det 263 264 real :: fvn_s_det
264 265
real, allocatable :: wc_a(:,:) 265 266 real, allocatable :: wc_a(:,:)
integer, allocatable :: ipiv(:) 266 267 integer, allocatable :: ipiv(:)
integer :: info,i 267 268 integer :: info,i
268 269
status=1 269 270 status=1
allocate(wc_a(d,d)) 270 271 allocate(wc_a(d,d))
allocate(ipiv(d)) 271 272 allocate(ipiv(d))
wc_a(:,:)=a(:,:) 272 273 wc_a(:,:)=a(:,:)
call sgetrf(d,d,wc_a,d,ipiv,info) 273 274 call sgetrf(d,d,wc_a,d,ipiv,info)
if (info/= 0) then 274 275 if (info/= 0) then
status=0 275 276 status=0
fvn_s_det=0.e0 276 277 fvn_s_det=0.e0
deallocate(ipiv) 277 278 deallocate(ipiv)
deallocate(wc_a) 278 279 deallocate(wc_a)
return 279 280 return
end if 280 281 end if
fvn_s_det=1.e0 281 282 fvn_s_det=1.e0
do i=1,d 282 283 do i=1,d
if (ipiv(i)==i) then 283 284 if (ipiv(i)==i) then
fvn_s_det=fvn_s_det*wc_a(i,i) 284 285 fvn_s_det=fvn_s_det*wc_a(i,i)
else 285 286 else
fvn_s_det=-fvn_s_det*wc_a(i,i) 286 287 fvn_s_det=-fvn_s_det*wc_a(i,i)
end if 287 288 end if
end do 288 289 end do
deallocate(ipiv) 289 290 deallocate(ipiv)
deallocate(wc_a) 290 291 deallocate(wc_a)
291 292
end function 292 293 end function
293 294
function fvn_d_det(d,a,status) 294 295 function fvn_d_det(d,a,status)
! 295 296 !
! Evaluate the determinant of a square matrix using lapack LU factorization 296 297 ! Evaluate the determinant of a square matrix using lapack LU factorization
! 297 298 !
! d (in) : matrix rank 298 299 ! d (in) : matrix rank
! a (in) : The Matrix 299 300 ! a (in) : The Matrix
! status (out) : =0 if LU factorization failed 300 301 ! status (out) : =0 if LU factorization failed
! 301 302 !
integer, intent(in) :: d 302 303 integer, intent(in) :: d
double precision, intent(in) :: a(d,d) 303 304 double precision, intent(in) :: a(d,d)
integer, intent(out) :: status 304 305 integer, intent(out) :: status
double precision :: fvn_d_det 305 306 double precision :: fvn_d_det
306 307
double precision, allocatable :: wc_a(:,:) 307 308 double precision, allocatable :: wc_a(:,:)
integer, allocatable :: ipiv(:) 308 309 integer, allocatable :: ipiv(:)
integer :: info,i 309 310 integer :: info,i
310 311
status=1 311 312 status=1
allocate(wc_a(d,d)) 312 313 allocate(wc_a(d,d))
allocate(ipiv(d)) 313 314 allocate(ipiv(d))
wc_a(:,:)=a(:,:) 314 315 wc_a(:,:)=a(:,:)
call dgetrf(d,d,wc_a,d,ipiv,info) 315 316 call dgetrf(d,d,wc_a,d,ipiv,info)
if (info/= 0) then 316 317 if (info/= 0) then
status=0 317 318 status=0
fvn_d_det=0.d0 318 319 fvn_d_det=0.d0
deallocate(ipiv) 319 320 deallocate(ipiv)
deallocate(wc_a) 320 321 deallocate(wc_a)
return 321 322 return
end if 322 323 end if
fvn_d_det=1.d0 323 324 fvn_d_det=1.d0
do i=1,d 324 325 do i=1,d
if (ipiv(i)==i) then 325 326 if (ipiv(i)==i) then
fvn_d_det=fvn_d_det*wc_a(i,i) 326 327 fvn_d_det=fvn_d_det*wc_a(i,i)
else 327 328 else
fvn_d_det=-fvn_d_det*wc_a(i,i) 328 329 fvn_d_det=-fvn_d_det*wc_a(i,i)
end if 329 330 end if
end do 330 331 end do
deallocate(ipiv) 331 332 deallocate(ipiv)
deallocate(wc_a) 332 333 deallocate(wc_a)
333 334
end function 334 335 end function
335 336
function fvn_c_det(d,a,status) ! 336 337 function fvn_c_det(d,a,status) !
! Evaluate the determinant of a square matrix using lapack LU factorization 337 338 ! Evaluate the determinant of a square matrix using lapack LU factorization
! 338 339 !
! d (in) : matrix rank 339 340 ! d (in) : matrix rank
! a (in) : The Matrix 340 341 ! a (in) : The Matrix
! status (out) : =0 if LU factorization failed 341 342 ! status (out) : =0 if LU factorization failed
! 342 343 !
integer, intent(in) :: d 343 344 integer, intent(in) :: d
complex, intent(in) :: a(d,d) 344 345 complex, intent(in) :: a(d,d)
integer, intent(out) :: status 345 346 integer, intent(out) :: status
complex :: fvn_c_det 346 347 complex :: fvn_c_det
347 348
complex, allocatable :: wc_a(:,:) 348 349 complex, allocatable :: wc_a(:,:)
integer, allocatable :: ipiv(:) 349 350 integer, allocatable :: ipiv(:)
integer :: info,i 350 351 integer :: info,i
351 352
status=1 352 353 status=1
allocate(wc_a(d,d)) 353 354 allocate(wc_a(d,d))
allocate(ipiv(d)) 354 355 allocate(ipiv(d))
wc_a(:,:)=a(:,:) 355 356 wc_a(:,:)=a(:,:)
call cgetrf(d,d,wc_a,d,ipiv,info) 356 357 call cgetrf(d,d,wc_a,d,ipiv,info)
if (info/= 0) then 357 358 if (info/= 0) then
status=0 358 359 status=0
fvn_c_det=(0.e0,0.e0) 359 360 fvn_c_det=(0.e0,0.e0)
deallocate(ipiv) 360 361 deallocate(ipiv)
deallocate(wc_a) 361 362 deallocate(wc_a)
return 362 363 return
end if 363 364 end if
fvn_c_det=(1.e0,0.e0) 364 365 fvn_c_det=(1.e0,0.e0)
do i=1,d 365 366 do i=1,d
if (ipiv(i)==i) then 366 367 if (ipiv(i)==i) then
fvn_c_det=fvn_c_det*wc_a(i,i) 367 368 fvn_c_det=fvn_c_det*wc_a(i,i)
else 368 369 else
fvn_c_det=-fvn_c_det*wc_a(i,i) 369 370 fvn_c_det=-fvn_c_det*wc_a(i,i)
end if 370 371 end if
end do 371 372 end do
deallocate(ipiv) 372 373 deallocate(ipiv)
deallocate(wc_a) 373 374 deallocate(wc_a)
374 375
end function 375 376 end function
376 377
function fvn_z_det(d,a,status) 377 378 function fvn_z_det(d,a,status)
! 378 379 !
! Evaluate the determinant of a square matrix using lapack LU factorization 379 380 ! Evaluate the determinant of a square matrix using lapack LU factorization
! 380 381 !
! d (in) : matrix rank 381 382 ! d (in) : matrix rank
! a (in) : The Matrix 382 383 ! a (in) : The Matrix
! det (out) : determinant 383 384 ! det (out) : determinant
! status (out) : =0 if LU factorization failed 384 385 ! status (out) : =0 if LU factorization failed
! 385 386 !
integer, intent(in) :: d 386 387 integer, intent(in) :: d
double complex, intent(in) :: a(d,d) 387 388 double complex, intent(in) :: a(d,d)
integer, intent(out) :: status 388 389 integer, intent(out) :: status
double complex :: fvn_z_det 389 390 double complex :: fvn_z_det
390 391
double complex, allocatable :: wc_a(:,:) 391 392 double complex, allocatable :: wc_a(:,:)
integer, allocatable :: ipiv(:) 392 393 integer, allocatable :: ipiv(:)
integer :: info,i 393 394 integer :: info,i
394 395
status=1 395 396 status=1
allocate(wc_a(d,d)) 396 397 allocate(wc_a(d,d))
allocate(ipiv(d)) 397 398 allocate(ipiv(d))
wc_a(:,:)=a(:,:) 398 399 wc_a(:,:)=a(:,:)
call zgetrf(d,d,wc_a,d,ipiv,info) 399 400 call zgetrf(d,d,wc_a,d,ipiv,info)
if (info/= 0) then 400 401 if (info/= 0) then
status=0 401 402 status=0
fvn_z_det=(0.d0,0.d0) 402 403 fvn_z_det=(0.d0,0.d0)
deallocate(ipiv) 403 404 deallocate(ipiv)
deallocate(wc_a) 404 405 deallocate(wc_a)
return 405 406 return
end if 406 407 end if
fvn_z_det=(1.d0,0.d0) 407 408 fvn_z_det=(1.d0,0.d0)
do i=1,d 408 409 do i=1,d
if (ipiv(i)==i) then 409 410 if (ipiv(i)==i) then
fvn_z_det=fvn_z_det*wc_a(i,i) 410 411 fvn_z_det=fvn_z_det*wc_a(i,i)
else 411 412 else
fvn_z_det=-fvn_z_det*wc_a(i,i) 412 413 fvn_z_det=-fvn_z_det*wc_a(i,i)
end if 413 414 end if
end do 414 415 end do
deallocate(ipiv) 415 416 deallocate(ipiv)
deallocate(wc_a) 416 417 deallocate(wc_a)
417 418
end function 418 419 end function
419 420
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 420 421 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! 421 422 !
! Condition test 422 423 ! Condition test
! 423 424 !
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 424 425 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! 1-norm 425 426 ! 1-norm
! fonction lapack slange,dlange,clange,zlange pour obtenir la 1-norm 426 427 ! fonction lapack slange,dlange,clange,zlange pour obtenir la 1-norm
! fonction lapack sgecon,dgecon,cgecon,zgecon pour calculer la rcond 427 428 ! fonction lapack sgecon,dgecon,cgecon,zgecon pour calculer la rcond
! 428 429 !
subroutine fvn_s_matcon(d,a,rcond,status) 429 430 subroutine fvn_s_matcon(d,a,rcond,status)
! Matrix condition (reciprocal of condition number) 430 431 ! Matrix condition (reciprocal of condition number)
! 431 432 !
! d (in) : matrix rank 432 433 ! d (in) : matrix rank
! a (in) : The Matrix 433 434 ! a (in) : The Matrix
! rcond (out) : guess what 434 435 ! rcond (out) : guess what
! status (out) : =0 if something went wrong 435 436 ! status (out) : =0 if something went wrong
! 436 437 !
integer, intent(in) :: d 437 438 integer, intent(in) :: d
real, intent(in) :: a(d,d) 438 439 real, intent(in) :: a(d,d)
real, intent(out) :: rcond 439 440 real, intent(out) :: rcond
integer, intent(out) :: status 440 441 integer, intent(out) :: status
441 442
real, allocatable :: work(:) 442 443 real, allocatable :: work(:)
integer, allocatable :: iwork(:) 443 444 integer, allocatable :: iwork(:)
real :: anorm 444 445 real :: anorm
real, allocatable :: wc_a(:,:) ! working copy of a 445 446 real, allocatable :: wc_a(:,:) ! working copy of a
integer :: info 446 447 integer :: info
integer, allocatable :: ipiv(:) 447 448 integer, allocatable :: ipiv(:)
448 449
real, external :: slange 449 450 real, external :: slange
450 451
451 452
status=1 452 453 status=1
453 454
anorm=slange('1',d,d,a,d,work) ! work is unallocated as it is only used when computing infinity norm 454 455 anorm=slange('1',d,d,a,d,work) ! work is unallocated as it is only used when computing infinity norm
455 456
allocate(wc_a(d,d)) 456 457 allocate(wc_a(d,d))
!call scopy(d*d,a,1,wc_a,1) 457 458 !call scopy(d*d,a,1,wc_a,1)
wc_a(:,:)=a(:,:) 458 459 wc_a(:,:)=a(:,:)
459 460
allocate(ipiv(d)) 460 461 allocate(ipiv(d))
call sgetrf(d,d,wc_a,d,ipiv,info) 461 462 call sgetrf(d,d,wc_a,d,ipiv,info)
if (info /= 0) then 462 463 if (info /= 0) then
status=0 463 464 status=0
deallocate(ipiv) 464 465 deallocate(ipiv)
deallocate(wc_a) 465 466 deallocate(wc_a)
return 466 467 return
end if 467 468 end if
allocate(work(4*d)) 468 469 allocate(work(4*d))
allocate(iwork(d)) 469 470 allocate(iwork(d))
call sgecon('1',d,wc_a,d,anorm,rcond,work,iwork,info) 470 471 call sgecon('1',d,wc_a,d,anorm,rcond,work,iwork,info)
if (info /= 0) then 471 472 if (info /= 0) then
status=0 472 473 status=0
end if 473 474 end if
deallocate(iwork) 474 475 deallocate(iwork)
deallocate(work) 475 476 deallocate(work)
deallocate(ipiv) 476 477 deallocate(ipiv)
deallocate(wc_a) 477 478 deallocate(wc_a)
478 479
end subroutine 479 480 end subroutine
480 481
subroutine fvn_d_matcon(d,a,rcond,status) 481 482 subroutine fvn_d_matcon(d,a,rcond,status)
! Matrix condition (reciprocal of condition number) 482 483 ! Matrix condition (reciprocal of condition number)
! 483 484 !
! d (in) : matrix rank 484 485 ! d (in) : matrix rank
! a (in) : The Matrix 485 486 ! a (in) : The Matrix
! rcond (out) : guess what 486 487 ! rcond (out) : guess what
! status (out) : =0 if something went wrong 487 488 ! status (out) : =0 if something went wrong
! 488 489 !
integer, intent(in) :: d 489 490 integer, intent(in) :: d
double precision, intent(in) :: a(d,d) 490 491 double precision, intent(in) :: a(d,d)
double precision, intent(out) :: rcond 491 492 double precision, intent(out) :: rcond
integer, intent(out) :: status 492 493 integer, intent(out) :: status
493 494
double precision, allocatable :: work(:) 494 495 double precision, allocatable :: work(:)
integer, allocatable :: iwork(:) 495 496 integer, allocatable :: iwork(:)
double precision :: anorm 496 497 double precision :: anorm
double precision, allocatable :: wc_a(:,:) ! working copy of a 497 498 double precision, allocatable :: wc_a(:,:) ! working copy of a
integer :: info 498 499 integer :: info
integer, allocatable :: ipiv(:) 499 500 integer, allocatable :: ipiv(:)
500 501
double precision, external :: dlange 501 502 double precision, external :: dlange
502 503
503 504
status=1 504 505 status=1
505 506
anorm=dlange('1',d,d,a,d,work) ! work is unallocated as it is only used when computing infinity norm 506 507 anorm=dlange('1',d,d,a,d,work) ! work is unallocated as it is only used when computing infinity norm
507 508
allocate(wc_a(d,d)) 508 509 allocate(wc_a(d,d))
!call dcopy(d*d,a,1,wc_a,1) 509 510 !call dcopy(d*d,a,1,wc_a,1)
wc_a(:,:)=a(:,:) 510 511 wc_a(:,:)=a(:,:)
511 512
allocate(ipiv(d)) 512 513 allocate(ipiv(d))
call dgetrf(d,d,wc_a,d,ipiv,info) 513 514 call dgetrf(d,d,wc_a,d,ipiv,info)
if (info /= 0) then 514 515 if (info /= 0) then
status=0 515 516 status=0
deallocate(ipiv) 516 517 deallocate(ipiv)
deallocate(wc_a) 517 518 deallocate(wc_a)
return 518 519 return
end if 519 520 end if
520 521
allocate(work(4*d)) 521 522 allocate(work(4*d))
allocate(iwork(d)) 522 523 allocate(iwork(d))
call dgecon('1',d,wc_a,d,anorm,rcond,work,iwork,info) 523 524 call dgecon('1',d,wc_a,d,anorm,rcond,work,iwork,info)
if (info /= 0) then 524 525 if (info /= 0) then
status=0 525 526 status=0
end if 526 527 end if
deallocate(iwork) 527 528 deallocate(iwork)
deallocate(work) 528 529 deallocate(work)
deallocate(ipiv) 529 530 deallocate(ipiv)
deallocate(wc_a) 530 531 deallocate(wc_a)
531 532
end subroutine 532 533 end subroutine
533 534
subroutine fvn_c_matcon(d,a,rcond,status) 534 535 subroutine fvn_c_matcon(d,a,rcond,status)
! Matrix condition (reciprocal of condition number) 535 536 ! Matrix condition (reciprocal of condition number)
! 536 537 !
! d (in) : matrix rank 537 538 ! d (in) : matrix rank
! a (in) : The Matrix 538 539 ! a (in) : The Matrix
! rcond (out) : guess what 539 540 ! rcond (out) : guess what
! status (out) : =0 if something went wrong 540 541 ! status (out) : =0 if something went wrong
! 541 542 !
integer, intent(in) :: d 542 543 integer, intent(in) :: d
complex, intent(in) :: a(d,d) 543 544 complex, intent(in) :: a(d,d)
real, intent(out) :: rcond 544 545 real, intent(out) :: rcond
integer, intent(out) :: status 545 546 integer, intent(out) :: status
546 547
real, allocatable :: rwork(:) 547 548 real, allocatable :: rwork(:)
complex, allocatable :: work(:) 548 549 complex, allocatable :: work(:)
integer, allocatable :: iwork(:) 549 550 integer, allocatable :: iwork(:)
real :: anorm 550 551 real :: anorm
complex, allocatable :: wc_a(:,:) ! working copy of a 551 552 complex, allocatable :: wc_a(:,:) ! working copy of a
integer :: info 552 553 integer :: info
integer, allocatable :: ipiv(:) 553 554 integer, allocatable :: ipiv(:)
554 555
real, external :: clange 555 556 real, external :: clange
556 557
557 558
status=1 558 559 status=1
559 560
anorm=clange('1',d,d,a,d,rwork) ! rwork is unallocated as it is only used when computing infinity norm 560 561 anorm=clange('1',d,d,a,d,rwork) ! rwork is unallocated as it is only used when computing infinity norm
561 562
allocate(wc_a(d,d)) 562 563 allocate(wc_a(d,d))
!call ccopy(d*d,a,1,wc_a,1) 563 564 !call ccopy(d*d,a,1,wc_a,1)
wc_a(:,:)=a(:,:) 564 565 wc_a(:,:)=a(:,:)
565 566
allocate(ipiv(d)) 566 567 allocate(ipiv(d))
call cgetrf(d,d,wc_a,d,ipiv,info) 567 568 call cgetrf(d,d,wc_a,d,ipiv,info)
if (info /= 0) then 568 569 if (info /= 0) then
status=0 569 570 status=0
deallocate(ipiv) 570 571 deallocate(ipiv)
deallocate(wc_a) 571 572 deallocate(wc_a)
return 572 573 return
end if 573 574 end if
allocate(work(2*d)) 574 575 allocate(work(2*d))
allocate(rwork(2*d)) 575 576 allocate(rwork(2*d))
call cgecon('1',d,wc_a,d,anorm,rcond,work,rwork,info) 576 577 call cgecon('1',d,wc_a,d,anorm,rcond,work,rwork,info)
if (info /= 0) then 577 578 if (info /= 0) then
status=0 578 579 status=0
end if 579 580 end if
deallocate(rwork) 580 581 deallocate(rwork)
deallocate(work) 581 582 deallocate(work)
deallocate(ipiv) 582 583 deallocate(ipiv)
deallocate(wc_a) 583 584 deallocate(wc_a)
end subroutine 584 585 end subroutine
585 586
subroutine fvn_z_matcon(d,a,rcond,status) 586 587 subroutine fvn_z_matcon(d,a,rcond,status)
! Matrix condition (reciprocal of condition number) 587 588 ! Matrix condition (reciprocal of condition number)
! 588 589 !
! d (in) : matrix rank 589 590 ! d (in) : matrix rank
! a (in) : The Matrix 590 591 ! a (in) : The Matrix
! rcond (out) : guess what 591 592 ! rcond (out) : guess what
! status (out) : =0 if something went wrong 592 593 ! status (out) : =0 if something went wrong
! 593 594 !
integer, intent(in) :: d 594 595 integer, intent(in) :: d
double complex, intent(in) :: a(d,d) 595 596 double complex, intent(in) :: a(d,d)
double precision, intent(out) :: rcond 596 597 double precision, intent(out) :: rcond
integer, intent(out) :: status 597 598 integer, intent(out) :: status
598 599
double complex, allocatable :: work(:) 599 600 double complex, allocatable :: work(:)
double precision, allocatable :: rwork(:) 600 601 double precision, allocatable :: rwork(:)
double precision :: anorm 601 602 double precision :: anorm
double complex, allocatable :: wc_a(:,:) ! working copy of a 602 603 double complex, allocatable :: wc_a(:,:) ! working copy of a
integer :: info 603 604 integer :: info
integer, allocatable :: ipiv(:) 604 605 integer, allocatable :: ipiv(:)
605 606
double precision, external :: zlange 606 607 double precision, external :: zlange
607 608
608 609
status=1 609 610 status=1
610 611
anorm=zlange('1',d,d,a,d,rwork) ! rwork is unallocated as it is only used when computing infinity norm 611 612 anorm=zlange('1',d,d,a,d,rwork) ! rwork is unallocated as it is only used when computing infinity norm
612 613
allocate(wc_a(d,d)) 613 614 allocate(wc_a(d,d))
!call zcopy(d*d,a,1,wc_a,1) 614 615 !call zcopy(d*d,a,1,wc_a,1)
wc_a(:,:)=a(:,:) 615 616 wc_a(:,:)=a(:,:)
616 617
allocate(ipiv(d)) 617 618 allocate(ipiv(d))
call zgetrf(d,d,wc_a,d,ipiv,info) 618 619 call zgetrf(d,d,wc_a,d,ipiv,info)
if (info /= 0) then 619 620 if (info /= 0) then
status=0 620 621 status=0
deallocate(ipiv) 621 622 deallocate(ipiv)
deallocate(wc_a) 622 623 deallocate(wc_a)
return 623 624 return
end if 624 625 end if
625 626
allocate(work(2*d)) 626 627 allocate(work(2*d))
allocate(rwork(2*d)) 627 628 allocate(rwork(2*d))
call zgecon('1',d,wc_a,d,anorm,rcond,work,rwork,info) 628 629 call zgecon('1',d,wc_a,d,anorm,rcond,work,rwork,info)
if (info /= 0) then 629 630 if (info /= 0) then
status=0 630 631 status=0
end if 631 632 end if
deallocate(rwork) 632 633 deallocate(rwork)
deallocate(work) 633 634 deallocate(work)
deallocate(ipiv) 634 635 deallocate(ipiv)
deallocate(wc_a) 635 636 deallocate(wc_a)
end subroutine 636 637 end subroutine
637 638
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 638 639 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! 639 640 !
! Valeurs propres/ Vecteurs propre 640 641 ! Valeurs propres/ Vecteurs propre
! 641 642 !
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 642 643 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
643 644
subroutine fvn_s_matev(d,a,evala,eveca,status) 644 645 subroutine fvn_s_matev(d,a,evala,eveca,status)
! 645 646 !
! integer d (in) : matrice rank 646 647 ! integer d (in) : matrice rank
! real a(d,d) (in) : The Matrix 647 648 ! real a(d,d) (in) : The Matrix
! complex evala(d) (out) : eigenvalues 648 649 ! complex evala(d) (out) : eigenvalues
! complex eveca(d,d) (out) : eveca(:,j) = jth eigenvector 649 650 ! complex eveca(d,d) (out) : eveca(:,j) = jth eigenvector
! integer (out) : status =0 if something went wrong 650 651 ! integer (out) : status =0 if something went wrong
! 651 652 !
! interfacing Lapack routine SGEEV 652 653 ! interfacing Lapack routine SGEEV
653 654
integer, intent(in) :: d 654 655 integer, intent(in) :: d
real, intent(in) :: a(d,d) 655 656 real, intent(in) :: a(d,d)
complex, intent(out) :: evala(d) 656 657 complex, intent(out) :: evala(d)
complex, intent(out) :: eveca(d,d) 657 658 complex, intent(out) :: eveca(d,d)
integer, intent(out) :: status 658 659 integer, intent(out) :: status
659 660
real, allocatable :: wc_a(:,:) ! a working copy of a 660 661 real, allocatable :: wc_a(:,:) ! a working copy of a
integer :: info 661 662 integer :: info
integer :: lwork 662 663 integer :: lwork
real, allocatable :: wr(:),wi(:) 663 664 real, allocatable :: wr(:),wi(:)
real :: vl ! unused but necessary for the call 664 665 real :: vl ! unused but necessary for the call
real, allocatable :: vr(:,:) 665 666 real, allocatable :: vr(:,:)
real, allocatable :: work(:) 666 667 real, allocatable :: work(:)
real :: twork(1) 667 668 real :: twork(1)
integer i 668 669 integer i
integer j 669 670 integer j
670 671
! making a working copy of a 671 672 ! making a working copy of a
allocate(wc_a(d,d)) 672 673 allocate(wc_a(d,d))
!call scopy(d*d,a,1,wc_a,1) 673 674 !call scopy(d*d,a,1,wc_a,1)
wc_a(:,:)=a(:,:) 674 675 wc_a(:,:)=a(:,:)
675 676
allocate(wr(d)) 676 677 allocate(wr(d))
allocate(wi(d)) 677 678 allocate(wi(d))
allocate(vr(d,d)) 678 679 allocate(vr(d,d))
! query optimal work size 679 680 ! query optimal work size
call sgeev('N','V',d,wc_a,d,wr,wi,vl,1,vr,d,twork,-1,info) 680 681 call sgeev('N','V',d,wc_a,d,wr,wi,vl,1,vr,d,twork,-1,info)
lwork=int(twork(1)) 681 682 lwork=int(twork(1))
allocate(work(lwork)) 682 683 allocate(work(lwork))
call sgeev('N','V',d,wc_a,d,wr,wi,vl,1,vr,d,work,lwork,info) 683 684 call sgeev('N','V',d,wc_a,d,wr,wi,vl,1,vr,d,work,lwork,info)
684 685
if (info /= 0) then 685 686 if (info /= 0) then
status=0 686 687 status=0
deallocate(work) 687 688 deallocate(work)
deallocate(vr) 688 689 deallocate(vr)
deallocate(wi) 689 690 deallocate(wi)
deallocate(wr) 690 691 deallocate(wr)
deallocate(wc_a) 691 692 deallocate(wc_a)
return 692 693 return
end if 693 694 end if
694 695
! now fill in the results 695 696 ! now fill in the results
i=1 696 697 i=1
do while(i<=d) 697 698 do while(i<=d)
evala(i)=cmplx(wr(i),wi(i)) 698 699 evala(i)=cmplx(wr(i),wi(i))
if (wi(i) == 0.) then ! eigenvalue is real 699 700 if (wi(i) == 0.) then ! eigenvalue is real
eveca(:,i)=cmplx(vr(:,i),0.) 700 701 eveca(:,i)=cmplx(vr(:,i),0.)
else ! eigenvalue is complex 701 702 else ! eigenvalue is complex
evala(i+1)=cmplx(wr(i+1),wi(i+1)) 702 703 evala(i+1)=cmplx(wr(i+1),wi(i+1))
eveca(:,i)=cmplx(vr(:,i),vr(:,i+1)) 703 704 eveca(:,i)=cmplx(vr(:,i),vr(:,i+1))
eveca(:,i+1)=cmplx(vr(:,i),-vr(:,i+1)) 704 705 eveca(:,i+1)=cmplx(vr(:,i),-vr(:,i+1))
i=i+1 705 706 i=i+1
end if 706 707 end if
i=i+1 707 708 i=i+1
enddo 708 709 enddo
deallocate(work) 709 710 deallocate(work)
deallocate(vr) 710 711 deallocate(vr)
deallocate(wi) 711 712 deallocate(wi)
deallocate(wr) 712 713 deallocate(wr)
deallocate(wc_a) 713 714 deallocate(wc_a)
714 715
end subroutine 715 716 end subroutine
716 717
subroutine fvn_d_matev(d,a,evala,eveca,status) 717 718 subroutine fvn_d_matev(d,a,evala,eveca,status)
! 718 719 !
! integer d (in) : matrice rank 719 720 ! integer d (in) : matrice rank
! double precision a(d,d) (in) : The Matrix 720 721 ! double precision a(d,d) (in) : The Matrix
! double complex evala(d) (out) : eigenvalues 721 722 ! double complex evala(d) (out) : eigenvalues
! double complex eveca(d,d) (out) : eveca(:,j) = jth eigenvector 722 723 ! double complex eveca(d,d) (out) : eveca(:,j) = jth eigenvector
! integer (out) : status =0 if something went wrong 723 724 ! integer (out) : status =0 if something went wrong
! 724 725 !
! interfacing Lapack routine DGEEV 725 726 ! interfacing Lapack routine DGEEV
integer, intent(in) :: d 726 727 integer, intent(in) :: d
double precision, intent(in) :: a(d,d) 727 728 double precision, intent(in) :: a(d,d)
double complex, intent(out) :: evala(d) 728 729 double complex, intent(out) :: evala(d)
double complex, intent(out) :: eveca(d,d) 729 730 double complex, intent(out) :: eveca(d,d)
integer, intent(out) :: status 730 731 integer, intent(out) :: status
731 732
double precision, allocatable :: wc_a(:,:) ! a working copy of a 732 733 double precision, allocatable :: wc_a(:,:) ! a working copy of a
integer :: info 733 734 integer :: info
integer :: lwork 734 735 integer :: lwork
double precision, allocatable :: wr(:),wi(:) 735 736 double precision, allocatable :: wr(:),wi(:)
double precision :: vl ! unused but necessary for the call 736 737 double precision :: vl ! unused but necessary for the call
double precision, allocatable :: vr(:,:) 737 738 double precision, allocatable :: vr(:,:)
double precision, allocatable :: work(:) 738 739 double precision, allocatable :: work(:)
double precision :: twork(1) 739 740 double precision :: twork(1)
integer i 740 741 integer i
integer j 741 742 integer j
742 743
! making a working copy of a 743 744 ! making a working copy of a
allocate(wc_a(d,d)) 744 745 allocate(wc_a(d,d))
!call dcopy(d*d,a,1,wc_a,1) 745 746 !call dcopy(d*d,a,1,wc_a,1)
wc_a(:,:)=a(:,:) 746 747 wc_a(:,:)=a(:,:)
747 748
allocate(wr(d)) 748 749 allocate(wr(d))
allocate(wi(d)) 749 750 allocate(wi(d))
allocate(vr(d,d)) 750 751 allocate(vr(d,d))
! query optimal work size 751 752 ! query optimal work size
call dgeev('N','V',d,wc_a,d,wr,wi,vl,1,vr,d,twork,-1,info) 752 753 call dgeev('N','V',d,wc_a,d,wr,wi,vl,1,vr,d,twork,-1,info)
lwork=int(twork(1)) 753 754 lwork=int(twork(1))
allocate(work(lwork)) 754 755 allocate(work(lwork))
call dgeev('N','V',d,wc_a,d,wr,wi,vl,1,vr,d,work,lwork,info) 755 756 call dgeev('N','V',d,wc_a,d,wr,wi,vl,1,vr,d,work,lwork,info)
756 757
if (info /= 0) then 757 758 if (info /= 0) then
status=0 758 759 status=0
deallocate(work) 759 760 deallocate(work)
deallocate(vr) 760 761 deallocate(vr)
deallocate(wi) 761 762 deallocate(wi)
deallocate(wr) 762 763 deallocate(wr)
deallocate(wc_a) 763 764 deallocate(wc_a)
return 764 765 return
end if 765 766 end if
766 767
! now fill in the results 767 768 ! now fill in the results
i=1 768 769 i=1
do while(i<=d) 769 770 do while(i<=d)
evala(i)=dcmplx(wr(i),wi(i)) 770 771 evala(i)=dcmplx(wr(i),wi(i))
if (wi(i) == 0.) then ! eigenvalue is real 771 772 if (wi(i) == 0.) then ! eigenvalue is real
eveca(:,i)=dcmplx(vr(:,i),0.) 772 773 eveca(:,i)=dcmplx(vr(:,i),0.)
else ! eigenvalue is complex 773 774 else ! eigenvalue is complex
evala(i+1)=dcmplx(wr(i+1),wi(i+1)) 774 775 evala(i+1)=dcmplx(wr(i+1),wi(i+1))
eveca(:,i)=dcmplx(vr(:,i),vr(:,i+1)) 775 776 eveca(:,i)=dcmplx(vr(:,i),vr(:,i+1))
eveca(:,i+1)=dcmplx(vr(:,i),-vr(:,i+1)) 776 777 eveca(:,i+1)=dcmplx(vr(:,i),-vr(:,i+1))
i=i+1 777 778 i=i+1
end if 778 779 end if
i=i+1 779 780 i=i+1
enddo 780 781 enddo
781 782
deallocate(work) 782 783 deallocate(work)
deallocate(vr) 783 784 deallocate(vr)
deallocate(wi) 784 785 deallocate(wi)
deallocate(wr) 785 786 deallocate(wr)
deallocate(wc_a) 786 787 deallocate(wc_a)
787 788
end subroutine 788 789 end subroutine
789 790
subroutine fvn_c_matev(d,a,evala,eveca,status) 790 791 subroutine fvn_c_matev(d,a,evala,eveca,status)
! 791 792 !
! integer d (in) : matrice rank 792 793 ! integer d (in) : matrice rank
! complex a(d,d) (in) : The Matrix 793 794 ! complex a(d,d) (in) : The Matrix
! complex evala(d) (out) : eigenvalues 794 795 ! complex evala(d) (out) : eigenvalues
! complex eveca(d,d) (out) : eveca(:,j) = jth eigenvector 795 796 ! complex eveca(d,d) (out) : eveca(:,j) = jth eigenvector
! integer (out) : status =0 if something went wrong 796 797 ! integer (out) : status =0 if something went wrong
! 797 798 !
! interfacing Lapack routine CGEEV 798 799 ! interfacing Lapack routine CGEEV
799 800
integer, intent(in) :: d 800 801 integer, intent(in) :: d
complex, intent(in) :: a(d,d) 801 802 complex, intent(in) :: a(d,d)
complex, intent(out) :: evala(d) 802 803 complex, intent(out) :: evala(d)
complex, intent(out) :: eveca(d,d) 803 804 complex, intent(out) :: eveca(d,d)
integer, intent(out) :: status 804 805 integer, intent(out) :: status
805 806
complex, allocatable :: wc_a(:,:) ! a working copy of a 806 807 complex, allocatable :: wc_a(:,:) ! a working copy of a
integer :: info 807 808 integer :: info
integer :: lwork 808 809 integer :: lwork
complex, allocatable :: work(:) 809 810 complex, allocatable :: work(:)
complex :: twork(1) 810 811 complex :: twork(1)
real, allocatable :: rwork(:) 811 812 real, allocatable :: rwork(:)
complex :: vl ! unused but necessary for the call 812 813 complex :: vl ! unused but necessary for the call
813 814
status=1 814 815 status=1
815 816
! making a working copy of a 816 817 ! making a working copy of a
allocate(wc_a(d,d)) 817 818 allocate(wc_a(d,d))
!call ccopy(d*d,a,1,wc_a,1) 818 819 !call ccopy(d*d,a,1,wc_a,1)
wc_a(:,:)=a(:,:) 819 820 wc_a(:,:)=a(:,:)
820 821
821 822
! query optimal work size 822 823 ! query optimal work size
call cgeev('N','V',d,wc_a,d,evala,vl,1,eveca,d,twork,-1,rwork,info) 823 824 call cgeev('N','V',d,wc_a,d,evala,vl,1,eveca,d,twork,-1,rwork,info)
lwork=int(twork(1)) 824 825 lwork=int(twork(1))
allocate(work(lwork)) 825 826 allocate(work(lwork))
allocate(rwork(2*d)) 826 827 allocate(rwork(2*d))
call cgeev('N','V',d,wc_a,d,evala,vl,1,eveca,d,work,lwork,rwork,info) 827 828 call cgeev('N','V',d,wc_a,d,evala,vl,1,eveca,d,work,lwork,rwork,info)
828 829
if (info /= 0) then 829 830 if (info /= 0) then
status=0 830 831 status=0
end if 831 832 end if
deallocate(rwork) 832 833 deallocate(rwork)
deallocate(work) 833 834 deallocate(work)
deallocate(wc_a) 834 835 deallocate(wc_a)
835 836
end subroutine 836 837 end subroutine
837 838
subroutine fvn_z_matev(d,a,evala,eveca,status) 838 839 subroutine fvn_z_matev(d,a,evala,eveca,status)
! 839 840 !
! integer d (in) : matrice rank 840 841 ! integer d (in) : matrice rank
! double complex a(d,d) (in) : The Matrix 841 842 ! double complex a(d,d) (in) : The Matrix
! double complex evala(d) (out) : eigenvalues 842 843 ! double complex evala(d) (out) : eigenvalues
! double complex eveca(d,d) (out) : eveca(:,j) = jth eigenvector 843 844 ! double complex eveca(d,d) (out) : eveca(:,j) = jth eigenvector
! integer (out) : status =0 if something went wrong 844 845 ! integer (out) : status =0 if something went wrong
! 845 846 !
! interfacing Lapack routine ZGEEV 846 847 ! interfacing Lapack routine ZGEEV
847 848
integer, intent(in) :: d 848 849 integer, intent(in) :: d
double complex, intent(in) :: a(d,d) 849 850 double complex, intent(in) :: a(d,d)
double complex, intent(out) :: evala(d) 850 851 double complex, intent(out) :: evala(d)
double complex, intent(out) :: eveca(d,d) 851 852 double complex, intent(out) :: eveca(d,d)
integer, intent(out) :: status 852 853 integer, intent(out) :: status
853 854
double complex, allocatable :: wc_a(:,:) ! a working copy of a 854 855 double complex, allocatable :: wc_a(:,:) ! a working copy of a
integer :: info 855 856 integer :: info
integer :: lwork 856 857 integer :: lwork
double complex, allocatable :: work(:) 857 858 double complex, allocatable :: work(:)
double complex :: twork(1) 858 859 double complex :: twork(1)
double precision, allocatable :: rwork(:) 859 860 double precision, allocatable :: rwork(:)
double complex :: vl ! unused but necessary for the call 860 861 double complex :: vl ! unused but necessary for the call
861 862
status=1 862 863 status=1
863 864
! making a working copy of a 864 865 ! making a working copy of a
allocate(wc_a(d,d)) 865 866 allocate(wc_a(d,d))
!call zcopy(d*d,a,1,wc_a,1) 866 867 !call zcopy(d*d,a,1,wc_a,1)
wc_a(:,:)=a(:,:) 867 868 wc_a(:,:)=a(:,:)
868 869
! query optimal work size 869 870 ! query optimal work size
call zgeev('N','V',d,wc_a,d,evala,vl,1,eveca,d,twork,-1,rwork,info) 870 871 call zgeev('N','V',d,wc_a,d,evala,vl,1,eveca,d,twork,-1,rwork,info)
lwork=int(twork(1)) 871 872 lwork=int(twork(1))
allocate(work(lwork)) 872 873 allocate(work(lwork))
allocate(rwork(2*d)) 873 874 allocate(rwork(2*d))
call zgeev('N','V',d,wc_a,d,evala,vl,1,eveca,d,work,lwork,rwork,info) 874 875 call zgeev('N','V',d,wc_a,d,evala,vl,1,eveca,d,work,lwork,rwork,info)
875 876
if (info /= 0) then 876 877 if (info /= 0) then
status=0 877 878 status=0
end if 878 879 end if
deallocate(rwork) 879 880 deallocate(rwork)
deallocate(work) 880 881 deallocate(work)
deallocate(wc_a) 881 882 deallocate(wc_a)
882 883
end subroutine 883 884 end subroutine
884 885
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 885 886 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! 886 887 !
! Akima spline interpolation and spline evaluation 887 888 ! Akima spline interpolation and spline evaluation
! 888 889 !
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 889 890 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
890 891
! Single precision 891 892 ! Single precision
subroutine fvn_s_akima(n,x,y,br,co) 892 893 subroutine fvn_s_akima(n,x,y,br,co)
implicit none 893 894 implicit none
integer, intent(in) :: n 894 895 integer, intent(in) :: n
real, intent(in) :: x(n) 895 896 real, intent(in) :: x(n)
real, intent(in) :: y(n) 896 897 real, intent(in) :: y(n)
real, intent(out) :: br(n) 897 898 real, intent(out) :: br(n)
real, intent(out) :: co(4,n) 898 899 real, intent(out) :: co(4,n)
899 900
real, allocatable :: var(:),z(:) 900 901 real, allocatable :: var(:),z(:)
real :: wi_1,wi 901 902 real :: wi_1,wi
integer :: i 902 903 integer :: i
real :: dx,a,b 903 904 real :: dx,a,b
904 905
! br is just a copy of x 905 906 ! br is just a copy of x
br(:)=x(:) 906 907 br(:)=x(:)
907 908
allocate(var(n)) 908 909 allocate(var(n))
allocate(z(n)) 909 910 allocate(z(n))
! evaluate the variations 910 911 ! evaluate the variations
do i=1, n-1 911 912 do i=1, n-1
var(i+2)=(y(i+1)-y(i))/(x(i+1)-x(i)) 912 913 var(i+2)=(y(i+1)-y(i))/(x(i+1)-x(i))
end do 913 914 end do
var(n+2)=2.e0*var(n+1)-var(n) 914 915 var(n+2)=2.e0*var(n+1)-var(n)
var(n+3)=2.e0*var(n+2)-var(n+1) 915 916 var(n+3)=2.e0*var(n+2)-var(n+1)
var(2)=2.e0*var(3)-var(4) 916 917 var(2)=2.e0*var(3)-var(4)
var(1)=2.e0*var(2)-var(3) 917 918 var(1)=2.e0*var(2)-var(3)
918 919
do i = 1, n 919 920 do i = 1, n
wi_1=abs(var(i+3)-var(i+2)) 920 921 wi_1=abs(var(i+3)-var(i+2))
wi=abs(var(i+1)-var(i)) 921 922 wi=abs(var(i+1)-var(i))
if ((wi_1+wi).eq.0.e0) then 922 923 if ((wi_1+wi).eq.0.e0) then
z(i)=(var(i+2)+var(i+1))/2.e0 923 924 z(i)=(var(i+2)+var(i+1))/2.e0
else 924 925 else
z(i)=(wi_1*var(i+1)+wi*var(i+2))/(wi_1+wi) 925 926 z(i)=(wi_1*var(i+1)+wi*var(i+2))/(wi_1+wi)
end if 926 927 end if
end do 927 928 end do
928 929
do i=1, n-1 929 930 do i=1, n-1
dx=x(i+1)-x(i) 930 931 dx=x(i+1)-x(i)
a=(z(i+1)-z(i))*dx ! coeff intermediaires pour calcul wd 931 932 a=(z(i+1)-z(i))*dx ! coeff intermediaires pour calcul wd
b=y(i+1)-y(i)-z(i)*dx ! coeff intermediaires pour calcul wd 932 933 b=y(i+1)-y(i)-z(i)*dx ! coeff intermediaires pour calcul wd
co(1,i)=y(i) 933 934 co(1,i)=y(i)
co(2,i)=z(i) 934 935 co(2,i)=z(i)
!co(3,i)=-(a-3.*b)/dx**2 ! mรฉthode wd 935 936 !co(3,i)=-(a-3.*b)/dx**2 ! mรฉthode wd
!co(4,i)=(a-2.*b)/dx**3 ! mรฉthode wd 936 937 !co(4,i)=(a-2.*b)/dx**3 ! mรฉthode wd
co(3,i)=(3.e0*var(i+2)-2.e0*z(i)-z(i+1))/dx ! mรฉthode JP Moreau 937 938 co(3,i)=(3.e0*var(i+2)-2.e0*z(i)-z(i+1))/dx ! mรฉthode JP Moreau
co(4,i)=(z(i)+z(i+1)-2.e0*var(i+2))/dx**2 ! 938 939 co(4,i)=(z(i)+z(i+1)-2.e0*var(i+2))/dx**2 !
! les coefficients donnรฉs par imsl sont co(3,i)*2 et co(4,i)*6 939 940 ! les coefficients donnรฉs par imsl sont co(3,i)*2 et co(4,i)*6
! etrangement la fonction csval corrige et donne la bonne valeur ... 940 941 ! etrangement la fonction csval corrige et donne la bonne valeur ...
end do 941 942 end do
co(1,n)=y(n) 942 943 co(1,n)=y(n)
co(2,n)=z(n) 943 944 co(2,n)=z(n)
co(3,n)=0.e0 944 945 co(3,n)=0.e0
co(4,n)=0.e0 945 946 co(4,n)=0.e0
946 947
deallocate(z) 947 948 deallocate(z)
deallocate(var) 948 949 deallocate(var)
949 950
end subroutine 950 951 end subroutine
951 952
! Double precision 952 953 ! Double precision
subroutine fvn_d_akima(n,x,y,br,co) 953 954 subroutine fvn_d_akima(n,x,y,br,co)
954 955
implicit none 955 956 implicit none
integer, intent(in) :: n 956 957 integer, intent(in) :: n
double precision, intent(in) :: x(n) 957 958 double precision, intent(in) :: x(n)
double precision, intent(in) :: y(n) 958 959 double precision, intent(in) :: y(n)
double precision, intent(out) :: br(n) 959 960 double precision, intent(out) :: br(n)
double precision, intent(out) :: co(4,n) 960 961 double precision, intent(out) :: co(4,n)
961 962
double precision, allocatable :: var(:),z(:) 962 963 double precision, allocatable :: var(:),z(:)
double precision :: wi_1,wi 963 964 double precision :: wi_1,wi
integer :: i 964 965 integer :: i
double precision :: dx,a,b 965 966 double precision :: dx,a,b
966 967
! br is just a copy of x 967 968 ! br is just a copy of x
br(:)=x(:) 968 969 br(:)=x(:)
969 970
allocate(var(n)) 970 971 allocate(var(n))
allocate(z(n)) 971 972 allocate(z(n))
! evaluate the variations 972 973 ! evaluate the variations
do i=1, n-1 973 974 do i=1, n-1
var(i+2)=(y(i+1)-y(i))/(x(i+1)-x(i)) 974 975 var(i+2)=(y(i+1)-y(i))/(x(i+1)-x(i))
end do 975 976 end do
var(n+2)=2.d0*var(n+1)-var(n) 976 977 var(n+2)=2.d0*var(n+1)-var(n)
var(n+3)=2.d0*var(n+2)-var(n+1) 977 978 var(n+3)=2.d0*var(n+2)-var(n+1)
var(2)=2.d0*var(3)-var(4) 978 979 var(2)=2.d0*var(3)-var(4)
var(1)=2.d0*var(2)-var(3) 979 980 var(1)=2.d0*var(2)-var(3)
980 981
do i = 1, n 981 982 do i = 1, n
wi_1=dabs(var(i+3)-var(i+2)) 982 983 wi_1=dabs(var(i+3)-var(i+2))
wi=dabs(var(i+1)-var(i)) 983 984 wi=dabs(var(i+1)-var(i))
if ((wi_1+wi).eq.0.d0) then 984 985 if ((wi_1+wi).eq.0.d0) then
z(i)=(var(i+2)+var(i+1))/2.d0 985 986 z(i)=(var(i+2)+var(i+1))/2.d0
else 986 987 else
z(i)=(wi_1*var(i+1)+wi*var(i+2))/(wi_1+wi) 987 988 z(i)=(wi_1*var(i+1)+wi*var(i+2))/(wi_1+wi)
end if 988 989 end if
end do 989 990 end do
990 991
do i=1, n-1 991 992 do i=1, n-1
dx=x(i+1)-x(i) 992 993 dx=x(i+1)-x(i)
a=(z(i+1)-z(i))*dx ! coeff intermediaires pour calcul wd 993 994 a=(z(i+1)-z(i))*dx ! coeff intermediaires pour calcul wd
b=y(i+1)-y(i)-z(i)*dx ! coeff intermediaires pour calcul wd 994 995 b=y(i+1)-y(i)-z(i)*dx ! coeff intermediaires pour calcul wd
co(1,i)=y(i) 995 996 co(1,i)=y(i)
co(2,i)=z(i) 996 997 co(2,i)=z(i)
!co(3,i)=-(a-3.*b)/dx**2 ! mรฉthode wd 997 998 !co(3,i)=-(a-3.*b)/dx**2 ! mรฉthode wd
!co(4,i)=(a-2.*b)/dx**3 ! mรฉthode wd 998 999 !co(4,i)=(a-2.*b)/dx**3 ! mรฉthode wd
co(3,i)=(3.d0*var(i+2)-2.d0*z(i)-z(i+1))/dx ! mรฉthode JP Moreau 999 1000 co(3,i)=(3.d0*var(i+2)-2.d0*z(i)-z(i+1))/dx ! mรฉthode JP Moreau
co(4,i)=(z(i)+z(i+1)-2.d0*var(i+2))/dx**2 ! 1000 1001 co(4,i)=(z(i)+z(i+1)-2.d0*var(i+2))/dx**2 !
! les coefficients donnรฉs par imsl sont co(3,i)*2 et co(4,i)*6 1001 1002 ! les coefficients donnรฉs par imsl sont co(3,i)*2 et co(4,i)*6
! etrangement la fonction csval corrige et donne la bonne valeur ... 1002 1003 ! etrangement la fonction csval corrige et donne la bonne valeur ...
end do 1003 1004 end do
co(1,n)=y(n) 1004 1005 co(1,n)=y(n)
co(2,n)=z(n) 1005 1006 co(2,n)=z(n)
co(3,n)=0.d0 1006 1007 co(3,n)=0.d0
co(4,n)=0.d0 1007 1008 co(4,n)=0.d0
1008 1009
deallocate(z) 1009 1010 deallocate(z)
deallocate(var) 1010 1011 deallocate(var)
1011 1012
end subroutine 1012 1013 end subroutine
1013 1014
! 1014 1015 !
! Single precision spline evaluation 1015 1016 ! Single precision spline evaluation
! 1016 1017 !
function fvn_s_spline_eval(x,n,br,co) 1017 1018 function fvn_s_spline_eval(x,n,br,co)
implicit none 1018 1019 implicit none
real, intent(in) :: x ! x must be br(1)<= x <= br(n+1) otherwise value is extrapolated 1019 1020 real, intent(in) :: x ! x must be br(1)<= x <= br(n+1) otherwise value is extrapolated
integer, intent(in) :: n ! number of intervals 1020 1021 integer, intent(in) :: n ! number of intervals
real, intent(in) :: br(n+1) ! breakpoints 1021 1022 real, intent(in) :: br(n+1) ! breakpoints
real, intent(in) :: co(4,n+1) ! spline coeeficients 1022 1023 real, intent(in) :: co(4,n+1) ! spline coeeficients
real :: fvn_s_spline_eval 1023 1024 real :: fvn_s_spline_eval
1024 1025
integer :: i 1025 1026 integer :: i
real :: dx 1026 1027 real :: dx
1027 1028
if (x<=br(1)) then 1028 1029 if (x<=br(1)) then
i=1 1029 1030 i=1
else if (x>=br(n+1)) then 1030 1031 else if (x>=br(n+1)) then
i=n 1031 1032 i=n
else 1032 1033 else
i=1 1033 1034 i=1
do while(x>=br(i)) 1034 1035 do while(x>=br(i))
i=i+1 1035 1036 i=i+1
end do 1036 1037 end do
i=i-1 1037 1038 i=i-1
end if 1038 1039 end if
dx=x-br(i) 1039 1040 dx=x-br(i)
fvn_s_spline_eval=co(1,i)+co(2,i)*dx+co(3,i)*dx**2+co(4,i)*dx**3 1040 1041 fvn_s_spline_eval=co(1,i)+co(2,i)*dx+co(3,i)*dx**2+co(4,i)*dx**3
1041 1042
end function 1042 1043 end function
1043 1044
! Double precision spline evaluation 1044 1045 ! Double precision spline evaluation
function fvn_d_spline_eval(x,n,br,co) 1045 1046 function fvn_d_spline_eval(x,n,br,co)
implicit none 1046 1047 implicit none
double precision, intent(in) :: x ! x must be br(1)<= x <= br(n+1) otherwise value is extrapolated 1047 1048 double precision, intent(in) :: x ! x must be br(1)<= x <= br(n+1) otherwise value is extrapolated
integer, intent(in) :: n ! number of intervals 1048 1049 integer, intent(in) :: n ! number of intervals
double precision, intent(in) :: br(n+1) ! breakpoints 1049 1050 double precision, intent(in) :: br(n+1) ! breakpoints
double precision, intent(in) :: co(4,n+1) ! spline coeeficients 1050 1051 double precision, intent(in) :: co(4,n+1) ! spline coeeficients
double precision :: fvn_d_spline_eval 1051 1052 double precision :: fvn_d_spline_eval
1052 1053
integer :: i 1053 1054 integer :: i
double precision :: dx 1054 1055 double precision :: dx
1055 1056
1056 1057
if (x<=br(1)) then 1057 1058 if (x<=br(1)) then
i=1 1058 1059 i=1
else if (x>=br(n+1)) then 1059 1060 else if (x>=br(n+1)) then
i=n 1060 1061 i=n
else 1061 1062 else
i=1 1062 1063 i=1
do while(x>=br(i)) 1063 1064 do while(x>=br(i))
i=i+1 1064 1065 i=i+1
end do 1065 1066 end do
i=i-1 1066 1067 i=i-1
end if 1067 1068 end if
1068 1069
dx=x-br(i) 1069 1070 dx=x-br(i)
fvn_d_spline_eval=co(1,i)+co(2,i)*dx+co(3,i)*dx**2+co(4,i)*dx**3 1070 1071 fvn_d_spline_eval=co(1,i)+co(2,i)*dx+co(3,i)*dx**2+co(4,i)*dx**3
1071 1072
end function 1072 1073 end function
1073 1074
1074 1075
! 1075 1076 !
! Muller 1076 1077 ! Muller
! 1077 1078 !
! 1078 1079 !
! 1079 1080 !
! William Daniau 2007 1080 1081 ! William Daniau 2007
! 1081 1082 !
! This routine is a fortran 90 port of Hans D. Mittelmann's routine muller.f 1082 1083 ! This routine is a fortran 90 port of Hans D. Mittelmann's routine muller.f
! http://plato.asu.edu/ftp/other_software/muller.f 1083 1084 ! http://plato.asu.edu/ftp/other_software/muller.f
! 1084 1085 !
! it can be used as a replacement for imsl routine dzanly with minor changes 1085 1086 ! it can be used as a replacement for imsl routine dzanly with minor changes
! 1086 1087 !
!----------------------------------------------------------------------- 1087 1088 !-----------------------------------------------------------------------
! 1088 1089 !
! purpose - zeros of an analytic complex function 1089 1090 ! purpose - zeros of an analytic complex function
! using the muller method with deflation 1090 1091 ! using the muller method with deflation
! 1091 1092 !
! usage - call fvn_z_muller (f,eps,eps1,kn,n,nguess,x,itmax, 1092 1093 ! usage - call fvn_z_muller (f,eps,eps1,kn,n,nguess,x,itmax,
! infer,ier) 1093 1094 ! infer,ier)
! 1094 1095 !
! arguments f - a complex function subprogram, f(z), written 1095 1096 ! arguments f - a complex function subprogram, f(z), written
! by the user specifying the equation whose 1096 1097 ! by the user specifying the equation whose
! roots are to be found. f must appear in 1097 1098 ! roots are to be found. f must appear in
! an external statement in the calling pro- 1098 1099 ! an external statement in the calling pro-
! gram. 1099 1100 ! gram.
! eps - 1st stopping criterion. let fp(z)=f(z)/p 1100 1101 ! eps - 1st stopping criterion. let fp(z)=f(z)/p
! where p = (z-z(1))*(z-z(2))*,,,*(z-z(k-1)) 1101 1102 ! where p = (z-z(1))*(z-z(2))*,,,*(z-z(k-1))
! and z(1),...,z(k-1) are previously found 1102 1103 ! and z(1),...,z(k-1) are previously found
! roots. if ((cdabs(f(z)).le.eps) .and. 1103 1104 ! roots. if ((cdabs(f(z)).le.eps) .and.
! (cdabs(fp(z)).le.eps)), then z is accepted 1104 1105 ! (cdabs(fp(z)).le.eps)), then z is accepted
! as a root. (input) 1105 1106 ! as a root. (input)
! eps1 - 2nd stopping criterion. a root is accepted 1106 1107 ! eps1 - 2nd stopping criterion. a root is accepted
! if two successive approximations to a given 1107 1108 ! if two successive approximations to a given
! root agree within eps1. (input) 1108 1109 ! root agree within eps1. (input)
! note. if either or both of the stopping 1109 1110 ! note. if either or both of the stopping
! criteria are fulfilled, the root is 1110 1111 ! criteria are fulfilled, the root is
! accepted. 1111 1112 ! accepted.
! kn - the number of known roots which must be stored 1112 1113 ! kn - the number of known roots which must be stored
! in x(1),...,x(kn), prior to entry to muller 1113 1114 ! in x(1),...,x(kn), prior to entry to muller
! nguess - the number of initial guesses provided. these 1114 1115 ! nguess - the number of initial guesses provided. these
! guesses must be stored in x(kn+1),..., 1115 1116 ! guesses must be stored in x(kn+1),...,
! x(kn+nguess). nguess must be set equal 1116 1117 ! x(kn+nguess). nguess must be set equal
! to zero if no guesses are provided. (input) 1117 1118 ! to zero if no guesses are provided. (input)
! n - the number of new roots to be found by 1118 1119 ! n - the number of new roots to be found by
! muller (input) 1119 1120 ! muller (input)
! x - a complex vector of length kn+n. x(1),..., 1120 1121 ! x - a complex vector of length kn+n. x(1),...,
! x(kn) on input must contain any known 1121 1122 ! x(kn) on input must contain any known
! roots. x(kn+1),..., x(kn+n) on input may, 1122 1123 ! roots. x(kn+1),..., x(kn+n) on input may,
! on user option, contain initial guesses for 1123 1124 ! on user option, contain initial guesses for
! the n new roots which are to be computed. 1124 1125 ! the n new roots which are to be computed.
! if the user does not provide an initial 1125 1126 ! if the user does not provide an initial
! guess, zero is used. 1126 1127 ! guess, zero is used.
! on output, x(kn+1),...,x(kn+n) contain the 1127 1128 ! on output, x(kn+1),...,x(kn+n) contain the
! approximate roots found by muller. 1128 1129 ! approximate roots found by muller.
! itmax - the maximum allowable number of iterations 1129 1130 ! itmax - the maximum allowable number of iterations
! per root (input) 1130 1131 ! per root (input)
! infer - an integer vector of length kn+n. on 1131 1132 ! infer - an integer vector of length kn+n. on
! output infer(j) contains the number of 1132 1133 ! output infer(j) contains the number of
! iterations used in finding the j-th root 1133 1134 ! iterations used in finding the j-th root
! when convergence was achieved. if 1134 1135 ! when convergence was achieved. if
! convergence was not obtained in itmax 1135 1136 ! convergence was not obtained in itmax
! iterations, infer(j) will be greater than 1136 1137 ! iterations, infer(j) will be greater than
! itmax (output). 1137 1138 ! itmax (output).
! ier - error parameter (output) 1138 1139 ! ier - error parameter (output)
! warning error 1139 1140 ! warning error
! ier = 33 indicates failure to converge with- 1140 1141 ! ier = 33 indicates failure to converge with-
! in itmax iterations for at least one of 1141 1142 ! in itmax iterations for at least one of
! the (n) new roots. 1142 1143 ! the (n) new roots.
! 1143 1144 !
! 1144 1145 !
! remarks muller always returns the last approximation for root j 1145 1146 ! remarks muller always returns the last approximation for root j
! in x(j). if the convergence criterion is satisfied, 1146 1147 ! in x(j). if the convergence criterion is satisfied,
! then infer(j) is less than or equal to itmax. if the 1147 1148 ! then infer(j) is less than or equal to itmax. if the
! convergence criterion is not satisified, then infer(j) 1148 1149 ! convergence criterion is not satisified, then infer(j)
! is set to either itmax+1 or itmax+k, with k greater 1149 1150 ! is set to either itmax+1 or itmax+k, with k greater
! than 1. infer(j) = itmax+1 indicates that muller did 1150 1151 ! than 1. infer(j) = itmax+1 indicates that muller did
! not obtain convergence in the allowed number of iter- 1151 1152 ! not obtain convergence in the allowed number of iter-
! ations. in this case, the user may wish to set itmax 1152 1153 ! ations. in this case, the user may wish to set itmax
! to a larger value. infer(j) = itmax+k means that con- 1153 1154 ! to a larger value. infer(j) = itmax+k means that con-
! vergence was obtained (on iteration k) for the defla- 1154 1155 ! vergence was obtained (on iteration k) for the defla-
! ted function 1155 1156 ! ted function
! fp(z) = f(z)/((z-z(1)...(z-z(j-1))) 1156 1157 ! fp(z) = f(z)/((z-z(1)...(z-z(j-1)))
! 1157 1158 !
! but failed for f(z). in this case, better initial 1158 1159 ! but failed for f(z). in this case, better initial
! guesses might help or, it might be necessary to relax 1159 1160 ! guesses might help or, it might be necessary to relax
! the convergence criterion. 1160 1161 ! the convergence criterion.
! 1161 1162 !
!----------------------------------------------------------------------- 1162 1163 !-----------------------------------------------------------------------
! 1163 1164 !
subroutine fvn_z_muller (f,eps,eps1,kn,nguess,n,x,itmax,infer,ier) 1164 1165 subroutine fvn_z_muller (f,eps,eps1,kn,nguess,n,x,itmax,infer,ier)
implicit none 1165 1166 implicit none
double precision :: rzero,rten,rhun,rp01,ax,eps1,qz,eps,tpq 1166 1167 double precision :: rzero,rten,rhun,rp01,ax,eps1,qz,eps,tpq
double complex :: d,dd,den,fprt,frt,h,rt,t1,t2,t3, & 1167 1168 double complex :: d,dd,den,fprt,frt,h,rt,t1,t2,t3, &
tem,z0,z1,z2,bi,xx,xl,y0,y1,y2,x0, & 1168 1169 tem,z0,z1,z2,bi,xx,xl,y0,y1,y2,x0, &
zero,p1,one,four,p5 1169 1170 zero,p1,one,four,p5
1170 1171
double complex, external :: f 1171 1172 double complex, external :: f
integer :: ickmax,kn,nguess,n,itmax,ier,knp1,knpn,i,l,ic, & 1172 1173 integer :: ickmax,kn,nguess,n,itmax,ier,knp1,knpn,i,l,ic, &
knpng,jk,ick,nn,lm1,errcode 1173 1174 knpng,jk,ick,nn,lm1,errcode
double complex :: x(kn+n) 1174 1175 double complex :: x(kn+n)
integer :: infer(kn+n) 1175 1176 integer :: infer(kn+n)
1176 1177
1177 1178
data zero/(0.0,0.0)/,p1/(0.1,0.0)/, & 1178 1179 data zero/(0.0,0.0)/,p1/(0.1,0.0)/, &
one/(1.0,0.0)/,four/(4.0,0.0)/, & 1179 1180 one/(1.0,0.0)/,four/(4.0,0.0)/, &
p5/(0.5,0.0)/, & 1180 1181 p5/(0.5,0.0)/, &
rzero/0.0/,rten/10.0/,rhun/100.0/, & 1181 1182 rzero/0.0/,rten/10.0/,rhun/100.0/, &
ax/0.1/,ickmax/3/,rp01/0.01/ 1182 1183 ax/0.1/,ickmax/3/,rp01/0.01/
1183 1184
ier = 0 1184 1185 ier = 0
if (n .lt. 1) then ! What the hell are doing here then ... 1185 1186 if (n .lt. 1) then ! What the hell are doing here then ...
return 1186 1187 return
end if 1187 1188 end if
!eps1 = rten **(-nsig) 1188 1189 !eps1 = rten **(-nsig)
eps1 = min(eps1,rp01) 1189 1190 eps1 = min(eps1,rp01)
1190 1191
knp1 = kn+1 1191 1192 knp1 = kn+1
knpn = kn+n 1192 1193 knpn = kn+n
knpng = kn+nguess 1193 1194 knpng = kn+nguess
do i=1,knpn 1194 1195 do i=1,knpn
infer(i) = 0 1195 1196 infer(i) = 0
if (i .gt. knpng) x(i) = zero 1196 1197 if (i .gt. knpng) x(i) = zero
end do 1197 1198 end do
l= knp1 1198 1199 l= knp1
1199 1200
ic=0 1200 1201 ic=0
rloop: do while (l<=knpn) ! Main loop over new roots 1201 1202 rloop: do while (l<=knpn) ! Main loop over new roots
jk = 0 1202 1203 jk = 0
ick = 0 1203 1204 ick = 0
xl = x(l) 1204 1205 xl = x(l)
icloop: do 1205 1206 icloop: do
ic = 0 1206 1207 ic = 0
h = ax 1207 1208 h = ax
h = p1*h 1208 1209 h = p1*h
if (cdabs(xl) .gt. ax) h = p1*xl 1209 1210 if (cdabs(xl) .gt. ax) h = p1*xl
! first three points are 1210 1211 ! first three points are
! xl+h, xl-h, xl 1211 1212 ! xl+h, xl-h, xl
rt = xl+h 1212 1213 rt = xl+h
call deflated_work(errcode) 1213 1214 call deflated_work(errcode)
if (errcode == 1) then 1214 1215 if (errcode == 1) then
exit icloop 1215 1216 exit icloop
end if 1216 1217 end if
1217 1218
z0 = fprt 1218 1219 z0 = fprt
y0 = frt 1219 1220 y0 = frt
x0 = rt 1220 1221 x0 = rt
rt = xl-h 1221 1222 rt = xl-h
call deflated_work(errcode) 1222 1223 call deflated_work(errcode)
if (errcode == 1) then 1223 1224 if (errcode == 1) then
exit icloop 1224 1225 exit icloop
end if 1225 1226 end if
1226 1227
z1 = fprt 1227 1228 z1 = fprt
y1 = frt 1228 1229 y1 = frt
h = xl-rt 1229 1230 h = xl-rt
d = h/(rt-x0) 1230 1231 d = h/(rt-x0)
rt = xl 1231 1232 rt = xl
1232 1233
call deflated_work(errcode) 1233 1234 call deflated_work(errcode)
if (errcode == 1) then 1234 1235 if (errcode == 1) then
exit icloop 1235 1236 exit icloop
end if 1236 1237 end if
1237 1238
1238 1239
z2 = fprt 1239 1240 z2 = fprt
y2 = frt 1240 1241 y2 = frt
! begin main algorithm 1241 1242 ! begin main algorithm
iloop: do 1242 1243 iloop: do
dd = one + d 1243 1244 dd = one + d
t1 = z0*d*d 1244 1245 t1 = z0*d*d
t2 = z1*dd*dd 1245 1246 t2 = z1*dd*dd
xx = z2*dd 1246 1247 xx = z2*dd
t3 = z2*d 1247 1248 t3 = z2*d
bi = t1-t2+xx+t3 1248 1249 bi = t1-t2+xx+t3
den = bi*bi-four*(xx*t1-t3*(t2-xx)) 1249 1250 den = bi*bi-four*(xx*t1-t3*(t2-xx))
! use denominator of maximum amplitude 1250 1251 ! use denominator of maximum amplitude
t1 = cdsqrt(den) 1251 1252 t1 = cdsqrt(den)
qz = rhun*max(cdabs(bi),cdabs(t1)) 1252 1253 qz = rhun*max(cdabs(bi),cdabs(t1))
t2 = bi + t1 1253 1254 t2 = bi + t1
tpq = cdabs(t2)+qz 1254 1255 tpq = cdabs(t2)+qz
if (tpq .eq. qz) t2 = zero 1255 1256 if (tpq .eq. qz) t2 = zero
t3 = bi - t1 1256 1257 t3 = bi - t1
tpq = cdabs(t3) + qz 1257 1258 tpq = cdabs(t3) + qz
if (tpq .eq. qz) t3 = zero 1258 1259 if (tpq .eq. qz) t3 = zero
den = t2 1259 1260 den = t2
qz = cdabs(t3)-cdabs(t2) 1260 1261 qz = cdabs(t3)-cdabs(t2)
if (qz .gt. rzero) den = t3 1261 1262 if (qz .gt. rzero) den = t3
! test for zero denominator 1262 1263 ! test for zero denominator
if (cdabs(den) .eq. rzero) then 1263 1264 if (cdabs(den) .eq. rzero) then
call trans_rt() 1264 1265 call trans_rt()
call deflated_work(errcode) 1265 1266 call deflated_work(errcode)
if (errcode == 1) then 1266 1267 if (errcode == 1) then
exit icloop 1267 1268 exit icloop
end if 1268 1269 end if
z2 = fprt 1269 1270 z2 = fprt
y2 = frt 1270 1271 y2 = frt
cycle iloop 1271 1272 cycle iloop
end if 1272 1273 end if
1273 1274
1274 1275
d = -xx/den 1275 1276 d = -xx/den
d = d+d 1276 1277 d = d+d
h = d*h 1277 1278 h = d*h
rt = rt + h 1278 1279 rt = rt + h
! check convergence of the first kind 1279 1280 ! check convergence of the first kind
if (cdabs(h) .le. eps1*max(cdabs(rt),ax)) then 1280 1281 if (cdabs(h) .le. eps1*max(cdabs(rt),ax)) then
if (ic .ne. 0) then 1281 1282 if (ic .ne. 0) then
exit icloop 1282 1283 exit icloop
end if 1283 1284 end if
ic = 1 1284 1285 ic = 1
z0 = y1 1285 1286 z0 = y1
z1 = y2 1286 1287 z1 = y2
z2 = f(rt) 1287 1288 z2 = f(rt)
xl = rt 1288 1289 xl = rt
ick = ick+1 1289 1290 ick = ick+1
if (ick .le. ickmax) then 1290 1291 if (ick .le. ickmax) then
cycle iloop 1291 1292 cycle iloop
end if 1292 1293 end if
! warning error, itmax = maximum 1293 1294 ! warning error, itmax = maximum
jk = itmax + jk 1294 1295 jk = itmax + jk
ier = 33 1295 1296 ier = 33
end if 1296 1297 end if
if (ic .ne. 0) then 1297 1298 if (ic .ne. 0) then
cycle icloop 1298 1299 cycle icloop
end if 1299 1300 end if
call deflated_work(errcode) 1300 1301 call deflated_work(errcode)
if (errcode == 1) then 1301 1302 if (errcode == 1) then
exit icloop 1302 1303 exit icloop
end if 1303 1304 end if
1304 1305
do while ( (cdabs(fprt)-cdabs(z2)*rten) .ge. rzero) 1305 1306 do while ( (cdabs(fprt)-cdabs(z2)*rten) .ge. rzero)
! take remedial action to induce 1306 1307 ! take remedial action to induce
! convergence 1307 1308 ! convergence
d = d*p5 1308 1309 d = d*p5
h = h*p5 1309 1310 h = h*p5
rt = rt-h 1310 1311 rt = rt-h
call deflated_work(errcode) 1311 1312 call deflated_work(errcode)
if (errcode == 1) then 1312 1313 if (errcode == 1) then
exit icloop 1313 1314 exit icloop
end if 1314 1315 end if
end do 1315 1316 end do
z0 = z1 1316 1317 z0 = z1
z1 = z2 1317 1318 z1 = z2
z2 = fprt 1318 1319 z2 = fprt
y0 = y1 1319 1320 y0 = y1
y1 = y2 1320 1321 y1 = y2
y2 = frt 1321 1322 y2 = frt
end do iloop 1322 1323 end do iloop
end do icloop 1323 1324 end do icloop
x(l) = rt 1324 1325 x(l) = rt
infer(l) = jk 1325 1326 infer(l) = jk
l = l+1 1326 1327 l = l+1
end do rloop 1327 1328 end do rloop
1328 1329
contains 1329 1330 contains
subroutine trans_rt() 1330 1331 subroutine trans_rt()
tem = rten*eps1 1331 1332 tem = rten*eps1
if (cdabs(rt) .gt. ax) tem = tem*rt 1332 1333 if (cdabs(rt) .gt. ax) tem = tem*rt
rt = rt+tem 1333 1334 rt = rt+tem
d = (h+tem)*d/h 1334 1335 d = (h+tem)*d/h
h = h+tem 1335 1336 h = h+tem
end subroutine trans_rt 1336 1337 end subroutine trans_rt
1337 1338
subroutine deflated_work(errcode) 1338 1339 subroutine deflated_work(errcode)
! errcode=0 => no errors 1339 1340 ! errcode=0 => no errors
! errcode=1 => jk>itmax or convergence of second kind achieved 1340 1341 ! errcode=1 => jk>itmax or convergence of second kind achieved
integer :: errcode,flag 1341 1342 integer :: errcode,flag
1342 1343
flag=1 1343 1344 flag=1
loop1: do while(flag==1) 1344 1345 loop1: do while(flag==1)
errcode=0 1345 1346 errcode=0
jk = jk+1 1346 1347 jk = jk+1
if (jk .gt. itmax) then 1347 1348 if (jk .gt. itmax) then
ier=33 1348 1349 ier=33
errcode=1 1349 1350 errcode=1
return 1350 1351 return
end if 1351 1352 end if
frt = f(rt) 1352 1353 frt = f(rt)
fprt = frt 1353 1354 fprt = frt
if (l /= 1) then 1354 1355 if (l /= 1) then
lm1 = l-1 1355 1356 lm1 = l-1
do i=1,lm1 1356 1357 do i=1,lm1
tem = rt - x(i) 1357 1358 tem = rt - x(i)
if (cdabs(tem) .eq. rzero) then 1358 1359 if (cdabs(tem) .eq. rzero) then
!if (ic .ne. 0) go to 15 !! ?? possible? 1359 1360 !if (ic .ne. 0) go to 15 !! ?? possible?
call trans_rt() 1360 1361 call trans_rt()
cycle loop1 1361 1362 cycle loop1
end if 1362 1363 end if
fprt = fprt/tem 1363 1364 fprt = fprt/tem
end do 1364 1365 end do
end if 1365 1366 end if
flag=0 1366 1367 flag=0
end do loop1 1367 1368 end do loop1
1368 1369
if (cdabs(fprt) .le. eps .and. cdabs(frt) .le. eps) then 1369 1370 if (cdabs(fprt) .le. eps .and. cdabs(frt) .le. eps) then
errcode=1 1370 1371 errcode=1
return 1371 1372 return
end if 1372 1373 end if
1373 1374
end subroutine deflated_work 1374 1375 end subroutine deflated_work
1375 1376
end subroutine 1376 1377 end subroutine
1377 1378
1378 1379
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 1379 1380 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! 1380 1381 !
! Integration 1381 1382 ! Integration
! 1382 1383 !
! Only double precision coded atm 1383 1384 ! Only double precision coded atm
! 1384 1385 !
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 1385 1386 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1386 1387
1387 1388
subroutine fvn_d_gauss_legendre(n,qx,qw) 1388 1389 subroutine fvn_d_gauss_legendre(n,qx,qw)
! 1389 1390 !
! This routine compute the n Gauss Legendre abscissas and weights 1390 1391 ! This routine compute the n Gauss Legendre abscissas and weights
! Adapted from Numerical Recipes routine gauleg 1391 1392 ! Adapted from Numerical Recipes routine gauleg
! 1392 1393 !
! n (in) : number of points 1393 1394 ! n (in) : number of points
! qx(out) : abscissas 1394 1395 ! qx(out) : abscissas
! qw(out) : weights 1395 1396 ! qw(out) : weights
! 1396 1397 !
implicit none 1397 1398 implicit none
double precision,parameter :: pi=3.141592653589793d0 1398 1399 double precision,parameter :: pi=3.141592653589793d0
integer, intent(in) :: n 1399 1400 integer, intent(in) :: n
double precision, intent(out) :: qx(n),qw(n) 1400 1401 double precision, intent(out) :: qx(n),qw(n)
1401 1402
integer :: m,i,j 1402 1403 integer :: m,i,j
double precision :: z,z1,p1,p2,p3,pp 1403 1404 double precision :: z,z1,p1,p2,p3,pp
m=(n+1)/2 1404 1405 m=(n+1)/2
do i=1,m 1405 1406 do i=1,m
z=cos(pi*(dble(i)-0.25d0)/(dble(n)+0.5d0)) 1406 1407 z=cos(pi*(dble(i)-0.25d0)/(dble(n)+0.5d0))
iloop: do 1407 1408 iloop: do
p1=1.d0 1408 1409 p1=1.d0
p2=0.d0 1409 1410 p2=0.d0
do j=1,n 1410 1411 do j=1,n
p3=p2 1411 1412 p3=p2
p2=p1 1412 1413 p2=p1
p1=((2.d0*dble(j)-1.d0)*z*p2-(dble(j)-1.d0)*p3)/dble(j) 1413 1414 p1=((2.d0*dble(j)-1.d0)*z*p2-(dble(j)-1.d0)*p3)/dble(j)
end do 1414 1415 end do
pp=dble(n)*(z*p1-p2)/(z*z-1.d0) 1415 1416 pp=dble(n)*(z*p1-p2)/(z*z-1.d0)
z1=z 1416 1417 z1=z
z=z1-p1/pp 1417 1418 z=z1-p1/pp
if (dabs(z-z1)<=epsilon(z)) then 1418 1419 if (dabs(z-z1)<=epsilon(z)) then
exit iloop 1419 1420 exit iloop
end if 1420 1421 end if
end do iloop 1421 1422 end do iloop
qx(i)=-z 1422 1423 qx(i)=-z
qx(n+1-i)=z 1423 1424 qx(n+1-i)=z
qw(i)=2.d0/((1.d0-z*z)*pp*pp) 1424 1425 qw(i)=2.d0/((1.d0-z*z)*pp*pp)
qw(n+1-i)=qw(i) 1425 1426 qw(n+1-i)=qw(i)
end do 1426 1427 end do
end subroutine 1427 1428 end subroutine
1428 1429
1429 1430
1430 1431
subroutine fvn_d_gl_integ(f,a,b,n,res) 1431 1432 subroutine fvn_d_gl_integ(f,a,b,n,res)
! 1432 1433 !
! This is a simple non adaptative integration routine 1433 1434 ! This is a simple non adaptative integration routine
! using n gauss legendre abscissas and weights 1434 1435 ! using n gauss legendre abscissas and weights
! 1435 1436 !
! f(in) : the function to integrate 1436 1437 ! f(in) : the function to integrate
! a(in) : lower bound 1437 1438 ! a(in) : lower bound
! b(in) : higher bound 1438 1439 ! b(in) : higher bound
! n(in) : number of gauss legendre pairs 1439 1440 ! n(in) : number of gauss legendre pairs
! res(out): the evaluation of the integral 1440 1441 ! res(out): the evaluation of the integral
! 1441 1442 !
double precision,external :: f 1442 1443 double precision,external :: f
double precision, intent(in) :: a,b 1443 1444 double precision, intent(in) :: a,b
integer, intent(in):: n 1444 1445 integer, intent(in):: n
double precision, intent(out) :: res 1445 1446 double precision, intent(out) :: res
1446 1447
double precision, allocatable :: qx(:),qw(:) 1447 1448 double precision, allocatable :: qx(:),qw(:)
double precision :: xm,xr 1448 1449 double precision :: xm,xr
integer :: i 1449 1450 integer :: i
1450 1451
! First compute n gauss legendre abs and weight 1451 1452 ! First compute n gauss legendre abs and weight
allocate(qx(n)) 1452 1453 allocate(qx(n))
allocate(qw(n)) 1453 1454 allocate(qw(n))
call fvn_d_gauss_legendre(n,qx,qw) 1454 1455 call fvn_d_gauss_legendre(n,qx,qw)
1455 1456
xm=0.5d0*(b+a) 1456 1457 xm=0.5d0*(b+a)
xr=0.5d0*(b-a) 1457 1458 xr=0.5d0*(b-a)
1458 1459
res=0.d0 1459 1460 res=0.d0
1460 1461
do i=1,n 1461 1462 do i=1,n
res=res+qw(i)*f(xm+xr*qx(i)) 1462 1463 res=res+qw(i)*f(xm+xr*qx(i))
end do 1463 1464 end do
1464 1465
res=xr*res 1465 1466 res=xr*res
1466 1467
deallocate(qw) 1467 1468 deallocate(qw)
deallocate(qx) 1468 1469 deallocate(qx)
1469 1470
end subroutine 1470 1471 end subroutine
1471 1472
!!!!!!!!!!!!!!!!!!!!!!!! 1472 1473 !!!!!!!!!!!!!!!!!!!!!!!!
! 1473 1474 !
! Simple and double adaptative Gauss Kronrod integration based on 1474 1475 ! Simple and double adaptative Gauss Kronrod integration based on
! a modified version of quadpack ( http://www.netlib.org/quadpack 1475 1476 ! a modified version of quadpack ( http://www.netlib.org/quadpack
! 1476 1477 !
! Common parameters : 1477 1478 ! Common parameters :
! 1478 1479 !
! key (in) 1479 1480 ! key (in)
! epsabs 1480 1481 ! epsabs
! epsrel 1481 1482 ! epsrel
! 1482 1483 !
! 1483 1484 !
!!!!!!!!!!!!!!!!!!!!!!!! 1484 1485 !!!!!!!!!!!!!!!!!!!!!!!!
1485 1486
subroutine fvn_d_integ_1_gk(f,a,b,epsabs,epsrel,key,res,abserr,ier,limit) 1486 1487 subroutine fvn_d_integ_1_gk(f,a,b,epsabs,epsrel,key,res,abserr,ier,limit)
! 1487 1488 !
! Evaluate the integral of function f(x) between a and b 1488 1489 ! Evaluate the integral of function f(x) between a and b
! 1489 1490 !
! f(in) : the function 1490 1491 ! f(in) : the function
! a(in) : lower bound 1491 1492 ! a(in) : lower bound
! b(in) : higher bound 1492 1493 ! b(in) : higher bound
! epsabs(in) : desired absolute error 1493 1494 ! epsabs(in) : desired absolute error
! epsrel(in) : desired relative error 1494 1495 ! epsrel(in) : desired relative error
! key(in) : gauss kronrod rule 1495 1496 ! key(in) : gauss kronrod rule
! 1: 7 - 15 points 1496 1497 ! 1: 7 - 15 points
! 2: 10 - 21 points 1497 1498 ! 2: 10 - 21 points
! 3: 15 - 31 points 1498 1499 ! 3: 15 - 31 points
! 4: 20 - 41 points 1499 1500 ! 4: 20 - 41 points
! 5: 25 - 51 points 1500 1501 ! 5: 25 - 51 points
! 6: 30 - 61 points 1501 1502 ! 6: 30 - 61 points
! 1502 1503 !
! limit(in) : maximum number of subintervals in the partition of the 1503 1504 ! limit(in) : maximum number of subintervals in the partition of the
! given integration interval (a,b). A value of 500 will give the same 1504 1505 ! given integration interval (a,b). A value of 500 will give the same
! behaviour as the imsl routine dqdag 1505 1506 ! behaviour as the imsl routine dqdag
! 1506 1507 !
! res(out) : estimated integral value 1507 1508 ! res(out) : estimated integral value
! abserr(out) : estimated absolute error 1508 1509 ! abserr(out) : estimated absolute error
! ier(out) : error flag from quadpack routines 1509 1510 ! ier(out) : error flag from quadpack routines
! 0 : no error 1510 1511 ! 0 : no error
! 1 : maximum number of subdivisions allowed 1511 1512 ! 1 : maximum number of subdivisions allowed
! has been achieved. one can allow more 1512 1513 ! has been achieved. one can allow more
! subdivisions by increasing the value of 1513 1514 ! subdivisions by increasing the value of
! limit (and taking the according dimension 1514 1515 ! limit (and taking the according dimension
! adjustments into account). however, if 1515 1516 ! adjustments into account). however, if
! this yield no improvement it is advised 1516 1517 ! this yield no improvement it is advised
! to analyze the integrand in order to 1517 1518 ! to analyze the integrand in order to
! determine the integration difficulaties. 1518 1519 ! determine the integration difficulaties.
! if the position of a local difficulty can 1519 1520 ! if the position of a local difficulty can
! be determined (i.e.singularity, 1520 1521 ! be determined (i.e.singularity,
! discontinuity within the interval) one 1521 1522 ! discontinuity within the interval) one
! will probably gain from splitting up the 1522 1523 ! will probably gain from splitting up the
! interval at this point and calling the 1523 1524 ! interval at this point and calling the
! integrator on the subranges. if possible, 1524 1525 ! integrator on the subranges. if possible,
! an appropriate special-purpose integrator 1525 1526 ! an appropriate special-purpose integrator
! should be used which is designed for 1526 1527 ! should be used which is designed for
! handling the type of difficulty involved. 1527 1528 ! handling the type of difficulty involved.
! 2 : the occurrence of roundoff error is 1528 1529 ! 2 : the occurrence of roundoff error is
! detected, which prevents the requested 1529 1530 ! detected, which prevents the requested
! tolerance from being achieved. 1530 1531 ! tolerance from being achieved.
! 3 : extremely bad integrand behaviour occurs 1531 1532 ! 3 : extremely bad integrand behaviour occurs
! at some points of the integration 1532 1533 ! at some points of the integration
! interval. 1533 1534 ! interval.
! 6 : the input is invalid, because 1534 1535 ! 6 : the input is invalid, because
! (epsabs.le.0 and 1535 1536 ! (epsabs.le.0 and
! epsrel.lt.max(50*rel.mach.acc.,0.5d-28)) 1536 1537 ! epsrel.lt.max(50*rel.mach.acc.,0.5d-28))
! or limit.lt.1 or lenw.lt.limit*4. 1537 1538 ! or limit.lt.1 or lenw.lt.limit*4.
! result, abserr, neval, last are set 1538 1539 ! result, abserr, neval, last are set
! to zero. 1539 1540 ! to zero.
! except when lenw is invalid, iwork(1), 1540 1541 ! except when lenw is invalid, iwork(1),
! work(limit*2+1) and work(limit*3+1) are 1541 1542 ! work(limit*2+1) and work(limit*3+1) are
! set to zero, work(1) is set to a and 1542 1543 ! set to zero, work(1) is set to a and
! work(limit+1) to b. 1543 1544 ! work(limit+1) to b.
1544 1545
implicit none 1545 1546 implicit none
double precision, external :: f 1546 1547 double precision, external :: f
double precision, intent(in) :: a,b,epsabs,epsrel 1547 1548 double precision, intent(in) :: a,b,epsabs,epsrel
integer, intent(in) :: key 1548 1549 integer, intent(in) :: key
integer, intent(in) :: limit 1549 1550 integer, intent(in) :: limit
double precision, intent(out) :: res,abserr 1550 1551 double precision, intent(out) :: res,abserr
integer, intent(out) :: ier 1551 1552 integer, intent(out) :: ier
1552 1553
double precision, allocatable :: work(:) 1553 1554 double precision, allocatable :: work(:)
integer, allocatable :: iwork(:) 1554 1555 integer, allocatable :: iwork(:)
integer :: lenw,neval,last 1555 1556 integer :: lenw,neval,last
1556 1557
! imsl value for limit is 500 1557 1558 ! imsl value for limit is 500
lenw=limit*4 1558 1559 lenw=limit*4
1559 1560
allocate(iwork(limit)) 1560 1561 allocate(iwork(limit))
allocate(work(lenw)) 1561 1562 allocate(work(lenw))
1562 1563
call dqag(f,a,b,epsabs,epsrel,key,res,abserr,neval,ier,limit,lenw,last,iwork,work) 1563 1564 call dqag(f,a,b,epsabs,epsrel,key,res,abserr,neval,ier,limit,lenw,last,iwork,work)
1564 1565
deallocate(work) 1565 1566 deallocate(work)
deallocate(iwork) 1566 1567 deallocate(iwork)
1567 1568
end subroutine 1568 1569 end subroutine
1569 1570
1570 1571
1571 1572