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 :: rate_analytic_k16 = 21
129 integer,
parameter :: max_num_species = 100
132 integer,
parameter :: max_num_reactions = 500
150 character(len=comp_len),
public,
protected ::
species_list(max_num_species)
153 type(stochastic_species_t) :: stochastic_species_list(max_num_species)
162 type(reaction_t),
public,
protected ::
reactions(max_num_reactions)
165 type(tiny_react_t) :: tiny_react(max_num_reactions)
168 type(lt_t) :: chemtbl_fld
171 type(lt_t) :: chemtbl_ee
202 type(af_t),
intent(inout) :: tree
203 type(cfg_t),
intent(inout) :: cfg
204 integer :: n, i, j, i_elec, rtype
205 character(len=string_len) :: reaction_file
206 character(len=comp_len) :: tmp_name
207 logical :: read_success
209 call cfg_get(cfg,
"input_data%file", reaction_file)
220 if (.not. read_success)
then
221 print *,
"m_chemistry: no reaction table found, using standard model"
235 reactions(1)%rate_type = rate_tabulated_field
241 reactions(1)%description =
"e + M -> e + e + M+"
248 reactions(2)%rate_type = rate_tabulated_field
256 error stop
"Varying gas density not yet supported"
276 tiny_react(n)%ix_out =
reactions(n)%ix_out
277 tiny_react(n)%multiplicity_out =
reactions(n)%multiplicity_out
304 call check_charge_conservation()
310 if (any(
reactions(n)%ix_in == i_elec) .and. &
311 .not. any(
reactions(n)%ix_out == i_elec) .and. &
315 else if (any(
reactions(n)%ix_in == i_elec) .and. &
316 any(
reactions(n)%ix_out == i_elec .and. &
317 reactions(n)%multiplicity_out == 2))
then
324 else if (all(
reactions(n)%ix_in /= i_elec) .and. &
337 if (
reactions(n)%rate_type == rate_tabulated_field)
then
350 chemtbl_ee = lt_create(0.0_dp,
td_max_ev, &
356 if (
reactions(n)%rate_type == rate_tabulated_field)
then
382 call store_stochastic_species()
384 print *,
"--- List of reactions ---"
386 write(*,
"(I4,' (',I0,') ',A15,A)") n,
reactions(n)%n_species_in, &
390 print *,
"-------------------------"
392 print *,
"--- List of gas species ---"
396 print *,
"-------------------------"
398 print *,
"--- List of plasma species ---"
402 print *,
"-------------------------"
405 call chemistry_modify_rates(cfg)
410 subroutine store_stochastic_species()
411 integer :: n, i_stoch, namelen, iv
418 i_stoch = i_stoch + 1
425 print *,
"which should be present for stochastic species (stoch_)"
426 error stop
"Species for stochastic reaction not found"
435 end subroutine store_stochastic_species
439 type(af_t),
intent(inout) :: tree
440 type(rng_t),
intent(inout) :: rng
441 integer :: lvl, iblock, id, ijk, n
442 integer :: i_to, i_from, proc_id, n_procs
443 real(dp) :: dv, lambda, product_dr, n_produced
445 real(dp),
parameter :: two_pi = 2 * acos(-1.0_dp)
450 n_procs = omp_get_max_threads()
451 call prng%init_parallel(n_procs, rng)
455 proc_id = 1+omp_get_thread_num()
457 do lvl = 1, tree%highest_lvl
459 do iblock = 1,
size(tree%lvls(lvl)%leaves)
460 id = tree%lvls(lvl)%leaves(iblock)
461 product_dr = product(tree%boxes(id)%dr)
464 i_to = stochastic_species_list(n)%i_to
465 i_from = stochastic_species_list(n)%i_from
467 do kji_do(1, tree%n_cell)
469 if (tree%coord_t == af_cyl)
then
470 dv = two_pi * product_dr * af_cyl_radius_cc(tree%boxes(id), i)
478 lambda = dv * tree%boxes(id)%cc(ijk, i_from)
479 n_produced = prng%rngs(proc_id)%poisson(lambda)
481 tree%boxes(id)%cc(ijk, i_from) = 0.0_dp
482 tree%boxes(id)%cc(ijk, i_to) = tree%boxes(id)%cc(ijk, i_to) + &
492 call prng%update_seed(rng)
497 subroutine chemistry_modify_rates(cfg)
499 type(cfg_t),
intent(inout) :: cfg
500 integer :: n_modified, n, dummy_int(0), ix
501 real(dp) :: dummy_real(0)
502 integer,
allocatable :: reaction_ix(:)
503 real(dp),
allocatable :: rate_factors(:)
505 call cfg_add(cfg,
"input_data%modified_reaction_ix", dummy_int, &
506 "Indices of reactions to be modified", .true.)
507 call cfg_add(cfg,
"input_data%modified_rate_factors", dummy_real, &
508 "Reaction rate factors for modified reactions", .true.)
509 call cfg_get_size(cfg,
"input_data%modified_reaction_ix", n_modified)
510 call cfg_get_size(cfg,
"input_data%modified_rate_factors", n)
512 if (n /= n_modified) &
513 error stop
"size(modified_reaction_ix) /= size(modified_rate_factors)"
515 if (n_modified > 0)
then
516 allocate(reaction_ix(n_modified), rate_factors(n_modified))
517 call cfg_get(cfg,
"input_data%modified_reaction_ix", reaction_ix)
518 call cfg_get(cfg,
"input_data%modified_rate_factors", rate_factors)
520 if (minval(rate_factors) < 0) &
521 error stop
"Negative value in modified_rate_factors"
522 if (minval(reaction_ix) < 1 .or. maxval(reaction_ix) >
n_reactions) &
523 error stop
"modified_reaction_ix outside valid range"
531 end subroutine chemistry_modify_rates
538 character(len=*),
intent(in) :: fname
539 real(dp),
allocatable :: fields(:), energies(:)
540 real(dp),
allocatable :: rates(:, :)
541 real(dp),
allocatable :: eta(:), alpha(:), src(:), loss(:)
542 real(dp),
allocatable :: v(:), mu(:), diff(:)
543 integer :: n, n_fields, i_elec
548 n_fields =
td_tbl%n_points
550 if (n_fields < 3) error stop
"Not enough data for linear extrapolation"
552 allocate(fields(n_fields))
553 allocate(energies(n_fields))
555 allocate(eta(n_fields), alpha(n_fields), src(n_fields), loss(n_fields))
559 if (model_has_energy_equation)
then
561 call get_rates(fields, rates, n_fields, energies)
571 loss(:) = loss(:) + rates(:, n)
573 src(:) = src(:) + rates(:, n)
577 allocate(diff(n_fields))
580 allocate(mu(n_fields))
581 allocate(v(n_fields))
586 eta(2:) = loss(2:) / v(2:)
587 eta(1) = 2 * eta(2) - eta(3)
588 alpha(2:) = src(2:) / v(2:)
589 alpha(1) = 2 * alpha(2) - alpha(3)
592 open(newunit=my_unit, file=trim(fname), action=
"write")
593 write(my_unit,
"(A)") &
594 "E/N[Td] E[V/m] Electron_mobility[m^2/(Vs)] &
595 &Electron_diffusion[m^2/s] Townsend_ioniz._coef._alpha[1/m] &
596 &Townsend_attach._coef._eta[1/m] Ionization_rate[1/s] &
597 &Attachment_rate[1/s]"
599 write(my_unit, *) fields(n), &
610 subroutine check_charge_conservation()
611 integer :: n, q_in, q_out
617 if (q_in /= q_out)
then
619 error stop
"Charge is not conserved in the above reaction"
622 end subroutine check_charge_conservation
628 real(dp),
intent(out) :: field_td
630 real(dp),
intent(in) :: min_growth_rate
632 integer :: n, n_fields
633 real(dp),
allocatable :: energies(:)
634 real(dp),
allocatable :: fields(:), rates(:, :), src(:), loss(:)
636 n_fields =
td_tbl%n_points
637 allocate(fields(n_fields))
638 allocate(energies(n_fields))
640 allocate(src(n_fields), loss(n_fields))
643 if (model_has_energy_equation)
then
645 call get_rates(fields, rates, n_fields, energies)
655 loss(:) = loss(:) + rates(:, n)
657 src(:) = src(:) + rates(:, n)
661 do n = n_fields, 1, -1
662 if (src(n) - loss(n) < min_growth_rate)
exit
666 if (n > 0) field_td = fields(n)
676 integer,
intent(in) :: n_cells
677 real(dp),
intent(in) :: fields(n_cells)
678 real(dp),
intent(out) :: rates(n_cells,
n_reactions)
679 real(dp),
intent(in),
optional :: energy_ev(n_cells)
680 integer :: n, n_coeff
681 real(dp) :: c0, c(rate_max_num_coeff)
682 real(dp) :: te(n_cells)
683 logical :: te_available
686 real(dp),
parameter :: electron_ev_to_k = 2 *
uc_elec_volt / &
689 te_available = .false.
698 c(1:n_coeff) =
reactions(n)%rate_data(1:n_coeff)
702 if (.not.
present(energy_ev)) error stop
"energy_eV required"
703 rates(:, n) = c0 * lt_get_col(chemtbl_ee, &
704 reactions(n)%lookup_table_index, energy_ev)
705 case (rate_tabulated_field)
706 rates(:, n) = c0 * lt_get_col(chemtbl_fld, &
708 case (rate_analytic_constant)
709 rates(:, n) = c0 * c(1)
710 case (rate_analytic_linear)
711 rates(:, n) = c0 * c(1) * (fields - c(2))
712 case (rate_analytic_exp_v1)
713 rates(:, n) = c0 * c(1) * exp(-(c(2) / (c(3) + fields))**2)
714 case (rate_analytic_exp_v2)
715 rates(:, n) = c0 * c(1) * exp(-(fields/c(2))**2)
716 case (rate_analytic_k1)
717 if (.not. te_available)
then
721 te_available = .true.
723 rates(:, n) = c0 * c(1) * (300 / te)**c(2)
724 case (rate_analytic_k3)
725 if (.not. te_available)
then
727 te_available = .true.
731 case (rate_analytic_k4)
733 case (rate_analytic_k5)
735 case (rate_analytic_k6)
737 case (rate_analytic_k7)
739 case (rate_analytic_k8)
741 case (rate_analytic_k9)
743 case (rate_analytic_k10)
745 case (rate_analytic_k11)
747 case (rate_analytic_k12)
749 case (rate_analytic_k13)
750 rates(:, n) = c0 * c(1) * exp(-(c(2) / (c(3) + fields))**c(4))
751 case (rate_analytic_k14)
752 rates(:, n) = c0 * c(1) * exp(-(fields / c(2))**c(3))
753 case (rate_analytic_k15)
760 case (rate_analytic_k16)
761 if (.not. te_available)
then
763 te_available = .true.
765 rates(:, n) = c0 * c(1) * (300/te)**c(2) * exp(-c(3)/
gas_temperature) * &
774 integer,
intent(in) :: n_cells
776 real(dp),
intent(in) :: dens(n_cells,
n_species)
778 real(dp),
intent(inout) :: rates(n_cells,
n_reactions)
780 real(dp),
intent(out) :: derivs(n_cells,
n_species)
783 derivs(:, :) = 0.0_dp
788 rates(:, n) = rates(:, n) * &
789 product(dens(:, tiny_react(n)%ix_in), dim=2)
792 do i = 1,
size(tiny_react(n)%ix_in)
793 ix = tiny_react(n)%ix_in(i)
794 derivs(:, ix) = derivs(:, ix) - rates(:, n)
798 do i = 1,
size(tiny_react(n)%ix_out)
799 ix = tiny_react(n)%ix_out(i)
800 derivs(:, ix) = derivs(:, ix) + rates(:, n) * &
801 tiny_react(n)%multiplicity_out(i)
807 subroutine read_ignored_species(filename, ignored_species)
808 character(len=*),
intent(in) :: filename
809 character(len=comp_len),
allocatable,
intent(inout) :: &
811 character(len=comp_len) :: tmp(max_num_species)
812 character(len=string_len) :: line
813 integer :: my_unit, n_ignored
817 open(newunit=my_unit, file=filename, action=
"read")
821 read(my_unit,
"(A)",
end=998) line
824 if (line ==
"ignored_species")
then
826 read(my_unit,
"(A)") line
827 if (line(1:5) /=
"-----") &
828 error stop
"ignored_species not followed by -----"
835 read(my_unit,
"(A)",
end=999) line
839 if (line(1:1) ==
"#") cycle
842 if (line(1:5) ==
"-----")
exit
844 n_ignored = n_ignored + 1
845 read(line, *) tmp(n_ignored)
849 ignored_species = tmp(1:n_ignored)
853999 error stop
"read_ignored_species: no closing dashes"
854 end subroutine read_ignored_species
858 character(len=*),
intent(in) :: filename
859 logical,
intent(out) :: read_success
860 character(len=string_len) :: line
861 integer,
parameter :: field_len = 80
862 character(len=field_len) :: data_value(max_num_reactions)
863 character(len=field_len) :: reaction(max_num_reactions)
864 character(len=field_len) :: how_to_get(max_num_reactions)
865 character(len=10) :: length_unit(max_num_reactions)
866 type(reaction_t) :: new_reaction
868 integer :: n_reactions_found
869 integer,
parameter :: n_fields_max = 40
870 integer :: i0(n_fields_max), i1(n_fields_max)
871 integer :: n, i, k, n_found, lo, hi
872 logical :: keep_reaction
874 character(len=comp_len),
allocatable :: ignored_species(:)
877 character(len=name_len) :: name
878 character(len=field_len),
allocatable :: members(:)
881 integer,
parameter :: max_groups = 10
882 integer :: i_group, group_size
883 type(group) :: groups(max_groups)
885 call read_ignored_species(filename, ignored_species)
887 open(newunit=my_unit, file=filename, action=
"read")
889 n_reactions_found = 0
892 read_success = .false.
896 read(my_unit,
"(A)",
end=998) line
899 if (line ==
"reaction_list")
then
901 read(my_unit,
"(A)") line
902 if (line(1:5) /=
"-----") &
903 error stop
"read_reactions: reaction_list not followed by -----"
910 read(my_unit,
"(A)",
end=999) line
914 if (line(1:1) ==
"#") cycle
917 if (line(1:5) ==
"-----")
exit
920 if (line(1:1) ==
"@")
then
921 call get_fields_string(line,
"=,", n_fields_max, n_found, i0, i1)
922 i_group = i_group + 1
924 if (i_group > max_groups) error stop
"Too many groups"
926 if (i_group == 1)
then
927 group_size = n_found - 1
928 else if (n_found - 1 /= group_size)
then
930 error stop
"Groups for a reaction should have the same size"
933 groups(i_group)%name = line(i0(1):i1(1))
934 allocate(groups(i_group)%members(n_found - 1))
937 groups(i_group)%members(n-1) = adjustl(line(i0(n):i1(n)))
942 if (i_group > 0)
then
944 lo = n_reactions_found
945 hi = n_reactions_found+group_size-1
946 reaction(lo+1:hi) = reaction(lo)
947 how_to_get(lo+1:hi) = how_to_get(lo)
948 data_value(lo+1:hi) = data_value(lo)
949 length_unit(lo+1:hi) = length_unit(lo)
950 n_reactions_found = hi
955 reaction(n) = string_replace(reaction(n), &
956 groups(i)%name, groups(i)%members(k))
957 how_to_get(n) = string_replace(how_to_get(n), &
958 groups(i)%name, groups(i)%members(k))
959 data_value(n) = string_replace(data_value(n), &
960 groups(i)%name, groups(i)%members(k))
966 if (count(reaction(lo:hi) == reaction(n)) > 1 .and. &
967 count(data_value(lo:hi) == data_value(n)) > 1)
then
969 print *, trim(reaction(k)),
",", data_value(k)
971 error stop
"Groups lead to duplicate reactions"
979 call get_fields_string(line,
",", n_fields_max, n_found, i0, i1)
981 if (n_found < 3 .or. n_found > 4)
then
983 error stop
"Invalid chemistry syntax"
986 if (n_reactions_found >= max_num_reactions) &
987 error stop
"Too many reactions, increase max_num_reactions"
989 n_reactions_found = n_reactions_found + 1
990 reaction(n_reactions_found) = line(i0(1):i1(1))
991 how_to_get(n_reactions_found) = line(i0(2):i1(2))
992 data_value(n_reactions_found) = line(i0(3):i1(3))
995 if (n_found > 3)
then
996 length_unit(n_reactions_found) = line(i0(4):i1(4))
998 length_unit(n_reactions_found) =
"m"
1010 do n = 1, n_reactions_found
1011 call parse_reaction(trim(reaction(n)), new_reaction, &
1012 ignored_species, keep_reaction)
1014 if (keep_reaction)
then
1020 new_reaction%description = trim(reaction(n))
1024 select case (how_to_get(n))
1025 case (
"field_table")
1027 call read_reaction_table(filename, &
1028 trim(data_value(n)), new_reaction)
1029 new_reaction%n_coeff = 0
1031 new_reaction%rate_type = rate_analytic_constant
1032 new_reaction%n_coeff = 1
1033 read(data_value(n), *) new_reaction%rate_data(1)
1035 new_reaction%rate_type = rate_analytic_linear
1036 new_reaction%n_coeff = 2
1037 read(data_value(n), *) new_reaction%rate_data(1:2)
1038 case (
"c1*exp(-(c2/(c3+Td))**2)")
1039 new_reaction%rate_type = rate_analytic_exp_v1
1040 new_reaction%n_coeff = 3
1041 read(data_value(n), *) new_reaction%rate_data(1:3)
1042 case (
"c1*exp(-(Td/c2)**2)")
1043 new_reaction%rate_type = rate_analytic_exp_v2
1044 new_reaction%n_coeff = 2
1045 read(data_value(n), *) new_reaction%rate_data(1:2)
1046 case (
"c1*(300/Te)**c2")
1047 new_reaction%rate_type = rate_analytic_k1
1048 new_reaction%n_coeff = 2
1049 read(data_value(n), *) new_reaction%rate_data(1:2)
1050 case (
"(c1*(kB_eV*Te+c2)**2-c3)*c4")
1051 new_reaction%rate_type = rate_analytic_k3
1052 new_reaction%n_coeff = 4
1053 read(data_value(n), *) new_reaction%rate_data(1:4)
1054 case (
"c1*(Tg/300)**c2*exp(-c3/Tg)")
1055 new_reaction%rate_type = rate_analytic_k4
1056 new_reaction%n_coeff = 3
1057 read(data_value(n), *) new_reaction%rate_data(1:3)
1058 case (
"c1*exp(-c2/Tg)")
1059 new_reaction%rate_type = rate_analytic_k5
1060 new_reaction%n_coeff = 2
1061 read(data_value(n), *) new_reaction%rate_data(1:2)
1063 new_reaction%rate_type = rate_analytic_k6
1064 new_reaction%n_coeff = 2
1065 read(data_value(n), *) new_reaction%rate_data(1:2)
1066 case (
"c1*(Tg/c2)**c3")
1067 new_reaction%rate_type = rate_analytic_k7
1068 new_reaction%n_coeff = 3
1069 read(data_value(n), *) new_reaction%rate_data(1:3)
1070 case (
"c1*(300/Tg)**c2")
1071 new_reaction%rate_type = rate_analytic_k8
1072 new_reaction%n_coeff = 2
1073 read(data_value(n), *) new_reaction%rate_data(1:2)
1074 case (
"c1*exp(-c2*Tg)")
1075 new_reaction%rate_type = rate_analytic_k9
1076 new_reaction%n_coeff = 2
1077 read(data_value(n), *) new_reaction%rate_data(1:2)
1078 case (
"10**(c1+c2*(Tg-300))")
1079 new_reaction%rate_type = rate_analytic_k10
1080 new_reaction%n_coeff = 2
1081 read(data_value(n), *) new_reaction%rate_data(1:2)
1082 case (
"c1*(300/Tg)**c2*exp(-c3/Tg)")
1083 new_reaction%rate_type = rate_analytic_k11
1084 new_reaction%n_coeff = 3
1085 read(data_value(n), *) new_reaction%rate_data(1:3)
1086 case (
"c1*Tg**c2*exp(-c3/Tg)")
1087 new_reaction%rate_type = rate_analytic_k12
1088 new_reaction%n_coeff = 3
1089 read(data_value(n), *) new_reaction%rate_data(1:3)
1090 case (
"c1*exp(-(c2/(c3+Td))**c4)")
1091 new_reaction%rate_type = rate_analytic_k13
1092 new_reaction%n_coeff = 4
1093 read(data_value(n), *) new_reaction%rate_data(1:4)
1094 case (
"c1*exp(-(Td/c2)**c3)")
1095 new_reaction%rate_type = rate_analytic_k14
1096 new_reaction%n_coeff = 3
1097 read(data_value(n), *) new_reaction%rate_data(1:3)
1098 case (
"c1*exp(-(c2/(kb*(Tg+Td/c3)))**c4)")
1099 new_reaction%rate_type = rate_analytic_k15
1100 new_reaction%n_coeff = 4
1101 read(data_value(n), *) new_reaction%rate_data(1:4)
1102 case (
"c1*(300/Te)**c2*exp(-c3/Tg)*exp(c4*(Te-Tg)/(Te*Tg))")
1103 new_reaction%rate_type = rate_analytic_k16
1104 new_reaction%n_coeff = 4
1105 read(data_value(n), *) new_reaction%rate_data(1:4)
1107 print *,
"Unknown rate type: ", trim(how_to_get(n))
1108 print *,
"For reaction: ", trim(reaction(n))
1109 print *,
"In file: ", trim(filename)
1110 print *,
"See documentation/chemistry.md"
1111 if (how_to_get(n) /=
"field_table" .and. &
1112 index(how_to_get(n),
"c1") == 0)
then
1113 print *,
"You probably use the old reaction format"
1114 print *,
"Try to use tools/chemistry_update_reactions.sh"
1115 print *,
"See also the chemistry documentation"
1117 error stop
"Unknown chemical reaction"
1121 select case (length_unit(n))
1126 new_reaction%rate_factor = new_reaction%rate_factor * &
1127 1e-6_dp**(new_reaction%n_species_in-1)
1129 print *,
"For reaction: ", trim(reaction(n))
1130 print *,
"Invalid length unit: ", trim(length_unit(n))
1141999 error stop
"read_reactions: no closing dashes for reaction list"
1145 subroutine read_reaction_table(filename, dataname, rdata)
1147 character(len=*),
intent(in) :: filename
1148 character(len=*),
intent(in) :: dataname
1149 type(reaction_t),
intent(inout) :: rdata
1151 rdata%rate_type = rate_tabulated_field
1152 call table_from_file(filename, dataname, rdata%x_data, rdata%y_data)
1153 end subroutine read_reaction_table
1156 subroutine parse_reaction(reaction_text, reaction, ignored_species, &
1159 character(len=*),
intent(in) :: reaction_text
1160 type(reaction_t),
intent(out) :: reaction
1161 character(len=comp_len),
intent(in) :: ignored_species(:)
1162 logical,
intent(out) :: keep_reaction
1163 integer,
parameter :: max_components = 100
1164 character(len=comp_len) :: component
1165 integer :: i, ix, n, n_found, multiplicity
1166 integer :: n_in, n_out
1167 integer :: i0(max_components)
1168 integer :: i1(max_components)
1169 integer :: ix_in(max_components)
1170 integer :: ix_out(max_components)
1171 integer :: multiplicity_out(max_components)
1172 logical :: left_side, is_gas_species
1175 call get_fields_string(reaction_text,
" ", max_components, n_found, i0, i1)
1178 keep_reaction = .true.
1182 reaction%n_species_in = 0
1185 component = reaction_text(i0(n):i1(n))
1187 if (component ==
"+") cycle
1189 if (component ==
"->")
then
1195 if (lge(component(1:1),
'1') .and. lle(component(1:1),
'9'))
then
1196 read(component(1:1), *) multiplicity
1197 component = component(2:)
1203 reaction%n_species_in = reaction%n_species_in + multiplicity
1215 if (component ==
"M")
then
1223 if (findloc(ignored_species, component, dim=1) > 0)
then
1224 is_gas_species = (
gas_index(component) > 0 .or. component ==
"M")
1226 if (left_side .and. .not. is_gas_species)
then
1229 keep_reaction = .false.
1240 error stop
"Too many species, increase max_num_species"
1247 do i = 1, multiplicity
1254 if (ix == ix_out(i))
exit
1257 if (i <= n_out)
then
1258 multiplicity_out(i) = multiplicity_out(i) + multiplicity
1263 multiplicity_out(n_out) = multiplicity
1268 reaction%ix_in = ix_in(1:n_in)
1269 reaction%ix_out = ix_out(1:n_out)
1270 reaction%multiplicity_out = multiplicity_out(1:n_out)
1271 reaction%rate_factor = rfactor
1274 print *,
"Error in the following reaction:"
1275 print *, trim(reaction_text)
1276 error stop
"No input species"
1278 end subroutine parse_reaction
1282 character(len=*),
intent(in) :: name
1290 subroutine get_fields_string(line, delims, n_max, n_found, ixs_start, ixs_end)
1292 character(len=*),
intent(in) :: line
1294 character(len=*),
intent(in) :: delims
1296 integer,
intent(in) :: n_max
1298 integer,
intent(inout) :: n_found
1300 integer,
intent(inout) :: ixs_start(n_max)
1302 integer,
intent(inout) :: ixs_end(n_max)
1304 integer :: ix, ix_prev
1309 do while (n_found < n_max)
1312 ix = verify(line(ix_prev+1:), delims)
1315 n_found = n_found + 1
1316 ixs_start(n_found) = ix_prev + ix
1319 ix = scan(line(ixs_start(n_found)+1:), delims) - 1
1322 ixs_end(n_found) = len(line)
1324 ixs_end(n_found) = ixs_start(n_found) + ix
1327 ix_prev = ixs_end(n_found)
1330 end subroutine get_fields_string
1334 pure function string_replace(string, text, replacement)
result(outs)
1335 character(len=*),
intent(in) :: string
1336 character(len=*),
intent(in) :: text
1337 character(len=*),
intent(in) :: replacement
1338 character(len=:),
allocatable :: outs
1339 integer,
parameter :: buffer_space = 256
1340 character(len=(len(string)+buffer_space)) :: buffer
1341 integer :: i, nt, nr, len_outs
1345 nr = len_trim(replacement)
1348 i = index(buffer, text(:nt))
1350 buffer = buffer(:i-1) // replacement(:nr) // trim(buffer(i+nt:))
1353 len_outs = len_trim(buffer)
1354 allocate(
character(len=len_outs) :: outs)
1355 outs = buffer(1:len_outs)
1356 end function string_replace
1359 subroutine to_simple_ascii(text, simple, charge)
1360 character(len=*),
intent(in) :: text
1361 character(len=*),
intent(inout) :: simple
1362 integer,
intent(out) :: charge
1364 logical :: in_brackets = .false.
1369 do n = 1, len_trim(text)
1370 select case (text(n:n))
1372 in_brackets = .true.
1373 simple = trim(simple) //
"_"
1375 in_brackets = .false.
1377 simple = trim(simple) //
"_star"
1379 if (.not. in_brackets)
then
1382 simple = trim(simple) //
"_plus"
1384 if (.not. in_brackets)
then
1387 simple = trim(simple) //
"_min"
1389 simple = trim(simple) //
"_hat"
1391 simple = trim(simple) //
"p"
1393 simple = trim(simple) // text(n:n)
1398 if (simple ==
"e" .or. simple ==
"stoch_e") charge = -1
1399 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