diff --git a/src/reflections.f90 b/src/reflections.f90 new file mode 100644 index 0000000..ffe59bd --- /dev/null +++ b/src/reflections.f90 @@ -0,0 +1,287 @@ +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 +