Skip to content

Commit 3d75107

Browse files
author
Jannis Teunissen
committed
Add support for humid air with Monte Carlo photoionization
This can be enabled with photoi%source_type set to Aints_humid or Naidis_humid
1 parent 3923923 commit 3d75107

1 file changed

Lines changed: 54 additions & 39 deletions

File tree

src/m_photoi_mc.f90

Lines changed: 54 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)