aphirst

TammFTN

Feb 3rd, 2013
10,603
0
Never
2
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Fortran 24.03 KB | None | 0 0
  1. ! This file is part of TammFTN.
  2. ! Copyright (C) 2013 Adam Hirst <[email protected]>
  3. !
  4. ! TammFTN is free software: you can redistribute it and/or modify
  5. ! it under the terms of the GNU General Public License as published by
  6. ! the Free Software Foundation, either version 3 of the License, or
  7. ! (at your option) any later version.
  8. !
  9. ! TammFTN is distributed in the hope that it will be useful,
  10. ! but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. ! GNU General Public License for more details.
  13. !
  14. ! You should have received a copy of the GNU General Public License
  15. ! along with TammFTN. If not, see <http://www.gnu.org/licenses/>.
  16.  
  17.     module photonics
  18.     implicit none
  19.  
  20.     integer,  parameter :: dp = selected_real_kind(15, 307)
  21.     real(dp), parameter :: c = 299792458_dp
  22.     real(dp), parameter :: hbar = 1.05457172647E-34_dp
  23.     real(dp), parameter :: q = 1.60217656535E-19_dp ! elementary charge
  24.     real(dp), parameter :: e0 = 8.854187817E-12_dp
  25.     real(dp), parameter :: mu0 = 16*atan(1.0_dp)*1E-7 ! 4 pi 10^-7
  26.     real(dp), parameter :: pi = 4*atan(1.0_dp)
  27.  
  28.     contains
  29. !!
  30.     subroutine readin(Es, func, materl, pol, res, struct, thetas)
  31.     implicit none
  32.  
  33.     complex(dp),       pointer, intent(out) :: Es(:)
  34.     character(len=5),           intent(out) :: func
  35.     character(len=10), pointer, intent(out) :: materl(:)
  36.     character(len=2),           intent(out) :: pol
  37.     integer,                    intent(out) :: res
  38.     real(dp),          pointer, intent(out) :: struct(:), thetas(:)
  39.     integer                                 :: a, b, i, ioerr, j, gap, n, tokens
  40.     real(dp),          pointer              :: Etemp(:)
  41.     character(len=30)                       :: filename
  42.     character(len=10000)                    :: line
  43.     character(len=10)                       :: resstr
  44.  
  45.     call getarg(1, filename)
  46.     open(unit=10, file=trim(filename), status='old', iostat=ioerr)
  47.     if (ioerr /= 0) then
  48.         stop 'Error reading input file.'
  49.     end if
  50.     call getarg(2, func) ! function to perform, 'RT', 'EHS', 'SOLVE' or 'PHASE'
  51.     if (index('RT   EHS  SOLVE PHASE', func) == 0) then
  52.         stop 'Invalid function specified.'
  53.     end if
  54.     call getarg(3, pol) ! polarisation, either 'TE' or 'TM'
  55.     if (index('TE TM', pol) == 0) then
  56.         stop 'Invalid polarisation specified.'
  57.     end if
  58.     call getarg(4, resstr) ! number of points for graph-data generation, as string
  59.     read(resstr,*) res ! convert to integer via internal read
  60.     do i = 1, 4 ! first 4 lines have variable length, materials, thicknesses, energies, angles
  61.         read(10,'(a)') line ! '(a)' reads entire line
  62.         ! EXPAND n(A B) INTO A B A B ...
  63.         if (i .le. 2) then ! only do for materials and thicknesses
  64.             do
  65.                 a = scan(line, '(')
  66.                 b = scan(line, ')')
  67.                 if (a > b) then
  68.                     stop 'Formatting error, check parentheses.'
  69.                 else if ((a == 0) .or. (b == 0)) then
  70.                     exit ! no more () terms, done
  71.                 end if
  72.                 gap = scan(line(1:a), ' ', .true.) ! search backwards from ( for blank
  73.                 read(line(gap+1:a-1),*) n ! convert to integer using internal read
  74.                 line = line(1:gap) // repeat(line(a+1:b-1) // ' ', n) // line(b+2:)
  75.                 ! b+2 is start of first token after ')'
  76.             end do
  77.         end if
  78.         ! REMOVE DUPLICATED SPACES
  79.         do
  80.             gap = index(line(1:len_trim(line)),'  ')
  81.             if (gap == 0) then
  82.                 exit ! no more duplicated spaces, done
  83.             else
  84.                 line(gap:) = line(gap+1:)
  85.             end if
  86.         end do
  87.         ! COUNT TOKENS IN LINE
  88.         tokens = 0
  89.         gap = 1
  90.         do
  91.             if (len_trim(line(gap:)) == 0) then
  92.                 exit ! break when no tokens in line
  93.             end if
  94.             gap = gap + scan(line(gap+1:), ' ') ! find next blank (end of current token)
  95.             tokens = tokens + 1
  96.         end do
  97.         ! LOAD INTO ARRAYS
  98.         if (i == 1) then ! materials
  99.             allocate(materl(tokens))
  100.             read(line,*) materl ! internal read
  101.         else if (i == 2) then ! layer thicknesses, in nanometres
  102.             if (tokens /= size(materl) - 1) then
  103.                 stop 'Mismatch between materials and thicknesses.'
  104.             end if
  105.             allocate(struct(tokens))
  106.             read(line,*) struct ! internal read
  107.             ! converting thicknessses to positions deferred until later
  108.         else if (i == 3) then ! energies, in eV
  109.             if (mod(tokens,2) /= 0) then ! n complex numbers => 2n real numbers
  110.                 stop 'Mismatch between number of real and imaginary energy components.'
  111.             end if
  112.             allocate(Etemp(tokens)) ! use Etemp as temporary store for Ereal and Eimag
  113.             read(line,*) Etemp ! internal read
  114.             allocate(Es(tokens/2))
  115.             do j = 1, size(Es)
  116.                 Es(j) = cmplx(Etemp(2*j-1),Etemp(2*j),dp)
  117.                 ! cast real and imaginary components of energy into Es
  118.             end do
  119.         else if (i == 4) then ! angles, in degrees
  120.             if ((size(Es) == 2) .and. (size(thetas) == 2)) then
  121.                 stop '2D contour plot of energy and angle not implemented at this time.'
  122.             end if
  123.             allocate(thetas(tokens))
  124.             read(line,*) thetas
  125.             thetas = pi*thetas/180
  126.         end if
  127.     end do
  128.     close(10)
  129.  
  130.     end subroutine readin
  131. !
  132.     subroutine refindex(Ein, materl, n)
  133.     implicit none
  134.  
  135.     complex(dp),          intent(in)  :: Ein
  136.     character(len=*),     intent(in)  :: materl(:)
  137.     complex(dp), pointer, intent(out) :: n(:)
  138.     complex(dp)                       :: E
  139.     integer                           :: i
  140.  
  141.     allocate(n(size(materl)))
  142.     E = cmplx(real(Ein),0,dp)
  143.     ! only real(E) needed for refractive index
  144.     do i = 1, size(materl)
  145.         ! STANDARD DIELECTRICS
  146.         if (materl(i) == 'air') then
  147.             n(i) = (1,0)
  148.         else if (materl(i) == 'glass') then
  149.             n(i) = (1.5,0)
  150.         else if (materl(i) == 'prism') then
  151.             n(i) = (2,0)
  152.         else if (materl(i) == 'SiO2') then ! Silicon Dioxide
  153.             n(i) = (1.47,0)
  154.         else if (materl(i) == 'TiO2') then ! Titanium Dioxide
  155.             n(i) = (2.37,0)
  156.         ! MODEL METAL
  157.         else if (materl(i) == 'modmet') then
  158.             n(i) = sqrt(1 - 1/(E*(E + (0,0.01))))
  159.         ! STANDARD METALS
  160.         else if (materl(i) == 'Au') then ! Gold
  161.             n(i) = sqrt(1 - 73.1025/(E*(E + (0,0.0184))))
  162.         ! OTHER DRUDE-FORM MATERIALS
  163.         else if (materl(i) == 'TiN') then
  164.             !n(i) = sqrt(1 - 33.64/(E*(E + (0,1.1))))
  165.             n(i) = sqrt( 1 - 33.64/(E*(E + (0,0.3))) + 33.64/(15.21 - E*(E + (0,0.3))) ) ! 1.1
  166.             ! "SPP study of optical dielectric function of TiNx"
  167.         else if (materl(i) == 'ITO') then
  168.             n(i) = 1.94936 * sqrt(1 - 1.26113/(E * (E + (0,0.111)))) ! loss 0.111
  169.             ! Rhodes et al, full loss term
  170.         else if (materl(i) == 'ITO_NL') then ! NL = No Losses
  171.             n(i) = 1.94936 * sqrt(1 - 1.26113/(E * (E + (0,0))))
  172.         ! SPECIAL MATERIALS
  173.         else if (materl(i) == 'TiN_F') then
  174.             n(i) = sqrt(1.95 - 40.2083/(E**2 + E*(0,0.746)) + (2.16736)/(12.0409 - E**2 &
  175.                  - E*(0,0.91261)) + (229.85)/(33.4084 - E**2 - E*(0,5.85514)))
  176.             ! TiN Fitted, Applied Surface Science 175-176, p270
  177.         else
  178.             write(*,*) 'Unsupported material: ', materl(i), '.'
  179.             stop
  180.         end if
  181.     end do
  182.     end subroutine refindex
  183. !
  184.     subroutine wavevect(n, theta, k)
  185.     implicit none
  186.  
  187.     complex(dp),          intent(in)  :: n(:)
  188.     real(dp),             intent(in)  :: theta
  189.     complex(dp), pointer, intent(out) :: k(:)
  190.     integer                           :: i
  191.  
  192.     allocate(k(0:size(n))) ! k'z is at entry 0
  193.     k(0) = n(1) * sin(theta) ! fixed at left of structure
  194.     do i = 1, size(n)
  195.         k(i) = sqrt(n(i)**2 - k(0)**2)
  196.     end do
  197.     end subroutine wavevect
  198. !
  199.     subroutine interpos(struct)
  200.     implicit none
  201.  
  202.     real(dp), intent(inout) :: struct(:)
  203.     integer                 :: i
  204.  
  205.     if (size(struct) .gt. 1) then
  206.         do i = 2, size(struct)
  207.             struct(i) = struct(i) + struct(i-1) ! convert thicknesses into interface positions
  208.         end do
  209.     end if
  210.  
  211.     end subroutine interpos
  212. !
  213.     subroutine trnsmtrx(E, materl, pol, struct, theta, k, n, trnsfr)
  214.     implicit none
  215.  
  216.     complex(dp),          intent(in)  :: E
  217.     character(len=*),     intent(in)  :: materl(:), pol
  218.     real(dp),             intent(in)  :: struct(:), theta
  219.     complex(dp), pointer, intent(out) :: k(:), n(:), trnsfr(:,:,:)
  220.     complex(dp)                       :: M(2,2)
  221.     integer                           :: i
  222.  
  223.     call refindex(E, materl, n)
  224.     call wavevect(n, theta, k)
  225.     allocate(trnsfr(size(n),2,2))
  226.     trnsfr(1,:,:) = reshape((/1,0,0,1/),(/2,2/))
  227.     ! identity matrix, since transferring into layer 1 does not alter coefficients
  228.     do i = 2, size(n)
  229.         if (pol == 'TE') then
  230.             M(1,1) = (k(i) + k(i-1)) * exp(E * cmplx(0,pi*struct(i-1)/620,dp) * (k(i) - k(i-1)))
  231.             M(1,2) = (k(i) - k(i-1)) * exp(E * cmplx(0,pi*struct(i-1)/620,dp) * (k(i) + k(i-1)))
  232.             M(2,1) = (k(i) - k(i-1)) * exp(E * cmplx(0,-pi*struct(i-1)/620,dp) * (k(i) + k(i-1)))
  233.             M(2,2) = (k(i) + k(i-1)) * exp(E * cmplx(0,-pi*struct(i-1)/620,dp) * (k(i) - k(i-1)))
  234.             ! interface matrix characterising coefficient transfer from (i-1) 'into' (i)
  235.             ! struct(i-1) since (i-1)th interface precedes (i)th layer
  236.             trnsfr(i,:,:) = M / (2 * k(i))
  237.         else if (pol == 'TM') then
  238.             M(1,1) = (k(i-1)*n(i)**2 + k(i)*n(i-1)**2) * exp(E * cmplx(0,pi*struct(i-1)/620,dp) &
  239.                    * (k(i) - k(i-1)))
  240.             M(1,2) = (k(i-1)*n(i)**2 - k(i)*n(i-1)**2) * exp(E * cmplx(0,pi*struct(i-1)/620,dp) &
  241.                    * (k(i-1) + k(i)))
  242.             M(2,1) = (k(i-1)*n(i)**2 - k(i)*n(i-1)**2) * exp(E * cmplx(0,-pi*struct(i-1)/620,dp) &
  243.                    * (k(i-1) + k(i)))
  244.             M(2,2) = (k(i-1)*n(i)**2 + k(i)*n(i-1)**2) * exp(E * cmplx(0,pi*struct(i-1)/620,dp) &
  245.                    * (k(i-1) - k(i)))
  246.             trnsfr(i,:,:) = M / (2 * k(i-1) * n(i)**2)
  247.         end if
  248.         trnsfr(i,:,:) = matmul(trnsfr(i,:,:),trnsfr(i-1,:,:))
  249.         ! multiply interface matrix with previous transfer matrix
  250.     end do
  251.     end subroutine trnsmtrx
  252. !
  253.     subroutine fieldint(A, B, E, k, kz, n, pol, x, EH)
  254.     implicit none
  255.  
  256.     complex(dp),      intent(in)  :: A, B, E, k, kz, n
  257.     character(len=2), intent(in)  :: pol
  258.     real(dp),         intent(in)  :: x
  259.     real(dp),         intent(out) :: EH(2,2) ! E in row 1, H in row 2
  260.  
  261.     if (pol == 'TE') then
  262.         ! (:,1) is perpendicular to planar interfaces (x)
  263.         ! (:,2) is parallel to planar interfaces (y or z)
  264.         ! E_x, E_y
  265.         EH(1,1) = 0_dp
  266.         EH(1,2) = abs(A*exp(k*E*cmplx(0,-pi*x/620,dp)) + B*exp(k*E*cmplx(0,pi*x/620,dp)))**2
  267.         ! H_x, H_z
  268.         EH(2,1) = abs(kz*(A*exp(k*E*cmplx(0,-pi*x/620,dp)) + B*exp(k*E*cmplx(0,pi*x/620,dp))) &
  269.                 / (c*mu0))**2
  270.         EH(2,2) = abs(k*(B*exp(k*E*cmplx(0,pi*x/620,dp)) - A*exp(k*E*cmplx(0,-pi*x/620,dp))) &
  271.                 /(c*mu0))**2
  272.     else if (pol == 'TM') then
  273.         ! E_x, E_z
  274.         EH(1,1) = abs((kz/k)*(A*exp(k*E*cmplx(0,-pi*x/620,dp)) + B*exp(k*E*cmplx(0,pi*x/620,dp))))**2
  275.         EH(1,2) = abs(A*exp(k*E*cmplx(0,-pi*x/620,dp)) + B*exp(k*E*cmplx(0,pi*x/620,dp)))**2
  276.         ! H_x, H_y
  277.         EH(2,1) = 0_dp
  278.         EH(2,2) = abs((A*exp(k*E*cmplx(0,-pi*x/620,dp)) - B*exp(k*E*cmplx(0,pi*x/620,dp))) &
  279.                 * (n**2 * c * e0)/k)**2
  280.     end if
  281.  
  282.     end subroutine fieldint
  283. !
  284.     subroutine poweravg(A, B, E, k, n, pol, x, S)
  285.     implicit none
  286.  
  287.     complex(dp),      intent(in)  :: A, B, E, k, n
  288.     character(len=*), intent(in)  :: pol
  289.     real(dp),         intent(in)  :: x
  290.     real(dp),         intent(out) :: S
  291.  
  292.     if (pol == 'TE') then
  293.         S = real((A*exp(k*E*cmplx(0,-pi*x/620,dp)) + B*exp(k*E*cmplx(0,pi*x/620,dp))) &
  294.           * conjg(k*(B*exp(k*E*cmplx(0,pi*x/620,dp)) - A*exp(k*E*cmplx(0,-pi*x/620,dp)))) / (2*c*mu0))
  295.     else if (pol == 'TM') then
  296.         S = real((A*exp(k*E*cmplx(0,-pi*x/620,dp)) + B*exp(k*E*cmplx(0,pi*x/620,dp))) * (c*e0/2) &
  297.           * conjg((n**2 / k) * (A*exp(k*E*cmplx(0,-pi*x/620,dp)) - B*exp(k*E*cmplx(0,pi*x/620,dp)))))
  298.     end if
  299.  
  300.     end subroutine poweravg
  301. !
  302.     subroutine reftrans(E, materl, pol, struct, theta, Rc, Tc, phi)
  303.     implicit none
  304.  
  305.     complex(dp),      intent(in)  :: E
  306.     character(len=*), intent(in)  :: materl(:), pol
  307.     real(dp),         intent(in)  :: struct(:), theta
  308.     real(dp),         intent(out) :: phi, Rc, Tc
  309.     complex(dp), pointer          :: k(:), n(:), trnsfr(:,:,:)
  310.     complex(dp)                   :: M(2,2), r, t
  311.     real(dp)                      :: SI, ST
  312.  
  313.  
  314.     call trnsmtrx(E, materl, pol, struct, theta, k, n, trnsfr)
  315.     M = trnsfr(size(n),:,:)
  316.     r = -M(1,2)/M(1,1)
  317.     t = M(2,2) - M(1,2)*M(2,1)/M(1,1)
  318.     Rc = abs(r)**2
  319.     call poweravg(cmplx(0,0,dp), t, E, k(size(n)), n(size(n)), pol, struct(1), ST)
  320.     call poweravg(cmplx(0,0,dp), cmplx(1,0,dp), E, k(1), n(1), pol, struct(size(struct)), SI)
  321.     Tc = ST/SI
  322.     phi = 180*atan2(imag(r),real(r))/pi
  323.     ! ENSURE -180 RENDERS AS 180
  324.     if (phi == -180) then
  325.         phi = 180
  326.     end if
  327.  
  328.     end subroutine reftrans
  329. !
  330.     subroutine rtenergy(Ecs, materl, pol, res, struct, theta, output)
  331.     implicit none
  332.  
  333.     complex(dp),          intent(in)  :: Ecs(2)
  334.     character(len=*),     intent(in)  :: materl(:), pol
  335.     integer,              intent(in)  :: res
  336.     real(dp),             intent(in)  :: struct(:), theta
  337.     real(dp),    pointer, intent(out) :: output(:,:)
  338.     complex(dp)                       :: E, Es(2)
  339.     integer                           :: i
  340.  
  341.     write(*,*) 'Plotting R, T and phi against E...'
  342.     do i = 1,2
  343.         Es(i) = cmplx(real(Ecs(i)),0,dp) ! varying E, so disregard imaginary components
  344.     end do
  345.     allocate(output(res,4)) ! E, R, T, phi
  346.     do i = 1, res
  347.         E = Es(1) + (Es(2) - Es(1))*(i-1)/res
  348.         output(i,1) = real(E)
  349.         call reftrans(E, materl, pol, struct, theta, output(i,2), output(i,3), output(i,4))
  350.         ! outputs are (Rc, Tc, phi)
  351.     end do
  352.  
  353.     end subroutine rtenergy
  354. !
  355.     subroutine rttheta(E, materl, pol, res, struct, thetas, output)
  356.     implicit none
  357.  
  358.     complex(dp),       intent(in)  :: E
  359.     character(len=*),  intent(in)  :: materl(:), pol
  360.     integer,           intent(in)  :: res
  361.     real(dp),          intent(in)  :: struct(:), thetas(2)
  362.     real(dp), pointer, intent(out) :: output(:,:)
  363.     integer                        :: i
  364.     real(dp)                       :: theta
  365.  
  366.     write(*,*) 'Plotting R, T and phi against theta...'
  367.     allocate(output(res,4)) ! theta, R, T, phi
  368.     do i = 1, res
  369.         theta = thetas(1) + (thetas(2) - thetas(1))*(i-1)/res
  370.         output(i,1) = 180*theta/pi
  371.         call reftrans(E, materl, pol, struct, theta, output(i,2), output(i,3), output(i,4)) ! R, T, phi
  372.     end do
  373.  
  374.     end subroutine rttheta
  375. !
  376.     subroutine ehsplot(E, func, materl, pol, res, struct, theta, output)
  377.  
  378.     implicit none
  379.  
  380.     complex(dp),          intent(in)  :: E
  381.     character(len=*),     intent(in)  :: func, materl(:), pol
  382.     integer,              intent(in)  :: res
  383.     real(dp),             intent(in)  :: struct(:), theta
  384.     real(dp),    pointer, intent(out) :: output(:,:)
  385.     complex(dp), pointer              :: AB(:,:), k(:), n(:), trnsfr(:,:,:)
  386.     real(dp)                          :: EH(2,2), S, x
  387.     integer                           :: i, j
  388.     complex(dp)                       :: M(2,2), r
  389.  
  390.     write(*,*) 'Plotting E, H and S through structure...'
  391.     allocate(output(res,7)) ! x, n, E(1er), E(||), H(1er), H(||), S
  392.     call trnsmtrx(E, materl, pol, struct, theta, k, n, trnsfr)
  393.     allocate(AB(size(n),2))
  394.     ! SET LHS COEFFICIENTS TO (r,1) OR (1,0) FOR INCIDENT/SURFACE RESPECTIVELY
  395.     if (func == 'SOLVE') then
  396.         AB(1,:) = (/cmplx(1,0,dp), cmplx(0,0,dp)/) ! reflected = r, 0 (confined)
  397.     else
  398.         M = trnsfr(size(n),:,:)
  399.         r = -M(1,2)/M(1,1)
  400.         AB(1,:) = (/r, cmplx(1,0,dp)/) ! reflected, incident
  401.     end if
  402.     ! GENERATE ALL COEFFICIENTS
  403.     do i = 2, size(n) ! no need to recalculate AB(1)
  404.         AB(i,:) = matmul(trnsfr(i,:,:),AB(1,:))
  405.     end do
  406.     ! CALCULATE E, H AND S FOR ALL x
  407.     do i = 1, res
  408.         x = struct(1) + (struct(size(struct)) - struct(1))*(i-1)/res
  409.         output(i,1) = x
  410.         do j = 1, size(struct)
  411.             if (x < struct(j)) then ! .lt. interface i => in material i
  412.                 call fieldint(AB(j,1), AB(j,2), E, k(j), k(0), n(j), pol, x, EH)
  413.                 call poweravg(AB(j,1), AB(j,2), E, k(j), n(j), pol, x, S)
  414.                 output(i,2) = real(n(j))
  415.                 exit
  416.             end if
  417.         end do
  418.         output(i,3:4) = EH(1,:) ! store E
  419.         output(i,5:6) = EH(2,:) ! store H
  420.         output(i,7) = S ! store S
  421.     end do
  422.  
  423.     end subroutine ehsplot
  424. !
  425.     subroutine surfsolv(E, materl, pol, res, struct, theta, output)
  426.     implicit none
  427.  
  428.     complex(dp),          intent(in)  :: E
  429.     character(len=*),     intent(in)  :: materl(:), pol
  430.     integer,              intent(in)  :: res
  431.     real(dp),             intent(in)  :: struct(:), theta
  432.     real(dp),    pointer, intent(out) :: output(:,:)
  433.     integer                           :: best, i, ioerr
  434.     complex(dp)                       :: Es(5)
  435.     character(len=10)                 :: filename
  436.     complex(dp), pointer              :: k(:), n(:), trnsfr(:,:,:)
  437.     real(dp)                          :: M(5), step
  438.  
  439.     write(*,*) 'Solving for defect/surface state...'
  440.     call getarg(1, filename)
  441.     open(unit=20, file= trim(filename) // '_log', status='replace', iostat=ioerr)
  442.     if (ioerr /= 0) then
  443.         stop 'Error writing to log file.'
  444.     end if
  445.     ! DETERMINE BEST SOLUTION OF E
  446.     step = 0.01 ! eV
  447.     Es(1) = E
  448.     do
  449.         ! GENERATE "CROSS" OF E "POINTS"
  450.         Es(:) = (/Es(1), Es(1)+step*(0,1), Es(1)+step, Es(1)-step*(0,1), Es(1)-step/)
  451.         ! centre, up (+i), right (+1), down (-i), left (-1)
  452.         ! CALCULATE M(1,1) FOR EACH E IN CROSS
  453.         do i = 1, 5
  454.             call trnsmtrx(Es(i), materl, pol, struct, theta, k, n, trnsfr)
  455.             M(i) = abs(trnsfr(size(n),1,1))
  456.             if (i == 1) then
  457.                 write(*,*) real(E)*real(k(0))
  458.             end if
  459.         end do
  460.         best = minloc(M,1)
  461.         write(20,'(4ES14.6)') real(Es(best)), imag(Es(best)), step, M(best)
  462.         ! HALVE STEP SIZE IF BEST E IS THE "CENTRE", ELSE RECENTRE AROUND BEST E
  463.         if (best == 1) then
  464.             step = step/2
  465.         else
  466.             Es(1) = Es(best)
  467.         end if
  468.         ! SMALL STEP SIZE IMPLIES SUFFICIENT CONVERGENCE
  469.         if (step < epsilon(step)) then
  470.             exit
  471.         end if
  472.     end do
  473.     write(*,*) 'Solution found!'
  474.     write(*,*) 'E = ', real(Es(1)), '-', -imag(Es(1)), 'i'
  475.     write(*,*) 'Characteristic lifetime is ',-hbar/(q*imag(Es(1))),' seconds.'
  476.     close(20)
  477.     ! GENERATE EHS PLOT DATA AT OPTIMUM E
  478.     call ehsplot(Es(1), 'SOLVE', materl, pol, res, struct, theta, output)
  479.  
  480.     end subroutine surfsolv
  481. !
  482.     subroutine phasmtch(Es, materl, pol, res, struct, theta, output)
  483.     implicit none
  484.  
  485.     complex(dp),                intent(in)  :: Es(:)
  486.     character(len=*),           intent(in)  :: materl(:), pol
  487.     integer,                    intent(in)  :: res
  488.     real(dp),                   intent(in)  :: struct(:), theta
  489.     real(dp),          pointer, intent(out) :: output(:,:)
  490.     integer                                 :: layer
  491.     character(len=10), pointer              :: matlef(:), matrig(:)
  492.     complex(dp), pointer                    :: n(:)
  493.     real(dp),          pointer              :: strlef(:), strrig(:), outlef(:,:), outrig(:,:)
  494.     real(dp)                                :: thetin
  495.  
  496.     !write(*,*) 'Generating phase plots for interface matching condition...'
  497.     allocate(output(res,4)) ! E, phiL, phiR, phiTOT
  498.     write(*,*) 'First three materials: ',trim(materl(1)),', ',trim(materl(2)),', ',trim(materl(3)),'.'
  499.     write(*,*) 'In which layer should the virtual interface be constructed (at the far left)?'
  500.     read(*,*) layer ! read layer # in which to perform phase-matching, as string
  501.     ! ALLOCATE LEFT AND RIGHT materl(:) AND struct(:) ARRAYS
  502.     allocate(matlef(layer))
  503.     allocate(matrig(size(materl) - layer + 1))
  504.     allocate(strlef(layer - 1))
  505.     allocate(strrig(size(materl) - layer ))
  506.     ! CONSTRUCT materl(:) ARRAYS
  507.     matlef(:) = materl(layer:1:-1) ! third entry indicates "stride", negative reverses
  508.     matrig(1) = materl(layer)
  509.     matrig(2:size(matrig)) = materl(layer:size(materl))
  510.     ! CONSTRUCT struct(:) ARRAYS
  511.     strlef(1) = 0
  512.     strlef(2:size(strlef)) = struct(layer-1:2:-1)
  513.     strrig(1) = 0
  514.     strrig(2:size(strrig)) = struct(layer:size(struct))
  515.     ! CONVERT THICKNESSES TO POSITIONS
  516.     call interpos(strlef)
  517.     call interpos(strrig)
  518.     ! DETERMINE INTERNAL ANGLE WITHIN CONSIDERED INTERFACE
  519.     call refindex(cmplx(1,0,dp), materl(1:layer:layer-1), n)
  520.     thetin = asin(real(n(1))*sin(theta)/real(n(2)))
  521.     write(*,*) 'Internal angle is ',180*thetin/pi,' degrees.'
  522.     ! PERFORM REFLECTION CALCULATION FOR LEFT AND RIGHT HALF-STRUCTURES
  523.     call rtenergy(Es, matlef, pol, res, strlef, thetin, outlef)
  524.     write(*,*) 'Left phase complete!'
  525.     call rtenergy(Es, matrig, pol, res, strrig, thetin, outrig)
  526.     write(*,*) 'Right phase complete!'
  527.     ! EXTRACT PHASES AND CONSTRUCT FINAL OUTPUT ARRAY
  528.     output(:,1) = outlef(:,1) ! populate Energy column
  529.     output(:,2) = outlef(:,4) ! phiL
  530.     output(:,3) = outrig(:,4) ! phiR
  531.     output(:,4) = outlef(:,4) + outrig(:,4) ! phiL + phiR = phiTOT
  532.  
  533.     end subroutine phasmtch
  534. !
  535.     subroutine writeout(output)
  536.     implicit none
  537.  
  538.     real(dp), intent(in) :: output(:,:)
  539.     character(len=20)    :: filename
  540.     integer              :: i, ioerr, j
  541.  
  542.     call getarg(1, filename)
  543.     write(*,*) 'Writing data to file...'
  544.     open(unit=30, file=trim(filename) // '_out', status='replace', iostat=ioerr)
  545.     if (ioerr /= 0) then
  546.         stop 'Error writing to output file.'
  547.     end if
  548.     do i = 1, size(output(:,1))
  549.         write(30,'(7ES13.5)') (output(i,j), j = 1, size(output(1,:)))
  550.         ! format statement with 7 repeats, scientific, 14 width, 6 decimal
  551.         ! implied do loop
  552.     end do
  553.     close(30)
  554.     write(*,*) 'Data written!'
  555.  
  556.     end subroutine writeout
  557. !
  558.     subroutine flowctrl
  559.     implicit none
  560.  
  561.     complex(dp), pointer       :: Es(:)
  562.     character(len=5)           :: func
  563.     character(len=10), pointer :: materl(:)
  564.     character(len=2)           :: pol
  565.     integer                    :: res
  566.     real(dp), pointer          :: output(:,:), struct(:), thetas(:)
  567.  
  568.     call readin(Es, func, materl, pol, res, struct, thetas)
  569.     if (func .ne. 'PHASE') then
  570.         call interpos(struct) ! convert thicknesses to positions, except for phase-matching
  571.     end if
  572.     if ((func == 'RT') .and. (size(thetas) == 1)) then
  573.         call rtenergy(Es, materl, pol, res, struct, thetas(1), output)
  574.     else if ((func == 'RT') .and. (size(thetas) == 2)) then
  575.         call rttheta(Es(1), materl, pol, res, struct, thetas, output)
  576.     else if (func == 'EHS') then
  577.         call ehsplot(Es(1), func, materl, pol, res, struct, thetas(1), output)
  578.     else if (func == 'SOLVE') then
  579.         call surfsolv(Es(1), materl, pol, res, struct, thetas(1), output)
  580.     else if (func == 'PHASE') then
  581.         call phasmtch(Es, materl, pol, res, struct, thetas(1), output)
  582.     else
  583.         stop 'Parameters incompatible with desired function, or function unavailable.'
  584.     end if
  585.     call writeout(output)
  586.  
  587.     end subroutine flowctrl
  588. !!
  589.     end module photonics
  590. !
  591. !
  592.     program main
  593.     use photonics
  594.  
  595.     implicit none
  596.  
  597.     call flowctrl
  598.  
  599.     end program main
Advertisement