PageRenderTime 47ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/src/kerneldensity.F90

http://github.com/galtay/sphray
FORTRAN Modern | 478 lines | 395 code | 68 blank | 15 comment | 30 complexity | 15ecb846991405739dae83194c086038 MD5 | raw file
  1. !> \file kerneldensity.F90
  2. !> \brief Module for calculating the kernel density.
  3. !<
  4. module kernel_density_mod
  5. use particle_system_mod, only: particle_system_type, particle_type
  6. use sphpar_mod, only: sphpar_type
  7. use nblist_mod
  8. implicit none
  9. private
  10. ! public :: localpart_type
  11. public :: initdensity,gradrho,density,hsmdens,fromsphpar
  12. public :: massres,rhomin,spherevol
  13. integer,parameter :: ndim=3
  14. real :: massres
  15. real :: rhomin
  16. integer, parameter :: TARGETNN=32
  17. integer, parameter :: Ninterpolation=1000
  18. integer, parameter :: HSM_NEWTON_MAX_ITERATION=10
  19. real, parameter :: HSM_NEWTON_PREC=0.0001
  20. integer, parameter :: HSM_BISECTION_MAX_ITERATION=50
  21. real, parameter :: HSM_BISECTION_PREC=0.001
  22. integer, parameter :: HSM_BRACKET_TRY=50
  23. real, parameter :: HSM_BRACKET_FAC=2.
  24. real, parameter :: Pi=3.141592653589793238
  25. real, parameter :: kfac(3)=(/ 2.6666666666666666667, &
  26. 1.8189136353359466945, &
  27. 2.5464790894703253723 /)
  28. real :: spherevol,dspherevol
  29. real :: wsmooth(0:Ninterpolation+1),dwsmooth(0:Ninterpolation+1)
  30. real, parameter :: deldr2=1./Ninterpolation
  31. integer :: nnewton=0,nbisect=0
  32. contains
  33. subroutine initdensity(mass)
  34. real :: mass
  35. massres=TARGETNN*mass
  36. rhomin=0.0
  37. call initkernel
  38. spherevol=UnitSphereVolume(ndim)
  39. dspherevol=spherevol*ndim
  40. end subroutine initdensity
  41. subroutine initkernel
  42. integer :: i
  43. real :: xw2,xw
  44. do i=0,1+Ninterpolation
  45. xw2=i*deldr2*4.
  46. xw=SQRT(xw2)
  47. if(xw2.LE.1.) then
  48. wsmooth(i)=1.-1.5*xw2+0.75*xw*xw2
  49. dwsmooth(i)=-3.+2.25*xw
  50. else
  51. wsmooth(i)=0.25*(2.-xw)**3
  52. dwsmooth(i)=-0.75*(2.-xw)**2/xw
  53. endif
  54. if(xw2.GE.4.) then
  55. wsmooth(i)=0.
  56. dwsmooth(i)=0.
  57. endif
  58. dwsmooth(i)=dwsmooth(i)*4 ! geloofik
  59. enddo
  60. end subroutine initkernel
  61. subroutine hsmdens(sphpar,psys,nblist)
  62. use oct_tree_mod, only: getlocalscale
  63. type(particle_system_type) :: psys
  64. type(sphpar_type) :: sphpar
  65. type(nblist_type) :: nblist
  66. ! try if part%hsmooth=0.0 then get local scale
  67. if (sphpar%hsmooth==0.0) then
  68. sphpar%hsmooth = getlocalscale(sphpar%pos,nblist%stree)
  69. end if
  70. call resetnblist(nblist,sphpar%hsmooth,sphpar%pos)
  71. call hnewton(sphpar,psys,nblist)
  72. call hfunc(sphpar,psys,nblist)
  73. end subroutine hsmdens
  74. subroutine hnewton(sphpar,psys,nblist)
  75. type(particle_system_type) :: psys
  76. type(sphpar_type) :: sphpar
  77. type(nblist_type) :: nblist
  78. real :: hsmold,hmin,hmax
  79. integer :: i
  80. hmin=0.5*sphpar%hsmooth
  81. hmax=2*sphpar%hsmooth
  82. hsmold=sphpar%hsmooth
  83. nnewton=nnewton+1
  84. i=0
  85. 10 if(sphpar%hsmooth.LT.hmax .AND. &
  86. sphpar%hsmooth.GT.hmin .AND. &
  87. i.LT.HSM_NEWTON_MAX_ITERATION) then
  88. i=i+1
  89. call hfunc(sphpar,psys,nblist)
  90. if(sphpar%dfi.NE.0) then
  91. sphpar%hsmooth=sphpar%hsmooth-sphpar%fi/sphpar%dfi
  92. ! print*,'nw',sphpar%hsmooth
  93. else
  94. sphpar%hsmooth=0
  95. endif
  96. if(ABS(sphpar%fi).LT.ABS(sphpar%hsmooth*HSM_NEWTON_PREC*sphpar%dfi)) then
  97. return
  98. endif
  99. goto 10
  100. else
  101. sphpar%hsmooth=hsmold
  102. call bisect(sphpar,psys,nblist)
  103. endif
  104. end subroutine hnewton
  105. subroutine hfunc(sphpar,psys,nblist)
  106. type(particle_system_type) :: psys
  107. type(sphpar_type) :: sphpar
  108. type(nblist_type) :: nblist
  109. if(nblist%nnb.LE.0.OR. &
  110. sphpar%hsmooth.GT.nblist%searchrange.OR. &
  111. sphpar%hsmooth.LT.0.5*nblist%searchrange) then
  112. call resetnblist(nblist,range=sphpar%hsmooth)
  113. endif
  114. call fidfi(sphpar,psys,nblist)
  115. return
  116. end subroutine hfunc
  117. subroutine do_nbsum(sphpar,psys,nblist,sumroutine)
  118. type(sphpar_type) :: sphpar
  119. type(particle_system_type) :: psys
  120. type(nblist_type) :: nblist
  121. interface
  122. subroutine sumroutine(pa,nb)
  123. use sphpar_mod, only: sphpar_type
  124. use nblist_mod, only: nblist_type
  125. type(sphpar_type) :: pa
  126. type(nblist_type) :: nb
  127. end subroutine sumroutine
  128. end interface
  129. if(nblist%reuseable) then
  130. call sumroutine(sphpar,nblist)
  131. return
  132. endif
  133. call resetnblist(nblist)
  134. do while(nblist%searchcell.NE.0)
  135. nblist%nnb=0
  136. call fullsearch(psys,nblist)
  137. call sumroutine(sphpar,nblist)
  138. enddo
  139. end subroutine do_nbsum
  140. subroutine gradrhosum(sphpar,nblist)
  141. type(sphpar_type) :: sphpar
  142. type(nblist_type) :: nblist
  143. integer iwsm,i
  144. real :: dx(ndim),hinv,dknorm,dist2norm,dr2p,dist2,drw
  145. real :: dkernel
  146. real :: particle_mass
  147. hinv=1./sphpar%hsmooth
  148. dknorm=kfac(ndim)*hinv**(ndim+2)
  149. dist2norm=hinv**2/deldr2
  150. do i=1,nblist%nnb
  151. dx=sphpar%pos-nblist%sphpar(i)%pos
  152. dist2=sum(dx**2)
  153. dr2p=dist2*dist2norm
  154. if(Ninterpolation.GE.dr2p) then
  155. iwsm=INT(dr2p)
  156. drw=dr2p-iwsm
  157. dkernel=(1.-drw)*dwsmooth(iwsm)+drw*dwsmooth(1+iwsm)
  158. dkernel=dknorm*dkernel
  159. particle_mass = nblist%sphpar(i)%mass
  160. sphpar%gradrho=sphpar%gradrho+dx*particle_mass*dkernel
  161. endif
  162. enddo
  163. end subroutine gradrhosum
  164. subroutine gradrho(sphpar,nblist)
  165. type(sphpar_type) :: sphpar
  166. type(nblist_type) :: nblist
  167. type(particle_system_type) psys
  168. sphpar%gradrho=0
  169. call do_nbsum(sphpar,psys,nblist,gradrhosum)
  170. end subroutine gradrho
  171. subroutine densitysum(sphpar,nblist)
  172. type(sphpar_type) sphpar
  173. type(nblist_type) nblist
  174. integer iwsm, i
  175. real :: dx(ndim), hinv, knorm, dknorm, dist2norm, dr2p, dist2, drw
  176. real :: kernel
  177. real :: particle_mass
  178. ! real :: dkernel
  179. hinv=1./sphpar%hsmooth
  180. knorm=kfac(ndim)*hinv**ndim
  181. dknorm=kfac(ndim)*hinv**(ndim+2)
  182. dist2norm=hinv**2/deldr2
  183. do i=1,nblist%nnb
  184. dx=sphpar%pos-nblist%sphpar(i)%pos
  185. dist2=sum(dx**2)
  186. dr2p=dist2*dist2norm
  187. if(Ninterpolation.GE.dr2p) then
  188. sphpar%nnb=sphpar%nnb+1
  189. iwsm=INT(dr2p)
  190. drw=dr2p-iwsm
  191. kernel=(1.-drw)*wsmooth(iwsm)+drw*wsmooth(1+iwsm)
  192. kernel=knorm*kernel
  193. particle_mass = nblist%sphpar(i)%mass
  194. sphpar%rho=sphpar%rho+particle_mass*kernel
  195. sphpar%xHII = sphpar%xHII + particle_mass * nblist%sphpar(i)%xHII * kernel
  196. sphpar%T = sphpar%T + particle_mass * nblist%sphpar(i)%T * kernel
  197. endif
  198. enddo
  199. end subroutine densitysum
  200. subroutine density(sphpar,psys,nblist)
  201. type(particle_system_type) psys
  202. type(sphpar_type) sphpar
  203. type(nblist_type) nblist
  204. sphpar%nnb=0
  205. sphpar%rho=0
  206. call do_nbsum(sphpar,psys,nblist,densitysum)
  207. if(sphpar%rho.NE.0) sphpar%xHII = sphpar%xHII / sphpar%rho
  208. if(sphpar%rho.NE.0) sphpar%T = sphpar%T / sphpar%rho
  209. ! I added this to see about the vertical stripes
  210. ! if(sphpar%rho.LT.rhomin) then
  211. ! sphpar%rho = rhomin
  212. ! sphpar%xHII = 1.00
  213. ! sphpar%T = 1.0e4
  214. ! end if
  215. end subroutine density
  216. subroutine fidfisum(sphpar,nblist)
  217. type(sphpar_type) sphpar
  218. type(nblist_type) nblist
  219. integer iwsm,i
  220. real :: dx(ndim),hinv, knorm,dknorm,dist2norm,dr2p,dist2,drw
  221. real :: kernel,dkernel
  222. real :: particle_mass
  223. hinv=1./sphpar%hsmooth
  224. knorm=kfac(ndim)*hinv**ndim
  225. dknorm=kfac(ndim)*hinv**(ndim+2)
  226. dist2norm=hinv**2/deldr2
  227. do i=1,nblist%nnb
  228. dx=sphpar%pos-nblist%sphpar(i)%pos
  229. dist2=sum(dx**2)
  230. dr2p=dist2*dist2norm
  231. if(dr2p.LT.0) then
  232. print*,'!!!!',dr2p
  233. stop
  234. endif
  235. if(Ninterpolation.GE.dr2p) then
  236. sphpar%nnb=sphpar%nnb+1
  237. iwsm=INT(dr2p)
  238. drw=dr2p-iwsm
  239. kernel=(1.-drw)*wsmooth(iwsm)+drw*wsmooth(1+iwsm)
  240. dkernel=(1.-drw)*dwsmooth(iwsm)+drw*dwsmooth(1+iwsm)
  241. kernel=knorm*kernel
  242. dkernel=dknorm*dkernel
  243. particle_mass = nblist%sphpar(i)%mass
  244. sphpar%rho=sphpar%rho+particle_mass*kernel
  245. sphpar%drhodh=sphpar%drhodh-ndim*hinv*particle_mass*kernel
  246. sphpar%drhodh=sphpar%drhodh-dist2*hinv*particle_mass*dkernel
  247. endif
  248. enddo
  249. end subroutine fidfisum
  250. subroutine fidfi(sphpar,psys,nblist)
  251. type(particle_system_type) psys
  252. type(sphpar_type) sphpar
  253. type(nblist_type) nblist
  254. sphpar%nnb=0
  255. sphpar%rho=0
  256. sphpar%drhodh=0
  257. call do_nbsum(sphpar,psys,nblist,fidfisum)
  258. sphpar%fi=spherevol*sphpar%hsmooth**ndim*(sphpar%rho+rhomin)-massres
  259. sphpar%dfi=spherevol*ndim*sphpar%hsmooth**(ndim-1)*(sphpar%rho+rhomin)+ &
  260. spherevol*sphpar%hsmooth**ndim*sphpar%drhodh
  261. end subroutine fidfi
  262. subroutine bisect(sphpar,psys,nblist)
  263. type(particle_system_type) :: psys
  264. type(sphpar_type) :: sphpar
  265. type(nblist_type) :: nblist
  266. real :: hmin,hmax
  267. nbisect=nbisect+1
  268. call bracketh(sphpar,psys,nblist,hmin,hmax)
  269. call hsafe(sphpar,psys,nblist,hmin,hmax)
  270. call hfunc(sphpar,psys,nblist)
  271. end subroutine bisect
  272. subroutine hsafe(sphpar,psys,nblist,hmin,hmax)
  273. type(particle_system_type) :: psys
  274. type(sphpar_type) :: sphpar
  275. type(nblist_type) :: nblist
  276. integer :: j
  277. real :: hmin, hmax
  278. real :: dx, dxold, fh, fl, temp, xl, xh
  279. ! integer :: p, maxit, nneigh
  280. ! real :: prec, hneigh
  281. sphpar%hsmooth=hmax
  282. call hfunc(sphpar,psys,nblist)
  283. fh=sphpar%fi
  284. sphpar%hsmooth=hmin
  285. call hfunc(sphpar,psys,nblist)
  286. fl=sphpar%fi
  287. if(hmin.GE.hmax.OR.fl.GE.fh) call kernelError('hsafe error')
  288. if(fl.eq.0) then
  289. sphpar%hsmooth=hmin
  290. return
  291. if(fh.eq.0) then
  292. sphpar%hsmooth=hmax
  293. return
  294. endif
  295. endif
  296. xl=hmin
  297. xh=hmax
  298. sphpar%hsmooth=.5*(xl+xh)
  299. dxold=(xh-xl)
  300. dx=dxold
  301. call hfunc(sphpar,psys,nblist)
  302. do j=1,HSM_BISECTION_MAX_ITERATION
  303. if( ((sphpar%hsmooth-xh)*sphpar%dfi - sphpar%fi) * &
  304. ((sphpar%hsmooth-xl)*sphpar%dfi - sphpar%fi) .GT. 0 .OR. &
  305. abs(2*sphpar%fi) .GT. ABS(dxold*sphpar%dfi) ) then
  306. dxold=dx
  307. dx=0.5*(xh-xl)
  308. sphpar%hsmooth=xl+dx
  309. if(xl.EQ.sphpar%hsmooth)return
  310. else
  311. dxold=dx
  312. dx=sphpar%fi/sphpar%dfi
  313. temp=sphpar%hsmooth
  314. sphpar%hsmooth=temp-dx
  315. if(temp.EQ.sphpar%hsmooth)return
  316. endif
  317. if(abs(dx).LT.HSM_BISECTION_PREC*hmax) return
  318. call hfunc(sphpar,psys,nblist)
  319. if(sphpar%fi.lt.0) then
  320. xl=sphpar%hsmooth
  321. else
  322. xh=sphpar%hsmooth
  323. endif
  324. enddo
  325. return
  326. end subroutine hsafe
  327. subroutine bracketh(sphpar,psys,nblist,hmin,hmax)
  328. type(particle_system_type) psys
  329. type(sphpar_type) sphpar
  330. type(nblist_type) nblist
  331. integer j
  332. real hmin,hmax,f1,f2
  333. hmax=sphpar%hsmooth
  334. hmin=hmax/HSM_BRACKET_FAC
  335. call hfunc(sphpar,psys,nblist)
  336. f2=sphpar%fi
  337. sphpar%hsmooth=hmin
  338. call hfunc(sphpar,psys,nblist)
  339. f1=sphpar%fi
  340. do j=1,HSM_BRACKET_TRY
  341. if(f1*f2.LT.0) return
  342. if(abs(f1).lt.abs(f2)) then
  343. hmin=hmin/HSM_BRACKET_FAC
  344. sphpar%hsmooth=hmin
  345. call hfunc(sphpar,psys,nblist)
  346. f1=sphpar%fi
  347. else
  348. hmax=hmax*HSM_BRACKET_FAC
  349. sphpar%hsmooth=hmax
  350. call hfunc(sphpar,psys,nblist)
  351. f2=sphpar%fi
  352. endif
  353. enddo
  354. print*,sphpar,hmin,hmax
  355. call kernelError('hsm bracketing')
  356. return
  357. end subroutine bracketh
  358. subroutine kernelError(string,i)
  359. character(len=*) :: string
  360. integer, optional :: i
  361. print*,'error detected'
  362. if(present(i)) then
  363. print*,string,i
  364. else
  365. print*,string
  366. endif
  367. stop
  368. end subroutine kernelError
  369. function UnitSphereVolume(m) result(vol)
  370. real :: vol
  371. integer,intent(in) :: m
  372. if(mod(m,2).eq.0) then
  373. vol=Pi**(m/2)/fac(m/2)
  374. else
  375. vol=2**((m+1)/2)*Pi**((m-1)/2)/fac2(m)
  376. endif
  377. end function UnitSphereVolume
  378. function fac(n)
  379. integer :: fac
  380. integer,intent(in) :: n
  381. integer :: i
  382. fac=1
  383. do i=1,n
  384. fac=fac*i
  385. enddo
  386. end function fac
  387. recursive function fac2(n) result(f2)
  388. integer :: f2
  389. integer,intent(in) :: n
  390. f2=1
  391. if(n.le.0) return
  392. if(mod(n,2).eq.0) then
  393. f2=fac(n/2)*2**(n/2)
  394. else
  395. f2=fac(n)/(fac2(n-1))
  396. endif
  397. end function fac2
  398. function fromsphpar(part)
  399. type(particle_type) :: part
  400. type(sphpar_type) :: fromsphpar
  401. fromsphpar%pos=part%pos
  402. fromsphpar%rho=massres/spherevol/part%hsml**ndim-rhomin
  403. fromsphpar%nnb=0
  404. fromsphpar%gradrho=0.
  405. fromsphpar%drhodh=0.
  406. fromsphpar%hsmooth=part%hsml
  407. fromsphpar%fi=0.
  408. fromsphpar%dfi=0.
  409. end function fromsphpar
  410. end module kernel_density_mod