module reflections implicit none private integer, parameter :: r8=selected_real_kind(15,300) real(r8), parameter :: tinyr8=tiny(1._r8) public :: reflect,inters_linewall,inside public :: linecone_coord,interssegm_coord,interssegm contains subroutine reflect(ki,nsurf,ko) implicit none real(r8), intent(in), dimension(3) :: ki real(r8), intent(in), dimension(3) :: nsurf real(r8), intent(out), dimension(3) :: ko real(r8) :: twokn,norm2 norm2 = dot_product(nsurf,nsurf) if (norm2>0.0_r8) then twokn = 2.0_r8*dot_product(ki,nsurf)/norm2 ko=ki-twokn*nsurf else ko=ki end if end subroutine reflect subroutine inters_linewall(xv,kv,rw,zw,nw,sint,normw) implicit none real(r8), intent(in), dimension(3) :: xv,kv integer, intent(in) :: nw real(r8), dimension(nw), intent(in) :: rw,zw real(r8), intent(out) :: sint real(r8), dimension(3), intent(out) :: normw integer :: i,j,ni,iint real(r8), dimension(2) :: si,ti real(r8) :: drw,dzw,xint,yint,rint,l,kxy real(r8) :: tol=sqrt(epsilon(1.0_r8)) sint=huge(sint) iint=0 normw=0.0_r8 do i=1,nw-1 !search intersections with i-th wall segment call linecone_coord(xv,kv,rw(i:i+1),zw(i:i+1),si,ti,ni) do while (ni>0 .and. si(1)<=tol) !remove solutions with s<=0 ni = ni-1 si(1) = si(2) ti(1) = ti(2) end do do j=1,ni if ((si(j)=0._r8 .and. ti(j)<=1._r8) then !check intersection is in r,z range and keep the closest sint = si(j) iint = i end if end do end do if (iint==0) return !calculate wall normal at intersection point drw = rw(iint+1)-rw(iint) dzw = zw(iint+1)-zw(iint) xint = xv(1) + sint*kv(1) yint = xv(2) + sint*kv(2) rint = sqrt(xint**2+yint**2) l = sqrt(drw**2+dzw**2) kxy = sqrt(kv(1)**2+kv(2)**2) normw(3) = -drw/l if (rint>0.0_r8) then normw(1) = xint/rint*dzw/l normw(2) = yint/rint*dzw/l else normw(1) = kv(1)/kxy*dzw/l normw(2) = kv(2)/kxy*dzw/l end if !reverse normal if k.n>0 if (dot_product(normw,kv)>0.0_r8) normw=-normw end subroutine inters_linewall subroutine linecone_coord(xv,kv,rs,zs,s,t,n) implicit none real(r8), intent(in), dimension(3) :: xv,kv real(r8), intent(in), dimension(2) :: rs,zs real(r8), dimension(2), intent(out) :: s,t integer, intent(out) :: n real(r8) :: x0,y0,z0,kx,ky,kz real(r8) :: dr,dz,r,a,bhalf,c,delta,tvertex,zvertex,srmin,rmin,zrmin x0=xv(1) y0=xv(2) z0=xv(3) kx=kv(1) ky=kv(2) kz=kv(3) dr = rs(2)-rs(1) dz = zs(2)-zs(1) s = 0 t = 0 if (abs(dz)=0._r8 .and. s<=1._r8 .and. & t>=0._r8 .and. t<=1._r8) interssegm = .true. end function interssegm function inside(xc,yc,n,x,y) implicit none integer, intent(in) :: n real(r8), dimension(n), intent(in) :: xc,yc real(r8), intent(in) :: x,y logical :: inside integer, dimension(n) :: jint real(r8), dimension(n) :: xint real(r8), dimension(n+1) :: xclosed,yclosed integer :: i,nj xclosed(1:n)=xc(1:n) yclosed(1:n)=yc(1:n) xclosed(n+1)=xc(1) yclosed(n+1)=yc(1) call locate_unord(yclosed,n+1,y,jint,n,nj) inside=.false. if (nj==0) return do i=1,nj xint(i)=intlin(yclosed(jint(i)),xclosed(jint(i)), & yclosed(jint(i)+1),xclosed(jint(i)+1),y) end do call bubble(xint,nj) inside=(mod(locate(xint,nj,x),2)==1) end function inside function intlin(x1,y1,x2,y2,x) result(y) !linear interpolation !must be x1 != x2 implicit none real(r8),intent(in) :: x1,y1,x2,y2,x real(r8) :: y real(r8) :: a a=(x2-x)/(x2-x1) y=a*y1+(1._r8-a)*y2 end function intlin subroutine locate_unord(a,n,x,j,m,nj) implicit none integer, intent(in) :: n,m integer, intent(out) :: nj real(r8), dimension(n), intent(in) :: a real(r8), intent(in) :: x integer, dimension(m), intent(inout) :: j integer :: i nj=0 do i=1,n-1 if (x>a(i).neqv.x>a(i+1)) then nj=nj+1 if (nj<=m) j(nj)=i end if end do end subroutine locate_unord function locate(a,n,x) result(j) !Given an array a(n), and a value x, with a(n) monotonic, either !increasing or decreasing, returns a value j such that !a(j) < x <= a(j+1) for a increasing, and such that !a(j+1) < x <= a(j) for a decreasing. !j=0 or j=n indicate that x is out of range (Numerical Recipes) implicit none integer, intent(in) :: n real(r8), dimension(n), intent(in) :: a real(r8), intent(in) :: x integer :: j integer :: jl,ju,jm logical :: incr jl=0 ju=n+1 incr=a(n)>a(1) do while ((ju-jl)>1) jm=(ju+jl)/2 if(incr.eqv.(x>a(jm))) then jl=jm else ju=jm endif end do j=jl end function locate subroutine order(p,q) !returns p,q in ascending order implicit none real(r8), intent(inout) :: p,q real(r8) :: temp if (p>q) then temp=p p=q q=temp end if end subroutine order subroutine bubble(a,n) !bubble sorting of array a implicit none integer, intent(in) :: n real(r8), dimension(n), intent(inout) :: a integer :: i, j do i=1,n do j=n,i+1,-1 call order(a(j-1), a(j)) end do end do end subroutine bubble end module reflections