@@ -35,6 +35,9 @@ module m_photoi_mc
3535 ! > Minimal photon weight
3636 real (dp), protected :: phmc_min_weight = 1.0_dp
3737
38+ ! > Non-ionizing absorption coefficient (1/m), 0 if none
39+ real (dp), protected :: phmc_k3 = 0.0_dp
40+
3841 ! > Table for photoionization
3942 type (phmc_tbl_t), public , protected :: phmc_tbl
4043
@@ -104,12 +107,15 @@ subroutine phmc_initialize(cfg, is_used, source_type)
104107
105108 select case (source_type)
106109 case (" Zheleznyak" )
110+ phmc_k3 = 0.0_dp
107111 ! Standard Zheleznyak model for dry air
108112 call phmc_get_table_air(phmc_tbl, p_O2, p_H2O, absfunc_Zheleznyak)
109113 case (" Naidis_humid" )
114+ phmc_k3 = (0.26e2_dp / UC_torr_to_bar) * p_H2O
110115 ! Naidis model for humid air
111- call phmc_get_table_air(phmc_tbl, p_O2, p_H2O, absfunc_Naidis_humid )
116+ call phmc_get_table_air(phmc_tbl, p_O2, p_H2O, absfunc_Zheleznyak )
112117 case (" Aints_humid" )
118+ phmc_k3 = 0.0_dp
113119 ! Aints model for humid air
114120 call phmc_get_table_air(phmc_tbl, p_O2, p_H2O, absfunc_Aints_humid)
115121 case default
@@ -354,49 +360,58 @@ end function get_rlvl_length
354360
355361 ! > Given a list of photon production positions (xyz_in), compute where they
356362 ! > end up (xyz_out).
357- subroutine phmc_do_absorption (xyz_in , xyz_out , n_dim , n_photons , tbl , prng )
363+ subroutine phmc_do_absorption (xyz_in , xyz_out , n_dim , n_photons , tbl , prng , k3 )
358364 use m_lookup_table
359365 use m_random
360366 use omp_lib
361- integer , intent (in ) :: n_photons ! < Number of photons
362- ! > Input (x,y,z) values
363- real (dp), intent (in ) :: xyz_in(3 , n_photons)
364- ! > Output (x,y,z) values
365- real (dp), intent (out ) :: xyz_out(3 , n_photons)
366- integer , intent (in ) :: n_dim ! < 2 or 3 dimensional
367- ! < Lookup table
368- type (LT_t), intent (in ) :: tbl
369- type (PRNG_t), intent (inout ) :: prng ! < Random number generator
370- integer :: n, proc_id
371- real (dp) :: rr, dist
372-
373- ! $omp parallel private(n, rr, dist, proc_id)
367+ ! > Input: number of generated photons. Output: number of ionizing photons.
368+ ! > These can differ when k3 is non-zero.
369+ integer , intent (inout ) :: n_photons
370+ ! > Input (x,y,z) values of photon production
371+ real (dp), intent (in ) :: xyz_in(3 , n_photons)
372+ ! > Output (x,y,z) values of photon absorption
373+ real (dp), intent (out ) :: xyz_out(3 , n_photons)
374+ integer , intent (in ) :: n_dim ! < 2 or 3 dimensional
375+ type (LT_t), intent (in ) :: tbl ! < Lookup table for absorption distance
376+ type (PRNG_t), intent (inout ) :: prng ! < Random number generator
377+ real (dp), intent (in ) :: k3 ! < non-ionizing absorption coefficient
378+ logical , allocatable :: mask(:)
379+ integer :: n, proc_id
380+ real (dp) :: rr, dist, p_ionization
381+
382+ if (n_dim < 2 .or. n_dim > 3 ) error stop " n_dim should be 2 or 3"
383+
384+ allocate (mask(n_photons))
385+
386+ ! $omp parallel private(n, rr, dist, proc_id, p_ionization)
374387 proc_id = 1 + omp_get_thread_num()
375388
376- if (n_dim == 2 ) then
377- ! $omp do
378- do n = 1 , n_photons
379- rr = prng% rngs(proc_id)% unif_01()
380- dist = LT_get_col(tbl, 1 , rr)
381- ! Pick a random point on a sphere, and ignore the last dimension
382- xyz_out(1 :3 , n) = xyz_in(1 :3 , n) + &
383- prng% rngs(proc_id)% sphere(dist)
384- end do
385- ! $omp end do
386- else if (n_dim == 3 ) then
387- ! $omp do
388- do n = 1 , n_photons
389- rr = prng% rngs(proc_id)% unif_01()
390- dist = LT_get_col(tbl, 1 , rr)
391- xyz_out(:, n) = xyz_in(:, n) + prng% rngs(proc_id)% sphere(dist)
392- end do
393- ! $omp end do
394- else
395- print * , " phmc_do_absorption: unknown n_dim" , n_dim
396- stop
397- end if
389+ ! $omp do
390+ do n = 1 , n_photons
391+ rr = prng% rngs(proc_id)% unif_01()
392+ ! Sample travel distance
393+ dist = LT_get_col(tbl, 1 , rr)
394+ ! Note that in 2D we ignore the last dimension
395+ xyz_out(:, n) = xyz_in(:, n) + prng% rngs(proc_id)% sphere(dist)
396+
397+ ! Test for non-ionizing absorption
398+ if (k3 > 0 ) then
399+ p_ionization = exp (- k3 * dist)
400+ mask(n) = (prng% rngs(proc_id)% unif_01() < p_ionization)
401+ else
402+ mask(n) = .true.
403+ end if
404+ end do
398405 ! $omp end parallel
399406
407+ ! Keep only photons that led to ionization
408+ n_photons = 0
409+ do n = 1 , size (mask)
410+ if (mask(n)) then
411+ n_photons = n_photons + 1
412+ xyz_out(:, n_photons) = xyz_out(:, n)
413+ end if
414+ end do
400415 end subroutine phmc_do_absorption
401416
402417 ! !> Given a list of photon production positions (xyz_in), compute where they
@@ -524,7 +539,7 @@ subroutine phmc_set_src(tree, rng, i_src, i_photo, use_cyl, dt)
524539 if (use_cyl) then ! 2D only
525540 ! Get location of absorption. On input, xyz is set to (r, z, 0). On
526541 ! output, the coordinates thus correspond to (x, z, y)
527- call phmc_do_absorption(xyz_src, xyz_abs, 3 , n_used, phmc_tbl% tbl, prng)
542+ call phmc_do_absorption(xyz_src, xyz_abs, 3 , n_used, phmc_tbl% tbl, prng, phmc_k3 )
528543
529544 ! $omp do
530545 do n = 1 , n_used
@@ -541,7 +556,7 @@ subroutine phmc_set_src(tree, rng, i_src, i_photo, use_cyl, dt)
541556 end if
542557 else
543558 ! Get location of absorbption
544- call phmc_do_absorption(xyz_src, xyz_abs, NDIM, n_used, phmc_tbl% tbl, prng)
559+ call phmc_do_absorption(xyz_src, xyz_abs, NDIM, n_used, phmc_tbl% tbl, prng, phmc_k3 )
545560
546561 if (ST_use_dielectric) then
547562 ! Handle photons that collide with dielectrics separately
0 commit comments