3#include "../afivo/src/cpp_macros.h"
27 [character(len=20) ::
"ionization",
"attachment",
"recombination", &
28 "detachment",
"general"]
31 integer,
parameter :: rate_max_num_coeff = 9
35 integer,
allocatable :: ix_in(:)
36 integer,
allocatable :: ix_out(:)
37 integer,
allocatable :: multiplicity_out(:)
38 integer :: n_species_in
42 real(dp) :: rate_factor
45 real(dp) :: rate_data(rate_max_num_coeff) = -huge(1.0_dp)
46 integer :: lookup_table_index
47 real(dp),
allocatable :: x_data(:)
48 real(dp),
allocatable :: y_data(:)
49 character(len=50) :: description
54 integer,
allocatable :: ix_in(:)
55 integer,
allocatable :: ix_out(:)
56 integer,
allocatable :: multiplicity_out(:)
60 type stochastic_species_t
63 end type stochastic_species_t
69 integer,
parameter :: rate_tabulated_field = 1
72 integer,
parameter :: rate_analytic_constant = 2
75 integer,
parameter :: rate_analytic_linear = 3
78 integer,
parameter :: rate_analytic_exp_v1 = 4
81 integer,
parameter :: rate_analytic_exp_v2 = 5
84 integer,
parameter :: rate_analytic_k1 = 6
87 integer,
parameter :: rate_analytic_k3 = 8
90 integer,
parameter :: rate_analytic_k4 = 9
93 integer,
parameter :: rate_analytic_k5 = 10
96 integer,
parameter :: rate_analytic_k6 = 11
99 integer,
parameter :: rate_analytic_k7 = 12
102 integer,
parameter :: rate_analytic_k8 = 13
105 integer,
parameter :: rate_analytic_k9 = 14
108 integer,
parameter :: rate_analytic_k10 = 15
111 integer,
parameter :: rate_analytic_k11 = 16
114 integer,
parameter :: rate_analytic_k12 = 17
117 integer,
parameter :: rate_analytic_k13 = 18
120 integer,
parameter :: rate_analytic_k14 = 19
123 integer,
parameter :: rate_analytic_k15 = 20
126 integer,
parameter :: max_num_species = 100
129 integer,
parameter :: max_num_reactions = 500
147 character(len=comp_len),
public,
protected ::
species_list(max_num_species)
150 type(stochastic_species_t) :: stochastic_species_list(max_num_species)
159 type(reaction_t),
public,
protected ::
reactions(max_num_reactions)
162 type(tiny_react_t) :: tiny_react(max_num_reactions)
165 type(lt_t) :: chemtbl_fld
168 type(lt_t) :: chemtbl_ee
199 type(af_t),
intent(inout) :: tree
200 type(cfg_t),
intent(inout) :: cfg
201 integer :: n, i, j, i_elec, rtype
202 character(len=string_len) :: reaction_file
203 character(len=comp_len) :: tmp_name
204 logical :: read_success
206 call cfg_get(cfg,
"input_data%file", reaction_file)
217 if (.not. read_success)
then
218 print *,
"m_chemistry: no reaction table found, using standard model"
232 reactions(1)%rate_type = rate_tabulated_field
238 reactions(1)%description =
"e + M -> e + e + M+"
245 reactions(2)%rate_type = rate_tabulated_field
253 error stop
"Varying gas density not yet supported"
273 tiny_react(n)%ix_out =
reactions(n)%ix_out
274 tiny_react(n)%multiplicity_out =
reactions(n)%multiplicity_out
301 call check_charge_conservation()
307 if (any(
reactions(n)%ix_in == i_elec) .and. &
308 .not. any(
reactions(n)%ix_out == i_elec) .and. &
312 else if (any(
reactions(n)%ix_in == i_elec) .and. &
313 any(
reactions(n)%ix_out == i_elec .and. &
314 reactions(n)%multiplicity_out == 2))
then
321 else if (all(
reactions(n)%ix_in /= i_elec) .and. &
334 if (
reactions(n)%rate_type == rate_tabulated_field)
then
347 chemtbl_ee = lt_create(0.0_dp,
td_max_ev, &
353 if (
reactions(n)%rate_type == rate_tabulated_field)
then
379 call store_stochastic_species()
381 print *,
"--- List of reactions ---"
383 write(*,
"(I4,' (',I0,') ',A15,A)") n,
reactions(n)%n_species_in, &
387 print *,
"-------------------------"
389 print *,
"--- List of gas species ---"
393 print *,
"-------------------------"
395 print *,
"--- List of plasma species ---"
399 print *,
"-------------------------"
402 call chemistry_modify_rates(cfg)
407 subroutine store_stochastic_species()
408 integer :: n, i_stoch, namelen, iv
415 i_stoch = i_stoch + 1
422 print *,
"which should be present for stochastic species (stoch_)"
423 error stop
"Species for stochastic reaction not found"
432 end subroutine store_stochastic_species
436 type(af_t),
intent(inout) :: tree
437 type(rng_t),
intent(inout) :: rng
438 integer :: lvl, iblock, id, ijk, n
439 integer :: i_to, i_from, proc_id, n_procs
440 real(dp) :: dv, lambda, product_dr, n_produced
442 real(dp),
parameter :: two_pi = 2 * acos(-1.0_dp)
447 n_procs = omp_get_max_threads()
448 call prng%init_parallel(n_procs, rng)
452 proc_id = 1+omp_get_thread_num()
454 do lvl = 1, tree%highest_lvl
456 do iblock = 1,
size(tree%lvls(lvl)%leaves)
457 id = tree%lvls(lvl)%leaves(iblock)
458 product_dr = product(tree%boxes(id)%dr)
461 i_to = stochastic_species_list(n)%i_to
462 i_from = stochastic_species_list(n)%i_from
464 do kji_do(1, tree%n_cell)
466 if (tree%coord_t == af_cyl)
then
467 dv = two_pi * product_dr * af_cyl_radius_cc(tree%boxes(id), i)
475 lambda = dv * tree%boxes(id)%cc(ijk, i_from)
476 n_produced = prng%rngs(proc_id)%poisson(lambda)
478 tree%boxes(id)%cc(ijk, i_from) = 0.0_dp
479 tree%boxes(id)%cc(ijk, i_to) = tree%boxes(id)%cc(ijk, i_to) + &
489 call prng%update_seed(rng)
494 subroutine chemistry_modify_rates(cfg)
496 type(cfg_t),
intent(inout) :: cfg
497 integer :: n_modified, n, dummy_int(0), ix
498 real(dp) :: dummy_real(0)
499 integer,
allocatable :: reaction_ix(:)
500 real(dp),
allocatable :: rate_factors(:)
502 call cfg_add(cfg,
"input_data%modified_reaction_ix", dummy_int, &
503 "Indices of reactions to be modified", .true.)
504 call cfg_add(cfg,
"input_data%modified_rate_factors", dummy_real, &
505 "Reaction rate factors for modified reactions", .true.)
506 call cfg_get_size(cfg,
"input_data%modified_reaction_ix", n_modified)
507 call cfg_get_size(cfg,
"input_data%modified_rate_factors", n)
509 if (n /= n_modified) &
510 error stop
"size(modified_reaction_ix) /= size(modified_rate_factors)"
512 if (n_modified > 0)
then
513 allocate(reaction_ix(n_modified), rate_factors(n_modified))
514 call cfg_get(cfg,
"input_data%modified_reaction_ix", reaction_ix)
515 call cfg_get(cfg,
"input_data%modified_rate_factors", rate_factors)
517 if (minval(rate_factors) < 0) &
518 error stop
"Negative value in modified_rate_factors"
519 if (minval(reaction_ix) < 1 .or. maxval(reaction_ix) >
n_reactions) &
520 error stop
"modified_reaction_ix outside valid range"
528 end subroutine chemistry_modify_rates
535 character(len=*),
intent(in) :: fname
536 real(dp),
allocatable :: fields(:), energies(:)
537 real(dp),
allocatable :: rates(:, :)
538 real(dp),
allocatable :: eta(:), alpha(:), src(:), loss(:)
539 real(dp),
allocatable :: v(:), mu(:), diff(:)
540 integer :: n, n_fields, i_elec
545 n_fields =
td_tbl%n_points
547 if (n_fields < 3) error stop
"Not enough data for linear extrapolation"
549 allocate(fields(n_fields))
550 allocate(energies(n_fields))
552 allocate(eta(n_fields), alpha(n_fields), src(n_fields), loss(n_fields))
556 if (model_has_energy_equation)
then
558 call get_rates(fields, rates, n_fields, energies)
568 loss(:) = loss(:) + rates(:, n)
570 src(:) = src(:) + rates(:, n)
574 allocate(diff(n_fields))
577 allocate(mu(n_fields))
578 allocate(v(n_fields))
583 eta(2:) = loss(2:) / v(2:)
584 eta(1) = 2 * eta(2) - eta(3)
585 alpha(2:) = src(2:) / v(2:)
586 alpha(1) = 2 * alpha(2) - alpha(3)
589 open(newunit=my_unit, file=trim(fname), action=
"write")
590 write(my_unit,
"(A)") &
591 "E/N[Td] E[V/m] Electron_mobility[m^2/(Vs)] &
592 &Electron_diffusion[m^2/s] Townsend_ioniz._coef._alpha[1/m] &
593 &Townsend_attach._coef._eta[1/m] Ionization_rate[1/s] &
594 &Attachment_rate[1/s]"
596 write(my_unit, *) fields(n), &
607 subroutine check_charge_conservation()
608 integer :: n, q_in, q_out
614 if (q_in /= q_out)
then
616 error stop
"Charge is not conserved in the above reaction"
619 end subroutine check_charge_conservation
625 real(dp),
intent(out) :: field_td
627 real(dp),
intent(in) :: min_growth_rate
629 integer :: n, n_fields
630 real(dp),
allocatable :: energies(:)
631 real(dp),
allocatable :: fields(:), rates(:, :), src(:), loss(:)
633 n_fields =
td_tbl%n_points
634 allocate(fields(n_fields))
635 allocate(energies(n_fields))
637 allocate(src(n_fields), loss(n_fields))
640 if (model_has_energy_equation)
then
642 call get_rates(fields, rates, n_fields, energies)
652 loss(:) = loss(:) + rates(:, n)
654 src(:) = src(:) + rates(:, n)
658 do n = n_fields, 1, -1
659 if (src(n) - loss(n) < min_growth_rate)
exit
663 if (n > 0) field_td = fields(n)
673 integer,
intent(in) :: n_cells
674 real(dp),
intent(in) :: fields(n_cells)
675 real(dp),
intent(out) :: rates(n_cells,
n_reactions)
676 real(dp),
intent(in),
optional :: energy_ev(n_cells)
677 integer :: n, n_coeff
678 real(dp) :: c0, c(rate_max_num_coeff)
679 real(dp) :: te(n_cells)
680 logical :: te_available
683 real(dp),
parameter :: electron_ev_to_k = 2 *
uc_elec_volt / &
686 te_available = .false.
695 c(1:n_coeff) =
reactions(n)%rate_data(1:n_coeff)
699 if (.not.
present(energy_ev)) error stop
"energy_eV required"
700 rates(:, n) = c0 * lt_get_col(chemtbl_ee, &
701 reactions(n)%lookup_table_index, energy_ev)
702 case (rate_tabulated_field)
703 rates(:, n) = c0 * lt_get_col(chemtbl_fld, &
705 case (rate_analytic_constant)
706 rates(:, n) = c0 * c(1)
707 case (rate_analytic_linear)
708 rates(:, n) = c0 * c(1) * (fields - c(2))
709 case (rate_analytic_exp_v1)
710 rates(:, n) = c0 * c(1) * exp(-(c(2) / (c(3) + fields))**2)
711 case (rate_analytic_exp_v2)
712 rates(:, n) = c0 * c(1) * exp(-(fields/c(2))**2)
713 case (rate_analytic_k1)
714 if (.not. te_available)
then
719 rates(:, n) = c0 * c(1) * (300 / te)**c(2)
720 case (rate_analytic_k3)
721 if (.not. te_available)
then
726 case (rate_analytic_k4)
728 case (rate_analytic_k5)
730 case (rate_analytic_k6)
732 case (rate_analytic_k7)
734 case (rate_analytic_k8)
736 case (rate_analytic_k9)
738 case (rate_analytic_k10)
740 case (rate_analytic_k11)
742 case (rate_analytic_k12)
744 case (rate_analytic_k13)
745 rates(:, n) = c0 * c(1) * exp(-(c(2) / (c(3) + fields))**c(4))
746 case (rate_analytic_k14)
747 rates(:, n) = c0 * c(1) * exp(-(fields / c(2))**c(3))
748 case (rate_analytic_k15)
762 integer,
intent(in) :: n_cells
764 real(dp),
intent(in) :: dens(n_cells,
n_species)
766 real(dp),
intent(inout) :: rates(n_cells,
n_reactions)
768 real(dp),
intent(out) :: derivs(n_cells,
n_species)
771 derivs(:, :) = 0.0_dp
776 rates(:, n) = rates(:, n) * &
777 product(dens(:, tiny_react(n)%ix_in), dim=2)
780 do i = 1,
size(tiny_react(n)%ix_in)
781 ix = tiny_react(n)%ix_in(i)
782 derivs(:, ix) = derivs(:, ix) - rates(:, n)
786 do i = 1,
size(tiny_react(n)%ix_out)
787 ix = tiny_react(n)%ix_out(i)
788 derivs(:, ix) = derivs(:, ix) + rates(:, n) * &
789 tiny_react(n)%multiplicity_out(i)
795 subroutine read_ignored_species(filename, ignored_species)
796 character(len=*),
intent(in) :: filename
797 character(len=comp_len),
allocatable,
intent(inout) :: &
799 character(len=comp_len) :: tmp(max_num_species)
800 character(len=string_len) :: line
801 integer :: my_unit, n_ignored
805 open(newunit=my_unit, file=filename, action=
"read")
809 read(my_unit,
"(A)",
end=998) line
812 if (line ==
"ignored_species")
then
814 read(my_unit,
"(A)") line
815 if (line(1:5) /=
"-----") &
816 error stop
"ignored_species not followed by -----"
823 read(my_unit,
"(A)",
end=999) line
827 if (line(1:1) ==
"#") cycle
830 if (line(1:5) ==
"-----")
exit
832 n_ignored = n_ignored + 1
833 read(line, *) tmp(n_ignored)
837 ignored_species = tmp(1:n_ignored)
841999 error stop
"read_ignored_species: no closing dashes"
842 end subroutine read_ignored_species
846 character(len=*),
intent(in) :: filename
847 logical,
intent(out) :: read_success
848 character(len=string_len) :: line
849 integer,
parameter :: field_len = 50
850 character(len=field_len) :: data_value(max_num_reactions)
851 character(len=field_len) :: reaction(max_num_reactions)
852 character(len=field_len) :: how_to_get(max_num_reactions)
853 character(len=10) :: length_unit(max_num_reactions)
854 type(reaction_t) :: new_reaction
856 integer :: n_reactions_found
857 integer,
parameter :: n_fields_max = 40
858 integer :: i0(n_fields_max), i1(n_fields_max)
859 integer :: n, i, k, n_found, lo, hi
860 logical :: keep_reaction
862 character(len=comp_len),
allocatable :: ignored_species(:)
865 character(len=name_len) :: name
866 character(len=field_len),
allocatable :: members(:)
869 integer,
parameter :: max_groups = 10
870 integer :: i_group, group_size
871 type(group) :: groups(max_groups)
873 call read_ignored_species(filename, ignored_species)
875 open(newunit=my_unit, file=filename, action=
"read")
877 n_reactions_found = 0
880 read_success = .false.
884 read(my_unit,
"(A)",
end=998) line
887 if (line ==
"reaction_list")
then
889 read(my_unit,
"(A)") line
890 if (line(1:5) /=
"-----") &
891 error stop
"read_reactions: reaction_list not followed by -----"
898 read(my_unit,
"(A)",
end=999) line
902 if (line(1:1) ==
"#") cycle
905 if (line(1:5) ==
"-----")
exit
908 if (line(1:1) ==
"@")
then
909 call get_fields_string(line,
"=,", n_fields_max, n_found, i0, i1)
910 i_group = i_group + 1
912 if (i_group > max_groups) error stop
"Too many groups"
914 if (i_group == 1)
then
915 group_size = n_found - 1
916 else if (n_found - 1 /= group_size)
then
918 error stop
"Groups for a reaction should have the same size"
921 groups(i_group)%name = line(i0(1):i1(1))
922 allocate(groups(i_group)%members(n_found - 1))
925 groups(i_group)%members(n-1) = adjustl(line(i0(n):i1(n)))
930 if (i_group > 0)
then
932 lo = n_reactions_found
933 hi = n_reactions_found+group_size-1
934 reaction(lo+1:hi) = reaction(lo)
935 how_to_get(lo+1:hi) = how_to_get(lo)
936 data_value(lo+1:hi) = data_value(lo)
937 length_unit(lo+1:hi) = length_unit(lo)
938 n_reactions_found = hi
943 reaction(n) = string_replace(reaction(n), &
944 groups(i)%name, groups(i)%members(k))
945 how_to_get(n) = string_replace(how_to_get(n), &
946 groups(i)%name, groups(i)%members(k))
947 data_value(n) = string_replace(data_value(n), &
948 groups(i)%name, groups(i)%members(k))
954 if (count(reaction(lo:hi) == reaction(n)) > 1 .and. &
955 count(data_value(lo:hi) == data_value(n)) > 1)
then
957 print *, trim(reaction(k)),
",", data_value(k)
959 error stop
"Groups lead to duplicate reactions"
967 call get_fields_string(line,
",", n_fields_max, n_found, i0, i1)
969 if (n_found < 3 .or. n_found > 4)
then
971 error stop
"Invalid chemistry syntax"
974 if (n_reactions_found >= max_num_reactions) &
975 error stop
"Too many reactions, increase max_num_reactions"
977 n_reactions_found = n_reactions_found + 1
978 reaction(n_reactions_found) = line(i0(1):i1(1))
979 how_to_get(n_reactions_found) = line(i0(2):i1(2))
980 data_value(n_reactions_found) = line(i0(3):i1(3))
983 if (n_found > 3)
then
984 length_unit(n_reactions_found) = line(i0(4):i1(4))
986 length_unit(n_reactions_found) =
"m"
998 do n = 1, n_reactions_found
999 call parse_reaction(trim(reaction(n)), new_reaction, &
1000 ignored_species, keep_reaction)
1002 if (keep_reaction)
then
1008 new_reaction%description = trim(reaction(n))
1012 select case (how_to_get(n))
1013 case (
"field_table")
1015 call read_reaction_table(filename, &
1016 trim(data_value(n)), new_reaction)
1017 new_reaction%n_coeff = 0
1019 new_reaction%rate_type = rate_analytic_constant
1020 new_reaction%n_coeff = 1
1021 read(data_value(n), *) new_reaction%rate_data(1)
1023 new_reaction%rate_type = rate_analytic_linear
1024 new_reaction%n_coeff = 2
1025 read(data_value(n), *) new_reaction%rate_data(1:2)
1026 case (
"c1*exp(-(c2/(c3+Td))**2)")
1027 new_reaction%rate_type = rate_analytic_exp_v1
1028 new_reaction%n_coeff = 3
1029 read(data_value(n), *) new_reaction%rate_data(1:3)
1030 case (
"c1*exp(-(Td/c2)**2)")
1031 new_reaction%rate_type = rate_analytic_exp_v2
1032 new_reaction%n_coeff = 2
1033 read(data_value(n), *) new_reaction%rate_data(1:2)
1034 case (
"c1*(300/Te)**c2")
1035 new_reaction%rate_type = rate_analytic_k1
1036 new_reaction%n_coeff = 2
1037 read(data_value(n), *) new_reaction%rate_data(1:2)
1038 case (
"(c1*(kB_eV*Te+c2)**2-c3)*c4")
1039 new_reaction%rate_type = rate_analytic_k3
1040 new_reaction%n_coeff = 4
1041 read(data_value(n), *) new_reaction%rate_data(1:4)
1042 case (
"c1*(Tg/300)**c2*exp(-c3/Tg)")
1043 new_reaction%rate_type = rate_analytic_k4
1044 new_reaction%n_coeff = 3
1045 read(data_value(n), *) new_reaction%rate_data(1:3)
1046 case (
"c1*exp(-c2/Tg)")
1047 new_reaction%rate_type = rate_analytic_k5
1048 new_reaction%n_coeff = 2
1049 read(data_value(n), *) new_reaction%rate_data(1:2)
1051 new_reaction%rate_type = rate_analytic_k6
1052 new_reaction%n_coeff = 2
1053 read(data_value(n), *) new_reaction%rate_data(1:2)
1054 case (
"c1*(Tg/c2)**c3")
1055 new_reaction%rate_type = rate_analytic_k7
1056 new_reaction%n_coeff = 3
1057 read(data_value(n), *) new_reaction%rate_data(1:3)
1058 case (
"c1*(300/Tg)**c2")
1059 new_reaction%rate_type = rate_analytic_k8
1060 new_reaction%n_coeff = 2
1061 read(data_value(n), *) new_reaction%rate_data(1:2)
1062 case (
"c1*exp(-c2*Tg)")
1063 new_reaction%rate_type = rate_analytic_k9
1064 new_reaction%n_coeff = 2
1065 read(data_value(n), *) new_reaction%rate_data(1:2)
1066 case (
"10**(c1+c2*(Tg-300))")
1067 new_reaction%rate_type = rate_analytic_k10
1068 new_reaction%n_coeff = 2
1069 read(data_value(n), *) new_reaction%rate_data(1:2)
1070 case (
"c1*(300/Tg)**c2*exp(-c3/Tg)")
1071 new_reaction%rate_type = rate_analytic_k11
1072 new_reaction%n_coeff = 3
1073 read(data_value(n), *) new_reaction%rate_data(1:3)
1074 case (
"c1*Tg**c2*exp(-c3/Tg)")
1075 new_reaction%rate_type = rate_analytic_k12
1076 new_reaction%n_coeff = 3
1077 read(data_value(n), *) new_reaction%rate_data(1:3)
1078 case (
"c1*exp(-(c2/(c3+Td))**c4)")
1079 new_reaction%rate_type = rate_analytic_k13
1080 new_reaction%n_coeff = 4
1081 read(data_value(n), *) new_reaction%rate_data(1:4)
1082 case (
"c1*exp(-(Td/c2)**c3)")
1083 new_reaction%rate_type = rate_analytic_k14
1084 new_reaction%n_coeff = 3
1085 read(data_value(n), *) new_reaction%rate_data(1:3)
1086 case (
"c1*exp(-(c2/(kb*(Tg+Td/c3)))**c4)")
1087 new_reaction%rate_type = rate_analytic_k15
1088 new_reaction%n_coeff = 4
1089 read(data_value(n), *) new_reaction%rate_data(1:4)
1091 print *,
"Unknown rate type: ", trim(how_to_get(n))
1092 print *,
"For reaction: ", trim(reaction(n))
1093 print *,
"In file: ", trim(filename)
1094 print *,
"See documentation/chemistry.md"
1095 if (how_to_get(n) /=
"field_table" .and. &
1096 index(how_to_get(n),
"c1") == 0)
then
1097 print *,
"You probably use the old reaction format"
1098 print *,
"Try to use tools/chemistry_update_reactions.sh"
1099 print *,
"See also the chemistry documentation"
1101 error stop
"Unknown chemical reaction"
1105 select case (length_unit(n))
1110 new_reaction%rate_factor = new_reaction%rate_factor * &
1111 1e-6_dp**(new_reaction%n_species_in-1)
1113 print *,
"For reaction: ", trim(reaction(n))
1114 print *,
"Invalid length unit: ", trim(length_unit(n))
1125999 error stop
"read_reactions: no closing dashes for reaction list"
1129 subroutine read_reaction_table(filename, dataname, rdata)
1131 character(len=*),
intent(in) :: filename
1132 character(len=*),
intent(in) :: dataname
1133 type(reaction_t),
intent(inout) :: rdata
1135 rdata%rate_type = rate_tabulated_field
1136 call table_from_file(filename, dataname, rdata%x_data, rdata%y_data)
1137 end subroutine read_reaction_table
1140 subroutine parse_reaction(reaction_text, reaction, ignored_species, &
1143 character(len=*),
intent(in) :: reaction_text
1144 type(reaction_t),
intent(out) :: reaction
1145 character(len=comp_len),
intent(in) :: ignored_species(:)
1146 logical,
intent(out) :: keep_reaction
1147 integer,
parameter :: max_components = 100
1148 character(len=comp_len) :: component
1149 integer :: i, ix, n, n_found, multiplicity
1150 integer :: n_in, n_out
1151 integer :: i0(max_components)
1152 integer :: i1(max_components)
1153 integer :: ix_in(max_components)
1154 integer :: ix_out(max_components)
1155 integer :: multiplicity_out(max_components)
1156 logical :: left_side, is_gas_species
1159 call get_fields_string(reaction_text,
" ", max_components, n_found, i0, i1)
1162 keep_reaction = .true.
1166 reaction%n_species_in = 0
1169 component = reaction_text(i0(n):i1(n))
1171 if (component ==
"+") cycle
1173 if (component ==
"->")
then
1179 if (lge(component(1:1),
'1') .and. lle(component(1:1),
'9'))
then
1180 read(component(1:1), *) multiplicity
1181 component = component(2:)
1187 reaction%n_species_in = reaction%n_species_in + multiplicity
1199 if (component ==
"M")
then
1207 if (findloc(ignored_species, component, dim=1) > 0)
then
1208 is_gas_species = (
gas_index(component) > 0 .or. component ==
"M")
1210 if (left_side .and. .not. is_gas_species)
then
1213 keep_reaction = .false.
1224 error stop
"Too many species, increase max_num_species"
1231 do i = 1, multiplicity
1238 if (ix == ix_out(i))
exit
1241 if (i <= n_out)
then
1242 multiplicity_out(i) = multiplicity_out(i) + multiplicity
1247 multiplicity_out(n_out) = multiplicity
1252 reaction%ix_in = ix_in(1:n_in)
1253 reaction%ix_out = ix_out(1:n_out)
1254 reaction%multiplicity_out = multiplicity_out(1:n_out)
1255 reaction%rate_factor = rfactor
1258 print *,
"Error in the following reaction:"
1259 print *, trim(reaction_text)
1260 error stop
"No input species"
1262 end subroutine parse_reaction
1266 character(len=*),
intent(in) :: name
1274 subroutine get_fields_string(line, delims, n_max, n_found, ixs_start, ixs_end)
1276 character(len=*),
intent(in) :: line
1278 character(len=*),
intent(in) :: delims
1280 integer,
intent(in) :: n_max
1282 integer,
intent(inout) :: n_found
1284 integer,
intent(inout) :: ixs_start(n_max)
1286 integer,
intent(inout) :: ixs_end(n_max)
1288 integer :: ix, ix_prev
1293 do while (n_found < n_max)
1296 ix = verify(line(ix_prev+1:), delims)
1299 n_found = n_found + 1
1300 ixs_start(n_found) = ix_prev + ix
1303 ix = scan(line(ixs_start(n_found)+1:), delims) - 1
1306 ixs_end(n_found) = len(line)
1308 ixs_end(n_found) = ixs_start(n_found) + ix
1311 ix_prev = ixs_end(n_found)
1314 end subroutine get_fields_string
1318 pure function string_replace(string, text, replacement)
result(outs)
1319 character(len=*),
intent(in) :: string
1320 character(len=*),
intent(in) :: text
1321 character(len=*),
intent(in) :: replacement
1322 character(len=:),
allocatable :: outs
1323 integer,
parameter :: buffer_space = 256
1324 character(len=(len(string)+buffer_space)) :: buffer
1325 integer :: i, nt, nr, len_outs
1329 nr = len_trim(replacement)
1332 i = index(buffer, text(:nt))
1334 buffer = buffer(:i-1) // replacement(:nr) // trim(buffer(i+nt:))
1337 len_outs = len_trim(buffer)
1338 allocate(
character(len=len_outs) :: outs)
1339 outs = buffer(1:len_outs)
1340 end function string_replace
1343 subroutine to_simple_ascii(text, simple, charge)
1344 character(len=*),
intent(in) :: text
1345 character(len=*),
intent(inout) :: simple
1346 integer,
intent(out) :: charge
1348 logical :: in_brackets = .false.
1353 do n = 1, len_trim(text)
1354 select case (text(n:n))
1356 in_brackets = .true.
1357 simple = trim(simple) //
"_"
1359 in_brackets = .false.
1361 simple = trim(simple) //
"_star"
1363 if (.not. in_brackets)
then
1366 simple = trim(simple) //
"_plus"
1368 if (.not. in_brackets)
then
1371 simple = trim(simple) //
"_min"
1373 simple = trim(simple) //
"_hat"
1375 simple = trim(simple) //
"p"
1377 simple = trim(simple) // text(n:n)
1382 if (simple ==
"e" .or. simple ==
"stoch_e") charge = -1
1383 end subroutine to_simple_ascii
Module for handling chemical reactions.
character(len=20), dimension(*), parameter, public reaction_names
integer, parameter rate_tabulated_energy
Reaction with a field-dependent reaction rate.
subroutine, public read_reactions(filename, read_success)
Read reactions from a file.
subroutine, public chemistry_write_summary(fname)
Write a summary of the reactions (TODO) and the ionization and attachment coefficients (if working at...
integer, dimension(max_num_species), public, protected species_charge
Charge of the species.
integer, parameter, public attachment_reaction
Identifier for attachment reactions.
integer, parameter, public ionization_reaction
Identifier for ionization reactions.
subroutine, public get_rates(fields, rates, n_cells, energy_ev)
Compute reaction rates.
integer, parameter, public detachment_reaction
Identifier for detachment reactions.
integer, parameter, public general_reaction
Identifier for general reactions (not of any particular type)
subroutine, public chemistry_initialize(tree, cfg)
Initialize module and load chemical reactions.
integer, dimension(:), allocatable, public, protected charged_species_itree
List with indices of charged species.
integer, parameter, public recombination_reaction
Identifier for recombination reactions.
integer, public, protected n_stochastic_species
Number of stochastic species.
subroutine, public get_derivatives(dens, rates, derivs, n_cells)
Compute derivatives due to chemical reactions. Note that the 'rates' argument is modified.
integer, dimension(max_num_species), public, protected species_itree
species_itree(n) holds the index of species n in the tree (cell-centered variables)
subroutine, public chemistry_convert_stochastic_species(tree, rng)
Convert stochastic species into regular species, using random numbers.
subroutine, public chemistry_get_breakdown_field(field_td, min_growth_rate)
Get the breakdown field in Townsend.
character(len=comp_len), dimension(max_num_species), public, protected species_list
List of the species.
integer, public, protected n_species
Number of species present.
integer, public, protected n_plasma_species
Number of plasma species present.
elemental integer function, public species_index(name)
Find index of a species, return -1 if not found.
integer, dimension(:), allocatable, public, protected charged_species_charge
List with charges of charged species.
type(reaction_t), dimension(max_num_reactions), public, protected reactions
List of reactions.
integer, public, protected n_gas_species
Number of gas species present.
integer, public, protected n_reactions
Number of reactions present.
Module to set the time step.
integer, public, protected time_integrator
Which time integrator is used.
Module that stores parameters related to the gas.
character(len=comp_len), dimension(:), allocatable, public, protected gas_components
elemental integer function, public gas_index(name)
Find index of a gas component, return -1 if not found.
real(dp), public, protected gas_temperature
real(dp), parameter, public townsend_to_si
real(dp), dimension(:), allocatable, public, protected gas_densities
logical, public, protected gas_constant_density
Whether the gas has a constant density.
real(dp), public, protected gas_number_density
Module to set the type of model.
logical, public, protected model_has_energy_equation
Whether the model has an energy equation.
Module with settings and routines for tabulated data.
subroutine, public table_set_column(tbl, i_col, x, y, max_err)
Interpolate data and store in lookup table.
integer, public, protected table_xspacing
X-spacing for lookup table.
integer, public, protected table_size
How large lookup tables should be.
Module that provides routines for reading in arbritrary transport data.
real(dp), public, protected td_max_ev
Maximal energy (eV) in input data (automatically updated)
type(lt_t), public, protected td_tbl
integer, parameter, public td_diffusion
Electron diffusion constant.
integer, parameter, public td_eta
Attachment coefficient.
integer, public, protected td_energy_ev
Electron energy in eV (used with chemistry)
integer, parameter, public td_alpha
Ionization coefficient.
integer, parameter, public td_mobility
Electron mobility.
Module that contains physical and numerical constants.
real(dp), parameter uc_boltzmann_const
real(dp), parameter uc_elec_volt